func primProcedureParams(e Env, head ast.Node, args []ast.Node) ast.Node { arg := args[0] switch val := arg.(type) { case *Procedure: return ast.NewList(val.Parameters) default: panicEvalError(args[0], "Argument to 'routine-params' not a procedure: "+arg.String()) } return nil }
func primNow(e Env, head ast.Node, args []ast.Node) ast.Node { t := time.Now() year, month, day := t.Date() hour, minute, second := t.Clock() result := ast.NewList([]ast.Node{ &ast.Number{Value: float64(year)}, &ast.Number{Value: float64(month)}, &ast.Number{Value: float64(day)}, &ast.Number{Value: float64(hour)}, &ast.Number{Value: float64(minute)}, &ast.Number{Value: float64(second)}, }) return result }
func evalInvokeProcedure(dynamicEnv Env, f *Procedure, head ast.Node, unevaledArgs ast.Nodes, shouldEvalMacros bool) packet { defer func() { if e := recover(); e != nil { switch errorValue := e.(type) { case *EvalError: fmt.Printf("TRACE: (%v: %v): call to %v\n", head.Loc().Filename, head.Loc().Line, f.Name) panic(errorValue) default: panic(errorValue) } } }() // Validate parameters isVariableNumberOfParams := false for _, param := range f.Parameters { switch paramVal := param.(type) { case *ast.Symbol: if paramVal.Name == "&rest" { isVariableNumberOfParams = true } default: panicEvalError(head, "Procedure parameters should only be symbols: "+param.String()) } } if !isVariableNumberOfParams { if len(unevaledArgs) != len(f.Parameters) { panicEvalError(head, fmt.Sprintf( "Procedure '%v' expects %v argument(s), but was given %v. Procedure parameter list: %v. Arguments: %v.", f.Name, len(f.Parameters), len(unevaledArgs), f.Parameters, unevaledArgs)) } } // Create the lexical environment based on the procedure's lexical parent lexicalEnv := NewMapEnv(f.Name, f.ParentEnv) // Prepare the arguments for application var args []ast.Node if f.IsMacro { args = unevaledArgs } else { args = evalEachNode(dynamicEnv, unevaledArgs) } // Map arguments to parameters isMappingRestArgs := false iarg := 0 for iparam, param := range f.Parameters { paramName := toSymbolName(param) if isMappingRestArgs { restArgs := args[iarg:] restList := ast.NewList(restArgs) lexicalEnv.Set(paramName, restList) } else if paramName == "&rest" { isMappingRestArgs = true } else { lexicalEnv.Set(paramName, args[iparam]) iarg++ } } if f.IsMacro { expandedMacro := trampoline(func() packet { return evalNode(lexicalEnv, f.Body) }) if shouldEvalMacros { return bounce(func() packet { // This is executed in the environment of its application, not the // environment of its definition return evalNode(dynamicEnv, expandedMacro) }) } else { return respond(expandedMacro) } } else { // Evaluate the body in the new lexical environment return bounce(func() packet { return evalNode(lexicalEnv, f.Body) }) } }