feat(command line arguments): Add --target and --help flags

- Move generate_rust_code to interpreter
- Clean stuff.js
- Parse command line arguments
This commit is contained in:
Gers2017 2023-05-04 16:23:08 -06:00
parent 9898335592
commit 9a1ad1e7a4
4 changed files with 108 additions and 37 deletions

24
interpreter.js Normal file
View file

@ -0,0 +1,24 @@
import { writeFileSync } from "fs";
import { Stmt, PrintStmt, ReturnStmt } from "./stuff.js";
/**
*
* @param {Stmt[]} statements
*/
export function generate_rust_code(filename, statements) {
const output = [];
output.push("fn main() {");
for (const stmt of statements) {
if (stmt instanceof PrintStmt) {
output.push(`\tprint!("${stmt.string}");`);
} else if (stmt instanceof ReturnStmt) {
output.push(`\tstd::process::exit(${stmt.value});`);
}
}
output.push("}\n");
const text = output.join("\n");
writeFileSync(filename, text);
}

92
main.js
View file

@ -1,6 +1,7 @@
import { readFileSync, writeFileSync } from "fs"; import { readFileSync } from "fs";
import { Parser } from "./parser.js"; import { Parser } from "./parser.js";
import { PrintStmt, ReturnStmt } from "./stuff.js"; import { generate_rust_code } from "./interpreter.js";
import { import {
is_alpha, is_alpha,
is_alphanum, is_alphanum,
@ -8,6 +9,7 @@ import {
is_whitespace, is_whitespace,
pretty_error, pretty_error,
panic, panic,
exit_rand,
} from "./utils.js"; } from "./utils.js";
// Javascript enums at home // Javascript enums at home
@ -287,46 +289,96 @@ class Lexer {
} }
} }
const TARGETS = [
"rust",
"x86_64-fasm-linux-gnu",
// "x86_64-fasm-windows"
];
try { try {
_main(); _main();
} catch (e) { } catch (e) {
console.error(e); console.error(e);
} }
function check_next_arg(arg, next_arg) {
if (next_arg === null && !next_arg.startsWith("-")) {
console.error(`Missing or invalid value for flag "${arg}"`);
exit_rand();
}
return true;
}
function print_usage() {
console.log("Cpp.js");
console.log("USAGE:");
console.log(" node cpp.js <filename>");
console.log(" node cpp.js <filename> --target <target>");
console.log(" node cpp.js --target list");
console.log(" node cpp.js --help");
console.log();
console.log(" <filename>: The cpp file to compile");
console.log(" <target>: The target platform");
}
function _main() { function _main() {
const CPP_REGEX = /.\.cpp/i; const CPP_REGEX = /.\.cpp/i;
const args = process.argv; const args = process.argv;
let filename = "main.cpp";
for (const arg of args) { let filename = "main.cpp";
let target = TARGETS[0]; // default target is rust
for (let i = 0; i < args.length; i++) {
const arg = args[i];
const next_arg = i + 1 < args.length ? args[i + 1] : null;
if (arg === "--help") {
print_usage();
process.exit(0);
}
if (CPP_REGEX.test(arg)) { if (CPP_REGEX.test(arg)) {
filename = arg; filename = arg;
} }
if (arg === "--target" && check_next_arg(arg, next_arg)) {
if (next_arg === "list") {
console.log("Valid targets:");
for (const target of TARGETS) {
console.log(target);
}
process.exit(0);
}
if (!TARGETS.includes(next_arg)) {
console.error(
`Unknown target "${next_arg}\nMaybe try: --target list`
);
exit_rand();
}
target = next_arg;
}
} }
const source = readFileSync(filename, "utf8"); const source = readFileSync(filename, "utf8");
const lexer = new Lexer(source); const lexer = new Lexer(source);
const tokens = lexer.scan_tokens(); const tokens = lexer.scan_tokens();
// console.log(lexer.tokens);
const parser = new Parser(tokens); const parser = new Parser(tokens);
const statements = parser.parse(); const statements = parser.parse();
const output = []; switch (target) {
output.push("fn main() {"); case TARGETS[0]: // rust
filename = filename.replace(".cpp", ".rs");
generate_rust_code(filename, statements);
break;
for (const stmt of statements) { case TARGETS[1]: // x86_64-fasm-linux-gnu
if (stmt instanceof PrintStmt) { filename = filename.replace(".cpp", ".asm");
output.push(`\tprint!("${stmt.string}");`); // TODO GENERATE ASM!
} else if (stmt instanceof ReturnStmt) { default:
output.push(`\tstd::process::exit(${stmt.value});`); break;
} }
} }
output.push("}\n");
const text = output.join("\n");
filename = filename.replace("cpp", "rs");
writeFileSync(filename, text);
}

View file

@ -1,7 +1,7 @@
// ------- Parser -------- // ------- Parser --------
import { Token, TokenType } from "./main.js"; import { Token, TokenType } from "./main.js";
import { PrintStmt, ReturnStmt } from "./stuff.js"; import { PrintStmt, ReturnStmt, Stmt } from "./stuff.js";
import { panic } from "./utils.js"; import { panic } from "./utils.js";
const Errors = { const Errors = {

View file

@ -1,13 +1,5 @@
export class AST {}
export class Stmt {} export class Stmt {}
export class Block extends AST {
constructor(stmts) {
super();
this.stmts = stmts;
}
}
export class PrintStmt extends Stmt { export class PrintStmt extends Stmt {
/** /**
* *
@ -37,23 +29,26 @@ export class IfStmt extends Stmt {}
export class ElseStmt extends Stmt {} export class ElseStmt extends Stmt {}
export class Expr {} export class AST {}
export class EqualsExpr { export class Block extends AST {
constructor(a, b) { constructor(stmts) {
this.a = a; super();
this.b = b; this.stmts = stmts;
} }
} }
export class Num { export class NumberNode extends AST {
constructor(value) { constructor(value) {
super();
this.value = value; this.value = value;
} }
} }
export class FunctionDeclaration extends Stmt { export class BinaryExpr extends AST {
constructor(name, params, body) { constructor(left, right) {
super(); super();
this.left = left;
this.right = right;
} }
} }