Skip to content

Commit

Permalink
Merge branch 'main' into parser-simplification
Browse files Browse the repository at this point in the history
  • Loading branch information
Philogy authored Oct 18, 2024
2 parents 4d1d0b6 + d184772 commit 3845094
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 39 deletions.
10 changes: 8 additions & 2 deletions crates/ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pub enum Definition<'src> {
Macro(Macro<'src>),
Constant {
name: Spanned<&'src str>,
value: U256,
expr: Spanned<ConstExpr>,
},
Jumptable(Jumptable<'src>),
Table {
Expand All @@ -37,6 +37,12 @@ pub struct Macro<'src> {
pub body: Box<[MacroStatement<'src>]>,
}

#[derive(Debug, PartialEq, Eq)]
pub enum ConstExpr {
Value(U256),
FreeStoragePointer,
}

#[derive(Debug, PartialEq, Eq)]
pub enum MacroStatement<'src> {
LabelDefinition(Spanned<&'src str>),
Expand Down Expand Up @@ -69,7 +75,7 @@ pub enum Invoke<'src> {

#[derive(Debug, PartialEq, Eq)]
pub struct Jumptable<'src> {
pub name: (Span, &'src str),
pub name: Spanned<&'src str>,
pub size: u8,
pub labels: Box<[&'src str]>,
}
Expand Down
56 changes: 45 additions & 11 deletions crates/ast/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,11 +252,19 @@ fn invoke<'tokens, 'src: 'tokens>() -> impl Parser<'tokens, 'src, ast::Invoke<'s
}

fn constant<'tokens, 'src: 'tokens>() -> impl Parser<'tokens, 'src, ast::Definition<'src>> {
let const_expr = choice((
word().map(|(value, span)| (ast::ConstExpr::Value(value), span)),
just(Ident("FREE_STORAGE_POINTER"))
.ignore_then(just(Punct('(')))
.ignore_then(just(Punct(')')))
.map_with(|_, ex| (ast::ConstExpr::FreeStoragePointer, ex.span())),
));

just(Ident("constant"))
.ignore_then(ident())
.then_ignore(punct('='))
.then(word())
.map(|(name, (value, _))| ast::Definition::Constant { name, value })
.then(const_expr)
.map(|(name, expr)| ast::Definition::Constant { name, expr })
}

fn table<'tokens, 'src: 'tokens>() -> impl Parser<'tokens, 'src, ast::Definition<'src>> {
Expand All @@ -283,13 +291,18 @@ fn sol_function<'tokens, 'src: 'tokens>() -> impl Parser<'tokens, 'src, ast::Def
.ignore_then(ident())
.then(sol_type_list())
.then(
choice((just(Ident("public")), just(Ident("external"))))
.then_ignore(choice((just(Ident("view")), just(Ident("pure")))).or_not())
.then_ignore(choice((just(Ident("payable")), just(Ident("nonpayable")))).or_not())
.or_not()
.ignore_then(just(Ident("returns")))
.ignore_then(sol_type_list())
.or_not(),
choice((
just(Ident("public")),
just(Ident("external")),
just(Ident("payable")),
just(Ident("nonpayable")),
))
.or_not()
.then_ignore(choice((just(Ident("view")), just(Ident("pure")))).or_not())
.or_not()
.ignore_then(just(Ident("returns")))
.ignore_then(sol_type_list())
.or_not(),
)
.map(|((name, args), rets)| {
let rets = rets.unwrap_or(Box::new([]));
Expand Down Expand Up @@ -607,15 +620,36 @@ mod tests {
}

#[test]
fn parse_constant() {
fn parse_constant_value() {
let span: Span = SimpleSpan::new(0, 0);

assert_ok!(
constant(),
vec![Ident("constant"), Ident("TEST"), Punct('='), Hex("0x1")],
ast::Definition::Constant {
name: ("TEST", span),
value: uint!(1_U256)
expr: (ast::ConstExpr::Value(uint!(1_U256)), span)
}
);
}

#[test]
fn parse_constant_storage_pointer() {
let span: Span = SimpleSpan::new(0, 0);

assert_ok!(
constant(),
vec![
Ident("constant"),
Ident("VAR_LOCATION"),
Punct('='),
Ident("FREE_STORAGE_POINTER"),
Punct('('),
Punct(')')
],
ast::Definition::Constant {
name: ("VAR_LOCATION", span),
expr: (ast::ConstExpr::FreeStoragePointer, span)
}
);
}
Expand Down
70 changes: 44 additions & 26 deletions crates/cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,16 @@ use std::{fs::read_to_string, io, process::exit};
use thiserror::Error;

fn main() {
let cli = argh::from_env();
if let Err(e) = run(cli) {
let cli: Cli = argh::from_env();
let res = match cli.command {
Commands::Build(cmd) => build(cmd),
};
if let Err(e) = res {
eprintln!("error: {}", e);
exit(1);
}
}

fn run(cli: Cli) -> HuffResult {
let src = read_to_string(&cli.filename)?;
let filename: String = cli.filename;
match parse(&src) {
Ok(ast) => println!("{:?}", ast),
Err(errs) => errs.into_iter().for_each(|e| {
Report::build(ReportKind::Error, filename.clone(), e.span().start)
.with_config(Config::default().with_index_type(IndexType::Byte))
.with_message(e.reason())
.with_label(
Label::new((filename.clone(), e.span().into_range()))
.with_message(e.reason())
.with_color(Color::Red),
)
.finish()
.print(sources([(filename.clone(), &src)]))
.unwrap()
}),
}

Ok(())
}

#[derive(Error, Debug)]
enum HuffError {
/// Wrapper around `io::Error`
Expand All @@ -44,12 +24,50 @@ enum HuffError {
// Parser(Report),
// Parser(#[from] ParseError<usize, Token<'src>, huff_ast::Error>),
}

type HuffResult = Result<(), HuffError>;

fn build(cmd: BuildCommand) -> HuffResult {
let src = read_to_string(&cmd.filename)?;
let filename: String = cmd.filename;
match parse(&src) {
Ok(ast) => println!("{:?}", ast),
Err(errs) => {
errs.into_iter().for_each(|e| {
Report::build(ReportKind::Error, filename.clone(), e.span().start)
.with_config(Config::default().with_index_type(IndexType::Byte))
// .with_message(e.reason())
.with_label(
Label::new((filename.clone(), e.span().into_range()))
.with_message(e.reason())
.with_color(Color::Red),
)
.finish()
.print(sources([(filename.clone(), &src)]))
.unwrap()
});
}
}

Ok(())
}

#[derive(FromArgs)]
/// Huff Language Compiler
struct Cli {
#[argh(subcommand)]
command: Commands,
}

#[derive(FromArgs)]
#[argh(subcommand)]
enum Commands {
Build(BuildCommand),
}

#[derive(FromArgs)]
#[argh(subcommand, name = "build")]
/// Build compiles a huff file.
struct BuildCommand {
/// filename
#[argh(positional)]
filename: String,
Expand Down

0 comments on commit 3845094

Please sign in to comment.