import { describe } from 'bun:test' import { expect, test } from 'bun:test' describe('exception handling', () => { test('try with catch - no error thrown', () => { expect(` try: 42 catch err: 99 end `).toEvaluateTo(42) }) test('try with catch - error thrown', () => { expect(` try: throw 'something went wrong' 99 catch err: err end `).toEvaluateTo('something went wrong') }) test('try with catch - catch variable binding', () => { expect(` try: throw 100 catch my-error: my-error + 50 end `).toEvaluateTo(150) }) test('try with finally - no error', () => { expect(` x = 0 result = try: x = 10 42 finally: x = x + 5 end x `).toEvaluateTo(15) }) test('try with finally - return value from try', () => { expect(` x = 0 result = try: x = 10 42 finally: x = x + 5 999 end result `).toEvaluateTo(42) }) test('try with catch and finally - no error', () => { expect(` x = 0 try: x = 10 42 catch err: x = 999 0 finally: x = x + 5 end x `).toEvaluateTo(15) }) test('try with catch and finally - error thrown', () => { expect(` x = 0 result = try: x = 10 throw 'error' 99 catch err: x = 20 err finally: x = x + 5 end x `).toEvaluateTo(25) }) test('try with catch and finally - return value from catch', () => { expect(` result = try: throw 'oops' catch err: 'caught' finally: 'finally' end result `).toEvaluateTo('caught') }) test('throw statement with string', () => { expect(` try: throw 'error message' catch err: err end `).toEvaluateTo('error message') }) test('throw statement with number', () => { expect(` try: throw 404 catch err: err end `).toEvaluateTo(404) }) test('throw statement with dict', () => { expect(` try: throw [code=500 message=failed] catch e: e end `).toEvaluateTo({ code: 500, message: 'failed' }) }) test('uncaught exception fails', () => { expect(`throw 'uncaught error'`).toFailEvaluation() }) test('single-line try catch', () => { expect(`result = try: throw 'err' catch e: 'handled' end; result`).toEvaluateTo('handled') }) test('nested try blocks - inner catches', () => { expect(` try: result = try: throw 'inner error' catch err: err end result catch outer: 'outer' end `).toEvaluateTo('inner error') }) test('nested try blocks - outer catches', () => { expect(` try: try: throw 'inner error' catch err: throw 'outer error' end catch outer: outer end `).toEvaluateTo('outer error') }) test('try as expression', () => { expect(` x = try: 10 catch err: 0 end y = try: throw 'err' catch err: 20 end x + y `).toEvaluateTo(30) }) }) describe('function-level exception handling', () => { test('function with catch - no error', () => { expect(` read-file = do path: path catch e: 'default' end read-file test.txt `).toEvaluateTo('test.txt') }) test('function with catch - error thrown', () => { expect(` read-file = do path: throw 'file not found' catch e: 'default' end read-file test.txt `).toEvaluateTo('default') }) test('function with catch - error variable binding', () => { expect(` safe-call = do: throw 'operation failed' catch err: err end safe-call `).toEvaluateTo('operation failed') }) test('function with finally - always runs', () => { expect(` counter = 0 increment-task = do: result = 42 result finally: counter = counter + 1 end x = increment-task y = increment-task counter `).toEvaluateTo(2) }) test('function with finally - return value from body', () => { expect(` get-value = do: 100 finally: 999 end get-value `).toEvaluateTo(100) }) test('function with catch and finally', () => { expect(` cleanup-count = 0 safe-op = do should-fail: if should-fail: throw 'failed' end 'success' catch e: 'caught' finally: cleanup-count = cleanup-count + 1 end result1 = safe-op false result2 = safe-op true cleanup-count `).toEvaluateTo(2) }) test('function with catch and finally - catch return value', () => { expect(` safe-fail = do: throw 'always fails' catch e: 'error handled' finally: noop = 1 end safe-fail `).toEvaluateTo('error handled') }) test('function without catch/finally still works', () => { expect(` regular = do x: x + 10 end regular 5 `).toEvaluateTo(15) }) test('nested functions with catch', () => { expect(` inner = do: throw 'inner error' catch e: 'inner caught' end outer = do: inner catch e: 'outer caught' end outer `).toEvaluateTo('inner caught') }) })