react / wstein / node_modules / jest-cli / node_modules / istanbul / node_modules / handlebars / lib / handlebars / compiler / javascript-compiler.js
80713 viewsimport { COMPILER_REVISION, REVISION_CHANGES } from "../base";1import Exception from "../exception";2import {isArray} from "../utils";3import CodeGen from "./code-gen";45function Literal(value) {6this.value = value;7}89function JavaScriptCompiler() {}1011JavaScriptCompiler.prototype = {12// PUBLIC API: You can override these methods in a subclass to provide13// alternative compiled forms for name lookup and buffering semantics14nameLookup: function(parent, name /* , type*/) {15if (JavaScriptCompiler.isValidJavaScriptVariableName(name)) {16return [parent, ".", name];17} else {18return [parent, "['", name, "']"];19}20},21depthedLookup: function(name) {22return [this.aliasable('this.lookup'), '(depths, "', name, '")'];23},2425compilerInfo: function() {26var revision = COMPILER_REVISION,27versions = REVISION_CHANGES[revision];28return [revision, versions];29},3031appendToBuffer: function(source, location, explicit) {32// Force a source as this simplifies the merge logic.33if (!isArray(source)) {34source = [source];35}36source = this.source.wrap(source, location);3738if (this.environment.isSimple) {39return ['return ', source, ';'];40} else if (explicit) {41// This is a case where the buffer operation occurs as a child of another42// construct, generally braces. We have to explicitly output these buffer43// operations to ensure that the emitted code goes in the correct location.44return ['buffer += ', source, ';'];45} else {46source.appendToBuffer = true;47return source;48}49},5051initializeBuffer: function() {52return this.quotedString("");53},54// END PUBLIC API5556compile: function(environment, options, context, asObject) {57this.environment = environment;58this.options = options;59this.stringParams = this.options.stringParams;60this.trackIds = this.options.trackIds;61this.precompile = !asObject;6263this.name = this.environment.name;64this.isChild = !!context;65this.context = context || {66programs: [],67environments: []68};6970this.preamble();7172this.stackSlot = 0;73this.stackVars = [];74this.aliases = {};75this.registers = { list: [] };76this.hashes = [];77this.compileStack = [];78this.inlineStack = [];79this.blockParams = [];8081this.compileChildren(environment, options);8283this.useDepths = this.useDepths || environment.useDepths || this.options.compat;84this.useBlockParams = this.useBlockParams || environment.useBlockParams;8586var opcodes = environment.opcodes,87opcode,88firstLoc,89i,90l;9192for (i = 0, l = opcodes.length; i < l; i++) {93opcode = opcodes[i];9495this.source.currentLocation = opcode.loc;96firstLoc = firstLoc || opcode.loc;97this[opcode.opcode].apply(this, opcode.args);98}99100// Flush any trailing content that might be pending.101this.source.currentLocation = firstLoc;102this.pushSource('');103104/* istanbul ignore next */105if (this.stackSlot || this.inlineStack.length || this.compileStack.length) {106throw new Exception('Compile completed with content left on stack');107}108109var fn = this.createFunctionContext(asObject);110if (!this.isChild) {111var ret = {112compiler: this.compilerInfo(),113main: fn114};115var programs = this.context.programs;116for (i = 0, l = programs.length; i < l; i++) {117if (programs[i]) {118ret[i] = programs[i];119}120}121122if (this.environment.usePartial) {123ret.usePartial = true;124}125if (this.options.data) {126ret.useData = true;127}128if (this.useDepths) {129ret.useDepths = true;130}131if (this.useBlockParams) {132ret.useBlockParams = true;133}134if (this.options.compat) {135ret.compat = true;136}137138if (!asObject) {139ret.compiler = JSON.stringify(ret.compiler);140141this.source.currentLocation = {start: {line: 1, column: 0}};142ret = this.objectLiteral(ret);143144if (options.srcName) {145ret = ret.toStringWithSourceMap({file: options.destName});146ret.map = ret.map && ret.map.toString();147} else {148ret = ret.toString();149}150} else {151ret.compilerOptions = this.options;152}153154return ret;155} else {156return fn;157}158},159160preamble: function() {161// track the last context pushed into place to allow skipping the162// getContext opcode when it would be a noop163this.lastContext = 0;164this.source = new CodeGen(this.options.srcName);165},166167createFunctionContext: function(asObject) {168var varDeclarations = '';169170var locals = this.stackVars.concat(this.registers.list);171if(locals.length > 0) {172varDeclarations += ", " + locals.join(", ");173}174175// Generate minimizer alias mappings176//177// When using true SourceNodes, this will update all references to the given alias178// as the source nodes are reused in situ. For the non-source node compilation mode,179// aliases will not be used, but this case is already being run on the client and180// we aren't concern about minimizing the template size.181var aliasCount = 0;182for (var alias in this.aliases) {183var node = this.aliases[alias];184185if (this.aliases.hasOwnProperty(alias) && node.children && node.referenceCount > 1) {186varDeclarations += ', alias' + (++aliasCount) + '=' + alias;187node.children[0] = 'alias' + aliasCount;188}189}190191var params = ["depth0", "helpers", "partials", "data"];192193if (this.useBlockParams || this.useDepths) {194params.push('blockParams');195}196if (this.useDepths) {197params.push('depths');198}199200// Perform a second pass over the output to merge content when possible201var source = this.mergeSource(varDeclarations);202203if (asObject) {204params.push(source);205206return Function.apply(this, params);207} else {208return this.source.wrap(['function(', params.join(','), ') {\n ', source, '}']);209}210},211mergeSource: function(varDeclarations) {212var isSimple = this.environment.isSimple,213appendOnly = !this.forceBuffer,214appendFirst,215216sourceSeen,217bufferStart,218bufferEnd;219this.source.each(function(line) {220if (line.appendToBuffer) {221if (bufferStart) {222line.prepend(' + ');223} else {224bufferStart = line;225}226bufferEnd = line;227} else {228if (bufferStart) {229if (!sourceSeen) {230appendFirst = true;231} else {232bufferStart.prepend('buffer += ');233}234bufferEnd.add(';');235bufferStart = bufferEnd = undefined;236}237238sourceSeen = true;239if (!isSimple) {240appendOnly = false;241}242}243});244245246if (appendOnly) {247if (bufferStart) {248bufferStart.prepend('return ');249bufferEnd.add(';');250} else if (!sourceSeen) {251this.source.push('return "";');252}253} else {254varDeclarations += ", buffer = " + (appendFirst ? '' : this.initializeBuffer());255256if (bufferStart) {257bufferStart.prepend('return buffer + ');258bufferEnd.add(';');259} else {260this.source.push('return buffer;');261}262}263264if (varDeclarations) {265this.source.prepend('var ' + varDeclarations.substring(2) + (appendFirst ? '' : ';\n'));266}267268return this.source.merge();269},270271// [blockValue]272//273// On stack, before: hash, inverse, program, value274// On stack, after: return value of blockHelperMissing275//276// The purpose of this opcode is to take a block of the form277// `{{#this.foo}}...{{/this.foo}}`, resolve the value of `foo`, and278// replace it on the stack with the result of properly279// invoking blockHelperMissing.280blockValue: function(name) {281var blockHelperMissing = this.aliasable('helpers.blockHelperMissing'),282params = [this.contextName(0)];283this.setupHelperArgs(name, 0, params);284285var blockName = this.popStack();286params.splice(1, 0, blockName);287288this.push(this.source.functionCall(blockHelperMissing, 'call', params));289},290291// [ambiguousBlockValue]292//293// On stack, before: hash, inverse, program, value294// Compiler value, before: lastHelper=value of last found helper, if any295// On stack, after, if no lastHelper: same as [blockValue]296// On stack, after, if lastHelper: value297ambiguousBlockValue: function() {298// We're being a bit cheeky and reusing the options value from the prior exec299var blockHelperMissing = this.aliasable('helpers.blockHelperMissing'),300params = [this.contextName(0)];301this.setupHelperArgs('', 0, params, true);302303this.flushInline();304305var current = this.topStack();306params.splice(1, 0, current);307308this.pushSource([309'if (!', this.lastHelper, ') { ',310current, ' = ', this.source.functionCall(blockHelperMissing, 'call', params),311'}']);312},313314// [appendContent]315//316// On stack, before: ...317// On stack, after: ...318//319// Appends the string value of `content` to the current buffer320appendContent: function(content) {321if (this.pendingContent) {322content = this.pendingContent + content;323} else {324this.pendingLocation = this.source.currentLocation;325}326327this.pendingContent = content;328},329330// [append]331//332// On stack, before: value, ...333// On stack, after: ...334//335// Coerces `value` to a String and appends it to the current buffer.336//337// If `value` is truthy, or 0, it is coerced into a string and appended338// Otherwise, the empty string is appended339append: function() {340if (this.isInline()) {341this.replaceStack(function(current) {342return [' != null ? ', current, ' : ""'];343});344345this.pushSource(this.appendToBuffer(this.popStack()));346} else {347var local = this.popStack();348this.pushSource(['if (', local, ' != null) { ', this.appendToBuffer(local, undefined, true), ' }']);349if (this.environment.isSimple) {350this.pushSource(['else { ', this.appendToBuffer("''", undefined, true), ' }']);351}352}353},354355// [appendEscaped]356//357// On stack, before: value, ...358// On stack, after: ...359//360// Escape `value` and append it to the buffer361appendEscaped: function() {362this.pushSource(this.appendToBuffer(363[this.aliasable('this.escapeExpression'), '(', this.popStack(), ')']));364},365366// [getContext]367//368// On stack, before: ...369// On stack, after: ...370// Compiler value, after: lastContext=depth371//372// Set the value of the `lastContext` compiler value to the depth373getContext: function(depth) {374this.lastContext = depth;375},376377// [pushContext]378//379// On stack, before: ...380// On stack, after: currentContext, ...381//382// Pushes the value of the current context onto the stack.383pushContext: function() {384this.pushStackLiteral(this.contextName(this.lastContext));385},386387// [lookupOnContext]388//389// On stack, before: ...390// On stack, after: currentContext[name], ...391//392// Looks up the value of `name` on the current context and pushes393// it onto the stack.394lookupOnContext: function(parts, falsy, scoped) {395var i = 0;396397if (!scoped && this.options.compat && !this.lastContext) {398// The depthed query is expected to handle the undefined logic for the root level that399// is implemented below, so we evaluate that directly in compat mode400this.push(this.depthedLookup(parts[i++]));401} else {402this.pushContext();403}404405this.resolvePath('context', parts, i, falsy);406},407408// [lookupBlockParam]409//410// On stack, before: ...411// On stack, after: blockParam[name], ...412//413// Looks up the value of `parts` on the given block param and pushes414// it onto the stack.415lookupBlockParam: function(blockParamId, parts) {416this.useBlockParams = true;417418this.push(['blockParams[', blockParamId[0], '][', blockParamId[1], ']']);419this.resolvePath('context', parts, 1);420},421422// [lookupData]423//424// On stack, before: ...425// On stack, after: data, ...426//427// Push the data lookup operator428lookupData: function(depth, parts) {429/*jshint -W083 */430if (!depth) {431this.pushStackLiteral('data');432} else {433this.pushStackLiteral('this.data(data, ' + depth + ')');434}435436this.resolvePath('data', parts, 0, true);437},438439resolvePath: function(type, parts, i, falsy) {440/*jshint -W083 */441if (this.options.strict || this.options.assumeObjects) {442this.push(strictLookup(this.options.strict, this, parts, type));443return;444}445446var len = parts.length;447for (; i < len; i++) {448this.replaceStack(function(current) {449var lookup = this.nameLookup(current, parts[i], type);450// We want to ensure that zero and false are handled properly if the context (falsy flag)451// needs to have the special handling for these values.452if (!falsy) {453return [' != null ? ', lookup, ' : ', current];454} else {455// Otherwise we can use generic falsy handling456return [' && ', lookup];457}458});459}460},461462// [resolvePossibleLambda]463//464// On stack, before: value, ...465// On stack, after: resolved value, ...466//467// If the `value` is a lambda, replace it on the stack by468// the return value of the lambda469resolvePossibleLambda: function() {470this.push([this.aliasable('this.lambda'), '(', this.popStack(), ', ', this.contextName(0), ')']);471},472473// [pushStringParam]474//475// On stack, before: ...476// On stack, after: string, currentContext, ...477//478// This opcode is designed for use in string mode, which479// provides the string value of a parameter along with its480// depth rather than resolving it immediately.481pushStringParam: function(string, type) {482this.pushContext();483this.pushString(type);484485// If it's a subexpression, the string result486// will be pushed after this opcode.487if (type !== 'SubExpression') {488if (typeof string === 'string') {489this.pushString(string);490} else {491this.pushStackLiteral(string);492}493}494},495496emptyHash: function(omitEmpty) {497if (this.trackIds) {498this.push('{}'); // hashIds499}500if (this.stringParams) {501this.push('{}'); // hashContexts502this.push('{}'); // hashTypes503}504this.pushStackLiteral(omitEmpty ? 'undefined' : '{}');505},506pushHash: function() {507if (this.hash) {508this.hashes.push(this.hash);509}510this.hash = {values: [], types: [], contexts: [], ids: []};511},512popHash: function() {513var hash = this.hash;514this.hash = this.hashes.pop();515516if (this.trackIds) {517this.push(this.objectLiteral(hash.ids));518}519if (this.stringParams) {520this.push(this.objectLiteral(hash.contexts));521this.push(this.objectLiteral(hash.types));522}523524this.push(this.objectLiteral(hash.values));525},526527// [pushString]528//529// On stack, before: ...530// On stack, after: quotedString(string), ...531//532// Push a quoted version of `string` onto the stack533pushString: function(string) {534this.pushStackLiteral(this.quotedString(string));535},536537// [pushLiteral]538//539// On stack, before: ...540// On stack, after: value, ...541//542// Pushes a value onto the stack. This operation prevents543// the compiler from creating a temporary variable to hold544// it.545pushLiteral: function(value) {546this.pushStackLiteral(value);547},548549// [pushProgram]550//551// On stack, before: ...552// On stack, after: program(guid), ...553//554// Push a program expression onto the stack. This takes555// a compile-time guid and converts it into a runtime-accessible556// expression.557pushProgram: function(guid) {558if (guid != null) {559this.pushStackLiteral(this.programExpression(guid));560} else {561this.pushStackLiteral(null);562}563},564565// [invokeHelper]566//567// On stack, before: hash, inverse, program, params..., ...568// On stack, after: result of helper invocation569//570// Pops off the helper's parameters, invokes the helper,571// and pushes the helper's return value onto the stack.572//573// If the helper is not found, `helperMissing` is called.574invokeHelper: function(paramSize, name, isSimple) {575var nonHelper = this.popStack();576var helper = this.setupHelper(paramSize, name);577var simple = isSimple ? [helper.name, ' || '] : '';578579var lookup = ['('].concat(simple, nonHelper);580if (!this.options.strict) {581lookup.push(' || ', this.aliasable('helpers.helperMissing'));582}583lookup.push(')');584585this.push(this.source.functionCall(lookup, 'call', helper.callParams));586},587588// [invokeKnownHelper]589//590// On stack, before: hash, inverse, program, params..., ...591// On stack, after: result of helper invocation592//593// This operation is used when the helper is known to exist,594// so a `helperMissing` fallback is not required.595invokeKnownHelper: function(paramSize, name) {596var helper = this.setupHelper(paramSize, name);597this.push(this.source.functionCall(helper.name, 'call', helper.callParams));598},599600// [invokeAmbiguous]601//602// On stack, before: hash, inverse, program, params..., ...603// On stack, after: result of disambiguation604//605// This operation is used when an expression like `{{foo}}`606// is provided, but we don't know at compile-time whether it607// is a helper or a path.608//609// This operation emits more code than the other options,610// and can be avoided by passing the `knownHelpers` and611// `knownHelpersOnly` flags at compile-time.612invokeAmbiguous: function(name, helperCall) {613this.useRegister('helper');614615var nonHelper = this.popStack();616617this.emptyHash();618var helper = this.setupHelper(0, name, helperCall);619620var helperName = this.lastHelper = this.nameLookup('helpers', name, 'helper');621622var lookup = ['(', '(helper = ', helperName, ' || ', nonHelper, ')'];623if (!this.options.strict) {624lookup[0] = '(helper = ';625lookup.push(626' != null ? helper : ',627this.aliasable('helpers.helperMissing')628);629}630631this.push([632'(', lookup,633(helper.paramsInit ? ['),(', helper.paramsInit] : []), '),',634'(typeof helper === ', this.aliasable('"function"'), ' ? ',635this.source.functionCall('helper','call', helper.callParams), ' : helper))'636]);637},638639// [invokePartial]640//641// On stack, before: context, ...642// On stack after: result of partial invocation643//644// This operation pops off a context, invokes a partial with that context,645// and pushes the result of the invocation back.646invokePartial: function(isDynamic, name, indent) {647var params = [],648options = this.setupParams(name, 1, params, false);649650if (isDynamic) {651name = this.popStack();652delete options.name;653}654655if (indent) {656options.indent = JSON.stringify(indent);657}658options.helpers = 'helpers';659options.partials = 'partials';660661if (!isDynamic) {662params.unshift(this.nameLookup('partials', name, 'partial'));663} else {664params.unshift(name);665}666667if (this.options.compat) {668options.depths = 'depths';669}670options = this.objectLiteral(options);671params.push(options);672673this.push(this.source.functionCall('this.invokePartial', '', params));674},675676// [assignToHash]677//678// On stack, before: value, ..., hash, ...679// On stack, after: ..., hash, ...680//681// Pops a value off the stack and assigns it to the current hash682assignToHash: function(key) {683var value = this.popStack(),684context,685type,686id;687688if (this.trackIds) {689id = this.popStack();690}691if (this.stringParams) {692type = this.popStack();693context = this.popStack();694}695696var hash = this.hash;697if (context) {698hash.contexts[key] = context;699}700if (type) {701hash.types[key] = type;702}703if (id) {704hash.ids[key] = id;705}706hash.values[key] = value;707},708709pushId: function(type, name, child) {710if (type === 'BlockParam') {711this.pushStackLiteral(712'blockParams[' + name[0] + '].path[' + name[1] + ']'713+ (child ? ' + ' + JSON.stringify('.' + child) : ''));714} else if (type === 'PathExpression') {715this.pushString(name);716} else if (type === 'SubExpression') {717this.pushStackLiteral('true');718} else {719this.pushStackLiteral('null');720}721},722723// HELPERS724725compiler: JavaScriptCompiler,726727compileChildren: function(environment, options) {728var children = environment.children, child, compiler;729730for(var i=0, l=children.length; i<l; i++) {731child = children[i];732compiler = new this.compiler();733734var index = this.matchExistingProgram(child);735736if (index == null) {737this.context.programs.push(''); // Placeholder to prevent name conflicts for nested children738index = this.context.programs.length;739child.index = index;740child.name = 'program' + index;741this.context.programs[index] = compiler.compile(child, options, this.context, !this.precompile);742this.context.environments[index] = child;743744this.useDepths = this.useDepths || compiler.useDepths;745this.useBlockParams = this.useBlockParams || compiler.useBlockParams;746} else {747child.index = index;748child.name = 'program' + index;749750this.useDepths = this.useDepths || child.useDepths;751this.useBlockParams = this.useBlockParams || child.useBlockParams;752}753}754},755matchExistingProgram: function(child) {756for (var i = 0, len = this.context.environments.length; i < len; i++) {757var environment = this.context.environments[i];758if (environment && environment.equals(child)) {759return i;760}761}762},763764programExpression: function(guid) {765var child = this.environment.children[guid],766programParams = [child.index, 'data', child.blockParams];767768if (this.useBlockParams || this.useDepths) {769programParams.push('blockParams');770}771if (this.useDepths) {772programParams.push('depths');773}774775return 'this.program(' + programParams.join(', ') + ')';776},777778useRegister: function(name) {779if(!this.registers[name]) {780this.registers[name] = true;781this.registers.list.push(name);782}783},784785push: function(expr) {786if (!(expr instanceof Literal)) {787expr = this.source.wrap(expr);788}789790this.inlineStack.push(expr);791return expr;792},793794pushStackLiteral: function(item) {795this.push(new Literal(item));796},797798pushSource: function(source) {799if (this.pendingContent) {800this.source.push(801this.appendToBuffer(this.source.quotedString(this.pendingContent), this.pendingLocation));802this.pendingContent = undefined;803}804805if (source) {806this.source.push(source);807}808},809810replaceStack: function(callback) {811var prefix = ['('],812stack,813createdStack,814usedLiteral;815816/* istanbul ignore next */817if (!this.isInline()) {818throw new Exception('replaceStack on non-inline');819}820821// We want to merge the inline statement into the replacement statement via ','822var top = this.popStack(true);823824if (top instanceof Literal) {825// Literals do not need to be inlined826stack = [top.value];827prefix = ['(', stack];828usedLiteral = true;829} else {830// Get or create the current stack name for use by the inline831createdStack = true;832var name = this.incrStack();833834prefix = ['((', this.push(name), ' = ', top, ')'];835stack = this.topStack();836}837838var item = callback.call(this, stack);839840if (!usedLiteral) {841this.popStack();842}843if (createdStack) {844this.stackSlot--;845}846this.push(prefix.concat(item, ')'));847},848849incrStack: function() {850this.stackSlot++;851if(this.stackSlot > this.stackVars.length) { this.stackVars.push("stack" + this.stackSlot); }852return this.topStackName();853},854topStackName: function() {855return "stack" + this.stackSlot;856},857flushInline: function() {858var inlineStack = this.inlineStack;859this.inlineStack = [];860for (var i = 0, len = inlineStack.length; i < len; i++) {861var entry = inlineStack[i];862/* istanbul ignore if */863if (entry instanceof Literal) {864this.compileStack.push(entry);865} else {866var stack = this.incrStack();867this.pushSource([stack, ' = ', entry, ';']);868this.compileStack.push(stack);869}870}871},872isInline: function() {873return this.inlineStack.length;874},875876popStack: function(wrapped) {877var inline = this.isInline(),878item = (inline ? this.inlineStack : this.compileStack).pop();879880if (!wrapped && (item instanceof Literal)) {881return item.value;882} else {883if (!inline) {884/* istanbul ignore next */885if (!this.stackSlot) {886throw new Exception('Invalid stack pop');887}888this.stackSlot--;889}890return item;891}892},893894topStack: function() {895var stack = (this.isInline() ? this.inlineStack : this.compileStack),896item = stack[stack.length - 1];897898/* istanbul ignore if */899if (item instanceof Literal) {900return item.value;901} else {902return item;903}904},905906contextName: function(context) {907if (this.useDepths && context) {908return 'depths[' + context + ']';909} else {910return 'depth' + context;911}912},913914quotedString: function(str) {915return this.source.quotedString(str);916},917918objectLiteral: function(obj) {919return this.source.objectLiteral(obj);920},921922aliasable: function(name) {923var ret = this.aliases[name];924if (ret) {925ret.referenceCount++;926return ret;927}928929ret = this.aliases[name] = this.source.wrap(name);930ret.aliasable = true;931ret.referenceCount = 1;932933return ret;934},935936setupHelper: function(paramSize, name, blockHelper) {937var params = [],938paramsInit = this.setupHelperArgs(name, paramSize, params, blockHelper);939var foundHelper = this.nameLookup('helpers', name, 'helper');940941return {942params: params,943paramsInit: paramsInit,944name: foundHelper,945callParams: [this.contextName(0)].concat(params)946};947},948949setupParams: function(helper, paramSize, params) {950var options = {}, contexts = [], types = [], ids = [], param;951952options.name = this.quotedString(helper);953options.hash = this.popStack();954955if (this.trackIds) {956options.hashIds = this.popStack();957}958if (this.stringParams) {959options.hashTypes = this.popStack();960options.hashContexts = this.popStack();961}962963var inverse = this.popStack(),964program = this.popStack();965966// Avoid setting fn and inverse if neither are set. This allows967// helpers to do a check for `if (options.fn)`968if (program || inverse) {969options.fn = program || 'this.noop';970options.inverse = inverse || 'this.noop';971}972973// The parameters go on to the stack in order (making sure that they are evaluated in order)974// so we need to pop them off the stack in reverse order975var i = paramSize;976while (i--) {977param = this.popStack();978params[i] = param;979980if (this.trackIds) {981ids[i] = this.popStack();982}983if (this.stringParams) {984types[i] = this.popStack();985contexts[i] = this.popStack();986}987}988989if (this.trackIds) {990options.ids = this.source.generateArray(ids);991}992if (this.stringParams) {993options.types = this.source.generateArray(types);994options.contexts = this.source.generateArray(contexts);995}996997if (this.options.data) {998options.data = 'data';999}1000if (this.useBlockParams) {1001options.blockParams = 'blockParams';1002}1003return options;1004},10051006setupHelperArgs: function(helper, paramSize, params, useRegister) {1007var options = this.setupParams(helper, paramSize, params, true);1008options = this.objectLiteral(options);1009if (useRegister) {1010this.useRegister('options');1011params.push('options');1012return ['options=', options];1013} else {1014params.push(options);1015return '';1016}1017}1018};101910201021var reservedWords = (1022"break else new var" +1023" case finally return void" +1024" catch for switch while" +1025" continue function this with" +1026" default if throw" +1027" delete in try" +1028" do instanceof typeof" +1029" abstract enum int short" +1030" boolean export interface static" +1031" byte extends long super" +1032" char final native synchronized" +1033" class float package throws" +1034" const goto private transient" +1035" debugger implements protected volatile" +1036" double import public let yield await" +1037" null true false"1038).split(" ");10391040var compilerWords = JavaScriptCompiler.RESERVED_WORDS = {};10411042for(var i=0, l=reservedWords.length; i<l; i++) {1043compilerWords[reservedWords[i]] = true;1044}10451046JavaScriptCompiler.isValidJavaScriptVariableName = function(name) {1047return !JavaScriptCompiler.RESERVED_WORDS[name] && /^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(name);1048};10491050function strictLookup(requireTerminal, compiler, parts, type) {1051var stack = compiler.popStack();10521053var i = 0,1054len = parts.length;1055if (requireTerminal) {1056len--;1057}10581059for (; i < len; i++) {1060stack = compiler.nameLookup(stack, parts[i], type);1061}10621063if (requireTerminal) {1064return [compiler.aliasable('this.strict'), '(', stack, ', ', compiler.quotedString(parts[i]), ')'];1065} else {1066return stack;1067}1068}10691070export default JavaScriptCompiler;107110721073