コード例 #1
0
ファイル: Compiler.cs プロジェクト: blueOkiris/snake-script
        // <program> ::= { <func-def> | <stmt> }
        public static (OpCode[], Function[]) Translate(CompoundToken ast)
        {
            var opCodes = new List <OpCode>();
            var funcs   = new List <Function>();

            var children = ast.Children;

            foreach (var child in children)
            {
                switch (child.Type)
                {
                case TokenType.FuncDef:
                    funcs.Add(compileFunc(child as CompoundToken));
                    break;

                case TokenType.Stmt:
                    var stmtOpCodes = compileStmt(child as CompoundToken);
                    foreach (var opCode in stmtOpCodes)
                    {
                        opCodes.Add(opCode);
                    }
                    break;
                }
            }
            return(opCodes.ToArray(), funcs.ToArray());
        }
コード例 #2
0
        public CompoundToken(TokenType type, Token[] children) : base(type)
        {
            // Make sure we make COPIES of children, not just add their refs
            var childs = new List <Token>();

            foreach (var child in children)
            {
                Token childCopy;

                if (child is SymbolToken)
                {
                    childCopy = new SymbolToken(
                        child.Type,
                        (child as SymbolToken).Source,
                        (child as SymbolToken).Line, (child as SymbolToken).Pos
                        );
                }
                else if (child is CompoundToken)
                {
                    childCopy = new CompoundToken(
                        child.Type, (child as CompoundToken).Children
                        );
                }
                else
                {
                    childCopy = new Token(child.Type);
                }
                childs.Add(childCopy);
            }
            Children = childs.ToArray();
        }
コード例 #3
0
        // <while> ::= <while-op> <body>
        private static OpCode[] compileWhile(CompoundToken wh)
        {
            var opCodes = new List <OpCode>();

            opCodes.Add(new OpCode(Instruction.WhileStart, "WH_" + WhileInd));
            var body = wh.Children[1] as CompoundToken;

            for (int i = 1; i < body.Children.Length - 1; i++)
            {
                var stmtCodes = compileStmt(body.Children[i] as CompoundToken);
                foreach (var opCode in stmtCodes)
                {
                    opCodes.Add(opCode);
                }
            }
            opCodes.Add(new OpCode(Instruction.WhileEnd, "EW_" + WhileInd));
            WhileInd++;

            return(opCodes.ToArray());
        }
コード例 #4
0
        private string toString(CompoundToken token, int tabInd = -1)
        {
            var tokenStr = new StringBuilder();

            if (token.Type == TokenType.Program)
            {
                tokenStr.Append("Program:\n");
            }
            else
            {
                for (int i = 0; i < tabInd; i++)
                {
                    tokenStr.Append("|--");
                }
                tokenStr.Append(token.Type);
                tokenStr.Append('\n');
            }
            foreach (var child in token.Children)
            {
                if (!(child is CompoundToken))
                {
                    for (int i = 0; i < tabInd + 1; i++)
                    {
                        tokenStr.Append("|--");
                    }
                    tokenStr.Append(child.ToString());
                    tokenStr.Append('\n');
                }
                else
                {
                    tokenStr.Append(
                        toString(child as CompoundToken, tabInd + 1)
                        );
                }
            }
            return(tokenStr.ToString());
        }
コード例 #5
0
ファイル: Compiler.cs プロジェクト: blueOkiris/snake-script
        // <func-def> ::= <func-op> <ident> <type-op> <type>
        //                                          <bool-op> <type> <body>
        private static Function compileFunc(CompoundToken funcDef)
        {
            var ident      = funcDef.Children[1] as SymbolToken;
            var typeTok    = funcDef.Children[3] as CompoundToken;
            var retTypeTok = funcDef.Children[5] as CompoundToken;
            var body       = funcDef.Children[6] as CompoundToken;

            // <body> ::= <l-brace> { <stmt> } <r-brace>
            var opCodes = new List <OpCode>();

            for (int i = 1; i < body.Children.Length - 1; i++)
            {
                var stmtCodes = compileStmt(body.Children[i] as CompoundToken);
                foreach (var opCode in stmtCodes)
                {
                    opCodes.Add(opCode);
                }
            }

            var type    = toVmValueType(typeTok);
            var retType = toVmValueType(retTypeTok);

            return(new Function(ident.Source, type, retType, opCodes.ToArray()));
        }
コード例 #6
0
        static void Main(string[] args)
        {
            if (args.Length < 1)
            {
                Console.WriteLine("No input file provided");
                Environment.Exit(-1);
            }
            else
            {
                var debug    = false;
                var fileName = args[0];

                foreach (var arg in args)
                {
                    if (arg == args[0])
                    {
                        continue;
                    }

                    if (arg == "--debug")
                    {
                        debug = true;
                    }
                    else
                    {
                        Console.WriteLine("Unexpected argument: '" + arg + "'");
                        Environment.Exit(-1);
                    }
                }

                // File name is actually a MODULE DIRECTORY
                if (Directory.Exists(fileName))
                {
                    fileName += "/main.snake";
                }

                var code = "";
                try {
                    code = File.ReadAllText(fileName);
                } catch (Exception e) {
                    Console.WriteLine("Error reading file: '" + fileName + "'");
                    Console.WriteLine(e.Message);
                    Environment.Exit(-1);
                }

                var deSnakedCode = "";
                try {
                    deSnakedCode = Lexer.DeSnakeCode(code);
                } catch (Exception e) {
                    Console.WriteLine("Desnaking Error: " + e.Message);
                    Environment.Exit(-1);
                }
                var tokens = Lexer.Tokens(deSnakedCode);
                if (debug)
                {
                    Console.WriteLine("Desnaked code:");
                    Console.WriteLine(deSnakedCode);
                    Console.WriteLine();
                    Console.WriteLine("Lexer Output:");
                    foreach (var token in tokens)
                    {
                        Console.WriteLine(token);
                    }
                }

                CompoundToken ast = null;
                try {
                    ast = Parser.BuildProgram(tokens);
                } catch (ParserException pe) {
                    Console.WriteLine("Parser Error: " + pe.Message);
                    Environment.Exit(-1);
                }
                if (debug && ast != null)
                {
                    Console.WriteLine();
                    Console.WriteLine("Parser Output:");
                    Console.WriteLine(ast);
                }

                var insts = Compiler.Translate(ast);
                if (debug)
                {
                    Console.WriteLine(Compiler.OutputString(insts));
                }
                var vm = new VirtualMachine(insts.Item1, insts.Item2, debug);

                try {
                    Directory.SetCurrentDirectory(
                        Path.GetDirectoryName(fileName)
                        );
                    vm.Run();
                } catch (Exception e) {
                    Console.WriteLine("Runtime Error: " + e.Message);
                    Environment.Exit(-1);
                }
            }
        }
コード例 #7
0
        // <value> ::= <ident> | <char> | <num> | <bool>
        //              | <str> | <list> | <tuple>
        // <list> ::= <l-bracket> { <value> } <r-bracket>
        // <tuple> ::= <l-parenth> <value> <value> <r-parenth>
        public static OpCode[] CompileValue(CompoundToken value)
        {
            var opCodes = new List <OpCode>();

            OpCode[] tempArr;
            Token    subChild = value.Children[0];

            switch (subChild.Type)
            {
            case TokenType.Num:
                opCodes.Add(
                    new OpCode(
                        Instruction.PushNum,
                        (subChild as SymbolToken).Source
                        )
                    );
                break;

            case TokenType.Char:
                opCodes.Add(
                    new OpCode(
                        Instruction.PushChar,
                        (subChild as SymbolToken).Source
                        )
                    );
                break;

            case TokenType.Bool:
                opCodes.Add(
                    new OpCode(
                        Instruction.PushBool,
                        (subChild as SymbolToken).Source
                        )
                    );
                break;

            case TokenType.Ident:
                opCodes.Add(
                    new OpCode(
                        Instruction.PushIdent,
                        (subChild as SymbolToken).Source
                        )
                    );
                break;

            case TokenType.Str:
                for (int i = (subChild as SymbolToken).Source.Length - 2;
                     i >= 1; i--)
                {
                    if ((subChild as SymbolToken).Source[i - 1] == '\\')
                    {
                        opCodes.Add(
                            new OpCode(
                                Instruction.PushChar,
                                "'\\" + (subChild as SymbolToken).Source[i]
                                + "'"
                                )
                            );
                        i--;
                    }
                    else
                    {
                        opCodes.Add(
                            new OpCode(
                                Instruction.PushChar,
                                "'" + (subChild as SymbolToken).Source[i]
                                + "'"
                                )
                            );
                    }
                }
                opCodes.Add(
                    new OpCode(Instruction.PopItemsOfSameTypePushList)
                    );
                break;

            case TokenType.List:
                for (
                    int i =
                        (subChild as CompoundToken).Children.Length - 2;
                    i >= 1; i--)
                {
                    tempArr = CompileValue(
                        (subChild as CompoundToken).Children[i]
                        as CompoundToken
                        );
                    foreach (var opCode in tempArr)
                    {
                        opCodes.Add(opCode);
                    }
                }
                opCodes.Add(
                    new OpCode(Instruction.PopItemsOfSameTypePushList)
                    );
                break;

            case TokenType.Tuple:
                tempArr = CompileValue(
                    (subChild as CompoundToken).Children[2]
                    as CompoundToken
                    );
                foreach (var opCode in tempArr)
                {
                    opCodes.Add(opCode);
                }
                tempArr = CompileValue(
                    (subChild as CompoundToken).Children[1]
                    as CompoundToken
                    );
                foreach (var opCode in tempArr)
                {
                    opCodes.Add(opCode);
                }
                opCodes.Add(new OpCode(Instruction.Pop2PushTuple));
                break;
            }

            return(opCodes.ToArray());
        }
コード例 #8
0
        // <type-name> ::= <raw-type-name> | <l-bracket> <type-name> <r-bracket>
        //                  | <l-parenth> <type-name> <type-name> <r-parenth>
        // <raw-type-name> ::= /([#@])|(\?\?)/
        // <tuple> ::= <l-parenth> <value> <value> <r-parenth>
        // <list> ::= <l-bracket> { <value> } <r-bracket>
        private static VmValueType[] toVmValueType(CompoundToken typeTok)
        {
            if (typeTok.Children.Length == 1)
            {
                return(valueTypeFromStr(typeTok.Children[0] as SymbolToken));
            }
            else if (typeTok.Children[0].Type == TokenType.LParenth)
            {
                var types = new List <VmValueType>();
                types.Add(VmValueType.Tup);

                VmValueType[] item1Types, item2Types;
                if (typeTok.Children[1] is SymbolToken)
                {
                    item1Types = valueTypeFromStr(
                        typeTok.Children[1] as SymbolToken
                        );
                }
                else
                {
                    item1Types = toVmValueType(
                        typeTok.Children[1] as CompoundToken
                        );
                }
                if (typeTok.Children[2] is SymbolToken)
                {
                    item2Types = valueTypeFromStr(
                        typeTok.Children[2] as SymbolToken
                        );
                }
                else
                {
                    item2Types = toVmValueType(
                        typeTok.Children[2] as CompoundToken
                        );
                }

                foreach (var type in item1Types)
                {
                    types.Add(type);
                }
                types.Add(VmValueType.UndDef);
                foreach (var type in item2Types)
                {
                    types.Add(type);
                }

                return(types.ToArray());
            }
            else if (typeTok.Children[0].Type == TokenType.LBracket)
            {
                var types = new List <VmValueType>();
                types.Add(VmValueType.Ls);

                VmValueType[] subTypes;
                if (typeTok.Children[1] is SymbolToken)
                {
                    subTypes = valueTypeFromStr(
                        typeTok.Children[1] as SymbolToken
                        );
                }
                else
                {
                    subTypes = toVmValueType(
                        typeTok.Children[1] as CompoundToken
                        );
                }

                foreach (var type in subTypes)
                {
                    types.Add(type);
                }

                return(types.ToArray());
            }

            return(new VmValueType[] { VmValueType.UndDef });
        }
コード例 #9
0
        // <op> ::= <stack-op> | <math-op> | <bool-op> | <ls-tp-op>
        private static OpCode[] compileOp(CompoundToken op)
        {
            var opCodes = new List <OpCode>();

            switch (op.Children[0].Type)
            {
            case TokenType.AsgnOp:
                opCodes.Add(new OpCode(Instruction.SetVar));
                break;

            case TokenType.IoOp:
                switch ((op.Children[0] as SymbolToken).Source)
                {
                case ".":
                    opCodes.Add(new OpCode(Instruction.Print));
                    break;

                case ",":
                    opCodes.Add(new OpCode(Instruction.Input));
                    break;
                }
                break;

            case TokenType.FileIoOp:
                switch ((op.Children[0] as SymbolToken).Source)
                {
                case "..":
                    opCodes.Add(new OpCode(Instruction.WriteFile));
                    break;

                case ",,":
                    opCodes.Add(new OpCode(Instruction.ReadFile));
                    break;
                }
                break;

            case TokenType.RoundOp:
                opCodes.Add(new OpCode(Instruction.Round));
                break;

            case TokenType.StackOp:
                switch ((op.Children[0] as SymbolToken).Source)
                {
                case ">>":
                    opCodes.Add(new OpCode(Instruction.Pop));
                    break;

                case "><":
                    opCodes.Add(new OpCode(Instruction.Duplicate));
                    break;

                case "<>":
                    opCodes.Add(new OpCode(Instruction.Swap));
                    break;
                }
                break;

            case TokenType.MathOp:
                switch ((op.Children[0] as SymbolToken).Source)
                {
                case "+":
                    opCodes.Add(new OpCode(Instruction.Pop2PushSum));
                    break;

                case "-":
                    opCodes.Add(
                        new OpCode(Instruction.Pop2PushDifference)
                        );
                    break;

                case "*":
                    opCodes.Add(
                        new OpCode(Instruction.Pop2PushProduct)
                        );
                    break;

                case "^":
                    opCodes.Add(new OpCode(Instruction.Pop2PushPower));
                    break;
                }
                break;

            case TokenType.BoolOp:
                switch ((op.Children[0] as SymbolToken).Source)
                {
                case "?=":
                    opCodes.Add(new OpCode(Instruction.Pop2PushEqual));
                    break;

                case "?>":
                    opCodes.Add(
                        new OpCode(Instruction.Pop2PushGreaterThan)
                        );
                    break;

                case "?<":
                    opCodes.Add(
                        new OpCode(Instruction.Pop2PushLessThan)
                        );
                    break;

                case "?!":
                    opCodes.Add(new OpCode(Instruction.Pop1PushNot));
                    break;

                case "?&":
                    opCodes.Add(new OpCode(Instruction.Pop2PushAnd));
                    break;

                case "?|":
                    opCodes.Add(new OpCode(Instruction.Pop2PushOr));
                    break;
                }
                break;

            case TokenType.ListTupleOp:
                switch ((op.Children[0] as SymbolToken).Source)
                {
                case "++":
                    opCodes.Add(new OpCode(Instruction.Pop2PushConcat));
                    break;

                case "--":
                    opCodes.Add(
                        new OpCode(Instruction.Pop2PushWithRemovedInd)
                        );
                    break;

                case "@@":
                    opCodes.Add(
                        new OpCode(
                            Instruction.Pop2PushListPushListAtInd
                            )
                        );
                    break;

                case "[]":
                    opCodes.Add(
                        new OpCode(
                            Instruction.PopItemsOfSameTypePushList
                            )
                        );
                    break;

                case "][":
                    opCodes.Add(
                        new OpCode(Instruction.PopListPushUnzipped)
                        );
                    break;
                }
                break;
            }

            return(opCodes.ToArray());
        }
コード例 #10
0
ファイル: Compiler.cs プロジェクト: blueOkiris/snake-script
        // <stmt> ::= <op> | <while> | <func-call> | <return> | <value>
        //          | <to-str> | <to-chr> | <mk-tup> | <parse-str> | <to-bool>
        private static OpCode[] compileStmt(CompoundToken stmt)
        {
            var opCodes = new List <OpCode>();

            OpCode[] tempArr;

            foreach (var child in stmt.Children)
            {
                switch (child.Type)
                {
                case TokenType.Op:
                    tempArr = compileOp(child as CompoundToken);
                    foreach (var opCode in tempArr)
                    {
                        opCodes.Add(opCode);
                    }
                    break;

                case TokenType.While:
                    tempArr = compileWhile(child as CompoundToken);
                    foreach (var opCode in tempArr)
                    {
                        opCodes.Add(opCode);
                    }
                    break;

                // <func-call> ::= <l-parenth> <ident> <r-parenth>
                case TokenType.FuncCall:
                    opCodes.Add(
                        new OpCode(
                            Instruction.FuncCall,
                            ((child as CompoundToken)
                             .Children[1] as SymbolToken).Source
                            )
                        );
                    break;

                case TokenType.Return:
                    opCodes.Add(new OpCode(Instruction.Return));
                    break;

                case TokenType.Value:
                    tempArr = CompileValue(child as CompoundToken);
                    foreach (var opCode in tempArr)
                    {
                        opCodes.Add(opCode);
                    }
                    break;

                case TokenType.ToStr:
                    opCodes.Add(new OpCode(Instruction.PopAnyPushStr));
                    break;

                case TokenType.ToChr:
                    opCodes.Add(new OpCode(Instruction.PopNumPushChr));
                    break;

                case TokenType.ToBool:
                    opCodes.Add(new OpCode(Instruction.PopNumChrPushBool));
                    break;

                case TokenType.MakeTuple:
                    opCodes.Add(new OpCode(Instruction.Pop2PushTuple));
                    break;

                case TokenType.ParseStr:
                    opCodes.Add(new OpCode(Instruction.PopStrPushAny));
                    break;
                }
            }

            return(opCodes.ToArray());
        }
コード例 #11
0
        private void execute(OpCode opCode, ref VmStackFrame stackFrame)
        {
            var localStack = stackFrame.LocalStack;
            var varLookup  = stackFrame.CurrentVariables;

            if (Debug)
            {
                //Console.WriteLine("Curr Inst: " + opCode);
            }
            switch (opCode.Inst)
            {
            case Instruction.Pop: {
                if (localStack.Count < 1)
                {
                    throw new StackUnderflowException();
                }
                localStack.Pop();
            }
            break;

            case Instruction.Duplicate: {
                if (localStack.Count < 1)
                {
                    throw new StackUnderflowException();
                }
                localStack.Push(localStack.Peek());
            }
            break;

            case Instruction.Swap: {
                if (localStack.Count < 2)
                {
                    throw new StackUnderflowException();
                }
                var tos = localStack.Pop();
                var sos = localStack.Pop();
                localStack.Push(tos);
                localStack.Push(sos);
            }
            break;

            case Instruction.SetVar: {
                if (localStack.Count < 2)
                {
                    throw new StackUnderflowException();
                }
                var tos = localStack.Pop();
                var sos = localStack.Pop();
                if (!(tos is VmVar))
                {
                    throw new TypeException(
                              new VmValueType[] { VmValueType.Var },
                              tos.Types
                              );
                }

                if (varLookup.ContainsKey((tos as VmVar).Name))
                {
                    if (varLookup[(tos as VmVar).Name].Types[0]
                        != VmValueType.UndDef)
                    {
                        if (!VmValue.ShareType(
                                (tos as VmVar).Value, sos))
                        {
                            throw new TypeException(
                                      (tos as VmVar).Value.Types,
                                      tos.Types
                                      );
                        }

                        varLookup[(tos as VmVar).Name].Value = sos;
                    }
                    else
                    {
                        var types = new List <VmValueType>();
                        types.Add(VmValueType.Var);
                        foreach (var type in sos.Types)
                        {
                            types.Add(type);
                        }
                        varLookup[(tos as VmVar).Name].Value = sos;
                        varLookup[(tos as VmVar).Name].Types =
                            types.ToArray();
                    }
                }
            }
            break;

            case Instruction.Input: {
                var input = Console.ReadLine();
                if (input != "")
                {
                    var chars = new List <VmValue>();
                    for (int i = 0; i < input.Length; i++)
                    {
                        chars.Add(new VmChar(input[i]));
                    }
                    localStack.Push(new VmList(chars[0].Types, chars));
                }
            }
            break;

            case Instruction.Print: {
                if (localStack.Count < 1)
                {
                    throw new StackUnderflowException();
                }
                var tos = localStack.Pop();
                Console.Write(tos.ToString());
            }
            break;

            case Instruction.ReadFile: {
                if (localStack.Count < 1)
                {
                    throw new StackUnderflowException();
                }
                var tos = localStack.Pop();
                if (!(tos is VmList) ||
                    (tos as VmList).Types[1] != VmValueType.Chr
                    )
                {
                    throw new TypeException(
                              new VmValueType[] {
                            VmValueType.Ls, VmValueType.Chr
                        },
                              tos.Types
                              );
                }
                var input = File.ReadAllText(tos.ToString());
                var chars = new List <VmValue>();
                for (int i = 0; i < input.Length; i++)
                {
                    chars.Add(new VmChar(input[i]));
                }
                localStack.Push(new VmList(chars[0].Types, chars));
            }
            break;

            case Instruction.WriteFile: {
                if (localStack.Count < 2)
                {
                    throw new StackUnderflowException();
                }
                var tos = localStack.Pop();
                var sos = localStack.Pop();
                if (!(sos is VmList) ||
                    (sos as VmList).Types[1] != VmValueType.Chr
                    )
                {
                    throw new TypeException(
                              new VmValueType[] {
                            VmValueType.Ls, VmValueType.Chr
                        },
                              sos.Types
                              );
                }
                File.WriteAllText(sos.ToString(), tos.ToString());
            }
            break;

            case Instruction.Round: {
                if (localStack.Count < 1)
                {
                    throw new StackUnderflowException();
                }
                var tos = localStack.Pop();
                if (!VmValue.ShareType(tos, new VmNum(0)))
                {
                    throw new TypeException(
                              tos.Types, (new VmNum(0)).Types
                              );
                }

                localStack.Push(
                    new VmNum(Math.Round((tos as VmNum).Value))
                    );
            }
            break;

            case Instruction.Pop2PushSum: {
                if (localStack.Count < 2)
                {
                    throw new StackUnderflowException();
                }
                var tos = localStack.Pop();
                var sos = localStack.Pop();
                if (!VmValue.ShareType(tos, new VmNum(0)))
                {
                    throw new TypeException(
                              tos.Types, (new VmNum(0)).Types
                              );
                }
                if (!VmValue.ShareType(sos, new VmNum(0)))
                {
                    throw new TypeException(
                              sos.Types, (new VmNum(0)).Types
                              );
                }

                if (tos is VmVar && sos is VmVar)
                {
                    localStack.Push(
                        new VmNum(
                            ((sos as VmVar).Value as VmNum).Value
                            + ((tos as VmVar).Value as VmNum).Value
                            )
                        );
                }
                else if (tos is VmVar)
                {
                    localStack.Push(
                        new VmNum(
                            (sos as VmNum).Value
                            + ((tos as VmVar).Value as VmNum).Value
                            )
                        );
                }
                else if (sos is VmVar)
                {
                    localStack.Push(
                        new VmNum(
                            ((sos as VmVar).Value as VmNum).Value
                            + (tos as VmNum).Value
                            )
                        );
                }
                else
                {
                    localStack.Push(
                        new VmNum(
                            (sos as VmNum).Value
                            + (tos as VmNum).Value
                            )
                        );
                }
            }
            break;

            case Instruction.Pop2PushDifference: {
                if (localStack.Count < 2)
                {
                    throw new StackUnderflowException();
                }
                var tos = localStack.Pop();
                var sos = localStack.Pop();
                if (!VmValue.ShareType(tos, new VmNum(0)))
                {
                    throw new TypeException(
                              tos.Types, (new VmNum(0)).Types
                              );
                }
                if (!VmValue.ShareType(sos, new VmNum(0)))
                {
                    throw new TypeException(
                              sos.Types, (new VmNum(0)).Types
                              );
                }

                if (tos is VmVar && sos is VmVar)
                {
                    localStack.Push(
                        new VmNum(
                            ((sos as VmVar).Value as VmNum).Value
                            - ((tos as VmVar).Value as VmNum).Value
                            )
                        );
                }
                else if (tos is VmVar)
                {
                    localStack.Push(
                        new VmNum(
                            (sos as VmNum).Value
                            - ((tos as VmVar).Value as VmNum).Value
                            )
                        );
                }
                else if (sos is VmVar)
                {
                    localStack.Push(
                        new VmNum(
                            ((sos as VmVar).Value as VmNum).Value
                            - (tos as VmNum).Value
                            )
                        );
                }
                else
                {
                    localStack.Push(
                        new VmNum(
                            (sos as VmNum).Value
                            - (tos as VmNum).Value
                            )
                        );
                }
            }
            break;

            case Instruction.Pop2PushProduct: {
                if (localStack.Count < 2)
                {
                    throw new StackUnderflowException();
                }
                var tos = localStack.Pop();
                var sos = localStack.Pop();
                if (!VmValue.ShareType(tos, new VmNum(0)))
                {
                    throw new TypeException(
                              tos.Types, (new VmNum(0)).Types
                              );
                }
                if (!VmValue.ShareType(sos, new VmNum(0)))
                {
                    throw new TypeException(
                              sos.Types, (new VmNum(0)).Types
                              );
                }

                if (tos is VmVar && sos is VmVar)
                {
                    localStack.Push(
                        new VmNum(
                            ((sos as VmVar).Value as VmNum).Value
                            * ((tos as VmVar).Value as VmNum).Value
                            )
                        );
                }
                else if (tos is VmVar)
                {
                    localStack.Push(
                        new VmNum(
                            (sos as VmNum).Value
                            * ((tos as VmVar).Value as VmNum).Value
                            )
                        );
                }
                else if (sos is VmVar)
                {
                    localStack.Push(
                        new VmNum(
                            ((sos as VmVar).Value as VmNum).Value
                            * (tos as VmNum).Value
                            )
                        );
                }
                else
                {
                    localStack.Push(
                        new VmNum(
                            (sos as VmNum).Value
                            * (tos as VmNum).Value
                            )
                        );
                }
            }
            break;

            case Instruction.Pop2PushQuotient: {
                if (localStack.Count < 2)
                {
                    throw new StackUnderflowException();
                }
                var tos = localStack.Pop();
                var sos = localStack.Pop();
                if (!VmValue.ShareType(tos, new VmNum(0)))
                {
                    throw new TypeException(
                              tos.Types, (new VmNum(0)).Types
                              );
                }
                if (!VmValue.ShareType(sos, new VmNum(0)))
                {
                    throw new TypeException(
                              sos.Types, (new VmNum(0)).Types
                              );
                }

                if (tos is VmVar && sos is VmVar)
                {
                    localStack.Push(
                        new VmNum(
                            ((sos as VmVar).Value as VmNum).Value
                            / ((tos as VmVar).Value as VmNum).Value
                            )
                        );
                }
                else if (tos is VmVar)
                {
                    localStack.Push(
                        new VmNum(
                            (sos as VmNum).Value
                            / ((tos as VmVar).Value as VmNum).Value
                            )
                        );
                }
                else if (sos is VmVar)
                {
                    localStack.Push(
                        new VmNum(
                            ((sos as VmVar).Value as VmNum).Value
                            / (tos as VmNum).Value
                            )
                        );
                }
                else
                {
                    localStack.Push(
                        new VmNum(
                            (sos as VmNum).Value
                            / (tos as VmNum).Value
                            )
                        );
                }
            }
            break;

            case Instruction.Pop2PushPower: {
                if (localStack.Count < 2)
                {
                    throw new StackUnderflowException();
                }
                var tos = localStack.Pop();
                var sos = localStack.Pop();
                if (!VmValue.ShareType(tos, new VmNum(0)))
                {
                    throw new TypeException(
                              tos.Types, (new VmNum(0)).Types
                              );
                }
                if (!VmValue.ShareType(sos, new VmNum(0)))
                {
                    throw new TypeException(
                              sos.Types, (new VmNum(0)).Types
                              );
                }

                if (tos is VmVar && sos is VmVar)
                {
                    localStack.Push(
                        new VmNum(
                            Math.Pow(
                                ((sos as VmVar).Value as VmNum).Value,
                                ((tos as VmVar).Value as VmNum).Value
                                )
                            )
                        );
                }
                else if (tos is VmVar)
                {
                    localStack.Push(
                        new VmNum(
                            Math.Pow(
                                (sos as VmNum).Value,
                                ((tos as VmVar).Value as VmNum).Value
                                )
                            )
                        );
                }
                else if (sos is VmVar)
                {
                    localStack.Push(
                        new VmNum(
                            Math.Pow(
                                ((sos as VmVar).Value as VmNum).Value,
                                (tos as VmNum).Value
                                )
                            )
                        );
                }
                else
                {
                    localStack.Push(
                        new VmNum(
                            Math.Pow(
                                (sos as VmNum).Value,
                                (tos as VmNum).Value
                                )
                            )
                        );
                }
            }
            break;

            case Instruction.Pop2PushEqual: {
                if (localStack.Count < 2)
                {
                    throw new StackUnderflowException();
                }
                var tos = localStack.Pop();
                var sos = localStack.Pop();
                if (!VmValue.ShareType(tos, sos))
                {
                    throw new TypeException(tos.Types, sos.Types);
                }

                localStack.Push(new VmBool(sos.CompareTo(tos) == 0));
            }
            break;

            case Instruction.Pop2PushGreaterThan: {
                if (localStack.Count < 2)
                {
                    throw new StackUnderflowException();
                }
                var tos = localStack.Pop();
                var sos = localStack.Pop();
                if (!VmValue.ShareType(tos, sos))
                {
                    throw new TypeException(tos.Types, sos.Types);
                }

                localStack.Push(new VmBool(sos.CompareTo(tos) > 0));
            }
            break;

            case Instruction.Pop2PushLessThan: {
                if (localStack.Count < 2)
                {
                    throw new StackUnderflowException();
                }
                var tos = localStack.Pop();
                var sos = localStack.Pop();
                if (!VmValue.ShareType(tos, sos))
                {
                    throw new TypeException(tos.Types, sos.Types);
                }

                localStack.Push(new VmBool(sos.CompareTo(tos) < 0));
            }
            break;

            case Instruction.Pop2PushAnd: {
                if (localStack.Count < 2)
                {
                    throw new StackUnderflowException();
                }
                var tos = localStack.Pop();
                var sos = localStack.Pop();
                if (!VmValue.ShareType(tos, new VmBool(true)))
                {
                    throw new TypeException(
                              tos.Types, (new VmBool(true)).Types
                              );
                }
                if (!VmValue.ShareType(sos, new VmBool(true)))
                {
                    throw new TypeException(
                              sos.Types, (new VmBool(true)).Types
                              );
                }

                localStack.Push(
                    new VmBool(
                        (sos as VmBool).Value && (tos as VmBool).Value
                        )
                    );
            }
            break;

            case Instruction.Pop2PushOr: {
                if (localStack.Count < 2)
                {
                    throw new StackUnderflowException();
                }
                var tos = localStack.Pop();
                var sos = localStack.Pop();
                if (!VmValue.ShareType(tos, new VmBool(true)))
                {
                    throw new TypeException(
                              tos.Types, (new VmBool(true)).Types
                              );
                }
                if (!VmValue.ShareType(sos, new VmBool(true)))
                {
                    throw new TypeException(
                              sos.Types, (new VmBool(true)).Types
                              );
                }

                localStack.Push(
                    new VmBool(
                        (sos as VmBool).Value || (tos as VmBool).Value
                        )
                    );
            }
            break;

            case Instruction.Pop1PushNot: {
                if (localStack.Count < 1)
                {
                    throw new StackUnderflowException();
                }
                var tos = localStack.Pop();
                if (!VmValue.ShareType(tos, new VmBool(true)))
                {
                    throw new TypeException(
                              tos.Types, (new VmBool(true)).Types
                              );
                }

                localStack.Push(new VmBool((tos as VmBool).Value));
            }
            break;

            case Instruction.Pop2PushConcat: {
                if (localStack.Count < 2)
                {
                    throw new StackUnderflowException();
                }
                var list2 = localStack.Pop();
                var list1 = localStack.Pop();

                if (!(list1 is VmList))
                {
                    throw new TypeException(
                              new VmValueType[] { VmValueType.Ls },
                              list1.Types
                              );
                }
                if (!VmValue.ShareType(list1, list2))
                {
                    throw new TypeException(
                              list2.Types,
                              list1.Types
                              );
                }

                foreach (var value in (list2 as VmList).Values)
                {
                    (list1 as VmList).Values.Add(value);
                }
                localStack.Push(list1);
            }
            break;

            case Instruction.PopItemsOfSameTypePushList: {
                if (localStack.Count < 1)
                {
                    throw new StackUnderflowException();
                }
                var lsTypes = localStack.Peek().Types;
                var items   = new List <VmValue>();

                while (localStack.Count > 0 &&
                       VmValue.ShareType(
                           new VmValue(lsTypes), localStack.Peek()))
                {
                    items.Add(localStack.Pop());
                }

                localStack.Push(new VmList(lsTypes, items));
            }
            break;

            case Instruction.PopListPushUnzipped: {
                if (localStack.Count < 1)
                {
                    throw new StackUnderflowException();
                }
                var tos = localStack.Pop();
                if (!(tos is VmList))
                {
                    throw new TypeException(
                              new VmValueType[] { VmValueType.Ls }, tos.Types
                              );
                }
                var tosCopy = new List <VmValue>();
                foreach (var value in (tos as VmList).Values)
                {
                    tosCopy.Add(value);
                }
                tosCopy.Reverse();

                foreach (var value in tosCopy)
                {
                    localStack.Push(value);
                }
            }
            break;

            case Instruction.Pop2PushListPushListAtInd: {
                if (localStack.Count < 2)
                {
                    throw new StackUnderflowException();
                }
                var tos = localStack.Pop();
                var sos = localStack.Pop();
                if (!(sos is VmList))
                {
                    throw new TypeException(
                              new VmValueType[] { VmValueType.Ls }, tos.Types
                              );
                }
                if (!(tos is VmNum))
                {
                    throw new TypeException(
                              new VmValueType[] { VmValueType.Num }, tos.Types
                              );
                }

                localStack.Push(sos);
                localStack.Push(
                    (sos as VmList).Values[
                        (int)Math.Round((tos as VmNum).Value)
                    ]
                    );
            }
            break;

            case Instruction.Pop2PushWithRemovedInd: {
                if (localStack.Count < 2)
                {
                    throw new StackUnderflowException();
                }
                var tos = localStack.Pop();
                var sos = localStack.Pop();
                if (!(sos is VmList))
                {
                    throw new TypeException(
                              new VmValueType[] { VmValueType.Ls }, tos.Types
                              );
                }
                if (!(tos is VmNum))
                {
                    throw new TypeException(
                              new VmValueType[] { VmValueType.Num }, tos.Types
                              );
                }

                var remInd = (int)Math.Round((tos as VmNum).Value);

                var sosCopy = new List <VmValue>();
                foreach (var value in (sos as VmList).Values)
                {
                    if (value != (sos as VmList).Values[remInd])
                    {
                        sosCopy.Add(value);
                    }
                }

                localStack.Push(
                    new VmList((sos as VmList).Values[0].Types, sosCopy)
                    );
            }
            break;

            case Instruction.Pop2PushTuple: {
                if (localStack.Count < 2)
                {
                    throw new StackUnderflowException();
                }
                var tos = localStack.Pop();
                var sos = localStack.Pop();

                var tup = new VmTuple(sos, tos, sos.Types, tos.Types);
                localStack.Push(tup);
            }
            break;

            case Instruction.PopNumChrPushBool: {
                if (localStack.Count < 1)
                {
                    throw new StackUnderflowException();
                }
                var tos = localStack.Pop();
                if (!VmValue.ShareType(tos, new VmNum(0)) &&
                    !VmValue.ShareType(tos, new VmChar('0')))
                {
                    throw new TypeException(
                              new VmValueType[] {
                            VmValueType.Num,
                            VmValueType.Chr
                        },
                              tos.Types
                              );
                }

                if (tos is VmNum)
                {
                    localStack.Push(
                        new VmBool((tos as VmNum).Value != 0)
                        );
                }
                else if (tos is VmChar)
                {
                    localStack.Push(
                        new VmBool(((int)(tos as VmChar).Value) != 0)
                        );
                }
            }
            break;

            case Instruction.PopStrPushAny: {
                if (localStack.Count < 1)
                {
                    throw new StackUnderflowException();
                }
                var tos = localStack.Pop();
                if (!VmValue.ShareType(
                        tos, new VmList(
                            new VmChar(' ').Types, new List <VmValue>()
                            )
                        )
                    )
                {
                    throw new TypeException(
                              new VmValueType[] {
                            VmValueType.Ls, VmValueType.Chr
                        }, tos.Types
                              );
                }
                var tosStr = new StringBuilder();
                for (int i = 0; i < (tos as VmList).Values.Count; i++)
                {
                    var val = (tos as VmList).Values[i];
                    tosStr.Append((val as VmChar).Value);
                }

                var           tokens   = Lexer.Tokens(tosStr.ToString());
                CompoundToken valueAst = Parser.BuildProgram(tokens);
                foreach (CompoundToken stmt in valueAst.Children)
                {
                    if (stmt.Type != TokenType.Stmt)
                    {
                        throw new Exception("Expected stmt in input");
                    }

                    foreach (CompoundToken value in stmt.Children)
                    {
                        if (value.Type != TokenType.Value)
                        {
                            throw new Exception(
                                      "Expected value in input"
                                      );
                        }
                        var valCodes = Compiler.CompileValue(value);
                        foreach (var inst in valCodes)
                        {
                            execute(inst, ref stackFrame);
                        }
                    }
                }
            }
            break;

            case Instruction.PopAnyPushStr: {
                if (localStack.Count < 1)
                {
                    throw new StackUnderflowException();
                }
                var tos        = localStack.Pop();
                var valStr     = tos.ToString();
                var valStrList = new List <VmValue>();
                foreach (var chr in valStr)
                {
                    valStrList.Add(new VmChar(chr));
                }
                localStack.Push(
                    new VmList(valStrList[0].Types, valStrList)
                    );
            }
            break;

            case Instruction.PopNumPushChr: {
                if (localStack.Count < 1)
                {
                    throw new StackUnderflowException();
                }
                var tos = localStack.Pop();
                if (!VmValue.ShareType(tos, new VmNum(0)))
                {
                    throw new TypeException(
                              new VmValueType[] { VmValueType.Num },
                              tos.Types
                              );
                }

                localStack.Push(
                    new VmChar((char)(tos as VmNum).Value)
                    );
            }
            break;

            case Instruction.PushNum: {
                var valueStr = opCode.Argument;
                var num      = new VmNum(double.Parse(valueStr));

                localStack.Push(num);
            }
            break;

            case Instruction.PushChar: {
                var valueStr = opCode.Argument.Substring(
                    1, opCode.Argument.Length - 2
                    );
                if (valueStr[0] == '\\')
                {
                    switch (valueStr[1])
                    {
                    case '\'':
                        localStack.Push(new VmChar('\''));
                        break;

                    case 'n':
                        localStack.Push(new VmChar('\n'));
                        break;

                    case 't':
                        localStack.Push(new VmChar('\t'));
                        break;

                    case 'r':
                        localStack.Push(new VmChar('\r'));
                        break;

                    case '\\':
                        localStack.Push(new VmChar('\\'));
                        break;
                    }
                }
                else
                {
                    localStack.Push(new VmChar(valueStr[0]));
                }
            }
            break;

            case Instruction.PushBool: {
                var valueStr = opCode.Argument;

                if (valueStr == "?t")
                {
                    var chr = new VmBool(true);
                    localStack.Push(chr);
                }
                else if (valueStr == "?f")
                {
                    var chr = new VmBool(false);
                    localStack.Push(chr);
                }
            }
            break;

            case Instruction.PushIdent: {
                var varName = opCode.Argument;
                if (!varLookup.ContainsKey(varName))
                {
                    varLookup.Add(varName, new VmVar(varName));
                }

                localStack.Push(varLookup[varName]);
            }
            break;

            case Instruction.FuncCall: {
                if (opCode.Argument == "import_external")
                {
                    if (localStack.Count < 1)
                    {
                        throw new StackUnderflowException();
                    }
                    var tos = localStack.Pop();
                    if (!(tos is VmList) ||
                        (tos as VmList).Types[1]
                        != VmValueType.Chr)
                    {
                        throw new TypeException(
                                  new VmValueType[] {
                                VmValueType.Ls, VmValueType.Chr
                            },
                                  tos.Types
                                  );
                    }
                    var function = new NativeFunction(
                        tos.ToString() + ".csf", tos.ToString()
                        );
                    NativeFunctions.Add(tos.ToString(), function);
                }
                else if (opCode.Argument == "import")
                {
                    if (localStack.Count < 1)
                    {
                        throw new StackUnderflowException();
                    }
                    var tos = localStack.Pop();
                    if (!(tos is VmList) ||
                        (tos as VmList).Types[1]
                        != VmValueType.Chr)
                    {
                        throw new TypeException(
                                  new VmValueType[] {
                                VmValueType.Ls, VmValueType.Chr
                            },
                                  tos.Types
                                  );
                    }

                    // Compile and run module file
                    var code = "";
                    try {
                        code = File.ReadAllText(tos.ToString());
                    } catch (Exception e) {
                        Console.WriteLine(
                            "Error reading file: '"
                            + tos.ToString() + "'"
                            );
                        Console.WriteLine(e.Message);
                        Environment.Exit(-1);
                    }
                    var deSnakedCode = "";
                    try {
                        deSnakedCode = Lexer.DeSnakeCode(code);
                    } catch (Exception e) {
                        Console.WriteLine(
                            "Desnaking Error: " + e.Message
                            );
                        Environment.Exit(-1);
                    }
                    var           tokens = Lexer.Tokens(deSnakedCode);
                    CompoundToken ast    = null;
                    try {
                        ast = Parser.BuildProgram(tokens);
                    } catch (ParserException pe) {
                        Console.WriteLine("Parser Error: " + pe.Message);
                        Environment.Exit(-1);
                    }
                    var insts = Compiler.Translate(ast);
                    var vm    = new VirtualMachine(
                        insts.Item1, insts.Item2, Debug
                        );
                    try {
                        vm.Run();
                    } catch (Exception e) {
                        Console.WriteLine("Runtime Error: " + e.Message);
                        Environment.Exit(-1);
                    }

                    // Then copy the functions over into our file
                    foreach (var funcName in vm.Functions.Keys)
                    {
                        Functions.Add(funcName, vm.Functions[funcName]);
                    }
                }
                else
                {
                    if (NativeFunctions.ContainsKey(opCode.Argument))
                    {
                        if (localStack.Count < 1)
                        {
                            throw new StackUnderflowException();
                        }
                        var tos = localStack.Pop();

                        var function = NativeFunctions[opCode.Argument];
                        localStack.Push(function.Execute(tos));
                    }
                    else
                    {
                        var tos      = localStack.Pop();
                        var newLocal = new Stack <VmValue>();
                        newLocal.Push(tos);

                        var function = Functions[opCode.Argument];
                        if (!VmValue.ShareType(
                                tos,
                                new VmValue(function.InputTypes)
                                ))
                        {
                            throw new TypeException(
                                      function.InputTypes, tos.Types
                                      );
                        }

                        CallStack.Push(stackFrame);
                        stackFrame = new VmStackFrame(
                            newLocal, function.OpCodes,
                            function.OutputTypes
                            );
                        stackFrame.InstructionCounter = -1;
                    }
                }
            }
            break;

            case Instruction.Return: {
                var tos = localStack.Pop();
                if (!VmValue.ShareType(
                        tos, new VmValue(stackFrame.ReturnTypes)))
                {
                    throw new TypeException(
                              stackFrame.ReturnTypes, tos.Types
                              );
                }

                stackFrame = CallStack.Pop();
                stackFrame.LocalStack.Push(tos);
            }
            break;

            case Instruction.WhileStart: {
                if (localStack.Count < 1)
                {
                    throw new StackUnderflowException();
                }
                var tos = localStack.Pop();
                if (!VmValue.ShareType(tos, new VmBool(true)))
                {
                    throw new TypeException(
                              new VmBool(true).Types, tos.Types
                              );
                }

                if (!(tos as VmBool).Value)
                {
                    var endLabelName =
                        opCode.Argument.Replace("WH", "EW");
                    while (stackFrame.OpCodes[
                               stackFrame.InstructionCounter
                           ].Inst != Instruction.WhileEnd ||
                           stackFrame.OpCodes[
                               stackFrame.InstructionCounter
                           ].Argument != endLabelName)
                    {
                        stackFrame.InstructionCounter++;
                    }
                }
            }
            break;

            case Instruction.WhileEnd: {
                var startLabelName =
                    opCode.Argument.Replace("EW", "WH");
                while (stackFrame.OpCodes[
                           stackFrame.InstructionCounter
                       ].Inst != Instruction.WhileStart ||
                       stackFrame.OpCodes[
                           stackFrame.InstructionCounter
                       ].Argument != startLabelName)
                {
                    stackFrame.InstructionCounter--;
                }
                stackFrame.InstructionCounter--;
            }
            break;
            }
        }