symtable.js 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027
  1. /* Flags for def-use information */
  2. var DEF_GLOBAL = 1;
  3. /* global stmt */
  4. var DEF_LOCAL = 2;
  5. /* assignment in code block */
  6. var DEF_PARAM = 2 << 1;
  7. /* formal parameter */
  8. var USE = 2 << 2;
  9. /* name is used */
  10. var DEF_STAR = 2 << 3;
  11. /* parameter is star arg */
  12. var DEF_DOUBLESTAR = 2 << 4;
  13. /* parameter is star-star arg */
  14. var DEF_INTUPLE = 2 << 5;
  15. /* name defined in tuple in parameters */
  16. var DEF_FREE = 2 << 6;
  17. /* name used but not defined in nested block */
  18. var DEF_FREE_GLOBAL = 2 << 7;
  19. /* free variable is actually implicit global */
  20. var DEF_FREE_CLASS = 2 << 8;
  21. /* free variable from class's method */
  22. var DEF_IMPORT = 2 << 9;
  23. /* assignment occurred via import */
  24. var DEF_BOUND = (DEF_LOCAL | DEF_PARAM | DEF_IMPORT);
  25. /* GLOBAL_EXPLICIT and GLOBAL_IMPLICIT are used internally by the symbol
  26. table. GLOBAL is returned from PyST_GetScope() for either of them.
  27. It is stored in ste_symbols at bits 12-14.
  28. */
  29. var SCOPE_OFF = 11;
  30. var SCOPE_MASK = 7;
  31. var LOCAL = 1;
  32. var GLOBAL_EXPLICIT = 2;
  33. var GLOBAL_IMPLICIT = 3;
  34. var FREE = 4;
  35. var CELL = 5;
  36. /* The following three names are used for the ste_unoptimized bit field */
  37. var OPT_IMPORT_STAR = 1;
  38. var OPT_EXEC = 2;
  39. var OPT_BARE_EXEC = 4;
  40. var OPT_TOPLEVEL = 8;
  41. /* top-level names, including eval and exec */
  42. var GENERATOR = 2;
  43. var GENERATOR_EXPRESSION = 2;
  44. var ModuleBlock = "module";
  45. var FunctionBlock = "function";
  46. var ClassBlock = "class";
  47. /**
  48. * @constructor
  49. * @param {string} name
  50. * @param {number} flags
  51. * @param {Array.<SymbolTableScope>} namespaces
  52. */
  53. function Symbol (name, flags, namespaces) {
  54. this.__name = name;
  55. this.__flags = flags;
  56. this.__scope = (flags >> SCOPE_OFF) & SCOPE_MASK;
  57. this.__namespaces = namespaces || [];
  58. }
  59. Symbol.prototype.get_name = function () {
  60. return this.__name;
  61. };
  62. Symbol.prototype.is_referenced = function () {
  63. return !!(this.__flags & USE);
  64. };
  65. Symbol.prototype.is_parameter = function () {
  66. return !!(this.__flags & DEF_PARAM);
  67. };
  68. Symbol.prototype.is_global = function () {
  69. return this.__scope === GLOBAL_IMPLICIT || this.__scope == GLOBAL_EXPLICIT;
  70. };
  71. Symbol.prototype.is_declared_global = function () {
  72. return this.__scope == GLOBAL_EXPLICIT;
  73. };
  74. Symbol.prototype.is_local = function () {
  75. return !!(this.__flags & DEF_BOUND);
  76. };
  77. Symbol.prototype.is_free = function () {
  78. return this.__scope == FREE;
  79. };
  80. Symbol.prototype.is_imported = function () {
  81. return !!(this.__flags & DEF_IMPORT);
  82. };
  83. Symbol.prototype.is_assigned = function () {
  84. return !!(this.__flags & DEF_LOCAL);
  85. };
  86. Symbol.prototype.is_namespace = function () {
  87. return this.__namespaces && this.__namespaces.length > 0;
  88. };
  89. Symbol.prototype.get_namespaces = function () {
  90. return this.__namespaces;
  91. };
  92. var astScopeCounter = 0;
  93. /**
  94. * @constructor
  95. * @param {SymbolTable} table
  96. * @param {string} name
  97. * @param {string} type
  98. * @param {number} lineno
  99. */
  100. function SymbolTableScope (table, name, type, ast, lineno) {
  101. this.symFlags = {};
  102. this.name = name;
  103. this.varnames = [];
  104. this.children = [];
  105. this.blockType = type;
  106. this.isNested = false;
  107. this.hasFree = false;
  108. this.childHasFree = false; // true if child block has free vars including free refs to globals
  109. this.generator = false;
  110. this.varargs = false;
  111. this.varkeywords = false;
  112. this.returnsValue = false;
  113. this.lineno = lineno;
  114. this.table = table;
  115. if (table.cur && (table.cur.nested || table.cur.blockType === FunctionBlock)) {
  116. this.isNested = true;
  117. }
  118. ast.scopeId = astScopeCounter++;
  119. table.stss[ast.scopeId] = this;
  120. // cache of Symbols for returning to other parts of code
  121. this.symbols = {};
  122. }
  123. SymbolTableScope.prototype.get_type = function () {
  124. return this.blockType;
  125. };
  126. SymbolTableScope.prototype.get_name = function () {
  127. return this.name;
  128. };
  129. SymbolTableScope.prototype.get_lineno = function () {
  130. return this.lineno;
  131. };
  132. SymbolTableScope.prototype.is_nested = function () {
  133. return this.isNested;
  134. };
  135. SymbolTableScope.prototype.has_children = function () {
  136. return this.children.length > 0;
  137. };
  138. SymbolTableScope.prototype.get_identifiers = function () {
  139. return this._identsMatching(function () {
  140. return true;
  141. });
  142. };
  143. SymbolTableScope.prototype.lookup = function (name) {
  144. var namespaces;
  145. var flags;
  146. var sym;
  147. if (!this.symbols.hasOwnProperty(name)) {
  148. flags = this.symFlags[name];
  149. namespaces = this.__check_children(name);
  150. sym = this.symbols[name] = new Symbol(name, flags, namespaces);
  151. }
  152. else {
  153. sym = this.symbols[name];
  154. }
  155. return sym;
  156. };
  157. SymbolTableScope.prototype.__check_children = function (name) {
  158. //print(" check_children:", name);
  159. var child;
  160. var i;
  161. var ret = [];
  162. for (i = 0; i < this.children.length; ++i) {
  163. child = this.children[i];
  164. if (child.name === name) {
  165. ret.push(child);
  166. }
  167. }
  168. return ret;
  169. };
  170. SymbolTableScope.prototype._identsMatching = function (f) {
  171. var k;
  172. var ret = [];
  173. for (k in this.symFlags) {
  174. if (this.symFlags.hasOwnProperty(k)) {
  175. if (f(this.symFlags[k])) {
  176. ret.push(k);
  177. }
  178. }
  179. }
  180. ret.sort();
  181. return ret;
  182. };
  183. SymbolTableScope.prototype.get_parameters = function () {
  184. goog.asserts.assert(this.get_type() == "function", "get_parameters only valid for function scopes");
  185. if (!this._funcParams) {
  186. this._funcParams = this._identsMatching(function (x) {
  187. return x & DEF_PARAM;
  188. });
  189. }
  190. return this._funcParams;
  191. };
  192. SymbolTableScope.prototype.get_locals = function () {
  193. goog.asserts.assert(this.get_type() == "function", "get_locals only valid for function scopes");
  194. if (!this._funcLocals) {
  195. this._funcLocals = this._identsMatching(function (x) {
  196. return x & DEF_BOUND;
  197. });
  198. }
  199. return this._funcLocals;
  200. };
  201. SymbolTableScope.prototype.get_globals = function () {
  202. goog.asserts.assert(this.get_type() == "function", "get_globals only valid for function scopes");
  203. if (!this._funcGlobals) {
  204. this._funcGlobals = this._identsMatching(function (x) {
  205. var masked = (x >> SCOPE_OFF) & SCOPE_MASK;
  206. return masked == GLOBAL_IMPLICIT || masked == GLOBAL_EXPLICIT;
  207. });
  208. }
  209. return this._funcGlobals;
  210. };
  211. SymbolTableScope.prototype.get_frees = function () {
  212. goog.asserts.assert(this.get_type() == "function", "get_frees only valid for function scopes");
  213. if (!this._funcFrees) {
  214. this._funcFrees = this._identsMatching(function (x) {
  215. var masked = (x >> SCOPE_OFF) & SCOPE_MASK;
  216. return masked == FREE;
  217. });
  218. }
  219. return this._funcFrees;
  220. };
  221. SymbolTableScope.prototype.get_methods = function () {
  222. var i;
  223. var all;
  224. goog.asserts.assert(this.get_type() == "class", "get_methods only valid for class scopes");
  225. if (!this._classMethods) {
  226. // todo; uniq?
  227. all = [];
  228. for (i = 0; i < this.children.length; ++i) {
  229. all.push(this.children[i].name);
  230. }
  231. all.sort();
  232. this._classMethods = all;
  233. }
  234. return this._classMethods;
  235. };
  236. SymbolTableScope.prototype.getScope = function (name) {
  237. //print("getScope");
  238. //for (var k in this.symFlags) print(k);
  239. var v = this.symFlags[name];
  240. if (v === undefined) {
  241. return 0;
  242. }
  243. return (v >> SCOPE_OFF) & SCOPE_MASK;
  244. };
  245. /**
  246. * @constructor
  247. * @param {string} filename
  248. */
  249. function SymbolTable (filename) {
  250. this.filename = filename;
  251. this.cur = null;
  252. this.top = null;
  253. this.stack = [];
  254. this.global = null; // points at top level module symFlags
  255. this.curClass = null; // current class or null
  256. this.tmpname = 0;
  257. // mapping from ast nodes to their scope if they have one. we add an
  258. // id to the ast node when a scope is created for it, and store it in
  259. // here for the compiler to lookup later.
  260. this.stss = {};
  261. }
  262. SymbolTable.prototype.getStsForAst = function (ast) {
  263. var v;
  264. goog.asserts.assert(ast.scopeId !== undefined, "ast wasn't added to st?");
  265. v = this.stss[ast.scopeId];
  266. goog.asserts.assert(v !== undefined, "unknown sym tab entry");
  267. return v;
  268. };
  269. SymbolTable.prototype.SEQStmt = function (nodes) {
  270. var val;
  271. var i;
  272. var len;
  273. goog.asserts.assert(goog.isArrayLike(nodes), "SEQ: nodes isn't array? got %s", nodes);
  274. len = nodes.length;
  275. for (i = 0; i < len; ++i) {
  276. val = nodes[i];
  277. if (val) {
  278. this.visitStmt(val);
  279. }
  280. }
  281. };
  282. SymbolTable.prototype.SEQExpr = function (nodes) {
  283. var val;
  284. var i;
  285. var len;
  286. goog.asserts.assert(goog.isArrayLike(nodes), "SEQ: nodes isn't array? got %s", nodes);
  287. len = nodes.length;
  288. for (i = 0; i < len; ++i) {
  289. val = nodes[i];
  290. if (val) {
  291. this.visitExpr(val);
  292. }
  293. }
  294. };
  295. SymbolTable.prototype.enterBlock = function (name, blockType, ast, lineno) {
  296. var prev;
  297. name = fixReservedNames(name);
  298. //print("enterBlock:", name);
  299. prev = null;
  300. if (this.cur) {
  301. prev = this.cur;
  302. this.stack.push(this.cur);
  303. }
  304. this.cur = new SymbolTableScope(this, name, blockType, ast, lineno);
  305. if (name === "top") {
  306. this.global = this.cur.symFlags;
  307. }
  308. if (prev) {
  309. //print(" adding", this.cur.name, "to", prev.name);
  310. prev.children.push(this.cur);
  311. }
  312. };
  313. SymbolTable.prototype.exitBlock = function () {
  314. //print("exitBlock");
  315. this.cur = null;
  316. if (this.stack.length > 0) {
  317. this.cur = this.stack.pop();
  318. }
  319. };
  320. SymbolTable.prototype.visitParams = function (args, toplevel) {
  321. var arg;
  322. var i;
  323. for (i = 0; i < args.length; ++i) {
  324. arg = args[i];
  325. if (arg.constructor === Name) {
  326. goog.asserts.assert(arg.ctx === Param || (arg.ctx === Store && !toplevel));
  327. this.addDef(arg.id, DEF_PARAM, arg.lineno);
  328. }
  329. else {
  330. // Tuple isn't supported
  331. throw new Sk.builtin.SyntaxError("invalid expression in parameter list", this.filename);
  332. }
  333. }
  334. };
  335. SymbolTable.prototype.visitArguments = function (a, lineno) {
  336. if (a.args) {
  337. this.visitParams(a.args, true);
  338. }
  339. if (a.vararg) {
  340. this.addDef(a.vararg, DEF_PARAM, lineno);
  341. this.cur.varargs = true;
  342. }
  343. if (a.kwarg) {
  344. this.addDef(a.kwarg, DEF_PARAM, lineno);
  345. this.cur.varkeywords = true;
  346. }
  347. };
  348. SymbolTable.prototype.newTmpname = function (lineno) {
  349. this.addDef(new Sk.builtin.str("_[" + (++this.tmpname) + "]"), DEF_LOCAL, lineno);
  350. };
  351. SymbolTable.prototype.addDef = function (name, flag, lineno) {
  352. var fromGlobal;
  353. var val;
  354. var mangled = mangleName(this.curClass, new Sk.builtin.str(name)).v;
  355. mangled = fixReservedNames(mangled);
  356. val = this.cur.symFlags[mangled];
  357. if (val !== undefined) {
  358. if ((flag & DEF_PARAM) && (val & DEF_PARAM)) {
  359. throw new Sk.builtin.SyntaxError("duplicate argument '" + name.v + "' in function definition", this.filename, lineno);
  360. }
  361. val |= flag;
  362. }
  363. else {
  364. val = flag;
  365. }
  366. this.cur.symFlags[mangled] = val;
  367. if (flag & DEF_PARAM) {
  368. this.cur.varnames.push(mangled);
  369. }
  370. else if (flag & DEF_GLOBAL) {
  371. val = flag;
  372. fromGlobal = this.global[mangled];
  373. if (fromGlobal !== undefined) {
  374. val |= fromGlobal;
  375. }
  376. this.global[mangled] = val;
  377. }
  378. };
  379. SymbolTable.prototype.visitSlice = function (s) {
  380. var i;
  381. switch (s.constructor) {
  382. case Slice:
  383. if (s.lower) {
  384. this.visitExpr(s.lower);
  385. }
  386. if (s.upper) {
  387. this.visitExpr(s.upper);
  388. }
  389. if (s.step) {
  390. this.visitExpr(s.step);
  391. }
  392. break;
  393. case ExtSlice:
  394. for (i = 0; i < s.dims.length; ++i) {
  395. this.visitSlice(s.dims[i]);
  396. }
  397. break;
  398. case Index:
  399. this.visitExpr(s.value);
  400. break;
  401. case Ellipsis:
  402. break;
  403. }
  404. };
  405. SymbolTable.prototype.visitStmt = function (s) {
  406. var cur;
  407. var name;
  408. var i;
  409. var nameslen;
  410. var tmp;
  411. goog.asserts.assert(s !== undefined, "visitStmt called with undefined");
  412. switch (s.constructor) {
  413. case FunctionDef:
  414. this.addDef(s.name, DEF_LOCAL, s.lineno);
  415. if (s.args.defaults) {
  416. this.SEQExpr(s.args.defaults);
  417. }
  418. if (s.decorator_list) {
  419. this.SEQExpr(s.decorator_list);
  420. }
  421. this.enterBlock(s.name.v, FunctionBlock, s, s.lineno);
  422. this.visitArguments(s.args, s.lineno);
  423. this.SEQStmt(s.body);
  424. this.exitBlock();
  425. break;
  426. case ClassDef:
  427. this.addDef(s.name, DEF_LOCAL, s.lineno);
  428. this.SEQExpr(s.bases);
  429. if (s.decorator_list) {
  430. this.SEQExpr(s.decorator_list);
  431. }
  432. this.enterBlock(s.name.v, ClassBlock, s, s.lineno);
  433. tmp = this.curClass;
  434. this.curClass = s.name;
  435. this.SEQStmt(s.body);
  436. this.exitBlock();
  437. break;
  438. case Return_:
  439. if (s.value) {
  440. this.visitExpr(s.value);
  441. this.cur.returnsValue = true;
  442. if (this.cur.generator) {
  443. throw new Sk.builtin.SyntaxError("'return' with argument inside generator", this.filename);
  444. }
  445. }
  446. break;
  447. case Delete_:
  448. this.SEQExpr(s.targets);
  449. break;
  450. case Assign:
  451. this.SEQExpr(s.targets);
  452. this.visitExpr(s.value);
  453. break;
  454. case AugAssign:
  455. this.visitExpr(s.target);
  456. this.visitExpr(s.value);
  457. break;
  458. case Print:
  459. if (s.dest) {
  460. this.visitExpr(s.dest);
  461. }
  462. this.SEQExpr(s.values);
  463. break;
  464. case For_:
  465. this.visitExpr(s.target);
  466. this.visitExpr(s.iter);
  467. this.SEQStmt(s.body);
  468. if (s.orelse) {
  469. this.SEQStmt(s.orelse);
  470. }
  471. break;
  472. case While_:
  473. this.visitExpr(s.test);
  474. this.SEQStmt(s.body);
  475. if (s.orelse) {
  476. this.SEQStmt(s.orelse);
  477. }
  478. break;
  479. case If_:
  480. this.visitExpr(s.test);
  481. this.SEQStmt(s.body);
  482. if (s.orelse) {
  483. this.SEQStmt(s.orelse);
  484. }
  485. break;
  486. case Raise:
  487. if (s.type) {
  488. this.visitExpr(s.type);
  489. if (s.inst) {
  490. this.visitExpr(s.inst);
  491. if (s.tback) {
  492. this.visitExpr(s.tback);
  493. }
  494. }
  495. }
  496. break;
  497. case TryExcept:
  498. this.SEQStmt(s.body);
  499. this.SEQStmt(s.orelse);
  500. this.visitExcepthandlers(s.handlers);
  501. break;
  502. case TryFinally:
  503. this.SEQStmt(s.body);
  504. this.SEQStmt(s.finalbody);
  505. break;
  506. case Assert:
  507. this.visitExpr(s.test);
  508. if (s.msg) {
  509. this.visitExpr(s.msg);
  510. }
  511. break;
  512. case Import_:
  513. case ImportFrom:
  514. this.visitAlias(s.names, s.lineno);
  515. break;
  516. case Exec:
  517. this.visitExpr(s.body);
  518. if (s.globals) {
  519. this.visitExpr(s.globals);
  520. if (s.locals) {
  521. this.visitExpr(s.locals);
  522. }
  523. }
  524. break;
  525. case Global:
  526. nameslen = s.names.length;
  527. for (i = 0; i < nameslen; ++i) {
  528. name = mangleName(this.curClass, s.names[i]).v;
  529. name = fixReservedNames(name);
  530. cur = this.cur.symFlags[name];
  531. if (cur & (DEF_LOCAL | USE)) {
  532. if (cur & DEF_LOCAL) {
  533. throw new Sk.builtin.SyntaxError("name '" + name + "' is assigned to before global declaration", this.filename, s.lineno);
  534. }
  535. else {
  536. throw new Sk.builtin.SyntaxError("name '" + name + "' is used prior to global declaration", this.filename, s.lineno);
  537. }
  538. }
  539. this.addDef(new Sk.builtin.str(name), DEF_GLOBAL, s.lineno);
  540. }
  541. break;
  542. case Expr:
  543. this.visitExpr(s.value);
  544. break;
  545. case Pass:
  546. case Break_:
  547. case Debugger_:
  548. case Continue_:
  549. // nothing
  550. break;
  551. case With_:
  552. this.newTmpname(s.lineno);
  553. this.visitExpr(s.context_expr);
  554. if (s.optional_vars) {
  555. this.newTmpname(s.lineno);
  556. this.visitExpr(s.optional_vars);
  557. }
  558. this.SEQStmt(s.body);
  559. break;
  560. default:
  561. goog.asserts.fail("Unhandled type " + s.constructor.name + " in visitStmt");
  562. }
  563. };
  564. SymbolTable.prototype.visitExpr = function (e) {
  565. var i;
  566. goog.asserts.assert(e !== undefined, "visitExpr called with undefined");
  567. //print(" e: ", e.constructor.name);
  568. switch (e.constructor) {
  569. case BoolOp:
  570. this.SEQExpr(e.values);
  571. break;
  572. case BinOp:
  573. this.visitExpr(e.left);
  574. this.visitExpr(e.right);
  575. break;
  576. case UnaryOp:
  577. this.visitExpr(e.operand);
  578. break;
  579. case Lambda:
  580. this.addDef(new Sk.builtin.str("lambda"), DEF_LOCAL, e.lineno);
  581. if (e.args.defaults) {
  582. this.SEQExpr(e.args.defaults);
  583. }
  584. this.enterBlock("lambda", FunctionBlock, e, e.lineno);
  585. this.visitArguments(e.args, e.lineno);
  586. this.visitExpr(e.body);
  587. this.exitBlock();
  588. break;
  589. case IfExp:
  590. this.visitExpr(e.test);
  591. this.visitExpr(e.body);
  592. this.visitExpr(e.orelse);
  593. break;
  594. case Dict:
  595. this.SEQExpr(e.keys);
  596. this.SEQExpr(e.values);
  597. break;
  598. case DictComp:
  599. case SetComp:
  600. this.visitComprehension(e.generators, 0);
  601. break;
  602. case ListComp:
  603. this.newTmpname(e.lineno);
  604. this.visitExpr(e.elt);
  605. this.visitComprehension(e.generators, 0);
  606. break;
  607. case GeneratorExp:
  608. this.visitGenexp(e);
  609. break;
  610. case Yield:
  611. if (e.value) {
  612. this.visitExpr(e.value);
  613. }
  614. this.cur.generator = true;
  615. if (this.cur.returnsValue) {
  616. throw new Sk.builtin.SyntaxError("'return' with argument inside generator", this.filename);
  617. }
  618. break;
  619. case Compare:
  620. this.visitExpr(e.left);
  621. this.SEQExpr(e.comparators);
  622. break;
  623. case Call:
  624. this.visitExpr(e.func);
  625. this.SEQExpr(e.args);
  626. for (i = 0; i < e.keywords.length; ++i) {
  627. this.visitExpr(e.keywords[i].value);
  628. }
  629. //print(JSON.stringify(e.starargs, null, 2));
  630. //print(JSON.stringify(e.kwargs, null,2));
  631. if (e.starargs) {
  632. this.visitExpr(e.starargs);
  633. }
  634. if (e.kwargs) {
  635. this.visitExpr(e.kwargs);
  636. }
  637. break;
  638. case Num:
  639. case Str:
  640. break;
  641. case Attribute:
  642. this.visitExpr(e.value);
  643. break;
  644. case Subscript:
  645. this.visitExpr(e.value);
  646. this.visitSlice(e.slice);
  647. break;
  648. case Name:
  649. this.addDef(e.id, e.ctx === Load ? USE : DEF_LOCAL, e.lineno);
  650. break;
  651. case List:
  652. case Tuple:
  653. case Set:
  654. this.SEQExpr(e.elts);
  655. break;
  656. default:
  657. goog.asserts.fail("Unhandled type " + e.constructor.name + " in visitExpr");
  658. }
  659. };
  660. SymbolTable.prototype.visitComprehension = function (lcs, startAt) {
  661. var lc;
  662. var i;
  663. var len = lcs.length;
  664. for (i = startAt; i < len; ++i) {
  665. lc = lcs[i];
  666. this.visitExpr(lc.target);
  667. this.visitExpr(lc.iter);
  668. this.SEQExpr(lc.ifs);
  669. }
  670. };
  671. SymbolTable.prototype.visitAlias = function (names, lineno) {
  672. /* Compute store_name, the name actually bound by the import
  673. operation. It is diferent than a->name when a->name is a
  674. dotted package name (e.g. spam.eggs)
  675. */
  676. var dot;
  677. var storename;
  678. var name;
  679. var a;
  680. var i;
  681. for (i = 0; i < names.length; ++i) {
  682. a = names[i];
  683. name = a.asname === null ? a.name.v : a.asname.v;
  684. storename = name;
  685. dot = name.indexOf(".");
  686. if (dot !== -1) {
  687. storename = name.substr(0, dot);
  688. }
  689. if (name !== "*") {
  690. this.addDef(new Sk.builtin.str(storename), DEF_IMPORT, lineno);
  691. }
  692. else {
  693. if (this.cur.blockType !== ModuleBlock) {
  694. throw new Sk.builtin.SyntaxError("import * only allowed at module level", this.filename);
  695. }
  696. }
  697. }
  698. };
  699. SymbolTable.prototype.visitGenexp = function (e) {
  700. var outermost = e.generators[0];
  701. // outermost is evaled in current scope
  702. this.visitExpr(outermost.iter);
  703. this.enterBlock("genexpr", FunctionBlock, e, e.lineno);
  704. this.cur.generator = true;
  705. this.addDef(new Sk.builtin.str(".0"), DEF_PARAM, e.lineno);
  706. this.visitExpr(outermost.target);
  707. this.SEQExpr(outermost.ifs);
  708. this.visitComprehension(e.generators, 1);
  709. this.visitExpr(e.elt);
  710. this.exitBlock();
  711. };
  712. SymbolTable.prototype.visitExcepthandlers = function (handlers) {
  713. var i, eh;
  714. for (i = 0; eh = handlers[i]; ++i) {
  715. if (eh.type) {
  716. this.visitExpr(eh.type);
  717. }
  718. if (eh.name) {
  719. this.visitExpr(eh.name);
  720. }
  721. this.SEQStmt(eh.body);
  722. }
  723. };
  724. function _dictUpdate (a, b) {
  725. var kb;
  726. for (kb in b) {
  727. a[kb] = b[kb];
  728. }
  729. }
  730. SymbolTable.prototype.analyzeBlock = function (ste, bound, free, global) {
  731. var c;
  732. var i;
  733. var childlen;
  734. var allfree;
  735. var flags;
  736. var name;
  737. var local = {};
  738. var scope = {};
  739. var newglobal = {};
  740. var newbound = {};
  741. var newfree = {};
  742. if (ste.blockType == ClassBlock) {
  743. _dictUpdate(newglobal, global);
  744. if (bound) {
  745. _dictUpdate(newbound, bound);
  746. }
  747. }
  748. for (name in ste.symFlags) {
  749. flags = ste.symFlags[name];
  750. this.analyzeName(ste, scope, name, flags, bound, local, free, global);
  751. }
  752. if (ste.blockType !== ClassBlock) {
  753. if (ste.blockType === FunctionBlock) {
  754. _dictUpdate(newbound, local);
  755. }
  756. if (bound) {
  757. _dictUpdate(newbound, bound);
  758. }
  759. _dictUpdate(newglobal, global);
  760. }
  761. allfree = {};
  762. childlen = ste.children.length;
  763. for (i = 0; i < childlen; ++i) {
  764. c = ste.children[i];
  765. this.analyzeChildBlock(c, newbound, newfree, newglobal, allfree);
  766. if (c.hasFree || c.childHasFree) {
  767. ste.childHasFree = true;
  768. }
  769. }
  770. _dictUpdate(newfree, allfree);
  771. if (ste.blockType === FunctionBlock) {
  772. this.analyzeCells(scope, newfree);
  773. }
  774. this.updateSymbols(ste.symFlags, scope, bound, newfree, ste.blockType === ClassBlock);
  775. _dictUpdate(free, newfree);
  776. };
  777. SymbolTable.prototype.analyzeChildBlock = function (entry, bound, free, global, childFree) {
  778. var tempGlobal;
  779. var tempFree;
  780. var tempBound = {};
  781. _dictUpdate(tempBound, bound);
  782. tempFree = {};
  783. _dictUpdate(tempFree, free);
  784. tempGlobal = {};
  785. _dictUpdate(tempGlobal, global);
  786. this.analyzeBlock(entry, tempBound, tempFree, tempGlobal);
  787. _dictUpdate(childFree, tempFree);
  788. };
  789. SymbolTable.prototype.analyzeCells = function (scope, free) {
  790. var flags;
  791. var name;
  792. for (name in scope) {
  793. flags = scope[name];
  794. if (flags !== LOCAL) {
  795. continue;
  796. }
  797. if (free[name] === undefined) {
  798. continue;
  799. }
  800. scope[name] = CELL;
  801. delete free[name];
  802. }
  803. };
  804. /**
  805. * store scope info back into the st symbols dict. symbols is modified,
  806. * others are not.
  807. */
  808. SymbolTable.prototype.updateSymbols = function (symbols, scope, bound, free, classflag) {
  809. var i;
  810. var o;
  811. var pos;
  812. var freeValue;
  813. var w;
  814. var flags;
  815. var name;
  816. for (name in symbols) {
  817. flags = symbols[name];
  818. w = scope[name];
  819. flags |= w << SCOPE_OFF;
  820. symbols[name] = flags;
  821. }
  822. freeValue = FREE << SCOPE_OFF;
  823. pos = 0;
  824. for (name in free) {
  825. o = symbols[name];
  826. if (o !== undefined) {
  827. // it could be a free variable in a method of the class that has
  828. // the same name as a local or global in the class scope
  829. if (classflag && (o & (DEF_BOUND | DEF_GLOBAL))) {
  830. i = o | DEF_FREE_CLASS;
  831. symbols[name] = i;
  832. }
  833. // else it's not free, probably a cell
  834. continue;
  835. }
  836. if (bound[name] === undefined) {
  837. continue;
  838. }
  839. symbols[name] = freeValue;
  840. }
  841. };
  842. SymbolTable.prototype.analyzeName = function (ste, dict, name, flags, bound, local, free, global) {
  843. if (flags & DEF_GLOBAL) {
  844. if (flags & DEF_PARAM) {
  845. throw new Sk.builtin.SyntaxError("name '" + name + "' is local and global", this.filename, ste.lineno);
  846. }
  847. dict[name] = GLOBAL_EXPLICIT;
  848. global[name] = null;
  849. if (bound && bound[name] !== undefined) {
  850. delete bound[name];
  851. }
  852. return;
  853. }
  854. if (flags & DEF_BOUND) {
  855. dict[name] = LOCAL;
  856. local[name] = null;
  857. delete global[name];
  858. return;
  859. }
  860. if (bound && bound[name] !== undefined) {
  861. dict[name] = FREE;
  862. ste.hasFree = true;
  863. free[name] = null;
  864. }
  865. else if (global && global[name] !== undefined) {
  866. dict[name] = GLOBAL_IMPLICIT;
  867. }
  868. else {
  869. if (ste.isNested) {
  870. ste.hasFree = true;
  871. }
  872. dict[name] = GLOBAL_IMPLICIT;
  873. }
  874. };
  875. SymbolTable.prototype.analyze = function () {
  876. var free = {};
  877. var global = {};
  878. this.analyzeBlock(this.top, null, free, global);
  879. };
  880. /**
  881. * @param {Object} ast
  882. * @param {string} filename
  883. */
  884. Sk.symboltable = function (ast, filename) {
  885. var i;
  886. var ret = new SymbolTable(filename);
  887. ret.enterBlock("top", ModuleBlock, ast, 0);
  888. ret.top = ret.cur;
  889. //print(Sk.astDump(ast));
  890. for (i = 0; i < ast.body.length; ++i) {
  891. ret.visitStmt(ast.body[i]);
  892. }
  893. ret.exitBlock();
  894. ret.analyze();
  895. return ret;
  896. };
  897. Sk.dumpSymtab = function (st) {
  898. var pyBoolStr = function (b) {
  899. return b ? "True" : "False";
  900. }
  901. var pyList = function (l) {
  902. var i;
  903. var ret = [];
  904. for (i = 0; i < l.length; ++i) {
  905. ret.push(new Sk.builtin.str(l[i])["$r"]().v);
  906. }
  907. return "[" + ret.join(", ") + "]";
  908. };
  909. var getIdents = function (obj, indent) {
  910. var ns;
  911. var j;
  912. var sub;
  913. var nsslen;
  914. var nss;
  915. var info;
  916. var i;
  917. var objidentslen;
  918. var objidents;
  919. var ret;
  920. if (indent === undefined) {
  921. indent = "";
  922. }
  923. ret = "";
  924. ret += indent + "Sym_type: " + obj.get_type() + "\n";
  925. ret += indent + "Sym_name: " + obj.get_name() + "\n";
  926. ret += indent + "Sym_lineno: " + obj.get_lineno() + "\n";
  927. ret += indent + "Sym_nested: " + pyBoolStr(obj.is_nested()) + "\n";
  928. ret += indent + "Sym_haschildren: " + pyBoolStr(obj.has_children()) + "\n";
  929. if (obj.get_type() === "class") {
  930. ret += indent + "Class_methods: " + pyList(obj.get_methods()) + "\n";
  931. }
  932. else if (obj.get_type() === "function") {
  933. ret += indent + "Func_params: " + pyList(obj.get_parameters()) + "\n";
  934. ret += indent + "Func_locals: " + pyList(obj.get_locals()) + "\n";
  935. ret += indent + "Func_globals: " + pyList(obj.get_globals()) + "\n";
  936. ret += indent + "Func_frees: " + pyList(obj.get_frees()) + "\n";
  937. }
  938. ret += indent + "-- Identifiers --\n";
  939. objidents = obj.get_identifiers();
  940. objidentslen = objidents.length;
  941. for (i = 0; i < objidentslen; ++i) {
  942. info = obj.lookup(objidents[i]);
  943. ret += indent + "name: " + info.get_name() + "\n";
  944. ret += indent + " is_referenced: " + pyBoolStr(info.is_referenced()) + "\n";
  945. ret += indent + " is_imported: " + pyBoolStr(info.is_imported()) + "\n";
  946. ret += indent + " is_parameter: " + pyBoolStr(info.is_parameter()) + "\n";
  947. ret += indent + " is_global: " + pyBoolStr(info.is_global()) + "\n";
  948. ret += indent + " is_declared_global: " + pyBoolStr(info.is_declared_global()) + "\n";
  949. ret += indent + " is_local: " + pyBoolStr(info.is_local()) + "\n";
  950. ret += indent + " is_free: " + pyBoolStr(info.is_free()) + "\n";
  951. ret += indent + " is_assigned: " + pyBoolStr(info.is_assigned()) + "\n";
  952. ret += indent + " is_namespace: " + pyBoolStr(info.is_namespace()) + "\n";
  953. nss = info.get_namespaces();
  954. nsslen = nss.length;
  955. ret += indent + " namespaces: [\n";
  956. sub = [];
  957. for (j = 0; j < nsslen; ++j) {
  958. ns = nss[j];
  959. sub.push(getIdents(ns, indent + " "));
  960. }
  961. ret += sub.join("\n");
  962. ret += indent + " ]\n";
  963. }
  964. return ret;
  965. };
  966. return getIdents(st.top, "");
  967. };
  968. goog.exportSymbol("Sk.symboltable", Sk.symboltable);
  969. goog.exportSymbol("Sk.dumpSymtab", Sk.dumpSymtab);