示例#1
0
 public static ResolvedType GetFunctionType(FunctionDefinition func)
 {
     if (!funcTypesByRef.ContainsKey(func))
     {
         ResolvedType type = GetFunctionType(func.ResolvedReturnType, func.ResolvedArgTypes, FunctionCall.CountOptionalArgs(func.DefaultValues));
         funcTypesByRef[func] = type;
     }
     return(funcTypesByRef[func]);
 }
示例#2
0
        /// <summary>
        /// Takes an arithmetical or logical expression and returns the corresponding variable
        /// <para/>Examples:
        /// <para/>* "5 + 6" : returns Integer (11)
        /// <para/>* "$l[5 * (1 - $i)]" : returns the elements at index 5*(1-i) in the list "l"
        /// <para/>* "$l" : returns the list variable l
        /// </summary>
        /// <param name="expr_string"> expression to parse</param>
        /// <returns> Variable object containing the value of the evaluated expression value (at time t)</returns>
        public static Variable parse(string expr_string)
        {
            /* Order of operations:
             * checking expression string integrity
             * raw dynamic list
             * clean redundant symbols
             * raw integer value
             * raw boolean value (not done yet)
             * raw float value (not done yet)
             * mathematical or logical operation
             * function call
             * variable access (e.g. $name or in list by index)
             */

            // clean expression
            expr_string = StringUtils.normalizeWhiteSpaces(expr_string);
            Exception invalid_expr_exception =
                new AquilaExceptions.SyntaxExceptions.SyntaxError($"The sentence \"{expr_string}\" is not understood");

            Debugging.print("input expression: " + expr_string);

            // matching parentheses & brackets
            Debugging.assert(StringUtils.checkMatchingDelimiters(expr_string, '(', ')'),
                             new AquilaExceptions.SyntaxExceptions.UnclosedTagError("Unclosed parenthesis"));
            Debugging.assert(StringUtils.checkMatchingDelimiters(expr_string, '[', ']'),
                             new AquilaExceptions.SyntaxExceptions.UnclosedTagError("Unclosed bracket"));
            expr_string = StringUtils.removeRedundantMatchingDelimiters(expr_string, '(', ')');

            Debugging.print("dynamic list ?");
            // dynamic list
            {
                DynamicList list = StringUtils.parseListExpression(expr_string);
                if (list != null)
                {
                    return(list);
                }
            }

            // now that lists are over, check for redundant brackets
            expr_string = StringUtils.removeRedundantMatchingDelimiters(expr_string, '[', ']');

            if (expr_string == null)
            {
                throw new AquilaExceptions.SyntaxExceptions.SyntaxError("Null Expression");
            }

            Debugging.assert(expr_string != ""); //! NullValue here, instead of Exception

            Debugging.print("int ?");
            // try evaluating expression as an integer
            if (int.TryParse(expr_string, out int int_value))
            {
                return(new Integer(int_value, true));
            }

            Debugging.print("bool ?");
            // try evaluating expression as a boolean
            if (expr_string == "true")
            {
                return(new BooleanVar(true, true));
            }

            if (expr_string == "false")
            {
                return(new BooleanVar(false, true));
            }

            Debugging.print("float ?");
            // try evaluating expression as float
            if (!expr_string.Contains(' '))
            {
                if (float.TryParse(expr_string, out float float_value))
                {
                    Debugging.print("french/classic float");
                    return(new FloatVar(float_value, true));
                }

                if (float.TryParse(expr_string.Replace('.', ','), out float_value))
                {
                    Debugging.print("normalized float");
                    return(new FloatVar(float_value, true));
                }

                if (expr_string.EndsWith("f") &&
                    float.TryParse(expr_string.Substring(0, expr_string.Length - 1), out float_value))
                {
                    Debugging.print("f-float");
                    return(new FloatVar(float_value, true));
                }

                if (expr_string.EndsWith("f") &&
                    float.TryParse(expr_string.Replace('.', ',').Substring(0, expr_string.Length - 1), out float_value))
                {
                    Debugging.print("f-float");
                    return(new FloatVar(float_value, true));
                }
            }

            Debugging.print("checking for negative expression");
            // special step: check for -(expr)
            if (expr_string.StartsWith("-"))
            {
                Debugging.print("evaluating expression without \"-\" sign");
                string   opposite_sign_expr = expr_string.Substring(1); // take away the "-"
                Variable opposite_sign_var  = parse(opposite_sign_expr);
                Debugging.print("evaluated expression without the \"-\" symbol is of type ", opposite_sign_var.getTypeString(), " and value ", opposite_sign_var.getValue());

                // ReSharper disable once ConvertIfStatementToSwitchExpression
                if (opposite_sign_var is Integer)
                {
                    return(new Integer(-opposite_sign_var.getValue()));
                }
                if (opposite_sign_var is FloatVar)
                {
                    return(new FloatVar(-opposite_sign_var.getValue()));
                }
                throw new AquilaExceptions.InvalidTypeError($"Cannot cast \"-\" on a {opposite_sign_var.getTypeString()} variable");
            }

            Debugging.print("AL operations ?");
            // mathematical and logical operations
            foreach (char op in Global.al_operations)
            {
                // ReSharper disable once PossibleNullReferenceException
                if (expr_string.Contains(op.ToString()))
                {
                    string simplified = StringUtils.simplifyExpr(expr_string, new [] { op }); // only look for specific delimiter
                    // more than one simplified expression ?
                    if (simplified.Split(op).Length > 1)
                    {
                        Debugging.print("operation ", expr_string, " and op: ", op);
                        List <string> splitted_str =
                            StringUtils.splitStringKeepingStructureIntegrity(expr_string, op, Global.base_delimiters);

                        // custom: logic operations laziness here (tmp) //!
                        Variable variable = parse(splitted_str[0]);
                        if (Global.getSetting("lazy logic") && variable is BooleanVar)
                        {
                            Debugging.print("lazy logic evaluation");
                            bool first = (variable as BooleanVar).getValue();
                            switch (op)
                            {
                            case '|':    // when first:
                                if (first)
                                {
                                    return(new BooleanVar(true, true));
                                }
                                break;

                            case '&':    // when !first:
                                if (!first)
                                {
                                    return(new BooleanVar(false, true));
                                }
                                break;
                            }
                        }

                        var splitted_var = new List <Variable> {
                            variable
                        };
                        splitted_var.AddRange(splitted_str.GetRange(1, splitted_str.Count - 1).Select(parse));

                        // reduce the list to a list of one element
                        // e.g. expr1 + expr2 + expr3 => final_expr
                        while (splitted_var.Count > 1)
                        {
                            // merge the two first expressions
                            Variable expr1_var = splitted_var[0];
                            Variable expr2_var = splitted_var[1];
                            Variable result    = applyOperator(expr1_var, expr2_var, op);
                            // merge result of 0 and 1
                            splitted_var[0] = result;
                            // remove 1 (part of it found in 0 now)
                            splitted_var.RemoveAt(1);
                        }

                        return(splitted_var[0]);
                    }
                }
            }
            Debugging.print("not (!) operator ?");
            // '!' operator (only one to take one variable)
            if (expr_string.StartsWith("!"))
            {
                Debugging.assert(expr_string[1] == '(');
                Debugging.assert(expr_string[expr_string.Length - 1] == ')');
                Variable expr = parse(expr_string.Substring(2, expr_string.Length - 3));
                Debugging.assert(expr is BooleanVar);
                Debugging.print("base val b4 not operator is ", expr.getValue());
                return(((BooleanVar)expr).not());
            }

            Debugging.print("value function call ?");
            // value function call
            if (expr_string.Contains("("))
            {
                string function_name    = expr_string.Split('(')[0]; // extract function name
                int    func_call_length = function_name.Length;
                function_name = StringUtils.normalizeWhiteSpaces(function_name);
                Debugging.print("function name: ", function_name);
                Functions.assertFunctionExists(function_name);
                expr_string = expr_string.Substring(func_call_length);          // remove function name
                expr_string = expr_string.Substring(1, expr_string.Length - 2); // remove parenthesis
                Debugging.print("expr_string for function call ", expr_string);

                var arg_list = new List <Expression>();
                foreach (string arg_string in StringUtils.splitStringKeepingStructureIntegrity(expr_string, ',', Global.base_delimiters))
                {
                    string     purged_arg_string = StringUtils.normalizeWhiteSpaces(arg_string);
                    Expression arg_expr          = new Expression(purged_arg_string);
                    arg_list.Add(arg_expr);
                }

                if (arg_list.Count == 1 && arg_list[0].expr == "")
                {
                    arg_list = new List <Expression>();
                }

                Debugging.print("creating value function call with ", arg_list.Count, " parameters");

                FunctionCall func_call = new FunctionCall(function_name, arg_list);
                return(func_call.callFunction());
            }

            // function call without parenthesis -> no parameters either
            if (!expr_string.StartsWith(StringConstants.Other.VARIABLE_PREFIX) && !expr_string.Contains(' '))
            {
                Debugging.print($"Call the function \"{expr_string}\" with no parameters");
                var func_call = new FunctionCall(expr_string, new List <Expression>());
                return(func_call.callFunction());
            }

            Debugging.print("variable ?");
            // variable access

            // since it is the last possibility for the parse call to return something, assert it is a variable
            Debugging.assert(expr_string.StartsWith(StringConstants.Other.VARIABLE_PREFIX), invalid_expr_exception);
            Debugging.print("list access ?");
            // ReSharper disable once PossibleNullReferenceException
            if (expr_string.Contains("["))
            {
                // brackets
                Debugging.assert(expr_string.EndsWith("]"), invalid_expr_exception); // cannot be "$l[0] + 5" bc AL_operations have already been processed
                int bracket_start_index = expr_string.IndexOf('[');
                Debugging.assert(bracket_start_index > 1, invalid_expr_exception);   // "$[$i - 4]" is not valid
                // variable
                Expression var_name_expr = new Expression(expr_string.Substring(0, bracket_start_index));
                Debugging.print("list name: " + var_name_expr.expr);
                // index list
                IEnumerable <string> index_list = StringUtils.getBracketsContent(expr_string.Substring(bracket_start_index));
                string index_list_expr_string   = index_list.Aggregate("", (current, s) => current + s + ", ");
                index_list_expr_string = "[" + index_list_expr_string.Substring(0, index_list_expr_string.Length - 2) + "]";
                var index_list_expr = new Expression(index_list_expr_string);

                Debugging.print("index: " + index_list_expr.expr);

                // create a value function call (list_at call)
                object[] args = { var_name_expr, index_list_expr };
                return(Functions.callFunctionByName("list_at", args));
            }

            // only variable name, no brackets
            Debugging.print("var by name: ", expr_string);
            return(variableFromName(expr_string));
        }
示例#3
0
        private Expression ParseEntity(TokenStream tokens, Node owner)
        {
            Expression root;
            Token      firstToken = tokens.Peek();
            AType      castPrefix = firstToken.Value == "(" ? this.MaybeParseCastPrefix(tokens) : null;

            if (castPrefix != null)
            {
                root = this.ParseEntity(tokens, owner);
                return(new Cast(firstToken, castPrefix, root, owner, true));
            }

            Token maybeOpenParen = tokens.Peek();

            if (tokens.PopIfPresent("("))
            {
                if (tokens.PopIfPresent(")"))
                {
                    root = this.ParseLambda(tokens, firstToken, new AType[0], new Token[0], owner);
                }
                else
                {
                    if (this.parser.CurrentScope.IsStaticallyTyped)
                    {
                        TokenStream.StreamState state = tokens.RecordState();
                        AType lambdaArgType           = this.parser.TypeParser.TryParse(tokens);
                        Token lambdaArg = null;
                        if (lambdaArgType != null)
                        {
                            lambdaArg = tokens.PopIfWord();
                        }

                        if (lambdaArg != null)
                        {
                            List <AType> lambdaArgTypes = new List <AType>()
                            {
                                lambdaArgType
                            };
                            List <Token> lambdaArgs = new List <Token>()
                            {
                                lambdaArg
                            };
                            while (tokens.PopIfPresent(","))
                            {
                                lambdaArgTypes.Add(this.parser.TypeParser.Parse(tokens));
                                lambdaArgs.Add(tokens.PopWord());
                            }
                            tokens.PopExpected(")");
                            return(this.ParseLambda(tokens, maybeOpenParen, lambdaArgTypes, lambdaArgs, owner));
                        }
                        else
                        {
                            tokens.RestoreState(state);
                        }
                    }

                    root = this.Parse(tokens, owner);
                    if (root is Variable)
                    {
                        if (tokens.PopIfPresent(")"))
                        {
                            if (tokens.IsNext("=>"))
                            {
                                root = this.ParseLambda(tokens, firstToken, new AType[] { AType.Any(root.FirstToken) }, new Token[] { root.FirstToken }, owner);
                            }
                        }
                        else if (tokens.IsNext(","))
                        {
                            List <Token> lambdaArgs = new List <Token>()
                            {
                                root.FirstToken
                            };
                            List <AType> lambdaArgTypes = new List <AType>()
                            {
                                AType.Any(root.FirstToken)
                            };
                            Token comma = tokens.Peek();
                            while (tokens.PopIfPresent(","))
                            {
                                Token nextArg = tokens.Pop();
                                if (nextArg.Type != TokenType.WORD)
                                {
                                    throw new ParserException(comma, "Unexpected comma.");
                                }
                                lambdaArgTypes.Add(AType.Any(nextArg));
                                lambdaArgs.Add(nextArg);
                                comma = tokens.Peek();
                            }
                            tokens.PopExpected(")");

                            root = this.ParseLambda(tokens, firstToken, lambdaArgTypes, lambdaArgs, owner);
                        }
                        else
                        {
                            // This will purposely cause an unexpected token error
                            // since it's none of the above conditions.
                            tokens.PopExpected(")");
                        }
                    }
                    else
                    {
                        tokens.PopExpected(")");
                    }
                }
            }
            else
            {
                root = ParseEntityWithoutSuffixChain(tokens, owner);
            }
            bool anySuffixes    = true;
            bool isPreviousADot = false;

            while (anySuffixes)
            {
                if (tokens.IsNext("."))
                {
                    isPreviousADot = true;
                    Token dotToken   = tokens.Pop();
                    Token fieldToken = tokens.Pop();
                    // HACK alert: "class" is a valid field on a class.
                    // ParserVerifyIdentifier is invoked downstream for non-resolved fields.
                    if (fieldToken.Value != this.parser.Keywords.CLASS)
                    {
                        this.parser.VerifyIdentifier(fieldToken);
                    }
                    root = new DotField(root, dotToken, fieldToken, owner);
                }
                else if (tokens.IsNext("["))
                {
                    Token             openBracket     = tokens.Pop();
                    List <Expression> sliceComponents = new List <Expression>();
                    if (tokens.IsNext(":"))
                    {
                        sliceComponents.Add(null);
                    }
                    else
                    {
                        sliceComponents.Add(Parse(tokens, owner));
                    }

                    for (int i = 0; i < 2; ++i)
                    {
                        if (tokens.PopIfPresent(":"))
                        {
                            if (tokens.IsNext(":") || tokens.IsNext("]"))
                            {
                                sliceComponents.Add(null);
                            }
                            else
                            {
                                sliceComponents.Add(Parse(tokens, owner));
                            }
                        }
                    }

                    tokens.PopExpected("]");

                    if (sliceComponents.Count == 1)
                    {
                        Expression index = sliceComponents[0];
                        root = new BracketIndex(root, openBracket, index, owner);
                    }
                    else
                    {
                        root = new ListSlice(root, sliceComponents, openBracket, owner);
                    }
                }
                else if (tokens.IsNext("("))
                {
                    Token             openParen = tokens.Pop();
                    List <Expression> args      = new List <Expression>();
                    while (!tokens.PopIfPresent(")"))
                    {
                        if (args.Count > 0)
                        {
                            tokens.PopExpected(",");
                        }

                        args.Add(Parse(tokens, owner));
                    }
                    root = new FunctionCall(root, openParen, args, owner);
                }
                else if (tokens.IsNext(this.parser.Keywords.IS))
                {
                    Token  isToken    = tokens.Pop();
                    Token  classToken = tokens.Pop();
                    string className  = this.parser.PopClassNameWithFirstTokenAlreadyPopped(tokens, classToken);
                    root = new IsComparison(root, isToken, classToken, className, owner);
                }
                else if (isPreviousADot && this.parser.IsCSharpCompat && tokens.IsNext("<"))
                {
                    TokenStream.StreamState s = tokens.RecordState();
                    Token openBracket         = tokens.Pop();
                    AType funcType            = this.parser.TypeParser.TryParse(tokens);

                    List <AType> types = new List <AType>()
                    {
                        funcType
                    };
                    if (funcType != null)
                    {
                        while (tokens.PopIfPresent(","))
                        {
                            types.Add(this.parser.TypeParser.Parse(tokens));
                        }
                    }

                    if (funcType == null)
                    {
                        anySuffixes = false;
                        tokens.RestoreState(s);
                    }
                    else if (!tokens.PopIfPresent(">") || !tokens.IsNext("("))
                    {
                        anySuffixes = false;
                        tokens.RestoreState(s);
                    }
                    else
                    {
                        // TODO(acrylic-conversion): do something with this types list.
                    }
                }
                else
                {
                    anySuffixes = false;
                }
            }
            return(root);
        }
示例#4
0
        private Expression ParseEntity(TokenStream tokens, TopLevelConstruct owner)
        {
            Expression root;

            if (tokens.PopIfPresent("("))
            {
                root = this.Parse(tokens, owner);
                tokens.PopExpected(")");
            }
            else
            {
                root = ParseEntityWithoutSuffixChain(tokens, owner);
            }
            bool anySuffixes = true;

            while (anySuffixes)
            {
                if (tokens.IsNext("."))
                {
                    Token dotToken  = tokens.Pop();
                    Token stepToken = tokens.Pop();
                    // HACK alert: "class" is a valid field on a class.
                    // ParserVerifyIdentifier is invoked downstream for non-resolved fields.
                    if (stepToken.Value != this.parser.Keywords.CLASS)
                    {
                        this.parser.VerifyIdentifier(stepToken);
                    }
                    root = new DotStep(root, dotToken, stepToken, owner);
                }
                else if (tokens.IsNext("["))
                {
                    Token             openBracket     = tokens.Pop();
                    List <Expression> sliceComponents = new List <Expression>();
                    if (tokens.IsNext(":"))
                    {
                        sliceComponents.Add(null);
                    }
                    else
                    {
                        sliceComponents.Add(Parse(tokens, owner));
                    }

                    for (int i = 0; i < 2; ++i)
                    {
                        if (tokens.PopIfPresent(":"))
                        {
                            if (tokens.IsNext(":") || tokens.IsNext("]"))
                            {
                                sliceComponents.Add(null);
                            }
                            else
                            {
                                sliceComponents.Add(Parse(tokens, owner));
                            }
                        }
                    }

                    tokens.PopExpected("]");

                    if (sliceComponents.Count == 1)
                    {
                        Expression index = sliceComponents[0];
                        root = new BracketIndex(root, openBracket, index, owner);
                    }
                    else
                    {
                        root = new ListSlice(root, sliceComponents, openBracket, owner);
                    }
                }
                else if (tokens.IsNext("("))
                {
                    Token             openParen = tokens.Pop();
                    List <Expression> args      = new List <Expression>();
                    while (!tokens.PopIfPresent(")"))
                    {
                        if (args.Count > 0)
                        {
                            tokens.PopExpected(",");
                        }

                        args.Add(Parse(tokens, owner));
                    }
                    root = new FunctionCall(root, openParen, args, owner);
                }
                else if (tokens.IsNext(this.parser.Keywords.IS))
                {
                    Token  isToken    = tokens.Pop();
                    Token  classToken = tokens.Pop();
                    string className  = this.parser.PopClassNameWithFirstTokenAlreadyPopped(tokens, classToken);
                    root = new IsComparison(root, isToken, classToken, className, owner);
                }
                else
                {
                    anySuffixes = false;
                }
            }
            return(root);
        }