diff --git a/.gitignore b/.gitignore index ba75b16..e08447c 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ examples/CSharp/Example/obj examples/definition.json examples/Rust/Gen examples/Rust/Impl/target +examples/Dart/out templates/CSharp/bin templates/CSharp/obj lib/ diff --git a/src/ir.ts b/src/ir.ts index b360796..31672f7 100644 --- a/src/ir.ts +++ b/src/ir.ts @@ -2,7 +2,7 @@ import type { Parsed, StatementNode } from "./parser"; import dbg from "debug"; const log = dbg("app"); -const BUILTIN = ["float", "int", "string", "boolean"]; +export const BUILTIN = ["float", "int", "string", "boolean"]; export class IRError extends Error { constructor(public statement: StatementNode, message: string) { diff --git a/src/process.ts b/src/process.ts index a6db5b0..dcebc2a 100644 --- a/src/process.ts +++ b/src/process.ts @@ -13,6 +13,7 @@ import { import { CSharpTarget } from "./targets/csharp"; import { RustTarget } from "./targets/rust"; import { ZIGTarget } from "./targets/zig"; +import { DartTarget } from "./targets/dart"; class CatchedError extends Error {} @@ -25,6 +26,7 @@ Targets.set("ts-node", NodeJSTypescriptTarget); Targets.set("c#", CSharpTarget as typeof CompileTarget); Targets.set("rust", RustTarget as typeof CompileTarget); Targets.set("zig", ZIGTarget as typeof CompileTarget); +Targets.set("dart", DartTarget as typeof CompileTarget); function indexToLineAndCol(src: string, index: number) { let line = 1; diff --git a/src/targets/dart.ts b/src/targets/dart.ts new file mode 100644 index 0000000..5b85263 --- /dev/null +++ b/src/targets/dart.ts @@ -0,0 +1,168 @@ +import { TypeDefinition, ServiceDefinition, EnumDefinition, Step } from "../ir"; + +import { CompileTarget } from "../compile"; +import { LineAppender, lineAppender } from "../utils"; +import chalk from "chalk"; + +const conversion = { + boolean: "bool", + int: "int", + float: "double", + string: "String", + void: "void", + bytes: "Uint8List", //TODO: Check this +}; + +function toDartType(type: string): string { + return (conversion as any)[type] || type; +} + +export class DartTarget extends CompileTarget<{}> { + name: string = "dart"; + + start(): void { + if (this.options.allow_bytes == true) { + throw new Error("Dart has no support for 'bytes' yet!"); + } + } + + getImport(name: string) { + return `import "./${name}.dart";`; + } + + generateImports(a: lineAppender, def: TypeDefinition | ServiceDefinition) { + + def.depends.forEach((dep) => { + a(0, this.getImport(dep)); + }); + } + + generateType(definition: TypeDefinition): void { + const { a, getResult } = LineAppender(); + + this.generateImports(a, definition); + + a(0, ``); + a(0, `class ${definition.name} {`); + for (const field of definition.fields) { + if (field.array) { + a(1, `List<${toDartType(field.type)}>? ${field.name};`); + } else if (field.map) { + a(1, `Map<${toDartType(field.map)},${toDartType(field.type)}>? ${field.name};`); + } else { + a(1, `${toDartType(field.type)}? ${field.name};`); + } + } + + a(0, ``); + a(1, `${definition.name}(${definition.fields.map(e => `this.${e.name}`).join(",")});`); + a(0, ``); + a(1, `${definition.name}.fromJson(Map json) {`); + for (const field of definition.fields) { + a(2, `if(json.containsKey("${field.name}")) {`); + + const parseField = (value: string)=>{ + if (conversion[field.type]) { + return value; + } else { + return `${field.type}.fromJson(${value})`; + } + } + + if(field.array) { + a(3, `this.${field.name} = [];`); + a(3, `(json["${field.name}"] as List).forEach((e) => {`) + a(4, `this.${field.name}!.add(${parseField("e")})`); + a(3, `});`) + } else if(field.map) { + a(3, `this.${field.name} = {};`); + a(3, `(json["${field.name}"] as Map<${toDartType(field.map)},dynamic>).forEach((key, value) => {`) + a(4, `this.${field.name}![key] = ${parseField("value")}`); + a(3, `});`) + } else { + a(3, `this.${field.name} = ${parseField(`json["${field.name}"]`)};`); + } + a(2, `} else {`); + a(3, `this.${field.name} = null;`); + a(2, `}`); + a(0, ``); + } + + a(1, `}`); + a(0, `}`); + + this.writeFile(`${definition.name}.dart`, getResult()); + } + + generateEnum(definition: EnumDefinition): void { + const { a, getResult } = LineAppender(); + + a(0, `enum ${definition.name} {`); + for (const entry of definition.values) { + const isLast = definition.values[definition.values.length - 1] == entry; + a(1, `${entry.name}(${entry.value})${isLast ? ";" : ","}`); + + } + a(0, ``); + a(1, `final int val;`); + a(1, `const ${definition.name}(int valT) : val= valT;`); + a(1, `static ${definition.name}? fromJson(int val) {`); + a(2, `switch(val){`); + for (const entry of definition.values) { + a(3, `case ${entry.value}:`); + a(4, `return ${definition.name}.${entry.name};`); + } + a(3, `default:`); + a(4, `return null;`); + a(1, `}`); + a(0, `}`); + + a(0, ``); + + // a(0, `extension ${definition.name}Ext on ${definition.name} {`); + // a(1, `int get val {`); + // a(2, `switch(this) {`); + // for(const entry of definition.values) { + // a(3, `case ${definition.name}.${entry.name}:`); + // a(4, `return ${entry.value};`); + // } + // a(3, `default:`); + // a(4, `return -double.maxFinite.toInt();`); + // a(2, `}`); + // a(1, `}`); + // a(0, `}`); + + this.writeFile(`${definition.name}.dart`, getResult()); + } + + generateService(definition: ServiceDefinition): void { + console.log( + chalk.yellow("[DART] WARNING:"), + "DART support for services is not yet there. Service generation is skipped!" + ); + } + + finalize(steps: Step[]): void { + const { a, getResult } = LineAppender(); + + // steps.forEach(([type, def]) => { + // switch (type) { + // case "type": + // a(0, `pub ${this.getImport(def.name)}`); + // break; + // case "enum": + // a(0, `pub ${this.getImport(def.name)}`); + // break; + // default: + // console.warn( + // chalk.yellow("[DART] WARNING:"), + // "unimplemented step found:", + // type + // ); + // // case "service": + // } + // }); + + // this.writeFile(`mod.dart`, getResult()); + } +} diff --git a/src/targets/zig.ts b/src/targets/zig.ts index 4b3bb88..f418ce0 100644 --- a/src/targets/zig.ts +++ b/src/targets/zig.ts @@ -17,7 +17,7 @@ function toZigType(type: string): string { return (conversion as any)[type] || type; } -export class ZIGTarget extends CompileTarget<{ csharp_namespace: string }> { +export class ZIGTarget extends CompileTarget<{ }> { name: string = "zig"; start(): void {