示例#1
0
        static void HandleStatement(Mizu.Parser.ParseNode stmt, ILGenerator ILgen, ref List<LocalBuilderEx> locals, out bool err)
        {
            switch (stmt.Token.Type)
            {
                case Parser.TokenType.VarStatement:
                    {
                        #region VAR
                        int i = 0;
                        while (i != stmt.Nodes.Count - 1)
                        {
                            var token = stmt.Nodes[i];

                            if (IsDebug)
                            {
                                int sline = 0, scol = 0;

                                FindLineAndCol(code, stmt.Token.StartPos, ref sline, ref scol);

                                int eline = 0, ecol = 0;

                                FindLineAndCol(code, stmt.Token.EndPos, ref eline, ref ecol);

                                ILgen.MarkSequencePoint(doc, sline, scol, eline, ecol);
                            }

                            if (token.Token.Type == TokenType.IDENTIFIER) //If its a var declaration.
                            {
                                if (locals.Find(it => it.Name == token.Token.Text) == null)
                                {
                                    var set = stmt.Nodes[i + 1];
                                    if (set.Token.Type == TokenType.SET)
                                    {
                                        i += 1;
                                        var next = stmt.Nodes[i + 1];
                                        if (next.Token.Type == TokenType.NUMBER) //Integers
                                        {
                                            //Declares a variable and leaves a reference to it.

                                            LocalBuilderEx local = new LocalBuilderEx();
                                            local.VariableType = typeof(int);
                                            local.Base = ILgen.DeclareLocal(local.VariableType);

                                            if (IsDebug) local.Base.SetLocalSymInfo(token.Token.Text); //Set variable name for debug info.

                                            ILgen.Emit(OpCodes.Ldc_I4, int.Parse(next.Token.Text)); //Sets the number
                                            ILgen.Emit(OpCodes.Stloc, (LocalBuilder)local.Base); //Assigns the number to the variable.

                                            local.Name = token.Token.Text;
                                            local.Type = LocalType.Var;

                                            locals.Add(local); //Remembers the variable.
                                            i += 1;
                                        }
                                        else if (next.Token.Type == TokenType.FLOAT)
                                        {
                                            //Declares a variable and leaves a reference to it.

                                            LocalBuilderEx local = new LocalBuilderEx();
                                            local.VariableType = typeof(float);
                                            local.Base = ILgen.DeclareLocal(local.VariableType);

                                            if (IsDebug) local.Base.SetLocalSymInfo(token.Token.Text); //Set variable name for debug info.

                                            ILgen.Emit(OpCodes.Ldc_R4, float.Parse(next.Token.Text)); //Sets the number
                                            ILgen.Emit(OpCodes.Stloc, (LocalBuilder)local.Base); //Assigns the number to the variable.

                                            local.Name = token.Token.Text;
                                            local.Type = LocalType.Var;

                                            locals.Add(local); //Remembers the variable.
                                            i += 1;
                                        }
                                        else if (next.Token.Type == TokenType.UPPER)
                                        {
                                            //A variable that reads from stdin (Console.ReadLne)
                                            //Declares a variable and leaves a reference to it.

                                            LocalBuilderEx local = new LocalBuilderEx();

                                            local.VariableType = typeof(int);

                                            local.Base = ILgen.DeclareLocal(local.VariableType);

                                            local.Name = token.Token.Text;
                                            local.Type = LocalType.Var;

                                            if (IsDebug) local.Base.SetLocalSymInfo(token.Token.Text); //Set variable name for debug info.

                                            try
                                            {
                                                //If theres a WAVEY symbol, print the variable name.
                                                var wavey = stmt.Nodes[i + 2];
                                                ILgen.Emit(OpCodes.Ldstr, local.Name + " = ");
                                                ILgen.Emit(OpCodes.Call, typeof(Console).GetMethod("Write", new Type[] { typeof(string) }));
                                                i += 1;
                                            }
                                            catch (Exception) { }

                                            ILgen.Emit(OpCodes.Call, typeof(Console).GetMethod("ReadLine")); //Sets the number from STDIN.

                                            ILgen.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToInt32", new Type[] { typeof(string) })); //Parses it into an integer.
                                            ILgen.Emit(OpCodes.Stloc, (LocalBuilder)local.Base); //Assigns the number to the variable.

                                            locals.Add(local); //Remembers the variable.
                                            i += 1;
                                        }
                                        else if (next.Token.Type == TokenType.COMMA)
                                        {
                                            //An array.

                                            dynamic info = GetLineAndCol(code, stmt.Token.StartPos);

                                            Console.Error.WriteLine("Error: Static arrays are not supported at this time. Line: {0}, Col: {1}", info.Line, info.Col);
                                            err = true;
                                            return;
                                        }
                                        else
                                        {
                                            #region Iterating Variable
                                            //Its a range
                                            var lowNum = stmt.Nodes[i + 2]; //Name is mis-informing. This is really the first number.
                                            var highNum = stmt.Nodes[i + 5]; //Same ^^, this is the second number.

                                            LocalBuilderEx local = new LocalBuilderEx();

                                            local.LoopHigh = int.Parse(highNum.Token.Text);
                                            local.LoopLow = int.Parse(lowNum.Token.Text);

                                            local.Name = token.Token.Text;
                                            local.Type = LocalType.LoopVar;
                                            local.VariableType = typeof(int);

                                            var looplab = ILgen.DefineLabel();

                                            ILgen.BeginScope();
                                            local.Base = ILgen.DeclareLocal(local.VariableType);

                                            local.LoopLabel = looplab;

                                            if (IsDebug) local.Base.SetLocalSymInfo(token.Token.Text); //Set variable name for debug info.

                                            ILgen.Emit(OpCodes.Ldc_I4, local.LoopLow); //Sets the number
                                            ILgen.Emit(OpCodes.Stloc, (LocalBuilder)local.Base); //Assigns the number to the variable.

                                            ILgen.MarkLabel(looplab);
                                            //this is where the IL will execute.

                                            local.LoopAction = () =>
                                            {

                                                //Updates the iterator by 1
                                                ILgen.Emit(OpCodes.Ldloc, local.Base);
                                                ILgen.Emit(OpCodes.Ldc_I4_1);

                                                if (local.LoopLow < local.LoopHigh)
                                                {
                                                    ILgen.Emit(OpCodes.Add); //Loop up
                                                    local.LoopDirection = LoopDirectionEnum.Up;
                                                }
                                                else if (local.LoopLow > local.LoopHigh)
                                                {
                                                    ILgen.Emit(OpCodes.Sub); //Loop down.
                                                    local.LoopDirection = LoopDirectionEnum.Down;
                                                }
                                                else
                                                {
                                                    dynamic info = GetLineAndCol(code, stmt.Token.StartPos);

                                                    Console.Error.WriteLine("Error: Variable '{0}' should be set as {1}. In this case, looping is not allowed. Line: {2}, Col: {3}", local.Name, local.LoopLow.ToString(), info.Line, info.Col);
                                                    return true; //Abort because of error.
                                                }

                                                ILgen.Emit(OpCodes.Stloc, (LocalBuilder)local.Base);
                                                ILgen.EndScope();
                                                return false;
                                            };

                                            locals.Add(local); //Remembers the variable.

                                            i += 6;
                                            #endregion
                                        }
                                    }
                                }
                                else
                                {
                                    //Report an error and stop compile process.

                                    dynamic info = GetLineAndCol(code, stmt.Token.StartPos);

                                    err = true;
                                    Console.Error.WriteLine("Error: '{0}' already exist! Line: {1}, Col: {2}", token.Token.Text, info.Line, info.Col);
                                    return;
                                }
                            }
                        }
                        break;
                        #endregion
                    }
                case TokenType.PrintStatement:
                    {
                        #region Printing
                        if (IsDebug)
                        {
                            int sline = 0, scol = 0;

                            FindLineAndCol(code, stmt.Token.StartPos, ref sline, ref scol);

                            int eline = 0, ecol = 0;

                            FindLineAndCol(code, stmt.Token.EndPos, ref eline, ref ecol);

                            ILgen.MarkSequencePoint(doc, sline, scol, eline, ecol);
                        }

                        ///Generates output by making a print statement.
                        var period = stmt.Nodes[0];
                        var outpt = stmt.Nodes[1];
                        switch (outpt.Token.Type)
                        {
                            case TokenType.IDENTIFIER:
                                {
                                    //Prints a variable.
                                    LocalBuilderEx local = locals.Find(it => it.Name == outpt.Token.Text);

                                    if (local == null)
                                    {
                                        dynamic info = GetLineAndCol(code, stmt.Token.StartPos);

                                        err = true;
                                        Console.Error.WriteLine("Error: '{0}' doesn't exist! Line: {1}, Col: {2}", outpt.Token.Text, info.Line, info.Col);
                                        return;
                                    }

                                    ILgen.Emit(OpCodes.Ldloc, local.Base);

                                    ILgen.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToString", new Type[] { local.VariableType })); //Converts the integer to a string.

                                    ILgen.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) })); //Prints the newly formed string.
                                    break;
                                }
                            case TokenType.FLOAT:
                            case TokenType.NUMBER:
                                {
                                    //Prints a integer or float (decimal) number.
                                    if (outpt.Token.Type == TokenType.NUMBER) //if its a integer
                                    {
                                        ILgen.Emit(OpCodes.Ldc_I4, int.Parse(outpt.Token.Text));

                                        ILgen.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToString", new Type[] { typeof(int) })); //Converts the integer to a string.
                                    }
                                    else
                                    {
                                        //Otherwise, its a float (decimal).
                                        ILgen.Emit(OpCodes.Ldc_R4, float.Parse(outpt.Token.Text));

                                        ILgen.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToString", new Type[] { typeof(float) })); //Converts the integer to a string.
                                    }

                                    ILgen.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) })); //Prints the newly formed string.
                                    break;
                                }
                            case TokenType.STRING:
                                {
                                    //Prints just a plain string. See the next case for a format string.

                                    string formt = outpt.Token.Text.Substring(1); formt = formt.Remove(formt.Length - 1); //Removes surrounding quotes.

                                    ILgen.Emit(OpCodes.Ldstr, formt); //Loads the string onto the stack

                                    ILgen.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) })); //Prints the newly formed string.
                                    break;
                                }
                            case TokenType.SIN:
                                {

                                    //Prints a format string

                                    ParseNode formtnd = stmt.Nodes[2];

                                    string formt = formtnd.Token.Text.Substring(1); formt = formt.Remove(formt.Length - 1); //Removes surrounding quotes.

                                    ILgen.Emit(OpCodes.Ldstr, formt); //Loads the format string.

                                    int arrymax = (stmt.Nodes.Count / 2 - 1);
                                    ILgen.Emit(OpCodes.Ldc_I4, arrymax);
                                    ILgen.Emit(OpCodes.Newarr, typeof(string));

                                    int arry_i = 0;

                                    for (int i = 3; i < stmt.Nodes.Count; i++)
                                    {
                                        if (stmt.Nodes[i].Token.Type == TokenType.WHITESPACE)
                                        {
                                            if (stmt.Nodes.Count - 1 == i)
                                                break;

                                            continue;
                                        }
                                        else if (stmt.Nodes[i].Token.Type == TokenType.PERIOD)
                                        {
                                            break;
                                        }
                                        else
                                        {
                                            ParseNode nd = stmt.Nodes[i];

                                            ILgen.Emit(OpCodes.Dup);
                                            ILgen.Emit(OpCodes.Ldc_I4, arry_i);

                                            switch (nd.Token.Type)
                                            {
                                                case TokenType.IDENTIFIER:
                                                    {
                                                        LocalBuilderEx local = locals.Find(it => it.Name == nd.Token.Text);

                                                        if (local == null)
                                                        {
                                                            err = true;
                                                            Console.Error.WriteLine("Error: '{0}' doesn't exist!", nd.Token.Text);
                                                            return;
                                                        }

                                                        ILgen.Emit(OpCodes.Ldloc, local.Base);
                                                        ILgen.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToString", new Type[] { typeof(int) }));
                                                        break;
                                                    }
                                                case TokenType.NUMBER:
                                                    {
                                                        ILgen.Emit(OpCodes.Ldc_I4, int.Parse(nd.Token.Text));
                                                        ILgen.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToString", new Type[] { typeof(int) }));
                                                        break;
                                                    }
                                            }

                                            ILgen.Emit(OpCodes.Stelem_Ref);

                                            arry_i += 1;

                                        }
                                    }

                                    ILgen.Emit(OpCodes.Call,
                                        typeof(System.String).GetMethod("Format",
                                            new Type[] { typeof(string), typeof(string[]) }));

                                    ILgen.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) })); //Prints the newly formed string.
                                    break;
                                }
                        }
                        break;
                        #endregion
                    }
                case TokenType.EvalStatement:
                    {
                        #region EvalStatement
                        var identifier = stmt.Nodes[1];
                        var expr = stmt.Nodes[3];

                        LocalBuilderEx local = new LocalBuilderEx();

                        //Check if a variable of the same name exist.
                        LocalBuilderEx lct = locals.Find(it => it.Name == identifier.Token.Text);
                        if (lct != null)
                        {
                            //Variable exist, stop compiling.
                            dynamic info = GetLineAndCol(code, stmt.Token.StartPos);

                            Console.Error.WriteLine("Error: {0} variable already exist! Line: {1}, Col: {2}", identifier.Token.Text, info.Line, info.Col);

                            if (lct.Type == LocalType.LoopVar)
                                Console.Error.WriteLine("- Error: Iterating variables are readonly!");

                            err = true;
                            return;
                        }

                        if (!NoEval)
                        {
                            #region Eval using Mizu.Lib.Evaluator

                            local.VariableType = typeof(int);

                            local.Base = ILgen.DeclareLocal(local.VariableType); //Sets the number

                            var exprstr = "";
                            bool localsadded = false;

                            List<LocalBuilder> tmplocals = new List<LocalBuilder>();

                            foreach (LocalBuilderEx lc in locals)
                            {

                                ILgen.Emit(OpCodes.Ldstr, "var " + lc.Name + "={0}");

                                ILgen.Emit(OpCodes.Ldloc, (LocalBuilder)lc.Base);

                                ILgen.Emit(OpCodes.Call,
                                    typeof(Convert).GetMethod("ToString", new Type[] { typeof(int) }));

                                ILgen.Emit(OpCodes.Call,
                                    typeof(System.String).GetMethod("Format",
                                    new Type[] { typeof(string), typeof(string) }));

                                LocalBuilder lb = ILgen.DeclareLocal(typeof(string));
                                ILgen.Emit(OpCodes.Stloc, lb);

                                tmplocals.Add(lb);

                                localsadded = true;
                            }

                            //Creates an array to store all of the variables for the String.Concat call.
                            int arrymax = (tmplocals.Count * 2) + 1;
                            ILgen.Emit(OpCodes.Ldc_I4, arrymax);
                            ILgen.Emit(OpCodes.Newarr, typeof(string));

                            int arry_i = 0;

                            if (localsadded)
                            {
                                foreach (LocalBuilder tmploc in tmplocals)
                                {
                                    ILgen.Emit(OpCodes.Dup);
                                    ILgen.Emit(OpCodes.Ldc_I4, arry_i);
                                    ILgen.Emit(OpCodes.Ldloc, tmploc);
                                    ILgen.Emit(OpCodes.Stelem_Ref);

                                    arry_i += 1;

                                    ILgen.Emit(OpCodes.Dup);
                                    ILgen.Emit(OpCodes.Ldc_I4, arry_i);
                                    ILgen.Emit(OpCodes.Ldstr, ";");
                                    ILgen.Emit(OpCodes.Stelem_Ref);

                                    arry_i += 1;
                                }
                            }

                            ILgen.Emit(OpCodes.Dup);
                            ILgen.Emit(OpCodes.Ldc_I4, arry_i);

                            exprstr += GenerateExprStr(expr);
                            ILgen.Emit(OpCodes.Ldstr, exprstr);

                            ILgen.Emit(OpCodes.Stelem_Ref);
                            arry_i += 1;

                            ILgen.Emit(OpCodes.Call,
                                typeof(System.String).GetMethod("Concat",
                                         new Type[] { typeof(string[]) }));

                            ILgen.Emit(OpCodes.Call, typeof(Mizu.Lib.Evaluator.Evaluator).GetMethod("Eval"));

                            ILgen.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToInt32", new Type[] { typeof(string) })); //Parses it into an integer.

                            ILgen.Emit(OpCodes.Stloc, (LocalBuilder)local.Base); //Assigns the number to the variable.
                            #endregion
                        }
                        else
                        {
                            if (ExprStrHasVar(expr))
                            {
                                HandleMathExpr(ILgen, locals, expr);

                                local.VariableType = typeof(float);

                                local.Base = ILgen.DeclareLocal(local.VariableType); //Sets the number;
                            }
                            else
                            {
                                //Optimize. If the equation is constant, might as well calculate the result and place it in the code.

                                var res = Mizu.Lib.Evaluator.Evaluator.Eval(GenerateExprStr(expr));

                                if (res.Contains("."))
                                {
                                    local.VariableType = typeof(float);

                                    local.Base = ILgen.DeclareLocal(local.VariableType); //Sets the number

                                    ILgen.Emit(OpCodes.Ldc_R4, float.Parse(res));
                                }
                                else
                                {
                                    local.VariableType = typeof(int);

                                    local.Base = ILgen.DeclareLocal(local.VariableType); //Sets the number

                                    ILgen.Emit(OpCodes.Ldc_I4, int.Parse(res));
                                }
                            }
                            ILgen.Emit(OpCodes.Stloc, (LocalBuilder)local.Base); //Assigns the number to the variable.
                        }

                        if (IsDebug) local.Base.SetLocalSymInfo(identifier.Token.Text);

                        local.Name = identifier.Token.Text;
                        local.Type = LocalType.Var;

                        locals.Add(local); //Remembers the variable.

                        break;
                        #endregion
                    }
                case TokenType.MathCMDStatement:
                    {
                        #region MathCommandStatement
                        var cmd = stmt.Nodes[0];
                        var input = stmt.Nodes[2];
                        var local = locals.Find(it => it.Name == input.Token.Text);
                        if (local != null)
                        {
                            if (IsDebug)
                            {
                                int sline = 0, scol = 0;

                                FindLineAndCol(code, cmd.Token.StartPos, ref sline, ref scol);

                                int eline = 0, ecol = 0;

                                FindLineAndCol(code, cmd.Token.EndPos, ref eline, ref ecol);

                                ILgen.MarkSequencePoint(doc, sline, scol, eline, ecol);

                            }

                            switch (cmd.Token.Type)
                            {
                                case TokenType.SQRT:
                                    {
                                        ILgen.Emit(OpCodes.Ldloca, local.Base);
                                        ILgen.Emit(OpCodes.Call, typeof(Math).GetMethod("Sqrt"));
                                        ILgen.Emit(OpCodes.Stloc, (LocalBuilder)local.Base);
                                        break;
                                    }
                                case TokenType.SIN:
                                    {
                                        ILgen.Emit(OpCodes.Ldloca, local.Base);
                                        ILgen.Emit(OpCodes.Call, typeof(Math).GetMethod("Sin"));
                                        ILgen.Emit(OpCodes.Stloc, (LocalBuilder)local.Base);
                                        break;
                                    }
                                case TokenType.ABS:
                                    {
                                        ILgen.Emit(OpCodes.Ldloca, local.Base);
                                        ILgen.Emit(OpCodes.Call, typeof(Math).GetMethod("Abs", new Type[] { typeof(int) }));
                                        ILgen.Emit(OpCodes.Stloc, (LocalBuilder)local.Base);
                                        break;
                                    }
                                case TokenType.TAN:
                                    {
                                        ILgen.Emit(OpCodes.Ldloca, local.Base);
                                        ILgen.Emit(OpCodes.Call, typeof(Math).GetMethod("Tan"));
                                        ILgen.Emit(OpCodes.Stloc, (LocalBuilder)local.Base);
                                        break;
                                    }
                                case TokenType.COS:
                                    {
                                        ILgen.Emit(OpCodes.Ldloca, local.Base);
                                        ILgen.Emit(OpCodes.Call, typeof(Math).GetMethod("Cos"));
                                        ILgen.Emit(OpCodes.Stloc, (LocalBuilder)local.Base);
                                        break;
                                    }
                            }

                        }
                        else
                        {
                            //Report an error and stop compile process.

                            dynamic info = GetLineAndCol(code, stmt.Token.StartPos);

                            err = true;
                            Console.Error.WriteLine("Error: '{0}' doesn't exist! Line: {1}, Col: {2}", input.Token.Text, info.Line, info.Col);
                            return;
                        }

                        break;
                        #endregion
                    }
                case TokenType.BlockedStatement:
                    {
                        //Due to parser limitations, I have to handle this token in order for both the if blocks and the switch blocks to begin with [.
                        HandleStatement(stmt.Nodes[1], ILgen, ref locals, out err);
                        break;
                    }
                case TokenType.IfStatement: //If block
                    {
                        #region If Statement
                        bool hasElse = false;

                        var left = stmt.Nodes[0];
                        var com = stmt.Nodes[1];
                        var right = stmt.Nodes[2];

                        if (IsDebug)
                        {
                            int sline = 0, scol = 0;

                            FindLineAndCol(code, left.Token.StartPos, ref sline, ref scol);

                            int eline = 0, ecol = 0;

                            FindLineAndCol(code, right.Token.EndPos, ref eline, ref ecol);

                            ILgen.MarkSequencePoint(doc, sline, scol, eline, ecol);
                        }

                        var bodies = stmt.Nodes.FindAll(it => it.Token.Type == TokenType.Statements);

                        hasElse = bodies.Count == 2;

                        //Load the 'left' hand type onto the stack.
                        HandleDataToken(ILgen, locals, left, out err);

                        //Load the 'right' hand type to the stack.
                        HandleDataToken(ILgen, locals, right, out err);

                        //Load the 'comparison' function onto the stack.

                        HandleDataToken(ILgen, locals, com, out err);

                        Label endofifblock = ILgen.DefineLabel();

                        Label ifbodyloc = ILgen.DefineLabel();

                        Label elsebodyloc = ILgen.DefineLabel();

                        if (!hasElse)
                        {
                            //No else block.
                            ILgen.Emit(OpCodes.Brfalse, endofifblock);
                        }
                        else
                        {
                            //Has an else block.

                            //ILgen.Emit(OpCodes.Brtrue, ifbodyloc);
                            //ILgen.Emit(OpCodes.Brtrue, ifbodyloc);
                            ILgen.Emit(OpCodes.Brfalse, elsebodyloc);
                            //ILgen.Emit(OpCodes.Br, ifbodyloc);
                        }

                        // Handle the first body of an if statement.

                        ILgen.MarkLabel(ifbodyloc);
                        ILgen.BeginScope();
                        var ifbody = bodies[0];

                        List<LocalBuilderEx> ifbody_locals = new List<LocalBuilderEx>();
                        locals.ForEach((it) => ifbody_locals.Add(it));

                        foreach (ParseNode pn in ifbody.Nodes)
                        {
                            bool iferr = false;
                            HandleStatement(pn.Nodes[0], ILgen, ref ifbody_locals, out iferr);

                            if (iferr)
                            {
                                err = true;
                                return;
                            }
                        }

                        ILgen.Emit(OpCodes.Br, endofifblock);
                        ILgen.EndScope();

                        //Handle the else bit (if any)
                        if (hasElse)
                        {
                            ILgen.MarkLabel(elsebodyloc);
                            ILgen.BeginScope();

                            var elsebody = bodies[1];

                            List<LocalBuilderEx> elsebody_locals = new List<LocalBuilderEx>();
                            locals.ForEach((it) => elsebody_locals.Add(it));

                            foreach (ParseNode pn in elsebody.Nodes)
                            {
                                bool elerr = false;
                                HandleStatement(pn.Nodes[0], ILgen, ref elsebody_locals, out elerr);

                                if (elerr)
                                {
                                    err = true;
                                    return;
                                }
                            }

                            ILgen.Emit(OpCodes.Br, endofifblock);
                            ILgen.EndScope();

                        }

                        ILgen.MarkLabel(endofifblock);

                        break;
                        #endregion
                    }
                case TokenType.SwitchStatement: //Switch block
                    {
                        #region Switch Statement
                        Label endofswitch = ILgen.DefineLabel();
                        SwitchCaseInfo defaultcase = new SwitchCaseInfo()
                        {
                            Label = ILgen.DefineLabel()
                        };

                        List<SwitchCaseInfo> caselist = new List<SwitchCaseInfo>();

                        bool hasDefault = false;

                        var ident = stmt.Nodes[1];

                        var compar = new Comparison<ParseNode>((node1, node2) =>
                        {
                            try
                            {
                                if (node1 == node2)
                                {
                                    return 0;
                                }
                                else if (node1.Nodes[0].Token.Type == TokenType.NUMBER)
                                {
                                    return -1;
                                }
                                else
                                {
                                    return 1;
                                }
                            }
                            catch (Exception)
                            {
                                return 0;
                            }
                        });

                        var cases = stmt.Nodes.FindAll(it => it.Token.Type == TokenType.SwitchCaseStatement);
                        cases.Sort(compar);

                        var addedcases = new List<int>();

                        if (IsDebug)
                        {
                            int sline = 0, scol = 0;

                            FindLineAndCol(code, ident.Token.StartPos, ref sline, ref scol);

                            int eline = 0, ecol = 0;

                            FindLineAndCol(code, ident.Token.EndPos, ref eline, ref ecol);

                            ILgen.MarkSequencePoint(doc, sline, scol, eline, ecol);
                        }

                        foreach (ParseNode casen in cases)
                        {
                            SwitchCaseInfo caseinfo = new SwitchCaseInfo();

                            var casename = casen.Nodes[0];
                            if (casename.Token.Text == "*")
                            {
                                defaultcase.Node = casen;
                                defaultcase.CaseName = casename;
                                defaultcase.CaseType = SwitchCase_TypeEnum.Default;

                                if (hasDefault == true)
                                {
                                    //Report an error and stop compile process.
                                    err = true;

                                    dynamic info = GetLineAndCol(code, stmt.Token.StartPos);

                                    Console.Error.WriteLine("Error: Switch block already has a default case. Line: {0}, Col: {1}", info.Line, info.Col);
                                    return;
                                }

                                hasDefault = true;
                            }
                            else
                            {
                                caseinfo.Number = int.Parse(casen.Nodes[0].Token.Text);
                                caseinfo.CaseType = SwitchCase_TypeEnum.Number;
                                caseinfo.CaseName = casename;
                                caseinfo.Node = casen;
                                caseinfo.Label = ILgen.DefineLabel();

                                if (addedcases.Contains(caseinfo.Number))
                                {
                                    err = true;

                                    dynamic info = GetLineAndCol(code, stmt.Token.StartPos);

                                    Console.Error.WriteLine("Error: Switch block already has a case for '{0}'. Line: {1}, Col: {2}",caseinfo.Number, info.Line, info.Col);
                                    return;
                                }

                                addedcases.Add(caseinfo.Number);

                                caselist.Add(caseinfo);
                            }
                        }

                        foreach (SwitchCaseInfo cse in caselist)
                        {
                            //Build the instruction table.
                            if (cse.CaseType == SwitchCase_TypeEnum.Number)
                            {
                                HandleDataToken(ILgen, locals, ident, out err); //Load identifier.

                                HandleDataToken(ILgen, locals, cse.CaseName, out err); //Loads the number.

                                ILgen.Emit(OpCodes.Ceq);
                                ILgen.Emit(OpCodes.Brtrue, cse.Label);
                            }
                            else
                            {
                                ILgen.Emit(OpCodes.Br, defaultcase.Label);
                            }
                        }

                        if (hasDefault == false)
                        {
                            //Report an error and stop compile process.
                            err = true;

                            dynamic info = GetLineAndCol(code, stmt.Token.StartPos);

                            Console.Error.WriteLine("Error: Switch block doesn't have a default case. Line: {0}, Col: {1}", info.Line, info.Col);
                            return;
                        }

                        ///Handle default case

                        var dcase = defaultcase.Node;

                        ILgen.BeginScope();

                        List<LocalBuilderEx> d_locals = new List<LocalBuilderEx>();
                        locals.ForEach((it) => d_locals.Add(it));

                        var dstmts = dcase.Nodes.Find(it => it.Token.Type == TokenType.Statements);

                        ILgen.MarkLabel(defaultcase.Label);
                        foreach (ParseNode pn in dstmts.Nodes)
                        {
                            HandleStatement(pn.Nodes[0], ILgen, ref d_locals, out err);
                        }

                        ILgen.EndScope();
                        ILgen.Emit(OpCodes.Br, endofswitch); //Jumps out of switvch at the end of the method.

                        ////

                        foreach (SwitchCaseInfo inner in caselist)
                        {
                            ILgen.BeginScope();

                            List<LocalBuilderEx> tmp_locals = new List<LocalBuilderEx>();
                            locals.ForEach((it) => tmp_locals.Add(it));

                            var stmts = inner.Node.Nodes.Find(it => it.Token.Type == TokenType.Statements);

                            ILgen.MarkLabel(inner.Label);

                            bool ierr = false;

                            foreach (ParseNode pn in stmts.Nodes)
                            {
                                HandleStatement(pn.Nodes[0], ILgen, ref tmp_locals, out ierr);
                            }

                            if (ierr)
                            {
                                err = true;
                                return;
                            }

                            ILgen.EndScope();
                            ILgen.Emit(OpCodes.Br, endofswitch); //Jumps out of switvch at the end of the method.
                        }

                        ILgen.MarkLabel(endofswitch);
                        break;
                        #endregion
                    }
                default:
                    {
                        //Report an error and stop compile process.
                        err = true;

                        dynamic info = GetLineAndCol(code, stmt.Token.StartPos);

                        Console.Error.WriteLine("Error: Unsupported statement: {0}. Line: {1}, Col: {2}", stmt.Text, info.Line, info.Col);
                        return;
                    }
            }
            err = false;
        }
示例#2
0
        static bool Compile(Mizu.Parser.ParseTree tree, FileInfo input, FileInfo output)
        {
            var start = tree.Nodes[0];
            var statements = start.Nodes[0];

            //Declares the assembly and the entypoint
            var name = new AssemblyName(output.Name.Replace(output.Extension,""));
            AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly(name,AssemblyBuilderAccess.Save,output.DirectoryName);

            if (IsDebug)
            {
                //Make assembly debug-able.
                Type debugattr = typeof(DebuggableAttribute);
                ConstructorInfo db_const = debugattr.GetConstructor(new Type[] { typeof(DebuggableAttribute.DebuggingModes) });
                CustomAttributeBuilder db_builder = new CustomAttributeBuilder(db_const, new object[] {
            DebuggableAttribute.DebuggingModes.DisableOptimizations |
            DebuggableAttribute.DebuggingModes.Default });

                ab.SetCustomAttribute(db_builder);
            }

            //Defines main module.
            ModuleBuilder mb = ab.DefineDynamicModule(name.Name, name.Name + ".exe", IsDebug);

            if (IsDebug)
            {
                //Define the source code file.
                doc = mb.DefineDocument(input.FullName, Guid.Empty, Guid.Empty, Guid.Empty);
            }

            TypeBuilder tb = mb.DefineType("App"); //Defines main type.

            MethodBuilder entrypoint = tb.DefineMethod("Main", MethodAttributes.Public | MethodAttributes.Static); //Makes the main method.

            var ILgen = entrypoint.GetILGenerator(3072); //gets the IL generator

            List<LocalBuilderEx> locals = new List<LocalBuilderEx>(); //A list to hold variables.

            ILgen.BeginExceptionBlock(); //Start a try statement.

            ILgen.BeginScope();

            // Generate body IL
            bool err = false;
            foreach (Mizu.Parser.ParseNode statement in statements.Nodes)
            {
                //Iterate though the statements, generating IL.
                var basestmt = statement.Nodes[0];
                HandleStatement(basestmt, ILgen, ref locals, out err);
                if (err == true)
                {
                    return false;
                }
            }
            var loops = locals.FindAll(it => it.Type == LocalType.LoopVar);
            if (loops.Count > 0)
            {
                int i = loops.Count -1;
                while(i != -1) //Iterates through any loops backwards, closing all of the opened loops.
                {
                    var lastloop = loops[i];
                    if (lastloop != null)
                    {

                        if (lastloop.LoopAction()) //Calls actions to be called after all of the statements.
                            return false; //An error has occurred. Abort.

                        //Checks if the current iterator is equal to the higher number.
                        ILgen.Emit(OpCodes.Ldloc, lastloop.Base.LocalIndex);

                        if (lastloop.LoopDirection == LoopDirectionEnum.Up)
                        {
                            ILgen.Emit(OpCodes.Ldc_I4, lastloop.LoopHigh);
                            ILgen.Emit(OpCodes.Clt);
                        }
                        else
                        {
                            ILgen.Emit(OpCodes.Ldc_I4, lastloop.LoopHigh);
                            ILgen.Emit(OpCodes.Cgt);
                        }
                        ILgen.Emit(OpCodes.Brtrue, lastloop.LoopLabel);

                    }
                    i -= 1;
                }
            }

            ILgen.EndScope();

            ILgen.BeginCatchBlock(typeof(Exception)); //Ends the try statement and starts the catch section.

            if (!IsDebug)
            {
                //If its not a debug build, add code to print out the error safely.

                /*LocalBuilder ex = ILgen.DeclareLocal(typeof(Exception));

                ILgen.Emit(OpCodes.Stloc,ex);

                ILgen.Emit(OpCodes.Ldloc, ex); */

                //ILgen.Emit(OpCodes.Box, typeof(Exception));

                ILgen.Emit(OpCodes.Callvirt, typeof(Exception).GetMethod("ToString"));

                ILgen.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
            }
            else
            {
                ILgen.Emit(OpCodes.Rethrow);
            }

            ILgen.EndExceptionBlock();  //Ends the catch section.

            if (!IsInvalid) ILgen.Emit(OpCodes.Ret); //Finishes the statement by calling return. If a invalid exe is wanted, it omits this statement.

            ab.SetEntryPoint(entrypoint, PEFileKinds.ConsoleApplication); //Sets entry point

            Type finishedtype = tb.CreateType(); //Compile the type

            ab.Save(output.Name); //Save

            return true; //Compilation process completed successfully.
        }