Permalink
Browse files

Merge pull request #43 from paulcuth/dev

v0.3.2
  • Loading branch information...
paulcuth committed Aug 9, 2016
2 parents 5d6cab3 + ada4523 commit f4e5253a1cb0c27999241295b948746e99e3aaef
View
@@ -1,7 +1,7 @@
{
"name": "starlight",
"description": "A Lua -> ES6 transpiler",
"version": "0.3.1",
"version": "0.3.2",
"author": {
"name": "Paul Cuthbertson"
},
View
@@ -72,6 +72,45 @@
}
obj[key] = luaToJS(val);
},
__pairs: function (t) {
var keys = Object.keys(obj);
for (i = 0, l = keys.length; i < l; i++) {
if (!isNaN(+keys[i])) {
keys[i]++;
}
}
var iterator = function (t, key) {
if (key === undefined) {
key = keys[0];
} else {
key = keys[keys.indexOf(key) + 1];
}
if (key === undefined) {
return;
} else if (isNaN(+key)) {
return [key, obj[key]];
} else {
return [key, obj[key - 1]];
}
};
return [iterator, t];
},
__ipairs: function (t) {
var iterator = function (t, key) {
if (!(obj instanceof Array)) {
return;
}
if (key > obj.length) {
return;
}
return [key + 1, obj[key]];
};
return [iterator, t, 0];
}
});
@@ -110,7 +149,7 @@
for (i in strValues) {
if (strValues.hasOwnProperty(i)) {
result[i] = (val[i] instanceof T)? luaToJS(val[i]) : val[i];
result[i] = (strValues[i] instanceof T)? luaToJS(strValues[i]) : strValues[i];
}
}
@@ -35,13 +35,12 @@ const GENERATORS = {
AssignmentStatement(node, scope) {
let assignments = node.variables.map((variable, index) => {
let name;
name = scoped(variable, scope);
const name = scoped(variable, scope);
if (name instanceof MemExpr) {
return name.set(`__star_tmp[${index}]`);
} else {
let [match, args] = [].concat(name.match(/^\$get\((.*)\)$/));
const [match, args] = [].concat(name.match(/^\$get\((.*)\)$/));
if (!match) {
throw new Error('Unhandled');
}
@@ -50,15 +49,8 @@ const GENERATORS = {
}
}).join(';\n');
let values = node.init.map((init, index) => {
let value = scoped(init, scope);
if (isCallExpression(init)) {
return `...${value}`;
}
return value;
});
return `__star_tmp = [${values.join(', ')}];${assignments}`;
const values = parseExpressionList(node.init, scope).join(', ');
return `__star_tmp = [${values}];${assignments}`;
},
@@ -101,11 +93,7 @@ const GENERATORS = {
CallExpression(node, scope) {
let functionName = scoped(node.base, scope);
let args = node.arguments.map(arg => {
let path = scoped(arg, scope);
let prefix = isCallExpression(arg) ? '...' : '';
return `${prefix}${path}`;
});
const args = parseExpressionList(node.arguments, scope);
if (isCallExpression(node.base)) {
args.unshift(`${functionName}[0]`);
@@ -164,19 +152,17 @@ const GENERATORS = {
ForGenericStatement(node, outerScope) {
console.assert(node.iterators.length === 1, 'Only one iterator is assumed. Need to implement more!');
let { scope, scopeDef } = extendScope(outerScope);
let iterator = scoped(node.iterators[0], outerScope);
let body = this.Chunk(node, scope);
const { scope, scopeDef } = extendScope(outerScope);
const iterators = parseExpressionList(node.iterators, outerScope).join(', ');
const body = this.Chunk(node, scope);
let variables = node.variables.map((variable, index) => {
let name = generate(variable, scope);
const variables = node.variables.map((variable, index) => {
const name = generate(variable, scope);
return `$setLocal($, '${name}', __star_tmp[${index}])`;
}).join(';\n');
let defs = scopeDef.split(', ');
return `${defs[0]};\n[$${scope}._iterator, $${scope}._table, $${scope}._next] = ${iterator};\nwhile((__star_tmp = __star_call($${scope}._iterator, $${scope}._table, $${scope}._next)),__star_tmp[0] !== undefined) {\nlet ${defs[1]}\$${scope}._next = __star_tmp[0]\n${variables}\n${body}\n}`;
const defs = scopeDef.split(', ');
return `${defs[0]};\n[$${scope}._iterator, $${scope}._table, $${scope}._next] = [${iterators}];\nwhile((__star_tmp = __star_call($${scope}._iterator, $${scope}._table, $${scope}._next)),__star_tmp[0] !== undefined) {\nlet ${defs[1]}\$${scope}._next = __star_tmp[0]\n${variables}\n${body}\n}`;
},
@@ -262,26 +248,13 @@ const GENERATORS = {
LocalStatement(node, scope) {
let canOptimise = true;
let assignments = node.variables.map((variable, index) => {
let name = generate(variable, scope);
return `$setLocal($, '${name}', __star_tmp[${index}])`;
}).join(';\n');
let values = node.init.map((init, index) => {
let value = scoped(init, scope);
if (isCallExpression(init)) {
canOptimise = false;
value = `...${value}`;
}
return value;
});
// if (canOptimise) {
// return assignments.replace(/__star_tmp\[(\d+)\]/g, (match, index) => values[index]);
// } else {
return `__star_tmp = [${values.join(', ')}];${assignments}`;
// }
const values = parseExpressionList(node.init, scope).join(', ');
return `__star_tmp = [${values}];${assignments}`;
},
@@ -343,10 +316,7 @@ const GENERATORS = {
ReturnStatement(node, scope) {
let args = node.arguments.map(arg => {
let result = scoped(arg, scope);
return isCallExpression(arg) ? `...${result}` : result;
}).join(', ');
const args = parseExpressionList(node.arguments, scope).join(', ');
return `return [${args}];`;
},
@@ -358,10 +328,11 @@ const GENERATORS = {
StringLiteral(node) {
const raw = node.raw.replace(/\\(\d+)/g, (_, oct) => `\\x0${parseInt(oct, 8).toString(16)}`);
let raw = node.raw;
if (/^\[\[[^]*]$/m.test(raw)) {
return `\`${raw.substr(2, raw.length - 4)}\``;
return `\`${raw.substr(2, raw.length - 4).replace(/\\/g, '\\\\')}\``;
} else {
raw = raw.replace(/([^\\])\\(\d{1,3})/g, (_, pre, dec) => `${pre}\\u${('000' + parseInt(dec, 10).toString(16)).substr(-4)}`);
return raw;
}
},
@@ -383,7 +354,14 @@ const GENERATORS = {
TableConstructorExpression(node, scope) {
let fields = node.fields.map(field => generate(field, scope)).join(';\n');
let fields = node.fields.map((field, index, arr) => {
if (field.type == 'TableValue') {
const isLastItem = index === arr.length - 1;
return this.TableValue(field, scope, isLastItem);
}
return generate(field, scope);
}).join(';\n');
return `new __star_T(t => {${fields}})`;
},
@@ -402,10 +380,12 @@ const GENERATORS = {
},
TableValue(node, scope) {
TableValue(node, scope, isLastItem) {
let value = scoped(node.value, scope);
let operator = isCallExpression(node.value) ? '...' : '';
return `Tins(t, ${operator}${value})`;
if (isCallExpression(node.value)) {
value = isLastItem ? `...${value}` : `${value}[0]`;
}
return `Tins(t, ${value})`;
},
@@ -437,11 +417,26 @@ const GENERATORS = {
let body = this.Chunk(node, scope);
return `while(${condition}) {\n${scopeDef}\n${body}\n}`;
}
}
},
};
function parseExpressionList(expressionNodeArray, scope) {
return expressionNodeArray.map((node, index, arr) => {
let value = scoped(node, scope);
if (isCallExpression(node)) {
if (index == arr.length - 1) {
return `...${value}`;
}
return `${value}[0]`;
}
return value;
});
}
function extendScope(outerIndex) {
let scope = scopeIndex++;
let scopeDef = `let $${scope} = $${outerIndex}.extend(), $ = $${scope};`;
@@ -87,7 +87,9 @@ export function getmetatable(table) {
export function ipairs(t) {
t = coerceArgToTable(t, 'ipairs', 1);
return [ipairsIterator, t, 0];
const mt = getmetatable(t);
const mm = mt && mt.get('__ipairs');
return mm ? mm(t).slice(0, 3) : [ipairsIterator, t, 0];
}
@@ -185,7 +187,9 @@ export function next(table, index) {
export function pairs(table) {
table = coerceArgToTable(table, 'pairs', 1);
return [next, table];
const mt = getmetatable(table);
const mm = mt && mt.get('__pairs');
return mm ? mm(table).slice(0, 3) : [next, table];
}
@@ -98,7 +98,33 @@ end
assertTrue (a == '[1==1]', 'Break should exit generic for loop')
function iter(t, i)
if i < 5 then
return i + 1, i
else
return nil
end
end
a = ''
for key, val in iter, {}, 2 do
a = a..'['..tostring(key)..'=='..tostring(val)..']'
end
assertTrue (a == '[3==2][4==3][5==4]', 'Generic for loop should accept an expression list')
function iter(t, i)
i = i + 1
v = t[i]
if v then
return i, v, v * 2
end
end
a = ''
for x,y,z in iter, {4,5,6}, 0 do
a = a..'['..tostring(x)..','..tostring(y)..','..tostring(z)..']'
end
assertTrue (a == '[1,4,8][2,5,10][3,6,12]', 'Generic for loop should pass all values returned from iterator to the variables in the loop')
a = ''
b = 1
@@ -238,4 +264,3 @@ end
testReturn()
assertEqual (a, '123', 'Do block containing return should return from parent function')
View
@@ -125,5 +125,38 @@ local z = y()
assertTrue (z == 'inner', 'Local functions should be locally scoped')
function oneTwo()
return 1, 2
end
function testReturnValues()
return oneTwo(), 10
end
local a, b, c = testReturnValues()
assertTrue (a == 1, 'return should return the first item returned from a function call')
assertTrue (b == 10, 'return should only return the first item from a function call when not last item in an expression list')
assertTrue (c == nil, 'return should know when to stop')
function testReturnValues2()
return 10, oneTwo()
end
local a, b, c = testReturnValues2()
assertTrue (a == 10, 'return should return the first item in an expression list')
assertTrue (b == 1, 'return should return the first item from a function call')
assertTrue (c == 2, 'return should return all items returned from a function call if at end of expression list')
function testArgs1(a, b, c)
assertTrue (a == 1, 'Function call in argument list should pass return value as argument')
assertTrue (b == 10, 'Function call in middle of argument list should only pass one argument')
assertTrue (c == nil, 'Arguments should stop at the end of argument list')
end
testArgs1(oneTwo(), 10)
function testArgs2(a, b, c)
assertTrue (a == 10, 'Arguments should be passed in order')
assertTrue (b == 1, 'Function call should pass return values')
assertTrue (c == 2, 'Function call at end of argument list should pass all return values')
end
testArgs2(10, oneTwo())
Oops, something went wrong.

0 comments on commit f4e5253

Please sign in to comment.