bengaliscript
Version:
🚀 BengaliScript — Code in pure বাংলা! Write, run, and see output entirely in Bengali. Break language barriers, bring code closer to culture. Crafted with ❤️ by Atikin Verse.
153 lines (133 loc) • 4.72 kB
JavaScript
/* Created by Atikin Verse */
import fs from "fs";
import vm from "vm";
import path from "path";
import { fileURLToPath } from "url";
import { KEYWORDS, ALIASES } from "./bengaliKeywords.js";
import fetch from "node-fetch";
import { JSDOM } from "jsdom";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// Build replacement map (include aliases that point to canonical keys)
const MAP = { ...KEYWORDS };
for (const [alias, to] of Object.entries(ALIASES)) {
if (MAP[alias] === undefined && MAP[to]) {
MAP[alias] = MAP[to];
}
}
function escapeRegExp(s) {
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
// Replace Bengali tokens in code sections, skip strings/comments
function replaceKeywordsPreservingStrings(source, map) {
const parts = [];
let i = 0;
const len = source.length;
while (i < len) {
const ch = source[i];
// Strings
if (ch === "'" || ch === '"' || ch === "`") {
const quote = ch;
let j = i + 1;
while (j < len) {
if (source[j] === "\\" && j + 1 < len) { j += 2; continue; }
if (source[j] === quote) { j++; break; }
j++;
}
parts.push({ type: "string", text: source.slice(i, j) });
i = j;
continue;
}
// Line comment
if (ch === "/" && i + 1 < len && source[i + 1] === "/") {
let j = i + 2;
while (j < len && source[j] !== "\n") j++;
parts.push({ type: "comment", text: source.slice(i, j) });
i = j;
continue;
}
// Block comment
if (ch === "/" && i + 1 < len && source[i + 1] === "*") {
let j = i + 2;
while (j + 1 < len && !(source[j] === "*" && source[j + 1] === "/")) j++;
j = Math.min(len, j + 2);
parts.push({ type: "comment", text: source.slice(i, j) });
i = j;
continue;
}
// Code chunk
let j = i + 1;
while (j < len) {
const c = source[j];
if (c === "'" || c === '"' || c === "`") break;
if (c === "/" && (source[j + 1] === "/" || source[j + 1] === "*")) break;
j++;
}
parts.push({ type: "code", text: source.slice(i, j) });
i = j;
}
// Longest-first token replacement with unicode-aware boundaries
const keys = Object.keys(map).sort((a, b) => b.length - a.length);
const letter = "\\p{L}\\p{N}_"; // letters, numbers, underscore
for (const part of parts) {
if (part.type !== "code") continue;
let chunk = part.text;
for (const key of keys) {
const val = map[key];
const pattern = new RegExp(`(?<![${letter}])${escapeRegExp(key)}(?![${letter}])`, "gu");
chunk = chunk.replace(pattern, val);
}
part.text = chunk;
}
return parts.map(p => p.text).join("");
}
export async function runBS(filePath, { enableDOM = true } = {}) {
const abs = path.isAbsolute(filePath) ? filePath : path.join(process.cwd(), filePath);
if (!fs.existsSync(abs)) throw new Error(`File not found: ${abs}`);
const src = fs.readFileSync(abs, "utf8");
const translated = replaceKeywordsPreservingStrings(src, MAP);
// Sandbox with optional DOM and utilities
const sandbox = {
console,
setTimeout,
setInterval,
clearTimeout,
clearInterval,
fetch,
global: null
};
if (enableDOM) {
const dom = new JSDOM(
`<!doctype html><html><head></head><body><div id="app"></div></body></html>`,
{ url: "https://example.org" }
);
sandbox.window = dom.window;
sandbox.document = dom.window.document;
sandbox.navigator = dom.window.navigator;
sandbox.location = dom.window.location;
// Simple browser-like APIs
sandbox.alert = (msg) => console.log(String(msg));
sandbox.prompt = (q) => { console.log(String(q)); return ""; };
sandbox.confirm = (q) => { console.log(String(q)); return true; };
// Storage shims
sandbox.localStorage = {
_m: new Map(),
getItem(k){ return this._m.has(k) ? this._m.get(k) : null; },
setItem(k,v){ this._m.set(k, String(v)); },
removeItem(k){ this._m.delete(k); },
clear(){ this._m.clear(); }
};
sandbox.sessionStorage = {
_m: new Map(),
getItem(k){ return this._m.has(k) ? this._m.get(k) : null; },
setItem(k,v){ this._m.set(k, String(v)); },
removeItem(k){ this._m.delete(k); },
clear(){ this._m.clear(); }
};
}
sandbox.global = sandbox;
const script = new vm.Script(translated, { filename: path.basename(abs) });
const context = vm.createContext(sandbox);
const result = await script.runInContext(context);
return result;
}