/// <summary> /// This method binds names with values, but doesn't allow their usage within expressions /// that are being bound. /// </summary> private Bounce ApplyLetSpecialForm(IExpression expressions, Environment env, Cont cont) { var letSpecialForm = expressions as ScmLetSpecialForm; // Split keys and values in separate lists. var bindingKeys = new List <IExpression> (); var bindingValues = new List <IExpression> (); foreach (var keyValue in letSpecialForm.Bindings) { bindingValues.Add(keyValue.Value); bindingKeys.Add(keyValue.Key); } // Evaluate values. return(() => EvalList(bindingValues, env, evalBindingResults => { var bindingResultsAsList = evalBindingResults as List <IExpression>; // Create a temporary environment frame that will hold these // bindings. var environmentFrame = new EnvironmentFrame(); for (int i = 0; i < bindingKeys.Count; ++i) { var bindingName = bindingKeys[i] as ScmSymbol; var bindingValue = bindingResultsAsList[i]; environmentFrame.Set(bindingName, bindingValue); } // Extend the environemnt with these bindings. var newEnvironment = (new Environment(env)).Extend(environmentFrame); // Evaluate the body in the new environment. return EvalList(letSpecialForm.Expressions, newEnvironment, evalResults => { var evalResultsAsList = evalResults as List <IExpression>; return (Bounce)cont(evalResultsAsList.Last()); }); })); }
public Environment() { // Set up global environment. var initialFrame = new EnvironmentFrame(); // Numeric operations. initialFrame.Set(new ScmSymbol("+"), new ScmAddition()); initialFrame.Set(new ScmSymbol("-"), new ScmSubtraction()); initialFrame.Set(new ScmSymbol("*"), new ScmMultiplication()); initialFrame.Set(new ScmSymbol("/"), new ScmDivision()); initialFrame.Set(new ScmSymbol("zero?"), new ScmZeroPredicateProcedure()); initialFrame.Set(new ScmSymbol("odd?"), new ScmOddPredicateProcedure()); initialFrame.Set(new ScmSymbol("even?"), new ScmEvenPredicateProcedure()); initialFrame.Set(new ScmSymbol("quotient"), new ScmQuotientProcedure()); initialFrame.Set(new ScmSymbol("remainder"), new ScmRemainderProcedure()); initialFrame.Set(new ScmSymbol("modulo"), new ScmModuloProcedure()); initialFrame.Set(new ScmSymbol("abs"), new ScmAbsProcedure()); initialFrame.Set(new ScmSymbol("min"), new ScmMinProcedure()); initialFrame.Set(new ScmSymbol("max"), new ScmMaxProcedure()); initialFrame.Set(new ScmSymbol("number?"), new ScmNumberPredicateProcedure()); initialFrame.Set(new ScmSymbol("integer?"), new ScmIntegerPredicateProcedure()); initialFrame.Set(new ScmSymbol("real?"), new ScmRealPredicateProcedure()); // TODO: exact?, inexact?, positive?, negative?, // sin, cos, sqrt etc. // True, false and comparison operations. initialFrame.Set(new ScmSymbol("#t"), ScmTrueValue.Instance); initialFrame.Set(new ScmSymbol("#f"), ScmFalseValue.Instance); initialFrame.Set(new ScmSymbol("<"), new ScmLessThan()); initialFrame.Set(new ScmSymbol(">"), new ScmGreaterThan()); initialFrame.Set(new ScmSymbol("="), new ScmEqualTo()); initialFrame.Set(new ScmSymbol("<="), new ScmLessThanOrEqualTo()); initialFrame.Set(new ScmSymbol(">="), new ScmGreaterThanOrEqualTo()); // List procedures. initialFrame.Set(new ScmSymbol("cons"), new ScmConsProcedure()); initialFrame.Set(new ScmSymbol("list"), new ScmListProcedure()); initialFrame.Set(new ScmSymbol("list?"), new ScmListPredicateProcedure()); initialFrame.Set(new ScmSymbol("null?"), new ScmNullPredicateProcedure()); initialFrame.Set(new ScmSymbol("length"), new ScmLengthProcedure()); initialFrame.Set(new ScmSymbol("list-ref"), new ScmListRefProcedure()); initialFrame.Set(new ScmSymbol("car"), new ScmCarProcedure()); initialFrame.Set(new ScmSymbol("cdr"), new ScmCdrProcedure()); initialFrame.Set(new ScmSymbol("set-car!"), new ScmSetCarProcedure()); initialFrame.Set(new ScmSymbol("set-cdr!"), new ScmSetCdrProcedure()); // Continuation and evaluation procedures. initialFrame.Set(new ScmSymbol("eval"), new ScmEvalProcedure()); initialFrame.Set(new ScmSymbol("call/cc"), new ScmCallCcProcedure()); initialFrame.Set(new ScmSymbol("call-with-current-continuation"), new ScmCallCcProcedure()); Extend(initialFrame); }
private Bounce ApplyClosureProcedure(ScmCombination combination, Environment env, Cont cont) { //((lambda (b . a) a) 1) var closure = combination.Procedure as ScmClosure; var numberOfArguments = closure.ArgumentList.Count; var operands = new List <IExpression> (combination.Operands); if (!closure.Dotted && numberOfArguments != operands.Count) { throw new EvaluatorException(String.Format("Expecting {0} argument{1}", numberOfArguments, numberOfArguments > 1 ? "s" : ""), combination); } else if (closure.Dotted) { var numberOfArgumentsButLast = numberOfArguments - 1; if (numberOfArgumentsButLast > operands.Count) { throw new EvaluatorException(String.Format("Expecting at least {0} argument{1}", numberOfArgumentsButLast, numberOfArgumentsButLast > 1 ? "s" : ""), combination); } else if (numberOfArgumentsButLast == operands.Count) { operands.Add(ScmEmptyList.Instance); } else { var lastArgument = new ScmPair(operands.TailFrom(numberOfArgumentsButLast)); operands = new List <IExpression> (operands.GetRange(0, numberOfArgumentsButLast)); operands.Add(lastArgument); } } return(() => EvalList(operands, env, evalResults => { var environmentFrame = new EnvironmentFrame(); var evalResultsAsList = evalResults as List <IExpression>; for (int i = 0; i < closure.ArgumentList.Count; ++i) { var argumentName = closure.ArgumentList[i]; var argumentValue = evalResultsAsList[i]; environmentFrame.Set(argumentName, argumentValue); } var newEnvironment = (new Environment(closure.Env)).Extend(environmentFrame); return EvalList(closure.Body.AllButLast(), newEnvironment, bodyEvalResults => { return Eval(closure.Body.Last(), newEnvironment, cont); }); })); }
/// <summary> /// This method binds names with values allowing their usage within expressions /// that are being bound. /// </summary> private Bounce ApplyLetrecSpecialForm(IExpression expression, Environment env, Cont cont) { // In comments below we refer to bindings as key-value pairs. var letRecSpecialForm = expression as ScmLetrecSpecialForm; // We are going to use a temporary environmental frame, using which we are // going to define dummy values for each identifier first, and then substitute with // evaluated ones. var environmentFrame = new EnvironmentFrame(); // A list of names (keys) that we are going to bind. var bindingKeys = new List <IExpression> (); // A list of corresponding values. var bindingValues = new List <IExpression> (); // Proccess each pair in the list of bindings, by saving // them in corresponding lists and assigning // the unassigned value to each of the identifiers. foreach (var keyValue in letRecSpecialForm.Bindings) { bindingValues.Add(keyValue.Value); bindingKeys.Add(keyValue.Key); environmentFrame.Set((ScmSymbol)keyValue.Key, ScmUnassigned.Instance); } // Now evaluate each expression (i.e. "value"). return(() => EvalList(bindingValues, env, evalBindingsResult => { var bindingResultsAsList = evalBindingsResult as List <IExpression>; // Substitute evaluated results. for (int i = 0; i < bindingKeys.Count; ++i) { var bindingName = bindingKeys[i] as ScmSymbol; var bindingValue = bindingResultsAsList[i]; environmentFrame.Set(bindingName, bindingValue); } // Extend the environment with this new frame. // FIXME: it should "branch" here, and not create a copy of entire environment. var newEnvironment = (new Environment(env)).Extend(environmentFrame); // And evalute expressions in the environment with those bindings. return EvalList(letRecSpecialForm.Expressions, newEnvironment, evalResults => { // FIXME: rewrite this in the same manner as for closure. var evalResultsAsList = evalResults as List <IExpression>; return (Bounce)cont(evalResultsAsList.Last()); }); })); }
/// <summary> /// Extends the environment by adding a given frame on top of the stack. /// </summary> /// <param name="frame"></param> /// <returns>This environment.</returns> public Environment Extend(EnvironmentFrame frame) { m_Env.Push(frame); return(this); }