Пример #1
0
        private IEnumerable <ExecutionMessage> SDefine(List <SExpression> args, Environment e)
        {
            if (e.hasParent())
            {
                throw new Exception("Define only allowed at global scope");
            }

            SID name             = (SID)args[0];
            ExecutionMessage msg = null;

            foreach (var tmsg in evaluate(args[1], e))
            {
                msg = tmsg;
                if (msg.status == ExecStatus.DONE)
                {
                    break;
                }
                yield return(msg);
            }
            e.addVal(name.identifier, msg.returnVal);

            yield return(new ExecutionMessage(ExecStatus.DONE, new SNone()));
        }
Пример #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);
        }