Skip to content

Commit 341d65b

Browse files
authored
Merge pull request #104 from Perryvw/feature/get-set-accessors
Added get/set accessors for #102
2 parents acf4ee0 + 1034fe7 commit 341d65b

File tree

6 files changed

+235
-7
lines changed

6 files changed

+235
-7
lines changed

src/TSHelper.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,4 +108,30 @@ export class TSHelper {
108108
}
109109
return null;
110110
}
111+
112+
public static hasGetAccessor(node: ts.Node, checker: ts.TypeChecker): boolean {
113+
if (ts.isPropertyAccessExpression(node)) {
114+
const name = node.name.escapedText;
115+
const type = checker.getTypeAtLocation(node.expression);
116+
117+
if (type && type.symbol && type.symbol.members) {
118+
const field = type.symbol.members.get(name);
119+
return field && (field.flags & ts.SymbolFlags.GetAccessor) !== 0;
120+
}
121+
}
122+
return false;
123+
}
124+
125+
public static hasSetAccessor(node: ts.Node, checker: ts.TypeChecker): boolean {
126+
if (ts.isPropertyAccessExpression(node)) {
127+
const name = node.name.escapedText;
128+
const type = checker.getTypeAtLocation(node.expression);
129+
130+
if (type && type.symbol && type.symbol.members) {
131+
const field = type.symbol.members.get(name);
132+
return field && (field.flags & ts.SymbolFlags.SetAccessor) !== 0;
133+
}
134+
}
135+
return false;
136+
}
111137
}

src/Transpiler.ts

Lines changed: 111 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@ export class TranspileError extends Error {
1717
}
1818
}
1919

20-
export enum Target {
20+
export enum LuaTarget {
2121
Lua53 = "5.3",
2222
LuaJIT = "JIT",
2323
}
2424

2525
export class LuaTranspiler {
26-
public static AvailableLuaTargets = [Target.LuaJIT, Target.Lua53];
26+
public static AvailableLuaTargets = [LuaTarget.LuaJIT, LuaTarget.Lua53];
2727

2828
// Transpile a source file
2929
public static transpileSourceFile(node: ts.SourceFile,
@@ -627,36 +627,56 @@ export class LuaTranspiler {
627627
let result = "";
628628

629629
// Transpile Bitops
630-
if (this.options.luaTarget === Target.LuaJIT) {
630+
if (this.options.luaTarget === LuaTarget.LuaJIT) {
631631
switch (node.operatorToken.kind) {
632632
case ts.SyntaxKind.AmpersandToken:
633633
result = `bit.band(${lhs},${rhs})`;
634634
break;
635635
case ts.SyntaxKind.AmpersandEqualsToken:
636+
if (tsEx.hasSetAccessor(node.left, this.checker)) {
637+
return this.transpileSetAccessor(node.left as ts.PropertyAccessExpression,
638+
`bit.band(${lhs},${rhs})`);
639+
}
636640
result = `${lhs}=bit.band(${lhs},${rhs})`;
637641
break;
638642
case ts.SyntaxKind.BarToken:
639643
result = `bit.bor(${lhs},${rhs})`;
640644
break;
641645
case ts.SyntaxKind.BarEqualsToken:
646+
if (tsEx.hasSetAccessor(node.left, this.checker)) {
647+
return this.transpileSetAccessor(node.left as ts.PropertyAccessExpression,
648+
`bit.bor(${lhs},${rhs})`);
649+
}
642650
result = `${lhs}=bit.bor(${lhs},${rhs})`;
643651
break;
644652
case ts.SyntaxKind.LessThanLessThanToken:
645653
result = `bit.lshift(${lhs},${rhs})`;
646654
break;
647655
case ts.SyntaxKind.LessThanLessThanEqualsToken:
656+
if (tsEx.hasSetAccessor(node.left, this.checker)) {
657+
return this.transpileSetAccessor(node.left as ts.PropertyAccessExpression,
658+
`bit.lshift(${lhs},${rhs})`);
659+
}
648660
result = `${lhs}=bit.lshift(${lhs},${rhs})`;
649661
break;
650662
case ts.SyntaxKind.GreaterThanGreaterThanToken:
651663
result = `bit.arshift(${lhs},${rhs})`;
652664
break;
653665
case ts.SyntaxKind.GreaterThanGreaterThanEqualsToken:
666+
if (tsEx.hasSetAccessor(node.left, this.checker)) {
667+
return this.transpileSetAccessor(node.left as ts.PropertyAccessExpression,
668+
`bit.arshift(${lhs},${rhs})`);
669+
}
654670
result = `${lhs}=bit.arshift(${lhs},${rhs})`;
655671
break;
656672
case ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken:
657673
result = `bit.rshift(${lhs},${rhs})`;
658674
break;
659675
case ts.SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken:
676+
if (tsEx.hasSetAccessor(node.left, this.checker)) {
677+
return this.transpileSetAccessor(node.left as ts.PropertyAccessExpression,
678+
`bit.rshift(${lhs},${rhs})`);
679+
}
660680
result = `${lhs}=bit.rshift(${lhs},${rhs})`;
661681
break;
662682
}
@@ -666,30 +686,45 @@ export class LuaTranspiler {
666686
result = `${lhs}&${rhs}`;
667687
break;
668688
case ts.SyntaxKind.AmpersandEqualsToken:
689+
if (tsEx.hasSetAccessor(node.left, this.checker)) {
690+
return this.transpileSetAccessor(node.left as ts.PropertyAccessExpression, `${lhs}&${rhs}`);
691+
}
669692
result = `${lhs}=${lhs}&${rhs}`;
670693
break;
671694
case ts.SyntaxKind.BarToken:
672695
result = `${lhs}|${rhs}`;
673696
break;
674697
case ts.SyntaxKind.BarEqualsToken:
698+
if (tsEx.hasSetAccessor(node.left, this.checker)) {
699+
return this.transpileSetAccessor(node.left as ts.PropertyAccessExpression, `${lhs}|${rhs}`);
700+
}
675701
result = `${lhs}=${lhs}|${rhs}`;
676702
break;
677703
case ts.SyntaxKind.LessThanLessThanToken:
678704
result = `${lhs}<<${rhs}`;
679705
break;
680706
case ts.SyntaxKind.LessThanLessThanEqualsToken:
707+
if (tsEx.hasSetAccessor(node.left, this.checker)) {
708+
return this.transpileSetAccessor(node.left as ts.PropertyAccessExpression, `${lhs}<<${rhs}`);
709+
}
681710
result = `${lhs}=${lhs}<<${rhs}`;
682711
break;
683712
case ts.SyntaxKind.GreaterThanGreaterThanToken:
684713
result = `${lhs}>>${rhs}`;
685714
break;
686715
case ts.SyntaxKind.GreaterThanGreaterThanEqualsToken:
716+
if (tsEx.hasSetAccessor(node.left, this.checker)) {
717+
return this.transpileSetAccessor(node.left as ts.PropertyAccessExpression, `${lhs}>>${rhs}`);
718+
}
687719
result = `${lhs}=${lhs}>>${rhs}`;
688720
break;
689721
case ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken:
690722
result = `${lhs}>>>${rhs}`;
691723
break;
692724
case ts.SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken:
725+
if (tsEx.hasSetAccessor(node.left, this.checker)) {
726+
return this.transpileSetAccessor(node.left as ts.PropertyAccessExpression, `${lhs}>>>${rhs}`);
727+
}
693728
result = `${lhs}=${lhs}>>>${rhs}`;
694729
break;
695730
}
@@ -699,15 +734,27 @@ export class LuaTranspiler {
699734
if (result === "") {
700735
switch (node.operatorToken.kind) {
701736
case ts.SyntaxKind.PlusEqualsToken:
737+
if (tsEx.hasSetAccessor(node.left, this.checker)) {
738+
return this.transpileSetAccessor(node.left as ts.PropertyAccessExpression, `${lhs}+${rhs}`);
739+
}
702740
result = `${lhs}=${lhs}+${rhs}`;
703741
break;
704742
case ts.SyntaxKind.MinusEqualsToken:
743+
if (tsEx.hasSetAccessor(node.left, this.checker)) {
744+
return this.transpileSetAccessor(node.left as ts.PropertyAccessExpression, `${lhs}-${rhs}`);
745+
}
705746
result = `${lhs}=${lhs}-${rhs}`;
706747
break;
707748
case ts.SyntaxKind.AsteriskEqualsToken:
749+
if (tsEx.hasSetAccessor(node.left, this.checker)) {
750+
return this.transpileSetAccessor(node.left as ts.PropertyAccessExpression, `${lhs}*${rhs}`);
751+
}
708752
result = `${lhs}=${lhs}*${rhs}`;
709753
break;
710754
case ts.SyntaxKind.SlashEqualsToken:
755+
if (tsEx.hasSetAccessor(node.left, this.checker)) {
756+
return this.transpileSetAccessor(node.left as ts.PropertyAccessExpression, `${lhs}/${rhs}`);
757+
}
711758
result = `${lhs}=${lhs}/${rhs}`;
712759
break;
713760
case ts.SyntaxKind.AmpersandAmpersandToken:
@@ -751,6 +798,9 @@ export class LuaTranspiler {
751798
result = `${lhs}<=${rhs}`;
752799
break;
753800
case ts.SyntaxKind.EqualsToken:
801+
if (tsEx.hasSetAccessor(node.left, this.checker)) {
802+
return this.transpileSetAccessor(node.left as ts.PropertyAccessExpression, rhs);
803+
}
754804
result = `${lhs}=${rhs}`;
755805
break;
756806
case ts.SyntaxKind.EqualsEqualsToken:
@@ -931,7 +981,7 @@ export class LuaTranspiler {
931981
fromCodePoint: "utf8.char",
932982
};
933983

934-
if (identifier.escapedText as string === "fromCodePoint" && this.options.luaTarget !== Target.Lua53) {
984+
if (identifier.escapedText as string === "fromCodePoint" && this.options.luaTarget !== LuaTarget.Lua53) {
935985
throw new TranspileError(
936986
`Unsupported string property ${identifier.escapedText} is only supported for lua 5.3.`,
937987
identifier
@@ -1007,6 +1057,8 @@ export class LuaTranspiler {
10071057
case ts.TypeFlags.Object:
10081058
if (tsEx.isArrayType(type, this.checker)) {
10091059
return this.transpileArrayProperty(node);
1060+
} else if (tsEx.hasGetAccessor(node, this.checker)) {
1061+
return this.transpileGetAccessor(node);
10101062
}
10111063
}
10121064

@@ -1024,6 +1076,18 @@ export class LuaTranspiler {
10241076
return `${callPath}.${property}`;
10251077
}
10261078

1079+
public transpileGetAccessor(node: ts.PropertyAccessExpression): string {
1080+
const name = node.name.escapedText;
1081+
const expression = this.transpileExpression(node.expression);
1082+
return `${expression}:get__${name}()`;
1083+
}
1084+
1085+
public transpileSetAccessor(node: ts.PropertyAccessExpression, value: string): string {
1086+
const name = node.name.escapedText;
1087+
const expression = this.transpileExpression(node.expression);
1088+
return `${expression}:set__${name}(${value})`;
1089+
}
1090+
10271091
// Transpile a Math._ property
10281092
public transpileMathExpression(identifier: ts.Identifier): string {
10291093
const translation = {
@@ -1322,6 +1386,16 @@ export class LuaTranspiler {
13221386
);
13231387
}
13241388

1389+
// Transpile get accessors
1390+
node.members.filter(ts.isGetAccessor).forEach((getAccessor) => {
1391+
result += this.transpileGetAccessorDeclaration(getAccessor, className);
1392+
});
1393+
1394+
// Transpile set accessors
1395+
node.members.filter(ts.isSetAccessor).forEach((setAccessor) => {
1396+
result += this.transpileSetAccessorDeclaration(setAccessor, className);
1397+
});
1398+
13251399
// Transpile methods
13261400
node.members.filter(ts.isMethodDeclaration).forEach((method) => {
13271401
result += this.transpileMethodDeclaration(method, `${className}.`);
@@ -1330,6 +1404,39 @@ export class LuaTranspiler {
13301404
return result;
13311405
}
13321406

1407+
public transpileGetAccessorDeclaration(getAccessor: ts.GetAccessorDeclaration, className: string): string {
1408+
const name = (getAccessor.name as ts.Identifier).escapedText;
1409+
1410+
let result = this.indent + `function ${className}.get__${name}(self)\n`;
1411+
1412+
this.pushIndent();
1413+
result += this.transpileBlock(getAccessor.body);
1414+
this.popIndent();
1415+
1416+
result += this.indent + `end\n`;
1417+
1418+
return result;
1419+
}
1420+
1421+
public transpileSetAccessorDeclaration(setAccessor: ts.SetAccessorDeclaration, className: string): string {
1422+
const name = (setAccessor.name as ts.Identifier).escapedText;
1423+
1424+
const paramNames: string[] = ["self"];
1425+
setAccessor.parameters.forEach((param) => {
1426+
paramNames.push((param.name as ts.Identifier).escapedText as string);
1427+
});
1428+
1429+
let result = this.indent + `function ${className}.set__${name}(${paramNames.join(",")})\n`;
1430+
1431+
this.pushIndent();
1432+
result += this.transpileBlock(setAccessor.body);
1433+
this.popIndent();
1434+
1435+
result += this.indent + `end\n`;
1436+
1437+
return result;
1438+
}
1439+
13331440
public transpileConstructor(node: ts.ConstructorDeclaration,
13341441
className: string,
13351442
instanceFields: ts.PropertyDeclaration[]): string {

test/src/util.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@ import * as path from "path";
33

44
import { Expect } from "alsatian";
55

6-
import { LuaTranspiler, TranspileError } from "../../src/Transpiler";
6+
import { LuaTranspiler, TranspileError, LuaTarget } from "../../src/Transpiler";
77
import { CompilerOptions } from "../../src/CommandLineParser";
88

99
const LuaVM = require("lua.vm.js");
1010
const fs = require("fs");
1111

1212
const libSource = fs.readFileSync(path.join(path.dirname(require.resolve('typescript')), 'lib.d.ts')).toString();
1313

14-
export function transpileString(str: string, options: CompilerOptions = { dontRequireLuaLib: true }): string {
14+
export function transpileString(str: string, options: CompilerOptions = { dontRequireLuaLib: true, luaTarget: LuaTarget.LuaJIT }): string {
1515
let compilerHost = {
1616
getSourceFile: (filename, languageVersion) => {
1717
if (filename === "file.ts") {
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MyClass = MyClass or {}
2+
MyClass.__index = MyClass
3+
function MyClass.new(construct, ...)
4+
local instance = setmetatable({}, MyClass)
5+
if construct and MyClass.constructor then MyClass.constructor(instance, ...) end
6+
return instance
7+
end
8+
function MyClass.constructor(self)
9+
end
10+
function MyClass.get__field(self)
11+
return self._field+4
12+
end
13+
function MyClass.set__field(self,v)
14+
self._field=(v*2)
15+
end
16+
local instance = MyClass.new(true)
17+
18+
instance:set__field(4)
19+
local b = instance:get__field()
20+
21+
local c = (4+instance:get__field())*3
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
class MyClass {
2+
private _field: number;
3+
public get field(): number {
4+
return this._field + 4;
5+
}
6+
public set field(v: number) {
7+
this._field = v*2;
8+
}
9+
}
10+
11+
var instance = new MyClass();
12+
instance.field = 4;
13+
const b = instance.field;
14+
const c = (4 + instance.field)*3;

0 commit comments

Comments
 (0)