import { expect, describe, test } from 'bun:test' import { parser } from '../shrimp' import '../shrimp.grammar' // Importing this so changes cause it to retest! describe('pipe expressions', () => { test('simple pipe expression', () => { expect('echo hello | grep h').toMatchTree(` PipeExpr FunctionCall Identifier echo PositionalArg Identifier hello operator | FunctionCall Identifier grep PositionalArg Identifier h `) }) test('multi-stage pipe chain', () => { expect('find files | filter active | sort').toMatchTree(` PipeExpr FunctionCall Identifier find PositionalArg Identifier files operator | FunctionCall Identifier filter PositionalArg Identifier active operator | FunctionCallOrIdentifier Identifier sort `) }) test('pipe with identifier', () => { expect('get-value | process').toMatchTree(` PipeExpr FunctionCallOrIdentifier Identifier get-value operator | FunctionCallOrIdentifier Identifier process `) }) test('pipe expression in assignment', () => { expect('result = echo hello | grep h').toMatchTree(` Assign AssignableIdentifier result Eq = PipeExpr FunctionCall Identifier echo PositionalArg Identifier hello operator | FunctionCall Identifier grep PositionalArg Identifier h `) }) test('pipe with inline function', () => { expect('items | each do x: x end').toMatchTree(` PipeExpr FunctionCallOrIdentifier Identifier items operator | FunctionCall Identifier each PositionalArg FunctionDef Do do Params Identifier x colon : FunctionCallOrIdentifier Identifier x keyword end `) }) test(`double trouble (do keyword isn't over eager)`, () => { expect(` double 2 | double`).toMatchTree(` PipeExpr FunctionCall Identifier double PositionalArg Number 2 operator | FunctionCallOrIdentifier Identifier double `) }) test('string literals can be piped', () => { expect(`'hey there' | echo`).toMatchTree(` PipeExpr String StringFragment hey there operator | FunctionCallOrIdentifier Identifier echo `) }) test('number literals can be piped', () => { expect(`42 | echo`).toMatchTree(` PipeExpr Number 42 operator | FunctionCallOrIdentifier Identifier echo`) expect(`4.22 | echo`).toMatchTree(` PipeExpr Number 4.22 operator | FunctionCallOrIdentifier Identifier echo`) }) test('null literals can be piped', () => { expect(`null | echo`).toMatchTree(` PipeExpr Null null operator | FunctionCallOrIdentifier Identifier echo`) }) test('boolean literals can be piped', () => { expect(`true | echo`).toMatchTree(` PipeExpr Boolean true operator | FunctionCallOrIdentifier Identifier echo`) }) test('array literals can be piped', () => { expect(`[1 2 3] | echo`).toMatchTree(` PipeExpr Array Number 1 Number 2 Number 3 operator | FunctionCallOrIdentifier Identifier echo `) }) test('dict literals can be piped', () => { expect(`[a=1 b=2 c=3] | echo`).toMatchTree(` PipeExpr Dict NamedArg NamedArgPrefix a= Number 1 NamedArg NamedArgPrefix b= Number 2 NamedArg NamedArgPrefix c= Number 3 operator | FunctionCallOrIdentifier Identifier echo `) }) }) describe('pipe continuation', () => { test('pipe on next line', () => { expect(`hello | echo`).toMatchTree(` PipeExpr FunctionCallOrIdentifier Identifier hello operator | FunctionCallOrIdentifier Identifier echo `) expect(`echo hello | grep h`).toMatchTree(` PipeExpr FunctionCall Identifier echo PositionalArg Identifier hello operator | FunctionCall Identifier grep PositionalArg Identifier h `) }) test('pipe on next non-empty line', () => { expect(`hello | echo`).toMatchTree(` PipeExpr FunctionCallOrIdentifier Identifier hello operator | FunctionCallOrIdentifier Identifier echo `) }) test('multi-line pipe chain', () => { expect(`echo hello | grep h | sort`).toMatchTree(` PipeExpr FunctionCall Identifier echo PositionalArg Identifier hello operator | FunctionCall Identifier grep PositionalArg Identifier h operator | FunctionCallOrIdentifier Identifier sort `) }) test('pipe with indentation', () => { expect(`echo hello | grep h | sort`).toMatchTree(` PipeExpr FunctionCall Identifier echo PositionalArg Identifier hello operator | FunctionCall Identifier grep PositionalArg Identifier h operator | FunctionCallOrIdentifier Identifier sort `) }) test('pipe after operand on next line (trailing pipe style)', () => { expect(`echo hello | grep h`).toMatchTree(` PipeExpr FunctionCall Identifier echo PositionalArg Identifier hello operator | FunctionCall Identifier grep PositionalArg Identifier h `) }) test('same-line pipes still work', () => { expect('echo hello | grep h | sort').toMatchTree(` PipeExpr FunctionCall Identifier echo PositionalArg Identifier hello operator | FunctionCall Identifier grep PositionalArg Identifier h operator | FunctionCallOrIdentifier Identifier sort `) }) test('lots of pipes', () => { expect(` 'this should help readability in long chains' | split ' ' | map (ref str.to-upper) | join '-' | echo `).toMatchTree(` PipeExpr String StringFragment this should help readability in long chains operator | FunctionCall Identifier split PositionalArg String StringFragment operator | FunctionCall Identifier map PositionalArg ParenExpr FunctionCall Identifier ref PositionalArg DotGet IdentifierBeforeDot str Identifier to-upper operator | FunctionCall Identifier join PositionalArg String StringFragment - operator | FunctionCallOrIdentifier Identifier echo `) }) })