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 | [_ _ _]`).
159 lines
4.2 KiB
TypeScript
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)
|
|
})
|
|
})
|