From 0c8c71ea5decc06624d931ae742a8028063e304a Mon Sep 17 00:00:00 2001 From: Maxwell Alexius Date: Sun, 20 Oct 2019 22:59:16 +0800 Subject: [PATCH] Set up ternary operator lexing tokens and expression structure --- compiler/ast/expressions.go | 23 ++++++++++++++++++++++ compiler/ast/testable_expressions.go | 8 ++++++++ compiler/lexer/lexer.go | 4 ++-- compiler/lexer/lexer_test.go | 13 ++++++++++-- compiler/parser/expression_parsing.go | 4 ++++ compiler/parser/expression_parsing_test.go | 3 ++- compiler/parser/parser.go | 2 ++ compiler/parser/precedence/precedence.go | 1 + compiler/token/token.go | 2 ++ 9 files changed, 55 insertions(+), 5 deletions(-) diff --git a/compiler/ast/expressions.go b/compiler/ast/expressions.go index 9e51675d9..eaef7b80a 100644 --- a/compiler/ast/expressions.go +++ b/compiler/ast/expressions.go @@ -262,6 +262,29 @@ func (n *NilExpression) String() string { return "nil" } +type TernaryExpression struct { + *BaseNode + Condition Expression + Consequence Expression + Alternative Expression +} + +func (te *TernaryExpression) expressionNode() {} +func (te *TernaryExpression) TokenLiteral() string { + return te.Token.Literal +} +func (te *TernaryExpression) String() string { + var out bytes.Buffer + + out.WriteString(te.Condition.String()) + out.WriteString(" ? ") + out.WriteString(te.Consequence.String()) + out.WriteString(" : ") + out.WriteString(te.Alternative.String()) + + return out.String() +} + type IfExpression struct { *BaseNode Conditionals []*ConditionalExpression diff --git a/compiler/ast/testable_expressions.go b/compiler/ast/testable_expressions.go index ef09b9e22..ce727842c 100644 --- a/compiler/ast/testable_expressions.go +++ b/compiler/ast/testable_expressions.go @@ -165,6 +165,14 @@ func (ti *TestableIdentifier) ShouldHaveName(expectedName string) { } } +// TestableTernaryExpression +type TestableTernaryExpression struct { + *TernaryExpression + t *testing.T +} + +// TODO: Test helpers + // TestableIfExpression type TestableIfExpression struct { *IfExpression diff --git a/compiler/lexer/lexer.go b/compiler/lexer/lexer.go index 4070659db..b7f962b66 100644 --- a/compiler/lexer/lexer.go +++ b/compiler/lexer/lexer.go @@ -160,8 +160,8 @@ func (l *Lexer) NextToken() token.Token { l.readChar() tok = token.CreateOperator("&&", l.line) } - case '%': - tok = token.CreateOperator("%", l.line) + case '%', '?': + tok = token.CreateOperator(string(l.ch), l.line) case '#': tok.Literal = string(l.absorbComment()) tok.Type = token.Comment diff --git a/compiler/lexer/lexer_test.go b/compiler/lexer/lexer_test.go index 1864193e2..26dbb6c2d 100644 --- a/compiler/lexer/lexer_test.go +++ b/compiler/lexer/lexer_test.go @@ -1,8 +1,9 @@ package lexer import ( - "github.com/goby-lang/goby/compiler/token" "testing" + + "github.com/goby-lang/goby/compiler/token" ) func TestNextToken(t *testing.T) { @@ -125,6 +126,8 @@ func TestNextToken(t *testing.T) { '\"string\"' "\'string\'" '\'string\'' + + flag ? true_result : false_result ` tests := []struct { @@ -439,7 +442,13 @@ func TestNextToken(t *testing.T) { {token.String, "'string'", 117}, {token.String, "'string'", 118}, - {token.EOF, "", 119}, + {token.Ident, "flag", 120}, + {token.TernaryOperator, "?", 120}, + {token.Ident, "true_result", 120}, + {token.Colon, ":", 120}, + {token.Ident, "false_result", 120}, + + {token.EOF, "", 121}, } l := New(input) diff --git a/compiler/parser/expression_parsing.go b/compiler/parser/expression_parsing.go index 53c7415de..2b9fbaddd 100644 --- a/compiler/parser/expression_parsing.go +++ b/compiler/parser/expression_parsing.go @@ -261,6 +261,10 @@ func (p *Parser) parseIndexExpression(left ast.Expression) ast.Expression { return callExpression } +// TODO: Add Parse Ternary Expression +// func (p *Parser) parseTernaryExpression(cond ast.Expression) ast.Expression { +// } + func (p *Parser) parseInfixExpression(left ast.Expression) ast.Expression { operator := p.curToken preced := p.curPrecedence() diff --git a/compiler/parser/expression_parsing_test.go b/compiler/parser/expression_parsing_test.go index 84b4171a6..39cae4ddd 100644 --- a/compiler/parser/expression_parsing_test.go +++ b/compiler/parser/expression_parsing_test.go @@ -2,9 +2,10 @@ package parser import ( "fmt" + "testing" + "github.com/goby-lang/goby/compiler/ast" "github.com/goby-lang/goby/compiler/lexer" - "testing" ) const ( diff --git a/compiler/parser/parser.go b/compiler/parser/parser.go index 3e3693a99..615d0c9bd 100644 --- a/compiler/parser/parser.go +++ b/compiler/parser/parser.go @@ -103,6 +103,8 @@ func New(l *lexer.Lexer) *Parser { p.registerInfix(token.OrEq, p.parseAssignExpression) p.registerInfix(token.Comma, p.parseMultiVariables) p.registerInfix(token.ResolutionOperator, p.parseInfixExpression) + // TODO: Add Parse Ternary Expression + // p.registerInfix(token.TernaryOperator, p.parseTernaryExpression) p.registerInfix(token.Assign, p.parseAssignExpression) p.registerInfix(token.Range, p.parseRangeExpression) p.registerInfix(token.Dot, p.parseCallExpressionWithReceiver) diff --git a/compiler/parser/precedence/precedence.go b/compiler/parser/precedence/precedence.go index 5928d02b7..ca1973929 100644 --- a/compiler/parser/precedence/precedence.go +++ b/compiler/parser/precedence/precedence.go @@ -32,6 +32,7 @@ var LookupTable = map[token.Type]int{ token.COMP: Compare, token.And: Logic, token.Or: Logic, + token.TernaryOperator: Logic, token.Range: Range, token.Plus: Sum, token.Minus: Sum, diff --git a/compiler/token/token.go b/compiler/token/token.go index af869febe..843df14b2 100644 --- a/compiler/token/token.go +++ b/compiler/token/token.go @@ -83,6 +83,7 @@ const ( Module = "MODULE" ResolutionOperator = "::" + TernaryOperator = "?" ) var keywords = map[string]Type{ @@ -136,6 +137,7 @@ var operators = map[string]Type{ "..": Range, "::": ResolutionOperator, + "?": TernaryOperator, } var separators = map[string]Type{