idlize

Форк
0
/
LanguageWriters.ts 
1434 строки · 59.5 Кб
1
/*
2
 * Copyright (c) 2024 Huawei Device Co., Ltd.
3
 * Licensed under the Apache License, Version 2.0 (the "License");
4
 * you may not use this file except in compliance with the License.
5
 * You may obtain a copy of the License at
6
 *
7
 * http://www.apache.org/licenses/LICENSE-2.0
8
 *
9
 * Unless required by applicable law or agreed to in writing, software
10
 * distributed under the License is distributed on an "AS IS" BASIS,
11
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
 * See the License for the specific language governing permissions and
13
 * limitations under the License.
14
 */
15

16
import { IndentedPrinter } from "../IndentedPrinter";
17
import { Language, stringOrNone } from "../util";
18
import {
19
    AggregateConvertor,
20
    ArgConvertor,
21
    ArrayConvertor,
22
    BaseArgConvertor,
23
    EnumConvertor,
24
    MapConvertor,
25
    OptionConvertor,
26
    TupleConvertor,
27
    UnionConvertor
28
} from "./Convertors";
29
import { FieldRecord, PrimitiveType } from "./DeclarationTable";
30
import { RuntimeType } from "./PeerGeneratorVisitor";
31
import { mapType, TSTypeNodeNameConvertor } from "./TypeNodeNameConvertor";
32

33
import * as ts from "typescript"
34
import * as fs from "fs"
35
import { PeerFile } from "./PeerFile";
36
import { PeerGeneratorConfig } from "./PeerGeneratorConfig";
37

38
export class Type {
39
    constructor(public name: string, public nullable = false) {}
40
    static Int32 = new Type('int32')
41
    static Boolean = new Type('boolean')
42
    static Number = new Type('number')
43
    static Pointer = new Type('KPointer')
44
    static This = new Type('this')
45
    static Void = new Type('void')
46
}
47

48
export enum FieldModifier {
49
    READONLY,
50
}
51

52
export enum MethodModifier {
53
    PUBLIC,
54
    PRIVATE,
55
    STATIC,
56
    NATIVE,
57
    INLINE,
58
    GETTER,
59
    SETTER,
60
}
61

62
export interface LanguageStatement {
63
    write(writer: LanguageWriter): void
64
}
65

66
export interface LanguageExpression {
67
    asString(): string
68
}
69

70
export class AssignStatement implements LanguageStatement {
71
    constructor(public variableName: string,
72
                public type: Type | undefined,
73
                public expression: LanguageExpression | undefined,
74
                public isDeclared: boolean = true,
75
                protected isConst: boolean = true) { }
76
    write(writer: LanguageWriter): void {
77
        if (this.isDeclared) {
78
            const typeSpec = this.type ? `: ${writer.mapType(this.type)}${this.type.nullable ? "|undefined" : ""}` : ""
79
            const initValue = this.expression ? `= ${this.expression.asString()}` : ""
80
            const constSpec = this.isConst ? "const" : "let"
81
            writer.print(`${constSpec} ${this.variableName}${typeSpec} ${initValue}`)
82
        } else {
83
            writer.print(`${this.variableName} = ${this.expression?.asString()}`)
84
        }
85
    }
86
}
87

88
export class DeclareStatement implements LanguageStatement {
89
    constructor(public variableName: string,
90
                public type: Type,
91
                public expression: LanguageExpression | undefined = undefined) { }
92
    write(writer: LanguageWriter): void {
93
        const type = this.type ? `: ${this.type.name}` : ""
94
        if (this.expression) {
95
            writer.print(`const ${this.variableName}${type} = ${this.expression.asString()}`)
96
        } else {
97
            writer.print(`let ${this.variableName}${type}`)
98
        }
99
    }
100
}
101

102
export class JavaAssignStatement extends AssignStatement {
103
    constructor(public variableName: string,
104
                public type: Type | undefined,
105
                public expression: LanguageExpression,
106
                public isDeclared: boolean = true,
107
                protected isConst: boolean = true) {
108
        super(variableName, type, expression, isDeclared, isConst)
109
     }
110
     write(writer: LanguageWriter): void{
111
        if (this.isDeclared) {
112
            const typeSpec = this.type ? writer.mapType(this.type) : "var"
113
            writer.print(`${typeSpec} ${this.variableName} = ${this.expression.asString()};`)
114
        } else {
115
            writer.print(`${this.variableName} = ${this.expression.asString()};`)
116
        }
117
    }
118
}
119

120
export class EtsAssignStatement implements LanguageStatement {
121
    constructor(public variableName: string,
122
                public type: Type | undefined,
123
                public expression: LanguageExpression,
124
                public isDeclared: boolean = true,
125
                protected isConst: boolean = true) { }
126
    write(writer: LanguageWriter): void {
127
        if (this.isDeclared) {
128
            const typeSpec = ""
129
            writer.print(`${this.isConst ? "const" : "let"} ${this.variableName}${typeSpec} = ${this.expression.asString()}`)
130
        } else {
131
            writer.print(`${this.variableName} = ${this.expression.asString()}`)
132
        }
133
    }
134
}
135

136
export class CppAssignStatement extends AssignStatement {
137
    constructor(public variableName: string,
138
                public type: Type | undefined,
139
                public expression: LanguageExpression | undefined,
140
                public isDeclared: boolean = true,
141
                public isConst: boolean = true) {
142
        super(variableName, type, expression, isDeclared, isConst)
143
     }
144
     write(writer: LanguageWriter): void{
145
        if (this.isDeclared) {
146
            const typeSpec = this.type ? writer.mapType(this.type) : "auto"
147
            const initValue = this.expression ? this.expression.asString() : "{}"
148
            const constSpec = this.isConst ? "const " : ""
149
            writer.print(`${constSpec}${typeSpec} ${this.variableName} = ${initValue};`)
150
        } else {
151
            writer.print(`${this.variableName} = ${this.expression!.asString()};`)
152
        }
153
    }
154
}
155

156
export class CDefinedExpression implements LanguageExpression {
157
    constructor(private value: string) { }
158
    asString(): string {
159
        return `${this.value} != ARK_TAG_UNDEFINED`
160
    }
161
}
162

163
export class CheckDefinedExpression implements LanguageExpression {
164
    constructor(private value: string) { }
165
    asString(): string {
166
        return `${this.value} != "undefined"`
167
    }
168
}
169

170
export class JavaCheckDefinedExpression implements LanguageExpression {
171
    constructor(private value: string) { }
172
    asString(): string {
173
        return `${this.value} != null`
174
    }
175
}
176

177
export class FunctionCallExpression implements LanguageExpression {
178
    constructor(
179
        private name: string,
180
        private params: LanguageExpression[]) { }
181
    asString(): string {
182
        return `${this.name}(${this.params.map(it => it.asString()).join(", ")})`
183
    }
184
}
185

186
export class MethodCallExpression extends FunctionCallExpression {
187
    constructor(
188
        public receiver: string,
189
        method: string,
190
        params: LanguageExpression[],
191
        public nullable = false)
192
    {
193
        super(method, params)
194
    }
195
    asString(): string {
196
        return `${this.receiver}${this.nullable ? "?" : ""}.${super.asString()}`
197
    }
198
}
199

200
export class ExpressionStatement implements LanguageStatement {
201
    constructor(public expression: LanguageExpression) { }
202
    write(writer: LanguageWriter): void {
203
        const text = this.expression.asString()
204
        if (text.length > 0) {
205
            writer.print(`${this.expression.asString()}`)
206
        }
207
    }
208
}
209

210
export class CLikeExpressionStatement extends ExpressionStatement {
211
    constructor(public expression: LanguageExpression) { super(expression) }
212
    write(writer: LanguageWriter): void {
213
        const text = this.expression.asString()
214
        if (text.length > 0) {
215
            writer.print(`${this.expression.asString()};`)
216
        }
217
    }
218
}
219

220
export class ReturnStatement implements LanguageStatement {
221
    constructor(public expression?: LanguageExpression) { }
222
    write(writer: LanguageWriter): void {
223
        writer.print(this.expression ? `return ${this.expression.asString()}` : "return")
224
    }
225
}
226

227
export class TSReturnStatement extends ReturnStatement {
228
    constructor(public expression: LanguageExpression) { super(expression) }
229
}
230

231
export class CLikeReturnStatement extends ReturnStatement {
232
    constructor(public expression: LanguageExpression) { super(expression) }
233
    write(writer: LanguageWriter): void {
234
        writer.print(this.expression ? `return ${this.expression.asString()};` : "return;")
235
    }
236
}
237

238
export class TSCastExpression implements LanguageExpression {
239
    constructor(public value: LanguageExpression, public type: Type, private unsafe = false) {}
240
    asString(): string {
241
        return this.unsafe
242
            ? `unsafeCast<${this.type.name}>(${this.value.asString()})`
243
            : `(${this.value.asString()} as ${this.type.name})`
244
    }
245
}
246

247
export class JavaCastExpression implements LanguageExpression {
248
    constructor(public value: LanguageExpression, public type: Type, private unsafe = false) {}
249
    asString(): string {
250
        return `(${this.type.name})(${this.value.asString()})`
251
    }
252
}
253

254
export class CppCastExpression implements LanguageExpression {
255
    constructor(public value: LanguageExpression, public type: Type, private unsafe = false) {}
256
    asString(): string {
257
        if (this.type.name === PrimitiveType.Tag.getText()) {
258
            return `${this.value.asString()} == ARK_RUNTIME_UNDEFINED ? ARK_TAG_UNDEFINED : ARK_TAG_OBJECT`
259
        }
260
        return this.unsafe
261
            ? `reinterpret_cast<${this.type.name}>(${this.value.asString()})`
262
            : `static_cast<${this.type.name}>(${this.value.asString()})`
263
    }
264
}
265

266
class TSLoopStatement implements LanguageStatement {
267
    constructor(private counter: string, private limit: string, private statement: LanguageStatement | undefined) {}
268
    write(writer: LanguageWriter): void {
269
        writer.print(`for (let ${this.counter} = 0; ${this.counter} < ${this.limit}; ${this.counter}++) {`)
270
        if (this.statement) {
271
            writer.pushIndent()
272
            this.statement.write(writer)
273
            writer.popIndent()
274
            writer.print("}")
275
        }
276
    }
277
}
278

279
class CLikeLoopStatement implements LanguageStatement {
280
    constructor(private counter: string, private limit: string, private statement: LanguageStatement | undefined) {}
281
    write(writer: LanguageWriter): void {
282
        writer.print(`for (int ${this.counter} = 0; ${this.counter} < ${this.limit}; ${this.counter}++) {`)
283
        if (this.statement) {
284
            writer.pushIndent()
285
            this.statement.write(writer)
286
            writer.popIndent()
287
            writer.print("}")
288
        }
289
    }
290
}
291

292
class TSMapForEachStatement implements LanguageStatement {
293
    constructor(private map: string, private key: string, private value: string, private op: () => void) {}
294
    write(writer: LanguageWriter): void {
295
        writer.print(`for (const [${this.key}, ${this.value}] of ${this.map}) {`)
296
        writer.pushIndent()
297
        this.op()
298
        writer.popIndent()
299
        writer.print(`}`)
300
    }
301
}
302

303
class ArkTSMapForEachStatement implements LanguageStatement {
304
    constructor(private map: string, private key: string, private value: string, private op: () => void) {}
305
    write(writer: LanguageWriter): void {
306
        writer.print(`// TODO: map serialization not implemented`)
307
    }
308
}
309

310

311
class JavaMapForEachStatement implements LanguageStatement {
312
    constructor(private map: string, private key: string, private value: string, private op: () => void) {}
313
    write(writer: LanguageWriter): void {
314
        const entryVar = `${this.map}Entry`
315
        writer.print(`for (Map.Entry<?, ?> ${entryVar}: ${this.map}.entrySet()) {`)
316
        writer.pushIndent()
317
        writer.print(`var ${this.key} = ${entryVar}.getKey();`)
318
        writer.print(`var ${this.value} = ${entryVar}.getValue();`)
319
        this.op()
320
        writer.popIndent()
321
        writer.print(`}`)
322
    }
323
}
324

325
class CppMapForEachStatement implements LanguageStatement {
326
    constructor(private map: string, private key: string, private value: string, private op: () => void) {}
327
    write(writer: LanguageWriter): void {
328
        writer.print(`for (int32_t i = 0; i < ${this.map}.size; i++) {`)
329
        writer.pushIndent()
330
        writer.print(`auto ${this.key} = ${this.map}.keys[i];`)
331
        writer.print(`auto ${this.value} = ${this.map}.values[i];`)
332
        this.op()
333
        writer.popIndent()
334
        writer.print(`}`)
335
    }
336
}
337

338
class CppArrayResizeStatement implements LanguageStatement {
339
    constructor(private array: string, private length: string, private deserializer: string) {}
340
    write(writer: LanguageWriter): void {
341
        writer.print(`${this.deserializer}.resizeArray<std::decay<decltype(${this.array})>::type,
342
        std::decay<decltype(*${this.array}.array)>::type>(&${this.array}, ${this.length});`)
343
    }
344
}
345

346
class CppMapResizeStatement implements LanguageStatement {
347
    constructor(private keyType: string, private valueType: string, private map: string, private size: string, private deserializer: string) {}
348
    write(writer: LanguageWriter): void {
349
        writer.print(`${this.deserializer}.resizeMap<Map_${this.keyType}_${this.valueType}, ${this.keyType}, ${this.valueType}>(&${this.map}, ${this.size});`)
350
    }
351
}
352

353
class TsTupleAllocStatement implements LanguageStatement {
354
    constructor(private tuple: string) {}
355
    write(writer: LanguageWriter): void {
356
        writer.writeStatement(writer.makeAssign(this.tuple, undefined, writer.makeString("[]"), false, false))
357
    }
358
}
359

360
class TsObjectAssignStatement implements LanguageStatement {
361
    constructor(private object: string, private type: Type | undefined, private isDeclare: boolean) {}
362
    write(writer: LanguageWriter): void {
363
        writer.writeStatement(writer.makeAssign(this.object,
364
            this.type,
365
            writer.makeString(`{}`),
366
            this.isDeclare,
367
            false))
368
    }
369
}
370

371
class TsObjectDeclareStatement implements LanguageStatement {
372
    constructor(private object: string, private type: Type | undefined, private fields: readonly FieldRecord[]) {}
373
    write(writer: LanguageWriter): void {
374
        const nameConvertor = new TsObjectDeclareNodeNameConvertor()
375
        // Constructing a new type with all optional fields
376
        const objectType = new Type(`{${this.fields.map(it => {
377
            return `${it.name}?: ${nameConvertor.convert(it.type)}`
378
        }).join(",")}}`)
379
        new TsObjectAssignStatement(this.object, objectType, true).write(writer)
380
    }
381
}
382

383
export class BlockStatement implements LanguageStatement {
384
    constructor(public statements: LanguageStatement[], private inScope: boolean = true) { }
385
    write(writer: LanguageWriter): void {
386
        if (this.inScope) {
387
            writer.print("{")
388
            writer.pushIndent()
389
        }
390
        this.statements.forEach(s => s.write(writer))
391
        if (this.inScope) {
392
            writer.popIndent()
393
            writer.print("}")
394
        }
395
    }
396
}
397

398
export class IfStatement implements LanguageStatement {
399
    constructor(public condition: LanguageExpression,
400
        public thenStatement: LanguageStatement,
401
        public elseStatement: LanguageStatement | undefined) { }
402
    write(writer: LanguageWriter): void {
403
        writer.print(`if (${this.condition.asString()}) {`)
404
        writer.pushIndent()
405
        this.thenStatement.write(writer)
406
        writer.popIndent()
407
        if (this.elseStatement !== undefined) {
408
            writer.print("} else {")
409
            writer.pushIndent()
410
            this.elseStatement.write(writer)
411
            writer.popIndent()
412
            writer.print("}")
413
        } else {
414
            writer.print("}")
415
        }
416

417
    }
418
}
419

420
export type BranchStatement = {expr: LanguageExpression, stmt: LanguageStatement}
421

422
export class MultiBranchIfStatement implements LanguageStatement {
423
    constructor(private readonly statements: BranchStatement[],
424
                private readonly elseStatement: LanguageStatement | undefined) { }
425
    write(writer: LanguageWriter): void {
426
        this.statements.forEach((value, index) => {
427
            const {expr, stmt}= value
428
            if (index == 0) {
429
                writer.print(`if (${expr.asString()}) {`)
430
            } else {
431
                writer.print(`else if (${expr.asString()}) {`)
432
            }
433
            writer.pushIndent()
434
            stmt.write(writer)
435
            writer.popIndent()
436
            writer.print("}")
437
        })
438

439
        if (this.elseStatement !== undefined) {
440
            writer.print(" else {")
441
            writer.pushIndent()
442
            this.elseStatement.write(writer)
443
            writer.popIndent()
444
            writer.print("}")
445
        }
446
    }
447
}
448

449
export class TernaryExpression implements LanguageExpression {
450
    constructor(public condition: LanguageExpression,
451
        public trueExpression: LanguageExpression,
452
        public falseExpression: LanguageExpression) {}
453
    asString(): string {
454
        return `(${this.condition.asString()}) ? (${this.trueExpression.asString()}) : (${this.falseExpression.asString()})`
455
    }
456
}
457

458
export class NaryOpExpression implements LanguageExpression {
459
    constructor(public op: string, public args: LanguageExpression[]) { }
460
    asString(): string {
461
        return `${this.args.map(arg => `(${arg.asString()})`).join(` ${this.op} `)}`
462
    }
463
}
464

465
export class StringExpression implements LanguageExpression {
466
    constructor(public value: string) { }
467
    asString(): string {
468
        return this.value
469
    }
470
}
471

472
export class MethodSignature {
473
    constructor(public returnType: Type, public args: Type[], public defaults: stringOrNone[]|undefined = undefined) {}
474

475
    argName(index: number): string {
476
        return `arg${index}`
477
    }
478
    argDefault(index: number): string|undefined {
479
        return this.defaults?.[index]
480
    }
481
}
482

483
export class NamedMethodSignature extends MethodSignature {
484
    constructor(returnType: Type, args: Type[] = [], public argsNames: string[] = [], defaults: stringOrNone[]|undefined = undefined) {
485
        super(returnType, args, defaults)
486
    }
487

488
    static make(returnType: string, args: {name: string, type: string}[]): NamedMethodSignature {
489
        return new NamedMethodSignature(new Type(returnType), args.map(it => new Type(it.type)), args.map(it => it.name))
490
    }
491

492
    argName(index: number): string {
493
        return this.argsNames[index]
494
    }
495
}
496

497
export class Field {
498
    constructor(
499
        public name: string,
500
        public type: Type,
501
        public modifiers: FieldModifier[] = []
502
    ) {}
503
}
504

505
export class Method {
506
    constructor(
507
        public name: string,
508
        public signature: MethodSignature,
509
        public modifiers: MethodModifier[]|undefined = undefined,
510
        public generics?: string[],
511
    ) {}
512
}
513

514
export function mangleMethodName(method: Method): string {
515
    const argsPostfix = method.signature.args.map(it => {
516
        return Array.from(it.name).filter(it => it.match(/[a-zA-Z]/)).join("")
517
    }).join("_")
518
    return `${method.name}_${argsPostfix}`
519
}
520

521
export interface ObjectArgs {
522
    [name: string]: string
523
}
524

525
export interface PrinterLike {
526
    getOutput(): string[]
527
}
528

529
export abstract class LanguageWriter {
530
    constructor(public printer: IndentedPrinter, public language: Language) {}
531

532
    indentDepth(): number {
533
        return this.printer.indentDepth()
534
    }
535

536
    abstract writeClass(name: string, op: (writer: LanguageWriter) => void, superClass?: string, interfaces?: string[], generics?: string[]): void
537
    abstract writeInterface(name: string, op: (writer: LanguageWriter) => void, superInterfaces?: string[]): void
538
    abstract writeFieldDeclaration(name: string, type: Type, modifiers: string[]|undefined, optional: boolean): void
539
    abstract writeMethodDeclaration(name: string, signature: MethodSignature, modifiers?: MethodModifier[]): void
540
    abstract writeConstructorImplementation(className: string, signature: MethodSignature, op: (writer: LanguageWriter) => void, superCall?: Method): void
541
    abstract writeMethodImplementation(method: Method, op: (writer: LanguageWriter) => void): void
542
    abstract makeAssign(variableName: string, type: Type | undefined, expr: LanguageExpression | undefined, isDeclared: boolean, isConst?: boolean): LanguageStatement;
543
    abstract makeReturn(expr?: LanguageExpression): LanguageStatement;
544
    abstract makeRuntimeType(rt: RuntimeType): LanguageExpression
545
    abstract getObjectAccessor(p: BaseArgConvertor, param: string, value: string, args?: ObjectArgs): string
546
    abstract makeCast(value: LanguageExpression, type: Type): LanguageExpression
547
    abstract makeCast(value: LanguageExpression, type: Type, unsafe: boolean): LanguageExpression
548
    abstract writePrintLog(message: string): void
549
    abstract makeUndefined(): LanguageExpression
550
    abstract makeMapKeyTypeName(c: MapConvertor): string
551
    abstract makeMapValueTypeName(c: MapConvertor): string
552
    abstract makeMapInsert(keyAccessor: string, key: string, valueAccessor: string, value: string): LanguageStatement
553
    abstract makeLoop(counter: string, limit: string): LanguageStatement
554
    abstract makeLoop(counter: string, limit: string, statement: LanguageStatement): LanguageStatement
555
    abstract makeMapForEach(map: string, key: string, value: string, op: () => void): LanguageStatement
556
    abstract getTagType(): Type
557
    abstract getRuntimeType(): Type
558
    abstract makeTupleAssign(receiver: string, tupleFields: string[]): LanguageStatement
559
    abstract get supportedModifiers(): MethodModifier[]
560
    abstract enumFromOrdinal(value: LanguageExpression, enumType: string): LanguageExpression
561
    abstract ordinalFromEnum(value: LanguageExpression, enumType: string): LanguageExpression
562

563
    concat(other: PrinterLike): this {
564
        other.getOutput().forEach(it => this.print(it))
565
        return this
566
    }
567
    printTo(file: string): void {
568
        fs.writeFileSync(file, this.getOutput().join("\n"))
569
    }
570
    writeLines(lines: string): void {
571
        lines.split("\n").forEach(it => this.print(it))
572
    }
573
    writeGetterImplementation(method: Method, op: (writer: LanguageWriter) => void): void {
574
        this.writeMethodImplementation(new Method(method.name, method.signature, [MethodModifier.GETTER].concat(method.modifiers ?? [])), op)
575
    }
576
    writeSetterImplementation(method: Method, op: (writer: LanguageWriter) => void): void {
577
        this.writeMethodImplementation(new Method(method.name, method.signature, [MethodModifier.SETTER].concat(method.modifiers ?? [])), op)
578
    }
579
    writeSuperCall(params: string[]): void {
580
        this.printer.print(`super(${params.join(", ")});`)
581
    }
582
    writeMethodCall(receiver: string, method: string, params: string[], nullable = false): void {
583
        this.printer.print(`${receiver}${nullable ? "?" : ""}.${method}(${params.join(", ")})`)
584
    }
585
    writeStatement(stmt: LanguageStatement) {
586
        //this.printer.print(stmt.asString())
587
        stmt.write(this)
588
    }
589
    makeTag(tag: string): string {
590
        return "Tag." + tag
591
    }
592
    makeRef(varName: string): string {
593
        return varName
594
    }
595
    makeThis(): LanguageExpression {
596
        return new StringExpression("this")
597
    }
598
    makeNull(): LanguageExpression {
599
        return new StringExpression("null")
600
    }
601
    makeRuntimeTypeCondition(typeVarName: string, equals: boolean, type: RuntimeType): LanguageExpression {
602
        const op = equals ? "==" : "!="
603
        return this.makeNaryOp(op, [this.makeRuntimeType(type), this.makeString(typeVarName)])
604
    }
605
    makeValueFromOption(value: string, destinationConvertor: ArgConvertor): LanguageExpression {
606
        return this.makeString(`${value}!`)
607
    }
608
    makeFunctionCall(name: string, params: LanguageExpression[]): LanguageExpression {
609
        return new FunctionCallExpression(name, params)
610
    }
611
    makeMethodCall(receiver: string, method: string, params: LanguageExpression[], nullable?: boolean): LanguageExpression {
612
        return new MethodCallExpression(receiver, method, params, nullable)
613
    }
614
    makeNativeCall(method: string, params: LanguageExpression[], nullable?: boolean): LanguageExpression {
615
        return new MethodCallExpression(this.nativeReceiver(), method, params, nullable)
616
    }
617
    nativeReceiver(): string { return 'nativeModule()' }
618
    makeDefinedCheck(value: string): LanguageExpression {
619
        return new CheckDefinedExpression(value)
620
    }
621
    makeRuntimeTypeDefinedCheck(runtimeType: string): LanguageExpression {
622
        return this.makeRuntimeTypeCondition(runtimeType, false, RuntimeType.UNDEFINED)
623
    }
624
    makeCondition(condition: LanguageExpression, thenStatement: LanguageStatement, elseStatement?: LanguageStatement): LanguageStatement {
625
        return new IfStatement(condition, thenStatement, elseStatement)
626
    }
627
    makeMultiBranchCondition(conditions: BranchStatement[], elseStatement?: LanguageStatement): LanguageStatement {
628
        return new MultiBranchIfStatement(conditions, elseStatement)
629
    }
630
    makeTernary(condition: LanguageExpression, trueExpression: LanguageExpression, falseExpression: LanguageExpression): LanguageExpression {
631
        return new TernaryExpression(condition, trueExpression, falseExpression)
632
    }
633
    makeArrayLength(array: string, length?: string): LanguageExpression {
634
        return this.makeString(`${array}.length`)
635
    }
636
    makeArrayAccess(value: string, indexVar: string) {
637
        return this.makeString(`${value}[${indexVar}]`)
638
    }
639
    makeTupleAccess(value: string, index: number): LanguageExpression {
640
        return this.makeString(`${value}[${index}]`)
641
    }
642
    makeUnionSelector(value: string, valueType: string): LanguageStatement {
643
        return this.makeAssign(valueType, undefined, this.makeString(`runtimeType(${value})`), false)
644
    }
645
    makeUnionVariantCondition(value: string, type: string, index?: number): LanguageExpression {
646
        return this.makeString(`RuntimeType.${type.toUpperCase()} == ${value}`)
647
    }
648
    makeUnionVariantCast(value: string, type: Type, index?: number): LanguageExpression {
649
        return this.makeString(`unsafeCast<${type.name}>(${value})`)
650
    }
651
    makeUnionTypeDefaultInitializer() {
652
        return this.makeRuntimeType(RuntimeType.UNDEFINED)
653
    }
654
    makeRuntimeTypeGetterCall(value: string): LanguageExpression {
655
        return this.makeFunctionCall("runtimeType", [ this.makeString(value) ])
656
    }
657
    makeArrayResize(array: string, typeName: string, length: string, deserializer: string): LanguageStatement {
658
        return new ExpressionStatement(this.makeString(`${array} = [] as ${typeName}`))
659
    }
660
    makeMapResize(keyType: string, valueType: string, map: string, size: string, deserializer: string): LanguageStatement {
661
        return new ExpressionStatement(new StringExpression("// TODO: TS map resize"))
662
    }
663
    makeTupleAlloc(option: string): LanguageStatement {
664
        return new ExpressionStatement(new StringExpression(""))
665
    }
666
    makeObjectAlloc(object: string, fields: readonly FieldRecord[]): LanguageStatement {
667
        return new ExpressionStatement(new StringExpression(""))
668
    }
669
    makeSetUnionSelector(value: string, index: string): LanguageStatement {
670
        // empty expression
671
        return new ExpressionStatement(new StringExpression(""))
672
    }
673
    makeSetOptionTag(value: string, tag: LanguageExpression): LanguageStatement {
674
        // empty expression
675
        return new ExpressionStatement(new StringExpression(""))
676
    }
677
    makeString(value: string): LanguageExpression {
678
        return new StringExpression(value)
679
    }
680
    makeNaryOp(op: string, args: LanguageExpression[]): LanguageExpression {
681
        return new NaryOpExpression(op, args)
682
    }
683
    makeStatement(expr: LanguageExpression): LanguageStatement {
684
        return new ExpressionStatement(expr)
685
    }
686
    writeNativeMethodDeclaration(name: string, signature: MethodSignature): void {
687
        this.writeMethodDeclaration(name, signature)
688
    }
689
    pushIndent() {
690
        this.printer.pushIndent()
691
    }
692
    popIndent() {
693
        this.printer.popIndent()
694
    }
695
    print(string: stringOrNone) {
696
        this.printer.print(string)
697
    }
698
    getOutput(): string[] {
699
        return this.printer.getOutput()
700
    }
701
    mapType(type: Type, convertor?: ArgConvertor): string {
702
        return type.name
703
    }
704
    mapFiledModifier(modifier: FieldModifier): string {
705
        return `${FieldModifier[modifier].toLowerCase()}`
706
    }
707
    mapMethodModifier(modifier: MethodModifier): string {
708
        return `${MethodModifier[modifier].toLowerCase()}`
709
    }
710
    makeObjectDeclare(name: string, type: Type | undefined, fields: readonly FieldRecord[]): LanguageStatement {
711
        return this.makeAssign(name, type, this.makeString("{}"), true, false)
712
    }
713
    makeType(typeName: string, nullable: boolean, receiver?: string): Type {
714
        return new Type(typeName, nullable)
715
    }
716
    makeUnsafeCast(convertor: ArgConvertor, param: string): string {
717
        return `unsafeCast<int32>(${param})`
718
    }
719
    runtimeType(param: ArgConvertor, valueType: string, value: string) {
720
        this.writeStatement(this.makeAssign(valueType, Type.Int32,
721
            this.makeFunctionCall("runtimeType", [this.makeString(value)]), false))
722
    }
723
    makeDiscriminatorFromFields(convertor: BaseArgConvertor, value: string, accessors: string[]): LanguageExpression {
724
        return this.makeString(`(${this.makeNaryOp("||",
725
            accessors.map(it => this.makeString(`${value}!.hasOwnProperty("${it}")`))).asString()})`)
726
    }
727
    makeCallIsResource(value: string) {
728
        return this.makeString(`isResource(${value})`)
729
    }
730
}
731

732
export class TSLanguageWriter extends LanguageWriter {
733
    constructor(printer: IndentedPrinter, language: Language = Language.TS) {
734
        super(printer, language)
735
    }
736
    writeClass(name: string, op: (writer: LanguageWriter) => void, superClass?: string, interfaces?: string[], generics?: string[]): void {
737
        let extendsClause = superClass ? ` extends ${superClass}` : ''
738
        let implementsClause = interfaces ? ` implements ${interfaces.join(",")}` : ''
739
        const genericsClause = generics ? `<${generics.join(", ")}>` : ''
740
        this.printer.print(`export class ${name}${genericsClause}${extendsClause}${implementsClause} {`)
741
        this.pushIndent()
742
        op(this)
743
        this.popIndent()
744
        this.printer.print(`}`)
745
    }
746
    writeInterface(name: string, op: (writer: LanguageWriter) => void, superInterfaces?: string[]): void {
747
        let extendsClause = superInterfaces ? ` extends ${superInterfaces.join(",")}` : ''
748
        this.printer.print(`export interface ${name}${extendsClause} {`)
749
        this.pushIndent()
750
        op(this)
751
        this.popIndent()
752
        this.printer.print(`}`)
753
    }
754
    writeFieldDeclaration(name: string, type: Type, modifiers: string[]|undefined, optional: boolean): void {
755
        this.printer.print(`${modifiers?.join(' ') ?? ""} ${name}${optional ? "?"  : ""}: ${type.name}`)
756
    }
757
    writeMethodDeclaration(name: string, signature: MethodSignature, modifiers?: MethodModifier[]): void {
758
        this.writeDeclaration(name, signature, true, false, modifiers)
759
    }
760
    writeConstructorImplementation(className: string, signature: MethodSignature, op: (writer: LanguageWriter) => void, superCall?: Method) {
761
        this.writeDeclaration('constructor', signature, false, true)
762
        this.pushIndent()
763
        if (superCall) {
764
            this.print(`super(${superCall.signature.args.map((_, i) => superCall?.signature.argName(i)).join(", ")})`)
765
        }
766
        op(this)
767
        this.popIndent()
768
        this.printer.print(`}`)
769

770
    }
771
    writeMethodImplementation(method: Method, op: (writer: LanguageWriter) => void) {
772
        this.writeDeclaration(method.name, method.signature, true, true, method.modifiers, method.generics)
773
        this.pushIndent()
774
        op(this)
775
        this.popIndent()
776
        this.printer.print(`}`)
777
    }
778
    private writeDeclaration(name: string, signature: MethodSignature, needReturn: boolean, needBracket: boolean, modifiers?: MethodModifier[], generics?: string[]) {
779
        let prefix = modifiers
780
            ?.filter(it => this.supportedModifiers.includes(it))
781
            .map(it => this.mapMethodModifier(it)).join(" ")
782
        if (modifiers?.includes(MethodModifier.GETTER)) {
783
            prefix = `get ${prefix}`
784
        } else if (modifiers?.includes(MethodModifier.SETTER)) {
785
            prefix = `set ${prefix}`
786
            needReturn = false
787
        }
788
        prefix = prefix ? prefix + " " : ""
789
        const typeParams = generics ? `<${generics.join(", ")}>` : ""
790
        this.printer.print(`${prefix}${name}${typeParams}(${signature.args.map((it, index) => `${signature.argName(index)}${it.nullable ? "?" : ""}: ${this.mapType(it)}${signature.argDefault(index) ? ' = ' + signature.argDefault(index) : ""}`).join(", ")})${needReturn ? ": " + this.mapType(signature.returnType) : ""} ${needBracket ? "{" : ""}`)
791
    }
792
    makeAssign(variableName: string, type: Type | undefined, expr: LanguageExpression | undefined, isDeclared: boolean = true, isConst: boolean = true): LanguageStatement {
793
        return new AssignStatement(variableName, type, expr, isDeclared, isConst)
794
    }
795
    makeReturn(expr: LanguageExpression): LanguageStatement {
796
        return new TSReturnStatement(expr)
797
    }
798
    makeStatement(expr: LanguageExpression): LanguageStatement {
799
        return new ExpressionStatement(expr)
800
    }
801
    makeLoop(counter: string, limit: string, statement?: LanguageStatement): LanguageStatement {
802
        return new TSLoopStatement(counter, limit, statement)
803
    }
804
    makeMapForEach(map: string, key: string, value: string, op: () => void): LanguageStatement {
805
        return new TSMapForEachStatement(map, key, value, op)
806
    }
807
    writePrintLog(message: string): void {
808
        this.print(`console.log("${message}")`)
809
    }
810
    makeCast(value: LanguageExpression, type: Type, unsafe = false): LanguageExpression {
811
        return new TSCastExpression(value, type, unsafe)
812
    }
813
    getObjectAccessor(convertor: BaseArgConvertor, param: string, value: string, args?: ObjectArgs): string {
814
        if (convertor instanceof OptionConvertor || convertor instanceof UnionConvertor) {
815
            return value
816
        }
817
        if (convertor instanceof ArrayConvertor && args?.index != undefined) {
818
            return `${value}${args.index}`
819
        }
820
        if (convertor instanceof ArrayConvertor) {
821
            return `${value}`
822
        }
823
        if (convertor instanceof TupleConvertor && args?.index != undefined) {
824
            return `${value}[${args.index}]`
825
        }
826
        if (convertor instanceof MapConvertor) {
827
            return `${value}`
828
        }
829
        if (convertor.useArray && args?.index != undefined) {
830
            return `${value}[${args.index}]`
831
        }
832
        return `${value}`
833
    }
834
    makeUndefined(): LanguageExpression {
835
        return this.makeString("undefined")
836
    }
837
    makeRuntimeType(rt: RuntimeType): LanguageExpression {
838
        return this.makeString(`RuntimeType.${RuntimeType[rt]}`)
839
    }
840
    makeTupleAlloc(option: string): LanguageStatement {
841
        return new TsTupleAllocStatement(option)
842
    }
843
    makeObjectAlloc(object: string, fields: readonly FieldRecord[]): LanguageStatement {
844
        if (fields.length > 0) {
845
            return this.makeAssign(object, undefined,
846
                this.makeCast(this.makeString("{}"),
847
                    new Type(`{${fields.map(it=>`${it.name}: ${mapType(it.type)}`).join(",")}}`)),
848
                false)
849
        }
850
        return new TsObjectAssignStatement(object, undefined, false)
851
    }
852
    makeMapResize(keyType: string, valueType: string, map: string, size: string, deserializer: string): LanguageStatement {
853
        return this.makeAssign(map, undefined, this.makeString(`new Map<${keyType}, ${valueType}>()`), false)
854
    }
855
    makeMapKeyTypeName(c: MapConvertor): string {
856
        return c.keyConvertor.tsTypeName;
857
    }
858
    makeMapValueTypeName(c: MapConvertor): string {
859
        return c.valueConvertor.tsTypeName;
860
    }
861
    makeMapInsert(keyAccessor: string, key: string, valueAccessor: string, value: string): LanguageStatement {
862
        // keyAccessor and valueAccessor are equal in TS
863
        return this.makeStatement(this.makeMethodCall(keyAccessor, "set", [this.makeString(key), this.makeString(value)]))
864
    }
865
    makeObjectDeclare(name: string, type: Type, fields: readonly FieldRecord[]): LanguageStatement {
866
        return new TsObjectDeclareStatement(name, type, fields)
867
    }
868
    getTagType(): Type {
869
        return new Type("Tags");
870
    }
871
    getRuntimeType(): Type {
872
        return new Type("number");
873
    }
874
    makeTupleAssign(receiver: string, fields: string[]): LanguageStatement {
875
        return this.makeAssign(receiver, undefined,
876
            this.makeString(`[${fields.map(it=> `${it}!`).join(",")}]`), false)
877
    }
878
    get supportedModifiers(): MethodModifier[] {
879
        return [MethodModifier.PUBLIC, MethodModifier.PRIVATE, MethodModifier.STATIC]
880
    }
881
    enumFromOrdinal(value: LanguageExpression, enumType: string): LanguageExpression {
882
        return this.makeString(`Object.values(${enumType})[${value.asString()}]`);
883
    }
884
    ordinalFromEnum(value: LanguageExpression, enumType: string): LanguageExpression {
885
        return this.makeString(`Object.keys(${enumType}).indexOf(${this.makeCast(value, new Type('string')).asString()})`);
886
    }
887
    mapType(type: Type, convertor?: ArgConvertor): string {
888
        switch (type.name) {
889
            case 'Function': return 'Object'
890
        }
891
        return type.name
892
    }
893
}
894

895
export class ETSLanguageWriter extends TSLanguageWriter {
896
    constructor(printer: IndentedPrinter) {
897
        super(printer, Language.ARKTS)
898
    }
899
    writeNativeMethodDeclaration(name: string, signature: MethodSignature): void {
900
        this.writeMethodDeclaration(name, signature, [MethodModifier.STATIC, MethodModifier.NATIVE])
901
    }
902
    makeAssign(variableName: string, type: Type | undefined, expr: LanguageExpression, isDeclared: boolean = true, isConst: boolean = true): LanguageStatement {
903
        return new EtsAssignStatement(variableName, type, expr, isDeclared, isConst)
904
    }
905
    makeMapForEach(map: string, key: string, value: string, op: () => void): LanguageStatement {
906
        return new ArkTSMapForEachStatement(map, key, value, op)
907
    }
908
    mapType(type: Type, convertor?: ArgConvertor): string {
909
        if (convertor instanceof EnumConvertor) {
910
            return 'int'
911
        }
912
        if (convertor instanceof AggregateConvertor && convertor.aliasName !== undefined) {
913
            return convertor.aliasName
914
        }
915
        if (convertor instanceof ArrayConvertor) {
916
            return `${convertor.elementTypeName()}[]`
917
        }
918
        switch (type.name) {
919
            case 'KPointer': return 'long'
920
            case 'Uint8Array': return 'byte[]'
921
            case 'int32': case 'KInt': return 'int'
922
            case 'KStringPtr': return 'String'
923
            case 'KLength': return 'Object'
924
            case 'number': return 'double'
925
        }
926
        return super.mapType(type)
927
    }
928
    get supportedModifiers(): MethodModifier[] {
929
        return [MethodModifier.PUBLIC, MethodModifier.PRIVATE, MethodModifier.NATIVE, MethodModifier.STATIC]
930
    }
931
    nativeReceiver(): string { return 'NativeModule' }
932
    makeUnsafeCast(convertor: ArgConvertor, param: string): string {
933
        if (convertor instanceof EnumConvertor) {
934
            return `${param} as int32`
935
        }
936
        return super.makeUnsafeCast(convertor, param)
937
    }
938
    runtimeType(param: ArgConvertor, valueType: string, value: string) {
939
        if (param instanceof OptionConvertor) {
940
            this.writeStatement(this.makeCondition(this.makeString(`${value} != undefined`), this.makeAssign(valueType, undefined,
941
                this.makeRuntimeType(RuntimeType.OBJECT), false)))
942
        } else {
943
            super.runtimeType(param, valueType, value);
944
        }
945
    }
946
    makeUnionSelector(value: string, valueType: string): LanguageStatement {
947
        let statements = [this.makeAssign("type", undefined, this.makeString(`typeof ${value}`))]
948
        Object.keys(RuntimeType)
949
            .filter((value) => isNaN(Number(value)))
950
            .forEach((value) => {
951
                statements.push(
952
                    this.makeCondition(this.makeNaryOp("==", [this.makeString("type"), this.makeString(`"${value.toLowerCase()}"`)]),
953
                        this.makeAssign(valueType, undefined, this.makeString(`RuntimeType.${value}`), false))
954
                )
955
        })
956
        return new BlockStatement(statements)
957
    }
958
    makeUnionVariantCast(value: string, type: Type, index?: number): LanguageExpression {
959
        return this.makeString(`${value} as ${type.name}`)
960
    }
961
    ordinalFromEnum(value: LanguageExpression, enumType: string): LanguageExpression {
962
        return this.makeCast(value, new Type('int'));
963
    }
964
    makeDiscriminatorFromFields(convertor: BaseArgConvertor, value: string, accessors: string[]): LanguageExpression {
965
        return this.makeString(`${value} instanceof ${convertor.targetType(this).name}`)
966
    }
967
    makeValueFromOption(value: string, destinationConvertor: ArgConvertor): LanguageExpression {
968
        // This preventing arkts compiler from segfault. No need to apply the assertion operator (!) to enum.
969
        if (destinationConvertor instanceof EnumConvertor) {
970
            return this.makeString(`${value}`)
971
        }
972
        return super.makeValueFromOption(value, destinationConvertor)
973
    }
974
    makeCallIsResource(value: string): LanguageExpression {
975
        return this.makeString(`(${value} instanceof Resource)`);
976
    }
977
}
978

979
abstract class CLikeLanguageWriter extends LanguageWriter {
980
    protected constructor(printer: IndentedPrinter, language: Language) {
981
        super(printer, language)
982
    }
983
    writeMethodCall(receiver: string, method: string, params: string[], nullable = false): void {
984
        this.printer.print(`${receiver}.${method}(${params.join(", ")});`)
985
    }
986
    writeMethodDeclaration(name: string, signature: MethodSignature, modifiers?: MethodModifier[]): void {
987
        this.writeDeclaration(name, signature, modifiers, ";")
988
    }
989
    writeMethodImplementation(method: Method, op: (writer: LanguageWriter) => void) {
990
        this.writeDeclaration(method.name, method.signature, method.modifiers, " {")
991
        this.pushIndent()
992
        op(this)
993
        this.popIndent()
994
        this.printer.print(`}`)
995
    }
996
    private writeDeclaration(name: string, signature: MethodSignature, modifiers?: MethodModifier[], postfix?: string): void {
997
        let prefix = modifiers
998
            ?.filter(it => this.supportedModifiers.includes(it))
999
            .map(it => this.mapMethodModifier(it)).join(" ")
1000
        prefix = prefix ? prefix + " " : ""
1001
        this.print(`${prefix}${this.mapType(signature.returnType)} ${name}(${signature.args.map((it, index) => `${this.mapType(it)} ${signature.argName(index)}`).join(", ")})${postfix ?? ""}`)
1002
    }
1003
}
1004

1005
export class JavaLanguageWriter extends CLikeLanguageWriter {
1006
    constructor(printer: IndentedPrinter) {
1007
        super(printer, Language.JAVA)
1008
    }
1009
    writeClass(name: string, op: (writer: LanguageWriter) => void, superClass?: string, interfaces?: string[]): void {
1010
        let extendsClause = superClass ? ` extends ${superClass}` : ''
1011
        let implementsClause = interfaces ? ` implements ${interfaces.join(",")}` : ''
1012
        this.printer.print(`class ${name}${extendsClause}${implementsClause} {`)
1013
        this.pushIndent()
1014
        op(this)
1015
        this.popIndent()
1016
        this.printer.print(`}`)
1017
    }
1018
    writeInterface(name: string, op: (writer: LanguageWriter) => void, superInterfaces?: string[]): void {
1019
        let extendsClause = superInterfaces ? ` extends ${superInterfaces.join(",")}` : ''
1020
        this.printer.print(`interface ${name}${extendsClause} {`)
1021
        this.pushIndent()
1022
        op(this)
1023
        this.popIndent()
1024
        this.printer.print(`}`)
1025
    }
1026
    writeMethodCall(receiver: string, method: string, params: string[], nullable = false): void {
1027
        if (nullable) {
1028
            this.printer.print(`if (${receiver} != null) ${receiver}.${method}(${params.join(", ")});`)
1029
        } else {
1030
            super.writeMethodCall(receiver, method, params, nullable)
1031
        }
1032
    }
1033
    writeFieldDeclaration(name: string, type: Type, modifiers: string[]|undefined, optional: boolean): void {
1034
        this.printer.print(`${modifiers?.join(' ') ?? ""}  ${type.name} ${name}${optional ? " = null"  : ""};`)
1035
    }
1036
    writeNativeMethodDeclaration(name: string, signature: MethodSignature): void {
1037
        this.writeMethodDeclaration(name, signature, [MethodModifier.STATIC, MethodModifier.NATIVE])
1038
    }
1039
    writeConstructorImplementation(className: string, signature: MethodSignature, op: (writer: LanguageWriter) => void, superCall?: Method) {
1040
        this.printer.print(`${className}(${signature.args.map((it, index) => `${this.mapType(it)} ${signature.argName(index)}`).join(", ")}) {`)
1041
        this.pushIndent()
1042
        if (superCall) {
1043
            this.print(`super(${superCall.signature.args.map((_, i) => superCall?.signature.argName(i)).join(", ")});`)
1044
        }
1045
        op(this)
1046
        this.popIndent()
1047
        this.printer.print(`}`)
1048
    }
1049
    makeAssign(variableName: string, type: Type | undefined, expr: LanguageExpression, isDeclared: boolean = true, isConst: boolean = true): LanguageStatement {
1050
        return new JavaAssignStatement(variableName, type, expr, isDeclared, isConst)
1051
    }
1052
    makeReturn(expr: LanguageExpression): LanguageStatement {
1053
        return new CLikeReturnStatement(expr)
1054
    }
1055
    makeDefinedCheck(value: string): LanguageExpression {
1056
        return new JavaCheckDefinedExpression(value)
1057
    }
1058
    makeLoop(counter: string, limit: string, statement?: LanguageStatement): LanguageStatement {
1059
        return new CLikeLoopStatement(counter, limit, statement)
1060
    }
1061
    makeMapForEach(map: string, key: string, value: string, op: () => void): LanguageStatement {
1062
        return new JavaMapForEachStatement(map, key, value, op)
1063
    }
1064
    makeCast(value: LanguageExpression, type: Type, unsafe = false): LanguageExpression {
1065
        return new JavaCastExpression(value, type, unsafe)
1066
    }
1067
    makeStatement(expr: LanguageExpression): LanguageStatement {
1068
        return new CLikeExpressionStatement(expr)
1069
    }
1070
    makeUnionSelector(value: string, valueType: string): LanguageStatement {
1071
        return this.makeAssign(valueType, undefined, this.makeMethodCall(value, "getSelector", []), false)
1072
    }
1073
    makeUnionVariantCondition(value: string, type: string, index: number): LanguageExpression {
1074
        return this.makeString(`${value} == ${index}`)
1075
    }
1076
    makeUnionVariantCast(value: string, type: Type, index: number) {
1077
        return this.makeMethodCall(value, `getValue${index}`, [])
1078
    }
1079
    makeUnionTypeDefaultInitializer() {
1080
        return this.makeString("-1")
1081
    }
1082
    writePrintLog(message: string): void {
1083
        this.print(`System.out.println("${message}")`)
1084
    }
1085
    mapType(type: Type): string {
1086
        switch (type.name) {
1087
            case 'KPointer': return 'long'
1088
            case 'Uint8Array': return 'byte[]'
1089
            case 'int32': case 'KInt': return 'int'
1090
            case 'KStringPtr': return 'String'
1091
            case 'string': return 'String'
1092
            case 'number': return 'double'
1093
        }
1094
        return super.mapType(type)
1095
    }
1096
    applyToObject(p: BaseArgConvertor, param: string, value: string, args?: ObjectArgs): LanguageStatement {
1097
        throw new Error("Method not implemented.")
1098
    }
1099
    getObjectAccessor(convertor: BaseArgConvertor, param: string, value: string, args?: ObjectArgs): string {
1100
        throw new Error("Method not implemented.")
1101
    }
1102
    makeUndefined(): LanguageExpression {
1103
        return this.makeString("undefined")
1104
    }
1105
    makeRuntimeType(rt: RuntimeType): LanguageExpression {
1106
        return this.makeString(`RuntimeType.${RuntimeType[rt]}`)
1107
    }
1108
    makeRuntimeTypeGetterCall(value: string): LanguageExpression {
1109
        const call = this.makeMethodCall(value, "getRuntimeType", []).asString()
1110
        return this.makeString(`${call}`)
1111
    }
1112
    makeMapKeyTypeName(c: MapConvertor): string {
1113
        throw new Error("Method not implemented.")
1114
    }
1115
    makeMapValueTypeName(c: MapConvertor): string {
1116
        throw new Error("Method not implemented.")
1117
    }
1118
    makeMapInsert(keyAccessor: string, key: string, valueAccessor: string, value: string): LanguageStatement {
1119
        throw new Error("Method not implemented.")
1120
    }
1121
    getTagType(): Type {
1122
        throw new Error("Method not implemented.")
1123
    }
1124
    getRuntimeType(): Type {
1125
        throw new Error("Method not implemented.")
1126
    }
1127
    makeTupleAssign(receiver: string, tupleFields: string[]): LanguageStatement {
1128
        throw new Error("Method not implemented.")
1129
    }
1130
    get supportedModifiers(): MethodModifier[] {
1131
        return [MethodModifier.PUBLIC, MethodModifier.PRIVATE, MethodModifier.STATIC, MethodModifier.NATIVE]
1132
    }
1133
    makeTupleAccess(value: string, index: number): LanguageExpression {
1134
        return this.makeString(`${value}.value${index}`)
1135
    }
1136
    enumFromOrdinal(value: LanguageExpression, enumType: string): LanguageExpression {
1137
        throw new Error("Method not implemented.")
1138
    }
1139
    ordinalFromEnum(value: LanguageExpression, enumType: string): LanguageExpression {
1140
        throw new Error("Method not implemented.")
1141
    }
1142
    makeValueFromOption(value: string): LanguageExpression {
1143
        return this.makeString(`${value}.value`)
1144
    }
1145
    runtimeType(param: ArgConvertor, valueType: string, value: string) {
1146
        this.writeStatement(this.makeAssign(valueType, undefined,
1147
            this.makeRuntimeTypeGetterCall(value), false))
1148
    }
1149
}
1150

1151
export class CppLanguageWriter extends CLikeLanguageWriter {
1152
    constructor(printer: IndentedPrinter) {
1153
        super(printer, Language.CPP)
1154
    }
1155
    writeClass(name: string, op: (writer: LanguageWriter) => void, superClass?: string, interfaces?: string[]): void {
1156
        const superClasses = (superClass ? [superClass] : []).concat(interfaces ?? [])
1157
        const extendsClause = superClasses ? ` : ${superClasses.map(c => `public ${c}`).join(", ")}` : ''
1158
        this.printer.print(`class ${name}${extendsClause} {`)
1159
        this.pushIndent()
1160
        op(this)
1161
        this.popIndent()
1162
        this.printer.print(`};`)
1163
    }
1164
    writeInterface(name: string, op: (writer: LanguageWriter) => void, superInterfaces?: string[]): void {
1165
        throw new Error("Method not implemented.")
1166
    }
1167
    writeMethodCall(receiver: string, method: string, params: string[], nullable = false): void {
1168
        if (nullable) {
1169
            this.printer.print(`if (${receiver}) ${receiver}.${method}(${params.join(", ")});`)
1170
        } else {
1171
            super.writeMethodCall(receiver, method, params, nullable)
1172
        }
1173
    }
1174
    writeFieldDeclaration(name: string, type: Type, modifiers: string[] | undefined, optional: boolean): void {
1175
        const modifier = modifiers?.find(mod => mod !== "static")
1176
        if (modifier) {
1177
            this.printer.print(`${modifier}:`)
1178
        }
1179
        this.printer.pushIndent()
1180
        this.printer.print(`${type.name} ${name};`)
1181
        this.printer.popIndent()
1182
    }
1183
    writeConstructorImplementation(className: string, signature: MethodSignature, op: (writer: LanguageWriter) => void, superCall?: Method) {
1184
        const superInvocation = superCall
1185
            ? ` : ${superCall.name}(${superCall.signature.args.map((_, i) => superCall?.signature.argName(i)).join(", ")})`
1186
            : ""
1187
        const argList = signature.args.map((it, index) => `${this.mapType(it)} ${signature.argName(index)}`).join(", ");
1188
        this.print("public:")
1189
        this.print(`${className}(${argList})${superInvocation} {`)
1190
        this.pushIndent()
1191
        op(this)
1192
        this.popIndent()
1193
        this.print(`}`)
1194
    }
1195

1196
    /**
1197
     * Writes multiline comments decorated with stars
1198
     */
1199
    writeMultilineCommentBlock(lines: string) {
1200
        this.print('/*')
1201
        lines.split("\n").forEach(it => this.print(' * ' + it))
1202
        this.print(' */')
1203
    }
1204

1205
    /**
1206
     * Writes `#include "path"`
1207
     * @param path File path to be included
1208
     */
1209
    writeInclude(path: string) {
1210
        this.print(`#include "${path}"`)
1211
    }
1212

1213
    /**
1214
     * Writes `#include <path>`
1215
     * @param path File path to be included
1216
     */
1217
    writeGlobalInclude(path: string) {
1218
        this.print(`#include <${path}>`)
1219
    }
1220

1221
    /**
1222
     * Writes `namespace <namespace> {` and adds extra indent
1223
     * @param namespace Namespace to begin
1224
     */
1225
    pushNamespace(namespace: string) {
1226
        this.print(`namespace ${namespace} {`)
1227
        this.pushIndent()
1228
    }
1229

1230
    /**
1231
     * Writes closing brace of namespace block and removes one level of indent
1232
     */
1233
    popNamespace() {
1234
        this.popIndent()
1235
        this.print(`}`)
1236
    }
1237

1238
    override makeTag(tag: string): string {
1239
        return "ARK_TAG_" + tag
1240
    }
1241
    override makeRef(varName: string): string {
1242
        return `${varName}&`
1243
    }
1244
    override makeThis(): LanguageExpression {
1245
        return new StringExpression("*this")
1246
    }
1247
    override makeNull(): LanguageExpression {
1248
        return new StringExpression("nullptr")
1249
    }
1250
    override makeValueFromOption(value: string): LanguageExpression {
1251
        return this.makeString(`${value}.value`)
1252
    }
1253
    makeAssign(variableName: string, type: Type | undefined, expr: LanguageExpression | undefined, isDeclared: boolean = true, isConst: boolean = true): LanguageStatement {
1254
        return new CppAssignStatement(variableName, type, expr, isDeclared, isConst)
1255
    }
1256
    makeReturn(expr: LanguageExpression): LanguageStatement {
1257
        return new CLikeReturnStatement(expr)
1258
    }
1259
    makeStatement(expr: LanguageExpression): LanguageStatement {
1260
        return new CLikeExpressionStatement(expr)
1261
    }
1262
    override makeArrayAccess(value: string, indexVar: string) {
1263
        return this.makeString(`${value}.array[${indexVar}]`)
1264
    }
1265
    override makeTupleAccess(value: string, index: number): LanguageExpression {
1266
        return this.makeString(`${value}.value${index}`)
1267
    }
1268
    override makeUnionSelector(value: string, valueType: string): LanguageStatement {
1269
        return this.makeAssign(valueType, undefined, this.makeString(`${value}.selector`), false)
1270
    }
1271
    override makeUnionVariantCondition(value: string, type: string, index: number) {
1272
        return this.makeString(`${value} == ${index}`)
1273
    }
1274
    override makeUnionVariantCast(value: string, type: Type, index: number) {
1275
        return this.makeString(`${value}.value${index}`)
1276
    }
1277
    makeLoop(counter: string, limit: string, statement?: LanguageStatement): LanguageStatement {
1278
        return new CLikeLoopStatement(counter, limit, statement)
1279
    }
1280
    makeMapForEach(map: string, key: string, value: string, op: () => void): LanguageStatement {
1281
        return new CppMapForEachStatement(map, key, value, op)
1282
    }
1283
    makeArrayResize(array: string, typeName: string, length: string, deserializer: string): LanguageStatement {
1284
        return new CppArrayResizeStatement(array, length, deserializer)
1285
    }
1286
    makeMapResize(keyType: string, valueType: string, map: string, size: string, deserializer: string): LanguageStatement {
1287
        return new CppMapResizeStatement(keyType, valueType, map, size, deserializer)
1288
    }
1289
    makeCast(expr: LanguageExpression, type: Type, unsafe = false): LanguageExpression {
1290
        return new CppCastExpression(expr, type, unsafe)
1291
    }
1292
    writePrintLog(message: string): void {
1293
        this.print(`printf("${message}\n")`)
1294
    }
1295
    makeDefinedCheck(value: string): LanguageExpression {
1296
        return new CDefinedExpression(value);
1297
    }
1298
    mapType(type: Type): string {
1299
        switch (type.name) {
1300
            case 'KPointer': return 'void*'
1301
            case 'Uint8Array': return 'byte[]'
1302
            case 'int32':
1303
            case 'KInt': return 'int32_t'
1304
            case 'string':
1305
            case 'KStringPtr': return 'Ark_String'
1306
            case 'number': return 'Ark_Number'
1307
            case 'boolean': return 'Ark_Boolean'
1308
            case 'Function': return `Ark_Function`
1309
            case 'Length': return 'Ark_Length'
1310
            // TODO: oh no
1311
            case 'Array<string[]>' : return `Array_Array_${PrimitiveType.String.getText()}`
1312
        }
1313
        if (type.name.startsWith("Array<")) {
1314
            const typeSpec = type.name.match(/<(.*)>/)!
1315
            const elementType = this.mapType(new Type(typeSpec[1]))
1316
            return `Array_${elementType}`
1317
        }
1318
        if (!type.name.includes("std::decay<") && type.name.includes("<")) {
1319
            return type.name.replace(/<(.*)>/, "")
1320
        }
1321
        return super.mapType(type)
1322
    }
1323
    makeSetUnionSelector(value: string, index: string): LanguageStatement {
1324
        return this.makeAssign(`${value}.selector`, undefined, this.makeString(index), false)
1325
    }
1326
    makeSetOptionTag(value: string, tag: LanguageExpression): LanguageStatement {
1327
        return this.makeAssign(`${value}.tag`, undefined, tag, false)
1328
    }
1329
    getObjectAccessor(convertor: BaseArgConvertor, param: string, value: string, args?: ObjectArgs): string {
1330
        if (convertor instanceof OptionConvertor) {
1331
            return `${value}.value`
1332
        }
1333
        if (convertor instanceof ArrayConvertor && args?.index) {
1334
            return `${value}.array${args.index}`
1335
        }
1336
        if ((convertor instanceof UnionConvertor || convertor instanceof TupleConvertor) && args?.index) {
1337
            return `${value}.value${args.index}`
1338
        }
1339
        if (convertor instanceof MapConvertor && args?.index && args?.field) {
1340
            return `${value}.${args.field}[${args.index}]`
1341
        }
1342
        return value
1343
    }
1344
    makeUndefined(): LanguageExpression {
1345
        return this.makeString(`${PrimitiveType.Undefined.getText()}()`)
1346
    }
1347
    makeRuntimeType(rt: RuntimeType): LanguageExpression {
1348
        return this.makeString(`ARK_RUNTIME_${RuntimeType[rt]}`)
1349
    }
1350
    makeMapKeyTypeName(c: MapConvertor): string {
1351
        return c.table.computeTargetName(c.table.toTarget(c.keyType), false)
1352
    }
1353
    makeMapValueTypeName(c: MapConvertor): string {
1354
        return c.table.computeTargetName(c.table.toTarget(c.valueType), false)
1355
    }
1356
    makeMapInsert(keyAccessor: string, key: string, valueAccessor: string, value: string): LanguageStatement {
1357
        // TODO: maybe use std::move?
1358
        return new BlockStatement([
1359
            this.makeAssign(keyAccessor, undefined, this.makeString(key), false),
1360
            this.makeAssign(valueAccessor, undefined, this.makeString(value), false)
1361
        ], false)
1362
    }
1363
    getTagType(): Type {
1364
        return new Type(PrimitiveType.Tag.getText())
1365
    }
1366
    getRuntimeType(): Type {
1367
        return new Type(PrimitiveType.RuntimeType.getText())
1368
    }
1369
    makeType(typeName: string, nullable: boolean, receiver?: string): Type {
1370
        // make deducing type from receiver
1371
        if (receiver != undefined) {
1372
            return new Type(`std::decay<decltype(${receiver})>::type`)
1373
        }
1374
        return new Type(typeName)
1375
    }
1376
    makeTupleAssign(receiver: string, tupleFields: string[]): LanguageStatement {
1377
        const statements =
1378
            tupleFields.map((field, index) => {
1379
                //TODO: maybe use std::move?
1380
                return this.makeAssign(`${receiver}.value${index}`, undefined, this.makeString(field), false)
1381
            })
1382
        return new BlockStatement(statements, false)
1383
    }
1384
    get supportedModifiers(): MethodModifier[] {
1385
        return [MethodModifier.INLINE, MethodModifier.STATIC]
1386
    }
1387
    enumFromOrdinal(value: LanguageExpression, enumType: string): LanguageExpression {
1388
        return value;
1389
    }
1390
    ordinalFromEnum(value: LanguageExpression, enumType: string): LanguageExpression {
1391
        return value;
1392
    }
1393
    makeUnsafeCast(convertor: ArgConvertor, param: string): string {
1394
        return param
1395
    }
1396
}
1397

1398
export function createLanguageWriter(language: Language): LanguageWriter {
1399
    switch (language) {
1400
        case Language.TS: return new TSLanguageWriter(new IndentedPrinter())
1401
        case Language.ARKTS: return new ETSLanguageWriter(new IndentedPrinter())
1402
        case Language.JAVA: return new JavaLanguageWriter(new IndentedPrinter())
1403
        case Language.CPP: return new CppLanguageWriter(new IndentedPrinter())
1404
        default: throw new Error(`Language ${language.toString()} is not supported`)
1405
    }
1406
}
1407

1408
class TsObjectDeclareNodeNameConvertor extends TSTypeNodeNameConvertor {
1409
    private useOptionalTypes = true
1410

1411
    override convertTuple(node: ts.TupleTypeNode): string {
1412
        this.useOptionalTypes = false
1413
        const name = super.convertTuple(node);
1414
        this.useOptionalTypes = true
1415
        return name
1416
    }
1417
    override convertOptional(node: ts.OptionalTypeNode): string {
1418
        let name = super.convertOptional(node);
1419
        if (!this.useOptionalTypes) {
1420
            name = name.replace("?", "")
1421
        }
1422
        return name
1423
    }
1424
    override convertImport(_node: ts.ImportTypeNode): string {
1425
        //TODO: to preventing an error IMPORT_* types were  not found
1426
        return "object"
1427
    }
1428
    override convert(node: ts.Node | undefined): string {
1429
        if (node) {
1430
            return super.convert(node)
1431
        }
1432
        return "undefined";
1433
    }
1434
}

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.