diff options
Diffstat (limited to 'src/bin/bedrock-asm.rs')
-rw-r--r-- | src/bin/bedrock-asm.rs | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/src/bin/bedrock-asm.rs b/src/bin/bedrock-asm.rs new file mode 100644 index 0000000..2a29ee3 --- /dev/null +++ b/src/bin/bedrock-asm.rs @@ -0,0 +1,148 @@ +use bedrock_asm::*; + +use std::io::{Read, Write}; +use std::path::{Path, PathBuf}; + + +static mut VERBOSE: bool = false; + +macro_rules! verbose { + ($($tokens:tt)*) => { if unsafe { VERBOSE } { + eprint!("[INFO] "); eprintln!($($tokens)*); + } }; +} +macro_rules! error { + ($($tokens:tt)*) => {{ + eprint!("[ERROR] "); eprintln!($($tokens)*); std::process::exit(1); + }}; +} + + +fn main() { + let args = Arguments::from_env_or_exit(); + + // ----------------------------------------------------------------------- + // RESOLVE syntactic symbols + let ext = args.ext.unwrap_or(String::from("brc")); + let mut resolver = if let Some(path) = &args.source { + match SourceUnit::from_path(&path, &ext) { + Ok(source_unit) => SymbolResolver::from_source_unit(source_unit), + Err(err) => match err { + ParseError::InvalidExtension => error!( + "File {path:?} has invalid extension, must be '.{ext}'"), + ParseError::NotFound => error!( + "File {path:?} was not found"), + ParseError::InvalidUtf8 => error!( + "File {path:?} does not contain valid UTF-8 text"), + ParseError::NotReadable => error!( + "File {path:?} is not readable"), + ParseError::IsADirectory => error!( + "File {path:?} is a directory"), + ParseError::Unknown => error!( + "Unknown error while attempting to read from {path:?}") + } + } + } else { + let mut source_code = String::new(); + verbose!("Reading program source from standard input"); + if let Err(err) = std::io::stdin().read_to_string(&mut source_code) { + eprintln!("Could not read from standard input, exiting."); + eprintln!("({err:?})"); + std::process::exit(1); + } + let path = "<standard input>"; + let source_unit = SourceUnit::from_source_code(source_code, path); + SymbolResolver::from_source_unit(source_unit) + }; + // Load project libraries. + if let Some(path) = &args.source { + if !args.no_libs && !args.no_project_libs { + let project_library = gather_project_libraries(path, &ext); + resolver.add_library_units(project_library); + } + } + // Load environment libraries. + if !args.no_libs && !args.no_env_libs { + for env_library in gather_environment_libraries(&ext) { + resolver.add_library_units(env_library); + } + } + resolver.resolve(); + + // ----------------------------------------------------------------------- + // PRINT information, generate merged source code + if args.tree { + print_source_tree(&resolver); + } + if print_resolver_errors(&resolver) { + std::process::exit(1); + }; + let merged_source = resolver.get_merged_source_code(); + if args.resolve { + write_bytes_and_exit(merged_source.as_bytes(), args.output.as_ref()); + } + + // ----------------------------------------------------------------------- + // PARSE semantic tokens from merged source code + let path = Some("<merged source>"); + let mut semantic_tokens = generate_semantic_tokens(&merged_source, path); + if print_semantic_errors(&semantic_tokens, &merged_source) { + std::process::exit(1); + }; + + // ----------------------------------------------------------------------- + // GENERATE symbols file and bytecode + let bytecode = generate_bytecode(&mut semantic_tokens); + // let symbols = generate_symbols_file(&semantic_tokens); + write_bytes_and_exit(&bytecode, args.output.as_ref()); +} + + +fn write_bytes_and_exit<P: AsRef<Path>>(bytes: &[u8], path: Option<&P>) -> ! { + if let Some(path) = path { + if let Err(err) = std::fs::write(path, bytes) { + eprintln!("Could not write to path {:?}, exiting.", path.as_ref()); + eprintln!("({err:?})"); + std::process::exit(1); + } + } else { + if let Err(err) = std::io::stdout().write_all(bytes) { + eprintln!("Could not write to standard output, exiting."); + eprintln!("({err:?})"); + std::process::exit(1); + } + } + std::process::exit(0); +} + + +xflags::xflags! { + cmd arguments { + /// Print additional debug information + optional --verbose + /// Print the assembler version and exit + optional --version + + + /// Bedrock source code file to assemble. + optional source: PathBuf + /// Destination path for assembler output. + optional output: PathBuf + /// File extension to identify source files. + optional ext: String + + /// Don't include libraries or resolve references. + optional --no-libs + /// Don't include project libraries + optional --no-project-libs + /// Don't include environment libraries. + optional --no-env-libs + + /// Show the resolved source file heirarchy + optional --tree + /// Assemble the program without saving any output + optional --check + /// Only return resolved source code. + optional --resolve + } +} |