walk.odin 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. package odin_ast
  2. import "core:fmt"
  3. // A Visitor's visit procedure is invoked for each node encountered by walk
  4. // If the result visitor is not nil, walk visits each of the children of node with the new visitor,
  5. // followed by a call of v.visit(v, nil)
  6. Visitor :: struct {
  7. visit: proc(visitor: ^Visitor, node: ^Node) -> ^Visitor,
  8. data: rawptr,
  9. }
  10. // inspect traverses an AST in depth-first order
  11. // It starts by calling f(node), and node must be non-nil
  12. // If f returns true, inspect invokes f recursively for each of the non-nil children of node,
  13. // followed by a call of f(nil)
  14. inspect :: proc(node: ^Node, f: proc(^Node) -> bool) {
  15. v := &Visitor{
  16. visit = proc(v: ^Visitor, node: ^Node) -> ^Visitor {
  17. f := (proc(^Node) -> bool)(v.data);
  18. if f(node) {
  19. return v;
  20. }
  21. return nil;
  22. },
  23. data = rawptr(f),
  24. };
  25. walk(v, node);
  26. }
  27. // walk traverses an AST in depth-first order: It starts by calling v.visit(v, node), and node must not be nil
  28. // If the visitor returned by v.visit(v, node) is not nil, walk is invoked recursively with the new visitor for
  29. // each of the non-nil children of node, followed by a call of the new visit procedure
  30. walk :: proc(v: ^Visitor, node: ^Node) {
  31. walk_expr_list :: proc(v: ^Visitor, list: []^Expr) {
  32. for x in list {
  33. walk(v, x);
  34. }
  35. }
  36. walk_stmt_list :: proc(v: ^Visitor, list: []^Stmt) {
  37. for x in list {
  38. walk(v, x);
  39. }
  40. }
  41. walk_attribute_list :: proc(v: ^Visitor, list: []^Attribute) {
  42. for x in list {
  43. walk(v, x);
  44. }
  45. }
  46. v := v;
  47. if v = v->visit(node); v == nil {
  48. return;
  49. }
  50. switch n in &node.derived {
  51. case File:
  52. if n.docs != nil {
  53. walk(v, n.docs);
  54. }
  55. walk_stmt_list(v, n.decls[:]);
  56. case Package:
  57. for _, f in n.files {
  58. walk(v, f);
  59. }
  60. case Comment_Group:
  61. // empty
  62. case Bad_Expr:
  63. case Ident:
  64. case Implicit:
  65. case Undef:
  66. case Basic_Lit:
  67. case Basic_Directive:
  68. case Ellipsis:
  69. if n.expr != nil {
  70. walk(v, n.expr);
  71. }
  72. case Proc_Lit:
  73. walk(v, n.type);
  74. walk(v, n.body);
  75. walk_expr_list(v, n.where_clauses);
  76. case Comp_Lit:
  77. if n.type != nil {
  78. walk(v, n.type);
  79. }
  80. walk_expr_list(v, n.elems);
  81. case Tag_Expr:
  82. walk(v, n.expr);
  83. case Unary_Expr:
  84. walk(v, n.expr);
  85. case Binary_Expr:
  86. walk(v, n.left);
  87. walk(v, n.right);
  88. case Paren_Expr:
  89. walk(v, n.expr);
  90. case Selector_Expr:
  91. walk(v, n.expr);
  92. walk(v, n.field);
  93. case Implicit_Selector_Expr:
  94. walk(v, n.field);
  95. case Selector_Call_Expr:
  96. walk(v, n.expr);
  97. walk(v, n.call);
  98. case Index_Expr:
  99. walk(v, n.expr);
  100. walk(v, n.index);
  101. case Deref_Expr:
  102. walk(v, n.expr);
  103. case Slice_Expr:
  104. walk(v, n.expr);
  105. if n.low != nil {
  106. walk(v, n.low);
  107. }
  108. if n.high != nil {
  109. walk(v, n.high);
  110. }
  111. case Call_Expr:
  112. walk(v, n.expr);
  113. walk_expr_list(v, n.args);
  114. case Field_Value:
  115. walk(v, n.field);
  116. walk(v, n.value);
  117. case Ternary_Expr:
  118. walk(v, n.cond);
  119. walk(v, n.x);
  120. walk(v, n.y);
  121. case Ternary_If_Expr:
  122. walk(v, n.x);
  123. walk(v, n.cond);
  124. walk(v, n.y);
  125. case Ternary_When_Expr:
  126. walk(v, n.x);
  127. walk(v, n.cond);
  128. walk(v, n.y);
  129. case Type_Assertion:
  130. walk(v, n.expr);
  131. if n.type != nil {
  132. walk(v, n.type);
  133. }
  134. case Type_Cast:
  135. walk(v, n.type);
  136. walk(v, n.expr);
  137. case Auto_Cast:
  138. walk(v, n.expr);
  139. case Inline_Asm_Expr:
  140. walk_expr_list(v, n.param_types);
  141. walk(v, n.return_type);
  142. walk(v, n.constraints_string);
  143. walk(v, n.asm_string);
  144. case Bad_Stmt:
  145. case Empty_Stmt:
  146. case Expr_Stmt:
  147. walk(v, n.expr);
  148. case Tag_Stmt:
  149. walk(v, n.stmt);
  150. case Assign_Stmt:
  151. walk_expr_list(v, n.lhs);
  152. walk_expr_list(v, n.rhs);
  153. case Block_Stmt:
  154. if n.label != nil {
  155. walk(v, n.label);
  156. }
  157. walk_stmt_list(v, n.stmts);
  158. case If_Stmt:
  159. if n.label != nil {
  160. walk(v, n.label);
  161. }
  162. if n.init != nil {
  163. walk(v, n.init);
  164. }
  165. walk(v, n.cond);
  166. walk(v, n.body);
  167. if n.else_stmt != nil {
  168. walk(v, n.else_stmt);
  169. }
  170. case When_Stmt:
  171. walk(v, n.cond);
  172. walk(v, n.body);
  173. if n.else_stmt != nil {
  174. walk(v, n.else_stmt);
  175. }
  176. case Return_Stmt:
  177. walk_expr_list(v, n.results);
  178. case Defer_Stmt:
  179. walk(v, n.stmt);
  180. case For_Stmt:
  181. if n.label != nil {
  182. walk(v, n.label);
  183. }
  184. if n.init != nil {
  185. walk(v, n.init);
  186. }
  187. if n.cond != nil {
  188. walk(v, n.cond);
  189. }
  190. if n.post != nil {
  191. walk(v, n.post);
  192. }
  193. walk(v, n.body);
  194. case Range_Stmt:
  195. if n.label != nil {
  196. walk(v, n.label);
  197. }
  198. for val in n.vals {
  199. if val != nil {
  200. walk(v, val);
  201. }
  202. }
  203. walk(v, n.expr);
  204. walk(v, n.body);
  205. case Inline_Range_Stmt:
  206. if n.label != nil {
  207. walk(v, n.label);
  208. }
  209. if n.val0 != nil {
  210. walk(v, n.val0);
  211. }
  212. if n.val1 != nil {
  213. walk(v, n.val1);
  214. }
  215. walk(v, n.expr);
  216. walk(v, n.body);
  217. case Case_Clause:
  218. walk_expr_list(v, n.list);
  219. walk_stmt_list(v, n.body);
  220. case Switch_Stmt:
  221. if n.label != nil {
  222. walk(v, n.label);
  223. }
  224. if n.init != nil {
  225. walk(v, n.init);
  226. }
  227. if n.cond != nil {
  228. walk(v, n.cond);
  229. }
  230. walk(v, n.body);
  231. case Type_Switch_Stmt:
  232. if n.label != nil {
  233. walk(v, n.label);
  234. }
  235. if n.tag != nil {
  236. walk(v, n.tag);
  237. }
  238. if n.expr != nil {
  239. walk(v, n.expr);
  240. }
  241. walk(v, n.body);
  242. case Branch_Stmt:
  243. if n.label != nil {
  244. walk(v, n.label);
  245. }
  246. case Using_Stmt:
  247. walk_expr_list(v, n.list);
  248. case Bad_Decl:
  249. case Value_Decl:
  250. if n.docs != nil {
  251. walk(v, n.docs);
  252. }
  253. walk_attribute_list(v, n.attributes[:]);
  254. walk_expr_list(v, n.names);
  255. if n.type != nil {
  256. walk(v, n.type);
  257. }
  258. walk_expr_list(v, n.values);
  259. if n.comment != nil {
  260. walk(v, n.comment);
  261. }
  262. case Package_Decl:
  263. if n.docs != nil {
  264. walk(v, n.docs);
  265. }
  266. if n.comment != nil {
  267. walk(v, n.comment);
  268. }
  269. case Import_Decl:
  270. if n.docs != nil {
  271. walk(v, n.docs);
  272. }
  273. if n.comment != nil {
  274. walk(v, n.comment);
  275. }
  276. case Foreign_Block_Decl:
  277. if n.docs != nil {
  278. walk(v, n.docs);
  279. }
  280. walk_attribute_list(v, n.attributes[:]);
  281. if n.foreign_library != nil {
  282. walk(v, n.foreign_library);
  283. }
  284. walk(v, n.body);
  285. case Foreign_Import_Decl:
  286. if n.docs != nil {
  287. walk(v, n.docs);
  288. }
  289. walk_attribute_list(v, n.attributes[:]);
  290. walk(v, n.name);
  291. if n.comment != nil {
  292. walk(v, n.comment);
  293. }
  294. case Proc_Group:
  295. walk_expr_list(v, n.args);
  296. case Attribute:
  297. walk_expr_list(v, n.elems);
  298. case Field:
  299. if n.docs != nil {
  300. walk(v, n.docs);
  301. }
  302. walk_expr_list(v, n.names);
  303. if n.type != nil {
  304. walk(v, n.type);
  305. }
  306. if n.default_value != nil {
  307. walk(v, n.default_value);
  308. }
  309. if n.comment != nil {
  310. walk(v, n.comment);
  311. }
  312. case Field_List:
  313. for x in n.list {
  314. walk(v, x);
  315. }
  316. case Typeid_Type:
  317. if n.specialization != nil {
  318. walk(v, n.specialization);
  319. }
  320. case Helper_Type:
  321. walk(v, n.type);
  322. case Distinct_Type:
  323. walk(v, n.type);
  324. case Poly_Type:
  325. walk(v, n.type);
  326. if n.specialization != nil {
  327. walk(v, n.specialization);
  328. }
  329. case Proc_Type:
  330. walk(v, n.params);
  331. walk(v, n.results);
  332. case Pointer_Type:
  333. walk(v, n.elem);
  334. case Array_Type:
  335. if n.tag != nil {
  336. walk(v, n.tag);
  337. }
  338. if n.len != nil {
  339. walk(v, n.len);
  340. }
  341. walk(v, n.elem);
  342. case Dynamic_Array_Type:
  343. if n.tag != nil {
  344. walk(v, n.tag);
  345. }
  346. walk(v, n.elem);
  347. case Struct_Type:
  348. if n.poly_params != nil {
  349. walk(v, n.poly_params);
  350. }
  351. if n.align != nil {
  352. walk(v, n.align);
  353. }
  354. walk_expr_list(v, n.where_clauses);
  355. walk(v, n.fields);
  356. case Union_Type:
  357. if n.poly_params != nil {
  358. walk(v, n.poly_params);
  359. }
  360. if n.align != nil {
  361. walk(v, n.align);
  362. }
  363. walk_expr_list(v, n.where_clauses);
  364. walk_expr_list(v, n.variants);
  365. case Enum_Type:
  366. if n.base_type != nil {
  367. walk(v, n.base_type);
  368. }
  369. walk_expr_list(v, n.fields);
  370. case Bit_Set_Type:
  371. walk(v, n.elem);
  372. if n.underlying != nil {
  373. walk(v, n.underlying);
  374. }
  375. case Map_Type:
  376. walk(v, n.key);
  377. walk(v, n.value);
  378. case Relative_Type:
  379. walk(v, n.tag);
  380. walk(v, n.type);
  381. case:
  382. fmt.panicf("ast.walk: unexpected node type %T", n);
  383. }
  384. v->visit(nil);
  385. }