aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBobby <[email protected]>2023-11-03 17:53:17 +0000
committerBobby <[email protected]>2023-11-03 17:53:17 +0000
commit0a868d6263ccd3de687eeb07d85b7e95056f8340 (patch)
tree34f7260fbcb1ecfea51cd891d3a78b7c48a12e22
parente8a6c163c9a58b69f6f96c373118ac6996637e25 (diff)
downloadmana-0a868d6263ccd3de687eeb07d85b7e95056f8340.tar.xz
mana-0a868d6263ccd3de687eeb07d85b7e95056f8340.zip
Add PrefixExpressions and ParseIntegerLiterals w/tests
-rw-r--r--ast/ast.go22
-rw-r--r--parser/parser.go2
-rw-r--r--parser/parser_test.go69
3 files changed, 91 insertions, 2 deletions
diff --git a/ast/ast.go b/ast/ast.go
index ec53a8c..021b387 100644
--- a/ast/ast.go
+++ b/ast/ast.go
@@ -129,6 +129,28 @@ func (es *ExpressionStatement) String() string {
return ""
}
+// PrefixExpression represents a prefix expression.
+type PrefixExpression struct {
+ Token tokens.Token // the prefix token, e.g. !
+ Operator string
+ Right Expression
+}
+
+func (pe *PrefixExpression) expressionNode() {}
+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()
+}
+
// IntegerLiteral represents an integer literal.
type IntegerLiteral struct {
Token tokens.Token // the token.INT token
diff --git a/parser/parser.go b/parser/parser.go
index 32bb4bc..d236bf0 100644
--- a/parser/parser.go
+++ b/parser/parser.go
@@ -115,7 +115,7 @@ func (p *Parser) parseIdentifier() ast.Expression {
// parseIntegerLiteral parses an integer literal.
func (p *Parser) parseIntegerLiteral() ast.Expression {
- var lit *ast.IntegerLiteral = &ast.IntegerLiteral{ Token: p.curToken }
+ var lit *ast.IntegerLiteral = &ast.IntegerLiteral{Token: p.curToken}
var value, err = strconv.ParseInt(p.curToken.Literal, 0, 64)
if err != nil {
diff --git a/parser/parser_test.go b/parser/parser_test.go
index cd1d506..828db24 100644
--- a/parser/parser_test.go
+++ b/parser/parser_test.go
@@ -1,6 +1,7 @@
package parser
import (
+ "fmt"
"mana/ast"
"mana/lexer"
"testing"
@@ -182,7 +183,6 @@ func TestIntegerLiteralExpression(t *testing.T) {
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)
}
@@ -192,3 +192,70 @@ func TestIntegerLiteralExpression(t *testing.T) {
}
}
+// Prefix expression tests.
+
+func TestParsingPrefixExpressions(t *testing.T) {
+ var prefixTests = []struct {
+ input string
+ operator string
+ integerValue int64
+ }{
+ {"!5;", "!", 5},
+ {"-15;", "-", 15},
+ }
+
+ for _, tt := range prefixTests {
+ var l *lexer.Lexer = lexer.New(tt.input)
+ var p *Parser = New(l)
+ var program *ast.Program = p.ParseProgram()
+ checkParserErrors(t, p)
+
+ if len(program.Statements) != 1 {
+ t.Fatalf("program.Statements does not contain %d statements. got=%d", 1, len(program.Statements))
+ }
+
+ stmt, ok := program.Statements[0].(*ast.ExpressionStatement)
+
+ if !ok {
+ t.Fatalf("program.Statements[0] is not ast.ExpressionStatement. got=%T", program.Statements[0])
+ }
+
+ exp, ok := stmt.Expression.(*ast.PrefixExpression)
+
+ if !ok {
+ 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", tt.operator, exp.Operator)
+ }
+
+ if !testIntegerLiteral(t, exp.Right, tt.integerValue) {
+ return
+ }
+ }
+}
+
+func testIntegerLiteral(t *testing.T, il ast.Expression, value int64) bool {
+ var 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
+}