public override Node VisitBlockStatement(MetaCodeParser.BlockStatementContext context)
        {
            var attributes = GetAttributes(context.attribute());
            var body = context.statement()
                              .Select(stmt => stmt.Accept(this) as StatementNodeBase)
                              .ToArray();

            return StatementFactory.Block(body, attributes);
        }
        public override Node VisitWhileStatement(MetaCodeParser.WhileStatementContext context)
        {
            var attributes = GetAttributes(context.attribute());
            var condition = context.ConditionExpression.Accept(this) as ExpressionNode;

            var body = context.Body.Accept(this) as StatementNodeBase;

            return StatementFactory.While(condition, body, attributes);
        }
        public override Node VisitTypeName(MetaCodeParser.TypeNameContext context)
        {
            var attributes = context.attribute()
                                    .Select(attribute => attribute.Accept(this) as AttributeNode)
                                    .ToArray();

            var identifiers = context.ID()
                                     .Select(id => id.GetText())
                                     .ToArray();
            
            return ExpressionFactory.Type(string.Join(".", identifiers), attributes);
        }
        public override Node VisitIfStatement(MetaCodeParser.IfStatementContext context)
        {
            var attributes = GetAttributes(context.attribute());
            var condition = context.Condition.Accept(this) as ExpressionNode;
            var statements = context.Statements.Accept(this) as BlockStatementNode;
            var elseIfStatements = context.elseIfStatement()
                                          .Select(elseIf => elseIf.Accept(this) as IfStatementNode)
                                          .ToArray();
            var elseStatements = context.ElseStatements.With(statement => statement.Accept(this)) as BlockStatementNode;

            return StatementFactory.IfThenElse(condition, statements, elseIfStatements, elseStatements, attributes);
        }
        /*public override Node VisitFunctionExpression(MetaCodeParser.FunctionExpressionContext context)
        {
            var identifier = context.FunctionName.With(functionName => functionName.Text);
            var returnType = context.ReturnType.Accept(this) as TypeNameNode;

            var parameters = context.Parameters;

            var formalParameters = new Func<FormalParameterNode[]>(() => {
                if (parameters == null)
                    return new FormalParameterNode[0];

                var result = parameters.formalParameter().Select(param => {
                    return ExpressionFactory.FormalParameter(param.Identifier.Text,
                        param.VariableType.With(type => type.Accept(this) as TypeNameNode),
                        null);
                });

                return result.ToArray();
            })();

            if (context.BodyExpression != null)
                return ExpressionFactory.Function(identifier,
                                                  returnType.VariableType,
                                                  formalParameters,
                                                  new Lazy<ExpressionNode>(() => context.BodyExpression.Accept(this) as ExpressionNode));

            return ExpressionFactory.Function(identifier,
                                              returnType.VariableType,
                                              formalParameters,
                                              new Lazy<BlockStatementNode>(() => context.BodyStatements.Accept(this) as BlockStatementNode));
        }*/

        public override Node VisitPrimaryExpression(MetaCodeParser.PrimaryExpressionContext context)
        {
            var attributes = context.attribute()
                                    .Select(attribute => attribute.Accept(this) as AttributeNode)
                                    .ToArray();

            if (context.Constant != null)
            {
                var constant = context.Constant.Accept(this) as ConstantLiteralNode;
                return ExpressionFactory.Constant(constant, attributes);
            }

            if (context.Id != null)
                return ExpressionFactory.Identifier(context.Id.Text, attributes);

            if (context.Assignment != null)
            {
                var assignment = context.Assignment;
                var member = assignment.LeftValue.With(leftValue => leftValue.Accept(this) as MemberExpressionNode) ??
                             ExpressionFactory.Member(new[] { assignment.VariableName.Text });

                var value = assignment.RightValue.Accept(this) as ExpressionNode;

                return ExpressionFactory.Assignment(member, value, attributes);
            }

            if (context.InnerExpression != null)
                return ExpressionFactory.InnerExpression(context.InnerExpression.Accept(this) as ExpressionNode, attributes);

            return base.VisitPrimaryExpression(context);
        }
        public override Node VisitForeachStatement(MetaCodeParser.ForeachStatementContext context)
        {
            var attributes = GetAttributes(context.attribute());
            var identifier = context.Id.Text;
            var arrayExpression = context.ArrayExpression.Accept(this) as ExpressionNode;
            var variableType = context.VariableType.With(variable => variable.Accept(this)) as TypeNameNode;

            return StatementFactory.Foreach(identifier,
                                            variableType,
                                            arrayExpression,
                                            context.Body.Accept(this) as StatementNodeBase,
                                            attributes);
        }
        public override Node VisitFormalParameter(MetaCodeParser.FormalParameterContext context)
        {
            var parameterName = context.Name.Text;
            var typeName = context.Type.Accept(this) as TypeNameNode;
            var attributes = context.attribute()
                                    .Select(attribute => attribute.Accept(this) as AttributeNode)
                                    .ToArray();

            return StatementFactory.FormalParameter(parameterName, typeName, attributes);
        }
        public override Node VisitAttributeDeclaration(MetaCodeParser.AttributeDeclarationContext context)
        {
            var attributes = GetAttributes(context.attribute());
            var attributeName = context.AttributeName.Text;
            var parameters = context.formalParameter()
                                    .Select(parameter => parameter.Accept(this) as FormalParameterNode)
                                    .ToArray();

            return StatementFactory.Attribute(attributeName, parameters, attributes);
        }
        public override Node VisitFunctionStatement(MetaCodeParser.FunctionStatementContext context)
        {
            var attributes = GetAttributes(context.attribute());

            var functionName = context.FunctionName.Text;
            var returnType = context.ReturnType.With(type => type.Accept(this) as TypeNameNode);
            var parameters = context.formalParameter()
                                    .Select(parameter => parameter.Accept(this) as FormalParameterNode)
                                    .ToArray();
            var body = context.BodyStatements.Accept(this) as BlockStatementNode;

            return StatementFactory.Function(functionName, returnType, parameters, body, attributes);
        }
        public override Node VisitVariableDeclaration(MetaCodeParser.VariableDeclarationContext context)
        {
            var attributes = GetAttributes(context.attribute());
            var name = context.VariableName.Text;
            var typeName = context.VariableType.With(variable => variable.Accept(this)) as TypeNameNode;
            var defaultValue = context.VariableDefaultValue.With(expression => expression.Accept(this)) as ExpressionNode;

            return StatementFactory.DeclareVariable(name, typeName, defaultValue, attributes);
        }