add prefix operator parsing

parent 73b9a654
......@@ -118,3 +118,22 @@ type IntegerLiteral struct {
func (il *IntegerLiteral) expressionNode() {}
func (il *IntegerLiteral) TokenLiteral() string { return il.Token.Literal }
func (il *IntegerLiteral) String() string { return il.Token.Literal }
type PrefixExpression struct {
Token token.Token
Operator string
Right Expression
}
func (pe *PrefixExpression) expressionNode() {}
func (pe *PrefixExpression) TokenLiteral() string { return pe.Token.Literal }
func (pe *PrefixExpression) String() string {
var out strings.Builder
out.WriteString("(")
out.WriteString(pe.Operator)
out.WriteString(pe.Right.String())
out.WriteString(")")
return out.String()
}
......@@ -46,6 +46,8 @@ func New(l *lexer.Lexer) *Parser {
p.prefixParseFns = make(map[token.TokenType]prefixParseFn)
p.registerPrefix(token.IDENT, p.parseIdentifier)
p.registerPrefix(token.INT, p.parseIntegerLiteral)
p.registerPrefix(token.BANG, p.parsePrefixExpression)
p.registerPrefix(token.MINUS, p.parsePrefixExpression)
// read two tokens so curToken and peekToken are set
p.nextToken()
......@@ -165,9 +167,15 @@ func (p *Parser) parseExpressionStatement() *ast.ExpressionStatement {
return stmt
}
func (p *Parser) noPrefixParseFnError(t token.TokenType) {
msg := fmt.Sprintf("no prefix parse function for %s found", t)
p.errors = append(p.errors, msg)
}
func (p *Parser) parseExpression(precedence int) ast.Expression {
prefix := p.prefixParseFns[p.curToken.Type]
if prefix == nil {
p.noPrefixParseFnError(p.curToken.Type)
return nil
}
leftExp := prefix()
......@@ -193,3 +201,16 @@ func (p *Parser) parseIntegerLiteral() ast.Expression {
return lit
}
func (p *Parser) parsePrefixExpression() ast.Expression {
expression := &ast.PrefixExpression{
Token: p.curToken,
Operator: p.curToken.Literal,
}
p.nextToken()
expression.Right = p.parseExpression(PREFIX)
return expression
}
package parser
import (
"fmt"
"testing"
"gitlab.csos95.com/csos95/monkey/ast"
......@@ -152,15 +153,18 @@ func TestIntegerLiteralExpression(t *testing.T) {
t.Fatalf("program.Statements[0] is not *ast.ExpressionStatement. got=%T", program.Statements[0])
}
literal, ok := stmt.Expression.(*ast.IntegerLiteral)
if !ok {
t.Fatalf("exp not *ast.IntegerLiteral. got=%T", stmt.Expression)
}
if literal.Value != 5 {
t.Errorf("literal.Value not %d. got=%d", 5, literal.Value)
}
if literal.TokenLiteral() != "5" {
t.Errorf("literal.TokenLiteral not %s. got=%s", "5", literal.TokenLiteral())
// literal, ok := stmt.Expression.(*ast.IntegerLiteral)
// if !ok {
// t.Fatalf("exp not *ast.IntegerLiteral. got=%T", stmt.Expression)
// }
// if literal.Value != 5 {
// t.Errorf("literal.Value not %d. got=%d", 5, literal.Value)
// }
// if literal.TokenLiteral() != "5" {
// t.Errorf("literal.TokenLiteral not %s. got=%s", "5", literal.TokenLiteral())
// }
if !testIntegerLiteral(t, stmt.Expression, 5) {
return
}
}
......@@ -194,10 +198,30 @@ func TestParsingPrefixExpressions(t *testing.T) {
t.Fatalf("stmt is not ast.PrefixExpression. got=%T", stmt.Expression)
}
if exp.Operator != tt.operator {
t.Fatalf("exp.Operator is not '%s'. got=%s", stmt.Expression)
t.Fatalf("exp.Operator is not '%s'. got=%s", tt.operator, exp.Operator)
}
if !testIntegerLiteral(t, exp.Right, tt.integerValue) {
return
}
}
}
func testIntegerLiteral(t *testing.T, il ast.Expression, value int64) bool {
integ, ok := il.(*ast.IntegerLiteral)
if !ok {
t.Errorf("il not *ast.IntegerLiteral. got=%T", il)
return false
}
if integ.Value != value {
t.Errorf("integ.Value not %d. got=%d", value, integ.Value)
return false
}
if integ.TokenLiteral() != fmt.Sprintf("%d", value) {
t.Errorf("integ.TokenLiteral not %d. got=%s", value, integ.TokenLiteral())
return false
}
return true
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment