Skip to content

Commit c880ef6

Browse files
tomblindPerryvw
authored andcommitted
Custom Iterators (#316)
* custom iterator support * Updates from feedback: - luaLibFeatureSet returned to being a Set - added lua lib dependency table - moved lua lib stuff to its own file - fixed logic for importing Symbol lib so it isn't accidentally imported when it shouldn't be - reworked property name transpiling to properly handle numeric/string literals and computed names in all places - updated Map and Set to take a generic Iterable in their constructors * deferred identifier check in computeEnumMembers and using StringLiteralLike union
1 parent 3afdd09 commit c880ef6

File tree

16 files changed

+864
-166
lines changed

16 files changed

+864
-166
lines changed

build_lualib.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as fs from "fs";
22
import * as glob from "glob";
33
import {compile} from "./src/Compiler";
4+
import {LuaLib as luaLib, LuaLibFeature} from "./src/LuaLib";
45

56
const bundlePath = "./dist/lualib/lualib_bundle.lua";
67

@@ -15,14 +16,11 @@ compile([
1516
"--rootDir",
1617
"./src/lualib",
1718
...glob.sync("./src/lualib/*.ts"),
18-
]);
19+
]);
1920

2021
if (fs.existsSync(bundlePath)) {
21-
fs.unlinkSync(bundlePath);
22+
fs.unlinkSync(bundlePath);
2223
}
2324

24-
let bundle = "";
25-
26-
glob.sync("./dist/lualib/*.lua").forEach(fileName => bundle += fs.readFileSync(fileName));
27-
25+
const bundle = luaLib.loadFeatures(Object.keys(LuaLibFeature).map(lib => LuaLibFeature[lib]));
2826
fs.writeFileSync(bundlePath, bundle);

src/Decorator.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export class Decorator {
1414
case "phantom": return DecoratorKind.Phantom;
1515
case "tuplereturn": return DecoratorKind.TupleReturn;
1616
case "noclassor": return DecoratorKind.NoClassOr;
17+
case "luaiterator": return DecoratorKind.LuaIterator;
1718
}
1819

1920
return undefined;
@@ -37,4 +38,5 @@ export enum DecoratorKind {
3738
Phantom = "Phantom",
3839
TupleReturn = "TupleReturn",
3940
NoClassOr = "NoClassOr",
41+
LuaIterator = "LuaIterator",
4042
}

src/Errors.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,4 +109,11 @@ export class TSTLErrors {
109109
node);
110110
}
111111
}
112+
113+
public static UnsupportedNonDestructuringLuaIterator = (node: ts.Node) => {
114+
return new TranspileError("Unsupported use of lua iterator with TupleReturn decorator in for...of statement. "
115+
+ "You must use a destructuring statement to catch results from a lua iterator with "
116+
+ "the TupleReturn decorator.",
117+
node);
118+
}
112119
}

src/LuaLib.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import * as fs from "fs";
2+
import * as path from "path";
3+
4+
export enum LuaLibFeature {
5+
ArrayConcat = "ArrayConcat",
6+
ArrayEvery = "ArrayEvery",
7+
ArrayFilter = "ArrayFilter",
8+
ArrayForEach = "ArrayForEach",
9+
ArrayIndexOf = "ArrayIndexOf",
10+
ArrayMap = "ArrayMap",
11+
ArrayPush = "ArrayPush",
12+
ArrayReverse = "ArrayReverse",
13+
ArrayShift = "ArrayShift",
14+
ArrayUnshift = "ArrayUnshift",
15+
ArraySort = "ArraySort",
16+
ArraySlice = "ArraySlice",
17+
ArraySome = "ArraySome",
18+
ArraySplice = "ArraySplice",
19+
FunctionApply = "FunctionApply",
20+
FunctionBind = "FunctionBind",
21+
FunctionCall = "FunctionCall",
22+
InstanceOf = "InstanceOf",
23+
Iterator = "Iterator",
24+
Map = "Map",
25+
Set = "Set",
26+
StringReplace = "StringReplace",
27+
StringSplit = "StringSplit",
28+
Symbol = "Symbol",
29+
Ternary = "Ternary",
30+
}
31+
32+
const luaLibDependencies: { [lib in LuaLibFeature]?: LuaLibFeature[] } = {
33+
Iterator: [LuaLibFeature.Symbol],
34+
Map: [LuaLibFeature.InstanceOf, LuaLibFeature.Iterator, LuaLibFeature.Symbol],
35+
Set: [LuaLibFeature.InstanceOf, LuaLibFeature.Iterator, LuaLibFeature.Symbol],
36+
};
37+
38+
export class LuaLib {
39+
public static loadFeatures(features: Iterable<LuaLibFeature>): string {
40+
let result = "";
41+
42+
const loadedFeatures = new Set<LuaLibFeature>();
43+
44+
function load(feature: LuaLibFeature): void {
45+
if (!loadedFeatures.has(feature)) {
46+
loadedFeatures.add(feature);
47+
if (luaLibDependencies[feature]) {
48+
luaLibDependencies[feature].forEach(load);
49+
}
50+
const featureFile = path.resolve(__dirname, `../dist/lualib/${feature}.lua`);
51+
result += fs.readFileSync(featureFile).toString() + "\n";
52+
}
53+
}
54+
55+
for (const feature of features) {
56+
load(feature);
57+
}
58+
return result;
59+
}
60+
}

src/TSHelper.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,16 @@ export class TSHelper {
138138
return this.forTypeOrAnySupertype(type, checker, t => this.isExplicitArrayType(t, checker));
139139
}
140140

141+
public static isLuaIteratorCall(node: ts.Node, checker: ts.TypeChecker): boolean {
142+
if (ts.isCallExpression(node) && node.parent && ts.isForOfStatement(node.parent)) {
143+
const type = checker.getTypeAtLocation(node.expression);
144+
return this.getCustomDecorators(type, checker)
145+
.has(DecoratorKind.LuaIterator);
146+
} else {
147+
return false;
148+
}
149+
}
150+
141151
public static isTupleReturnCall(node: ts.Node, checker: ts.TypeChecker): boolean {
142152
if (ts.isCallExpression(node)) {
143153
const type = checker.getTypeAtLocation(node.expression);
@@ -157,7 +167,9 @@ export class TSHelper {
157167
checker.getTypeAtLocation(declaration),
158168
checker
159169
);
160-
return decorators.has(DecoratorKind.TupleReturn);
170+
return decorators.has(DecoratorKind.TupleReturn)
171+
// Lua iterators are not 'true' tupleReturn functions as they actually return a function
172+
&& !decorators.has(DecoratorKind.LuaIterator);
161173
} else {
162174
return false;
163175
}

0 commit comments

Comments
 (0)