ast.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. // Copyright 2009 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // Parse input AST and prepare Prog structure.
  5. package main
  6. import (
  7. "fmt"
  8. "go/ast"
  9. "go/parser"
  10. "go/scanner"
  11. "go/token"
  12. "os"
  13. "path/filepath"
  14. "strings"
  15. )
  16. func parse(name string, flags parser.Mode) *ast.File {
  17. ast1, err := parser.ParseFile(fset, name, nil, flags)
  18. if err != nil {
  19. if list, ok := err.(scanner.ErrorList); ok {
  20. // If err is a scanner.ErrorList, its String will print just
  21. // the first error and then (+n more errors).
  22. // Instead, turn it into a new Error that will return
  23. // details for all the errors.
  24. for _, e := range list {
  25. fmt.Fprintln(os.Stderr, e)
  26. }
  27. os.Exit(2)
  28. }
  29. fatalf("parsing %s: %s", name, err)
  30. }
  31. return ast1
  32. }
  33. func sourceLine(n ast.Node) int {
  34. return fset.Position(n.Pos()).Line
  35. }
  36. // ReadGo populates f with information learned from reading the
  37. // Go source file with the given file name. It gathers the C preamble
  38. // attached to the import "C" comment, a list of references to C.xxx,
  39. // a list of exported functions, and the actual AST, to be rewritten and
  40. // printed.
  41. func (f *File) ReadGo(name string) {
  42. // Create absolute path for file, so that it will be used in error
  43. // messages and recorded in debug line number information.
  44. // This matches the rest of the toolchain. See golang.org/issue/5122.
  45. if aname, err := filepath.Abs(name); err == nil {
  46. name = aname
  47. }
  48. // Two different parses: once with comments, once without.
  49. // The printer is not good enough at printing comments in the
  50. // right place when we start editing the AST behind its back,
  51. // so we use ast1 to look for the doc comments on import "C"
  52. // and on exported functions, and we use ast2 for translating
  53. // and reprinting.
  54. ast1 := parse(name, parser.ParseComments)
  55. ast2 := parse(name, 0)
  56. f.Package = ast1.Name.Name
  57. f.Name = make(map[string]*Name)
  58. // In ast1, find the import "C" line and get any extra C preamble.
  59. sawC := false
  60. for _, decl := range ast1.Decls {
  61. d, ok := decl.(*ast.GenDecl)
  62. if !ok {
  63. continue
  64. }
  65. for _, spec := range d.Specs {
  66. s, ok := spec.(*ast.ImportSpec)
  67. if !ok || string(s.Path.Value) != `"C"` {
  68. continue
  69. }
  70. sawC = true
  71. if s.Name != nil {
  72. error_(s.Path.Pos(), `cannot rename import "C"`)
  73. }
  74. cg := s.Doc
  75. if cg == nil && len(d.Specs) == 1 {
  76. cg = d.Doc
  77. }
  78. if cg != nil {
  79. f.Preamble += fmt.Sprintf("#line %d %q\n", sourceLine(cg), name)
  80. f.Preamble += commentText(cg) + "\n"
  81. }
  82. }
  83. }
  84. if !sawC {
  85. error_(token.NoPos, `cannot find import "C"`)
  86. }
  87. // In ast2, strip the import "C" line.
  88. w := 0
  89. for _, decl := range ast2.Decls {
  90. d, ok := decl.(*ast.GenDecl)
  91. if !ok {
  92. ast2.Decls[w] = decl
  93. w++
  94. continue
  95. }
  96. ws := 0
  97. for _, spec := range d.Specs {
  98. s, ok := spec.(*ast.ImportSpec)
  99. if !ok || string(s.Path.Value) != `"C"` {
  100. d.Specs[ws] = spec
  101. ws++
  102. }
  103. }
  104. if ws == 0 {
  105. continue
  106. }
  107. d.Specs = d.Specs[0:ws]
  108. ast2.Decls[w] = d
  109. w++
  110. }
  111. ast2.Decls = ast2.Decls[0:w]
  112. // Accumulate pointers to uses of C.x.
  113. if f.Ref == nil {
  114. f.Ref = make([]*Ref, 0, 8)
  115. }
  116. f.walk(ast2, "prog", (*File).saveRef)
  117. // Accumulate exported functions.
  118. // The comments are only on ast1 but we need to
  119. // save the function bodies from ast2.
  120. // The first walk fills in ExpFunc, and the
  121. // second walk changes the entries to
  122. // refer to ast2 instead.
  123. f.walk(ast1, "prog", (*File).saveExport)
  124. f.walk(ast2, "prog", (*File).saveExport2)
  125. f.Comments = ast1.Comments
  126. f.AST = ast2
  127. }
  128. // Like ast.CommentGroup's Text method but preserves
  129. // leading blank lines, so that line numbers line up.
  130. func commentText(g *ast.CommentGroup) string {
  131. if g == nil {
  132. return ""
  133. }
  134. var pieces []string
  135. for _, com := range g.List {
  136. c := string(com.Text)
  137. // Remove comment markers.
  138. // The parser has given us exactly the comment text.
  139. switch c[1] {
  140. case '/':
  141. //-style comment (no newline at the end)
  142. c = c[2:] + "\n"
  143. case '*':
  144. /*-style comment */
  145. c = c[2 : len(c)-2]
  146. }
  147. pieces = append(pieces, c)
  148. }
  149. return strings.Join(pieces, "")
  150. }
  151. // Save references to C.xxx for later processing.
  152. func (f *File) saveRef(x interface{}, context string) {
  153. n, ok := x.(*ast.Expr)
  154. if !ok {
  155. return
  156. }
  157. if sel, ok := (*n).(*ast.SelectorExpr); ok {
  158. // For now, assume that the only instance of capital C is
  159. // when used as the imported package identifier.
  160. // The parser should take care of scoping in the future,
  161. // so that we will be able to distinguish a "top-level C"
  162. // from a local C.
  163. if l, ok := sel.X.(*ast.Ident); ok && l.Name == "C" {
  164. if context == "as2" {
  165. context = "expr"
  166. }
  167. if context == "embed-type" {
  168. error_(sel.Pos(), "cannot embed C type")
  169. }
  170. goname := sel.Sel.Name
  171. if goname == "errno" {
  172. error_(sel.Pos(), "cannot refer to errno directly; see documentation")
  173. return
  174. }
  175. if goname == "_CMalloc" {
  176. error_(sel.Pos(), "cannot refer to C._CMalloc; use C.malloc")
  177. return
  178. }
  179. if goname == "malloc" {
  180. goname = "_CMalloc"
  181. }
  182. name := f.Name[goname]
  183. if name == nil {
  184. name = &Name{
  185. Go: goname,
  186. }
  187. f.Name[goname] = name
  188. }
  189. f.Ref = append(f.Ref, &Ref{
  190. Name: name,
  191. Expr: n,
  192. Context: context,
  193. })
  194. return
  195. }
  196. }
  197. }
  198. // If a function should be exported add it to ExpFunc.
  199. func (f *File) saveExport(x interface{}, context string) {
  200. n, ok := x.(*ast.FuncDecl)
  201. if !ok {
  202. return
  203. }
  204. if n.Doc == nil {
  205. return
  206. }
  207. for _, c := range n.Doc.List {
  208. if !strings.HasPrefix(string(c.Text), "//export ") {
  209. continue
  210. }
  211. name := strings.TrimSpace(string(c.Text[9:]))
  212. if name == "" {
  213. error_(c.Pos(), "export missing name")
  214. }
  215. if name != n.Name.Name {
  216. error_(c.Pos(), "export comment has wrong name %q, want %q", name, n.Name.Name)
  217. }
  218. f.ExpFunc = append(f.ExpFunc, &ExpFunc{
  219. Func: n,
  220. ExpName: name,
  221. })
  222. break
  223. }
  224. }
  225. // Make f.ExpFunc[i] point at the Func from this AST instead of the other one.
  226. func (f *File) saveExport2(x interface{}, context string) {
  227. n, ok := x.(*ast.FuncDecl)
  228. if !ok {
  229. return
  230. }
  231. for _, exp := range f.ExpFunc {
  232. if exp.Func.Name.Name == n.Name.Name {
  233. exp.Func = n
  234. break
  235. }
  236. }
  237. }
  238. // walk walks the AST x, calling visit(f, x, context) for each node.
  239. func (f *File) walk(x interface{}, context string, visit func(*File, interface{}, string)) {
  240. visit(f, x, context)
  241. switch n := x.(type) {
  242. case *ast.Expr:
  243. f.walk(*n, context, visit)
  244. // everything else just recurs
  245. default:
  246. error_(token.NoPos, "unexpected type %T in walk", x, visit)
  247. panic("unexpected type")
  248. case nil:
  249. // These are ordered and grouped to match ../../go/ast/ast.go
  250. case *ast.Field:
  251. if len(n.Names) == 0 && context == "field" {
  252. f.walk(&n.Type, "embed-type", visit)
  253. } else {
  254. f.walk(&n.Type, "type", visit)
  255. }
  256. case *ast.FieldList:
  257. for _, field := range n.List {
  258. f.walk(field, context, visit)
  259. }
  260. case *ast.BadExpr:
  261. case *ast.Ident:
  262. case *ast.Ellipsis:
  263. case *ast.BasicLit:
  264. case *ast.FuncLit:
  265. f.walk(n.Type, "type", visit)
  266. f.walk(n.Body, "stmt", visit)
  267. case *ast.CompositeLit:
  268. f.walk(&n.Type, "type", visit)
  269. f.walk(n.Elts, "expr", visit)
  270. case *ast.ParenExpr:
  271. f.walk(&n.X, context, visit)
  272. case *ast.SelectorExpr:
  273. f.walk(&n.X, "selector", visit)
  274. case *ast.IndexExpr:
  275. f.walk(&n.X, "expr", visit)
  276. f.walk(&n.Index, "expr", visit)
  277. case *ast.SliceExpr:
  278. f.walk(&n.X, "expr", visit)
  279. if n.Low != nil {
  280. f.walk(&n.Low, "expr", visit)
  281. }
  282. if n.High != nil {
  283. f.walk(&n.High, "expr", visit)
  284. }
  285. if n.Max != nil {
  286. f.walk(&n.Max, "expr", visit)
  287. }
  288. case *ast.TypeAssertExpr:
  289. f.walk(&n.X, "expr", visit)
  290. f.walk(&n.Type, "type", visit)
  291. case *ast.CallExpr:
  292. if context == "as2" {
  293. f.walk(&n.Fun, "call2", visit)
  294. } else {
  295. f.walk(&n.Fun, "call", visit)
  296. }
  297. f.walk(n.Args, "expr", visit)
  298. case *ast.StarExpr:
  299. f.walk(&n.X, context, visit)
  300. case *ast.UnaryExpr:
  301. f.walk(&n.X, "expr", visit)
  302. case *ast.BinaryExpr:
  303. f.walk(&n.X, "expr", visit)
  304. f.walk(&n.Y, "expr", visit)
  305. case *ast.KeyValueExpr:
  306. f.walk(&n.Key, "expr", visit)
  307. f.walk(&n.Value, "expr", visit)
  308. case *ast.ArrayType:
  309. f.walk(&n.Len, "expr", visit)
  310. f.walk(&n.Elt, "type", visit)
  311. case *ast.StructType:
  312. f.walk(n.Fields, "field", visit)
  313. case *ast.FuncType:
  314. f.walk(n.Params, "param", visit)
  315. if n.Results != nil {
  316. f.walk(n.Results, "param", visit)
  317. }
  318. case *ast.InterfaceType:
  319. f.walk(n.Methods, "field", visit)
  320. case *ast.MapType:
  321. f.walk(&n.Key, "type", visit)
  322. f.walk(&n.Value, "type", visit)
  323. case *ast.ChanType:
  324. f.walk(&n.Value, "type", visit)
  325. case *ast.BadStmt:
  326. case *ast.DeclStmt:
  327. f.walk(n.Decl, "decl", visit)
  328. case *ast.EmptyStmt:
  329. case *ast.LabeledStmt:
  330. f.walk(n.Stmt, "stmt", visit)
  331. case *ast.ExprStmt:
  332. f.walk(&n.X, "expr", visit)
  333. case *ast.SendStmt:
  334. f.walk(&n.Chan, "expr", visit)
  335. f.walk(&n.Value, "expr", visit)
  336. case *ast.IncDecStmt:
  337. f.walk(&n.X, "expr", visit)
  338. case *ast.AssignStmt:
  339. f.walk(n.Lhs, "expr", visit)
  340. if len(n.Lhs) == 2 && len(n.Rhs) == 1 {
  341. f.walk(n.Rhs, "as2", visit)
  342. } else {
  343. f.walk(n.Rhs, "expr", visit)
  344. }
  345. case *ast.GoStmt:
  346. f.walk(n.Call, "expr", visit)
  347. case *ast.DeferStmt:
  348. f.walk(n.Call, "expr", visit)
  349. case *ast.ReturnStmt:
  350. f.walk(n.Results, "expr", visit)
  351. case *ast.BranchStmt:
  352. case *ast.BlockStmt:
  353. f.walk(n.List, context, visit)
  354. case *ast.IfStmt:
  355. f.walk(n.Init, "stmt", visit)
  356. f.walk(&n.Cond, "expr", visit)
  357. f.walk(n.Body, "stmt", visit)
  358. f.walk(n.Else, "stmt", visit)
  359. case *ast.CaseClause:
  360. if context == "typeswitch" {
  361. context = "type"
  362. } else {
  363. context = "expr"
  364. }
  365. f.walk(n.List, context, visit)
  366. f.walk(n.Body, "stmt", visit)
  367. case *ast.SwitchStmt:
  368. f.walk(n.Init, "stmt", visit)
  369. f.walk(&n.Tag, "expr", visit)
  370. f.walk(n.Body, "switch", visit)
  371. case *ast.TypeSwitchStmt:
  372. f.walk(n.Init, "stmt", visit)
  373. f.walk(n.Assign, "stmt", visit)
  374. f.walk(n.Body, "typeswitch", visit)
  375. case *ast.CommClause:
  376. f.walk(n.Comm, "stmt", visit)
  377. f.walk(n.Body, "stmt", visit)
  378. case *ast.SelectStmt:
  379. f.walk(n.Body, "stmt", visit)
  380. case *ast.ForStmt:
  381. f.walk(n.Init, "stmt", visit)
  382. f.walk(&n.Cond, "expr", visit)
  383. f.walk(n.Post, "stmt", visit)
  384. f.walk(n.Body, "stmt", visit)
  385. case *ast.RangeStmt:
  386. f.walk(&n.Key, "expr", visit)
  387. f.walk(&n.Value, "expr", visit)
  388. f.walk(&n.X, "expr", visit)
  389. f.walk(n.Body, "stmt", visit)
  390. case *ast.ImportSpec:
  391. case *ast.ValueSpec:
  392. f.walk(&n.Type, "type", visit)
  393. f.walk(n.Values, "expr", visit)
  394. case *ast.TypeSpec:
  395. f.walk(&n.Type, "type", visit)
  396. case *ast.BadDecl:
  397. case *ast.GenDecl:
  398. f.walk(n.Specs, "spec", visit)
  399. case *ast.FuncDecl:
  400. if n.Recv != nil {
  401. f.walk(n.Recv, "param", visit)
  402. }
  403. f.walk(n.Type, "type", visit)
  404. if n.Body != nil {
  405. f.walk(n.Body, "stmt", visit)
  406. }
  407. case *ast.File:
  408. f.walk(n.Decls, "decl", visit)
  409. case *ast.Package:
  410. for _, file := range n.Files {
  411. f.walk(file, "file", visit)
  412. }
  413. case []ast.Decl:
  414. for _, d := range n {
  415. f.walk(d, context, visit)
  416. }
  417. case []ast.Expr:
  418. for i := range n {
  419. f.walk(&n[i], context, visit)
  420. }
  421. case []ast.Stmt:
  422. for _, s := range n {
  423. f.walk(s, context, visit)
  424. }
  425. case []ast.Spec:
  426. for _, s := range n {
  427. f.walk(s, context, visit)
  428. }
  429. }
  430. }