func primFunctionParams(e Env, head ast.Node, args []ast.Node) ast.Node { arg := args[0] switch val := arg.(type) { case *Function: return ast.NewList(val.Parameters) default: panicEvalError(args[0], "Argument to 'function-params' not a function: "+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 evalFunctionApplication(dynamicEnv Env, f *Function, head ast.Node, unevaledArgs []ast.Node, shouldEvalMacros bool) packet { // Validate parameters isVariableNumberOfParams := false for _, param := range f.Parameters { paramName := toSymbolName(param) if paramName == "&rest" { isVariableNumberOfParams = true } } if !isVariableNumberOfParams { if len(unevaledArgs) != len(f.Parameters) { panicEvalError(head, fmt.Sprintf( "Function '%v' expects %v argument(s), but was given %v", f.Name, len(f.Parameters), len(unevaledArgs))) } } // Create the lexical environment based on the function'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) }) } }