public void setLocalVal(string id, SExpression val) { if (store.Keys.Contains(id)) { store[id] = val; } else { throw new Exception(String.Format("ID {0} does not exist", id)); } }
public SFunc(SID arglst, SExpression body, Environment e) { arglist = arglst; names = null; //our starting environment is the env we were defined in env = new Environment(e); env.addVal(arglist.identifier, new SNone()); //add bound variables to environment with default None value fixedArgCount = false; this.body = body; }
public void setVal(string id, SExpression val) { if (store.Keys.Contains(id)) { store[id] = val; } if (parent == null) { throw new Exception(String.Format("ID {0} does not exist", id)); } parent.setVal(id, val); }
public SExpression body; //body of execution public SFunc(List <SID> names, SExpression body, Environment e) { //our starting environment is the env we were defined in arglist = null; env = new Environment(e); foreach (SID id in names) { env.addVal(id.identifier, new SNone()); //add bound variables to environment with default None value } this.names = names; this.body = body; fixedArgCount = true; argCount = names.Count; }
private IEnumerable <ExecutionMessage> SLambda(List <SExpression> args, Environment e) { SExpression body = args[1]; if (args[0] is SID) //If arg 0 is a single SID, that means this func takes a variable # of args, and thus will have a single name for the list of args { yield return(new ExecutionMessage(ExecStatus.DONE, new SFunc((SID)args[0], body, e))); } //otherwise, build the list of names and pass it off to the other constructor List <SExpression> nameList = ((SPair)args[0]).flatten(); List <SID> names = new List <SID>(); for (int i = 0; i < nameList.Count - 1; i++) { names.Add((SID)nameList[i]); } yield return(new ExecutionMessage(ExecStatus.DONE, new SFunc(names, body, e))); }
public IEnumerable <ExecutionMessage> evaluate(SExpression expr, Environment e) { if (expr is SID) { yield return(new ExecutionMessage(ExecStatus.DONE, e.lookup((SID)expr))); yield break; } else if (!(expr is SPair)) { yield return(new ExecutionMessage(ExecStatus.DONE, expr)); yield break; } SPair exprL = (SPair)expr; if (!exprL.isProperList()) { throw new Exception("Not a proper list!"); } //We need to get the value of the head, but that could be another step of execution that can be interrupted //So, yield the value if it's not done. It it is, continue on List <SExpression> elms = exprL.flatten(); var subcall = evaluate(elms[0], e).GetEnumerator(); SExpression head = null; while (subcall.MoveNext()) { ExecutionMessage current = subcall.Current; if (current.status == ExecStatus.DONE) { head = current.returnVal; break; } else { yield return(current); } } if (!(head is SApplicable)) { throw new Exception("SExpression not applicable!"); } //args are going to be body. But because this is a proper list, the last element is going to be a empty list we want to drop elms.RemoveAt(0); //drop head elms.RemoveAt(elms.Count - 1); // remove empty list at end SApplicable appHead = (SApplicable)head; //Convert arguments to primatives if (appHead.fixedArgCount) { if (elms.Count != appHead.argCount) // make sure expected num arguments matches num arguments { throw new Exception(String.Format("Expected {0} arguments, recieved {1}", appHead.argCount, elms.Count)); } } //Convert arguments to usable values, the goofy escape is so that specific primatives (define, lambda, let, if) are skipped //preEval is always true for user created functions if (appHead.preEval) { for (int i = 0; i < elms.Count; i++) { var elmEnum = evaluate(elms[i], e).GetEnumerator(); SExpression elm = null; while (elmEnum.MoveNext()) { ExecutionMessage current = elmEnum.Current; if (current.status == ExecStatus.DONE) { elm = current.returnVal; break; } yield return(current); } elms[i] = elm; } } //Actually CALL the dang thing if (appHead is SPrimitive) { SPrimitive prim = (SPrimitive)appHead; foreach (var msg in prim.func(elms, e)) { yield return(msg); } yield break; } //Therefore is SFunc SFunc lambda = (SFunc)appHead; //bind names to variables to create new subenvironment if (lambda.fixedArgCount) { //if there is fixed number of args, pair each evaluated argument with its name for (int i = 0; i < elms.Count; i++) { lambda.env.setLocalVal(lambda.names[i].identifier, elms[i]); } } else { //if there are not, match the generic identifier with the list of args (need to convert to SPair w/tail first) lambda.env.setLocalVal(lambda.arglist.identifier, new SPair(elms, true)); } callStack.Add(expr);//append current function to call stack yield return(new ExecutionMessage(ExecStatus.PENDING_STEP, expr)); foreach (var msg in evaluate(lambda.body, lambda.env)) { yield return(msg); } callStack.RemoveAt(callStack.Count - 1); }
public ExecutionMessage(ExecStatus stat, SExpression rv) { status = stat; returnVal = rv; }
public void setHead(SExpression expr) { head = expr; }
public SPair(SExpression head, SExpression tail) { this.head = head; this.tail = tail; }