コード例 #1
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);
        }
コード例 #2
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);
        }