Skip to content

Commit

Permalink
add if-else conditional
Browse files Browse the repository at this point in the history
  • Loading branch information
OlgaNovg committed Dec 4, 2024
1 parent fe88af5 commit 49ec2ce
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 4 deletions.
2 changes: 1 addition & 1 deletion docs/language-definition.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ Backticks strings are raw strings, they do not support escape sequences.
<tr>
<td><strong>Conditional</strong></td>
<td>
<code>?:</code> (ternary), <code>??</code> (nil coalescing)
<code>?:</code> (ternary), <code>??</code> (nil coalescing), <code>if {} else {}</code> (multiline)
</td>
</tr>
<tr>
Expand Down
15 changes: 15 additions & 0 deletions expr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1291,6 +1291,21 @@ func TestExpr(t *testing.T) {
`1 < 2 < 3 == true`,
true,
},
{
`if 1 > 2 { 333 * 2 + 1 } else { 444 }`,
444,
},
{
`let a = 3;
let b = 2;
if a>b {let c = Add(a, b); c+1} else {Add(10, b)}
`,
6,
},
{
`if "a" < "b" {let x = "a"; x} else {"abc"}`,
"a",
},
}

for _, tt := range tests {
Expand Down
36 changes: 36 additions & 0 deletions parser/lexer/lexer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,42 @@ func TestLex(t *testing.T) {
{Kind: EOF},
},
},
{
`if a>b {x1+x2} else {x2}`,
[]Token{
{Kind: Operator, Value: "if"},
{Kind: Identifier, Value: "a"},
{Kind: Operator, Value: ">"},
{Kind: Identifier, Value: "b"},
{Kind: Bracket, Value: "{"},
{Kind: Identifier, Value: "x1"},
{Kind: Operator, Value: "+"},
{Kind: Identifier, Value: "x2"},
{Kind: Bracket, Value: "}"},
{Kind: Operator, Value: "else"},
{Kind: Bracket, Value: "{"},
{Kind: Identifier, Value: "x2"},
{Kind: Bracket, Value: "}"},
{Kind: EOF},
},
},
{
`a>b if {x1} else {x2}`,
[]Token{
{Kind: Identifier, Value: "a"},
{Kind: Operator, Value: ">"},
{Kind: Identifier, Value: "b"},
{Kind: Operator, Value: "if"},
{Kind: Bracket, Value: "{"},
{Kind: Identifier, Value: "x1"},
{Kind: Bracket, Value: "}"},
{Kind: Operator, Value: "else"},
{Kind: Bracket, Value: "{"},
{Kind: Identifier, Value: "x2"},
{Kind: Bracket, Value: "}"},
{Kind: EOF},
},
},
}

for _, test := range tests {
Expand Down
4 changes: 1 addition & 3 deletions parser/lexer/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,7 @@ loop:
switch l.word() {
case "not":
return not
case "in", "or", "and", "matches", "contains", "startsWith", "endsWith":
l.emit(Operator)
case "let":
case "in", "or", "and", "matches", "contains", "startsWith", "endsWith", "let", "if", "else":
l.emit(Operator)
default:
l.emit(Identifier)
Expand Down
22 changes: 22 additions & 0 deletions parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ func (p *parser) parseExpression(precedence int) Node {
if precedence == 0 && p.current.Is(Operator, "let") {
return p.parseVariableDeclaration()
}
if p.current.Is(Operator, "if") {
return p.parseConditionalIf()
}

nodeLeft := p.parsePrimary()

Expand Down Expand Up @@ -235,6 +238,25 @@ func (p *parser) parseVariableDeclaration() Node {
return let
}

func (p *parser) parseConditionalIf() Node {
p.next()
nodeCondition := p.parseExpression(0)
p.expect(Bracket, "{")
expr1 := p.parseExpression(0)
p.expect(Bracket, "}")
p.expect(Operator, "else")
p.expect(Bracket, "{")
expr2 := p.parseExpression(0)
p.expect(Bracket, "}")

return &ConditionalNode{
Cond: nodeCondition,
Exp1: expr1,
Exp2: expr2,
}

}

func (p *parser) parseConditional(node Node) Node {
var expr1, expr2 Node
for p.current.Is(Operator, "?") && p.err == nil {
Expand Down
11 changes: 11 additions & 0 deletions parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,17 @@ world`},
Right: &BoolNode{Value: true},
},
},
{
"if a>b {true} else {x}",
&ConditionalNode{
Cond: &BinaryNode{
Operator: ">",
Left: &IdentifierNode{Value: "a"},
Right: &IdentifierNode{Value: "b"},
},
Exp1: &BoolNode{Value: true},
Exp2: &IdentifierNode{Value: "x"}},
},
}
for _, test := range tests {
t.Run(test.input, func(t *testing.T) {
Expand Down

0 comments on commit 49ec2ce

Please sign in to comment.