diff options
Diffstat (limited to 'src/main.rs')
-rw-r--r-- | src/main.rs | 201 |
1 files changed, 65 insertions, 136 deletions
diff --git a/src/main.rs b/src/main.rs index e7e52d9..9fb404c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,18 +1,21 @@ mod compiler; -mod environment; mod parsers; +mod report; mod tokens; +mod formats; pub use compiler::*; -pub use environment::*; pub use parsers::*; +pub use report::*; pub use tokens::*; +pub use formats::*; pub use assembler::*; use log::{info, fatal}; use switchboard::{Switchboard, SwitchQuery}; use std::io::{Read, Write}; +use std::str::FromStr; fn print_version() -> ! { @@ -39,10 +42,13 @@ fn main() { let no_project_libs = args.named("no-project-libs").as_bool(); let no_environment_libs = args.named("no-env-libs").as_bool(); + let format = args.named("format").default("debug").as_string(); let print_tree = args.named("tree").as_bool(); let dry_run = args.named("dry-run").short('n').as_bool(); - let only_resolve = args.named("resolve").as_bool(); - let _export_symbols = args.named("symbols").as_bool(); + + let Ok(format) = Format::from_str(format.as_str()) else { + fatal!("Unknown format '{format}', expected 'debug', 'inhx32', 'raw', or 'source'. "); + }; // ----------------------------------------------------------------------- @@ -86,10 +92,11 @@ fn main() { std::process::exit(1); } - let merged_source = compiler.get_compiled_source().unwrap_or_else( - |error| { error.report(); std::process::exit(1); } - ); - if only_resolve && !dry_run { + let merged_source = compiler.get_compiled_source().unwrap_or_else(|error| { + error.report(); + std::process::exit(1); + }); + if format == Format::Source && !dry_run { write_bytes_and_exit(merged_source.as_bytes(), destination_path.as_ref()); } @@ -97,12 +104,44 @@ fn main() { // Parse syntactic tokens from merged source code. let path = Some("<merged source>"); - let parser = SyntacticParser::from_source_code(&merged_source, path); - let syntactic_tokens: Vec<_> = parser.collect(); + let syntactic_tokens = SyntacticParser::new(&merged_source, path).parse(); report_syntactic_errors(&syntactic_tokens, &merged_source); - let program = ProgramParser::new(syntactic_tokens).parse(); + let program = SemanticParser::new(syntactic_tokens).parse(); report_semantic_errors(&program, &merged_source); + + // program.print_definitions(); + let assembled_tokens = program.assemble(); + report_assembler_errors(&assembled_tokens, &merged_source); + + let bytecode = BytecodeGenerator::new(&assembled_tokens).generate(); + report_bytecode_errors(&bytecode, &merged_source); + + if !dry_run { + match format { + Format::Debug => { + let mut output = String::new(); + for word in &bytecode.words { + output.push_str(&word.to_string()); + output.push('\n'); + } + write_bytes_and_exit(output.as_bytes(), destination_path.as_ref()); + } + Format::Inhx32 => { + let output = format_inhx32(&bytecode.words); + write_bytes_and_exit(output.as_bytes(), destination_path.as_ref()); + } + Format::Raw => { + let mut output = Vec::new(); + for word in &bytecode.words { + let value = word.value as u16; + output.extend(value.to_be_bytes()); + } + write_bytes_and_exit(&output, destination_path.as_ref()); + } + Format::Source => unreachable!(), + } + } } @@ -120,133 +159,23 @@ fn write_bytes_and_exit<P: AsRef<Path>>(bytes: &[u8], path: Option<&P>) -> ! { std::process::exit(0); } - -fn report_syntactic_errors(syntactic_tokens: &[syntactic::Token], source_code: &str) { - use syntactic::*; - - for token in syntactic_tokens { - let context = Context { source_code: &source_code, source: &token.source }; - match &token.variant { - TokenVariant::ConstantExpression(expr) => for t in &expr.tokens { - let context = Context { source_code: &source_code, source: &t.source }; - if let ConstantExpressionTokenVariant::Error(err) = &t.variant { - let ConstantExpressionParseError::InvalidHexadecimalLiteral(hex) = err; - let message = format!("Invalid hexadecimal literal {hex:?} in constant expression"); - report_source_issue(LogLevel::Error, &context, &message); - } - } - TokenVariant::PackedBinaryLiteral(pbl) => for e in &pbl.errors { - let context = Context { source_code: &source_code, source: &e.source }; - match e.variant { - PackedBinaryLiteralParseErrorVariant::DuplicateFieldName(name) => { - let message = format!("Duplicate field name {name:?} in packed binary literal"); - report_source_issue(LogLevel::Error, &context, &message); - } - PackedBinaryLiteralParseErrorVariant::InvalidCharacter(c) => { - let message = format!("Invalid character {c:?} in packed binary literal"); - report_source_issue(LogLevel::Error, &context, &message); - } - } - } - TokenVariant::Error(err) => match err { - ParseError::InvalidHexadecimalLiteral(hex) => { - let message = format!("Invalid hexadecimal literal {hex:?}"); - report_source_issue(LogLevel::Error, &context, &message); - } - ParseError::InvalidSymbolIdentifier(name) => { - let message = format!("Invalid identifier {name:?}"); - report_source_issue(LogLevel::Error, &context, &message); - } - ParseError::UnterminatedComment => { - let message = format!("Unterminated comment"); - report_source_issue(LogLevel::Error, &context, &message); - } - ParseError::UnterminatedConstantExpression => { - let message = format!("Unterminated constant expression"); - report_source_issue(LogLevel::Error, &context, &message); - } - } - _ => (), - } - } -} - - -fn report_semantic_errors(program: &semantic::Program, source_code: &str) { - for error in &program.errors { - report_parse_error(error, source_code); - } - for definition in &program.definitions { - report_definition_errors(&definition.variant, source_code); - } - for invocation in &program.invocations { - report_invocation_errors(invocation, source_code); - } +#[derive(PartialEq)] +enum Format { + Debug, + Inhx32, + Raw, + Source, } -fn report_parse_error(error: &semantic::ParseError, source_code: &str) { - use semantic::*; - let message = match &error.variant { - ParseErrorVariant::UnterminatedMacroDefinition(name) => - format!("The macro definition '{name}' is missing a terminating ';' character"), - ParseErrorVariant::UnterminatedBlockDefinition => - format!("Block literal is missing a terminating '}}' character"), - ParseErrorVariant::InvalidArgumentDefinition(name) => - format!("The macro definition '{name}' has an invalid argument definition"), - ParseErrorVariant::InvalidToken => - format!("Invalid token"), - }; - let context = Context { source: &error.source, source_code}; - report_source_issue(LogLevel::Error, &context, &message); -} - -fn report_definition_errors(definition: &semantic::DefinitionVariant, source_code: &str) { - use semantic::*; - match definition { - DefinitionVariant::Integer(integer) => match &integer.variant { - IntegerDefinitionVariant::Constant(expr) => for token in &expr.tokens { - if let ConstantExpressionTokenVariant::Error(error) = &token.variant { - let message = match error { - ConstantExpressionParseError::InvalidHexadecimalLiteral(hex) => - format!("Invalid hexadecimal literal '{hex}' in constant expression"), - }; - let context = Context { source: &token.source, source_code}; - report_source_issue(LogLevel::Error, &context, &message); - } - } - _ => (), +impl FromStr for Format { + type Err = (); + fn from_str(string: &str) -> Result<Self, ()> { + match string { + "debug" => Ok(Self::Debug), + "inhx32" => Ok(Self::Inhx32), + "raw" => Ok(Self::Raw), + "source" => Ok(Self::Source), + _ => Err(()), } - DefinitionVariant::Block(block) => { - for error in &block.errors { - report_parse_error(&error, source_code); - } - for token in &block.tokens { - match &token.variant { - BlockTokenVariant::Word(pbl) => for error in &pbl.errors { - let message = match error.variant { - PackedBinaryLiteralParseErrorVariant::DuplicateFieldName(name) => - format!("Duplicate field name '{name}' in packed binary literal"), - PackedBinaryLiteralParseErrorVariant::InvalidCharacter(c) => - format!("Invalid character '{c}' in packed binary literal"), - }; - let context = Context { source: &error.source, source_code }; - report_source_issue(LogLevel::Error, &context, &message); - } - BlockTokenVariant::Invocation(invocation) => - report_invocation_errors(invocation, source_code), - BlockTokenVariant::Comment(_) => (), - } - } - } - DefinitionVariant::Reference(_) => (), - } -} - -fn report_invocation_errors(invocation: &semantic::Invocation, source_code: &str) { - for error in &invocation.errors { - report_parse_error(&error, source_code); - } - for argument in &invocation.arguments { - report_definition_errors(argument, source_code); } } |