├── README.md
├── examples
└── editor.html
├── src
├── index.ts
├── node
│ ├── index.ts
│ ├── main.ts
│ ├── context.ts
│ └── library.ts
├── browser
│ ├── index.ts
│ ├── library.ts
│ └── context.ts
└── common
│ ├── diagnostics.ts
│ ├── scope.ts
│ ├── writer.ts
│ ├── util.ts
│ ├── dom.ts
│ ├── parser.ts
│ ├── document.ts
│ ├── library.ts
│ ├── context.ts
│ ├── predefined.ts
│ ├── graphics.ts
│ └── symbols.ts
├── package.json
├── webpack.config.js
├── .gitignore
├── tsconfig.json
└── OSMC-License.txt
/README.md:
--------------------------------------------------------------------------------
1 | # OMFrontend.js
2 |
3 | An [open-source](OSMC-License.txt) front-end for Modelica written in TypeScript/JavaScript.
4 | Works together with [tree-sitter-modelica](https://github.com/OpenModelica/tree-sitter-modelica).
5 |
--------------------------------------------------------------------------------
/examples/editor.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Modelica Editor
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * OMFrontend.js
3 | * Copyright (C) 2022 Perpetual Labs, Ltd.
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU Affero General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU Affero General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Affero General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | /**
20 | * @author Mohamad Omar Nachawati
21 | */
22 |
23 | export * from "./browser/index.js";
24 | export * from "./node/index.js";
25 |
--------------------------------------------------------------------------------
/src/node/index.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * OMFrontend.js
3 | * Copyright (C) 2022 Perpetual Labs, Ltd.
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU Affero General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU Affero General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Affero General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | /**
20 | * @author Mohamad Omar Nachawati
21 | */
22 |
23 | export * from "../common/context.js";
24 | export * from "../common/diagnostics.js";
25 | export * from "../common/document.js";
26 | export * from "../common/graphics.js";
27 | export * from "../common/library.js";
28 | export * from "../common/parser.js";
29 | export * from "../common/predefined.js";
30 | export * from "../common/scope.js";
31 | export * from "../common/symbols.js";
32 | export * from "../common/syntax.js";
33 | export * from "../common/util.js";
34 | export * from "../common/writer.js";
35 |
36 | export * from "./context.js";
37 | export * from "./library.js";
38 | export * from "./main.js";
--------------------------------------------------------------------------------
/src/browser/index.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * OMFrontend.js
3 | * Copyright (C) 2022 Perpetual Labs, Ltd.
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU Affero General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU Affero General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Affero General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | /**
20 | * @author Mohamad Omar Nachawati
21 | */
22 |
23 | export * from "../common/context.js";
24 | export * from "../common/diagnostics.js";
25 | export * from "../common/document.js";
26 | export * from "../common/dom.js";
27 | export * from "../common/graphics.js";
28 | export * from "../common/library.js";
29 | export * from "../common/parser.js";
30 | export * from "../common/predefined.js";
31 | export * from "../common/scope.js";
32 | export * from "../common/symbols.js";
33 | export * from "../common/syntax.js";
34 | export * from "../common/util.js";
35 | export * from "../common/writer.js";
36 |
37 | export * from "./context.js";
38 | export * from "./library.js";
--------------------------------------------------------------------------------
/src/common/diagnostics.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * OMFrontend.js
3 | * Copyright (C) 2022 Perpetual Labs, Ltd.
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU Affero General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU Affero General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Affero General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | /**
20 | * @author Mohamad Omar Nachawati
21 | */
22 |
23 | import { Range } from "./parser.js";
24 |
25 | export enum ModelicaDiagnosticSeverity {
26 | ERROR = 0,
27 | HINT = 3,
28 | INFORMATION = 2,
29 | WARNING = 1,
30 | }
31 |
32 | export class ModelicaDiagnostic {
33 |
34 | code: number;
35 | message: string;
36 | range?: Range;
37 | severity: ModelicaDiagnosticSeverity;
38 | source?: string;
39 |
40 | constructor(code: number, message: string, severity: ModelicaDiagnosticSeverity, range?: Range | null) {
41 | this.code = code;
42 | this.message = message;
43 | this.severity = severity;
44 | this.range = range ?? undefined;
45 | }
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/src/browser/library.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * OMFrontend.js
3 | * Copyright (C) 2022 Perpetual Labs, Ltd.
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU Affero General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU Affero General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Affero General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | /**
20 | * @author Mohamad Omar Nachawati
21 | */
22 |
23 | import { ModelicaContext } from "../common/context.js";
24 | import { ModelicaLibrary } from "../common/library.js";
25 |
26 | export class ModelicaBrowserFileSystemLibrary extends ModelicaLibrary {
27 |
28 | #rootPath: string;
29 |
30 | constructor(context: ModelicaContext, rootPath: string) {
31 | super(context);
32 | this.#rootPath = rootPath;
33 | }
34 |
35 | override list(...path: string[]): AsyncIterableIterator {
36 | throw new Error("Method not implemented.");
37 | }
38 |
39 | override read(...path: string[]): Promise {
40 | throw new Error("Method not implemented.");
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "omfrontend",
3 | "version": "0.0.1",
4 | "description": "Modelica frontend in JavaScript",
5 | "type": "module",
6 | "main": "dist/node/index.js",
7 | "browser": "dist/browser/index.js",
8 | "types": "dist/types/index.d.ts",
9 | "files": [
10 | "dist"
11 | ],
12 | "bin": {
13 | "omf": "./dist/node/main.js"
14 | },
15 | "scripts": {
16 | "build-cli": "tsc",
17 | "build": "tsc && cd node_modules/tree-sitter-modelica && npx tree-sitter build --wasm . --docker && cd ../.. && webpack",
18 | "serve": "tsc -w & webpack serve & wait"
19 | },
20 | "devDependencies": {
21 | "@types/d3": "^7.1.0",
22 | "@types/jsdom": "^16.2.14",
23 | "@types/node": "^17.0.10",
24 | "@types/yargs": "^17.0.8",
25 | "copy-webpack-plugin": "^10.2.1",
26 | "file-loader": "^6.2.0",
27 | "resolve-typescript-plugin": "^1.1.5",
28 | "tree-sitter-cli": "^0.22.1",
29 | "ts-loader": "^9.2.6",
30 | "typescript": "^4.5.5",
31 | "webpack": "^5.67.0",
32 | "webpack-cli": "^4.9.2",
33 | "webpack-dev-server": "^4.7.3"
34 | },
35 | "dependencies": {
36 | "browser-process-hrtime": "^1.0.0",
37 | "jszip": "^3.7.1",
38 | "monaco-editor": "^0.32.1",
39 | "monaco-editor-core": "^0.32.1",
40 | "process": "^0.11.10",
41 | "tree-sitter": "^0.21.1",
42 | "tree-sitter-modelica": "file:../tree-sitter-modelica",
43 | "vscode-languageserver-textdocument": "^1.0.4",
44 | "web-tree-sitter": "^0.22.5",
45 | "yargs": "^17.3.1"
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/common/scope.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * OMFrontend.js
3 | * Copyright (C) 2022 Perpetual Labs, Ltd.
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU Affero General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU Affero General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Affero General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | /**
20 | * @author Mohamad Omar Nachawati
21 | */
22 |
23 | import { ModelicaContext } from "./context.js";
24 | import { ModelicaClassSymbol, ModelicaNamedElementSymbol } from "./symbols.js";
25 | import { ModelicaComponentReferenceExpressionSyntax, ModelicaIdentifierSyntax, ModelicaNameSyntax, ModelicaTypeSpecifierSyntax } from "./syntax.js";
26 |
27 | export interface ModelicaScope {
28 |
29 | get context(): ModelicaContext;
30 |
31 | resolve(reference: ModelicaIdentifierSyntax | ModelicaNameSyntax | ModelicaTypeSpecifierSyntax | string[] | string | null | undefined, global?: boolean): Promise;
32 |
33 | resolveFunction(reference: ModelicaComponentReferenceExpressionSyntax | ModelicaIdentifierSyntax | ModelicaNameSyntax | ModelicaTypeSpecifierSyntax | string[] | string | null | undefined, global?: boolean): Promise;
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/common/writer.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * OMFrontend.js
3 | * Copyright (C) 2022 Perpetual Labs, Ltd.
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU Affero General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU Affero General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Affero General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | /**
20 | * @author Mohamad Omar Nachawati
21 | */
22 |
23 | export interface Writer {
24 | write(message: string): void;
25 | }
26 |
27 | export abstract class PrintWriter implements Writer {
28 |
29 | print(message: string, indent?: number): void {
30 |
31 | if (indent != null)
32 | this.write(" ".repeat(indent));
33 |
34 | this.write(message);
35 |
36 | }
37 |
38 | println(message?: string, indent?: number): void {
39 |
40 | if (message != null) {
41 |
42 | if (indent != null)
43 | this.write(" ".repeat(indent));
44 |
45 | this.write(message);
46 |
47 | }
48 |
49 | this.write("\n");
50 |
51 | }
52 |
53 | abstract write(message: string): void;
54 |
55 | }
56 |
57 | export class BufferedPrintWriter extends PrintWriter {
58 |
59 | #buffer: string[] = [];
60 |
61 | override toString(): string {
62 | return this.#buffer.join("");
63 | }
64 |
65 | override write(message: string): void {
66 | this.#buffer.push(message);
67 | }
68 |
69 | }
--------------------------------------------------------------------------------
/src/common/util.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * OMFrontend.js
3 | * Copyright (C) 2022 Perpetual Labs, Ltd.
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU Affero General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU Affero General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Affero General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | /**
20 | * @author Mohamad Omar Nachawati
21 | */
22 |
23 | import { ModelicaIdentifierSyntax, ModelicaNameSyntax, ModelicaTypeSpecifierSyntax } from "./syntax.js";
24 |
25 | export function getIdentifiers(reference: ModelicaIdentifierSyntax | ModelicaNameSyntax | ModelicaTypeSpecifierSyntax | string | string[] | null | undefined): string[] {
26 |
27 | if (reference == null)
28 | return [];
29 |
30 | if (reference instanceof ModelicaIdentifierSyntax) {
31 |
32 | if (reference.value != null)
33 | return [reference.value];
34 |
35 | return [];
36 |
37 | }
38 |
39 | if (reference instanceof ModelicaNameSyntax)
40 | return reference.identifiers ?? [];
41 |
42 | if (reference instanceof ModelicaTypeSpecifierSyntax)
43 | return reference.identifiers ?? [];
44 |
45 | if (Array.isArray(reference))
46 | return reference;
47 |
48 | return reference.split(".").map(item => item.trim());
49 |
50 | }
51 |
52 | export function toArray(iterator: IterableIterator | null | undefined): T[] {
53 |
54 | let values: T[] = [];
55 |
56 | for (let value of iterator ?? [])
57 | values.push(value);
58 |
59 | return values;
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/src/node/main.ts:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env -S node --enable-source-maps
2 |
3 | /*
4 | * OMFrontend.js
5 | * Copyright (C) 2022 Perpetual Labs, Ltd.
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Affero General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Affero General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Affero General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | /**
22 | * @author Mohamad Omar Nachawati
23 | */
24 |
25 | import yargs from "yargs";
26 | import { hideBin } from "yargs/helpers";
27 | import { ModelicaNodeContext } from "./context.js";
28 | import fs from "fs";
29 | import { ModelicaStoredDefinitionSyntax } from "../common/syntax.js";
30 | const yargz = yargs(hideBin(process.argv));
31 | import { BufferedPrintWriter } from "../common/writer.js";
32 | import JSZip from "jszip";
33 |
34 | import util from "util";
35 |
36 | yargz.scriptName("omf")
37 | .usage("usage: $0 [options]")
38 | .alias("h", "help")
39 | .alias("v", "version")
40 | .option("silent", {
41 | alias: "q",
42 | default: false,
43 | describe: "Turns on silent mode",
44 | type: "boolean"
45 | })
46 | .option("std", {
47 | choices: ["3.5", "latest"],
48 | default: "latest",
49 | describe: "Sets the language standard that should be used"
50 | })
51 | .showHelpOnFail(true)
52 | .demandCommand(1)
53 | .wrap(yargz.terminalWidth())
54 | .command("parse ", "Parse Modelica file", (yargs) => {
55 | yargs.positional("file", {
56 | describe: "file to parse",
57 | type: "string",
58 | })
59 | }, async (args: any) => {
60 | let context = new ModelicaNodeContext();
61 | let text = fs.readFileSync(args.file, { encoding: "utf8" });
62 | let tree = context.parse(text);
63 | console.log(tree.rootNode.toString());
64 | })
65 | .argv;
66 |
--------------------------------------------------------------------------------
/src/node/context.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * OMFrontend.js
3 | * Copyright (C) 2022 Perpetual Labs, Ltd.
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU Affero General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU Affero General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Affero General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | /**
20 | * @author Mohamad Omar Nachawati
21 | */
22 |
23 | import Parser from "tree-sitter";
24 |
25 | // @ts-ignore
26 | import Modelica from "tree-sitter-modelica";
27 |
28 | import { ModelicaContext } from "../common/context.js";
29 | import { ModelicaLibrary } from "../common/library.js";
30 | import { InputReader, Tree } from "../common/parser.js";
31 | import { ModelicaNodeFileSystemLibrary } from "./library.js";
32 |
33 |
34 | export class ModelicaNodeContext extends ModelicaContext {
35 |
36 | static #parser: Parser;
37 |
38 | constructor(workspace?: ModelicaLibrary, libraries?: ModelicaLibrary[]) {
39 |
40 | super(workspace, libraries);
41 |
42 | ModelicaNodeContext.initialize();
43 |
44 | if (ModelicaNodeContext.#parser == null)
45 | throw new Error("ModelicaNodeContext is not initialized.");
46 |
47 | }
48 |
49 | addLibrary(rootPath: string): ModelicaLibrary {
50 | let library = new ModelicaNodeFileSystemLibrary(this, rootPath);
51 | this.libraries.push(library);
52 | return library;
53 | }
54 |
55 | static initialize(): void {
56 |
57 | if (ModelicaNodeContext.#parser != null)
58 | return;
59 |
60 | let parser = new Parser();
61 | parser.setLanguage(Modelica);
62 | ModelicaNodeContext.#parser = parser;
63 |
64 | }
65 |
66 | override parse(input: string | InputReader, previousTree?: Tree): Tree {
67 | return ModelicaNodeContext.#parser.parse(input, previousTree as Parser.Tree | undefined);
68 | }
69 |
70 | }
71 |
--------------------------------------------------------------------------------
/src/browser/context.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * OMFrontend.js
3 | * Copyright (C) 2022 Perpetual Labs, Ltd.
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU Affero General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU Affero General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Affero General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | /**
20 | * @author Mohamad Omar Nachawati
21 | */
22 |
23 | import * as Parser from 'web-tree-sitter';
24 |
25 | import { ModelicaContext } from "../common/context";
26 | import { ModelicaLibrary } from "../common/library";
27 | import { InputReader, Tree } from "../common/parser";
28 | import { ModelicaBrowserFileSystemLibrary } from "./library";
29 |
30 | export class ModelicaBrowserContext extends ModelicaContext {
31 |
32 | static #parser: Parser;
33 |
34 | constructor(workspace?: ModelicaLibrary, libraries?: ModelicaLibrary[]) {
35 |
36 | super(workspace, libraries);
37 |
38 | if (ModelicaBrowserContext.#parser == null)
39 | throw new Error("ModelicaBrowserContext is not initialized.");
40 |
41 | }
42 |
43 | addLibrary(rootPath: string): ModelicaLibrary {
44 | let library = new ModelicaBrowserFileSystemLibrary(this, rootPath);
45 | this.libraries.push(library);
46 | return library;
47 | }
48 |
49 | static async initialize(parser?: Parser): Promise {
50 |
51 | if (ModelicaBrowserContext.#parser != null)
52 | return;
53 |
54 | if (parser != null) {
55 | ModelicaBrowserContext.#parser = parser;
56 | return;
57 | }
58 |
59 | await Parser.default.init();
60 | parser = new Parser.default();
61 | parser.setLanguage(await Parser.Language.load("tree-sitter-modelica.wasm"));
62 |
63 | ModelicaBrowserContext.#parser = parser;
64 |
65 | }
66 |
67 | override parse(input: string | InputReader, previousTree?: Tree): Tree {
68 | return ModelicaBrowserContext.#parser.parse(input, previousTree);
69 | }
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/src/node/library.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * OMFrontend.js
3 | * Copyright (C) 2022 Perpetual Labs, Ltd.
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU Affero General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU Affero General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Affero General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | /**
20 | * @author Mohamad Omar Nachawati
21 | */
22 |
23 | import { ModelicaContext } from "../common/context.js";
24 | import { ModelicaLibrary } from "../common/library.js";
25 | import fs from "fs";
26 | import path from "path";
27 |
28 | export class ModelicaNodeFileSystemLibrary extends ModelicaLibrary {
29 |
30 | #rootPath: string;
31 |
32 | constructor(context: ModelicaContext, rootPath: string) {
33 | super(context);
34 | this.#rootPath = path.resolve(rootPath);
35 | }
36 |
37 | override async *list(...filePath: string[]): AsyncIterableIterator {
38 |
39 | try {
40 |
41 | for (let fileName of await fs.promises.readdir(path.join(this.#rootPath, ...filePath))) {
42 |
43 | try {
44 |
45 | let absoluteFilePath = path.join(this.#rootPath, ...filePath, fileName);
46 |
47 | if (absoluteFilePath.endsWith("/package.mo"))
48 | continue;
49 |
50 | let stats = await fs.promises.stat(absoluteFilePath);
51 |
52 | if (stats.isDirectory() == true)
53 | yield fileName;
54 |
55 | else if (stats.isFile() && fileName.endsWith(".mo"))
56 | yield fileName;
57 |
58 | } catch (e) {
59 | }
60 |
61 | }
62 |
63 | } catch (e) {
64 | }
65 |
66 | }
67 |
68 | override async read(...filePath: string[]): Promise {
69 |
70 | try {
71 |
72 | let absoluteFilePath = path.join(this.#rootPath, ...filePath);
73 | return await fs.promises.readFile(absoluteFilePath, "utf-8");
74 |
75 | } catch (e) {
76 | return null;
77 | }
78 |
79 | }
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | /*
2 | * OMFrontend.js
3 | * Copyright (C) 2022 Perpetual Labs, Ltd.
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU Affero General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU Affero General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Affero General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | import CopyPlugin from "copy-webpack-plugin";
20 | import ResolveTypeScriptPlugin from "resolve-typescript-plugin";
21 | import { dirname, join, resolve } from "path";
22 | import { fileURLToPath } from "url";
23 |
24 | const __filename = fileURLToPath(import.meta.url);
25 | const __dirname = dirname(__filename);
26 |
27 | export default (env, argv) => {
28 | return {
29 | mode: "development",
30 | entry: {
31 | OMFrontend: "./src/browser/index.ts",
32 | "editor.worker": "monaco-editor-core/esm/vs/editor/editor.worker.js",
33 | "json.worker": "monaco-editor/esm/vs/language/json/json.worker"
34 | },
35 | target: "web",
36 | output: {
37 | filename: "[name].js",
38 | globalObject: "self",
39 | path: resolve(__dirname, "./dist")
40 | },
41 | module: {
42 | rules: [
43 | {
44 | test: /\.tsx?$/,
45 | use: "ts-loader",
46 | exclude: /node_modules/,
47 | }
48 | ]
49 | },
50 | resolve: {
51 | extensions: [".js", ".ts"],
52 | fallback: {
53 | assert: false,
54 | child_process: false,
55 | fs: false,
56 | http: false,
57 | https: false,
58 | net: false,
59 | os: false,
60 | path: false,
61 | process: false,
62 | stream: false,
63 | tls: false,
64 | url: false,
65 | util: false,
66 | zlib: false
67 | },
68 | modules: [
69 | join(__dirname, "./node_modules"),
70 | ],
71 | plugins: [
72 | new ResolveTypeScriptPlugin()
73 | ]
74 | },
75 | plugins: [
76 | new CopyPlugin({
77 | patterns: [
78 | { from: "./node_modules/web-tree-sitter/tree-sitter.wasm", to: "./" },
79 | { from: "./node_modules/tree-sitter-modelica/tree-sitter-modelica.wasm", to: "./" },
80 | ],
81 | })
82 | ],
83 | performance: {
84 | hints: false,
85 | maxEntrypointSize: 512000,
86 | maxAssetSize: 512000
87 | }
88 | }
89 | };
90 |
--------------------------------------------------------------------------------
/src/common/dom.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * OMFrontend.js
3 | * Copyright (C) 2022 Perpetual Labs, Ltd.
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU Affero General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU Affero General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Affero General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | /**
20 | * @author Mohamad Omar Nachawati
21 | */
22 |
23 | import { BufferedPrintWriter, PrintWriter } from './writer.js';
24 |
25 | export abstract class XmlNode {
26 |
27 | #parent?: XmlElement;
28 |
29 | constructor(parent?: XmlElement) {
30 | this.#parent = parent;
31 | }
32 |
33 | get parent(): XmlElement | undefined {
34 | return this.#parent;
35 | }
36 |
37 | abstract serialize(printWriter: PrintWriter): void;
38 |
39 | }
40 |
41 | export class XmlElement extends XmlNode {
42 |
43 | #attributes: Map = new Map();
44 | #children: XmlNode[] = [];
45 | #styles: Map = new Map();
46 | #type: string;
47 |
48 | constructor(type: string, parent?: XmlElement) {
49 | super(parent);
50 | this.#type = type;
51 | }
52 |
53 | append(type: string): XmlElement {
54 | let element = new XmlElement(type, this);
55 | this.#children.push(element);
56 | return element;
57 | }
58 |
59 | appendText(value: any): XmlText {
60 | let text = new XmlText(String(value), this);
61 | this.#children.push(text);
62 | return text;
63 | }
64 |
65 | attr(name: string): string | undefined
66 | attr(name: string, value: any): XmlElement
67 | attr(name: string, value?: any): XmlElement | string | undefined {
68 | if (value == null)
69 | return this.#attributes.get(name);
70 | this.#attributes.set(name, value);
71 | return this;
72 | }
73 |
74 | get attributes(): Map {
75 | return this.#attributes;
76 | }
77 |
78 | get children(): XmlNode[] {
79 | return this.#children;
80 | }
81 |
82 | override serialize(printWriter: PrintWriter): void {
83 | printWriter.print("<" + this.#type);
84 | for (let attribute of this.#attributes.entries())
85 | printWriter.print(` ${attribute[0]}="${attribute[1]}"`);
86 | if (this.#styles.size > 0) {
87 | printWriter.print(` style="`);
88 | for (let style of this.#styles.entries())
89 | printWriter.print(` ${style[0]}:${style[1]};`);
90 | printWriter.print(`"`);
91 | }
92 | printWriter.print(">");
93 | for (let child of this.#children)
94 | child.serialize(printWriter);
95 | printWriter.print("" + this.#type + ">");
96 | }
97 |
98 | style(name: string): string | undefined
99 | style(name: string, value: any): XmlElement
100 | style(name: string, value?: string): XmlElement | string | undefined {
101 | if (value == null)
102 | return this.#styles.get(name);
103 | this.#styles.set(name, value);
104 | return this;
105 | }
106 |
107 | get styles(): Map {
108 | return this.#styles;
109 | }
110 |
111 | override toString(): string {
112 | let printWriter = new BufferedPrintWriter();
113 | this.serialize(printWriter);
114 | return printWriter.toString();
115 | }
116 |
117 | }
118 |
119 | export class XmlText extends XmlNode {
120 |
121 | #value: string;
122 |
123 | constructor(value: string, parent?: XmlElement) {
124 | super(parent);
125 | this.#value = value;
126 | }
127 |
128 | override serialize(printWriter: PrintWriter): void {
129 | printWriter.print(this.#value);
130 | }
131 |
132 | get value(): string {
133 | return this.#value;
134 | }
135 |
136 | set value(value: string) {
137 | this.#value = value;
138 | }
139 |
140 | }
141 |
--------------------------------------------------------------------------------
/src/common/parser.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * OMFrontend.js
3 | * Copyright (C) 2022 Perpetual Labs, Ltd.
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU Affero General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU Affero General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Affero General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | /**
20 | * @author Mohamad Omar Nachawati
21 | */
22 |
23 | export type Edit = {
24 | startIndex: number;
25 | oldEndIndex: number;
26 | newEndIndex: number;
27 | startPosition: Point;
28 | oldEndPosition: Point;
29 | newEndPosition: Point;
30 | };
31 |
32 | export type InputReader = (index: any, position?: Point) => string;
33 |
34 | export interface Parser {
35 | parse(input: string | InputReader, previousTree?: Tree): Tree;
36 | }
37 |
38 | export type Point = {
39 | row: number;
40 | column: number;
41 | };
42 |
43 | export type Range = {
44 | startPosition: Point;
45 | endPosition: Point;
46 | startIndex: number;
47 | endIndex: number;
48 | };
49 |
50 | export interface SyntaxNode {
51 |
52 | childCount: number;
53 | children: Array;
54 | endIndex: number;
55 | endPosition: Point;
56 | firstChild: SyntaxNode | null;
57 | firstNamedChild: SyntaxNode | null;
58 | lastChild: SyntaxNode | null;
59 | lastNamedChild: SyntaxNode | null;
60 | namedChildCount: number;
61 | namedChildren: Array;
62 | nextNamedSibling: SyntaxNode | null;
63 | nextSibling: SyntaxNode | null;
64 | parent: SyntaxNode | null;
65 | previousNamedSibling: SyntaxNode | null;
66 | previousSibling: SyntaxNode | null;
67 | startIndex: number;
68 | startPosition: Point;
69 | text: string;
70 | tree: Tree;
71 | type: string;
72 | hasChanges: boolean;
73 | hasError: boolean;
74 | isMissing: boolean;
75 |
76 | toString(): string;
77 | walk(): TreeCursor;
78 |
79 | }
80 |
81 | export interface Tree {
82 |
83 | readonly rootNode: SyntaxNode;
84 |
85 | edit(delta: Edit): Tree;
86 | getChangedRanges(other: Tree): Range[];
87 | getEditedRange(other: Tree): Range;
88 |
89 | }
90 |
91 | export interface TreeCursor {
92 |
93 | nodeType: string;
94 | nodeText: string;
95 | nodeIsNamed: boolean;
96 | startPosition: Point;
97 | endPosition: Point;
98 | startIndex: number;
99 | endIndex: number;
100 |
101 | reset(node: SyntaxNode): void
102 | gotoParent(): boolean;
103 | gotoFirstChild(): boolean;
104 | gotoFirstChildForIndex(index: number): boolean;
105 | gotoNextSibling(): boolean;
106 |
107 | }
108 |
109 | export function currentFieldName(cursor: TreeCursor): string {
110 |
111 | let currentFieldName = (cursor).currentFieldName;
112 |
113 | if (typeof currentFieldName === "function")
114 | return currentFieldName.bind(cursor)();
115 |
116 | else
117 | return currentFieldName;
118 |
119 | }
120 |
121 | export function currentNode(cursor: TreeCursor): SyntaxNode {
122 |
123 | let currentNode = (cursor).currentNode;
124 |
125 | if (typeof currentNode === "function")
126 | return currentNode.bind(cursor)();
127 |
128 | else
129 | return currentNode;
130 |
131 | }
132 |
133 |
134 | export function childForFieldName(syntaxNode: SyntaxNode | null | undefined, ...fieldNames: string[]): SyntaxNode | undefined {
135 |
136 | if (syntaxNode == null)
137 | return;
138 |
139 | for (let child of childrenForFieldName(syntaxNode, ...fieldNames))
140 | return child;
141 |
142 | }
143 |
144 | export function* childrenForFieldName(syntaxNode: SyntaxNode | null | undefined, ...fieldNames: string[]): IterableIterator {
145 |
146 | let cursor = syntaxNode?.walk();
147 |
148 | if (cursor == null || !cursor.gotoFirstChild())
149 | return;
150 |
151 | do {
152 |
153 | if (!fieldNames.includes(currentFieldName(cursor)))
154 | continue;
155 |
156 | yield currentNode(cursor);
157 |
158 | } while (cursor.gotoNextSibling());
159 |
160 | }
161 |
--------------------------------------------------------------------------------
/src/common/document.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * OMFrontend.js
3 | * Copyright (C) 2022 Perpetual Labs, Ltd.
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU Affero General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU Affero General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Affero General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | /**
20 | * @author Mohamad Omar Nachawati
21 | */
22 |
23 | import { Position, Range, TextDocument, TextDocumentContentChangeEvent, TextEdit } from "vscode-languageserver-textdocument";
24 |
25 | import { ModelicaContext } from "./context.js";
26 | import { Point, SyntaxNode, Tree } from "./parser.js";
27 | import { ModelicaScope } from "./scope.js";
28 | import { ModelicaClassSymbol, ModelicaNamedElementSymbol } from "./symbols.js";
29 | import { ModelicaComponentReferenceExpressionSyntax, ModelicaIdentifierSyntax, ModelicaNameSyntax, ModelicaStoredDefinitionSyntax, ModelicaTypeSpecifierSyntax } from "./syntax.js";
30 |
31 | export class ModelicaDocument implements ModelicaScope, TextDocument {
32 |
33 | #context: ModelicaContext;
34 | #document: TextDocument;
35 | #tree: Tree;
36 | #symbols: ModelicaClassSymbol[];
37 | #syntax: ModelicaStoredDefinitionSyntax;
38 |
39 | constructor(context: ModelicaContext, uri: string, version: number, content: string) {
40 | this.#context = context;
41 | this.#document = TextDocument.create(uri, "modelica", version, content);
42 | this.#tree = this.#context.parse(content);
43 | this.#syntax = new ModelicaStoredDefinitionSyntax(this.#tree.rootNode);
44 | this.#symbols = [];
45 | }
46 |
47 | private asPoint(position: Position): Point {
48 | return {
49 | column: position.character,
50 | row: position.line
51 | };
52 | }
53 |
54 | get context(): ModelicaContext {
55 | return this.#context;
56 | }
57 |
58 | getText(range?: Range): string {
59 | return this.#document.getText(range);
60 | }
61 |
62 | get languageId(): string {
63 | return this.#document.languageId;
64 | }
65 |
66 | get lineCount(): number {
67 | return this.#document.lineCount;
68 | }
69 |
70 | offsetAt(position: Position): number {
71 | return this.#document.offsetAt(position);
72 | }
73 |
74 | positionAt(offset: number): Position {
75 | return this.#document.positionAt(offset);
76 | }
77 |
78 | async resolve(reference: ModelicaIdentifierSyntax | ModelicaNameSyntax | ModelicaTypeSpecifierSyntax | string[] | string | null | undefined, global?: boolean): Promise {
79 | throw new Error("Method not implemented.");
80 | }
81 |
82 | async resolveFunction(reference: ModelicaComponentReferenceExpressionSyntax | ModelicaIdentifierSyntax | ModelicaNameSyntax | ModelicaTypeSpecifierSyntax | string[] | string | null | undefined, global?: boolean): Promise {
83 | return null;
84 | }
85 |
86 | get syntax(): ModelicaStoredDefinitionSyntax {
87 | return this.#syntax;
88 | }
89 |
90 | * syntaxErrors(node?: SyntaxNode): IterableIterator {
91 |
92 | if (node == null)
93 | node = this.tree.rootNode;
94 |
95 | if (!node.hasError)
96 | return;
97 |
98 | if (node.type === "ERROR" || node.isMissing)
99 | yield node;
100 |
101 | for (let child of node.children)
102 | yield* this.syntaxErrors(child);
103 |
104 | }
105 |
106 | get tree(): Tree {
107 | return this.#tree;
108 | }
109 |
110 | update(text: string, range?: Range): void {
111 |
112 | if (range == null) {
113 |
114 | TextDocument.update(this.#document, [{ text: text }], this.#document.version + 1);
115 | this.#tree = this.#context.parse(this.#document.getText());
116 |
117 | } else {
118 |
119 | let startIndex = this.offsetAt(range.start);
120 | let oldEndIndex = this.offsetAt(range.end);
121 | let startPosition = this.asPoint(this.positionAt(startIndex));
122 | let oldEndPosition = this.asPoint(this.positionAt(oldEndIndex));
123 | let newEndIndex = startIndex + text.length;
124 |
125 | TextDocument.update(this.#document, [{ range: range, text: text }], this.#document.version + 1);
126 | let newEndPosition = this.asPoint(this.positionAt(newEndIndex));
127 |
128 | this.#tree.edit({
129 | newEndIndex: newEndIndex,
130 | newEndPosition: newEndPosition,
131 | oldEndIndex: oldEndIndex,
132 | oldEndPosition: oldEndPosition,
133 | startIndex: startIndex,
134 | startPosition: startPosition
135 | });
136 |
137 | this.#tree = this.#context.parse((index: number, position?: Point) => {
138 |
139 | if (position != null) {
140 | return this.getText({
141 | end: {
142 | character: position.column + 1,
143 | line: position.row,
144 | },
145 | start: {
146 | character: position.column,
147 | line: position.row,
148 | }
149 | });
150 | }
151 |
152 | return this.getText({
153 | end: this.positionAt(index + 1),
154 | start: this.positionAt(index)
155 | });
156 |
157 | }, this.#tree);
158 |
159 | }
160 |
161 | this.#syntax = new ModelicaStoredDefinitionSyntax(this.#tree.rootNode);
162 |
163 | }
164 |
165 | get uri(): string {
166 | return this.#document.uri;
167 | }
168 |
169 | get version(): number {
170 | return this.#document.version;
171 | }
172 |
173 | }
174 |
--------------------------------------------------------------------------------
/src/common/library.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * OMFrontend.js
3 | * Copyright (C) 2022 Perpetual Labs, Ltd.
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU Affero General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU Affero General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Affero General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | /**
20 | * @author Mohamad Omar Nachawati
21 | */
22 |
23 | import * as JSZip from "jszip";
24 |
25 | import { ModelicaContext } from "./context.js";
26 | import { ModelicaScope } from "./scope.js";
27 | import { ModelicaClassSymbol, ModelicaNamedElementSymbol } from "./symbols.js";
28 | import { ModelicaComponentReferenceExpressionSyntax, ModelicaIdentifierSyntax, ModelicaNameSyntax, ModelicaStoredDefinitionSyntax, ModelicaTypeSpecifierSyntax } from "./syntax.js";
29 | import { getIdentifiers } from "./util.js";
30 |
31 | export abstract class ModelicaLibrary implements ModelicaScope {
32 |
33 | #context: ModelicaContext;
34 | #symbols: Map = new Map();
35 |
36 | constructor(context: ModelicaContext) {
37 | this.#context = context;
38 | }
39 |
40 | get context(): ModelicaContext {
41 | return this.#context;
42 | }
43 |
44 | abstract list(...filePath: string[]): AsyncIterableIterator;
45 |
46 | async load(...filePath: string[]): Promise {
47 |
48 | // TODO: implement caching...
49 |
50 | if (filePath == null || filePath.length == 0)
51 | return null;
52 |
53 | let text = null;
54 | let fileName = filePath[filePath.length - 1];
55 |
56 | if (fileName.endsWith(".mo"))
57 | text = await this.read(...filePath);
58 |
59 | else
60 | text = await this.read(...filePath, "package.mo");
61 |
62 | if (text == null)
63 | return null;
64 |
65 | let tree = this.#context.parse(text);
66 |
67 | if (fileName.endsWith(".mo"))
68 | return ModelicaStoredDefinitionSyntax.new(tree.rootNode) ?? null;
69 |
70 | return ModelicaStoredDefinitionSyntax.new(tree.rootNode, this, filePath) ?? null;
71 |
72 | }
73 |
74 | async resolve(reference: ModelicaIdentifierSyntax | ModelicaNameSyntax | ModelicaTypeSpecifierSyntax | string[] | string | null | undefined, global?: boolean): Promise {
75 |
76 | // TODO: structured entity should not have more than one class definition
77 |
78 | let identifiers = getIdentifiers(reference);
79 | let identifier = identifiers[0];
80 |
81 | if (identifier == null)
82 | return null;
83 |
84 | let classSymbols = null;
85 |
86 | if (this.#symbols.get(identifier) !== undefined) {
87 |
88 | classSymbols = this.#symbols.get(identifier);
89 |
90 | } else {
91 |
92 | let text = await this.read(identifier + ".mo");
93 |
94 | if (text != null) {
95 |
96 | let tree = this.#context.parse(text);
97 | let node = ModelicaStoredDefinitionSyntax.new(tree.rootNode);
98 | classSymbols = await node?.instantiate(this.#context);
99 |
100 | } else {
101 |
102 | text = await this.read(identifier, "package.mo");
103 |
104 | if (text != null) {
105 | let tree = this.#context.parse(text);
106 | let node = ModelicaStoredDefinitionSyntax.new(tree.rootNode, this, [identifier]);
107 | classSymbols = await node?.instantiate(this.#context);
108 | }
109 |
110 | }
111 |
112 | this.#symbols.set(identifier, classSymbols ?? null);
113 |
114 | }
115 |
116 | if (classSymbols != null) {
117 |
118 | identifiers = identifiers.slice(1);
119 |
120 | if (identifiers.length > 0)
121 | return classSymbols[0]?.resolve(identifiers) ?? null;
122 |
123 | return classSymbols[0] ?? null;
124 |
125 | }
126 |
127 | return null;
128 |
129 | }
130 |
131 | async resolveFunction(reference: ModelicaComponentReferenceExpressionSyntax | ModelicaIdentifierSyntax | ModelicaNameSyntax | ModelicaTypeSpecifierSyntax | string[] | string | null | undefined, global?: boolean): Promise {
132 | return null;
133 | }
134 |
135 | abstract read(...filePath: string[]): Promise;
136 |
137 | }
138 |
139 | export abstract class ModelicaFileSystemLibrary extends ModelicaLibrary {
140 |
141 | constructor(context: ModelicaContext) {
142 | super(context);
143 | }
144 |
145 | }
146 |
147 | export class ModelicaWebLibrary extends ModelicaLibrary {
148 |
149 | constructor(context: ModelicaContext) {
150 | super(context);
151 | }
152 |
153 | override list(...filePath: string[]): AsyncIterableIterator {
154 | throw new Error("Method not implemented.");
155 | }
156 |
157 | override read(...filePath: string[]): Promise {
158 | throw new Error("Method not implemented.");
159 | }
160 |
161 | }
162 |
163 | export class ModelicaZipLibrary extends ModelicaLibrary {
164 |
165 | #rootPath?: string;
166 | #zip: JSZip;
167 |
168 | constructor(context: ModelicaContext, zip: JSZip, rootPath?: string | string[]) {
169 | super(context);
170 | this.#zip = zip;
171 | this.#rootPath = Array.isArray(rootPath) ? rootPath.join("/") : rootPath;
172 | }
173 |
174 | override async *list(...filePath: string[]): AsyncIterableIterator {
175 |
176 | if (filePath.length > 0) {
177 |
178 | let firstName = filePath[0];
179 |
180 | for await (let name of this.list()) {
181 |
182 | if (name == firstName || name.startsWith(firstName + " ")) {
183 | filePath[0] = name;
184 | break;
185 | }
186 |
187 | }
188 |
189 | }
190 |
191 | let name = null;
192 |
193 | if (this.#rootPath == null)
194 | name = filePath.join("/");
195 |
196 | else
197 | name = this.#rootPath + "/" + filePath.join("/");
198 |
199 | let list: string[] = [];
200 |
201 | this.#zip.folder(name)?.forEach((relativePath: string, file: JSZip.JSZipObject) => {
202 |
203 | if (file.name.endsWith("/package.mo"))
204 | return;
205 |
206 | let relativePathParts = relativePath.split("/");
207 |
208 | if (file.dir == true && relativePathParts.length == 2)
209 | list.push(relativePathParts[0]);
210 |
211 | else if (file.name.endsWith(".mo") && relativePathParts.length == 1)
212 | list.push(relativePathParts[0]);
213 |
214 | });
215 |
216 | yield* list;
217 |
218 | }
219 |
220 | override async read(...filePath: string[]): Promise {
221 |
222 | if (filePath.length == 0)
223 | return null;
224 |
225 | let firstName = filePath[0];
226 |
227 | for await (let name of this.list()) {
228 |
229 | if (name == firstName || name.startsWith(firstName + " ")) {
230 | filePath[0] = name;
231 | break;
232 | }
233 |
234 | }
235 |
236 | let name = null;
237 |
238 | if (this.#rootPath == null)
239 | name = filePath.join("/");
240 |
241 | else
242 | name = this.#rootPath + "/" + filePath.join("/");
243 |
244 | //console.log("READ ZIP FILE: " + name);
245 |
246 | return this.#zip.file(name)?.async("string") ?? null;
247 |
248 | }
249 |
250 | }
251 |
--------------------------------------------------------------------------------
/src/common/context.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * OMFrontend.js
3 | * Copyright (C) 2022 Perpetual Labs, Ltd.
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU Affero General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU Affero General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Affero General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | /**
20 | * @author Mohamad Omar Nachawati
21 | */
22 |
23 | import * as JSZip from "jszip";
24 |
25 | import { ModelicaDocument } from "./document.js";
26 | import { ModelicaLibrary, ModelicaZipLibrary } from "./library.js";
27 | import { InputReader, Tree } from "./parser.js";
28 | import { MODELICA_PREDEFINED } from "./predefined.js";
29 | import { ModelicaScope } from "./scope.js";
30 | import { ModelicaArrayClassSymbol, ModelicaBooleanClassSymbol, ModelicaClassSymbol, ModelicaIntegerClassSymbol, ModelicaNamedElementSymbol, ModelicaNumberObjectSymbol, ModelicaRealClassSymbol, ModelicaStringClassSymbol } from "./symbols.js";
31 | import { ModelicaComponentReferenceExpressionSyntax, ModelicaIdentifierSyntax, ModelicaNameSyntax, ModelicaStoredDefinitionSyntax, ModelicaTypeSpecifierSyntax } from "./syntax.js";
32 |
33 | export abstract class ModelicaContext implements ModelicaScope {
34 |
35 | static #annotations?: ModelicaClassSymbol;
36 | #builtins: Map = new Map();
37 | #documents: Map = new Map();
38 | #libraries: ModelicaLibrary[];
39 | #workspace?: ModelicaLibrary;
40 |
41 | constructor(workspace?: ModelicaLibrary, libraries?: ModelicaLibrary[]) {
42 | this.#workspace = workspace;
43 | this.#libraries = libraries ?? [];
44 | this.#builtins = new Map();
45 | this.#builtins.set("Boolean", new ModelicaBooleanClassSymbol(this));
46 | this.#builtins.set("Integer", new ModelicaIntegerClassSymbol(this));
47 | this.#builtins.set("Real", new ModelicaRealClassSymbol(this));
48 | this.#builtins.set("String", new ModelicaStringClassSymbol(this));
49 | }
50 |
51 | abstract addLibrary(path: string): ModelicaLibrary;
52 |
53 | addZipLibrary(zip: JSZip, rootPath?: string | string[]): ModelicaZipLibrary {
54 | let library = new ModelicaZipLibrary(this, zip, rootPath);
55 | this.libraries.push(library);
56 | return library;
57 | }
58 |
59 | get annotations(): Promise {
60 |
61 | let context = this;
62 |
63 | return async function () {
64 |
65 | if (ModelicaContext.#annotations != null)
66 | return ModelicaContext.#annotations;
67 |
68 | let tree = context.parse(MODELICA_PREDEFINED);
69 |
70 | let node = ModelicaStoredDefinitionSyntax.new(tree.rootNode);
71 |
72 | ModelicaContext.#annotations = (await node?.instantiate(context))?.[0] ?? new ModelicaClassSymbol(context);
73 |
74 | return ModelicaContext.#annotations;
75 |
76 | }();
77 |
78 | }
79 |
80 | get builtins(): Map {
81 | return this.#builtins;
82 | }
83 |
84 | get roots(): AsyncIterableIterator {
85 |
86 | let context = this;
87 |
88 | return async function* () {
89 |
90 | for (let library of context.libraries) {
91 |
92 | let root = await library.resolve("Modelica");
93 |
94 | if (root instanceof ModelicaClassSymbol)
95 | yield root;
96 |
97 | root = await library.resolve("PL_Lib");
98 |
99 | if (root instanceof ModelicaClassSymbol)
100 | yield root;
101 |
102 | root = await library.resolve("ThermoPower");
103 |
104 | if (root instanceof ModelicaClassSymbol)
105 | yield root;
106 |
107 | root = await library.resolve("FirstBookExamples");
108 |
109 | if (root instanceof ModelicaClassSymbol)
110 | yield root;
111 |
112 | }
113 |
114 | }();
115 |
116 | }
117 |
118 | get context(): ModelicaContext {
119 | return this;
120 | }
121 |
122 | get documents(): Map {
123 | return this.#documents;
124 | }
125 |
126 | get libraries(): ModelicaLibrary[] {
127 | return this.#libraries;
128 | }
129 |
130 | async resolve(reference: ModelicaIdentifierSyntax | ModelicaNameSyntax | ModelicaTypeSpecifierSyntax | string[] | string | null | undefined, global?: boolean): Promise {
131 |
132 | if (reference == null)
133 | return null;
134 |
135 | for (let document of this.documents.values()) {
136 |
137 | let symbol = await document.resolve(reference, global);
138 |
139 | if (symbol != null)
140 | return symbol;
141 |
142 | }
143 |
144 | let symbol = await this.workspace?.resolve(reference, global);
145 |
146 | if (symbol != null)
147 | return symbol;
148 |
149 | for (let library of this.libraries) {
150 |
151 | let symbol = await library.resolve(reference, global);
152 |
153 | if (symbol != null)
154 | return symbol;
155 |
156 | }
157 |
158 | let name: string | null | undefined = null;
159 |
160 | if (reference instanceof ModelicaIdentifierSyntax)
161 | name = reference.toString();
162 |
163 | else if (reference instanceof ModelicaNameSyntax)
164 | name = reference.toString();
165 |
166 | else if (reference instanceof ModelicaTypeSpecifierSyntax)
167 | name = reference.name?.toString();
168 |
169 | else if (Array.isArray(reference))
170 | name = reference.join(".");
171 |
172 | else
173 | name = reference;
174 |
175 | if (name != null) {
176 |
177 | symbol = (await (await this.annotations).getNamedElement(name)) ?? this.builtins.get(name) ?? null;
178 |
179 | if (reference instanceof ModelicaTypeSpecifierSyntax && reference.subscripts != null && reference.subscripts.length > 0) {
180 |
181 | if (symbol instanceof ModelicaClassSymbol) {
182 |
183 | let shape = [];
184 |
185 | for (let subscript of reference.subscripts) {
186 |
187 | let value = await subscript.expression?.evaluate(this);
188 |
189 | if (value instanceof ModelicaNumberObjectSymbol)
190 | shape.push(value.value);
191 |
192 | else
193 | shape.push(undefined);
194 |
195 | }
196 |
197 | return new ModelicaArrayClassSymbol(symbol.parent, undefined, undefined, symbol, shape);
198 |
199 | }
200 |
201 | return null;
202 |
203 | }
204 |
205 | return symbol;
206 |
207 | }
208 |
209 | return null;
210 |
211 | }
212 |
213 | async resolveFunction(reference: ModelicaComponentReferenceExpressionSyntax | ModelicaIdentifierSyntax | ModelicaNameSyntax | ModelicaTypeSpecifierSyntax | string[] | string | null | undefined, global?: boolean): Promise {
214 |
215 | if (reference == null)
216 | return null;
217 |
218 | for (let document of this.documents.values()) {
219 |
220 | let symbol = await document.resolveFunction(reference, global);
221 |
222 | if (symbol != null)
223 | return symbol;
224 |
225 | }
226 |
227 | let symbol = await this.workspace?.resolveFunction(reference, global);
228 |
229 | if (symbol != null)
230 | return symbol;
231 |
232 | for (let library of this.libraries) {
233 |
234 | let symbol = await library.resolveFunction(reference, global);
235 |
236 | if (symbol != null)
237 | return symbol;
238 |
239 | }
240 |
241 | return null;
242 |
243 | }
244 |
245 |
246 | abstract parse(input: string | InputReader, previousTree?: Tree): Tree;
247 |
248 | get workspace(): ModelicaLibrary | undefined {
249 | return this.#workspace;
250 | }
251 |
252 | }
253 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Created by https://www.toptal.com/developers/gitignore/api/maven,git,eclipse,visualstudiocode,java,python,c++,node,angular
3 | # Edit at https://www.toptal.com/developers/gitignore?templates=maven,git,eclipse,visualstudiocode,java,python,c++,node,angular
4 |
5 | ### Angular ###
6 | ## Angular ##
7 | # compiled output
8 | dist/
9 | tmp/
10 | app/**/*.js
11 | app/**/*.js.map
12 |
13 | # dependencies
14 | node_modules/
15 | bower_components/
16 |
17 | # IDEs and editors
18 | .idea/
19 |
20 | # misc
21 | .sass-cache/
22 | connect.lock/
23 | coverage/
24 | libpeerconnection.log/
25 | npm-debug.log
26 | testem.log
27 | typings/
28 |
29 | # e2e
30 | e2e/*.js
31 | e2e/*.map
32 |
33 | # System Files
34 | .DS_Store/
35 |
36 | ### C++ ###
37 | # Prerequisites
38 | *.d
39 |
40 | # Compiled Object files
41 | *.slo
42 | *.lo
43 | *.o
44 | *.obj
45 |
46 | # Precompiled Headers
47 | *.gch
48 | *.pch
49 |
50 | # Linker files
51 | *.ilk
52 |
53 | # Debugger Files
54 | *.pdb
55 |
56 | # Compiled Dynamic libraries
57 | *.so
58 | *.dylib
59 | *.dll
60 |
61 | # Fortran module files
62 | *.mod
63 | *.smod
64 |
65 | # Compiled Static libraries
66 | *.lai
67 | *.la
68 | *.a
69 | *.lib
70 |
71 | # Executables
72 | *.exe
73 | *.out
74 | *.app
75 |
76 | ### Eclipse ###
77 | .metadata
78 | bin/
79 | *.tmp
80 | *.bak
81 | *.swp
82 | *~.nib
83 | local.properties
84 | .settings/
85 | .loadpath
86 | .recommenders
87 |
88 | # External tool builders
89 | .externalToolBuilders/
90 |
91 | # Locally stored "Eclipse launch configurations"
92 | *.launch
93 |
94 | # PyDev specific (Python IDE for Eclipse)
95 | *.pydevproject
96 |
97 | # CDT-specific (C/C++ Development Tooling)
98 | .cproject
99 |
100 | # CDT- autotools
101 | .autotools
102 |
103 | # Java annotation processor (APT)
104 | .factorypath
105 |
106 | # PDT-specific (PHP Development Tools)
107 | .buildpath
108 |
109 | # sbteclipse plugin
110 | .target
111 |
112 | # Tern plugin
113 | .tern-project
114 |
115 | # TeXlipse plugin
116 | .texlipse
117 |
118 | # STS (Spring Tool Suite)
119 | .springBeans
120 |
121 | # Code Recommenders
122 | .recommenders/
123 |
124 | # Annotation Processing
125 | .apt_generated/
126 | .apt_generated_test/
127 |
128 | # Scala IDE specific (Scala & Java development for Eclipse)
129 | .cache-main
130 | .scala_dependencies
131 | .worksheet
132 |
133 | # Uncomment this line if you wish to ignore the project description file.
134 | # Typically, this file would be tracked if it contains build/dependency configurations:
135 | #.project
136 |
137 | ### Eclipse Patch ###
138 | # Spring Boot Tooling
139 | .sts4-cache/
140 |
141 | ### Git ###
142 | # Created by git for backups. To disable backups in Git:
143 | # $ git config --global mergetool.keepBackup false
144 | *.orig
145 |
146 | # Created by git when using merge tools for conflicts
147 | *.BACKUP.*
148 | *.BASE.*
149 | *.LOCAL.*
150 | *.REMOTE.*
151 | *_BACKUP_*.txt
152 | *_BASE_*.txt
153 | *_LOCAL_*.txt
154 | *_REMOTE_*.txt
155 |
156 | ### Java ###
157 | # Compiled class file
158 | *.class
159 |
160 | # Log file
161 | *.log
162 |
163 | # BlueJ files
164 | *.ctxt
165 |
166 | # Mobile Tools for Java (J2ME)
167 | .mtj.tmp/
168 |
169 | # Package Files #
170 | *.jar
171 | *.war
172 | *.nar
173 | *.ear
174 | *.zip
175 | *.tar.gz
176 | *.rar
177 |
178 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
179 | hs_err_pid*
180 |
181 | ### Maven ###
182 | target/
183 | pom.xml.tag
184 | pom.xml.releaseBackup
185 | pom.xml.versionsBackup
186 | pom.xml.next
187 | release.properties
188 | dependency-reduced-pom.xml
189 | buildNumber.properties
190 | .mvn/timing.properties
191 | # https://github.com/takari/maven-wrapper#usage-without-binary-jar
192 | .mvn/wrapper/maven-wrapper.jar
193 | .flattened-pom.xml
194 |
195 | ### Node ###
196 | # Logs
197 | logs
198 | npm-debug.log*
199 | yarn-debug.log*
200 | yarn-error.log*
201 | lerna-debug.log*
202 |
203 | # Diagnostic reports (https://nodejs.org/api/report.html)
204 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
205 |
206 | # Runtime data
207 | pids
208 | *.pid
209 | *.seed
210 | *.pid.lock
211 |
212 | # Directory for instrumented libs generated by jscoverage/JSCover
213 | lib-cov
214 |
215 | # Coverage directory used by tools like istanbul
216 | coverage
217 | *.lcov
218 |
219 | # nyc test coverage
220 | .nyc_output
221 |
222 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
223 | .grunt
224 |
225 | # Bower dependency directory (https://bower.io/)
226 | bower_components
227 |
228 | # node-waf configuration
229 | .lock-wscript
230 |
231 | # Compiled binary addons (https://nodejs.org/api/addons.html)
232 | build/Release
233 |
234 | # Dependency directories
235 | jspm_packages/
236 |
237 | # TypeScript v1 declaration files
238 |
239 | # TypeScript cache
240 | *.tsbuildinfo
241 |
242 | # Optional npm cache directory
243 | .npm
244 |
245 | # Optional eslint cache
246 | .eslintcache
247 |
248 | # Optional stylelint cache
249 | .stylelintcache
250 |
251 | # Microbundle cache
252 | .rpt2_cache/
253 | .rts2_cache_cjs/
254 | .rts2_cache_es/
255 | .rts2_cache_umd/
256 |
257 | # Optional REPL history
258 | .node_repl_history
259 |
260 | # Output of 'npm pack'
261 | *.tgz
262 |
263 | # Yarn Integrity file
264 | .yarn-integrity
265 |
266 | # dotenv environment variables file
267 | .env
268 | .env.test
269 | .env*.local
270 |
271 | # parcel-bundler cache (https://parceljs.org/)
272 | .cache
273 | .parcel-cache
274 |
275 | # Next.js build output
276 | .next
277 |
278 | # Nuxt.js build / generate output
279 | .nuxt
280 | dist
281 |
282 | # Storybook build outputs
283 | .out
284 | .storybook-out
285 | storybook-static
286 |
287 | # rollup.js default build output
288 |
289 | # Gatsby files
290 | .cache/
291 | # Comment in the public line in if your project uses Gatsby and not Next.js
292 | # https://nextjs.org/blog/next-9-1#public-directory-support
293 | # public
294 |
295 | # vuepress build output
296 | .vuepress/dist
297 |
298 | # Serverless directories
299 | .serverless/
300 |
301 | # FuseBox cache
302 | .fusebox/
303 |
304 | # DynamoDB Local files
305 | .dynamodb/
306 |
307 | # TernJS port file
308 | .tern-port
309 |
310 | # Stores VSCode versions used for testing VSCode extensions
311 | .vscode-test
312 |
313 | # Temporary folders
314 | temp/
315 |
316 | ### Python ###
317 | # Byte-compiled / optimized / DLL files
318 | __pycache__/
319 | *.py[cod]
320 | *$py.class
321 |
322 | # C extensions
323 |
324 | # Distribution / packaging
325 | .Python
326 | build/
327 | develop-eggs/
328 | downloads/
329 | eggs/
330 | .eggs/
331 | parts/
332 | sdist/
333 | var/
334 | wheels/
335 | pip-wheel-metadata/
336 | share/python-wheels/
337 | *.egg-info/
338 | .installed.cfg
339 | *.egg
340 | MANIFEST
341 |
342 | # PyInstaller
343 | # Usually these files are written by a python script from a template
344 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
345 | *.manifest
346 | *.spec
347 |
348 | # Installer logs
349 | pip-log.txt
350 | pip-delete-this-directory.txt
351 |
352 | # Unit test / coverage reports
353 | htmlcov/
354 | .tox/
355 | .nox/
356 | .coverage
357 | .coverage.*
358 | nosetests.xml
359 | coverage.xml
360 | *.cover
361 | *.py,cover
362 | .hypothesis/
363 | .pytest_cache/
364 | pytestdebug.log
365 |
366 | # Translations
367 | *.mo
368 | *.pot
369 |
370 | # Django stuff:
371 | local_settings.py
372 | db.sqlite3
373 | db.sqlite3-journal
374 |
375 | # Flask stuff:
376 | instance/
377 | .webassets-cache
378 |
379 | # Scrapy stuff:
380 | .scrapy
381 |
382 | # Sphinx documentation
383 | docs/_build/
384 | doc/_build/
385 |
386 | # PyBuilder
387 |
388 | # Jupyter Notebook
389 | .ipynb_checkpoints
390 |
391 | # IPython
392 | profile_default/
393 | ipython_config.py
394 |
395 | # pyenv
396 | .python-version
397 |
398 | # pipenv
399 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
400 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
401 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
402 | # install all needed dependencies.
403 | #Pipfile.lock
404 |
405 | # poetry
406 | #poetry.lock
407 |
408 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
409 | __pypackages__/
410 |
411 | # Celery stuff
412 | celerybeat-schedule
413 | celerybeat.pid
414 |
415 | # SageMath parsed files
416 | *.sage.py
417 |
418 | # Environments
419 | # .env
420 | .env/
421 | .venv/
422 | env/
423 | venv/
424 | ENV/
425 | env.bak/
426 | venv.bak/
427 | pythonenv*
428 |
429 | # Spyder project settings
430 | .spyderproject
431 | .spyproject
432 |
433 | # Rope project settings
434 | .ropeproject
435 |
436 | # mkdocs documentation
437 | /site
438 |
439 | # mypy
440 | .mypy_cache/
441 | .dmypy.json
442 | dmypy.json
443 |
444 | # Pyre type checker
445 | .pyre/
446 |
447 | # pytype static type analyzer
448 | .pytype/
449 |
450 | # operating system-related files
451 | # file properties cache/storage on macOS
452 | *.DS_Store
453 | # thumbnail cache on Windows
454 | Thumbs.db
455 |
456 | # profiling data
457 | .prof
458 |
459 |
460 | ### VisualStudioCode ###
461 | .vscode/*
462 | !.vscode/settings.json
463 | !.vscode/tasks.json
464 | !.vscode/launch.json
465 | !.vscode/extensions.json
466 | *.code-workspace
467 |
468 | ### VisualStudioCode Patch ###
469 | # Ignore all local history of files
470 | .history
471 | .ionide
472 |
473 | # End of https://www.toptal.com/developers/gitignore/api/maven,git,eclipse,visualstudiocode,java,python,c++,node,angular
474 |
475 | *.wasm
--------------------------------------------------------------------------------
/src/common/predefined.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * OMFrontend.js
3 | * Copyright (C) 2022 Perpetual Labs, Ltd.
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU Affero General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU Affero General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Affero General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | /**
20 | * @author Mohamad Omar Nachawati
21 | */
22 |
23 | export const MODELICA_PREDEFINED = `
24 | /*
25 | * Copyright © 1998-2020, Modelica Association (https://www.modelica.org)
26 | *
27 | * All rights reserved. Reproduction or use of editorial or pictorial content is permitted, i.e., this document can
28 | * be freely distributed especially electronically, provided the copyright notice and these conditions are retained.
29 | * No patent liability is assumed with respect to the use of information contained herein. While every precaution
30 | * has been taken in the preparation of this document no responsibility for errors or omissions is assumed.
31 | */
32 |
33 | package ModelicaAnnotations
34 |
35 | type Arrow = enumeration(None, Open, Filled, Half);
36 |
37 | record Authorization
38 | String licensor = "" "Optional string to show information about the licensor";
39 | String libraryKey "Matching the key in the class. Must be encrypted and not visible";
40 | License license[:] "Definition of the license options and of the access rights";
41 | end Authorization;
42 |
43 | record Axis
44 | Real min "Axis lower bound, in ’unit’";
45 | Real max "Axis upper bound, in ’unit’";
46 | String unit = "" "Unit of axis tick labels";
47 | String label "Axis label";
48 | end Axis;
49 |
50 | record Bitmap
51 | extends GraphicItem;
52 | Extent extent;
53 | String fileName "Name of bitmap file";
54 | String imageSource "Base64 representation of bitmap";
55 | end Bitmap;
56 |
57 | constant Color Black = {0, 0, 0};
58 |
59 | type BorderPattern = enumeration(None, Raised, Sunken, Engraved);
60 |
61 | type Color = Integer[3](min = 0, max = 255) "RGB representation";
62 |
63 | record CoordinateSystem
64 | Extent extent;
65 | Boolean preserveAspectRatio = true;
66 | Real initialScale = 0.1;
67 | DrawingUnit grid[2];
68 | end CoordinateSystem;
69 |
70 | record Curve
71 | expression x = time "X coordinate values";
72 | expression y "Y coordinate values";
73 | String legend "Legend";
74 | end Curve;
75 |
76 | record Diagram "Representation of the diagram layer"
77 | CoordinateSystem coordinateSystem(extent = {{-100, -100}, {100, 100}});
78 | GraphicItem[:] graphics;
79 | end Diagram;
80 |
81 | record DiagramMap
82 | Extent extent = {{0, 0}, {0, 0}};
83 | Boolean primitivesVisible = true;
84 | end DiagramMap;
85 |
86 | record Dialog
87 | parameter String tab = "General";
88 | parameter String group = "Parameters";
89 | parameter Boolean enable = true;
90 | parameter Boolean showStartAttribute = false;
91 | parameter Boolean colorSelector = false;
92 | parameter Selector loadSelector;
93 | parameter Selector saveSelector;
94 | parameter String groupImage = "";
95 | parameter Boolean connectorSizing = false;
96 | end Dialog;
97 |
98 | record Documentation
99 | String info = "" "Description of the class";
100 | String revisions = "" "Revision history";
101 | Figure[:] figures = {}; "Simulation result figures";
102 | end Documentation;
103 |
104 | type DrawingUnit = Real(final unit="mm");
105 |
106 | record Ellipse
107 | extends GraphicItem;
108 | extends FilledShape;
109 | Extent extent;
110 | Real startAngle(quantity = "angle", unit = "deg") = 0;
111 | Real endAngle(quantity = "angle", unit = "deg") = 360;
112 | EllipseClosure closure = if startAngle == 0 and endAngle == 360
113 | then EllipseClosure.Chord
114 | else EllipseClosure.Radial;
115 | end Ellipse;
116 |
117 | type EllipseClosure = enumeration(None, Chord, Radial);
118 |
119 | type Extent = Point[2] "Defines a rectangular area {{x1, y1}, {x2, y2}}";
120 |
121 | record Figure
122 | String title = "" "Title meant for display";
123 | String identifier "Identifier meant for programmatic access";
124 | String group = "" "Name of plot group";
125 | Boolean preferred = false "Automatically display figure after simulation";
126 | Plot[:] plots "Plots";
127 | String caption "Figure caption";
128 | end Figure;
129 |
130 | record FilledShape "Style attributes for filled shapes"
131 | Color lineColor = Black "Color of border line";
132 | Color fillColor = Black "Interior fill color";
133 | LinePattern pattern = LinePattern.Solid "Border line pattern";
134 | FillPattern fillPattern = FillPattern.None "Interior fill pattern";
135 | DrawingUnit lineThickness = 0.25 "Line thickness";
136 | end FilledShape;
137 |
138 | type FillPattern = enumeration(None, Solid, Horizontal, Vertical,
139 | Cross, Forward, Backward, CrossDiag,
140 | HorizontalCylinder, VerticalCylinder, Sphere);
141 |
142 | partial record GraphicItem
143 | Boolean visible = true;
144 | Point origin = {0, 0};
145 | Real rotation(quantity="angle", unit="deg")=0;
146 | end GraphicItem;
147 |
148 | record Icon "Representation of the icon layer"
149 | CoordinateSystem coordinateSystem(extent = {{-100, -100}, {100, 100}});
150 | GraphicItem[:] graphics;
151 | end Icon;
152 |
153 | record IconMap
154 | Extent extent = {{0, 0}, {0, 0}};
155 | Boolean primitivesVisible = true;
156 | end IconMap;
157 |
158 | record License
159 | String licensee = "" "Optional string to show information about the licensee";
160 | String id[:] "Unique machine identifications, e.g.\ MAC addresses";
161 | String features[:] = fill("", 0) "Activated library license features";
162 | String startDate = "" "Optional start date in UTCformat YYYY-MM-DD";
163 | String expirationDate = "" "Optional expiration date in UTCformat YYYY-MM-DD";
164 | String operations[:] = fill("", 0) "Library usage conditions";
165 | end License;
166 |
167 | record Line
168 | extends GraphicItem;
169 | Point points[:];
170 | Color color = Black;
171 | LinePattern pattern = LinePattern.Solid;
172 | DrawingUnit thickness = 0.25;
173 | Arrow arrow[2] = {Arrow.None, Arrow.None} "{start arrow, end arrow}";
174 | DrawingUnit arrowSize = 3;
175 | Smooth smooth = Smooth.None "Spline";
176 | end Line;
177 |
178 | type LinePattern = enumeration(None, Solid, Dash, Dot, DashDot, DashDotDot);
179 |
180 | record OnMouseDownEditInteger
181 | Integer variable "Name of variable to change";
182 | end OnMouseDownEditInteger;
183 |
184 | record OnMouseDownEditReal
185 | Real variable "Name of variable to change";
186 | end OnMouseDownEditReal;
187 |
188 | record OnMouseDownEditString
189 | String variable "Name of variable to change";
190 | end OnMouseDownEditString;
191 |
192 | record OnMouseDownSetBoolean
193 | Boolean variable "Name of variable to change when mouse button pressed";
194 | Boolean value "Assigned value";
195 | end OnMouseDownSetBoolean;
196 |
197 | record OnMouseMoveXSetReal
198 | Real xVariable "Name of variable to change when cursor moved in x direction";
199 | Real minValue;
200 | Real maxValue;
201 | end OnMouseMoveXSetReal;
202 |
203 | record OnMouseMoveYSetReal
204 | Real yVariable "Name of variable to change when cursor moved in y direction";
205 | Real minValue;
206 | Real maxValue;
207 | end OnMouseMoveYSetReal;
208 |
209 | record OnMouseUpSetBoolean
210 | Boolean variable "Name of variable to change when mouse button released";
211 | Boolean value "Assigned value";
212 | end OnMouseUpSetBoolean;
213 |
214 | record Placement
215 | Boolean visible = true;
216 | Transformation transformation "Placement in the diagram layer";
217 | Boolean iconVisible "Visible in icon layer; for public connector";
218 | Transformation iconTransformation "Placement in the icon layer; for public connector";
219 | end Placement;
220 |
221 | record Plot
222 | String title "Title meant for display";
223 | String identifier "Identifier meant for programmatic access";
224 | Curve[:] curves "Plot curves";
225 | Axis x "X axis properties";
226 | Axis y "Y axis properties";
227 | end Plot;
228 |
229 | type Point = DrawingUnit[2] "{x, y}";
230 |
231 | record Polygon
232 | extends GraphicItem;
233 | extends FilledShape;
234 | Point points[:];
235 | Smooth smooth = Smooth.None "Spline outline";
236 | end Polygon;
237 |
238 | record Rectangle
239 | extends GraphicItem;
240 | extends FilledShape;
241 | BorderPattern borderPattern = BorderPattern.None;
242 | Extent extent;
243 | DrawingUnit radius = 0 "Corner radius";
244 | end Rectangle;
245 |
246 | record Selector
247 | parameter String filter = "";
248 | parameter String caption = "";
249 | end Selector;
250 |
251 | type Smooth = enumeration(None, Bezier);
252 |
253 | record Text
254 | extends GraphicItem;
255 | extends FilledShape;
256 | Extent extent;
257 | String string;
258 | String textString;
259 | Real fontSize = 0 "unit pt";
260 | String fontName;
261 | TextStyle textStyle[:];
262 | Color textColor = lineColor;
263 | TextAlignment horizontalAlignment = TextAlignment.Center;
264 | Integer index;
265 | end Text;
266 |
267 | type TextAlignment = enumeration(Left, Center, Right);
268 |
269 | type TextStyle = enumeration(Bold, Italic, UnderLine);
270 |
271 | record Transformation
272 | Point origin = {0, 0};
273 | Extent extent;
274 | Real rotation(quantity = "angle", unit = "deg") = 0;
275 | end Transformation;
276 |
277 | end ModelicaAnnotations;
278 | `;
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */
4 |
5 | /* Projects */
6 | // "incremental": true, /* Enable incremental compilation */
7 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
8 | // "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */
9 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */
10 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
11 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
12 |
13 | /* Language and Environment */
14 | "target": "es6", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
15 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
16 | // "jsx": "preserve", /* Specify what JSX code is generated. */
17 | // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
18 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
19 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */
20 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
21 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */
22 | // "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */
23 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
24 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
25 |
26 | /* Modules */
27 | "module": "es6", /* Specify what module code is generated. */
28 | // "rootDir": "./", /* Specify the root folder within your source files. */
29 | "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
30 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
31 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
32 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
33 | // "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */
34 | // "types": [], /* Specify type package names to be included without being referenced in a source file. */
35 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
36 | // "resolveJsonModule": true, /* Enable importing .json files */
37 | // "noResolve": true, /* Disallow `import`s, `require`s or ``s from expanding the number of files TypeScript should add to a project. */
38 |
39 | /* JavaScript Support */
40 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */
41 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
42 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */
43 |
44 | /* Emit */
45 | "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
46 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */
47 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
48 | "sourceMap": true, /* Create source map files for emitted JavaScript files. */
49 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */
50 | "outDir": "./dist", /* Specify an output folder for all emitted files. */
51 | // "removeComments": true, /* Disable emitting comments. */
52 | // "noEmit": true, /* Disable emitting files from a compilation. */
53 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
54 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */
55 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
56 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
57 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
58 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
59 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
60 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
61 | // "newLine": "crlf", /* Set the newline character for emitting files. */
62 | // "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */
63 | // "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */
64 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
65 | // "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */
66 | "declarationDir": "./dist/types", /* Specify the output directory for generated declaration files. */
67 | // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
68 |
69 | /* Interop Constraints */
70 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
71 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
72 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */
73 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
74 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
75 |
76 | /* Type Checking */
77 | "strict": true, /* Enable all strict type-checking options. */
78 | "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */
79 | "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */
80 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
81 | // "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */
82 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
83 | // "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */
84 | // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */
85 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
86 | // "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */
87 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */
88 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
89 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
90 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
91 | // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
92 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
93 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */
94 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
95 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
96 |
97 | /* Completeness */
98 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
99 | "skipLibCheck": true /* Skip type checking all .d.ts files. */
100 | },
101 | "include": [
102 | "src"
103 | ]
104 | }
105 |
--------------------------------------------------------------------------------
/OSMC-License.txt:
--------------------------------------------------------------------------------
1 | --- Start of Definition of OSMC Public License ---
2 |
3 | /*
4 | * This file is part of OpenModelica.
5 | *
6 | * Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC),
7 | * c/o Linköpings universitet, Department of Computer and Information Science,
8 | * SE-58183 Linköping, Sweden.
9 | *
10 | * All rights reserved.
11 | *
12 | * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF AGPL VERSION 3 LICENSE OR
13 | * THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.8.
14 | * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES
15 | * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GNU AGPL
16 | * VERSION 3, ACCORDING TO RECIPIENTS CHOICE.
17 | *
18 | * The OpenModelica software and the OSMC (Open Source Modelica Consortium)
19 | * Public License (OSMC-PL) are obtained from OSMC, either from the above
20 | * address, from the URLs:
21 | * http://www.openmodelica.org or
22 | * https://github.com/OpenModelica/ or
23 | * http://www.ida.liu.se/projects/OpenModelica,
24 | * and in the OpenModelica distribution.
25 | *
26 | * GNU AGPL version 3 is obtained from:
27 | * https://www.gnu.org/licenses/licenses.html#GPL
28 | *
29 | * This program is distributed WITHOUT ANY WARRANTY; without
30 | * even the implied warranty of MERCHANTABILITY or FITNESS
31 | * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH
32 | * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL.
33 | *
34 | * See the full OSMC Public License conditions for more details.
35 | *
36 | */
37 |
38 | --- End of OSMC Public License Header ---
39 |
40 | The OSMC-PL is a public license for OpenModelica with three modes/alternatives
41 | (AGPL, OSMC-Internal-EPL, OSMC-External-EPL) for use and redistribution,
42 | in source and/or binary/object-code form:
43 |
44 | * AGPL. Any party (member or non-member of OSMC) may use and redistribute
45 | OpenModelica under GNU AGPL version 3.
46 |
47 | * Level 1 members of OSMC may also use and redistribute OpenModelica under
48 | OSMC-Internal-EPL conditions.
49 |
50 | * Level 2 members of OSMC may also use and redistribute OpenModelica under
51 | OSMC-Internal-EPL or OSMC-External-EPL conditions.
52 | Definitions of OSMC Public license modes:
53 |
54 | * AGPL = GNU AGPL version 3.
55 |
56 | * OSMC-Internal-EPL = These OSMC Public license conditions together with
57 | Internally restricted EPL, i.e., EPL version 1.0 with the Additional
58 | Condition that use and redistribution by an OSMC member is only allowed
59 | within the OSMC member's own organization (i.e., its own legal entity),
60 | or for an OSMC member paying an annual fee corresponding to the size
61 | of the organization including all its affiliates, use and redistribution
62 | is allowed within/between its affiliates.
63 |
64 | * OSMC-External-EPL = These OSMC Public license conditions together with
65 | Externally restricted EPL, i.e., EPL version 1.0 with the Additional
66 | Condition that use and redistribution by an OSMC member, or by a Licensed
67 | Third Party Distributor having a redistribution agreement with that member,
68 | to parties external to the OSMC member’s own organization (i.e., its own
69 | legal entity) is only allowed in binary/object-code form, except the case of
70 | redistribution to other OSMC members to which source is also allowed to be
71 | distributed.
72 |
73 | [This has the consequence that an external party who wishes to use
74 | OpenModelica in source form together with its own proprietary software in all
75 | cases must be a member of OSMC].
76 |
77 | In all cases of usage and redistribution by recipients, the following
78 | conditions also apply:
79 |
80 | a) Redistributions of source code must retain the above copyright notice,
81 | all definitions, and conditions. It is sufficient if the OSMC-PL Header
82 | is present in each source file, if the full OSMC-PL is available in a
83 | prominent and easily located place in the redistribution.
84 |
85 | b) Redistributions in binary/object-code form must reproduce the above
86 | copyright notice, all definitions, and conditions. It is sufficient if the
87 | OSMC-PL Header and the location in the redistribution of the full OSMC-PL
88 | are present in the documentation and/or other materials provided with the
89 | redistribution, if the full OSMC-PL is available in a prominent and easily
90 | located place in the redistribution.
91 |
92 | c) A recipient must clearly indicate its chosen usage mode of OSMC-PL,
93 | in accompanying documentation and in a text file OSMC-USAGE-MODE.txt,
94 | provided with the distribution.
95 |
96 | d) Contributor(s) making a Contribution to OpenModelica thereby also makes a
97 | Transfer of Contribution Copyright. In return, upon the effective date of
98 | the transfer, OSMC grants the Contributor(s) a Contribution License of the
99 | Contribution. OSMC has the right to accept or refuse Contributions.
100 |
101 | Definitions:
102 |
103 | "Subsidiary license conditions" means:
104 |
105 | The additional license conditions depending on the by the recipient chosen
106 | mode of OSMC-PL, defined by GNU AGPL version 3.0 for AGPL, and by EPL for
107 | OSMC-Internal-EPL and OSMC-External-EPL.
108 | "OSMC-PL" means:
109 |
110 | Open Source Modelica Consortium Public License version 1.8, i.e., the license
111 | defined here (the text between
112 | "--- Start of Definition of OSMC Public License ---" and
113 | "--- End of Definition of OSMC Public License ---", or later versions thereof.
114 |
115 | "OSMC-PL Header" means:
116 |
117 | Open Source Modelica Consortium Public License Header version 1.8, i.e., the
118 | text between "--- Start of Definition of OSMC Public License ---" and
119 | "--- End of OSMC Public License Header ---", or later versions thereof.
120 |
121 | "Contribution" means:
122 |
123 | a) in the case of the initial Contributor, the initial code and documentation
124 | distributed under OSMC-PL, and
125 |
126 | b) in the case of each subsequent Contributor:
127 | i) changes to OpenModelica, and
128 | ii) additions to OpenModelica;
129 |
130 | where such changes and/or additions to OpenModelica originate from and are
131 | distributed by that particular Contributor. A Contribution 'originates' from
132 | a Contributor if it was added to OpenModelica by such Contributor itself or
133 | anyone acting on such Contributor's behalf.
134 |
135 | For Contributors licensing OpenModelica under OSMC-Internal-EPL or
136 | OSMC-External-EPL conditions, the following conditions also hold:
137 |
138 | Contributions do not include additions to the distributed Program which: (i)
139 | are separate modules of software distributed in conjunction with OpenModelica
140 | under their own license agreement, (ii) are separate modules which are not
141 | derivative works of OpenModelica, and (iii) are separate modules of software
142 | distributed in conjunction with OpenModelica under their own license agreement
143 | where these separate modules are merged with (weaved together with) modules of
144 | OpenModelica to form new modules that are distributed as object code or source
145 | code under their own license agreement, as allowed under the Additional
146 | Condition of internal distribution according to OSMC-Internal-EPL and/or
147 | Additional Condition for external distribution according to OSMC-External-EPL.
148 |
149 | "Transfer of Contribution Copyright" means that the Contributors of a
150 | Contribution transfer the ownership and the copyright of the Contribution to
151 | Open Source Modelica Consortium, the OpenModelica Copyright owner, for
152 | inclusion in OpenModelica. The transfer takes place upon the effective date
153 | when the Contribution is made available on the OSMC web site under OSMC-PL, by
154 | such Contributors themselves or anyone acting on such Contributors' behalf.
155 | The transfer is free of charge. If the Contributors or OSMC so wish,
156 | an optional Copyright transfer agreement can be signed between OSMC and the
157 | Contributors, as specified in an Appendix of the OSMC Bylaws.
158 |
159 | "Contribution License" means a license from OSMC to the Contributors of the
160 | Contribution, effective on the date of the Transfer of Contribution Copyright,
161 | where OSMC grants the Contributors a non-exclusive, world-wide, transferable,
162 | free of charge, perpetual license, including sublicensing rights, to use,
163 | have used, modify, have modified, reproduce and or have reproduced the
164 | contributed material, for business and other purposes, including but not
165 | limited to evaluation, development, testing, integration and merging with
166 | other software and distribution. The warranty and liability disclaimers of
167 | OSMC-PL apply to this license.
168 |
169 | "Contributor" means any person or entity that distributes (part of)
170 | OpenModelica.
171 |
172 | "The Program" means the Contributions distributed in accordance with OSMC-PL.
173 |
174 | "OpenModelica" means the Contributions distributed in accordance with OSMC-PL.
175 |
176 | "Recipient" means anyone who receives OpenModelica under OSMC-PL,
177 | including all Contributors.
178 |
179 | "Licensed Third Party Distributor" means a reseller/distributor having signed
180 | a redistribution/resale agreement in accordance with OSMC-PL and OSMC Bylaws,
181 | with an OSMC Level 2 organizational member which is not an Affiliate of the
182 | reseller/distributor, for distributing a product containing part(s) of
183 | OpenModelica. The Licensed Third Party Distributor shall only be allowed
184 | further redistribution to other resellers if the Level 2 member is granting
185 | such a right to it in the redistribution/resale agreement between the
186 | Level 2 member and the Licensed Third Party Distributor.
187 |
188 | "Affiliate" shall mean any legal entity, directly or indirectly, through one
189 | or more intermediaries, controlling or controlled by or under common control
190 | with any other legal entity, as the case may be. For purposes of this
191 | definition, the term "control" (including the terms "controlling",
192 | "controlled by" and "under common control with") means the possession,
193 | direct or indirect, of the power to direct or cause the direction of the
194 | management and policies of a legal entity, whether through the ownership of
195 | voting securities, by contract or otherwise.
196 |
197 | NO WARRANTY
198 |
199 | EXCEPT AS EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY
200 | LICENSE CONDITIONS OF OSMC-PL, OPENMODELICA IS PROVIDED ON AN "AS IS"
201 | BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR
202 | IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF
203 | TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR
204 | PURPOSE. Each Recipient is solely responsible for determining the
205 | appropriateness of using and distributing OPENMODELICA and assumes all risks
206 | associated with its exercise of rights under OSMC-PL , including but not
207 | limited to the risks and costs of program errors, compliance with applicable
208 | laws, damage to or loss of data, programs or equipment, and unavailability
209 | or interruption of operations.
210 |
211 | DISCLAIMER OF LIABILITY
212 |
213 | EXCEPT AS EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY
214 | LICENSE CONDITIONS OF OSMC-PL, NEITHER RECIPIENT NOR ANY CONTRIBUTORS
215 | SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
216 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION
217 | LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
218 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
219 | ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF OPENMODELICA OR THE
220 | EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE
221 | POSSIBILITY OF SUCH DAMAGES.
222 |
223 | A Contributor licensing OpenModelica under OSMC-Internal-EPL or
224 | OSMC-External-EPL may choose to distribute (parts of) OpenModelica in object
225 | code form under its own license agreement, provided that:
226 |
227 | a) it complies with the terms and conditions of OSMC-PL; or for the case of
228 | redistribution of OpenModelica together with proprietary code it is a dual
229 | license where the OpenModelica parts are distributed under OSMC-PL compatible
230 | conditions and the proprietary code is distributed under proprietary license
231 | conditions; and
232 |
233 | b) its license agreement:
234 | i) effectively disclaims on behalf of all Contributors all warranties and
235 | conditions, express and implied, including warranties or conditions of title
236 | and non-infringement, and implied warranties or conditions of merchantability
237 | and fitness for a particular purpose;
238 | ii) effectively excludes on behalf of all Contributors all liability for
239 | damages, including direct, indirect, special, incidental and consequential
240 | damages, such as lost profits;
241 | iii) states that any provisions which differ from OSMC-PL are offered by that
242 | Contributor alone and not by any other party; and
243 | iv) states from where the source code for OpenModelica is available, and
244 | informs licensees how to obtain it in a reasonable manner on or through a
245 | medium customarily used for software exchange.
246 |
247 | When OPENMODELICA is made available in source code form:
248 |
249 | a) it must be made available under OSMC-PL; and
250 |
251 | b) a copy of OSMC-PL must be included with each copy of OPENMODELICA.
252 |
253 | c) a copy of the subsidiary license associated with the selected mode of
254 | OSMC-PL must be included with each copy of OPENMODELICA.
255 |
256 | Contributors may not remove or alter any copyright notices contained within
257 | OPENMODELICA.
258 |
259 | If there is a conflict between OSMC-PL and the subsidiary license conditions,
260 | OSMC-PL has priority.
261 |
262 | This Agreement is governed by the laws of Sweden. The place of jurisdiction
263 | for all disagreements related to this Agreement, is Linköping, Sweden.
264 |
265 | The EPL 1.0 license definition has been obtained from:
266 | http://www.eclipse.org/legal/epl-v10.html. It is also reproduced in Appendix B
267 | of the OSMC Bylaws, and in the OpenModelica distribution.
268 |
269 | The AGPL Version 3 license definition has been obtained from
270 | https://www.gnu.org/licenses/licenses.html#GPL. It is also reproduced in
271 | Appendix C of the OSMC Bylaws, and in the OpenModelica distribution.
272 |
273 | --- End of Definition of OSMC Public License ---
274 |
--------------------------------------------------------------------------------
/src/common/graphics.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * OMFrontend.js
3 | * Copyright (C) 2021-2022 Perpetual Labs, Ltd.
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU Affero General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU Affero General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Affero General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | /**
20 | * @author Mohamad Omar Nachawati
21 | */
22 |
23 | import { ModelicaClassSymbol, ModelicaComponentSymbol } from "./symbols.js";
24 | import { ModelicaClassRestriction } from "./syntax.js";
25 | import { XmlElement } from "./dom.js";
26 |
27 | function computeExtent(extent?: any, coordinateSystem?: any, origin?: any, rotation?: any): [[number, number], [number, number]] {
28 |
29 | let cextent = coordinateSystem?.extent;
30 |
31 | let xmin = Math.min(cextent?.[0]?.[0] ?? -100, cextent?.[1]?.[0] ?? 100);
32 | let ymax = Math.max(cextent?.[1]?.[1] ?? 100, cextent?.[0]?.[1] ?? -100);
33 |
34 | let x0 = origin?.[0] ?? 0;
35 | let y0 = origin?.[1] ?? 0;
36 | let r = rotation ?? 0;
37 |
38 | return [
39 | computePoint(extent[0]?.[0] ?? 0, extent[0]?.[1] ?? 0, x0, y0, xmin, ymax, r),
40 | computePoint(extent[1]?.[0] ?? 0, extent[1]?.[1] ?? 0, x0, y0, xmin, ymax, r)
41 | ];
42 |
43 | }
44 |
45 | function computeFillPattern(defs: XmlElement, graphic: any): string {
46 |
47 | let id = defs.children.length;
48 |
49 | let fillColor = graphic.fillColor;
50 | let fillPattern = graphic.fillPattern;
51 | let lineColor = graphic.lineColor;
52 | let lineThickness = graphic.lineThickness ?? 0.25;
53 |
54 | switch (fillPattern) {
55 |
56 | case 1: // Solid
57 | return `rgb(${fillColor?.[0] ?? 0},${fillColor?.[1] ?? 0},${fillColor?.[2] ?? 0})`;
58 |
59 | case 2: { // Horizontal
60 |
61 | let pattern = defs.append("pattern")
62 | .attr("height", 5)
63 | .attr("id", "Horizontal" + id)
64 | .attr("patternUnits", "userSpaceOnUse")
65 | .attr("width", 5)
66 | .attr("x", 0)
67 | .attr("y", 0);
68 |
69 | pattern.append("rect")
70 | .attr("height", 5)
71 | .attr("fill", `rgb(${fillColor?.[0] ?? 0},${fillColor?.[1] ?? 0},${fillColor?.[2] ?? 0})`)
72 | .attr("width", 5)
73 | .attr("x", 0)
74 | .attr("y", 0);
75 |
76 | pattern.append("path")
77 | .attr("d", "M0,0 L5,0")
78 | .attr("stroke", `rgb(${lineColor?.[0] ?? 0},${lineColor?.[1] ?? 0},${lineColor?.[2] ?? 0})`);
79 |
80 | return `url(#Horizontal${id})`;
81 |
82 | }
83 |
84 | case 3: { // Vertical
85 |
86 | let pattern = defs.append("pattern")
87 | .attr("height", 5)
88 | .attr("id", "Vertical" + id)
89 | .attr("patternUnits", "userSpaceOnUse")
90 | .attr("width", 5)
91 | .attr("x", 0)
92 | .attr("y", 0);
93 |
94 | pattern.append("rect")
95 | .attr("height", 5)
96 | .attr("fill", `rgb(${fillColor?.[0] ?? 0},${fillColor?.[1] ?? 0},${fillColor?.[2] ?? 0})`)
97 | .attr("width", 5)
98 | .attr("x", 0)
99 | .attr("y", 0);
100 |
101 | pattern.append("path")
102 | .attr("d", "M0,0 L0,5")
103 | .attr("stroke", `rgb(${lineColor?.[0] ?? 0},${lineColor?.[1] ?? 0},${lineColor?.[2] ?? 0})`);
104 |
105 | return `url(#Vertical${id})`;
106 |
107 | }
108 |
109 | case 4: { // Cross
110 |
111 | let pattern = defs.append("pattern")
112 | .attr("height", 5)
113 | .attr("id", "Cross" + id)
114 | .attr("patternUnits", "userSpaceOnUse")
115 | .attr("width", 5)
116 | .attr("x", 0)
117 | .attr("y", 0);
118 |
119 | pattern.append("rect")
120 | .attr("height", 5)
121 | .attr("fill", `rgb(${fillColor?.[0] ?? 0},${fillColor?.[1] ?? 0},${fillColor?.[2] ?? 0})`)
122 | .attr("width", 5)
123 | .attr("x", 0)
124 | .attr("y", 0);
125 |
126 | pattern.append("path")
127 | .attr("d", "M0,0 L5,0")
128 | .attr("stroke", `rgb(${lineColor?.[0] ?? 0},${lineColor?.[1] ?? 0},${lineColor?.[2] ?? 0})`);
129 |
130 | pattern.append("path")
131 | .attr("d", "M0,0 L0,5")
132 | .attr("stroke", `rgb(${lineColor?.[0] ?? 0},${lineColor?.[1] ?? 0},${lineColor?.[2] ?? 0})`);
133 |
134 | return `url(#Cross${id})`;
135 |
136 | }
137 |
138 | case 5: { // Forward
139 |
140 | let pattern = defs.append("pattern")
141 | .attr("height", 7)
142 | .attr("id", "Forward" + id)
143 | .attr("patternUnits", "userSpaceOnUse")
144 | .attr("width", 7)
145 | .attr("x", 0)
146 | .attr("y", 0);
147 |
148 | pattern.append("rect")
149 | .attr("height", 7)
150 | .attr("fill", `rgb(${fillColor?.[0] ?? 0},${fillColor?.[1] ?? 0},${fillColor?.[2] ?? 0})`)
151 | .attr("width", 7)
152 | .attr("x", 0)
153 | .attr("y", 0);
154 |
155 | pattern.append("path")
156 | .attr("d", "M0,0 L7,7")
157 | .attr("stroke", `rgb(${lineColor?.[0] ?? 0},${lineColor?.[1] ?? 0},${lineColor?.[2] ?? 0})`);
158 |
159 | pattern.append("path")
160 | .attr("d", "M6,-1 l3,3")
161 | .attr("stroke", `rgb(${lineColor?.[0] ?? 0},${lineColor?.[1] ?? 0},${lineColor?.[2] ?? 0})`);
162 |
163 | pattern.append("path")
164 | .attr("d", "M-1,6 l3,3")
165 | .attr("stroke", `rgb(${lineColor?.[0] ?? 0},${lineColor?.[1] ?? 0},${lineColor?.[2] ?? 0})`);
166 |
167 | return `url(#Forward${id})`;
168 |
169 | }
170 |
171 | case 6: { // Backward
172 |
173 | let pattern = defs.append("pattern")
174 | .attr("height", 7)
175 | .attr("id", "Backward" + id)
176 | .attr("patternUnits", "userSpaceOnUse")
177 | .attr("width", 7)
178 | .attr("x", 0)
179 | .attr("y", 0);
180 |
181 | pattern.append("rect")
182 | .attr("height", 7)
183 | .attr("fill", `rgb(${fillColor?.[0] ?? 0},${fillColor?.[1] ?? 0},${fillColor?.[2] ?? 0})`)
184 | .attr("width", 7)
185 | .attr("x", 0)
186 | .attr("y", 0);
187 |
188 | pattern.append("path")
189 | .attr("d", "M7,0 l-7,7")
190 | .attr("stroke", `rgb(${lineColor?.[0] ?? 0},${lineColor?.[1] ?? 0},${lineColor?.[2] ?? 0})`);
191 |
192 | pattern.append("path")
193 | .attr("d", "M1,-1 l-7,7")
194 | .attr("stroke", `rgb(${lineColor?.[0] ?? 0},${lineColor?.[1] ?? 0},${lineColor?.[2] ?? 0})`);
195 |
196 | pattern.append("path")
197 | .attr("d", "M8,6 l-7,7")
198 | .attr("stroke", `rgb(${lineColor?.[0] ?? 0},${lineColor?.[1] ?? 0},${lineColor?.[2] ?? 0})`);
199 |
200 | return `url(#Backward${id})`;
201 |
202 | }
203 |
204 | case 7: { // CrossDiag
205 |
206 | let pattern = defs.append("pattern")
207 | .attr("height", 8)
208 | .attr("id", "CrossDiag" + id)
209 | .attr("patternUnits", "userSpaceOnUse")
210 | .attr("width", 8)
211 | .attr("x", 0)
212 | .attr("y", 0);
213 |
214 | pattern.append("rect")
215 | .attr("height", 8)
216 | .attr("fill", `rgb(${fillColor?.[0] ?? 0},${fillColor?.[1] ?? 0},${fillColor?.[2] ?? 0})`)
217 | .attr("width", 8)
218 | .attr("x", 0)
219 | .attr("y", 0);
220 |
221 | pattern.append("path")
222 | .attr("d", "M0,0 l8,8")
223 | .attr("stroke", `rgb(${lineColor?.[0] ?? 0},${lineColor?.[1] ?? 0},${lineColor?.[2] ?? 0})`);
224 |
225 | pattern.append("path")
226 | .attr("d", "M8,0 l-8,8")
227 | .attr("stroke", `rgb(${lineColor?.[0] ?? 0},${lineColor?.[1] ?? 0},${lineColor?.[2] ?? 0})`);
228 |
229 | return `url(#CrossDiag${id})`;
230 |
231 | }
232 |
233 | case 8: { // HorizontalCylinder
234 |
235 | let gradient = defs.append("linearGradient")
236 | .attr("id", "HorizontalCylinder" + id)
237 | .attr("x1", "0%")
238 | .attr("x2", "0%")
239 | .attr("y1", "0%")
240 | .attr("y2", "100%");
241 |
242 | let stops = [
243 | [0, 0],
244 | [0.3, 1],
245 | [0.7, 1],
246 | [1, 0]
247 | ];
248 |
249 | for (let stop of stops) {
250 |
251 | let color = getGradientColor(stop[1], lineColor, fillColor, 1);
252 |
253 | gradient.append("stop")
254 | .attr("offset", stop[0])
255 | .attr("stop-color", `rgb(${color[0]},${color[1]},${color[2]})`)
256 | .attr("stop-opacity", 1);
257 |
258 | }
259 |
260 | return `url(#HorizontalCylinder${id})`;
261 |
262 | }
263 |
264 | case 9: { // VerticalCylinder
265 |
266 | let gradient = defs.append("linearGradient")
267 | .attr("id", "VerticalCylinder" + id)
268 | .attr("x1", "0%")
269 | .attr("x2", "100%")
270 | .attr("y1", "0%")
271 | .attr("y2", "0%");
272 |
273 | let stops = [
274 | [0, 0],
275 | [0.3, 1],
276 | [0.7, 1],
277 | [1, 0]
278 | ];
279 |
280 | for (let stop of stops) {
281 |
282 | let color = getGradientColor(stop[1], lineColor, fillColor, 1);
283 |
284 | gradient.append("stop")
285 | .attr("offset", stop[0])
286 | .attr("stop-color", `rgb(${color[0]},${color[1]},${color[2]})`)
287 | .attr("stop-opacity", 1);
288 |
289 | }
290 |
291 | return `url(#VerticalCylinder${id})`;
292 |
293 | }
294 |
295 | case 10: { // Sphere
296 |
297 | let gradient;
298 | let stops;
299 |
300 | if (graphic["@type"] == "Ellipse") {
301 |
302 | gradient = defs.append("radialGradient")
303 | .attr("id", "Sphere" + id)
304 | .attr("cx", "50%")
305 | .attr("cy", "50%")
306 | .attr("fx", "50%")
307 | .attr("fy", "50%")
308 | .attr("r", "55%");
309 |
310 | stops = [
311 | [0, 10],
312 | [0.45, 8],
313 | [0.7, 6],
314 | [1, 0]
315 | ];
316 |
317 | } else {
318 |
319 | gradient = defs.append("radialGradient")
320 | .attr("id", "Sphere" + id)
321 | .attr("cx", "50%")
322 | .attr("cy", "50%")
323 | .attr("fx", "50%")
324 | .attr("fy", "50%")
325 | .attr("r", "0.9");
326 |
327 | stops = [
328 | [0, 1],
329 | [1, 0]
330 | ];
331 |
332 | }
333 |
334 | for (let stop of stops) {
335 |
336 | let color = getGradientColor(stop[1], lineColor, fillColor, 1);
337 |
338 | gradient.append("stop")
339 | .attr("offset", stop[0])
340 | .attr("stop-color", `rgb(${color[0]},${color[1]},${color[2]})`)
341 | .attr("stop-opacity", 1);
342 |
343 | }
344 |
345 | return `url(#Sphere${id})`;
346 |
347 | }
348 |
349 | case 0: // None
350 | default: {
351 |
352 | if (graphic["@type"] == "Text")
353 | return `rgb(${lineColor?.[0] ?? 0},${lineColor?.[1] ?? 0},${lineColor?.[2] ?? 0})`;
354 |
355 | return "none";
356 |
357 | }
358 |
359 | }
360 |
361 | }
362 |
363 | function computeLinePattern(linePattern: number, lineThickness: number): string | null {
364 |
365 | let dash = 16 * lineThickness;
366 | let dot = 4 * lineThickness;
367 | let space = 8 * lineThickness;
368 |
369 | switch (linePattern) {
370 |
371 | case 1: // Solid
372 | return null;
373 |
374 | case 2: // Dash
375 | return `${dash} ${space}`;
376 |
377 | case 3: // Dot
378 | return `${dot} ${space}`;
379 |
380 | case 4: // DashDot
381 | return `${dash} ${space} ${dot} ${space}`;
382 |
383 | case 5: // DashDotDot
384 | return `${dash} ${space} ${dot} ${space} ${dot} ${space}`;
385 |
386 | case 0: // None
387 | default:
388 | return null;
389 |
390 | }
391 |
392 | }
393 |
394 | function computeArrow(defs: XmlElement, arrow: number, arrowSize: number, lineThickness: number, lineColor?: any[]): string {
395 |
396 | let id = defs.children.length;
397 |
398 | switch (Math.abs(arrow)) {
399 |
400 | case 1: { // Open
401 |
402 | let marker = defs.append("marker")
403 | .attr("id", "Marker" + id)
404 | .attr("orient", "auto")
405 | .attr("overflow", "visible")
406 | .attr("viewBox", "0 0 3 3")
407 | .attr("markerHeight", `${arrowSize}`)
408 | .attr("markerUnits", "userSpaceOnUse")
409 | .attr("markerWidth", `${arrowSize}`)
410 | .attr("refY", 1.5);
411 |
412 | if (arrow > 0) {
413 | marker.attr("refX", 0).append("path")
414 | .attr("d", "M 3 2.5 L 0 1.5 L 3 0.5")
415 | .attr("stroke", `rgb(${lineColor?.[0] ?? 0},${lineColor?.[1] ?? 0},${lineColor?.[2] ?? 0})`)
416 | .attr("stroke-width", `${lineThickness}mm`)
417 | .attr("vector-effect", "non-scaling-stroke")
418 | .attr("fill", "none");
419 | } else {
420 | marker.attr("refX", 3).append("path")
421 | .attr("d", "M 0 2.5 L 3 1.5 L 0 0.5")
422 | .attr("stroke", `rgb(${lineColor?.[0] ?? 0},${lineColor?.[1] ?? 0},${lineColor?.[2] ?? 0})`)
423 | .attr("stroke-width", `${lineThickness}mm`)
424 | .attr("vector-effect", "non-scaling-stroke")
425 | .attr("fill", "none");
426 | }
427 |
428 | break;
429 |
430 | }
431 |
432 | case 3: { // Half
433 |
434 | let marker = defs.append("marker")
435 | .attr("id", "Marker" + id)
436 | .attr("orient", "auto")
437 | .attr("overflow", "visible")
438 | .attr("viewBox", "0 0 3 3")
439 | .attr("markerHeight", `${arrowSize}`)
440 | .attr("markerUnits", "userSpaceOnUse")
441 | .attr("markerWidth", `${arrowSize}`)
442 | .attr("refY", 1.5);
443 |
444 | if (arrow > 0) {
445 | marker.attr("refX", 0).append("path")
446 | .attr("d", "M 3 2.5 L 0 1.5 L 3 1.5")
447 | .attr("stroke", `rgb(${lineColor?.[0] ?? 0},${lineColor?.[1] ?? 0},${lineColor?.[2] ?? 0})`)
448 | .attr("stroke-width", `${lineThickness}mm`)
449 | .attr("vector-effect", "non-scaling-stroke")
450 | .attr("fill", "none");
451 | } else {
452 | marker.attr("refX", 3).append("path")
453 | .attr("d", "M 0 2.5 L 3 1.5 L 0 1.5")
454 | .attr("stroke", `rgb(${lineColor?.[0] ?? 0},${lineColor?.[1] ?? 0},${lineColor?.[2] ?? 0})`)
455 | .attr("stroke-width", `${lineThickness}mm`)
456 | .attr("vector-effect", "non-scaling-stroke")
457 | .attr("fill", "none");
458 | }
459 |
460 | break;
461 |
462 | }
463 |
464 | case 2: { // Filled
465 |
466 | let marker = defs.append("marker")
467 | .attr("id", "Marker" + id)
468 | .attr("orient", "auto")
469 | .attr("overflow", "visible")
470 | .attr("viewBox", "0 0 3 3")
471 | .attr("markerHeight", `${arrowSize}`)
472 | .attr("markerUnits", "userSpaceOnUse")
473 | .attr("markerWidth", `${arrowSize}`)
474 | .attr("refY", 1.5);
475 |
476 | if (arrow > 0) {
477 | marker.attr("refX", 0).append("path")
478 | .attr("d", "M 3 2.5 L 0 1.5 L 3 0.5 z")
479 | .attr("fill", `rgb(${lineColor?.[0] ?? 0},${lineColor?.[1] ?? 0},${lineColor?.[2] ?? 0})`);
480 | } else {
481 | marker.attr("refX", 3).append("path")
482 | .attr("d", "M 0 2.5 L 3 1.5 L 0 0.5 z")
483 | .attr("fill", `rgb(${lineColor?.[0] ?? 0},${lineColor?.[1] ?? 0},${lineColor?.[2] ?? 0})`);
484 | }
485 |
486 | break;
487 |
488 | }
489 |
490 | }
491 |
492 | return `url(#Marker${id})`;
493 | }
494 |
495 | function computePath(points: any[], coordinateSystem?: any, origin?: any, rotation?: any, closed?: boolean): string {
496 |
497 | let extent = coordinateSystem?.extent;
498 |
499 | let xmin = Math.min(extent?.[0]?.[0] ?? -100, extent?.[1]?.[0] ?? 100);
500 | let ymax = Math.max(extent?.[1]?.[1] ?? 100, extent?.[0]?.[1] ?? -100);
501 |
502 | let x0 = origin?.[0] ?? 0;
503 | let y0 = origin?.[1] ?? 0;
504 | let r = rotation ?? 0;
505 | let n = points.length - 1;
506 |
507 | let p0 = computePoint(points[0]?.[0] ?? 0, points[0]?.[1] ?? 0, x0, y0, xmin, ymax, r);
508 | let p1 = computePoint(points[1]?.[0] ?? 0, points[1]?.[1] ?? 0, x0, y0, xmin, ymax, r);
509 | let p2 = computePoint(points[2]?.[0] ?? 0, points[2]?.[1] ?? 0, x0, y0, xmin, ymax, r);
510 | let pn = computePoint(points[n]?.[0] ?? 0, points[n]?.[1] ?? 0, x0, y0, xmin, ymax, r);
511 |
512 | let result;
513 |
514 | if ((closed ?? false) == false) {
515 | result = `M ${p0[0]} ${p0[1]}`;
516 | result += ` L ${p0[0] + (p1[0] - p0[0]) / 2} ${p0[1] + (p1[1] - p0[1]) / 2}`;
517 | } else {
518 | result = `M ${p0[0]} ${p0[1]}`;
519 | result += ` Q ${p0[0]} ${p0[1]} ${p0[0] + (p1[0] - p0[0]) / 2} ${p0[1] + (p1[1] - p0[1]) / 2}`;
520 | }
521 |
522 | result += ` Q ${p1[0]} ${p1[1]} ${p1[0] + (p2[0] - p1[0]) / 2} ${p1[1] + (p2[1] - p1[1]) / 2}`;
523 |
524 | let pp = p2;
525 | for (let point of points.slice(3)) {
526 | let p = computePoint(point?.[0] ?? 0, point?.[1] ?? 0, x0, y0, xmin, ymax, r);
527 | result += ` Q ${pp[0]} ${pp[1]} ${pp[0] + (p[0] - pp[0]) / 2} ${pp[1] + (p[1] - pp[1]) / 2}`;
528 | pp = p;
529 | }
530 |
531 | if ((closed ?? false) == false)
532 | result += ` L ${pn[0]} ${pn[1]}`;
533 |
534 | else
535 | result += ` Z`;
536 |
537 | return result;
538 |
539 | }
540 |
541 | function computePoint(x: number, y: number, x0: number, y0: number, xmin: number, ymax: number, r: number): [number, number] {
542 |
543 | r = r / 180 * Math.PI;
544 |
545 | return [
546 | (x * Math.cos(r) - y * Math.sin(r) + x0) - xmin,
547 | ymax - (y * Math.sin(r) + y * Math.cos(r) + y0)
548 | ];
549 |
550 | }
551 |
552 | function computePoints(points?: any[], coordinateSystem?: any, origin?: any, rotation?: any, closed?: boolean): string {
553 |
554 | let extent = coordinateSystem?.extent;
555 |
556 | let xmin = Math.min(extent?.[0]?.[0] ?? -100, extent?.[1]?.[0] ?? 100);
557 | let ymax = Math.max(extent?.[1]?.[1] ?? 100, extent?.[0]?.[1] ?? -100);
558 |
559 | let x0 = origin?.[0] ?? 0;
560 | let y0 = origin?.[1] ?? 0;
561 | let r = rotation ?? 0;
562 |
563 | let result = "";
564 |
565 | for (let point of points ?? []) {
566 | let p = computePoint(point?.[0] ?? 0, point?.[1] ?? 0, x0, y0, xmin, ymax, r);
567 | result += `,${p[0]},${p[1]}`;
568 | }
569 |
570 | return result.substring(1) + (closed == true ? " Z" : "");
571 |
572 | }
573 |
574 | async function computeTextMacros(graphic: any, componentSymbol?: ModelicaComponentSymbol): Promise {
575 |
576 | let textString: string = graphic.textString ?? graphic.string ?? "";
577 |
578 | textString = textString.replace(/\%\%/, "%");
579 |
580 | textString = textString.replace(/\%name\b/, componentSymbol?.identifier?.value ?? "%name");
581 |
582 | textString = textString.replace(/\%class\b/, (await componentSymbol?.classSymbol)?.identifier?.value ?? "%class");
583 |
584 | //textString = textString.replace(/\%[A-Za-z][A-Za-z0-9]*\b/, componentSymbol?.identifier?.value ?? "?");
585 |
586 | return textString;
587 |
588 | }
589 |
590 | function computeTransform(coordinateSystem: any, transformation: any): string {
591 |
592 | let cextent = coordinateSystem?.extent;
593 |
594 | let cx1 = cextent?.[0]?.[0] ?? -100;
595 | let cy1 = cextent?.[0]?.[1] ?? -100;
596 | let cx2 = cextent?.[1]?.[0] ?? 100;
597 | let cy2 = cextent?.[1]?.[1] ?? 100;
598 |
599 | let cxmin = Math.min(cx1, cx2);
600 | let cxmax = Math.max(cx2, cx1);
601 | let cymin = Math.min(cy1, cy2);
602 | let cymax = Math.max(cy2, cy1);
603 |
604 | let cwidth = Math.abs(cxmax - cxmin);
605 | let cheight = Math.abs(cymax - cymin);
606 |
607 | let textent = transformation?.extent;
608 |
609 | let tx1 = textent?.[0]?.[0] ?? -100;
610 | let ty1 = textent?.[0]?.[1] ?? -100;
611 | let tx2 = textent?.[1]?.[0] ?? 100;
612 | let ty2 = textent?.[1]?.[1] ?? 100;
613 |
614 | let txmin = Math.min(tx1, tx2);
615 | let txmax = Math.max(tx2, tx1);
616 | let tymin = Math.min(ty1, ty2);
617 | let tymax = Math.max(ty2, ty1);
618 |
619 | let twidth = Math.abs(txmax - txmin);
620 | let theight = Math.abs(tymax - tymin);
621 |
622 | let torigin = transformation?.origin;
623 |
624 | let tox = torigin?.[0] ?? 0;
625 | let toy = torigin?.[1] ?? 0;
626 |
627 | let tx = tox - cxmin - twidth / 2 + txmin + twidth / 2;
628 | let ty = cymax - toy - theight / 2 - tymin - theight / 2;
629 |
630 | let sx = twidth / cwidth;
631 | let sy = theight / cheight;
632 |
633 | let r = transformation?.rotation ?? 0;
634 | let ox = twidth / 2;
635 | let oy = theight / 2;
636 |
637 | return `translate(${tx},${ty}) rotate(${r},${ox},${oy}) scale(${sx},${sy})`;
638 |
639 | }
640 |
641 | function configureLayer(svg: XmlElement, coordinateSystem: any): void {
642 |
643 | let extent = coordinateSystem?.extent;
644 | let preserveAspectRatio = coordinateSystem?.preserveAspectRatio ?? true;
645 |
646 | let x1 = extent?.[0]?.[0] ?? -100;
647 | let y1 = extent?.[0]?.[1] ?? -100;
648 | let x2 = extent?.[1]?.[0] ?? 100;
649 | let y2 = extent?.[1]?.[1] ?? 100;
650 |
651 | let xmin = Math.min(x1, x2);
652 | let xmax = Math.max(x2, x1);
653 | let ymin = Math.min(y1, y2);
654 | let ymax = Math.max(y2, y1);
655 |
656 | let width = Math.abs(xmax - xmin);
657 | let height = Math.abs(ymax - ymin);
658 |
659 | svg.attr("overflow", "visible");
660 | svg.attr("width", `${width}`);
661 | svg.attr("height", `${height}`);
662 | svg.attr("viewBox", `0 0 ${width} ${height}`);
663 | svg.attr("preserveAspectRatio", preserveAspectRatio ? "xMidYMid" : "none");
664 |
665 | }
666 |
667 | function getGradientColor(index: number, startColor: number[], stopColor: number[], midpoints: number): number[] {
668 |
669 | index |= 0;
670 | startColor = [(startColor[0] ?? 0) | 0, (startColor[1] ?? 0) | 0, (startColor[2] ?? 0) | 0];
671 | stopColor = [(stopColor[0] ?? 0) | 0, (stopColor[1] ?? 0) | 0, (stopColor[2] ?? 0) | 0];
672 | midpoints = midpoints < 0 ? 0 : midpoints | 0;
673 |
674 | if (index <= 0)
675 | return startColor;
676 |
677 | if (index > midpoints)
678 | return stopColor;
679 |
680 | return [
681 | startColor[0] + index * (stopColor[0] - startColor[0]) / (midpoints + 1),
682 | startColor[1] + index * (stopColor[1] - startColor[1]) / (midpoints + 1),
683 | startColor[2] + index * (stopColor[2] - startColor[2]) / (midpoints + 1)
684 | ];
685 | }
686 |
687 | export async function renderDiagram(svg: XmlElement, classSymbol: ModelicaClassSymbol, defs?: XmlElement): Promise {
688 |
689 | if (defs == null)
690 | defs = svg.append("defs");
691 |
692 | for await (let baseClass of classSymbol.baseClasses)
693 | if (baseClass != null)
694 | await renderDiagram(svg, baseClass, defs);
695 |
696 | let diagram: any = null;
697 | let diagramAnnotation = await (await classSymbol.annotation)?.getNamedElement("Diagram");
698 |
699 | if (diagramAnnotation instanceof ModelicaClassSymbol)
700 | diagram = (await diagramAnnotation.construct())?.toJSON();
701 |
702 | let coordinateSystem = diagram?.coordinateSystem;
703 | let graphics = diagram?.graphics;
704 |
705 | configureLayer(svg, coordinateSystem);
706 |
707 | for (let graphic of graphics ?? [])
708 | await renderGraphic(svg, defs, graphic, coordinateSystem);
709 |
710 | for await (let connection of classSymbol.connections) {
711 |
712 | let annotation = await connection.annotationClause?.instantiate(classSymbol);
713 |
714 | if (annotation == null)
715 | continue;
716 |
717 | for await (let namedElement of annotation.namedElements) {
718 |
719 | if (!(namedElement instanceof ModelicaClassSymbol))
720 | continue;
721 |
722 | let graphic = (await namedElement.construct())?.toJSON();
723 |
724 | if (graphic == null)
725 | continue;
726 |
727 | await renderGraphic(svg, defs, graphic, coordinateSystem);
728 |
729 | }
730 |
731 | }
732 |
733 | for await (let componentSymbol of classSymbol.components) {
734 |
735 | let componentClassSymbol = await componentSymbol.classSymbol;
736 |
737 | if (componentClassSymbol == null)
738 | continue;
739 |
740 | let placement: any = null;
741 | let placementAnnotation = await (await componentSymbol?.annotation)?.getNamedElement("Placement");
742 |
743 | if (placementAnnotation instanceof ModelicaClassSymbol)
744 | placement = (await placementAnnotation.construct())?.toJSON();
745 |
746 | if (placement != null && placement["@type"] != "Placement")
747 | placement = null;
748 |
749 | if (placement?.visible == false)
750 | continue;
751 |
752 | let transformation = placement?.transformation;
753 |
754 | let g = svg.append("g");
755 |
756 | g.attr("transform", computeTransform(coordinateSystem, transformation));
757 |
758 | await renderIcon(g.append("svg").attr("overflow", "visible"), componentClassSymbol, componentSymbol, defs);
759 |
760 | }
761 |
762 | }
763 |
764 | export async function renderIcon(svg: XmlElement, classSymbol: ModelicaClassSymbol, componentSymbol?: ModelicaComponentSymbol, defs?: XmlElement): Promise {
765 |
766 | if (defs == null)
767 | defs = svg.append("defs");
768 |
769 | for await (let baseClass of classSymbol.baseClasses)
770 | if (baseClass != null)
771 | await renderIcon(svg, baseClass, componentSymbol, defs);
772 |
773 | let icon: any = null;
774 | let iconAnnotation = await (await classSymbol.annotation)?.getNamedElement("Icon");
775 |
776 | if (iconAnnotation instanceof ModelicaClassSymbol)
777 | icon = (await iconAnnotation.construct())?.toJSON();
778 |
779 | if (icon == null || icon["@type"] != "Icon")
780 | return;
781 |
782 | let coordinateSystem = icon.coordinateSystem;
783 | let graphics = icon.graphics;
784 |
785 | configureLayer(svg, coordinateSystem);
786 |
787 | for (let graphic of graphics ?? [])
788 | await renderGraphic(svg, defs, graphic, coordinateSystem, componentSymbol);
789 |
790 | for await (let connectorSymbol of classSymbol.components) {
791 |
792 | let connectorClassSymbol = await connectorSymbol.classSymbol;
793 |
794 | if (connectorClassSymbol?.classRestriction != ModelicaClassRestriction.CONNECTOR)
795 | continue;
796 |
797 | let placement: any = null;
798 | let placementAnnotation = await (await connectorSymbol?.annotation)?.getNamedElement("Placement");
799 |
800 | if (placementAnnotation instanceof ModelicaClassSymbol)
801 | placement = (await placementAnnotation.construct())?.toJSON();
802 |
803 | if (placement != null && placement["@type"] != "Placement")
804 | placement = null;
805 |
806 | if (placement?.iconVisible == false || (placement?.iconVisible == null && placement?.visible == false))
807 | continue;
808 |
809 | let iconTransformation = placement?.iconTransformation;
810 |
811 | if (iconTransformation?.extent?.["@type"] == "Extent")
812 | iconTransformation = placement?.transformation;
813 |
814 | let g = svg.append("g");
815 |
816 | g.attr("transform", computeTransform(coordinateSystem, iconTransformation));
817 |
818 | await renderIcon(g.append("svg").attr("overflow", "visible"), connectorClassSymbol, connectorSymbol, defs);
819 |
820 | }
821 |
822 | }
823 |
824 |
825 | export async function renderSimpleIcon(svg: XmlElement, classSymbol: ModelicaClassSymbol, componentSymbol?: ModelicaComponentSymbol, defs?: XmlElement): Promise {
826 |
827 | if (defs == null)
828 | defs = svg.append("defs");
829 |
830 | let icon: any = null;
831 | let iconAnnotation = await (await classSymbol.annotation)?.getNamedElement("Icon");
832 |
833 | if (iconAnnotation instanceof ModelicaClassSymbol)
834 | icon = (await iconAnnotation.construct())?.toJSON();
835 |
836 | if (icon == null || icon["@type"] != "Icon")
837 | return;
838 |
839 | let coordinateSystem = icon.coordinateSystem;
840 | let graphics = icon.graphics;
841 |
842 | configureLayer(svg, coordinateSystem);
843 |
844 | svg.attr("width", "100%");
845 | svg.attr("height", "100%");
846 |
847 | for (let graphic of graphics ?? [])
848 | await renderGraphic(svg, defs, graphic, coordinateSystem, componentSymbol);
849 |
850 | }
851 |
852 | async function renderGraphic(svg: XmlElement, defs: XmlElement, graphic: any, coordinateSystem?: any, componentSymbol?: ModelicaComponentSymbol): Promise {
853 |
854 | if (graphic?.visible == false)
855 | return;
856 |
857 | switch (graphic["@type"]) {
858 |
859 | case "Bitmap":
860 | await renderBitmap(svg, defs, graphic, coordinateSystem);
861 | break;
862 |
863 | case "Ellipse":
864 | await renderEllipse(svg, defs, graphic, coordinateSystem);
865 | break;
866 |
867 | case "Line":
868 | await renderLine(svg, defs, graphic, coordinateSystem);
869 | break;
870 |
871 | case "Polygon":
872 | await renderPolygon(svg, defs, graphic, coordinateSystem);
873 | break;
874 |
875 | case "Rectangle":
876 | await renderRectangle(svg, defs, graphic, coordinateSystem);
877 | break;
878 |
879 | case "Text":
880 | await renderText(svg, defs, graphic, coordinateSystem, componentSymbol);
881 | break;
882 |
883 | }
884 |
885 | }
886 |
887 | async function renderBitmap(svg: XmlElement, defs: XmlElement, graphic: any, coordinateSystem?: any): Promise {
888 | }
889 |
890 | async function renderEllipse(svg: XmlElement, defs: XmlElement, graphic: any, coordinateSystem?: any): Promise {
891 |
892 | let element = svg.append("ellipse");
893 |
894 | let extent = computeExtent(graphic.extent, coordinateSystem, graphic.origin, graphic.rotation);
895 |
896 | element.attr('cx', extent[0][0] + Math.abs(extent[1][0] - extent[0][0]) / 2)
897 | .attr('cy', extent[0][1] - Math.abs(extent[1][1] - extent[0][1]) / 2)
898 | .attr('rx', (extent[1][0] - extent[0][0]) / 2)
899 | .attr('ry', (extent[1][1] - extent[0][1]) / 2);
900 |
901 |
902 | let lineColor = graphic.lineColor;
903 | let lineThickness = graphic.lineThickness ?? 0.25;
904 | let linePattern = computeLinePattern(graphic.pattern, lineThickness);
905 |
906 | if (linePattern != null || (graphic.pattern ?? 0) > 0) {
907 |
908 | if (lineColor != null)
909 | element.attr("stroke", `rgb(${lineColor[0] ?? 0},${lineColor[1] ?? 0},${lineColor[2] ?? 0})`);
910 |
911 | else
912 | element.attr("stroke", "none");
913 |
914 | element.attr("stroke-width", `${lineThickness}mm`);
915 |
916 | if (linePattern != null)
917 | element.attr("stroke-dasharray", linePattern);
918 |
919 | }
920 |
921 | element.attr('fill', computeFillPattern(defs, graphic));
922 |
923 | element.attr("vector-effect", "non-scaling-stroke");
924 |
925 | }
926 |
927 | async function renderLine(svg: XmlElement, defs: XmlElement, graphic: any, coordinateSystem?: any): Promise {
928 |
929 | let element;
930 |
931 | if (graphic.smooth == 1 && graphic.points?.length > 2) {
932 |
933 | element = svg.append("path")
934 | .attr("d", computePath(graphic.points, coordinateSystem, graphic.origin, graphic.rotation));
935 |
936 | } else {
937 |
938 | element = svg.append("polyline")
939 | .attr("points", computePoints(graphic.points, coordinateSystem, graphic.origin, graphic.rotation));
940 |
941 | }
942 |
943 | let lineColor = graphic.color;
944 | let lineThickness = graphic.thickness ?? 0.25;
945 | let linePattern = computeLinePattern(graphic.pattern, lineThickness);
946 |
947 | if (linePattern != null || (graphic.pattern ?? 0) > 0) {
948 |
949 | if (lineColor != null)
950 | element.attr("stroke", `rgb(${lineColor[0] ?? 0},${lineColor[1] ?? 0},${lineColor[2] ?? 0})`);
951 |
952 | else
953 | element.attr("stroke", "none");
954 |
955 | element.attr("stroke-width", `${lineThickness}mm`);
956 |
957 | if (linePattern != null)
958 | element.attr("stroke-dasharray", linePattern);
959 |
960 | }
961 |
962 | let arrowSize = graphic.arrowSize ?? 3;
963 |
964 | if ((graphic.arrow?.[0] ?? 0) > 0)
965 | element.attr("marker-start", computeArrow(defs, graphic.arrow[0], arrowSize, lineThickness, lineColor));
966 |
967 | if ((graphic.arrow?.[1] ?? 0) > 0)
968 | element.attr("marker-end", computeArrow(defs, -graphic.arrow[1], arrowSize, lineThickness, lineColor));
969 |
970 | element.attr("fill", "none");
971 | element.attr("vector-effect", "non-scaling-stroke");
972 |
973 | }
974 |
975 | async function renderPolygon(svg: XmlElement, defs: XmlElement, graphic: any, coordinateSystem?: any): Promise {
976 |
977 | let element;
978 |
979 | if (graphic.smooth == 1 && graphic.points?.length > 2) {
980 |
981 | element = svg.append("path")
982 | .attr("d", computePath(graphic.points, coordinateSystem, graphic.origin, graphic.rotation, true));
983 |
984 | } else {
985 |
986 | element = svg.append("polyline")
987 | .attr("points", computePoints(graphic.points, coordinateSystem, graphic.origin, graphic.rotation, true));
988 |
989 | }
990 |
991 | let lineColor = graphic.lineColor;
992 | let lineThickness = graphic.lineThickness ?? 0.25;
993 | let linePattern = computeLinePattern(graphic.pattern, lineThickness);
994 |
995 | if (linePattern != null || (graphic.pattern ?? 0) > 0) {
996 |
997 | if (lineColor != null)
998 | element.attr("stroke", `rgb(${lineColor[0] ?? 0},${lineColor[1] ?? 0},${lineColor[2] ?? 0})`);
999 |
1000 | else
1001 | element.attr("stroke", "none");
1002 |
1003 | element.attr("stroke-width", `${lineThickness}mm`);
1004 |
1005 | if (linePattern != null)
1006 | element.attr("stroke-dasharray", linePattern);
1007 |
1008 | }
1009 |
1010 | element.attr('fill', computeFillPattern(defs, graphic));
1011 |
1012 | element.attr("vector-effect", "non-scaling-stroke");
1013 |
1014 | }
1015 |
1016 | async function renderRectangle(svg: XmlElement, defs: XmlElement, graphic: any, coordinateSystem?: any): Promise {
1017 |
1018 | let element = svg.append("rect");
1019 |
1020 | let extent = computeExtent(graphic.extent, coordinateSystem, graphic.origin, graphic.rotation);
1021 |
1022 | element.attr('x', extent[0][0])
1023 | .attr('y', extent[1][1] - Math.abs(extent[1][1] - extent[0][1]))
1024 | .attr('width', Math.abs(extent[1][0] - extent[0][0]))
1025 | .attr('height', Math.abs(extent[1][1] - extent[0][1]));
1026 |
1027 | let radius = graphic.radius ?? 0;
1028 | element.attr("rx", radius);
1029 | element.attr("ry", radius);
1030 |
1031 | let lineColor = graphic.lineColor;
1032 | let lineThickness = graphic.lineThickness ?? 0.25;
1033 | let linePattern = computeLinePattern(graphic.pattern, lineThickness);
1034 |
1035 | if (linePattern != null || (graphic.pattern ?? 0) > 0) {
1036 |
1037 | if (lineColor != null)
1038 | element.attr("stroke", `rgb(${lineColor[0] ?? 0},${lineColor[1] ?? 0},${lineColor[2] ?? 0})`);
1039 |
1040 | else
1041 | element.attr("stroke", "none");
1042 |
1043 | element.attr("stroke-width", `${lineThickness}mm`);
1044 |
1045 | if (linePattern != null)
1046 | element.attr("stroke-dasharray", linePattern);
1047 |
1048 | }
1049 |
1050 | element.attr('fill', computeFillPattern(defs, graphic));
1051 |
1052 | element.attr("vector-effect", "non-scaling-stroke");
1053 |
1054 | }
1055 |
1056 | async function renderText(svg: XmlElement, defs: XmlElement, graphic: any, coordinateSystem?: any, componentSymbol?: ModelicaComponentSymbol): Promise {
1057 |
1058 | let element = svg.append("text");
1059 |
1060 | element.appendText(await computeTextMacros(graphic, componentSymbol));
1061 |
1062 | element.attr('font-family', 'monospace');
1063 |
1064 | let textColor = graphic.textColor;
1065 |
1066 | if (textColor != null)
1067 | element.attr("fill", `rgb(${textColor[0] ?? 0},${textColor[1] ?? 0},${textColor[2] ?? 0})`);
1068 |
1069 | else
1070 | element.attr("fill", "none");
1071 |
1072 | let extent = computeExtent(graphic.extent, coordinateSystem);
1073 |
1074 | element.attr('x', extent[0][0] + (extent[1][0] - extent[0][0]) / 2);
1075 | element.attr('y', extent[0][1] + (extent[1][1] - extent[0][1]) / 2);
1076 |
1077 | let fontSize = Number(graphic.fontSize) ?? 0;
1078 |
1079 | element.attr("font-size", fontSize > 0 ? fontSize : Math.abs(extent[1][1] - extent[0][1]));
1080 | element.attr("dominant-baseline", "middle");
1081 | element.attr("text-anchor", "middle");
1082 | //element.attr("textLength", extent[1][0] - extent[0][0]);
1083 |
1084 | }
1085 |
1086 |
--------------------------------------------------------------------------------
/src/common/symbols.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * OMFrontend.js
3 | * Copyright (C) 2022 Perpetual Labs, Ltd.
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU Affero General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU Affero General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Affero General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | /**
20 | * @author Mohamad Omar Nachawati
21 | */
22 |
23 | import { ModelicaScope } from "./scope.js";
24 | import { ModelicaAlgorithmSectionSyntax, ModelicaClassDefinitionSyntax, ModelicaClassRedeclarationSyntax, ModelicaClassRestriction, ModelicaComponentDeclarationSyntax, ModelicaComponentReferenceExpressionSyntax, ModelicaConnectClauseSyntax, ModelicaDescriptionStringSyntax, ModelicaElementModificationSyntax, ModelicaElementSyntax, ModelicaEnumerationLiteralSyntax, ModelicaEquationSectionSyntax, ModelicaExpressionSyntax, ModelicaExtendsClauseSyntax, ModelicaIdentifierSyntax, ModelicaImportClauseSyntax, ModelicaModificationEnvironment, ModelicaNamedArgumentSyntax, ModelicaNamedElementSyntax, ModelicaNameSyntax, ModelicaTypeSpecifierSyntax, ModelicaVisibility } from "./syntax.js";
25 | import { BufferedPrintWriter, PrintWriter } from "./writer.js";
26 | import { getIdentifiers, toArray } from "./util.js";
27 | import { ModelicaContext } from "./context.js";
28 | import { renderDiagram, renderIcon, renderSimpleIcon } from "./graphics.js";
29 | import { XmlElement } from "./dom.js";
30 |
31 |
32 | export abstract class ModelicaSymbol {
33 |
34 | constructor() {
35 | }
36 |
37 | abstract accept(visitor: ModelicaSymbolVisitor, ...args: any[]): Promise;
38 |
39 | abstract print(printWriter: PrintWriter, indent?: number): Promise;
40 |
41 | }
42 |
43 | export class ModelicaObjectSymbol extends ModelicaSymbol {
44 |
45 | #properties: Map = new Map();
46 | #type: ModelicaClassSymbol;
47 | #value?: Array | boolean | number | string;
48 |
49 | constructor(type: ModelicaClassSymbol, value?: Array | boolean | number | string) {
50 | super();
51 | this.#type = type;
52 | this.#value = value;
53 | }
54 |
55 | override accept(visitor: ModelicaSymbolVisitor, ...args: any[]): Promise {
56 | return visitor.visitObject(this, ...args);
57 | }
58 |
59 | override async print(printWriter: PrintWriter, indent?: number): Promise {
60 |
61 | printWriter.println("<" + this.type.name + "> {");
62 |
63 | if (this.value != null) {
64 |
65 | if (this instanceof ModelicaArrayObjectSymbol) {
66 |
67 | printWriter.println("value: [", (indent ?? 0) + 1);
68 |
69 | for (let item of this.value) {
70 |
71 | if (item != null) {
72 |
73 | printWriter.print("", (indent ?? 0) + 2);
74 | await item.print(printWriter, (indent ?? 0) + 2);
75 |
76 | } else {
77 | printWriter.println("null", (indent ?? 0) + 2);
78 | }
79 |
80 | }
81 |
82 | printWriter.println("]", (indent ?? 0) + 1);
83 |
84 | } else if (this instanceof ModelicaEnumerationObjectSymbol) {
85 |
86 | printWriter.println("value: " + this.value, (indent ?? 0) + 1);
87 |
88 | } else {
89 |
90 | switch (this.type.name) {
91 |
92 | case "Boolean":
93 | printWriter.println("value: " + this.value, (indent ?? 0) + 1);
94 | break;
95 |
96 | case "Integer":
97 | printWriter.println("value: " + this.value, (indent ?? 0) + 1);
98 | break;
99 |
100 | case "Real":
101 | printWriter.println("value: " + this.value, (indent ?? 0) + 1);
102 | break;
103 |
104 | case "String":
105 | printWriter.println("value: \"" + this.value + "\"", (indent ?? 0) + 1);
106 | break;
107 |
108 | }
109 |
110 | }
111 |
112 | }
113 |
114 | for (let entry of this.#properties.entries()) {
115 |
116 | printWriter.print(entry[0] + ": ", (indent ?? 0) + 1);
117 |
118 | if (entry[1] != null)
119 | await entry[1].print(printWriter, (indent ?? 0) + 1);
120 |
121 | else
122 | printWriter.println("null");
123 |
124 | }
125 |
126 | printWriter.println("}", indent);
127 |
128 | }
129 |
130 | get properties(): Map {
131 | return this.#properties;
132 | }
133 |
134 | toJSON(): any {
135 |
136 | let value: any;
137 |
138 | if (this.type instanceof ModelicaBuiltinClassSymbol) {
139 |
140 | if (Array.isArray(this.value)) {
141 |
142 | value = [];
143 |
144 | for (let element of this.value)
145 | value.push(element?.toJSON());
146 |
147 | } else {
148 |
149 | value = this.value ?? null;
150 |
151 | }
152 |
153 | } else {
154 |
155 | value = {};
156 | value["@type"] = this.type.toString();
157 |
158 | for (let key of this.properties.keys())
159 | value[key] = this.properties.get(key)?.toJSON();
160 |
161 | }
162 |
163 | return value;
164 |
165 | }
166 |
167 | get type(): ModelicaClassSymbol {
168 | return this.#type;
169 | }
170 |
171 | get value(): Array | boolean | number | string | undefined {
172 | return this.#value;
173 | }
174 |
175 | set value(value: Array | boolean | number | string | undefined) {
176 | this.#value = value;
177 | }
178 |
179 | }
180 |
181 | export class ModelicaArrayObjectSymbol extends ModelicaObjectSymbol {
182 |
183 | constructor(type: ModelicaArrayClassSymbol, value?: Array) {
184 | super(type, value ?? []);
185 | }
186 |
187 | override get type(): ModelicaArrayClassSymbol {
188 | return super.type;
189 | }
190 |
191 | override get value(): Array {
192 | return >super.value ?? [];
193 | }
194 |
195 | override set value(value: Array) {
196 | super.value = value;
197 | }
198 |
199 | }
200 |
201 | export class ModelicaBooleanObjectSymbol extends ModelicaObjectSymbol {
202 |
203 | constructor(type: ModelicaBooleanClassSymbol, value: boolean) {
204 | super(type, value);
205 | }
206 |
207 | override get type(): ModelicaBooleanClassSymbol {
208 | return super.type;
209 | }
210 |
211 | override get value(): boolean {
212 | return super.value === true;
213 | }
214 |
215 | override set value(value: boolean) {
216 | super.value = value;
217 | }
218 |
219 | }
220 |
221 | export class ModelicaEnumerationObjectSymbol extends ModelicaObjectSymbol {
222 |
223 | constructor(type: ModelicaClassSymbol, value: number) {
224 | super(type, value);
225 | }
226 |
227 | override get value(): number {
228 | return Number(super.value);
229 | }
230 |
231 | override set value(value: number) {
232 | super.value = value;
233 | }
234 |
235 | }
236 |
237 | export abstract class ModelicaNumberObjectSymbol extends ModelicaObjectSymbol {
238 |
239 | constructor(type: ModelicaNumberClassSymbol, value: number) {
240 | super(type, value);
241 | }
242 |
243 | override get type(): ModelicaNumberClassSymbol {
244 | return super.type;
245 | }
246 |
247 | override get value(): number {
248 | return Number(super.value);
249 | }
250 |
251 | override set value(value: number) {
252 | super.value = value;
253 | }
254 |
255 | }
256 |
257 | export class ModelicaIntegerObjectSymbol extends ModelicaNumberObjectSymbol {
258 |
259 | constructor(type: ModelicaIntegerClassSymbol, value: number) {
260 | super(type, value | 0);
261 | }
262 |
263 | override get type(): ModelicaIntegerClassSymbol {
264 | return super.type;
265 | }
266 |
267 | override get value(): number {
268 | return super.value | 0;
269 | }
270 |
271 | override set value(value: number) {
272 | super.value = value;
273 | }
274 |
275 | }
276 |
277 | export class ModelicaRealObjectSymbol extends ModelicaNumberObjectSymbol {
278 |
279 | constructor(type: ModelicaRealClassSymbol, value: number) {
280 | super(type, value);
281 | }
282 |
283 | override get type(): ModelicaRealClassSymbol {
284 | return super.type;
285 | }
286 |
287 | override get value(): number {
288 | return super.value;
289 | }
290 |
291 | override set value(value: number) {
292 | super.value = value;
293 | }
294 |
295 | }
296 |
297 | export class ModelicaStringObjectSymbol extends ModelicaObjectSymbol {
298 |
299 | constructor(type: ModelicaStringClassSymbol, value: string) {
300 | super(type, value);
301 | }
302 |
303 | override get type(): ModelicaStringClassSymbol {
304 | return super.type;
305 | }
306 |
307 | override get value(): string {
308 | return String(super.value);
309 | }
310 |
311 | override set value(value: string) {
312 | super.value = value;
313 | }
314 |
315 | }
316 |
317 | export abstract class ModelicaElementSymbol extends ModelicaSymbol {
318 |
319 | #parent: ModelicaScope;
320 |
321 | constructor(parent: ModelicaScope) {
322 | super();
323 | this.#parent = parent;
324 | }
325 |
326 | abstract get annotation(): Promise;
327 |
328 | get parent() {
329 | return this.#parent;
330 | }
331 |
332 | abstract get syntax(): ModelicaElementSyntax | undefined;
333 |
334 | get visibility(): ModelicaVisibility | undefined {
335 | return this.syntax?.visibility;
336 | }
337 |
338 | }
339 |
340 | export class ModelicaAlgorithmSectionSymbol extends ModelicaElementSymbol {
341 |
342 | #syntax?: ModelicaAlgorithmSectionSyntax;
343 |
344 | constructor(parent: ModelicaScope, syntax?: ModelicaAlgorithmSectionSyntax) {
345 | super(parent);
346 | this.#syntax = syntax;
347 | }
348 |
349 | override async accept(visitor: ModelicaSymbolVisitor, ...args: any[]): Promise {
350 | return await visitor.visitAlgorithmSection(this, ...args);
351 | }
352 |
353 | override get annotation(): Promise {
354 |
355 | return async function () {
356 | return undefined;
357 | }();
358 |
359 | }
360 |
361 | override async print(printWriter: PrintWriter, indent?: number): Promise {
362 | printWriter.println("algorithm;", indent);
363 | }
364 |
365 | override get syntax(): ModelicaAlgorithmSectionSyntax | undefined {
366 | return this.#syntax;
367 | }
368 |
369 | }
370 |
371 | export class ModelicaEquationSectionSymbol extends ModelicaElementSymbol {
372 |
373 | #syntax?: ModelicaEquationSectionSyntax;
374 |
375 | constructor(parent: ModelicaScope, syntax?: ModelicaEquationSectionSyntax) {
376 | super(parent);
377 | this.#syntax = syntax;
378 | }
379 |
380 | override async accept(visitor: ModelicaSymbolVisitor, ...args: any[]): Promise {
381 | return await visitor.visitEquationSection(this, ...args);
382 | }
383 |
384 | override get annotation(): Promise {
385 |
386 | return async function () {
387 | return undefined;
388 | }();
389 |
390 | }
391 |
392 | override async print(printWriter: PrintWriter, indent?: number): Promise {
393 | printWriter.println("equation;", indent);
394 | }
395 |
396 | override get syntax(): ModelicaEquationSectionSyntax | undefined {
397 | return this.#syntax;
398 | }
399 |
400 | }
401 |
402 | export class ModelicaExtendsSymbol extends ModelicaElementSymbol {
403 |
404 | #annotation?: ModelicaAnnotationClassSymbol;
405 | #classSymbol?: ModelicaClassSymbol;
406 | #instantiated?: boolean;
407 | #instantiating?: boolean;
408 | #modificationEnvironment: ModelicaModificationEnvironment;
409 | #syntax?: ModelicaExtendsClauseSyntax;
410 |
411 | constructor(parent: ModelicaScope, modificationEnvironment?: ModelicaModificationEnvironment, syntax?: ModelicaExtendsClauseSyntax) {
412 | super(parent);
413 | this.#modificationEnvironment = modificationEnvironment ?? new ModelicaModificationEnvironment();
414 | this.#syntax = syntax;
415 | }
416 |
417 | override async accept(visitor: ModelicaSymbolVisitor, ...args: any[]): Promise {
418 | return await visitor.visitExtends(this, ...args);
419 | }
420 |
421 | override get annotation(): Promise {
422 |
423 | let node = this;
424 |
425 | return async function () {
426 |
427 | if (node.#annotation == null)
428 | node.#annotation = await node.syntax?.annotationClause?.instantiate(node.parent);
429 |
430 | return node.#annotation;
431 |
432 | }();
433 |
434 | }
435 |
436 | get classSymbol(): Promise {
437 |
438 | let node = this;
439 |
440 | return async function () {
441 |
442 | await node.instantiate();
443 | return node.#classSymbol;
444 |
445 | }();
446 |
447 | }
448 |
449 | async instantiate(): Promise {
450 |
451 | if (this.#instantiated == true)
452 | return;
453 |
454 | if (this.#instantiating == true) {
455 | this.#instantiated = true;
456 | return;
457 | //throw new Error("Inconsistency detected when instantiating extends: " + this.syntax?.source?.text);
458 | }
459 |
460 | //console.log("Start instantiate extends", this.syntax?.source?.text);
461 |
462 | this.#instantiating = true;
463 |
464 | //console.log("GOOD1");
465 | let classSymbol = await this.parent?.resolve(this.syntax?.typeSpecifier);
466 | //console.log("GOOD2");
467 |
468 | if (classSymbol != null && classSymbol instanceof ModelicaClassSymbol) {
469 | //console.log("GOOD3");
470 | this.#classSymbol = await classSymbol.instantiate(classSymbol.parent, this.modificationEnvironment.merge(this.syntax?.classModification));
471 |
472 | // FIND BETTER WAY TO RECURSIVLEY INSTANTIATE BASE CLASSES
473 | for await (let baseClass of this.#classSymbol.baseClasses)
474 | ;
475 | //console.log("GOOD4");
476 | }
477 |
478 |
479 | //console.log("End instantiate extends", this.syntax?.source?.text);
480 |
481 | this.#instantiated = true;
482 | this.#instantiating = undefined;
483 |
484 | }
485 |
486 | get modificationEnvironment(): ModelicaModificationEnvironment {
487 | return this.#modificationEnvironment;
488 | }
489 |
490 | override async print(printWriter: PrintWriter, indent?: number): Promise {
491 |
492 | printWriter.print("extends ", indent);
493 |
494 | let typeSpecifier = this.syntax?.typeSpecifier?.toString();
495 |
496 | if (typeSpecifier != null)
497 | printWriter.print(typeSpecifier);
498 |
499 | printWriter.println(";");
500 |
501 | }
502 |
503 | override get syntax(): ModelicaExtendsClauseSyntax | undefined {
504 | return this.#syntax;
505 | }
506 |
507 | }
508 |
509 | export class ModelicaImportSymbol extends ModelicaElementSymbol {
510 |
511 | #syntax?: ModelicaImportClauseSyntax;
512 |
513 | constructor(parent: ModelicaScope, syntax?: ModelicaImportClauseSyntax) {
514 | super(parent);
515 | this.#syntax = syntax;
516 | }
517 |
518 | override accept(visitor: ModelicaSymbolVisitor, ...args: any[]): any {
519 | return visitor.visitImport(this, ...args);
520 | }
521 |
522 | get alias(): ModelicaIdentifierSyntax | undefined {
523 | return this.syntax?.alias;
524 | }
525 |
526 | override get annotation(): Promise {
527 |
528 | return async function () {
529 | return undefined;
530 | }();
531 |
532 | }
533 |
534 | get elements(): AsyncIterableIterator {
535 |
536 | let node = this;
537 |
538 | return async function* () {
539 |
540 | let element = await node.parent.resolve(node.name, true);
541 |
542 | if (element == null)
543 | return;
544 |
545 | if (node.wildcard) {
546 |
547 | if (element instanceof ModelicaClassSymbol)
548 | yield* element.namedElements;
549 |
550 | } else if (node.imports != null && node.imports.length > 0) {
551 |
552 | if (element instanceof ModelicaClassSymbol) {
553 |
554 | for (let importName of node.imports) {
555 |
556 | let importElement = await element.getNamedElement(importName);
557 |
558 | if (importElement != null)
559 | yield importElement;
560 |
561 | }
562 |
563 | }
564 |
565 | } else {
566 | yield element;
567 | }
568 |
569 | }();
570 |
571 | }
572 |
573 | get imports(): ModelicaIdentifierSyntax[] | undefined {
574 | return this.syntax?.imports;
575 | }
576 |
577 | get name(): ModelicaNameSyntax | undefined {
578 | return this.syntax?.name;
579 | }
580 |
581 | override async print(printWriter: PrintWriter, indent?: number): Promise {
582 |
583 | printWriter.print("import ", indent);
584 |
585 | let alias = this.alias?.toString();
586 |
587 | if (alias != null)
588 | printWriter.print(alias + " = ");
589 |
590 | let name = this.name?.toString();
591 |
592 | if (name != null)
593 | printWriter.print(name);
594 |
595 | if (this.imports != null && this.imports.length > 0) {
596 |
597 | printWriter.print(".{");
598 |
599 | for (let i = 0; i < this.imports.length; i++) {
600 |
601 | let importName = this.imports[i].toString();
602 |
603 | if (importName != null)
604 | printWriter.print(importName);
605 |
606 | if (i < this.imports.length - 1)
607 | printWriter.print(", ");
608 |
609 | }
610 |
611 | printWriter.print("}");
612 |
613 | } else if (this.wildcard == true) {
614 | printWriter.print(".*");
615 | }
616 |
617 | printWriter.println(";");
618 |
619 | }
620 |
621 | override get syntax(): ModelicaImportClauseSyntax | undefined {
622 | return this.#syntax;
623 | }
624 |
625 | get wildcard(): boolean | undefined {
626 | return this.syntax?.wildcard;
627 | }
628 |
629 | }
630 |
631 | export abstract class ModelicaNamedElementSymbol extends ModelicaElementSymbol {
632 |
633 | #modificationEnvironment: ModelicaModificationEnvironment;
634 |
635 | constructor(parent: ModelicaScope, modificationEnvironment?: ModelicaModificationEnvironment) {
636 | super(parent);
637 | this.#modificationEnvironment = modificationEnvironment ?? new ModelicaModificationEnvironment();
638 | }
639 |
640 | get descriptionString(): ModelicaDescriptionStringSyntax | undefined {
641 | return this.syntax?.descriptionString;
642 | }
643 |
644 | abstract get diagram(): Promise;
645 |
646 | abstract get icon(): Promise;
647 |
648 | abstract get simpleIcon(): Promise;
649 |
650 | get identifier(): ModelicaIdentifierSyntax | undefined {
651 | return this.syntax?.identifier;
652 | }
653 |
654 | get modificationEnvironment(): ModelicaModificationEnvironment {
655 | return this.#modificationEnvironment;
656 | }
657 |
658 | get name(): string | undefined {
659 |
660 | if (this.identifier == null || this.identifier.value == null)
661 | return undefined;
662 |
663 | if (this.parent instanceof ModelicaClassSymbol) {
664 |
665 | let parentName = this.parent.name;
666 |
667 | if (parentName == null)
668 | return undefined;
669 |
670 | return parentName + "." + this.identifier.value;
671 |
672 | }
673 |
674 | return this.identifier.value;
675 |
676 | }
677 |
678 | abstract get syntax(): ModelicaNamedElementSyntax | undefined;
679 |
680 | override toString(): string | undefined {
681 | return this.name;
682 | }
683 |
684 | }
685 |
686 | export class ModelicaClassSymbol extends ModelicaNamedElementSymbol implements ModelicaScope {
687 |
688 | #annotation?: ModelicaAnnotationClassSymbol;
689 | #diagram?: string;
690 | #elements?: ModelicaElementSymbol[];
691 | #icon?: string;
692 | #inconsistent?: boolean;
693 | #instantiated?: boolean;
694 | #instantiatedBaseClasses?: boolean;
695 | #instantiatedComponents?: boolean;
696 | #instantiating?: boolean;
697 | #instantiatingBaseClasses?: boolean;
698 | #instantiatingComponents?: boolean;
699 | #syntax?: ModelicaClassDefinitionSyntax;
700 |
701 | constructor(parent: ModelicaScope, modificationEnvironment?: ModelicaModificationEnvironment, syntax?: ModelicaClassDefinitionSyntax) {
702 | super(parent, modificationEnvironment);
703 | this.#syntax = syntax;
704 | }
705 |
706 | override accept(visitor: ModelicaSymbolVisitor, ...args: any[]): any {
707 | return visitor.visitClass(this, ...args);
708 | }
709 |
710 | get algorithmSections(): AsyncIterableIterator {
711 |
712 | let node = this;
713 |
714 | return async function* () {
715 |
716 | await node.#instantiateBaseClasses();
717 |
718 | for await (let element of node.elements) {
719 |
720 | if (element instanceof ModelicaAlgorithmSectionSymbol)
721 | yield element;
722 |
723 | else if (node.#instantiatedBaseClasses && element instanceof ModelicaExtendsSymbol) {
724 |
725 | let classSymbol = await element.classSymbol;
726 |
727 | if (classSymbol != null)
728 | yield* classSymbol.algorithmSections;
729 |
730 | }
731 |
732 | }
733 |
734 | }();
735 |
736 | }
737 |
738 | override get annotation(): Promise {
739 |
740 | let node = this;
741 |
742 | return async function () {
743 |
744 | if (node.#annotation == null)
745 | node.#annotation = await node.syntax?.classSpecifier?.annotationClause?.instantiate(node);
746 |
747 | return node.#annotation;
748 |
749 | }();
750 |
751 | }
752 |
753 | get baseClasses(): AsyncIterableIterator {
754 |
755 | let node = this;
756 |
757 | return async function* () {
758 |
759 | await node.#instantiateBaseClasses();
760 |
761 | for await (let element of node.elements ?? []) {
762 |
763 | if (element instanceof ModelicaExtendsSymbol) {
764 |
765 | let classSymbol = await element.classSymbol;
766 |
767 | if (classSymbol != null) {
768 | yield classSymbol;
769 | yield* classSymbol.baseClasses;
770 | }
771 |
772 | }
773 | }
774 |
775 | }();
776 |
777 | }
778 |
779 | get classes(): AsyncIterableIterator {
780 |
781 | let node = this;
782 |
783 | return async function* () {
784 |
785 | for await (let element of node.namedElements) {
786 |
787 | if (element instanceof ModelicaClassSymbol)
788 | yield element;
789 |
790 | }
791 |
792 | }();
793 |
794 | }
795 |
796 | get classRestriction(): ModelicaClassRestriction | undefined {
797 | return this.syntax?.classRestriction;
798 | }
799 |
800 | get components(): AsyncIterableIterator {
801 |
802 | let node = this;
803 |
804 | return async function* () {
805 |
806 | await node.#instantiateComponents();
807 |
808 | for await (let element of node.namedElements) {
809 |
810 | if (element instanceof ModelicaComponentSymbol)
811 | yield element;
812 |
813 | }
814 |
815 | }();
816 |
817 | }
818 |
819 | get connections(): AsyncIterableIterator {
820 |
821 | let node = this;
822 |
823 | return async function* () {
824 |
825 | for await (let element of node.equationSections) {
826 |
827 | for (let equation of element.syntax?.equations ?? []) {
828 |
829 | if (equation instanceof ModelicaConnectClauseSyntax)
830 | yield equation;
831 |
832 | }
833 |
834 | }
835 |
836 | }();
837 |
838 | }
839 |
840 | async construct(positionalArguments?: ModelicaExpressionSyntax[], namedArguments?: ModelicaNamedArgumentSyntax[]): Promise {
841 |
842 | let object = new ModelicaObjectSymbol(this);
843 |
844 | let position = 0;
845 |
846 | for await (let component of this.components) {
847 |
848 | if (component instanceof ModelicaEnumerationLiteralComponentSymbol)
849 | continue;
850 |
851 | let key = component.identifier?.toString();
852 | let value = null;
853 |
854 | for (let namedArgument of namedArguments ?? []) {
855 |
856 | if (namedArgument.identifier?.value == key) {
857 | value = await namedArgument.expression?.evaluate(this);
858 | break;
859 | }
860 |
861 | }
862 |
863 | if (value == null && positionalArguments?.[position] != null)
864 | value = await positionalArguments?.[position]?.evaluate(this);
865 |
866 | if (value == null)
867 | value = await component.value;
868 |
869 | if (value == null)
870 | value = await (await component.classSymbol)?.construct();
871 |
872 | if (key != null)
873 | object.properties.set(key, value ?? null);
874 |
875 | position++;
876 |
877 | }
878 |
879 | return object;
880 |
881 | }
882 |
883 | get context(): ModelicaContext {
884 | return this.parent.context;
885 | }
886 |
887 | override get diagram(): Promise {
888 |
889 | let node = this;
890 |
891 | return async function () {
892 |
893 | if (node.#diagram != null)
894 | return node.#diagram;
895 |
896 | let svg = new XmlElement("svg");
897 | svg.attributes.set("xmlns", "http://www.w3.org/2000/svg");
898 | await renderDiagram(svg, node);
899 | node.#diagram = svg.toString();
900 |
901 | return node.#diagram;
902 |
903 | }();
904 |
905 | }
906 |
907 | get elements(): AsyncIterableIterator {
908 |
909 | let node = this;
910 |
911 | return async function* () {
912 |
913 | await node.#instantiate();
914 |
915 | for (let element of node.#elements ?? [])
916 | yield element;
917 |
918 | }();
919 |
920 | }
921 |
922 | get equationSections(): AsyncIterableIterator {
923 |
924 | let node = this;
925 |
926 | return async function* () {
927 |
928 | await node.#instantiateBaseClasses();
929 |
930 | for await (let element of node.elements) {
931 |
932 | if (element instanceof ModelicaEquationSectionSymbol)
933 | yield element;
934 |
935 | else if (node.#instantiatedBaseClasses && element instanceof ModelicaExtendsSymbol) {
936 |
937 | let classSymbol = await element.classSymbol;
938 |
939 | if (classSymbol != null)
940 | yield* classSymbol.equationSections;
941 |
942 | }
943 |
944 | }
945 |
946 | }();
947 |
948 | }
949 |
950 |
951 | async getNamedElement(identifier: string | ModelicaIdentifierSyntax | null | undefined): Promise {
952 |
953 | identifier = identifier?.toString();
954 |
955 | if (identifier == null)
956 | return null;
957 |
958 | for await (let namedElement of this.namedElements) {
959 |
960 | if (namedElement.identifier?.toString() == identifier)
961 | return namedElement;
962 |
963 | }
964 |
965 | return null;
966 |
967 | }
968 |
969 | override get simpleIcon(): Promise {
970 |
971 | let node = this;
972 |
973 | return async function () {
974 |
975 | if (node.#icon != null)
976 | return node.#icon;
977 |
978 | let svg = new XmlElement("svg");
979 | svg.attributes.set("xmlns", "http://www.w3.org/2000/svg");
980 | await renderSimpleIcon(svg, node);
981 | node.#icon = svg.toString();
982 |
983 | return node.#icon;
984 |
985 | }();
986 |
987 | }
988 |
989 | override get icon(): Promise {
990 |
991 | let node = this;
992 |
993 | return async function () {
994 |
995 | if (node.#icon != null)
996 | return node.#icon;
997 |
998 | let svg = new XmlElement("svg");
999 | svg.attributes.set("xmlns", "http://www.w3.org/2000/svg");
1000 | await renderIcon(svg, node);
1001 | node.#icon = svg.toString();
1002 |
1003 | return node.#icon;
1004 |
1005 | }();
1006 |
1007 | }
1008 |
1009 | get imports(): AsyncIterableIterator {
1010 |
1011 | let node = this;
1012 |
1013 | return async function* () {
1014 |
1015 | for await (let element of node.elements ?? []) {
1016 |
1017 | if (element instanceof ModelicaImportSymbol)
1018 | yield element;
1019 |
1020 | }
1021 |
1022 | }();
1023 |
1024 | }
1025 |
1026 | async instantiate(parent: ModelicaScope, modificationEnvironment?: ModelicaModificationEnvironment): Promise {
1027 |
1028 | if (modificationEnvironment == null || modificationEnvironment.arguments == null || modificationEnvironment.arguments.length == 0)
1029 | //modificationEnvironment = this.modificationEnvironment;
1030 | return this;
1031 |
1032 |
1033 | modificationEnvironment = modificationEnvironment.merge(this.modificationEnvironment);
1034 | return new ModelicaClassSymbol(parent, modificationEnvironment, this.syntax);
1035 |
1036 | }
1037 |
1038 | async #instantiate(): Promise {
1039 |
1040 | if (this.#instantiated == true)
1041 | return;
1042 |
1043 | if (this.#instantiating == true) {
1044 | this.#instantiated = true;
1045 | return;
1046 | //throw new Error("Inconsistency detected when instantiating class: " + this.name);
1047 | }
1048 |
1049 | //console.log("Start Instantiate:", this.name);
1050 |
1051 | this.#instantiating = true;
1052 |
1053 | this.#elements = [];
1054 |
1055 | let enumerationValue = 0;
1056 |
1057 | for (let element of this.syntax?.elements ?? []) {
1058 |
1059 | if (element instanceof ModelicaEnumerationLiteralSyntax)
1060 | this.#elements.push(await element.instantiate(this, this.modificationEnvironment.getModificationEnvironment(element.identifier?.value), enumerationValue++));
1061 |
1062 | else if (element instanceof ModelicaNamedElementSyntax)
1063 | this.#elements.push(await element.instantiate(this, this.modificationEnvironment.getModificationEnvironment(element.identifier?.value)));
1064 |
1065 | else
1066 | this.#elements.push(await element.instantiate(this, this.modificationEnvironment));
1067 |
1068 | }
1069 |
1070 | if (this.syntax?.library != null && this.syntax?.filePath != null) {
1071 |
1072 | for await (let fileName of this.syntax.library.list(...this.syntax.filePath)) {
1073 |
1074 | let storedDefinition = await this.syntax.library.load(...this.syntax.filePath, fileName);
1075 |
1076 | if (storedDefinition != null) {
1077 |
1078 | let classSymbols = await storedDefinition.instantiate(this, this.modificationEnvironment);
1079 |
1080 | if (classSymbols.length > 0)
1081 | this.#elements.push(classSymbols[0]);
1082 |
1083 | }
1084 |
1085 | }
1086 |
1087 | }
1088 |
1089 | //console.log("End Instantiate:", this.name);
1090 |
1091 | this.#instantiated = true;
1092 | this.#instantiating = undefined;
1093 |
1094 | }
1095 |
1096 | async #instantiateBaseClasses(): Promise {
1097 |
1098 | if (this.#instantiatedBaseClasses == true)
1099 | return;
1100 |
1101 | if (this.#instantiatingBaseClasses == true) {
1102 | this.#instantiatedBaseClasses = true;
1103 | return;
1104 | //throw new Error("Inconsistency detected when instantiating base classes for class: " + this.name);
1105 | }
1106 |
1107 | //console.log("Start Base Instantiate1:", this.name);
1108 |
1109 | await this.#instantiate();
1110 |
1111 | //console.log("Start Base Instantiate2:", this.name);
1112 |
1113 | this.#instantiatingBaseClasses = true;
1114 |
1115 | for (let element of this.#elements ?? []) {
1116 |
1117 | if (element instanceof ModelicaExtendsSymbol)
1118 | await element.instantiate();
1119 |
1120 | }
1121 |
1122 | //console.log("End Base Instantiate:", this.name);
1123 |
1124 | this.#instantiatedBaseClasses = true;
1125 | this.#instantiatingBaseClasses = undefined;
1126 |
1127 | }
1128 |
1129 | async #instantiateComponents(): Promise {
1130 |
1131 | if (this.#instantiatedComponents == true)
1132 | return;
1133 |
1134 | if (this.#instantiatingComponents == true) {
1135 | this.#instantiatedComponents = true;
1136 | return;
1137 | //throw new Error("Inconsistency detected when instantiating components for class: " + this.name);
1138 | }
1139 |
1140 | await this.#instantiateBaseClasses();
1141 |
1142 | this.#instantiatingComponents = true;
1143 |
1144 | for await (let element of this.#elements ?? []) {
1145 |
1146 | if (element instanceof ModelicaComponentSymbol)
1147 | await element.instantiate();
1148 |
1149 | }
1150 |
1151 | this.#instantiatedComponents = true;
1152 | this.#instantiatingComponents = undefined;
1153 |
1154 | }
1155 |
1156 | get namedElements(): AsyncIterableIterator {
1157 |
1158 | let node = this;
1159 |
1160 | return async function* () {
1161 |
1162 | for await (let element of node.elements) {
1163 |
1164 | if (element instanceof ModelicaNamedElementSymbol)
1165 | yield element;
1166 |
1167 | else if (node.#instantiatedBaseClasses && element instanceof ModelicaExtendsSymbol) {
1168 |
1169 | let classSymbol = await element.classSymbol;
1170 |
1171 | if (classSymbol != null)
1172 | yield* classSymbol.namedElements;
1173 |
1174 | }
1175 |
1176 | }
1177 |
1178 | }();
1179 |
1180 | }
1181 |
1182 | override async print(printWriter: PrintWriter, indent?: number): Promise {
1183 |
1184 | await this.#instantiateBaseClasses();
1185 | await this.#instantiateComponents();
1186 |
1187 | printWriter.println(this.classRestriction + " " + this.identifier, indent);
1188 |
1189 | for await (let element of this.namedElements)
1190 | await element.print(printWriter, (indent ?? 0) + 1);
1191 |
1192 | let annotation = await (await this.annotation)?.evaluate();
1193 |
1194 | if (annotation != null) {
1195 |
1196 | printWriter.println("annotation(", (indent ?? 0) + 1);
1197 |
1198 | for (let element of annotation.value) {
1199 |
1200 | printWriter.print(element.type.name + ": ", (indent ?? 0) + 2);
1201 | await element.print(printWriter, (indent ?? 0) + 2);
1202 | }
1203 |
1204 | printWriter.println(");", (indent ?? 0) + 1);
1205 |
1206 | }
1207 |
1208 | printWriter.println("end " + this.identifier + ";", indent);
1209 |
1210 | }
1211 |
1212 | async rdf(printWriter: PrintWriter, indent?: number): Promise {
1213 |
1214 | printWriter.println(":" + this.name + " rdf:type owl:Class .", indent);
1215 |
1216 | for await (let baseClass of this.baseClasses)
1217 | printWriter.println(":" + this.name + " rdfs:subClassOf " + ":" + baseClass.name);
1218 |
1219 | for await (let clazz of this.classes) {
1220 | await clazz.rdf(printWriter, indent);
1221 | }
1222 |
1223 | }
1224 |
1225 | async resolve(reference: ModelicaIdentifierSyntax | ModelicaNameSyntax | ModelicaTypeSpecifierSyntax | string[] | string | null | undefined, global?: boolean): Promise {
1226 |
1227 | //console.log("RESOLVE: ", reference?.toString(), " in scope ", this.name);
1228 |
1229 | if (reference == null)
1230 | return null;
1231 |
1232 | global = global ?? false;
1233 |
1234 | if (reference instanceof ModelicaTypeSpecifierSyntax)
1235 | global = reference.global;
1236 |
1237 | let namedElementSymbol = null;
1238 |
1239 | if (this.parent == null || global != true) {
1240 |
1241 | let identifiers = getIdentifiers(reference);
1242 |
1243 | //console.log("RGOOD1", this.#instantiated, this.#instantiating, identifiers?.[0]);
1244 | namedElementSymbol = await this.getNamedElement(identifiers?.[0]);
1245 | //console.log("RGOOD2", namedElementSymbol);
1246 |
1247 | if (namedElementSymbol != null) {
1248 |
1249 | for (let part of identifiers?.slice(1) ?? []) {
1250 |
1251 | if (namedElementSymbol instanceof ModelicaClassSymbol)
1252 | namedElementSymbol = await namedElementSymbol.getNamedElement(part);
1253 |
1254 | else
1255 | namedElementSymbol = null;
1256 |
1257 | if (namedElementSymbol == null)
1258 | break;
1259 |
1260 | }
1261 |
1262 | }
1263 |
1264 | }
1265 |
1266 | if (namedElementSymbol == null) {
1267 |
1268 | namedElementSymbol = await this.parent?.resolve(reference, global);
1269 |
1270 | } else if (reference instanceof ModelicaTypeSpecifierSyntax && reference.subscripts != null && reference.subscripts.length > 0) {
1271 |
1272 | if (namedElementSymbol instanceof ModelicaClassSymbol) {
1273 |
1274 | let shape = [];
1275 |
1276 | for (let subscript of reference.subscripts) {
1277 |
1278 | let value = await subscript.expression?.evaluate(this);
1279 |
1280 | if (value instanceof ModelicaNumberObjectSymbol)
1281 | shape.push(value.value);
1282 |
1283 | else
1284 | shape.push(undefined);
1285 |
1286 | }
1287 |
1288 | return new ModelicaArrayClassSymbol(namedElementSymbol.parent, undefined, undefined, namedElementSymbol, shape);
1289 |
1290 | }
1291 |
1292 | return null;
1293 |
1294 | }
1295 |
1296 | return namedElementSymbol;
1297 |
1298 | }
1299 |
1300 | async resolveFunction(reference: ModelicaComponentReferenceExpressionSyntax | ModelicaIdentifierSyntax | ModelicaNameSyntax | ModelicaTypeSpecifierSyntax | string[] | string | null | undefined, global?: boolean): Promise {
1301 |
1302 | if (reference == null)
1303 | return null;
1304 |
1305 | if (!(reference instanceof ModelicaComponentReferenceExpressionSyntax))
1306 | return null;
1307 |
1308 | let components = toArray(reference.components);
1309 |
1310 | if (components.length == 0)
1311 | return null;
1312 |
1313 | let symbol: ModelicaNamedElementSymbol | null = await this.resolve(components[0].identifier, components[0].global);
1314 |
1315 | for (let component of components.slice(1)) {
1316 |
1317 | if (symbol instanceof ModelicaClassSymbol)
1318 | symbol = await symbol.getNamedElement(component.identifier);
1319 |
1320 | else if (symbol instanceof ModelicaComponentSymbol)
1321 | symbol = await (await symbol.classSymbol)?.getNamedElement(component.identifier) ?? null;
1322 |
1323 | else
1324 | symbol = null;
1325 |
1326 | if (symbol == null)
1327 | break;
1328 |
1329 | }
1330 |
1331 | if (symbol instanceof ModelicaClassSymbol && (symbol.classRestriction == ModelicaClassRestriction.FUNCTION || symbol.classRestriction == ModelicaClassRestriction.RECORD))
1332 | return symbol;
1333 |
1334 | return null;
1335 |
1336 | }
1337 |
1338 | override get syntax(): ModelicaClassDefinitionSyntax | undefined {
1339 | return this.#syntax;
1340 | }
1341 |
1342 | override toString(): string | undefined {
1343 | return this.identifier?.toString();
1344 | }
1345 |
1346 | }
1347 |
1348 | export abstract class ModelicaBuiltinClassSymbol extends ModelicaClassSymbol {
1349 |
1350 | #identifier?: ModelicaIdentifierSyntax;
1351 |
1352 | constructor(parent: ModelicaScope, modificationEnvironment?: ModelicaModificationEnvironment, identifier?: string) {
1353 |
1354 | super(parent, modificationEnvironment);
1355 |
1356 | if (identifier != null)
1357 | this.#identifier = new ModelicaIdentifierSyntax(null, identifier);
1358 |
1359 | }
1360 |
1361 | abstract override get classRestriction(): ModelicaClassRestriction | undefined;
1362 |
1363 | override get identifier(): ModelicaIdentifierSyntax | undefined {
1364 | return this.#identifier;
1365 | }
1366 |
1367 | override get name(): string | undefined {
1368 |
1369 | if (this.identifier == null || this.identifier.value == null)
1370 | return undefined;
1371 |
1372 | return this.identifier.value;
1373 |
1374 | }
1375 |
1376 | abstract override instantiate(parent: ModelicaScope, modificationEnvironment?: ModelicaModificationEnvironment): Promise;
1377 |
1378 | }
1379 |
1380 | export class ModelicaArrayClassSymbol extends ModelicaBuiltinClassSymbol {
1381 |
1382 | #dtype?: ModelicaClassSymbol;
1383 | #shape?: (number | undefined)[];
1384 |
1385 | constructor(parent: ModelicaScope, modificationEnvironment?: ModelicaModificationEnvironment, identifier?: string, dtype?: ModelicaClassSymbol, shape?: (number | undefined)[]) {
1386 | super(parent, modificationEnvironment, (identifier ?? "Array<" + (dtype?.name ?? "object") + ">") + "[" + (shape?.join(",") ?? ":") + "]");
1387 | this.#dtype = dtype;
1388 | this.#shape = shape;
1389 | }
1390 |
1391 | override get classRestriction(): ModelicaClassRestriction {
1392 | return ModelicaClassRestriction.TYPE;
1393 | }
1394 |
1395 | get dtype(): ModelicaClassSymbol | undefined {
1396 | return this.#dtype;
1397 | }
1398 |
1399 | set dtype(dtype: ModelicaClassSymbol | undefined) {
1400 | this.#dtype = dtype;
1401 | }
1402 |
1403 | override async construct(): Promise {
1404 |
1405 | let object = new ModelicaArrayObjectSymbol(this);
1406 |
1407 | for await (let component of this.components) {
1408 |
1409 | let key = component.identifier?.toString();
1410 | let value = await component.value;
1411 |
1412 | if (value == null)
1413 | value = await (await component.classSymbol)?.construct();
1414 |
1415 | if (key != null)
1416 | object.properties.set(key, value ?? null);
1417 |
1418 | }
1419 |
1420 | return object;
1421 |
1422 | }
1423 |
1424 | override async instantiate(parent: ModelicaScope, modificationEnvironment?: ModelicaModificationEnvironment): Promise {
1425 | return new ModelicaArrayClassSymbol(parent, modificationEnvironment);
1426 | }
1427 |
1428 | get shape(): (number | undefined)[] | undefined {
1429 | return this.#shape;
1430 | }
1431 |
1432 | set shape(shape: (number | undefined)[] | undefined) {
1433 | this.#shape = shape;
1434 | }
1435 |
1436 | }
1437 |
1438 | export class ModelicaBooleanClassSymbol extends ModelicaBuiltinClassSymbol {
1439 |
1440 | constructor(parent: ModelicaScope, modificationEnvironment?: ModelicaModificationEnvironment, identifier?: string) {
1441 | super(parent, modificationEnvironment, identifier ?? "Boolean");
1442 | }
1443 |
1444 | override get classRestriction(): ModelicaClassRestriction {
1445 | return ModelicaClassRestriction.TYPE;
1446 | }
1447 |
1448 | override async instantiate(parent: ModelicaScope, modificationEnvironment?: ModelicaModificationEnvironment): Promise {
1449 | return new ModelicaBooleanClassSymbol(parent, modificationEnvironment);
1450 | }
1451 |
1452 | }
1453 |
1454 | export abstract class ModelicaNumberClassSymbol extends ModelicaBuiltinClassSymbol {
1455 |
1456 | constructor(parent: ModelicaScope, modificationEnvironment?: ModelicaModificationEnvironment, identifier?: string) {
1457 | super(parent, modificationEnvironment, identifier);
1458 | }
1459 |
1460 | override get classRestriction(): ModelicaClassRestriction {
1461 | return ModelicaClassRestriction.TYPE;
1462 | }
1463 |
1464 | abstract override instantiate(parent: ModelicaScope, modificationEnvironment?: ModelicaModificationEnvironment): Promise;
1465 |
1466 | }
1467 |
1468 | export class ModelicaIntegerClassSymbol extends ModelicaNumberClassSymbol {
1469 |
1470 | constructor(parent: ModelicaScope, modificationEnvironment?: ModelicaModificationEnvironment, identifier?: string) {
1471 | super(parent, modificationEnvironment, identifier ?? "Integer");
1472 | }
1473 |
1474 | override async instantiate(parent: ModelicaScope, modificationEnvironment?: ModelicaModificationEnvironment): Promise {
1475 | return new ModelicaIntegerClassSymbol(parent, modificationEnvironment);
1476 | }
1477 |
1478 | }
1479 |
1480 | export class ModelicaRealClassSymbol extends ModelicaNumberClassSymbol {
1481 |
1482 | constructor(parent: ModelicaScope, modificationEnvironment?: ModelicaModificationEnvironment, identifier?: string) {
1483 | super(parent, modificationEnvironment, identifier ?? "Real");
1484 | }
1485 |
1486 | override async instantiate(parent: ModelicaScope, modificationEnvironment?: ModelicaModificationEnvironment): Promise {
1487 | return new ModelicaRealClassSymbol(parent, modificationEnvironment);
1488 | }
1489 |
1490 | }
1491 |
1492 | export class ModelicaStringClassSymbol extends ModelicaBuiltinClassSymbol {
1493 |
1494 | constructor(parent: ModelicaScope, modificationEnvironment?: ModelicaModificationEnvironment, identifer?: string) {
1495 | super(parent, modificationEnvironment, identifer ?? "String");
1496 | }
1497 |
1498 | override get classRestriction(): ModelicaClassRestriction {
1499 | return ModelicaClassRestriction.TYPE;
1500 | }
1501 |
1502 | override async instantiate(parent: ModelicaScope, modificationEnvironment?: ModelicaModificationEnvironment): Promise {
1503 | return new ModelicaStringClassSymbol(parent, modificationEnvironment);
1504 | }
1505 |
1506 | }
1507 |
1508 | export class ModelicaAnnotationClassSymbol extends ModelicaClassSymbol {
1509 |
1510 | #elements?: ModelicaElementSymbol[];
1511 |
1512 | constructor(parent: ModelicaScope, elements?: ModelicaElementSymbol[]) {
1513 | super(parent);
1514 | this.#elements = elements;
1515 | }
1516 |
1517 | override get classRestriction(): undefined {
1518 | return undefined;
1519 | }
1520 |
1521 | override get elements(): AsyncIterableIterator {
1522 |
1523 | let node = this;
1524 |
1525 | return async function* () {
1526 |
1527 | if (node.#elements != null)
1528 | yield* node.#elements;
1529 |
1530 | }();
1531 |
1532 | }
1533 |
1534 | async evaluate(): Promise {
1535 |
1536 | let values = [];
1537 |
1538 | for await (let annotation of this.classes) {
1539 |
1540 | let value = await annotation.construct();
1541 |
1542 | if (value != null)
1543 | values.push(value);
1544 |
1545 | }
1546 |
1547 | return new ModelicaArrayObjectSymbol(new ModelicaArrayClassSymbol(this), values);
1548 |
1549 | }
1550 |
1551 | override get identifier(): undefined {
1552 | return undefined;
1553 | }
1554 |
1555 | override async instantiate(parent: ModelicaScope): Promise {
1556 |
1557 | let elements: ModelicaElementSymbol[] = [];
1558 |
1559 | for await (let element of this.elements)
1560 | elements.push(element);
1561 |
1562 | return new ModelicaAnnotationClassSymbol(parent, elements);
1563 |
1564 | }
1565 |
1566 | override async print(printWriter: PrintWriter, indent?: number): Promise {
1567 |
1568 | for await (let element of this.elements) {
1569 | await element.print(printWriter, indent);
1570 | }
1571 |
1572 | }
1573 |
1574 | }
1575 |
1576 | export class ModelicaComponentSymbol extends ModelicaNamedElementSymbol {
1577 |
1578 | #annotation?: ModelicaAnnotationClassSymbol;
1579 | #classSymbol?: ModelicaClassSymbol;
1580 | #instantiated?: boolean;
1581 | #instantiating?: boolean;
1582 | #syntax?: ModelicaComponentDeclarationSyntax;
1583 | #value?: ModelicaObjectSymbol;
1584 |
1585 | constructor(parent: ModelicaScope, modificationEnvironment?: ModelicaModificationEnvironment, syntax?: ModelicaComponentDeclarationSyntax, classSymbol?: ModelicaClassSymbol, value?: ModelicaObjectSymbol) {
1586 | super(parent, modificationEnvironment);
1587 | this.#syntax = syntax;
1588 | this.#classSymbol = classSymbol;
1589 | this.#value = value;
1590 | }
1591 |
1592 | override accept(visitor: ModelicaSymbolVisitor, ...args: any[]): any {
1593 | return visitor.visitComponent(this, ...args);
1594 | }
1595 |
1596 | override get annotation(): Promise {
1597 |
1598 | let node = this;
1599 |
1600 | return async function () {
1601 |
1602 | if (node.#annotation == null)
1603 | node.#annotation = await node.syntax?.annotationClause?.instantiate(node.parent);
1604 |
1605 | return node.#annotation;
1606 |
1607 | }();
1608 |
1609 | }
1610 |
1611 | get classSymbol(): Promise {
1612 |
1613 | let node = this;
1614 |
1615 | return async function () {
1616 |
1617 | await node.instantiate();
1618 | return node.#classSymbol;
1619 |
1620 | }();
1621 |
1622 | }
1623 |
1624 | override get diagram(): Promise {
1625 |
1626 | let node = this;
1627 |
1628 | return async function () {
1629 | return await (await node.classSymbol)?.diagram;
1630 | }();
1631 |
1632 | }
1633 |
1634 | override get simpleIcon(): Promise {
1635 |
1636 | let node = this;
1637 |
1638 | return async function () {
1639 | return await (await node.classSymbol)?.simpleIcon;
1640 | }();
1641 |
1642 | }
1643 |
1644 | override get icon(): Promise {
1645 |
1646 | let node = this;
1647 |
1648 | return async function () {
1649 | return await (await node.classSymbol)?.icon;
1650 | }();
1651 |
1652 | }
1653 |
1654 | async instantiate(): Promise {
1655 |
1656 | if (this.#instantiated == true)
1657 | return;
1658 |
1659 | if (this.#instantiating == true) {
1660 | this.#instantiated = true;
1661 | return;
1662 | //throw new Error("Inconsistency detected");
1663 | }
1664 |
1665 | //console.log("START INSTANTIATE COMPONENT", this.name)
1666 |
1667 | this.#instantiating = true;
1668 |
1669 | let elementModification = this.modificationEnvironment.getElementModification(this.identifier?.value);
1670 |
1671 | if (this.#value == null) {
1672 |
1673 | if (elementModification?.modification?.expression != null)
1674 | this.#value = await elementModification?.modification?.expression?.evaluate(this.parent);
1675 |
1676 | else
1677 | this.#value = await this.syntax?.modification?.expression?.evaluate(this.parent);
1678 |
1679 | }
1680 |
1681 | if (this.#classSymbol == null) {
1682 |
1683 | let classSymbol = await this.parent?.resolve(this.syntax?.typeSpecifier);
1684 |
1685 | if (classSymbol != null && classSymbol instanceof ModelicaClassSymbol) {
1686 | let modificationEnvironment = new ModelicaModificationEnvironment(...(elementModification?.modification?.classModification?.arguments ?? []));
1687 | this.#classSymbol = await classSymbol.instantiate(classSymbol.parent, modificationEnvironment.merge(this.syntax?.modification?.classModification));
1688 | }
1689 |
1690 | if (this.#classSymbol != null && this.#value == null && this.syntax?.modification?.expression == null)
1691 | this.#value = await this.#classSymbol.construct();
1692 |
1693 | }
1694 |
1695 | //console.log("END INSTANTIATE COMPONENT", this.name)
1696 |
1697 | this.#instantiated = true;
1698 | this.#instantiating = undefined;
1699 |
1700 | }
1701 |
1702 | override async print(printWriter: PrintWriter, indent?: number): Promise {
1703 |
1704 | printWriter.print("", indent);
1705 |
1706 | let classSymbol = await this.classSymbol;
1707 |
1708 | let classSymbolIdentifier = classSymbol?.identifier?.toString();
1709 |
1710 | if (classSymbolIdentifier != null)
1711 | printWriter.print(classSymbolIdentifier);
1712 |
1713 | printWriter.print(" ");
1714 |
1715 | let identifier = this.identifier?.toString();
1716 |
1717 | if (identifier != null)
1718 | printWriter.print(identifier);
1719 |
1720 | if (this.syntax?.modification != null && classSymbol != null) {
1721 | //console.log(this.syntax.modification.expression?.evaluate(classSymbol));
1722 | }
1723 |
1724 | printWriter.println("");
1725 |
1726 | //printWriter.println(" {");
1727 | //await classSymbol?.print(printWriter, (indent ?? 0) + 1);
1728 |
1729 | let annotation = await (await this.annotation)?.evaluate();
1730 |
1731 | if (annotation != null) {
1732 |
1733 | printWriter.println("component-annotation(", (indent ?? 0) + 1);
1734 |
1735 | for (let element of annotation.value) {
1736 |
1737 | printWriter.print(element.type.name + ": ", (indent ?? 0) + 2);
1738 | await element.print(printWriter, (indent ?? 0) + 2);
1739 | }
1740 |
1741 | printWriter.println(")", (indent ?? 0) + 1);
1742 |
1743 | }
1744 |
1745 | annotation = await (await (await this.classSymbol)?.annotation)?.evaluate();
1746 |
1747 | if (annotation != null) {
1748 |
1749 | printWriter.println("class-annotation(", (indent ?? 0) + 1);
1750 |
1751 | for (let element of annotation.value) {
1752 |
1753 | printWriter.print(element.type.name + ": ", (indent ?? 0) + 2);
1754 | await element.print(printWriter, (indent ?? 0) + 2);
1755 | }
1756 |
1757 | printWriter.println(")", (indent ?? 0) + 1);
1758 |
1759 | }
1760 |
1761 | }
1762 |
1763 | override get syntax(): ModelicaComponentDeclarationSyntax | undefined {
1764 | return this.#syntax;
1765 | }
1766 |
1767 | get value(): Promise {
1768 |
1769 | let node = this;
1770 |
1771 | return async function () {
1772 | await node.instantiate();
1773 | return node.#value;
1774 | }();
1775 |
1776 | }
1777 |
1778 | }
1779 |
1780 | export class ModelicaEnumerationLiteralComponentSymbol extends ModelicaComponentSymbol {
1781 |
1782 | constructor(parent: ModelicaScope, modificationEnvironment?: ModelicaModificationEnvironment, syntax?: ModelicaEnumerationLiteralSyntax, classSymbol?: ModelicaClassSymbol, value?: number) {
1783 | super(parent, modificationEnvironment, syntax, classSymbol, value != null ? new ModelicaEnumerationObjectSymbol(new ModelicaIntegerClassSymbol(parent.context, undefined, syntax?.identifier?.value), value) : undefined);
1784 | }
1785 |
1786 | accept(visitor: ModelicaSymbolVisitor, ...args: any[]): Promise {
1787 | return visitor.visitEnumerationLiteralComponent(this, ...args);
1788 | }
1789 |
1790 | override toString(): string | undefined {
1791 | return this.identifier?.value;
1792 | }
1793 |
1794 | }
1795 |
1796 | export abstract class ModelicaSymbolVisitor {
1797 |
1798 | visitAlgorithmSection(node: ModelicaAlgorithmSectionSymbol, ...args: any[]): any {
1799 | throw new Error("Method not implemented.");
1800 | }
1801 |
1802 | visitClass(node: ModelicaClassSymbol, ...args: any[]): any {
1803 | throw new Error("Method not implemented.");
1804 | }
1805 |
1806 | visitComponent(node: ModelicaComponentSymbol, ...args: any[]): any {
1807 | throw new Error("Method not implemented.");
1808 | }
1809 |
1810 | visitEnumerationLiteralComponent(node: ModelicaEnumerationLiteralComponentSymbol, ...args: any[]): any {
1811 | throw new Error("Method not implemented.");
1812 | }
1813 |
1814 | visitEquationSection(node: ModelicaEquationSectionSymbol, ...args: any[]): any {
1815 | throw new Error("Method not implemented.");
1816 | }
1817 |
1818 | visitExtends(node: ModelicaExtendsSymbol, ...args: any[]): any {
1819 | throw new Error("Method not implemented.");
1820 | }
1821 |
1822 | visitImport(node: ModelicaImportSymbol, ...args: any[]): any {
1823 | throw new Error("Method not implemented.");
1824 | }
1825 |
1826 | visitObject(node: ModelicaObjectSymbol, ...args: any[]): any {
1827 | throw new Error("Method not implemented.");
1828 | }
1829 |
1830 | }
1831 |
--------------------------------------------------------------------------------