summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkpdecker <kpdecker@gmail.com>2015-08-18 23:57:27 -0700
committerkpdecker <kpdecker@gmail.com>2015-08-18 23:57:27 -0700
commit95d84badcae89aa72a6f1433b851304700320920 (patch)
tree78dfd5cad87cb77d4353484781ff580bcbf2ad1c
parent9a2d1d6009406915d1ca177ed5321e4727b9776f (diff)
downloadhandlebars.js-95d84badcae89aa72a6f1433b851304700320920.zip
handlebars.js-95d84badcae89aa72a6f1433b851304700320920.tar.gz
handlebars.js-95d84badcae89aa72a6f1433b851304700320920.tar.bz2
Drop AST constructors in favor of JSON
These were little more than object literal statements that were less clear due to their use of index-based arguments. Fixes #1077
-rw-r--r--lib/handlebars/compiler/ast.js126
-rw-r--r--lib/handlebars/compiler/base.js3
-rw-r--r--lib/handlebars/compiler/compiler.js9
-rw-r--r--lib/handlebars/compiler/helpers.js72
-rw-r--r--lib/handlebars/compiler/visitor.js3
-rw-r--r--spec/ast.js151
-rw-r--r--spec/compiler.js10
-rw-r--r--spec/parser.js5
-rw-r--r--spec/visitor.js4
-rw-r--r--src/handlebars.yy57
10 files changed, 141 insertions, 299 deletions
diff --git a/lib/handlebars/compiler/ast.js b/lib/handlebars/compiler/ast.js
index 599dab8..1699569 100644
--- a/lib/handlebars/compiler/ast.js
+++ b/lib/handlebars/compiler/ast.js
@@ -1,130 +1,4 @@
let AST = {
- Program: function(statements, blockParams, strip, locInfo) {
- this.loc = locInfo;
- this.type = 'Program';
- this.body = statements;
-
- this.blockParams = blockParams;
- this.strip = strip;
- },
-
- MustacheStatement: function(path, params, hash, escaped, strip, locInfo) {
- this.loc = locInfo;
- this.type = 'MustacheStatement';
-
- this.path = path;
- this.params = params || [];
- this.hash = hash;
- this.escaped = escaped;
-
- this.strip = strip;
- },
-
- BlockStatement: function(path, params, hash, program, inverse, openStrip, inverseStrip, closeStrip, locInfo) {
- this.loc = locInfo;
- this.type = 'BlockStatement';
-
- this.path = path;
- this.params = params || [];
- this.hash = hash;
- this.program = program;
- this.inverse = inverse;
-
- this.openStrip = openStrip;
- this.inverseStrip = inverseStrip;
- this.closeStrip = closeStrip;
- },
-
- PartialStatement: function(name, params, hash, strip, locInfo) {
- this.loc = locInfo;
- this.type = 'PartialStatement';
-
- this.name = name;
- this.params = params || [];
- this.hash = hash;
-
- this.indent = '';
- this.strip = strip;
- },
-
- ContentStatement: function(string, locInfo) {
- this.loc = locInfo;
- this.type = 'ContentStatement';
- this.original = this.value = string;
- },
-
- CommentStatement: function(comment, strip, locInfo) {
- this.loc = locInfo;
- this.type = 'CommentStatement';
- this.value = comment;
-
- this.strip = strip;
- },
-
- SubExpression: function(path, params, hash, locInfo) {
- this.loc = locInfo;
-
- this.type = 'SubExpression';
- this.path = path;
- this.params = params || [];
- this.hash = hash;
- },
-
- PathExpression: function(data, depth, parts, original, locInfo) {
- this.loc = locInfo;
- this.type = 'PathExpression';
-
- this.data = data;
- this.original = original;
- this.parts = parts;
- this.depth = depth;
- },
-
- StringLiteral: function(string, locInfo) {
- this.loc = locInfo;
- this.type = 'StringLiteral';
- this.original =
- this.value = string;
- },
-
- NumberLiteral: function(number, locInfo) {
- this.loc = locInfo;
- this.type = 'NumberLiteral';
- this.original =
- this.value = Number(number);
- },
-
- BooleanLiteral: function(bool, locInfo) {
- this.loc = locInfo;
- this.type = 'BooleanLiteral';
- this.original =
- this.value = bool === 'true';
- },
-
- UndefinedLiteral: function(locInfo) {
- this.loc = locInfo;
- this.type = 'UndefinedLiteral';
- this.original = this.value = undefined;
- },
-
- NullLiteral: function(locInfo) {
- this.loc = locInfo;
- this.type = 'NullLiteral';
- this.original = this.value = null;
- },
-
- Hash: function(pairs, locInfo) {
- this.loc = locInfo;
- this.type = 'Hash';
- this.pairs = pairs;
- },
- HashPair: function(key, value, locInfo) {
- this.loc = locInfo;
- this.type = 'HashPair';
- this.key = key;
- this.value = value;
- },
-
// Public API used to evaluate derived attributes regarding AST nodes
helpers: {
// a mustache is definitely a helper if:
diff --git a/lib/handlebars/compiler/base.js b/lib/handlebars/compiler/base.js
index 85c2997..c6871d3 100644
--- a/lib/handlebars/compiler/base.js
+++ b/lib/handlebars/compiler/base.js
@@ -1,5 +1,4 @@
import parser from './parser';
-import AST from './ast';
import WhitespaceControl from './whitespace-control';
import * as Helpers from './helpers';
import { extend } from '../utils';
@@ -7,7 +6,7 @@ import { extend } from '../utils';
export { parser };
let yy = {};
-extend(yy, Helpers, AST);
+extend(yy, Helpers);
export function parse(input, options) {
// Just return if an already-compiled AST was passed in.
diff --git a/lib/handlebars/compiler/compiler.js b/lib/handlebars/compiler/compiler.js
index 59a425f..c8db7c9 100644
--- a/lib/handlebars/compiler/compiler.js
+++ b/lib/handlebars/compiler/compiler.js
@@ -514,6 +514,13 @@ function transformLiteralToPath(sexpr) {
let literal = sexpr.path;
// Casting to string here to make false and 0 literal values play nicely with the rest
// of the system.
- sexpr.path = new AST.PathExpression(false, 0, [literal.original + ''], literal.original + '', literal.loc);
+ sexpr.path = {
+ type: 'PathExpression',
+ data: false,
+ depth: 0,
+ parts: [literal.original + ''],
+ original: literal.original + '',
+ loc: literal.loc
+ };
}
}
diff --git a/lib/handlebars/compiler/helpers.js b/lib/handlebars/compiler/helpers.js
index f2edfa1..bf72034 100644
--- a/lib/handlebars/compiler/helpers.js
+++ b/lib/handlebars/compiler/helpers.js
@@ -32,8 +32,8 @@ export function stripComment(comment) {
.replace(/-?-?~?\}\}$/, '');
}
-export function preparePath(data, parts, locInfo) {
- locInfo = this.locInfo(locInfo);
+export function preparePath(data, parts, loc) {
+ loc = this.locInfo(loc);
let original = data ? '@' : '',
dig = [],
@@ -49,7 +49,7 @@ export function preparePath(data, parts, locInfo) {
if (!isLiteral && (part === '..' || part === '.' || part === 'this')) {
if (dig.length > 0) {
- throw new Exception('Invalid path: ' + original, {loc: locInfo});
+ throw new Exception('Invalid path: ' + original, {loc});
} else if (part === '..') {
depth++;
depthString += '../';
@@ -59,7 +59,14 @@ export function preparePath(data, parts, locInfo) {
}
}
- return new this.PathExpression(data, depth, dig, original, locInfo);
+ return {
+ type: 'PathExpression',
+ data,
+ depth,
+ parts: dig,
+ original,
+ loc
+ };
}
export function prepareMustache(path, params, hash, open, strip, locInfo) {
@@ -67,7 +74,15 @@ export function prepareMustache(path, params, hash, open, strip, locInfo) {
let escapeFlag = open.charAt(3) || open.charAt(2),
escaped = escapeFlag !== '{' && escapeFlag !== '&';
- return new this.MustacheStatement(path, params, hash, escaped, strip, this.locInfo(locInfo));
+ return {
+ type: 'MustacheStatement',
+ path,
+ params,
+ hash,
+ escaped,
+ strip,
+ loc: this.locInfo(locInfo)
+ };
}
export function prepareRawBlock(openRawBlock, contents, close, locInfo) {
@@ -78,13 +93,24 @@ export function prepareRawBlock(openRawBlock, contents, close, locInfo) {
}
locInfo = this.locInfo(locInfo);
- let program = new this.Program(contents, null, {}, locInfo);
+ let program = {
+ type: 'Program',
+ body: contents,
+ strip: {},
+ loc: locInfo
+ };
- return new this.BlockStatement(
- openRawBlock.path, openRawBlock.params, openRawBlock.hash,
- program, undefined,
- {}, {}, {},
- locInfo);
+ return {
+ type: 'BlockStatement',
+ path: openRawBlock.path,
+ params: openRawBlock.params,
+ hash: openRawBlock.hash,
+ program,
+ openStrip: {},
+ inverseStrip: {},
+ closeStrip: {},
+ loc: locInfo
+ };
}
export function prepareBlock(openBlock, program, inverseAndProgram, close, inverted, locInfo) {
@@ -115,11 +141,18 @@ export function prepareBlock(openBlock, program, inverseAndProgram, close, inver
program = inverted;
}
- return new this.BlockStatement(
- openBlock.path, openBlock.params, openBlock.hash,
- program, inverse,
- openBlock.strip, inverseStrip, close && close.strip,
- this.locInfo(locInfo));
+ return {
+ type: 'BlockStatement',
+ path: openBlock.path,
+ params: openBlock.params,
+ hash: openBlock.hash,
+ program,
+ inverse,
+ openStrip: openBlock.strip,
+ inverseStrip,
+ closeStrip: close && close.strip,
+ loc: this.locInfo(locInfo)
+ };
}
export function prepareProgram(statements, loc) {
@@ -143,7 +176,12 @@ export function prepareProgram(statements, loc) {
}
}
- return new this.Program(statements, null, {}, loc);
+ return {
+ type: 'Program',
+ body: statements,
+ strip: {},
+ loc: loc
+ };
}
diff --git a/lib/handlebars/compiler/visitor.js b/lib/handlebars/compiler/visitor.js
index ba7b376..47f86e0 100644
--- a/lib/handlebars/compiler/visitor.js
+++ b/lib/handlebars/compiler/visitor.js
@@ -1,5 +1,4 @@
import Exception from '../exception';
-import AST from './ast';
function Visitor() {
this.parents = [];
@@ -14,7 +13,7 @@ Visitor.prototype = {
let value = this.accept(node[name]);
if (this.mutating) {
// Hacky sanity check:
- if (value && (!value.type || !AST[value.type])) {
+ if (value && typeof value.type !== 'string') {
throw new Exception('Unexpected node type "' + value.type + '" found when accepting ' + name + ' on ' + node.type);
}
node[name] = value;
diff --git a/spec/ast.js b/spec/ast.js
index dc5410f..8f346d8 100644
--- a/spec/ast.js
+++ b/spec/ast.js
@@ -5,159 +5,46 @@ describe('ast', function() {
var AST = Handlebars.AST;
- var LOCATION_INFO = {
- start: {
- line: 1,
- column: 1
- },
- end: {
- line: 1,
- column: 1
- }
- };
-
- function testLocationInfoStorage(node) {
- equals(node.loc.start.line, 1);
- equals(node.loc.start.column, 1);
- equals(node.loc.end.line, 1);
- equals(node.loc.end.column, 1);
- }
-
- describe('MustacheStatement', function() {
- it('should store args', function() {
- var mustache = new AST.MustacheStatement({}, null, null, true, {}, LOCATION_INFO);
- equals(mustache.type, 'MustacheStatement');
- equals(mustache.escaped, true);
- testLocationInfoStorage(mustache);
- });
- });
describe('BlockStatement', function() {
it('should throw on mustache mismatch', function() {
shouldThrow(function() {
handlebarsEnv.parse('\n {{#foo}}{{/bar}}');
}, Handlebars.Exception, "foo doesn't match bar - 2:5");
});
-
- it('stores location info', function() {
- var mustacheNode = new AST.MustacheStatement([{ original: 'foo'}], null, null, false, {});
- var block = new AST.BlockStatement(
- mustacheNode,
- null, null,
- {body: []},
- {body: []},
- {},
- {},
- {},
- LOCATION_INFO);
- testLocationInfoStorage(block);
- });
- });
- describe('PathExpression', function() {
- it('stores location info', function() {
- var idNode = new AST.PathExpression(false, 0, [], 'foo', LOCATION_INFO);
- testLocationInfoStorage(idNode);
- });
- });
-
- describe('Hash', function() {
- it('stores location info', function() {
- var hash = new AST.Hash([], LOCATION_INFO);
- testLocationInfoStorage(hash);
- });
- });
-
- describe('ContentStatement', function() {
- it('stores location info', function() {
- var content = new AST.ContentStatement('HI', LOCATION_INFO);
- testLocationInfoStorage(content);
- });
- });
-
- describe('CommentStatement', function() {
- it('stores location info', function() {
- var comment = new AST.CommentStatement('HI', {}, LOCATION_INFO);
- testLocationInfoStorage(comment);
- });
- });
-
- describe('NumberLiteral', function() {
- it('stores location info', function() {
- var integer = new AST.NumberLiteral('6', LOCATION_INFO);
- testLocationInfoStorage(integer);
- });
- });
-
- describe('StringLiteral', function() {
- it('stores location info', function() {
- var string = new AST.StringLiteral('6', LOCATION_INFO);
- testLocationInfoStorage(string);
- });
- });
-
- describe('BooleanLiteral', function() {
- it('stores location info', function() {
- var bool = new AST.BooleanLiteral('true', LOCATION_INFO);
- testLocationInfoStorage(bool);
- });
- });
-
- describe('PartialStatement', function() {
- it('provides default params', function() {
- var pn = new AST.PartialStatement('so_partial', undefined, {}, {}, LOCATION_INFO);
- equals(pn.params.length, 0);
- });
- it('stores location info', function() {
- var pn = new AST.PartialStatement('so_partial', [], {}, {}, LOCATION_INFO);
- testLocationInfoStorage(pn);
- });
- });
-
- describe('Program', function() {
- it('storing location info', function() {
- var pn = new AST.Program([], null, {}, LOCATION_INFO);
- testLocationInfoStorage(pn);
- });
- });
-
- describe('SubExpression', function() {
- it('provides default params', function() {
- var pn = new AST.SubExpression('path', undefined, {}, LOCATION_INFO);
- equals(pn.params.length, 0);
- });
});
describe('helpers', function() {
describe('#helperExpression', function() {
it('should handle mustache statements', function() {
- equals(AST.helpers.helperExpression(new AST.MustacheStatement('foo', [], undefined, false, {}, LOCATION_INFO)), false);
- equals(AST.helpers.helperExpression(new AST.MustacheStatement('foo', [1], undefined, false, {}, LOCATION_INFO)), true);
- equals(AST.helpers.helperExpression(new AST.MustacheStatement('foo', [], {}, false, {}, LOCATION_INFO)), true);
+ equals(AST.helpers.helperExpression({type: 'MustacheStatement', params: [], hash: undefined}), false);
+ equals(AST.helpers.helperExpression({type: 'MustacheStatement', params: [1], hash: undefined}), true);
+ equals(AST.helpers.helperExpression({type: 'MustacheStatement', params: [], hash: {}}), true);
});
it('should handle block statements', function() {
- equals(AST.helpers.helperExpression(new AST.BlockStatement('foo', [], undefined, false, {}, LOCATION_INFO)), false);
- equals(AST.helpers.helperExpression(new AST.BlockStatement('foo', [1], undefined, false, {}, LOCATION_INFO)), true);
- equals(AST.helpers.helperExpression(new AST.BlockStatement('foo', [], {}, false, {}, LOCATION_INFO)), true);
+ equals(AST.helpers.helperExpression({type: 'BlockStatement', params: [], hash: undefined}), false);
+ equals(AST.helpers.helperExpression({type: 'BlockStatement', params: [1], hash: undefined}), true);
+ equals(AST.helpers.helperExpression({type: 'BlockStatement', params: [], hash: {}}), true);
});
it('should handle subexpressions', function() {
- equals(AST.helpers.helperExpression(new AST.SubExpression()), true);
+ equals(AST.helpers.helperExpression({type: 'SubExpression'}), true);
});
it('should work with non-helper nodes', function() {
- equals(AST.helpers.helperExpression(new AST.Program([], [], {}, LOCATION_INFO)), false);
+ equals(AST.helpers.helperExpression({type: 'Program'}), false);
- equals(AST.helpers.helperExpression(new AST.PartialStatement()), false);
- equals(AST.helpers.helperExpression(new AST.ContentStatement('a', LOCATION_INFO)), false);
- equals(AST.helpers.helperExpression(new AST.CommentStatement('a', {}, LOCATION_INFO)), false);
+ equals(AST.helpers.helperExpression({type: 'PartialStatement'}), false);
+ equals(AST.helpers.helperExpression({type: 'ContentStatement'}), false);
+ equals(AST.helpers.helperExpression({type: 'CommentStatement'}), false);
- equals(AST.helpers.helperExpression(new AST.PathExpression(false, 0, ['a'], 'a', LOCATION_INFO)), false);
+ equals(AST.helpers.helperExpression({type: 'PathExpression'}), false);
- equals(AST.helpers.helperExpression(new AST.StringLiteral('a', LOCATION_INFO)), false);
- equals(AST.helpers.helperExpression(new AST.NumberLiteral(1, LOCATION_INFO)), false);
- equals(AST.helpers.helperExpression(new AST.BooleanLiteral(true, LOCATION_INFO)), false);
- equals(AST.helpers.helperExpression(new AST.UndefinedLiteral(LOCATION_INFO)), false);
- equals(AST.helpers.helperExpression(new AST.NullLiteral(LOCATION_INFO)), false);
+ equals(AST.helpers.helperExpression({type: 'StringLiteral'}), false);
+ equals(AST.helpers.helperExpression({type: 'NumberLiteral'}), false);
+ equals(AST.helpers.helperExpression({type: 'BooleanLiteral'}), false);
+ equals(AST.helpers.helperExpression({type: 'UndefinedLiteral'}), false);
+ equals(AST.helpers.helperExpression({type: 'NullLiteral'}), false);
- equals(AST.helpers.helperExpression(new AST.Hash([], LOCATION_INFO)), false);
- equals(AST.helpers.helperExpression(new AST.HashPair('foo', 'bar', LOCATION_INFO)), false);
+ equals(AST.helpers.helperExpression({type: 'Hash'}), false);
+ equals(AST.helpers.helperExpression({type: 'HashPair'}), false);
});
});
});
diff --git a/spec/compiler.js b/spec/compiler.js
index fe4b63a..be1fb00 100644
--- a/spec/compiler.js
+++ b/spec/compiler.js
@@ -39,7 +39,10 @@ describe('compiler', function() {
});
it('can utilize AST instance', function() {
- equal(Handlebars.compile(new Handlebars.AST.Program([ new Handlebars.AST.ContentStatement('Hello')], null, {}))(), 'Hello');
+ equal(Handlebars.compile({
+ type: 'Program',
+ body: [ {type: 'ContentStatement', value: 'Hello'}]
+ })(), 'Hello');
});
it('can pass through an empty string', function() {
@@ -58,7 +61,10 @@ describe('compiler', function() {
});
it('can utilize AST instance', function() {
- equal(/return "Hello"/.test(Handlebars.precompile(new Handlebars.AST.Program([ new Handlebars.AST.ContentStatement('Hello')]), null, {})), true);
+ equal(/return "Hello"/.test(Handlebars.precompile({
+ type: 'Program',
+ body: [ {type: 'ContentStatement', value: 'Hello'}]
+ })), true);
});
it('can pass through an empty string', function() {
diff --git a/spec/parser.js b/spec/parser.js
index 424e2d1..82c32d0 100644
--- a/spec/parser.js
+++ b/spec/parser.js
@@ -228,7 +228,10 @@ describe('parser', function() {
describe('externally compiled AST', function() {
it('can pass through an already-compiled AST', function() {
- equals(astFor(new Handlebars.AST.Program([new Handlebars.AST.ContentStatement('Hello')], null)), 'CONTENT[ \'Hello\' ]\n');
+ equals(astFor({
+ type: 'Program',
+ body: [ {type: 'ContentStatement', value: 'Hello'}]
+ }), 'CONTENT[ \'Hello\' ]\n');
});
});
diff --git a/spec/visitor.js b/spec/visitor.js
index 1f50d79..23113cf 100644
--- a/spec/visitor.js
+++ b/spec/visitor.js
@@ -49,7 +49,7 @@ describe('Visitor', function() {
visitor.mutating = true;
visitor.StringLiteral = function(string) {
- return new Handlebars.AST.NumberLiteral(42, string.locInfo);
+ return {type: 'NumberLiteral', value: 42, loc: string.loc};
};
var ast = Handlebars.parse('{{foo foo="foo"}}');
@@ -109,7 +109,7 @@ describe('Visitor', function() {
visitor.mutating = true;
visitor.StringLiteral = function(string) {
- return new Handlebars.AST.NumberLiteral(42, string.locInfo);
+ return {type: 'NumberLiteral', value: 42, loc: string.locInfo};
};
var ast = Handlebars.parse('{{foo "foo"}}');
diff --git a/src/handlebars.yy b/src/handlebars.yy
index ecc79af..a05b477 100644
--- a/src/handlebars.yy
+++ b/src/handlebars.yy
@@ -18,12 +18,24 @@ statement
| rawBlock -> $1
| partial -> $1
| content -> $1
- | COMMENT -> new yy.CommentStatement(yy.stripComment($1), yy.stripFlags($1, $1), yy.locInfo(@$))
- ;
+ | COMMENT {
+ $$ = {
+ type: 'CommentStatement',
+ value: yy.stripComment($1),
+ strip: yy.stripFlags($1, $1),
+ loc: yy.locInfo(@$)
+ };
+ };
content
- : CONTENT -> new yy.ContentStatement($1, yy.locInfo(@$))
- ;
+ : CONTENT {
+ $$ = {
+ type: 'ContentStatement',
+ original: $1,
+ value: $1,
+ loc: yy.locInfo(@$)
+ };
+ };
rawBlock
: openRawBlock content+ END_RAW_BLOCK -> yy.prepareRawBlock($1, $2, $3, @$)
@@ -77,7 +89,17 @@ mustache
;
partial
- : OPEN_PARTIAL partialName param* hash? CLOSE -> new yy.PartialStatement($2, $3, $4, yy.stripFlags($1, $5), yy.locInfo(@$))
+ : OPEN_PARTIAL partialName param* hash? CLOSE {
+ $$ = {
+ type: 'PartialStatement',
+ name: $2,
+ params: $3,
+ hash: $4,
+ indent: '',
+ strip: yy.stripFlags($1, $5),
+ loc: yy.locInfo(@$)
+ };
+ }
;
param
@@ -86,15 +108,22 @@ param
;
sexpr
- : OPEN_SEXPR helperName param* hash? CLOSE_SEXPR -> new yy.SubExpression($2, $3, $4, yy.locInfo(@$))
- ;
+ : OPEN_SEXPR helperName param* hash? CLOSE_SEXPR {
+ $$ = {
+ type: 'SubExpression',
+ path: $2,
+ params: $3,
+ hash: $4,
+ loc: yy.locInfo(@$)
+ };
+ };
hash
- : hashSegment+ -> new yy.Hash($1, yy.locInfo(@$))
+ : hashSegment+ -> {type: 'Hash', pairs: $1, loc: yy.locInfo(@$)}
;
hashSegment
- : ID EQUALS param -> new yy.HashPair(yy.id($1), $3, yy.locInfo(@$))
+ : ID EQUALS param -> {type: 'HashPair', key: yy.id($1), value: $3, loc: yy.locInfo(@$)}
;
blockParams
@@ -104,11 +133,11 @@ blockParams
helperName
: path -> $1
| dataName -> $1
- | STRING -> new yy.StringLiteral($1, yy.locInfo(@$))
- | NUMBER -> new yy.NumberLiteral($1, yy.locInfo(@$))
- | BOOLEAN -> new yy.BooleanLiteral($1, yy.locInfo(@$))
- | UNDEFINED -> new yy.UndefinedLiteral(yy.locInfo(@$))
- | NULL -> new yy.NullLiteral(yy.locInfo(@$))
+ | STRING -> {type: 'StringLiteral', value: $1, original: $1, loc: yy.locInfo(@$)}
+ | NUMBER -> {type: 'NumberLiteral', value: Number($1), original: Number($1), loc: yy.locInfo(@$)}
+ | BOOLEAN -> {type: 'BooleanLiteral', value: $1 === 'true', original: $1 === 'true', loc: yy.locInfo(@$)}
+ | UNDEFINED -> {type: 'UndefinedLiteral', original: undefined, value: undefined, loc: yy.locInfo(@$)}
+ | NULL -> {type: 'NullLiteral', original: null, value: null, loc: yy.locInfo(@$)}
;
partialName