idlize
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
16import { IndentedPrinter } from "../IndentedPrinter";
17import { Language, stringOrNone } from "../util";
18import {
19AggregateConvertor,
20ArgConvertor,
21ArrayConvertor,
22BaseArgConvertor,
23EnumConvertor,
24MapConvertor,
25OptionConvertor,
26TupleConvertor,
27UnionConvertor
28} from "./Convertors";
29import { FieldRecord, PrimitiveType } from "./DeclarationTable";
30import { RuntimeType } from "./PeerGeneratorVisitor";
31import { mapType, TSTypeNodeNameConvertor } from "./TypeNodeNameConvertor";
32
33import * as ts from "typescript"
34import * as fs from "fs"
35import { PeerFile } from "./PeerFile";
36import { PeerGeneratorConfig } from "./PeerGeneratorConfig";
37
38export class Type {
39constructor(public name: string, public nullable = false) {}
40static Int32 = new Type('int32')
41static Boolean = new Type('boolean')
42static Number = new Type('number')
43static Pointer = new Type('KPointer')
44static This = new Type('this')
45static Void = new Type('void')
46}
47
48export enum FieldModifier {
49READONLY,
50}
51
52export enum MethodModifier {
53PUBLIC,
54PRIVATE,
55STATIC,
56NATIVE,
57INLINE,
58GETTER,
59SETTER,
60}
61
62export interface LanguageStatement {
63write(writer: LanguageWriter): void
64}
65
66export interface LanguageExpression {
67asString(): string
68}
69
70export class AssignStatement implements LanguageStatement {
71constructor(public variableName: string,
72public type: Type | undefined,
73public expression: LanguageExpression | undefined,
74public isDeclared: boolean = true,
75protected isConst: boolean = true) { }
76write(writer: LanguageWriter): void {
77if (this.isDeclared) {
78const typeSpec = this.type ? `: ${writer.mapType(this.type)}${this.type.nullable ? "|undefined" : ""}` : ""
79const initValue = this.expression ? `= ${this.expression.asString()}` : ""
80const constSpec = this.isConst ? "const" : "let"
81writer.print(`${constSpec} ${this.variableName}${typeSpec} ${initValue}`)
82} else {
83writer.print(`${this.variableName} = ${this.expression?.asString()}`)
84}
85}
86}
87
88export class DeclareStatement implements LanguageStatement {
89constructor(public variableName: string,
90public type: Type,
91public expression: LanguageExpression | undefined = undefined) { }
92write(writer: LanguageWriter): void {
93const type = this.type ? `: ${this.type.name}` : ""
94if (this.expression) {
95writer.print(`const ${this.variableName}${type} = ${this.expression.asString()}`)
96} else {
97writer.print(`let ${this.variableName}${type}`)
98}
99}
100}
101
102export class JavaAssignStatement extends AssignStatement {
103constructor(public variableName: string,
104public type: Type | undefined,
105public expression: LanguageExpression,
106public isDeclared: boolean = true,
107protected isConst: boolean = true) {
108super(variableName, type, expression, isDeclared, isConst)
109}
110write(writer: LanguageWriter): void{
111if (this.isDeclared) {
112const typeSpec = this.type ? writer.mapType(this.type) : "var"
113writer.print(`${typeSpec} ${this.variableName} = ${this.expression.asString()};`)
114} else {
115writer.print(`${this.variableName} = ${this.expression.asString()};`)
116}
117}
118}
119
120export class EtsAssignStatement implements LanguageStatement {
121constructor(public variableName: string,
122public type: Type | undefined,
123public expression: LanguageExpression,
124public isDeclared: boolean = true,
125protected isConst: boolean = true) { }
126write(writer: LanguageWriter): void {
127if (this.isDeclared) {
128const typeSpec = ""
129writer.print(`${this.isConst ? "const" : "let"} ${this.variableName}${typeSpec} = ${this.expression.asString()}`)
130} else {
131writer.print(`${this.variableName} = ${this.expression.asString()}`)
132}
133}
134}
135
136export class CppAssignStatement extends AssignStatement {
137constructor(public variableName: string,
138public type: Type | undefined,
139public expression: LanguageExpression | undefined,
140public isDeclared: boolean = true,
141public isConst: boolean = true) {
142super(variableName, type, expression, isDeclared, isConst)
143}
144write(writer: LanguageWriter): void{
145if (this.isDeclared) {
146const typeSpec = this.type ? writer.mapType(this.type) : "auto"
147const initValue = this.expression ? this.expression.asString() : "{}"
148const constSpec = this.isConst ? "const " : ""
149writer.print(`${constSpec}${typeSpec} ${this.variableName} = ${initValue};`)
150} else {
151writer.print(`${this.variableName} = ${this.expression!.asString()};`)
152}
153}
154}
155
156export class CDefinedExpression implements LanguageExpression {
157constructor(private value: string) { }
158asString(): string {
159return `${this.value} != ARK_TAG_UNDEFINED`
160}
161}
162
163export class CheckDefinedExpression implements LanguageExpression {
164constructor(private value: string) { }
165asString(): string {
166return `${this.value} != "undefined"`
167}
168}
169
170export class JavaCheckDefinedExpression implements LanguageExpression {
171constructor(private value: string) { }
172asString(): string {
173return `${this.value} != null`
174}
175}
176
177export class FunctionCallExpression implements LanguageExpression {
178constructor(
179private name: string,
180private params: LanguageExpression[]) { }
181asString(): string {
182return `${this.name}(${this.params.map(it => it.asString()).join(", ")})`
183}
184}
185
186export class MethodCallExpression extends FunctionCallExpression {
187constructor(
188public receiver: string,
189method: string,
190params: LanguageExpression[],
191public nullable = false)
192{
193super(method, params)
194}
195asString(): string {
196return `${this.receiver}${this.nullable ? "?" : ""}.${super.asString()}`
197}
198}
199
200export class ExpressionStatement implements LanguageStatement {
201constructor(public expression: LanguageExpression) { }
202write(writer: LanguageWriter): void {
203const text = this.expression.asString()
204if (text.length > 0) {
205writer.print(`${this.expression.asString()}`)
206}
207}
208}
209
210export class CLikeExpressionStatement extends ExpressionStatement {
211constructor(public expression: LanguageExpression) { super(expression) }
212write(writer: LanguageWriter): void {
213const text = this.expression.asString()
214if (text.length > 0) {
215writer.print(`${this.expression.asString()};`)
216}
217}
218}
219
220export class ReturnStatement implements LanguageStatement {
221constructor(public expression?: LanguageExpression) { }
222write(writer: LanguageWriter): void {
223writer.print(this.expression ? `return ${this.expression.asString()}` : "return")
224}
225}
226
227export class TSReturnStatement extends ReturnStatement {
228constructor(public expression: LanguageExpression) { super(expression) }
229}
230
231export class CLikeReturnStatement extends ReturnStatement {
232constructor(public expression: LanguageExpression) { super(expression) }
233write(writer: LanguageWriter): void {
234writer.print(this.expression ? `return ${this.expression.asString()};` : "return;")
235}
236}
237
238export class TSCastExpression implements LanguageExpression {
239constructor(public value: LanguageExpression, public type: Type, private unsafe = false) {}
240asString(): string {
241return this.unsafe
242? `unsafeCast<${this.type.name}>(${this.value.asString()})`
243: `(${this.value.asString()} as ${this.type.name})`
244}
245}
246
247export class JavaCastExpression implements LanguageExpression {
248constructor(public value: LanguageExpression, public type: Type, private unsafe = false) {}
249asString(): string {
250return `(${this.type.name})(${this.value.asString()})`
251}
252}
253
254export class CppCastExpression implements LanguageExpression {
255constructor(public value: LanguageExpression, public type: Type, private unsafe = false) {}
256asString(): string {
257if (this.type.name === PrimitiveType.Tag.getText()) {
258return `${this.value.asString()} == ARK_RUNTIME_UNDEFINED ? ARK_TAG_UNDEFINED : ARK_TAG_OBJECT`
259}
260return this.unsafe
261? `reinterpret_cast<${this.type.name}>(${this.value.asString()})`
262: `static_cast<${this.type.name}>(${this.value.asString()})`
263}
264}
265
266class TSLoopStatement implements LanguageStatement {
267constructor(private counter: string, private limit: string, private statement: LanguageStatement | undefined) {}
268write(writer: LanguageWriter): void {
269writer.print(`for (let ${this.counter} = 0; ${this.counter} < ${this.limit}; ${this.counter}++) {`)
270if (this.statement) {
271writer.pushIndent()
272this.statement.write(writer)
273writer.popIndent()
274writer.print("}")
275}
276}
277}
278
279class CLikeLoopStatement implements LanguageStatement {
280constructor(private counter: string, private limit: string, private statement: LanguageStatement | undefined) {}
281write(writer: LanguageWriter): void {
282writer.print(`for (int ${this.counter} = 0; ${this.counter} < ${this.limit}; ${this.counter}++) {`)
283if (this.statement) {
284writer.pushIndent()
285this.statement.write(writer)
286writer.popIndent()
287writer.print("}")
288}
289}
290}
291
292class TSMapForEachStatement implements LanguageStatement {
293constructor(private map: string, private key: string, private value: string, private op: () => void) {}
294write(writer: LanguageWriter): void {
295writer.print(`for (const [${this.key}, ${this.value}] of ${this.map}) {`)
296writer.pushIndent()
297this.op()
298writer.popIndent()
299writer.print(`}`)
300}
301}
302
303class ArkTSMapForEachStatement implements LanguageStatement {
304constructor(private map: string, private key: string, private value: string, private op: () => void) {}
305write(writer: LanguageWriter): void {
306writer.print(`// TODO: map serialization not implemented`)
307}
308}
309
310
311class JavaMapForEachStatement implements LanguageStatement {
312constructor(private map: string, private key: string, private value: string, private op: () => void) {}
313write(writer: LanguageWriter): void {
314const entryVar = `${this.map}Entry`
315writer.print(`for (Map.Entry<?, ?> ${entryVar}: ${this.map}.entrySet()) {`)
316writer.pushIndent()
317writer.print(`var ${this.key} = ${entryVar}.getKey();`)
318writer.print(`var ${this.value} = ${entryVar}.getValue();`)
319this.op()
320writer.popIndent()
321writer.print(`}`)
322}
323}
324
325class CppMapForEachStatement implements LanguageStatement {
326constructor(private map: string, private key: string, private value: string, private op: () => void) {}
327write(writer: LanguageWriter): void {
328writer.print(`for (int32_t i = 0; i < ${this.map}.size; i++) {`)
329writer.pushIndent()
330writer.print(`auto ${this.key} = ${this.map}.keys[i];`)
331writer.print(`auto ${this.value} = ${this.map}.values[i];`)
332this.op()
333writer.popIndent()
334writer.print(`}`)
335}
336}
337
338class CppArrayResizeStatement implements LanguageStatement {
339constructor(private array: string, private length: string, private deserializer: string) {}
340write(writer: LanguageWriter): void {
341writer.print(`${this.deserializer}.resizeArray<std::decay<decltype(${this.array})>::type,
342std::decay<decltype(*${this.array}.array)>::type>(&${this.array}, ${this.length});`)
343}
344}
345
346class CppMapResizeStatement implements LanguageStatement {
347constructor(private keyType: string, private valueType: string, private map: string, private size: string, private deserializer: string) {}
348write(writer: LanguageWriter): void {
349writer.print(`${this.deserializer}.resizeMap<Map_${this.keyType}_${this.valueType}, ${this.keyType}, ${this.valueType}>(&${this.map}, ${this.size});`)
350}
351}
352
353class TsTupleAllocStatement implements LanguageStatement {
354constructor(private tuple: string) {}
355write(writer: LanguageWriter): void {
356writer.writeStatement(writer.makeAssign(this.tuple, undefined, writer.makeString("[]"), false, false))
357}
358}
359
360class TsObjectAssignStatement implements LanguageStatement {
361constructor(private object: string, private type: Type | undefined, private isDeclare: boolean) {}
362write(writer: LanguageWriter): void {
363writer.writeStatement(writer.makeAssign(this.object,
364this.type,
365writer.makeString(`{}`),
366this.isDeclare,
367false))
368}
369}
370
371class TsObjectDeclareStatement implements LanguageStatement {
372constructor(private object: string, private type: Type | undefined, private fields: readonly FieldRecord[]) {}
373write(writer: LanguageWriter): void {
374const nameConvertor = new TsObjectDeclareNodeNameConvertor()
375// Constructing a new type with all optional fields
376const objectType = new Type(`{${this.fields.map(it => {
377return `${it.name}?: ${nameConvertor.convert(it.type)}`
378}).join(",")}}`)
379new TsObjectAssignStatement(this.object, objectType, true).write(writer)
380}
381}
382
383export class BlockStatement implements LanguageStatement {
384constructor(public statements: LanguageStatement[], private inScope: boolean = true) { }
385write(writer: LanguageWriter): void {
386if (this.inScope) {
387writer.print("{")
388writer.pushIndent()
389}
390this.statements.forEach(s => s.write(writer))
391if (this.inScope) {
392writer.popIndent()
393writer.print("}")
394}
395}
396}
397
398export class IfStatement implements LanguageStatement {
399constructor(public condition: LanguageExpression,
400public thenStatement: LanguageStatement,
401public elseStatement: LanguageStatement | undefined) { }
402write(writer: LanguageWriter): void {
403writer.print(`if (${this.condition.asString()}) {`)
404writer.pushIndent()
405this.thenStatement.write(writer)
406writer.popIndent()
407if (this.elseStatement !== undefined) {
408writer.print("} else {")
409writer.pushIndent()
410this.elseStatement.write(writer)
411writer.popIndent()
412writer.print("}")
413} else {
414writer.print("}")
415}
416
417}
418}
419
420export type BranchStatement = {expr: LanguageExpression, stmt: LanguageStatement}
421
422export class MultiBranchIfStatement implements LanguageStatement {
423constructor(private readonly statements: BranchStatement[],
424private readonly elseStatement: LanguageStatement | undefined) { }
425write(writer: LanguageWriter): void {
426this.statements.forEach((value, index) => {
427const {expr, stmt}= value
428if (index == 0) {
429writer.print(`if (${expr.asString()}) {`)
430} else {
431writer.print(`else if (${expr.asString()}) {`)
432}
433writer.pushIndent()
434stmt.write(writer)
435writer.popIndent()
436writer.print("}")
437})
438
439if (this.elseStatement !== undefined) {
440writer.print(" else {")
441writer.pushIndent()
442this.elseStatement.write(writer)
443writer.popIndent()
444writer.print("}")
445}
446}
447}
448
449export class TernaryExpression implements LanguageExpression {
450constructor(public condition: LanguageExpression,
451public trueExpression: LanguageExpression,
452public falseExpression: LanguageExpression) {}
453asString(): string {
454return `(${this.condition.asString()}) ? (${this.trueExpression.asString()}) : (${this.falseExpression.asString()})`
455}
456}
457
458export class NaryOpExpression implements LanguageExpression {
459constructor(public op: string, public args: LanguageExpression[]) { }
460asString(): string {
461return `${this.args.map(arg => `(${arg.asString()})`).join(` ${this.op} `)}`
462}
463}
464
465export class StringExpression implements LanguageExpression {
466constructor(public value: string) { }
467asString(): string {
468return this.value
469}
470}
471
472export class MethodSignature {
473constructor(public returnType: Type, public args: Type[], public defaults: stringOrNone[]|undefined = undefined) {}
474
475argName(index: number): string {
476return `arg${index}`
477}
478argDefault(index: number): string|undefined {
479return this.defaults?.[index]
480}
481}
482
483export class NamedMethodSignature extends MethodSignature {
484constructor(returnType: Type, args: Type[] = [], public argsNames: string[] = [], defaults: stringOrNone[]|undefined = undefined) {
485super(returnType, args, defaults)
486}
487
488static make(returnType: string, args: {name: string, type: string}[]): NamedMethodSignature {
489return new NamedMethodSignature(new Type(returnType), args.map(it => new Type(it.type)), args.map(it => it.name))
490}
491
492argName(index: number): string {
493return this.argsNames[index]
494}
495}
496
497export class Field {
498constructor(
499public name: string,
500public type: Type,
501public modifiers: FieldModifier[] = []
502) {}
503}
504
505export class Method {
506constructor(
507public name: string,
508public signature: MethodSignature,
509public modifiers: MethodModifier[]|undefined = undefined,
510public generics?: string[],
511) {}
512}
513
514export function mangleMethodName(method: Method): string {
515const argsPostfix = method.signature.args.map(it => {
516return Array.from(it.name).filter(it => it.match(/[a-zA-Z]/)).join("")
517}).join("_")
518return `${method.name}_${argsPostfix}`
519}
520
521export interface ObjectArgs {
522[name: string]: string
523}
524
525export interface PrinterLike {
526getOutput(): string[]
527}
528
529export abstract class LanguageWriter {
530constructor(public printer: IndentedPrinter, public language: Language) {}
531
532indentDepth(): number {
533return this.printer.indentDepth()
534}
535
536abstract writeClass(name: string, op: (writer: LanguageWriter) => void, superClass?: string, interfaces?: string[], generics?: string[]): void
537abstract writeInterface(name: string, op: (writer: LanguageWriter) => void, superInterfaces?: string[]): void
538abstract writeFieldDeclaration(name: string, type: Type, modifiers: string[]|undefined, optional: boolean): void
539abstract writeMethodDeclaration(name: string, signature: MethodSignature, modifiers?: MethodModifier[]): void
540abstract writeConstructorImplementation(className: string, signature: MethodSignature, op: (writer: LanguageWriter) => void, superCall?: Method): void
541abstract writeMethodImplementation(method: Method, op: (writer: LanguageWriter) => void): void
542abstract makeAssign(variableName: string, type: Type | undefined, expr: LanguageExpression | undefined, isDeclared: boolean, isConst?: boolean): LanguageStatement;
543abstract makeReturn(expr?: LanguageExpression): LanguageStatement;
544abstract makeRuntimeType(rt: RuntimeType): LanguageExpression
545abstract getObjectAccessor(p: BaseArgConvertor, param: string, value: string, args?: ObjectArgs): string
546abstract makeCast(value: LanguageExpression, type: Type): LanguageExpression
547abstract makeCast(value: LanguageExpression, type: Type, unsafe: boolean): LanguageExpression
548abstract writePrintLog(message: string): void
549abstract makeUndefined(): LanguageExpression
550abstract makeMapKeyTypeName(c: MapConvertor): string
551abstract makeMapValueTypeName(c: MapConvertor): string
552abstract makeMapInsert(keyAccessor: string, key: string, valueAccessor: string, value: string): LanguageStatement
553abstract makeLoop(counter: string, limit: string): LanguageStatement
554abstract makeLoop(counter: string, limit: string, statement: LanguageStatement): LanguageStatement
555abstract makeMapForEach(map: string, key: string, value: string, op: () => void): LanguageStatement
556abstract getTagType(): Type
557abstract getRuntimeType(): Type
558abstract makeTupleAssign(receiver: string, tupleFields: string[]): LanguageStatement
559abstract get supportedModifiers(): MethodModifier[]
560abstract enumFromOrdinal(value: LanguageExpression, enumType: string): LanguageExpression
561abstract ordinalFromEnum(value: LanguageExpression, enumType: string): LanguageExpression
562
563concat(other: PrinterLike): this {
564other.getOutput().forEach(it => this.print(it))
565return this
566}
567printTo(file: string): void {
568fs.writeFileSync(file, this.getOutput().join("\n"))
569}
570writeLines(lines: string): void {
571lines.split("\n").forEach(it => this.print(it))
572}
573writeGetterImplementation(method: Method, op: (writer: LanguageWriter) => void): void {
574this.writeMethodImplementation(new Method(method.name, method.signature, [MethodModifier.GETTER].concat(method.modifiers ?? [])), op)
575}
576writeSetterImplementation(method: Method, op: (writer: LanguageWriter) => void): void {
577this.writeMethodImplementation(new Method(method.name, method.signature, [MethodModifier.SETTER].concat(method.modifiers ?? [])), op)
578}
579writeSuperCall(params: string[]): void {
580this.printer.print(`super(${params.join(", ")});`)
581}
582writeMethodCall(receiver: string, method: string, params: string[], nullable = false): void {
583this.printer.print(`${receiver}${nullable ? "?" : ""}.${method}(${params.join(", ")})`)
584}
585writeStatement(stmt: LanguageStatement) {
586//this.printer.print(stmt.asString())
587stmt.write(this)
588}
589makeTag(tag: string): string {
590return "Tag." + tag
591}
592makeRef(varName: string): string {
593return varName
594}
595makeThis(): LanguageExpression {
596return new StringExpression("this")
597}
598makeNull(): LanguageExpression {
599return new StringExpression("null")
600}
601makeRuntimeTypeCondition(typeVarName: string, equals: boolean, type: RuntimeType): LanguageExpression {
602const op = equals ? "==" : "!="
603return this.makeNaryOp(op, [this.makeRuntimeType(type), this.makeString(typeVarName)])
604}
605makeValueFromOption(value: string, destinationConvertor: ArgConvertor): LanguageExpression {
606return this.makeString(`${value}!`)
607}
608makeFunctionCall(name: string, params: LanguageExpression[]): LanguageExpression {
609return new FunctionCallExpression(name, params)
610}
611makeMethodCall(receiver: string, method: string, params: LanguageExpression[], nullable?: boolean): LanguageExpression {
612return new MethodCallExpression(receiver, method, params, nullable)
613}
614makeNativeCall(method: string, params: LanguageExpression[], nullable?: boolean): LanguageExpression {
615return new MethodCallExpression(this.nativeReceiver(), method, params, nullable)
616}
617nativeReceiver(): string { return 'nativeModule()' }
618makeDefinedCheck(value: string): LanguageExpression {
619return new CheckDefinedExpression(value)
620}
621makeRuntimeTypeDefinedCheck(runtimeType: string): LanguageExpression {
622return this.makeRuntimeTypeCondition(runtimeType, false, RuntimeType.UNDEFINED)
623}
624makeCondition(condition: LanguageExpression, thenStatement: LanguageStatement, elseStatement?: LanguageStatement): LanguageStatement {
625return new IfStatement(condition, thenStatement, elseStatement)
626}
627makeMultiBranchCondition(conditions: BranchStatement[], elseStatement?: LanguageStatement): LanguageStatement {
628return new MultiBranchIfStatement(conditions, elseStatement)
629}
630makeTernary(condition: LanguageExpression, trueExpression: LanguageExpression, falseExpression: LanguageExpression): LanguageExpression {
631return new TernaryExpression(condition, trueExpression, falseExpression)
632}
633makeArrayLength(array: string, length?: string): LanguageExpression {
634return this.makeString(`${array}.length`)
635}
636makeArrayAccess(value: string, indexVar: string) {
637return this.makeString(`${value}[${indexVar}]`)
638}
639makeTupleAccess(value: string, index: number): LanguageExpression {
640return this.makeString(`${value}[${index}]`)
641}
642makeUnionSelector(value: string, valueType: string): LanguageStatement {
643return this.makeAssign(valueType, undefined, this.makeString(`runtimeType(${value})`), false)
644}
645makeUnionVariantCondition(value: string, type: string, index?: number): LanguageExpression {
646return this.makeString(`RuntimeType.${type.toUpperCase()} == ${value}`)
647}
648makeUnionVariantCast(value: string, type: Type, index?: number): LanguageExpression {
649return this.makeString(`unsafeCast<${type.name}>(${value})`)
650}
651makeUnionTypeDefaultInitializer() {
652return this.makeRuntimeType(RuntimeType.UNDEFINED)
653}
654makeRuntimeTypeGetterCall(value: string): LanguageExpression {
655return this.makeFunctionCall("runtimeType", [ this.makeString(value) ])
656}
657makeArrayResize(array: string, typeName: string, length: string, deserializer: string): LanguageStatement {
658return new ExpressionStatement(this.makeString(`${array} = [] as ${typeName}`))
659}
660makeMapResize(keyType: string, valueType: string, map: string, size: string, deserializer: string): LanguageStatement {
661return new ExpressionStatement(new StringExpression("// TODO: TS map resize"))
662}
663makeTupleAlloc(option: string): LanguageStatement {
664return new ExpressionStatement(new StringExpression(""))
665}
666makeObjectAlloc(object: string, fields: readonly FieldRecord[]): LanguageStatement {
667return new ExpressionStatement(new StringExpression(""))
668}
669makeSetUnionSelector(value: string, index: string): LanguageStatement {
670// empty expression
671return new ExpressionStatement(new StringExpression(""))
672}
673makeSetOptionTag(value: string, tag: LanguageExpression): LanguageStatement {
674// empty expression
675return new ExpressionStatement(new StringExpression(""))
676}
677makeString(value: string): LanguageExpression {
678return new StringExpression(value)
679}
680makeNaryOp(op: string, args: LanguageExpression[]): LanguageExpression {
681return new NaryOpExpression(op, args)
682}
683makeStatement(expr: LanguageExpression): LanguageStatement {
684return new ExpressionStatement(expr)
685}
686writeNativeMethodDeclaration(name: string, signature: MethodSignature): void {
687this.writeMethodDeclaration(name, signature)
688}
689pushIndent() {
690this.printer.pushIndent()
691}
692popIndent() {
693this.printer.popIndent()
694}
695print(string: stringOrNone) {
696this.printer.print(string)
697}
698getOutput(): string[] {
699return this.printer.getOutput()
700}
701mapType(type: Type, convertor?: ArgConvertor): string {
702return type.name
703}
704mapFiledModifier(modifier: FieldModifier): string {
705return `${FieldModifier[modifier].toLowerCase()}`
706}
707mapMethodModifier(modifier: MethodModifier): string {
708return `${MethodModifier[modifier].toLowerCase()}`
709}
710makeObjectDeclare(name: string, type: Type | undefined, fields: readonly FieldRecord[]): LanguageStatement {
711return this.makeAssign(name, type, this.makeString("{}"), true, false)
712}
713makeType(typeName: string, nullable: boolean, receiver?: string): Type {
714return new Type(typeName, nullable)
715}
716makeUnsafeCast(convertor: ArgConvertor, param: string): string {
717return `unsafeCast<int32>(${param})`
718}
719runtimeType(param: ArgConvertor, valueType: string, value: string) {
720this.writeStatement(this.makeAssign(valueType, Type.Int32,
721this.makeFunctionCall("runtimeType", [this.makeString(value)]), false))
722}
723makeDiscriminatorFromFields(convertor: BaseArgConvertor, value: string, accessors: string[]): LanguageExpression {
724return this.makeString(`(${this.makeNaryOp("||",
725accessors.map(it => this.makeString(`${value}!.hasOwnProperty("${it}")`))).asString()})`)
726}
727makeCallIsResource(value: string) {
728return this.makeString(`isResource(${value})`)
729}
730}
731
732export class TSLanguageWriter extends LanguageWriter {
733constructor(printer: IndentedPrinter, language: Language = Language.TS) {
734super(printer, language)
735}
736writeClass(name: string, op: (writer: LanguageWriter) => void, superClass?: string, interfaces?: string[], generics?: string[]): void {
737let extendsClause = superClass ? ` extends ${superClass}` : ''
738let implementsClause = interfaces ? ` implements ${interfaces.join(",")}` : ''
739const genericsClause = generics ? `<${generics.join(", ")}>` : ''
740this.printer.print(`export class ${name}${genericsClause}${extendsClause}${implementsClause} {`)
741this.pushIndent()
742op(this)
743this.popIndent()
744this.printer.print(`}`)
745}
746writeInterface(name: string, op: (writer: LanguageWriter) => void, superInterfaces?: string[]): void {
747let extendsClause = superInterfaces ? ` extends ${superInterfaces.join(",")}` : ''
748this.printer.print(`export interface ${name}${extendsClause} {`)
749this.pushIndent()
750op(this)
751this.popIndent()
752this.printer.print(`}`)
753}
754writeFieldDeclaration(name: string, type: Type, modifiers: string[]|undefined, optional: boolean): void {
755this.printer.print(`${modifiers?.join(' ') ?? ""} ${name}${optional ? "?" : ""}: ${type.name}`)
756}
757writeMethodDeclaration(name: string, signature: MethodSignature, modifiers?: MethodModifier[]): void {
758this.writeDeclaration(name, signature, true, false, modifiers)
759}
760writeConstructorImplementation(className: string, signature: MethodSignature, op: (writer: LanguageWriter) => void, superCall?: Method) {
761this.writeDeclaration('constructor', signature, false, true)
762this.pushIndent()
763if (superCall) {
764this.print(`super(${superCall.signature.args.map((_, i) => superCall?.signature.argName(i)).join(", ")})`)
765}
766op(this)
767this.popIndent()
768this.printer.print(`}`)
769
770}
771writeMethodImplementation(method: Method, op: (writer: LanguageWriter) => void) {
772this.writeDeclaration(method.name, method.signature, true, true, method.modifiers, method.generics)
773this.pushIndent()
774op(this)
775this.popIndent()
776this.printer.print(`}`)
777}
778private writeDeclaration(name: string, signature: MethodSignature, needReturn: boolean, needBracket: boolean, modifiers?: MethodModifier[], generics?: string[]) {
779let prefix = modifiers
780?.filter(it => this.supportedModifiers.includes(it))
781.map(it => this.mapMethodModifier(it)).join(" ")
782if (modifiers?.includes(MethodModifier.GETTER)) {
783prefix = `get ${prefix}`
784} else if (modifiers?.includes(MethodModifier.SETTER)) {
785prefix = `set ${prefix}`
786needReturn = false
787}
788prefix = prefix ? prefix + " " : ""
789const typeParams = generics ? `<${generics.join(", ")}>` : ""
790this.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}
792makeAssign(variableName: string, type: Type | undefined, expr: LanguageExpression | undefined, isDeclared: boolean = true, isConst: boolean = true): LanguageStatement {
793return new AssignStatement(variableName, type, expr, isDeclared, isConst)
794}
795makeReturn(expr: LanguageExpression): LanguageStatement {
796return new TSReturnStatement(expr)
797}
798makeStatement(expr: LanguageExpression): LanguageStatement {
799return new ExpressionStatement(expr)
800}
801makeLoop(counter: string, limit: string, statement?: LanguageStatement): LanguageStatement {
802return new TSLoopStatement(counter, limit, statement)
803}
804makeMapForEach(map: string, key: string, value: string, op: () => void): LanguageStatement {
805return new TSMapForEachStatement(map, key, value, op)
806}
807writePrintLog(message: string): void {
808this.print(`console.log("${message}")`)
809}
810makeCast(value: LanguageExpression, type: Type, unsafe = false): LanguageExpression {
811return new TSCastExpression(value, type, unsafe)
812}
813getObjectAccessor(convertor: BaseArgConvertor, param: string, value: string, args?: ObjectArgs): string {
814if (convertor instanceof OptionConvertor || convertor instanceof UnionConvertor) {
815return value
816}
817if (convertor instanceof ArrayConvertor && args?.index != undefined) {
818return `${value}${args.index}`
819}
820if (convertor instanceof ArrayConvertor) {
821return `${value}`
822}
823if (convertor instanceof TupleConvertor && args?.index != undefined) {
824return `${value}[${args.index}]`
825}
826if (convertor instanceof MapConvertor) {
827return `${value}`
828}
829if (convertor.useArray && args?.index != undefined) {
830return `${value}[${args.index}]`
831}
832return `${value}`
833}
834makeUndefined(): LanguageExpression {
835return this.makeString("undefined")
836}
837makeRuntimeType(rt: RuntimeType): LanguageExpression {
838return this.makeString(`RuntimeType.${RuntimeType[rt]}`)
839}
840makeTupleAlloc(option: string): LanguageStatement {
841return new TsTupleAllocStatement(option)
842}
843makeObjectAlloc(object: string, fields: readonly FieldRecord[]): LanguageStatement {
844if (fields.length > 0) {
845return this.makeAssign(object, undefined,
846this.makeCast(this.makeString("{}"),
847new Type(`{${fields.map(it=>`${it.name}: ${mapType(it.type)}`).join(",")}}`)),
848false)
849}
850return new TsObjectAssignStatement(object, undefined, false)
851}
852makeMapResize(keyType: string, valueType: string, map: string, size: string, deserializer: string): LanguageStatement {
853return this.makeAssign(map, undefined, this.makeString(`new Map<${keyType}, ${valueType}>()`), false)
854}
855makeMapKeyTypeName(c: MapConvertor): string {
856return c.keyConvertor.tsTypeName;
857}
858makeMapValueTypeName(c: MapConvertor): string {
859return c.valueConvertor.tsTypeName;
860}
861makeMapInsert(keyAccessor: string, key: string, valueAccessor: string, value: string): LanguageStatement {
862// keyAccessor and valueAccessor are equal in TS
863return this.makeStatement(this.makeMethodCall(keyAccessor, "set", [this.makeString(key), this.makeString(value)]))
864}
865makeObjectDeclare(name: string, type: Type, fields: readonly FieldRecord[]): LanguageStatement {
866return new TsObjectDeclareStatement(name, type, fields)
867}
868getTagType(): Type {
869return new Type("Tags");
870}
871getRuntimeType(): Type {
872return new Type("number");
873}
874makeTupleAssign(receiver: string, fields: string[]): LanguageStatement {
875return this.makeAssign(receiver, undefined,
876this.makeString(`[${fields.map(it=> `${it}!`).join(",")}]`), false)
877}
878get supportedModifiers(): MethodModifier[] {
879return [MethodModifier.PUBLIC, MethodModifier.PRIVATE, MethodModifier.STATIC]
880}
881enumFromOrdinal(value: LanguageExpression, enumType: string): LanguageExpression {
882return this.makeString(`Object.values(${enumType})[${value.asString()}]`);
883}
884ordinalFromEnum(value: LanguageExpression, enumType: string): LanguageExpression {
885return this.makeString(`Object.keys(${enumType}).indexOf(${this.makeCast(value, new Type('string')).asString()})`);
886}
887mapType(type: Type, convertor?: ArgConvertor): string {
888switch (type.name) {
889case 'Function': return 'Object'
890}
891return type.name
892}
893}
894
895export class ETSLanguageWriter extends TSLanguageWriter {
896constructor(printer: IndentedPrinter) {
897super(printer, Language.ARKTS)
898}
899writeNativeMethodDeclaration(name: string, signature: MethodSignature): void {
900this.writeMethodDeclaration(name, signature, [MethodModifier.STATIC, MethodModifier.NATIVE])
901}
902makeAssign(variableName: string, type: Type | undefined, expr: LanguageExpression, isDeclared: boolean = true, isConst: boolean = true): LanguageStatement {
903return new EtsAssignStatement(variableName, type, expr, isDeclared, isConst)
904}
905makeMapForEach(map: string, key: string, value: string, op: () => void): LanguageStatement {
906return new ArkTSMapForEachStatement(map, key, value, op)
907}
908mapType(type: Type, convertor?: ArgConvertor): string {
909if (convertor instanceof EnumConvertor) {
910return 'int'
911}
912if (convertor instanceof AggregateConvertor && convertor.aliasName !== undefined) {
913return convertor.aliasName
914}
915if (convertor instanceof ArrayConvertor) {
916return `${convertor.elementTypeName()}[]`
917}
918switch (type.name) {
919case 'KPointer': return 'long'
920case 'Uint8Array': return 'byte[]'
921case 'int32': case 'KInt': return 'int'
922case 'KStringPtr': return 'String'
923case 'KLength': return 'Object'
924case 'number': return 'double'
925}
926return super.mapType(type)
927}
928get supportedModifiers(): MethodModifier[] {
929return [MethodModifier.PUBLIC, MethodModifier.PRIVATE, MethodModifier.NATIVE, MethodModifier.STATIC]
930}
931nativeReceiver(): string { return 'NativeModule' }
932makeUnsafeCast(convertor: ArgConvertor, param: string): string {
933if (convertor instanceof EnumConvertor) {
934return `${param} as int32`
935}
936return super.makeUnsafeCast(convertor, param)
937}
938runtimeType(param: ArgConvertor, valueType: string, value: string) {
939if (param instanceof OptionConvertor) {
940this.writeStatement(this.makeCondition(this.makeString(`${value} != undefined`), this.makeAssign(valueType, undefined,
941this.makeRuntimeType(RuntimeType.OBJECT), false)))
942} else {
943super.runtimeType(param, valueType, value);
944}
945}
946makeUnionSelector(value: string, valueType: string): LanguageStatement {
947let statements = [this.makeAssign("type", undefined, this.makeString(`typeof ${value}`))]
948Object.keys(RuntimeType)
949.filter((value) => isNaN(Number(value)))
950.forEach((value) => {
951statements.push(
952this.makeCondition(this.makeNaryOp("==", [this.makeString("type"), this.makeString(`"${value.toLowerCase()}"`)]),
953this.makeAssign(valueType, undefined, this.makeString(`RuntimeType.${value}`), false))
954)
955})
956return new BlockStatement(statements)
957}
958makeUnionVariantCast(value: string, type: Type, index?: number): LanguageExpression {
959return this.makeString(`${value} as ${type.name}`)
960}
961ordinalFromEnum(value: LanguageExpression, enumType: string): LanguageExpression {
962return this.makeCast(value, new Type('int'));
963}
964makeDiscriminatorFromFields(convertor: BaseArgConvertor, value: string, accessors: string[]): LanguageExpression {
965return this.makeString(`${value} instanceof ${convertor.targetType(this).name}`)
966}
967makeValueFromOption(value: string, destinationConvertor: ArgConvertor): LanguageExpression {
968// This preventing arkts compiler from segfault. No need to apply the assertion operator (!) to enum.
969if (destinationConvertor instanceof EnumConvertor) {
970return this.makeString(`${value}`)
971}
972return super.makeValueFromOption(value, destinationConvertor)
973}
974makeCallIsResource(value: string): LanguageExpression {
975return this.makeString(`(${value} instanceof Resource)`);
976}
977}
978
979abstract class CLikeLanguageWriter extends LanguageWriter {
980protected constructor(printer: IndentedPrinter, language: Language) {
981super(printer, language)
982}
983writeMethodCall(receiver: string, method: string, params: string[], nullable = false): void {
984this.printer.print(`${receiver}.${method}(${params.join(", ")});`)
985}
986writeMethodDeclaration(name: string, signature: MethodSignature, modifiers?: MethodModifier[]): void {
987this.writeDeclaration(name, signature, modifiers, ";")
988}
989writeMethodImplementation(method: Method, op: (writer: LanguageWriter) => void) {
990this.writeDeclaration(method.name, method.signature, method.modifiers, " {")
991this.pushIndent()
992op(this)
993this.popIndent()
994this.printer.print(`}`)
995}
996private writeDeclaration(name: string, signature: MethodSignature, modifiers?: MethodModifier[], postfix?: string): void {
997let prefix = modifiers
998?.filter(it => this.supportedModifiers.includes(it))
999.map(it => this.mapMethodModifier(it)).join(" ")
1000prefix = prefix ? prefix + " " : ""
1001this.print(`${prefix}${this.mapType(signature.returnType)} ${name}(${signature.args.map((it, index) => `${this.mapType(it)} ${signature.argName(index)}`).join(", ")})${postfix ?? ""}`)
1002}
1003}
1004
1005export class JavaLanguageWriter extends CLikeLanguageWriter {
1006constructor(printer: IndentedPrinter) {
1007super(printer, Language.JAVA)
1008}
1009writeClass(name: string, op: (writer: LanguageWriter) => void, superClass?: string, interfaces?: string[]): void {
1010let extendsClause = superClass ? ` extends ${superClass}` : ''
1011let implementsClause = interfaces ? ` implements ${interfaces.join(",")}` : ''
1012this.printer.print(`class ${name}${extendsClause}${implementsClause} {`)
1013this.pushIndent()
1014op(this)
1015this.popIndent()
1016this.printer.print(`}`)
1017}
1018writeInterface(name: string, op: (writer: LanguageWriter) => void, superInterfaces?: string[]): void {
1019let extendsClause = superInterfaces ? ` extends ${superInterfaces.join(",")}` : ''
1020this.printer.print(`interface ${name}${extendsClause} {`)
1021this.pushIndent()
1022op(this)
1023this.popIndent()
1024this.printer.print(`}`)
1025}
1026writeMethodCall(receiver: string, method: string, params: string[], nullable = false): void {
1027if (nullable) {
1028this.printer.print(`if (${receiver} != null) ${receiver}.${method}(${params.join(", ")});`)
1029} else {
1030super.writeMethodCall(receiver, method, params, nullable)
1031}
1032}
1033writeFieldDeclaration(name: string, type: Type, modifiers: string[]|undefined, optional: boolean): void {
1034this.printer.print(`${modifiers?.join(' ') ?? ""} ${type.name} ${name}${optional ? " = null" : ""};`)
1035}
1036writeNativeMethodDeclaration(name: string, signature: MethodSignature): void {
1037this.writeMethodDeclaration(name, signature, [MethodModifier.STATIC, MethodModifier.NATIVE])
1038}
1039writeConstructorImplementation(className: string, signature: MethodSignature, op: (writer: LanguageWriter) => void, superCall?: Method) {
1040this.printer.print(`${className}(${signature.args.map((it, index) => `${this.mapType(it)} ${signature.argName(index)}`).join(", ")}) {`)
1041this.pushIndent()
1042if (superCall) {
1043this.print(`super(${superCall.signature.args.map((_, i) => superCall?.signature.argName(i)).join(", ")});`)
1044}
1045op(this)
1046this.popIndent()
1047this.printer.print(`}`)
1048}
1049makeAssign(variableName: string, type: Type | undefined, expr: LanguageExpression, isDeclared: boolean = true, isConst: boolean = true): LanguageStatement {
1050return new JavaAssignStatement(variableName, type, expr, isDeclared, isConst)
1051}
1052makeReturn(expr: LanguageExpression): LanguageStatement {
1053return new CLikeReturnStatement(expr)
1054}
1055makeDefinedCheck(value: string): LanguageExpression {
1056return new JavaCheckDefinedExpression(value)
1057}
1058makeLoop(counter: string, limit: string, statement?: LanguageStatement): LanguageStatement {
1059return new CLikeLoopStatement(counter, limit, statement)
1060}
1061makeMapForEach(map: string, key: string, value: string, op: () => void): LanguageStatement {
1062return new JavaMapForEachStatement(map, key, value, op)
1063}
1064makeCast(value: LanguageExpression, type: Type, unsafe = false): LanguageExpression {
1065return new JavaCastExpression(value, type, unsafe)
1066}
1067makeStatement(expr: LanguageExpression): LanguageStatement {
1068return new CLikeExpressionStatement(expr)
1069}
1070makeUnionSelector(value: string, valueType: string): LanguageStatement {
1071return this.makeAssign(valueType, undefined, this.makeMethodCall(value, "getSelector", []), false)
1072}
1073makeUnionVariantCondition(value: string, type: string, index: number): LanguageExpression {
1074return this.makeString(`${value} == ${index}`)
1075}
1076makeUnionVariantCast(value: string, type: Type, index: number) {
1077return this.makeMethodCall(value, `getValue${index}`, [])
1078}
1079makeUnionTypeDefaultInitializer() {
1080return this.makeString("-1")
1081}
1082writePrintLog(message: string): void {
1083this.print(`System.out.println("${message}")`)
1084}
1085mapType(type: Type): string {
1086switch (type.name) {
1087case 'KPointer': return 'long'
1088case 'Uint8Array': return 'byte[]'
1089case 'int32': case 'KInt': return 'int'
1090case 'KStringPtr': return 'String'
1091case 'string': return 'String'
1092case 'number': return 'double'
1093}
1094return super.mapType(type)
1095}
1096applyToObject(p: BaseArgConvertor, param: string, value: string, args?: ObjectArgs): LanguageStatement {
1097throw new Error("Method not implemented.")
1098}
1099getObjectAccessor(convertor: BaseArgConvertor, param: string, value: string, args?: ObjectArgs): string {
1100throw new Error("Method not implemented.")
1101}
1102makeUndefined(): LanguageExpression {
1103return this.makeString("undefined")
1104}
1105makeRuntimeType(rt: RuntimeType): LanguageExpression {
1106return this.makeString(`RuntimeType.${RuntimeType[rt]}`)
1107}
1108makeRuntimeTypeGetterCall(value: string): LanguageExpression {
1109const call = this.makeMethodCall(value, "getRuntimeType", []).asString()
1110return this.makeString(`${call}`)
1111}
1112makeMapKeyTypeName(c: MapConvertor): string {
1113throw new Error("Method not implemented.")
1114}
1115makeMapValueTypeName(c: MapConvertor): string {
1116throw new Error("Method not implemented.")
1117}
1118makeMapInsert(keyAccessor: string, key: string, valueAccessor: string, value: string): LanguageStatement {
1119throw new Error("Method not implemented.")
1120}
1121getTagType(): Type {
1122throw new Error("Method not implemented.")
1123}
1124getRuntimeType(): Type {
1125throw new Error("Method not implemented.")
1126}
1127makeTupleAssign(receiver: string, tupleFields: string[]): LanguageStatement {
1128throw new Error("Method not implemented.")
1129}
1130get supportedModifiers(): MethodModifier[] {
1131return [MethodModifier.PUBLIC, MethodModifier.PRIVATE, MethodModifier.STATIC, MethodModifier.NATIVE]
1132}
1133makeTupleAccess(value: string, index: number): LanguageExpression {
1134return this.makeString(`${value}.value${index}`)
1135}
1136enumFromOrdinal(value: LanguageExpression, enumType: string): LanguageExpression {
1137throw new Error("Method not implemented.")
1138}
1139ordinalFromEnum(value: LanguageExpression, enumType: string): LanguageExpression {
1140throw new Error("Method not implemented.")
1141}
1142makeValueFromOption(value: string): LanguageExpression {
1143return this.makeString(`${value}.value`)
1144}
1145runtimeType(param: ArgConvertor, valueType: string, value: string) {
1146this.writeStatement(this.makeAssign(valueType, undefined,
1147this.makeRuntimeTypeGetterCall(value), false))
1148}
1149}
1150
1151export class CppLanguageWriter extends CLikeLanguageWriter {
1152constructor(printer: IndentedPrinter) {
1153super(printer, Language.CPP)
1154}
1155writeClass(name: string, op: (writer: LanguageWriter) => void, superClass?: string, interfaces?: string[]): void {
1156const superClasses = (superClass ? [superClass] : []).concat(interfaces ?? [])
1157const extendsClause = superClasses ? ` : ${superClasses.map(c => `public ${c}`).join(", ")}` : ''
1158this.printer.print(`class ${name}${extendsClause} {`)
1159this.pushIndent()
1160op(this)
1161this.popIndent()
1162this.printer.print(`};`)
1163}
1164writeInterface(name: string, op: (writer: LanguageWriter) => void, superInterfaces?: string[]): void {
1165throw new Error("Method not implemented.")
1166}
1167writeMethodCall(receiver: string, method: string, params: string[], nullable = false): void {
1168if (nullable) {
1169this.printer.print(`if (${receiver}) ${receiver}.${method}(${params.join(", ")});`)
1170} else {
1171super.writeMethodCall(receiver, method, params, nullable)
1172}
1173}
1174writeFieldDeclaration(name: string, type: Type, modifiers: string[] | undefined, optional: boolean): void {
1175const modifier = modifiers?.find(mod => mod !== "static")
1176if (modifier) {
1177this.printer.print(`${modifier}:`)
1178}
1179this.printer.pushIndent()
1180this.printer.print(`${type.name} ${name};`)
1181this.printer.popIndent()
1182}
1183writeConstructorImplementation(className: string, signature: MethodSignature, op: (writer: LanguageWriter) => void, superCall?: Method) {
1184const superInvocation = superCall
1185? ` : ${superCall.name}(${superCall.signature.args.map((_, i) => superCall?.signature.argName(i)).join(", ")})`
1186: ""
1187const argList = signature.args.map((it, index) => `${this.mapType(it)} ${signature.argName(index)}`).join(", ");
1188this.print("public:")
1189this.print(`${className}(${argList})${superInvocation} {`)
1190this.pushIndent()
1191op(this)
1192this.popIndent()
1193this.print(`}`)
1194}
1195
1196/**
1197* Writes multiline comments decorated with stars
1198*/
1199writeMultilineCommentBlock(lines: string) {
1200this.print('/*')
1201lines.split("\n").forEach(it => this.print(' * ' + it))
1202this.print(' */')
1203}
1204
1205/**
1206* Writes `#include "path"`
1207* @param path File path to be included
1208*/
1209writeInclude(path: string) {
1210this.print(`#include "${path}"`)
1211}
1212
1213/**
1214* Writes `#include <path>`
1215* @param path File path to be included
1216*/
1217writeGlobalInclude(path: string) {
1218this.print(`#include <${path}>`)
1219}
1220
1221/**
1222* Writes `namespace <namespace> {` and adds extra indent
1223* @param namespace Namespace to begin
1224*/
1225pushNamespace(namespace: string) {
1226this.print(`namespace ${namespace} {`)
1227this.pushIndent()
1228}
1229
1230/**
1231* Writes closing brace of namespace block and removes one level of indent
1232*/
1233popNamespace() {
1234this.popIndent()
1235this.print(`}`)
1236}
1237
1238override makeTag(tag: string): string {
1239return "ARK_TAG_" + tag
1240}
1241override makeRef(varName: string): string {
1242return `${varName}&`
1243}
1244override makeThis(): LanguageExpression {
1245return new StringExpression("*this")
1246}
1247override makeNull(): LanguageExpression {
1248return new StringExpression("nullptr")
1249}
1250override makeValueFromOption(value: string): LanguageExpression {
1251return this.makeString(`${value}.value`)
1252}
1253makeAssign(variableName: string, type: Type | undefined, expr: LanguageExpression | undefined, isDeclared: boolean = true, isConst: boolean = true): LanguageStatement {
1254return new CppAssignStatement(variableName, type, expr, isDeclared, isConst)
1255}
1256makeReturn(expr: LanguageExpression): LanguageStatement {
1257return new CLikeReturnStatement(expr)
1258}
1259makeStatement(expr: LanguageExpression): LanguageStatement {
1260return new CLikeExpressionStatement(expr)
1261}
1262override makeArrayAccess(value: string, indexVar: string) {
1263return this.makeString(`${value}.array[${indexVar}]`)
1264}
1265override makeTupleAccess(value: string, index: number): LanguageExpression {
1266return this.makeString(`${value}.value${index}`)
1267}
1268override makeUnionSelector(value: string, valueType: string): LanguageStatement {
1269return this.makeAssign(valueType, undefined, this.makeString(`${value}.selector`), false)
1270}
1271override makeUnionVariantCondition(value: string, type: string, index: number) {
1272return this.makeString(`${value} == ${index}`)
1273}
1274override makeUnionVariantCast(value: string, type: Type, index: number) {
1275return this.makeString(`${value}.value${index}`)
1276}
1277makeLoop(counter: string, limit: string, statement?: LanguageStatement): LanguageStatement {
1278return new CLikeLoopStatement(counter, limit, statement)
1279}
1280makeMapForEach(map: string, key: string, value: string, op: () => void): LanguageStatement {
1281return new CppMapForEachStatement(map, key, value, op)
1282}
1283makeArrayResize(array: string, typeName: string, length: string, deserializer: string): LanguageStatement {
1284return new CppArrayResizeStatement(array, length, deserializer)
1285}
1286makeMapResize(keyType: string, valueType: string, map: string, size: string, deserializer: string): LanguageStatement {
1287return new CppMapResizeStatement(keyType, valueType, map, size, deserializer)
1288}
1289makeCast(expr: LanguageExpression, type: Type, unsafe = false): LanguageExpression {
1290return new CppCastExpression(expr, type, unsafe)
1291}
1292writePrintLog(message: string): void {
1293this.print(`printf("${message}\n")`)
1294}
1295makeDefinedCheck(value: string): LanguageExpression {
1296return new CDefinedExpression(value);
1297}
1298mapType(type: Type): string {
1299switch (type.name) {
1300case 'KPointer': return 'void*'
1301case 'Uint8Array': return 'byte[]'
1302case 'int32':
1303case 'KInt': return 'int32_t'
1304case 'string':
1305case 'KStringPtr': return 'Ark_String'
1306case 'number': return 'Ark_Number'
1307case 'boolean': return 'Ark_Boolean'
1308case 'Function': return `Ark_Function`
1309case 'Length': return 'Ark_Length'
1310// TODO: oh no
1311case 'Array<string[]>' : return `Array_Array_${PrimitiveType.String.getText()}`
1312}
1313if (type.name.startsWith("Array<")) {
1314const typeSpec = type.name.match(/<(.*)>/)!
1315const elementType = this.mapType(new Type(typeSpec[1]))
1316return `Array_${elementType}`
1317}
1318if (!type.name.includes("std::decay<") && type.name.includes("<")) {
1319return type.name.replace(/<(.*)>/, "")
1320}
1321return super.mapType(type)
1322}
1323makeSetUnionSelector(value: string, index: string): LanguageStatement {
1324return this.makeAssign(`${value}.selector`, undefined, this.makeString(index), false)
1325}
1326makeSetOptionTag(value: string, tag: LanguageExpression): LanguageStatement {
1327return this.makeAssign(`${value}.tag`, undefined, tag, false)
1328}
1329getObjectAccessor(convertor: BaseArgConvertor, param: string, value: string, args?: ObjectArgs): string {
1330if (convertor instanceof OptionConvertor) {
1331return `${value}.value`
1332}
1333if (convertor instanceof ArrayConvertor && args?.index) {
1334return `${value}.array${args.index}`
1335}
1336if ((convertor instanceof UnionConvertor || convertor instanceof TupleConvertor) && args?.index) {
1337return `${value}.value${args.index}`
1338}
1339if (convertor instanceof MapConvertor && args?.index && args?.field) {
1340return `${value}.${args.field}[${args.index}]`
1341}
1342return value
1343}
1344makeUndefined(): LanguageExpression {
1345return this.makeString(`${PrimitiveType.Undefined.getText()}()`)
1346}
1347makeRuntimeType(rt: RuntimeType): LanguageExpression {
1348return this.makeString(`ARK_RUNTIME_${RuntimeType[rt]}`)
1349}
1350makeMapKeyTypeName(c: MapConvertor): string {
1351return c.table.computeTargetName(c.table.toTarget(c.keyType), false)
1352}
1353makeMapValueTypeName(c: MapConvertor): string {
1354return c.table.computeTargetName(c.table.toTarget(c.valueType), false)
1355}
1356makeMapInsert(keyAccessor: string, key: string, valueAccessor: string, value: string): LanguageStatement {
1357// TODO: maybe use std::move?
1358return new BlockStatement([
1359this.makeAssign(keyAccessor, undefined, this.makeString(key), false),
1360this.makeAssign(valueAccessor, undefined, this.makeString(value), false)
1361], false)
1362}
1363getTagType(): Type {
1364return new Type(PrimitiveType.Tag.getText())
1365}
1366getRuntimeType(): Type {
1367return new Type(PrimitiveType.RuntimeType.getText())
1368}
1369makeType(typeName: string, nullable: boolean, receiver?: string): Type {
1370// make deducing type from receiver
1371if (receiver != undefined) {
1372return new Type(`std::decay<decltype(${receiver})>::type`)
1373}
1374return new Type(typeName)
1375}
1376makeTupleAssign(receiver: string, tupleFields: string[]): LanguageStatement {
1377const statements =
1378tupleFields.map((field, index) => {
1379//TODO: maybe use std::move?
1380return this.makeAssign(`${receiver}.value${index}`, undefined, this.makeString(field), false)
1381})
1382return new BlockStatement(statements, false)
1383}
1384get supportedModifiers(): MethodModifier[] {
1385return [MethodModifier.INLINE, MethodModifier.STATIC]
1386}
1387enumFromOrdinal(value: LanguageExpression, enumType: string): LanguageExpression {
1388return value;
1389}
1390ordinalFromEnum(value: LanguageExpression, enumType: string): LanguageExpression {
1391return value;
1392}
1393makeUnsafeCast(convertor: ArgConvertor, param: string): string {
1394return param
1395}
1396}
1397
1398export function createLanguageWriter(language: Language): LanguageWriter {
1399switch (language) {
1400case Language.TS: return new TSLanguageWriter(new IndentedPrinter())
1401case Language.ARKTS: return new ETSLanguageWriter(new IndentedPrinter())
1402case Language.JAVA: return new JavaLanguageWriter(new IndentedPrinter())
1403case Language.CPP: return new CppLanguageWriter(new IndentedPrinter())
1404default: throw new Error(`Language ${language.toString()} is not supported`)
1405}
1406}
1407
1408class TsObjectDeclareNodeNameConvertor extends TSTypeNodeNameConvertor {
1409private useOptionalTypes = true
1410
1411override convertTuple(node: ts.TupleTypeNode): string {
1412this.useOptionalTypes = false
1413const name = super.convertTuple(node);
1414this.useOptionalTypes = true
1415return name
1416}
1417override convertOptional(node: ts.OptionalTypeNode): string {
1418let name = super.convertOptional(node);
1419if (!this.useOptionalTypes) {
1420name = name.replace("?", "")
1421}
1422return name
1423}
1424override convertImport(_node: ts.ImportTypeNode): string {
1425//TODO: to preventing an error IMPORT_* types were not found
1426return "object"
1427}
1428override convert(node: ts.Node | undefined): string {
1429if (node) {
1430return super.convert(node)
1431}
1432return "undefined";
1433}
1434}