Ast expression macro

This commit is contained in:
2026-05-15 01:24:55 +02:00
parent 25f4b5470d
commit 80e17ffafb
5 changed files with 81 additions and 39 deletions
+5 -5
View File
@@ -10,10 +10,10 @@ pub enum ParseError<'a, T> {
#[derive(Debug, Clone)]
pub struct AstError<'a, T> {
span: pest::Span<'a>,
error_code: ErrorCode,
error_message: String,
recovered: Option<T>,
pub span: pest::Span<'a>,
pub error_code: ErrorCode,
pub error_message: String,
pub recovered: Option<T>,
}
#[derive(Debug, Clone)]
@@ -89,7 +89,7 @@ where
span: ast_err.span,
error_code: ast_err.error_code,
error_message: ast_err.error_message,
recovered: None,
recovered: Some(items),
}),
None => Ok(items),
}
+48
View File
@@ -26,3 +26,51 @@ pub fn parse<'a>(source: &'a str) -> Result<Vec<TopLevel>, ParseError<'a, Vec<To
Ok(statements)
}
#[macro_export]
macro_rules! ast_expr {
($inner:tt@$item:path { $($name:ident $t:tt $val:tt $($val2:tt)?),*}) => {{
$(
let $name = $crate::_ast_t!($t $crate::_ast_ti!($inner, $val $($val2)?));
)*
$item { $($name,)* }
}};
}
#[macro_export]
macro_rules! _ast_t {
(: $val:expr) => {
$val.get()?
};
(? $val:expr) => {
$val.or_else(|e| {
if let Some(recovered) = e.recovered {
Ok(recovered)
} else {
Err(e)
}
})
.get()?
};
}
#[macro_export]
macro_rules! _ast_ti {
($inner:ident, ! $val:ident) => {
$val::try_from(&mut $inner)
};
($inner:ident, @ $val:ident) => {
$val::try_from($inner.next().unwrap())
};
($inner:ident, ? ($rule:path)) => {
$crate::parser::listen_rule(&mut $inner, $rule)
};
($inner:ident, & $val:expr) => {
$val
};
}
+20 -29
View File
@@ -1,8 +1,8 @@
use crate::{
Rule,
ast::*,
ast_expr,
error::{AstError, GetParseError},
parser::listen_rule,
};
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for VarDeclStmt {
@@ -53,27 +53,22 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for VarDecl {
Rule::var_decl => {
let mut inner = pair.into_inner();
let type_ = inner
.next()
.and_then(|pair| {
if pair.as_str().trim() == "var" {
None
} else {
Some(TypeExpr::try_from(pair))
}
})
.transpose()
.get()?;
Ok(ast_expr!(inner@VarDecl {
type_: & (inner
.next()
.and_then(|pair| {
if pair.as_str().trim() == "var" {
None
} else {
Some(TypeExpr::try_from(pair))
}
})
.transpose()),
let mutable = listen_rule(&mut inner, Rule::mutable);
mutable: ?(Rule::mutable),
let name = Pattern::try_from(inner.next().unwrap()).get()?;
Ok(VarDecl {
mutable,
name,
type_,
})
name: @Pattern
}))
}
_ => unimplemented!("{:?}", pair.as_rule()),
@@ -89,15 +84,11 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for FieldDecl {
Rule::field => {
let mut inner = pair.into_inner();
let visibility = Visibility::try_from(&mut inner).get()?;
let type_ = TypeExpr::try_from(inner.next().unwrap()).get()?;
let name = Identifier::try_from(inner.next().unwrap()).get()?;
Ok(FieldDecl {
visibility,
type_,
name,
})
Ok(ast_expr!(inner@FieldDecl {
visibility: !Visibility,
type_: @TypeExpr,
name: @Identifier
}))
}
_ => unimplemented!("{:?}", pair.as_rule()),
+2 -2
View File
@@ -1,7 +1,7 @@
use crate::{
Rule,
ast::*,
error::{AstError, AstResult},
error::{AstError, AstResult, GetParseError},
};
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Expression {
@@ -72,7 +72,7 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Postfix {
Ok(match rule {
Rule::postfix => Postfix::try_from(inner.next().unwrap())?,
Rule::field_px => Postfix::FieldAccess(Identifier::try_from(inner.next().unwrap())?),
Rule::field_px => Postfix::FieldAccess(Identifier::try_from(inner.next().unwrap()).get()?),
Rule::call_px => Postfix::Call(inner.map(Expression::try_from).collect::<AstResult<
'a,
+6 -3
View File
@@ -1,9 +1,12 @@
pub mod common;
pub mod items;
use crate::Rule;
use crate::{Rule, error::AstResult};
pub fn listen_rule(pairs: &mut pest::iterators::Pairs<'_, Rule>, rule: Rule) -> bool {
pub fn listen_rule<'a>(
pairs: &mut pest::iterators::Pairs<'_, Rule>,
rule: Rule,
) -> AstResult<'a, bool> {
let consumed = pairs
.peek()
.map(|p| p.as_rule() == rule)
@@ -13,7 +16,7 @@ pub fn listen_rule(pairs: &mut pest::iterators::Pairs<'_, Rule>, rule: Rule) ->
pairs.next();
}
consumed
Ok(consumed)
}
pub fn consume_rule<'a>(