From 1a0984a0600f7dfcc10a961c6fde146116973b8a Mon Sep 17 00:00:00 2001 From: Ruthenic Date: Wed, 22 Feb 2023 09:29:45 -0500 Subject: [PATCH] init --- .gitignore | 1 + .vscode/settings.json | 9 + LrisScript.d.ts | 7 + deno.json | 7 + deno.lock | 134 ++++++++++++ src/index.d.ts | 12 ++ src/index.ts | 144 +++++++++++++ src/nodes/ExpressionStatement.ts | 217 +++++++++++++++++++ src/nodes/IfStatement.ts | 130 ++++++++++++ src/nodes/VariableDeclaration.ts | 325 ++++++++++++++++++++++++++++ src/nodes/WhileStatement.ts | 354 +++++++++++++++++++++++++++++++ 11 files changed, 1340 insertions(+) create mode 100644 .gitignore create mode 100644 .vscode/settings.json create mode 100644 LrisScript.d.ts create mode 100644 deno.json create mode 100644 deno.lock create mode 100644 src/index.d.ts create mode 100644 src/index.ts create mode 100644 src/nodes/ExpressionStatement.ts create mode 100644 src/nodes/IfStatement.ts create mode 100644 src/nodes/VariableDeclaration.ts create mode 100644 src/nodes/WhileStatement.ts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4a559b5 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +tstest.ts diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..c8bd270 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,9 @@ +{ + "deno.enable": true, + "deno.unstable": true, + "editor.formatOnSave": true, + "[typescript]": { + "editor.tabSize": 4, + "editor.defaultFormatter": "denoland.vscode-deno" + } +} diff --git a/LrisScript.d.ts b/LrisScript.d.ts new file mode 100644 index 0000000..8cb184b --- /dev/null +++ b/LrisScript.d.ts @@ -0,0 +1,7 @@ +export {}; + +declare global { + function free(variable: unknown): void; + function print(arg: string | number | boolean): void; + function println(arg: string | number | boolean): void; +} diff --git a/deno.json b/deno.json new file mode 100644 index 0000000..541a5c4 --- /dev/null +++ b/deno.json @@ -0,0 +1,7 @@ +{ + "fmt": { + "options": { + "indentWidth": 4 + } + } +} diff --git a/deno.lock b/deno.lock new file mode 100644 index 0000000..d8a788f --- /dev/null +++ b/deno.lock @@ -0,0 +1,134 @@ +{ + "version": "2", + "remote": { + "https://deno.land/std@0.170.0/fmt/colors.ts": "03ad95e543d2808bc43c17a3dd29d25b43d0f16287fe562a0be89bf632454a12", + "https://deno.land/x/cliffy@v0.25.7/_utils/distance.ts": "02af166952c7c358ac83beae397aa2fbca4ad630aecfcd38d92edb1ea429f004", + "https://deno.land/x/cliffy@v0.25.7/command/_errors.ts": "a9bd23dc816b32ec96c9b8f3057218241778d8c40333b43341138191450965e5", + "https://deno.land/x/cliffy@v0.25.7/command/_utils.ts": "9ab3d69fabab6c335b881b8a5229cbd5db0c68f630a1c307aff988b6396d9baf", + "https://deno.land/x/cliffy@v0.25.7/command/command.ts": "a2b83c612acd65c69116f70dec872f6da383699b83874b70fcf38cddf790443f", + "https://deno.land/x/cliffy@v0.25.7/command/completions/_bash_completions_generator.ts": "43b4abb543d4dc60233620d51e69d82d3b7c44e274e723681e0dce2a124f69f9", + "https://deno.land/x/cliffy@v0.25.7/command/completions/_fish_completions_generator.ts": "d0289985f5cf0bd288c05273bfa286b24c27feb40822eb7fd9d7fee64e6580e8", + "https://deno.land/x/cliffy@v0.25.7/command/completions/_zsh_completions_generator.ts": "14461eb274954fea4953ee75938821f721da7da607dc49bcc7db1e3f33a207bd", + "https://deno.land/x/cliffy@v0.25.7/command/completions/bash.ts": "053aa2006ec327ccecacb00ba28e5eb836300e5c1bec1b3cfaee9ddcf8189756", + "https://deno.land/x/cliffy@v0.25.7/command/completions/complete.ts": "58df61caa5e6220ff2768636a69337923ad9d4b8c1932aeb27165081c4d07d8b", + "https://deno.land/x/cliffy@v0.25.7/command/completions/fish.ts": "9938beaa6458c6cf9e2eeda46a09e8cd362d4f8c6c9efe87d3cd8ca7477402a5", + "https://deno.land/x/cliffy@v0.25.7/command/completions/mod.ts": "aeef7ec8e319bb157c39a4bab8030c9fe8fa327b4c1e94c9c1025077b45b40c0", + "https://deno.land/x/cliffy@v0.25.7/command/completions/zsh.ts": "8b04ab244a0b582f7927d405e17b38602428eeb347a9968a657e7ea9f40e721a", + "https://deno.land/x/cliffy@v0.25.7/command/deprecated.ts": "bbe6670f1d645b773d04b725b8b8e7814c862c9f1afba460c4d599ffe9d4983c", + "https://deno.land/x/cliffy@v0.25.7/command/deps.ts": "275b964ce173770bae65f6b8ebe9d2fd557dc10292cdd1ed3db1735f0d77fa1d", + "https://deno.land/x/cliffy@v0.25.7/command/help/_help_generator.ts": "f7c349cb2ddb737e70dc1f89bcb1943ca9017a53506be0d4138e0aadb9970a49", + "https://deno.land/x/cliffy@v0.25.7/command/help/mod.ts": "09d74d3eb42d21285407cda688074c29595d9c927b69aedf9d05ff3f215820d3", + "https://deno.land/x/cliffy@v0.25.7/command/mod.ts": "d0a32df6b14028e43bb2d41fa87d24bc00f9662a44e5a177b3db02f93e473209", + "https://deno.land/x/cliffy@v0.25.7/command/type.ts": "24e88e3085e1574662b856ccce70d589959648817135d4469fab67b9cce1b364", + "https://deno.land/x/cliffy@v0.25.7/command/types.ts": "ae02eec0ed7a769f7dba2dd5d3a931a61724b3021271b1b565cf189d9adfd4a0", + "https://deno.land/x/cliffy@v0.25.7/command/types/action_list.ts": "33c98d449617c7a563a535c9ceb3741bde9f6363353fd492f90a74570c611c27", + "https://deno.land/x/cliffy@v0.25.7/command/types/boolean.ts": "3879ec16092b4b5b1a0acb8675f8c9250c0b8a972e1e4c7adfba8335bd2263ed", + "https://deno.land/x/cliffy@v0.25.7/command/types/child_command.ts": "f1fca390c7fbfa7a713ca15ef55c2c7656bcbb394d50e8ef54085bdf6dc22559", + "https://deno.land/x/cliffy@v0.25.7/command/types/command.ts": "325d0382e383b725fd8d0ef34ebaeae082c5b76a1f6f2e843fee5dbb1a4fe3ac", + "https://deno.land/x/cliffy@v0.25.7/command/types/enum.ts": "2178345972adf7129a47e5f02856ca3e6852a91442a1c78307dffb8a6a3c6c9f", + "https://deno.land/x/cliffy@v0.25.7/command/types/file.ts": "8618f16ac9015c8589cbd946b3de1988cc4899b90ea251f3325c93c46745140e", + "https://deno.land/x/cliffy@v0.25.7/command/types/integer.ts": "29864725fd48738579d18123d7ee78fed37515e6dc62146c7544c98a82f1778d", + "https://deno.land/x/cliffy@v0.25.7/command/types/number.ts": "aeba96e6f470309317a16b308c82e0e4138a830ec79c9877e4622c682012bc1f", + "https://deno.land/x/cliffy@v0.25.7/command/types/string.ts": "e4dadb08a11795474871c7967beab954593813bb53d9f69ea5f9b734e43dc0e0", + "https://deno.land/x/cliffy@v0.25.7/command/upgrade/mod.ts": "17e2df3b620905583256684415e6c4a31e8de5c59066eb6d6c9c133919292dc4", + "https://deno.land/x/cliffy@v0.25.7/command/upgrade/provider.ts": "d6fb846043232cbd23c57d257100c7fc92274984d75a5fead0f3e4266dc76ab8", + "https://deno.land/x/cliffy@v0.25.7/command/upgrade/provider/deno_land.ts": "24f8d82e38c51e09be989f30f8ad21f9dd41ac1bb1973b443a13883e8ba06d6d", + "https://deno.land/x/cliffy@v0.25.7/command/upgrade/provider/github.ts": "99e1b133dd446c6aa79f69e69c46eb8bc1c968dd331c2a7d4064514a317c7b59", + "https://deno.land/x/cliffy@v0.25.7/command/upgrade/provider/nest_land.ts": "0e07936cea04fa41ac9297f32d87f39152ea873970c54cb5b4934b12fee1885e", + "https://deno.land/x/cliffy@v0.25.7/command/upgrade/upgrade_command.ts": "3640a287d914190241ea1e636774b1b4b0e1828fa75119971dd5304784061e05", + "https://deno.land/x/cliffy@v0.25.7/flags/_errors.ts": "f1fbb6bfa009e7950508c9d491cfb4a5551027d9f453389606adb3f2327d048f", + "https://deno.land/x/cliffy@v0.25.7/flags/_utils.ts": "340d3ecab43cde9489187e1f176504d2c58485df6652d1cdd907c0e9c3ce4cc2", + "https://deno.land/x/cliffy@v0.25.7/flags/_validate_flags.ts": "16eb5837986c6f6f7620817820161a78d66ce92d690e3697068726bbef067452", + "https://deno.land/x/cliffy@v0.25.7/flags/deprecated.ts": "a72a35de3cc7314e5ebea605ca23d08385b218ef171c32a3f135fb4318b08126", + "https://deno.land/x/cliffy@v0.25.7/flags/flags.ts": "68a9dfcacc4983a84c07ba19b66e5e9fccd04389fad215210c60fb414cc62576", + "https://deno.land/x/cliffy@v0.25.7/flags/types.ts": "7452ea5296758fb7af89930349ce40d8eb9a43b24b3f5759283e1cb5113075fd", + "https://deno.land/x/cliffy@v0.25.7/flags/types/boolean.ts": "4c026dd66ec9c5436860dc6d0241427bdb8d8e07337ad71b33c08193428a2236", + "https://deno.land/x/cliffy@v0.25.7/flags/types/integer.ts": "b60d4d590f309ddddf066782d43e4dc3799f0e7d08e5ede7dc62a5ee94b9a6d9", + "https://deno.land/x/cliffy@v0.25.7/flags/types/number.ts": "610936e2d29de7c8c304b65489a75ebae17b005c6122c24e791fbed12444d51e", + "https://deno.land/x/cliffy@v0.25.7/flags/types/string.ts": "e89b6a5ce322f65a894edecdc48b44956ec246a1d881f03e97bbda90dd8638c5", + "https://deno.land/x/cliffy@v0.25.7/table/border.ts": "2514abae4e4f51eda60a5f8c927ba24efd464a590027e900926b38f68e01253c", + "https://deno.land/x/cliffy@v0.25.7/table/cell.ts": "1d787d8006ac8302020d18ec39f8d7f1113612c20801b973e3839de9c3f8b7b3", + "https://deno.land/x/cliffy@v0.25.7/table/deps.ts": "5b05fa56c1a5e2af34f2103fd199e5f87f0507549963019563eae519271819d2", + "https://deno.land/x/cliffy@v0.25.7/table/layout.ts": "46bf10ae5430cf4fbb92f23d588230e9c6336edbdb154e5c9581290562b169f4", + "https://deno.land/x/cliffy@v0.25.7/table/row.ts": "5f519ba7488d2ef76cbbf50527f10f7957bfd668ce5b9169abbc44ec88302645", + "https://deno.land/x/cliffy@v0.25.7/table/table.ts": "ec204c9d08bb3ff1939c5ac7412a4c9ed7d00925d4fc92aff9bfe07bd269258d", + "https://deno.land/x/cliffy@v0.25.7/table/utils.ts": "187bb7dcbcfb16199a5d906113f584740901dfca1007400cba0df7dcd341bc29" + }, + "npm": { + "specifiers": { + "@swc/core@1.3.35": "@swc/core@1.3.35", + "@swc/wasm-web@1.3.35": "@swc/wasm-web@1.3.35", + "@swc/wasm@1.3.35": "@swc/wasm@1.3.35", + "acorn@8.8.2": "acorn@8.8.2" + }, + "packages": { + "@swc/core-darwin-arm64@1.3.35": { + "integrity": "sha512-zQUFkHx4gZpu0uo2IspvPnKsz8bsdXd5bC33xwjtoAI1cpLerDyqo4v2zIahEp+FdKZjyVsLHtfJiQiA1Qka3A==", + "dependencies": {} + }, + "@swc/core-darwin-x64@1.3.35": { + "integrity": "sha512-oOSkSGWtALovaw22lNevKD434OQTPf8X+dVPvPMrJXJpJ34dWDlFWpLntoc+arvKLNZ7LQmTuk8rR1hkrAY7cw==", + "dependencies": {} + }, + "@swc/core-linux-arm-gnueabihf@1.3.35": { + "integrity": "sha512-Yie8k00O6O8BCATS/xeKStquV4OYSskUGRDXBQVDw1FrE23PHaSeHCgg4q6iNZjJzXCOJbaTCKnYoIDn9DMf7A==", + "dependencies": {} + }, + "@swc/core-linux-arm64-gnu@1.3.35": { + "integrity": "sha512-Zlv3WHa/4x2p51HSvjUWXHfSe1Gl2prqImUZJc8NZOlj75BFzVuR0auhQ+LbwvIQ3gaA1LODX9lyS9wXL3yjxA==", + "dependencies": {} + }, + "@swc/core-linux-arm64-musl@1.3.35": { + "integrity": "sha512-u6tCYsrSyZ8U+4jLMA/O82veBfLy2aUpn51WxQaeH7wqZGy9TGSJXoO8vWxARQ6b72vjsnKDJHP4MD8hFwcctg==", + "dependencies": {} + }, + "@swc/core-linux-x64-gnu@1.3.35": { + "integrity": "sha512-Dtxf2IbeH7XlNhP1Qt2/MvUPkpEbn7hhGfpSRs4ot8D3Vf5QEX4S/QtC1OsFWuciiYgHAT1Ybjt4xZic9DSkmA==", + "dependencies": {} + }, + "@swc/core-linux-x64-musl@1.3.35": { + "integrity": "sha512-4XavNJ60GprjpTiESCu5daJUnmErixPAqDitJSMu4TV32LNIE8G00S9pDLXinDTW1rgcGtQdq1NLkNRmwwovtg==", + "dependencies": {} + }, + "@swc/core-win32-arm64-msvc@1.3.35": { + "integrity": "sha512-dNGfKCUSX2M4qVyaS80Lyos0FkXyHRCvrdQ2Y4Hrg3FVokiuw3yY6fLohpUfQ5ws3n2A39dh7jGDeh34+l0sGA==", + "dependencies": {} + }, + "@swc/core-win32-ia32-msvc@1.3.35": { + "integrity": "sha512-ChuPSrDR+JBf7S7dEKPicnG8A3bM0uWPsW2vG+V2wH4iNfNxKVemESHosmYVeEZXqMpomNMvLyeHep1rjRsc0Q==", + "dependencies": {} + }, + "@swc/core-win32-x64-msvc@1.3.35": { + "integrity": "sha512-/RvphT4WfuGfIK84Ha0dovdPrKB1bW/mc+dtdmhv2E3EGkNc5FoueNwYmXWRimxnU7X0X7IkcRhyKB4G5DeAmg==", + "dependencies": {} + }, + "@swc/core@1.3.35": { + "integrity": "sha512-KmiBin0XSVzJhzX19zTiCqmLslZ40Cl7zqskJcTDeIrRhfgKdiAsxzYUanJgMJIRjYtl9Kcg1V/Ip2o2wL8v3w==", + "dependencies": { + "@swc/core-darwin-arm64": "@swc/core-darwin-arm64@1.3.35", + "@swc/core-darwin-x64": "@swc/core-darwin-x64@1.3.35", + "@swc/core-linux-arm-gnueabihf": "@swc/core-linux-arm-gnueabihf@1.3.35", + "@swc/core-linux-arm64-gnu": "@swc/core-linux-arm64-gnu@1.3.35", + "@swc/core-linux-arm64-musl": "@swc/core-linux-arm64-musl@1.3.35", + "@swc/core-linux-x64-gnu": "@swc/core-linux-x64-gnu@1.3.35", + "@swc/core-linux-x64-musl": "@swc/core-linux-x64-musl@1.3.35", + "@swc/core-win32-arm64-msvc": "@swc/core-win32-arm64-msvc@1.3.35", + "@swc/core-win32-ia32-msvc": "@swc/core-win32-ia32-msvc@1.3.35", + "@swc/core-win32-x64-msvc": "@swc/core-win32-x64-msvc@1.3.35" + } + }, + "@swc/wasm-web@1.3.35": { + "integrity": "sha512-iMNkVgHGJgSJsekNIyyDme8DazmQvMwd2qYsWAqA9IZHtbuvurIfhSiK2nMqN5nM+YEWIoa/y1Daug49DuyDxg==", + "dependencies": {} + }, + "@swc/wasm@1.3.35": { + "integrity": "sha512-8xBOgl9eziAuqF4HYwYx4Kh6eHfOQECvO0ZMlrFNW0jgE+ntqxcRjBhuzZ6iWb24nifzXbuGLQntbns4IJYJgQ==", + "dependencies": {} + }, + "acorn@8.8.2": { + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "dependencies": {} + } + } + } +} diff --git a/src/index.d.ts b/src/index.d.ts new file mode 100644 index 0000000..1bfb179 --- /dev/null +++ b/src/index.d.ts @@ -0,0 +1,12 @@ +type VariablesTableType = { + [name: string]: { + memoryLocation: number; + memorySize: number; + memoryType: "string" | "int" | "bool"; + }; +}; + +type VariablesThingType = { + getVariableMemoryOffset: (varSize: number) => number; + freeVariable: (variableName: string) => void; +}; diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..a06b7a0 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,144 @@ +import { Command } from "https://deno.land/x/cliffy@v0.25.7/command/mod.ts"; +import swc from "npm:@swc/wasm@1.3.35"; + +import VariableDeclaration from "./nodes/VariableDeclaration.ts"; +import ExpressionStatement from "./nodes/ExpressionStatement.ts"; +import IfStatement from "./nodes/IfStatement.ts"; +import WhileStatement from "./nodes/WhileStatement.ts"; + +const { args } = await new Command() + .name("lrisscript") + .version("0.0.1") + .description( + "Compiles LrisScript (goofy subset of JS) to LASM (LRIS text representation)", + ) + .arguments(" [output:string]") + .parse(Deno.args); + +let ast: swc.Module; + +if (args[0].endsWith(".ts")) { + ast = await swc.parse(await Deno.readTextFile(args[0]), { + syntax: "typescript", + }); +} else { + ast = await swc.parse(await Deno.readTextFile(args[0]), { + syntax: "ecmascript", + }); +} + +const variablesTable: VariablesTableType = {}; +const variableHoles: { + memoryLocation: number; + memorySize: number; +}[] = []; // 😳 +// deno-lint-ignore prefer-const +let variableMemoryOffset = { + offset: 0x011F, +}; +function getVariableMemoryOffset(varSize: number) { + for (const memoryHole of variableHoles) { + if (varSize <= memoryHole.memorySize) { + memoryHole.memorySize -= varSize; + return memoryHole.memoryLocation; + } + } + const oldMemoryOffset = variableMemoryOffset.offset; + variableMemoryOffset.offset += varSize; + return oldMemoryOffset; +} +// FIXME: zero out old memory here +function freeVariable(variableName: string) { + const variableInfo = variablesTable[variableName]; + delete variablesTable[variableName]; + variableHoles.push({ + memoryLocation: variableInfo.memoryLocation, + memorySize: variableInfo.memorySize, + }); +} + +function resolveNode( + node: swc.Node, + prc: { count: number }, + variableModificationThings: VariablesThingType, + variablesTable: VariablesTableType, +) { + // deno-lint-ignore prefer-const + let instructions: string[] = []; + switch (node.type) { + case "VariableDeclaration": { + VariableDeclaration( + node, + variablesTable, + variableModificationThings, + prc, + instructions, + ); + break; + } + case "ExpressionStatement": { + ExpressionStatement( + node, + variablesTable, + variableModificationThings, + prc, + instructions, + ); + break; + } + case "IfStatement": { + IfStatement( + node, + variablesTable, + variableModificationThings, + prc, + instructions, + ); + break; + } + case "WhileStatement": { + WhileStatement( + node, + variablesTable, + variableModificationThings, + prc, + instructions, + ); + break; + } + default: + throw new Error(`Unimplemented node ${node.type}`); + } + return instructions; +} + +export { resolveNode }; + +// deno-lint-ignore prefer-const +let prc = { + // i love java's crypt for only doing references in objects + count: 0, +}; +let outputInstructions: string[] = []; +for (const node of ast.body) { + outputInstructions = outputInstructions.concat( + resolveNode( + node, + prc, + { + getVariableMemoryOffset, + freeVariable, + }, + variablesTable, + ), + ); + console.log(variablesTable); + console.log(prc.count); +} +outputInstructions.push("HLT"); + +if (args[1]) { + await Deno.writeTextFile(`./${args[1]}`, outputInstructions.join("\n")); +} else { + console.log(outputInstructions.join("\n")); +} diff --git a/src/nodes/ExpressionStatement.ts b/src/nodes/ExpressionStatement.ts new file mode 100644 index 0000000..1acc08d --- /dev/null +++ b/src/nodes/ExpressionStatement.ts @@ -0,0 +1,217 @@ +import swc from "npm:@swc/wasm@1.3.35"; +import VariableDeclaration from "./VariableDeclaration.ts"; + +export default function ExpressionStatement( + node: swc.Node, + variablesTable: VariablesTableType, + variableModificationThings: VariablesThingType, + prc: { count: number }, + instructions: string[], +) { + const expression = (node as swc.ExpressionStatement) + .expression; + switch (expression.type) { + case "CallExpression": { + const typedNode = expression as swc.CallExpression; + const functionName = (typedNode.callee as swc.Identifier).value; + + switch (functionName) { + case "print": + case "println": { + if (typedNode.arguments.length !== 1) { + throw new Error( + "Incorrect arguments passed to println", + ); + } + switch (typedNode.arguments[0].expression.type) { + case "Identifier": { + const typedExpr = typedNode.arguments[0] + .expression as swc.Identifier; + const variableInfo = + variablesTable[typedExpr.value]; + if ( + variableInfo.memoryType === "int" || + variableInfo.memoryType === "bool" + ) { + instructions.push(`LOL 01 0119`); + prc.count += 4; + } + instructions.push(`LOL 00 0118`); + instructions.push(`LOL 01 0117`); + prc.count += 8; + for ( + let i = variableInfo.memoryLocation; + i < + variableInfo.memoryLocation + + variableInfo.memorySize; + i++ + ) { + instructions.push( + `LOA ${ + i.toString(16).padStart( + 4, + "0", + ) + } 0118`, + ); + prc.count += 5; + } + instructions.push(`LOL 00 0117`); + prc.count += 4; + break; + } + case "StringLiteral": { + //define tmp variable + const typedExpr = typedNode.arguments[0] + .expression as swc.StringLiteral; + const tmpVariableName = "printTmpVar"; + VariableDeclaration( + { + declarations: [{ + id: { + value: tmpVariableName, + }, + init: { + type: "StringLiteral", + value: typedExpr.value, + }, + }], + } as swc.VariableDeclaration, + variablesTable, + variableModificationThings, + prc, + instructions, + ); + const variableInfo = + variablesTable[tmpVariableName]; + // pritning code + instructions.push(`LOL 00 0118`); + instructions.push(`LOL 01 0117`); + prc.count += 8; + for ( + let i = variableInfo.memoryLocation; + i < + variableInfo.memoryLocation + + variableInfo.memorySize; + i++ + ) { + instructions.push( + `LOA ${ + i.toString(16).padStart( + 4, + "0", + ) + } 0118`, + ); + prc.count += 5; + } + instructions.push(`LOL 00 0117`); + prc.count += 4; + //free tmp variable + variableModificationThings.freeVariable( + tmpVariableName, + ); + break; + } + default: + throw new Error( + `node type ${ + typedNode.arguments[0].expression.type + } not allowed in println`, + ); + } + instructions.push(`LOL 00 0119`); + instructions.push(`LOL 00 0118`); + prc.count += 8; + + // print newline + if (functionName === "println") { + instructions.push(`LOL 01 0116`); + instructions.push(`LOL 01 0117`); + instructions.push(`LOL 00 0116`); + instructions.push(`LOL 00 0117`); + prc.count += 16; + } + break; + } + case "asm": { + const typedNode = (node as swc.ExpressionStatement) + .expression as swc.CallExpression; + const typedValue = typedNode.arguments[0] + .expression as swc.Identifier; + instructions.push(typedValue.value); + const eles = typedValue.value.split(" "); + eles.shift(); + prc.count += 1; + for (let i = 0; i < eles.length; i++) { + const e = eles[i]; + + switch (e.length) { + case 2: { + prc.count += 1; + break; + } + case 4: { + prc.count += 2; + break; + } + default: + throw new Error( + "what the hell are you doing in your inline assembly", + ); + } + } + break; + } + case "free": { + const typedNode = (node as swc.ExpressionStatement) + .expression as swc.CallExpression; + const typedValue = typedNode.arguments[0] + .expression as swc.Identifier; + variableModificationThings.freeVariable(typedValue.value); + break; + } + default: + throw new Error( + `Unimplemented function ${functionName}`, + ); + } + break; + } + case "AssignmentExpression": { + const typedNode = expression as swc.AssignmentExpression; + switch (expression.operator) { + case "=": { + const variableInfo = variablesTable[ + (expression.left as swc.Identifier).value + ]; + if (variableInfo.memoryType === "string") { + throw new Error( + "string variable reassignment not supported", + ); + } else { + VariableDeclaration( + { + type: "VariableDeclaration", + declarations: [ + { + init: typedNode.right, + id: typedNode.left, + }, + ], + } as swc.VariableDeclaration, + variablesTable, + variableModificationThings, + prc, + instructions, + ); + } + break; + } + default: + throw new Error("please kill me"); + } + break; + } + } +} diff --git a/src/nodes/IfStatement.ts b/src/nodes/IfStatement.ts new file mode 100644 index 0000000..59f4856 --- /dev/null +++ b/src/nodes/IfStatement.ts @@ -0,0 +1,130 @@ +import swc from "npm:@swc/wasm@1.3.35"; +import { resolveNode } from "../index.ts"; + +export default function IfStatement( + node: swc.Node, + variablesTable: VariablesTableType, + variableModificationThings: VariablesThingType, + prc: { count: number }, + mainInstructions: string[], +) { + const typedNode = node as swc.IfStatement; + switch (typedNode.test.type) { + case "BinaryExpression": { + const typedExpr = typedNode.test as swc.BinaryExpression; + let addr1: number; + let addr2: number; + switch (typedExpr.left.type) { + case "Identifier": { + const typedValue = typedExpr.left; + const variableInfo = variablesTable[typedValue.value]; + if (variableInfo.memoryType === "string") { + // TODO: implement string comparisons + throw new Error( + "i would rather pipi in pampers than implement string comparisons", + ); + } + addr1 = variableInfo.memoryLocation; + break; + } + default: + throw new Error( + `left side comparison not implemented for node type ${typedExpr.left.type}`, + ); + } + switch (typedExpr.right.type) { + case "Identifier": { + const typedValue = typedExpr.right; + const variableInfo = variablesTable[typedValue.value]; + if (variableInfo.memoryType === "string") { + // TODO: implement string comparisons + throw new Error( + "i would rather pipi in pampers than implement string comparisons", + ); + } + addr2 = variableInfo.memoryLocation; + break; + } + case "BooleanLiteral": { + const value = typedExpr.right.value; + mainInstructions.push( + `LOL ${value ? "01" : "00"} 00F2`, + ); + addr2 = 0x00F2; + prc.count += 4; + break; + } + default: + throw new Error( + `right side comparison not implemented for node type ${typedExpr.right.type}`, + ); + } + let ourInsts = [`${(() => { + switch (typedExpr.operator) { + case "!=": + case "!==": + return "JEA"; + case "==": + case "===": + return "JNA"; + default: + throw new Error( + `if statement comparison operator ${typedExpr.operator} unimplemented`, + ); + } + })} TODO${ + ( + typedExpr.operator === "<" || + typedExpr.operator === ">" + ) + ? ` ${ + addr1.toString(16).padStart( + 4, + "0", + ) + } ${ + addr2.toString(16).padStart( + 4, + "0", + ) + }` + : "" + }`]; + prc.count += 7; + const oldPRC = prc; + for ( + const node of (typedNode.consequent as swc.BlockStatement) + .stmts + ) { + ourInsts = ourInsts.concat( + resolveNode( + node, + prc, + variableModificationThings, + variablesTable, + ), + ); + } + ourInsts[0] = ourInsts[0].replace( + "TODO", + prc.count.toString(16).padStart( + 4, + "0", + ), + ); + + ourInsts.push("NOP"); + prc.count++; + + for (const inst of ourInsts) { + mainInstructions.push(inst); + } + + break; + } + default: + throw new Error( + `if statement test with node type ${typedNode.test.type} not implemented`, + ); + } +} diff --git a/src/nodes/VariableDeclaration.ts b/src/nodes/VariableDeclaration.ts new file mode 100644 index 0000000..46eda9d --- /dev/null +++ b/src/nodes/VariableDeclaration.ts @@ -0,0 +1,325 @@ +import swc from "npm:@swc/wasm@1.3.35"; + +export default function VariableDeclaration( + node: swc.Node, + variablesTable: VariablesTableType, + variableModificationThings: VariablesThingType, + prc: { count: number }, + instructions: string[], +) { + const typedNode = node as swc.VariableDeclaration; + switch (typedNode.declarations[0].init?.type) { + case "StringLiteral": { + const typedValue = typedNode.declarations[0] + .init as swc.StringLiteral; + variablesTable[ + (typedNode.declarations[0].id as swc.Identifier).value + ] = { + memorySize: typedValue.value.length, + memoryLocation: variableModificationThings + .getVariableMemoryOffset(typedValue.value.length), + memoryType: "string", + }; + for (let i = 0; i < typedValue.value.length; i++) { + const char = typedValue.value[i]; + const charCode = char.charCodeAt(0); + instructions.push( + `LOL ${charCode.toString(16).padStart(2, "0")} ${ + (variablesTable[ + (typedNode.declarations[0].id as swc.Identifier) + .value + ].memoryLocation + i).toString(16).padStart( + 4, + "0", + ) + }`, + ); + prc.count += 4; + } + break; + } + case "NumericLiteral": { + const typedValue = typedNode.declarations[0] + .init as swc.NumericLiteral; + if (typedValue.value > 255) { + // TODO: implement 16-bit etc. + throw new Error("only 8-bit integers allowed"); + } + if ( + !variablesTable[ + (typedNode.declarations[0].id as swc.Identifier).value + ] + ) { + variablesTable[ + (typedNode.declarations[0].id as swc.Identifier).value + ] = { + memorySize: 1, + memoryLocation: variableModificationThings + .getVariableMemoryOffset(1), + memoryType: "int", + }; + } + instructions.push( + `LOL ${typedValue.value.toString(16).padStart(2, "0")} ${ + variablesTable[ + (typedNode.declarations[0].id as swc.Identifier).value + ].memoryLocation.toString(16).padStart( + 4, + "0", + ) + }`, + ); + prc.count += 4; + break; + } + case "BooleanLiteral": { + const typedValue = typedNode.declarations[0] + .init as swc.BooleanLiteral; + if ( + !variablesTable[ + (typedNode.declarations[0].id as swc.Identifier).value + ] + ) { + variablesTable[ + (typedNode.declarations[0].id as swc.Identifier).value + ] = { + memorySize: 1, + memoryLocation: variableModificationThings + .getVariableMemoryOffset(1), + memoryType: "bool", + }; + } + instructions.push( + `LOL ${typedValue.value ? "01" : "00"} ${ + variablesTable[ + (typedNode.declarations[0].id as swc.Identifier).value + ].memoryLocation.toString(16).padStart( + 4, + "0", + ) + }`, + ); + prc.count += 4; + break; + } + // FIXME: this should be impled elsewhere, especially because recursion + case "BinaryExpression": { + const typedValue = typedNode.declarations[0] + .init as swc.BinaryExpression; + switch (typedValue.operator) { + case "+": { + switch (typedValue.left.type) { + case "Identifier": { + switch (typedValue.right.type) { + case "Identifier": { + const leftVar = variablesTable[ + typedValue.left.value + ]; + const rightVar = variablesTable[ + typedValue.right.value + ]; + instructions.push( + `AAA ${ + leftVar.memoryLocation + .toString(16).padStart( + 4, + "0", + ) + } ${ + rightVar.memoryLocation + .toString(16).padStart( + 4, + "0", + ) + }`, + ); + prc.count += 5; + if ( + !variablesTable[ + (typedNode.declarations[0] + .id as swc.Identifier).value + ] + ) { + variablesTable[ + (typedNode.declarations[0] + .id as swc.Identifier).value + ] = { + memorySize: 1, + memoryLocation: + variableModificationThings + .getVariableMemoryOffset(1), + memoryType: "int", + }; + } + instructions.push( + `STA ${ + variablesTable[ + (typedNode.declarations[0] + .id as swc.Identifier).value + ].memoryLocation + .toString(16).padStart( + 4, + "0", + ) + }`, + ); + prc.count += 3; + break; + } + case "NumericLiteral": { + const leftVar = variablesTable[ + typedValue.left.value + ]; + const rightVal = typedValue.right.value; + instructions.push( + `LOL ${ + rightVal.toString(16).padStart( + 2, + "0", + ) + } 00F0`, + ); + prc.count += 4; + instructions.push( + `AAA ${ + leftVar.memoryLocation + .toString(16).padStart( + 4, + "0", + ) + } 00F0`, + ); + prc.count += 5; + if ( + !variablesTable[ + (typedNode.declarations[0] + .id as swc.Identifier).value + ] + ) { + variablesTable[ + (typedNode.declarations[0] + .id as swc.Identifier).value + ] = { + memorySize: 1, + memoryLocation: + variableModificationThings + .getVariableMemoryOffset(1), + memoryType: "int", + }; + } + instructions.push( + `STA ${ + variablesTable[ + (typedNode.declarations[0] + .id as swc.Identifier).value + ].memoryLocation + .toString(16).padStart( + 4, + "0", + ) + }`, + ); + prc.count += 3; + break; + } + default: + throw new Error( + `Arithmetic on ${typedValue.right.type} not implemented`, + ); + } + break; + } + default: + throw new Error( + `Arithmetic on ${typedValue.left.type} not implemented`, + ); + } + break; + } + case "-": { + switch (typedValue.left.type) { + case "Identifier": { + switch (typedValue.right.type) { + case "Identifier": { + const leftVar = variablesTable[ + typedValue.left.value + ]; + const rightVar = variablesTable[ + typedValue.right.value + ]; + instructions.push( + `SAA ${ + leftVar.memoryLocation + .toString(16).padStart( + 4, + "0", + ) + } ${ + rightVar.memoryLocation + .toString(16).padStart( + 4, + "0", + ) + }`, + ); + prc.count += 5; + if ( + !variablesTable[ + (typedNode.declarations[0] + .id as swc.Identifier).value + ] + ) { + variablesTable[ + (typedNode.declarations[0] + .id as swc.Identifier).value + ] = { + memorySize: 1, + memoryLocation: + variableModificationThings + .getVariableMemoryOffset(1), + memoryType: "int", + }; + } + instructions.push( + `STA ${ + variablesTable[ + (typedNode.declarations[0] + .id as swc.Identifier).value + ].memoryLocation + .toString(16).padStart( + 4, + "0", + ) + }`, + ); + prc.count += 3; + break; + } + default: + throw new Error( + `Arithmetic on ${typedValue.right.type} not implemented`, + ); + } + break; + } + default: + throw new Error( + `Arithmetic on ${typedValue.left.type} not implemented`, + ); + } + break; + } + default: + throw new Error( + `Operator type ${typedValue.operator} not implemented`, + ); + } + break; + } + default: + throw new Error( + `Variable type ${typedNode.declarations[0].init + ?.type} not implemented`, + ); + } +} diff --git a/src/nodes/WhileStatement.ts b/src/nodes/WhileStatement.ts new file mode 100644 index 0000000..d256f6a --- /dev/null +++ b/src/nodes/WhileStatement.ts @@ -0,0 +1,354 @@ +import swc from "npm:@swc/wasm@1.3.35"; +import { resolveNode } from "../index.ts"; + +export default function WhileStatement( + node: swc.Node, + variablesTable: VariablesTableType, + variableModificationThings: VariablesThingType, + prc: { count: number }, + mainInstructions: string[], +) { + const typedNode = node as swc.WhileStatement; + switch (typedNode.test.type) { + case "BinaryExpression": { + const typedExpr = typedNode.test as swc.BinaryExpression; + switch (typedExpr.operator) { + case "==": + case "===": { + let addr1: number; + let addr2: number; + switch (typedExpr.left.type) { + case "Identifier": { + const typedValue = typedExpr.left; + const variableInfo = + variablesTable[typedValue.value]; + if (variableInfo.memoryType === "string") { + // TODO: implement string comparisons + throw new Error( + "i would rather pipi in pampers than implement string comparisons", + ); + } + addr1 = variableInfo.memoryLocation; + break; + } + default: + throw new Error( + "probably something idk i don't feel like writing error messages anymore", + ); + } + switch (typedExpr.right.type) { + case "Identifier": { + const typedValue = typedExpr.right; + const variableInfo = + variablesTable[typedValue.value]; + if (variableInfo.memoryType === "string") { + // TODO: implement string comparisons + throw new Error( + "i would rather pipi in pampers than implement string comparisons", + ); + } + addr2 = variableInfo.memoryLocation; + break; + } + default: + throw new Error( + "probably something idk i don't feel like writing error messages anymore", + ); + } + let ourInsts = [`JMP TODO`]; + prc.count += 3; + const oldPRC = prc; + for ( + const node of (typedNode.body as swc.BlockStatement) + .stmts + ) { + ourInsts = ourInsts.concat( + resolveNode( + node, + prc, + variableModificationThings, + variablesTable, + ), + ); + } + ourInsts[0] = ourInsts[0].replace( + "TODO", + prc.count.toString(16).padStart( + 4, + "0", + ), + ); + + ourInsts.push(`JEA ${ + oldPRC.count.toString(16).padStart( + 4, + "0", + ) + } ${ + addr1.toString(16).padStart( + 4, + "0", + ) + } ${ + addr2.toString(16).padStart( + 4, + "0", + ) + }`); + prc.count += 7; + + for (const inst of ourInsts) { + mainInstructions.push(inst); + } + + break; + } + case "!=": + case "!==": { + let addr1: number; + let addr2: number; + switch (typedExpr.left.type) { + case "Identifier": { + const typedValue = typedExpr.left; + const variableInfo = + variablesTable[typedValue.value]; + if (variableInfo.memoryType === "string") { + // TODO: implement string comparisons + throw new Error( + "i would rather pipi in pampers than implement string comparisons", + ); + } + addr1 = variableInfo.memoryLocation; + break; + } + case "NumericLiteral": { + const value = typedExpr.left.value; + mainInstructions.push( + `LOL ${ + value.toString(16).padStart( + 2, + "0", + ) + } 00F1`, + ); + addr1 = 0x00F1; + prc.count += 4; + break; + } + default: + throw new Error( + "probably something idk i don't feel like writing error messages anymore", + ); + } + switch (typedExpr.right.type) { + case "Identifier": { + const typedValue = typedExpr.right; + const variableInfo = + variablesTable[typedValue.value]; + if (variableInfo.memoryType === "string") { + // TODO: implement string comparisons + throw new Error( + "i would rather pipi in pampers than implement string comparisons", + ); + } + addr2 = variableInfo.memoryLocation; + break; + } + case "NumericLiteral": { + const value = typedExpr.right.value; + mainInstructions.push( + `LOL ${ + value.toString(16).padStart( + 2, + "0", + ) + } 00F2`, + ); + addr2 = 0x00F2; + prc.count += 4; + break; + } + default: + throw new Error( + `probably something to do with ${typedExpr.right.type} idk i don't feel like writing error messages anymore`, + ); + } + let ourInsts = [`JML TODO`]; + prc.count += 3; + const oldPRC = prc.count; + for ( + const node of (typedNode.body as swc.BlockStatement) + .stmts + ) { + ourInsts = ourInsts.concat( + resolveNode( + node, + prc, + variableModificationThings, + variablesTable, + ), + ); + } + ourInsts[0] = ourInsts[0].replace( + "TODO", + prc.count.toString(16).padStart( + 4, + "0", + ), + ); + + ourInsts.push(`JNA ${ + oldPRC.toString(16).padStart( + 4, + "0", + ) + } ${ + addr1.toString(16).padStart( + 4, + "0", + ) + } ${ + addr2.toString(16).padStart( + 4, + "0", + ) + }`); + prc.count += 7; + + for (const inst of ourInsts) { + mainInstructions.push(inst); + } + + break; + } + case ">": { + let addr1: number; + let addr2: number; + switch (typedExpr.left.type) { + case "Identifier": { + const typedValue = typedExpr.left; + const variableInfo = + variablesTable[typedValue.value]; + if (variableInfo.memoryType === "string") { + // TODO: implement string comparisons + throw new Error( + "i would rather pipi in pampers than implement string comparisons", + ); + } + addr1 = variableInfo.memoryLocation; + break; + } + case "NumericLiteral": { + const value = typedExpr.left.value; + mainInstructions.push( + `LOL ${ + value.toString(16).padStart( + 2, + "0", + ) + } 00F1`, + ); + addr1 = 0x00F1; + prc.count += 4; + break; + } + default: + throw new Error( + "probably something idk i don't feel like writing error messages anymore", + ); + } + switch (typedExpr.right.type) { + case "Identifier": { + const typedValue = typedExpr.right; + const variableInfo = + variablesTable[typedValue.value]; + if (variableInfo.memoryType === "string") { + // TODO: implement string comparisons + throw new Error( + "i would rather pipi in pampers than implement string comparisons", + ); + } + addr2 = variableInfo.memoryLocation; + break; + } + case "NumericLiteral": { + const value = typedExpr.right.value; + mainInstructions.push( + `LOL ${ + value.toString(16).padStart( + 2, + "0", + ) + } 00F2`, + ); + addr2 = 0x00F2; + prc.count += 4; + break; + } + default: + throw new Error( + `probably something to do with ${typedExpr.right.type} idk i don't feel like writing error messages anymore`, + ); + } + let ourInsts = [`JML TODO`]; + prc.count += 3; + const oldPRC = prc.count; + for ( + const node of (typedNode.body as swc.BlockStatement) + .stmts + ) { + ourInsts = ourInsts.concat( + resolveNode( + node, + prc, + variableModificationThings, + variablesTable, + ), + ); + } + + ourInsts[0] = ourInsts[0].replace( + "TODO", + prc.count.toString(16).padStart( + 4, + "0", + ), + ); + + ourInsts.push(`JGT ${ + oldPRC.toString(16).padStart( + 4, + "0", + ) + } ${ + addr1.toString(16).padStart( + 4, + "0", + ) + } ${ + addr2.toString(16).padStart( + 4, + "0", + ) + }`); + prc.count += 7; + + for (const inst of ourInsts) { + mainInstructions.push(inst); + } + + break; + } + default: + throw new Error( + `comparison operator ${typedExpr.operator} not implemented`, + ); + } + break; + } + default: + throw new Error( + `if statement test with node type ${typedNode.test.type} not implemented`, + ); + } +}