private void ValidateReturnStatementType(MethodDeclr ast, Symbol symbol)
        {
            if (!ResolvingTypes)
            {
                return;
            }

            IType returnStatementType;

            // no return found
            if (ast.ReturnAst == null)
            {
                returnStatementType = new BuiltInType(ExpressionTypes.Void);
            }
            else
            {
                returnStatementType = ast.ReturnAst.AstSymbolType;
            }

            var delcaredSymbol = ScopeUtil.CreateSymbolType(ast.MethodReturnType);

            // if its inferred, just use whatever the return statement i
            if (delcaredSymbol.ExpressionType == ExpressionTypes.Inferred)
            {
                return;
            }

            if (!TokenUtil.EqualOrPromotable(returnStatementType.ExpressionType, delcaredSymbol.ExpressionType))
            {
                throw new InvalidSyntax(String.Format("Return type {0} for function {1} is not of the same type of declared method (type {2})",
                                                      returnStatementType.ExpressionType, symbol.Name, delcaredSymbol.ExpressionType));
            }
        }
        /// <summary>
        /// Creates a type for built in types or resolves user defined types
        /// </summary>
        /// <param name="ast"></param>
        /// <returns></returns>
        private IType ResolveOrDefine(Expr ast)
        {
            if (ast == null)
            {
                return(null);
            }

            switch (ast.Token.TokenType)
            {
            case TokenType.Word: return(ResolveType(ast));
            }

            return(ScopeUtil.CreateSymbolType(ast));
        }
        private LambdaDeclr CreateCurriedMethod(FuncInvoke ast, MethodSymbol functionType)
        {
            var srcMethod = functionType.MethodDeclr;

            var fixedAssignments = new List <VarDeclrAst>();

            var count = 0;

            foreach (var argValue in ast.Arguments)
            {
                var srcArg = srcMethod.Arguments[count] as VarDeclrAst;

                var token = new Token(srcArg.DeclarationType.Token.TokenType, argValue.Token.TokenValue);

                var declr = new VarDeclrAst(token, srcArg.Token, new Expr(argValue.Token));

                // if we're creating a curry using a variable then we need to resolve the variable type
                // otherwise we can make a symbol for the literal
                var newArgType = argValue.Token.TokenType == TokenType.Word ?
                                 ast.CurrentScope.Resolve(argValue).Type
                                    :   ScopeUtil.CreateSymbolType(argValue);

                // create a symbol type for the target we're invoking on so we can do type checking
                var targetArgType = ScopeUtil.CreateSymbolType(srcArg.DeclarationType);

                if (!TokenUtil.EqualOrPromotable(newArgType, targetArgType))
                {
                    throw new InvalidSyntax(String.Format("Cannot pass argument {0} of type {1} to partial function {2} as argument {3} of type {4}",
                                                          argValue.Token.TokenValue,
                                                          newArgType.TypeName,
                                                          srcMethod.MethodName.Token.TokenValue,
                                                          srcArg.VariableName.Token.TokenValue,
                                                          targetArgType.TypeName));
                }

                fixedAssignments.Add(declr);

                count++;
            }

            var newBody = fixedAssignments.Concat(srcMethod.Body.ScopedStatements).ToList();

            var curriedMethod = new LambdaDeclr(srcMethod.Arguments.Skip(ast.Arguments.Count).ToList(), new ScopeDeclr(newBody));

            SetScope(curriedMethod);

            return(curriedMethod);
        }
        private dynamic Exec(Ast ast)
        {
            try
            {
                if (ast == null)
                {
                    return(null);
                }

                if (ast.ConvertedExpression != null)
                {
                    return(Exec(ast.ConvertedExpression));
                }

                switch (ast.AstType)
                {
                case AstTypes.ScopeDeclr:
                    ScopeDelcaration(ast as ScopeDeclr);
                    break;

                case AstTypes.VarDeclr:
                    VariableDeclaration(ast as VarDeclrAst);
                    break;

                case AstTypes.Expression:
                    var ret = Expression(ast as Expr);
                    if (ret != null)
                    {
                        return(ret);
                    }
                    break;

                case AstTypes.Print:
                    Print(ast as PrintAst);
                    break;

                case AstTypes.FunctionInvoke:
                    return(InvokeFunction(ast as FuncInvoke));

                case AstTypes.Conditional:
                    ConditionalDo(ast as Conditional);
                    break;

                case AstTypes.MethodDeclr:
                    var methodDeclr = ast as MethodDeclr;
                    return(new MethodSymbol(methodDeclr.Token.TokenValue, ScopeUtil.CreateSymbolType(methodDeclr.ReturnAst), methodDeclr));

                case AstTypes.While:
                    WhileDo(ast as WhileLoop);
                    break;

                case AstTypes.Return:
                    ReturnDo(ast as ReturnAst);
                    break;

                case AstTypes.For:
                    ForDo(ast as ForLoop);
                    break;

                case AstTypes.Class:
                    ClassDo(ast as ClassAst);
                    break;

                case AstTypes.ClassRef:
                    return(ClassRefDo(ast as ClassReference));

                    break;

                case AstTypes.New:
                    return(NewDo(ast as NewAst));

                    break;
                }
            }
            catch (ReturnException ex)
            {
                // let the return value bubble up through all the exectuions until we
                // get to the source syntax tree that invoked it. at that point safely return the value
                if (ast.AstType == AstTypes.FunctionInvoke)
                {
                    return(ex.Value);
                }

                throw;
            }

            return(null);
        }
        public void Visit(VarDeclrAst ast)
        {
            var isVar = ast.DeclarationType.Token.TokenType == TokenType.Infer;

            if (ast.DeclarationType != null && !isVar)
            {
                var symbol = ScopeUtil.DefineUserSymbol(ast.DeclarationType, ast.VariableName);

                symbol.IsArray = ast is ArrayDeclrAst;

                DefineToScope(ast, symbol);

                ast.AstSymbolType = symbol.Type;
            }

            if (ast.VariableValue == null && isVar)
            {
                var symbol = ScopeUtil.DefineUserSymbol(ast.DeclarationType, ast.VariableName);

                DefineToScope(ast, symbol);

                ast.AstSymbolType = symbol.Type;
            }

            else if (ast.VariableValue != null)
            {
                ast.VariableValue.Visit(this);

                // if its type inferred, determine the declaration by the value's type
                if (isVar)
                {
                    // if the right hand side is a method declaration, make sure to track the source value
                    // this way we can reference it later to determine not only that this is a method type, but what
                    // is the expected return value for static type checking later

                    var val = ast.VariableValue.ConvertedExpression ?? ast.VariableValue;

                    ast.AstSymbolType = val is MethodDeclr
                                            ? new BuiltInType(ExpressionTypes.Method, val)
                                            : val.AstSymbolType;

                    var symbol = ScopeUtil.DefineUserSymbol(ast.AstSymbolType, ast.VariableName);

                    symbol.IsArray = ast is ArrayDeclrAst;

                    DefineToScope(ast, symbol);
                }
                else if (ResolvingTypes)
                {
                    var declaredType = ScopeUtil.CreateSymbolType(ast.DeclarationType);

                    var value = ast.VariableValue.ConvertedExpression ?? ast.VariableValue;

                    ReturnAst returnType = null;

                    // when we're resolving types check if the rhs is a function invoke. if it is, see
                    // what the return value of the src expression is so we can make sure that the
                    // lhs and the rhs match.
                    try
                    {
                        returnType =
                            value is FuncInvoke
                                ? ((value as FuncInvoke).AstSymbolType) != null
                                      ? ((value as FuncInvoke).AstSymbolType.Src as MethodDeclr).ReturnAst
                                      : null
                                : null;
                    }
                    catch
                    {
                    }

                    value = returnType != null ? returnType.ReturnExpression : value;

                    if (!TokenUtil.EqualOrPromotable(value.AstSymbolType.ExpressionType, declaredType.ExpressionType))
                    {
                        throw new InvalidSyntax(String.Format("Cannot assign {0} of type {1} to {2}", ast.VariableValue,
                                                              value.AstSymbolType.ExpressionType,
                                                              declaredType.ExpressionType));
                    }
                }
            }

            SetScope(ast);
        }