1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027 |
- /* Flags for def-use information */
- var DEF_GLOBAL = 1;
- /* global stmt */
- var DEF_LOCAL = 2;
- /* assignment in code block */
- var DEF_PARAM = 2 << 1;
- /* formal parameter */
- var USE = 2 << 2;
- /* name is used */
- var DEF_STAR = 2 << 3;
- /* parameter is star arg */
- var DEF_DOUBLESTAR = 2 << 4;
- /* parameter is star-star arg */
- var DEF_INTUPLE = 2 << 5;
- /* name defined in tuple in parameters */
- var DEF_FREE = 2 << 6;
- /* name used but not defined in nested block */
- var DEF_FREE_GLOBAL = 2 << 7;
- /* free variable is actually implicit global */
- var DEF_FREE_CLASS = 2 << 8;
- /* free variable from class's method */
- var DEF_IMPORT = 2 << 9;
- /* assignment occurred via import */
- var DEF_BOUND = (DEF_LOCAL | DEF_PARAM | DEF_IMPORT);
- /* GLOBAL_EXPLICIT and GLOBAL_IMPLICIT are used internally by the symbol
- table. GLOBAL is returned from PyST_GetScope() for either of them.
- It is stored in ste_symbols at bits 12-14.
- */
- var SCOPE_OFF = 11;
- var SCOPE_MASK = 7;
- var LOCAL = 1;
- var GLOBAL_EXPLICIT = 2;
- var GLOBAL_IMPLICIT = 3;
- var FREE = 4;
- var CELL = 5;
- /* The following three names are used for the ste_unoptimized bit field */
- var OPT_IMPORT_STAR = 1;
- var OPT_EXEC = 2;
- var OPT_BARE_EXEC = 4;
- var OPT_TOPLEVEL = 8;
- /* top-level names, including eval and exec */
- var GENERATOR = 2;
- var GENERATOR_EXPRESSION = 2;
- var ModuleBlock = "module";
- var FunctionBlock = "function";
- var ClassBlock = "class";
- /**
- * @constructor
- * @param {string} name
- * @param {number} flags
- * @param {Array.<SymbolTableScope>} namespaces
- */
- function Symbol (name, flags, namespaces) {
- this.__name = name;
- this.__flags = flags;
- this.__scope = (flags >> SCOPE_OFF) & SCOPE_MASK;
- this.__namespaces = namespaces || [];
- }
- Symbol.prototype.get_name = function () {
- return this.__name;
- };
- Symbol.prototype.is_referenced = function () {
- return !!(this.__flags & USE);
- };
- Symbol.prototype.is_parameter = function () {
- return !!(this.__flags & DEF_PARAM);
- };
- Symbol.prototype.is_global = function () {
- return this.__scope === GLOBAL_IMPLICIT || this.__scope == GLOBAL_EXPLICIT;
- };
- Symbol.prototype.is_declared_global = function () {
- return this.__scope == GLOBAL_EXPLICIT;
- };
- Symbol.prototype.is_local = function () {
- return !!(this.__flags & DEF_BOUND);
- };
- Symbol.prototype.is_free = function () {
- return this.__scope == FREE;
- };
- Symbol.prototype.is_imported = function () {
- return !!(this.__flags & DEF_IMPORT);
- };
- Symbol.prototype.is_assigned = function () {
- return !!(this.__flags & DEF_LOCAL);
- };
- Symbol.prototype.is_namespace = function () {
- return this.__namespaces && this.__namespaces.length > 0;
- };
- Symbol.prototype.get_namespaces = function () {
- return this.__namespaces;
- };
- var astScopeCounter = 0;
- /**
- * @constructor
- * @param {SymbolTable} table
- * @param {string} name
- * @param {string} type
- * @param {number} lineno
- */
- function SymbolTableScope (table, name, type, ast, lineno) {
- this.symFlags = {};
- this.name = name;
- this.varnames = [];
- this.children = [];
- this.blockType = type;
- this.isNested = false;
- this.hasFree = false;
- this.childHasFree = false; // true if child block has free vars including free refs to globals
- this.generator = false;
- this.varargs = false;
- this.varkeywords = false;
- this.returnsValue = false;
- this.lineno = lineno;
- this.table = table;
- if (table.cur && (table.cur.nested || table.cur.blockType === FunctionBlock)) {
- this.isNested = true;
- }
- ast.scopeId = astScopeCounter++;
- table.stss[ast.scopeId] = this;
- // cache of Symbols for returning to other parts of code
- this.symbols = {};
- }
- SymbolTableScope.prototype.get_type = function () {
- return this.blockType;
- };
- SymbolTableScope.prototype.get_name = function () {
- return this.name;
- };
- SymbolTableScope.prototype.get_lineno = function () {
- return this.lineno;
- };
- SymbolTableScope.prototype.is_nested = function () {
- return this.isNested;
- };
- SymbolTableScope.prototype.has_children = function () {
- return this.children.length > 0;
- };
- SymbolTableScope.prototype.get_identifiers = function () {
- return this._identsMatching(function () {
- return true;
- });
- };
- SymbolTableScope.prototype.lookup = function (name) {
- var namespaces;
- var flags;
- var sym;
- if (!this.symbols.hasOwnProperty(name)) {
- flags = this.symFlags[name];
- namespaces = this.__check_children(name);
- sym = this.symbols[name] = new Symbol(name, flags, namespaces);
- }
- else {
- sym = this.symbols[name];
- }
- return sym;
- };
- SymbolTableScope.prototype.__check_children = function (name) {
- //print(" check_children:", name);
- var child;
- var i;
- var ret = [];
- for (i = 0; i < this.children.length; ++i) {
- child = this.children[i];
- if (child.name === name) {
- ret.push(child);
- }
- }
- return ret;
- };
- SymbolTableScope.prototype._identsMatching = function (f) {
- var k;
- var ret = [];
- for (k in this.symFlags) {
- if (this.symFlags.hasOwnProperty(k)) {
- if (f(this.symFlags[k])) {
- ret.push(k);
- }
- }
- }
- ret.sort();
- return ret;
- };
- SymbolTableScope.prototype.get_parameters = function () {
- goog.asserts.assert(this.get_type() == "function", "get_parameters only valid for function scopes");
- if (!this._funcParams) {
- this._funcParams = this._identsMatching(function (x) {
- return x & DEF_PARAM;
- });
- }
- return this._funcParams;
- };
- SymbolTableScope.prototype.get_locals = function () {
- goog.asserts.assert(this.get_type() == "function", "get_locals only valid for function scopes");
- if (!this._funcLocals) {
- this._funcLocals = this._identsMatching(function (x) {
- return x & DEF_BOUND;
- });
- }
- return this._funcLocals;
- };
- SymbolTableScope.prototype.get_globals = function () {
- goog.asserts.assert(this.get_type() == "function", "get_globals only valid for function scopes");
- if (!this._funcGlobals) {
- this._funcGlobals = this._identsMatching(function (x) {
- var masked = (x >> SCOPE_OFF) & SCOPE_MASK;
- return masked == GLOBAL_IMPLICIT || masked == GLOBAL_EXPLICIT;
- });
- }
- return this._funcGlobals;
- };
- SymbolTableScope.prototype.get_frees = function () {
- goog.asserts.assert(this.get_type() == "function", "get_frees only valid for function scopes");
- if (!this._funcFrees) {
- this._funcFrees = this._identsMatching(function (x) {
- var masked = (x >> SCOPE_OFF) & SCOPE_MASK;
- return masked == FREE;
- });
- }
- return this._funcFrees;
- };
- SymbolTableScope.prototype.get_methods = function () {
- var i;
- var all;
- goog.asserts.assert(this.get_type() == "class", "get_methods only valid for class scopes");
- if (!this._classMethods) {
- // todo; uniq?
- all = [];
- for (i = 0; i < this.children.length; ++i) {
- all.push(this.children[i].name);
- }
- all.sort();
- this._classMethods = all;
- }
- return this._classMethods;
- };
- SymbolTableScope.prototype.getScope = function (name) {
- //print("getScope");
- //for (var k in this.symFlags) print(k);
- var v = this.symFlags[name];
- if (v === undefined) {
- return 0;
- }
- return (v >> SCOPE_OFF) & SCOPE_MASK;
- };
- /**
- * @constructor
- * @param {string} filename
- */
- function SymbolTable (filename) {
- this.filename = filename;
- this.cur = null;
- this.top = null;
- this.stack = [];
- this.global = null; // points at top level module symFlags
- this.curClass = null; // current class or null
- this.tmpname = 0;
- // mapping from ast nodes to their scope if they have one. we add an
- // id to the ast node when a scope is created for it, and store it in
- // here for the compiler to lookup later.
- this.stss = {};
- }
- SymbolTable.prototype.getStsForAst = function (ast) {
- var v;
- goog.asserts.assert(ast.scopeId !== undefined, "ast wasn't added to st?");
- v = this.stss[ast.scopeId];
- goog.asserts.assert(v !== undefined, "unknown sym tab entry");
- return v;
- };
- SymbolTable.prototype.SEQStmt = function (nodes) {
- var val;
- var i;
- var len;
- goog.asserts.assert(goog.isArrayLike(nodes), "SEQ: nodes isn't array? got %s", nodes);
- len = nodes.length;
- for (i = 0; i < len; ++i) {
- val = nodes[i];
- if (val) {
- this.visitStmt(val);
- }
- }
- };
- SymbolTable.prototype.SEQExpr = function (nodes) {
- var val;
- var i;
- var len;
- goog.asserts.assert(goog.isArrayLike(nodes), "SEQ: nodes isn't array? got %s", nodes);
- len = nodes.length;
- for (i = 0; i < len; ++i) {
- val = nodes[i];
- if (val) {
- this.visitExpr(val);
- }
- }
- };
- SymbolTable.prototype.enterBlock = function (name, blockType, ast, lineno) {
- var prev;
- name = fixReservedNames(name);
- //print("enterBlock:", name);
- prev = null;
- if (this.cur) {
- prev = this.cur;
- this.stack.push(this.cur);
- }
- this.cur = new SymbolTableScope(this, name, blockType, ast, lineno);
- if (name === "top") {
- this.global = this.cur.symFlags;
- }
- if (prev) {
- //print(" adding", this.cur.name, "to", prev.name);
- prev.children.push(this.cur);
- }
- };
- SymbolTable.prototype.exitBlock = function () {
- //print("exitBlock");
- this.cur = null;
- if (this.stack.length > 0) {
- this.cur = this.stack.pop();
- }
- };
- SymbolTable.prototype.visitParams = function (args, toplevel) {
- var arg;
- var i;
- for (i = 0; i < args.length; ++i) {
- arg = args[i];
- if (arg.constructor === Name) {
- goog.asserts.assert(arg.ctx === Param || (arg.ctx === Store && !toplevel));
- this.addDef(arg.id, DEF_PARAM, arg.lineno);
- }
- else {
- // Tuple isn't supported
- throw new Sk.builtin.SyntaxError("invalid expression in parameter list", this.filename);
- }
- }
- };
- SymbolTable.prototype.visitArguments = function (a, lineno) {
- if (a.args) {
- this.visitParams(a.args, true);
- }
- if (a.vararg) {
- this.addDef(a.vararg, DEF_PARAM, lineno);
- this.cur.varargs = true;
- }
- if (a.kwarg) {
- this.addDef(a.kwarg, DEF_PARAM, lineno);
- this.cur.varkeywords = true;
- }
- };
- SymbolTable.prototype.newTmpname = function (lineno) {
- this.addDef(new Sk.builtin.str("_[" + (++this.tmpname) + "]"), DEF_LOCAL, lineno);
- };
- SymbolTable.prototype.addDef = function (name, flag, lineno) {
- var fromGlobal;
- var val;
- var mangled = mangleName(this.curClass, new Sk.builtin.str(name)).v;
- mangled = fixReservedNames(mangled);
- val = this.cur.symFlags[mangled];
- if (val !== undefined) {
- if ((flag & DEF_PARAM) && (val & DEF_PARAM)) {
- throw new Sk.builtin.SyntaxError("duplicate argument '" + name.v + "' in function definition", this.filename, lineno);
- }
- val |= flag;
- }
- else {
- val = flag;
- }
- this.cur.symFlags[mangled] = val;
- if (flag & DEF_PARAM) {
- this.cur.varnames.push(mangled);
- }
- else if (flag & DEF_GLOBAL) {
- val = flag;
- fromGlobal = this.global[mangled];
- if (fromGlobal !== undefined) {
- val |= fromGlobal;
- }
- this.global[mangled] = val;
- }
- };
- SymbolTable.prototype.visitSlice = function (s) {
- var i;
- switch (s.constructor) {
- case Slice:
- if (s.lower) {
- this.visitExpr(s.lower);
- }
- if (s.upper) {
- this.visitExpr(s.upper);
- }
- if (s.step) {
- this.visitExpr(s.step);
- }
- break;
- case ExtSlice:
- for (i = 0; i < s.dims.length; ++i) {
- this.visitSlice(s.dims[i]);
- }
- break;
- case Index:
- this.visitExpr(s.value);
- break;
- case Ellipsis:
- break;
- }
- };
- SymbolTable.prototype.visitStmt = function (s) {
- var cur;
- var name;
- var i;
- var nameslen;
- var tmp;
- goog.asserts.assert(s !== undefined, "visitStmt called with undefined");
- switch (s.constructor) {
- case FunctionDef:
- this.addDef(s.name, DEF_LOCAL, s.lineno);
- if (s.args.defaults) {
- this.SEQExpr(s.args.defaults);
- }
- if (s.decorator_list) {
- this.SEQExpr(s.decorator_list);
- }
- this.enterBlock(s.name.v, FunctionBlock, s, s.lineno);
- this.visitArguments(s.args, s.lineno);
- this.SEQStmt(s.body);
- this.exitBlock();
- break;
- case ClassDef:
- this.addDef(s.name, DEF_LOCAL, s.lineno);
- this.SEQExpr(s.bases);
- if (s.decorator_list) {
- this.SEQExpr(s.decorator_list);
- }
- this.enterBlock(s.name.v, ClassBlock, s, s.lineno);
- tmp = this.curClass;
- this.curClass = s.name;
- this.SEQStmt(s.body);
- this.exitBlock();
- break;
- case Return_:
- if (s.value) {
- this.visitExpr(s.value);
- this.cur.returnsValue = true;
- if (this.cur.generator) {
- throw new Sk.builtin.SyntaxError("'return' with argument inside generator", this.filename);
- }
- }
- break;
- case Delete_:
- this.SEQExpr(s.targets);
- break;
- case Assign:
- this.SEQExpr(s.targets);
- this.visitExpr(s.value);
- break;
- case AugAssign:
- this.visitExpr(s.target);
- this.visitExpr(s.value);
- break;
- case Print:
- if (s.dest) {
- this.visitExpr(s.dest);
- }
- this.SEQExpr(s.values);
- break;
- case For_:
- this.visitExpr(s.target);
- this.visitExpr(s.iter);
- this.SEQStmt(s.body);
- if (s.orelse) {
- this.SEQStmt(s.orelse);
- }
- break;
- case While_:
- this.visitExpr(s.test);
- this.SEQStmt(s.body);
- if (s.orelse) {
- this.SEQStmt(s.orelse);
- }
- break;
- case If_:
- this.visitExpr(s.test);
- this.SEQStmt(s.body);
- if (s.orelse) {
- this.SEQStmt(s.orelse);
- }
- break;
- case Raise:
- if (s.type) {
- this.visitExpr(s.type);
- if (s.inst) {
- this.visitExpr(s.inst);
- if (s.tback) {
- this.visitExpr(s.tback);
- }
- }
- }
- break;
- case TryExcept:
- this.SEQStmt(s.body);
- this.SEQStmt(s.orelse);
- this.visitExcepthandlers(s.handlers);
- break;
- case TryFinally:
- this.SEQStmt(s.body);
- this.SEQStmt(s.finalbody);
- break;
- case Assert:
- this.visitExpr(s.test);
- if (s.msg) {
- this.visitExpr(s.msg);
- }
- break;
- case Import_:
- case ImportFrom:
- this.visitAlias(s.names, s.lineno);
- break;
- case Exec:
- this.visitExpr(s.body);
- if (s.globals) {
- this.visitExpr(s.globals);
- if (s.locals) {
- this.visitExpr(s.locals);
- }
- }
- break;
- case Global:
- nameslen = s.names.length;
- for (i = 0; i < nameslen; ++i) {
- name = mangleName(this.curClass, s.names[i]).v;
- name = fixReservedNames(name);
- cur = this.cur.symFlags[name];
- if (cur & (DEF_LOCAL | USE)) {
- if (cur & DEF_LOCAL) {
- throw new Sk.builtin.SyntaxError("name '" + name + "' is assigned to before global declaration", this.filename, s.lineno);
- }
- else {
- throw new Sk.builtin.SyntaxError("name '" + name + "' is used prior to global declaration", this.filename, s.lineno);
- }
- }
- this.addDef(new Sk.builtin.str(name), DEF_GLOBAL, s.lineno);
- }
- break;
- case Expr:
- this.visitExpr(s.value);
- break;
- case Pass:
- case Break_:
- case Debugger_:
- case Continue_:
- // nothing
- break;
- case With_:
- this.newTmpname(s.lineno);
- this.visitExpr(s.context_expr);
- if (s.optional_vars) {
- this.newTmpname(s.lineno);
- this.visitExpr(s.optional_vars);
- }
- this.SEQStmt(s.body);
- break;
- default:
- goog.asserts.fail("Unhandled type " + s.constructor.name + " in visitStmt");
- }
- };
- SymbolTable.prototype.visitExpr = function (e) {
- var i;
- goog.asserts.assert(e !== undefined, "visitExpr called with undefined");
- //print(" e: ", e.constructor.name);
- switch (e.constructor) {
- case BoolOp:
- this.SEQExpr(e.values);
- break;
- case BinOp:
- this.visitExpr(e.left);
- this.visitExpr(e.right);
- break;
- case UnaryOp:
- this.visitExpr(e.operand);
- break;
- case Lambda:
- this.addDef(new Sk.builtin.str("lambda"), DEF_LOCAL, e.lineno);
- if (e.args.defaults) {
- this.SEQExpr(e.args.defaults);
- }
- this.enterBlock("lambda", FunctionBlock, e, e.lineno);
- this.visitArguments(e.args, e.lineno);
- this.visitExpr(e.body);
- this.exitBlock();
- break;
- case IfExp:
- this.visitExpr(e.test);
- this.visitExpr(e.body);
- this.visitExpr(e.orelse);
- break;
- case Dict:
- this.SEQExpr(e.keys);
- this.SEQExpr(e.values);
- break;
- case DictComp:
- case SetComp:
- this.visitComprehension(e.generators, 0);
- break;
- case ListComp:
- this.newTmpname(e.lineno);
- this.visitExpr(e.elt);
- this.visitComprehension(e.generators, 0);
- break;
- case GeneratorExp:
- this.visitGenexp(e);
- break;
- case Yield:
- if (e.value) {
- this.visitExpr(e.value);
- }
- this.cur.generator = true;
- if (this.cur.returnsValue) {
- throw new Sk.builtin.SyntaxError("'return' with argument inside generator", this.filename);
- }
- break;
- case Compare:
- this.visitExpr(e.left);
- this.SEQExpr(e.comparators);
- break;
- case Call:
- this.visitExpr(e.func);
- this.SEQExpr(e.args);
- for (i = 0; i < e.keywords.length; ++i) {
- this.visitExpr(e.keywords[i].value);
- }
- //print(JSON.stringify(e.starargs, null, 2));
- //print(JSON.stringify(e.kwargs, null,2));
- if (e.starargs) {
- this.visitExpr(e.starargs);
- }
- if (e.kwargs) {
- this.visitExpr(e.kwargs);
- }
- break;
- case Num:
- case Str:
- break;
- case Attribute:
- this.visitExpr(e.value);
- break;
- case Subscript:
- this.visitExpr(e.value);
- this.visitSlice(e.slice);
- break;
- case Name:
- this.addDef(e.id, e.ctx === Load ? USE : DEF_LOCAL, e.lineno);
- break;
- case List:
- case Tuple:
- case Set:
- this.SEQExpr(e.elts);
- break;
- default:
- goog.asserts.fail("Unhandled type " + e.constructor.name + " in visitExpr");
- }
- };
- SymbolTable.prototype.visitComprehension = function (lcs, startAt) {
- var lc;
- var i;
- var len = lcs.length;
- for (i = startAt; i < len; ++i) {
- lc = lcs[i];
- this.visitExpr(lc.target);
- this.visitExpr(lc.iter);
- this.SEQExpr(lc.ifs);
- }
- };
- SymbolTable.prototype.visitAlias = function (names, lineno) {
- /* Compute store_name, the name actually bound by the import
- operation. It is diferent than a->name when a->name is a
- dotted package name (e.g. spam.eggs)
- */
- var dot;
- var storename;
- var name;
- var a;
- var i;
- for (i = 0; i < names.length; ++i) {
- a = names[i];
- name = a.asname === null ? a.name.v : a.asname.v;
- storename = name;
- dot = name.indexOf(".");
- if (dot !== -1) {
- storename = name.substr(0, dot);
- }
- if (name !== "*") {
- this.addDef(new Sk.builtin.str(storename), DEF_IMPORT, lineno);
- }
- else {
- if (this.cur.blockType !== ModuleBlock) {
- throw new Sk.builtin.SyntaxError("import * only allowed at module level", this.filename);
- }
- }
- }
- };
- SymbolTable.prototype.visitGenexp = function (e) {
- var outermost = e.generators[0];
- // outermost is evaled in current scope
- this.visitExpr(outermost.iter);
- this.enterBlock("genexpr", FunctionBlock, e, e.lineno);
- this.cur.generator = true;
- this.addDef(new Sk.builtin.str(".0"), DEF_PARAM, e.lineno);
- this.visitExpr(outermost.target);
- this.SEQExpr(outermost.ifs);
- this.visitComprehension(e.generators, 1);
- this.visitExpr(e.elt);
- this.exitBlock();
- };
- SymbolTable.prototype.visitExcepthandlers = function (handlers) {
- var i, eh;
- for (i = 0; eh = handlers[i]; ++i) {
- if (eh.type) {
- this.visitExpr(eh.type);
- }
- if (eh.name) {
- this.visitExpr(eh.name);
- }
- this.SEQStmt(eh.body);
- }
- };
- function _dictUpdate (a, b) {
- var kb;
- for (kb in b) {
- a[kb] = b[kb];
- }
- }
- SymbolTable.prototype.analyzeBlock = function (ste, bound, free, global) {
- var c;
- var i;
- var childlen;
- var allfree;
- var flags;
- var name;
- var local = {};
- var scope = {};
- var newglobal = {};
- var newbound = {};
- var newfree = {};
- if (ste.blockType == ClassBlock) {
- _dictUpdate(newglobal, global);
- if (bound) {
- _dictUpdate(newbound, bound);
- }
- }
- for (name in ste.symFlags) {
- flags = ste.symFlags[name];
- this.analyzeName(ste, scope, name, flags, bound, local, free, global);
- }
- if (ste.blockType !== ClassBlock) {
- if (ste.blockType === FunctionBlock) {
- _dictUpdate(newbound, local);
- }
- if (bound) {
- _dictUpdate(newbound, bound);
- }
- _dictUpdate(newglobal, global);
- }
- allfree = {};
- childlen = ste.children.length;
- for (i = 0; i < childlen; ++i) {
- c = ste.children[i];
- this.analyzeChildBlock(c, newbound, newfree, newglobal, allfree);
- if (c.hasFree || c.childHasFree) {
- ste.childHasFree = true;
- }
- }
- _dictUpdate(newfree, allfree);
- if (ste.blockType === FunctionBlock) {
- this.analyzeCells(scope, newfree);
- }
- this.updateSymbols(ste.symFlags, scope, bound, newfree, ste.blockType === ClassBlock);
- _dictUpdate(free, newfree);
- };
- SymbolTable.prototype.analyzeChildBlock = function (entry, bound, free, global, childFree) {
- var tempGlobal;
- var tempFree;
- var tempBound = {};
- _dictUpdate(tempBound, bound);
- tempFree = {};
- _dictUpdate(tempFree, free);
- tempGlobal = {};
- _dictUpdate(tempGlobal, global);
- this.analyzeBlock(entry, tempBound, tempFree, tempGlobal);
- _dictUpdate(childFree, tempFree);
- };
- SymbolTable.prototype.analyzeCells = function (scope, free) {
- var flags;
- var name;
- for (name in scope) {
- flags = scope[name];
- if (flags !== LOCAL) {
- continue;
- }
- if (free[name] === undefined) {
- continue;
- }
- scope[name] = CELL;
- delete free[name];
- }
- };
- /**
- * store scope info back into the st symbols dict. symbols is modified,
- * others are not.
- */
- SymbolTable.prototype.updateSymbols = function (symbols, scope, bound, free, classflag) {
- var i;
- var o;
- var pos;
- var freeValue;
- var w;
- var flags;
- var name;
- for (name in symbols) {
- flags = symbols[name];
- w = scope[name];
- flags |= w << SCOPE_OFF;
- symbols[name] = flags;
- }
- freeValue = FREE << SCOPE_OFF;
- pos = 0;
- for (name in free) {
- o = symbols[name];
- if (o !== undefined) {
- // it could be a free variable in a method of the class that has
- // the same name as a local or global in the class scope
- if (classflag && (o & (DEF_BOUND | DEF_GLOBAL))) {
- i = o | DEF_FREE_CLASS;
- symbols[name] = i;
- }
- // else it's not free, probably a cell
- continue;
- }
- if (bound[name] === undefined) {
- continue;
- }
- symbols[name] = freeValue;
- }
- };
- SymbolTable.prototype.analyzeName = function (ste, dict, name, flags, bound, local, free, global) {
- if (flags & DEF_GLOBAL) {
- if (flags & DEF_PARAM) {
- throw new Sk.builtin.SyntaxError("name '" + name + "' is local and global", this.filename, ste.lineno);
- }
- dict[name] = GLOBAL_EXPLICIT;
- global[name] = null;
- if (bound && bound[name] !== undefined) {
- delete bound[name];
- }
- return;
- }
- if (flags & DEF_BOUND) {
- dict[name] = LOCAL;
- local[name] = null;
- delete global[name];
- return;
- }
- if (bound && bound[name] !== undefined) {
- dict[name] = FREE;
- ste.hasFree = true;
- free[name] = null;
- }
- else if (global && global[name] !== undefined) {
- dict[name] = GLOBAL_IMPLICIT;
- }
- else {
- if (ste.isNested) {
- ste.hasFree = true;
- }
- dict[name] = GLOBAL_IMPLICIT;
- }
- };
- SymbolTable.prototype.analyze = function () {
- var free = {};
- var global = {};
- this.analyzeBlock(this.top, null, free, global);
- };
- /**
- * @param {Object} ast
- * @param {string} filename
- */
- Sk.symboltable = function (ast, filename) {
- var i;
- var ret = new SymbolTable(filename);
- ret.enterBlock("top", ModuleBlock, ast, 0);
- ret.top = ret.cur;
- //print(Sk.astDump(ast));
- for (i = 0; i < ast.body.length; ++i) {
- ret.visitStmt(ast.body[i]);
- }
- ret.exitBlock();
- ret.analyze();
- return ret;
- };
- Sk.dumpSymtab = function (st) {
- var pyBoolStr = function (b) {
- return b ? "True" : "False";
- }
- var pyList = function (l) {
- var i;
- var ret = [];
- for (i = 0; i < l.length; ++i) {
- ret.push(new Sk.builtin.str(l[i])["$r"]().v);
- }
- return "[" + ret.join(", ") + "]";
- };
- var getIdents = function (obj, indent) {
- var ns;
- var j;
- var sub;
- var nsslen;
- var nss;
- var info;
- var i;
- var objidentslen;
- var objidents;
- var ret;
- if (indent === undefined) {
- indent = "";
- }
- ret = "";
- ret += indent + "Sym_type: " + obj.get_type() + "\n";
- ret += indent + "Sym_name: " + obj.get_name() + "\n";
- ret += indent + "Sym_lineno: " + obj.get_lineno() + "\n";
- ret += indent + "Sym_nested: " + pyBoolStr(obj.is_nested()) + "\n";
- ret += indent + "Sym_haschildren: " + pyBoolStr(obj.has_children()) + "\n";
- if (obj.get_type() === "class") {
- ret += indent + "Class_methods: " + pyList(obj.get_methods()) + "\n";
- }
- else if (obj.get_type() === "function") {
- ret += indent + "Func_params: " + pyList(obj.get_parameters()) + "\n";
- ret += indent + "Func_locals: " + pyList(obj.get_locals()) + "\n";
- ret += indent + "Func_globals: " + pyList(obj.get_globals()) + "\n";
- ret += indent + "Func_frees: " + pyList(obj.get_frees()) + "\n";
- }
- ret += indent + "-- Identifiers --\n";
- objidents = obj.get_identifiers();
- objidentslen = objidents.length;
- for (i = 0; i < objidentslen; ++i) {
- info = obj.lookup(objidents[i]);
- ret += indent + "name: " + info.get_name() + "\n";
- ret += indent + " is_referenced: " + pyBoolStr(info.is_referenced()) + "\n";
- ret += indent + " is_imported: " + pyBoolStr(info.is_imported()) + "\n";
- ret += indent + " is_parameter: " + pyBoolStr(info.is_parameter()) + "\n";
- ret += indent + " is_global: " + pyBoolStr(info.is_global()) + "\n";
- ret += indent + " is_declared_global: " + pyBoolStr(info.is_declared_global()) + "\n";
- ret += indent + " is_local: " + pyBoolStr(info.is_local()) + "\n";
- ret += indent + " is_free: " + pyBoolStr(info.is_free()) + "\n";
- ret += indent + " is_assigned: " + pyBoolStr(info.is_assigned()) + "\n";
- ret += indent + " is_namespace: " + pyBoolStr(info.is_namespace()) + "\n";
- nss = info.get_namespaces();
- nsslen = nss.length;
- ret += indent + " namespaces: [\n";
- sub = [];
- for (j = 0; j < nsslen; ++j) {
- ns = nss[j];
- sub.push(getIdents(ns, indent + " "));
- }
- ret += sub.join("\n");
- ret += indent + " ]\n";
- }
- return ret;
- };
- return getIdents(st.top, "");
- };
- goog.exportSymbol("Sk.symboltable", Sk.symboltable);
- goog.exportSymbol("Sk.dumpSymtab", Sk.dumpSymtab);
|