oclang 1.2.1 → 1.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/BUG_REGISTRY.md +1 -0
- package/CHANGELOG.md +9 -2
- package/dist/cli/index.js +1 -0
- package/dist/cli/ocat/commands/index.js +2 -0
- package/dist/cli/ocat/commands/repl.js +39 -0
- package/dist/cli/ocat/commands/run.js +19 -0
- package/dist/cli/ocat/index.js +20 -0
- package/dist/cli/ocm/commands/index.js +2 -0
- package/dist/cli/ocm/commands/init.js +41 -0
- package/dist/cli/ocm/commands/run.js +17 -0
- package/dist/cli/ocm/index.js +15 -0
- package/dist/cli/utils/chalkText.js +6 -0
- package/dist/core/ast/astBuilder.js +150 -0
- package/dist/core/ast/types/base/index.js +2 -0
- package/dist/core/ast/types/base/source.js +1 -0
- package/dist/core/ast/types/base/statement.js +7 -0
- package/dist/core/ast/types/statements/callStatement.js +1 -0
- package/dist/core/ast/types/statements/functionStatement.js +1 -0
- package/dist/core/ast/types/statements/index.js +4 -0
- package/dist/core/ast/types/statements/printStatement.js +1 -0
- package/dist/core/ast/types/statements/variableStatement.js +1 -0
- package/dist/core/context/contextType.js +5 -0
- package/dist/core/context/coreContext.js +6 -0
- package/dist/core/index.js +22 -0
- package/dist/core/lexer/tokens/attrs.js +6 -0
- package/dist/core/lexer/tokens/comments.js +12 -0
- package/dist/core/lexer/tokens/delimiters.js +11 -0
- package/dist/core/lexer/tokens/function.js +10 -0
- package/dist/core/lexer/tokens/ignored.js +3 -0
- package/dist/core/lexer/tokens/index.js +29 -0
- package/dist/core/lexer/tokens/keywords.js +3 -0
- package/dist/core/lexer/tokens/literals.js +14 -0
- package/dist/core/lexer/tokens/operators.js +3 -0
- package/dist/core/lexer/tokens/vars.js +12 -0
- package/dist/core/lexer/tokens.js +3 -0
- package/dist/core/parser/parser.js +84 -0
- package/dist/core/runner/runner.js +108 -0
- package/dist/core/runner/utils/string.js +14 -0
- package/dist/core/services/log.service.js +53 -0
- package/dist/project/index.js +22 -0
- package/dist/project/models/project.js +5 -0
- package/dist/project/utils/project.js +11 -0
- package/dist/shared/context/globalContext.js +16 -0
- package/dist/shared/io/json.js +7 -0
- package/dist/shared/manager/baseManager.js +30 -0
- package/dist/shared/manager/errors/coreErrors.js +8 -0
- package/dist/shared/manager/errors/io/extension.js +7 -0
- package/dist/shared/manager/errors/io/file.js +7 -0
- package/dist/shared/manager/errors/semantic/undefined/declared.js +24 -0
- package/dist/shared/manager/errors/semantic/undefined/undeclared.js +18 -0
- package/dist/shared/manager/errors/syntax/syntaxErrors.js +7 -0
- package/dist/shared/manager/errors/syntax/token.js +11 -0
- package/dist/shared/manager/warn/coreWarnings.js +8 -0
- package/dist/shared/models/func.js +1 -0
- package/dist/shared/models/value.js +7 -0
- package/dist/shared/models/var.js +1 -0
- package/dist/shared/utils/objects.js +6 -0
- package/dist/shared/utils/strformat.js +12 -0
- package/package.json +30 -30
- package/src/core/ast/astBuilder.ts +15 -153
- package/src/core/ast/statements/base.ts +3 -0
- package/src/core/ast/statements/function.ts +58 -0
- package/src/core/ast/statements/io.ts +51 -0
- package/src/core/ast/statements/vars.ts +47 -0
- package/src/core/lexer/tokens/keywords.ts +3 -1
- package/src/core/parser/parser.ts +11 -0
package/BUG_REGISTRY.md
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -16,15 +16,22 @@ PATCH version when you make backwards-compatible bug fixes.
|
|
|
16
16
|
|
|
17
17
|
- OCM mode added
|
|
18
18
|
|
|
19
|
-
#### 1.2.
|
|
19
|
+
#### 1.2.3 - AST Structure
|
|
20
|
+
|
|
21
|
+
- AST Structure updated
|
|
22
|
+
|
|
23
|
+
#### 1.2.1 & 1.2.2 - Uploading error
|
|
20
24
|
|
|
21
25
|
- Uploading error in 1.2.0
|
|
22
|
-
- Updated the CLI ```ocm init``` command
|
|
23
26
|
|
|
24
27
|
### 1.1.0 - REPL
|
|
25
28
|
|
|
26
29
|
- REPL mode added
|
|
27
30
|
|
|
31
|
+
#### 1.1.2 - BUG-002C-100-MmP
|
|
32
|
+
|
|
33
|
+
- BUG-002C-100-MmP: Dist folder is not created
|
|
34
|
+
|
|
28
35
|
#### 1.1.1 - BUG-002B-101-MmP
|
|
29
36
|
|
|
30
37
|
- BUG-002B-100-MmP: The errors in the CLI shows 'undefined'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import readline from "readline";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import { execute } from "../../../core/index.js";
|
|
4
|
+
export function repl() {
|
|
5
|
+
console.log(chalk.yellow("Orange Cat REPL v1.0.0"));
|
|
6
|
+
const rl = readline.createInterface({
|
|
7
|
+
input: process.stdin,
|
|
8
|
+
output: process.stdout,
|
|
9
|
+
prompt: chalk.cyan("ocat> "),
|
|
10
|
+
});
|
|
11
|
+
rl.prompt();
|
|
12
|
+
rl.on("line", (line) => {
|
|
13
|
+
const input = line.trim();
|
|
14
|
+
// comandos internos
|
|
15
|
+
if (input === ".exit") {
|
|
16
|
+
rl.close();
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
if (input === ".help") {
|
|
20
|
+
console.log(`
|
|
21
|
+
.exit Exit REPL
|
|
22
|
+
.clear Clear screen
|
|
23
|
+
`);
|
|
24
|
+
rl.prompt();
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (input === ".clear") {
|
|
28
|
+
console.clear();
|
|
29
|
+
rl.prompt();
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
execute(input);
|
|
33
|
+
rl.prompt();
|
|
34
|
+
});
|
|
35
|
+
rl.on("close", () => {
|
|
36
|
+
console.log("\nBye!");
|
|
37
|
+
process.exit(0);
|
|
38
|
+
});
|
|
39
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { execute } from "../../../core/index.js";
|
|
2
|
+
import { ExtensionError } from "../../../shared/manager/errors/io/extension.js";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import fs from "fs";
|
|
5
|
+
import { FileDoesntExistError } from "../../../shared/manager/errors/io/file.js";
|
|
6
|
+
export function runfile(file, options) {
|
|
7
|
+
if (!file.endsWith(".ocat") && !options.force) {
|
|
8
|
+
new ExtensionError("File must be a .ocat file. Use -f to force execution with other extensions").throw();
|
|
9
|
+
}
|
|
10
|
+
if (options.force) {
|
|
11
|
+
console.log(chalk.blue(`Running in force mode`));
|
|
12
|
+
}
|
|
13
|
+
if (!fs.existsSync(file)) {
|
|
14
|
+
new FileDoesntExistError(`File ${file} doesn't exist`)
|
|
15
|
+
.throw();
|
|
16
|
+
}
|
|
17
|
+
const fileText = fs.readFileSync(file, "utf8");
|
|
18
|
+
execute(fileText);
|
|
19
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { runfile } from "./commands/index.js";
|
|
4
|
+
import { repl } from "./commands/index.js";
|
|
5
|
+
const program = new Command();
|
|
6
|
+
program
|
|
7
|
+
.name("ocat")
|
|
8
|
+
.description("The Orange Cat language compiler")
|
|
9
|
+
.version("1.0.0");
|
|
10
|
+
program
|
|
11
|
+
.command("run")
|
|
12
|
+
.description("Run a file. This file must be a .ocat file")
|
|
13
|
+
.argument("<file>", "The file to run")
|
|
14
|
+
.option("-f, --force", "Force the execution with other extensions")
|
|
15
|
+
.action(runfile);
|
|
16
|
+
program
|
|
17
|
+
.command("inline")
|
|
18
|
+
.description("An REPL for the Orange Cat language")
|
|
19
|
+
.action(repl);
|
|
20
|
+
program.parse();
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import inquirer from "inquirer";
|
|
2
|
+
import chalk, {} from "chalk";
|
|
3
|
+
import { chalkText } from "../../utils/chalkText.js";
|
|
4
|
+
import { createProject } from "../../../project/index.js";
|
|
5
|
+
import { fromCamelToDash } from "../../../shared/utils/strformat.js";
|
|
6
|
+
export async function init() {
|
|
7
|
+
const projectTypes = [{ name: "App", color: chalk.red }, { name: "Lib", color: chalk.yellow }];
|
|
8
|
+
const answers = await inquirer.prompt([
|
|
9
|
+
{
|
|
10
|
+
type: "input",
|
|
11
|
+
name: "name",
|
|
12
|
+
message: "How do you want to name your project?",
|
|
13
|
+
default: "myProject",
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
type: "input",
|
|
17
|
+
name: "dir",
|
|
18
|
+
message: "Where do you want to create your project?",
|
|
19
|
+
default: (answers) => answers.name,
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
type: "input",
|
|
23
|
+
name: "id",
|
|
24
|
+
message: "What is your project ID?",
|
|
25
|
+
default: (answers) => fromCamelToDash(answers.name),
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
type: "select",
|
|
29
|
+
name: "type",
|
|
30
|
+
message: "What type of project do you want to create?",
|
|
31
|
+
choices: projectTypes
|
|
32
|
+
.map((choice) => chalkText(choice.name, choice.color)),
|
|
33
|
+
}
|
|
34
|
+
]);
|
|
35
|
+
createProject({
|
|
36
|
+
name: answers.name,
|
|
37
|
+
dir: answers.dir,
|
|
38
|
+
type: answers.type,
|
|
39
|
+
id: answers.id,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import { readJSON } from "../../../shared/io/json.js";
|
|
3
|
+
import { runfile } from "../../ocat/commands/index.js";
|
|
4
|
+
import * as context from "../../../shared/context/globalContext.js";
|
|
5
|
+
import { defaultLoggerConfig, LoggerService } from "../../../core/services/log.service.js";
|
|
6
|
+
export function run() {
|
|
7
|
+
const projectConfig = readJSON(path.join(".ocat", "config.json"));
|
|
8
|
+
context.set("isProject", true);
|
|
9
|
+
context.set("projectConfig", projectConfig);
|
|
10
|
+
context.set("services", {});
|
|
11
|
+
context.useObject("services", services => {
|
|
12
|
+
return {
|
|
13
|
+
log: new LoggerService(defaultLoggerConfig),
|
|
14
|
+
};
|
|
15
|
+
});
|
|
16
|
+
runfile(projectConfig.main, { force: false });
|
|
17
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { init, run } from "./commands/index.js";
|
|
4
|
+
const program = new Command();
|
|
5
|
+
program.name("ocm").description("The Orange Cat manager").version("1.0.0");
|
|
6
|
+
program
|
|
7
|
+
.command("initialize")
|
|
8
|
+
.alias("init")
|
|
9
|
+
.description("Initialize a new Orange Cat project")
|
|
10
|
+
.action(async () => { await init(); });
|
|
11
|
+
program
|
|
12
|
+
.command("run")
|
|
13
|
+
.description("Run the project")
|
|
14
|
+
.action(run);
|
|
15
|
+
program.parse();
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { createCoreContext } from "../context/coreContext.js";
|
|
2
|
+
import { ValueType } from "../../shared/models/value.js";
|
|
3
|
+
import { StatementKind } from "./types/base/index.js";
|
|
4
|
+
export function buildAst(cst) {
|
|
5
|
+
const statements = cst.children.statement ?? [];
|
|
6
|
+
const ast = [];
|
|
7
|
+
for (const statement of statements) {
|
|
8
|
+
let __tmp = null;
|
|
9
|
+
const __$tmp = () => { if (__tmp)
|
|
10
|
+
ast.push(__tmp); };
|
|
11
|
+
__tmp = printStatement(statement);
|
|
12
|
+
__$tmp();
|
|
13
|
+
__tmp = variableStatement(statement);
|
|
14
|
+
__$tmp();
|
|
15
|
+
__tmp = functionStatement(statement);
|
|
16
|
+
__$tmp();
|
|
17
|
+
__tmp = callStatement(statement);
|
|
18
|
+
__$tmp();
|
|
19
|
+
}
|
|
20
|
+
return ast;
|
|
21
|
+
}
|
|
22
|
+
const printStatement = (statement) => {
|
|
23
|
+
const printStmt = statement.children.printStatement?.[0];
|
|
24
|
+
if (printStmt) {
|
|
25
|
+
const strToken = printStmt.children.StringLiteral?.[0];
|
|
26
|
+
if (strToken) {
|
|
27
|
+
return {
|
|
28
|
+
kind: StatementKind.PrintStatement,
|
|
29
|
+
sourceInfo: {
|
|
30
|
+
tokens: printStmt.children,
|
|
31
|
+
cstNode: printStmt,
|
|
32
|
+
startLine: printStmt.startLine,
|
|
33
|
+
endLine: printStmt.endLine,
|
|
34
|
+
startColumn: printStmt.startColumn,
|
|
35
|
+
endColumn: printStmt.endColumn,
|
|
36
|
+
},
|
|
37
|
+
value: {
|
|
38
|
+
value: strToken.image,
|
|
39
|
+
type: ValueType.String,
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
const idToken = printStmt.children.Identifier?.[0];
|
|
44
|
+
if (idToken) {
|
|
45
|
+
return {
|
|
46
|
+
kind: StatementKind.PrintStatement,
|
|
47
|
+
sourceInfo: {
|
|
48
|
+
tokens: printStmt.children,
|
|
49
|
+
cstNode: printStmt,
|
|
50
|
+
startLine: printStmt.startLine,
|
|
51
|
+
endLine: printStmt.endLine,
|
|
52
|
+
startColumn: printStmt.startColumn,
|
|
53
|
+
endColumn: printStmt.endColumn,
|
|
54
|
+
},
|
|
55
|
+
value: {
|
|
56
|
+
value: idToken.image,
|
|
57
|
+
type: ValueType.Identifier,
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return null;
|
|
63
|
+
};
|
|
64
|
+
const variableStatement = (statement) => {
|
|
65
|
+
const varStmt = statement.children.variableStatement?.[0];
|
|
66
|
+
if (varStmt) {
|
|
67
|
+
const typeToken = varStmt.children.VarType?.[0];
|
|
68
|
+
const idToken = varStmt.children.Identifier?.[0];
|
|
69
|
+
const valueToken = varStmt.children.StringLiteral?.[0] ??
|
|
70
|
+
varStmt.children.NumberLiteral?.[0] ??
|
|
71
|
+
varStmt.children.BooleanLiteral?.[0];
|
|
72
|
+
if (!typeToken || !idToken || !valueToken)
|
|
73
|
+
return null;
|
|
74
|
+
const setToken = varStmt.children.Set?.[0];
|
|
75
|
+
const constToken = varStmt.children.Const?.[0];
|
|
76
|
+
const type = typeToken.image;
|
|
77
|
+
const id = idToken.image;
|
|
78
|
+
const value = valueToken.image;
|
|
79
|
+
return {
|
|
80
|
+
kind: StatementKind.VariableStatement,
|
|
81
|
+
sourceInfo: {
|
|
82
|
+
tokens: varStmt.children,
|
|
83
|
+
cstNode: varStmt,
|
|
84
|
+
startLine: varStmt.startLine,
|
|
85
|
+
endLine: varStmt.endLine,
|
|
86
|
+
startColumn: varStmt.startColumn,
|
|
87
|
+
endColumn: varStmt.endColumn,
|
|
88
|
+
},
|
|
89
|
+
id,
|
|
90
|
+
var: {
|
|
91
|
+
type,
|
|
92
|
+
value,
|
|
93
|
+
props: {
|
|
94
|
+
isConst: !!constToken,
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
set: !!setToken,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
return null;
|
|
101
|
+
};
|
|
102
|
+
const functionStatement = (statement) => {
|
|
103
|
+
const funcStmt = statement.children.functionStatement?.[0];
|
|
104
|
+
if (funcStmt) {
|
|
105
|
+
const idToken = funcStmt.children.Identifier?.[0];
|
|
106
|
+
if (!idToken)
|
|
107
|
+
return null;
|
|
108
|
+
const id = idToken.image;
|
|
109
|
+
const body = buildAst(funcStmt);
|
|
110
|
+
return {
|
|
111
|
+
kind: StatementKind.FunctionStatement,
|
|
112
|
+
sourceInfo: {
|
|
113
|
+
tokens: funcStmt.children,
|
|
114
|
+
cstNode: funcStmt,
|
|
115
|
+
startLine: funcStmt.startLine,
|
|
116
|
+
endLine: funcStmt.endLine,
|
|
117
|
+
startColumn: funcStmt.startColumn,
|
|
118
|
+
endColumn: funcStmt.endColumn,
|
|
119
|
+
},
|
|
120
|
+
id,
|
|
121
|
+
func: {
|
|
122
|
+
body,
|
|
123
|
+
scope: createCoreContext(),
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
return null;
|
|
128
|
+
};
|
|
129
|
+
const callStatement = (statement) => {
|
|
130
|
+
const callStmt = statement.children.callStatement?.[0];
|
|
131
|
+
if (callStmt) {
|
|
132
|
+
const idToken = callStmt.children.Identifier?.[0];
|
|
133
|
+
if (!idToken)
|
|
134
|
+
return null;
|
|
135
|
+
const id = idToken.image;
|
|
136
|
+
return {
|
|
137
|
+
kind: StatementKind.CallStatement,
|
|
138
|
+
sourceInfo: {
|
|
139
|
+
tokens: callStmt.children,
|
|
140
|
+
cstNode: callStmt,
|
|
141
|
+
startLine: callStmt.startLine,
|
|
142
|
+
endLine: callStmt.endLine,
|
|
143
|
+
startColumn: callStmt.startColumn,
|
|
144
|
+
endColumn: callStmt.endColumn,
|
|
145
|
+
},
|
|
146
|
+
id,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
return null;
|
|
150
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export var StatementKind;
|
|
2
|
+
(function (StatementKind) {
|
|
3
|
+
StatementKind[StatementKind["PrintStatement"] = 0] = "PrintStatement";
|
|
4
|
+
StatementKind[StatementKind["VariableStatement"] = 1] = "VariableStatement";
|
|
5
|
+
StatementKind[StatementKind["FunctionStatement"] = 2] = "FunctionStatement";
|
|
6
|
+
StatementKind[StatementKind["CallStatement"] = 3] = "CallStatement";
|
|
7
|
+
})(StatementKind || (StatementKind = {}));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ocatLexer } from "./lexer/tokens.js";
|
|
2
|
+
import { OcatParser } from "./parser/parser.js";
|
|
3
|
+
import { run } from "./runner/runner.js";
|
|
4
|
+
import { createCoreContext } from "./context/coreContext.js";
|
|
5
|
+
import { buildAst } from "./ast/astBuilder.js";
|
|
6
|
+
import * as ctx from "../shared/context/globalContext.js";
|
|
7
|
+
import fs from "fs";
|
|
8
|
+
export function execute(code) {
|
|
9
|
+
const lexingResult = ocatLexer.tokenize(code);
|
|
10
|
+
const parser = new OcatParser();
|
|
11
|
+
parser.input = lexingResult.tokens;
|
|
12
|
+
const cst = parser.program();
|
|
13
|
+
const ast = buildAst(cst);
|
|
14
|
+
process.on("exit", () => {
|
|
15
|
+
if (ctx.get("isProject")) {
|
|
16
|
+
const logs = ctx.get("services").log.toString();
|
|
17
|
+
fs.writeFileSync(".ocat/logs.txt", logs);
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
const context = createCoreContext();
|
|
21
|
+
run(ast, context);
|
|
22
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createToken, Lexer } from "chevrotain";
|
|
2
|
+
export const LineComment = createToken({
|
|
3
|
+
name: "LineComment",
|
|
4
|
+
pattern: /\/\/[^\n]*/,
|
|
5
|
+
group: Lexer.SKIPPED,
|
|
6
|
+
});
|
|
7
|
+
export const BlockComment = createToken({
|
|
8
|
+
name: "BlockComment",
|
|
9
|
+
pattern: /\/\*[\s\S]*?\*\//,
|
|
10
|
+
group: Lexer.SKIPPED,
|
|
11
|
+
});
|
|
12
|
+
export const comments = [LineComment, BlockComment];
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createToken } from "chevrotain";
|
|
2
|
+
export const LeftParen = createToken({ name: "LeftParen", pattern: /\(/ });
|
|
3
|
+
export const RightParen = createToken({ name: "RightParen", pattern: /\)/ });
|
|
4
|
+
export const LeftBrace = createToken({ name: "LeftBrace", pattern: /\{/ });
|
|
5
|
+
export const RightBrace = createToken({ name: "RightBrace", pattern: /\}/ });
|
|
6
|
+
export const LeftBracket = createToken({ name: "LeftBracket", pattern: /\[/ });
|
|
7
|
+
export const RightBracket = createToken({ name: "RightBracket", pattern: /\]/ });
|
|
8
|
+
export const LeftTag = createToken({ name: "LeftTag", pattern: /</ });
|
|
9
|
+
export const RightTag = createToken({ name: "RightTag", pattern: />/ });
|
|
10
|
+
export const Comma = createToken({ name: "Comma", pattern: /,/ });
|
|
11
|
+
export const delimiters = [LeftParen, RightParen, LeftBrace, RightBrace, LeftBracket, RightBracket, LeftTag, RightTag, Comma];
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export * from "./ignored.js";
|
|
2
|
+
export * from "./comments.js";
|
|
3
|
+
export * from "./keywords.js";
|
|
4
|
+
export * from "./literals.js";
|
|
5
|
+
export * from "./delimiters.js";
|
|
6
|
+
export * from "./vars.js";
|
|
7
|
+
export * from "./operators.js";
|
|
8
|
+
export * from "./attrs.js";
|
|
9
|
+
export * from "./function.js";
|
|
10
|
+
import { ignored } from "./ignored.js";
|
|
11
|
+
import { comments } from "./comments.js";
|
|
12
|
+
import { keywords } from "./keywords.js";
|
|
13
|
+
import { literals } from "./literals.js";
|
|
14
|
+
import { delimiters } from "./delimiters.js";
|
|
15
|
+
import { variablesAndConstants } from "./vars.js";
|
|
16
|
+
import { operators } from "./operators.js";
|
|
17
|
+
import { attributes } from "./attrs.js";
|
|
18
|
+
import { functions } from "./function.js";
|
|
19
|
+
export const allTokens = [
|
|
20
|
+
...ignored,
|
|
21
|
+
...comments,
|
|
22
|
+
...keywords,
|
|
23
|
+
...attributes,
|
|
24
|
+
...functions,
|
|
25
|
+
...literals,
|
|
26
|
+
...delimiters,
|
|
27
|
+
...variablesAndConstants,
|
|
28
|
+
...operators,
|
|
29
|
+
];
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { createToken } from "chevrotain";
|
|
2
|
+
export const StringLiteral = createToken({
|
|
3
|
+
name: "StringLiteral",
|
|
4
|
+
pattern: /"(?:[^\\"]|\\.)*"/,
|
|
5
|
+
});
|
|
6
|
+
export const NumberLiteral = createToken({
|
|
7
|
+
name: "NumberLiteral",
|
|
8
|
+
pattern: /\d+(\.\d+)?/,
|
|
9
|
+
});
|
|
10
|
+
export const BooleanLiteral = createToken({
|
|
11
|
+
name: "BooleanLiteral",
|
|
12
|
+
pattern: /true|false/,
|
|
13
|
+
});
|
|
14
|
+
export const literals = [StringLiteral, NumberLiteral, BooleanLiteral];
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createToken } from "chevrotain";
|
|
2
|
+
import { ValueType } from "../../../shared/models/value.js";
|
|
3
|
+
export const VarType = createToken({
|
|
4
|
+
name: "VarType",
|
|
5
|
+
pattern: new RegExp(Object.values(ValueType).join("|")),
|
|
6
|
+
});
|
|
7
|
+
export const Set = createToken({ name: "Set", pattern: /set/ });
|
|
8
|
+
export const Identifier = createToken({
|
|
9
|
+
name: "Identifier",
|
|
10
|
+
pattern: /[a-zA-Z_]\w*/,
|
|
11
|
+
});
|
|
12
|
+
export const variablesAndConstants = [VarType, Set, Identifier];
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { CstParser } from "chevrotain";
|
|
2
|
+
import { ValueType } from "../../shared/models/value.js";
|
|
3
|
+
import * as token from "../lexer/tokens/index.js";
|
|
4
|
+
export class OcatParser extends CstParser {
|
|
5
|
+
constructor() {
|
|
6
|
+
super(token.allTokens, {
|
|
7
|
+
recoveryEnabled: true,
|
|
8
|
+
});
|
|
9
|
+
this.performSelfAnalysis();
|
|
10
|
+
}
|
|
11
|
+
program = this.RULE("program", () => {
|
|
12
|
+
this.MANY(() => this.SUBRULE(this.statement));
|
|
13
|
+
});
|
|
14
|
+
statement = this.RULE("statement", () => {
|
|
15
|
+
this.OR([
|
|
16
|
+
{
|
|
17
|
+
ALT: () => this.SUBRULE(this.printStatement, {
|
|
18
|
+
LABEL: "printStatement",
|
|
19
|
+
}),
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
ALT: () => this.SUBRULE(this.variableStatement, {
|
|
23
|
+
LABEL: "variableStatement",
|
|
24
|
+
}),
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
ALT: () => this.SUBRULE(this.functionStatement, {
|
|
28
|
+
LABEL: "functionStatement",
|
|
29
|
+
}),
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
ALT: () => this.SUBRULE(this.callStatement, {
|
|
33
|
+
LABEL: "callStatement",
|
|
34
|
+
}),
|
|
35
|
+
},
|
|
36
|
+
]);
|
|
37
|
+
});
|
|
38
|
+
printStatement = this.RULE("printStatement", () => {
|
|
39
|
+
this.CONSUME(token.Output);
|
|
40
|
+
this.CONSUME(token.LeftParen);
|
|
41
|
+
this.OR([
|
|
42
|
+
...token.literals.map((lit) => ({
|
|
43
|
+
ALT: () => this.CONSUME(lit, { LABEL: lit.name }),
|
|
44
|
+
})),
|
|
45
|
+
{
|
|
46
|
+
ALT: () => this.CONSUME(token.Identifier, { LABEL: "Identifier" }),
|
|
47
|
+
},
|
|
48
|
+
]);
|
|
49
|
+
this.CONSUME(token.RightParen);
|
|
50
|
+
});
|
|
51
|
+
variableStatement = this.RULE("variableStatement", () => {
|
|
52
|
+
this.OPTION(() => {
|
|
53
|
+
this.OR([
|
|
54
|
+
{ ALT: () => this.CONSUME(token.Set, { LABEL: "Set" }) },
|
|
55
|
+
{ ALT: () => this.CONSUME(token.Const, { LABEL: "Const" }) },
|
|
56
|
+
]);
|
|
57
|
+
});
|
|
58
|
+
const type = this.CONSUME(token.VarType).image;
|
|
59
|
+
this.CONSUME(token.Identifier);
|
|
60
|
+
this.CONSUME(token.Assign);
|
|
61
|
+
switch (type) {
|
|
62
|
+
case ValueType.String:
|
|
63
|
+
this.CONSUME(token.StringLiteral);
|
|
64
|
+
break;
|
|
65
|
+
case ValueType.Number:
|
|
66
|
+
this.CONSUME(token.NumberLiteral);
|
|
67
|
+
break;
|
|
68
|
+
case ValueType.Boolean:
|
|
69
|
+
this.CONSUME(token.BooleanLiteral);
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
functionStatement = this.RULE("functionStatement", () => {
|
|
74
|
+
this.CONSUME(token.Function);
|
|
75
|
+
this.CONSUME(token.Identifier);
|
|
76
|
+
this.CONSUME(token.LeftBrace);
|
|
77
|
+
this.MANY(() => this.SUBRULE(this.statement));
|
|
78
|
+
this.CONSUME(token.RightBrace);
|
|
79
|
+
});
|
|
80
|
+
callStatement = this.RULE("callStatement", () => {
|
|
81
|
+
this.CONSUME(token.Call);
|
|
82
|
+
this.CONSUME(token.Identifier);
|
|
83
|
+
});
|
|
84
|
+
}
|