Пример #1
0
 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));
     }
 }
Пример #2
0
        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;
        }
Пример #3
0
        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);
        }
Пример #4
0
        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;
        }
Пример #5
0
        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)));
        }
Пример #6
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);
        }
Пример #7
0
 public ExecutionMessage(ExecStatus stat, SExpression rv)
 {
     status = stat; returnVal = rv;
 }
Пример #8
0
 public void setHead(SExpression expr)
 {
     head = expr;
 }
Пример #9
0
 public SPair(SExpression head, SExpression tail)
 {
     this.head = head; this.tail = tail;
 }