From c8ea78490d5ed64687218e52e4a7ab7a7779b8d5 Mon Sep 17 00:00:00 2001 From: emilkrebs Date: Sun, 19 Nov 2023 19:43:10 +0100 Subject: [PATCH] moved showcase to langium ast helper --- .../scripts/arithmetics/arithmetics-tools.tsx | 6 +- .../scripts/arithmetics/arithmetics.tsx | 2 +- .../scripts/domainmodel/domainmodel-tools.ts | 3 +- .../scripts/domainmodel/domainmodel.tsx | 4 +- .../scripts/langium-utils/langium-ast.ts | 151 ------------------ .../statemachine/statemachine-tools.ts | 2 +- .../scripts/statemachine/statemachine.tsx | 4 +- hugo/package.json | 3 +- package-lock.json | 6 + 9 files changed, 20 insertions(+), 161 deletions(-) delete mode 100644 hugo/assets/scripts/langium-utils/langium-ast.ts diff --git a/hugo/assets/scripts/arithmetics/arithmetics-tools.tsx b/hugo/assets/scripts/arithmetics/arithmetics-tools.tsx index 651b1777..1a4322ea 100644 --- a/hugo/assets/scripts/arithmetics/arithmetics-tools.tsx +++ b/hugo/assets/scripts/arithmetics/arithmetics-tools.tsx @@ -1,5 +1,9 @@ import { monaco } from "langium-website-core/bundle"; -import { Pos } from "../langium-utils/langium-ast"; + +type Pos = { + character: number; + line: number; +} export interface Evaluation { range: { diff --git a/hugo/assets/scripts/arithmetics/arithmetics.tsx b/hugo/assets/scripts/arithmetics/arithmetics.tsx index 19ff8c76..4b0fafde 100644 --- a/hugo/assets/scripts/arithmetics/arithmetics.tsx +++ b/hugo/assets/scripts/arithmetics/arithmetics.tsx @@ -2,8 +2,8 @@ import { addMonacoStyles, createUserConfig, MonacoEditorReactComp, UserConfig } import { buildWorkerDefinition } from "monaco-editor-workers"; import React from "react"; import { createRoot } from "react-dom/client"; -import { Diagnostic, DocumentChangeResponse } from "../langium-utils/langium-ast"; import { Evaluation, examples, syntaxHighlighting } from "./arithmetics-tools"; +import { Diagnostic, DocumentChangeResponse } from "langium-ast-helper"; addMonacoStyles('monaco-styles-helper'); diff --git a/hugo/assets/scripts/domainmodel/domainmodel-tools.ts b/hugo/assets/scripts/domainmodel/domainmodel-tools.ts index c174eb44..f80e8e3a 100644 --- a/hugo/assets/scripts/domainmodel/domainmodel-tools.ts +++ b/hugo/assets/scripts/domainmodel/domainmodel-tools.ts @@ -1,5 +1,4 @@ - -import { AstNode } from "../langium-utils/langium-ast"; +import { AstNode } from "langium-ast-helper"; import { TreeNode } from "./d3tree"; diff --git a/hugo/assets/scripts/domainmodel/domainmodel.tsx b/hugo/assets/scripts/domainmodel/domainmodel.tsx index c07a4ab4..b63b4f5a 100644 --- a/hugo/assets/scripts/domainmodel/domainmodel.tsx +++ b/hugo/assets/scripts/domainmodel/domainmodel.tsx @@ -2,8 +2,8 @@ import { addMonacoStyles, createUserConfig, MonacoEditorReactComp, UserConfig } import { buildWorkerDefinition } from "monaco-editor-workers"; import React from "react"; import { createRoot } from "react-dom/client"; -import { Diagnostic, DocumentChangeResponse, LangiumAST } from "../langium-utils/langium-ast"; import { DomainModelAstNode, example, getMainTreeNode, syntaxHighlighting } from "./domainmodel-tools"; +import { deserializeAST, Diagnostic, DocumentChangeResponse } from 'langium-ast-helper'; import D3Tree from "./d3tree"; @@ -70,7 +70,7 @@ class App extends React.Component<{}, AppState> { */ onDocumentChange(resp: DocumentChangeResponse) { // get the AST from the response and deserialize it - const ast = new LangiumAST().deserializeAST(resp.content) as DomainModelAstNode; + const ast = deserializeAST(resp.content) as DomainModelAstNode; this.setState({ ast: ast, diff --git a/hugo/assets/scripts/langium-utils/langium-ast.ts b/hugo/assets/scripts/langium-utils/langium-ast.ts deleted file mode 100644 index 92e29311..00000000 --- a/hugo/assets/scripts/langium-utils/langium-ast.ts +++ /dev/null @@ -1,151 +0,0 @@ - -/** - * Provides utilities for deserializing Langium ASTs - */ -export class LangiumAST { - // Identify an AST node by it's type & shape - isReference(obj: unknown): obj is Reference { - return typeof obj === 'object' && obj !== null && typeof (obj as Reference).$ref === 'string'; - } - - // Identify a ref by its type & shape as well - isAstNode(obj: unknown): obj is AstNode { - return typeof obj === 'object' && obj !== null && typeof (obj as AstNode).$type === 'string'; - } - - // Takes the root, and a path string, traversing the root to find the node denoted by the path - getAstNode(root: AstNode, path: string): AstNode | undefined { - if (!path.startsWith('#')) { - // this isn't something we can decode, skip - return undefined; - } - - // break up path segments for traversal - const segments = path.substring(1).split('/'); - - return segments.reduce((previousValue, currentValue) => { - if (!previousValue || currentValue.length === 0) { - // no root or nothing else to check, return what we have so far - return previousValue; - } - const propertyIndex = currentValue.indexOf('@'); - if (propertyIndex > 0) { - // Array part of path to extract - const property = currentValue.substring(0, propertyIndex); - // get array index using prop - const arrayIndex = parseInt(currentValue.substring(propertyIndex + 1)); - // find array with prop & return via index - const array = (previousValue as unknown as Record)[property]; - return array?.[arrayIndex]; - } - // instead, index one farther down the tree using the current value - return (previousValue as unknown as Record)[currentValue]; - }, root); - } - - - // Link a given node - linkNode(node: AstNode, root: AstNode, container?: AstNode, containerProperty?: string, containerIndex?: number): void { - // set container details, if any (undefined for root) - node.$containerProperty = containerProperty; - node.$containerIndex = containerIndex; - node.$container = container; - - // iterate over all props in this node - for (const [propertyName, item] of Object.entries(node)) { - - if (propertyName === '$container') { - // don't evaluate containers again (causes a recursive loop) - continue; - } - - if (Array.isArray(item)) { - // Array of refs/nodes - for (let index = 0; index < item.length; index++) { - const element = item[index]; - if (this.isReference(element)) { - // reconstruct cross ref - element.ref = this.getAstNode(root, element.$ref); - } else if (this.isAstNode(element)) { - // another AST node we should link with proper details - this.linkNode(element, root, node, propertyName, index); - } - } - } else if (this.isReference(item)) { - // single reference to handle - item.ref = this.getAstNode(root, item.$ref); - } else if (this.isAstNode(item)) { - // single ast node to handle - this.linkNode(item, root, node, propertyName); - } - } - } - - // link given ast - linkAst(root: AstNode): void { - this.linkNode(root, root); - } - - /** - * Takes a string corresponding to a serialized Langium AST, and returns a deserialized AST node - * - * @param content String to parse & deserialize - * @returns A Langium AST with cross-refs restored - */ - deserializeAST(content: string): AstNode { - const root = JSON.parse(content); - this.linkNode(root, root); - return root; - } -} - -/** - * General position data for diagnostics - */ -export type Pos = { - character: number; - line: number; -} - -/** - * Diagnostics that can be returned in a DocumentChange response - */ -export type Diagnostic = { - // general string-based code for this diagnostic (like 'linking-error') - code: string; - // user-friendly diagnostic message - message: string; - // start -> end range of the diagnostic - range: { - start: Pos; - end: Pos; - } - // severity code - severity: number; - // source language by string - source: string; -}; - -/** - * Response for a DocumentChange notification - */ -export type DocumentChangeResponse = { - uri: string; - content: string; - diagnostics: Diagnostic[]; -}; - -/** -* Approximation of a langium AST, capturing the most relevant information -*/ -export interface AstNode { - $type: string; - $container?: AstNode; - $containerProperty?: string; - $containerIndex?: number; -} - -export interface Reference { - ref?: T; - $ref: string -} \ No newline at end of file diff --git a/hugo/assets/scripts/statemachine/statemachine-tools.ts b/hugo/assets/scripts/statemachine/statemachine-tools.ts index 035b2221..72003e51 100644 --- a/hugo/assets/scripts/statemachine/statemachine-tools.ts +++ b/hugo/assets/scripts/statemachine/statemachine-tools.ts @@ -1,4 +1,4 @@ -import { AstNode } from "../langium-utils/langium-ast"; +import { AstNode } from "langium-ast-helper"; export class StateMachineTools { currentState: StateMachineState; diff --git a/hugo/assets/scripts/statemachine/statemachine.tsx b/hugo/assets/scripts/statemachine/statemachine.tsx index 2bb3d540..368ea90a 100644 --- a/hugo/assets/scripts/statemachine/statemachine.tsx +++ b/hugo/assets/scripts/statemachine/statemachine.tsx @@ -2,9 +2,9 @@ import { addMonacoStyles, createUserConfig, MonacoEditorReactComp, UserConfig } import { buildWorkerDefinition } from "monaco-editor-workers"; import React from "react"; import { createRoot } from "react-dom/client"; -import { Diagnostic, DocumentChangeResponse, LangiumAST } from "../langium-utils/langium-ast"; import { defaultText, StateMachineAstNode, StateMachineState, StateMachineTools } from "./statemachine-tools"; import statemachineGrammar from 'langium-statemachine-dsl/syntaxes/statemachine.tmLanguage.json'; +import { deserializeAST, Diagnostic, DocumentChangeResponse } from "langium-ast-helper"; addMonacoStyles('monaco-styles-helper'); @@ -249,7 +249,7 @@ class StateMachineComponent extends React.Component<{ */ onDocumentChange(resp: DocumentChangeResponse) { // decode the received Ast - const statemachineAst = new LangiumAST().deserializeAST(resp.content) as StateMachineAstNode; + const statemachineAst = deserializeAST(resp.content) as StateMachineAstNode; this.preview.current?.startPreview(statemachineAst, resp.diagnostics); } diff --git a/hugo/package.json b/hugo/package.json index 7a1e6aa5..c6255185 100644 --- a/hugo/package.json +++ b/hugo/package.json @@ -49,7 +49,8 @@ "monaco-editor-workers": "~0.44.0", "react": "~18.2.0", "react-dom": "~18.2.0", - "vscode-languageserver": "~8.0.2" + "vscode-languageserver": "~8.0.2", + "langium-ast-helper": "0.1.2" }, "volta": { "node": "18.18.1", diff --git a/package-lock.json b/package-lock.json index 155d8ee0..a62eea17 100644 --- a/package-lock.json +++ b/package-lock.json @@ -80,6 +80,7 @@ "hugo-extended": "~0.89.4", "langium": "^1.2.0", "langium-arithmetics-dsl": "~1.2.1", + "langium-ast-helper": "0.1.2", "langium-domainmodel-dsl": "~1.2.0", "langium-minilogo": "^1.2.0", "langium-sql": "^0.2.3", @@ -4296,6 +4297,11 @@ "node": ">=14" } }, + "node_modules/langium-ast-helper": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/langium-ast-helper/-/langium-ast-helper-0.1.2.tgz", + "integrity": "sha512-xS64ZOp3fOUcTnlQoLwYwJKi2SU8yPeKGLFZlhxFUR4zJCtJ0teFfwsC+TR7GXWS5Tf3pxG+/Lf4mgkpKhOY+Q==" + }, "node_modules/langium-domainmodel-dsl": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/langium-domainmodel-dsl/-/langium-domainmodel-dsl-1.2.0.tgz",