Skip to content

Commit

Permalink
✨ Make AST components spanned (#9)
Browse files Browse the repository at this point in the history
  • Loading branch information
Philogy authored Oct 13, 2024
1 parent c221b5d commit aa340ec
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 29 deletions.
25 changes: 16 additions & 9 deletions crates/ast/src/grammar.lalrpop
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,22 @@ pub Definition: ast::Definition<'input> = {
};

pub Macro: ast::Definition<'input> = {
"macro" <name:IDENT> <args:MacroArgs> "=" <tr:("takes" "(" DEC ")" "returns" "(" DEC ")")?> "{" <insts:MacroStatement*> "}" => {
"macro" <name:Spanned<IDENT>> <args:MacroArgs>
"=" <tr:("takes" "(" DEC ")" "returns" "(" DEC ")")?>
"{" <stmts:Spanned<MacroStatement>*> "}"
=> {
let takes_returns = if let Some((_, _, takes, _, _, _, returns, _)) = tr {
Some((takes.parse::<usize>().unwrap(), returns.parse::<usize>().unwrap()))
} else {
None
};
ast::Definition::Macro(ast::Macro{ name, args, takes_returns, body: insts.into_boxed_slice() })
ast::Definition::Macro(ast::Macro{ name, args, takes_returns, body: stmts.into_boxed_slice() })
}
};

pub MacroArgs: Box<[&'input str]> = {
pub MacroArgs: Box<[(ast::Span, &'input str)]> = {
"(" ")" => Box::new([]),
"(" <first:IDENT> <rest:("," IDENT)*> ")" => {
"(" <first:Spanned<IDENT>> <rest:("," Spanned<IDENT>)*> ")" => {
let mut list = vec![first];
list.extend(rest.into_iter().map(|(_, t)| t));
list.into_boxed_slice()
Expand Down Expand Up @@ -97,7 +100,7 @@ pub Instruction: ast::Instruction<'input> = {
}

pub Invoke: ast::Invoke<'input> = {
<name:IDENT> <args:InvokeMacroArgs> => ast::Invoke::Macro{ name, args },
<name:Spanned<IDENT>> <args:InvokeMacroArgs> => ast::Invoke::Macro{ name, args },
"__tablestart" "(" <arg:IDENT> ")" => ast::Invoke::BuiltinTableStart(arg),
"__tablesize" "(" <arg:IDENT> ")" => ast::Invoke::BuiltinTableSize(arg),
"__codesize" "(" <arg:IDENT> ")" => ast::Invoke::BuiltinCodeSize(arg),
Expand All @@ -107,21 +110,21 @@ pub Invoke: ast::Invoke<'input> = {
"__ERROR" "(" <arg:IDENT> ")" => ast::Invoke::BuiltinError(arg),
};

pub InvokeMacroArgs: Box<[ast::Instruction<'input>]> = {
pub InvokeMacroArgs: Box<[(ast::Span, ast::Instruction<'input>)]> = {
"(" ")" => Box::new([]),
"(" <first:Instruction> <rest:("," Instruction)*> ")" => {
"(" <first:Spanned<Instruction>> <rest:("," Spanned<Instruction>)*> ")" => {
let mut list = vec![first];
list.extend(rest.into_iter().map(|(_, t)| t));
list.into_boxed_slice()
}
}

pub Constant: ast::Definition<'input> = {
"constant" <name:IDENT> "=" <value:Word> => ast::Definition::Constant { name, value }
"constant" <name:Spanned<IDENT>> "=" <value:Word> => ast::Definition::Constant { name, value }
};

pub Table: ast::Definition<'input> = {
"table" <name:IDENT> "{" <code:Code+> "}" => {
"table" <name:Spanned<IDENT>> "{" <code:Code+> "}" => {
let data = code.into_iter().flatten().collect::<Vec<u8>>().into_boxed_slice();
ast::Definition::Codetable { name, data }
},
Expand Down Expand Up @@ -215,6 +218,10 @@ pub Code: Vec<u8> = {
.map_err(|e| ParseError::User{ error: ast::Error::BytesOddLength(e) })
}

Spanned<T>: (ast::Span, T) = {
<start: @L> <inner: T> <end: @R> => (start..end, inner)
}

match {
r"\s+" => {}, // whitespace
r"//[^\n\r]*[\n\r]*" => {}, // single-line comments
Expand Down
24 changes: 16 additions & 8 deletions crates/ast/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ mod parser;
pub use error::Error;
pub use parser::parse;

pub type Span = std::ops::Range<usize>;

lalrpop_util::lalrpop_mod!(
#[allow(clippy::all)]
grammar
Expand All @@ -19,20 +21,26 @@ pub struct Root<'src>(pub Box<[Definition<'src>]>);
#[derive(Debug, PartialEq, Eq)]
pub enum Definition<'src> {
Macro(Macro<'src>),
Constant { name: &'src str, value: U256 },
Constant {
name: (Span, &'src str),
value: U256,
},
Jumptable(Jumptable<'src>),
Codetable { name: &'src str, data: Box<[u8]> },
Codetable {
name: (Span, &'src str),
data: Box<[u8]>,
},
SolFunction(SolFunction<'src>),
SolEvent(SolEvent<'src>),
SolError(SolError<'src>),
}

#[derive(Debug, PartialEq, Eq)]
pub struct Macro<'src> {
pub name: &'src str,
pub args: Box<[&'src str]>,
pub name: (Span, &'src str),
pub args: Box<[(Span, &'src str)]>,
pub takes_returns: Option<(usize, usize)>,
pub body: Box<[MacroStatement<'src>]>,
pub body: Box<[(Span, MacroStatement<'src>)]>,
}

#[derive(Debug, PartialEq, Eq)]
Expand All @@ -53,8 +61,8 @@ pub enum Instruction<'src> {
#[derive(Debug, PartialEq, Eq)]
pub enum Invoke<'src> {
Macro {
name: &'src str,
args: Box<[Instruction<'src>]>,
name: (Span, &'src str),
args: Box<[(Span, Instruction<'src>)]>,
},
BuiltinTableStart(&'src str),
BuiltinTableSize(&'src str),
Expand All @@ -67,7 +75,7 @@ pub enum Invoke<'src> {

#[derive(Debug, PartialEq, Eq)]
pub struct Jumptable<'src> {
pub name: &'src str,
pub name: (Span, &'src str),
pub size: u8,
pub labels: Box<[&'src str]>,
}
Expand Down
25 changes: 13 additions & 12 deletions crates/ast/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ mod tests {
assert_eq!(
grammar::MacroParser::new().parse("macro MAIN() = { }"),
Ok(ast::Definition::Macro(ast::Macro {
name: "MAIN",
name: (6..10, "MAIN"),
args: Box::new([]),
takes_returns: None,
body: Box::new([])
Expand All @@ -117,12 +117,13 @@ mod tests {
grammar::MacroParser::new()
.parse("macro READ_ADDRESS(offset) = takes (0) returns (1) { stop }"),
Ok(ast::Definition::Macro(ast::Macro {
name: "READ_ADDRESS",
args: Box::new(["offset"]),
name: (6..18, "READ_ADDRESS"),
args: Box::new([(19..25, "offset")]),
takes_returns: Some((0, 1)),
body: Box::new([ast::MacroStatement::Instruction(ast::Instruction::Op(
Opcode::STOP
))])
body: Box::new([(
53..57,
ast::MacroStatement::Instruction(ast::Instruction::Op(Opcode::STOP))
)])
}))
);
}
Expand All @@ -142,8 +143,8 @@ mod tests {
assert_eq!(
grammar::MacroStatementParser::new().parse("READ_ADDRESS(0x4)"),
Ok(ast::MacroStatement::Invoke(ast::Invoke::Macro {
name: "READ_ADDRESS",
args: Box::new([ast::Instruction::Op(Opcode::PUSH1([0x04]))])
name: (0..12, "READ_ADDRESS"),
args: Box::new([(13..16, ast::Instruction::Op(Opcode::PUSH1([0x04])))])
}))
);
}
Expand Down Expand Up @@ -181,15 +182,15 @@ mod tests {
assert_eq!(
grammar::ConstantParser::new().parse("constant TEST = 0x1"),
Ok(ast::Definition::Constant {
name: "TEST",
name: (9..13, "TEST"),
value: uint!(1_U256),
})
);
assert_eq!(
grammar::ConstantParser::new()
.parse(" constant TEST /* comment */ = 0b1101 // comment"),
Ok(ast::Definition::Constant {
name: "TEST",
name: (10..14, "TEST"),
value: uint!(13_U256),
})
);
Expand All @@ -200,14 +201,14 @@ mod tests {
assert_eq!(
grammar::TableParser::new().parse("table TEST { 0xc0de }"),
Ok(ast::Definition::Codetable {
name: "TEST",
name: (6..10, "TEST"),
data: Box::new([0xc0, 0xde])
})
);
assert_eq!(
grammar::TableParser::new().parse("table TEST { 0xc0de 0xcc00ddee }"),
Ok(ast::Definition::Codetable {
name: "TEST",
name: (6..10, "TEST"),
data: Box::new([0xc0, 0xde, 0xcc, 0x00, 0xdd, 0xee])
})
);
Expand Down

0 comments on commit aa340ec

Please sign in to comment.