Пример #1
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);
                }
            }
        }
Пример #2
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;
            }
        }