From 3d06775ddc907bfe2476eb62edfa4f42f149c3fe Mon Sep 17 00:00:00 2001 From: James Shubin Date: Sun, 18 Nov 2018 20:22:35 -0500 Subject: [PATCH] lang: Add some lambda function parsing and tests Part of this isn't fully implemented, but might as well get the tests running. --- lang/lexparse_test.go | 134 ++++++++++++++++++++++++++++++++++++++++++ lang/parser.y | 14 +++++ 2 files changed, 148 insertions(+) diff --git a/lang/lexparse_test.go b/lang/lexparse_test.go index cd9091eb..cf0ccf92 100644 --- a/lang/lexparse_test.go +++ b/lang/lexparse_test.go @@ -1769,6 +1769,140 @@ func TestLexParse0(t *testing.T) { exp: exp, }) } + { + + fn := &ExprFunc{ + Body: &ExprInt{ + V: 42, + }, + } + exp := &StmtProg{ + Prog: []interfaces.Stmt{ + &StmtBind{ + Ident: "fn", + Value: fn, + }, + }, + } + testCases = append(testCases, test{ + name: "simple function expr 1", + code: ` + # lambda + $fn = func() { + 42 + } + `, + fail: false, + exp: exp, + }) + } + { + fn := &ExprFunc{ + Args: []*Arg{ + { + Name: "x", + Type: types.TypeStr, + }, + }, + Return: types.TypeStr, + Body: &ExprCall{ + Name: operatorFuncName, + Args: []interfaces.Expr{ + &ExprStr{ + V: "+", + }, + &ExprStr{ + V: "hello", + }, + &ExprVar{ + Name: "x", + }, + }, + }, + } + if err := fn.SetType(types.NewType("func(x str) str")); err != nil { + t.Fatal("could not build type") + } + exp := &StmtProg{ + Prog: []interfaces.Stmt{ + &StmtBind{ + Ident: "fn", + Value: fn, + }, + }, + } + testCases = append(testCases, test{ + name: "simple function expr 2", + code: ` + # lambda + $fn = func($x str) str { + "hello" + $x + } + `, + fail: false, + exp: exp, + }) + } + { + fn := &ExprFunc{ + Args: []*Arg{ + { + Name: "x", + Type: types.TypeStr, + }, + }, + Return: types.TypeStr, + Body: &ExprCall{ + Name: operatorFuncName, + Args: []interfaces.Expr{ + &ExprStr{ + V: "+", + }, + &ExprStr{ + V: "hello", + }, + &ExprVar{ + Name: "x", + }, + }, + }, + } + if err := fn.SetType(types.NewType("func(x str) str")); err != nil { + t.Fatal("could not build type") + } + exp := &StmtProg{ + Prog: []interfaces.Stmt{ + &StmtBind{ + Ident: "fn", + Value: fn, + }, + &StmtBind{ + Ident: "foo", + Value: &ExprCall{ + Name: "fn", + Args: []interfaces.Expr{ + &ExprStr{ + V: "world", + }, + }, + //Var: true, // XXX: add this! + }, + }, + }, + } + testCases = append(testCases, test{ + name: "simple function expr 3", + code: ` + # lambda + $fn = func($x str) str { + "hello" + $x + } + $foo = $fn("world") # helloworld + `, + fail: false, + exp: exp, + }) + } names := []string{} for index, tc := range testCases { // run all the tests diff --git a/lang/parser.y b/lang/parser.y index f5830531..e16eaf67 100644 --- a/lang/parser.y +++ b/lang/parser.y @@ -496,12 +496,26 @@ struct_field: } ; call: + // fmt.printf(...) dotted_identifier OPEN_PAREN call_args CLOSE_PAREN { posLast(yylex, yyDollar) // our pos $$.expr = &ExprCall{ Name: $1.str, Args: $3.exprs, + //Var: false, // default + } + } + // calling a function that's stored in a variable (a lambda) + // `$foo(4, "hey")` # call function value +| VAR_IDENTIFIER OPEN_PAREN call_args CLOSE_PAREN + { + posLast(yylex, yyDollar) // our pos + $$.expr = &ExprCall{ + Name: $1.str, + Args: $3.exprs, + // XXX: this Var option isn't implemented yet + //Var: true, // lambda } } | expr PLUS expr