diff --git a/ast/ast.go b/ast/ast.go index c69559f..ab31cf1 100644 --- a/ast/ast.go +++ b/ast/ast.go @@ -242,15 +242,16 @@ func (ie *IfExpression) TokenLiteral() string { return ie.Token.Literal } func (ie *IfExpression) String() string { var out bytes.Buffer - out.WriteString("if") + out.WriteString("if ") out.WriteString(ie.Condition.String()) out.WriteString(" ") out.WriteString(ie.Consequence.String()) if ie.Alternative != nil { - out.WriteString("else ") + out.WriteString(" else ") out.WriteString(ie.Alternative.String()) } + out.WriteString(" end") return out.String() } diff --git a/docs/content/en/docs/control_expressions/if.md b/docs/content/en/docs/control_expressions/if.md index aa5dcf9..9268c48 100644 --- a/docs/content/en/docs/control_expressions/if.md +++ b/docs/content/en/docs/control_expressions/if.md @@ -13,6 +13,19 @@ With `if` and `else` keywords the flow of a program can be controlled. puts("is not a string") } +// which prints +is a string +``` + +{{< alert icon="👉" text="Since `0.13` curly braces are completely optional (closing brace needs to be replaced with `end`" />}} + +```js +🚀 > if (a.type() == "STRING") + puts("is a string") +else + puts("is not a string") +end + // which prints is a string ``` \ No newline at end of file diff --git a/docs/content/en/docs/home.md b/docs/content/en/docs/home.md index e2f36d8..72333f7 100644 --- a/docs/content/en/docs/home.md +++ b/docs/content/en/docs/home.md @@ -16,9 +16,9 @@ input = a increase = 0 foreach i, number in input { - if (number > input[i-1]) { + if (number > input[i-1]) increase = increase + 1 - } + end } puts(increase + 1) @@ -27,9 +27,9 @@ foreach i, number in input { sum = number + input[i+1] + input[i+2] sum_two = input[i+1] + input[i+2] + input[i+3] - if (sum_two > sum) { + if (sum_two > sum) increase = increase + 1 - } + end } puts(increase + 1) ``` \ No newline at end of file diff --git a/docs/content/en/docs/specification/functions.md b/docs/content/en/docs/specification/functions.md index 1574bf5..223081d 100644 --- a/docs/content/en/docs/specification/functions.md +++ b/docs/content/en/docs/specification/functions.md @@ -9,15 +9,15 @@ Implicit and explicit return statements are supported. ```js fibonacci = def (x) { - if (x == 0) { + if (x == 0) 0 - } else { - if (x == 1) { + else + if (x == 1) return 1; - } else { + else fibonacci(x - 1) + fibonacci(x - 2); - } - } + end + end }; ``` diff --git a/evaluator/evaluator.go b/evaluator/evaluator.go index 9512f44..096a6b0 100644 --- a/evaluator/evaluator.go +++ b/evaluator/evaluator.go @@ -333,7 +333,6 @@ func evalIfExpression(ie *ast.IfExpression, env *object.Environment) object.Obje if isError(condition) { return condition } - if isTruthy(condition) { return Eval(ie.Consequence, env) } else if ie.Alternative != nil { diff --git a/evaluator/evaluator_test.go b/evaluator/evaluator_test.go index 8fbb3a1..7942066 100644 --- a/evaluator/evaluator_test.go +++ b/evaluator/evaluator_test.go @@ -94,11 +94,15 @@ func TestIfElseExpressions(t *testing.T) { }{ {"if (true) { 10 }", 10}, {"if (false) { 10 }", nil}, + {"if (true)\n 10 end", 10}, + {"if (false) \n 10 end", nil}, {"if (1) { 10 }", 10}, + {"if (1) \n 10 end", 10}, {"if (1 < 2) { 10 }", 10}, {"if (1 > 2) { 10 }", nil}, {"if (1 > 2) { 10 } else { 20 }", 20}, {"if (1 < 2) { 10 } else { 20 }", 10}, + {"if (1 < 2) \n 10 \n else \n 20 end", 10}, } for _, tt := range tests { diff --git a/examples/aoc/2021/day-2/complete.rl b/examples/aoc/2021/day-2/complete.rl index 4ad0148..64bf29b 100644 --- a/examples/aoc/2021/day-2/complete.rl +++ b/examples/aoc/2021/day-2/complete.rl @@ -7,18 +7,18 @@ aim = 0 foreach i, line in input { command = line.split(" ")[0] value = line.strip().split(" ")[1].plz_i() - if (command == "forward") { + if (command == "forward") hor = hor + value depth = depth + (value * aim) - } + end - if (command == "down") { + if (command == "down") aim = aim + value - } + end - if (command == "up") { + if (command == "up") aim = aim - value - } + end } puts(hor * depth) \ No newline at end of file diff --git a/examples/misc/if.rl b/examples/misc/if.rl new file mode 100644 index 0000000..cf600a5 --- /dev/null +++ b/examples/misc/if.rl @@ -0,0 +1,15 @@ +if (false) + puts("true1") +else + puts("false1") +end + +if (true) + puts("true2") +else + puts("false2") +end + +if (true) + puts("true3") +end \ No newline at end of file diff --git a/parser/parser.go b/parser/parser.go index 1c8c6ab..b797944 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -400,7 +400,6 @@ func (p *Parser) parseGroupedExpression() ast.Expression { func (p *Parser) parseIfExpression() ast.Expression { expression := &ast.IfExpression{Token: p.curToken} - if !p.expectPeek(token.LPAREN) { return nil } @@ -412,22 +411,22 @@ func (p *Parser) parseIfExpression() ast.Expression { return nil } - if !p.expectPeek(token.LBRACE) { - return nil + if p.peekTokenIs(token.LBRACE) { + p.nextToken() } - expression.Consequence = p.parseBlockStatement() - if p.peekTokenIs(token.ELSE) { + if p.curTokenIs(token.RBRACE) { p.nextToken() + } - if !p.expectPeek(token.LBRACE) { - return nil - } + if p.curTokenIs(token.ELSE) { + if p.peekTokenIs(token.LBRACE) { + p.nextToken() + } expression.Alternative = p.parseBlockStatement() } - return expression } @@ -437,7 +436,7 @@ func (p *Parser) parseBlockStatement() *ast.BlockStatement { p.nextToken() - for !p.curTokenIs(token.RBRACE) && !p.curTokenIs(token.EOF) { + for !p.curTokenIs(token.RBRACE) && !p.curTokenIs(token.EOF) && !p.curTokenIs(token.END) && !p.curTokenIs(token.ELSE) { stmt := p.parseStatement() if stmt != nil { block.Statements = append(block.Statements, stmt) diff --git a/token/token.go b/token/token.go index 14c3284..5e45976 100644 --- a/token/token.go +++ b/token/token.go @@ -43,6 +43,7 @@ const ( FALSE = "FALSE" IF = "IF" ELSE = "ELSE" + END = "END" RETURN = "RETURN" EQ = "==" @@ -62,6 +63,7 @@ var keywords = map[string]TokenType{ "true": TRUE, "false": FALSE, "if": IF, + "end": END, "else": ELSE, "return": RETURN, "foreach": FOREACH,