public override XzaarExpression Visit(FunctionNode function) { currentFunctionVariables.Clear(); return(null); }
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); }