func (p *parser) parseFuncDecl(n *parse.Node) ast.Decl { scope := ast.NewScope(p.topScope) funcDecl := ast.FuncDecl{ Name: p.parseIdent(n.Child(1)), } funcOrSig := n.Child(2).Child(0) if funcOrSig.Rule() == signature { funcDecl.Type = p.parseSignature(funcOrSig, scope) } else { funcDecl.Type, funcDecl.Body = p.parseFunc(funcOrSig, scope) } funcDecl.Type.Func = token.Pos(n.Child(0).Pos()) return &funcDecl }
// topLevelNodeToDecl converts an AST node to Go ast.Decl func topLevelNodeToDecl(node *parser.CallNode) ast.Decl { if node.Callee.(*parser.IdentNode).Ident != "defn" { panic("Top level node has to be defn") } switch node.Callee.(*parser.IdentNode).Ident { case "defn": decl := ast.FuncDecl{ Name: &ast.Ident{ NamePos: 2, Name: node.Args[0].(*parser.IdentNode).Ident, }, } fmt.Printf("SHOW ARGS: %+v\n", node.Args[1:]) // @TODO Fix this to support signature properly params := &ast.FieldList{ Opening: 1, Closing: 3, } params.List = make([]*ast.Field, 1) params.List[0] = &ast.Field{ Names: []*ast.Ident{ &ast.Ident{ Name: "lol", }, }, Type: &ast.Ident{ Name: "interface{}", }, } decl.Type = &ast.FuncType{ Func: 1, Params: params, Results: nil, } //decl.Body = nodeFnBody(node.Args[1:]) // TODO: Check argument lengths decl.Body = nodeFnBody(node.Args[1]) return &decl default: // The rest is normal function call probably //return nodeFnCall(node) fmt.Println("got nil %+v", node) return nil } }
func transformAction(action *ast.FuncDecl) { // Save the old function signature, then replace it with the standard http request handler signature... params := action.Type.Params action.Type = ActionFuncDecl.Type /* Create some strconv statements to parse URL parameters, then stick those lines at the top of the function body. Going to need to change this if we ever want to support more than oneliner converters... */ blockStmtList := make([]*ast.BlockStmt, params.NumFields()) for i, field := range params.List { paramName := field.Names[0].Name paramType := field.Type.(*ast.Ident).Name donorBody := createParamConverterBlockStmt(paramName, paramType) blockStmtList[i] = donorBody } totalStmts := 0 for _, blockStmt := range blockStmtList { totalStmts += len(blockStmt.List) } newBodyList := make([]ast.Stmt, 0, totalStmts+len(action.Body.List)) for _, blockStmt := range blockStmtList { for _, stmt := range blockStmt.List { newBodyList = append(newBodyList, stmt) } } newBodyList = append(newBodyList, action.Body.List...) action.Body.List = newBodyList }
// Track imports simplifies all imports into a single large package // with mangled names. In the process, it drops functions that are // never referred to. func TrackImports(pkgs map[string](map[string]*ast.File)) (main *ast.File) { // Let's first set of the package we're going to generate... main = new(ast.File) main.Name = ast.NewIdent("main") initstmts := []ast.Stmt{} // this is where we'll stash the init statements... todo := make(map[string]struct{}) todo["main.init"] = struct{}{} todo["main.main"] = struct{}{} done := make(map[string]struct{}) for len(todo) > 0 { for pkgfn := range todo { pkg := splitLast(pkgfn, ".")[0] // FIXME: Need to split after last "." only fn := splitLast(pkgfn, ".")[1] fmt.Println("Working on", fn, "in", pkg) if _, ok := done[pkg+".init"]; !ok && fn != "init" { // We still need to init this package! todo[pkg+".init"] = struct{}{} } // fmt.Println("Working on package", pkg, "function", fn) // We need to look in all this package's files... for _, f := range pkgs[pkg] { // FIXME: it'd be marginally faster to first check if the // function we want is in this particular file. On the other // hand, when there's only one file per package, that would be // slower... // First we'll track down the import declarations... sc := PackageScoping{ Imports: make(map[string]string), Globals: make(map[string]string), } for _, d := range f.Decls { if i, ok := d.(*ast.GenDecl); ok && i.Tok == token.IMPORT { for _, s := range i.Specs { ispec := s.(*ast.ImportSpec) // This should always be okay! path, _ := strconv.Unquote(string(ispec.Path.Value)) name := path if ispec.Name != nil { name = ispec.Name.Name } else { for _, f := range pkgs[path] { name = f.Name.Name } } sc.Imports[name] = path } } else if vdecl, ok := d.(*ast.GenDecl); ok && vdecl.Tok == token.VAR { for _, spec0 := range vdecl.Specs { spec := spec0.(*ast.ValueSpec) for _, n := range spec.Names { sc.Globals[n.Name] = pkg } } } else if tdecl, ok := d.(*ast.GenDecl); ok && vdecl.Tok == token.TYPE { for _, spec0 := range tdecl.Specs { spec := spec0.(*ast.TypeSpec) sc.Globals[spec.Name.Name] = pkg } } else if fdecl, ok := d.(*ast.FuncDecl); ok { sc.Globals[fdecl.Name.Name] = pkg } } // Now we'll go ahead and mangle things... for _, d := range f.Decls { if cdecl, ok := d.(*ast.GenDecl); ok && cdecl.Tok == token.CONST { fmt.Println("FIXME: I don't handle const yet at all... (ignoring)") } else if tdecl, ok := d.(*ast.GenDecl); ok && tdecl.Tok == token.TYPE { for _, spec0 := range tdecl.Specs { spec := spec0.(*ast.TypeSpec) if spec.Name.Name == fn { // fmt.Println("Got type declaration of", spec.Name) spec := *spec spec.Name = ast.NewIdent(fn) spec.Type = sc.MangleExpr(spec.Type) sc.MangleExpr(spec.Name) d := &ast.GenDecl{ Tok: token.TYPE, Specs: []ast.Spec{&spec}, } main.Decls = append(main.Decls, d) } } } else if vdecl, ok := d.(*ast.GenDecl); ok && vdecl.Tok == token.VAR { for _, spec0 := range vdecl.Specs { spec := spec0.(*ast.ValueSpec) for i, n := range spec.Names { if n.Name == fn { // fmt.Println("I got variable", fn) nnew := *n sc.MangleExpr(&nnew) vs := []ast.Expr(nil) if len(spec.Values) > i { vs = append(vs, spec.Values[i]) sc.MangleExpr(spec.Values[i]) } sc.MangleExpr(spec.Type) d := ast.GenDecl{ Tok: token.VAR, Specs: []ast.Spec{ &ast.ValueSpec{ Names: []*ast.Ident{&nnew}, Type: spec.Type, Values: vs, }, }, } main.Decls = append(main.Decls, &d) } } } } else if fdecl, ok := d.(*ast.FuncDecl); ok { if fdecl.Name.Name == fn { // first, let's update the name... but in a copy of the // function declaration fdecl := *fdecl fdecl.Name = ast.NewIdent(pkg + "_" + fn) if fdecl.Type.Params != nil { for _, f := range fdecl.Type.Params.List { sc.MangleExpr(f.Type) } } if fdecl.Type.Results != nil { for _, f := range fdecl.Type.Results.List { sc.MangleExpr(f.Type) } } sc.MangleStatement(fdecl.Body) // fmt.Println("Dumping out", pkg, fn) main.Decls = append(main.Decls, &fdecl) if fn == "init" && fdecl.Recv == nil { initstmts = append(initstmts, &ast.ExprStmt{&ast.CallExpr{Fun: fdecl.Name}}) } } } } // See what else we need to compile... for _, x := range sc.ToDo { if _, done := done[x]; !done { todo[x] = struct{}{} } } } delete(todo, pkgfn) done[pkgfn] = struct{}{} } } // Now we reverse the order, so that the declarations will be in // C-style order, not requiring forward declarations. newdecls := make([]ast.Decl, len(main.Decls)) for i := range main.Decls { newdecls[i] = main.Decls[len(main.Decls)-i-1] } main.Decls = newdecls mainfn := new(ast.FuncDecl) mainfn.Name = ast.NewIdent("main") mainfn.Type = &ast.FuncType{Params: &ast.FieldList{}} initstmts = append(initstmts, &ast.ExprStmt{&ast.CallExpr{Fun: ast.NewIdent("main_main")}}) mainfn.Body = &ast.BlockStmt{List: initstmts} main.Decls = append(main.Decls, mainfn) return main }