Example #1
0
File: eval.go Project: jbert/gol
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
}
Example #2
0
File: eval.go Project: jbert/gol
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
}
Example #3
0
File: compile.go Project: jbert/gol
func (gb *GolangBackend) compile(node gol.Node) (string, error) {
	switch n := node.(type) {
	case *gol.NodeInt:
		return gb.compileInt(n)
	case *gol.NodeString:
		return gb.compileString(n)
	case *gol.NodeBool:
		return gb.compileBool(n)

	case *gol.NodeProgn:
		return gb.compileProgn(n)

	case *gol.NodeList:
		return gb.compileList(n)
	case *gol.NodeLet:
		return gb.compileLet(n)
	case *gol.NodeIdentifier:
		return gb.compileIdentifier(n)

	case *gol.NodeLambda:
		return gb.compileLambda(n)

	case *gol.NodeIf:
		return gb.compileIf(n)

	case *gol.NodeError:
		return gb.compileError(n)
	case *gol.NodeDefine:
		return gb.compileDefine(n)

	case *gol.NodeSymbol:
		return "", gol.NodeErrorf(n, "TODO node type %T", node)
	case *gol.NodeQuote:
		return "", gol.NodeErrorf(n, "TODO node type %T", node)
	case *gol.NodeUnQuote:
		return "", gol.NodeErrorf(n, "TODO node type %T", node)
	case *gol.NodeSet:
		return "", gol.NodeErrorf(n, "TODO node type %T", node)
	default:
		return "", gol.NodeErrorf(n, "Unrecognised node type %T", node)

	}
}
Example #4
0
File: infer.go Project: jbert/gol
func (gb *GolangBackend) infer(n gol.Node, typeEnv typ.Env, depth int) (int, error) {
	numChanges, err := gb.inferUnwrappedError(n, typeEnv, depth)
	if err != nil {
		_, isNodeErr := err.(*gol.NodeError)
		if !isNodeErr {
			err = gol.NodeErrorf(n, err.Error())
		}
	}
	return numChanges, err
}
Example #5
0
File: compile.go Project: jbert/gol
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)
	}
}
Example #6
0
File: eval.go Project: jbert/gol
func (e *Evaluator) evalIf(ni *gol.NodeIf) (gol.Node, error) {
	condition, err := e.Eval(ni.Condition)
	if err != nil {
		return nil, err
	}
	conditionBool, ok := condition.(*gol.NodeBool)
	if !ok {
		return nil, gol.NodeErrorf(ni, "Non-boolean in 'if' condition")
	}
	if conditionBool.IsTrue() {
		return e.Eval(ni.TBranch)
	} else {
		return e.Eval(ni.FBranch)
	}
}
Example #7
0
File: eval.go Project: jbert/gol
func (e *Evaluator) Eval(node gol.Node) (gol.Node, error) {
	switch n := node.(type) {
	case *gol.NodeError:
		return nil, n
	case *gol.NodeIdentifier:
		value, err := e.Env.Lookup(n.String())
		if err != nil {
			return nil, gol.NodeErrorf(node, "Failed to find [%s]: %s", n.String(), err.Error())
		}
		return value, nil
	case *gol.NodeInt:
		return n, nil
	case *gol.NodeSymbol:
		return n, nil
	case *gol.NodeString:
		return n, nil
	case *gol.NodeBool:
		return n, nil
	case *gol.NodeQuote:
		if n.Quasi {
			e.nesting++
			value, err := e.Eval(n.Arg)
			e.nesting--
			return value, err
		}
		return n.Arg, nil
	case *gol.NodeUnQuote:
		e.nesting--
		value, err := e.Eval(n.Arg)
		e.nesting++
		return value, err
	case *gol.NodeLambda:
		if e.Quoting() {
			return e.evalList(n.NodeList)
		}
		return e.evalLambda(n)
	case *gol.NodeList:
		if e.Quoting() {
			return e.evalList(n)
		}
		return e.evalList(n)
	case *gol.NodeIf:
		if e.Quoting() {
			return e.evalList(n.NodeList)
		}
		return e.evalIf(n)
	case *gol.NodeSet:
		if e.Quoting() {
			return e.evalList(n.NodeList)
		}
		return e.evalSet(n)
	case *gol.NodeLet:
		if e.Quoting() {
			return e.evalList(n.NodeList)
		}
		return e.evalLet(n)
	case *gol.NodeProgn:
		if e.Quoting() {
			return e.evalList(n.NodeList)
		}
		return e.evalProgn(n)
	case *gol.NodeDefine:
		if e.Quoting() {
			return e.evalList(n.NodeList)
		}
		return e.evalDefine(n)
	default:
		return nil, gol.NodeErrorf(n, "Unrecognised node type %T", node)

	}
}
Example #8
0
File: infer.go Project: jbert/gol
func (gb *GolangBackend) inferUnwrappedError(n gol.Node, typeEnv typ.Env, depth int) (int, error) {
	numChanges := 0

	iprintf := func(format string, args ...interface{}) {
		indentStr := indentString(depth)
		s := fmt.Sprintf(format, args...)
		log.Printf("infer: %d %s%s", depth, indentStr, s)
	}

	iprintf("node %p: %s [%T]: %s (%s)\n", n, n, n, n.Type(), typ.ResolveStr(n.Type()))
	// Remember this to see if we changed it
	origType := n.Type()

	switch node := n.(type) {
	case *gol.NodeProgn:
		iprintf("progn\n")
		first := true
		err := node.NodeList.ForeachLast(func(child gol.Node, last bool) error {
			if first {
				// Skip the 'progn' symbol
				first = false
				return nil
			}

			childChanges, err := gb.infer(child, typeEnv, depth+1)
			if err != nil {
				return err
			}
			numChanges += childChanges

			if last {
				// Type of last child should match that of progn as a whole
				iprintf("Inferring type %s for child %s (type %s)\n", n.Type(), child, child.Type())
				err = child.NodeUnify(n.Type(), typeEnv)
				if err != nil {
					return err
				}
			} else {
				// All other children should be void
				iprintf("Inferring void for %s [%T] %s\n", child, child.Type(), child.Type())
				err = child.NodeUnify(typ.Void, typeEnv)
				if err != nil {
					return err
				}
				iprintf("after infer void for %s [%T] %s\n", child, child.Type(), child.Type())
			}
			changed, err := gb.infer(child, typeEnv, depth+1)
			if err != nil {
				return err
			}
			numChanges += changed
			return nil
		})
		if err != nil {
			return 0, err
		}

	case *gol.NodeList:
		iprintf("nodelist\n")
		if node.Len() == 0 {
			return 0, fmt.Errorf("Empty application")
		}

		// What types are in the list?
		var head gol.Node
		argTypes := make([]typ.Type, 0)
		first := true
		node.Foreach(func(child gol.Node) error {
			childChanges, err := gb.infer(child, typeEnv, depth+1)
			if err != nil {
				return err
			}
			numChanges += childChanges

			if first {
				first = false
				head = child
			} else {
				argTypes = append(argTypes, child.Type())
			}
			return nil
		})

		// What type of function would fit these (and return type)?
		wantedType := typ.Func{
			Args:   argTypes,
			Result: node.Type(),
		}

		// Unify that what we have in head position
		err := head.NodeUnify(wantedType, typeEnv)
		if err != nil {
			return 0, err
		}

	case *gol.NodeLambda:
		iprintf("NodeLambda (%s): %s\n", n.String(), typ.ResolveStr(n.Type()))
		argTypes := make([]typ.Type, node.Args.Len())
		i := 0
		frame := make(map[string]typ.Type)
		err := node.Args.Foreach(func(child gol.Node) error {
			id, ok := child.(*gol.NodeIdentifier)
			if !ok {
				return gol.NodeErrorf(n, "non-identifier in lambda args: %s", child.String())
			}

			frame[id.String()] = child.Type()
			argTypes[i] = child.Type()
			i++
			return nil
		})
		if err != nil {
			return 0, err
		}

		oldEnv := typeEnv
		defer func() {
			typeEnv = oldEnv
		}()
		typeEnv = typeEnv.WithFrame(frame)

		childChanges, err := gb.infer(node.Body, typeEnv, depth+1)
		if err != nil {
			return 0, err
		}
		numChanges += childChanges

		resultType := node.Body.Type()

		calcType := typ.NewFunc(argTypes, resultType)
		err = node.NodeUnify(calcType, typeEnv)
		if err != nil {
			return 0, err
		}

	case *gol.NodeIdentifier:
		iprintf("NodeIdentifier (%s)\n", n.String())
		newType, err := typeEnv.Lookup(n.String())
		if err == nil {
			iprintf("NodeIdentifier (%s) [%s]\n", n.String(), newType.String())
			err = node.NodeUnify(newType, typeEnv)
			if err != nil {
				return 0, err
			}
		}

	case *gol.NodeLet:
		iprintf("NodeLet (%s)\n", n.String())

		frame := make(map[string]typ.Type)
		for k, v := range node.Bindings {
			frame[k] = v.Type()
			childChanges, err := gb.infer(v, typeEnv, depth+1)
			if err != nil {
				return 0, err
			}
			numChanges += childChanges
		}

		oldEnv := typeEnv
		defer func() {
			typeEnv = oldEnv
		}()
		typeEnv = typeEnv.WithFrame(frame)

		childChanges, err := gb.infer(node.Body, typeEnv, depth+1)
		if err != nil {
			return 0, err
		}
		numChanges += childChanges

		err = node.NodeUnify(node.Body.Type(), typeEnv)
		if err != nil {
			return 0, err
		}

	case *gol.NodeInt:
		err := node.NodeUnify(typ.Int, typeEnv)
		if err != nil {
			return 0, err
		}
	case *gol.NodeIf:
		iprintf("NodeIf (%s)\n", n.String())
		childChanges, err := gb.infer(node.Condition, typeEnv, depth+1)
		if err != nil {
			return 0, err
		}
		numChanges += childChanges
		childChanges, err = gb.infer(node.TBranch, typeEnv, depth+1)
		if err != nil {
			return 0, err
		}
		numChanges += childChanges
		childChanges, err = gb.infer(node.FBranch, typeEnv, depth+1)
		if err != nil {
			return 0, err
		}
		numChanges += childChanges

		err = node.Condition.NodeUnify(typ.Bool, typeEnv)
		if err != nil {
			return 0, err
		}
		err = node.TBranch.NodeUnify(node.Type(), typeEnv)
		if err != nil {
			return 0, err
		}
		err = node.FBranch.NodeUnify(node.Type(), typeEnv)
		if err != nil {
			return 0, err
		}

	case *gol.NodeError:

	case *gol.NodeSymbol:
	case *gol.NodeString:
	case *gol.NodeBool:

	case *gol.NodeDefine:
		// JB - hack into top level
		typeEnv.AddTopLevel(node.Symbol.String(), node.Value.Type())
		iprintf("NodeDefine (%s)\n", n.String())

		childChanges, err := gb.infer(node.Value, typeEnv, depth+1)
		if err != nil {
			return 0, err
		}
		numChanges += childChanges

	case *gol.NodePair:
		// TODO: use an And type here....
		// Can leave newType as Any since all Pairs have an inferred type

	case *gol.NodeQuote:
		panic("implement")
	case *gol.NodeUnQuote:
		panic("implement")
	case *gol.NodeSet:
		panic("implement")

	default:
		return 0, gol.NodeErrorf(n, "unrecognised/unhandled node type %T", n)

	}

	if n.Type() != origType {
		numChanges++
	}

	iprintf("done\n")

	return numChanges, nil
}