|
|
@@ -469,3 +469,126 @@ func TestBooleanExpression(t *testing.T) {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+func TestIfExpression(t *testing.T) {
|
|
|
+ input := `if (x < y) { x }`
|
|
|
+ l := lexer.New(input)
|
|
|
+ p := New(l)
|
|
|
+ program := p.ParseProgram()
|
|
|
+ checkParseErrors(t, p)
|
|
|
+
|
|
|
+ if len(program.Statements) != 1 {
|
|
|
+ t.Fatalf("program.Body does not contain %d statements. got=%d\n",
|
|
|
+ 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.IfExpression)
|
|
|
+ if !ok {
|
|
|
+ t.Fatalf("stmt.Expression is not ast.IfExpression. got=%T", stmt.Expression)
|
|
|
+ }
|
|
|
+
|
|
|
+ if !testInfixExpression(t, exp.Condition, "x", "<", "y") {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if len(exp.Consequence.Statements) != 1 {
|
|
|
+ t.Errorf("consequence is not 1 statements. got=%d\n",
|
|
|
+ len(exp.Consequence.Statements))
|
|
|
+ }
|
|
|
+ consequence, ok := exp.Consequence.Statements[0].(*ast.ExpressionStatement)
|
|
|
+ if !ok {
|
|
|
+ t.Fatalf("Statements[0] is not ast.ExpressionStatement. got=%T", exp.Consequence.Statements[0])
|
|
|
+ }
|
|
|
+ if !testIdentifier(t, consequence.Expression, "x") {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if exp.Alternative != nil {
|
|
|
+ t.Errorf("exp.Alternative.Statements was not nil. got=%+v", exp.Alternative)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func TestIfElseExpression(t *testing.T) {
|
|
|
+ input := `if (x < y) { x } else { y }`
|
|
|
+
|
|
|
+ l := lexer.New(input)
|
|
|
+ p := New(l)
|
|
|
+ program := p.ParseProgram()
|
|
|
+ checkParseErrors(t, p)
|
|
|
+
|
|
|
+ if len(program.Statements) != 1 {
|
|
|
+ t.Fatalf("program.Body does not contain %d statements. got=%d\n",
|
|
|
+ 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.IfExpression)
|
|
|
+ if !ok {
|
|
|
+ t.Fatalf("stmt.Expression is not ast.IfExpression. got=%T", stmt.Expression)
|
|
|
+ }
|
|
|
+
|
|
|
+ if !testInfixExpression(t, exp.Condition, "x", "<", "y") {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if len(exp.Consequence.Statements) != 1 {
|
|
|
+ t.Errorf("consequence is not 1 statements. got=%d\n",
|
|
|
+ len(exp.Consequence.Statements))
|
|
|
+ }
|
|
|
+
|
|
|
+ consequence, ok := exp.Consequence.Statements[0].(*ast.ExpressionStatement)
|
|
|
+ if !ok {
|
|
|
+ t.Fatalf("Statements[0] is not ast.ExpressionStatement. got=%T",
|
|
|
+ exp.Consequence.Statements[0])
|
|
|
+ }
|
|
|
+
|
|
|
+ if !testIdentifier(t, consequence.Expression, "x") {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if len(exp.Alternative.Statements) != 1 {
|
|
|
+ t.Errorf("exp.Alternative.Statements does not contain 1 statements. got=%d\n",
|
|
|
+ len(exp.Alternative.Statements))
|
|
|
+ }
|
|
|
+
|
|
|
+ alternative, ok := exp.Alternative.Statements[0].(*ast.ExpressionStatement)
|
|
|
+ if !ok {
|
|
|
+ t.Fatalf("Statements[0] is not ast.ExpressionStatement. got=%T",
|
|
|
+ exp.Alternative.Statements[0])
|
|
|
+ }
|
|
|
+
|
|
|
+ if !testIdentifier(t, alternative.Expression, "y") {
|
|
|
+ return
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func testInfixExpression(t *testing.T, exp ast.Expression, left interface{},
|
|
|
+ operator string, right interface{}) bool {
|
|
|
+
|
|
|
+ opExp, ok := exp.(*ast.InfixExpression)
|
|
|
+ if !ok {
|
|
|
+ t.Errorf("exp is not ast.OperatorExpression. got=%T(%s)", exp, exp)
|
|
|
+ return false
|
|
|
+ }
|
|
|
+
|
|
|
+ if !testLiteralExpression(t, opExp.Left, left) {
|
|
|
+ return false
|
|
|
+ }
|
|
|
+
|
|
|
+ if opExp.Operator != operator {
|
|
|
+ t.Errorf("exp.Operator is not '%s'. got=%q", operator, opExp.Operator)
|
|
|
+ return false
|
|
|
+ }
|
|
|
+
|
|
|
+ if !testLiteralExpression(t, opExp.Right, right) {
|
|
|
+ return false
|
|
|
+ }
|
|
|
+
|
|
|
+ return true
|
|
|
+}
|