hindicode 1.3.0 → 1.4.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/README.md +75 -82
- package/bin/hindicode.js +5 -0
- package/index.js +13 -238
- package/package.json +7 -2
- package/src/cli/index.js +77 -0
- package/src/cli/main.js +20 -0
- package/src/compiler/compile.js +108 -0
- package/src/compiler/tokenizer.js +219 -0
- package/src/diagnostics/index.js +45 -0
- package/src/language/keywords.js +209 -0
- package/src/parser/index.js +66 -0
- package/src/runtime/register.js +24 -0
package/README.md
CHANGED
|
@@ -1,97 +1,90 @@
|
|
|
1
|
-
# HindiCode - हिंदी में जावास्क्रिप्ट लिखें!
|
|
2
|
-
> Write JavaScript in Hindi with Industrial-Grade Robustness.
|
|
1
|
+
# HindiCode - हिंदी में जावास्क्रिप्ट लिखें!
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
Hindicode is evolving from a runtime keyword translator into a Hindi-first JavaScript compiler pipeline.
|
|
5
4
|
|
|
6
|
-
##
|
|
7
|
-
**HindiCode** एक आधुनिक NPM पैकेज है जो आपको **हिंदी में जावास्क्रिप्ट** लिखने की सुविधा देता है। यह कोड को रन-टाइम पर पार्स करता है और हिंदी के कीवर्ड्स को जावास्क्रिप्ट में बदल देता है।
|
|
5
|
+
## What Hindicode Supports Today
|
|
8
6
|
|
|
9
|
-
|
|
7
|
+
- `.hindi.js` runtime execution in Node
|
|
8
|
+
- `hindicode run`, `hindicode check`, and `hindicode transpile`
|
|
9
|
+
- multi-file CommonJS-style Hindicode programs
|
|
10
|
+
- browser-targeted transpilation experiments
|
|
11
|
+
- structured diagnostics for compile-time syntax failures
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
```javascript
|
|
13
|
-
स्थिर x = 10;
|
|
14
|
-
अगर (x > 5) {
|
|
15
|
-
दिखाओ("x बड़ा है!");
|
|
16
|
-
} अन्यथा {
|
|
17
|
-
दिखाओ("x छोटा है!");
|
|
18
|
-
}
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
---
|
|
22
|
-
|
|
23
|
-
## 🌟 Features (विशेषताएँ)
|
|
24
|
-
- **Industrial-Grade Protection**:
|
|
25
|
-
- **🛡️ Comment Protection**: Keywords inside `//` or `/* */` are never translated.
|
|
26
|
-
- **🛡️ String Protection**: Your text inside `" "` or `' '` stays exactly as written.
|
|
27
|
-
- **🛡️ Regex Protection**: Search patterns like `/अगर/g` are preserved perfectly.
|
|
28
|
-
- **Smart Template Literals**: Supports full `${}` interpolation with recursive translation.
|
|
29
|
-
- **Unicode Boundaries**: Professional word boundaries ensure `नम` doesn't break `नमस्ते`.
|
|
30
|
-
- **Zero Configuration**: Just register the hook and run `.hindi.js` files.
|
|
31
|
-
|
|
32
|
-
---
|
|
33
|
-
|
|
34
|
-
## 🔧 Installation (स्थापना)
|
|
35
|
-
```sh
|
|
36
|
-
npm install hindicode
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
---
|
|
40
|
-
|
|
41
|
-
## 🚀 Usage (उपयोग)
|
|
13
|
+
## Quick Example
|
|
42
14
|
|
|
43
|
-
### 1. Register the Transpiler
|
|
44
|
-
Add this to your entry point (e.g., `index.js`):
|
|
45
15
|
```javascript
|
|
46
|
-
|
|
47
|
-
require('./your-file.hindi.js');
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
### 2. Write in Hindi (`.hindi.js`)
|
|
51
|
-
```javascript
|
|
52
|
-
// app.hindi.js
|
|
53
|
-
नया नाम = "अर्जुन";
|
|
54
|
-
दिखाओ(`नमस्ते ${नाम}!`);
|
|
16
|
+
स्थिर नाम = "अर्जुन";
|
|
55
17
|
|
|
56
|
-
कार्य
|
|
57
|
-
लौटाओ
|
|
18
|
+
कार्य स्वागत(व्यक्ति) {
|
|
19
|
+
लौटाओ `नमस्ते ${व्यक्ति}`;
|
|
58
20
|
}
|
|
59
21
|
|
|
60
|
-
दिखाओ(
|
|
22
|
+
दिखाओ(स्वागत(नाम));
|
|
61
23
|
```
|
|
62
24
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
## 📖 Keyword Mapping (कीवर्ड्स)
|
|
66
|
-
| Hindi | JavaScript | Hindi | JavaScript |
|
|
67
|
-
| :--- | :--- | :--- | :--- |
|
|
68
|
-
| अगर | if | अन्य | else |
|
|
69
|
-
| दिखाओ | console.log | कार्य | function |
|
|
70
|
-
| लौटाओ | return | चलाओ | for |
|
|
71
|
-
| जबतक | while | नया | let |
|
|
72
|
-
| स्थिर | const | सही | true |
|
|
73
|
-
| गलत | false | असांयकालिक | async |
|
|
74
|
-
| प्रतीक्षा | await | त्रुटि | Error |
|
|
75
|
-
|
|
76
|
-
*(Check `index.js` for the full dictionary of over 90+ terms!)*
|
|
77
|
-
|
|
78
|
-
---
|
|
25
|
+
## Install
|
|
79
26
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
- [ ] **VS Code Extension**: Syntax highlighting and snippets for `.hindi.js`.
|
|
84
|
-
- [ ] **Hindi Error Messages**: Localized compiler errors.
|
|
85
|
-
- [ ] **Hindi-DOM**: Support for `दस्तावेज़` (document) and `खिड़की` (window).
|
|
86
|
-
|
|
87
|
-
---
|
|
88
|
-
|
|
89
|
-
## 💖 Contribute (योगदान)
|
|
90
|
-
We welcome contributions! Star the repo and join the movement to make coding accessible in every language.
|
|
27
|
+
```powershell
|
|
28
|
+
npm install hindicode
|
|
29
|
+
```
|
|
91
30
|
|
|
92
|
-
|
|
31
|
+
## CLI
|
|
93
32
|
|
|
94
|
-
|
|
33
|
+
```powershell
|
|
34
|
+
hindicode run app.hindi.js
|
|
35
|
+
hindicode check app.hindi.js
|
|
36
|
+
hindicode transpile app.hindi.js
|
|
37
|
+
```
|
|
95
38
|
|
|
96
|
-
##
|
|
97
|
-
|
|
39
|
+
## Compiler Direction
|
|
40
|
+
|
|
41
|
+
Phase 1 now includes:
|
|
42
|
+
- keyword inventory module
|
|
43
|
+
- tokenizer
|
|
44
|
+
- parser-strategy layer
|
|
45
|
+
- compiler contract
|
|
46
|
+
- runtime registration module
|
|
47
|
+
- CLI entrypoints
|
|
48
|
+
- parser, CLI, integration, and scenario coverage
|
|
49
|
+
|
|
50
|
+
## Best-Supported Phase 1 Use Cases
|
|
51
|
+
|
|
52
|
+
- learning JavaScript in Hindi
|
|
53
|
+
- Node scripts and utilities
|
|
54
|
+
- multi-file CommonJS projects
|
|
55
|
+
- browser-oriented transpilation with mocked or real browser globals
|
|
56
|
+
|
|
57
|
+
## Current Limits
|
|
58
|
+
|
|
59
|
+
Not yet fully promised in Phase 1:
|
|
60
|
+
- full ESM runtime execution
|
|
61
|
+
- React/Angular integrations
|
|
62
|
+
- source maps
|
|
63
|
+
- framework loaders
|
|
64
|
+
- full AST parser behavior
|
|
65
|
+
|
|
66
|
+
## Important Docs
|
|
67
|
+
|
|
68
|
+
- `PHASE_ONE_PLAN.md`
|
|
69
|
+
- `PHASE_ONE_CHECKLIST.md`
|
|
70
|
+
- `PHASE_TWO_PLAN.md`
|
|
71
|
+
- `PHASE_TWO_CHECKLIST.md`
|
|
72
|
+
- `VISION.md`
|
|
73
|
+
- `ROADMAP.md`
|
|
74
|
+
- `docs/getting-started.md`
|
|
75
|
+
- `docs/cli-usage.md`
|
|
76
|
+
- `docs/cli-quick-reference.md`
|
|
77
|
+
- `docs/language-spec-v1.md`
|
|
78
|
+
- `docs/compiler-contract.md`
|
|
79
|
+
- `docs/runtime-support.md`
|
|
80
|
+
- `docs/source-map-design.md`
|
|
81
|
+
- `docs/contributor-guide.md`
|
|
82
|
+
- `docs/how-to-add-keyword.md`
|
|
83
|
+
|
|
84
|
+
## Contributing
|
|
85
|
+
|
|
86
|
+
If you add language features, please update tests and docs together. Phase 1 is focused on correctness, diagnostics, and compiler structure.
|
|
87
|
+
|
|
88
|
+
## License
|
|
89
|
+
|
|
90
|
+
MIT
|
package/bin/hindicode.js
ADDED
package/index.js
CHANGED
|
@@ -1,239 +1,14 @@
|
|
|
1
|
-
const
|
|
2
|
-
const
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
// ── Control Flow ─────────────────────────────────
|
|
16
|
-
"अगर": "if",
|
|
17
|
-
"वरना": "else",
|
|
18
|
-
"करो": "do",
|
|
19
|
-
"जबतक": "while",
|
|
20
|
-
"केलिए": "for",
|
|
21
|
-
"स्विच": "switch",
|
|
22
|
-
"मामला": "case",
|
|
23
|
-
"रोकें": "break",
|
|
24
|
-
"जारी": "continue",
|
|
25
|
-
"लौटाओ": "return",
|
|
26
|
-
"फेंको": "throw",
|
|
27
|
-
|
|
28
|
-
// ── Declarations ─────────────────────────────────
|
|
29
|
-
"नया": "let",
|
|
30
|
-
"स्थिर": "const",
|
|
31
|
-
"पुराना": "var",
|
|
32
|
-
"कार्य": "function",
|
|
33
|
-
"वर्ग": "class",
|
|
34
|
-
|
|
35
|
-
// ── Async ─────────────────────────────────────────
|
|
36
|
-
"असिंक": "async",
|
|
37
|
-
"इंतज़ार": "await",
|
|
38
|
-
|
|
39
|
-
// ── Literals ─────────────────────────────────────
|
|
40
|
-
"सच": "true",
|
|
41
|
-
"झूठ": "false",
|
|
42
|
-
"खाली": "null",
|
|
43
|
-
"अपरिभाषित": "undefined",
|
|
44
|
-
|
|
45
|
-
// ── OOP ──────────────────────────────────────────
|
|
46
|
-
"विस्तार": "extends",
|
|
47
|
-
"सुपर": "super",
|
|
48
|
-
"यह": "this",
|
|
49
|
-
"हटाओ": "delete",
|
|
50
|
-
"प्रोटो": "prototype",
|
|
51
|
-
"में": "in",
|
|
52
|
-
"सत्यापित": "instanceof",
|
|
53
|
-
"वापसी": "yield",
|
|
54
|
-
|
|
55
|
-
// ── Modules ──────────────────────────────────────
|
|
56
|
-
"आयात": "import",
|
|
57
|
-
"निर्यात": "export",
|
|
58
|
-
"डिफ़ॉल्ट": "default",
|
|
59
|
-
"से": "from",
|
|
60
|
-
"मांगो": "require",
|
|
61
|
-
"मॉड्यूल": "module",
|
|
62
|
-
|
|
63
|
-
// ── Operators ────────────────────────────────────
|
|
64
|
-
"और": "&&",
|
|
65
|
-
"या": "||",
|
|
66
|
-
"नहीं": "!",
|
|
67
|
-
"बराबर": "===",
|
|
68
|
-
"छोटा": "<",
|
|
69
|
-
"बड़ा": ">",
|
|
70
|
-
|
|
71
|
-
// ── Error Handling ────────────────────────────────
|
|
72
|
-
"कोशिश": "try",
|
|
73
|
-
"पकड़ो": "catch",
|
|
74
|
-
"पकड़": "catch",
|
|
75
|
-
"अंततः": "finally",
|
|
76
|
-
"त्रुटि": "Error",
|
|
77
|
-
|
|
78
|
-
// ── Console ──────────────────────────────────────
|
|
79
|
-
"दिखाओ": "console.log",
|
|
80
|
-
"गलती": "console.error",
|
|
81
|
-
"चेतावनी": "console.warn",
|
|
82
|
-
"जानकारी": "console.info",
|
|
83
|
-
"कंसोल": "console",
|
|
84
|
-
|
|
85
|
-
// ── Array Methods ────────────────────────────────
|
|
86
|
-
"पुश": "push",
|
|
87
|
-
"पॉप": "pop",
|
|
88
|
-
"शिफ्ट": "shift",
|
|
89
|
-
"अनशिफ्ट": "unshift",
|
|
90
|
-
"स्लाइस": "slice",
|
|
91
|
-
"जोड़ो": "concat",
|
|
92
|
-
"शामिल": "includes",
|
|
93
|
-
"ढूँढो": "find",
|
|
94
|
-
"मानचित्र": "map",
|
|
95
|
-
"फ़िल्टर": "filter",
|
|
96
|
-
"कमकरो": "reduce",
|
|
97
|
-
"हरएक": "forEach",
|
|
98
|
-
"लंबाई": "length",
|
|
99
|
-
"इंडेक्स": "indexOf",
|
|
100
|
-
"उलटाओ": "reverse",
|
|
101
|
-
"क्रमित": "sort",
|
|
102
|
-
|
|
103
|
-
// ── Object Methods ────────────────────────────────
|
|
104
|
-
"कुंजियाँ": "keys",
|
|
105
|
-
"मूल्य": "values",
|
|
106
|
-
"प्रविष्टियाँ": "entries",
|
|
107
|
-
"बनाएँ": "create",
|
|
108
|
-
"मिलाओ": "assign",
|
|
109
|
-
"जमाओ": "freeze",
|
|
110
|
-
|
|
111
|
-
// ── Map / Set ─────────────────────────────────────
|
|
112
|
-
"नक्शा": "Map",
|
|
113
|
-
"है": "has",
|
|
114
|
-
"प्राप्त": "get",
|
|
115
|
-
"रखो": "set",
|
|
116
|
-
"साफ़": "clear",
|
|
117
|
-
"आकार": "size",
|
|
118
|
-
"डालो": "add",
|
|
119
|
-
|
|
120
|
-
// ── Promise ───────────────────────────────────────
|
|
121
|
-
"फिर": "then",
|
|
122
|
-
"सभी": "all",
|
|
123
|
-
"हल": "resolve",
|
|
124
|
-
"अस्वीकार": "reject",
|
|
125
|
-
"प्रॉमिस": "Promise",
|
|
126
|
-
|
|
127
|
-
// ── Browser APIs ──────────────────────────────────
|
|
128
|
-
"विंडो": "window",
|
|
129
|
-
"दस्तावेज": "document",
|
|
130
|
-
"ब्राउज़र": "navigator",
|
|
131
|
-
"स्थान": "location",
|
|
132
|
-
"इतिहास": "history",
|
|
133
|
-
"संग्रह": "localStorage",
|
|
134
|
-
"सत्र_संग्रह": "sessionStorage",
|
|
135
|
-
"चेतावनी_डिब्बा": "alert",
|
|
136
|
-
"पूछो": "prompt",
|
|
137
|
-
"पक्का_करो": "confirm",
|
|
138
|
-
"लाओ": "fetch",
|
|
139
|
-
"समय_बाद": "setTimeout",
|
|
140
|
-
"बार_बार": "setInterval",
|
|
141
|
-
"समय_रोकें": "clearTimeout",
|
|
142
|
-
"बार_रोकें": "clearInterval",
|
|
143
|
-
|
|
144
|
-
// ── Node.js ───────────────────────────────────────
|
|
145
|
-
"प्रक्रिया": "process",
|
|
146
|
-
"__नाम": "__filename",
|
|
147
|
-
"__डायरेक्टरी": "__dirname",
|
|
148
|
-
"बफर": "Buffer",
|
|
149
|
-
|
|
150
|
-
// ── Built-ins ─────────────────────────────────────
|
|
151
|
-
"ऑब्जेक्ट": "Object",
|
|
152
|
-
"ऐरे": "Array",
|
|
153
|
-
"सेट": "Set",
|
|
154
|
-
"स्ट्रिंग": "String",
|
|
155
|
-
"टेक्स्ट": "String",
|
|
156
|
-
"नंबर": "Number",
|
|
157
|
-
"बूलियन": "Boolean",
|
|
158
|
-
"डेट": "Date",
|
|
159
|
-
"तारीख": "Date",
|
|
160
|
-
"गणित": "Math",
|
|
161
|
-
"जेसन": "JSON",
|
|
162
|
-
"रेगएक्स": "RegExp",
|
|
163
|
-
"अनंत": "Infinity",
|
|
164
|
-
"त्रुटि": "Error",
|
|
165
|
-
"प्रॉमिस": "Promise",
|
|
166
|
-
|
|
167
|
-
// ── Math Shortcuts ────────────────────────────────
|
|
168
|
-
"गोलाई": "Math.round",
|
|
169
|
-
"ऊपर": "Math.ceil",
|
|
170
|
-
"नीचे": "Math.floor",
|
|
171
|
-
"अधिकतम": "Math.max",
|
|
172
|
-
"न्यूनतम": "Math.min",
|
|
173
|
-
"यादृच्छ": "Math.random",
|
|
174
|
-
"वर्गमूल": "Math.sqrt",
|
|
175
|
-
"पाई": "Math.PI",
|
|
176
|
-
|
|
177
|
-
// ── JSON Shortcuts ────────────────────────────────
|
|
178
|
-
"पार्स": "JSON.parse",
|
|
179
|
-
"तार_बनाओ": "JSON.stringify",
|
|
180
|
-
|
|
181
|
-
// ── String Methods ────────────────────────────────
|
|
182
|
-
"बड़े_अक्षर": "toUpperCase",
|
|
183
|
-
"छोटे_अक्षर": "toLowerCase",
|
|
184
|
-
"काटो": "trim",
|
|
185
|
-
"विभाजन": "split",
|
|
186
|
-
"बदलो": "replace",
|
|
187
|
-
"खोजो": "search",
|
|
188
|
-
"शुरू_से": "startsWith",
|
|
189
|
-
"खत्म_से": "endsWith",
|
|
190
|
-
"दोहराओ": "repeat",
|
|
191
|
-
"हिस्सा": "substring",
|
|
1
|
+
const { compileHindiJS, tokenizeSource, translateHindiJS } = require("./src/compiler/compile");
|
|
2
|
+
const { registerHindiExtension } = require("./src/runtime/register");
|
|
3
|
+
const { hindiToJS, sortedKeywords } = require("./src/language/keywords");
|
|
4
|
+
|
|
5
|
+
registerHindiExtension();
|
|
6
|
+
|
|
7
|
+
module.exports = {
|
|
8
|
+
compileHindiJS,
|
|
9
|
+
hindiToJS,
|
|
10
|
+
registerHindiExtension,
|
|
11
|
+
sortedKeywords,
|
|
12
|
+
tokenizeSource,
|
|
13
|
+
translateHindiJS,
|
|
192
14
|
};
|
|
193
|
-
|
|
194
|
-
function translateHindiJS(code) {
|
|
195
|
-
const sortedKeywords = Object.keys(hindiToJS).sort((a, b) => b.length - a.length);
|
|
196
|
-
|
|
197
|
-
const parts = [
|
|
198
|
-
/(?<BLOCK>\/\*[\s\S]*?\*\/)/.source,
|
|
199
|
-
/(?<LINE>\/\/.*)/.source,
|
|
200
|
-
/(?<STRING_DBL>"(?:[^"\\]|\\.)*")/.source,
|
|
201
|
-
/(?<STRING_SGL>'(?:[^'\\]|\\.)*')/.source,
|
|
202
|
-
/(?<BACKTICK>`[\s\S]*?`)/.source,
|
|
203
|
-
/(?<REGEX>\/(?![*\/])(?:[^\/\\\n]|\\.)*?\/[gimuy]*)/.source,
|
|
204
|
-
`(?<KEYWORD>(?<![\\u0900-\\u097F\\w$])(?:${sortedKeywords.join("|")})(?![\\u0900-\\u097F\\w$]))`
|
|
205
|
-
];
|
|
206
|
-
|
|
207
|
-
const masterRegex = new RegExp(parts.join("|"), "g");
|
|
208
|
-
|
|
209
|
-
return code.replace(masterRegex, (...args) => {
|
|
210
|
-
const groups = args[args.length - 1];
|
|
211
|
-
const { BACKTICK, KEYWORD } = groups;
|
|
212
|
-
|
|
213
|
-
if (KEYWORD && hindiToJS[KEYWORD]) {
|
|
214
|
-
return hindiToJS[KEYWORD];
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
if (BACKTICK) {
|
|
218
|
-
return BACKTICK.replace(/\${([\s\S]*?)}/g, (m, inner) => {
|
|
219
|
-
return `${"$"}{${translateHindiJS(inner)}}`;
|
|
220
|
-
});
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
return args[0];
|
|
224
|
-
});
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
// Custom require hook for `.hindi.js` files
|
|
228
|
-
require.extensions[".hindi.js"] = function (module, filename) {
|
|
229
|
-
try {
|
|
230
|
-
let content = fs.readFileSync(filename, "utf8").trim();
|
|
231
|
-
content = translateHindiJS(content);
|
|
232
|
-
module._compile(content, filename);
|
|
233
|
-
} catch (error) {
|
|
234
|
-
console.error("❌ Hindi Transpiler Error:", error);
|
|
235
|
-
throw error; // Re-throw to allow runners to detect failure
|
|
236
|
-
}
|
|
237
|
-
};
|
|
238
|
-
|
|
239
|
-
module.exports = { translateHindiJS };
|
package/package.json
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hindicode",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Run JavaScript with Hindi keywords",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"hindicode": "./bin/hindicode.js"
|
|
9
|
+
},
|
|
7
10
|
"scripts": {
|
|
8
|
-
"test": "
|
|
11
|
+
"test": "node tests/tokenizer_runner.js && node tests/parser_runner.js && node tests/public_api_runner.js && node tests/cli_runner.js && node tests/integration_runner.js && node tests/spec_runner.js && node runner.js"
|
|
9
12
|
},
|
|
10
13
|
"keywords": [
|
|
11
14
|
"hindi",
|
|
@@ -27,8 +30,10 @@
|
|
|
27
30
|
},
|
|
28
31
|
"homepage": "https://github.com/Ujjwal-08/hindicode#readme",
|
|
29
32
|
"files": [
|
|
33
|
+
"bin",
|
|
30
34
|
"index.js",
|
|
31
35
|
"index.d.ts",
|
|
36
|
+
"src",
|
|
32
37
|
"README.md",
|
|
33
38
|
"LICENSE"
|
|
34
39
|
],
|
package/src/cli/index.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
|
|
4
|
+
const { compileHindiJS } = require("../compiler/compile");
|
|
5
|
+
const { createDiagnostic, formatDiagnostic } = require("../diagnostics");
|
|
6
|
+
const { registerHindiExtension } = require("../runtime/register");
|
|
7
|
+
|
|
8
|
+
function printHelp() {
|
|
9
|
+
console.log(`hindicode <command> <file>
|
|
10
|
+
|
|
11
|
+
Commands:
|
|
12
|
+
run <file> Run a Hindicode file
|
|
13
|
+
transpile <file> Print transpiled JavaScript
|
|
14
|
+
check <file> Validate a Hindicode file compiles
|
|
15
|
+
`);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function resolveInputFile(filePath) {
|
|
19
|
+
if (!filePath) {
|
|
20
|
+
throw createDiagnostic({
|
|
21
|
+
code: "HC_CLI_NO_INPUT",
|
|
22
|
+
message: "No input file provided.",
|
|
23
|
+
hint: "Use hindicode <command> <file>.",
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const resolved = path.resolve(process.cwd(), filePath);
|
|
28
|
+
if (!fs.existsSync(resolved)) {
|
|
29
|
+
throw createDiagnostic({
|
|
30
|
+
code: "HC_CLI_FILE_NOT_FOUND",
|
|
31
|
+
file: resolved,
|
|
32
|
+
message: "Input file does not exist.",
|
|
33
|
+
hint: "Check the path or run the command from the project root.",
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return resolved;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function runCommand(command, filePath) {
|
|
41
|
+
if (!command || command === "--help" || command === "-h") {
|
|
42
|
+
printHelp();
|
|
43
|
+
return 0;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const resolved = resolveInputFile(filePath);
|
|
47
|
+
|
|
48
|
+
if (command === "run") {
|
|
49
|
+
registerHindiExtension();
|
|
50
|
+
require(resolved);
|
|
51
|
+
return 0;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const source = fs.readFileSync(resolved, "utf8");
|
|
55
|
+
const result = compileHindiJS(source, { filename: resolved, mode: command });
|
|
56
|
+
|
|
57
|
+
if (command === "transpile") {
|
|
58
|
+
process.stdout.write(result.code);
|
|
59
|
+
return 0;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (command === "check") {
|
|
63
|
+
console.log(`OK: ${path.basename(resolved)}`);
|
|
64
|
+
return 0;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
throw createDiagnostic({
|
|
68
|
+
code: "HC_CLI_UNKNOWN_COMMAND",
|
|
69
|
+
message: `Unknown command: ${command}`,
|
|
70
|
+
hint: "Use --help to see supported commands.",
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
module.exports = {
|
|
75
|
+
formatDiagnostic,
|
|
76
|
+
runCommand,
|
|
77
|
+
};
|
package/src/cli/main.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const { formatDiagnostic, runCommand } = require("./index");
|
|
2
|
+
|
|
3
|
+
function runCli(argv = process.argv, io = console) {
|
|
4
|
+
try {
|
|
5
|
+
const [, , command, filePath] = argv;
|
|
6
|
+
const exitCode = runCommand(command, filePath);
|
|
7
|
+
return typeof exitCode === "number" ? exitCode : 0;
|
|
8
|
+
} catch (error) {
|
|
9
|
+
if (error && error.code && error.message) {
|
|
10
|
+
io.error(formatDiagnostic(error));
|
|
11
|
+
} else {
|
|
12
|
+
io.error(error.message);
|
|
13
|
+
}
|
|
14
|
+
return 1;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
module.exports = {
|
|
19
|
+
runCli,
|
|
20
|
+
};
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
const vm = require("vm");
|
|
2
|
+
const { createDiagnostic } = require("../diagnostics");
|
|
3
|
+
const { tokenizeSource } = require("./tokenizer");
|
|
4
|
+
const { parseSource } = require("../parser");
|
|
5
|
+
|
|
6
|
+
function translateHindiJS(source, options = {}) {
|
|
7
|
+
const tokens = tokenizeSource(source);
|
|
8
|
+
const parseResult = parseSource({
|
|
9
|
+
source,
|
|
10
|
+
tokens,
|
|
11
|
+
filename: options.filename || null,
|
|
12
|
+
recursiveTransform: (innerSource) => translateHindiJS(innerSource, options),
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
return parseResult.transformedCode;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function extractLocationFromSyntaxError(stackText, filename) {
|
|
19
|
+
const lines = String(stackText || "").split(/\r?\n/);
|
|
20
|
+
const header = lines.find((line) => line.startsWith(`${filename}:`)) || "";
|
|
21
|
+
const match = header.match(/:(\d+)$/);
|
|
22
|
+
const line = match ? Number(match[1]) : 1;
|
|
23
|
+
|
|
24
|
+
const caretLine = lines.find((lineText) => /\^/.test(lineText)) || "^";
|
|
25
|
+
const column = Math.max(caretLine.indexOf("^") + 1, 1);
|
|
26
|
+
|
|
27
|
+
return {
|
|
28
|
+
line,
|
|
29
|
+
column,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function validateGeneratedJavaScript(code, filename) {
|
|
34
|
+
try {
|
|
35
|
+
new vm.Script(code, { filename });
|
|
36
|
+
return [];
|
|
37
|
+
} catch (error) {
|
|
38
|
+
const location = extractLocationFromSyntaxError(error.stack, filename || "inline.hindi.js");
|
|
39
|
+
return [
|
|
40
|
+
createDiagnostic({
|
|
41
|
+
code: "HC_JS_SYNTAX_ERROR",
|
|
42
|
+
file: filename || null,
|
|
43
|
+
message: error.message,
|
|
44
|
+
start: {
|
|
45
|
+
line: location.line,
|
|
46
|
+
column: location.column,
|
|
47
|
+
index: 0,
|
|
48
|
+
},
|
|
49
|
+
end: {
|
|
50
|
+
line: location.line,
|
|
51
|
+
column: location.column,
|
|
52
|
+
index: 0,
|
|
53
|
+
},
|
|
54
|
+
hint: "Run hindicode transpile to inspect generated JavaScript around this location.",
|
|
55
|
+
}),
|
|
56
|
+
];
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function compileHindiJS(source, options = {}) {
|
|
61
|
+
let parseResult;
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
const tokens = tokenizeSource(source);
|
|
65
|
+
parseResult = parseSource({
|
|
66
|
+
source,
|
|
67
|
+
tokens,
|
|
68
|
+
filename: options.filename || null,
|
|
69
|
+
recursiveTransform: (innerSource) => translateHindiJS(innerSource, options),
|
|
70
|
+
});
|
|
71
|
+
} catch (error) {
|
|
72
|
+
const diagnostic = createDiagnostic({
|
|
73
|
+
code: "HC_COMPILE_FAILURE",
|
|
74
|
+
file: options.filename || null,
|
|
75
|
+
message: error.message,
|
|
76
|
+
hint: "Inspect the source near the reported location or use hindicode transpile for debugging.",
|
|
77
|
+
});
|
|
78
|
+
throw diagnostic;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const diagnostics = [
|
|
82
|
+
...parseResult.diagnostics,
|
|
83
|
+
...validateGeneratedJavaScript(parseResult.transformedCode, options.filename || "inline.hindi.js"),
|
|
84
|
+
];
|
|
85
|
+
|
|
86
|
+
if (diagnostics.length > 0) {
|
|
87
|
+
throw diagnostics[0];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
code: parseResult.transformedCode,
|
|
92
|
+
map: null,
|
|
93
|
+
diagnostics,
|
|
94
|
+
meta: {
|
|
95
|
+
filename: options.filename || null,
|
|
96
|
+
mode: options.mode || "runtime",
|
|
97
|
+
parserStrategy: parseResult.strategy,
|
|
98
|
+
parserStage: parseResult.meta.parserStage,
|
|
99
|
+
},
|
|
100
|
+
parseResult,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
module.exports = {
|
|
105
|
+
compileHindiJS,
|
|
106
|
+
tokenizeSource,
|
|
107
|
+
translateHindiJS,
|
|
108
|
+
};
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
const TOKEN_TYPES = {
|
|
2
|
+
CODE: "code",
|
|
3
|
+
LINE_COMMENT: "line_comment",
|
|
4
|
+
BLOCK_COMMENT: "block_comment",
|
|
5
|
+
STRING_SINGLE: "string_single",
|
|
6
|
+
STRING_DOUBLE: "string_double",
|
|
7
|
+
TEMPLATE: "template",
|
|
8
|
+
REGEX: "regex",
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
function isEscaped(source, index) {
|
|
12
|
+
let backslashes = 0;
|
|
13
|
+
for (let i = index - 1; i >= 0 && source[i] === "\\"; i--) {
|
|
14
|
+
backslashes++;
|
|
15
|
+
}
|
|
16
|
+
return backslashes % 2 === 1;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function isRegexAllowedAfter(previousNonWhitespace) {
|
|
20
|
+
if (!previousNonWhitespace) {
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return /[=([{:,;!?&|+\-*/%^<>~]/.test(previousNonWhitespace);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function readQuoted(source, start, quote) {
|
|
28
|
+
let index = start + 1;
|
|
29
|
+
|
|
30
|
+
while (index < source.length) {
|
|
31
|
+
if (source[index] === quote && !isEscaped(source, index)) {
|
|
32
|
+
return index + 1;
|
|
33
|
+
}
|
|
34
|
+
index++;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return source.length;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function readLineComment(source, start) {
|
|
41
|
+
let index = start + 2;
|
|
42
|
+
while (index < source.length && source[index] !== "\n") {
|
|
43
|
+
index++;
|
|
44
|
+
}
|
|
45
|
+
return index;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function readBlockComment(source, start) {
|
|
49
|
+
let index = start + 2;
|
|
50
|
+
while (index < source.length) {
|
|
51
|
+
if (source[index] === "*" && source[index + 1] === "/") {
|
|
52
|
+
return index + 2;
|
|
53
|
+
}
|
|
54
|
+
index++;
|
|
55
|
+
}
|
|
56
|
+
return source.length;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function readRegex(source, start) {
|
|
60
|
+
let index = start + 1;
|
|
61
|
+
let inCharClass = false;
|
|
62
|
+
|
|
63
|
+
while (index < source.length) {
|
|
64
|
+
const char = source[index];
|
|
65
|
+
|
|
66
|
+
if (char === "[" && !isEscaped(source, index)) {
|
|
67
|
+
inCharClass = true;
|
|
68
|
+
} else if (char === "]" && !isEscaped(source, index)) {
|
|
69
|
+
inCharClass = false;
|
|
70
|
+
} else if (char === "/" && !inCharClass && !isEscaped(source, index)) {
|
|
71
|
+
index++;
|
|
72
|
+
while (/[a-z]/i.test(source[index] || "")) {
|
|
73
|
+
index++;
|
|
74
|
+
}
|
|
75
|
+
return index;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
index++;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return source.length;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function readTemplate(source, start) {
|
|
85
|
+
let index = start + 1;
|
|
86
|
+
|
|
87
|
+
while (index < source.length) {
|
|
88
|
+
const char = source[index];
|
|
89
|
+
|
|
90
|
+
if (char === "`" && !isEscaped(source, index)) {
|
|
91
|
+
return index + 1;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (char === "$" && source[index + 1] === "{" && !isEscaped(source, index)) {
|
|
95
|
+
index += 2;
|
|
96
|
+
let depth = 1;
|
|
97
|
+
|
|
98
|
+
while (index < source.length && depth > 0) {
|
|
99
|
+
const inner = source[index];
|
|
100
|
+
|
|
101
|
+
if ((inner === "'" || inner === '"') && !isEscaped(source, index)) {
|
|
102
|
+
index = readQuoted(source, index, inner);
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (inner === "`" && !isEscaped(source, index)) {
|
|
107
|
+
index = readTemplate(source, index);
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (inner === "{" && !isEscaped(source, index)) {
|
|
112
|
+
depth++;
|
|
113
|
+
} else if (inner === "}" && !isEscaped(source, index)) {
|
|
114
|
+
depth--;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
index++;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
index++;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return source.length;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function getLocation(source, index) {
|
|
130
|
+
let line = 1;
|
|
131
|
+
let column = 1;
|
|
132
|
+
|
|
133
|
+
for (let i = 0; i < index; i++) {
|
|
134
|
+
if (source[i] === "\n") {
|
|
135
|
+
line++;
|
|
136
|
+
column = 1;
|
|
137
|
+
} else {
|
|
138
|
+
column++;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return { line, column, index };
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function createToken(source, type, start, end) {
|
|
146
|
+
return {
|
|
147
|
+
type,
|
|
148
|
+
value: source.slice(start, end),
|
|
149
|
+
start,
|
|
150
|
+
end,
|
|
151
|
+
startLoc: getLocation(source, start),
|
|
152
|
+
endLoc: getLocation(source, end),
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function tokenizeSource(source) {
|
|
157
|
+
const tokens = [];
|
|
158
|
+
let codeStart = 0;
|
|
159
|
+
let index = 0;
|
|
160
|
+
let previousNonWhitespace = "";
|
|
161
|
+
|
|
162
|
+
const pushCode = (end) => {
|
|
163
|
+
if (end > codeStart) {
|
|
164
|
+
tokens.push(createToken(source, TOKEN_TYPES.CODE, codeStart, end));
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
const pushProtected = (type, start, end) => {
|
|
169
|
+
pushCode(start);
|
|
170
|
+
tokens.push(createToken(source, type, start, end));
|
|
171
|
+
codeStart = end;
|
|
172
|
+
index = end;
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
while (index < source.length) {
|
|
176
|
+
const char = source[index];
|
|
177
|
+
const next = source[index + 1];
|
|
178
|
+
|
|
179
|
+
if (char === "/" && next === "/") {
|
|
180
|
+
pushProtected(TOKEN_TYPES.LINE_COMMENT, index, readLineComment(source, index));
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (char === "/" && next === "*") {
|
|
185
|
+
pushProtected(TOKEN_TYPES.BLOCK_COMMENT, index, readBlockComment(source, index));
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (char === "'" || char === '"') {
|
|
190
|
+
const type = char === "'" ? TOKEN_TYPES.STRING_SINGLE : TOKEN_TYPES.STRING_DOUBLE;
|
|
191
|
+
pushProtected(type, index, readQuoted(source, index, char));
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (char === "`") {
|
|
196
|
+
pushProtected(TOKEN_TYPES.TEMPLATE, index, readTemplate(source, index));
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (char === "/" && isRegexAllowedAfter(previousNonWhitespace)) {
|
|
201
|
+
pushProtected(TOKEN_TYPES.REGEX, index, readRegex(source, index));
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (!/\s/.test(char)) {
|
|
206
|
+
previousNonWhitespace = char;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
index++;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
pushCode(source.length);
|
|
213
|
+
return tokens;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
module.exports = {
|
|
217
|
+
TOKEN_TYPES,
|
|
218
|
+
tokenizeSource,
|
|
219
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
const DiagnosticSeverity = {
|
|
2
|
+
INFO: "info",
|
|
3
|
+
WARNING: "warning",
|
|
4
|
+
ERROR: "error",
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
function createSourceLocation(line = 1, column = 1, index = 0) {
|
|
8
|
+
return { line, column, index };
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function createDiagnostic({
|
|
12
|
+
code,
|
|
13
|
+
message,
|
|
14
|
+
severity = DiagnosticSeverity.ERROR,
|
|
15
|
+
file = null,
|
|
16
|
+
start = createSourceLocation(),
|
|
17
|
+
end = start,
|
|
18
|
+
hint = null,
|
|
19
|
+
}) {
|
|
20
|
+
return {
|
|
21
|
+
code,
|
|
22
|
+
message,
|
|
23
|
+
severity,
|
|
24
|
+
file,
|
|
25
|
+
start,
|
|
26
|
+
end,
|
|
27
|
+
hint,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function formatDiagnostic(diagnostic) {
|
|
32
|
+
const location = diagnostic.file
|
|
33
|
+
? `${diagnostic.file}:${diagnostic.start.line}:${diagnostic.start.column}`
|
|
34
|
+
: `line ${diagnostic.start.line}, column ${diagnostic.start.column}`;
|
|
35
|
+
|
|
36
|
+
const hint = diagnostic.hint ? `\nHint: ${diagnostic.hint}` : "";
|
|
37
|
+
return `[${diagnostic.severity}] ${diagnostic.code} at ${location}: ${diagnostic.message}${hint}`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
module.exports = {
|
|
41
|
+
createDiagnostic,
|
|
42
|
+
createSourceLocation,
|
|
43
|
+
DiagnosticSeverity,
|
|
44
|
+
formatDiagnostic,
|
|
45
|
+
};
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
const hindiToJS = {
|
|
2
|
+
// Multi-word phrases FIRST (longest -> shortest to avoid partial matches)
|
|
3
|
+
"नहीं तो": "else",
|
|
4
|
+
"अन्यथा": "else",
|
|
5
|
+
"के रूप में": "as",
|
|
6
|
+
"का प्रकार": "typeof",
|
|
7
|
+
"नया बनाओ": "new",
|
|
8
|
+
"कम या बराबर": "<=",
|
|
9
|
+
"ज्यादा या बराबर": ">=",
|
|
10
|
+
"बराबर नहीं": "!==",
|
|
11
|
+
|
|
12
|
+
// Control flow
|
|
13
|
+
"अगर": "if",
|
|
14
|
+
"वरना": "else",
|
|
15
|
+
"करो": "do",
|
|
16
|
+
"जबतक": "while",
|
|
17
|
+
"केलिए": "for",
|
|
18
|
+
"स्विच": "switch",
|
|
19
|
+
"मामला": "case",
|
|
20
|
+
"रोकें": "break",
|
|
21
|
+
"जारी": "continue",
|
|
22
|
+
"लौटाओ": "return",
|
|
23
|
+
"फेंको": "throw",
|
|
24
|
+
|
|
25
|
+
// Declarations
|
|
26
|
+
"नया": "let",
|
|
27
|
+
"स्थिर": "const",
|
|
28
|
+
"पुराना": "var",
|
|
29
|
+
"कार्य": "function",
|
|
30
|
+
"वर्ग": "class",
|
|
31
|
+
|
|
32
|
+
// Async
|
|
33
|
+
"असिंक": "async",
|
|
34
|
+
"इंतज़ार": "await",
|
|
35
|
+
|
|
36
|
+
// Literals
|
|
37
|
+
"सच": "true",
|
|
38
|
+
"सत्य": "true",
|
|
39
|
+
"झूठ": "false",
|
|
40
|
+
"असत्य": "false",
|
|
41
|
+
"खाली": "null",
|
|
42
|
+
"अपरिभाषित": "undefined",
|
|
43
|
+
|
|
44
|
+
// OOP
|
|
45
|
+
"विस्तार": "extends",
|
|
46
|
+
"सुपर": "super",
|
|
47
|
+
"यह": "this",
|
|
48
|
+
"हटाओ": "delete",
|
|
49
|
+
"प्रोटो": "prototype",
|
|
50
|
+
"में": "in",
|
|
51
|
+
"सत्यापित": "instanceof",
|
|
52
|
+
"वापसी": "yield",
|
|
53
|
+
|
|
54
|
+
// Modules
|
|
55
|
+
"आयात": "import",
|
|
56
|
+
"निर्यात": "export",
|
|
57
|
+
"डिफ़ॉल्ट": "default",
|
|
58
|
+
"डिफॉल्ट": "default",
|
|
59
|
+
"से": "from",
|
|
60
|
+
"मांगो": "require",
|
|
61
|
+
"अनुरोध": "require",
|
|
62
|
+
"मॉड्यूल": "module",
|
|
63
|
+
|
|
64
|
+
// Operators
|
|
65
|
+
"और": "&&",
|
|
66
|
+
"या": "||",
|
|
67
|
+
"नहीं": "!",
|
|
68
|
+
"बराबर": "===",
|
|
69
|
+
"छोटा": "<",
|
|
70
|
+
"बड़ा": ">",
|
|
71
|
+
|
|
72
|
+
// Error handling
|
|
73
|
+
"कोशिश": "try",
|
|
74
|
+
"पकड़ो": "catch",
|
|
75
|
+
"पकड़": "catch",
|
|
76
|
+
"अंततः": "finally",
|
|
77
|
+
"त्रुटि": "Error",
|
|
78
|
+
|
|
79
|
+
// Console
|
|
80
|
+
"दिखाओ": "console.log",
|
|
81
|
+
"गलती": "console.error",
|
|
82
|
+
"चेतावनी": "console.warn",
|
|
83
|
+
"जानकारी": "console.info",
|
|
84
|
+
"कंसोल": "console",
|
|
85
|
+
|
|
86
|
+
// Array methods
|
|
87
|
+
"पुश": "push",
|
|
88
|
+
"पॉप": "pop",
|
|
89
|
+
"शिफ्ट": "shift",
|
|
90
|
+
"अनशिफ्ट": "unshift",
|
|
91
|
+
"स्लाइस": "slice",
|
|
92
|
+
"जोड़ो": "concat",
|
|
93
|
+
"शामिल": "includes",
|
|
94
|
+
"ढूँढो": "find",
|
|
95
|
+
"मानचित्र": "map",
|
|
96
|
+
"फ़िल्टर": "filter",
|
|
97
|
+
"कमकरो": "reduce",
|
|
98
|
+
"हरएक": "forEach",
|
|
99
|
+
"लंबाई": "length",
|
|
100
|
+
"लम्बाई": "length",
|
|
101
|
+
"इंडेक्स": "indexOf",
|
|
102
|
+
"उलटाओ": "reverse",
|
|
103
|
+
"क्रमित": "sort",
|
|
104
|
+
|
|
105
|
+
// Object methods
|
|
106
|
+
"कुंजियाँ": "keys",
|
|
107
|
+
"मूल्य": "values",
|
|
108
|
+
"प्रविष्टियाँ": "entries",
|
|
109
|
+
"बनाएँ": "create",
|
|
110
|
+
"मिलाओ": "assign",
|
|
111
|
+
"जमाओ": "freeze",
|
|
112
|
+
|
|
113
|
+
// Map / Set
|
|
114
|
+
"नक्शा": "Map",
|
|
115
|
+
"है": "has",
|
|
116
|
+
"प्राप्त": "get",
|
|
117
|
+
"रखो": "set",
|
|
118
|
+
"साफ़": "clear",
|
|
119
|
+
"आकार": "size",
|
|
120
|
+
"डालो": "add",
|
|
121
|
+
|
|
122
|
+
// Promise
|
|
123
|
+
"फिर": "then",
|
|
124
|
+
"सभी": "all",
|
|
125
|
+
"हल": "resolve",
|
|
126
|
+
"अस्वीकार": "reject",
|
|
127
|
+
"प्रॉमिस": "Promise",
|
|
128
|
+
|
|
129
|
+
// Browser APIs
|
|
130
|
+
"विंडो": "window",
|
|
131
|
+
"दस्तावेज": "document",
|
|
132
|
+
"दस्तावेज़": "document",
|
|
133
|
+
"ब्राउज़र": "navigator",
|
|
134
|
+
"स्थान": "location",
|
|
135
|
+
"इतिहास": "history",
|
|
136
|
+
"संग्रह": "localStorage",
|
|
137
|
+
"सत्र_संग्रह": "sessionStorage",
|
|
138
|
+
"चेतावनी_डिब्बा": "alert",
|
|
139
|
+
"पूछो": "prompt",
|
|
140
|
+
"पक्का_करो": "confirm",
|
|
141
|
+
"लाओ": "fetch",
|
|
142
|
+
"समय_बाद": "setTimeout",
|
|
143
|
+
"बार_बार": "setInterval",
|
|
144
|
+
"समय_रोकें": "clearTimeout",
|
|
145
|
+
"बार_रोकें": "clearInterval",
|
|
146
|
+
"तत्व_ढूँढो_आईडी_से": "getElementById",
|
|
147
|
+
"तत्व_ढूँढो": "querySelector",
|
|
148
|
+
"सभी_तत्व_ढूँढो": "querySelectorAll",
|
|
149
|
+
"घटना_सुनो": "addEventListener",
|
|
150
|
+
"तत्व_बनाओ": "createElement",
|
|
151
|
+
"बच्चा_जोड़ो": "appendChild",
|
|
152
|
+
|
|
153
|
+
// Node.js
|
|
154
|
+
"प्रक्रिया": "process",
|
|
155
|
+
"__नाम": "__filename",
|
|
156
|
+
"__डायरेक्टरी": "__dirname",
|
|
157
|
+
"बफर": "Buffer",
|
|
158
|
+
|
|
159
|
+
// Built-ins
|
|
160
|
+
"ऑब्जेक्ट": "Object",
|
|
161
|
+
"ऐरे": "Array",
|
|
162
|
+
"सेट": "Set",
|
|
163
|
+
"स्ट्रिंग": "String",
|
|
164
|
+
"टेक्स्ट": "String",
|
|
165
|
+
"नंबर": "Number",
|
|
166
|
+
"बूलियन": "Boolean",
|
|
167
|
+
"डेट": "Date",
|
|
168
|
+
"तारीख": "Date",
|
|
169
|
+
"गणित": "Math",
|
|
170
|
+
"जेसन": "JSON",
|
|
171
|
+
"जेसन_डेटा": "json",
|
|
172
|
+
"जीसन": "JSON",
|
|
173
|
+
"जोड़ें": "join",
|
|
174
|
+
"रेगएक्स": "RegExp",
|
|
175
|
+
"अनंत": "Infinity",
|
|
176
|
+
|
|
177
|
+
// Math shortcuts
|
|
178
|
+
"गोलाई": "Math.round",
|
|
179
|
+
"ऊपर": "Math.ceil",
|
|
180
|
+
"नीचे": "Math.floor",
|
|
181
|
+
"अधिकतम": "Math.max",
|
|
182
|
+
"न्यूनतम": "Math.min",
|
|
183
|
+
"यादृच्छ": "Math.random",
|
|
184
|
+
"वर्गमूल": "Math.sqrt",
|
|
185
|
+
"पाई": "Math.PI",
|
|
186
|
+
|
|
187
|
+
// JSON shortcuts
|
|
188
|
+
"पार्स": "JSON.parse",
|
|
189
|
+
"तार_बनाओ": "JSON.stringify",
|
|
190
|
+
|
|
191
|
+
// String methods
|
|
192
|
+
"बड़े_अक्षर": "toUpperCase",
|
|
193
|
+
"छोटे_अक्षर": "toLowerCase",
|
|
194
|
+
"काटो": "trim",
|
|
195
|
+
"विभाजन": "split",
|
|
196
|
+
"बदलो": "replace",
|
|
197
|
+
"खोजो": "search",
|
|
198
|
+
"शुरू_से": "startsWith",
|
|
199
|
+
"खत्म_से": "endsWith",
|
|
200
|
+
"दोहराओ": "repeat",
|
|
201
|
+
"हिस्सा": "substring",
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
const sortedKeywords = Object.keys(hindiToJS).sort((a, b) => b.length - a.length);
|
|
205
|
+
|
|
206
|
+
module.exports = {
|
|
207
|
+
hindiToJS,
|
|
208
|
+
sortedKeywords,
|
|
209
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
const { TOKEN_TYPES } = require("../compiler/tokenizer");
|
|
2
|
+
const { sortedKeywords, hindiToJS } = require("../language/keywords");
|
|
3
|
+
|
|
4
|
+
function escapeForRegex(value) {
|
|
5
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const keywordRegex = new RegExp(
|
|
9
|
+
`(?<![\\u0900-\\u097F\\w$])(?:${sortedKeywords.map(escapeForRegex).join("|")})(?![\\u0900-\\u097F\\w$])`,
|
|
10
|
+
"g"
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
function transformCodeSegment(code) {
|
|
14
|
+
return code.replace(keywordRegex, (match) => hindiToJS[match] || match);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function transformTokens(tokens, recursiveTransform) {
|
|
18
|
+
return tokens
|
|
19
|
+
.map((token) => {
|
|
20
|
+
if (token.type === TOKEN_TYPES.CODE) {
|
|
21
|
+
return transformCodeSegment(token.value);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (token.type === TOKEN_TYPES.TEMPLATE) {
|
|
25
|
+
return token.value.replace(/\${([\s\S]*?)}/g, (fullMatch, expression) => {
|
|
26
|
+
return `${"$"}{${recursiveTransform(expression)}}`;
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return token.value;
|
|
31
|
+
})
|
|
32
|
+
.join("");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function createParseResult({ source, tokens, transformedCode, filename = null }) {
|
|
36
|
+
return {
|
|
37
|
+
source,
|
|
38
|
+
tokens,
|
|
39
|
+
transformedCode,
|
|
40
|
+
ast: null,
|
|
41
|
+
diagnostics: [],
|
|
42
|
+
strategy: "token-transform",
|
|
43
|
+
meta: {
|
|
44
|
+
filename,
|
|
45
|
+
parserStage: "phase-one-token-transform",
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function parseSource({ source, tokens, recursiveTransform, filename = null }) {
|
|
51
|
+
const transformedCode = transformTokens(tokens, recursiveTransform);
|
|
52
|
+
|
|
53
|
+
return createParseResult({
|
|
54
|
+
source,
|
|
55
|
+
tokens,
|
|
56
|
+
transformedCode,
|
|
57
|
+
filename,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
module.exports = {
|
|
62
|
+
createParseResult,
|
|
63
|
+
parseSource,
|
|
64
|
+
transformCodeSegment,
|
|
65
|
+
transformTokens,
|
|
66
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const { compileHindiJS } = require("../compiler/compile");
|
|
3
|
+
const { formatDiagnostic } = require("../diagnostics");
|
|
4
|
+
|
|
5
|
+
function registerHindiExtension() {
|
|
6
|
+
require.extensions[".hindi.js"] = function loadHindiModule(module, filename) {
|
|
7
|
+
try {
|
|
8
|
+
const content = fs.readFileSync(filename, "utf8").trim();
|
|
9
|
+
const compiled = compileHindiJS(content, { filename, mode: "runtime" });
|
|
10
|
+
module._compile(compiled.code, filename);
|
|
11
|
+
} catch (error) {
|
|
12
|
+
if (error && error.code && error.message) {
|
|
13
|
+
console.error("❌ Hindi Transpiler Error:", formatDiagnostic(error));
|
|
14
|
+
} else {
|
|
15
|
+
console.error("❌ Hindi Transpiler Error:", error);
|
|
16
|
+
}
|
|
17
|
+
throw error;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
module.exports = {
|
|
23
|
+
registerHindiExtension,
|
|
24
|
+
};
|