Added lexing and parsing of LAMBDA to monkey2 version

main
oabrivard 2 years ago
parent 8a5d7ab5d3
commit f69fa28995

@ -0,0 +1,3 @@
module gitea.paas.celticinfo.fr/oabrivard/monkeylang/monkey2
go 1.21.0

@ -33,7 +33,14 @@ func (l *Lexer) NextToken() token.Token {
case '+': case '+':
tok = newToken(token.PLUS, l.ch) tok = newToken(token.PLUS, l.ch)
case '-': case '-':
tok = newToken(token.MINUS, l.ch) if l.peekChar() == '>' {
ch := l.ch
l.readChar()
literal := string(ch) + string(l.ch)
tok = token.Token{Type: token.LAMBDA, Literal: literal}
} else {
tok = newToken(token.MINUS, l.ch)
}
case '!': case '!':
if l.peekChar() == '=' { if l.peekChar() == '=' {
ch := l.ch ch := l.ch

@ -14,6 +14,8 @@ let add = fn(x, y) {
x + y; x + y;
}; };
let addlambda = fn(x,y) -> x + y;
let result = add(five, ten); let result = add(five, ten);
!-/*5; !-/*5;
5 < 10 > 5; 5 < 10 > 5;
@ -59,6 +61,20 @@ if (5 < 10) {
{token.RBRACE, "}"}, {token.RBRACE, "}"},
{token.SEMICOLON, ";"}, {token.SEMICOLON, ";"},
{token.LET, "let"}, {token.LET, "let"},
{token.IDENT, "addlambda"},
{token.ASSIGN, "="},
{token.FUNCTION, "fn"},
{token.LPAREN, "("},
{token.IDENT, "x"},
{token.COMMA, ","},
{token.IDENT, "y"},
{token.RPAREN, ")"},
{token.LAMBDA, "->"},
{token.IDENT, "x"},
{token.PLUS, "+"},
{token.IDENT, "y"},
{token.SEMICOLON, ";"},
{token.LET, "let"},
{token.IDENT, "result"}, {token.IDENT, "result"},
{token.ASSIGN, "="}, {token.ASSIGN, "="},
{token.IDENT, "add"}, {token.IDENT, "add"},

@ -357,11 +357,28 @@ func (p *Parser) parseFunctionLiteral() ast.Expression {
lit.Parameters = p.parseFunctionParameters() lit.Parameters = p.parseFunctionParameters()
if !p.expectPeek(token.LBRACE) { if p.peekTokenIs(token.LAMBDA) {
return nil // parse fn() with lambda syntax
} p.nextToken()
p.nextToken()
block := &ast.BlockStatement{Token: p.curToken}
block.Statements = []ast.Statement{}
exp := p.parseExpressionStatement()
if exp != nil {
block.Statements = append(block.Statements, exp)
}
lit.Body = p.parseBlockStatement() lit.Body = block
} else {
// parse fn() with bloc statement syntax
if !p.expectPeek(token.LBRACE) {
return nil
}
lit.Body = p.parseBlockStatement()
}
return lit return lit
} }

@ -503,50 +503,58 @@ func TestIfElseExpression(t *testing.T) {
} }
func TestFunctionLiteralParsing(t *testing.T) { func TestFunctionLiteralParsing(t *testing.T) {
input := `fn(x, y) { x + y; }` tests := []struct {
input string
}{
{"fn(x, y) { x + y; }"},
{"fn(x, y) -> x + y;"},
}
l := lexer.New(input) for _, tt := range tests {
p := New(l)
program := p.ParseProgram()
checkParserErrors(t, p)
if len(program.Statements) != 1 { l := lexer.New(tt.input)
t.Fatalf("program.Body does not contain %d statements. got=%d\n", p := New(l)
1, len(program.Statements)) program := p.ParseProgram()
} checkParserErrors(t, p)
stmt, ok := program.Statements[0].(*ast.ExpressionStatement) if len(program.Statements) != 1 {
if !ok { t.Fatalf("program.Body does not contain %d statements. got=%d\n",
t.Fatalf("program.Statements[0] is not ast.ExpressionStatement. got=%T", 1, len(program.Statements))
program.Statements[0]) }
}
function, ok := stmt.Expression.(*ast.FunctionLiteral) stmt, ok := program.Statements[0].(*ast.ExpressionStatement)
if !ok { if !ok {
t.Fatalf("stmt.Expression is not ast.FunctionLiteral. got=%T", t.Fatalf("program.Statements[0] is not ast.ExpressionStatement. got=%T",
stmt.Expression) program.Statements[0])
} }
if len(function.Parameters) != 2 { function, ok := stmt.Expression.(*ast.FunctionLiteral)
t.Fatalf("function literal parameters wrong. want 2, got=%d\n", if !ok {
len(function.Parameters)) t.Fatalf("stmt.Expression is not ast.FunctionLiteral. got=%T",
} stmt.Expression)
}
testLiteralExpression(t, function.Parameters[0], "x") if len(function.Parameters) != 2 {
testLiteralExpression(t, function.Parameters[1], "y") t.Fatalf("function literal parameters wrong. want 2, got=%d\n",
len(function.Parameters))
}
if len(function.Body.Statements) != 1 { testLiteralExpression(t, function.Parameters[0], "x")
t.Fatalf("function.Body.Statements has not 1 statements. got=%d\n", testLiteralExpression(t, function.Parameters[1], "y")
len(function.Body.Statements))
}
bodyStmt, ok := function.Body.Statements[0].(*ast.ExpressionStatement) if len(function.Body.Statements) != 1 {
if !ok { t.Fatalf("function.Body.Statements has not 1 statements. got=%d\n",
t.Fatalf("function body stmt is not ast.ExpressionStatement. got=%T", len(function.Body.Statements))
function.Body.Statements[0]) }
}
testInfixExpression(t, bodyStmt.Expression, "x", "+", "y") bodyStmt, ok := function.Body.Statements[0].(*ast.ExpressionStatement)
if !ok {
t.Fatalf("function body stmt is not ast.ExpressionStatement. got=%T",
function.Body.Statements[0])
}
testInfixExpression(t, bodyStmt.Expression, "x", "+", "y")
}
} }
func TestFunctionParameterParsing(t *testing.T) { func TestFunctionParameterParsing(t *testing.T) {

@ -33,6 +33,8 @@ const (
LBRACE = "{" LBRACE = "{"
RBRACE = "}" RBRACE = "}"
LAMBDA = "->"
// Keywords // Keywords
FUNCTION = "FUNCTION" FUNCTION = "FUNCTION"
LET = "LET" LET = "LET"

Loading…
Cancel
Save