shrimp/src/compiler/tests/pipe.test.ts
Chris Wanstrath 248a53c887 Fix underscore handling in nested pipes and non-function receivers
Add pipeVarStack to track pipe variables for nested pipes, allowing _
to correctly reference the innermost piped value. Also enable piping
to array literals and parenthesized expressions (e.g., `5 | [_ _ _]`).
2026-01-27 19:12:48 -08:00

159 lines
4.2 KiB
TypeScript

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)
})
})