import { describe, test, expect } from 'bun:test' describe('pipe expressions', () => { test('simple pipe passes result as first argument', () => { const code = ` double = do x: x * 2 end double 2 | double` expect(code).toEvaluateTo(8) }) test('pipe chain with three stages', () => { const code = ` add-one = do x: x + 1 end double = do x: x * 2 end minus-point-one = do x: x - 0.1 end add-one 3 | double | minus-point-one` // 4 8 7.9 expect(code).toEvaluateTo(7.9) }) test('pipe with function that has additional arguments', () => { const code = ` multiply = do a b: a * b end get-five = do: 5 end get-five | multiply 3` expect(code).toEvaluateTo(15) }) test('pipe with bare identifier', () => { const code = ` get-value = 42 process = do x: x + 10 end get-value | process` expect(code).toEvaluateTo(52) }) test('pipe in assignment', () => { const code = ` add-ten = do x: x + 10 end result = add-ten 5 | add-ten result` // 5 + 10 = 15, then 15 + 10 = 25 expect(code).toEvaluateTo(25) }) test('pipe with named underscore arg', () => { expect(` divide = do a b: a / b end get-ten = do: 10 end get-ten | divide 2 b=_`).toEvaluateTo(0.2) expect(` divide = do a b: a / b end get-ten = do: 10 end get-ten | divide b=_ 2`).toEvaluateTo(0.2) expect(` divide = do a b: a / b end get-ten = do: 10 end get-ten | divide 2 a=_`).toEvaluateTo(5) expect(` divide = do a b: a / b end get-ten = do: 10 end get-ten | divide a=_ 2`).toEvaluateTo(5) }) test('nested pipes', () => { // This is complicated, but the idea is to make sure the underscore // handling logic works correctly when there are multiple pipe stages // in a single expression. expect(` sub = do a b: a - b end div = do a b: a / b end sub 3 1 | div (sub 110 9 | sub 1) _ | div 5`).toEvaluateTo(10) }) test('pipe with prelude functions (list.reverse and list.map)', () => { expect(` double = do x: x * 2 end range 1 3 | list.reverse | list.map double `).toEvaluateTo([6, 4, 2]) }) test('pipe with prelude function (echo)', () => { expect(` get-msg = do: 'hello' end get-msg | length `).toEvaluateTo(5) }) test('string literals can be piped', () => { expect(`'hey there' | str.to-upper`).toEvaluateTo('HEY THERE') }) test('number literals can be piped', () => { expect(`42 | str.trim`).toEvaluateTo('42') expect(`4.22 | str.trim`).toEvaluateTo('4.22') }) test('null literals can be piped', () => { expect(`null | type`).toEvaluateTo('null') }) test('boolean literals can be piped', () => { expect(`true | str.to-upper`).toEvaluateTo('TRUE') }) test('array literals can be piped', () => { expect(`[1 2 3] | str.join '-'`).toEvaluateTo('1-2-3') }) test('dict literals can be piped', () => { expect(`[a=1 b=2 c=3] | dict.values | list.sort | str.join '-'`).toEvaluateTo('1-2-3') }) test('pipe to array literal using _ in nested expressions', () => { // _ should be accessible inside nested function calls within array literals const code = ` double = do x: x * 2 end triple = do x: x * 3 end 5 | [(double _) (triple _)]` expect(code).toEvaluateTo([10, 15]) }) test('pipe to array literal using _ multiple times', () => { expect(`10 | [_ _ _]`).toEvaluateTo([10, 10, 10]) }) test('pipe to parenthesized expression using _', () => { const code = ` double = do x: x * 2 end 5 | (double _)` expect(code).toEvaluateTo(10) }) test('pipe chain with array literal receiver', () => { // Pipe to array, then pipe that array to a function const code = ` double = do x: x * 2 end 5 | [(double _) _] | list.sum` expect(code).toEvaluateTo(15) // [10, 5] -> 15 }) test('_ in deeply nested expressions within pipe', () => { // _ should work in nested function calls within function arguments const code = ` add = do a b: a + b end mul = do a b: a * b end 10 | add (mul _ 2) _` // add(mul(10, 2), 10) = add(20, 10) = 30 expect(code).toEvaluateTo(30) }) })