public SPair(List <SExpression> elms, bool makeProper = false) { if (makeProper) { elms.Add(new SEmptyList()); } if (elms.Count == 0) { throw new Exception("Error no elms to create chain of pairs"); } if (elms.Count == 1) { head = elms[0]; tail = new SEmptyList(); return; } if (elms.Count == 2) { head = elms[0]; tail = elms[1]; return; } SPair root = new SPair(elms[elms.Count - 2], elms[elms.Count - 1]); for (int i = elms.Count - 3; i > 0; i--) { root = new SPair(elms[i], root); } head = elms[0]; tail = root; }
private IEnumerable <ExecutionMessage> SLet(List <SExpression> args, Environment e) { Environment local = new Environment(e); //TODO BUG: (let () ...) parses the name name bindings that are the pair <EmptyList,NULL> if (args[0] is SPair) { SPair nameBindings = (SPair)args[0]; if (!nameBindings.isProperList()) { throw new Exception("Can't use impro per list in a let"); } List <SExpression> names = nameBindings.flatten(); for (int i = 0; i < names.Count - 1; i++) { String name = ((SID)((SPair)names[i]).getHead()).identifier; SExpression val = ((SPair)((SPair)names[i]).getTail()).getHead(); //Cycle through the yields until done var elmEnum = evaluate(val, e).GetEnumerator(); SExpression elm = null; while (elmEnum.MoveNext()) { ExecutionMessage current = elmEnum.Current; if (current.status == ExecStatus.DONE) { elm = current.returnVal; break; } yield return(current); } local.addVal(name, elm); } } else if (args[0] is SEmptyList) { } else { throw new Exception("Name bindings section of let must be a list"); } //Lets can have an arbitrary number of statements after the name bindings, execute them for stateful effects ExecutionMessage msg = null; for (int i = 1; i < args.Count; i++) { foreach (var tmsg in evaluate(args[i], local)) { msg = tmsg; if (msg.status == ExecStatus.DONE) { continue; } yield return(msg); } } //yield final message yield return(msg); }
private IEnumerable <ExecutionMessage> SCar(List <SExpression> args, Environment e) { if (args[0] is SPair) { SPair al = (SPair)args[0]; yield return(new ExecutionMessage(ExecStatus.DONE, (SExpression)al.getHead().Clone())); } else { throw new Exception("car expects a list!"); } }
public bool attemptParse() { while (tokens.Count > 0) { // Emulate recursive behavior with stacks / loops -- Blegh Token top = tokens.First(); //Pop! tokens.RemoveAt(0); //Pop! SExpression parsedExpr; //element that we finished parsing switch (top.type) { case TokenType.Int: //pass through parsedExpr = new SInt(Int32.Parse(top.token)); break; case TokenType.Id: //pass through parsedExpr = new SID(top.token); break; case TokenType.Bool: //pass through parsedExpr = new SBool(top.token == "#f"); break; case TokenType.Symbol: //pass through parsedExpr = new SSymbol(top.token); break; case TokenType.LParen: //LParen means we have a new subexpr to parse, so add to the stack parseStack.Add(new List <SExpression>()); continue; //we started a new subexpression, so there is nothing to add to the parse tree yet, so skip to top of loop case TokenType.RParen: //RParens means we can close a sub expr if (parseStack.Count == 1) //if count is 1, we are trying to close our root expression. Don't do that. { throw new Exception("Unexpected RParen\n" + top.ToString()); } parsedExpr = new SPair(parseStack.Last(), true); //Create an slist for our subexpression parseStack.RemoveAt(parseStack.Count - 1); //remove the subexpression we just finished parsing break; default: //Only happens if I add new token types, but don't add parsing logic for them throw new Exception("Unknown Token Type"); } parseStack.Last().Add(parsedExpr); } return(parseStack.Count == 1); }
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); }