func (np NodeProcedure) Apply(e *Evaluator, argVals *gol.NodeList) (gol.Node, error) { if argVals.Len() != np.Args.Len() { return nil, gol.NodeErrorf(argVals, "Arg mismatch") } f := gol.Frame{} z := np.Args.Zip(argVals) err := z.Foreach(func(n gol.Node) error { pair, ok := n.(*gol.NodePair) if !ok { return gol.NodeErrorf(argVals, "Internal error - zip returns non-pair") } id := pair.Car val := pair.Cdr idStr := id.String() f[idStr] = val return nil }) if err != nil { return nil, err } oldEnv := e.Env defer func() { e.Env = oldEnv }() e.Env = np.Env.WithFrame(f) value, err := e.Eval(np.Body) return value, err }
func (gb *GolangBackend) compileFuncCall(funcNameNode *gol.NodeIdentifier, argNodes *gol.NodeList) (string, error) { funcName := mangleIdentifier(funcNameNode.String()) args := []string{} err := argNodes.Foreach(func(n gol.Node) error { nStr, err := gb.compile(n) if err != nil { return err } args = append(args, nStr) return nil }) if err != nil { return "", err } s := funcName + "(" + strings.Join(args, ", ") + ")" return s, nil }
func (e *Evaluator) evalList(nl *gol.NodeList) (gol.Node, error) { nodes, err := nl.Map(func(child gol.Node) (gol.Node, error) { newVal, err := e.Eval(child) if err != nil { return nil, err } return newVal, nil }) if err != nil { return nil, err } if e.Quoting() { return nodes, nil } return e.Apply(nodes) }
func (gb *GolangBackend) compileLambdaApplication(nl *gol.NodeLambda, vals *gol.NodeList) (string, error) { bindings := make(map[string]gol.Node) args := nl.Args if args.Len() != vals.Len() { return "", fmt.Errorf("Wrong number of args for lambda. [%s] != [%s]", args.String(), vals.String()) } for vals.Len() > 0 { id := args.First().String() bindings[id] = vals.First() vals = vals.Rest() args = args.Rest() } letForLambda := &gol.NodeLet{ // NodeList: nl.NodeList, Bindings: bindings, Body: nl.Body, } lambdaVarType, ok := nl.Type().(*typ.Var) if !ok { // Not an error if it's a functype, but we assign vars to all nodes.... return "", fmt.Errorf("Odd - not a var, instead a %T: %s\n", nl.Type(), nl.Type()) } lambdaType, err := lambdaVarType.Lookup() if err != nil { return "", fmt.Errorf("Can't look up lambda var: %s [%T]\n", lambdaVarType, lambdaVarType) } funcType, ok := lambdaType.(typ.Func) if !ok { return "", fmt.Errorf("Lambda doesn't have function type: %s [%T]\n", nl.Type(), nl.Type()) } letForLambda.NodeList = gol.NewNodeListType(funcType.Result) return gb.compileLet(letForLambda) }
func (gb *GolangBackend) compileList(nl *gol.NodeList) (string, error) { if nl.Len() == 0 { return "", gol.NodeErrorf(nl, "empty application") } switch fst := nl.First().(type) { case *gol.NodeIdentifier: return gb.compileFuncCall(fst, nl.Rest()) case *gol.NodeLambda: return gb.compileLambdaApplication(fst, nl.Rest()) default: return "", fmt.Errorf("Non-applicable in head position: %T", fst) } }
func (e *Evaluator) Apply(nl *gol.NodeList) (gol.Node, error) { if nl.Len() == 0 { return nil, gol.NodeErrorf(nl, "Empty application") } applicable, ok := nl.First().(NodeApplicable) if !ok { return nil, gol.NodeErrorf(nl, "Can't evaluate list with non-applicable head: %T [%s]", nl.First(), nl) } node, err := applicable.Apply(e, nl.Rest()) if err != nil { return nil, err } return node, nil }