Example #1
0
File: parser.go Project: h12w/gombi
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
}
Example #2
0
// 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
	}
}
Example #3
0
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

}
Example #4
0
// 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
}