From 858c0ae9a52d9b98267db92bbb383ef2b676444f Mon Sep 17 00:00:00 2001 From: Christian Schneider Date: Fri, 26 May 2023 00:16:16 +0200 Subject: [PATCH] Contribution of a generator implementation using `expandToNode` and `joinToNode` --- src/arithmeticsEditor/index.ts | 2 +- src/generator/generator-with-nodes.ts | 93 +++++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 src/generator/generator-with-nodes.ts diff --git a/src/arithmeticsEditor/index.ts b/src/arithmeticsEditor/index.ts index 0f06b82..f56418a 100644 --- a/src/arithmeticsEditor/index.ts +++ b/src/arithmeticsEditor/index.ts @@ -8,7 +8,7 @@ import { expandToString } from 'langium'; import { buildWorkerDefinition } from 'monaco-editor-workers'; import { CodeEditorConfig, MonacoEditorLanguageClientWrapper, WorkerConfigOptions } from 'monaco-editor-wrapper'; import { Diagnostic, DiagnosticSeverity, NotificationType } from 'vscode-languageserver/browser.js'; -import { generate } from '../generator/generator.js'; +import { generate } from '../generator/generator-with-nodes.js'; type DocumentChange = { uri: string, content: string, diagnostics: Diagnostic[] }; diff --git a/src/generator/generator-with-nodes.ts b/src/generator/generator-with-nodes.ts new file mode 100644 index 0000000..f026617 --- /dev/null +++ b/src/generator/generator-with-nodes.ts @@ -0,0 +1,93 @@ +/****************************************************************************** + * Copyright 2023 TypeFox GmbH + * This program and the accompanying materials are made available under the + * terms of the MIT License, which is available in the project root. + ******************************************************************************/ + +import { DefaultAstNodeLocator, DefaultJsonSerializer, DefaultNameProvider, expandToNode, Generated, joinToNode, toString } from 'langium'; +import { Definition, Evaluation, Expression, isBinaryExpression, isDefinition, isFunctionCall, isNumberLiteral, Module, Statement } from 'langium-arithmetics-dsl/api'; + +export function generate({uri, content}: { uri: string, content: string | Module }): string { + if (typeof content === 'string') { + content = deserializeModule(content); + } + + return toString( + generateModule(content) + ); +} + +function generateModule(root: Module): Generated { + return expandToNode` + "use strict"; + (() => { + ${generateModuleContent(root)} + }) + `; +} + +const lastComputableExpressionValueVarName = 'lastComputableExpressionValue'; + +function generateModuleContent(module: Module): Generated { + return expandToNode` + let ${lastComputableExpressionValueVarName}; + ${ joinToNode(module.statements, generateStatement, { appendNewLineIfNotEmpty: true }) } + + return ${lastComputableExpressionValueVarName}; + `; +} + +function generateStatement(stmt: Statement): Generated { + if (isDefinition(stmt)) + return generateDefinition(stmt); + else + return generateEvaluation(stmt); +} + +function generateDefinition(def: Definition): Generated { + return def.args && def.args.length ? + expandToNode` + const ${def.name} = (${joinToNode(def.args, arg => arg.name, { separator: ', '})}) => ${generateExpression(def.expr)}; + ` : expandToNode` + const ${def.name} = ${lastComputableExpressionValueVarName} = ${generateExpression(def.expr)}; + `; +} + +function generateEvaluation(evaln: Evaluation): Generated { + return expandToNode` + ${lastComputableExpressionValueVarName} = ${generateExpression(evaln.expression)}; + `; +} + +function generateExpression(expr: Expression): Generated { + if (isNumberLiteral(expr)) { + return expr.value.toString(); + + } else if (isBinaryExpression(expr)) { + const leftAsIs = isNumberLiteral(expr.left) || isFunctionCall(expr.left); + const rightAsIs = isNumberLiteral(expr.right) || isFunctionCall(expr.right); + const left = leftAsIs ? generateExpression(expr.left) : expandToNode`(${generateExpression(expr.left )})`; + const right = rightAsIs ? generateExpression(expr.right) : expandToNode`(${generateExpression(expr.right)})`; + return expandToNode` + ${left} ${expr.operator} ${right} + `; + + } else { + return expandToNode`${expr.func.ref?.name}`.appendTemplateIf(!!expr.args.length)` + ( + ${joinToNode(expr.args, generateExpression, { separator: ', ' })} + ) + `; + }; +} + +function deserializeModule(input: string): Module { + return new DefaultJsonSerializer({ + workspace: { + AstNodeLocator: new DefaultAstNodeLocator() + }, + references: { + NameProvider: new DefaultNameProvider() + } + } as any).deserialize(input) as Module; +} \ No newline at end of file