@@ 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))
}
}