prometeuc improvements
This commit is contained in:
parent
73353d864d
commit
0496afc192
17
build/program.disasm.txt
Normal file
17
build/program.disasm.txt
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
00000000 Call U32(18) U32(0)
|
||||||
|
0000000A FrameSync
|
||||||
|
0000000C Jmp U32(0)
|
||||||
|
00000012 PushI32 U32(1) ; test_supported.ts:2
|
||||||
|
00000018 SetLocal U32(0) ; test_supported.ts:2
|
||||||
|
0000001E GetLocal U32(0) ; test_supported.ts:3
|
||||||
|
00000024 PushI32 U32(10) ; test_supported.ts:3
|
||||||
|
0000002A Lt ; test_supported.ts:3
|
||||||
|
0000002C JmpIfFalse U32(80) ; test_supported.ts:3
|
||||||
|
00000032 GetLocal U32(0) ; test_supported.ts:4
|
||||||
|
00000038 PushI32 U32(1) ; test_supported.ts:4
|
||||||
|
0000003E Add ; test_supported.ts:4
|
||||||
|
00000040 Dup ; test_supported.ts:4
|
||||||
|
00000042 SetLocal U32(0) ; test_supported.ts:4
|
||||||
|
00000048 Pop ; test_supported.ts:4
|
||||||
|
0000004A Jmp U32(80)
|
||||||
|
00000050 Ret
|
||||||
BIN
build/program.pbc
Normal file
BIN
build/program.pbc
Normal file
Binary file not shown.
74
build/symbols.json
Normal file
74
build/symbols.json
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"pc": 18,
|
||||||
|
"file": "test_supported.ts",
|
||||||
|
"line": 2,
|
||||||
|
"col": 13
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pc": 24,
|
||||||
|
"file": "test_supported.ts",
|
||||||
|
"line": 2,
|
||||||
|
"col": 9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pc": 30,
|
||||||
|
"file": "test_supported.ts",
|
||||||
|
"line": 3,
|
||||||
|
"col": 9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pc": 36,
|
||||||
|
"file": "test_supported.ts",
|
||||||
|
"line": 3,
|
||||||
|
"col": 13
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pc": 42,
|
||||||
|
"file": "test_supported.ts",
|
||||||
|
"line": 3,
|
||||||
|
"col": 9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pc": 44,
|
||||||
|
"file": "test_supported.ts",
|
||||||
|
"line": 3,
|
||||||
|
"col": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pc": 50,
|
||||||
|
"file": "test_supported.ts",
|
||||||
|
"line": 4,
|
||||||
|
"col": 13
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pc": 56,
|
||||||
|
"file": "test_supported.ts",
|
||||||
|
"line": 4,
|
||||||
|
"col": 17
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pc": 62,
|
||||||
|
"file": "test_supported.ts",
|
||||||
|
"line": 4,
|
||||||
|
"col": 13
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pc": 64,
|
||||||
|
"file": "test_supported.ts",
|
||||||
|
"line": 4,
|
||||||
|
"col": 9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pc": 66,
|
||||||
|
"file": "test_supported.ts",
|
||||||
|
"line": 4,
|
||||||
|
"col": 9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pc": 72,
|
||||||
|
"file": "test_supported.ts",
|
||||||
|
"line": 4,
|
||||||
|
"col": 9
|
||||||
|
}
|
||||||
|
]
|
||||||
@ -18,6 +18,18 @@ pub enum Asm {
|
|||||||
Label(String),
|
Label(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn update_pc_by_operand(initial_pc: u32, operands: &Vec<Operand>) -> u32 {
|
||||||
|
let mut pcp: u32 = initial_pc;
|
||||||
|
for operand in operands {
|
||||||
|
match operand {
|
||||||
|
Operand::U32(_) | Operand::I32(_) | Operand::Label(_) => pcp += 4,
|
||||||
|
Operand::I64(_) | Operand::F64(_) => pcp += 8,
|
||||||
|
Operand::Bool(_) => pcp += 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pcp
|
||||||
|
}
|
||||||
|
|
||||||
pub fn assemble(instructions: &[Asm]) -> Result<Vec<u8>, String> {
|
pub fn assemble(instructions: &[Asm]) -> Result<Vec<u8>, String> {
|
||||||
let mut labels = HashMap::new();
|
let mut labels = HashMap::new();
|
||||||
let mut current_pc = 0u32;
|
let mut current_pc = 0u32;
|
||||||
@ -30,13 +42,7 @@ pub fn assemble(instructions: &[Asm]) -> Result<Vec<u8>, String> {
|
|||||||
}
|
}
|
||||||
Asm::Op(_opcode, operands) => {
|
Asm::Op(_opcode, operands) => {
|
||||||
current_pc += 2; // OpCode is u16 (2 bytes)
|
current_pc += 2; // OpCode is u16 (2 bytes)
|
||||||
for operand in operands {
|
current_pc = update_pc_by_operand(current_pc, operands);
|
||||||
match operand {
|
|
||||||
Operand::U32(_) | Operand::I32(_) | Operand::Label(_) => current_pc += 4,
|
|
||||||
Operand::I64(_) | Operand::F64(_) => current_pc += 8,
|
|
||||||
Operand::Bool(_) => current_pc += 1,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
22
crates/prometeuc/src/codegen/ast_util.rs
Normal file
22
crates/prometeuc/src/codegen/ast_util.rs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
use oxc_ast::ast::*;
|
||||||
|
use anyhow::{Result, anyhow};
|
||||||
|
|
||||||
|
pub fn get_callee_name(expr: &Expression) -> Result<String> {
|
||||||
|
match expr {
|
||||||
|
Expression::Identifier(ident) => Ok(ident.name.to_string()),
|
||||||
|
Expression::StaticMemberExpression(member) => {
|
||||||
|
let obj = get_callee_name_from_member_obj(&member.object)?;
|
||||||
|
let prop = member.property.name.to_string();
|
||||||
|
Ok(format!("{}.{}", obj, prop))
|
||||||
|
}
|
||||||
|
_ => Err(anyhow!("Unsupported callee expression")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_callee_name_from_member_obj(expr: &Expression) -> Result<String> {
|
||||||
|
if let Expression::Identifier(ident) = expr {
|
||||||
|
Ok(ident.name.to_string())
|
||||||
|
} else {
|
||||||
|
Err(anyhow!("Unsupported member object expression"))
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,7 +5,9 @@ use prometeu_bytecode::opcode::OpCode;
|
|||||||
use prometeu_bytecode::asm::{Asm, Operand, assemble};
|
use prometeu_bytecode::asm::{Asm, Operand, assemble};
|
||||||
use crate::compiler::Symbol;
|
use crate::compiler::Symbol;
|
||||||
use crate::syscall_map;
|
use crate::syscall_map;
|
||||||
|
use crate::codegen::ast_util;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use prometeu_bytecode::asm;
|
||||||
|
|
||||||
pub struct Codegen {
|
pub struct Codegen {
|
||||||
file_name: String,
|
file_name: String,
|
||||||
@ -203,7 +205,7 @@ impl Codegen {
|
|||||||
self.emit_op(op, vec![], unary.span);
|
self.emit_op(op, vec![], unary.span);
|
||||||
}
|
}
|
||||||
Expression::CallExpression(call) => {
|
Expression::CallExpression(call) => {
|
||||||
let name = self.get_callee_name(&call.callee)?;
|
let name = ast_util::get_callee_name(&call.callee)?;
|
||||||
if let Some(syscall_id) = syscall_map::map_syscall(&name) {
|
if let Some(syscall_id) = syscall_map::map_syscall(&name) {
|
||||||
if name == "input.btnA" {
|
if name == "input.btnA" {
|
||||||
self.emit_op(OpCode::PushI32, vec![Operand::I32(syscall_map::BTN_A as i32)], call.span);
|
self.emit_op(OpCode::PushI32, vec![Operand::I32(syscall_map::BTN_A as i32)], call.span);
|
||||||
@ -222,7 +224,7 @@ impl Codegen {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expression::StaticMemberExpression(member) => {
|
Expression::StaticMemberExpression(member) => {
|
||||||
let obj = self.get_callee_name_from_member_obj(&member.object)?;
|
let obj = ast_util::get_callee_name_from_member_obj(&member.object)?;
|
||||||
let prop = member.property.name.to_string();
|
let prop = member.property.name.to_string();
|
||||||
let full_name = format!("{}.{}", obj, prop);
|
let full_name = format!("{}.{}", obj, prop);
|
||||||
// If it's used as a value (GetGlobal/GetLocal?), but for now we only support it in calls
|
// If it's used as a value (GetGlobal/GetLocal?), but for now we only support it in calls
|
||||||
@ -233,26 +235,6 @@ impl Codegen {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_callee_name(&self, expr: &Expression) -> Result<String> {
|
|
||||||
match expr {
|
|
||||||
Expression::Identifier(ident) => Ok(ident.name.to_string()),
|
|
||||||
Expression::StaticMemberExpression(member) => {
|
|
||||||
let obj = self.get_callee_name_from_member_obj(&member.object)?;
|
|
||||||
let prop = member.property.name.to_string();
|
|
||||||
Ok(format!("{}.{}", obj, prop))
|
|
||||||
}
|
|
||||||
_ => Err(anyhow!("Unsupported callee expression at {:?}", expr.span())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_callee_name_from_member_obj(&self, expr: &Expression) -> Result<String> {
|
|
||||||
if let Expression::Identifier(ident) = expr {
|
|
||||||
Ok(ident.name.to_string())
|
|
||||||
} else {
|
|
||||||
Err(anyhow!("Unsupported member object expression"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new_label(&mut self, prefix: &str) -> String {
|
fn new_label(&mut self, prefix: &str) -> String {
|
||||||
let label = format!("{}_{}", prefix, self.label_count);
|
let label = format!("{}_{}", prefix, self.label_count);
|
||||||
self.label_count += 1;
|
self.label_count += 1;
|
||||||
@ -310,13 +292,7 @@ impl Codegen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
current_pc += 2;
|
current_pc += 2;
|
||||||
for operand in operands {
|
current_pc = asm::update_pc_by_operand(current_pc, operands);
|
||||||
match operand {
|
|
||||||
Operand::U32(_) | Operand::I32(_) | Operand::Label(_) => current_pc += 4,
|
|
||||||
Operand::I64(_) | Operand::F64(_) => current_pc += 8,
|
|
||||||
Operand::Bool(_) => current_pc += 1,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
pub mod codegen;
|
pub mod codegen;
|
||||||
|
pub mod validator;
|
||||||
|
pub mod ast_util;
|
||||||
|
|
||||||
pub use codegen::Codegen;
|
pub use codegen::Codegen;
|
||||||
140
crates/prometeuc/src/codegen/validator.rs
Normal file
140
crates/prometeuc/src/codegen/validator.rs
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
use oxc_ast::ast::*;
|
||||||
|
use oxc_ast::visit::walk;
|
||||||
|
use oxc_ast::Visit;
|
||||||
|
use oxc_span::GetSpan;
|
||||||
|
use anyhow::{Result, anyhow};
|
||||||
|
use crate::syscall_map;
|
||||||
|
use crate::codegen::ast_util;
|
||||||
|
|
||||||
|
pub struct Validator {
|
||||||
|
errors: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Validator {
|
||||||
|
pub fn validate(program: &Program) -> Result<()> {
|
||||||
|
let mut validator = Self { errors: Vec::new() };
|
||||||
|
|
||||||
|
// 1. Check for exported tick function
|
||||||
|
let mut tick_fn_found = false;
|
||||||
|
for item in &program.body {
|
||||||
|
if let Statement::ExportNamedDeclaration(decl) = item {
|
||||||
|
if let Some(Declaration::FunctionDeclaration(f)) = &decl.declaration {
|
||||||
|
if let Some(ident) = &f.id {
|
||||||
|
if ident.name == "tick" {
|
||||||
|
tick_fn_found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !tick_fn_found {
|
||||||
|
validator.errors.push("export function tick() not found".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Recursive validation of the AST
|
||||||
|
validator.visit_program(program);
|
||||||
|
|
||||||
|
if validator.errors.is_empty() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(anyhow!("Validation errors:\n{}", validator.errors.join("\n")))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Visit<'a> for Validator {
|
||||||
|
fn visit_statement(&mut self, stmt: &Statement<'a>) {
|
||||||
|
match stmt {
|
||||||
|
Statement::VariableDeclaration(_) |
|
||||||
|
Statement::ExpressionStatement(_) |
|
||||||
|
Statement::IfStatement(_) |
|
||||||
|
Statement::BlockStatement(_) |
|
||||||
|
Statement::ExportNamedDeclaration(_) |
|
||||||
|
Statement::FunctionDeclaration(_) => {
|
||||||
|
// Supported
|
||||||
|
walk::walk_statement(self, stmt);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.errors.push(format!("Unsupported statement type at {:?}", stmt.span()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_expression(&mut self, expr: &Expression<'a>) {
|
||||||
|
match expr {
|
||||||
|
Expression::NumericLiteral(_) |
|
||||||
|
Expression::BooleanLiteral(_) |
|
||||||
|
Expression::Identifier(_) |
|
||||||
|
Expression::AssignmentExpression(_) |
|
||||||
|
Expression::BinaryExpression(_) |
|
||||||
|
Expression::LogicalExpression(_) |
|
||||||
|
Expression::UnaryExpression(_) |
|
||||||
|
Expression::CallExpression(_) |
|
||||||
|
Expression::StaticMemberExpression(_) => {
|
||||||
|
// Base types supported, detailed checks in specific visit methods if needed
|
||||||
|
walk::walk_expression(self, expr);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.errors.push(format!("Unsupported expression type at {:?}", expr.span()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_unary_expression(&mut self, expr: &UnaryExpression<'a>) {
|
||||||
|
match expr.operator {
|
||||||
|
UnaryOperator::UnaryNegation |
|
||||||
|
UnaryOperator::UnaryPlus |
|
||||||
|
UnaryOperator::LogicalNot => {
|
||||||
|
walk::walk_unary_expression(self, expr);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.errors.push(format!("Unsupported unary operator {:?} at {:?}", expr.operator, expr.span));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_binary_expression(&mut self, expr: &BinaryExpression<'a>) {
|
||||||
|
match expr.operator {
|
||||||
|
BinaryOperator::Addition |
|
||||||
|
BinaryOperator::Subtraction |
|
||||||
|
BinaryOperator::Multiplication |
|
||||||
|
BinaryOperator::Division |
|
||||||
|
BinaryOperator::Equality |
|
||||||
|
BinaryOperator::Inequality |
|
||||||
|
BinaryOperator::LessThan |
|
||||||
|
BinaryOperator::GreaterThan |
|
||||||
|
BinaryOperator::LessEqualThan |
|
||||||
|
BinaryOperator::GreaterEqualThan => {
|
||||||
|
walk::walk_binary_expression(self, expr);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.errors.push(format!("Unsupported binary operator {:?} at {:?}", expr.operator, expr.span));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_call_expression(&mut self, expr: &CallExpression<'a>) {
|
||||||
|
if let Ok(name) = ast_util::get_callee_name(&expr.callee) {
|
||||||
|
if syscall_map::map_syscall(&name).is_none() {
|
||||||
|
self.errors.push(format!("Unsupported function call: {} at {:?}", name, expr.span));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.errors.push(format!("Unsupported callee expression at {:?}", expr.callee.span()));
|
||||||
|
}
|
||||||
|
walk::walk_call_expression(self, expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_logical_expression(&mut self, expr: &LogicalExpression<'a>) {
|
||||||
|
match expr.operator {
|
||||||
|
LogicalOperator::And |
|
||||||
|
LogicalOperator::Or => {
|
||||||
|
walk::walk_logical_expression(self, expr);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.errors.push(format!("Unsupported logical operator {:?} at {:?}", expr.operator, expr.span));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -4,6 +4,7 @@ use oxc_allocator::Allocator;
|
|||||||
use oxc_parser::Parser;
|
use oxc_parser::Parser;
|
||||||
use oxc_span::SourceType;
|
use oxc_span::SourceType;
|
||||||
use crate::codegen::Codegen;
|
use crate::codegen::Codegen;
|
||||||
|
use crate::codegen::validator::Validator;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use prometeu_bytecode::disasm::disasm;
|
use prometeu_bytecode::disasm::disasm;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
@ -16,7 +17,49 @@ pub struct Symbol {
|
|||||||
pub col: usize,
|
pub col: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compile(entry: &Path, out: &Path, emit_disasm: bool, emit_symbols: bool) -> Result<()> {
|
pub struct CompilationUnit {
|
||||||
|
pub rom: Vec<u8>,
|
||||||
|
pub symbols: Vec<Symbol>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CompilationUnit {
|
||||||
|
pub fn export(&self, out: &Path, emit_disasm: bool, emit_symbols: bool) -> Result<()> {
|
||||||
|
fs::write(out, &self.rom).with_context(|| format!("Failed to write PBC to {:?}", out))?;
|
||||||
|
|
||||||
|
if emit_symbols {
|
||||||
|
let symbols_path = out.with_file_name("symbols.json");
|
||||||
|
let symbols_json = serde_json::to_string_pretty(&self.symbols)?;
|
||||||
|
fs::write(&symbols_path, symbols_json)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if emit_disasm {
|
||||||
|
let disasm_path = out.with_extension("disasm.txt");
|
||||||
|
let instructions = disasm(&self.rom).map_err(|e| anyhow::anyhow!("Disassembly failed: {}", e))?;
|
||||||
|
|
||||||
|
let mut disasm_text = String::new();
|
||||||
|
for instr in instructions {
|
||||||
|
let symbol = self.symbols.iter().find(|s| s.pc == instr.pc);
|
||||||
|
let comment = if let Some(s) = symbol {
|
||||||
|
format!(" ; {}:{}", s.file, s.line)
|
||||||
|
} else {
|
||||||
|
"".to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
let operands_str = instr.operands.iter()
|
||||||
|
.map(|o| format!("{:?}", o))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(" ");
|
||||||
|
|
||||||
|
disasm_text.push_str(&format!("{:08X} {:?} {}{}\n", instr.pc, instr.opcode, operands_str, comment));
|
||||||
|
}
|
||||||
|
fs::write(disasm_path, disasm_text)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compile(entry: &Path) -> Result<CompilationUnit> {
|
||||||
let source_text = fs::read_to_string(entry)
|
let source_text = fs::read_to_string(entry)
|
||||||
.with_context(|| format!("Failed to read entry file: {:?}", entry))?;
|
.with_context(|| format!("Failed to read entry file: {:?}", entry))?;
|
||||||
|
|
||||||
@ -34,39 +77,13 @@ pub fn compile(entry: &Path, out: &Path, emit_disasm: bool, emit_symbols: bool)
|
|||||||
return Err(anyhow::anyhow!("Failed to parse module"));
|
return Err(anyhow::anyhow!("Failed to parse module"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Validator::validate(&ret.program)?;
|
||||||
|
|
||||||
codegen.compile_program(&ret.program)?
|
codegen.compile_program(&ret.program)?
|
||||||
};
|
};
|
||||||
|
|
||||||
fs::write(out, &rom).with_context(|| format!("Failed to write PBC to {:?}", out))?;
|
Ok(CompilationUnit {
|
||||||
|
rom,
|
||||||
if emit_symbols {
|
symbols: codegen.symbols,
|
||||||
let symbols_path = out.with_file_name("symbols.json");
|
})
|
||||||
let symbols_json = serde_json::to_string_pretty(&codegen.symbols)?;
|
|
||||||
fs::write(&symbols_path, symbols_json)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if emit_disasm {
|
|
||||||
let disasm_path = out.with_extension("disasm.txt");
|
|
||||||
let instructions = disasm(&rom).map_err(|e| anyhow::anyhow!("Disassembly failed: {}", e))?;
|
|
||||||
|
|
||||||
let mut disasm_text = String::new();
|
|
||||||
for instr in instructions {
|
|
||||||
let symbol = codegen.symbols.iter().find(|s| s.pc == instr.pc);
|
|
||||||
let comment = if let Some(s) = symbol {
|
|
||||||
format!(" ; {}:{}", s.file, s.line)
|
|
||||||
} else {
|
|
||||||
"".to_string()
|
|
||||||
};
|
|
||||||
|
|
||||||
let operands_str = instr.operands.iter()
|
|
||||||
.map(|o| format!("{:?}", o))
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join(" ");
|
|
||||||
|
|
||||||
disasm_text.push_str(&format!("{:08X} {:?} {}{}\n", instr.pc, instr.opcode, operands_str, comment));
|
|
||||||
}
|
|
||||||
fs::write(disasm_path, disasm_text)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,7 +29,8 @@ fn main() -> Result<()> {
|
|||||||
println!("Entry: {:?}", entry);
|
println!("Entry: {:?}", entry);
|
||||||
println!("Output: {:?}", out);
|
println!("Output: {:?}", out);
|
||||||
|
|
||||||
compiler::compile(&entry, &out, emit_disasm, emit_symbols)?;
|
let compilation_unit = compiler::compile(&entry)?;
|
||||||
|
compilation_unit.export(&out, emit_disasm, emit_symbols)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user