redscript-mc 1.1.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +59 -0
- package/README.md +53 -10
- package/README.zh.md +53 -10
- package/dist/__tests__/cli.test.js +138 -0
- package/dist/__tests__/codegen.test.js +25 -0
- package/dist/__tests__/dce.test.d.ts +1 -0
- package/dist/__tests__/dce.test.js +137 -0
- package/dist/__tests__/e2e.test.js +190 -12
- package/dist/__tests__/lexer.test.js +31 -4
- package/dist/__tests__/lowering.test.js +172 -9
- package/dist/__tests__/mc-integration.test.js +145 -51
- package/dist/__tests__/mc-syntax.test.js +12 -0
- package/dist/__tests__/optimizer-advanced.test.js +3 -3
- package/dist/__tests__/parser.test.js +90 -0
- package/dist/__tests__/runtime.test.js +21 -8
- package/dist/__tests__/typechecker.test.js +188 -0
- package/dist/ast/types.d.ts +42 -3
- package/dist/cli.js +15 -10
- package/dist/codegen/mcfunction/index.js +30 -1
- package/dist/codegen/structure/index.d.ts +4 -1
- package/dist/codegen/structure/index.js +29 -2
- package/dist/compile.d.ts +11 -0
- package/dist/compile.js +40 -6
- package/dist/events/types.d.ts +35 -0
- package/dist/events/types.js +59 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +7 -3
- package/dist/ir/types.d.ts +4 -0
- package/dist/lexer/index.d.ts +2 -1
- package/dist/lexer/index.js +91 -1
- package/dist/lowering/index.d.ts +32 -1
- package/dist/lowering/index.js +476 -16
- package/dist/optimizer/dce.d.ts +23 -0
- package/dist/optimizer/dce.js +591 -0
- package/dist/parser/index.d.ts +4 -0
- package/dist/parser/index.js +160 -26
- package/dist/typechecker/index.d.ts +19 -0
- package/dist/typechecker/index.js +392 -17
- package/docs/ARCHITECTURE.zh.md +1088 -0
- package/docs/ENTITY_TYPE_SYSTEM.md +242 -0
- package/editors/vscode/.vscodeignore +3 -0
- package/editors/vscode/CHANGELOG.md +9 -0
- package/editors/vscode/icon.png +0 -0
- package/editors/vscode/out/extension.js +1144 -72
- package/editors/vscode/package-lock.json +2 -2
- package/editors/vscode/package.json +1 -1
- package/editors/vscode/syntaxes/redscript.tmLanguage.json +6 -2
- package/examples/spiral.mcrs +79 -0
- package/logo.png +0 -0
- package/package.json +1 -1
- package/src/__tests__/cli.test.ts +166 -0
- package/src/__tests__/codegen.test.ts +27 -0
- package/src/__tests__/dce.test.ts +129 -0
- package/src/__tests__/e2e.test.ts +201 -12
- package/src/__tests__/fixtures/event-test.mcrs +13 -0
- package/src/__tests__/fixtures/impl-test.mcrs +46 -0
- package/src/__tests__/fixtures/interval-test.mcrs +11 -0
- package/src/__tests__/fixtures/is-check-test.mcrs +20 -0
- package/src/__tests__/fixtures/timeout-test.mcrs +7 -0
- package/src/__tests__/lexer.test.ts +35 -4
- package/src/__tests__/lowering.test.ts +187 -9
- package/src/__tests__/mc-integration.test.ts +166 -51
- package/src/__tests__/mc-syntax.test.ts +14 -0
- package/src/__tests__/optimizer-advanced.test.ts +3 -3
- package/src/__tests__/parser.test.ts +102 -5
- package/src/__tests__/runtime.test.ts +24 -8
- package/src/__tests__/typechecker.test.ts +204 -0
- package/src/ast/types.ts +39 -2
- package/src/cli.ts +24 -10
- package/src/codegen/mcfunction/index.ts +31 -1
- package/src/codegen/structure/index.ts +40 -2
- package/src/compile.ts +59 -7
- package/src/events/types.ts +69 -0
- package/src/index.ts +9 -4
- package/src/ir/types.ts +4 -0
- package/src/lexer/index.ts +105 -2
- package/src/lowering/index.ts +566 -18
- package/src/optimizer/dce.ts +618 -0
- package/src/parser/index.ts +187 -29
- package/src/stdlib/README.md +34 -4
- package/src/stdlib/tags.mcrs +951 -0
- package/src/stdlib/timer.mcrs +54 -33
- package/src/typechecker/index.ts +469 -18
package/dist/parser/index.js
CHANGED
|
@@ -16,11 +16,31 @@ const PRECEDENCE = {
|
|
|
16
16
|
'||': 1,
|
|
17
17
|
'&&': 2,
|
|
18
18
|
'==': 3, '!=': 3,
|
|
19
|
-
'<': 4, '<=': 4, '>': 4, '>=': 4,
|
|
19
|
+
'<': 4, '<=': 4, '>': 4, '>=': 4, 'is': 4,
|
|
20
20
|
'+': 5, '-': 5,
|
|
21
21
|
'*': 6, '/': 6, '%': 6,
|
|
22
22
|
};
|
|
23
|
-
const BINARY_OPS = new Set(['||', '&&', '==', '!=', '<', '<=', '>', '>=', '+', '-', '*', '/', '%']);
|
|
23
|
+
const BINARY_OPS = new Set(['||', '&&', '==', '!=', '<', '<=', '>', '>=', 'is', '+', '-', '*', '/', '%']);
|
|
24
|
+
const ENTITY_TYPE_NAMES = new Set([
|
|
25
|
+
'entity',
|
|
26
|
+
'Player',
|
|
27
|
+
'Mob',
|
|
28
|
+
'HostileMob',
|
|
29
|
+
'PassiveMob',
|
|
30
|
+
'Zombie',
|
|
31
|
+
'Skeleton',
|
|
32
|
+
'Creeper',
|
|
33
|
+
'Spider',
|
|
34
|
+
'Enderman',
|
|
35
|
+
'Pig',
|
|
36
|
+
'Cow',
|
|
37
|
+
'Sheep',
|
|
38
|
+
'Chicken',
|
|
39
|
+
'Villager',
|
|
40
|
+
'ArmorStand',
|
|
41
|
+
'Item',
|
|
42
|
+
'Arrow',
|
|
43
|
+
]);
|
|
24
44
|
function computeIsSingle(raw) {
|
|
25
45
|
if (/^@[spr](\[|$)/.test(raw))
|
|
26
46
|
return true;
|
|
@@ -102,6 +122,7 @@ class Parser {
|
|
|
102
122
|
const globals = [];
|
|
103
123
|
const declarations = [];
|
|
104
124
|
const structs = [];
|
|
125
|
+
const implBlocks = [];
|
|
105
126
|
const enums = [];
|
|
106
127
|
const consts = [];
|
|
107
128
|
// Check for namespace declaration
|
|
@@ -119,6 +140,9 @@ class Parser {
|
|
|
119
140
|
else if (this.check('struct')) {
|
|
120
141
|
structs.push(this.parseStructDecl());
|
|
121
142
|
}
|
|
143
|
+
else if (this.check('impl')) {
|
|
144
|
+
implBlocks.push(this.parseImplBlock());
|
|
145
|
+
}
|
|
122
146
|
else if (this.check('enum')) {
|
|
123
147
|
enums.push(this.parseEnumDecl());
|
|
124
148
|
}
|
|
@@ -129,7 +153,7 @@ class Parser {
|
|
|
129
153
|
declarations.push(this.parseFnDecl());
|
|
130
154
|
}
|
|
131
155
|
}
|
|
132
|
-
return { namespace, globals, declarations, structs, enums, consts };
|
|
156
|
+
return { namespace, globals, declarations, structs, implBlocks, enums, consts };
|
|
133
157
|
}
|
|
134
158
|
// -------------------------------------------------------------------------
|
|
135
159
|
// Struct Declaration
|
|
@@ -175,6 +199,17 @@ class Parser {
|
|
|
175
199
|
this.expect('}');
|
|
176
200
|
return this.withLoc({ name, variants }, enumToken);
|
|
177
201
|
}
|
|
202
|
+
parseImplBlock() {
|
|
203
|
+
const implToken = this.expect('impl');
|
|
204
|
+
const typeName = this.expect('ident').value;
|
|
205
|
+
this.expect('{');
|
|
206
|
+
const methods = [];
|
|
207
|
+
while (!this.check('}') && !this.check('eof')) {
|
|
208
|
+
methods.push(this.parseFnDecl(typeName));
|
|
209
|
+
}
|
|
210
|
+
this.expect('}');
|
|
211
|
+
return this.withLoc({ kind: 'impl_block', typeName, methods }, implToken);
|
|
212
|
+
}
|
|
178
213
|
parseConstDecl() {
|
|
179
214
|
const constToken = this.expect('const');
|
|
180
215
|
const name = this.expect('ident').value;
|
|
@@ -198,15 +233,15 @@ class Parser {
|
|
|
198
233
|
// -------------------------------------------------------------------------
|
|
199
234
|
// Function Declaration
|
|
200
235
|
// -------------------------------------------------------------------------
|
|
201
|
-
parseFnDecl() {
|
|
236
|
+
parseFnDecl(implTypeName) {
|
|
202
237
|
const decorators = this.parseDecorators();
|
|
203
238
|
const fnToken = this.expect('fn');
|
|
204
239
|
const name = this.expect('ident').value;
|
|
205
240
|
this.expect('(');
|
|
206
|
-
const params = this.parseParams();
|
|
241
|
+
const params = this.parseParams(implTypeName);
|
|
207
242
|
this.expect(')');
|
|
208
243
|
let returnType = { kind: 'named', name: 'void' };
|
|
209
|
-
if (this.match('->')) {
|
|
244
|
+
if (this.match('->') || this.match(':')) {
|
|
210
245
|
returnType = this.parseType();
|
|
211
246
|
}
|
|
212
247
|
const body = this.parseBlock();
|
|
@@ -222,7 +257,7 @@ class Parser {
|
|
|
222
257
|
return decorators;
|
|
223
258
|
}
|
|
224
259
|
parseDecoratorValue(value) {
|
|
225
|
-
// Parse @tick
|
|
260
|
+
// Parse @tick, @on(PlayerDeath), or @on_trigger("name")
|
|
226
261
|
const match = value.match(/^@(\w+)(?:\(([^)]*)\))?$/);
|
|
227
262
|
if (!match) {
|
|
228
263
|
this.error(`Invalid decorator: ${value}`);
|
|
@@ -233,6 +268,13 @@ class Parser {
|
|
|
233
268
|
return { name };
|
|
234
269
|
}
|
|
235
270
|
const args = {};
|
|
271
|
+
if (name === 'on') {
|
|
272
|
+
const eventTypeMatch = argsStr.match(/^([A-Za-z_][A-Za-z0-9_]*)$/);
|
|
273
|
+
if (eventTypeMatch) {
|
|
274
|
+
args.eventType = eventTypeMatch[1];
|
|
275
|
+
return { name, args };
|
|
276
|
+
}
|
|
277
|
+
}
|
|
236
278
|
// Handle @on_trigger("name"), @on_advancement("id"), @on_craft("item"), @on_join_team("team")
|
|
237
279
|
if (name === 'on_trigger' || name === 'on_advancement' || name === 'on_craft' || name === 'on_join_team') {
|
|
238
280
|
const strMatch = argsStr.match(/^"([^"]*)"$/);
|
|
@@ -273,14 +315,20 @@ class Parser {
|
|
|
273
315
|
}
|
|
274
316
|
return { name, args };
|
|
275
317
|
}
|
|
276
|
-
parseParams() {
|
|
318
|
+
parseParams(implTypeName) {
|
|
277
319
|
const params = [];
|
|
278
320
|
if (!this.check(')')) {
|
|
279
321
|
do {
|
|
280
322
|
const paramToken = this.expect('ident');
|
|
281
323
|
const name = paramToken.value;
|
|
282
|
-
|
|
283
|
-
|
|
324
|
+
let type;
|
|
325
|
+
if (implTypeName && params.length === 0 && name === 'self' && !this.check(':')) {
|
|
326
|
+
type = { kind: 'struct', name: implTypeName };
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
this.expect(':');
|
|
330
|
+
type = this.parseType();
|
|
331
|
+
}
|
|
284
332
|
let defaultValue;
|
|
285
333
|
if (this.match('=')) {
|
|
286
334
|
defaultValue = this.parseExpr();
|
|
@@ -612,6 +660,11 @@ class Parser {
|
|
|
612
660
|
if (prec < minPrec)
|
|
613
661
|
break;
|
|
614
662
|
const opToken = this.advance();
|
|
663
|
+
if (op === 'is') {
|
|
664
|
+
const entityType = this.parseEntityTypeName();
|
|
665
|
+
left = this.withLoc({ kind: 'is_check', expr: left, entityType }, this.getLocToken(left) ?? opToken);
|
|
666
|
+
continue;
|
|
667
|
+
}
|
|
615
668
|
const right = this.parseBinaryExpr(prec + 1); // left associative
|
|
616
669
|
left = this.withLoc({ kind: 'binary', op: op, left, right }, this.getLocToken(left) ?? opToken);
|
|
617
670
|
}
|
|
@@ -630,6 +683,13 @@ class Parser {
|
|
|
630
683
|
}
|
|
631
684
|
return this.parsePostfixExpr();
|
|
632
685
|
}
|
|
686
|
+
parseEntityTypeName() {
|
|
687
|
+
const token = this.expect('ident');
|
|
688
|
+
if (ENTITY_TYPE_NAMES.has(token.value)) {
|
|
689
|
+
return token.value;
|
|
690
|
+
}
|
|
691
|
+
this.error(`Unknown entity type '${token.value}'`);
|
|
692
|
+
}
|
|
633
693
|
isSubtraction() {
|
|
634
694
|
// Check if this minus is binary (subtraction) by looking at previous token
|
|
635
695
|
// If previous was a value (literal, ident, ), ]) it's subtraction
|
|
@@ -710,6 +770,15 @@ class Parser {
|
|
|
710
770
|
}
|
|
711
771
|
parsePrimaryExpr() {
|
|
712
772
|
const token = this.peek();
|
|
773
|
+
if (token.kind === 'ident' && this.peek(1).kind === '::') {
|
|
774
|
+
const typeToken = this.advance();
|
|
775
|
+
this.expect('::');
|
|
776
|
+
const methodToken = this.expect('ident');
|
|
777
|
+
this.expect('(');
|
|
778
|
+
const args = this.parseArgs();
|
|
779
|
+
this.expect(')');
|
|
780
|
+
return this.withLoc({ kind: 'static_call', type: typeToken.value, method: methodToken.value, args }, typeToken);
|
|
781
|
+
}
|
|
713
782
|
if (token.kind === 'ident' && this.peek(1).kind === '=>') {
|
|
714
783
|
return this.parseSingleParamLambda();
|
|
715
784
|
}
|
|
@@ -723,6 +792,16 @@ class Parser {
|
|
|
723
792
|
this.advance();
|
|
724
793
|
return this.withLoc({ kind: 'float_lit', value: parseFloat(token.value) }, token);
|
|
725
794
|
}
|
|
795
|
+
// Relative coordinate: ~ ~5 ~-3 ~0.5
|
|
796
|
+
if (token.kind === 'rel_coord') {
|
|
797
|
+
this.advance();
|
|
798
|
+
return this.withLoc({ kind: 'rel_coord', value: token.value }, token);
|
|
799
|
+
}
|
|
800
|
+
// Local coordinate: ^ ^5 ^-3 ^0.5
|
|
801
|
+
if (token.kind === 'local_coord') {
|
|
802
|
+
this.advance();
|
|
803
|
+
return this.withLoc({ kind: 'local_coord', value: token.value }, token);
|
|
804
|
+
}
|
|
726
805
|
// NBT suffix literals
|
|
727
806
|
if (token.kind === 'byte_lit') {
|
|
728
807
|
this.advance();
|
|
@@ -745,6 +824,10 @@ class Parser {
|
|
|
745
824
|
this.advance();
|
|
746
825
|
return this.parseStringExpr(token);
|
|
747
826
|
}
|
|
827
|
+
if (token.kind === 'f_string') {
|
|
828
|
+
this.advance();
|
|
829
|
+
return this.parseFStringExpr(token);
|
|
830
|
+
}
|
|
748
831
|
// MC name literal: #health → mc_name node (value = "health", without #)
|
|
749
832
|
if (token.kind === 'mc_name') {
|
|
750
833
|
this.advance();
|
|
@@ -896,6 +979,56 @@ class Parser {
|
|
|
896
979
|
}
|
|
897
980
|
return this.withLoc({ kind: 'str_interp', parts }, token);
|
|
898
981
|
}
|
|
982
|
+
parseFStringExpr(token) {
|
|
983
|
+
const parts = [];
|
|
984
|
+
let current = '';
|
|
985
|
+
let index = 0;
|
|
986
|
+
while (index < token.value.length) {
|
|
987
|
+
if (token.value[index] === '{') {
|
|
988
|
+
if (current) {
|
|
989
|
+
parts.push({ kind: 'text', value: current });
|
|
990
|
+
current = '';
|
|
991
|
+
}
|
|
992
|
+
index++;
|
|
993
|
+
let depth = 1;
|
|
994
|
+
let exprSource = '';
|
|
995
|
+
let inString = false;
|
|
996
|
+
while (index < token.value.length && depth > 0) {
|
|
997
|
+
const char = token.value[index];
|
|
998
|
+
if (char === '"' && token.value[index - 1] !== '\\') {
|
|
999
|
+
inString = !inString;
|
|
1000
|
+
}
|
|
1001
|
+
if (!inString) {
|
|
1002
|
+
if (char === '{') {
|
|
1003
|
+
depth++;
|
|
1004
|
+
}
|
|
1005
|
+
else if (char === '}') {
|
|
1006
|
+
depth--;
|
|
1007
|
+
if (depth === 0) {
|
|
1008
|
+
index++;
|
|
1009
|
+
break;
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
if (depth > 0) {
|
|
1014
|
+
exprSource += char;
|
|
1015
|
+
}
|
|
1016
|
+
index++;
|
|
1017
|
+
}
|
|
1018
|
+
if (depth !== 0) {
|
|
1019
|
+
this.error('Unterminated f-string interpolation');
|
|
1020
|
+
}
|
|
1021
|
+
parts.push({ kind: 'expr', expr: this.parseEmbeddedExpr(exprSource) });
|
|
1022
|
+
continue;
|
|
1023
|
+
}
|
|
1024
|
+
current += token.value[index];
|
|
1025
|
+
index++;
|
|
1026
|
+
}
|
|
1027
|
+
if (current) {
|
|
1028
|
+
parts.push({ kind: 'text', value: current });
|
|
1029
|
+
}
|
|
1030
|
+
return this.withLoc({ kind: 'f_string', parts }, token);
|
|
1031
|
+
}
|
|
899
1032
|
parseEmbeddedExpr(source) {
|
|
900
1033
|
const tokens = new lexer_1.Lexer(source, this.filePath).tokenize();
|
|
901
1034
|
const parser = new Parser(tokens, source, this.filePath);
|
|
@@ -1043,19 +1176,10 @@ class Parser {
|
|
|
1043
1176
|
if (token.kind === '-') {
|
|
1044
1177
|
return this.peek(offset + 1).kind === 'int_lit' ? 2 : 0;
|
|
1045
1178
|
}
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
}
|
|
1049
|
-
const next = this.peek(offset + 1);
|
|
1050
|
-
if (next.kind === ',' || next.kind === ')') {
|
|
1179
|
+
// rel_coord (~, ~5, ~-3) and local_coord (^, ^5, ^-3) are single tokens now
|
|
1180
|
+
if (token.kind === 'rel_coord' || token.kind === 'local_coord') {
|
|
1051
1181
|
return 1;
|
|
1052
1182
|
}
|
|
1053
|
-
if (next.kind === 'int_lit') {
|
|
1054
|
-
return 2;
|
|
1055
|
-
}
|
|
1056
|
-
if (next.kind === '-' && this.peek(offset + 2).kind === 'int_lit') {
|
|
1057
|
-
return 3;
|
|
1058
|
-
}
|
|
1059
1183
|
return 0;
|
|
1060
1184
|
}
|
|
1061
1185
|
parseBlockPos() {
|
|
@@ -1070,15 +1194,25 @@ class Parser {
|
|
|
1070
1194
|
}
|
|
1071
1195
|
parseCoordComponent() {
|
|
1072
1196
|
const token = this.peek();
|
|
1073
|
-
|
|
1197
|
+
// Handle rel_coord (~, ~5, ~-3) and local_coord (^, ^5, ^-3) tokens
|
|
1198
|
+
if (token.kind === 'rel_coord') {
|
|
1074
1199
|
this.advance();
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1200
|
+
// Parse the offset from the token value (e.g., "~5" -> 5, "~" -> 0, "~-3" -> -3)
|
|
1201
|
+
const offset = this.parseCoordOffsetFromValue(token.value.slice(1));
|
|
1202
|
+
return { kind: 'relative', offset };
|
|
1203
|
+
}
|
|
1204
|
+
if (token.kind === 'local_coord') {
|
|
1205
|
+
this.advance();
|
|
1206
|
+
const offset = this.parseCoordOffsetFromValue(token.value.slice(1));
|
|
1207
|
+
return { kind: 'local', offset };
|
|
1079
1208
|
}
|
|
1080
1209
|
return { kind: 'absolute', value: this.parseSignedCoordOffset(true) };
|
|
1081
1210
|
}
|
|
1211
|
+
parseCoordOffsetFromValue(value) {
|
|
1212
|
+
if (value === '' || value === undefined)
|
|
1213
|
+
return 0;
|
|
1214
|
+
return parseFloat(value);
|
|
1215
|
+
}
|
|
1082
1216
|
parseSignedCoordOffset(requireValue = false) {
|
|
1083
1217
|
let sign = 1;
|
|
1084
1218
|
if (this.match('-')) {
|
|
@@ -9,12 +9,15 @@ import { DiagnosticError } from '../diagnostics';
|
|
|
9
9
|
export declare class TypeChecker {
|
|
10
10
|
private collector;
|
|
11
11
|
private functions;
|
|
12
|
+
private implMethods;
|
|
12
13
|
private structs;
|
|
13
14
|
private enums;
|
|
14
15
|
private consts;
|
|
15
16
|
private currentFn;
|
|
16
17
|
private currentReturnType;
|
|
17
18
|
private scope;
|
|
19
|
+
private selfTypeStack;
|
|
20
|
+
private readonly richTextBuiltins;
|
|
18
21
|
constructor(source?: string, filePath?: string);
|
|
19
22
|
private getNodeLocation;
|
|
20
23
|
private report;
|
|
@@ -23,19 +26,35 @@ export declare class TypeChecker {
|
|
|
23
26
|
*/
|
|
24
27
|
check(program: Program): DiagnosticError[];
|
|
25
28
|
private checkFunction;
|
|
29
|
+
private checkFunctionDecorators;
|
|
26
30
|
private checkBlock;
|
|
27
31
|
private checkStmt;
|
|
28
32
|
private checkLetStmt;
|
|
29
33
|
private checkReturnStmt;
|
|
30
34
|
private checkExpr;
|
|
31
35
|
private checkCallExpr;
|
|
36
|
+
private checkRichTextBuiltinCall;
|
|
32
37
|
private checkInvokeExpr;
|
|
33
38
|
private checkFunctionCallArgs;
|
|
34
39
|
private checkTpCall;
|
|
35
40
|
private checkMemberExpr;
|
|
41
|
+
private checkStaticCallExpr;
|
|
36
42
|
private checkLambdaExpr;
|
|
43
|
+
private checkIfBranches;
|
|
44
|
+
private getThenBranchNarrowing;
|
|
37
45
|
private inferType;
|
|
38
46
|
private inferLambdaType;
|
|
47
|
+
/** Infer entity type from a selector */
|
|
48
|
+
private inferEntityTypeFromSelector;
|
|
49
|
+
private resolveInstanceMethod;
|
|
50
|
+
/** Check if childType is a subtype of parentType */
|
|
51
|
+
private isEntitySubtype;
|
|
52
|
+
/** Push a new self type context */
|
|
53
|
+
private pushSelfType;
|
|
54
|
+
/** Pop self type context */
|
|
55
|
+
private popSelfType;
|
|
56
|
+
/** Get current @s type */
|
|
57
|
+
private getCurrentSelfType;
|
|
39
58
|
private typesMatch;
|
|
40
59
|
private typeToString;
|
|
41
60
|
private normalizeType;
|