func (self *Let) Eval(s *scope.Scope) value.Value { // The <init>s are evaluated in the current environment // (in some unspecified order), the <variable>s are bound // to fresh locations holding the results, the <body> is // evaluated in the extended environment, and the value(s) // of the last expression of <body> is(are) returned. env := scope.NewScope(s) extended := scope.NewScope(s) for i := 0; i < len(self.Patterns); i++ { binder.Define(extended, self.Patterns[i].Identifier, self.Exprs[i].Eval(env)) } return self.Body.Eval(extended) }
func (self *LetRec) Eval(s *scope.Scope) value.Value { // The <variable>s are bound to fresh locations holding undefined values, // the <init>s are evaluated in the resulting environment // (in some unspecified order), each <variable> is assigned to the result of // the corresponding <init>, the <body> is evaluated in the resulting // environment, and the value(s) of the last expression in <body> is(are) // returned. Each binding of a <variable> has the entire letrec expression // as its region, making it possible to define mutually recursive procedures. env := scope.NewScope(s) extended := make([]*scope.Scope, len(self.Patterns)) for i := 0; i < len(self.Patterns); i++ { extended[i] = scope.NewScope(env) binder.Define(extended[i], self.Patterns[i].Identifier, self.Exprs[i].Eval(env)) } for i := 0; i < len(extended); i++ { env.PutAll(extended[i]) } return self.Body.Eval(env) }
func (self *Go) Eval(env *scope.Scope) value.Value { // We need to recover the panic message of goroutine go func() { defer func() { if err := recover(); err != nil { fmt.Println(err) } }() self.Expr.Eval(scope.NewScope(env)) }() return nil }
func (self *LetStar) Eval(env *scope.Scope) value.Value { // Let* is similar to let, but the bindings are performed sequentially // from left to right, and the region of a binding indicated by // (<variable> <init>) is that part of the let* expression to the right // of the binding. Thus the second binding is done in an environment in // which the first binding is visible, and so on. for i := 0; i < len(self.Patterns); i++ { env = scope.NewScope(env) binder.Define(env, self.Patterns[i].Identifier, self.Exprs[i].Eval(env)) } return self.Body.Eval(env) }
func (self *Call) Eval(s *scope.Scope) value.Value { callee := self.Callee.Eval(s) // we will handle (+ . (1)) latter args := EvalList(self.Args, s) switch callee.(type) { case *value.Closure: curry := callee.(*value.Closure) env := scope.NewScope(curry.Env.(*scope.Scope)) lambda, ok := curry.Body.(*Lambda) if !ok { panic(fmt.Sprint("unexpected type: ", curry.Body)) } // bind call arguments to parameters // these nodes should be in Lisp pair structure BindArguments(env, lambda.Params, converter.SliceToPairValues(args)) return lambda.Body.Eval(env) case value.PrimFunc: return callee.(value.PrimFunc).Apply(args) default: panic(fmt.Sprintf("%s: not allowed in a call context, args: %s", callee, self.Args[0])) } }