Skip to content

Instantly share code, notes, and snippets.

@kakaroto
Last active May 1, 2020 23:34
Show Gist options
  • Select an option

  • Save kakaroto/97d04258deb7edede87cdf8533788d21 to your computer and use it in GitHub Desktop.

Select an option

Save kakaroto/97d04258deb7edede87cdf8533788d21 to your computer and use it in GitHub Desktop.
Script to convert pyj files into js files (very approximate)
const regexps = [
// comments
[new RegExp(/#/gm), "//"],
// Functions
[new RegExp(/def *\(([^:)]*)\) *: *$/gm), "($1) => {"],
[new RegExp(/def *\(([^:)]*)\) *: *return +(.*);/gm), "($1) => $2"],
[new RegExp(/def *\(([^:)]*)\) *: *(.*);/gm), "($1) => $2"],
[new RegExp(/def *\(([^:)]*)\) *: *return +(.*)$/gm), "($1) => $2"],
[new RegExp(/def *\(([^:)]*)\) *: *(.+)$/gm), "($1) => $2"],
[new RegExp(/def +([^ (]+) *\(self *,? *([^:)]*)\) *: *$/gm), "$1($2) {"],
[new RegExp(/def +([^ (]+) *\(([^:)]*)\) *: *$/gm), "function $1($2) {"],
// Classes
[new RegExp(/class +([^ ]+) *\(([^)]+)\) *:/gm), "class $1 extends $2 {"],
[new RegExp(/class +([^ ]+) *:/gm), "class $1 {"],
[new RegExp(/__init__/gm), "constructor"],
[new RegExp(/self/gm), "this"],
// if/else
[new RegExp(/\? ""/gm), " or \"\""],
[new RegExp(/\?/gm), " !== undefined"],
[new RegExp(/= *(.*) +if +(.+) +else +(.+)/gm), "= $2 ? $1 : $3"],
[new RegExp(/, *(.*) +if +(.+) +else +(.+)/gm), ", $2 ? $1 : $3"],
[new RegExp(/return *(.*) +if +(.+) +else +(.+)/gm), "return $2 ? $1 : $3"],
[new RegExp(/( +)if *([^:]+):/gm), "$1if ($2) {"],
[new RegExp(/( +)elif *([^:]+):/gm), "$1} else if ($2) {"],
[new RegExp(/( +)else *:/gm), "$1} else {"],
[new RegExp(/^if *([^:]+):/gm), "if ($1) {"],
[new RegExp(/^elif *([^:]+):/gm), "} else if ($1) {"],
[new RegExp(/^else *:/gm), "} else {"],
// Loops
[new RegExp(/( +)while *([^:]+):/gm), "$1while ($2) {"],
[new RegExp(/( +)for *([^ ,]+) +in +x?range(([^:]+)) *:/gm), "$1for (let $2 = 0; i < $3; i++) {"],
[new RegExp(/( +)for *([^ ,]+) +in +([^:]+) *:/gm), "$1for (let $2 of $3) {"],
[new RegExp(/( +)for *([^ ,]+) *, *([^ ,]+) +in enumerate\(+([^:]+)\) *:/gm), "$1for (let [$2, $3] of $4.entries()) {"],
// Try/Catch
[new RegExp(/( +)try *:/gm), "$1try {"],
[new RegExp(/( +)except *:/gm), "$1} catch(err) {"],
[new RegExp(/( +)except .* as ([^:]+)*:/gm), "$1} catch($2) {"],
// operators
[new RegExp(/is None/gm), "=== null"],
[new RegExp(/is not None/gm), "!== null"],
[new RegExp(/None/gm), "null"],
[new RegExp(/ or /gm), " || "],
[new RegExp(/ and /gm), " && "],
[new RegExp(/ not /gm), " !"],
[new RegExp(/\(not /gm), "(!"],
[new RegExp(/True/gm), "true"],
[new RegExp(/False/gm), "false"],
[new RegExp(/del /gm), " delete "],
[new RegExp(/jstype/gm), "typeof"],
[new RegExp(/str\(/gm), "String("],
[new RegExp(/len\(([^)]+)\)/gm), "$1.length"],
[new RegExp(/([( ])([^( ]+) +not in +([^ )]+)/gm), "$1!$3.includes($2)"],
[new RegExp(/([( ])([^( ]+) +in +([^ )]+)/gm), "$1$3.includes($2)"],
[new RegExp(/"""/gm), "`"],
// Arrays
[new RegExp(/\[ *([^]:]+) *: *\]/gm), ".slice($1)"],
[new RegExp(/\[ *: *([^]]+) *\]/gm), ".slice(0, $1)"],
[new RegExp(/\[ *([^]:]+) *: *([^]]+) *\]/gm), ".slice($1, $2)"],
[new RegExp(/\.append\(/gm), ".push("],
[new RegExp(/\.extend\(/gm), ".push(..."],
[new RegExp(/\[ *-([0-9]+) *\]/gm), ".slice(-$1)[0]"]
];
function getLineIndent(line) {
let non_space = false;
return line.split('').reduce((t, c) => {
if (non_space) return t;
if (c === ' ') t++;
else non_space = true;
return t;
}, 0)
}
function replaceFile(contents) {
let result = contents;
for (let change of regexps) {
result = result.replace(change[0], change[1])
}
const original_lines = result.split("\n");
const lines = [];
let previousLine = "";
let savedIndent = 0;
let lastNonEmpty = 0;
for (let line of original_lines) {
const currentIndent = getLineIndent(line);
if (line.trim() !== "" && currentIndent < savedIndent && line[currentIndent] != "}") {
let i = currentIndent;
let previousIndent = savedIndent;
const toAdd = []
while (i < previousIndent) {
previousIndent -= 4;
toAdd.push(" ".repeat(previousIndent) + "}")
}
lines.splice(lastNonEmpty + 1, 0, ...toAdd)
}
if (line.trim() !== "" && currentIndent < savedIndent)
savedIndent = currentIndent;
else if (currentIndent > savedIndent && previousLine.substr(-1) === "{") {
savedIndent += 4;
}
if (line.trim() !== "") {
previousLine = line.trim();
lastNonEmpty = lines.length;
}
line = line.trimEnd();
let lastChar = line.substr(-1);
if (lastChar == "\\") {
line.substr(0, line.length - 1).trimEnd();
lastChar = line.substr(-1);
}
if (![",", "{", "}", ""].includes(lastChar))
line += ";";
lines.push(line);
}
return lines.join("\n");
}
const fs = require("fs");
const glob = require("glob");
glob.glob("pyj/*.pyj", (err, files) => {
for (let file of files) {
const contents = fs.readFileSync(file).toString();
console.log("Converting ", file)
fs.writeFileSync(file + ".js", replaceFile(contents));
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment