darijacode 0.2.0
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/LICENSE +130 -0
- package/README.md +78 -0
- package/dist/cli.js +77 -0
- package/dist/compiler/ast.js +2 -0
- package/dist/compiler/checker/expressions.js +248 -0
- package/dist/compiler/checker/index.js +45 -0
- package/dist/compiler/checker/scope.js +57 -0
- package/dist/compiler/checker/statements.js +255 -0
- package/dist/compiler/checker/types.js +47 -0
- package/dist/compiler/codegen/codegen.js +122 -0
- package/dist/compiler/codegen/ctype.js +23 -0
- package/dist/compiler/codegen/expr.js +63 -0
- package/dist/compiler/codegen/infertype.js +70 -0
- package/dist/compiler/codegen/runtime.js +24 -0
- package/dist/compiler/codegen/scope.js +19 -0
- package/dist/compiler/codegen/stmts.js +90 -0
- package/dist/compiler/codegen/types.js +2 -0
- package/dist/compiler/compiler.js +115 -0
- package/dist/compiler/errors.js +59 -0
- package/dist/compiler/index.js +69 -0
- package/dist/compiler/lexer.js +303 -0
- package/dist/compiler/parser.js +513 -0
- package/dist/compiler/tokens.js +68 -0
- package/dist/utils/showType.js +10 -0
- package/package.json +58 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# DarijaCode Community License (DCL) v1.0
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025βpresent, krnl0xsns1nk and DarijaCode contributors.
|
|
4
|
+
|
|
5
|
+
This is a custom license. It is not a standard OSI-approved license β read
|
|
6
|
+
it, don't assume it matches something you've seen before.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Plain-language summary (not a substitute for the terms below)
|
|
11
|
+
|
|
12
|
+
- Install it, run it, change it, learn from it, do basically whatever you want with it.
|
|
13
|
+
- Build extra tools around it β an IDE, docs, an editor, error tooling, new language features β as your own separate project.
|
|
14
|
+
- Fork it, fix it, ship your own build.
|
|
15
|
+
|
|
16
|
+
- Don't take this project and present it as something you created. Keep the credit where it belongs.
|
|
17
|
+
- Don't publish a fork and call it "DarijaCode" as if it's the original, official project.
|
|
18
|
+
|
|
19
|
+
- ποΈ If the maintainer goes quiet for a long stretch, the community is free to keep this project alive β fixes, releases, all of it β until the maintainer returns, if ever.
|
|
20
|
+
|
|
21
|
+
If anything below conflicts with this summary, the terms below control.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## 1. Definitions
|
|
26
|
+
|
|
27
|
+
- **"The Project"** means the DarijaCode source code, documentation, and
|
|
28
|
+
associated files in this repository.
|
|
29
|
+
- **"You"** means anyone using, copying, modifying, or distributing the
|
|
30
|
+
Project under this license.
|
|
31
|
+
- **"Derivative Tool"** means a separate piece of software that works with
|
|
32
|
+
or alongside the Project β an editor, IDE plugin, documentation site,
|
|
33
|
+
linter, error formatter, package manager frontend, new-feature add-on,
|
|
34
|
+
and so on β but is not itself a redistribution of the Project as a
|
|
35
|
+
whole.
|
|
36
|
+
- **"The Maintainer"** means krnl0xsns1nk, the original author of the
|
|
37
|
+
Project, or anyone the Maintainer formally designates in writing.
|
|
38
|
+
|
|
39
|
+
## 2. What you're permitted to do
|
|
40
|
+
|
|
41
|
+
You are granted a free, worldwide, royalty-free license to:
|
|
42
|
+
|
|
43
|
+
1. **Use** the Project for any purpose, personal or commercial.
|
|
44
|
+
2. **Study and learn from** the source code.
|
|
45
|
+
3. **Modify** the source code, for your own use or to contribute back.
|
|
46
|
+
4. **Copy and redistribute** the Project, or your modified version of it,
|
|
47
|
+
subject to Section 3 (Attribution) and Section 4 (No Misrepresentation)
|
|
48
|
+
below.
|
|
49
|
+
5. **Build and distribute Derivative Tools** β an IDE, a docs site, a code
|
|
50
|
+
editor, error-handling libraries, new language features, package
|
|
51
|
+
registries, and so on β under any license you choose, including
|
|
52
|
+
proprietary or commercial ones, as long as the Derivative Tool does not
|
|
53
|
+
itself claim to *be* DarijaCode (see Section 4).
|
|
54
|
+
|
|
55
|
+
## 3. Attribution
|
|
56
|
+
|
|
57
|
+
Any copy or substantial redistribution of the Project, modified or not,
|
|
58
|
+
must:
|
|
59
|
+
|
|
60
|
+
1. Keep this license file intact.
|
|
61
|
+
2. Retain a visible credit to the original author and a link to the
|
|
62
|
+
original repository, in the copy's README or an equally prominent
|
|
63
|
+
location.
|
|
64
|
+
3. Clearly state, if modified, that changes were made.
|
|
65
|
+
|
|
66
|
+
## 4. No misrepresentation of authorship or origin
|
|
67
|
+
|
|
68
|
+
This is the core restriction of this license, and the main reason it
|
|
69
|
+
isn't a plain MIT/ISC license:
|
|
70
|
+
|
|
71
|
+
1. You may **not** present the Project, or a fork of it, as your own
|
|
72
|
+
original creation.
|
|
73
|
+
2. You may **not** publish a fork, rebrand, or redistribution in a way
|
|
74
|
+
that implies it is the official or original DarijaCode project, unless
|
|
75
|
+
you are the Maintainer or have been designated as a steward under
|
|
76
|
+
Section 5.
|
|
77
|
+
3. Forks are welcome and encouraged, but must be clearly labeled as a
|
|
78
|
+
fork or derivative (e.g. "MyLang, a DarijaCode fork") β not presented
|
|
79
|
+
as if it were the primary project or as if you created it from
|
|
80
|
+
scratch.
|
|
81
|
+
4. Derivative Tools (Section 2.5) are exempt from labeling themselves as
|
|
82
|
+
a "fork," since they are separate works β but they may not claim to
|
|
83
|
+
have authored the DarijaCode language or compiler itself.
|
|
84
|
+
|
|
85
|
+
## 5. Maintainer inactivity and community stewardship
|
|
86
|
+
|
|
87
|
+
This project is maintained by one person, for fun, with no promises about
|
|
88
|
+
how long that continues. So:
|
|
89
|
+
|
|
90
|
+
1. **Active** means the Maintainer has made at least one commit to the
|
|
91
|
+
main repository within the preceding **6 months**.
|
|
92
|
+
2. If the Project becomes **inactive** by that definition, the community
|
|
93
|
+
is explicitly permitted, without needing to ask, to:
|
|
94
|
+
- Fork the repository and continue development, bug fixes, and
|
|
95
|
+
releases under this same license.
|
|
96
|
+
- Coordinate a community-maintained fork as the de facto continuation
|
|
97
|
+
of the project, clearly labeled as community-maintained (per
|
|
98
|
+
Section 4.3) for as long as the Maintainer remains inactive.
|
|
99
|
+
3. If the Maintainer resumes committing to the original repository, the
|
|
100
|
+
original repository remains the canonical project, and community
|
|
101
|
+
forks are expected to acknowledge this and may merge their work back
|
|
102
|
+
if the Maintainer is willing.
|
|
103
|
+
4. This clause does not transfer copyright or ownership β it is a
|
|
104
|
+
standing permission to fork, maintain, and release, granted in
|
|
105
|
+
advance, so the community never has to wait for a response that may
|
|
106
|
+
never come.
|
|
107
|
+
|
|
108
|
+
## 6. No warranty
|
|
109
|
+
|
|
110
|
+
The Project is provided "as is," without warranty of any kind, express or
|
|
111
|
+
implied, including but not limited to warranties of merchantability,
|
|
112
|
+
fitness for a particular purpose, and non-infringement. In no event shall
|
|
113
|
+
the Maintainer or contributors be liable for any claim, damages, or other
|
|
114
|
+
liability arising from the Project or its use.
|
|
115
|
+
|
|
116
|
+
## 7. Termination
|
|
117
|
+
|
|
118
|
+
Your rights under this license terminate automatically if you violate
|
|
119
|
+
Section 4 (No Misrepresentation) and do not correct the violation within
|
|
120
|
+
30 days of being notified. All other rights survive termination for
|
|
121
|
+
copies already lawfully distributed.
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
*This license was written in plain terms to match how the Maintainer
|
|
126
|
+
actually wants this project used. If you need a legally binding
|
|
127
|
+
interpretation for a specific situation (e.g. enterprise use, a
|
|
128
|
+
large-scale fork, a dispute), consult a lawyer β this document has not
|
|
129
|
+
been reviewed by one.*
|
|
130
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# ποΈ DarijaCode
|
|
4
|
+
|
|
5
|
+
A programming language and compiler written for fun, using Moroccan Darija.
|
|
6
|
+
|
|
7
|
+
[](https://github.com/krnl0xsns1nk/DarijaCode)
|
|
8
|
+
[](https://www.typescriptlang.org/)
|
|
9
|
+
[](LICENSE)
|
|
10
|
+
[](https://github.com/krnl0xsns1nk/DarijaCode)
|
|
11
|
+
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
### Quick install
|
|
19
|
+
|
|
20
|
+
Linux / Termux:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
curl -fsSL https://raw.githubusercontent.com/krnl0xsns1nk/DarijaCode/main/scripts/install.sh | sh
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
> **DarijaCode is a hobby project built for learning compiler development and experimenting with a programming language based on Moroccan Darija.**
|
|
30
|
+
>
|
|
31
|
+
> It is **not** trying to replace JavaScript, Python, C, or any existing language.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Why?
|
|
36
|
+
|
|
37
|
+
The goal isn't simply replacing English keywords.
|
|
38
|
+
|
|
39
|
+
The goal is building a complete programming ecosystem where everything speaks Darija:
|
|
40
|
+
|
|
41
|
+
- lexer
|
|
42
|
+
- parser
|
|
43
|
+
- semantic checker
|
|
44
|
+
- native compiler
|
|
45
|
+
- CLI
|
|
46
|
+
- runtime
|
|
47
|
+
- package manager *(planned)*
|
|
48
|
+
- standard library *(planned)*
|
|
49
|
+
- compiler errors written in Darija
|
|
50
|
+
|
|
51
|
+
For example:
|
|
52
|
+
|
|
53
|
+
```drj
|
|
54
|
+
kteb("Salam");
|
|
55
|
+
```
|
|
56
|
+
and when something goes wrong, the compiler also responds in Darija:
|
|
57
|
+
- take a real example of mine :
|
|
58
|
+
|
|
59
|
+
<pre style="background:#0d1117; color:#c9d1d9; padding:16px; border-radius:8px; font-family:monospace; overflow-x:auto">
|
|
60
|
+
<span style="color:#7ee787">user@localhost</span> <span style="color:#a5d6ff">~/projects/DarijaCode</span> <span style="color:#ffa657">(masterβ)</span>
|
|
61
|
+
<span style="color:#7ee787">$</span> <span style="color:#ffa657">bat ex.drj</span>
|
|
62
|
+
|
|
63
|
+
<span style="color:#8b949e">β</span> <span style="color:#8b949e">File: ex.drj</span>
|
|
64
|
+
<span style="color:#8b949e">βββΌββββββββββββββββββββββββββββββββββββββββ</span>
|
|
65
|
+
<span style="color:#8b949e">1</span> <span style="color:#8b949e">β</span> <span style="color:#d2a8ff">dir</span> <span style="color:#79c0ff">name</span> <span style="color:#c9d1d9">:</span> <span style="color:#79c0ff">ra9m</span> <span style="color:#c9d1d9">=</span> <span style="color:#a5d6ff">"krnl0xsns"</span><span style="color:#c9d1d9">;</span>
|
|
66
|
+
<span style="color:#8b949e">2</span> <span style="color:#8b949e">β</span> <span style="color:#d2a8ff">kteb</span><span style="color:#c9d1d9">(</span><span style="color:#79c0ff">name</span><span style="color:#c9d1d9">);</span>
|
|
67
|
+
<span style="color:#8b949e">βββ΄ββββββββββββββββββββββββββββββββββββββββ</span>
|
|
68
|
+
|
|
69
|
+
<span style="color:#7ee787">user@localhost</span> <span style="color:#a5d6ff">~/projects/DarijaCode</span> <span style="color:#ffa657">(masterβ)</span>
|
|
70
|
+
<span style="color:#7ee787">$</span> <span style="color:#ffa657">drj run ex.drj</span>
|
|
71
|
+
<span style="color:#f85149; font-weight:bold">DarijaCode error[checker:DCE15]</span> <span style="color:#ffa657">twa93na ra9m, wlkin l9ina nass</span>
|
|
72
|
+
<span style="color:#58a6ff">--> /data/data/com.termux/files/home/projects/DarijaCode/ex.drj:1:1</span>
|
|
73
|
+
<span style="color:#8b949e">1</span> <span style="color:#8b949e">β</span> <span style="color:#d2a8ff">dir</span> <span style="color:#79c0ff">name</span> <span style="color:#c9d1d9">:</span> <span style="color:#79c0ff">ra9m</span> <span style="color:#c9d1d9">=</span> <span style="color:#a5d6ff">"krnl0xsns"</span><span style="color:#c9d1d9">;</span>
|
|
74
|
+
<span style="color:#8b949e">β</span> <span style="color:#f85149">^</span>
|
|
75
|
+
<span style="color:#a371f7">jrb/chof:</span> <span style="color:#ffa657">ach ban link tstkhdm ra9m fbalst nass</span>
|
|
76
|
+
</pre>
|
|
77
|
+
|
|
78
|
+
- see docs/error_codes.md for more info about these codes.
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
+
};
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
const fs_1 = require("fs");
|
|
8
|
+
const path_1 = require("path");
|
|
9
|
+
const index_1 = __importDefault(require("./compiler/index"));
|
|
10
|
+
const VERSION = "0.2.0";
|
|
11
|
+
function error(message) {
|
|
12
|
+
console.error(`β ${message}`);
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
function success(message) {
|
|
16
|
+
console.log(`β ${message}`);
|
|
17
|
+
}
|
|
18
|
+
function validateFile(file) {
|
|
19
|
+
const path = (0, path_1.resolve)(file);
|
|
20
|
+
if (!(0, fs_1.existsSync)(path)) {
|
|
21
|
+
error(`milaf mkaynch: ${path}`);
|
|
22
|
+
}
|
|
23
|
+
if ((0, path_1.extname)(path) !== ".drj") {
|
|
24
|
+
error(`twa93t milf b .drj`);
|
|
25
|
+
}
|
|
26
|
+
return path;
|
|
27
|
+
}
|
|
28
|
+
function help() {
|
|
29
|
+
console.log(`
|
|
30
|
+
DarijaCode ${VERSION}
|
|
31
|
+
|
|
32
|
+
listikhdam:
|
|
33
|
+
drj run <file>
|
|
34
|
+
drj build <file>
|
|
35
|
+
drj check <file>
|
|
36
|
+
|
|
37
|
+
lawamir:
|
|
38
|
+
run Compile and execute
|
|
39
|
+
build Compile to binary
|
|
40
|
+
check Check syntax and types
|
|
41
|
+
`);
|
|
42
|
+
}
|
|
43
|
+
async function main() {
|
|
44
|
+
const args = process.argv.slice(2);
|
|
45
|
+
if (args.length === 0) {
|
|
46
|
+
help();
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const command = args[0];
|
|
50
|
+
const v = ["--verion", "version", "-v", "--v", "-version", "lisdar", "--isdar"];
|
|
51
|
+
if (v.includes(command)) {
|
|
52
|
+
console.log(VERSION);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const file = args[1];
|
|
56
|
+
if (!file) {
|
|
57
|
+
error("khask milf dyal .drj");
|
|
58
|
+
}
|
|
59
|
+
const filePath = validateFile(file);
|
|
60
|
+
switch (command) {
|
|
61
|
+
case "check": {
|
|
62
|
+
(0, index_1.default)("check", filePath);
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
case "run": {
|
|
66
|
+
(0, index_1.default)("run", filePath);
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
case "build": {
|
|
70
|
+
(0, index_1.default)("build", filePath);
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
default:
|
|
74
|
+
help();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
main();
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ExpressionChecker = void 0;
|
|
4
|
+
const errors_1 = require("../errors");
|
|
5
|
+
const showType_1 = require("../../utils/showType");
|
|
6
|
+
const types_1 = require("./types");
|
|
7
|
+
/**
|
|
8
|
+
* ExpressionChecker handles type inference for all expression types.
|
|
9
|
+
* Validates expressions and returns their inferred types.
|
|
10
|
+
*/
|
|
11
|
+
class ExpressionChecker {
|
|
12
|
+
functions;
|
|
13
|
+
typeChecker;
|
|
14
|
+
constructor(functions) {
|
|
15
|
+
this.functions = functions;
|
|
16
|
+
this.typeChecker = new types_1.TypeChecker();
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Infer the type of an expression.
|
|
20
|
+
* Performs semantic validation and returns the resulting type.
|
|
21
|
+
*/
|
|
22
|
+
inferType(expr, scope) {
|
|
23
|
+
switch (expr.type) {
|
|
24
|
+
case "NumericLiteral":
|
|
25
|
+
return { base: "ra9m", d: 0 };
|
|
26
|
+
case "StringLiteral":
|
|
27
|
+
return { base: "nass", d: 0 };
|
|
28
|
+
case "BooleanLiteral":
|
|
29
|
+
return { base: "tona2i", d: 0 };
|
|
30
|
+
case "NullLiteral":
|
|
31
|
+
return { base: "khawi", d: 0 };
|
|
32
|
+
case "ArrayExpression":
|
|
33
|
+
return this.checkArrayExpression(expr, scope);
|
|
34
|
+
case "Identifier":
|
|
35
|
+
return this.checkIdentifier(expr, scope);
|
|
36
|
+
case "AssignmentExpression":
|
|
37
|
+
return this.checkAssignmentExpression(expr, scope);
|
|
38
|
+
case "BinaryExpression":
|
|
39
|
+
return this.checkBinaryExpression(expr, scope);
|
|
40
|
+
case "LogicalExpression":
|
|
41
|
+
return this.checkLogicalExpression(expr, scope);
|
|
42
|
+
case "UnaryExpression":
|
|
43
|
+
return this.checkUnaryExpression(expr, scope);
|
|
44
|
+
case "UpdateExpression":
|
|
45
|
+
return this.checkUpdateExpression(expr, scope);
|
|
46
|
+
case "ConditionalExpression":
|
|
47
|
+
return this.checkConditionalExpression(expr, scope);
|
|
48
|
+
case "CallExpression":
|
|
49
|
+
return this.checkCallExpression(expr, scope);
|
|
50
|
+
case "MemberExpression":
|
|
51
|
+
return this.checkMemberExpression(expr, scope);
|
|
52
|
+
default:
|
|
53
|
+
throw new errors_1.DarijaError({
|
|
54
|
+
code: "DCE-2",
|
|
55
|
+
stage: "checker",
|
|
56
|
+
message: `'${expr.type}' ba9i mmd3omach`,
|
|
57
|
+
location: {
|
|
58
|
+
line: expr.pos.line,
|
|
59
|
+
column: expr.pos.column,
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
checkArrayExpression(expr, scope) {
|
|
65
|
+
if (expr.elements.length === 0) {
|
|
66
|
+
return { base: "unknown", d: 1 };
|
|
67
|
+
}
|
|
68
|
+
const elementType = this.inferType(expr.elements[0], scope);
|
|
69
|
+
for (const element of expr.elements) {
|
|
70
|
+
this.inferType(element, scope);
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
base: elementType.base,
|
|
74
|
+
d: (elementType.d ?? 0) + 1,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
checkIdentifier(expr, scope) {
|
|
78
|
+
const info = scope.resolve(expr.name);
|
|
79
|
+
if (!info) {
|
|
80
|
+
throw new errors_1.DarijaError({
|
|
81
|
+
code: "DCE1",
|
|
82
|
+
stage: "checker",
|
|
83
|
+
message: `'${expr.name}' mm3rofach`,
|
|
84
|
+
location: {
|
|
85
|
+
line: expr.pos.line,
|
|
86
|
+
column: expr.pos.column,
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
return info.type;
|
|
91
|
+
}
|
|
92
|
+
checkAssignmentExpression(expr, scope) {
|
|
93
|
+
const valueType = this.inferType(expr.value, scope);
|
|
94
|
+
if (expr.target.type === "Identifier") {
|
|
95
|
+
const info = scope.resolve(expr.target.name);
|
|
96
|
+
if (!info) {
|
|
97
|
+
throw new errors_1.DarijaError({
|
|
98
|
+
code: "DCE1",
|
|
99
|
+
stage: "checker",
|
|
100
|
+
message: `'${expr.target.name}' mm3rofch`,
|
|
101
|
+
location: {
|
|
102
|
+
line: expr.pos.line,
|
|
103
|
+
column: expr.pos.column,
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
if (info.kind === "khli") {
|
|
108
|
+
throw new errors_1.DarijaError({
|
|
109
|
+
code: "DCE16",
|
|
110
|
+
stage: "checker",
|
|
111
|
+
message: `mat9drh t3ti 9ima l '${expr.target.name}', la79ach how tabit (m3rf b 'khli')`,
|
|
112
|
+
location: {
|
|
113
|
+
line: expr.pos.line,
|
|
114
|
+
column: expr.pos.column,
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
if (info.type.base !== types_1.UNKNOWN &&
|
|
119
|
+
!this.typeChecker.compatible(info.type, valueType)) {
|
|
120
|
+
throw new errors_1.DarijaError({
|
|
121
|
+
code: "DCE15",
|
|
122
|
+
stage: "checker",
|
|
123
|
+
message: `twa93na ${(0, showType_1.showType)(info.type)}, wlkin l9ina ${(0, showType_1.showType)(valueType)}`,
|
|
124
|
+
location: {
|
|
125
|
+
line: expr.pos.line,
|
|
126
|
+
column: expr.pos.column,
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
this.inferType(expr.target, scope);
|
|
133
|
+
}
|
|
134
|
+
return valueType;
|
|
135
|
+
}
|
|
136
|
+
checkBinaryExpression(expr, scope) {
|
|
137
|
+
const leftType = this.inferType(expr.left, scope);
|
|
138
|
+
const rightType = this.inferType(expr.right, scope);
|
|
139
|
+
if (["==", "!=", "<", "<=", ">", ">="].includes(expr.operator)) {
|
|
140
|
+
return { base: "tona2i", d: 0 };
|
|
141
|
+
}
|
|
142
|
+
if (expr.operator === "+") {
|
|
143
|
+
if (this.typeChecker.isType(leftType, "nass") || this.typeChecker.isType(rightType, "nass")) {
|
|
144
|
+
return { base: "nass", d: 0 };
|
|
145
|
+
}
|
|
146
|
+
this.typeChecker.expectType(leftType, "ra9m", expr.pos);
|
|
147
|
+
this.typeChecker.expectType(rightType, "ra9m", expr.pos);
|
|
148
|
+
return { base: "ra9m", d: 0 };
|
|
149
|
+
}
|
|
150
|
+
// Other arithmetic operators require numbers
|
|
151
|
+
this.typeChecker.expectType(leftType, "ra9m", expr.pos);
|
|
152
|
+
this.typeChecker.expectType(rightType, "ra9m", expr.pos);
|
|
153
|
+
return { base: "ra9m", d: 0 };
|
|
154
|
+
}
|
|
155
|
+
checkLogicalExpression(expr, scope) {
|
|
156
|
+
this.inferType(expr.left, scope);
|
|
157
|
+
this.inferType(expr.right, scope);
|
|
158
|
+
return { base: "tona2i", d: 0 };
|
|
159
|
+
}
|
|
160
|
+
checkUnaryExpression(expr, scope) {
|
|
161
|
+
const argType = this.inferType(expr.argument, scope);
|
|
162
|
+
if (expr.operator === "!") {
|
|
163
|
+
return { base: "tona2i", d: 0 };
|
|
164
|
+
}
|
|
165
|
+
this.typeChecker.expectType(argType, "ra9m", expr.pos);
|
|
166
|
+
return { base: "ra9m", d: 0 };
|
|
167
|
+
}
|
|
168
|
+
checkUpdateExpression(expr, scope) {
|
|
169
|
+
const argType = this.inferType(expr.argument, scope);
|
|
170
|
+
this.typeChecker.expectType(argType, "ra9m", expr.pos);
|
|
171
|
+
return { base: "ra9m", d: 0 };
|
|
172
|
+
}
|
|
173
|
+
checkConditionalExpression(expr, scope) {
|
|
174
|
+
this.inferType(expr.condition, scope);
|
|
175
|
+
const consequentType = this.inferType(expr.consequent, scope);
|
|
176
|
+
const alternateType = this.inferType(expr.alternate, scope);
|
|
177
|
+
return consequentType === alternateType
|
|
178
|
+
? consequentType
|
|
179
|
+
: { base: types_1.UNKNOWN, d: 0 };
|
|
180
|
+
}
|
|
181
|
+
checkCallExpression(expr, scope) {
|
|
182
|
+
if (expr.callee.type !== "Identifier") {
|
|
183
|
+
throw new errors_1.DarijaError({
|
|
184
|
+
code: "DCE-2",
|
|
185
|
+
stage: "checker",
|
|
186
|
+
message: "ghir dawal direct lli md3omim",
|
|
187
|
+
location: {
|
|
188
|
+
line: expr.pos.line,
|
|
189
|
+
column: expr.pos.column,
|
|
190
|
+
},
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
const fn = this.functions.get(expr.callee.name);
|
|
194
|
+
if (!fn) {
|
|
195
|
+
throw new errors_1.DarijaError({
|
|
196
|
+
code: "DCE1",
|
|
197
|
+
stage: "checker",
|
|
198
|
+
message: `dala '${expr.callee.name}' mm3rofach`,
|
|
199
|
+
location: {
|
|
200
|
+
line: expr.pos.line,
|
|
201
|
+
column: expr.pos.column,
|
|
202
|
+
},
|
|
203
|
+
hint: `dir ta3rif l dala ${expr.callee.name} bhal haka : dalla ${expr.callee.name}(){ chi logic }}`,
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
const required = fn.params.filter((p) => !p.defaultValue).length;
|
|
207
|
+
if (expr.args.length < required ||
|
|
208
|
+
expr.args.length > fn.params.length) {
|
|
209
|
+
throw new errors_1.DarijaError({
|
|
210
|
+
code: "DCE17",
|
|
211
|
+
stage: "checker",
|
|
212
|
+
message: `'${expr.callee.name}' twa93 ${required === fn.params.length
|
|
213
|
+
? required
|
|
214
|
+
: `${required}-${fn.params.length}`} dyal lhojaj, wlkin l9a ${expr.args.length}`,
|
|
215
|
+
location: {
|
|
216
|
+
line: expr.pos.line,
|
|
217
|
+
column: expr.pos.column,
|
|
218
|
+
},
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
expr.args.forEach((arg, i) => {
|
|
222
|
+
const argType = this.inferType(arg, scope);
|
|
223
|
+
const param = fn.params[i];
|
|
224
|
+
if (param.typeAnnotation &&
|
|
225
|
+
!this.typeChecker.compatible(param.typeAnnotation, argType)) {
|
|
226
|
+
throw new errors_1.DarijaError({
|
|
227
|
+
code: "DCE15",
|
|
228
|
+
stage: "checker",
|
|
229
|
+
message: `twa93na ${(0, showType_1.showType)(param.typeAnnotation)}, wlkin l9ina ${(0, showType_1.showType)(argType)}`,
|
|
230
|
+
location: {
|
|
231
|
+
line: expr.pos.line,
|
|
232
|
+
column: expr.pos.column,
|
|
233
|
+
},
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
return fn.returnType ?? { base: types_1.UNKNOWN, d: 0 };
|
|
238
|
+
}
|
|
239
|
+
checkMemberExpression(expr, scope) {
|
|
240
|
+
const objectType = this.inferType(expr.object, scope);
|
|
241
|
+
if (expr.computed)
|
|
242
|
+
this.inferType(expr.property, scope);
|
|
243
|
+
return objectType.d
|
|
244
|
+
? { base: objectType.base, d: objectType.d - 1 }
|
|
245
|
+
: { base: types_1.UNKNOWN, d: 0 };
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
exports.ExpressionChecker = ExpressionChecker;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Checker = void 0;
|
|
4
|
+
const errors_1 = require("../errors");
|
|
5
|
+
const scope_1 = require("./scope");
|
|
6
|
+
const statements_1 = require("./statements");
|
|
7
|
+
class Checker {
|
|
8
|
+
globalScope = new scope_1.Scope();
|
|
9
|
+
functions = new scope_1.FunctionRegistry();
|
|
10
|
+
statementChecker;
|
|
11
|
+
constructor() {
|
|
12
|
+
this.statementChecker = new statements_1.StatementChecker(this.functions, this.globalScope);
|
|
13
|
+
}
|
|
14
|
+
check(program) {
|
|
15
|
+
// Pass 1: Hoist function signatures
|
|
16
|
+
for (const stmt of program.body) {
|
|
17
|
+
if (stmt.type === "FunctionDeclaration") {
|
|
18
|
+
this.registerFunctionSignature(stmt);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
// Pass 2: Validate all statements
|
|
22
|
+
for (const stmt of program.body) {
|
|
23
|
+
this.statementChecker.checkStatement(stmt, this.globalScope);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
registerFunctionSignature(fn) {
|
|
27
|
+
if (this.functions.has(fn.name)) {
|
|
28
|
+
throw new errors_1.DarijaError({
|
|
29
|
+
code: "DCE13",
|
|
30
|
+
stage: "checker",
|
|
31
|
+
message: `dala '${fn.name}' dija m3rfa`,
|
|
32
|
+
location: {
|
|
33
|
+
line: fn.pos.line,
|
|
34
|
+
column: fn.pos.column,
|
|
35
|
+
},
|
|
36
|
+
hint: `stkhdm dalla dyal ${fn.name}() awla dir dalla jdida`,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
this.functions.register(fn.name, {
|
|
40
|
+
params: fn.params,
|
|
41
|
+
returnType: fn.returnType ?? { base: "walo", d: 0 },
|
|
42
|
+
}, fn.pos.line, fn.pos.column);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
exports.Checker = Checker;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FunctionRegistry = exports.Scope = void 0;
|
|
4
|
+
const errors_1 = require("../errors");
|
|
5
|
+
//welcome to the scope
|
|
6
|
+
class Scope {
|
|
7
|
+
parent;
|
|
8
|
+
vars = new Map();
|
|
9
|
+
constructor(parent = null) {
|
|
10
|
+
this.parent = parent;
|
|
11
|
+
}
|
|
12
|
+
declare(name, info, line, column) {
|
|
13
|
+
if (this.vars.has(name)) {
|
|
14
|
+
throw new errors_1.DarijaError({
|
|
15
|
+
code: "DCE13",
|
|
16
|
+
stage: "checker",
|
|
17
|
+
message: `'${name}' dija m3rfa`,
|
|
18
|
+
location: { line, column },
|
|
19
|
+
hint: `${name} = 9ima fblast (dir/khli ${name} = 9ima)`,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
this.vars.set(name, info);
|
|
23
|
+
}
|
|
24
|
+
resolve(name) {
|
|
25
|
+
return this.vars.get(name) ?? this.parent?.resolve(name);
|
|
26
|
+
}
|
|
27
|
+
child() {
|
|
28
|
+
return new Scope(this);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
exports.Scope = Scope;
|
|
32
|
+
/**
|
|
33
|
+
* Global function registry.
|
|
34
|
+
* Tracks all function signatures for validation during calls and recursion.
|
|
35
|
+
*/
|
|
36
|
+
class FunctionRegistry {
|
|
37
|
+
functions = new Map();
|
|
38
|
+
register(name, info, line, column) {
|
|
39
|
+
if (this.functions.has(name)) {
|
|
40
|
+
throw new errors_1.DarijaError({
|
|
41
|
+
code: "DCE13",
|
|
42
|
+
stage: "checker",
|
|
43
|
+
message: `dala '${name}' dija m3rfa`,
|
|
44
|
+
location: { line, column },
|
|
45
|
+
hint: `stkhdm dalla dyal ${name}() awla dir dalla jdida`,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
this.functions.set(name, info);
|
|
49
|
+
}
|
|
50
|
+
get(name) {
|
|
51
|
+
return this.functions.get(name);
|
|
52
|
+
}
|
|
53
|
+
has(name) {
|
|
54
|
+
return this.functions.has(name);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
exports.FunctionRegistry = FunctionRegistry;
|