summaryrefslogtreecommitdiff
path: root/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs201
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);
}
}