~mna/snow

f403078a7866d9f7107b7c666ea16f424050c5c6 — Martin Angers 1 year, 9 months ago 2fc62bc
pkg/codegen: done with generating nodes for struct generics and all
1 files changed, 29 insertions(+), 47 deletions(-)

M pkg/codegen/translate.go
M pkg/codegen/translate.go => pkg/codegen/translate.go +29 -47
@@ 27,6 27,8 @@ type translator struct {
	convertFns map[convertFnKey]string
	// map of active replacement types for generic placeholder types
	curGenInst map[*semantic.GenericType]semantic.Type
	// set of already rendered generic instantiations, based on the mangled name
	renderedGenInsts map[string]bool

	// map of semantic.Node to []goast.Node, in the order they must appear when
	// processed by snow source order. Only statements, declarations and other


@@ 42,6 44,8 @@ type convertFnKey struct {
	from, to semantic.Type
}

type topLevelNode goast.Node

func (t *translator) append(n semantic.Node, gonodes ...goast.Node) {
	t.nodeToGoAST[n] = append(t.nodeToGoAST[n], gonodes...)
}


@@ 68,6 72,7 @@ func (t *translator) Visit(n semantic.Node) semantic.Visitor {
	case *semantic.Unit:
		t.nodeToGoAST = make(map[semantic.Node][]goast.Node)
		t.convertFns = make(map[convertFnKey]string)
		t.renderedGenInsts = make(map[string]bool)
		for _, f := range n.Files {
			t.curFile = f
			semantic.Walk(t, f)


@@ 302,7 307,7 @@ func (t *translator) Visit(n semantic.Node) semantic.Visitor {
	case *semantic.GenericInst:
		// render this generic instantiation if not already rendered
		name := t.resolver.NameForGenericInst(n)
		//t.renderGenInst(n, name)
		t.renderGenInst(n, name)
		t.generatedExpr = &goast.Ident{Name: name}

	case *semantic.Ident:


@@ 364,22 369,22 @@ func (t *translator) createFn(nm string, fn *semantic.Fn) []goast.Node {
		if str := fn.MethodOf; str != nil {
			t.convertFuncToMethod(fd, str, fn.IsRef)
		}
		return []goast.Node{fd}
		return []goast.Node{topLevelNode(fd)}
	}
	return createFuncLit(nm, ft, body)
}

func (t *translator) createStruct(nm string, str *semantic.Struct) interface{} {
	// all struct declarations are attached to the top-level scope of the
	// file, so the t.generated returned is nil (as the case takes care of
	// adding the struct to the file.Decls).
func (t *translator) createStruct(nm string, str *semantic.Struct) []goast.Node {
	// all struct declarations are attached to the top-level scope of the file.
	fields := &goast.FieldList{List: make([]*goast.Field, len(str.Vars))}

	// keep a map of values, will be used to generate the struct initializer
	// keep a map of field values, will be used to generate the struct
	// initializer
	propInit := make(map[*semantic.Var][]goast.Expr)
	for i, prop := range str.Vars {
		semantic.Walk(t, prop)
		vs := t.generated.(*goast.GenDecl).Specs[0].(*goast.ValueSpec)
		propDecls := t.nodeToGoAST[prop]
		vs := propDecls[len(propDecls)-1].(*goast.GenDecl).Specs[0].(*goast.ValueSpec)
		fields.List[i] = &goast.Field{
			Names: vs.Names,
			Type:  vs.Type,


@@ 388,30 393,26 @@ func (t *translator) createStruct(nm string, str *semantic.Struct) interface{} {
			propInit[prop] = vs.Values
		}
	}
	t.curFile.Decls = append(t.curFile.Decls, &goast.GenDecl{

	decl := &goast.GenDecl{
		Tok: gotoken.TYPE,
		Specs: []goast.Spec{
			&goast.TypeSpec{Name: &goast.Ident{Name: nm}, Type: &goast.StructType{Fields: fields}},
		},
	})
	}

	// generate struct initializer function
	strInit := t.createStructInit(str, propInit)
	t.curFile.Decls = append(t.curFile.Decls, strInit)

	// generate methods and nested structs
	for _, meth := range str.Fns {
		semantic.Walk(t, meth)
		switch fd := t.generated.(type) {
		case *goast.FuncDecl:
			t.curFile.Decls = append(t.curFile.Decls, fd)
		}
	}
	for _, str := range str.Structs {
		semantic.Walk(t, str)
		// structs are added on top-level file, so no t.generated is returned
	}
	t.generated = nil

	return []goast.Node{topLevelNode(decl), topLevelNode(strInit)}
}

func (t *translator) addFileImports(f *semantic.File, gof *goast.File) {


@@ 601,7 602,7 @@ func (t *translator) callStructInit(c *semantic.Call) *goast.CallExpr {
		semantic.Walk(t, arg)
		kve := &goast.KeyValueExpr{
			Key:   &goast.Ident{Name: t.resolver.NameForDecl(lblToDecl[c.Labels[i]])},
			Value: t.generated.(goast.Expr),
			Value: t.generatedExpr,
		}
		strLit.Elts[i] = kve
	}


@@ 712,22 713,12 @@ func (t *translator) createStructInit(str *semantic.Struct, propInit map[*semant
}

func (t *translator) renderGenInst(gi *semantic.GenericInst, name string) {
	decl := gi.GenericDecl.Ref
	info, ok := t.genDecls[decl]
	if !ok || info.slice == nil {
		// record the instantiation as pending, will be rendered when the declaration is processed.
		if info.pendingRenders == nil {
			info.pendingRenders = make(map[*semantic.GenericInst]string)
		}
		info.pendingRenders[gi] = name
		t.genDecls[decl] = info
		return
	}
	if info.renderedNames[name] {
	if t.renderedGenInsts[name] {
		return
	}

	info.renderedNames[name] = true
	t.renderedGenInsts[name] = true
	decl := gi.GenericDecl.Ref

	gd := decl.(semantic.GenericDecl)
	_, insts := gd.GenInsts()


@@ 736,22 727,13 @@ func (t *translator) renderGenInst(gi *semantic.GenericInst, name string) {
	old := t.cloneGenInst(gd.GenClause(), types)
	defer func() { t.curGenInst = old }()

	node := t.createFn(name, decl.(*semantic.Fn)) // TODO: for now, only fn
	switch node := node.(type) {
	case goast.Decl:
		target := info.slice.(*[]goast.Decl)
		if len(*target) < info.index {
			*target = append(*target, node)
		} else {
			*target = append((*target)[:info.index], append([]goast.Decl{node}, (*target)[info.index:]...)...)
		}
	case []goast.Stmt:
		target := info.slice.(*[]goast.Stmt)
		if len(*target) < info.index {
			*target = append(*target, node...)
		} else {
			*target = append((*target)[:info.index], append(node, (*target)[info.index:]...)...)
		}
	switch decl := decl.(type) {
	case *semantic.Fn:
		t.append(decl, t.createFn(name, decl)...)
	case *semantic.Struct:
		t.append(decl, t.createStruct(name, decl)...)
	default:
		panic(fmt.Sprintf("invalid generic type to render: %T", decl))
	}
}