* working on making Invocation a grammar Value * cleanup * update location when adding value properties * test for #4467 * more location data tests
This commit is contained in:
parent
56725ad275
commit
ab52fd75c2
|
@ -48,7 +48,7 @@
|
|||
return new StatementLiteral($1);
|
||||
}), o('Import'), o('Export')
|
||||
],
|
||||
Expression: [o('Value'), o('Invocation'), o('Code'), o('Operation'), o('Assign'), o('If'), o('Try'), o('While'), o('For'), o('Switch'), o('Class'), o('Throw'), o('Yield')],
|
||||
Expression: [o('Value'), o('Code'), o('Operation'), o('Assign'), o('If'), o('Try'), o('While'), o('For'), o('Switch'), o('Class'), o('Throw'), o('Yield')],
|
||||
Yield: [
|
||||
o('YIELD', function() {
|
||||
return new Op($1, new Value(new Literal('')));
|
||||
|
@ -242,8 +242,6 @@
|
|||
return new Value($1);
|
||||
}), o('Value Accessor', function() {
|
||||
return $1.add($2);
|
||||
}), o('Invocation Accessor', function() {
|
||||
return new Value($1, [].concat($2));
|
||||
}), o('ThisProperty')
|
||||
],
|
||||
Assignable: [
|
||||
|
@ -260,7 +258,11 @@
|
|||
return new Value($1);
|
||||
}), o('Range', function() {
|
||||
return new Value($1);
|
||||
}), o('This'), o('Super')
|
||||
}), o('Invocation', function() {
|
||||
return new Value($1);
|
||||
}), o('This'), o('Super', function() {
|
||||
return new Value($1);
|
||||
})
|
||||
],
|
||||
Super: [
|
||||
o('SUPER . Property', function() {
|
||||
|
@ -444,8 +446,6 @@
|
|||
return new TaggedTemplateCall($1, $3, $2);
|
||||
}), o('Value OptFuncExist Arguments', function() {
|
||||
return new Call($1, $3, $2);
|
||||
}), o('Invocation OptFuncExist Arguments', function() {
|
||||
return new Call($1, $3, $2);
|
||||
}), o('SUPER OptFuncExist Arguments', function() {
|
||||
return new SuperCall(LOC(1)(new Super), $3, $2);
|
||||
})
|
||||
|
|
|
@ -276,9 +276,10 @@
|
|||
}
|
||||
|
||||
updateLocationDataIfMissing(locationData) {
|
||||
if (this.locationData) {
|
||||
if (this.locationData && !this.forceUpdateLocation) {
|
||||
return this;
|
||||
}
|
||||
delete this.forceUpdateLocation;
|
||||
this.locationData = locationData;
|
||||
return this.eachChild(function(child) {
|
||||
return child.updateLocationDataIfMissing(locationData);
|
||||
|
@ -536,15 +537,15 @@
|
|||
}
|
||||
return results;
|
||||
}).call(this);
|
||||
rest = this.expressions.slice(preludeExps.length);
|
||||
this.expressions = preludeExps;
|
||||
if (preludeExps.length) {
|
||||
rest = this.expressions.slice(preludeExps.length);
|
||||
this.expressions = preludeExps;
|
||||
prelude = this.compileNode(merge(o, {
|
||||
indent: ''
|
||||
}));
|
||||
prelude.push(this.makeCode("\n"));
|
||||
this.expressions = rest;
|
||||
}
|
||||
this.expressions = rest;
|
||||
}
|
||||
fragments = this.compileWithDeclarations(o);
|
||||
HoistTarget.expand(fragments);
|
||||
|
@ -855,6 +856,7 @@
|
|||
|
||||
add(props) {
|
||||
this.properties = this.properties.concat(props);
|
||||
this.forceUpdateLocation = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -3393,9 +3395,7 @@
|
|||
if (res) {
|
||||
return super.makeReturn(res);
|
||||
} else {
|
||||
this.returns = !this.jumps({
|
||||
loop: true
|
||||
});
|
||||
this.returns = !this.jumps();
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
@ -3467,6 +3467,7 @@
|
|||
|
||||
class Op extends Base {
|
||||
constructor(op, first, second, flip) {
|
||||
var firstCall;
|
||||
super();
|
||||
if (op === 'in') {
|
||||
return new In(first, second);
|
||||
|
@ -3475,8 +3476,8 @@
|
|||
return Op.prototype.generateDo(first);
|
||||
}
|
||||
if (op === 'new') {
|
||||
if (first instanceof Call && !first.do && !first.isNew) {
|
||||
return first.newInstance();
|
||||
if ((firstCall = first.unwrap()) instanceof Call && !firstCall.do && !firstCall.isNew) {
|
||||
return firstCall.newInstance();
|
||||
}
|
||||
if (first instanceof Code && first.bound || first.do) {
|
||||
first = new Parens(first);
|
||||
|
@ -3945,7 +3946,7 @@
|
|||
return expr.compileToFragments(o);
|
||||
}
|
||||
fragments = expr.compileToFragments(o, LEVEL_PAREN);
|
||||
bare = o.level < LEVEL_OP && (expr instanceof Op || expr instanceof Call || (expr instanceof For && expr.returns)) && (o.level < LEVEL_COND || fragments.length <= 3);
|
||||
bare = o.level < LEVEL_OP && (expr instanceof Op || expr.unwrap() instanceof Call || (expr instanceof For && expr.returns)) && (o.level < LEVEL_COND || fragments.length <= 3);
|
||||
if (this.csxAttribute) {
|
||||
return this.wrapInBraces(fragments);
|
||||
}
|
||||
|
@ -4035,8 +4036,8 @@
|
|||
|
||||
isNestedTag(element) {
|
||||
var call, exprs, ref1;
|
||||
exprs = element != null ? (ref1 = element.body) != null ? ref1.expressions : void 0 : void 0;
|
||||
call = exprs != null ? exprs[0] : void 0;
|
||||
exprs = (ref1 = element.body) != null ? ref1.expressions : void 0;
|
||||
call = exprs != null ? exprs[0].unwrap() : void 0;
|
||||
return this.csx && exprs && exprs.length === 1 && call instanceof Call && call.csx;
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -112,7 +112,6 @@ grammar =
|
|||
# them somewhat circular.
|
||||
Expression: [
|
||||
o 'Value'
|
||||
o 'Invocation'
|
||||
o 'Code'
|
||||
o 'Operation'
|
||||
o 'Assign'
|
||||
|
@ -313,7 +312,6 @@ grammar =
|
|||
SimpleAssignable: [
|
||||
o 'Identifier', -> new Value $1
|
||||
o 'Value Accessor', -> $1.add $2
|
||||
o 'Invocation Accessor', -> new Value $1, [].concat $2
|
||||
o 'ThisProperty'
|
||||
]
|
||||
|
||||
|
@ -331,8 +329,9 @@ grammar =
|
|||
o 'Literal', -> new Value $1
|
||||
o 'Parenthetical', -> new Value $1
|
||||
o 'Range', -> new Value $1
|
||||
o 'Invocation', -> new Value $1
|
||||
o 'This'
|
||||
o 'Super'
|
||||
o 'Super', -> new Value $1
|
||||
]
|
||||
|
||||
# A `super`-based expression that can be used as a value.
|
||||
|
@ -459,7 +458,6 @@ grammar =
|
|||
Invocation: [
|
||||
o 'Value OptFuncExist String', -> new TaggedTemplateCall $1, $3, $2
|
||||
o 'Value OptFuncExist Arguments', -> new Call $1, $3, $2
|
||||
o 'Invocation OptFuncExist Arguments', -> new Call $1, $3, $2
|
||||
o 'SUPER OptFuncExist Arguments', -> new SuperCall LOC(1)(new Super), $3, $2
|
||||
]
|
||||
|
||||
|
|
|
@ -266,7 +266,8 @@ exports.Base = class Base
|
|||
# For this node and all descendents, set the location data to `locationData`
|
||||
# if the location data is not already set.
|
||||
updateLocationDataIfMissing: (locationData) ->
|
||||
return this if @locationData
|
||||
return this if @locationData and not @forceUpdateLocation
|
||||
delete @forceUpdateLocation
|
||||
@locationData = locationData
|
||||
|
||||
@eachChild (child) ->
|
||||
|
@ -286,11 +287,11 @@ exports.Base = class Base
|
|||
[@makeCode('{'), fragments..., @makeCode('}')]
|
||||
|
||||
# `fragmentsList` is an array of arrays of fragments. Each array in fragmentsList will be
|
||||
# concatonated together, with `joinStr` added in between each, to produce a final flat array
|
||||
# concatenated together, with `joinStr` added in between each, to produce a final flat array
|
||||
# of fragments.
|
||||
joinFragmentArrays: (fragmentsList, joinStr) ->
|
||||
answer = []
|
||||
for fragments,i in fragmentsList
|
||||
for fragments, i in fragmentsList
|
||||
if i then answer.push @makeCode joinStr
|
||||
answer = answer.concat fragments
|
||||
answer
|
||||
|
@ -453,12 +454,12 @@ exports.Block = class Block extends Base
|
|||
preludeExps = for exp, i in @expressions
|
||||
break unless exp.unwrap() instanceof Comment
|
||||
exp
|
||||
rest = @expressions[preludeExps.length...]
|
||||
@expressions = preludeExps
|
||||
if preludeExps.length
|
||||
rest = @expressions[preludeExps.length...]
|
||||
@expressions = preludeExps
|
||||
prelude = @compileNode merge(o, indent: '')
|
||||
prelude.push @makeCode "\n"
|
||||
@expressions = rest
|
||||
@expressions = rest
|
||||
fragments = @compileWithDeclarations o
|
||||
HoistTarget.expand fragments
|
||||
return fragments if o.bare
|
||||
|
@ -659,6 +660,7 @@ exports.Value = class Value extends Base
|
|||
# Add a property (or *properties* ) `Access` to the list.
|
||||
add: (props) ->
|
||||
@properties = @properties.concat props
|
||||
@forceUpdateLocation = yes
|
||||
this
|
||||
|
||||
hasProperties: ->
|
||||
|
@ -2585,7 +2587,7 @@ exports.While = class While extends Base
|
|||
if res
|
||||
super res
|
||||
else
|
||||
@returns = not @jumps loop: yes
|
||||
@returns = not @jumps()
|
||||
this
|
||||
|
||||
addBody: (@body) ->
|
||||
|
@ -2635,7 +2637,8 @@ exports.Op = class Op extends Base
|
|||
if op is 'do'
|
||||
return Op::generateDo first
|
||||
if op is 'new'
|
||||
return first.newInstance() if first instanceof Call and not first.do and not first.isNew
|
||||
if (firstCall = first.unwrap()) instanceof Call and not firstCall.do and not firstCall.isNew
|
||||
return firstCall.newInstance()
|
||||
first = new Parens first if first instanceof Code and first.bound or first.do
|
||||
|
||||
@operator = CONVERSIONS[op] or op
|
||||
|
@ -2984,7 +2987,7 @@ exports.Parens = class Parens extends Base
|
|||
expr.front = @front
|
||||
return expr.compileToFragments o
|
||||
fragments = expr.compileToFragments o, LEVEL_PAREN
|
||||
bare = o.level < LEVEL_OP and (expr instanceof Op or expr instanceof Call or
|
||||
bare = o.level < LEVEL_OP and (expr instanceof Op or expr.unwrap() instanceof Call or
|
||||
(expr instanceof For and expr.returns)) and (o.level < LEVEL_COND or
|
||||
fragments.length <= 3)
|
||||
return @wrapInBraces fragments if @csxAttribute
|
||||
|
@ -3046,8 +3049,8 @@ exports.StringWithInterpolations = class StringWithInterpolations extends Base
|
|||
fragments
|
||||
|
||||
isNestedTag: (element) ->
|
||||
exprs = element?.body?.expressions
|
||||
call = exprs?[0]
|
||||
exprs = element.body?.expressions
|
||||
call = exprs?[0].unwrap()
|
||||
@csx and exprs and exprs.length is 1 and call instanceof Call and call.csx
|
||||
|
||||
#### For
|
||||
|
|
|
@ -613,3 +613,38 @@ test "Verify all tokens get a location", ->
|
|||
tokens = CoffeeScript.tokens testScript
|
||||
for token in tokens
|
||||
ok !!token[2]
|
||||
|
||||
test 'Values with properties end up with a location that includes the properties', ->
|
||||
source = '''
|
||||
a.b
|
||||
a.b.c
|
||||
a['b']
|
||||
a[b.c()].d
|
||||
'''
|
||||
block = CoffeeScript.nodes source
|
||||
[
|
||||
singleProperty
|
||||
twoProperties
|
||||
indexed
|
||||
complexIndex
|
||||
] = block.expressions
|
||||
|
||||
eq singleProperty.locationData.first_line, 0
|
||||
eq singleProperty.locationData.first_column, 0
|
||||
eq singleProperty.locationData.last_line, 0
|
||||
eq singleProperty.locationData.last_column, 2
|
||||
|
||||
eq twoProperties.locationData.first_line, 1
|
||||
eq twoProperties.locationData.first_column, 0
|
||||
eq twoProperties.locationData.last_line, 1
|
||||
eq twoProperties.locationData.last_column, 4
|
||||
|
||||
eq indexed.locationData.first_line, 2
|
||||
eq indexed.locationData.first_column, 0
|
||||
eq indexed.locationData.last_line, 2
|
||||
eq indexed.locationData.last_column, 5
|
||||
|
||||
eq complexIndex.locationData.first_line, 3
|
||||
eq complexIndex.locationData.first_column, 0
|
||||
eq complexIndex.locationData.last_line, 3
|
||||
eq complexIndex.locationData.last_column, 9
|
||||
|
|
|
@ -18,6 +18,7 @@ func = (text, expressions...) ->
|
|||
outerobj =
|
||||
obj:
|
||||
func: func
|
||||
f: -> func
|
||||
|
||||
# Example use
|
||||
test "tagged template literal for html templating", ->
|
||||
|
@ -169,3 +170,8 @@ test "tagged template literal with unnecessarily escaped ES interpolation", ->
|
|||
test "tagged template literal special escaping", ->
|
||||
eq 'text: [` ` \\` \\` \\\\` $ { ${ ${ \\${ \\${ \\\\${ | ` ${] expressions: [1]',
|
||||
func"` \` \\` \\\` \\\\` $ { ${ \${ \\${ \\\${ \\\\${ #{1} ` ${"
|
||||
|
||||
test '#4467: tagged template literal call recognized as a callable function', ->
|
||||
eq 'text: [dot notation] expressions: []',
|
||||
outerobj.obj.f()'dot notation'
|
||||
|
||||
|
|
Loading…
Reference in New Issue