Ejemplo n.º 1
0
        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;
        }
Ejemplo n.º 2
0
        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);
        }
Ejemplo n.º 3
0
 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!");
     }
 }
Ejemplo n.º 4
0
        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);
        }
Ejemplo n.º 5
0
        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);
        }