Example #1
0
File: node.go Project: jbert/gol
func (ni NodeIdentifier) NodeUnify(t typ.Type, env typ.Env) error {
	envType, err := env.Lookup(ni.String())
	if err != nil {
		return err
	}
	// Unify our lazy var with our env type
	err = ni.t.Unify(envType)
	if err != nil {
		return err
	}
	// And with the passed in type
	return envType.Unify(t)
}
Example #2
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
}