Parsing prefix expressions, tests passes

git-svn-id: https://svn.tlawal.org/svn/monkey@24 f6afcba9-9ef1-4bdd-9b72-7484f5705bac
This commit is contained in:
Tijani Lawal 2022-05-31 11:32:43 +00:00
parent 45f6929c14
commit 2253d6b02c
3 changed files with 124 additions and 24 deletions

View File

@ -58,6 +58,12 @@ type IntegerLiteral struct {
Value int64
}
type PrefixExpression struct {
Token token.Token // prefix token i.e. !
Operator string
Right Expression
}
// Let Statements
func (ls *LetStatement) statement_node() {}
@ -139,3 +145,19 @@ func (il *IntegerLiteral) TokenLiteral() string {
func (il *IntegerLiteral) String() string {
return il.Token.Literal
}
// PrefixExpression
func (pe *PrefixExpression) expression_node() {}
func (pe *PrefixExpression) TokenLiteral() string {
return pe.Token.Literal
}
func (pe *PrefixExpression) String() string {
var out bytes.Buffer
out.WriteString("(")
out.WriteString(pe.Operator)
out.WriteString(pe.Right.String())
out.WriteString(")")
return out.String()
}

View File

@ -47,6 +47,8 @@ func New(l_lexer *lexer.Lexer) *Parser {
l_parser.prefix_parse_functions = make(map[token.TokenType]prefix_parse_function)
l_parser.register_prefix(token.IDENT, l_parser.parse_identifier)
l_parser.register_prefix(token.INT, l_parser.parse_integer_literal)
l_parser.register_prefix(token.BANG, l_parser.parse_prefix_expression)
l_parser.register_prefix(token.MINUS, l_parser.parse_prefix_expression)
return l_parser
}
@ -69,16 +71,17 @@ func (l_parser *Parser) ParseProgram() *ast.Program {
return program
}
func (l_parser *Parser) register_prefix(l_token_type token.TokenType, l_function prefix_parse_function) {
l_parser.prefix_parse_functions[l_token_type] = l_function
func (l_parser *Parser) peek_error(l_token token.TokenType) {
message := fmt.Sprintf("expected next token to be %s, got %s", l_token, l_parser.peek_token.Type)
l_parser.errors = append(l_parser.errors, message)
}
func (l_parser *Parser) parse_identifier() ast.Expression {
return &ast.Identifier{Token: l_parser.current_token, Value: l_parser.current_token.Literal}
func (l_parser *Parser) current_token_is(l_token token.TokenType) bool {
return l_parser.current_token.Type == l_token
}
func (l_parser *Parser) register_infix(l_token_type token.TokenType, l_function infix_parse_function) {
l_parser.infix_parse_functions[l_token_type] = l_function
func (l_parser *Parser) peek_token_is(l_token token.TokenType) bool {
return l_parser.peek_token.Type == l_token
}
func (l_parser *Parser) next_token() {
@ -86,6 +89,16 @@ func (l_parser *Parser) next_token() {
l_parser.peek_token = l_parser.lexer.NextToken()
}
func (l_parser *Parser) expect_peek(l_token token.TokenType) bool {
if l_parser.peek_token_is(l_token) {
l_parser.next_token()
return true
} else {
l_parser.peek_error(l_token)
return false
}
}
func (l_parser *Parser) parse_statement() ast.Statement {
switch l_parser.current_token.Type {
case token.LET:
@ -135,6 +148,18 @@ func (l_parser *Parser) parse_expression_statement() *ast.ExpressionStatement {
return statement
}
func (l_parser *Parser) register_prefix(l_token_type token.TokenType, l_function prefix_parse_function) {
l_parser.prefix_parse_functions[l_token_type] = l_function
}
func (l_parser *Parser) parse_identifier() ast.Expression {
return &ast.Identifier{Token: l_parser.current_token, Value: l_parser.current_token.Literal}
}
func (l_parser *Parser) register_infix(l_token_type token.TokenType, l_function infix_parse_function) {
l_parser.infix_parse_functions[l_token_type] = l_function
}
func (l_parser *Parser) parse_integer_literal() ast.Expression {
literal := &ast.IntegerLiteral{Token: l_parser.current_token}
value, error := strconv.ParseInt(l_parser.current_token.Literal, 0, 64)
@ -150,31 +175,24 @@ func (l_parser *Parser) parse_integer_literal() ast.Expression {
func (l_parser *Parser) parse_expression(precedence int) ast.Expression {
prefix := l_parser.prefix_parse_functions[l_parser.current_token.Type]
if prefix == nil {
l_parser.no_prefix_parse_function_error(l_parser.current_token.Type)
return nil
}
left_expression := prefix()
return left_expression
}
func (l_parser *Parser) expect_peek(l_token token.TokenType) bool {
if l_parser.peek_token_is(l_token) {
l_parser.next_token()
return true
} else {
l_parser.peek_error(l_token)
return false
}
}
func (l_parser *Parser) peek_error(l_token token.TokenType) {
message := fmt.Sprintf("expected next token to be %s, got %s", l_token, l_parser.peek_token.Type)
func (l_parser *Parser) no_prefix_parse_function_error(l_token_type token.TokenType) {
message := fmt.Sprintf("no prefix parse function for %s, found", l_token_type)
l_parser.errors = append(l_parser.errors, message)
}
func (l_parser *Parser) current_token_is(l_token token.TokenType) bool {
return l_parser.current_token.Type == l_token
func (l_parser *Parser) parse_prefix_expression() ast.Expression {
expression := &ast.PrefixExpression{
Token: l_parser.current_token,
Operator: l_parser.current_token.Literal,
}
func (l_parser *Parser) peek_token_is(l_token token.TokenType) bool {
return l_parser.peek_token.Type == l_token
l_parser.next_token()
expression.Right = l_parser.parse_expression(PREFIX)
return expression
}

View File

@ -1,6 +1,8 @@
package parser
import (
"fmt"
"monkey/ast"
"monkey/lexer"
"testing"
@ -175,3 +177,61 @@ func TestIntegerLiteralExpressions(l_test *testing.T) {
l_test.Errorf("literal.TokenLiteral not %s, got=%s", "5", literal.TokenLiteral())
}
}
func TestParsingPrefixExpression(l_test *testing.T) {
prefix_tests := []struct {
input string
operator string
integer_value int64
}{
{"!5;", "!", 5},
{"-15", "-", 15},
}
for _, tt := range prefix_tests {
l_lexer := lexer.New(tt.input)
l_parser := New(l_lexer)
program := l_parser.ParseProgram()
check_parser_errors(l_test, l_parser)
if len(program.Statements) != 1 {
l_test.Fatalf("program.Statements does not contain %d statements, got=%d\n", 1, len(program.Statements))
}
statement, ok := program.Statements[0].(*ast.ExpressionStatement)
if !ok {
l_test.Fatalf("program.Statements[0] is not ast.ExpressionStatement, got=%T", program.Statements[0])
}
expression, ok := statement.Expression.(*ast.PrefixExpression)
if !ok {
l_test.Fatalf("program.Statements[0] is not ast.PrefixEXpression, got=%T", statement.Expression)
}
if expression.Operator != tt.operator {
l_test.Fatalf("exp.Operator is not '%s', got %s", tt.operator, expression.Operator)
}
if !testIntegerLiteral(l_test, expression.Right, tt.integer_value) {
return
}
}
}
func testIntegerLiteral(l_test *testing.T, il ast.Expression, value int64) bool {
integer, ok := il.(*ast.IntegerLiteral)
if !ok {
l_test.Errorf("il not *ast.IntegerLiteral, got=%T", il)
return false
}
if integer.Value != value {
l_test.Errorf("integer.Value not %d, got=%d", value, integer.Value)
return false
}
if integer.TokenLiteral() != fmt.Sprintf("%d", value) {
l_test.Errorf("integer.TokenLiteral not %d, got=%s", value, integer.TokenLiteral())
return false
}
return true
}