- updated common with new compiler/builder trait to provide a common
interface for build tools - updated editor and build tooling to use new system
This commit is contained in:
@@ -10,7 +10,10 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub use common::logging::log;
|
pub use common::logging::log;
|
||||||
use common::prelude::Instruction;
|
use common::{
|
||||||
|
build::{BuildError, Builder},
|
||||||
|
prelude::Instruction,
|
||||||
|
};
|
||||||
|
|
||||||
// Module declarations
|
// Module declarations
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
@@ -37,17 +40,27 @@ pub use self::{
|
|||||||
|
|
||||||
use crate::util::logging::{Entry, Logger};
|
use crate::util::logging::{Entry, Logger};
|
||||||
|
|
||||||
pub struct CompilerEngine {
|
pub struct Assembler {
|
||||||
result_tx: mpsc::Sender<Result<Vec<Instruction>, AssembleError>>,
|
src_path: PathBuf,
|
||||||
result_rx: Option<mpsc::Receiver<Result<Vec<Instruction>, AssembleError>>>,
|
result_tx: mpsc::Sender<Result<Vec<u8>, AssembleError>>,
|
||||||
|
result_rx: Option<mpsc::Receiver<Result<Vec<u8>, AssembleError>>>,
|
||||||
is_running: bool,
|
is_running: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CompilerEngine {
|
impl From<AssembleError> for BuildError {
|
||||||
|
fn from(err: AssembleError) -> Self {
|
||||||
|
Self::Generic(err.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Builder for Assembler {
|
||||||
|
type Output = Vec<u8>;
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new() -> Self {
|
fn new(src_path: impl Into<PathBuf>) -> Self {
|
||||||
let (tx, rx) = mpsc::channel();
|
let (tx, rx) = mpsc::channel();
|
||||||
Self {
|
Self {
|
||||||
|
src_path: src_path.into(),
|
||||||
result_tx: tx,
|
result_tx: tx,
|
||||||
result_rx: Some(rx),
|
result_rx: Some(rx),
|
||||||
is_running: false,
|
is_running: false,
|
||||||
@@ -55,25 +68,29 @@ impl CompilerEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Start the compilation process in a separate thread
|
/// Start the compilation process in a separate thread
|
||||||
pub fn start_compilation(&mut self, src: &Path) {
|
fn start(&mut self) {
|
||||||
if self.is_running {
|
if self.is_running {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let src = src.to_path_buf();
|
let src = self.src_path.clone();
|
||||||
let tx = self.result_tx.clone();
|
let tx = self.result_tx.clone();
|
||||||
|
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
let result = assemble(&src);
|
if let Ok(res) = assemble(&src) {
|
||||||
tx.send(result)
|
let buffer: Vec<u8> = res
|
||||||
|
.iter()
|
||||||
|
.flat_map(|instruction| instruction.encode().to_be_bytes())
|
||||||
|
.collect();
|
||||||
|
tx.send(Ok(buffer))
|
||||||
.expect("Failed to send compilation result from worker thread");
|
.expect("Failed to send compilation result from worker thread");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
self.is_running = true;
|
self.is_running = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if compilation is complete and get the result
|
fn poll(&mut self) -> Option<Result<Self::Output, common::build::BuildError>> {
|
||||||
pub fn try_get_result(&mut self) -> Option<Result<Vec<Instruction>, AssembleError>> {
|
|
||||||
if !self.is_running {
|
if !self.is_running {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@@ -86,22 +103,20 @@ impl CompilerEngine {
|
|||||||
{
|
{
|
||||||
Ok(result) => {
|
Ok(result) => {
|
||||||
self.is_running = false;
|
self.is_running = false;
|
||||||
Some(result)
|
Some(result.map_err(std::convert::Into::into))
|
||||||
}
|
}
|
||||||
Err(mpsc::TryRecvError::Empty) => None,
|
Err(mpsc::TryRecvError::Empty) => None,
|
||||||
Err(mpsc::TryRecvError::Disconnected) => {
|
Err(mpsc::TryRecvError::Disconnected) => {
|
||||||
self.is_running = false;
|
self.is_running = false;
|
||||||
Some(Err(AssembleError::Generic))
|
Some(Err(BuildError::Generic(String::from(
|
||||||
|
"Compilation terminated before a result was returned",
|
||||||
|
))))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Block until compilation is complete and return the result
|
/// Block until compilation is complete and return the result
|
||||||
pub fn wait_for_result(&mut self) -> Result<Vec<Instruction>, AssembleError> {
|
fn output(&mut self) -> Result<Self::Output, common::build::BuildError> {
|
||||||
if !self.is_running {
|
|
||||||
return Err(AssembleError::Generic);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Ok(result) = self
|
if let Ok(result) = self
|
||||||
.result_rx
|
.result_rx
|
||||||
.take()
|
.take()
|
||||||
@@ -109,14 +124,18 @@ impl CompilerEngine {
|
|||||||
.recv()
|
.recv()
|
||||||
{
|
{
|
||||||
self.is_running = false;
|
self.is_running = false;
|
||||||
result
|
result.map_err(std::convert::Into::into)
|
||||||
} else {
|
} else {
|
||||||
self.is_running = false;
|
self.is_running = false;
|
||||||
Err(AssembleError::Generic)
|
Err(BuildError::Generic(String::from(
|
||||||
|
"Compilation terminated before a result was returned",
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Assembler {}
|
||||||
|
|
||||||
fn assemble(src: &Path) -> Result<Vec<Instruction>, AssembleError> {
|
fn assemble(src: &Path) -> Result<Vec<Instruction>, AssembleError> {
|
||||||
let mut modules = HashSet::new();
|
let mut modules = HashSet::new();
|
||||||
let mut program = Program::new();
|
let mut program = Program::new();
|
||||||
@@ -142,12 +161,6 @@ fn assemble(src: &Path) -> Result<Vec<Instruction>, AssembleError> {
|
|||||||
Ok(instructions)
|
Ok(instructions)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for CompilerEngine {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn prepare_dependency(
|
fn prepare_dependency(
|
||||||
path: &Path,
|
path: &Path,
|
||||||
modules: &mut HashSet<u64>,
|
modules: &mut HashSet<u64>,
|
||||||
|
|||||||
+1
-26
@@ -18,33 +18,8 @@ pub mod tooling;
|
|||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use crate::assembler::CompilerEngine;
|
pub use crate::assembler::Assembler;
|
||||||
pub use crate::image_builder;
|
pub use crate::image_builder;
|
||||||
pub use crate::tooling::brainf;
|
pub use crate::tooling::brainf;
|
||||||
pub use crate::tooling::project;
|
pub use crate::tooling::project;
|
||||||
}
|
}
|
||||||
|
|
||||||
use std::{fs, path::Path};
|
|
||||||
|
|
||||||
use num_cpus as _;
|
|
||||||
use threadpool as _;
|
|
||||||
|
|
||||||
use crate::prelude::CompilerEngine;
|
|
||||||
|
|
||||||
pub fn assemble_file(input: &str, output: &str) -> Result<(), std::io::Error> {
|
|
||||||
let mut engine = CompilerEngine::new();
|
|
||||||
engine.start_compilation(Path::new(input));
|
|
||||||
let result = engine.wait_for_result().expect("assembler failed.");
|
|
||||||
|
|
||||||
let buffer: Vec<u8> = result
|
|
||||||
.iter()
|
|
||||||
.flat_map(|instruction| instruction.encode().to_be_bytes())
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
if let Err(e) = fs::write(output, buffer) {
|
|
||||||
eprintln!("Failed to write to output file: {e}");
|
|
||||||
std::process::exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|||||||
+10
-5
@@ -1,9 +1,6 @@
|
|||||||
use common as _;
|
use common::{self as _, build::Builder};
|
||||||
use num_cpus as _;
|
|
||||||
use threadpool as _;
|
|
||||||
|
|
||||||
use assembler::{
|
use assembler::{
|
||||||
assemble_file,
|
|
||||||
prelude::*,
|
prelude::*,
|
||||||
tooling::{brainf, project},
|
tooling::{brainf, project},
|
||||||
};
|
};
|
||||||
@@ -47,5 +44,13 @@ fn main() {
|
|||||||
|
|
||||||
let input_path = &args[2];
|
let input_path = &args[2];
|
||||||
let output_path = &args[4];
|
let output_path = &args[4];
|
||||||
assemble_file(input_path, output_path).unwrap();
|
|
||||||
|
let mut engine = Assembler::new(PathBuf::from(input_path));
|
||||||
|
engine.start();
|
||||||
|
let result = engine.output().expect("assembler failed.");
|
||||||
|
|
||||||
|
if let Err(e) = fs::write(output_path, result) {
|
||||||
|
eprintln!("Failed to write to output file: {e}");
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
use std::{
|
||||||
|
fmt,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum BuildError {
|
||||||
|
IoError(String),
|
||||||
|
Generic(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<std::io::Error> for BuildError {
|
||||||
|
fn from(err: std::io::Error) -> Self {
|
||||||
|
Self::IoError(err.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Box<dyn std::error::Error>> for BuildError {
|
||||||
|
fn from(err: Box<dyn std::error::Error>) -> Self {
|
||||||
|
Self::Generic(err.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for BuildError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::IoError(err) => write!(f, "IO Error: {err}"),
|
||||||
|
Self::Generic(err) => write!(f, "Generic Error: {err}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Builder {
|
||||||
|
type Output: Clone + std::convert::AsRef<[u8]>;
|
||||||
|
|
||||||
|
fn new(src_path: impl Into<PathBuf>) -> Self;
|
||||||
|
|
||||||
|
// starts compilation
|
||||||
|
fn start(&mut self);
|
||||||
|
|
||||||
|
// non-blocking function, returns output if completed
|
||||||
|
fn poll(&mut self) -> Option<Result<Self::Output, BuildError>>;
|
||||||
|
|
||||||
|
// blocking function, returns output when completed.
|
||||||
|
fn output(&mut self) -> Result<Self::Output, BuildError>;
|
||||||
|
|
||||||
|
fn write_result(&mut self, path: impl AsRef<Path>) -> Result<(), BuildError> {
|
||||||
|
let output = self.output()?;
|
||||||
|
std::fs::write(path.as_ref(), output)
|
||||||
|
.map_err(|e| BuildError::IoError(e.to_string()))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,6 +12,7 @@
|
|||||||
clippy::match_wildcard_for_single_variants
|
clippy::match_wildcard_for_single_variants
|
||||||
)]
|
)]
|
||||||
|
|
||||||
|
pub mod build;
|
||||||
pub mod instructions;
|
pub mod instructions;
|
||||||
pub mod logging;
|
pub mod logging;
|
||||||
|
|
||||||
|
|||||||
+47
-37
@@ -1,8 +1,11 @@
|
|||||||
#![feature(try_trait_v2)]
|
#![feature(try_trait_v2)]
|
||||||
|
|
||||||
use std::path::Path;
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use common::logging::log;
|
use common::{
|
||||||
|
build::{BuildError, Builder},
|
||||||
|
logging::log,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{model::CompilerError, specialised::build_specialised};
|
use crate::{model::CompilerError, specialised::build_specialised};
|
||||||
|
|
||||||
@@ -11,33 +14,25 @@ mod frontend;
|
|||||||
mod model;
|
mod model;
|
||||||
mod specialised;
|
mod specialised;
|
||||||
|
|
||||||
pub fn compile_file(
|
pub struct Compiler {
|
||||||
input_path: &Path,
|
src_path: PathBuf,
|
||||||
output_path: &Path,
|
result: Option<Result<String, BuildError>>,
|
||||||
) -> Result<(), Box<dyn std::error::Error>> {
|
}
|
||||||
let input = std::fs::read_to_string(input_path).expect("Failed to read input file");
|
|
||||||
|
|
||||||
let input_ext = input_path
|
impl Compiler {
|
||||||
|
fn build(&mut self) -> Result<String, Box<dyn std::error::Error>> {
|
||||||
|
let input =
|
||||||
|
std::fs::read_to_string(&self.src_path).expect("Failed to read input file");
|
||||||
|
|
||||||
|
let input_ext = self
|
||||||
|
.src_path
|
||||||
.extension()
|
.extension()
|
||||||
.and_then(|s| s.to_str())
|
.and_then(|s| s.to_str())
|
||||||
.unwrap_or("");
|
.unwrap_or("");
|
||||||
|
|
||||||
// check if we're using a specialised compiler
|
// check if we're using a specialised compiler
|
||||||
if let Some(output) = build_specialised(input_ext, &input) {
|
if let Some(output) = build_specialised(input_ext, &input) {
|
||||||
let result = match output {
|
return output.map_err(|err| format!("Compilation failed: {err:?}").into());
|
||||||
Ok(output) => output,
|
|
||||||
Err(err) => return Err(format!("Compilation failed: {err:?}").into()),
|
|
||||||
};
|
|
||||||
|
|
||||||
std::fs::write(output_path, &result).expect("Failed to write output");
|
|
||||||
|
|
||||||
log(&format!(
|
|
||||||
"Compilation Successful ✅ \n\tSource: {}\n\tOutput: {}\n",
|
|
||||||
input_path.display(),
|
|
||||||
output_path.display(),
|
|
||||||
));
|
|
||||||
|
|
||||||
return Ok(());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the input using the frontend, providing the file extension and data.
|
// Parse the input using the frontend, providing the file extension and data.
|
||||||
@@ -46,29 +41,44 @@ pub fn compile_file(
|
|||||||
Err(err) => return Err(format!("Compilation failed: {err:?}").into()),
|
Err(err) => return Err(format!("Compilation failed: {err:?}").into()),
|
||||||
};
|
};
|
||||||
|
|
||||||
println!("Parsed AST: {:#?}", ast);
|
// println!("Parsed AST: {:#?}", ast);
|
||||||
|
|
||||||
let output_ext = output_path
|
|
||||||
.extension()
|
|
||||||
.and_then(|s| s.to_str())
|
|
||||||
.unwrap_or("");
|
|
||||||
|
|
||||||
// Generate the output using the backend with the parsed result.
|
// Generate the output using the backend with the parsed result.
|
||||||
let result = match backend::compiler_backend(output_ext, &ast) {
|
let result = match backend::compiler_backend("dsa", &ast) {
|
||||||
Ok(result) => result,
|
Ok(result) => result,
|
||||||
Err(err) => return Err(format!("Compilation failed: {err:?}").into()),
|
Err(err) => return Err(format!("Compilation failed: {err:?}").into()),
|
||||||
};
|
};
|
||||||
|
|
||||||
// println!("{result}");
|
Ok(result)
|
||||||
std::fs::write(output_path, &result).expect("Failed to write output");
|
}
|
||||||
|
}
|
||||||
|
|
||||||
log(&format!(
|
impl Builder for Compiler {
|
||||||
"Compilation Successful ✅ \n\tSource: {}\n\tOutput: {}\n",
|
type Output = String;
|
||||||
input_path.display(),
|
|
||||||
output_path.display(),
|
|
||||||
));
|
|
||||||
|
|
||||||
Ok(())
|
fn new(src_path: impl Into<PathBuf>) -> Self {
|
||||||
|
Self {
|
||||||
|
src_path: src_path.into(),
|
||||||
|
result: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start(&mut self) {
|
||||||
|
match self.build() {
|
||||||
|
Ok(x) => self.result = Some(Ok(x)),
|
||||||
|
Err(err) => self.result = Some(Err(err.into())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn poll(&mut self) -> Option<Result<Self::Output, BuildError>> {
|
||||||
|
self.result.take()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn output(&mut self) -> Result<Self::Output, BuildError> {
|
||||||
|
self.result.clone().ok_or(BuildError::Generic(String::from(
|
||||||
|
"Compiler was never started",
|
||||||
|
)))?
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn error(msg: impl Into<String>) -> CompilerError {
|
pub fn error(msg: impl Into<String>) -> CompilerError {
|
||||||
|
|||||||
+16
-2
@@ -1,4 +1,7 @@
|
|||||||
use std::path::Path;
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
use common::{build::Builder, logging::log};
|
||||||
|
use compiler::Compiler;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// read from input file: syntax "c_compiler <src.c> [output.dsa]"
|
// read from input file: syntax "c_compiler <src.c> [output.dsa]"
|
||||||
@@ -15,5 +18,16 @@ fn main() {
|
|||||||
"output.dsa"
|
"output.dsa"
|
||||||
};
|
};
|
||||||
|
|
||||||
compiler::compile_file(Path::new(input_file), Path::new(output_file)).unwrap();
|
{
|
||||||
|
let mut builder = Compiler::new(PathBuf::from(input_file));
|
||||||
|
builder.start();
|
||||||
|
let result = builder.output().unwrap();
|
||||||
|
|
||||||
|
std::fs::write(output_file, &result).expect("Failed to write output");
|
||||||
|
|
||||||
|
log(&format!(
|
||||||
|
"Compilation Successful ✅ \n\tSource: {}\n\tOutput: {}\n",
|
||||||
|
input_file, output_file,
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
|
||||||
|
use common::build::BuildError;
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum CompilerError {
|
pub enum CompilerError {
|
||||||
@@ -14,6 +16,12 @@ pub enum CompilerError {
|
|||||||
Unimplemented(String),
|
Unimplemented(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<CompilerError> for BuildError {
|
||||||
|
fn from(err: CompilerError) -> Self {
|
||||||
|
BuildError::Generic(format!("{:?}", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
pub struct Name {
|
pub struct Name {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
|||||||
@@ -5,7 +5,9 @@ use std::{
|
|||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use common::build::Builder;
|
||||||
use common::prelude::Instruction;
|
use common::prelude::Instruction;
|
||||||
|
use compiler::Compiler;
|
||||||
use egui::{Align, Context, Key, Layout, Ui};
|
use egui::{Align, Context, Key, Layout, Ui};
|
||||||
|
|
||||||
use dsa_editor::{CodeEditor, ColorTheme, Syntax};
|
use dsa_editor::{CodeEditor, ColorTheme, Syntax};
|
||||||
@@ -423,45 +425,39 @@ impl Editor {
|
|||||||
if let Some(path) = &self.path {
|
if let Some(path) = &self.path {
|
||||||
match path.extension().and_then(|ext| ext.to_str()) {
|
match path.extension().and_then(|ext| ext.to_str()) {
|
||||||
Some("dsa") => {
|
Some("dsa") => {
|
||||||
let mut compiler = CompilerEngine::new();
|
let mut assembler = Assembler::new(path);
|
||||||
compiler.start_compilation(path);
|
assembler.start();
|
||||||
|
|
||||||
// Or block until done
|
// Or block until done
|
||||||
let instructions = match compiler.wait_for_result() {
|
self.output = match assembler.output() {
|
||||||
Ok(instructions) => instructions,
|
Ok(instructions) => instructions,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
self.error = Some(e.to_string());
|
self.error = Some(e.to_string());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.output = instructions
|
|
||||||
.iter()
|
|
||||||
.flat_map(|i| i.encode().to_be_bytes().to_vec())
|
|
||||||
.collect();
|
|
||||||
}
|
}
|
||||||
Some("dsc") => {
|
Some("dsc") => {
|
||||||
let output_path = Path::new(path).with_extension("dsa");
|
let dsa_path = Path::new(path).with_extension("dsa");
|
||||||
if let Err(e) = compiler::compile_file(path, &output_path) {
|
let mut compiler = Compiler::new(path);
|
||||||
self.error = Some(format!("Compiler error: {e}"));
|
compiler.start();
|
||||||
|
|
||||||
|
if let Err(e) = compiler.write_result(&dsa_path) {
|
||||||
|
self.error = Some(e.to_string());
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut compiler = CompilerEngine::new();
|
let mut assembler = Assembler::new(&dsa_path);
|
||||||
compiler.start_compilation(&output_path);
|
compiler.start();
|
||||||
|
|
||||||
// Or block until done
|
// Or block until done
|
||||||
let instructions = match compiler.wait_for_result() {
|
self.output = match assembler.output() {
|
||||||
Ok(instructions) => instructions,
|
Ok(instructions) => instructions,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
self.error = Some(format!("Assembler error: {e}"));
|
self.error = Some(format!("Assembler error: {e}"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.output = instructions
|
|
||||||
.iter()
|
|
||||||
.flat_map(|i| i.encode().to_be_bytes().to_vec())
|
|
||||||
.collect();
|
|
||||||
}
|
}
|
||||||
Some("dsb") => {
|
Some("dsb") => {
|
||||||
if let Ok(bytes) = fs::read(path) {
|
if let Ok(bytes) = fs::read(path) {
|
||||||
|
|||||||
Reference in New Issue
Block a user