X Tutup
Skip to content

Commit 1a1e369

Browse files
authored
Generalize class accessors transform (#774)
* Generalize class accessors transform * Remove `rawset` from the list of used builtins * Fix sourcemaps * Improve class extends test case * Improve lualib types * Add few comments to lualib * Temporary revert getter property override removal * Add changelog * Change sourcemap class extends mapping pattern
1 parent c05029b commit 1a1e369

File tree

20 files changed

+272
-395
lines changed

20 files changed

+272
-395
lines changed

CHANGELOG.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,54 @@
44

55
- TypeScript has been updated to 3.8. See [release notes](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html) for details.
66

7+
- Fixed class accessors not working when base class is lacking type information (#725)
8+
9+
- Class extension code has been extracted to lualib
10+
11+
```ts
12+
class A {}
13+
class B extends A {}
14+
```
15+
16+
```diff
17+
A = __TS__Class()
18+
B = __TS__Class()
19+
-B.____super = A
20+
-setmetatable(B, B.____super)
21+
-setmetatable(B.prototype, B.____super.prototype)
22+
+__TS__ClassExtends(A, B)
23+
```
24+
25+
- Generated code for class accessors is more dynamic now
26+
27+
```ts
28+
class A {
29+
get a() {
30+
return true;
31+
}
32+
}
33+
```
34+
35+
```diff
36+
A = __TS__Class()
37+
-A.prototype.____getters = {}
38+
-A.prototype.__index = __TS__Index(A.prototype)
39+
-function A.prototype.____getters.a(self)
40+
- return true
41+
-end
42+
+__TS__SetDescriptor(
43+
+ A.prototype,
44+
+ "a",
45+
+ {
46+
+ get = function(self)
47+
+ return true
48+
+ end
49+
+ }
50+
+)
51+
```
52+
53+
This change simplifies our codebase and opens a path to object accessors implementation
54+
755
## 0.31.0
856

957
- **Breaking:** The old annotation syntax (`/* !varArg */`) **no longer works**, the only currently supported syntax is:

src/LuaLib.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,20 +26,18 @@ export enum LuaLibFeature {
2626
ArrayFlatMap = "ArrayFlatMap",
2727
ArraySetLength = "ArraySetLength",
2828
Class = "Class",
29-
ClassIndex = "ClassIndex",
30-
ClassNewIndex = "ClassNewIndex",
29+
ClassExtends = "ClassExtends",
3130
Decorate = "Decorate",
31+
Descriptors = "Descriptors",
3232
Error = "Error",
3333
FunctionApply = "FunctionApply",
3434
FunctionBind = "FunctionBind",
3535
FunctionCall = "FunctionCall",
36-
Index = "Index",
3736
InstanceOf = "InstanceOf",
3837
InstanceOfObject = "InstanceOfObject",
3938
Iterator = "Iterator",
4039
Map = "Map",
4140
New = "New",
42-
NewIndex = "NewIndex",
4341
Number = "Number",
4442
NumberIsFinite = "NumberIsFinite",
4543
NumberIsNaN = "NumberIsNaN",

src/lualib/Class.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
function __TS__Class(): LuaClass {
2-
const c = {} as LuaClass;
3-
c.__index = c;
4-
c.prototype = {};
2+
const c: LuaClass = { prototype: {} };
53
c.prototype.__index = c.prototype;
64
c.prototype.constructor = c;
75
return c;

src/lualib/ClassExtends.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
function __TS__ClassExtends(this: void, target: LuaClass, base: LuaClass): void {
2+
target.____super = base;
3+
4+
// Set base class as a metatable, because descriptors use `getmetatable` to get extended prototype
5+
const staticMetatable: any = setmetatable({ __index: base }, base);
6+
setmetatable(target, staticMetatable);
7+
8+
const baseMetatable = getmetatable(base);
9+
if (baseMetatable) {
10+
// Re-add metatable events defined by descriptors
11+
if (typeof baseMetatable.__index === "function") staticMetatable.__index = baseMetatable.__index;
12+
if (typeof baseMetatable.__newindex === "function") staticMetatable.__newindex = baseMetatable.__newindex;
13+
}
14+
15+
setmetatable(target.prototype, base.prototype);
16+
// Re-add metatable events defined by accessors with `__TS__SetDescriptor`
17+
if (typeof base.prototype.__index === "function") target.prototype.__index = base.prototype.__index;
18+
if (typeof base.prototype.__newindex === "function") target.prototype.__newindex = base.prototype.__newindex;
19+
}

src/lualib/ClassIndex.ts

Lines changed: 0 additions & 21 deletions
This file was deleted.

src/lualib/ClassNewIndex.ts

Lines changed: 0 additions & 17 deletions
This file was deleted.

src/lualib/Descriptors.ts

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
function ____descriptorIndex(this: any, key: string): void {
2+
const value = rawget(this, key);
3+
if (value !== null) {
4+
return value;
5+
}
6+
7+
let metatable = getmetatable(this);
8+
while (metatable) {
9+
const rawResult = rawget(metatable, key);
10+
if (rawResult !== undefined) {
11+
return rawResult;
12+
}
13+
14+
const descriptors = rawget(metatable, "_descriptors");
15+
if (descriptors) {
16+
const descriptor: PropertyDescriptor = descriptors[key];
17+
if (descriptor) {
18+
if (descriptor.get) {
19+
return descriptor.get.call(this);
20+
}
21+
22+
return;
23+
}
24+
}
25+
26+
metatable = getmetatable(metatable);
27+
}
28+
}
29+
30+
function ____descriptorNewindex(this: any, key: string, value: any): void {
31+
let metatable = getmetatable(this);
32+
while (metatable) {
33+
const descriptors = rawget(metatable, "_descriptors");
34+
if (descriptors) {
35+
const descriptor: PropertyDescriptor = descriptors[key];
36+
if (descriptor) {
37+
if (descriptor.set) {
38+
descriptor.set.call(this, value);
39+
}
40+
41+
return;
42+
}
43+
}
44+
45+
metatable = getmetatable(metatable);
46+
}
47+
48+
rawset(this, key, value);
49+
}
50+
51+
// It's also used directly in class transform to add descriptors to the prototype
52+
function __TS__SetDescriptor(this: void, metatable: Metatable, prop: string, descriptor: PropertyDescriptor): void {
53+
if (!metatable._descriptors) metatable._descriptors = {};
54+
metatable._descriptors[prop] = descriptor;
55+
56+
if (descriptor.get) metatable.__index = ____descriptorIndex;
57+
if (descriptor.set) metatable.__newindex = ____descriptorNewindex;
58+
}
59+
60+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
61+
function __TS__ObjectDefineProperty<T extends object>(
62+
this: void,
63+
object: T,
64+
prop: string,
65+
descriptor: PropertyDescriptor
66+
): T {
67+
let metatable = getmetatable(object);
68+
if (!metatable) {
69+
metatable = {};
70+
setmetatable(object, metatable);
71+
}
72+
73+
__TS__SetDescriptor(metatable, prop, descriptor);
74+
return object;
75+
}

src/lualib/Index.ts

Lines changed: 0 additions & 26 deletions
This file was deleted.

src/lualib/InstanceOf.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
function __TS__InstanceOf(this: void, obj: LuaObject, classTbl: LuaClass): boolean {
1+
function __TS__InstanceOf(this: void, obj: LuaClassInstance, classTbl: LuaClass): boolean {
22
if (typeof classTbl !== "object") {
33
// tslint:disable-next-line: no-string-throw
44
throw "Right-hand side of 'instanceof' is not an object";

src/lualib/NewIndex.ts

Lines changed: 0 additions & 24 deletions
This file was deleted.

0 commit comments

Comments
 (0)
X Tutup