Software zum Installieren eines Smart-Mirror Frameworks , zum Nutzen von hochschulrelevanten Informationen, auf einem Raspberry-Pi.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

compiler.js 37KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449
  1. 'use strict';
  2. function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); }
  3. function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
  4. var parser = require('./parser');
  5. var transformer = require('./transformer');
  6. var nodes = require('./nodes');
  7. var _require = require('./lib'),
  8. TemplateError = _require.TemplateError;
  9. var _require2 = require('./runtime'),
  10. Frame = _require2.Frame;
  11. var _require3 = require('./object'),
  12. Obj = _require3.Obj; // These are all the same for now, but shouldn't be passed straight
  13. // through
  14. var compareOps = {
  15. '==': '==',
  16. '===': '===',
  17. '!=': '!=',
  18. '!==': '!==',
  19. '<': '<',
  20. '>': '>',
  21. '<=': '<=',
  22. '>=': '>='
  23. };
  24. var Compiler = /*#__PURE__*/function (_Obj) {
  25. _inheritsLoose(Compiler, _Obj);
  26. function Compiler() {
  27. return _Obj.apply(this, arguments) || this;
  28. }
  29. var _proto = Compiler.prototype;
  30. _proto.init = function init(templateName, throwOnUndefined) {
  31. this.templateName = templateName;
  32. this.codebuf = [];
  33. this.lastId = 0;
  34. this.buffer = null;
  35. this.bufferStack = [];
  36. this._scopeClosers = '';
  37. this.inBlock = false;
  38. this.throwOnUndefined = throwOnUndefined;
  39. };
  40. _proto.fail = function fail(msg, lineno, colno) {
  41. if (lineno !== undefined) {
  42. lineno += 1;
  43. }
  44. if (colno !== undefined) {
  45. colno += 1;
  46. }
  47. throw new TemplateError(msg, lineno, colno);
  48. };
  49. _proto._pushBuffer = function _pushBuffer() {
  50. var id = this._tmpid();
  51. this.bufferStack.push(this.buffer);
  52. this.buffer = id;
  53. this._emit("var " + this.buffer + " = \"\";");
  54. return id;
  55. };
  56. _proto._popBuffer = function _popBuffer() {
  57. this.buffer = this.bufferStack.pop();
  58. };
  59. _proto._emit = function _emit(code) {
  60. this.codebuf.push(code);
  61. };
  62. _proto._emitLine = function _emitLine(code) {
  63. this._emit(code + '\n');
  64. };
  65. _proto._emitLines = function _emitLines() {
  66. var _this = this;
  67. for (var _len = arguments.length, lines = new Array(_len), _key = 0; _key < _len; _key++) {
  68. lines[_key] = arguments[_key];
  69. }
  70. lines.forEach(function (line) {
  71. return _this._emitLine(line);
  72. });
  73. };
  74. _proto._emitFuncBegin = function _emitFuncBegin(node, name) {
  75. this.buffer = 'output';
  76. this._scopeClosers = '';
  77. this._emitLine("function " + name + "(env, context, frame, runtime, cb) {");
  78. this._emitLine("var lineno = " + node.lineno + ";");
  79. this._emitLine("var colno = " + node.colno + ";");
  80. this._emitLine("var " + this.buffer + " = \"\";");
  81. this._emitLine('try {');
  82. };
  83. _proto._emitFuncEnd = function _emitFuncEnd(noReturn) {
  84. if (!noReturn) {
  85. this._emitLine('cb(null, ' + this.buffer + ');');
  86. }
  87. this._closeScopeLevels();
  88. this._emitLine('} catch (e) {');
  89. this._emitLine(' cb(runtime.handleError(e, lineno, colno));');
  90. this._emitLine('}');
  91. this._emitLine('}');
  92. this.buffer = null;
  93. };
  94. _proto._addScopeLevel = function _addScopeLevel() {
  95. this._scopeClosers += '})';
  96. };
  97. _proto._closeScopeLevels = function _closeScopeLevels() {
  98. this._emitLine(this._scopeClosers + ';');
  99. this._scopeClosers = '';
  100. };
  101. _proto._withScopedSyntax = function _withScopedSyntax(func) {
  102. var _scopeClosers = this._scopeClosers;
  103. this._scopeClosers = '';
  104. func.call(this);
  105. this._closeScopeLevels();
  106. this._scopeClosers = _scopeClosers;
  107. };
  108. _proto._makeCallback = function _makeCallback(res) {
  109. var err = this._tmpid();
  110. return 'function(' + err + (res ? ',' + res : '') + ') {\n' + 'if(' + err + ') { cb(' + err + '); return; }';
  111. };
  112. _proto._tmpid = function _tmpid() {
  113. this.lastId++;
  114. return 't_' + this.lastId;
  115. };
  116. _proto._templateName = function _templateName() {
  117. return this.templateName == null ? 'undefined' : JSON.stringify(this.templateName);
  118. };
  119. _proto._compileChildren = function _compileChildren(node, frame) {
  120. var _this2 = this;
  121. node.children.forEach(function (child) {
  122. _this2.compile(child, frame);
  123. });
  124. };
  125. _proto._compileAggregate = function _compileAggregate(node, frame, startChar, endChar) {
  126. var _this3 = this;
  127. if (startChar) {
  128. this._emit(startChar);
  129. }
  130. node.children.forEach(function (child, i) {
  131. if (i > 0) {
  132. _this3._emit(',');
  133. }
  134. _this3.compile(child, frame);
  135. });
  136. if (endChar) {
  137. this._emit(endChar);
  138. }
  139. };
  140. _proto._compileExpression = function _compileExpression(node, frame) {
  141. // TODO: I'm not really sure if this type check is worth it or
  142. // not.
  143. this.assertType(node, nodes.Literal, nodes.Symbol, nodes.Group, nodes.Array, nodes.Dict, nodes.FunCall, nodes.Caller, nodes.Filter, nodes.LookupVal, nodes.Compare, nodes.InlineIf, nodes.In, nodes.Is, nodes.And, nodes.Or, nodes.Not, nodes.Add, nodes.Concat, nodes.Sub, nodes.Mul, nodes.Div, nodes.FloorDiv, nodes.Mod, nodes.Pow, nodes.Neg, nodes.Pos, nodes.Compare, nodes.NodeList);
  144. this.compile(node, frame);
  145. };
  146. _proto.assertType = function assertType(node) {
  147. for (var _len2 = arguments.length, types = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
  148. types[_key2 - 1] = arguments[_key2];
  149. }
  150. if (!types.some(function (t) {
  151. return node instanceof t;
  152. })) {
  153. this.fail("assertType: invalid type: " + node.typename, node.lineno, node.colno);
  154. }
  155. };
  156. _proto.compileCallExtension = function compileCallExtension(node, frame, async) {
  157. var _this4 = this;
  158. var args = node.args;
  159. var contentArgs = node.contentArgs;
  160. var autoescape = typeof node.autoescape === 'boolean' ? node.autoescape : true;
  161. if (!async) {
  162. this._emit(this.buffer + " += runtime.suppressValue(");
  163. }
  164. this._emit("env.getExtension(\"" + node.extName + "\")[\"" + node.prop + "\"](");
  165. this._emit('context');
  166. if (args || contentArgs) {
  167. this._emit(',');
  168. }
  169. if (args) {
  170. if (!(args instanceof nodes.NodeList)) {
  171. this.fail('compileCallExtension: arguments must be a NodeList, ' + 'use `parser.parseSignature`');
  172. }
  173. args.children.forEach(function (arg, i) {
  174. // Tag arguments are passed normally to the call. Note
  175. // that keyword arguments are turned into a single js
  176. // object as the last argument, if they exist.
  177. _this4._compileExpression(arg, frame);
  178. if (i !== args.children.length - 1 || contentArgs.length) {
  179. _this4._emit(',');
  180. }
  181. });
  182. }
  183. if (contentArgs.length) {
  184. contentArgs.forEach(function (arg, i) {
  185. if (i > 0) {
  186. _this4._emit(',');
  187. }
  188. if (arg) {
  189. _this4._emitLine('function(cb) {');
  190. _this4._emitLine('if(!cb) { cb = function(err) { if(err) { throw err; }}}');
  191. var id = _this4._pushBuffer();
  192. _this4._withScopedSyntax(function () {
  193. _this4.compile(arg, frame);
  194. _this4._emitLine("cb(null, " + id + ");");
  195. });
  196. _this4._popBuffer();
  197. _this4._emitLine("return " + id + ";");
  198. _this4._emitLine('}');
  199. } else {
  200. _this4._emit('null');
  201. }
  202. });
  203. }
  204. if (async) {
  205. var res = this._tmpid();
  206. this._emitLine(', ' + this._makeCallback(res));
  207. this._emitLine(this.buffer + " += runtime.suppressValue(" + res + ", " + autoescape + " && env.opts.autoescape);");
  208. this._addScopeLevel();
  209. } else {
  210. this._emit(')');
  211. this._emit(", " + autoescape + " && env.opts.autoescape);\n");
  212. }
  213. };
  214. _proto.compileCallExtensionAsync = function compileCallExtensionAsync(node, frame) {
  215. this.compileCallExtension(node, frame, true);
  216. };
  217. _proto.compileNodeList = function compileNodeList(node, frame) {
  218. this._compileChildren(node, frame);
  219. };
  220. _proto.compileLiteral = function compileLiteral(node) {
  221. if (typeof node.value === 'string') {
  222. var val = node.value.replace(/\\/g, '\\\\');
  223. val = val.replace(/"/g, '\\"');
  224. val = val.replace(/\n/g, '\\n');
  225. val = val.replace(/\r/g, '\\r');
  226. val = val.replace(/\t/g, '\\t');
  227. val = val.replace(/\u2028/g, "\\u2028");
  228. this._emit("\"" + val + "\"");
  229. } else if (node.value === null) {
  230. this._emit('null');
  231. } else {
  232. this._emit(node.value.toString());
  233. }
  234. };
  235. _proto.compileSymbol = function compileSymbol(node, frame) {
  236. var name = node.value;
  237. var v = frame.lookup(name);
  238. if (v) {
  239. this._emit(v);
  240. } else {
  241. this._emit('runtime.contextOrFrameLookup(' + 'context, frame, "' + name + '")');
  242. }
  243. };
  244. _proto.compileGroup = function compileGroup(node, frame) {
  245. this._compileAggregate(node, frame, '(', ')');
  246. };
  247. _proto.compileArray = function compileArray(node, frame) {
  248. this._compileAggregate(node, frame, '[', ']');
  249. };
  250. _proto.compileDict = function compileDict(node, frame) {
  251. this._compileAggregate(node, frame, '{', '}');
  252. };
  253. _proto.compilePair = function compilePair(node, frame) {
  254. var key = node.key;
  255. var val = node.value;
  256. if (key instanceof nodes.Symbol) {
  257. key = new nodes.Literal(key.lineno, key.colno, key.value);
  258. } else if (!(key instanceof nodes.Literal && typeof key.value === 'string')) {
  259. this.fail('compilePair: Dict keys must be strings or names', key.lineno, key.colno);
  260. }
  261. this.compile(key, frame);
  262. this._emit(': ');
  263. this._compileExpression(val, frame);
  264. };
  265. _proto.compileInlineIf = function compileInlineIf(node, frame) {
  266. this._emit('(');
  267. this.compile(node.cond, frame);
  268. this._emit('?');
  269. this.compile(node.body, frame);
  270. this._emit(':');
  271. if (node.else_ !== null) {
  272. this.compile(node.else_, frame);
  273. } else {
  274. this._emit('""');
  275. }
  276. this._emit(')');
  277. };
  278. _proto.compileIn = function compileIn(node, frame) {
  279. this._emit('runtime.inOperator(');
  280. this.compile(node.left, frame);
  281. this._emit(',');
  282. this.compile(node.right, frame);
  283. this._emit(')');
  284. };
  285. _proto.compileIs = function compileIs(node, frame) {
  286. // first, we need to try to get the name of the test function, if it's a
  287. // callable (i.e., has args) and not a symbol.
  288. var right = node.right.name ? node.right.name.value // otherwise go with the symbol value
  289. : node.right.value;
  290. this._emit('env.getTest("' + right + '").call(context, ');
  291. this.compile(node.left, frame); // compile the arguments for the callable if they exist
  292. if (node.right.args) {
  293. this._emit(',');
  294. this.compile(node.right.args, frame);
  295. }
  296. this._emit(') === true');
  297. };
  298. _proto._binOpEmitter = function _binOpEmitter(node, frame, str) {
  299. this.compile(node.left, frame);
  300. this._emit(str);
  301. this.compile(node.right, frame);
  302. } // ensure concatenation instead of addition
  303. // by adding empty string in between
  304. ;
  305. _proto.compileOr = function compileOr(node, frame) {
  306. return this._binOpEmitter(node, frame, ' || ');
  307. };
  308. _proto.compileAnd = function compileAnd(node, frame) {
  309. return this._binOpEmitter(node, frame, ' && ');
  310. };
  311. _proto.compileAdd = function compileAdd(node, frame) {
  312. return this._binOpEmitter(node, frame, ' + ');
  313. };
  314. _proto.compileConcat = function compileConcat(node, frame) {
  315. return this._binOpEmitter(node, frame, ' + "" + ');
  316. };
  317. _proto.compileSub = function compileSub(node, frame) {
  318. return this._binOpEmitter(node, frame, ' - ');
  319. };
  320. _proto.compileMul = function compileMul(node, frame) {
  321. return this._binOpEmitter(node, frame, ' * ');
  322. };
  323. _proto.compileDiv = function compileDiv(node, frame) {
  324. return this._binOpEmitter(node, frame, ' / ');
  325. };
  326. _proto.compileMod = function compileMod(node, frame) {
  327. return this._binOpEmitter(node, frame, ' % ');
  328. };
  329. _proto.compileNot = function compileNot(node, frame) {
  330. this._emit('!');
  331. this.compile(node.target, frame);
  332. };
  333. _proto.compileFloorDiv = function compileFloorDiv(node, frame) {
  334. this._emit('Math.floor(');
  335. this.compile(node.left, frame);
  336. this._emit(' / ');
  337. this.compile(node.right, frame);
  338. this._emit(')');
  339. };
  340. _proto.compilePow = function compilePow(node, frame) {
  341. this._emit('Math.pow(');
  342. this.compile(node.left, frame);
  343. this._emit(', ');
  344. this.compile(node.right, frame);
  345. this._emit(')');
  346. };
  347. _proto.compileNeg = function compileNeg(node, frame) {
  348. this._emit('-');
  349. this.compile(node.target, frame);
  350. };
  351. _proto.compilePos = function compilePos(node, frame) {
  352. this._emit('+');
  353. this.compile(node.target, frame);
  354. };
  355. _proto.compileCompare = function compileCompare(node, frame) {
  356. var _this5 = this;
  357. this.compile(node.expr, frame);
  358. node.ops.forEach(function (op) {
  359. _this5._emit(" " + compareOps[op.type] + " ");
  360. _this5.compile(op.expr, frame);
  361. });
  362. };
  363. _proto.compileLookupVal = function compileLookupVal(node, frame) {
  364. this._emit('runtime.memberLookup((');
  365. this._compileExpression(node.target, frame);
  366. this._emit('),');
  367. this._compileExpression(node.val, frame);
  368. this._emit(')');
  369. };
  370. _proto._getNodeName = function _getNodeName(node) {
  371. switch (node.typename) {
  372. case 'Symbol':
  373. return node.value;
  374. case 'FunCall':
  375. return 'the return value of (' + this._getNodeName(node.name) + ')';
  376. case 'LookupVal':
  377. return this._getNodeName(node.target) + '["' + this._getNodeName(node.val) + '"]';
  378. case 'Literal':
  379. return node.value.toString();
  380. default:
  381. return '--expression--';
  382. }
  383. };
  384. _proto.compileFunCall = function compileFunCall(node, frame) {
  385. // Keep track of line/col info at runtime by settings
  386. // variables within an expression. An expression in javascript
  387. // like (x, y, z) returns the last value, and x and y can be
  388. // anything
  389. this._emit('(lineno = ' + node.lineno + ', colno = ' + node.colno + ', ');
  390. this._emit('runtime.callWrap('); // Compile it as normal.
  391. this._compileExpression(node.name, frame); // Output the name of what we're calling so we can get friendly errors
  392. // if the lookup fails.
  393. this._emit(', "' + this._getNodeName(node.name).replace(/"/g, '\\"') + '", context, ');
  394. this._compileAggregate(node.args, frame, '[', '])');
  395. this._emit(')');
  396. };
  397. _proto.compileFilter = function compileFilter(node, frame) {
  398. var name = node.name;
  399. this.assertType(name, nodes.Symbol);
  400. this._emit('env.getFilter("' + name.value + '").call(context, ');
  401. this._compileAggregate(node.args, frame);
  402. this._emit(')');
  403. };
  404. _proto.compileFilterAsync = function compileFilterAsync(node, frame) {
  405. var name = node.name;
  406. var symbol = node.symbol.value;
  407. this.assertType(name, nodes.Symbol);
  408. frame.set(symbol, symbol);
  409. this._emit('env.getFilter("' + name.value + '").call(context, ');
  410. this._compileAggregate(node.args, frame);
  411. this._emitLine(', ' + this._makeCallback(symbol));
  412. this._addScopeLevel();
  413. };
  414. _proto.compileKeywordArgs = function compileKeywordArgs(node, frame) {
  415. this._emit('runtime.makeKeywordArgs(');
  416. this.compileDict(node, frame);
  417. this._emit(')');
  418. };
  419. _proto.compileSet = function compileSet(node, frame) {
  420. var _this6 = this;
  421. var ids = []; // Lookup the variable names for each identifier and create
  422. // new ones if necessary
  423. node.targets.forEach(function (target) {
  424. var name = target.value;
  425. var id = frame.lookup(name);
  426. if (id === null || id === undefined) {
  427. id = _this6._tmpid(); // Note: This relies on js allowing scope across
  428. // blocks, in case this is created inside an `if`
  429. _this6._emitLine('var ' + id + ';');
  430. }
  431. ids.push(id);
  432. });
  433. if (node.value) {
  434. this._emit(ids.join(' = ') + ' = ');
  435. this._compileExpression(node.value, frame);
  436. this._emitLine(';');
  437. } else {
  438. this._emit(ids.join(' = ') + ' = ');
  439. this.compile(node.body, frame);
  440. this._emitLine(';');
  441. }
  442. node.targets.forEach(function (target, i) {
  443. var id = ids[i];
  444. var name = target.value; // We are running this for every var, but it's very
  445. // uncommon to assign to multiple vars anyway
  446. _this6._emitLine("frame.set(\"" + name + "\", " + id + ", true);");
  447. _this6._emitLine('if(frame.topLevel) {');
  448. _this6._emitLine("context.setVariable(\"" + name + "\", " + id + ");");
  449. _this6._emitLine('}');
  450. if (name.charAt(0) !== '_') {
  451. _this6._emitLine('if(frame.topLevel) {');
  452. _this6._emitLine("context.addExport(\"" + name + "\", " + id + ");");
  453. _this6._emitLine('}');
  454. }
  455. });
  456. };
  457. _proto.compileSwitch = function compileSwitch(node, frame) {
  458. var _this7 = this;
  459. this._emit('switch (');
  460. this.compile(node.expr, frame);
  461. this._emit(') {');
  462. node.cases.forEach(function (c, i) {
  463. _this7._emit('case ');
  464. _this7.compile(c.cond, frame);
  465. _this7._emit(': ');
  466. _this7.compile(c.body, frame); // preserve fall-throughs
  467. if (c.body.children.length) {
  468. _this7._emitLine('break;');
  469. }
  470. });
  471. if (node.default) {
  472. this._emit('default:');
  473. this.compile(node.default, frame);
  474. }
  475. this._emit('}');
  476. };
  477. _proto.compileIf = function compileIf(node, frame, async) {
  478. var _this8 = this;
  479. this._emit('if(');
  480. this._compileExpression(node.cond, frame);
  481. this._emitLine(') {');
  482. this._withScopedSyntax(function () {
  483. _this8.compile(node.body, frame);
  484. if (async) {
  485. _this8._emit('cb()');
  486. }
  487. });
  488. if (node.else_) {
  489. this._emitLine('}\nelse {');
  490. this._withScopedSyntax(function () {
  491. _this8.compile(node.else_, frame);
  492. if (async) {
  493. _this8._emit('cb()');
  494. }
  495. });
  496. } else if (async) {
  497. this._emitLine('}\nelse {');
  498. this._emit('cb()');
  499. }
  500. this._emitLine('}');
  501. };
  502. _proto.compileIfAsync = function compileIfAsync(node, frame) {
  503. this._emit('(function(cb) {');
  504. this.compileIf(node, frame, true);
  505. this._emit('})(' + this._makeCallback());
  506. this._addScopeLevel();
  507. };
  508. _proto._emitLoopBindings = function _emitLoopBindings(node, arr, i, len) {
  509. var _this9 = this;
  510. var bindings = [{
  511. name: 'index',
  512. val: i + " + 1"
  513. }, {
  514. name: 'index0',
  515. val: i
  516. }, {
  517. name: 'revindex',
  518. val: len + " - " + i
  519. }, {
  520. name: 'revindex0',
  521. val: len + " - " + i + " - 1"
  522. }, {
  523. name: 'first',
  524. val: i + " === 0"
  525. }, {
  526. name: 'last',
  527. val: i + " === " + len + " - 1"
  528. }, {
  529. name: 'length',
  530. val: len
  531. }];
  532. bindings.forEach(function (b) {
  533. _this9._emitLine("frame.set(\"loop." + b.name + "\", " + b.val + ");");
  534. });
  535. };
  536. _proto.compileFor = function compileFor(node, frame) {
  537. var _this10 = this;
  538. // Some of this code is ugly, but it keeps the generated code
  539. // as fast as possible. ForAsync also shares some of this, but
  540. // not much.
  541. var i = this._tmpid();
  542. var len = this._tmpid();
  543. var arr = this._tmpid();
  544. frame = frame.push();
  545. this._emitLine('frame = frame.push();');
  546. this._emit("var " + arr + " = ");
  547. this._compileExpression(node.arr, frame);
  548. this._emitLine(';');
  549. this._emit("if(" + arr + ") {");
  550. this._emitLine(arr + ' = runtime.fromIterator(' + arr + ');'); // If multiple names are passed, we need to bind them
  551. // appropriately
  552. if (node.name instanceof nodes.Array) {
  553. this._emitLine("var " + i + ";"); // The object could be an arroy or object. Note that the
  554. // body of the loop is duplicated for each condition, but
  555. // we are optimizing for speed over size.
  556. this._emitLine("if(runtime.isArray(" + arr + ")) {");
  557. this._emitLine("var " + len + " = " + arr + ".length;");
  558. this._emitLine("for(" + i + "=0; " + i + " < " + arr + ".length; " + i + "++) {"); // Bind each declared var
  559. node.name.children.forEach(function (child, u) {
  560. var tid = _this10._tmpid();
  561. _this10._emitLine("var " + tid + " = " + arr + "[" + i + "][" + u + "];");
  562. _this10._emitLine("frame.set(\"" + child + "\", " + arr + "[" + i + "][" + u + "]);");
  563. frame.set(node.name.children[u].value, tid);
  564. });
  565. this._emitLoopBindings(node, arr, i, len);
  566. this._withScopedSyntax(function () {
  567. _this10.compile(node.body, frame);
  568. });
  569. this._emitLine('}');
  570. this._emitLine('} else {'); // Iterate over the key/values of an object
  571. var _node$name$children = node.name.children,
  572. key = _node$name$children[0],
  573. val = _node$name$children[1];
  574. var k = this._tmpid();
  575. var v = this._tmpid();
  576. frame.set(key.value, k);
  577. frame.set(val.value, v);
  578. this._emitLine(i + " = -1;");
  579. this._emitLine("var " + len + " = runtime.keys(" + arr + ").length;");
  580. this._emitLine("for(var " + k + " in " + arr + ") {");
  581. this._emitLine(i + "++;");
  582. this._emitLine("var " + v + " = " + arr + "[" + k + "];");
  583. this._emitLine("frame.set(\"" + key.value + "\", " + k + ");");
  584. this._emitLine("frame.set(\"" + val.value + "\", " + v + ");");
  585. this._emitLoopBindings(node, arr, i, len);
  586. this._withScopedSyntax(function () {
  587. _this10.compile(node.body, frame);
  588. });
  589. this._emitLine('}');
  590. this._emitLine('}');
  591. } else {
  592. // Generate a typical array iteration
  593. var _v = this._tmpid();
  594. frame.set(node.name.value, _v);
  595. this._emitLine("var " + len + " = " + arr + ".length;");
  596. this._emitLine("for(var " + i + "=0; " + i + " < " + arr + ".length; " + i + "++) {");
  597. this._emitLine("var " + _v + " = " + arr + "[" + i + "];");
  598. this._emitLine("frame.set(\"" + node.name.value + "\", " + _v + ");");
  599. this._emitLoopBindings(node, arr, i, len);
  600. this._withScopedSyntax(function () {
  601. _this10.compile(node.body, frame);
  602. });
  603. this._emitLine('}');
  604. }
  605. this._emitLine('}');
  606. if (node.else_) {
  607. this._emitLine('if (!' + len + ') {');
  608. this.compile(node.else_, frame);
  609. this._emitLine('}');
  610. }
  611. this._emitLine('frame = frame.pop();');
  612. };
  613. _proto._compileAsyncLoop = function _compileAsyncLoop(node, frame, parallel) {
  614. var _this11 = this;
  615. // This shares some code with the For tag, but not enough to
  616. // worry about. This iterates across an object asynchronously,
  617. // but not in parallel.
  618. var i = this._tmpid();
  619. var len = this._tmpid();
  620. var arr = this._tmpid();
  621. var asyncMethod = parallel ? 'asyncAll' : 'asyncEach';
  622. frame = frame.push();
  623. this._emitLine('frame = frame.push();');
  624. this._emit('var ' + arr + ' = runtime.fromIterator(');
  625. this._compileExpression(node.arr, frame);
  626. this._emitLine(');');
  627. if (node.name instanceof nodes.Array) {
  628. var arrayLen = node.name.children.length;
  629. this._emit("runtime." + asyncMethod + "(" + arr + ", " + arrayLen + ", function(");
  630. node.name.children.forEach(function (name) {
  631. _this11._emit(name.value + ",");
  632. });
  633. this._emit(i + ',' + len + ',next) {');
  634. node.name.children.forEach(function (name) {
  635. var id = name.value;
  636. frame.set(id, id);
  637. _this11._emitLine("frame.set(\"" + id + "\", " + id + ");");
  638. });
  639. } else {
  640. var id = node.name.value;
  641. this._emitLine("runtime." + asyncMethod + "(" + arr + ", 1, function(" + id + ", " + i + ", " + len + ",next) {");
  642. this._emitLine('frame.set("' + id + '", ' + id + ');');
  643. frame.set(id, id);
  644. }
  645. this._emitLoopBindings(node, arr, i, len);
  646. this._withScopedSyntax(function () {
  647. var buf;
  648. if (parallel) {
  649. buf = _this11._pushBuffer();
  650. }
  651. _this11.compile(node.body, frame);
  652. _this11._emitLine('next(' + i + (buf ? ',' + buf : '') + ');');
  653. if (parallel) {
  654. _this11._popBuffer();
  655. }
  656. });
  657. var output = this._tmpid();
  658. this._emitLine('}, ' + this._makeCallback(output));
  659. this._addScopeLevel();
  660. if (parallel) {
  661. this._emitLine(this.buffer + ' += ' + output + ';');
  662. }
  663. if (node.else_) {
  664. this._emitLine('if (!' + arr + '.length) {');
  665. this.compile(node.else_, frame);
  666. this._emitLine('}');
  667. }
  668. this._emitLine('frame = frame.pop();');
  669. };
  670. _proto.compileAsyncEach = function compileAsyncEach(node, frame) {
  671. this._compileAsyncLoop(node, frame);
  672. };
  673. _proto.compileAsyncAll = function compileAsyncAll(node, frame) {
  674. this._compileAsyncLoop(node, frame, true);
  675. };
  676. _proto._compileMacro = function _compileMacro(node, frame) {
  677. var _this12 = this;
  678. var args = [];
  679. var kwargs = null;
  680. var funcId = 'macro_' + this._tmpid();
  681. var keepFrame = frame !== undefined; // Type check the definition of the args
  682. node.args.children.forEach(function (arg, i) {
  683. if (i === node.args.children.length - 1 && arg instanceof nodes.Dict) {
  684. kwargs = arg;
  685. } else {
  686. _this12.assertType(arg, nodes.Symbol);
  687. args.push(arg);
  688. }
  689. });
  690. var realNames = [].concat(args.map(function (n) {
  691. return "l_" + n.value;
  692. }), ['kwargs']); // Quoted argument names
  693. var argNames = args.map(function (n) {
  694. return "\"" + n.value + "\"";
  695. });
  696. var kwargNames = (kwargs && kwargs.children || []).map(function (n) {
  697. return "\"" + n.key.value + "\"";
  698. }); // We pass a function to makeMacro which destructures the
  699. // arguments so support setting positional args with keywords
  700. // args and passing keyword args as positional args
  701. // (essentially default values). See runtime.js.
  702. var currFrame;
  703. if (keepFrame) {
  704. currFrame = frame.push(true);
  705. } else {
  706. currFrame = new Frame();
  707. }
  708. this._emitLines("var " + funcId + " = runtime.makeMacro(", "[" + argNames.join(', ') + "], ", "[" + kwargNames.join(', ') + "], ", "function (" + realNames.join(', ') + ") {", 'var callerFrame = frame;', 'frame = ' + (keepFrame ? 'frame.push(true);' : 'new runtime.Frame();'), 'kwargs = kwargs || {};', 'if (Object.prototype.hasOwnProperty.call(kwargs, "caller")) {', 'frame.set("caller", kwargs.caller); }'); // Expose the arguments to the template. Don't need to use
  709. // random names because the function
  710. // will create a new run-time scope for us
  711. args.forEach(function (arg) {
  712. _this12._emitLine("frame.set(\"" + arg.value + "\", l_" + arg.value + ");");
  713. currFrame.set(arg.value, "l_" + arg.value);
  714. }); // Expose the keyword arguments
  715. if (kwargs) {
  716. kwargs.children.forEach(function (pair) {
  717. var name = pair.key.value;
  718. _this12._emit("frame.set(\"" + name + "\", ");
  719. _this12._emit("Object.prototype.hasOwnProperty.call(kwargs, \"" + name + "\")");
  720. _this12._emit(" ? kwargs[\"" + name + "\"] : ");
  721. _this12._compileExpression(pair.value, currFrame);
  722. _this12._emit(');');
  723. });
  724. }
  725. var bufferId = this._pushBuffer();
  726. this._withScopedSyntax(function () {
  727. _this12.compile(node.body, currFrame);
  728. });
  729. this._emitLine('frame = ' + (keepFrame ? 'frame.pop();' : 'callerFrame;'));
  730. this._emitLine("return new runtime.SafeString(" + bufferId + ");");
  731. this._emitLine('});');
  732. this._popBuffer();
  733. return funcId;
  734. };
  735. _proto.compileMacro = function compileMacro(node, frame) {
  736. var funcId = this._compileMacro(node); // Expose the macro to the templates
  737. var name = node.name.value;
  738. frame.set(name, funcId);
  739. if (frame.parent) {
  740. this._emitLine("frame.set(\"" + name + "\", " + funcId + ");");
  741. } else {
  742. if (node.name.value.charAt(0) !== '_') {
  743. this._emitLine("context.addExport(\"" + name + "\");");
  744. }
  745. this._emitLine("context.setVariable(\"" + name + "\", " + funcId + ");");
  746. }
  747. };
  748. _proto.compileCaller = function compileCaller(node, frame) {
  749. // basically an anonymous "macro expression"
  750. this._emit('(function (){');
  751. var funcId = this._compileMacro(node, frame);
  752. this._emit("return " + funcId + ";})()");
  753. };
  754. _proto._compileGetTemplate = function _compileGetTemplate(node, frame, eagerCompile, ignoreMissing) {
  755. var parentTemplateId = this._tmpid();
  756. var parentName = this._templateName();
  757. var cb = this._makeCallback(parentTemplateId);
  758. var eagerCompileArg = eagerCompile ? 'true' : 'false';
  759. var ignoreMissingArg = ignoreMissing ? 'true' : 'false';
  760. this._emit('env.getTemplate(');
  761. this._compileExpression(node.template, frame);
  762. this._emitLine(", " + eagerCompileArg + ", " + parentName + ", " + ignoreMissingArg + ", " + cb);
  763. return parentTemplateId;
  764. };
  765. _proto.compileImport = function compileImport(node, frame) {
  766. var target = node.target.value;
  767. var id = this._compileGetTemplate(node, frame, false, false);
  768. this._addScopeLevel();
  769. this._emitLine(id + '.getExported(' + (node.withContext ? 'context.getVariables(), frame, ' : '') + this._makeCallback(id));
  770. this._addScopeLevel();
  771. frame.set(target, id);
  772. if (frame.parent) {
  773. this._emitLine("frame.set(\"" + target + "\", " + id + ");");
  774. } else {
  775. this._emitLine("context.setVariable(\"" + target + "\", " + id + ");");
  776. }
  777. };
  778. _proto.compileFromImport = function compileFromImport(node, frame) {
  779. var _this13 = this;
  780. var importedId = this._compileGetTemplate(node, frame, false, false);
  781. this._addScopeLevel();
  782. this._emitLine(importedId + '.getExported(' + (node.withContext ? 'context.getVariables(), frame, ' : '') + this._makeCallback(importedId));
  783. this._addScopeLevel();
  784. node.names.children.forEach(function (nameNode) {
  785. var name;
  786. var alias;
  787. var id = _this13._tmpid();
  788. if (nameNode instanceof nodes.Pair) {
  789. name = nameNode.key.value;
  790. alias = nameNode.value.value;
  791. } else {
  792. name = nameNode.value;
  793. alias = name;
  794. }
  795. _this13._emitLine("if(Object.prototype.hasOwnProperty.call(" + importedId + ", \"" + name + "\")) {");
  796. _this13._emitLine("var " + id + " = " + importedId + "." + name + ";");
  797. _this13._emitLine('} else {');
  798. _this13._emitLine("cb(new Error(\"cannot import '" + name + "'\")); return;");
  799. _this13._emitLine('}');
  800. frame.set(alias, id);
  801. if (frame.parent) {
  802. _this13._emitLine("frame.set(\"" + alias + "\", " + id + ");");
  803. } else {
  804. _this13._emitLine("context.setVariable(\"" + alias + "\", " + id + ");");
  805. }
  806. });
  807. };
  808. _proto.compileBlock = function compileBlock(node) {
  809. var id = this._tmpid(); // If we are executing outside a block (creating a top-level
  810. // block), we really don't want to execute its code because it
  811. // will execute twice: once when the child template runs and
  812. // again when the parent template runs. Note that blocks
  813. // within blocks will *always* execute immediately *and*
  814. // wherever else they are invoked (like used in a parent
  815. // template). This may have behavioral differences from jinja
  816. // because blocks can have side effects, but it seems like a
  817. // waste of performance to always execute huge top-level
  818. // blocks twice
  819. if (!this.inBlock) {
  820. this._emit('(parentTemplate ? function(e, c, f, r, cb) { cb(""); } : ');
  821. }
  822. this._emit("context.getBlock(\"" + node.name.value + "\")");
  823. if (!this.inBlock) {
  824. this._emit(')');
  825. }
  826. this._emitLine('(env, context, frame, runtime, ' + this._makeCallback(id));
  827. this._emitLine(this.buffer + " += " + id + ";");
  828. this._addScopeLevel();
  829. };
  830. _proto.compileSuper = function compileSuper(node, frame) {
  831. var name = node.blockName.value;
  832. var id = node.symbol.value;
  833. var cb = this._makeCallback(id);
  834. this._emitLine("context.getSuper(env, \"" + name + "\", b_" + name + ", frame, runtime, " + cb);
  835. this._emitLine(id + " = runtime.markSafe(" + id + ");");
  836. this._addScopeLevel();
  837. frame.set(id, id);
  838. };
  839. _proto.compileExtends = function compileExtends(node, frame) {
  840. var k = this._tmpid();
  841. var parentTemplateId = this._compileGetTemplate(node, frame, true, false); // extends is a dynamic tag and can occur within a block like
  842. // `if`, so if this happens we need to capture the parent
  843. // template in the top-level scope
  844. this._emitLine("parentTemplate = " + parentTemplateId);
  845. this._emitLine("for(var " + k + " in parentTemplate.blocks) {");
  846. this._emitLine("context.addBlock(" + k + ", parentTemplate.blocks[" + k + "]);");
  847. this._emitLine('}');
  848. this._addScopeLevel();
  849. };
  850. _proto.compileInclude = function compileInclude(node, frame) {
  851. this._emitLine('var tasks = [];');
  852. this._emitLine('tasks.push(');
  853. this._emitLine('function(callback) {');
  854. var id = this._compileGetTemplate(node, frame, false, node.ignoreMissing);
  855. this._emitLine("callback(null," + id + ");});");
  856. this._emitLine('});');
  857. var id2 = this._tmpid();
  858. this._emitLine('tasks.push(');
  859. this._emitLine('function(template, callback){');
  860. this._emitLine('template.render(context.getVariables(), frame, ' + this._makeCallback(id2));
  861. this._emitLine('callback(null,' + id2 + ');});');
  862. this._emitLine('});');
  863. this._emitLine('tasks.push(');
  864. this._emitLine('function(result, callback){');
  865. this._emitLine(this.buffer + " += result;");
  866. this._emitLine('callback(null);');
  867. this._emitLine('});');
  868. this._emitLine('env.waterfall(tasks, function(){');
  869. this._addScopeLevel();
  870. };
  871. _proto.compileTemplateData = function compileTemplateData(node, frame) {
  872. this.compileLiteral(node, frame);
  873. };
  874. _proto.compileCapture = function compileCapture(node, frame) {
  875. var _this14 = this;
  876. // we need to temporarily override the current buffer id as 'output'
  877. // so the set block writes to the capture output instead of the buffer
  878. var buffer = this.buffer;
  879. this.buffer = 'output';
  880. this._emitLine('(function() {');
  881. this._emitLine('var output = "";');
  882. this._withScopedSyntax(function () {
  883. _this14.compile(node.body, frame);
  884. });
  885. this._emitLine('return output;');
  886. this._emitLine('})()'); // and of course, revert back to the old buffer id
  887. this.buffer = buffer;
  888. };
  889. _proto.compileOutput = function compileOutput(node, frame) {
  890. var _this15 = this;
  891. var children = node.children;
  892. children.forEach(function (child) {
  893. // TemplateData is a special case because it is never
  894. // autoescaped, so simply output it for optimization
  895. if (child instanceof nodes.TemplateData) {
  896. if (child.value) {
  897. _this15._emit(_this15.buffer + " += ");
  898. _this15.compileLiteral(child, frame);
  899. _this15._emitLine(';');
  900. }
  901. } else {
  902. _this15._emit(_this15.buffer + " += runtime.suppressValue(");
  903. if (_this15.throwOnUndefined) {
  904. _this15._emit('runtime.ensureDefined(');
  905. }
  906. _this15.compile(child, frame);
  907. if (_this15.throwOnUndefined) {
  908. _this15._emit("," + node.lineno + "," + node.colno + ")");
  909. }
  910. _this15._emit(', env.opts.autoescape);\n');
  911. }
  912. });
  913. };
  914. _proto.compileRoot = function compileRoot(node, frame) {
  915. var _this16 = this;
  916. if (frame) {
  917. this.fail('compileRoot: root node can\'t have frame');
  918. }
  919. frame = new Frame();
  920. this._emitFuncBegin(node, 'root');
  921. this._emitLine('var parentTemplate = null;');
  922. this._compileChildren(node, frame);
  923. this._emitLine('if(parentTemplate) {');
  924. this._emitLine('parentTemplate.rootRenderFunc(env, context, frame, runtime, cb);');
  925. this._emitLine('} else {');
  926. this._emitLine("cb(null, " + this.buffer + ");");
  927. this._emitLine('}');
  928. this._emitFuncEnd(true);
  929. this.inBlock = true;
  930. var blockNames = [];
  931. var blocks = node.findAll(nodes.Block);
  932. blocks.forEach(function (block, i) {
  933. var name = block.name.value;
  934. if (blockNames.indexOf(name) !== -1) {
  935. throw new Error("Block \"" + name + "\" defined more than once.");
  936. }
  937. blockNames.push(name);
  938. _this16._emitFuncBegin(block, "b_" + name);
  939. var tmpFrame = new Frame();
  940. _this16._emitLine('var frame = frame.push(true);');
  941. _this16.compile(block.body, tmpFrame);
  942. _this16._emitFuncEnd();
  943. });
  944. this._emitLine('return {');
  945. blocks.forEach(function (block, i) {
  946. var blockName = "b_" + block.name.value;
  947. _this16._emitLine(blockName + ": " + blockName + ",");
  948. });
  949. this._emitLine('root: root\n};');
  950. };
  951. _proto.compile = function compile(node, frame) {
  952. var _compile = this['compile' + node.typename];
  953. if (_compile) {
  954. _compile.call(this, node, frame);
  955. } else {
  956. this.fail("compile: Cannot compile node: " + node.typename, node.lineno, node.colno);
  957. }
  958. };
  959. _proto.getCode = function getCode() {
  960. return this.codebuf.join('');
  961. };
  962. return Compiler;
  963. }(Obj);
  964. module.exports = {
  965. compile: function compile(src, asyncFilters, extensions, name, opts) {
  966. if (opts === void 0) {
  967. opts = {};
  968. }
  969. var c = new Compiler(name, opts.throwOnUndefined); // Run the extension preprocessors against the source.
  970. var preprocessors = (extensions || []).map(function (ext) {
  971. return ext.preprocess;
  972. }).filter(function (f) {
  973. return !!f;
  974. });
  975. var processedSrc = preprocessors.reduce(function (s, processor) {
  976. return processor(s);
  977. }, src);
  978. c.compile(transformer.transform(parser.parse(processedSrc, extensions, opts), asyncFilters, name));
  979. return c.getCode();
  980. },
  981. Compiler: Compiler
  982. };