예제 #1
0
 /// <summary>
 /// Raised by the "return()" function in Aquila
 /// </summary>
 /// <param name="expr_as_msg"> The expression string which should be returned by the <see cref="Algorithm"/> or <see cref="Function"/></param>
 public ReturnValueException(string expr_as_msg)
 {
     Debugging.print("Resetting Context in Return Exception constructor. Context: " +
                     (Context.StatusEnum)Context.getStatus());
     Context.reset();
     _return_expr = expr_as_msg;
 }
예제 #2
0
        public Variable callFunction()
        {
            Debugging.print("calling \"" + _function_name + "\" as value");
            // manually set context
            Context.setStatus(Context.StatusEnum.predefined_function_call);
            Context.setInfo(this);
            // for rec functions:
            bool frozen_at_start = Context.isFrozen();

            _called = true;
            // from list to array of objects
            // ReSharper disable once SuggestVarOrType_Elsewhere
            object[] args = _arg_expr_list.Select(x => (object)x).ToArray();

            // call by name
            Variable result = Functions.callFunctionByName(_function_name, args);

            // have to trace manually here
            if (isTraced())
            {
                Tracer.printTrace("Tracing manually value function");
                tracer.update(new Event(new Alteration(_function_name, this, result, args)));
            }

            // reset Context
            if (!frozen_at_start)
            {
                Context.reset();
            }

            return(result);
        }
예제 #3
0
        public override void execute()
        {
            setContext();
            int context_integrity_check = Context.getStatusStackCount();

            Debugging.print("Assignment: ", _var_name, " = ", _var_value.expr);

            // set the new value
            Variable variable;

            try
            {
                variable = Expression.parse(_var_name);
            }
            catch (AquilaExceptions.NameError)
            {
                // implicit declaration
                if (!Global.getSetting("implicit declaration in assignment"))
                {
                    throw;
                }
                Debugging.print("Implicit declaration in Assignment!");
                Declaration decl = new Declaration(line_index, _var_name.Substring(1), _var_value); // in the Assignment constructor: already check if _var_name != ""
                decl.execute();

                // update things 'n stuff
                Global.onElementaryInstruction();

                // reset Context
                // Smooth Context
                Context.resetUntilCountReached(context_integrity_check);
                Context.reset();

                return;
            }

            // parsing new value
            Variable val = _var_value.evaluate();

            Debugging.print("assigning " + _var_name + " with expr " + _var_value.expr + " with value " + val + " (2nd value assigned: " + val.assigned + ") and type: " + val.getTypeString());
            // assert the new is not an unassigned (only declared) variable
            val.assertAssignment();

            if (variable.hasSameParent(val))
            {
                variable.setValue(val);
            }
            else
            {
                throw new AquilaExceptions.InvalidTypeError("You cannot change the type of your variables (" + variable.getTypeString() + " -> " + val.getTypeString() + "). This will never be supported because it would be considered bad style.");
            }

            // update things 'n stuff
            Global.onElementaryInstruction();

            // reset Context
            // Smooth Context
            Context.resetUntilCountReached(context_integrity_check);
            Context.reset();
        }
예제 #4
0
        /// <summary>
        /// Call a function from the <see cref="functions_dict"/> or <see cref="functions_dict"/> dictionary.
        /// This can be a default function or a custom function
        /// </summary>
        /// <param name="name"> The function name (key)</param>
        /// <param name="args"> The arguments for you function</param>
        /// <returns> Returned value from the function</returns>
        /// <exception cref="AquilaExceptions.FunctionNameError"> Function does not exist</exception>
        public static Variable callFunctionByName(string name, params object[] args)
        {
            if (functions_dict.ContainsKey(name))
            {
                // no new context scope needed, because no function defined here would benefit from it. plus, wouldn't it break some functionalities ? idk

                Context.assertStatus(Context.StatusEnum.predefined_function_call);
                Debugging.print("invoking value function ", name, " dynamically with ", args.Length, " argument(s)");
                return(functions_dict[name].DynamicInvoke(args) as Variable);
            }
            if (user_functions.ContainsKey(name))
            {
                Debugging.print("calling user function: " + name);
                Dictionary <string, Variable> arg_dict = args2Dict(name, args);

                // user-functions: should not be frozen
                // bool unfreeze = Context.tryFreeze();
                Global.newMainContextScope();
                Variable result = user_functions[name].callFunction(arg_dict);
                Global.resetMainContextScope();
                // if (unfreeze) Context.unfreeze();

                return(result);
            }

            throw new AquilaExceptions.FunctionNameError($"Function \"{name}\" does not exist");
        }
예제 #5
0
        /// <summary>
        /// Prints a new-line-char to the stdout
        /// </summary>
        /// <returns> <see cref="NullVar"/> (equivalent of null/void)</returns>
        private static NullVar printEndlFunction()
        {
            Debugging.print("begin printing to console");
            Global.stdoutWrite('\n');
            Debugging.print("end printing to console");

            return(new NullVar());
        }
예제 #6
0
        /// <summary>
        /// Prints the string of the Expression
        /// </summary>
        /// <param name="expr"> <see cref="NullVar"/> (equivalent of null/void)</param>
        /// <returns> <see cref="NullVar"/> (equivalent of null/void)</returns>
        private static NullVar printStrFunction(Expression expr)
        {
            Debugging.print("begin printing to console");
            Global.stdoutWrite(expr.expr);
            Debugging.print("end printing to console");

            return(new NullVar());
        }
예제 #7
0
        /// <summary>
        /// Prints the value of an <see cref="Expression"/> to the stdout. Does add a return '\n' symbol
        /// </summary>
        /// <param name="value"> Expression you want to print (the evaluated value)</param>
        /// <returns> <see cref="NullVar"/> (equivalent of null/void)</returns>
        private static NullVar printValEndlFunction(Expression value)
        {
            Debugging.print("begin printing to console: (" + value.expr + ")");
            Global.stdoutWriteLine(value.evaluate().ToString());
            Debugging.print("end printing to console");

            return(new NullVar());
        }
예제 #8
0
 protected override void updateTestModeValues()
 {
     Global.instruction_count++;
     Debugging.print("instruction count incrementation");
     if (!Global.getSetting("test mode"))
     {
         return;
     }
     Algorithm.testModeInstructionUpdate();
 }
예제 #9
0
        /// <summary>
        /// Run the Algorithm as a test run. <see cref="Instruction"/> by <see cref="Instruction"/>,
        /// until the list of instructions is exhausted and we can return the <see cref="_return_value"/>,
        /// using <see cref="Expression.parse"/> on it (it is an <see cref="Expression"/>)
        /// </summary>
        /// <returns> The evaluated <see cref="_return_value"/> after all the <see cref="_instructions"/> have been executed</returns>
        /// <exception cref="AquilaExceptions.RuntimeError"> ReturnValueException is null</exception>
        public Variable testRun()
        {
            initTestMode();
            try
            {
                // Run start
                Debugging.print("Starting Algorithm test run");
                setStartContext();

                foreach (Instruction instr in _instructions)
                {
                    try
                    {
                        instr.execute();
                    }
                    catch (System.Reflection.TargetInvocationException out_exception)
                    {
                        // normal TargetInvocationException
                        if (!(out_exception.InnerException is AquilaControlFlowExceptions.ReturnValueException))
                        {
                            throw;
                        }
                        // casted ReturnValueException
                        AquilaControlFlowExceptions.ReturnValueException exception =
                            (AquilaControlFlowExceptions.ReturnValueException)out_exception.InnerException;

                        if (exception == null)
                        {
                            throw new AquilaExceptions.RuntimeError("The inner ReturnValueException in the TargetInvocationException is null");                    // something went wrong
                        }
                        _return_value = new Expression(exception.getExprStr());
                        Context.reset();
                        Debugging.print("Ended Algorithm test run with return value");
                        Global.setSetting("test mode", false);
                        return(_return_value.evaluate());
                    }
                }

                // no resetting here. algorithm finished
                setEndContext();

                Debugging.print("Ended Algorithm test run with no return");
                Global.setSetting("test mode", false);
                return(new NullVar()); // NoReturnCallWarning
            }
            catch (Exception e)
            {
                Global.stdoutWriteLine(e.ToString());

                Debugging.print("Ended Algorithm test run with exception");
                Global.setSetting("test mode", false);
                return(new NullVar());
            }
        }
예제 #10
0
        public override void execute()
        {
            setContext();

            foreach (Instruction instruction in _instructions)
            {
                Debugging.print("multiple instruction: ", instruction);
                instruction.execute();
            }

            Context.reset();
        }
예제 #11
0
 /// <summary>
 /// Remove the last local context scope variable dict.
 /// This is called when exiting a nested instruction
 /// </summary>
 public static void resetLocalContextScope()
 {
     Debugging.print("exiting local scope (current): ", getLocalScopeDepth());
     Debugging.assert(getLocalScopeDepth() > 0);
     foreach (var pair in getCurrentDict().Where(pair => pair.Value.isTraced()))
     {
         pair.Value.tracer.update(new Event(new Alteration("delete_var", pair.Value,
                                                           pair.Value.getRawValue(), new dynamic[] {})));
     }
     removeVariableStackElement();
     Debugging.print("new local scope: " + getLocalScopeDepth());
 }
예제 #12
0
 /// <summary>
 /// Add a <see cref="Function"/> to the <see cref="user_functions"/> dict.
 /// If the function already exists and the settings are set accordingly ("user function overwriting"),
 /// the function will be overwritten
 /// </summary>
 /// <param name="func"> <see cref="Function"/> object</param>
 public static void addUserFunction(Function func)
 {
     if (user_functions.ContainsKey(func.getName()) && Global.getSetting("user function overwriting"))
     {
         Debugging.print("overwriting already existing user defined function: " + func.getName());
         user_functions[func.getName()] = func;
     }
     else
     {
         user_functions.Add(func.getName(), func);
     }
 }
예제 #13
0
 /// <summary>
 /// Get the <see cref="Variable"/> from the current variable Dictionary.
 /// You an give the variable name with or without the "$" (<see cref="StringConstants.Other.VARIABLE_PREFIX"/>) prefix
 /// </summary>
 /// <param name="var_name"> The variable name (with or without the prefix)</param>
 /// <returns> the corresponding <see cref="Variable"/></returns>
 private static Variable variableFromName(string var_name)
 {
     if (var_name.StartsWith(StringConstants.Other.VARIABLE_PREFIX))
     {
         var_name = var_name.Substring(1);
     }
     Debugging.print("Variable access: ", var_name);
     //Interpreter.processInterpreterInput("vars");
     Debugging.assert(Global.variableExistsInCurrentScope(var_name),
                      new AquilaExceptions.NameError($"Variable name \"{var_name}\" does not exist in the current Context"));
     return(Global.variableFromName(var_name));
 }
예제 #14
0
        /// <summary>
        /// Removes the last added variable stack layer.
        /// This is called when exiting, for example, a function call
        /// </summary>
        public static void resetMainContextScope()
        {
            Debugging.print("exiting main scope depth (current): " + getMainScopeDepth());
            Debugging.assert(getMainScopeDepth() > 0); // cannot exit a function call or something in the main instruction loop
            foreach (var pair in _variable_stack.Peek().SelectMany(dictionary => dictionary.Where(pair => pair.Value.isTraced())))
            {
                pair.Value.tracer.update(new Event(new Alteration("delete_var", pair.Value,
                                                                  pair.Value.getRawValue(), Array.Empty <dynamic>())));
            }

            removeVariableStackLayer();
            Debugging.print("new main scope depth: " + getMainScopeDepth());
        }
예제 #15
0
        /// <summary>
        /// Should be called BEFORE executing the <see cref="Function"/>.
        /// Initializes a new Main Context Stack, as well as a new Local Context Stack with the given variables
        /// </summary>
        /// <exception cref="Context.ContextException"> If not a recursive function, already executing this very function</exception>
        private void initialize(Dictionary <string, Variable> args)
        {
            _call_depth++;
            Debugging.print("calling function with depth: ", _call_depth);
            // Debugging.assert(Global.getSetting("flame mode") || Context.isFrozen());
            if (!_rec_function && _in_function_scope)
            {
                throw new Context.ContextException("Already in function scope. Missing \"recursive\" keyword ?");                                      // recursive ?
            }
            // new local context scope using custom function args
            Global.newLocalContextScope(args);

            _in_function_scope = true;
        }
예제 #16
0
 internal static void testModeInstructionUpdate()
 {
     Debugging.assert(Global.getSetting("test mode"),
                      new AquilaExceptions.RuntimeError("Not in test mode"));
     // update instruction counter
     Global.test_values["instruction counter"]++;
     Debugging.print("- test run - Instruction count: ", Global.test_values["instruction counter"]);
     // still valid runtime ?
     if (Global.test_values["stopwatch"].ElapsedMilliseconds <= Global.test_values["max elapsed ms"] &&
         Global.test_values["instruction counter"] <= Global.test_values["max instruction counter"])
     {
         return;
     }
     // unfinished algorithm
     Global.test_values["unfinished run"] = true;
     throw new AquilaExceptions.RuntimeError("Test max run time exceeded");
 }
예제 #17
0
 /// <summary>
 /// Trace the variable value <see cref="Alteration"/>.
 /// This is done manually in <see cref="FunctionCall"/> to prevent from infinite recursive calls
 /// </summary>
 /// <param name="info_name"> name of the method</param>
 /// <param name="sub_values"> sub_values are e.g. function parameters</param>
 /// <param name="check"> force checking for different value in ?</param>
 protected void trace(string info_name, dynamic[] sub_values, bool check = false)
 {
     if (!_traced)
     {
         return;
     }
     if (check)
     {
         Debugging.print("checking if any values have changed");
         if (tracer.peekValue() == getValue())
         {
             Debugging.print("values equal. no updating done");
             return;
         }
     }
     tracer.update(new Event(new Alteration(info_name, this, getRawValue(), sub_values, trace_mode)));
 }
예제 #18
0
        /// <summary>
        /// Load an Aquila library
        /// </summary>
        /// <param name="lib_path"> lib_path to the library source file</param>
        /// <exception cref="AquilaExceptions.LibraryLoadingFailedError"> Library load failed</exception>
        public static void loadLibrary(string lib_path)
        {
            Debugging.print("loading lib: " + lib_path);
            // generate the Algorithm
            Algorithm algo = algorithmFromSrcCode(lib_path, default_name: $"use-header-file \"{lib_path}\"");

            // try loading the library
            try
            {
                algo.run();
            }
            catch (Exception e)
            {
                throw new AquilaExceptions.LibraryLoadingFailedError($"Unable to load library at \"{lib_path}\" because of: " + e.Message);
            }

            Debugging.print("finished loading lib: " + lib_path);
        }
예제 #19
0
        public Declaration(int line_index, string var_name, Expression var_expr, string var_type = StringConstants.Types.AUTO_TYPE, bool assignment = true,
                           bool safe_mode = false,
                           bool overwrite = false,
                           bool constant  = false,
                           bool global    = false)
        {
            // mode: 0 -> new var (must not exist); 1 -> force overwrite (must exist); 2 -> safe overwrite (can exist)
            this.line_index = line_index;
            _var_name       = var_name;
            _var_expr       = var_expr;
            _var_type       = var_type;
            _assignment     = assignment;
            _constant       = constant;
            _global         = global;
            // check variable naming
            Debugging.assert(StringUtils.validObjectName(var_name),
                             new AquilaExceptions.SyntaxExceptions.SyntaxError($"Invalid object name \"{var_name}\""));
            // the declaration is not initiated in the right scope... cannot do this here
            bool var_exists = Global.variableExistsInCurrentScope(var_name);

            Debugging.print("new declaration: var_name = " + var_name +
                            ", var_expr = ", var_expr.expr,
                            ", var_type = ", var_type,
                            ", assignment = ", assignment,
                            ", mode = ", StringUtils.boolString(safe_mode, overwrite, _constant, _global),
                            ", exists = ", var_exists);
            // should not check overwriting modes if this is true
            if (Global.getSetting("implicit declaration in assignment"))
            {
                Debugging.print("implicit declaration in assignments, so skipping var existence checks (var exists: ", var_exists, ")");
                return;
            }

            if (safe_mode && var_exists)
            {
                Debugging.assert(!Global.variableFromName(var_name).isTraced());
            }
            if (overwrite)
            {
                Debugging.assert(var_exists);
            }
        }
예제 #20
0
        public override void execute()
        {
            setContext();
            int context_integrity_check = Context.getStatusStackCount();

            // the tracing instruction execution doesn't take any Tracer.updateTracers() calls
            foreach (Expression traced_expr in _traced_vars)
            {
                Variable traced_var = traced_expr.evaluate();
                if (traced_var.isTraced())
                {
                    Debugging.print("trying to trace a variable that is already traced: " + traced_expr.expr);
                    continue;
                }
                traced_var.startTracing();
            }

            // Smooth Context
            Context.resetUntilCountReached(context_integrity_check);
            Context.reset();
        }
예제 #21
0
        /// <summary>
        /// Call the function with input parameters (args)
        /// </summary>
        /// <param name="args"> The variables defining the new Main Context Stack</param>
        /// <returns> The return value of the function</returns>
        public Variable callFunction(Dictionary <string, Variable> args)
        {
            initialize(args);

            Debugging.assert(_in_function_scope);
            foreach (Instruction instruction in _instructions)
            {
                try
                {
                    instruction.execute(); // return here (not continue, nor break)
                }
                catch (System.Reflection.TargetInvocationException out_exception)
                {
                    if (!(out_exception.InnerException is AquilaControlFlowExceptions.ReturnValueException return_value_exception))
                    {
                        throw;
                    }
                    Debugging.print("ReturnValueException was thrown");
                    string     return_value_string     = return_value_exception.getExprStr();
                    Expression return_value_expression = new Expression(return_value_string);
                    Variable   return_value            = return_value_expression.evaluate();

                    if (_type != StringConstants.Types.AUTO_TYPE && _type != StringConstants.Types.NULL_TYPE)
                    {
                        Debugging.assert(return_value.getTypeString() == _type);
                    }
                    restore();
                    return(return_value);
                }
            }
            Debugging.print("no ReturnValueException thrown. returning NullVar");

            if (_type != StringConstants.Types.AUTO_TYPE)
            {
                Debugging.assert(_type == StringConstants.Types.NULL_TYPE);
            }
            restore();
            return(new NullVar());
        }
예제 #22
0
 /// <summary>
 /// Enter a new variable stack layer.
 /// This is called when entering, for example, a function call
 /// </summary>
 public static void newMainContextScope()
 {
     Debugging.print("new main scope depth from (current): ", getMainScopeDepth());
     addVariableStackLayer(); // defaults are added automatically
     Debugging.print("new main scope depth: " + getMainScopeDepth());
 }
예제 #23
0
        /// <summary>
        /// Applies an arithmetical or logical operation on two <see cref="Variable"/>s
        /// <para/>result = (variable1) op (variable2)
        /// </summary>
        /// <param name="v1"> var 1</param>
        /// <param name="v2"> var 2</param>
        /// <param name="op"> operator (e.g. '+', '-', '&')</param>
        /// <returns> result <see cref="Variable"/></returns>
        /// <exception cref="AquilaExceptions.InvalidTypeError"> Invalid type with this operator</exception>
        /// <exception cref="AquilaExceptions.SyntaxExceptions.SyntaxError"> Unknown operator char</exception>
        private static Variable applyOperator(Variable v1, Variable v2, char op)
        {
            int comparison;

            Debugging.print("applyOperator: ", v1.ToString(), " ", op, " ", v2.ToString(), " (", v1.getTypeString(), " ", op, " ", v2.getTypeString(), ")");
            // Debugging.assert(v1.hasSameParent(v2)); // operations between same classes/subclasses
            if (!v1.hasSameParent(v2))
            {
                if (v2.isConst())
                {
                    if (v2 is Integer)
                    {
                        Debugging.print("Converting int to float because of const status: ", v1.ToString());
                        Debugging.assert(v1 is FloatVar, new AquilaExceptions.InvalidTypeError($"The type \"{v1.getTypeString()}\" was not expected. \"{v1.getTypeString()}\" expected")); // if this is not a float, operation is not permitted !
                        v2 = new FloatVar((float)v2.getValue());
                    }
                }
                else
                {
                    throw new AquilaExceptions.InvalidTypeError($"The type \"{v1.getTypeString()}\" was not expected");
                }
            }
            switch (op)
            {
            // arithmetic
            case '+':
                if (v1 is NumericalValue)
                {
                    return(((NumericalValue)v1).addition((NumericalValue)v2));
                }
                else
                {
                    throw new AquilaExceptions.InvalidTypeError($"Invalid type \"{v1.getTypeString()}\" with operator \"{op}\"");
                }

            case '-':
                if (v1 is NumericalValue)
                {
                    return(((NumericalValue)v1).subtraction((NumericalValue)v2));
                }
                else
                {
                    throw new AquilaExceptions.InvalidTypeError($"Invalid type \"{v1.getTypeString()}\" with operator \"{op}\"");
                }

            case '/':
                if (v1 is NumericalValue)
                {
                    return(((NumericalValue)v1).division((NumericalValue)v2));
                }
                else
                {
                    throw new AquilaExceptions.InvalidTypeError($"Invalid type \"{v1.getTypeString()}\" with operator \"{op}\"");
                }

            case '*':
                if (v1 is NumericalValue)
                {
                    return(((NumericalValue)v1).mult((NumericalValue)v2));
                }
                else
                {
                    throw new AquilaExceptions.InvalidTypeError($"Invalid type \"{v1.getTypeString()}\" with operator \"{op}\"");
                }

            case '%':
                if (v1 is Integer)
                {
                    return(((Integer)v1).modulo((Integer)v2));
                }
                else
                {
                    throw new AquilaExceptions.InvalidTypeError($"Invalid type \"{v1.getTypeString()}\" with operator \"{op}\"");
                }

            // logic
            case '<':
                Debugging.assert(v1 is Integer || v1 is FloatVar);
                comparison = v1 is Integer
                        ? ((Integer)v1).compare(v2 as Integer)
                        : ((FloatVar)v1).compare(v2 as FloatVar);
                return(new BooleanVar(comparison == -1));

            case '>':
                Debugging.assert(v1 is Integer || v1 is FloatVar);
                comparison = v1 is Integer
                        ? ((Integer)v1).compare(v2 as Integer)
                        : ((FloatVar)v1).compare(v2 as FloatVar);
                return(new BooleanVar(comparison == 1));

            case '{':
                Debugging.assert(v1 is Integer || v1 is FloatVar);
                comparison = v1 is Integer
                        ? ((Integer)v1).compare(v2 as Integer)
                        : ((FloatVar)v1).compare(v2 as FloatVar);
                return(new BooleanVar(comparison != 1));

            case '}':
                Debugging.assert(v1 is Integer || v1 is FloatVar);
                comparison = v1 is Integer
                        ? ((Integer)v1).compare(v2 as Integer)
                        : ((FloatVar)v1).compare(v2 as FloatVar);
                return(new BooleanVar(comparison != -1));

            case '~':
                Debugging.assert(v1 is Integer || v1 is FloatVar);
                comparison = v1 is Integer
                        ? ((Integer)v1).compare(v2 as Integer)
                        : ((FloatVar)v1).compare(v2 as FloatVar);
                return(new BooleanVar(comparison == 0));

            case ':':
                Debugging.assert(v1 is Integer || v1 is FloatVar);
                comparison = v1 is Integer
                        ? ((Integer)v1).compare(v2 as Integer)
                        : ((FloatVar)v1).compare(v2 as FloatVar);
                return(new BooleanVar(comparison != 0));

            case '|':
                Debugging.assert(v1 is BooleanVar);
                return(((BooleanVar)v1).or((BooleanVar)v2));

            case '^':
                Debugging.assert(v1 is BooleanVar);
                return(((BooleanVar)v1).xor((BooleanVar)v2));

            case '&':
                Debugging.assert(v1 is BooleanVar);
                return(((BooleanVar)v1).and((BooleanVar)v2));

            default:
                throw new AquilaExceptions.SyntaxExceptions.SyntaxError("Unknown operand " + op);
            }
        }
예제 #24
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));
        }
예제 #25
0
        _variable_stack.Peek().Remove(getCurrentDict());     // last element index

        /// <summary>
        /// Add a new local context scope variable dict.
        /// This is called when entering a nested instruction
        /// </summary>
        public static void newLocalContextScope(Dictionary <string, Variable> vars = null)
        {
            Debugging.print("new local scope depth from (current): ", getLocalScopeDepth());
            addVariableStackElement(vars);
            Debugging.print("new local scope depth: " + getLocalScopeDepth());
        }
예제 #26
0
 public MultiInstruction(Instruction[] instructions)
 {
     _instructions = instructions;
     Debugging.print("num multiple instructions: ", _instructions.Length);
 }
예제 #27
0
        public override void execute()
        {
            setContext();

            // get variable value
            Variable variable_value = _var_expr.evaluate();

            // is the value assigned ? (only relevant if other variable)
            variable_value.assertAssignment();
            Variable variable = Variable.fromRawValue(variable_value.getRawValue());

            // keep track of source vars -> should do something generic for lots of attributes ...
            if (variable is NumericalValue)
            {
                ((NumericalValue)variable).source_vars = new Dictionary <string, NumericalValue>(((NumericalValue)variable_value).source_vars);
            }
            variable.setName(_var_name);
            // explicit typing
            if (_var_type != StringConstants.Types.AUTO_TYPE)
            {
                Debugging.print("checking variable explicit type");
                Expression default_value = Global.default_values_by_var_type[_var_type];
                Debugging.assert(variable_value.hasSameParent(default_value.evaluate()));   // TypeException
            }
            // constant
            if (_constant)
            {
                if (variable_value.isConst())
                {
                    variable.setConst();
                }
                else
                {
                    throw new AquilaExceptions.InvalidVariableClassifierException(
                              "The \"const\" cannot be used when assigning to a non-const value");
                }
            }
            // actually declare it to its value
            if (_global)
            {
                Global.addGlobalVariable(_var_name, variable);
            }
            else
            {
                Global.getCurrentDict()[_var_name] = variable; // overwriting is mandatory
                Debugging.print("variable exists ", Global.variableExistsInCurrentScope(_var_name));
                if (_assignment)
                {
                    variable.assign();              // should not need this, but doing anyway
                }
                else
                {
                    variable.assigned = false;
                }
            }
            Debugging.print("finished declaration with value assignment: ", variable.assigned);

            // automatic tracing ?
            if (_assignment && Global.getSetting("auto trace"))
            {
                Debugging.print("Tracing variable: \"auto trace\" setting set to true");
                // Does NOT work by simply doing "variable.startTracing()", and idk why
                Tracing tracing_instr = new RawInstruction($"trace ${_var_name}", line_index).toInstr() as Tracing;
                //Tracing tracing_instr = new Tracing(line_index, new List<Expression>{_var_expr}); // <- does not work either :(
                tracing_instr.execute();
            }

            // update things 'n stuff
            Global.onElementaryInstruction();

            // reset Context
            Context.reset();
        }