Test for IfExpressions, and IfElseExpression

git-svn-id: https://svn.tlawal.org/svn/monkey@36 f6afcba9-9ef1-4bdd-9b72-7484f5705bac
This commit is contained in:
Tijani Lawal 2022-07-31 21:55:09 +00:00
parent 5d1197160d
commit 1ac48b0cad
2 changed files with 151 additions and 3 deletions

View File

@ -103,6 +103,9 @@ func New(l_lexer *lexer.Lexer) *Parser {
// Grouped Expression
l_parser.register_prefix(token.LPAREN, l_parser.parse_grouped_expression)
// IF Expression
l_parser.register_prefix(token.IF, l_parser.parse_if_expression)
return l_parser
}
@ -282,11 +285,62 @@ func (l_parser *Parser) parse_boolean() ast.Expression {
}
}
func (l_parser *Parser) parse_grouped_expression() ast.Expression{
func (l_parser *Parser) parse_grouped_expression() ast.Expression {
defer untrace(trace("parse_grouped_expression"))
l_parser.next_token()
expression := l_parser.parse_expression(LOWEST)
if !l_parser.expect_peek(token.RPAREN){
if !l_parser.expect_peek(token.RPAREN) {
return nil
}
return expression
}
func (l_parser *Parser) parse_if_expression() ast.Expression {
defer untrace(trace("parse_if_expression"))
expression := &ast.IfExpression{
Token: l_parser.current_token,
}
if !l_parser.expect_peek(token.LPAREN) {
return nil
}
l_parser.next_token()
expression.Condition = l_parser.parse_expression(LOWEST)
if !l_parser.expect_peek(token.RPAREN) {
return nil
}
if !l_parser.expect_peek(token.LBRACE) {
return nil
}
expression.Consequence = l_parser.parse_block_statement()
if l_parser.peek_token_is(token.ELSE) {
l_parser.next_token()
if !l_parser.expect_peek(token.LBRACE) {
return nil
}
expression.Alternative = l_parser.parse_block_statement()
}
return expression
}
func (l_parser *Parser) parse_block_statement() *ast.BlockStatement {
block := &ast.BlockStatement{Token: l_parser.current_token}
block.Statements = []ast.Statement{}
l_parser.next_token()
for !l_parser.current_token_is(token.RBRACE) && !l_parser.current_token_is(token.EOF) {
statement := l_parser.parse_statement()
if statement != nil {
block.Statements = append(block.Statements, statement)
}
l_parser.next_token()
}
return block
}

View File

@ -359,6 +359,100 @@ func TestBooleanExpression(l_test *testing.T) {
}
}
func TestIfExpression(l_test *testing.T) {
input := `if (x < y) { x }`
l_lexer := lexer.New(input)
l_parser := New(l_lexer)
program := l_parser.ParseProgram()
check_parser_errors(l_test, l_parser)
if len(program.Statements) != 1 {
l_test.Fatalf("program.Statements does not contain %d statements, got=%d\n", 1, len(program.Statements))
}
statement, ok := program.Statements[0].(*ast.ExpressionStatement)
if !ok {
l_test.Fatalf("program.Statements[0] is not ast.ExpressionStatement, got=%T", program.Statements[0])
}
expression, ok := statement.Expression.(*ast.IfExpression)
if !ok {
l_test.Fatalf("statement.Expression is not ast.IfExpression, got=%T", statement.Expression)
}
if !testInfixExpression(l_test, expression.Condition, "x", "<", "y") {
return
}
if len(expression.Consequence.Statements) != 1 {
l_test.Errorf("consequence is not 1 statements, got=%d\n", len(expression.Consequence.Statements))
}
consequence, ok := expression.Consequence.Statements[0].(*ast.ExpressionStatement)
if !ok {
l_test.Fatalf("Statements[0] is not ast.ExpressionStatement, got=%T", expression.Consequence.Statements[0])
}
if !testIdentifier(l_test, consequence.Expression, "x") {
return
}
if expression.Alternative != nil {
l_test.Errorf("expression.Alternative.Statements was not nil, got=%+v", expression.Alternative)
}
}
func TestIfElseExpression(l_test *testing.T) {
input := `if (x < y) { x } else { y }`
l_lexer := lexer.New(input)
l_parser := New(l_lexer)
program := l_parser.ParseProgram()
check_parser_errors(l_test, l_parser)
if len(program.Statements) != 1 {
l_test.Fatalf("program.Statements does not contain %d statements, got=%d\n", 1, len(program.Statements))
}
statement, ok := program.Statements[0].(*ast.ExpressionStatement)
if !ok {
l_test.Fatalf("program.Statements[0] is not an ast.ExpressionStatement, got=%T", program.Statements[0])
}
expression, ok := statement.Expression.(*ast.IfExpression)
if !ok {
l_test.Fatalf("statement.Expression is not ast.IfExpression, got=%T", statement.Expression)
}
if !testInfixExpression(l_test, expression.Condition, "x", "<", "y") {
return
}
if len(expression.Consequence.Statements) != 1 {
l_test.Errorf("consequence is not 1 statements, got=%d\n", len(expression.Consequence.Statements))
}
consequence, ok := expression.Consequence.Statements[0].(*ast.ExpressionStatement)
if !ok {
l_test.Fatalf("Statements[0] is not ast.ExpressionStatement, got=%T", expression.Consequence.Statements[0])
}
if !testIdentifier(l_test, consequence.Expression, "x") {
return
}
if len(expression.Alternative.Statements) != 1 {
l_test.Errorf("expression.Alterative.Statements does not contain 1 statement, got=%d\n", len(expression.Alternative.Statements))
}
alternative, ok := expression.Alternative.Statements[0].(*ast.ExpressionStatement)
if !ok {
l_test.Fatalf("Statements[0] is not ast.ExpressionStatement, got=%T", expression.Alternative.Statements[0])
}
if !testIdentifier(l_test, alternative.Expression, "y") {
return
}
}
// Helpers
func check_parser_errors(l_test *testing.T, l_parser *Parser) {