예제 #1
0
 public override XzaarExpression Visit(FunctionNode function)
 {
     currentFunctionVariables.Clear();
     return(null);
 }
예제 #2
0
        private XzaarType TryGetTypeFromExpression(AstNode expr, FunctionNode currentFunction = null)
        {
            if (expr.Kind == SyntaxKind.Empty)
            {
                return(XzaarBaseTypes.Void);
            }

            if (SyntaxFacts.IsMath(expr.Kind))
            {
                var m = expr as BinaryOperatorNode;
                if (m != null)
                {
                    if (m.Op == "==" || m.Op == "!=")
                    {
                        return(XzaarBaseTypes.Boolean);
                    }
                    var leftType  = TryGetTypeFromExpression(m.Left, currentFunction);
                    var rightType = TryGetTypeFromExpression(m.Right, currentFunction);
                    if (leftType?.Name == "string" || rightType?.Name == "string")
                    {
                        return(XzaarBaseTypes.String);
                    }
                }

                return(XzaarBaseTypes.Number);
            }

            if (SyntaxFacts.IsEquality(expr.Kind))
            {
                return(XzaarBaseTypes.Boolean);
            }

            if (expr.Kind == SyntaxKind.KeywordTrue || expr.Kind == SyntaxKind.KeywordFalse)
            {
                return(XzaarBaseTypes.Boolean);
            }

            if (SyntaxFacts.IsLiteral(expr.Kind))
            {
                switch (expr.NodeName.ToLower())
                {
                case "string": return(XzaarBaseTypes.String);

                case "number": return(XzaarBaseTypes.Number);

                case "name":
                {
                    var constValue = (expr.Value + "").ToLower();
                    if (constValue == "true" || constValue == "false")
                    {
                        return(XzaarBaseTypes.Boolean);
                    }
                    if (expr.Value + "" == "null")
                    {
                        return(XzaarBaseTypes.Any);
                    }
                }
                break;
                }
            }

            if (expr.Kind == SyntaxKind.KeywordNull)
            {
                return(XzaarBaseTypes.Any);
            }

            if (expr.Kind == SyntaxKind.KeywordTrue || expr.Kind == SyntaxKind.KeywordTrue)
            {
                return(XzaarBaseTypes.Boolean);
            }

            if (expr.Kind == SyntaxKind.Identifier || SyntaxFacts.IsLiteral(expr.Kind))
            {
                var nn = expr.NodeName.ToLower();
                if (nn == "string")
                {
                    return(XzaarBaseTypes.String);
                }
                if (nn == "date")
                {
                    return(XzaarBaseTypes.Date);
                }
                if (nn == "number")
                {
                    return(XzaarBaseTypes.Number);
                }
                if (nn == "array")
                {
                    return(XzaarBaseTypes.Array);
                }
                if (nn == "char")
                {
                    return(XzaarBaseTypes.Char);
                }
                if (nn == "boolean" || nn == "bool")
                {
                    return(XzaarBaseTypes.Boolean);
                }
                if (nn == "name")
                {
                    // check known constants
                    var constValue = expr.Value + "";
                    if (constValue == "true" || constValue == "True" || constValue == "false" || constValue == "False")
                    {
                        return(XzaarBaseTypes.Boolean);
                    }

                    // check parameters
                    if (currentFunction != null)
                    {
                        var param = currentFunction.FindParameter(constValue);
                        if (param != null)
                        {
                            var t = XzaarType.GetType(param.Type);
                            if (t != null)
                            {
                                return(t);
                            }
                        }

                        if (currentFunctionVariables.ContainsKey(constValue))
                        {
                            return(currentFunctionVariables[constValue]);
                        }
                    }
                }
            }

            if (expr.Kind == SyntaxKind.Expression)
            {
                // expression can include either a boolean return, number, string or object. well any actaully. damn xD
                throw new NotImplementedException();
            }

            if (SyntaxFacts.IsMemberAccess(expr.Kind))
            {
                var access = expr as MemberAccessNode;
                if (access != null)
                {
                    if (access.MemberType != null)
                    {
                        return(XzaarType.GetType(access.MemberType));
                    }

                    var variable = context.FindVariableByExpression(access, true);
                    if (variable != null)
                    {
                        return(variable.Type);
                    }
                }
                // find member, get type
                return(null);
            }

            if (SyntaxFacts.IsAnyUnaryExpression(expr.Kind))
            {
                return(XzaarBaseTypes.Number);
            }

            if (expr.Kind == SyntaxKind.FunctionInvocation)
            {
                var anon = context.FindFunctionByExpression(expr);
                if (anon == null)
                {
                    var similar = context.FindSimilarNamedFunctionByExpression(expr);
                    if (context.IgnoreMissingMembers)
                    {
                        return(null);
                    }
                    throw new ExpressionException("Target function '" + expr.Value + "' ;could not be found! Are you 100% sure that you have defined it? Or could it be a typo?" +
                                                  (similar != null ? " Did you possibly mean '" + similar.Name + "'?" : ""));
                }

                if (currentFunction != null && anon is FunctionExpression function)
                {
                    if (function.Name == currentFunction.Name) // && ParameterSequenceMatch(function, currentFunction))
                    {
                        // recursion detected, we cannot determine the return type here.
                        // unfortunately we will only check the very first 'return' node right now
                        // so we have to return null here so we can default to 'object' as return type
                        return(null);
                    }
                    else
                    {
                        // if the function we found has a 'NULL' returntype, then add this 'call' to a temporary call-stack
                        // so we can break out from any potential 8-looped recursions (or other kind of recursions)
                        if (function.ReturnType == null)
                        {
                            this.context.AddToCallStack(currentFunction, anon);

                            // we need to late bind the returntype to match this function's type,
                            // that way it will autocorrect itself the moment the other function has determined its return type.
                            currentFunction.BindReturnType(function.Name, () => function.ReturnType);
                        }
                        else
                        {
                            return(function.ReturnType);
                        }
                    }
                }
            }
            return(null);
        }