From a42cc5fce46f4d924a6513423b28105ffad51336 Mon Sep 17 00:00:00 2001 From: Geoffrey Booth Date: Thu, 30 Mar 2017 00:06:37 -0700 Subject: [PATCH] Compiler in JavaScript, now with some destructuring --- lib/coffeescript/coffeescript.js | 6 ++-- lib/coffeescript/command.js | 2 +- lib/coffeescript/grammar.js | 2 +- lib/coffeescript/lexer.js | 10 +++--- lib/coffeescript/nodes.js | 59 ++++++++++++++++++++------------ lib/coffeescript/optparse.js | 2 +- lib/coffeescript/register.js | 2 +- lib/coffeescript/rewriter.js | 18 +++++----- 8 files changed, 59 insertions(+), 42 deletions(-) diff --git a/lib/coffeescript/coffeescript.js b/lib/coffeescript/coffeescript.js index 66556ffd77..11a54ab2ef 100644 --- a/lib/coffeescript/coffeescript.js +++ b/lib/coffeescript/coffeescript.js @@ -9,9 +9,9 @@ path = require('path'); - Lexer = require('./lexer').Lexer; + ({ Lexer } = require('./lexer')); - parser = require('./parser').parser; + ({ parser } = require('./parser')); helpers = require('./helpers'); @@ -295,7 +295,7 @@ parser.yy.parseError = function(message, arg) { var errorLoc, errorTag, errorText, errorToken, token, tokens; - token = arg.token; + ({ token } = arg); errorToken = parser.errorToken, tokens = parser.tokens; errorTag = errorToken[0], errorText = errorToken[1], errorLoc = errorToken[2]; errorText = (function() { diff --git a/lib/coffeescript/command.js b/lib/coffeescript/command.js index 3bd6487dde..6ad59fb3fd 100644 --- a/lib/coffeescript/command.js +++ b/lib/coffeescript/command.js @@ -15,7 +15,7 @@ ref = require('child_process'), spawn = ref.spawn, exec = ref.exec; - EventEmitter = require('events').EventEmitter; + ({ EventEmitter } = require('events')); useWinPathSep = path.sep === '\\'; diff --git a/lib/coffeescript/grammar.js b/lib/coffeescript/grammar.js index c47943faac..953bd5ff2e 100644 --- a/lib/coffeescript/grammar.js +++ b/lib/coffeescript/grammar.js @@ -2,7 +2,7 @@ (function() { var Parser, alt, alternatives, grammar, name, o, operators, token, tokens, unwrap; - Parser = require('jison').Parser; + ({ Parser } = require('jison')); unwrap = /^function\s*\(\)\s*\{\s*return\s*([\s\S]*);\s*\}/; diff --git a/lib/coffeescript/lexer.js b/lib/coffeescript/lexer.js index cd97d9f9bf..7b576ba0f7 100644 --- a/lib/coffeescript/lexer.js +++ b/lib/coffeescript/lexer.js @@ -224,7 +224,7 @@ stringToken() { var $, attempt, delimiter, doc, end, heredoc, i, indent, indentRegex, match, quote, ref2, ref3, regex, token, tokens; - quote = (STRING_START.exec(this.chunk) || [])[0]; + [ quote ] = STRING_START.exec(this.chunk) || []; if (!quote) { return 0; } @@ -370,7 +370,7 @@ default: return 0; } - flags = REGEX_FLAGS.exec(this.chunk.slice(index))[0]; + [ flags ] = REGEX_FLAGS.exec(this.chunk.slice(index)); end = index + flags.length; origin = this.makeToken('REGEX', null, 0, end); switch (false) { @@ -543,7 +543,7 @@ literalToken() { var match, message, origin, prev, ref2, ref3, ref4, ref5, ref6, skipToken, tag, token, value; if (match = OPERATOR.exec(this.chunk)) { - value = match[0]; + [ value ] = match; if (CODE.test(value)) { this.tagParameters(); } @@ -634,7 +634,7 @@ return this; } stack = []; - tokens = this.tokens; + ({ tokens } = this); i = tokens.length; tokens[--i][0] = 'PARAM_END'; while (tok = tokens[--i]) { @@ -670,7 +670,7 @@ } str = this.chunk.slice(offsetInChunk); while (true) { - strPart = regex.exec(str)[0]; + [ strPart ] = regex.exec(str); this.validateEscapes(strPart, { isRegex: delimiter.charAt(0) === '/', offsetInChunk: offsetInChunk diff --git a/lib/coffeescript/nodes.js b/lib/coffeescript/nodes.js index a730820c45..e1c6586339 100644 --- a/lib/coffeescript/nodes.js +++ b/lib/coffeescript/nodes.js @@ -6,7 +6,7 @@ Error.stackTraceLimit = 2e308; - Scope = require('./scope').Scope; + ({ Scope } = require('./scope')); ref1 = require('./lexer'), isUnassignable = ref1.isUnassignable, JS_FORBIDDEN = ref1.JS_FORBIDDEN; @@ -579,7 +579,7 @@ this.expressions = rest; } post = this.compileNode(o); - scope = o.scope; + ({ scope } = o); if (scope.expressions === this) { declars = o.scope.hasDeclarations(); assigns = scope.hasAssignments; @@ -1714,13 +1714,13 @@ this.boundMethods = []; executableBody = null; initializer = []; - expressions = this.body.expressions; + ({ expressions } = this.body); i = 0; ref3 = expressions.slice(); for (j = 0, len1 = ref3.length; j < len1; j++) { expression = ref3[j]; if (expression instanceof Value && expression.isObject(true)) { - properties = expression.base.properties; + ({ properties } = expression.base); exprs = []; end = 0; start = 0; @@ -2244,7 +2244,7 @@ this.variable = variable1; this.value = value1; this.context = context1; - this.param = options.param, this.subpattern = options.subpattern, this.operatorToken = options.operatorToken, this.moduleDeclaration = options.moduleDeclaration, this.wrapVariableInBraces = options.wrapVariableInBraces, this.wrapVariableInBrackets = options.wrapVariableInBrackets; + this.param = options.param, this.subpattern = options.subpattern, this.operatorToken = options.operatorToken, this.moduleDeclaration = options.moduleDeclaration, this.defaultValue = options.defaultValue, this.wrapVariableInBraces = options.wrapVariableInBraces, this.wrapVariableInBrackets = options.wrapVariableInBrackets; } isStatement(o) { @@ -2256,7 +2256,7 @@ } isAssignable() { - return this.isDestructured(); + return this.isDestructured() || this.defaultValue !== void 0; } checkAssignability(o, varBase) { @@ -2321,6 +2321,10 @@ this.variable.front = true; } compiledName = this.variable.compileToFragments(o, LEVEL_LIST); + if (this.defaultValue !== void 0) { + compiledName.push(this.makeCode(' = ')); + compiledName = compiledName.concat(this.defaultValue.compileToFragments(o, LEVEL_LIST)); + } if (this.wrapVariableInBraces) { compiledName = this.wrapInBraces(compiledName); } @@ -2338,7 +2342,7 @@ return compiledName.concat(this.makeCode(": "), val); } answer = compiledName.concat(this.makeCode(` ${this.context || '='} `), val); - if (o.level > LEVEL_LIST || this.wrapVariableInBraces || this.wrapVariableInBrackets) { + if (o.level > LEVEL_LIST || this.wrapVariableInBraces) { return this.wrapInParentheses(answer); } else { return answer; @@ -2346,10 +2350,10 @@ } compilePatternMatch(o) { - var acc, assigns, code, defaultValue, expandedIdx, fragments, i, idx, isObject, ivar, j, len1, message, name, obj, objects, olen, ref, ref3, ref4, ref5, ref6, rest, top, val, value, vvar, vvarText; + var acc, assignOptions, assigns, code, defaultValue, expandedIdx, fragments, i, idx, isObject, ivar, j, len1, message, name, obj, objects, olen, ref, ref3, ref4, ref5, ref6, regularObjectPatternMatch, rest, top, val, value, vvar, vvarText; top = o.level === LEVEL_TOP; - value = this.value; - objects = this.variable.base.objects; + ({ value } = this); + ({ objects } = this.variable.base); olen = objects.length; if (olen === 0) { code = value.compileToFragments(o); @@ -2359,14 +2363,15 @@ return code; } } - obj = objects[0]; + [ obj ] = objects; if (olen === 1 && obj instanceof Expansion) { obj.error('Destructuring assignment has no target'); } isObject = this.variable.isObject(); if (top && olen === 1 && !(obj instanceof Splat)) { - defaultValue = null; + defaultValue = void 0; if (obj instanceof Assign && obj.context === 'object') { + regularObjectPatternMatch = true; ref3 = obj, (ref4 = ref3.variable, idx = ref4.base), obj = ref3.value; if (obj instanceof Assign) { defaultValue = obj.value; @@ -2381,17 +2386,29 @@ } acc = idx.unwrap() instanceof PropertyName; value = new Value(value); - value.properties.push(new (acc ? Access : Index)(idx)); message = isUnassignable(obj.unwrap().value); if (message) { obj.error(message); } - if (defaultValue) { - value = new Op('?', value, defaultValue); + if (regularObjectPatternMatch || obj["this"]) { + value.properties.push(new (acc ? Access : Index)(idx)); + if (defaultValue !== void 0) { + value = new Op('??', value, defaultValue); + } + return new Assign(obj, value, null, { + param: this.param + }).compileToFragments(o, LEVEL_TOP); + } else { + assignOptions = { + param: this.param, + wrapVariableInBraces: isObject, + wrapVariableInBrackets: !isObject + }; + if (defaultValue !== void 0) { + assignOptions.defaultValue = defaultValue; + } + return new Assign(obj, value, null, assignOptions).compileToFragments(o, LEVEL_TOP); } - return new Assign(obj, value, null, { - param: this.param - }).compileToFragments(o, LEVEL_TOP); } vvar = value.compileToFragments(o, LEVEL_LIST); vvarText = fragmentsToText(vvar); @@ -3042,7 +3059,7 @@ jumps() { var expressions, j, jumpNode, len1, node; - expressions = this.body.expressions; + ({ expressions } = this.body); if (!expressions.length) { return false; } @@ -3061,7 +3078,7 @@ var answer, body, rvar, set; o.indent += TAB; set = ''; - body = this.body; + ({ body } = this); if (body.isEmpty()) { body = this.makeCode(''); } else { @@ -4104,7 +4121,7 @@ utility = function(name, o) { var ref, root; - root = o.scope.root; + ({ root } = o.scope); if (name in root.utilities) { return root.utilities[name]; } else { diff --git a/lib/coffeescript/optparse.js b/lib/coffeescript/optparse.js index 79cb367ddf..24f8c59fdd 100644 --- a/lib/coffeescript/optparse.js +++ b/lib/coffeescript/optparse.js @@ -2,7 +2,7 @@ (function() { var LONG_FLAG, MULTI_FLAG, OPTIONAL, OptionParser, SHORT_FLAG, buildRule, buildRules, normalizeArguments, repeat; - repeat = require('./helpers').repeat; + ({ repeat } = require('./helpers')); exports.OptionParser = OptionParser = class OptionParser { constructor(rules, banner) { diff --git a/lib/coffeescript/register.js b/lib/coffeescript/register.js index 4338790fe2..2e27afb892 100644 --- a/lib/coffeescript/register.js +++ b/lib/coffeescript/register.js @@ -48,7 +48,7 @@ } if (child_process) { - fork = child_process.fork; + ({ fork } = child_process); binary = require.resolve('../../bin/coffee'); child_process.fork = function(path, args, options) { if (helpers.isCoffee(path)) { diff --git a/lib/coffeescript/rewriter.js b/lib/coffeescript/rewriter.js index c3d7384d41..f25375cc83 100644 --- a/lib/coffeescript/rewriter.js +++ b/lib/coffeescript/rewriter.js @@ -30,7 +30,7 @@ scanTokens(block) { var i, token, tokens; - tokens = this.tokens; + ({ tokens } = this); i = 0; while (token = tokens[i]) { i += block.call(this, token, i, tokens); @@ -40,7 +40,7 @@ detectEnd(i, condition, action) { var levels, ref, ref1, token, tokens; - tokens = this.tokens; + ({ tokens } = this); levels = 0; while (token = tokens[i]) { if (levels === 0 && condition.call(this, token, i)) { @@ -63,7 +63,7 @@ var i, k, len, ref, tag; ref = this.tokens; for (i = k = 0, len = ref.length; k < len; i = ++k) { - tag = ref[i][0]; + [ tag ] = ref[i]; if (tag !== 'TERMINATOR') { break; } @@ -169,9 +169,9 @@ start = null; return this.scanTokens(function(token, i, tokens) { var endImplicitCall, endImplicitObject, forward, inImplicit, inImplicitCall, inImplicitControl, inImplicitObject, newLine, nextTag, offset, prevTag, prevToken, ref, ref1, ref2, ref3, ref4, ref5, s, sameLine, stackIdx, stackTag, stackTop, startIdx, startImplicitCall, startImplicitObject, startsLine, tag; - tag = token[0]; - prevTag = (prevToken = i > 0 ? tokens[i - 1] : [])[0]; - nextTag = (i < tokens.length - 1 ? tokens[i + 1] : [])[0]; + [ tag ] = token; + [ prevTag ] = prevToken = i > 0 ? tokens[i - 1] : []; + [ nextTag ] = i < tokens.length - 1 ? tokens[i + 1] : []; stackTop = function() { return stack[stack.length - 1]; }; @@ -396,7 +396,7 @@ }; return this.scanTokens(function(token, i, tokens) { var j, k, ref, ref1, ref2, tag; - tag = token[0]; + [ tag ] = token; if (tag === 'TERMINATOR') { if (this.tag(i + 1) === 'ELSE' && this.tag(i - 1) !== 'OUTDENT') { tokens.splice(i, 1, ...this.indentation()); @@ -438,8 +438,8 @@ original = null; condition = function(token, i) { var prevTag, tag; - tag = token[0]; - prevTag = this.tokens[i - 1][0]; + [ tag ] = token; + [ prevTag ] = this.tokens[i - 1]; return tag === 'TERMINATOR' || (tag === 'INDENT' && indexOf.call(SINGLE_LINERS, prevTag) < 0); }; action = function(token, i) {