Beispiel #1
0
        public static void Enter()
        {
            do
            {
                AnsiConsole.Write("> ");
                var userInput = Console.ReadLine()
                                .Trim();

                //if the input is a command
                if (userInput.StartsWith("/"))
                {
                    command.Commands.Execute(userInput, "calc");
                    continue;
                }

                //if the input is an assignment
                if (userInput.Contains("="))
                {
                    Variables.Assign(userInput);
                    continue;
                }

                var expression = new Expression(userInput);
                if (expression.IsValid)
                {
                    var value = expression.Solve();
                    if (value is null)
                    {
                        continue;
                    }
                    AnsiConsole.MarkupLine($"[blue]{value}[/]");
                }
            } while (true);
        }
Beispiel #2
0
        /// <summary>
        /// Parse input
        /// </summary>
        /// <param name="input">Console input</param>
        /// <returns>If program is active</returns>
        public static bool Parse(string input)
        {
            input = TranslateCulture(input);
            List <string> lexedValues = Lexer.Split(input);

            if (lexedValues.Count <= 0)
            {
                return(true);
            }

            // handle any exceptions thrown and display them as parse errors
            try
            {
                // check the keyword
                switch (lexedValues[0].ToLower())
                {
                case "let":
                    Variables.Define(lexedValues[1], GetValue(lexedValues, 3));
                    break;

                case "set":
                    Variables.Assign(lexedValues[1], GetValue(lexedValues, 3));
                    break;

                case "calc":
                    Console.WriteLine(GetValue(lexedValues, 1));
                    break;

                case "print":
                    Console.WriteLine(Controllers.Variables.GetValue(lexedValues[1]));
                    break;

                case "rem":
                    Variables.Destroy(lexedValues[1]);
                    break;

                case "exit":
                    return(false);
                }
            }
            catch (Exception ex)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine($"Parse error: {ex.Message}");
                Console.ResetColor();
            }


            return(true);
        }
Beispiel #3
0
        public Evaluator(Parser interpreter)
        {
            p = interpreter;
            interpreter.evaluator = this;

            var includeStatement = new Operation("include")
            {
                canBeGlobal   = true,
                association   = Operation.Association.None,
                unaryFunction = (none) =>
                {
                    List <string> toInclude = new List <string>();
                    p.Eat("l curly");
                    while (p.CurrentToken != "r curly")
                    {
                        toInclude.Add(p.GetIdentifier().ToLower());
                        if (p.CurrentToken != "r curly")
                        {
                            p.Eat("comma");
                        }
                    }
                    p.Eat();

                    /*toInclude.Reverse();
                     *
                     * Lexer.inputText = Lexer.inputText.Substring(Lexer.pointer);
                     * Lexer.pointer = 0;
                     * foreach (var file in toInclude)
                     * {
                     *  Lexer.inputText = System.IO.File.ReadAllText(file + ".hpy") + "\n" + Lexer.inputText;
                     * }
                     *
                     * p.lastLexerPoint = 0;
                     * p.PreviousToken = null;
                     * p.CurrentToken = Lexer.GetNextToken();*/

                    return(Value.VOID);
                }
            };

            var functionDeclaration = new Operation("function")
            {
                canBeGlobal   = true,
                association   = Operation.Association.None,
                unaryFunction = (none) =>
                {
                    if (p.depth > 0)
                    {
                        throw p.Exception("Can only declare a function in the global scope");
                    }

                    if (p.CurrentToken == "inline")
                    {
                        p.Eat();
                    }

                    string name = p.GetIdentifier();

                    List <string>          argNames = new List <string>();
                    List <Value.BatchType> argTypes = new List <Value.BatchType>();

                    p.Eat("l bracket");
                    while (p.CurrentToken != "r bracket")
                    {
                        argNames.Add(p.Eat <string>("identifier"));
                        p.Eat("colon");
                        argTypes.Add(Value.ParseType(p.GetIdentifier()));

                        if (p.CurrentToken != "r bracket")
                        {
                            p.Eat("comma");
                        }
                    }
                    p.Eat();

                    Value.BatchType returnType = Value.BatchType.Void;
                    if (p.CurrentToken == "colon")
                    {
                        p.Eat("colon");
                        returnType = Value.ParseType(p.GetIdentifier());
                    }

                    var func = UserFunctions.Get(name, argTypes);
                    int id   = UserFunctions.GetID(func);

                    Variables.suffix = "_F" + id;

                    int    index          = p.output.Length;
                    string originalOutput = p.output;

                    if (func.inline)
                    {
                        for (int i = 0; i < argNames.Count; i++)
                        {
                            Variables.Create(argNames[i] + "_I" + id, argTypes[i]);
                        }
                    }
                    else
                    {
                        p.Comment("BEGIN FUNCTION DECLARATION: " + UserFunctions.GetSignature(name, argTypes) + ": " + returnType.ToString().ToLower());
                        p.output += ":func_" + id + "\n";
                        for (int i = 0; i < argNames.Count; i++)
                        {
                            Variables.Create(argNames[i], new Value(argTypes[i], "%~" + (i + 1)), 1);
                        }
                    }

                    currentContext = func;

                    p.EvaluateBlock();

                    currentContext = null;

                    if (!func.inline)
                    {
                        if (!p.output.Trim().EndsWith("goto :EOF"))
                        {
                            //Variables.variables.Exists(x => false);
                            Variables.DeleteOutOfScopeVariables();
                            p.output += "goto :EOF\n";
                        }
                    }

                    //p.Comment("END FUNCTION DECLARATION");

                    if (UserFunctions.IsRecursive(func, func))
                    {
                        throw p.Exception("Recursion is forbidden");
                    }

                    Variables.suffix = "";

                    string newOutput = p.output;
                    p.output = originalOutput;
                    string code = newOutput.Substring(index);

                    func.body = code;

                    return(Value.VOID);
                }
            };

            var variableDeclaration = new Operation("var")
            {
                canBeGlobal   = true,
                association   = Operation.Association.None,
                unaryFunction = (none) =>
                {
                    int depth = p.depth;

                    string name;
                    Value  val;

                    if (depth == 0)
                    {
                        if (p.CurrentToken == "global")
                        {
                            p.Eat();
                        }

                        name = p.Eat <string>("identifier");
                        var v = Variables.Get(name);
                        p.Eat("colon");
                        var type = Value.ParseType(p.GetIdentifier());

                        if (p.CurrentToken == "equals")
                        {
                            p.Eat();
                            val = Evaluate();

                            if (type != val.type)
                            {
                                throw p.Exception("Attempt to assign value of type " + val.type + " to a variable of type " + type);
                            }

                            Variables.Assign(name, val);
                        }

                        return(Value.VOID);
                    }

                    if (p.CurrentToken == "global")
                    {
                        p.Eat();
                        depth = 0;
                    }

                    name = p.Eat <string>("identifier");

                    if (Variables.variables.Exists(x => x.name == name))
                    {
                        //throw p.Exception("Variable already exists in this scope: " + name);
                    }

                    if (p.CurrentToken == "colon")
                    {
                        p.Eat();
                        var type = Value.ParseType(p.GetIdentifier());

                        if (Value.TypeEquals(type, Value.BatchType.Void))
                        {
                            throw p.Exception("Cannot declare a variable of type Void");
                        }

                        if (p.CurrentToken != "equals")
                        {
                            Variables.Create(name, type, depth);
                            return(Value.VOID);
                        }

                        p.Eat("equals");
                        val = Evaluate();

                        if (type != val.type)
                        {
                            throw p.Exception("Attempt to assign value of type " + val.type + " to a variable of type " + type);
                        }

                        Variables.Create(name, val, depth);
                    }
                    else
                    {
                        if (depth == 0)
                        {
                            throw p.Exception("Variables in the global scope must have their types specified");
                        }

                        p.Eat("equals");
                        val = Evaluate();

                        if (Value.TypeEquals(val.type, Value.BatchType.Void))
                        {
                            throw p.Exception("Cannot declare a variable of type Void");
                        }

                        if (depth > 0)
                        {
                            Variables.Create(name, val, depth);
                        }
                    }

                    return(Value.VOID);
                }
            };

            var numberLiteral = new Operation("number")
            {
                eatOperator   = false,
                association   = Operation.Association.None,
                unaryFunction = (none) => new Value(Value.BatchType.Int, p.Eat <float>().ToString())
            };

            var stringLiteral = new Operation("string")
            {
                eatOperator   = false,
                association   = Operation.Association.None,
                unaryFunction = (none) => new Value(Value.BatchType.String, p.Eat <string>())
            };

            var boolLiteral = new Operation("bool")
            {
                eatOperator   = false,
                association   = Operation.Association.None,
                unaryFunction = (none) => new Value(Value.BatchType.Bool, p.Eat <bool>() ? "1==1" : "1==0")
            };

            var bracket = new Operation("l bracket")
            {
                association   = Operation.Association.None,
                unaryFunction = (none) => {
                    var outp = Evaluate();
                    p.Eat("r bracket");

                    if (outp.type == Value.BatchType.Int)
                    {
                        return(new Value(Value.BatchType.Int, "(" + outp.value + ")"));
                    }

                    var temp = Variables.CreateTemporary(outp.value);
                    return(new Value(outp.type, temp));
                }
            };

            var neg = new Operation("minus")
            {
                association   = Operation.Association.Right,
                unaryFunction = (right) => new Value(Value.BatchType.Int, "-" + right)
            };

            var mul = new Operation("multiply")
            {
                binaryFunction = (left, right) => binaryOp(left, right, Value.BatchType.Int, "*")
            };

            var div = new Operation("divide")
            {
                binaryFunction = (left, right) => binaryOp(left, right, Value.BatchType.Int, "/")
            };

            var mod = new Operation("modulus")
            {
                binaryFunction = (left, right) => binaryOp(left, right, Value.BatchType.Int, "%%")
            };

            var add = new Operation("plus")
            {
                binaryFunction = (left, right) => binaryOp(left, right, Value.BatchType.Int, "+")
            };

            var concat = new Operation("concat")
            {
                binaryFunction = (left, right) => new Value(Value.BatchType.String, left.value + right.value)
            };

            var sub = new Operation("minus")
            {
                binaryFunction = (left, right) => binaryOp(left, right, Value.BatchType.Int, "-")
            };



            var identifier = new Operation("identifier")
            {
                eatOperator   = false,
                association   = Operation.Association.None,
                unaryFunction = (none) =>
                {
                    string name = p.Eat <string>("identifier").ToString();

                    if (StandardLibrary.Exists(name))
                    {
                        List <Value> args = new List <Value>();
                        p.Eat("l bracket");
                        while (p.CurrentToken != "r bracket")
                        {
                            args.Add(Evaluate());
                            if (p.CurrentToken != "r bracket")
                            {
                                p.Eat("comma");
                            }
                        }
                        p.Eat();
                        return(StandardLibrary.CallFunction(name, args.ToArray()));
                    }
                    else
                    {
                        if (p.CurrentToken == "l bracket")
                        {
                            p.Comment("FUNCTION CALL TO " + name);

                            List <Value> args = new List <Value>();
                            p.Eat("l bracket");
                            while (p.CurrentToken != "r bracket")
                            {
                                args.Add(Evaluate());
                                if (p.CurrentToken != "r bracket")
                                {
                                    p.Eat("comma");
                                }
                            }
                            p.Eat();

                            var func = UserFunctions.Get(name, args.Select(x => x.type).ToList());
                            int id   = UserFunctions.GetID(func);

                            currentContext?.calls.Add(func);

                            if (func.inline)
                            {
                                for (int i = 0; i < func.argumentNames.Count; i++)
                                {
                                    Variables.Create(func.argumentNames[i] + "_I" + id, args[i]);
                                }

                                p.output += func.body;

                                for (int i = 0; i < func.argumentNames.Count; i++)
                                {
                                    Variables.Delete(func.argumentNames[i] + "_I" + id);
                                }
                            }
                            else
                            {
                                p.output += "call :func_" + id + " " +
                                            string.Join(" ", args.Select(x =>
                                                                         (x.type == Value.BatchType.String && x.value.Contains(" ")) ? "\"" + x.value + "\"" : x.value)) + "\n";
                            }

                            if (func.returnType == Value.BatchType.Void)
                            {
                                p.Comment("END FUNCTION CALL");
                                return(Value.VOID);
                            }
                            else
                            {
                                //string temp = Variables.CreateTemporary("%return_value%");
                                p.Comment("END FUNCTION CALL");
                                return(new Value(func.returnType, "%return_value%"));
                            }
                        }

                        if (p.CurrentToken == "increment")
                        {
                            p.Eat();
                            Variables.VerifyType(name, Value.BatchType.Int);
                            var va = Variables.Get(name);
                            p.output += "set /a var_" + name + (va.depth > 0 ? Variables.suffix : "") + "+=1\n";
                            return(Value.VOID);
                        }
                        else if (p.CurrentToken == "decrement")
                        {
                            p.Eat();
                            Variables.VerifyType(name, Value.BatchType.Int);
                            var va = Variables.Get(name);
                            p.output += "set /a var_" + name + (va.depth > 0 ? Variables.suffix : "") + "-=1\n";
                            return(Value.VOID);
                        }
                        else if (p.CurrentToken == "add")
                        {
                            p.Eat();
                            var v  = Evaluate();
                            var va = Variables.Get(name);
                            p.output += "set /a var_" + name + (va.depth > 0 ? Variables.suffix : "") + "+=" + v.value + "\n";
                            return(Value.VOID);
                        }
                        else if (p.CurrentToken == "subtract")
                        {
                            p.Eat();
                            var v  = Evaluate();
                            var va = Variables.Get(name);
                            p.output += "set /a var_" + name + (va.depth > 0 ? Variables.suffix : "") + "-=" + v.value + "\n";
                            return(Value.VOID);
                        }
                        else if (p.CurrentToken == "string add")
                        {
                            p.Eat();
                            var v  = Evaluate();
                            var va = Variables.Get(name);
                            p.output += "set var_" + name + (va.depth > 0 ? Variables.suffix : "") + "=!var_" + name + Variables.suffix + "!" + v.value + "\n";
                            return(Value.VOID);
                        }
                        else if (p.CurrentToken == "inc mul")
                        {
                            p.Eat();
                            var v  = Evaluate();
                            var va = Variables.Get(name);
                            p.output += "set /a var_" + name + (va.depth > 0 ? Variables.suffix : "") + "*=" + v.value + "\n";
                            return(Value.VOID);
                        }
                        else if (p.CurrentToken == "inc div")
                        {
                            p.Eat();
                            var v  = Evaluate();
                            var va = Variables.Get(name);
                            p.output += "set /a var_" + name + (va.depth > 0 ? Variables.suffix : "") + "/=" + v.value + "\n";
                            return(Value.VOID);
                        }
                        else if (p.CurrentToken == "equals")
                        {
                            p.Eat();
                            var v = Evaluate();

                            if (!Variables.Exists(name) && !name.Contains("%"))
                            {
                                throw p.Exception("No such variable exists: " + name);
                            }

                            Variables.Assign(name, v);
                            return(Value.VOID);
                        }
                        else
                        {
                            if (name.Contains("%"))
                            {
                                //var temp1 = Variables.CreateTemporary("var_" + name);
                                //var temp2 = Variables.CreateTemporary("");
                                //var temp2name = Variables.NameFromTempReference(temp2);
                                //p.EmitLn("call set " + temp2name + "=%%" + temp1 + "%%");
                                return(new Value(Value.BatchType.Indeterminate, "!var_" + name + "!"));
                            }
                            else
                            {
                                //return Variables.GetReference(name);
                                if (currentContext != null && currentContext.inline)
                                {
                                    return(Variables.GetReference(name + "_I" + UserFunctions.GetID(currentContext)));
                                }
                                else
                                {
                                    return(Variables.GetReference(name));
                                }
                            }
                            //return Variables.GetReference(name);
                        }
                    }
                }
            };

            var openBracket = new Operation("l curly")
            {
                eatOperator   = false,
                association   = Operation.Association.None,
                unaryFunction = (none) =>
                {
                    p.Eat();
                    return(new Value(Value.BatchType.Void, ""));
                }
            };

            var closeBracket = new Operation("r curly")
            {
                eatOperator   = false,
                association   = Operation.Association.None,
                unaryFunction = (none) =>
                {
                    p.Eat();
                    return(new Value(Value.BatchType.Void, ""));
                }
            };

            var ifStatement = new Operation("if")
            {
                association   = Operation.Association.None,
                unaryFunction = (none) =>
                {
                    int selfid = ++ifid;

                    var condition = EvaluateCondition();

                    string output = "";

                    string temp = Variables.CreateTemporary(condition.value);

                    output += "if " + temp + " (\n";
                    output += "goto if_" + selfid + "\n";
                    output += ")";

                    string ifContents = p.PreEvaluateBlock();

                    List <string> elseIfContents = new List <string>();
                    int           elseifs        = 0;
                    while (p.CurrentToken == "elseif")
                    {
                        elseifs++;
                        p.Eat();
                        condition = EvaluateCondition();
                        temp      = Variables.CreateTemporary(condition.value);

                        output += " else (\nif " + temp + " (\n";
                        output += "goto if_" + selfid + "_elseif_" + elseifs + "\n";
                        output += ")";

                        elseIfContents.Add(p.PreEvaluateBlock());
                    }

                    string elseContents = null;
                    if (p.CurrentToken == "else")
                    {
                        p.Eat();
                        output += " else (\n";
                        output += "goto if_" + selfid + "_else\n";
                        output += ")";

                        elseContents = p.PreEvaluateBlock();
                    }

                    for (int i = 0; i < elseifs; i++)
                    {
                        output += "\n)";
                    }

                    output += "\ngoto if_" + selfid + "_end";

                    output += "\n:if_" + selfid + "\n";
                    output += ifContents;
                    output += "goto if_" + selfid + "_end\n";

                    for (int i = 1; i <= elseifs; i++)
                    {
                        output += ":if_" + selfid + "_elseif_" + i + "\n";
                        output += elseIfContents[i - 1];
                        output += "goto if_" + selfid + "_end\n";
                    }

                    if (elseContents != null)
                    {
                        output += ":if_" + selfid + "_else\n";
                        output += elseContents;
                    }

                    output += ":if_" + selfid + "_end\n";

                    p.output += output;

                    return(new Value(Value.BatchType.Void, ""));
                }
            };

            var whileLoop = new Operation("while")
            {
                association   = Operation.Association.None,
                unaryFunction = (none) =>
                {
                    int loop = ++loopid;

                    p.output += ":loop_" + loop + "\n";

                    var condition = EvaluateCondition();
                    var temp      = Variables.CreateTemporary(condition.value);

                    p.output += "if not " + temp + " goto loop_" + loop + "_end\n";

                    p.loopIDs.Push(loop);

                    p.EvaluateBlock();

                    p.loopIDs.Pop();

                    p.output += "goto loop_" + loop + "\n";
                    p.output += ":loop_" + loop + "_end";

                    return(new Value(Value.BatchType.Void, ""));
                }
            };

            var untilLoop = new Operation("until")
            {
                association   = Operation.Association.None,
                unaryFunction = (none) =>
                {
                    int loop = ++loopid;

                    p.output += ":loop_" + loop + "\n";

                    var condition = EvaluateCondition();
                    var temp      = Variables.CreateTemporary(condition.value);

                    p.output += "if " + temp + " goto loop_" + loop + "_end\n";

                    p.loopIDs.Push(loop);

                    p.EvaluateBlock();

                    p.loopIDs.Pop();

                    p.output += "goto loop_" + loop + "\n";
                    p.output += ":loop_" + loop + "_end";


                    return(new Value(Value.BatchType.Void, ""));
                }
            };

            void VerifyType(Value v, Value.BatchType type)
            {
                if (v.type != type)
                {
                    throw p.Exception("Expected value of type " + type + ", not " + v.type);
                }
            }

            var forLoop = new Operation("from")
            {
                association   = Operation.Association.None,
                unaryFunction = (none) =>
                {
                    var start = Evaluate();
                    VerifyType(start, Value.BatchType.Int);

                    p.Eat("to");
                    var end = Evaluate();
                    VerifyType(end, Value.BatchType.Int);

                    bool upwards;
                    try
                    {
                        upwards = int.Parse(start.value) < int.Parse(end.value);
                    }
                    catch
                    {
                        upwards = true;
                    }

                    Value step;
                    if (p.CurrentToken == "by")
                    {
                        p.Eat();
                        step = Evaluate();
                        VerifyType(step, Value.BatchType.Int);
                    }
                    else
                    {
                        step = new Value(Value.BatchType.Int, upwards ? "1" : "-1");
                    }

                    bool usingVariable = p.CurrentToken == "with";

                    string name      = null;
                    string reference = null;

                    if (usingVariable)
                    {
                        p.Eat();
                        string varname = p.Eat <string>();

                        reference = Variables.Create(varname, start, p.depth).value; // %var_x%
                        name      = "var_" + varname;                                // var_x
                    }
                    else
                    {
                        reference = Variables.CreateTemporaryInt(start.value);  // %temp_x%
                        name      = Variables.NameFromTempReference(reference); // temp_x
                    }

                    int loop = ++loopid;
                    p.output += ":loop" + loop + "\n";

                    p.output += "if not " + reference + " " + (upwards ? "LSS" : "GTR") + " " + end.value + " goto loop" + loop + "_end\n";

                    p.EvaluateBlock();

                    p.loopIDs.Pop();

                    p.output += "set /a " + name + (usingVariable ? Variables.suffix : "") + "+=" + step.value + "\n";
                    p.output += "goto loop" + loop + "\n";
                    p.output += ":loop" + loop + "_end\n";

                    if (usingVariable)
                    {
                        Variables.Delete(Variables.NameFromReference(reference));
                    }

                    return(Value.VOID);
                }
            };

            var continueStatement = new Operation("continue")
            {
                association   = Operation.Association.None,
                unaryFunction = (none) =>
                {
                    return(new Value(Value.BatchType.Void, "goto loop" + p.loopIDs.Peek()));
                }
            };

            var breakStatement = new Operation("break")
            {
                association   = Operation.Association.None,
                unaryFunction = (none) =>
                {
                    return(new Value(Value.BatchType.Void, "goto loop" + p.loopIDs.Peek() + "_end"));
                }
            };

            var not = new Operation("not")
            {
                association   = Operation.Association.Right,
                unaryFunction = (right) => new Value(Value.BatchType.Bool, "not " + right)
            };

            Value BoolOp(Value left, Value right, string op)
            {
                var tempL      = Variables.FlexibleTemporary(left);
                var tempR      = Variables.FlexibleTemporary(right);
                var tempResult = Variables.CreateTemporary("1==0");
                var name       = Variables.NameFromTempReference(tempResult);

                p.EmitLn("if " + tempL + " " + op + " " + tempR + " set " + name + "=1==1");
                return(new Value(Value.BatchType.Bool, tempResult));
            }

            Value IntComparisonOp(Value left, Value right, string op)
            {
                VerifyType(left, Value.BatchType.Int);
                VerifyType(right, Value.BatchType.Int);
                return(BoolOp(left, right, op));
            }

            var eq = new Operation("double equal")
            {
                binaryFunction = (left, right) => BoolOp(left, right, "EQU")
            };

            var neq = new Operation("not equal")
            {
                binaryFunction = (left, right) => BoolOp(left, right, "NEQ")
            };

            var gr = new Operation("greater than")
            {
                binaryFunction = (left, right) => IntComparisonOp(left, right, "GTR")
            };

            var ls = new Operation("less than")
            {
                binaryFunction = (left, right) => IntComparisonOp(left, right, "LSS")
            };

            var geq = new Operation("greater or equal")
            {
                binaryFunction = (left, right) => IntComparisonOp(left, right, "GEQ")
            };

            var leq = new Operation("less or equal")
            {
                binaryFunction = (left, right) => IntComparisonOp(left, right, "LEQ")
            };

            var semicolon = new Operation("semicolon")
            {
                association   = Operation.Association.None,
                unaryFunction = (none) =>
                {
                    return(Value.VOID);
                }
            };

            var and = new Operation("and")
            {
                binaryFunction = (left, right) =>
                {
                    string reference = Variables.CreateTemporary("1==0");
                    string name      = Variables.NameFromTempReference(reference);
                    //p.output += NewTempBoolVar("1==0");
                    //int id = varid;
                    p.output += "if " + left.value + " ( if " + right.value + " ( \n";
                    p.output += "set " + name + "=1==1\n";
                    p.output += ") \n)\n";

                    return(new Value(Value.BatchType.Bool, reference));
                }
            };

            var or = new Operation("or")
            {
                binaryFunction = (left, right) =>
                {
                    string reference = Variables.CreateTemporary("1==0");
                    string name      = Variables.NameFromTempReference(reference);
                    //p.output += NewTempBoolVar("1==1");
                    //int id = varid;
                    p.output += "if " + left.value + " set " + name + "=1==1\n";
                    p.output += "if " + right.value + " set " + name + "=1==1\n";
                    return(new Value(Value.BatchType.Bool, reference));
                }
            };

            /*
             * var arrayLiteral = new Operation("l square")
             * {
             *  association = Operation.Association.None,
             *  unaryFunction = (none) =>
             *  {
             *      string array = "";
             *      while(p.CurrentToken != "r square")
             *      {
             *          array += Evaluate() + " ";
             *
             *          if (p.CurrentToken != "r square")
             *          {
             *              p.Eat("comma");
             *          }
             *      }
             *      p.Eat();
             *
             *      return new Value(Value.BatchType.Array, array.TrimEnd());
             *  }
             * };*/

            var returnStatement = new Operation("return")
            {
                association   = Operation.Association.None,
                unaryFunction = (none) =>
                {
                    if (currentContext == null)
                    {
                        throw p.Exception("Can only return a value from within a function");
                    }

                    Value v;

                    if (p.CurrentToken == "semicolon")
                    {
                        v = Value.VOID;
                    }
                    else
                    {
                        v         = Evaluate();
                        p.output += "set " + (v.type == Value.BatchType.Int ? "/a " : "") + "\"return_value=" + v.value + "\"\n";
                    }

                    if (currentContext.returnType != v.type)
                    {
                        throw p.Exception("Must return value of type " + currentContext.returnType + ", not " + v.type);
                    }

                    //returnValueType = v.type;
                    int depth = p.depth;
                    p.depth = 0;
                    Variables.DeleteOutOfScopeVariables();
                    p.depth = depth;

                    /*foreach (var name in variablesDeclaredInsideFunction)
                     * {
                     *  name.de
                     * }*/

                    return(new Value(Value.BatchType.Void, currentContext.inline ? "" : "goto :EOF"));
                }
            };

            var referenceOf = new Operation("ampersand")
            {
                association   = Operation.Association.None,
                unaryFunction = (none) =>
                {
                    var name = p.GetIdentifier();
                    if (name.Contains("%"))
                    {
                        return(new Value(Value.BatchType.String, name));
                    }

                    var val = Variables.Get(name);
                    return(new Value(Value.BatchType.String, name + (val.depth > 0 ? Variables.suffix : "")));
                }
            };

            var deleteStatement = new Operation("delete")
            {
                association   = Operation.Association.None,
                unaryFunction = (none) =>
                {
                    var var = p.GetIdentifier();
                    Variables.Delete(var, true);
                    return(Value.VOID);
                }
            };

            var asStatement = new Operation("as")
            {
                association   = Operation.Association.Left,
                unaryFunction = (left) =>
                {
                    VerifyType(left, Value.BatchType.Indeterminate);
                    return(new Value(Value.ParseType(p.GetIdentifier()), left.value));
                }
            };

            void register(Operation op)
            {
                precedences.Last().Add(op);
            }

            void precedence()
            {
                precedences.Add(new List <Operation>());
            }

            precedence();
            register(semicolon);

            precedence();
            register(referenceOf);
            //register(toStringLiteral);
            //register(thisLiteral);
            //register(baseLiteral);
            register(bracket);
            //register(undefinedLiteral);
            //register(arrayLiteral);
            register(numberLiteral);
            register(stringLiteral);
            register(boolLiteral);
            //register(tableLiteral);
            //register(charLiteral);
            ////register(instantiation);

            precedence();
            register(identifier);
            //register(methodCall);
            //register(traverse);
            //register(index);

            precedence();
            register(asStatement);

            precedence();
            register(variableDeclaration);

            precedence();
            register(neg);
            register(not);

            //precedence();
            //register(pow);

            precedence();
            register(mul);
            register(div);
            register(mod);

            precedence();
            register(concat);
            register(add);
            register(sub);

            precedence();
            register(eq);
            register(neq);
            register(gr);
            register(ls);
            register(geq);
            register(leq);

            precedence();
            register(and);

            precedence();
            register(or);

            //precedence();
            //register(conditional);

            precedence();
            register(closeBracket);
            register(openBracket);
            register(ifStatement);
            register(whileLoop);
            register(untilLoop);
            //register(includeStatement);
            //register(forEachLoop);
            register(continueStatement);
            register(breakStatement);
            register(functionDeclaration);
            //register(funcLiteral);
            register(returnStatement);
            register(deleteStatement);
            register(forLoop);
            //register(structureLiteral);
            //register(include);
            //register(tryCatch);
            //register(throwStatement);
        }
Beispiel #4
0
        /** <summary>Runs unit tests on the mode calc. To see how the tests work, see <see cref="CalcTest"/>.</summary>
         *
         * <remarks>The function runs two types of tests, normal tests and variables tests (organized into their
         * respectively named regions. Normal tests are normal computations that do not include any variables. Normal
         * tests are run in a loop later down the function. On the other hand, variable tests are run when they are declared.
         * These tests test that variables and constants are working (like throwing an error if the variable has not been
         * defined yet). Variables cannot be freely controlled in loops, so the execution of variable tests occur outside
         * them.</remarks>
         */
        // ReSharper disable once CognitiveComplexity
        public static void Enter()
        {
            #region NORMAL_TESTS

            List <CalcTest> tests = new List <CalcTest>();

            tests.Add(new CalcTest("validation1", "3 *** 5", false, null, false,
                                   new [] { "validation" }));
            tests.Add(new CalcTest("validation2", "10-", false, null, false,
                                   new [] { "validation" }));
            tests.Add(new CalcTest("validation3", "4 * (2 + 3", false, null, false,
                                   new [] { "validation" }));
            tests.Add(new CalcTest("validation4", "4+3)", false, null, false,
                                   new [] { "validation" }));
            tests.Add(new CalcTest("validation5", "123+", false, null, false,
                                   new [] { "validation" }));
            tests.Add(new CalcTest("validation6", "1 23 456 7890", false, null, false,
                                   new [] { "validation" }));
            tests.Add(new CalcTest("validation7", "-100", true, -100, false,
                                   new [] { "validation" }));
            tests.Add(new CalcTest("validation8", "0.00000000000000000000", true, 0, false,
                                   new [] { "validation", "output" }));
            tests.Add(new CalcTest("validation9", "()", false, null, false,
                                   new [] { "validation", "parenthesis", "empty expression" }));
            tests.Add(new CalcTest("validation10", "() + 5", true, -5, false,
                                   new [] { "validation", "parenthesis", "empty expression" }));
            tests.Add(new CalcTest("validation11", "(-4 + ()) + 5", true, 26, true,
                                   new [] { "validation", "parenthesis", "empty expression" }));

            tests.Add(new CalcTest("test1", "3.0 + 3.0", true, 6, false,
                                   new [] { "addition" }));
            tests.Add(new CalcTest("test2", "-3.5 +-+ 2.5", true, -6, false,
                                   new [] { "addition", "decimals" }));
            tests.Add(new CalcTest("test3", "-1987.50 + 1987", true, -0.5, false,
                                   new [] { "addition", "decimals" }));
            tests.Add(new CalcTest("test4", "10 + 9.9999", true, 19.9999, false,
                                   new [] { "addition", "decimals" }));
            tests.Add(new CalcTest("test5", "34.999 + 1.0", true, 35.999, false,
                                   new [] { "addition", "decimals" }));
            tests.Add(new CalcTest("test6", "300000000 + 900000000", true, 1200000000, true,
                                   new [] { "addition", "large numbers" }));

            tests.Add(new CalcTest("test7", " 7.12345678 - 2.21098765", true, 4.91246913, false,
                                   new [] { "subtraction", "decimals" }));
            tests.Add(new CalcTest("test8", " -500 -+-- 12.3456789", true, -512.3456789, false,
                                   new [] { "subtraction", "decimals" }));

            tests.Add(new CalcTest("test9", "1.23456789 *               -2.10987654", true, -2.6047858281483007, true,
                                   new [] { "multiplication", "decimals" }));
            tests.Add(new CalcTest("test10", "123456789 * 210987654", true, 26047858281483010, false,
                                   new [] { "multiplication", "large numbers" }));
            tests.Add(new CalcTest("test11", "-      500    * 123.456789", true, -61728.3945, true,
                                   new [] { "multiplication", "decimals" }));

            tests.Add(new CalcTest("test12", "3 + 8 * ((4 + 3) * 2 + 1) - 6 / (2 + 1)", true, 121, false,
                                   new [] { "addition", "subtraction", "multiplication", "division" }));
            tests.Add(new CalcTest("test13", "-+3+8((4+3)*2+1)-6/(2+1)", true, 115, false,
                                   new [] { "addition", "subtraction", "multiplication", "division" }));
            tests.Add(new CalcTest("test14", "+-2(-3+--4)/2", true, -1, false,
                                   new [] { "addition", "multiplication", "division" }));
            tests.Add(new CalcTest("test15", "8 * 3 + 12 * (4 - 2)", true, 48, true,
                                   new [] { "addition", "multiplication", "division" }));

            #endregion

            /* Variable tests can be executed with different circumstances. Like for example, a variable has not been defined yet,
             * a first test executes and returns an error (since the expression is invalid), then the variable is defined,
             * then the test passes.
             */
            #region VARIABLE_TESTS

            List <CalcTest> variableTests = new List <CalcTest>();

            Variables.Assign("someVariable = 10");
            var test16 = new CalcTest("test16", "someVariable", true, 10, false,
                                      new [] { "variables" });
            test16.Run();

            var test17 = new CalcTest("test17", "pi * e * tau", true, Math.PI * Math.E * Math.Tau, false,
                                      new [] { "constants" });
            test17.Run();

            Variables.Assign("a = 4");
            Variables.Assign("b = 5");
            var test18 = new CalcTest("test18", "a*2+b*3+c*(2+3)", false, null, false,
                                      new [] { "addition", "multiplication", "division", "validation", "variables" });
            test18.Run();
            Variables.Assign("c = 6");
            var test19 = new CalcTest("test19", "a*2+b*3+c*(2+3)", true, 53, false,
                                      new [] { "addition", "multiplication", "division", "variables" });
            test19.Run();
            Variables.Clear();

            Variables.Assign("a=1");
            Variables.Assign("b = a + 1");
            Variables.Assign("c = b + 1");
            var test20 = new CalcTest("test20", "c", true, 3, false,
                                      new [] { "addition", "variables" });
            test20.Run();
            Variables.Assign("a = 2");
            Variables.Assign("b = a + 2");
            var test21 = new CalcTest("test21", "c", true, 5, false,
                                      new [] { "addition", "dynamic variables" });
            test21.Run();
            Variables.Clear();

            variableTests.Add(test16);
            variableTests.Add(test17);
            variableTests.Add(test18);
            variableTests.Add(test19);
            variableTests.Add(test20);
            variableTests.Add(test21);

            #endregion



            var message = "";
            main : do
            {
                Console.Clear();
                AnsiConsole.MarkupLine(message);
                message = "";

                foreach (var test in tests)
                {
                    test.Run();
                    AnsiConsole.MarkupLine($">{test.TestName} :{(test.IsPassed() ? "[green]" : "[red]")}" +
                                           $"{(test.IsPassed() ? "Passed" : "Failed")}[/]:");
                    AnsiConsole.Write(test.AddBreak ? "\n" : "");
                }
                foreach (var test in variableTests)
                {
                    AnsiConsole.MarkupLine($">{test.TestName} :{(test.IsPassed() ? "[green]" : "[red]")}" +
                                           $"{(test.IsPassed() ? "Passed" : "Failed")}[/]:");
                    AnsiConsole.Write(test.AddBreak ? "\n" : "");
                }

                var userInput = Console.ReadLine();
                foreach (var test in tests
                         .Where(test => userInput.Equals(test.TestName)))
                {
                    test.PrintDetails();
                    goto main;
                }
                foreach (var test in variableTests
                         .Where(test => userInput.Equals(test.TestName)))
                {
                    test.PrintDetails();
                    goto main;
                }

                message = "[red]Invalid Input!\nEnter the name of a test to see the test details![/]";
            } while (true);
        }