~mna/snow

b73673a04d733741e60cd2809300f586ec8048f6 — Martin Angers 1 year, 8 months ago 693bd0a
pkg/codegen: simple generic struct works
M pkg/codegen/mangle.go => pkg/codegen/mangle.go +17 -7
@@ 117,6 117,13 @@ func (r *nameResolver) NameForDecl(n semantic.Decl) string {
	return nm
}

func (r *nameResolver) NameForStructType(st *semantic.StructType) string {
	if !st.Decl.IsGeneric() {
		return r.NameForDecl(st.Decl)
	}
	return r.NameForGenericDeclAndTypes(st.Decl, st.Inst)
}

func (r *nameResolver) NameForGenericInst(gi *semantic.GenericInst) string {
	if nm, ok := r.genNames[gi]; ok {
		return nm


@@ 126,15 133,18 @@ func (r *nameResolver) NameForGenericInst(gi *semantic.GenericInst) string {
	_, insts := gd.GenInsts()
	types := insts[gi]

	r.genNames[gi] = r.NameForGenericDeclAndTypes(gd, types)
	return r.genNames[gi]
}

func (r *nameResolver) NameForGenericDeclAndTypes(decl semantic.Decl, types []semantic.Type) string {
	var b fmtBuilder
	b.withPrefixFor(gd)
	typesID := r.idForGenericInst(gd, types)
	b.withPrefixFor(decl)
	typesID := r.idForGenericInst(decl, types)

	r.genNames[gi] = b.get(gd.Ident() +
	return b.get(decl.Ident() +
		string(scanner.NameManglingSeparator) +
		strconv.Itoa(typesID))

	return r.genNames[gi]
}

func (r *nameResolver) idForGenericInst(genDecl semantic.Decl, types []semantic.Type) int {


@@ 165,13 175,13 @@ func (r *nameResolver) NameForTuple(index int, exported bool) string {
	return b.get(strconv.Itoa(index))
}

func (r *nameResolver) NameForStructInit(str *semantic.Struct) string {
func (r *nameResolver) NameForStructInit(baseName string) string {
	// TODO: for now, just append the separator and "new", so it gets exported if
	// the struct is exported. This will require more thought when pub gets added,
	// as some struct fields might be exported but others not, and the struct
	// still has to be fully initialized on return. Possibly a static analysis
	// that makes sure all fields are assigned in the initializer.
	return r.NameForDecl(str) + string(scanner.NameManglingSeparator) + "new"
	return baseName + string(scanner.NameManglingSeparator) + "new"
}

// NameForConv returns the Go name for an automatically- generated function to

A pkg/codegen/testdata/struct_simple_generic.snow.err => pkg/codegen/testdata/struct_simple_generic.snow.err +0 -0
A pkg/codegen/testdata/struct_simple_generic.snow.want => pkg/codegen/testdata/struct_simple_generic.snow.want +29 -0
@@ 0,0 1,29 @@
package main

import "fmt"

type _اAا0 struct {
	_اx int
}

func _اAا0اnew(
	s _اAا0,
	m map[string]bool,
) _اAا0 {
	var r _اAا0
	if m["x"] {
		r._اx = s._اx
	}
	return r
}

func main() {
	var a _اAا0 = _اAا0اnew(_اAا0{_اx: 1}, map[string]bool{"x": true})
	_اprintln(a._اx)
}

func _اprintln(
	i int,
) {
	fmt.Println(i)
}

M pkg/codegen/translate.go => pkg/codegen/translate.go +25 -20
@@ 39,6 39,10 @@ type translator struct {
	// expressions are generated and returned to the parent node, and are not
	// recorded in nodeToGenerated.
	generatedExpr goast.Expr

	// TODO: maybe something like...
	//topLevel        *list.List // file-level
	//parentContainer *list.List // stack-like for current container, e.g. body block
}

type convertFnKey struct {


@@ 117,7 121,7 @@ func (t *translator) Visit(n semantic.Node) semantic.Visitor {
			break
		}
		name := t.resolver.NameForDecl(n)
		t.append(n, t.createStruct(name, n)...)
		t.append(n, t.createStruct(name, semantic.AsStructType(n.Type()))...)

	case *semantic.Var:
		name := t.resolver.NameForDecl(n)


@@ 257,7 261,7 @@ func (t *translator) Visit(n semantic.Node) semantic.Visitor {

		if n.InitOf != nil {
			// TODO : the name for the initialized struct should be the instantiated one
			// if n.Fun triggers a generic inst...???
			// if n.Fun triggers a generic inst...??? Maybe use the type to get the name?
			t.generatedExpr = t.callStructInit(n)
			break
			// TODO: once modules exist, the n.Fun might be a qualified struct type, and the initializer


@@ 384,14 388,14 @@ func (t *translator) createFn(nm string, fn *semantic.Fn) []goast.Node {
	return createFuncLit(nm, ft, body)
}

func (t *translator) createStruct(nm string, str *semantic.Struct) []goast.Node {
func (t *translator) createStruct(nm string, strTyp *semantic.StructType) []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))}
	fields := &goast.FieldList{List: make([]*goast.Field, len(strTyp.Decl.Vars))}

	// 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 {
	for i, prop := range strTyp.Decl.Vars {
		semantic.Walk(t, prop)
		propDecls := t.nodeToGenerated[prop]
		vs := propDecls[len(propDecls)-1].(*goast.GenDecl).Specs[0].(*goast.ValueSpec)


@@ 412,13 416,13 @@ func (t *translator) createStruct(nm string, str *semantic.Struct) []goast.Node 
	}

	// generate struct initializer function
	strInit := t.createStructInit(str, propInit)
	strInit := t.createStructInit(nm, strTyp, propInit)

	// generate methods and nested structs
	for _, meth := range str.Fns {
	for _, meth := range strTyp.Decl.Fns {
		semantic.Walk(t, meth)
	}
	for _, str := range str.Structs {
	for _, str := range strTyp.Decl.Structs {
		semantic.Walk(t, str)
	}



@@ 488,7 492,7 @@ func (t *translator) goTypeExprFor(T semantic.Type) goast.Expr {
		return st

	case *semantic.StructType:
		name := t.resolver.NameForDecl(T.Decl)
		name := t.resolver.NameForStructType(T)
		return &goast.Ident{Name: name}

	default:


@@ 598,14 602,15 @@ func (t *translator) callStructInit(c *semantic.Call) *goast.CallExpr {
	// The struct initializer has the signature (where S is the struct type):
	// func init(s S, m map[string]bool) S
	// The map m contains the labels (unmangled field names) set by the caller.
	strName := t.resolver.NameForStructType(semantic.AsStructType(c.Fun.Type()))
	ce := &goast.CallExpr{
		Fun:  &goast.Ident{Name: t.resolver.NameForStructInit(c.InitOf)},
		Fun:  &goast.Ident{Name: t.resolver.NameForStructInit(strName)},
		Args: make([]goast.Expr, 2),
	}

	// build the struct argument
	strLit := &goast.CompositeLit{
		Type: &goast.Ident{Name: t.resolver.NameForDecl(c.InitOf)},
		Type: &goast.Ident{Name: strName},
		Elts: make([]goast.Expr, len(c.Args)),
	}
	for i, arg := range c.Args {


@@ 635,29 640,29 @@ func (t *translator) callStructInit(c *semantic.Call) *goast.CallExpr {
	return ce
}

func (t *translator) createStructInit(str *semantic.Struct, propInit map[*semantic.Var][]goast.Expr) *goast.FuncDecl {
func (t *translator) createStructInit(baseName string, strTyp *semantic.StructType, propInit map[*semantic.Var][]goast.Expr) *goast.FuncDecl {
	// The struct initializer has the signature (where S is the struct type):
	// func init(s S, m map[string]bool) S
	// The map m contains the labels (unmangled field names) set by the caller.

	strTyp := t.goTypeExprFor(str.Type())
	strTypExpr := t.goTypeExprFor(strTyp)
	// declare the return variable
	ret := &goast.GenDecl{
		Tok: gotoken.VAR,
		Specs: []goast.Spec{
			&goast.ValueSpec{
				Names: []*goast.Ident{{Name: "r"}},
				Type:  strTyp,
				Type:  strTypExpr,
			},
		},
	}

	// build the statements that make up the body of the function
	stmts := make([]goast.Stmt, 0, len(str.Vars)*2+1)
	stmts := make([]goast.Stmt, 0, len(strTyp.Decl.Vars)*2+1)
	stmts = append(stmts, &goast.DeclStmt{Decl: ret})

	// assign variables with initial values, and overwrite if value was provided
	for _, v := range str.Vars {
	for _, v := range strTyp.Decl.Vars {
		name := t.resolver.NameForDecl(v)

		if v.Value != nil {


@@ 697,10 702,10 @@ func (t *translator) createStructInit(str *semantic.Struct, propInit map[*semant

	// create the partial signature type, minus the map as this is not a concept
	// that exists in Snow yet.
	name := t.resolver.NameForStructInit(str)
	name := t.resolver.NameForStructInit(baseName)
	sig := &semantic.SignatureType{
		Params: []semantic.Type{str.Type()},
		Return: str.Type(),
		Params: []semantic.Type{strTyp},
		Return: strTyp,
	}
	ft := t.goTypeExprFor(sig).(*goast.FuncType)



@@ 753,7 758,7 @@ func (t *translator) renderGenInst(gi *semantic.GenericInst, name string) {
	case *semantic.Fn:
		t.append(decl, t.createFn(name, decl)...)
	case *semantic.Struct:
		t.append(decl, t.createStruct(name, decl)...)
		t.append(decl, t.createStruct(name, semantic.AsStructType(gi.Type()))...)
	default:
		panic(fmt.Sprintf("invalid generic type to render: %T", decl))
	}