Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Jump Tables #26

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@ in Rust. It comes with:

## Missing Features / TODOs

- [ ] Jump tables
- [ ] parsing
- [ ] builtins (`__tablestart`, `__tablesize`)
- [ ] Code tables
- [ ] builtins (`__tablestart`, `__tablesize`)
- [ ] ABI builtins (`__FUNC_SIG`, `__EVEN_HASH`, `__ERROR`)
Expand Down
97 changes: 64 additions & 33 deletions crates/analysis/src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use ariadne::{Color, Config, Fmt, IndexType, Label, Report, ReportKind};
use huff_ast::{Definition, IdentifiableNode, Instruction, Macro, Spanned};
use huff_ast::{Definition, IdentifiableNode, Instruction, Macro, Span, Spanned, Text};

type InvokeChain<'src, 'ast> = Box<[(&'ast Macro<'src>, &'ast Spanned<&'src str>)]>;
type InvokeChain<'src, 'ast> = Box<[(&'ast Text<'src>, &'ast Text<'src>)]>;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Inclusion<'src, 'ast: 'src> {
pub entry_point: Spanned<&'src str>,
pub entry_point: Text<'src>,
pub invoke_stack: InvokeChain<'src, 'ast>,
pub inclusion: Spanned<&'src str>,
}
Expand All @@ -23,43 +23,48 @@ pub enum AnalysisError<'ast, 'src> {
RecursiveCodeInclusion {
linking_inclusions: Box<[Inclusion<'src, 'ast>]>,
},
LabelNotFound {
scope: &'ast Macro<'src>,
MacroLabelNotFound {
scope: &'ast Text<'src>,
invocation_chain: InvokeChain<'src, 'ast>,
not_found: &'ast Spanned<&'src str>,
not_found: &'ast Text<'src>,
},
TableLabelNotFound {
scope: &'ast Text<'src>,
table_ref: &'ast Text<'src>,
table_def: &'ast Text<'src>,
not_found: &'ast Text<'src>,
},
MacroArgNotFound {
scope: &'ast Macro<'src>,
not_found: &'ast Spanned<&'src str>,
not_found: &'ast Text<'src>,
},
EntryPointNotFound {
name: &'src str,
},
DefinitionNotFound {
scope: &'ast Macro<'src>,
def_type: &'static str,
not_found: &'ast Spanned<&'src str>,
not_found: &'ast Text<'src>,
},
EntryPointHasArgs {
target: &'ast Macro<'src>,
},
MacroArgumentCountMismatch {
scope: &'ast Macro<'src>,
invoke: &'ast Spanned<&'src str>,
invoke: &'ast Text<'src>,
args: &'ast Spanned<Box<[Instruction<'src>]>>,
target: &'ast Macro<'src>,
},
DuplicateLabelDefinition {
scope: &'ast Macro<'src>,
duplicates: Box<[&'ast Spanned<&'src str>]>,
duplicates: Box<[&'ast Text<'src>]>,
},
DuplicateMacroArgDefinition {
scope: &'ast Macro<'src>,
duplicates: Box<[&'ast Spanned<&'src str>]>,
duplicates: Box<[&'ast Text<'src>]>,
},
NotYetSupported {
intent: String,
span: Spanned<()>,
span: Span,
},
}

Expand Down Expand Up @@ -123,7 +128,7 @@ impl AnalysisError<'_, '_> {
})
.fold(base_report, |report, (is_last, scope, invoking)| {
let report = report.with_label(
Label::new((filename.clone(), scope.name.1.into_range()))
Label::new((filename.clone(), scope.1.into_range()))
.with_color(Color::Red),
);

Expand Down Expand Up @@ -190,22 +195,20 @@ impl AnalysisError<'_, '_> {
.finish()
}
Self::DefinitionNotFound {
scope,
def_type,
not_found,
} => Report::build(ReportKind::Error, filename.clone(), not_found.1.start)
.with_config(Config::default().with_index_type(IndexType::Byte))
.with_message(format!(
"Definition of {} '{}' not found in macro {}",
"Definition of {} '{}' not found ",
def_type.fg(Color::Cyan),
not_found.0.fg(Color::Red),
scope.ident().fg(Color::Blue)
))
.with_label(
Label::new((filename.clone(), not_found.1.into_range())).with_color(Color::Red),
)
.finish(),
Self::LabelNotFound {
Self::MacroLabelNotFound {
scope,
invocation_chain,
not_found,
Expand All @@ -221,12 +224,7 @@ impl AnalysisError<'_, '_> {
|(parent_scope, invoke)| {
[
Label::new((filename.clone(), parent_scope.span().into_range()))
.with_color(Color::Yellow)
.with_message(format!(
"No label '{}' found in parent {}",
not_found.ident().fg(Color::Red),
parent_scope.ident().fg(Color::Yellow)
)),
.with_color(Color::Yellow),
Label::new((filename.clone(), invoke.1.into_range())).with_color(
if invoke.ident() == scope.ident() {
Color::Blue
Expand All @@ -237,21 +235,54 @@ impl AnalysisError<'_, '_> {
]
},
))
.with_label(
Label::new((filename.clone(), not_found.span().into_range()))
.with_color(Color::Red),
)
.with_label(
Label::new((filename.clone(), scope.span().into_range()))
.with_color(Color::Blue)
.with_message(format!(
"No label '{}' found in {}",
not_found.ident().fg(Color::Red),
scope.ident().fg(Color::Blue)
)),
.with_color(Color::Blue),
)
.with_help(format!(
"Ensure you've correctly entered the label (case-sensitive) or {}",
"make sure to define it."
))
.finish()
}
Self::TableLabelNotFound {
scope,
table_ref,
table_def,
not_found,
} => Report::build(ReportKind::Error, filename.clone(), not_found.1.start)
.with_config(Config::default().with_index_type(IndexType::Byte))
.with_message(format!(
"Jump table {} referenced label '{}' not found in direct parent macro {}",
table_ref.ident().fg(Color::Magenta),
not_found.ident().fg(Color::Red),
scope.ident().fg(Color::Yellow)
))
.with_label(
Label::new((filename.clone(), scope.span().into_range()))
.with_color(Color::Yellow),
)
.with_label(
Label::new((filename.clone(), table_ref.span().into_range()))
.with_color(Color::Magenta),
)
.with_label(
Label::new((filename.clone(), table_def.span().into_range()))
.with_color(Color::Magenta),
)
.with_label(
Label::new((filename.clone(), not_found.span().into_range()))
.with_color(Color::Red),
)
.with_help(concat!(
"Unlike macro label references, jump tables can only reference labels in their",
" direct parent macro"
))
.finish(),
Self::MacroArgumentCountMismatch {
scope: _,
invoke,
Expand Down Expand Up @@ -359,11 +390,11 @@ impl AnalysisError<'_, '_> {
.finish()
}
Self::NotYetSupported { intent, span } => {
Report::build(ReportKind::Error, filename.clone(), span.1.start)
Report::build(ReportKind::Error, filename.clone(), span.start)
.with_config(Config::default().with_index_type(IndexType::Byte))
.with_message(format!("{} is not yet supported", intent.fg(Color::Cyan),))
.with_label(
Label::new((filename.clone(), span.1.into_range())).with_color(Color::Red),
Label::new((filename.clone(), span.into_range())).with_color(Color::Red),
)
.finish()
}
Expand Down Expand Up @@ -397,7 +428,7 @@ impl AnalysisError<'_, '_> {
|report, (scope, invoking)| {
report
.with_label(
Label::new((filename.clone(), scope.name.1.into_range()))
Label::new((filename.clone(), scope.1.into_range()))
.with_color(Color::Red),
)
.with_label(
Expand Down
7 changes: 6 additions & 1 deletion crates/analysis/src/label_stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ impl<'a, V> LabelStack<'a, V> {
}
}

pub fn get_locals(&self) -> &[(&'a str, V)] {
let local_start_index = *self.context_sizes.last().unwrap_or(&0);
&self.label_stack[local_start_index..]
}

pub fn enter_context(&mut self) {
self.context_sizes.push(self.label_stack.len());
}
Expand Down Expand Up @@ -42,7 +47,7 @@ impl<'a, V> LabelStack<'a, V> {
.next()
}

pub fn contains(&mut self, label: &'a str) -> bool {
pub fn contains(&self, label: &'a str) -> bool {
self.get(label).is_some()
}
}
Expand Down
Loading