public Evaluator(Interpreter interpreter) { i = interpreter; interpreter.evaluator = this; var throwStatement = new Operation("throw") { association = Operation.Association.Right, unaryFunction = (right) => { throw i.Exception(right.ToString()); } }; var tryCatch = new Operation("try") { association = Operation.Association.None, unaryFunction = (none) => { int depth = i.GetLocation().depth; try { i.ExecuteBlock(); i.Eat("catch"); i.EatUntilToken("l curly"); i.SkipBlock(); } catch (InterpreterException e) { i.SkipToDepth(depth); i.Eat("catch"); string exceptionName = null; string lineName = null; string columnName = null; if (i.CurrentToken == "of") { i.Eat(); exceptionName = i.GetIdentifier(); i.heap.DeclareReadOnly(exceptionName, new DException(e.message.ToDString())); if (i.CurrentToken == "comma") { i.Eat(); lineName = i.GetIdentifier(); i.heap.DeclareReadOnly(lineName, e.location.line.ToDNumber()); } if (i.CurrentToken == "comma") { i.Eat(); columnName = i.GetIdentifier(); i.heap.DeclareReadOnly(columnName, e.location.column.ToDNumber()); } } i.ExecuteBlock(); if (exceptionName != null) { i.heap.DeleteLocal(exceptionName); } if (lineName != null) { i.heap.DeleteLocal(lineName); } if (columnName != null) { i.heap.DeleteLocal(columnName); } } return(dvoid); } }; var include = new Operation("include") { association = Operation.Association.None, unaryFunction = (none) => { var filename = Evaluate <DString>().ToString(); if (i.includes.Contains(filename)) { throw new InterpreterException(i.CurrentToken, "File has already been included: " + filename); } i.TryEat("semicolon"); var tokens = Lexer.ScanFile(filename); tokens.RemoveAll(x => x == "eof"); i.tokens.InsertRange(i.pointer, tokens); i.includes.Add(filename); return(dvoid); } }; var charLiteral = new Operation("char") { eatOperator = false, association = Operation.Association.None, unaryFunction = (none) => { return(i.Eat <char>().ToDChar()); } }; var baseLiteral = new Operation("base") { association = Operation.Association.None, unaryFunction = (none) => { var super = i.functionOwners.Peek().GetMember("base"); lastVariable = super; if (i.CurrentToken == "l bracket") { i.Eat(); var p = i.GetParameters(); ((DFunction)super.Value.GetMemberValue("constructor")).Call(p); } return(lastVariable.Value); } }; var thisLiteral = new Operation("this") { association = Operation.Association.None, unaryFunction = (none) => { lastVariable = new ReadOnlyVariable(i.functionOwners.Peek(), i.depth); return(lastVariable.Value); } }; var structureLiteral = new Operation("structure") { association = Operation.Association.None, unaryFunction = (none) => { DTemplate super = null; if (i.CurrentToken == "extending") { i.Eat(); var extending = Evaluate(); if (extending is DTemplate) { super = (DTemplate)extending; } else { throw new InterpreterException(i.CurrentToken, "Expected a strong template or a weak template"); } } var structure = new DWeakTemplate() { i = i, definition = i.GetLocation(), super = super }; while (i.CurrentToken != "l curly") { i.Eat(); } i.SkipBlock(); return(structure); } }; var funcLiteral = new Operation("function") { association = Operation.Association.None, unaryFunction = (none) => { i.TryEat("of"); var location = i.GetLocation(); DWeakFunction func = new DWeakFunction() { i = i, location = location }; while (i.CurrentToken != "l curly") { i.Eat(); } i.SkipBlock(); return(func); } }; var tableLiteral = new Operation("table") { association = Operation.Association.None, unaryFunction = (none) => { i.UnsafeEat("l curly"); var table = new DTable(); var members = new Dictionary <string, Member>(); var properties = new Dictionary <string, WeakProperty>(); while (i.CurrentToken != "r curly") { if (i.CurrentToken == "get") { i.Eat(); string name = i.GetIdentifier(); DWeakFunction getter = (DWeakFunction)funcLiteral.unaryFunction.Invoke(null); getter.owner = table; properties.Add(name, new WeakProperty(getter)); } else if (i.CurrentToken == "set") { i.Eat(); string name = i.GetIdentifier(); if (!properties.ContainsKey(name)) { throw i.Exception("Must declare a getter for " + name + " before declaring a setter."); } DWeakFunction setter = (DWeakFunction)funcLiteral.unaryFunction.Invoke(null); setter.owner = table; properties[name].setter = setter; } else if (i.CurrentToken == "with") { i.Eat(); string name = i.GetIdentifier(); DObject value = new DUndefined(); if (i.CurrentToken == "equals") { i.Eat(); value = Evaluate(); if (value.GetType() == typeof(DWeakFunction)) { ((DWeakFunction)value).owner = table; } } members.Add(name, new Member(value)); } else if (i.CurrentToken == "constructor") { i.Eat(); DWeakFunction ctor = (DWeakFunction)funcLiteral.unaryFunction.Invoke(null); ctor.owner = table; members.Add("constructor", new ReadOnlyMember(ctor)); } else if (i.CurrentToken == "function") { i.Eat(); string name = i.GetIdentifier(); DWeakFunction ctor = (DWeakFunction)funcLiteral.unaryFunction.Invoke(null); ctor.owner = table; members.Add(name, new Member(ctor)); } else { throw i.Exception("Unexpected token: " + i.CurrentToken.Type); } i.TryEat("semicolon"); } properties.ToList().ForEach(x => members.Add(x.Key, x.Value)); table.SetMembers(members); i.UnsafeEat("r curly"); return(table); } }; tableOp = tableLiteral; var returnStatement = new Operation("return") { association = Operation.Association.None, unaryFunction = (none) => { i.returnValue = Evaluate(); return(dvoid); } }; var continueStatement = new Operation("continue") { association = Operation.Association.None, unaryFunction = (none) => { i.shouldContinue = true; return(dvoid); } }; var breakStatement = new Operation("break") { association = Operation.Association.None, unaryFunction = (none) => { i.shouldBreak = true; return(dvoid); } }; var forEachLoop = new Operation("for") { association = Operation.Association.None, unaryFunction = (none) => { i.Eat("each"); string varName = i.GetIdentifier(); i.Eat("in"); DSet set = Evaluate <DSet>(); var j = i.heap.DeclareLocal(varName); var beginning = i.GetLocation(); i.BeginLoop(beginning); foreach (var item in set.items) { if (i.shouldBreak) { break; } j.Value = item.Value; i.shouldContinue = false; i.ExecuteLoop(); i.Goto(beginning); } i.heap.DeleteLocal(varName); i.EndLoop(); return(dvoid); } }; var forLoop = new Operation("from") { association = Operation.Association.None, unaryFunction = (none) => { int from = Evaluate <DNumber>().ToInt(); i.Eat("to"); int to = Evaluate <DNumber>().ToInt(); int increment; if (from > to) { increment = -1; } else { increment = 1; } if (i.CurrentToken == "by") { i.Eat(); increment = Evaluate <DNumber>().ToInt(); } i.Eat("with"); string varName = i.GetIdentifier(); var j = i.heap.DeclareLocal(varName); var beginning = i.GetLocation(); i.BeginLoop(beginning); for (int k = from; increment > 0 ? k <to : k> to; k += increment) { if (i.shouldBreak) { break; } j.Value = k.ToDNumber(); i.ExecuteLoop(); i.Goto(beginning); } i.heap.DeleteLocal(varName); i.EndLoop(); return(dvoid); } }; var untilLoop = new Operation("until") { association = Operation.Association.None, unaryFunction = (none) => { var beginning = i.GetLocation(); i.BeginLoop(beginning); while (!i.GetCondition()) { if (i.shouldBreak) { break; } i.ExecuteLoop(); i.Goto(beginning); } i.EndLoop(); return(dvoid); } }; /* * var instantiation = new Operation("new") * { * association = Operation.Association.None, * unaryFunction = (none) => * { * var template = Evaluate<DTemplate>(); * i.Eat("l bracket"); * var args = i.GetParameters(); * return template.Instantiate(args); * } * }; */ var instantiation = new Operation("new") { association = Operation.Association.Right, unaryFunction = (right) => { //var template = Evaluate<DTemplate>(); i.Eat("l bracket"); var args = i.GetParameters(); return(DObject.AssertType <DTemplate>(right).Instantiate(args)); } }; var whileLoop = new Operation("while") { association = Operation.Association.None, unaryFunction = (none) => { var beginning = i.GetLocation(); i.BeginLoop(beginning); while (i.GetCondition()) { if (i.shouldBreak) { break; } i.ExecuteLoop(); i.Goto(beginning); } i.EndLoop(); return(dvoid); } }; var ifStatement = new Operation("if") { association = Operation.Association.None, unaryFunction = (none) => { bool satisfied = i.GetCondition(); if (satisfied) { i.ExecuteBlock(); } else { i.SkipBlock(); } while (i.CurrentToken == "else" && i.NextToken == "if") { i.Eat(); i.Eat(); bool meetsCondition = i.GetCondition(); if (satisfied || !meetsCondition) { i.SkipBlock(); } else { satisfied = true; i.ExecuteBlock(); } } if (i.CurrentToken == "else") { i.Eat(); if (satisfied) { i.SkipBlock(); } else { i.ExecuteBlock(); } } return(dvoid); } }; var openBracket = new Operation("l curly") { eatOperator = false, association = Operation.Association.None, unaryFunction = (none) => { i.Eat(); return(dvoid); } }; var closeBracket = new Operation("r curly") { eatOperator = false, association = Operation.Association.None, unaryFunction = (none) => { i.Eat(); return(dvoid); } }; var preInc = new Operation("increment") { association = Operation.Association.None, unaryFunction = (none) => { var right = Evaluate(); return(lastVariable.Value = (DObject.AssertType <DNumber>(lastVariable.Value).ToFloat() + 1).ToDNumber()); } }; var incAdd = new Operation("add") { association = Operation.Association.Left, unaryFunction = (left) => { return(lastVariable.Value = lastVariable.Value.OpADD(Evaluate())); } }; var incSub = new Operation("subtract") { association = Operation.Association.Left, unaryFunction = (left) => { return(lastVariable.Value = lastVariable.Value.OpSUB(Evaluate())); } }; var postInc = new Operation("increment") { association = Operation.Association.Left, unaryFunction = (left) => { return(lastVariable.Value = (DObject.AssertType <DNumber>(lastVariable.Value).ToFloat() + 1).ToDNumber()); } }; var preDec = new Operation("decrement") { association = Operation.Association.None, unaryFunction = (none) => { var right = Evaluate(); return(lastVariable.Value = (DObject.AssertType <DNumber>(lastVariable.Value).ToFloat() - 1).ToDNumber()); } }; var postDec = new Operation("decrement") { association = Operation.Association.Left, unaryFunction = (left) => { return(lastVariable.Value = (DObject.AssertType <DNumber>(lastVariable.Value).ToFloat() - 1).ToDNumber()); } }; var semicolon = new Operation("semicolon") { association = Operation.Association.None, unaryFunction = (none) => dvoid }; var declaration = new Operation("var") { association = Operation.Association.None, unaryFunction = (none) => { if (i.CurrentToken == "structure") { i.Eat(); string name = i.GetIdentifier(); DWeakTemplate value = (DWeakTemplate)structureLiteral.unaryFunction(null); i.heap.DeclareLocal(name, value); } else if (i.CurrentToken == "table") { i.Eat(); string name = i.GetIdentifier(); DTable value = (DTable)tableLiteral.unaryFunction(null); i.heap.DeclareLocal(name, value); } else if (i.CurrentToken == "function") { i.Eat(); string name = i.GetIdentifier(); DWeakFunction value = (DWeakFunction)funcLiteral.unaryFunction(null); i.heap.DeclareLocal(name, value); } else { string name = i.Eat <string>("identifier"); DObject value = DUndefined.instance; if (i.CurrentToken == "equals") { i.Eat(); value = Evaluate(); } i.heap.DeclareLocal(name, value); } return(dvoid); } }; var assignment = new Operation("equals") { association = Operation.Association.Left, unaryFunction = (left) => { var v = lastVariable; return(v.Value = Evaluate()); } }; var identifier = new Operation("identifier") { eatOperator = false, association = Operation.Association.None, unaryFunction = (none) => { string name = i.Eat <string>("identifier"); if (!i.heap.Exists(name)) { throw new InterpreterException(i.PreviousToken, "Variable does not exist in this scope: " + name); } lastVariable = i.heap.Get(name); if (i.CurrentToken == "equals") { return(DUndefined.instance); } return(lastVariable.Value); } }; var conditional = new Operation("question mark") { association = Operation.Association.Left, unaryFunction = (left) => { var ifTrue = Evaluate(); i.Eat("else"); var ifFalse = Evaluate(); if (DObject.AssertType <DBool>(left).ToBool()) { return(ifTrue); } else { return(ifFalse); } } }; var traverse = new Operation("dot") { association = Operation.Association.Left, unaryFunction = (left) => { var name = i.GetIdentifier(); var type = left.GetType(); if (left.HasMember(name)) { lastVariable = left.GetMember(name); if (i.CurrentToken == "equals") { return(DUndefined.instance); } return(lastVariable.Value); } else if (StrongTypeRegistry.strongFunctions.ContainsKey(type)) { var methods = StrongTypeRegistry.strongFunctions[type]; if (methods.ContainsKey(name)) { var method = methods[name]; lastVariable = null; return(new DStrongFunction(method, left)); } else if (left.HasMember("base")) { i.pointer -= 2; // recurse back to the dot, with base being the new left side return(left.GetMemberValue("base")); } } else if (left.HasMember("base")) { i.pointer -= 2; // recurse back to the dot, with base being the new left side return(left.GetMemberValue("base")); } throw new InterpreterException(i.CurrentToken, "Object (" + type.Name + ") does not contain member: " + name); } }; var methodCall = new Operation("l bracket") { association = Operation.Association.Left, unaryFunction = (left) => { var parameters = i.GetParameters(); if (left is DFunction) { return(((DFunction)left).Call(parameters)); } else if (left is DTemplate) { return(((DTemplate)left).Instantiate(parameters)); } else { throw i.Exception("Can only invoke a function or a template, not a " + left.GetType().Name); } } }; /*var eof = new Operation("eof") * { * eatOperator = false, * association = Operation.Association.None, * unaryFunction = (none) => DUndefined.instance * };*/ var arrayLiteral = new Operation("l square") { association = Operation.Association.None, unaryFunction = (none) => { List <DObject> p = new List <DObject>(); if (i.CurrentToken == "r square") { i.Eat(); return(new DSet(new List <DObject>())); } bool firstTime = true; do { if (!firstTime) { i.Eat("comma"); } p.Add(Evaluate()); firstTime = false; }while (i.CurrentToken == "comma"); i.Eat("r square"); return(new DSet(p)); } }; var undefinedLiteral = new Operation("undefined") { association = Operation.Association.None, unaryFunction = (none) => DUndefined.instance }; var numberLiteral = new Operation("number") { eatOperator = false, association = Operation.Association.None, unaryFunction = (none) => i.Eat <float>().ToDNumber() }; var stringLiteral = new Operation("string") { eatOperator = false, association = Operation.Association.None, unaryFunction = (none) => i.Eat <string>().ToDString() }; var boolLiteral = new Operation("bool") { eatOperator = false, association = Operation.Association.None, unaryFunction = (none) => i.Eat <bool>().ToDBool() }; var index = new Operation("l square") { association = Operation.Association.Left, unaryFunction = (left) => { lastVariable = left.OpINDEX(Evaluate()); i.Eat("r square"); return(lastVariable.Value); } }; var bracket = new Operation("l bracket") { association = Operation.Association.None, unaryFunction = (none) => { var result = Evaluate(); i.Eat("r bracket"); return(result); } }; var neg = new Operation("minus") { association = Operation.Association.Right, unaryFunction = (right) => right.OpNEG() }; var pow = new Operation("exponent") { binaryFunction = (left, right) => left.OpPOW(right) }; var mul = new Operation("multiply") { binaryFunction = (left, right) => left.OpMUL(right) }; var div = new Operation("divide") { binaryFunction = (left, right) => left.OpDIV(right) }; var mod = new Operation("modulus") { binaryFunction = (left, right) => left.OpMOD(right) }; var add = new Operation("plus") { binaryFunction = (left, right) => left.OpADD(right) }; var sub = new Operation("minus") { binaryFunction = (left, right) => left.OpSUB(right) }; var not = new Operation("not") { association = Operation.Association.Right, unaryFunction = (right) => DObject.AssertType <DBool>(right).OpNOT() }; var eq = new Operation("double equal") { binaryFunction = (left, right) => left.OpEQ(right) }; var neq = new Operation("not equal") { binaryFunction = (left, right) => left.OpNEQ(right) }; var gr = new Operation("greater than") { binaryFunction = (left, right) => left.OpGR(right) }; var ls = new Operation("less than") { binaryFunction = (left, right) => left.OpLS(right) }; var geq = new Operation("greater or equal") { binaryFunction = (left, right) => left.OpGEQ(right) }; var leq = new Operation("less or equal") { binaryFunction = (left, right) => left.OpLEQ(right) }; var and = new Operation("and") { binaryFunction = (left, right) => DObject.AssertType <DBool>(left).OpAND(DObject.AssertType <DBool>(right)) }; var or = new Operation("or") { binaryFunction = (left, right) => { if (left is DUndefined) { return(right); } else if (left.GetType() == typeof(DBool) && right.GetType() == typeof(DBool)) { return(((DBool)left).OpOR((DBool)right)); } return(left); //return DObject.AssertType<DBool>(left).OpOR(DObject.AssertType<DBool>(right)); } }; //operations.Add(eof); void register(Operation op) { precedences.Last().Add(op); } void precedence() { precedences.Add(new List <Operation>()); } precedence(); register(thisLiteral); register(baseLiteral); register(bracket); register(undefinedLiteral); register(arrayLiteral); register(numberLiteral); register(stringLiteral); register(boolLiteral); register(tableLiteral); register(charLiteral); //register(instantiation); precedence(); register(identifier); register(methodCall); register(traverse); register(index); precedence(); register(assignment); register(preInc); register(postInc); register(preDec); register(postDec); register(incAdd); register(incSub); precedence(); register(neg); register(not); precedence(); register(pow); precedence(); register(mul); register(div); register(mod); precedence(); register(add); register(sub); precedence(); register(eq); register(neq); register(gr); register(ls); register(geq); register(leq); precedence(); register(and); precedence(); register(or); precedence(); register(conditional); precedence(); register(semicolon); register(declaration); register(closeBracket); register(openBracket); register(ifStatement); register(whileLoop); register(untilLoop); register(forEachLoop); register(continueStatement); register(breakStatement); register(funcLiteral); register(returnStatement); register(forLoop); register(structureLiteral); register(include); register(tryCatch); register(throwStatement); }