AutomatedGoonChemiCompiler/compiler.js
2022-02-16 00:02:35 -05:00

347 lines
8.6 KiB
JavaScript

//Compiles code written in an assembly-like language into chemfuck for spacestation13 goonstation
//Version 1: No input code and only simple for-loop, no while-loop or true for, this allows variables to be completely hidden
////Notes:
// Number inputs are indicated with # followed by a number. So in code you should replace #s with just the number of the source
// The code ignores letter case and white space excluding the print command.
// new lines are used to indicate the next command
// comments begin with # just like python, however they must be on their own line
// The current version only checks for some syntax errors
// values must be separated by commas
////commands
//mov #a, #s, #t moves #a amount from #s source container number to #t target container
//movall #s, #t moves all the contents of #s source container number to #t target container
//temp #s, #v sets the temperature of #s source to #v value
//iso #a, #r, #s, #t isolates #a amount of #r reagent from #s source to #t target
//pill #s makes the contents of #s into pills. Identical to movall-ing the contents to 11
//vial #s makes the contents of #s into vials. Identical to movall-ing the contents to 12
//dump #s dumps the contents of #s. Identical to movall-ing the contents to 13
//compile this line anywhere in the code indicates that the resulting program should have ~ appended
//print <text> prints text. Ignores starting and ending whitespace
////loops
//sfor #i simple for loop, iterates the code below until end #i times. If #i <= 0 the code is skipped
//end markes the end of a loop
//setup globals
// ALL CREDDIT GOES TO SLUGO I (Caroline // retkid#9135) DIDN'T WRITE ANY OF THIS!
var ram = new Uint16Array(1024)
var regs = new Uint16Array(4)
var loopinds = []
//begin processing
function assembler(intext) {
ram = new Uint16Array(1024)
regs = new Uint16Array(4)
loopinds = []
let fck = ""
let compile = 0
let origlines = intext.split("\n")
//List of known commands
let vncoms = ["mov", "movall", "temp", "iso", "pill", "vial", "dump", "sfor"]
let vcoms = ["compile", "end"]
let lines = new Array(origlines.length)
for (let iter = 0; iter < origlines.length; iter++) {
let line = origlines[iter]
line = line.replace(/\s+/g, "")
line = line.toLowerCase()
lines[iter] = line
}
for (let iter = 1; iter <= lines.length; iter++) {
let line = lines[iter - 1]
//Ignore lines with no text or comments
if (!line || line.charAt(0) == "#") {
continue
}
//Commands with numbers
else if (vncoms.some((v) => line.startsWith(v))) {
if (!vncoms.some((x) => line.substring(0, 10).includes(x))) {
throw "No Valid Commands Found!\n" + line
}
//MOVALL command
if (line.substring(0, 6) == "movall") {
let vals = line.substring(6).split(",")
let tx = Number(vals[1])
app = settx(tx)
fck += app
let sx = Number(vals[0])
app = setsx(sx)
regs[3] = -1
app += prepnum(sx)
fck += app + ",@"
}
//MOV command
else if (line.substring(0, 3) == "mov") {
let vals = line.substring(3).split(",")
let ax = Number(vals[0])
let app = setax(ax)
fck += app
let sx = Number(vals[1])
app = setsx(sx)
fck += app
let tx = Number(vals[2])
app = settx(tx)
fck += app + "@"
}
//TEMP command
else if (line.substring(0, 4) == "temp") {
let vals = line.substring(4).split(",")
let sx = Number(vals[0])
let app = setsx(sx)
fck += app
let temp = Number(vals[1])
if (temp >= 273) {
app = settx(0)
fck += app
app = setax(temp - 273)
fck += app
} else {
app = setax(0)
fck += app
app = settx(273 - temp)
fck += app
}
fck += "$"
}
//ISO command
else if (line.substring(0, 3) == "iso") {
let vals = line.substring(3).split(",")
let ax = Number(vals[0])
let app = setax(ax)
fck += app
let sx = Number(vals[2])
app = setsx(sx)
fck += app
let tx = Number(vals[3])
app = settx(tx)
fck += app
let pnt = Number(vals[1])
app = prepnum(pnt)
fck += app + "#"
}
//PILL command
else if (line.substring(0, 4) == "pill") {
let app = settx(11)
fck += app
let sx = Number(line.substring(4))
app = setsx(sx)
regs[3] = -1
app += prepnum(sx)
fck += app + ",@"
}
//VIAL command
else if (line.substring(0, 4) == "vial") {
let app = settx(12)
fck += app
let sx = Number(line.substring(4))
app = setsx(sx)
regs[3] = -1
app += prepnum(sx)
fck += app + ",@"
}
//DUMP command
else if (line.substring(0, 4) == "dump") {
let app = settx(13)
fck += app
let sx = Number(line.substring(4))
app = setsx(sx)
regs[3] = -1
app += prepnum(sx)
fck += app + ",@"
}
//SFOR loop
else if (line.substring(0, 4) == "sfor") {
//Get all numbers in the loop before the loop
let endind = lines.indexOf("end", iter)
let numblist = []
for (let subind = iter; subind < endind; subind++) {
if (lines[subind].substring(0, 4) == "temp") {
let temp = Number(lines[subind].substring(4))
numblist.push(Math.abs(273 - temp))
} else {
numblist = numblist.concat(lines[subind].match(/\d+/g))
}
}
numblist = [...new Set(numblist)]
console.log(numblist)
for (let nmi = 0; nmi < numblist.length; nmi++) {
let nm = numblist[nmi]
let app = prepnum_nomove(Number(nm))
fck += app
}
//Set iterator and begin loop
let idx = ram.indexOf(0)
let app = setptr(idx, Number(line.substring(4)))
fck += app + "["
loopinds.push(regs[0])
}
}
//Commands without numbers
else if (vcoms.includes(line)) {
//COMPILE command
if (line == "compile") {
compile = 1
}
//END (sfor) command
else if (line == "end") {
let app = goTo(loopinds.pop())
fck += app + "-]"
}
}
//Print statement
else if (line.length > 5 && line.substring(0, 5) == "print") {
let text = origlines[iter - 1].substring(5)
text = text.trim()
let out = printtxt(text)
fck += out
}
//No known command
else {
return "Error: Unknown command >" + line + " on line " + iter
}
}
//Add compile character if requested
if (compile) {
fck += "~"
}
return fck
}
function printtxt(text) {
let fck = ""
for (var ci = 0; ci < text.length; ci++) {
let ascii = text.charCodeAt(ci)
let app = prepnum(ascii)
fck += app + "."
}
return fck
}
function setsx(val) {
if (regs[1] == val) {
return ""
}
let fck = prepnum(val)
fck += "}"
regs[1] = val
return fck
}
function settx(val) {
if (regs[2] == val) {
return ""
}
let fck = prepnum(val)
fck += ")"
regs[2] = val
return fck
}
function setax(val) {
if (regs[3] == val) {
return ""
}
let fck = prepnum(val)
fck += "'"
regs[3] = val
return fck
}
//sets the pointer to the requested value, this finds it if it exists
//already or sets a new value in ram
function prepnum(val) {
let inds = allInds(ram, val)
inds = inds.filter((x) => !loopinds.includes(x))
let fck = ""
if (inds.length > 0) {
fck = goTo(inds[0])
} else {
let idx = ram.indexOf(0)
fck = setptr(idx, val)
}
return fck
}
function prepnum_nomove(val) {
let inds = allInds(ram, val)
inds = inds.filter((x) => !loopinds.includes(x))
let fck = ""
if (inds.length > 0) {
fck = ""
} else {
let idx = ram.indexOf(0)
fck = setptr(idx, val)
}
return fck
}
function goTo(idx) {
let fck = ""
let ptr = regs[0]
let diff = idx - ptr
if (diff > 0) {
fck = ">".repeat(diff)
} else if (diff < 0) {
fck = "<".repeat(-diff)
}
regs[0] = idx
return fck
}
function setptr(idx, val) {
let fck = goTo(idx)
let diff = val - ram[idx]
if (diff > 0) {
fck += "+".repeat(diff)
} else if (diff < 0) {
fck += "-".repeat(-diff)
}
ram[idx] = val
return fck
}
//Found of stackexchange by user nnnnnn
function allInds(arr, val) {
var indexes = [],
i = -1
while ((i = arr.indexOf(val, i + 1)) != -1) {
indexes.push(i)
}
return indexes
}
exports.assembler = assembler