Skip to content

Commit

Permalink
Contribution of a generator implementation using expandToNode and `…
Browse files Browse the repository at this point in the history
…joinToNode`
  • Loading branch information
sailingKieler committed May 25, 2023
1 parent e7ed0cb commit 858c0ae
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/arithmeticsEditor/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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[] };

Expand Down
93 changes: 93 additions & 0 deletions src/generator/generator-with-nodes.ts
Original file line number Diff line number Diff line change
@@ -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;
}

0 comments on commit 858c0ae

Please sign in to comment.