summaryrefslogtreecommitdiff
path: root/src/print.rs
diff options
context:
space:
mode:
authorBen Bridle <bridle.benjamin@gmail.com>2025-02-14 09:36:52 +1300
committerBen Bridle <ben@derelict.engineering>2025-03-18 12:23:27 +1300
commit7d4dd52b8cfc865ae1b975ca3b6a3e72a812ebb9 (patch)
tree14ca9fa0ddcdd8c5155ddeaac241cd4f55486b6e /src/print.rs
parentf69a8f8c312ded212446082682bcabba8e3a9c9f (diff)
downloadbedrock-asm-7d4dd52b8cfc865ae1b975ca3b6a3e72a812ebb9.zip
Rewrite library
Diffstat (limited to 'src/print.rs')
-rw-r--r--src/print.rs264
1 files changed, 0 insertions, 264 deletions
diff --git a/src/print.rs b/src/print.rs
deleted file mode 100644
index 2110d37..0000000
--- a/src/print.rs
+++ /dev/null
@@ -1,264 +0,0 @@
-use crate::*;
-
-use SemanticTokenVariant as SemVar;
-use SemanticParseError as SemErr;
-use SyntacticParseError as SynErr;
-
-
-const NORMAL: &str = "\x1b[0m";
-const BOLD: &str = "\x1b[1m";
-const DIM: &str = "\x1b[2m";
-const WHITE: &str = "\x1b[37m";
-const RED: &str = "\x1b[31m";
-const YELLOW: &str = "\x1b[33m";
-const BLUE: &str = "\x1b[34m";
-
-
-pub struct Context<'a> {
- pub source_code: &'a str,
- pub source: &'a SourceSpan,
-}
-
-
-/// Print all errors found in the semantic tokens, including those inside macro
-/// definitions. Returns true if at least one error was printed.
-pub fn print_semantic_errors(semantic_tokens: &[SemanticToken], source_code: &str) -> bool {
- let mut found_error = false;
- for semantic_token in semantic_tokens {
- match &semantic_token.variant {
- SemVar::Error(err) => {
- let context = Context {
- source_code: source_code,
- source: &semantic_token.source,
- };
- found_error = true;
- print_semantic_error(&err, context)
- }
- SemVar::MacroDefinition(definition) => {
- for body_token in &definition.body_tokens {
- if let SemVar::Error(err) = &body_token.variant {
- let context = Context {
- source_code: source_code,
- source: &body_token.source,
- };
- found_error = true;
- print_semantic_error(err, context)
- }
- }
- }
- _ => (),
- }
- }
- return found_error;
-}
-
-fn print_semantic_error(error: &SemanticParseError, context: Context) {
- let message = get_message_for_semantic_error(error);
- print_error(&message, context);
-}
-
-fn get_message_for_semantic_error(error: &SemanticParseError) -> String {
- match error {
- SemErr::LabelDefinitionInMacroDefinition =>
- format!("Label cannot be defined inside a macro"),
- SemErr::MacroDefinitionInMacroDefinition =>
- format!("Macro cannot be defined inside a macro"),
- SemErr::StrayMacroTerminator =>
- format!("Macro definition terminator is missing a macro definition"),
- SemErr::StrayBlockClose =>
- format!("Block was not opened, add a '{{' character to open"),
- SemErr::UnclosedBlock =>
- format!("Block was not closed, add a '}}' character to close"),
- SemErr::UndefinedSymbol(name) =>
- format!("Undefined symbol, no label or macro has been defined with the name '{name}'"),
- SemErr::RedefinedSymbol((_, source)) =>
- format!("Redefined symbol, first defined at {}", source.location()),
- SemErr::MacroInvocationBeforeDefinition((_, source)) =>
- format!("Macro used before definition, definition is at {}", source.location()),
- SemErr:: SyntaxError(syntax_error) => match syntax_error {
- SynErr::UnterminatedComment =>
- format!("Unclosed comment, add a ')' character to close"),
- SynErr::UnterminatedRawString =>
- format!("Unclosed string, add a ' character to close"),
- SynErr::UnterminatedNullString =>
- format!("Unclosed string, add a \" character to close"),
- SynErr::InvalidPaddingValue(_) =>
- format!("Padding value must be two or four hexadecimal digits"),
- }
- }
-}
-
-
-pub fn print_resolver_errors(resolver: &SymbolResolver) -> bool {
- let mut found_error = false;
- for reference in &resolver.unresolved {
- found_error = true;
- let message = format!(
- "Undefined symbol, no label or macro has been defined with the name '{}'",
- &reference.symbol.source.string,
- );
- let source_code = resolver.get_source_code_for_tracked_symbol(reference);
- let source = &reference.symbol.source;
- print_error(&message, Context { source_code, source } )
- }
- for redefinition in &resolver.redefinitions {
- found_error = true;
- let definition = resolver.definitions.get(redefinition.1).unwrap();
- let message = format!(
- "Redefined symbol, first defined at {}",
- &definition.symbol.source.in_merged,
- );
- let source_code = resolver.get_source_code_for_tracked_symbol(&redefinition.0);
- let source = &redefinition.0.symbol.source;
- print_error(&message, Context { source_code, source } )
- }
- return found_error;
-}
-
-
-/// The `ids` argument contains a list of the IDs of the source units which
-/// cyclicly depend on one another.
-pub fn print_cyclic_source_units(ids: &[usize], resolver: &SymbolResolver) {
- eprintln!("{BOLD}{RED}[ERROR]{WHITE}: Some libraries contain a dependency cycle{NORMAL}");
- for id in ids {
- if let Some(unit) = resolver.source_units.get(*id) {
- let path = &unit.source_unit.main.path;
- let path_str = path.as_os_str().to_string_lossy();
- if let Some(name_str) = get_unit_name(&unit.source_unit) {
- eprintln!("{name_str}{NORMAL}{DIM} ({path_str}){NORMAL}");
- } else {
- eprintln!("{path_str}");
- };
- // Print parents involved in dependency cycle.
- for parent_id in &unit.parent_ids {
- if !ids.contains(parent_id) { continue; }
- if let Some(parent_unit) = resolver.source_units.get(*parent_id) {
- let parent_path = &parent_unit.source_unit.main.path;
- let parent_path_str = parent_path.as_os_str().to_string_lossy();
- let parent_name_str = match get_unit_name(&parent_unit.source_unit) {
- Some(parent_name_str) => parent_name_str,
- None => parent_path_str.to_string(),
- };
- eprintln!(" => {parent_name_str} {DIM}({parent_path_str}){NORMAL}");
- }
- }
- }
- }
-}
-
-
-pub fn print_error(message: &str, context: Context) {
- print_source_issue(message, context, SourceIssueVariant::Error);
-}
-
-pub fn print_warning(message: &str, context: Context) {
- print_source_issue(message, context, SourceIssueVariant::Warning);
-}
-
-fn print_source_issue(message: &str, context: Context, variant: SourceIssueVariant) {
- let (label, colour) = match variant {
- SourceIssueVariant::Warning => ("WARNING", YELLOW),
- SourceIssueVariant::Error => ("ERROR", RED),
- };
-
- // Prepare variables.
- let location = &context.source.in_merged;
- let y = location.start.line + 1;
- let digits = y.to_string().len();
- let arrow = "-->";
- let space = " ";
-
- // Print message and file path.
- eprintln!("{BOLD}{colour}[{label}]{WHITE}: {message}{NORMAL}");
- eprintln!("{BLUE}{arrow:>w$}{NORMAL} {location}{NORMAL}", w=digits+3);
- if let Some(source) = &context.source.in_source {
- eprintln!("{BLUE}{arrow:>w$}{NORMAL} {source}{NORMAL}", w=digits+3);
- }
-
- let start = location.start.column;
- let end = location.end.column + 1;
-
- // Print source code line.
- eprint!("{BLUE} {y} | {NORMAL}");
- let line = get_line_from_source_code(context.source_code, location.start.line);
- for (i, c) in line.chars().enumerate() {
- if i == start { eprint!("{colour}") }
- if i == end { eprint!("{NORMAL}") }
- eprint!("{c}");
- }
- eprintln!("{NORMAL}");
-
- // Print source code underline.
- eprint!("{BLUE} {space:>w$} | {NORMAL}", w=digits);
- for _ in 0..start { eprint!(" "); }
- eprint!("{colour}");
- for _ in start..end { eprint!("^"); }
- eprintln!("{NORMAL}");
-}
-
-
-fn get_line_from_source_code(source_code: &str, line: usize) -> &str {
- source_code.split('\n').nth(line).unwrap_or("<error reading line from source>")
-}
-
-
-enum SourceIssueVariant {
- Warning,
- Error,
-}
-
-
-/// Print a tree containing the name and path of each source unit.
-pub fn print_source_tree(resolver: &SymbolResolver) {
- eprintln!(".");
- let len = resolver.root_unit_ids.len();
- for (i, id) in resolver.root_unit_ids.iter().enumerate() {
- let end = i + 1 == len;
- print_source_tree_leaf(resolver, *id, Vec::new(), end);
- }
- eprintln!();
-}
-
-fn print_source_tree_leaf(resolver: &SymbolResolver, id: usize, mut levels: Vec<bool>, end: bool) {
- // A level entry is true if all entries in that level have been printed.
- for level in &levels {
- match level {
- false => eprint!("│ "),
- true => eprint!(" "),
- }
- }
- // The end value is true if all siblings of this entry have been printed.
- match end {
- false => eprint!("├── "),
- true => eprint!("└── "),
- }
- if let Some(unit) = resolver.source_units.get(id) {
- let path_str = &unit.source_unit.main.path.as_os_str().to_string_lossy();
- if let Some(name_str) = get_unit_name(&unit.source_unit) {
- eprint!("{name_str}{BLUE}");
- if unit.source_unit.head.is_some() { eprint!(" +head") }
- if unit.source_unit.tail.is_some() { eprint!(" +tail") }
- let mut unresolved = 0;
- for symbol in &resolver.unresolved {
- if symbol.source_id == id { unresolved += 1; }
- }
- if unresolved > 0 { eprint!("{RED} ({unresolved})"); }
- eprintln!("{NORMAL} {DIM}({path_str}){NORMAL}");
- } else {
- eprintln!("{path_str}");
- }
- levels.push(end);
- let len = unit.child_ids.len();
- for (i, id) in unit.child_ids.iter().enumerate() {
- let end = i + 1 == len;
- print_source_tree_leaf(resolver, *id, levels.clone(), end);
- }
- } else {
- eprintln!("<error loading source unit details>");
- }
-}
-
-
-fn get_unit_name(source_unit: &SourceUnit) -> Option<String> {
- source_unit.main.path.file_name().map(|s| s.to_string_lossy().to_string())
-}