/*
 *  Licensed to the Apache Software Foundation (ASF) under one
 *  or more contributor license agreements.  See the NOTICE file
 *  distributed with this work for additional information
 *  regarding copyright ownership.  The ASF licenses this file
 *  to you under the Apache License, Version 2.0 (the
 *  "License"); you may not use this file except in compliance
 *  with the License.  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing,
 *  software distributed under the License is distributed on an
 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *  KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations
 *  under the License.
 */
package org.codehaus.groovy.ast.builder

import org.codehaus.groovy.ast.builder.AstBuilder as FactoryAlias
import org.codehaus.groovy.control.CompilePhase
import org.codehaus.groovy.ast.ASTNode
import org.codehaus.groovy.ast.ClassNode
import org.codehaus.groovy.ast.Parameter
import org.codehaus.groovy.ast.stmt.BlockStatement
import org.codehaus.groovy.ast.VariableScope
import org.codehaus.groovy.ast.expr.ConstantExpression
import org.codehaus.groovy.ast.stmt.ExpressionStatement
import org.codehaus.groovy.ast.expr.BinaryExpression
import org.codehaus.groovy.ast.expr.VariableExpression
import org.codehaus.groovy.syntax.Token
import org.codehaus.groovy.syntax.Types
import org.codehaus.groovy.ast.expr.ConstructorCallExpression
import org.codehaus.groovy.ast.expr.TupleExpression
import org.codehaus.groovy.ast.expr.NamedArgumentListExpression
import org.codehaus.groovy.ast.expr.MapEntryExpression
import org.codehaus.groovy.ast.stmt.ReturnStatement
import org.codehaus.groovy.ast.expr.ElvisOperatorExpression
import org.codehaus.groovy.ast.expr.BooleanExpression
import org.codehaus.groovy.ast.stmt.WhileStatement
import org.codehaus.groovy.ast.expr.PostfixExpression
import org.codehaus.groovy.ast.stmt.ContinueStatement
import org.codehaus.groovy.ast.expr.TernaryExpression
import org.codehaus.groovy.ast.expr.MethodCallExpression
import org.codehaus.groovy.ast.expr.SpreadMapExpression
import org.codehaus.groovy.ast.expr.ArgumentListExpression
import org.codehaus.groovy.ast.stmt.ForStatement
import org.codehaus.groovy.ast.expr.ClosureListExpression
import org.codehaus.groovy.ast.expr.DeclarationExpression
import org.codehaus.groovy.ast.stmt.TryCatchStatement
import org.codehaus.groovy.ast.stmt.SynchronizedStatement
import org.codehaus.groovy.ast.stmt.AssertStatement
import org.codehaus.groovy.ast.stmt.BreakStatement
import org.codehaus.groovy.ast.stmt.SwitchStatement
import org.codehaus.groovy.ast.stmt.CaseStatement
import org.codehaus.groovy.ast.stmt.EmptyStatement
import org.codehaus.groovy.ast.expr.RangeExpression
import org.codehaus.groovy.ast.expr.MethodPointerExpression
import org.codehaus.groovy.ast.expr.ClassExpression
import org.codehaus.groovy.ast.expr.GStringExpression
import org.codehaus.groovy.ast.expr.MapExpression
import org.codehaus.groovy.ast.expr.UnaryPlusExpression
import org.codehaus.groovy.ast.expr.UnaryMinusExpression
import org.codehaus.groovy.ast.expr.PrefixExpression
import org.codehaus.groovy.ast.expr.NotExpression
import org.codehaus.groovy.ast.expr.ClosureExpression
import org.codehaus.groovy.ast.expr.CastExpression
import org.codehaus.groovy.ast.expr.ListExpression
import org.codehaus.groovy.ast.stmt.IfStatement
import org.codehaus.groovy.ast.ClassHelper

/**
 * Test case to show an ASTBuilder working off of a code block.
 *
 * The field declarations, static initializers, instance initializers, 
 * and most of the comments are all meaningful and tested. 
 *
 * @author Hamlet D'Arcy
 */
@WithAstBuilder 
public class AstBuilderFromCodeTest extends GroovyTestCase {
 
    List<ASTNode> normalField = new AstBuilder().buildFromCode { "constant#1" }

    static List<ASTNode> staticInitializedField
    static {
        staticInitializedField = new AstBuilder().buildFromCode { "constant#3" }
    }
    List<ASTNode> constructorInializedField

    AstBuilderFromCodeTest() {
        constructorInializedField = new AstBuilder().buildFromCode { "constant#4" }
    }

    List<ASTNode> normalProperty = new AstBuilder().buildFromCode { "constant#5" }


    public void testImportedClassName() {

        def expected = new AstBuilder().buildFromString(""" println "Hello World" """)

        def result = new AstBuilder().buildFromCode {
            println "Hello World"
        }
        AstAssert.assertSyntaxTree(expected, result)
    }

    public void testFullyQualifiedClassName() {

        def expected = new AstBuilder().buildFromString(""" println "Hello World" """)

        // it is important for this to remain a method invocation on a fully qualified class name
        def result = new org.codehaus.groovy.ast.builder.AstBuilder().buildFromCode {
            println "Hello World"
        }
        AstAssert.assertSyntaxTree(expected, result)
    }

    public void testAliasedClassName() {

        def expected = new AstBuilder().buildFromString(""" println "Hello World" """)

        def result = new FactoryAlias().buildFromCode {
            println "Hello World"
        }
        AstAssert.assertSyntaxTree(expected, result)
    }

    public void testVariableInvocation() {

        def expected = new AstBuilder().buildFromString(""" println "Hello World" """)

        AstBuilder factory = new AstBuilder()  //temporary variable is important to test
        def result = factory.buildFromCode {
            println "Hello World"
        } 
        AstAssert.assertSyntaxTree(expected, result)
    }

    public void testMethodReturnTypeInvocation() {
        shouldFail(IllegalStateException) {
            //todo: is there any way to make this work?
            makeAstFactory().buildFromCode {    // typed as Object in AST :(
                println "Hello World"
            }
        }
    }

    /**
     * Factory method used in testing.
     */
    private AstBuilder makeAstFactory() {
        return new AstBuilder()
    }


    public void testPhase_SemanticAnalysis() {

        def expected = new AstBuilder().buildFromString(CompilePhase.SEMANTIC_ANALYSIS, """ println "Hello World" """)

        def result = new AstBuilder().buildFromCode(CompilePhase.SEMANTIC_ANALYSIS) {
            println "Hello World"
        }
        AstAssert.assertSyntaxTree(expected, result)
    }

    public void testPhase_Conversion() {

        def expected = new AstBuilder().buildFromString(CompilePhase.CONVERSION, """ println "Hello World" """)

        def result = new AstBuilder().buildFromCode(CompilePhase.CONVERSION) {
            println "Hello World"
        }
        AstAssert.assertSyntaxTree(expected, result)
    }

    public void testStatementsOnly_ReturnsScriptClass() {
        def expected = new AstBuilder().buildFromString(CompilePhase.CONVERSION, false, """ println "Hello World" """)

        def result = new AstBuilder().buildFromCode(CompilePhase.CONVERSION, false) {
            println "Hello World"
        }
        AstAssert.assertSyntaxTree(expected, result)
    }

    public void testSingleLineClosure() {
        def expected = new AstBuilder().buildFromString(""" println "Hello World" """)

        def result = new AstBuilder().buildFromCode {println "Hello World"}
        AstAssert.assertSyntaxTree(expected, result)
    }

    public void testSingleLineClosure_WithComment() {
        def expected = new AstBuilder().buildFromString(""" println "Hello World" """)

        def result = new AstBuilder().buildFromCode {println "Hello World"} // a comment DO NOT REMOVE
        AstAssert.assertSyntaxTree(expected, result)
    }

    public void testSingleLineClosure_MultipleStatements() {
        def expected = new AstBuilder().buildFromString(""" println "Hello World" """)

        def result = new AstBuilder().buildFromCode {println "Hello World"};4+5
        AstAssert.assertSyntaxTree(expected, result)
    }

    public void testMultilineClosure_WithComments() {
        def expected = new AstBuilder().buildFromString(""" println "Hello World" """)

        def result = new AstBuilder().buildFromCode {//comment1
            println "Hello World"//comment2
        }//comment3
        AstAssert.assertSyntaxTree(expected, result)
    }

    public void testSingleLineClosure_WithCStyleComment() {
        def expected = new AstBuilder().buildFromString(""" println "Hello World" """)

        def result = new AstBuilder().buildFromCode {println "Hello World"} /* a comment DO NOT REMOVE */
        AstAssert.assertSyntaxTree(expected, result)
    }

    public void testSingleLineClosure_WithMultipleCStyleComments() {
        def expected = new AstBuilder().buildFromString(""" println "Hello World" """)

        def result = new AstBuilder()./*comment1*/buildFromCode/*comment2*/{/*comment3*/println/*comment4*/"Hello World"/*comment5*/}/*comment6*/
        AstAssert.assertSyntaxTree(expected, result)
    }

    public void testThreeLineClosure() {
        def expected = new AstBuilder().buildFromString(""" println "I"; println "Love"; println "Groovy" """)

        def result = new AstBuilder().buildFromCode {
            println "I"
            println "Love"
            println "Groovy"
        }
        AstAssert.assertSyntaxTree(expected, result)
    }

    public void testInitializationInFieldDeclaration() {
        def expected = new AstBuilder().buildFromString(""" "constant#1" """)
        AstAssert.assertSyntaxTree(expected, normalField)
    }

    public void testInitializationInstaticInialization() {
        def expected = new AstBuilder().buildFromString(""" "constant#3" """)
        AstAssert.assertSyntaxTree(expected, staticInitializedField)
    }

    public void testInitializationInConstructor() {
        def expected = new AstBuilder().buildFromString(""" "constant#4" """)
        AstAssert.assertSyntaxTree(expected, constructorInializedField)
    }

    public void testInitializationInPropertyDeclaration() {
        def expected = new AstBuilder().buildFromString(""" "constant#5" """)
        AstAssert.assertSyntaxTree(expected, normalProperty)
    }

    public void testNamedArgumentListExpression() {

        def result = new AstBuilder().buildFromCode {
            new String(foo: 'bar')
        }

        def expected = new BlockStatement(
                [new ReturnStatement(
                        new ConstructorCallExpression(
                                new ClassNode(String),
                                new TupleExpression(
                                        new NamedArgumentListExpression(
                                                [
                                                        new MapEntryExpression(
                                                                new ConstantExpression('foo'),
                                                                new ConstantExpression('bar'),
                                                        )
                                                ]
                                        )
                                )
                        ))], new VariableScope())

        AstAssert.assertSyntaxTree([expected], result)
    }

    public void testElvisOperatorExpression() {

        def result = new AstBuilder().buildFromCode(CompilePhase.SEMANTIC_ANALYSIS) {
                name ?: 'Anonymous'
        }

        def expected = new BlockStatement(
                [new ExpressionStatement(
                        new ElvisOperatorExpression(
                                new VariableExpression('name'),
                                new ConstantExpression('Anonymous')
                        ))], new VariableScope())

        AstAssert.assertSyntaxTree([expected], result)
    }


    public void testWhileStatementAndContinue() {

        def result = new AstBuilder().buildFromCode(CompilePhase.SEMANTIC_ANALYSIS) {
            while (true) {
                x++;
                continue
            }
        }

        def expected = new BlockStatement(
                [new WhileStatement(
                        new BooleanExpression(
                                new ConstantExpression(true)
                        ),
                        new BlockStatement(
                                [
                                        new ExpressionStatement(
                                                new PostfixExpression(
                                                        new VariableExpression("x"),
                                                        new Token(Types.PLUS_PLUS, "++", -1, -1),
                                                )
                                        ),
                                        new ContinueStatement()
                                ],
                                new VariableScope()
                        )
                )], new VariableScope())

        AstAssert.assertSyntaxTree([expected], result)
    }


    public void testTernaryExpression() {
        def result = new AstBuilder().buildFromCode(CompilePhase.SEMANTIC_ANALYSIS) {
            true ? 'male' : 'female'
        }

        def expected = new BlockStatement(
                [new ExpressionStatement(
                        new TernaryExpression(
                                new BooleanExpression(
                                        new ConstantExpression(true)
                                ),
                                new ConstantExpression('male'),
                                new ConstantExpression('female')
                        ))], new VariableScope())

        AstAssert.assertSyntaxTree([expected], result)
    }

    public void testSpreadMapExpression() {
        def result = new AstBuilder().buildFromCode(CompilePhase.SEMANTIC_ANALYSIS) {
            func(*: m)
        }

        def expected = new BlockStatement(
                [new ExpressionStatement(
                        new MethodCallExpression(
                                new VariableExpression('this', ClassHelper.OBJECT_TYPE),
                                'func',
                                new NamedArgumentListExpression(
                                        [new MapEntryExpression(
                                                new SpreadMapExpression(
                                                        new VariableExpression('m', ClassHelper.OBJECT_TYPE)
                                                ),
                                                new VariableExpression('m', ClassHelper.OBJECT_TYPE)
                                        )]
                                )
                        ))], new VariableScope())

        AstAssert.assertSyntaxTree([expected], result)
    }


    public void testForStatementAndClosureListExpression() {

        def result = new AstBuilder().buildFromCode(CompilePhase.SEMANTIC_ANALYSIS) {
            for (int x = 0; x < 10; x++) {
                println x
            }
        }

        def expected = new BlockStatement([new ForStatement(
                new Parameter(ClassHelper.OBJECT_TYPE, "forLoopDummyParameter"),
                new ClosureListExpression(
                        [
                                new DeclarationExpression(
                                        new VariableExpression("x"),
                                        new Token(Types.EQUALS, "=", -1, -1),
                                        new ConstantExpression(0)
                                ),
                                new BinaryExpression(
                                        new VariableExpression("x"),
                                        new Token(Types.COMPARE_LESS_THAN, "<", -1, -1),
                                        new ConstantExpression(10)
                                ),
                                new PostfixExpression(
                                        new VariableExpression("x"),
                                        new Token(Types.PLUS_PLUS, "++", -1, -1)
                                )
                        ]
                ),
                new BlockStatement(
                        [
                                new ExpressionStatement(
                                        new MethodCallExpression(
                                                new VariableExpression("this"),
                                                new ConstantExpression("println"),
                                                new ArgumentListExpression(
                                                        new VariableExpression("x"),
                                                )
                                        )
                                )
                        ],
                        new VariableScope()
                )
        )], new VariableScope())

        AstAssert.assertSyntaxTree([expected], result)
    }

    public void testFinallyStatement() {
        def result = new AstBuilder().buildFromCode(CompilePhase.SEMANTIC_ANALYSIS) {
            try {
                return 1
            } finally {
                x.close()
            }
        }

        def expected = new BlockStatement(
                [new TryCatchStatement(
                        new BlockStatement(
                                [new ReturnStatement(
                                        new ConstantExpression(1)
                                )],
                                new VariableScope()
                        ),
                        new BlockStatement(
                                [
                                        new BlockStatement(
                                                [
                                                        new ExpressionStatement(
                                                                new MethodCallExpression(
                                                                        new VariableExpression('x'),
                                                                        'close',
                                                                        new ArgumentListExpression()
                                                                )
                                                        )
                                                ],
                                                new VariableScope())
                                ],
                                new VariableScope()
                        )
                )], new VariableScope())
        AstAssert.assertSyntaxTree([expected], result)
    }

    public void testReturnAndSynchronizedStatement() {

        def result = new AstBuilder().buildFromCode(CompilePhase.SEMANTIC_ANALYSIS) {
            synchronized (this) {
                return 1
            }
        }

        def expected = new BlockStatement(
                [new SynchronizedStatement(
                        new VariableExpression("this"),
                        new BlockStatement(
                                [new ReturnStatement(
                                        new ConstantExpression(1)
                                )],
                                new VariableScope()
                        )
                )], new VariableScope())

        AstAssert.assertSyntaxTree([expected], result)
    }


    public void testAssertStatement() {

        def result = new AstBuilder().buildFromCode(CompilePhase.SEMANTIC_ANALYSIS) {
            assert true: "should always be true"
            assert 1 == 2
        }

        def expected = new BlockStatement(
                [
                        new AssertStatement(
                                new BooleanExpression(
                                        new ConstantExpression(true)
                                ),
                                new ConstantExpression("should always be true")
                        ),
                        new AssertStatement(
                                new BooleanExpression(
                                        new BinaryExpression(
                                                new ConstantExpression(1),
                                                new Token(Types.COMPARE_EQUAL, "==", -1, -1),
                                                new ConstantExpression(2)
                                        )
                                )
                        ),
                ],
                new VariableScope()
        )

        AstAssert.assertSyntaxTree([expected], result)
    }

    public void testSwitchAndCaseAndBreakStatements() {

        def result = new AstBuilder().buildFromCode(CompilePhase.SEMANTIC_ANALYSIS) {
            switch (foo) {
                case 0:
                    break
                case 1:
                case 2:
                    println "<3"
                    break
                default:
                    println ">2"
            }
        }

        def expected = new BlockStatement(
                [new SwitchStatement(
                        new VariableExpression("foo"),
                        [
                                new CaseStatement(
                                        new ConstantExpression(0),
                                        new BlockStatement(
                                                [new BreakStatement()], new VariableScope())
                                ),
                                new CaseStatement(
                                        new ConstantExpression(1),
                                        EmptyStatement.INSTANCE
                                ),
                                new CaseStatement(
                                        new ConstantExpression(2),
                                        new BlockStatement(
                                                [
                                                        new ExpressionStatement(
                                                                new MethodCallExpression(
                                                                        new VariableExpression("this"),
                                                                        new ConstantExpression("println"),
                                                                        new ArgumentListExpression(
                                                                                [new ConstantExpression("<3")]
                                                                        )
                                                                )
                                                        ),
                                                        new BreakStatement()
                                                ], new VariableScope()
                                        )
                                )
                        ],
                        new BlockStatement(
                                [new ExpressionStatement(
                                        new MethodCallExpression(
                                                new VariableExpression("this"),
                                                new ConstantExpression("println"),
                                                new ArgumentListExpression(
                                                        [new ConstantExpression(">2")]
                                                )
                                        )
                                )],
                                new VariableScope()
                        )
                )], new VariableScope())

        AstAssert.assertSyntaxTree([expected], result)
    }


    public void testRangeExpression_SimpleForm() {

        def result = new AstBuilder().buildFromCode(CompilePhase.SEMANTIC_ANALYSIS) {
            (0..10)
        }

        def expected = new BlockStatement(
                [new ExpressionStatement(
                        new RangeExpression(
                                new ConstantExpression(0),
                                new ConstantExpression(10),
                                true
                        ))], new VariableScope())

        AstAssert.assertSyntaxTree([expected], result)
    }

    public void testMethodPointerExpression() {

        def result = new AstBuilder().buildFromCode(CompilePhase.SEMANTIC_ANALYSIS) {
            Integer.&toString
        }

        def expected = new BlockStatement(
                [new ExpressionStatement(
                        new MethodPointerExpression(
                                new ClassExpression(ClassHelper.Integer_TYPE),
                                new ConstantExpression("toString")
                        ))], new VariableScope())

        AstAssert.assertSyntaxTree([expected], result)
    }


    public void testGStringExpression() {
        def result = new AstBuilder().buildFromCode(CompilePhase.SEMANTIC_ANALYSIS) {
            "$foo"
        }

        def expected = new BlockStatement(
                [new ExpressionStatement(
                        new GStringExpression('$foo',
                        [new ConstantExpression(''), new ConstantExpression('')],
                        [new VariableExpression('foo')])
                )], new VariableScope())

        AstAssert.assertSyntaxTree([expected], result)
    }

    public void testMapAndMapEntryExpression() {

        def result = new AstBuilder().buildFromCode(CompilePhase.SEMANTIC_ANALYSIS) {
            [foo: 'bar', baz: 'buz']
        }

        def expected = new BlockStatement(
                [new ExpressionStatement(
                        new MapExpression(
                                [
                                        new MapEntryExpression(
                                                new ConstantExpression('foo'),
                                                new ConstantExpression('bar')
                                        ),
                                        new MapEntryExpression(
                                                new ConstantExpression('baz'),
                                                new ConstantExpression('buz')
                                        ),
                                ]
                        ))], new VariableScope())

        AstAssert.assertSyntaxTree([expected], result)
    }


    public void testClassExpression() {

        def result = new AstBuilder().buildFromCode(CompilePhase.SEMANTIC_ANALYSIS) {
            def foo = String
        }

        def expected = new BlockStatement(
                [new ExpressionStatement(
                        new DeclarationExpression(
                                new VariableExpression("foo"),
                                new Token(Types.EQUALS, "=", -1, -1),
                                new ClassExpression(ClassHelper.STRING_TYPE)
                        ))], new VariableScope())

        AstAssert.assertSyntaxTree([expected], result)
    }


    public void testUnaryPlusExpression() {

        def result = new AstBuilder().buildFromCode(CompilePhase.SEMANTIC_ANALYSIS) {
            (+foo)
        }

        def expected = new BlockStatement(
                [new ExpressionStatement(
                        new UnaryPlusExpression(
                                new VariableExpression("foo")
                        ))], new VariableScope())

        AstAssert.assertSyntaxTree([expected], result)
    }

    public void testUnaryMinusExpression() {

        def result = new AstBuilder().buildFromCode(CompilePhase.SEMANTIC_ANALYSIS) {
            (-foo)
        }

        def expected = new BlockStatement(
                [new ExpressionStatement(
                        new UnaryMinusExpression(
                                new VariableExpression("foo")
                        ))], new VariableScope())

        AstAssert.assertSyntaxTree([expected], result)
    }

    public void testPrefixExpression() {

        def result = new AstBuilder().buildFromCode(CompilePhase.SEMANTIC_ANALYSIS) {
            ++1
        }

        def expected = new BlockStatement(
                [new ExpressionStatement(
                        new PrefixExpression(
                                new Token(Types.PLUS_PLUS, "++", -1, -1),
                                new ConstantExpression(1)
                        ))], new VariableScope())

        AstAssert.assertSyntaxTree([expected], result)
    }


    public void testPostfixExpression() {

        def result = new AstBuilder().buildFromCode(CompilePhase.SEMANTIC_ANALYSIS) {
            1++
        }

        def expected = new BlockStatement(
                [new ExpressionStatement(
                        new PostfixExpression(
                                new ConstantExpression(1),
                                new Token(Types.PLUS_PLUS, "++", -1, -1)
                        ))], new VariableScope())

        AstAssert.assertSyntaxTree([expected], result)
    }


    public void testNotExpression() {

        def result = new AstBuilder().buildFromCode(CompilePhase.SEMANTIC_ANALYSIS) {
            !true
        }

        def expected = new BlockStatement(
                [new ExpressionStatement(
                        new NotExpression(
                                new ConstantExpression(true)
                        ))], new VariableScope())

        AstAssert.assertSyntaxTree([expected], result)
    }


    public void testConstructorCallExpression() {

        def result = new AstBuilder().buildFromCode(CompilePhase.SEMANTIC_ANALYSIS) {
            new Integer(4)
        }

        def expected = new BlockStatement(
                [new ExpressionStatement(
                        new ConstructorCallExpression(
                                new ClassNode(Integer),
                                new ArgumentListExpression(
                                        new ConstantExpression(4)
                                )
                        ))], new VariableScope())

        AstAssert.assertSyntaxTree([expected], result)
    }


    public void testClosureExpression_MultipleParameters() {

        def result = new AstBuilder().buildFromCode(CompilePhase.SEMANTIC_ANALYSIS) {
            {x, y, z -> println z }
        }

        def expected = new BlockStatement(
                [new ExpressionStatement(
                        new ClosureExpression(
                                [
                                        new Parameter(ClassHelper.OBJECT_TYPE, "x"),
                                        new Parameter(ClassHelper.OBJECT_TYPE, "y"),
                                        new Parameter(ClassHelper.OBJECT_TYPE, "z")] as Parameter[],
                                new BlockStatement(
                                        [new ExpressionStatement(
                                                new MethodCallExpression(
                                                        new VariableExpression("this"),
                                                        new ConstantExpression("println"),
                                                        new ArgumentListExpression(
                                                                new VariableExpression("z")
                                                        )
                                                )
                                        )],
                                        new VariableScope()
                                )
                        ))], new VariableScope())
        AstAssert.assertSyntaxTree([expected], result)
    }


    public void testCastExpression() {
        def result = new AstBuilder().buildFromCode(CompilePhase.SEMANTIC_ANALYSIS) {
            (Integer) ""
        }

        def expected = new BlockStatement(
                [new ExpressionStatement(
                        new CastExpression(
                                new ClassNode(Integer),
                                new ConstantExpression("")
                        ))], new VariableScope())
        AstAssert.assertSyntaxTree([expected], result)
    }

    public void testDeclarationAndListExpression() {

        def result = new AstBuilder().buildFromCode(CompilePhase.SEMANTIC_ANALYSIS) {
            def foo = [1, 2, 3]
        }

        def expected = new BlockStatement(
                [new ExpressionStatement(
                        new DeclarationExpression(
                                new VariableExpression("foo"),
                                new Token(Types.EQUALS, "=", -1, -1),
                                new ListExpression(
                                        [new ConstantExpression(1),
                                                new ConstantExpression(2),
                                                new ConstantExpression(3),]
                                )
                        ))], new VariableScope())
        AstAssert.assertSyntaxTree([expected], result)
    }

    public void testIfStatement() {

        def result = new AstBuilder().buildFromCode(CompilePhase.SEMANTIC_ANALYSIS) {
            if (foo == bar) println "Hello" else println "World"
        }

        def expected = new BlockStatement(
                [new IfStatement(
                        new BooleanExpression(
                                new BinaryExpression(
                                        new VariableExpression("foo"),
                                        new Token(Types.COMPARE_EQUAL, "==", -1, -1),
                                        new VariableExpression("bar")
                                )
                        ),
                        new ExpressionStatement(
                                new MethodCallExpression(
                                        new VariableExpression("this"),
                                        new ConstantExpression("println"),
                                        new ArgumentListExpression(
                                                [new ConstantExpression("Hello")]
                                        )
                                )
                        ),
                        new ExpressionStatement(
                                new MethodCallExpression(
                                        new VariableExpression("this"),
                                        new ConstantExpression("println"),
                                        new ArgumentListExpression(
                                                [new ConstantExpression("World")]
                                        )
                                )
                        )
                )], new VariableScope())
        AstAssert.assertSyntaxTree([expected], result)
    }

}
