Skip to content

Commit

Permalink
Fix lambda chaining parsing (#209)
Browse files Browse the repository at this point in the history
* Fix lambda chaining/precedence

* adding more tests

* check assign works
  • Loading branch information
ldemailly authored Sep 3, 2024
1 parent 79d7d99 commit 7189b8a
Show file tree
Hide file tree
Showing 6 changed files with 42 additions and 14 deletions.
3 changes: 2 additions & 1 deletion ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const (
ASSIGN // =
OR // ||
AND // &&
LAMBDA // =>
EQUALS // ==
LESSGREATER // > or <
SUM // +
Expand All @@ -38,7 +39,7 @@ var Precedences = map[token.Type]Priority{
token.COLON: AND, // range operator and maps (lower than lambda)
token.EQ: EQUALS,
token.NOTEQ: EQUALS,
token.LAMBDA: EQUALS,
token.LAMBDA: LAMBDA,
token.LT: LESSGREATER,
token.GT: LESSGREATER,
token.LTEQ: LESSGREATER,
Expand Down
23 changes: 12 additions & 11 deletions ast/priority_string.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions main_test.txtar
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,16 @@ stdout '^\(\)=>if 1\+2==3\{4\}$'
grol -quiet -c '(()=> if 1+2==3 {4})()'
stdout '^4$'

# lamda chaining:
grol -quiet -c '(()=>a=>b=>c=>a+b+c)()(1)(2)(3)'
stdout '^6$'

grol -quiet -c '(()=>a=>b=>()=>c=>a+b+c)()(1)(2)()(3)'
stdout '^6$'

grol -quiet -c 'f= a=>b=>(x,y)=>c=>a+b+c+x+y;f(1)(2)(4,5)(3)'
stdout '^15$'

# stack trace in errors
!grol -quiet -c 'func level1(){1+"x"}; func level2(){level1()}; func level3(){level2()}; level3()'
stderr 'Total 1 error'
Expand Down
4 changes: 3 additions & 1 deletion object/object.go
Original file line number Diff line number Diff line change
Expand Up @@ -568,7 +568,9 @@ func (f *Function) lambdaPrint(ps *ast.PrintState, out *strings.Builder) string
} else {
out.WriteString("=>")
}
needBraces := len(f.Body.Statements) != 1 || f.Body.Statements[0].Value().Type() == token.LBRACE
needBraces := len(f.Body.Statements) != 1 ||
f.Body.Statements[0].Value().Type() == token.LBRACE ||
f.Body.Statements[0].Value().Type() == token.LAMBDA
if needBraces {
out.WriteString("{")
}
Expand Down
4 changes: 4 additions & 0 deletions parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,10 @@ func (p *Parser) parseExpression(precedence ast.Priority) ast.Node {
return nil
}
leftExp := prefix()
if p.peekTokenIs(token.LAMBDA) && precedence == ast.LAMBDA { // allow lambda chaining without parentheses in input.
p.nextToken()
return p.parseLambdaMulti(leftExp)
}
for !p.peekTokenIs(token.SEMICOLON) && precedence < p.peekPrecedence() {
t := p.peekToken.Type()
infix := p.infixParseFns[t]
Expand Down
12 changes: 11 additions & 1 deletion parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,12 +214,22 @@ func Test_OperatorPrecedenceParsing(t *testing.T) {
}
}

func TestFormat(t *testing.T) {
func TestFormat(t *testing.T) { //nolint:funlen // long table driven tests.
tests := []struct {
input string
expected string
compact string
}{
{
`a=>b=>a+b`,
"a => {\n\tb => {\n\t\ta + b\n\t}\n}",
"a=>{b=>{a+b}}",
},
{
"a=>{b=>{a+b}}", // check it parses back fine, unlike before https://github.com/grol-io/grol/issues/208 fix
"a => {\n\tb => {\n\t\ta + b\n\t}\n}",
"a=>{b=>{a+b}}",
},
{
`a=[1,2,3]
a[1]
Expand Down

0 comments on commit 7189b8a

Please sign in to comment.