From 7bc9adebaa75f46fb5325f2255d5d859cd444c8d Mon Sep 17 00:00:00 2001 From: Fabian Stamm Date: Thu, 18 Jan 2024 19:08:44 +0100 Subject: [PATCH] Fix some keyword errors --- examples/CSharp/Example/Program.cs | 4 ++ examples/example.jrpc | 8 ++++ package.json | 2 +- src/parser.ts | 6 +-- src/targets/csharp.ts | 61 ++++++++++++++++++++---------- src/targets/rust.ts | 24 ++++++++---- templates/ts_service_client.ts | 2 +- 7 files changed, 76 insertions(+), 31 deletions(-) diff --git a/examples/CSharp/Example/Program.cs b/examples/CSharp/Example/Program.cs index 138cdbd..3fe9e23 100644 --- a/examples/CSharp/Example/Program.cs +++ b/examples/CSharp/Example/Program.cs @@ -41,6 +41,10 @@ class TestSrvimpl : Example.TestServiceServer throw new Exception("This is a remote error :)"); } + public override Task FunctionWithKeywords(double type, double static_, double event_, int ctx) + { + throw new NotImplementedException(); + } } class CopyTransportS2 : Example.JRpcTransport diff --git a/examples/example.jrpc b/examples/example.jrpc index ca6ec4e..a156746 100644 --- a/examples/example.jrpc +++ b/examples/example.jrpc @@ -52,6 +52,8 @@ service TestService { FunctionWithArrayAsParamAndReturn(values1: float[], values2: float[]): float[]; + + FunctionWithKeywords(type: float, static: float, event: float): float; } type Test2 { @@ -59,6 +61,12 @@ type Test2 { age: int; } +type TestKeywords { + type: float; + static: float; + event: float; +} + service SimpleTestService { @Description("asdasdasd") GetTest(name: string, age: int): Test2; diff --git a/package.json b/package.json index a543fe9..b87d366 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@hibas123/jrpcgen", - "version": "1.2.16", + "version": "1.2.17", "main": "lib/index.js", "license": "MIT", "packageManager": "yarn@3.1.1", diff --git a/src/parser.ts b/src/parser.ts index 2224736..e3b8308 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -115,8 +115,8 @@ export default function parse(tokens: Token[], file: string): Parsed { return idx; }; - const eatText = (): [string, number] => { - checkTypes("text"); + const eatText = (allowKeyword?: boolean): [string, number] => { + checkTypes(...(allowKeyword ? ["text", "keyword"] : ["text"])); let val = currentToken.value; let idx = currentToken.startIdx; eatToken(); @@ -351,7 +351,7 @@ export default function parse(tokens: Token[], file: string): Parsed { if (currentToken.value !== ")") { while (true) { - const [name] = eatText(); + const [name] = eatText(true); eatToken(":"); const [type] = eatText(); let array = false; diff --git a/src/targets/csharp.ts b/src/targets/csharp.ts index 0d5cce5..cd666a7 100644 --- a/src/targets/csharp.ts +++ b/src/targets/csharp.ts @@ -8,6 +8,7 @@ import { import { CompileTarget } from "../compile"; import { LineAppender } from "../utils"; +import chalk from "chalk"; const conversion = { boolean: "bool", @@ -22,6 +23,16 @@ function toCSharpType(type: string): string { return (conversion as any)[type] || type; } +// TODO: Add other keywords as well! +const keywords = new Set(["event", "internal", "public", "private", "static"]); + +const fixKeywordName = (name: string) => { + if (keywords.has(name)) { + return `${name}_`; + } + return name; +} + export class CSharpTarget extends CompileTarget<{ csharp_namespace: string }> { name: string = "c#"; @@ -61,11 +72,20 @@ export class CSharpTarget extends CompileTarget<{ csharp_namespace: string }> { a(0, ``); a(0, `public class ${definition.name} {`); for (const field of definition.fields) { + let fn = field.name; + if (keywords.has(field.name)) { + console.log( + chalk.yellow("[RUST] WARNING:"), + `Field name '${fn}' is not allowed in C#. Renaming to '${fn}_'` + ); + fn = fixKeywordName(fn); + a(1, `[JsonPropertyName("${fn}")]`); + } + if (field.array) { a( 1, - `public IList<${toCSharpType(field.type)}>? ${ - field.name + `public IList<${toCSharpType(field.type)}>? ${fn } { get; set; }` ); } else if (field.map) { @@ -73,12 +93,12 @@ export class CSharpTarget extends CompileTarget<{ csharp_namespace: string }> { 1, `public Dictionary<${toCSharpType(field.map)}, ${toCSharpType( field.type - )}>? ${field.name} { get; set; }` + )}>? ${fn} { get; set; }` ); } else { a( 1, - `public ${toCSharpType(field.type)}? ${field.name} { get; set; }` + `public ${toCSharpType(field.type)}? ${fn} { get; set; }` ); } } @@ -127,10 +147,12 @@ export class CSharpTarget extends CompileTarget<{ csharp_namespace: string }> { for (const fnc of definition.functions) { let params = fnc.inputs .map((inp) => { + let name = fixKeywordName(inp.name); + if (inp.array) { - return `List<${toCSharpType(inp.type)}> ${inp.name}`; + return `List<${toCSharpType(inp.type)}> ${name}`; } else { - return `${toCSharpType(inp.type)} ${inp.name}`; + return `${toCSharpType(inp.type)} ${name}`; } }) .join(", "); @@ -139,7 +161,7 @@ export class CSharpTarget extends CompileTarget<{ csharp_namespace: string }> { a( 2, `var param = new JsonArray(${fnc.inputs - .map((e) => `JsonSerializer.SerializeToNode(${e.name})`) + .map((e) => `JsonSerializer.SerializeToNode(${fixKeywordName(e.name)})`) .join(", ")});` ); @@ -219,10 +241,11 @@ export class CSharpTarget extends CompileTarget<{ csharp_namespace: string }> { for (const fnc of definition.functions) { let params = [ ...fnc.inputs.map((inp) => { + let name = fixKeywordName(inp.name) if (inp.array) { - return `List<${toCSharpType(inp.type)}> ${inp.name}`; + return `List<${toCSharpType(inp.type)}> ${name}`; } else { - return `${toCSharpType(inp.type)} ${inp.name}`; + return `${toCSharpType(inp.type)} ${name}`; } }), "TContext ctx", @@ -272,15 +295,15 @@ export class CSharpTarget extends CompileTarget<{ csharp_namespace: string }> { a( 4, pref + - `this.${fnc.name}(${[ - ...fnc.inputs.map((inp, idx) => { - let type = inp.array - ? `List<${toCSharpType(inp.type)}>` - : `${toCSharpType(inp.type)}`; - return `param[${idx}]!.Deserialize<${type}>()`; - }), - "context", - ].join(", ")});` + `this.${fnc.name}(${[ + ...fnc.inputs.map((inp, idx) => { + let type = inp.array + ? `List<${toCSharpType(inp.type)}>` + : `${toCSharpType(inp.type)}`; + return `param[${idx}]!.Deserialize<${type}>()`; + }), + "context", + ].join(", ")});` ); if (fnc.return && fnc.return.type != "void") { @@ -314,5 +337,5 @@ export class CSharpTarget extends CompileTarget<{ csharp_namespace: string }> { this.generateServiceServer(definition); } - finalize(steps: Step[]): void {} + finalize(steps: Step[]): void { } } diff --git a/src/targets/rust.ts b/src/targets/rust.ts index c702080..ff2820c 100644 --- a/src/targets/rust.ts +++ b/src/targets/rust.ts @@ -23,6 +23,16 @@ function toSnake(input: string) { ); } +// TODO: Add other keywords as well! +const keywords = new Set(["type", "static"]); + +const fixKeywordName = (name: string) => { + if (keywords.has(name)) { + return `${name}_`; + } + return name; +} + export class RustTarget extends CompileTarget<{ rust_crate: string }> { name: string = "rust"; @@ -74,14 +84,14 @@ export class RustTarget extends CompileTarget<{ rust_crate: string }> { a(1, `#[allow(non_snake_case)]`); let fn = `pub ${field.name}:`; - if (field.name == "type") { + if (keywords.has(field.name)) { // TODO: Add other keywords as well! console.log( chalk.yellow("[RUST] WARNING:"), - "Field name 'type' is not allowed in Rust. Renaming to 'type_'" + `Field name '${field.name}' is not allowed in Rust. Renaming to '${field.name}_'` ); - fn = `pub type_:`; - a(1, `#[serde(rename = "type")]`); + fn = `pub ${fixKeywordName(field.name)}:`; + a(1, `#[serde(rename = "${field.name}")]`); } let opts = ""; let opte = ""; @@ -156,7 +166,7 @@ export class RustTarget extends CompileTarget<{ rust_crate: string }> { a(0, ``); for (const fnc of definition.functions) { let params = fnc.inputs - .map((i) => i.name + ": " + typeToRust(i.type, i.array)) + .map((i) => fixKeywordName(i.name) + ": " + typeToRust(i.type, i.array)) .join(", "); let ret = fnc.return ? typeToRust(fnc.return.type, fnc.return.array) @@ -167,7 +177,7 @@ export class RustTarget extends CompileTarget<{ rust_crate: string }> { a(3, `jsonrpc: "2.0".to_owned(),`); a(3, `id: None, // 'id' will be set by the send_request function`); a(3, `method: "${definition.name}.${fnc.name}".to_owned(),`); - a(3, `params: json!([${fnc.inputs.map((e) => e.name)}])`); + a(3, `params: json!([${fnc.inputs.map((e) => fixKeywordName(e.name))}])`); a(2, `};`); a(2, ``); if (fnc.return) { @@ -220,7 +230,7 @@ export class RustTarget extends CompileTarget<{ rust_crate: string }> { let params = fnc.inputs.length > 0 ? fnc.inputs - .map((i) => i.name + ": " + typeToRust(i.type, i.array)) + .map((i) => fixKeywordName(i.name) + ": " + typeToRust(i.type, i.array)) .join(", ") : ""; let ret = fnc.return diff --git a/templates/ts_service_client.ts b/templates/ts_service_client.ts index 17abdd1..0048b83 100644 --- a/templates/ts_service_client.ts +++ b/templates/ts_service_client.ts @@ -1,7 +1,7 @@ //@template-ignore import { VerificationError } from "./ts_base"; //@template-ignore -import { RequestObject, ResponseObject, ErrorCodes, Logging } from "./ts_service_base"; +import { type RequestObject, type ResponseObject, ErrorCodes, Logging } from "./ts_service_base"; export type IMessageCallback = (data: any) => void;