// <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()); }
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(); }
// <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()); }
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()); }
// <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())); }
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); } } }
// <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()); }
// <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 }); }
// <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()); }
// <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()); }
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; } }