updated access grammar

This commit is contained in:
Julian Rosse
2018-08-24 13:21:23 -04:00
parent 71350d67c4
commit ddfde6810c
7 changed files with 195 additions and 40 deletions

View File

@@ -650,27 +650,45 @@
o('?. Property',
function() {
return new Access($2,
'soak');
{
soak: true
});
}),
o(':: Property',
function() {
return [LOC(1)(new Access(new PropertyName('prototype'))),
LOC(2)(new Access($2))];
return [
LOC(1)(new Access(new PropertyName('prototype'),
{
shorthand: true
})),
LOC(2)(new Access($2))
];
}),
o('?:: Property',
function() {
return [LOC(1)(new Access(new PropertyName('prototype'),
'soak')),
LOC(2)(new Access($2))];
return [
LOC(1)(new Access(new PropertyName('prototype'),
{
shorthand: true,
soak: true
})),
LOC(2)(new Access($2))
];
}),
o('::',
function() {
return new Access(new PropertyName('prototype'));
return new Access(new PropertyName('prototype'),
{
shorthand: true
});
}),
o('?::',
function() {
return new Access(new PropertyName('prototype'),
'soak');
{
shorthand: true,
soak: true
});
}),
o('Index')
],

View File

@@ -5,7 +5,7 @@
// arrays, count characters, that sort of thing.
// Peek at the beginning of a given string to see if it matches a sequence.
var UNICODE_CODE_POINT_ESCAPE, attachCommentsToNode, buildLocationData, buildLocationHash, buildTokenDataDictionary, extend, flatten, isBoolean, isNumber, isString, ref, repeat, syntaxErrorToString, unicodeCodePointToUnicodeEscapes,
var UNICODE_CODE_POINT_ESCAPE, attachCommentsToNode, buildLocationData, buildLocationHash, buildTokenDataDictionary, extend, flatten, isBoolean, isNumber, isString, mergeAstLocationData, ref, repeat, syntaxErrorToString, unicodeCodePointToUnicodeEscapes,
indexOf = [].indexOf;
exports.starts = function(string, literal, start) {
@@ -349,6 +349,45 @@
}
};
// Extends the location data of an AST node to include the location data from
// another AST node.
exports.mergeAstLocationData = mergeAstLocationData = function(intoNode, fromNode) {
var fromItem, fromRange, i, intoRange, len1;
if (Array.isArray(fromNode)) {
for (i = 0, len1 = fromNode.length; i < len1; i++) {
fromItem = fromNode[i];
mergeAstLocationData(intoNode, fromItem);
}
return intoNode;
}
({
range: intoRange
} = intoNode);
({
range: fromRange
} = fromNode);
if (!(intoRange && fromRange)) {
return intoNode;
}
if (fromRange[0] < intoRange[0]) {
intoNode.range = [fromRange[0], intoRange[1]];
intoNode.start = fromNode.start;
intoNode.loc = {
start: fromNode.loc.start,
end: intoNode.loc.end
};
}
if (fromRange[1] > intoRange[1]) {
intoNode.range = [intoRange[0], fromRange[1]];
intoNode.end = fromNode.end;
intoNode.loc = {
start: intoNode.loc.start,
end: fromNode.loc.end
};
}
return intoNode;
};
exports.isFunction = function(obj) {
return Object.prototype.toString.call(obj) === '[object Function]';
};

View File

@@ -4,7 +4,7 @@
// nodes are created as the result of actions in the [grammar](grammar.html),
// but some are created by other nodes as a method of code generation. To convert
// the syntax tree into a string of JavaScript code, call `compile()` on the root.
var Access, Arr, Assign, AwaitReturn, Base, Block, BooleanLiteral, CSXTag, Call, Class, Code, CodeFragment, ComputedPropertyName, Elision, ExecutableClassBody, Existence, Expansion, ExportAllDeclaration, ExportDeclaration, ExportDefaultDeclaration, ExportNamedDeclaration, ExportSpecifier, ExportSpecifierList, Extends, For, FuncGlyph, HEREGEX_OMIT, HereComment, HoistTarget, IdentifierLiteral, If, ImportClause, ImportDeclaration, ImportDefaultSpecifier, ImportNamespaceSpecifier, ImportSpecifier, ImportSpecifierList, In, Index, InfinityLiteral, Interpolation, JS_FORBIDDEN, LEADING_BLANK_LINE, LEVEL_ACCESS, LEVEL_COND, LEVEL_LIST, LEVEL_OP, LEVEL_PAREN, LEVEL_TOP, LineComment, Literal, ModuleDeclaration, ModuleSpecifier, ModuleSpecifierList, NEGATE, NO, NaNLiteral, NullLiteral, NumberLiteral, Obj, Op, Param, Parens, PassthroughLiteral, PropertyName, Range, RegexLiteral, RegexWithInterpolations, Return, SIMPLENUM, SIMPLE_STRING_OMIT, STRING_OMIT, Scope, Slice, Splat, StatementLiteral, StringLiteral, StringWithInterpolations, Super, SuperCall, Switch, TAB, THIS, TRAILING_BLANK_LINE, TaggedTemplateCall, ThisLiteral, Throw, Try, UTILITIES, UndefinedLiteral, Value, While, YES, YieldReturn, addDataToNode, attachCommentsToNode, compact, del, ends, extend, flatten, fragmentsToText, hasLineComments, indentInitial, isFunction, isLiteralArguments, isLiteralThis, isNumber, isPlainObject, isUnassignable, locationDataToString, makeDelimitedLiteral, merge, moveComments, multident, replaceUnicodeCodePointEscapes, shouldCacheOrIsAssignable, some, starts, throwSyntaxError, unfoldSoak, unshiftAfterComments, utility,
var Access, Arr, Assign, AwaitReturn, Base, Block, BooleanLiteral, CSXTag, Call, Class, Code, CodeFragment, ComputedPropertyName, Elision, ExecutableClassBody, Existence, Expansion, ExportAllDeclaration, ExportDeclaration, ExportDefaultDeclaration, ExportNamedDeclaration, ExportSpecifier, ExportSpecifierList, Extends, For, FuncGlyph, HEREGEX_OMIT, HereComment, HoistTarget, IdentifierLiteral, If, ImportClause, ImportDeclaration, ImportDefaultSpecifier, ImportNamespaceSpecifier, ImportSpecifier, ImportSpecifierList, In, Index, InfinityLiteral, Interpolation, JS_FORBIDDEN, LEADING_BLANK_LINE, LEVEL_ACCESS, LEVEL_COND, LEVEL_LIST, LEVEL_OP, LEVEL_PAREN, LEVEL_TOP, LineComment, Literal, ModuleDeclaration, ModuleSpecifier, ModuleSpecifierList, NEGATE, NO, NaNLiteral, NullLiteral, NumberLiteral, Obj, Op, Param, Parens, PassthroughLiteral, PropertyName, Range, RegexLiteral, RegexWithInterpolations, Return, SIMPLENUM, SIMPLE_STRING_OMIT, STRING_OMIT, Scope, Slice, Splat, StatementLiteral, StringLiteral, StringWithInterpolations, Super, SuperCall, Switch, TAB, THIS, TRAILING_BLANK_LINE, TaggedTemplateCall, ThisLiteral, Throw, Try, UTILITIES, UndefinedLiteral, Value, While, YES, YieldReturn, addDataToNode, attachCommentsToNode, compact, del, ends, extend, flatten, fragmentsToText, hasLineComments, indentInitial, isFunction, isLiteralArguments, isLiteralThis, isNumber, isPlainObject, isUnassignable, locationDataToString, makeDelimitedLiteral, merge, mergeAstLocationData, moveComments, multident, replaceUnicodeCodePointEscapes, shouldCacheOrIsAssignable, some, starts, throwSyntaxError, unfoldSoak, unshiftAfterComments, utility,
indexOf = [].indexOf,
splice = [].splice,
slice1 = [].slice;
@@ -16,7 +16,7 @@
({isUnassignable, JS_FORBIDDEN} = require('./lexer'));
// Import the helpers we plan to use.
({compact, flatten, extend, merge, del, starts, ends, some, addDataToNode, attachCommentsToNode, locationDataToString, throwSyntaxError, replaceUnicodeCodePointEscapes, isFunction, isPlainObject, isNumber} = require('./helpers'));
({compact, flatten, extend, merge, del, starts, ends, some, addDataToNode, attachCommentsToNode, locationDataToString, throwSyntaxError, replaceUnicodeCodePointEscapes, mergeAstLocationData, isFunction, isPlainObject, isNumber} = require('./helpers'));
// Functions required by parser.
exports.extend = extend;
@@ -58,7 +58,7 @@
toString() {
// This is only intended for debugging.
return `${this.code}${this.locationData ? ": " + locationDataToString(this.locationData) : ''}`;
return `${this.code}${(this.locationData ? ": " + locationDataToString(this.locationData) : '')}`;
}
};
@@ -897,7 +897,7 @@
}
fragments.push(this.makeCode(scope.assignedVariables().join(`,\n${this.tab + TAB}`)));
}
fragments.push(this.makeCode(`;\n${this.spaced ? '\n' : ''}`));
fragments.push(this.makeCode(`;\n${(this.spaced ? '\n' : '')}`));
} else if (fragments.length && post.length) {
fragments.push(this.makeCode("\n"));
}
@@ -1105,7 +1105,7 @@
toString() {
// This is only intended for debugging.
return ` ${this.isStatement() ? super.toString() : this.constructor.name}: ${this.value}`;
return ` ${(this.isStatement() ? super.toString() : this.constructor.name)}: ${this.value}`;
}
};
@@ -1726,6 +1726,27 @@
return fragments;
}
_toAst(o) {
var j, len1, prop, propIndex, props, ref1, ret;
props = this.properties;
ret = this.base.toAst(o, props.length ? LEVEL_ACCESS : null);
for (propIndex = j = 0, len1 = props.length; j < len1; propIndex = ++j) {
prop = props[propIndex];
ret = mergeAstLocationData(prop.withAstLocationData({
type: 'MemberExpression',
object: ret,
property: prop.toAst(o),
computed: prop instanceof Index || !(((ref1 = prop.name) != null ? ref1.unwrap() : void 0) instanceof PropertyName),
optional: !!prop.soak,
shorthand: !!prop.shorthand
}), ret);
if (propIndex === 0 && this.base instanceof Parens && (this.base.locationData != null)) {
mergeAstLocationData(ret, this.base.astLocationData());
}
}
return ret;
}
checkNewTarget(o) {
if (!(this.base instanceof IdentifierLiteral && this.base.value === 'new' && this.properties.length)) {
return;
@@ -1831,7 +1852,7 @@
}
this.content = this.content.replace(RegExp(`^(${leadingWhitespace})`, "gm"), '');
}
this.content = `/*${this.content}${hasLeadingMarks ? ' ' : ''}*/`;
this.content = `/*${this.content}${(hasLeadingMarks ? ' ' : '')}*/`;
fragment = this.makeCode(this.content);
fragment.newLine = this.newLine;
fragment.unshift = this.unshift;
@@ -2234,10 +2255,14 @@
// an access into the object's prototype.
exports.Access = Access = (function() {
class Access extends Base {
constructor(name1, tag) {
constructor(name1, {
soak: soak1,
shorthand
} = {}) {
super();
this.name = name1;
this.soak = tag === 'soak';
this.soak = soak1;
this.shorthand = shorthand;
}
compileToFragments(o) {
@@ -2251,6 +2276,10 @@
}
}
_toAst(o) {
return this.name.toAst(o);
}
};
Access.prototype.children = ['name'];
@@ -2348,9 +2377,9 @@
// Always check if the `step` isn't zero to avoid the infinite loop.
stepNotZero = `${(ref1 = this.stepNum) != null ? ref1 : this.stepVar} !== 0`;
stepCond = `${(ref2 = this.stepNum) != null ? ref2 : this.stepVar} > 0`;
lowerBound = `${lt} ${known ? to : this.toVar}`;
upperBound = `${gt} ${known ? to : this.toVar}`;
condPart = this.step != null ? (this.stepNum != null) && this.stepNum !== 0 ? this.stepNum > 0 ? `${lowerBound}` : `${upperBound}` : `${stepNotZero} && (${stepCond} ? ${lowerBound} : ${upperBound})` : known ? `${from <= to ? lt : gt} ${to}` : `(${this.fromVar} <= ${this.toVar} ? ${lowerBound} : ${upperBound})`;
lowerBound = `${lt} ${(known ? to : this.toVar)}`;
upperBound = `${gt} ${(known ? to : this.toVar)}`;
condPart = this.step != null ? (this.stepNum != null) && this.stepNum !== 0 ? this.stepNum > 0 ? `${lowerBound}` : `${upperBound}` : `${stepNotZero} && (${stepCond} ? ${lowerBound} : ${upperBound})` : known ? `${(from <= to ? lt : gt)} ${to}` : `(${this.fromVar} <= ${this.toVar} ? ${lowerBound} : ${upperBound})`;
cond = this.stepVar ? `${this.stepVar} > 0` : `${this.fromVar} <= ${this.toVar}`;
// Generate the step.
stepPart = this.stepVar ? `${idx} += ${this.stepVar}` : known ? namedIndex ? from <= to ? `++${idx}` : `--${idx}` : from <= to ? `${idx}++` : `${idx}--` : namedIndex ? `${cond} ? ++${idx} : --${idx}` : `${cond} ? ${idx}++ : ${idx}--`;
@@ -4308,7 +4337,7 @@
modifiers.push('async');
}
if (!(this.isMethod || this.bound)) {
modifiers.push(`function${this.isGenerator ? '*' : ''}`);
modifiers.push(`function${(this.isGenerator ? '*' : '')}`);
} else if (this.isGenerator) {
modifiers.push('*');
}
@@ -5012,7 +5041,7 @@
var fragments, fst, shared;
[this.first.second, shared] = this.first.second.cache(o);
fst = this.first.compileToFragments(o, LEVEL_OP);
fragments = fst.concat(this.makeCode(` ${this.invert ? '&&' : '||'} `), shared.compileToFragments(o), this.makeCode(` ${this.operator} `), this.second.compileToFragments(o, LEVEL_OP));
fragments = fst.concat(this.makeCode(` ${(this.invert ? '&&' : '||')} `), shared.compileToFragments(o), this.makeCode(` ${this.operator} `), this.second.compileToFragments(o, LEVEL_OP));
return this.wrapInParentheses(fragments);
}
@@ -5605,7 +5634,7 @@
this.index.error('cannot use index with for-from');
}
if (this.own && !this.object) {
this.ownTag.error(`cannot use own with for-${this.from ? 'from' : 'in'}`);
this.ownTag.error(`cannot use own with for-${(this.from ? 'from' : 'in')}`);
}
if (this.object) {
[this.name, this.index] = [this.index, this.name];
@@ -5716,7 +5745,7 @@
} else {
svar = this.source.compile(o, LEVEL_LIST);
if ((name || this.own) && !(this.source.unwrap() instanceof IdentifierLiteral)) {
defPart += `${this.tab}${ref = scope.freeVariable('ref')} = ${svar};\n`;
defPart += `${this.tab}${(ref = scope.freeVariable('ref'))} = ${svar};\n`;
svar = ref;
}
if (name && !this.pattern && !this.from) {
@@ -5746,7 +5775,7 @@
}
increment = `${ivar} += ${stepVar}`;
} else {
increment = `${kvar !== ivar ? `++${ivar}` : `${ivar}++`}`;
increment = `${(kvar !== ivar ? `++${ivar}` : `${ivar}++`)}`;
}
forPartFragments = [this.makeCode(`${declare}; ${compare}; ${kvarAssign}${increment}`)];
}

View File

@@ -391,23 +391,41 @@ this.$ = yy.addDataToNode(yy, _$[$0-3], _$[$0])(new yy.Super(yy.addDataToNode(yy
break;
case 140:
this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.Access($$[$0],
'soak'));
{
soak: true
}));
break;
case 141:
this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])([yy.addDataToNode(yy, _$[$0-1])(new yy.Access(new yy.PropertyName('prototype'))),
yy.addDataToNode(yy, _$[$0])(new yy.Access($$[$0]))]);
this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])([
yy.addDataToNode(yy, _$[$0-1])(new yy.Access(new yy.PropertyName('prototype'),
{
shorthand: true
})),
yy.addDataToNode(yy, _$[$0])(new yy.Access($$[$0]))
]);
break;
case 142:
this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])([yy.addDataToNode(yy, _$[$0-1])(new yy.Access(new yy.PropertyName('prototype'),
'soak')),
yy.addDataToNode(yy, _$[$0])(new yy.Access($$[$0]))]);
this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])([
yy.addDataToNode(yy, _$[$0-1])(new yy.Access(new yy.PropertyName('prototype'),
{
shorthand: true,
soak: true
})),
yy.addDataToNode(yy, _$[$0])(new yy.Access($$[$0]))
]);
break;
case 143:
this.$ = yy.addDataToNode(yy, _$[$0], _$[$0])(new yy.Access(new yy.PropertyName('prototype')));
this.$ = yy.addDataToNode(yy, _$[$0], _$[$0])(new yy.Access(new yy.PropertyName('prototype'),
{
shorthand: true
}));
break;
case 144:
this.$ = yy.addDataToNode(yy, _$[$0], _$[$0])(new yy.Access(new yy.PropertyName('prototype'),
'soak'));
{
shorthand: true,
soak: true
}));
break;
case 147:
this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(yy.extend($$[$0],

View File

@@ -392,11 +392,11 @@ grammar =
# or by array index or slice.
Accessor: [
o '. Property', -> new Access $2
o '?. Property', -> new Access $2, 'soak'
o ':: Property', -> [LOC(1)(new Access new PropertyName('prototype')), LOC(2)(new Access $2)]
o '?:: Property', -> [LOC(1)(new Access new PropertyName('prototype'), 'soak'), LOC(2)(new Access $2)]
o '::', -> new Access new PropertyName 'prototype'
o '?::', -> new Access new PropertyName('prototype'), 'soak'
o '?. Property', -> new Access $2, soak: yes
o ':: Property', -> [LOC(1)(new Access new PropertyName('prototype'), shorthand: yes), LOC(2)(new Access $2)]
o '?:: Property', -> [LOC(1)(new Access new PropertyName('prototype'), shorthand: yes, soak: yes), LOC(2)(new Access $2)]
o '::', -> new Access new PropertyName('prototype'), shorthand: yes
o '?::', -> new Access new PropertyName('prototype'), shorthand: yes, soak: yes
o 'Index'
]

View File

@@ -248,6 +248,35 @@ exports.nameWhitespaceCharacter = (string) ->
when '\t' then 'tab'
else string
# Extends the location data of an AST node to include the location data from
# another AST node.
exports.mergeAstLocationData = mergeAstLocationData = (intoNode, fromNode) ->
if Array.isArray fromNode
mergeAstLocationData intoNode, fromItem for fromItem in fromNode
return intoNode
{range: intoRange} = intoNode
{range: fromRange} = fromNode
return intoNode unless intoRange and fromRange
if fromRange[0] < intoRange[0]
intoNode.range = [
fromRange[0]
intoRange[1]
]
intoNode.start = fromNode.start
intoNode.loc =
start: fromNode.loc.start
end: intoNode.loc.end
if fromRange[1] > intoRange[1]
intoNode.range = [
intoRange[0]
fromRange[1]
]
intoNode.end = fromNode.end
intoNode.loc =
start: intoNode.loc.start
end: fromNode.loc.end
intoNode
exports.isFunction = (obj) -> Object::toString.call(obj) is '[object Function]'
exports.isNumber = isNumber = (obj) -> Object::toString.call(obj) is '[object Number]'
exports.isString = isString = (obj) -> Object::toString.call(obj) is '[object String]'

View File

@@ -12,6 +12,7 @@ Error.stackTraceLimit = Infinity
{compact, flatten, extend, merge, del, starts, ends, some,
addDataToNode, attachCommentsToNode, locationDataToString,
throwSyntaxError, replaceUnicodeCodePointEscapes,
mergeAstLocationData,
isFunction, isPlainObject, isNumber} = require './helpers'
# Functions required by parser.
@@ -1145,6 +1146,25 @@ exports.Value = class Value extends Base
fragments
_toAst: (o) ->
props = @properties
ret = @base.toAst o, if props.length then LEVEL_ACCESS else null
for prop, propIndex in props
ret =
mergeAstLocationData(
prop.withAstLocationData
type: 'MemberExpression'
object: ret
property: prop.toAst o
computed: prop instanceof Index or prop.name?.unwrap() not instanceof PropertyName
optional: !!prop.soak
shorthand: !!prop.shorthand
ret
)
if propIndex is 0 and @base instanceof Parens and @base.locationData?
mergeAstLocationData ret, @base.astLocationData()
ret
checkNewTarget: (o) ->
return unless @base instanceof IdentifierLiteral and @base.value is 'new' and @properties.length
if @properties[0] instanceof Access and @properties[0].name.value is 'target'
@@ -1470,9 +1490,8 @@ exports.Extends = class Extends extends Base
# A `.` access into a property of a value, or the `::` shorthand for
# an access into the object's prototype.
exports.Access = class Access extends Base
constructor: (@name, tag) ->
constructor: (@name, {@soak, @shorthand} = {}) ->
super()
@soak = tag is 'soak'
children: ['name']
@@ -1484,6 +1503,9 @@ exports.Access = class Access extends Base
else
[@makeCode('['), name..., @makeCode(']')]
_toAst: (o) ->
@name.toAst o
shouldCache: NO
#### Index