Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lua 5.4 support #101

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 96 additions & 8 deletions luaparse.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,16 +106,32 @@
highMask | 0x80 | ((codepoint >> 6) & 0x3f),
highMask | 0x80 | ( codepoint & 0x3f)
);
} else /* istanbul ignore else */ if (codepoint < 0x110000) {
} else if (codepoint < 0x200000) {
return String.fromCharCode(
highMask | 0xf0 | (codepoint >> 18) ,
highMask | 0x80 | ((codepoint >> 12) & 0x3f),
highMask | 0x80 | ((codepoint >> 6) & 0x3f),
highMask | 0x80 | ( codepoint & 0x3f)
);
} else if (codepoint < 0x4000000) {
return String.fromCharCode(
highMask | 0xf8 | (codepoint >> 24) ,
highMask | 0x80 | ((codepoint >> 18) & 0x3f),
highMask | 0x80 | ((codepoint >> 12) & 0x3f),
highMask | 0x80 | ((codepoint >> 6) & 0x3f),
highMask | 0x80 | ( codepoint & 0x3f)
);
} else /* istanbul ignore else */ if (codepoint <= 0x7fffffff) {
return String.fromCharCode(
highMask | 0xfc | (codepoint >> 30) ,
highMask | 0x80 | ((codepoint >> 24) & 0x3f),
highMask | 0x80 | ((codepoint >> 18) & 0x3f),
highMask | 0x80 | ((codepoint >> 12) & 0x3f),
highMask | 0x80 | ((codepoint >> 6) & 0x3f),
highMask | 0x80 | ( codepoint & 0x3f)
);
} else {
// TODO: Lua 5.4 allows up to six-byte sequences, as in UTF-8:1993
return null;
throw new Error('Should not happen');
}
}

Expand Down Expand Up @@ -218,6 +234,7 @@
, gotoJumpInLocalScope: '<goto %1> jumps into the scope of local \'%2\''
, cannotUseVararg: 'cannot use \'...\' outside a vararg function near \'%1\''
, invalidCodeUnit: 'code unit U+%1 is not allowed in the current encoding mode'
, unknownAttribute: 'unknown attribute \'%1\''
};

// ### Abstract Syntax Tree
Expand Down Expand Up @@ -363,13 +380,28 @@
};
}

, attribute: function(name) {
return {
type: 'Attribute'
, name: name
};
}

, identifier: function(name) {
return {
type: 'Identifier'
, name: name
};
}

, identifierWithAttribute: function(name, attribute) {
return {
type: 'IdentifierWithAttribute'
, name: name
, attribute: attribute
};
}

, literal: function(type, value, raw) {
type = (type === StringLiteral) ? 'StringLiteral'
: (type === NumericLiteral) ? 'NumericLiteral'
Expand Down Expand Up @@ -1144,7 +1176,7 @@

while (isHexDigit(input.charCodeAt(index))) {
++index;
if (index - escStart > 6)
if (index - escStart > (features.relaxedUTF8 ? 8 : 6))
raise(null, errors.tooLargeCodepoint, '\\' + input.slice(sequenceStart, index));
}

Expand All @@ -1159,7 +1191,7 @@
var codepoint = parseInt(input.slice(escStart, index - 1) || '0', 16);
var frag = '\\' + input.slice(sequenceStart, index);

if (codepoint > 0x10ffff) {
if (codepoint > (features.relaxedUTF8 ? 0x7fffffff : 0x10ffff)) {
raise(null, errors.tooLargeCodepoint, frag);
}

Expand Down Expand Up @@ -1596,6 +1628,17 @@
return false;
};

FullFlowContext.prototype.findLabel = function (name) {
var i = this.scopes.length;
while (i --> 0) {
if (Object.prototype.hasOwnProperty.call(this.scopes[i].labels, name))
return this.scopes[i].labels[name];
if (!features.noLabelShadowing)
return null;
}
return null;
};

FullFlowContext.prototype.pushScope = function (isLoop) {
var scope = {
labels: {},
Expand Down Expand Up @@ -1637,9 +1680,10 @@

FullFlowContext.prototype.addLabel = function (name, token) {
var scope = this.currentScope();
var definedLabel = this.findLabel(name);

if (Object.prototype.hasOwnProperty.call(scope.labels, name)) {
raise(token, errors.labelAlreadyDefined, name, scope.labels[name].line);
if (definedLabel !== null) {
raise(token, errors.labelAlreadyDefined, name, definedLabel.line);
} else {
var newGotos = [];

Expand Down Expand Up @@ -2062,16 +2106,31 @@

function parseLocalStatement(flowContext) {
var name
, attribute
, marker
, declToken = previousToken;

if (Identifier === token.type) {
var variables = []
, init = [];

do {
if (trackLocations) marker = createLocationMarker();

name = parseIdentifier();

variables.push(name);
attribute = null;
if (features.attributes) {
attribute = parseAttribute();
}

if (attribute !== null) {
if (trackLocations) pushLocation(marker);
variables.push(finishNode(ast.identifierWithAttribute(name, attribute)));
} else {
variables.push(name);
}

flowContext.addLocal(name.name, declToken);
} while (consume(','));

Expand Down Expand Up @@ -2210,6 +2269,21 @@
return finishNode(ast.identifier(identifier));
}

function parseAttribute() {
markLocation();
if (consume('<')) {
if (Identifier !== token.type) raiseUnexpectedToken('<name>', token);
var identifier = token.value;
if (!features.attributes[identifier])
raise(token, errors.unknownAttribute, identifier);
next();
expect('>');
return finishNode(ast.attribute(identifier));
}
if (trackLocations) locations.pop();
return null;
}

// Parse the functions parameters and body block. The name should already
// have been parsed and passed to this declaration function. By separating
// this we allow for anonymous functions in expressions.
Expand Down Expand Up @@ -2647,6 +2721,20 @@
integerDivision: true,
relaxedBreak: true
},
'5.4': {
labels: true,
emptyStatement: true,
hexEscapes: true,
skipWhitespaceEscape: true,
strictEscapes: true,
unicodeEscapes: true,
bitwiseOperators: true,
integerDivision: true,
relaxedBreak: true,
noLabelShadowing: true,
attributes: { 'const': true, 'close': true },
relaxedUTF8: true
},
'LuaJIT': {
// XXX: LuaJIT language features may depend on compilation options; may need to
// rethink how to handle this. Specifically, there is a LUAJIT_ENABLE_LUA52COMPAT
Expand Down
27 changes: 22 additions & 5 deletions test/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,12 @@
visitKey('base');
visitKey('argument');
break;
case 'IdentifierWithAttribute':
visitKey('name');
visitKey('attribute');
break;
case 'Identifier':
case 'Attribute':
case 'NumericLiteral':
case 'BooleanLiteral':
case 'StringLiteral':
Expand Down Expand Up @@ -515,9 +520,19 @@
, [ '"\\u{1f4a9}"'
, '"\\u{000001f4a9}"'
, '"\\xf0\\x9f\\x92\\xa9"'
, '"\ud83d\udca9"'
, "'\ud83d\udca9'"
, '[[\ud83d\udca9]]'
, '[[\xf0\x9f\x92\xa9]]'
]
, [ '"\\u{db80}"'
, '"\\xed\\xae\\x80"'
, '[[\xed\xae\x80]]'
]
, [ '"\\u{1ffffff}"'
, '"\\xf9\\xbf\\xbf\\xbf\\xbf"'
, '[[\xf9\xbf\xbf\xbf\xbf]]'
]
, [ '"\\u{7fffffff}"'
, '"\\xfd\\xbf\\xbf\\xbf\\xbf\\xbf"'
, '[[\xfd\xbf\xbf\xbf\xbf\xbf]]'
]
, [ '"\\\\a"'
, '[==[\\a]==]'
Expand Down Expand Up @@ -546,11 +561,13 @@

var list = testcases[i];
var left = luaparse.parse('return ' + list[0],
{ "luaVersion": "5.3" }).body[0].arguments[0];
{ "luaVersion": "5.4",
"encodingMode": "pseudo-latin1" }).body[0].arguments[0];

for (var j = 1; j < list.length; ++j) {
var right = luaparse.parse('return ' + list[j],
{ "luaVersion": "5.3" }).body[0].arguments[0];
{ "luaVersion": "5.4",
"encodingMode": "pseudo-latin1" }).body[0].arguments[0];

this.equal(left.value, right.value, symbolicControlChars(left.raw) + ' == ' + symbolicControlChars(right.raw));
left = right;
Expand Down
2 changes: 2 additions & 0 deletions test/scaffolding/for
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,5 @@ for a = p, q do do return end end
// { "luaVersion": "5.2" }
for a in b do break break end
for a = p, q do break break end
// { "luaVersion": "5.4" }
for a <const> in b do end -- FAIL
3 changes: 3 additions & 0 deletions test/scaffolding/labels
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ do goto x local a ::x:: ::y:: ::z:: end
do do ::x:: end do goto x end end -- FAIL
do do goto x end do ::x:: end end -- FAIL
do do goto x end do end ::x:: end
::x:: do ::x:: end
// { "luaVersion": "5.4" }
::x:: do ::x:: end -- FAIL
// { "luaVersion": "LuaJIT" }
::foo::
goto "foo"
Expand Down
7 changes: 7 additions & 0 deletions test/scaffolding/local
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,10 @@ local a = { b = { z = 1 } }
local Дождь = {} -- FAIL
// { "extendedIdentifiers": true }
local Дождь = {}
// { "luaVersion": "5.4" }
local x <close> = {}
local x <const> = {}
local x <0> = {} -- FAIL
local x <+> = {} -- FAIL
local x <xyzzy> = {} -- FAIL
local x = {}
11 changes: 11 additions & 0 deletions test/spec/for.js
Original file line number Diff line number Diff line change
Expand Up @@ -3878,6 +3878,17 @@
"scope": true,
"luaVersion": "5.2"
}
},
{
"source": "for a <const> in b do end",
"result": "[1:6] 'in' expected near '<'",
"options": {
"comments": true,
"locations": true,
"ranges": true,
"scope": true,
"luaVersion": "5.4"
}
}
];
}));
Loading