Merge pull request #87 from mist-go/rm-err-recovery
Remove: Error recovery
This commit is contained in:
@@ -13,7 +13,7 @@ pub struct TranspiledFile {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum TranspileError<'a> {
|
||||
Parse(mist_parser::error::ParseError<'a, Vec<mist_parser::ast::TopLevel>>),
|
||||
Parse(mist_parser::error::ParseError<'a>),
|
||||
Semantic(Vec<mist_parser::semantics::SemanticError>),
|
||||
}
|
||||
|
||||
|
||||
@@ -186,7 +186,7 @@ std::io::Result<bool> is_source_newer(Path& source, Path& output) {
|
||||
}
|
||||
|
||||
pub enum TranspileError<'a> {
|
||||
Parse(error::ParseError<'a, Vec<mist_parser::ast::TopLevel>>),
|
||||
Parse(error::ParseError<'a>),
|
||||
Semantic(Vec<mist_parser::semantics::SemanticError>)
|
||||
}
|
||||
|
||||
|
||||
+16
-74
@@ -4,20 +4,19 @@ use pest::iterators::Pair;
|
||||
|
||||
use crate::Rule;
|
||||
|
||||
pub type AstResult<'a, T, ET = T> = Result<T, AstError<'a, ET>>;
|
||||
pub type AstResult<'a, T> = Result<T, AstError<'a>>;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ParseError<'a, T> {
|
||||
pub enum ParseError<'a> {
|
||||
PreAst(pest::error::Error<Rule>),
|
||||
Ast(AstError<'a, T>),
|
||||
Ast(AstError<'a>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct AstError<'a, T> {
|
||||
pub struct AstError<'a> {
|
||||
pub span: pest::Span<'a>,
|
||||
pub error_code: ErrorCode,
|
||||
pub error_message: String,
|
||||
pub recovered: Option<T>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -27,30 +26,21 @@ pub enum ErrorCode {
|
||||
Module,
|
||||
}
|
||||
|
||||
impl<T> From<pest::error::Error<Rule>> for ParseError<'_, T> {
|
||||
impl From<pest::error::Error<Rule>> for ParseError<'_> {
|
||||
fn from(value: pest::error::Error<Rule>) -> Self {
|
||||
Self::PreAst(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> From<AstError<'a, T>> for ParseError<'a, T> {
|
||||
fn from(value: AstError<'a, T>) -> Self {
|
||||
impl<'a> From<AstError<'a>> for ParseError<'a> {
|
||||
fn from(value: AstError<'a>) -> Self {
|
||||
Self::Ast(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, F> AstError<'a, F> {
|
||||
pub fn get<T>(self) -> AstError<'a, T> {
|
||||
AstError {
|
||||
span: self.span,
|
||||
error_code: self.error_code,
|
||||
error_message: self.error_message,
|
||||
recovered: None,
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> AstError<'a> {
|
||||
#[track_caller]
|
||||
pub fn bug_unimplemented<T>(pair: Pair<'a, Rule>) -> AstResult<'a, T, F> {
|
||||
pub fn bug_unimplemented<T>(pair: Pair<'a, Rule>) -> AstResult<'a, T> {
|
||||
let loc = std::panic::Location::caller();
|
||||
|
||||
Err(Self {
|
||||
@@ -62,7 +52,6 @@ impl<'a, F> AstError<'a, F> {
|
||||
loc.file(),
|
||||
loc.line(),
|
||||
),
|
||||
recovered: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -72,21 +61,6 @@ pub trait IntoErr<T, FA, FR> {
|
||||
fn get_map(self, m: impl Fn(FA) -> FR) -> T;
|
||||
}
|
||||
|
||||
impl<'a, T, TE, TE2> IntoErr<AstResult<'a, T, TE2>, TE, TE2> for AstResult<'a, T, TE> {
|
||||
fn get(self) -> AstResult<'a, T, TE2> {
|
||||
self.map_err(AstError::get)
|
||||
}
|
||||
|
||||
fn get_map(self, m: impl Fn(TE) -> TE2) -> AstResult<'a, T, TE2> {
|
||||
self.map_err(|e| AstError {
|
||||
span: e.span,
|
||||
error_code: e.error_code,
|
||||
error_message: e.error_message,
|
||||
recovered: e.recovered.map(m),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub trait GetLength {
|
||||
fn len(&self) -> usize;
|
||||
}
|
||||
@@ -97,24 +71,24 @@ impl<T, E> GetLength for Result<Vec<T>, E> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn collect_recovered<'a, T: Debug, ET>(
|
||||
pub fn collect_recovered<'a, T: Debug>(
|
||||
pairs: impl Iterator<Item = pest::iterators::Pair<'a, Rule>>,
|
||||
) -> AstResult<'a, Vec<T>, Vec<T>>
|
||||
) -> AstResult<'a, Vec<T>>
|
||||
where
|
||||
T: TryFrom<pest::iterators::Pair<'a, Rule>, Error = AstError<'a, ET>>,
|
||||
T: TryFrom<pest::iterators::Pair<'a, Rule>, Error = AstError<'a>>,
|
||||
{
|
||||
collect_recovered_map(pairs, T::try_from)
|
||||
}
|
||||
|
||||
pub fn collect_recovered_map<'a, T: Debug, F, ET>(
|
||||
pub fn collect_recovered_map<'a, T: Debug, F>(
|
||||
pairs: impl Iterator<Item = pest::iterators::Pair<'a, Rule>>,
|
||||
f: F,
|
||||
) -> AstResult<'a, Vec<T>, Vec<T>>
|
||||
) -> AstResult<'a, Vec<T>>
|
||||
where
|
||||
F: Fn(pest::iterators::Pair<'a, Rule>) -> AstResult<'a, T, ET>,
|
||||
F: Fn(pest::iterators::Pair<'a, Rule>) -> AstResult<'a, T>,
|
||||
{
|
||||
let mut items = Vec::new();
|
||||
let mut last_error: Option<AstError<'a, ET>> = None;
|
||||
let mut last_error: Option<AstError<'a>> = None;
|
||||
|
||||
for pair in pairs {
|
||||
match f(pair) {
|
||||
@@ -130,39 +104,7 @@ where
|
||||
span: ast_err.span,
|
||||
error_code: ast_err.error_code,
|
||||
error_message: ast_err.error_message,
|
||||
recovered: Some(items),
|
||||
}),
|
||||
None => Ok(items),
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AstErrorAnalyzer<'a, T>(pub Option<AstError<'a, T>>);
|
||||
|
||||
impl<'a, T> AstErrorAnalyzer<'a, T> {
|
||||
pub fn get<V: Clone, V2: Clone + Into<V>>(
|
||||
&mut self,
|
||||
r: AstResult<'a, V, V2>,
|
||||
) -> AstResult<'a, V, V2> {
|
||||
if let Err(e) = r {
|
||||
self.0 = Some(e.clone().get());
|
||||
|
||||
if let Some(recovered) = e.recovered {
|
||||
Ok(recovered.into())
|
||||
} else {
|
||||
Err(e)
|
||||
}
|
||||
} else {
|
||||
r
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build(self, v: T) -> AstResult<'a, T> {
|
||||
if let Some(mut e) = self.0 {
|
||||
e.recovered = Some(v);
|
||||
|
||||
Err(e)
|
||||
} else {
|
||||
Ok(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ pub mod semantics;
|
||||
|
||||
use ast::*;
|
||||
|
||||
use crate::error::{IntoErr, ParseError};
|
||||
use crate::error::ParseError;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[grammar = "./src/grammar.pest"]
|
||||
@@ -20,22 +20,18 @@ pub struct Program {
|
||||
pub items: Vec<TopLevel>,
|
||||
}
|
||||
|
||||
pub fn parse<'a>(source: &'a str) -> Result<Program, ParseError<'a, Vec<TopLevel>>> {
|
||||
pub fn parse<'a>(source: &'a str) -> Result<Program, ParseError<'a>> {
|
||||
let mut pairs = MistParser::parse(Rule::program, source)?;
|
||||
|
||||
let mut statements = vec![];
|
||||
|
||||
let mut analyzer = error::AstErrorAnalyzer(None);
|
||||
|
||||
for pair in pairs.next().unwrap().into_inner() {
|
||||
if pair.as_rule() != Rule::EOI {
|
||||
statements.push(analyzer.get(TopLevel::try_from(pair)).get()?);
|
||||
statements.push(TopLevel::try_from(pair)?);
|
||||
}
|
||||
}
|
||||
|
||||
match analyzer.build(statements) {
|
||||
Ok(v) => {
|
||||
let (mod_attributes, items): (Vec<_>, Vec<_>) = v
|
||||
let (mod_attributes, items): (Vec<_>, Vec<_>) = statements
|
||||
.into_iter()
|
||||
.partition(|item| matches!(item.0.item, TopLevelKind::ModAttribute));
|
||||
|
||||
@@ -44,21 +40,10 @@ pub fn parse<'a>(source: &'a str) -> Result<Program, ParseError<'a, Vec<TopLevel
|
||||
mod_attributes,
|
||||
})
|
||||
}
|
||||
Err(e) => {
|
||||
let rec = e.recovered.clone();
|
||||
|
||||
let mut e2 = e.get();
|
||||
|
||||
e2.recovered = rec;
|
||||
|
||||
Err(ParseError::Ast(e2))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_module<'a>(
|
||||
source: &'a str,
|
||||
) -> Result<Option<(Visibility, Identifier)>, ParseError<'a, Option<(Visibility, Identifier)>>> {
|
||||
) -> Result<Option<(Visibility, Identifier)>, ParseError<'a>> {
|
||||
let mut pairs = MistParser::parse(Rule::module_program, source)?;
|
||||
|
||||
if let Some(v) = pairs
|
||||
@@ -67,8 +52,7 @@ pub fn parse_module<'a>(
|
||||
.into_inner()
|
||||
.next()
|
||||
.map(TopLevel::try_from)
|
||||
.transpose()
|
||||
.get()?
|
||||
.transpose()?
|
||||
{
|
||||
if let TopLevelKind::DeclareModule(vis, name) = &v.0.item {
|
||||
Ok(Some((vis.clone(), name.clone())))
|
||||
@@ -90,49 +74,7 @@ macro_rules! ast_ensure {
|
||||
span: $pair.as_span(),
|
||||
error_code: crate::error::ErrorCode::AstGenBug,
|
||||
error_message: format!("Possible bug: expected {:?}, got {:?}", $rule, $pair.as_rule()),
|
||||
recovered: None,
|
||||
})
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! ast_expr {
|
||||
(use $r:expr, $($v:expr),* $(,)?) => {{
|
||||
let mut analyzer = $crate::error::AstErrorAnalyzer(None);
|
||||
|
||||
$(
|
||||
analyzer.get($v).get()?;
|
||||
)*
|
||||
|
||||
analyzer.build($r)
|
||||
}};
|
||||
|
||||
($($item:ident)::+ { $($k:ident: $v:expr),* $(,)? }) => {{
|
||||
let mut analyzer = $crate::error::AstErrorAnalyzer(None);
|
||||
|
||||
let v = $($item)::+ { $($k: analyzer.get($v).get()?),* };
|
||||
|
||||
analyzer.build(v)
|
||||
}};
|
||||
|
||||
($($item:ident)::+ ( $($v:expr),* $(,)? )) => {{
|
||||
let mut analyzer = $crate::error::AstErrorAnalyzer(None);
|
||||
|
||||
let v = $($item)::+ ( $(analyzer.get($v).get()?),* );
|
||||
|
||||
analyzer.build(v)
|
||||
}};
|
||||
|
||||
(( $($v:expr),* $(,)? )) => {{
|
||||
let mut analyzer = $crate::error::AstErrorAnalyzer(None);
|
||||
|
||||
let v = ( $(analyzer.get($v).get()?),* );
|
||||
|
||||
analyzer.build(v)
|
||||
}};
|
||||
|
||||
($($item:ident)::+) => {
|
||||
$($item)::+
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,22 +1,21 @@
|
||||
use crate::{
|
||||
Rule,
|
||||
ast::*,
|
||||
ast_expr,
|
||||
error::{AstError, IntoErr, collect_recovered},
|
||||
error::{AstError, collect_recovered},
|
||||
parser::consume_rule,
|
||||
};
|
||||
|
||||
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for VarDeclStmt {
|
||||
type Error = AstError<'a, Self>;
|
||||
type Error = AstError<'a>;
|
||||
|
||||
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
|
||||
match pair.as_rule() {
|
||||
Rule::var_decl_statement => {
|
||||
let mut inner = pair.into_inner();
|
||||
|
||||
ast_expr!(VarDeclStmt {
|
||||
decl: inner.next().unwrap().try_into(),
|
||||
init: inner.next().map(Expression::try_from).transpose()
|
||||
Ok(VarDeclStmt {
|
||||
decl: inner.next().unwrap().try_into()?,
|
||||
init: inner.next().map(Expression::try_from).transpose()?,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -26,16 +25,16 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for VarDeclStmt {
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for FieldDeclStmt {
|
||||
type Error = AstError<'a, Self>;
|
||||
type Error = AstError<'a>;
|
||||
|
||||
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
|
||||
match pair.as_rule() {
|
||||
Rule::class_field => {
|
||||
let mut inner = pair.into_inner();
|
||||
|
||||
ast_expr!(FieldDeclStmt {
|
||||
decl: inner.next().unwrap().try_into(),
|
||||
init: inner.next().map(Expression::try_from).transpose(),
|
||||
Ok(FieldDeclStmt {
|
||||
decl: inner.next().unwrap().try_into()?,
|
||||
init: inner.next().map(Expression::try_from).transpose()?,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -45,18 +44,18 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for FieldDeclStmt {
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for VarDecl {
|
||||
type Error = AstError<'a, Self>;
|
||||
type Error = AstError<'a>;
|
||||
|
||||
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
|
||||
match pair.as_rule() {
|
||||
Rule::var_decl | Rule::param => {
|
||||
let mut inner = pair.into_inner();
|
||||
|
||||
ast_expr!(VarDecl {
|
||||
Ok(VarDecl {
|
||||
type_: consume_rule(&mut inner, Rule::type_expr)
|
||||
.map(TypeExpr::try_from)
|
||||
.transpose(),
|
||||
name: Pattern::try_from(inner.next().unwrap()),
|
||||
.transpose()?,
|
||||
name: Pattern::try_from(inner.next().unwrap())?,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -66,17 +65,17 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for VarDecl {
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for FieldDecl {
|
||||
type Error = AstError<'a, Self>;
|
||||
type Error = AstError<'a>;
|
||||
|
||||
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
|
||||
match pair.as_rule() {
|
||||
Rule::field => {
|
||||
let mut inner = pair.into_inner();
|
||||
|
||||
ast_expr!(FieldDecl {
|
||||
visibility: Visibility::try_from(&mut inner),
|
||||
type_: TypeExpr::try_from(inner.next().unwrap()),
|
||||
name: Identifier::try_from(inner.next().unwrap()),
|
||||
Ok(FieldDecl {
|
||||
visibility: Visibility::try_from(&mut inner)?,
|
||||
type_: TypeExpr::try_from(inner.next().unwrap())?,
|
||||
name: Identifier::try_from(inner.next().unwrap())?,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -86,9 +85,9 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for FieldDecl {
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for ParamList {
|
||||
type Error = AstError<'a, Self>;
|
||||
type Error = AstError<'a>;
|
||||
|
||||
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
|
||||
Ok(ParamList(collect_recovered(pair.into_inner()).get()?))
|
||||
Ok(ParamList(collect_recovered(pair.into_inner())?))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
use crate::{
|
||||
Rule,
|
||||
ast::*,
|
||||
ast_ensure, ast_expr,
|
||||
error::{AstError, AstResult, GetLength, IntoErr, collect_recovered, collect_recovered_map},
|
||||
ast_ensure,
|
||||
error::{AstError, collect_recovered, collect_recovered_map},
|
||||
parser::consume_rule,
|
||||
};
|
||||
use pest::pratt_parser::PrattParser;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Expression {
|
||||
type Error = AstError<'a, Self>;
|
||||
type Error = AstError<'a>;
|
||||
|
||||
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
|
||||
let rule = pair.as_rule();
|
||||
@@ -27,10 +27,10 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Expression {
|
||||
pratt
|
||||
.map_primary(|primary_pair| Expression::try_from(primary_pair))
|
||||
.map_infix(|expr, op, rhs| {
|
||||
ast_expr!(Expression::Binary {
|
||||
lhs: expr.map(Box::new).get_map(Box::new),
|
||||
op: Ok(op.as_str().to_string()) as AstResult<'_, String>,
|
||||
rhs: rhs.map(Box::new).get_map(Box::new),
|
||||
Ok(Expression::Binary {
|
||||
lhs: expr.map(Box::new)?,
|
||||
op: op.as_str().to_string(),
|
||||
rhs: rhs.map(Box::new)?,
|
||||
})
|
||||
})
|
||||
.parse(inner)
|
||||
@@ -50,59 +50,51 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Expression {
|
||||
}
|
||||
}
|
||||
|
||||
let prefixes = collect_recovered::<Prefix, Prefix>(prefix_pairs.into_iter());
|
||||
let prefixes = collect_recovered::<Prefix>(prefix_pairs.into_iter())?;
|
||||
let exp = Expression::try_from(
|
||||
primary_pair.expect("Term must contain a primary expression"),
|
||||
);
|
||||
let postfixes = collect_recovered::<Postfix, Postfix>(postfix_pairs.into_iter());
|
||||
)?;
|
||||
let postfixes = collect_recovered::<Postfix>(postfix_pairs.into_iter())?;
|
||||
|
||||
if postfixes.len() > 0 || prefixes.len() > 0 {
|
||||
ast_expr!(Expression::Fix {
|
||||
initial: exp.map(Box::new),
|
||||
Ok(Expression::Fix {
|
||||
initial: Box::new(exp),
|
||||
prefixes: prefixes,
|
||||
postfixes: postfixes,
|
||||
})
|
||||
} else {
|
||||
ast_expr!(use exp?, prefixes, postfixes)
|
||||
Ok(exp)
|
||||
}
|
||||
}
|
||||
|
||||
Rule::tuple => {
|
||||
ast_expr!(Expression::Literal(
|
||||
collect_recovered(pair.into_inner())
|
||||
.map(Literal::Tuple)
|
||||
.get_map(Literal::Tuple)
|
||||
))
|
||||
}
|
||||
Rule::tuple => Ok(Expression::Literal(Literal::Tuple(collect_recovered(
|
||||
pair.into_inner(),
|
||||
)?))),
|
||||
|
||||
Rule::closure => {
|
||||
ast_expr!(Expression::Closure {
|
||||
Rule::closure => Ok(Expression::Closure {
|
||||
return_type: consume_rule(&mut inner, Rule::type_expr)
|
||||
.map(TypeExpr::try_from)
|
||||
.transpose(),
|
||||
params: collect_recovered(inner.next().unwrap().into_inner()),
|
||||
body: Expression::try_from(inner.next().unwrap()).map(Box::new),
|
||||
})
|
||||
}
|
||||
.transpose()?,
|
||||
params: collect_recovered(inner.next().unwrap().into_inner())?,
|
||||
body: Box::new(Expression::try_from(inner.next().unwrap())?),
|
||||
}),
|
||||
|
||||
Rule::array => {
|
||||
ast_expr!(Expression::Array(collect_recovered(inner)))
|
||||
}
|
||||
Rule::array => Ok(Expression::Array(collect_recovered(inner)?)),
|
||||
|
||||
Rule::array_repeat => {
|
||||
ast_expr!(Expression::ArrayRepeat(
|
||||
Expression::try_from(inner.next().unwrap()).map(Box::new),
|
||||
Expression::try_from(inner.next().unwrap()).map(Box::new)
|
||||
))
|
||||
}
|
||||
Rule::array_repeat => Ok(Expression::ArrayRepeat(
|
||||
Box::new(Expression::try_from(inner.next().unwrap())?),
|
||||
Box::new(Expression::try_from(inner.next().unwrap())?),
|
||||
)),
|
||||
|
||||
Rule::primary => pair.into_inner().next().unwrap().try_into(),
|
||||
Rule::static_path => ast_expr!(Expression::Path(pair.try_into())),
|
||||
Rule::literal => ast_expr!(Expression::Literal(pair.try_into())),
|
||||
Rule::expr_path => ast_expr!(Expression::Path(pair.try_into())),
|
||||
Rule::statement | Rule::basic_stmt | Rule::control_flow | Rule::block | Rule::unsafe_block => ast_expr!(
|
||||
Expression::Statement(pair.try_into().get_map(Box::new).map(Box::new))
|
||||
),
|
||||
Rule::static_path => Ok(Expression::Path(pair.try_into()?)),
|
||||
Rule::literal => Ok(Expression::Literal(pair.try_into()?)),
|
||||
Rule::expr_path => Ok(Expression::Path(pair.try_into()?)),
|
||||
Rule::statement
|
||||
| Rule::basic_stmt
|
||||
| Rule::control_flow
|
||||
| Rule::block
|
||||
| Rule::unsafe_block => Ok(Expression::Statement(Box::new(pair.try_into()?))),
|
||||
|
||||
_ => AstError::bug_unimplemented(pair),
|
||||
}
|
||||
@@ -110,7 +102,7 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Expression {
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Prefix {
|
||||
type Error = AstError<'a, Self>;
|
||||
type Error = AstError<'a>;
|
||||
|
||||
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
|
||||
Ok(match pair.as_rule() {
|
||||
@@ -127,7 +119,7 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Prefix {
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Postfix {
|
||||
type Error = AstError<'a, Self>;
|
||||
type Error = AstError<'a>;
|
||||
|
||||
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
|
||||
let rule = pair.as_rule();
|
||||
@@ -136,34 +128,27 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Postfix {
|
||||
match rule {
|
||||
Rule::postfix => Postfix::try_from(inner.next().unwrap()),
|
||||
|
||||
Rule::field_px => {
|
||||
ast_expr!(Postfix::FieldAccess(
|
||||
inner.next().unwrap().try_into(),
|
||||
inner.next().map(Generics::try_from).transpose()
|
||||
))
|
||||
}
|
||||
Rule::field_px => Ok(Postfix::FieldAccess(
|
||||
inner.next().unwrap().try_into()?,
|
||||
inner.next().map(Generics::try_from).transpose()?,
|
||||
)),
|
||||
|
||||
Rule::tuple_field_px => {
|
||||
ast_expr!(Postfix::TupleFieldAccess(
|
||||
Ok(inner.next().unwrap().as_str().parse().unwrap_or(255_u8))
|
||||
as AstResult<'_, u8>,
|
||||
inner.next().map(Generics::try_from).transpose(),
|
||||
))
|
||||
}
|
||||
Rule::tuple_field_px => Ok(Postfix::TupleFieldAccess(
|
||||
inner.next().unwrap().as_str().parse().unwrap_or(255_u8),
|
||||
inner.next().map(Generics::try_from).transpose()?,
|
||||
)),
|
||||
|
||||
Rule::call_px => ast_expr!(Postfix::Call(collect_recovered(inner))),
|
||||
Rule::call_px => Ok(Postfix::Call(collect_recovered(inner)?)),
|
||||
|
||||
Rule::struct_px => ast_expr!(Postfix::StructCall(collect_recovered_map(inner, |p| {
|
||||
Rule::struct_px => Ok(Postfix::StructCall(collect_recovered_map(inner, |p| {
|
||||
let mut pi = p.into_inner();
|
||||
Ok((
|
||||
Identifier::try_from(pi.next().unwrap())?,
|
||||
pi.next().map(Expression::try_from).transpose().get()?,
|
||||
pi.next().map(Expression::try_from).transpose()?,
|
||||
))
|
||||
}))),
|
||||
})?)),
|
||||
|
||||
Rule::index_px => {
|
||||
ast_expr!(Postfix::Index(Expression::try_from(inner.next().unwrap())))
|
||||
}
|
||||
Rule::index_px => Ok(Postfix::Index(Expression::try_from(inner.next().unwrap())?)),
|
||||
|
||||
Rule::macro_call_paren => Ok(Postfix::MacroCall {
|
||||
inner: inner.as_str().to_string(),
|
||||
@@ -178,9 +163,7 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Postfix {
|
||||
delimiter: MacroDelimiter::Brace,
|
||||
}),
|
||||
|
||||
Rule::as_px => {
|
||||
ast_expr!(Postfix::As(inner.next().unwrap().try_into()))
|
||||
}
|
||||
Rule::as_px => Ok(Postfix::As(inner.next().unwrap().try_into()?)),
|
||||
|
||||
Rule::try_px => Ok(Postfix::Try),
|
||||
|
||||
@@ -193,25 +176,25 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Postfix {
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for ExprPath {
|
||||
type Error = AstError<'a, Self>;
|
||||
type Error = AstError<'a>;
|
||||
|
||||
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
|
||||
ast_ensure!(pair, Rule::expr_path => {
|
||||
ast_expr!(ExprPath(collect_recovered(pair.into_inner())))
|
||||
Ok(ExprPath(collect_recovered(pair.into_inner())?))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for ExprPathSegment {
|
||||
type Error = AstError<'a, Self>;
|
||||
type Error = AstError<'a>;
|
||||
|
||||
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
|
||||
let mut inner = pair.clone().into_inner();
|
||||
|
||||
ast_ensure!(pair, Rule::expr_path_segment => {
|
||||
ast_expr!(ExprPathSegment {
|
||||
ident: Identifier::try_from(inner.next().unwrap()),
|
||||
generics: inner.next().map(Generics::try_from).transpose(),
|
||||
Ok(ExprPathSegment {
|
||||
ident: Identifier::try_from(inner.next().unwrap())?,
|
||||
generics: inner.next().map(Generics::try_from).transpose()?,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -6,13 +6,13 @@ pub mod types;
|
||||
use crate::{
|
||||
Rule,
|
||||
ast::*,
|
||||
ast_ensure, ast_expr,
|
||||
error::{AstError, AstResult, IntoErr, collect_recovered, collect_recovered_map},
|
||||
ast_ensure,
|
||||
error::{AstError, collect_recovered, collect_recovered_map},
|
||||
parser::{consume_rule, listen_rule},
|
||||
};
|
||||
|
||||
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Identifier {
|
||||
type Error = AstError<'a, Self>;
|
||||
type Error = AstError<'a>;
|
||||
|
||||
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
|
||||
ast_ensure!(pair, Rule::identifier => {
|
||||
@@ -22,18 +22,18 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Identifier {
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Path {
|
||||
type Error = AstError<'a, Self>;
|
||||
type Error = AstError<'a>;
|
||||
|
||||
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
|
||||
match pair.as_rule() {
|
||||
Rule::static_path => Ok(Path(collect_recovered(pair.into_inner()).get()?)),
|
||||
Rule::static_path => Ok(Path(collect_recovered(pair.into_inner())?)),
|
||||
_ => AstError::bug_unimplemented(pair),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Literal {
|
||||
type Error = AstError<'a, Self>;
|
||||
type Error = AstError<'a>;
|
||||
|
||||
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
|
||||
let rule = pair.as_rule();
|
||||
@@ -46,53 +46,52 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Literal {
|
||||
Rule::float => Literal::Float(pair.as_str().parse::<f64>().unwrap()),
|
||||
Rule::boolean => Literal::Bool(pair.as_str().parse::<bool>().unwrap()),
|
||||
Rule::string_lit => Literal::String(inner.as_str().to_string()),
|
||||
Rule::tuple => Literal::Tuple(collect_recovered(inner).get()?),
|
||||
Rule::tuple => Literal::Tuple(collect_recovered(inner)?),
|
||||
_ => return AstError::bug_unimplemented(pair),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Pattern {
|
||||
type Error = AstError<'a, Self>;
|
||||
type Error = AstError<'a>;
|
||||
|
||||
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
|
||||
let rule = pair.as_rule();
|
||||
let mut inner = pair.clone().into_inner();
|
||||
|
||||
match rule {
|
||||
Rule::tuple_pattern => ast_expr!(Pattern::Tuple(collect_recovered_map(inner, |v| {
|
||||
Rule::tuple_pattern => Ok(Pattern::Tuple(collect_recovered_map(inner, |v| {
|
||||
Self::try_from(v).map(Box::new)
|
||||
}))),
|
||||
})?)),
|
||||
|
||||
Rule::named_tuple_pattern => ast_expr!(Pattern::NamedTuple(
|
||||
Path::try_from(inner.next().unwrap()),
|
||||
collect_recovered_map(inner, |v| Self::try_from(v).map(Box::new)),
|
||||
Rule::named_tuple_pattern => Ok(Pattern::NamedTuple(
|
||||
Path::try_from(inner.next().unwrap())?,
|
||||
collect_recovered_map(inner, |v| Self::try_from(v).map(Box::new))?,
|
||||
)),
|
||||
|
||||
Rule::struct_pattern => ast_expr!(Pattern::Struct(
|
||||
Path::try_from(inner.next().unwrap()),
|
||||
Rule::struct_pattern => Ok(Pattern::Struct(
|
||||
Path::try_from(inner.next().unwrap())?,
|
||||
collect_recovered_map(inner, |v| {
|
||||
if v.as_rule() == Rule::etc_pattern {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let mut inner = v.into_inner();
|
||||
Some(ast_expr!((
|
||||
Identifier::try_from(inner.next().unwrap()),
|
||||
Ok(Some((
|
||||
Identifier::try_from(inner.next().unwrap())?,
|
||||
inner
|
||||
.next()
|
||||
.map(|v| Self::try_from(v).map(Box::new).get_map(Box::new))
|
||||
.transpose()
|
||||
.map(|v| Self::try_from(v).map(Box::new))
|
||||
.transpose()?,
|
||||
)))
|
||||
.transpose()
|
||||
}),
|
||||
})?,
|
||||
)),
|
||||
|
||||
Rule::literal => ast_expr!(Pattern::Literal(pair.try_into())),
|
||||
Rule::literal => Ok(Pattern::Literal(pair.try_into()?)),
|
||||
|
||||
Rule::path_pattern => ast_expr!(Pattern::Path(
|
||||
Ok(listen_rule(&mut inner, Rule::mutable)) as AstResult<'_, bool>,
|
||||
inner.next().unwrap().try_into()
|
||||
Rule::path_pattern => Ok(Pattern::Path(
|
||||
listen_rule(&mut inner, Rule::mutable),
|
||||
inner.next().unwrap().try_into()?,
|
||||
)),
|
||||
|
||||
Rule::etc_pattern => Ok(Pattern::Etc),
|
||||
@@ -103,13 +102,13 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Pattern {
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<&mut pest::iterators::Pairs<'a, Rule>> for Visibility {
|
||||
type Error = AstError<'a, Self>;
|
||||
type Error = AstError<'a>;
|
||||
|
||||
fn try_from(pairs: &mut pest::iterators::Pairs<'a, Rule>) -> Result<Self, Self::Error> {
|
||||
Ok(consume_rule(pairs, Rule::visibility)
|
||||
.map(|pair| -> Result<Visibility, AstError<'a, Self>> {
|
||||
.map(|pair| -> Result<Visibility, AstError<'a>> {
|
||||
if let Some(path) = pair.into_inner().next() {
|
||||
ast_expr!(Visibility::PublicTarget(Path::try_from(path)))
|
||||
Ok(Visibility::PublicTarget(Path::try_from(path)?))
|
||||
} else {
|
||||
Ok(Visibility::Public)
|
||||
}
|
||||
|
||||
@@ -1,42 +1,42 @@
|
||||
use crate::{
|
||||
Rule,
|
||||
ast::*,
|
||||
ast_ensure, ast_expr,
|
||||
error::{AstError, IntoErr, collect_recovered},
|
||||
ast_ensure,
|
||||
error::{AstError, collect_recovered},
|
||||
};
|
||||
|
||||
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Block {
|
||||
type Error = AstError<'a, Self>;
|
||||
type Error = AstError<'a>;
|
||||
|
||||
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
|
||||
let mut inner = pair.clone().into_inner();
|
||||
|
||||
ast_ensure!(pair, Rule::block => {
|
||||
ast_expr!(Block {
|
||||
statements: collect_recovered(inner.next().unwrap().into_inner()),
|
||||
soft_return: inner.next().map(Spanned::try_from).transpose(),
|
||||
Ok(Block {
|
||||
statements: collect_recovered(inner.next().unwrap().into_inner())?,
|
||||
soft_return: inner.next().map(Spanned::try_from).transpose()?,
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for StatementBranch {
|
||||
type Error = AstError<'a, Self>;
|
||||
type Error = AstError<'a>;
|
||||
|
||||
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
|
||||
let mut inner = pair.clone().into_inner();
|
||||
|
||||
ast_ensure!(pair, Rule::statement_branch => {
|
||||
ast_expr!(StatementBranch {
|
||||
condition: inner.next().unwrap().try_into(),
|
||||
body: inner.next().unwrap().try_into().map(Box::new),
|
||||
Ok(StatementBranch {
|
||||
condition: inner.next().unwrap().try_into()?,
|
||||
body: Box::new(inner.next().unwrap().try_into()?),
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Statement {
|
||||
type Error = AstError<'a, Self>;
|
||||
type Error = AstError<'a>;
|
||||
|
||||
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
|
||||
let rule = pair.as_rule();
|
||||
@@ -47,50 +47,46 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Statement {
|
||||
Statement::try_from(inner.next().unwrap())
|
||||
}
|
||||
|
||||
Rule::unsafe_block => ast_expr!(Statement::UnsafeBlock(inner.next().unwrap().try_into())),
|
||||
Rule::unsafe_block => Ok(Statement::UnsafeBlock(inner.next().unwrap().try_into()?)),
|
||||
|
||||
Rule::block => ast_expr!(Statement::Block(pair.try_into())),
|
||||
Rule::block => Ok(Statement::Block(pair.try_into()?)),
|
||||
|
||||
Rule::var_decl_statement => ast_expr!(Statement::VarDecl(pair.try_into())),
|
||||
Rule::var_decl_statement => Ok(Statement::VarDecl(pair.try_into()?)),
|
||||
|
||||
Rule::return_stmt => {
|
||||
ast_expr!(Statement::Return(
|
||||
inner.next().map(Expression::try_from).transpose()
|
||||
))
|
||||
}
|
||||
Rule::return_stmt => Ok(Statement::Return(
|
||||
inner.next().map(Expression::try_from).transpose()?,
|
||||
)),
|
||||
|
||||
Rule::break_stmt => Ok(Statement::Break),
|
||||
|
||||
Rule::continue_stmt => Ok(Statement::Continue),
|
||||
|
||||
Rule::if_stmt => {
|
||||
ast_expr!(Statement::If {
|
||||
initial: inner.next().unwrap().try_into(),
|
||||
else_if: collect_recovered(inner.next().unwrap().into_inner()),
|
||||
else_branch: inner.next().map(Block::try_from).transpose(),
|
||||
})
|
||||
}
|
||||
|
||||
Rule::while_stmt => ast_expr!(Statement::While(inner.next().unwrap().try_into())),
|
||||
|
||||
Rule::loop_stmt => ast_expr!(Statement::Loop(inner.next().unwrap().try_into())),
|
||||
|
||||
Rule::c_for_stmt => ast_expr!(Statement::CStyleFor {
|
||||
init: inner.next().unwrap().try_into(),
|
||||
condition: inner.next().unwrap().try_into(),
|
||||
update: inner.next().unwrap().try_into(),
|
||||
body: inner.next().unwrap().try_into(),
|
||||
Rule::if_stmt => Ok(Statement::If {
|
||||
initial: inner.next().unwrap().try_into()?,
|
||||
else_if: collect_recovered(inner.next().unwrap().into_inner())?,
|
||||
else_branch: inner.next().map(Block::try_from).transpose()?,
|
||||
}),
|
||||
|
||||
Rule::for_stmt => ast_expr!(Statement::For {
|
||||
pattern: inner.next().unwrap().try_into(),
|
||||
iterator: inner.next().unwrap().try_into(),
|
||||
body: inner.next().unwrap().try_into(),
|
||||
Rule::while_stmt => Ok(Statement::While(inner.next().unwrap().try_into()?)),
|
||||
|
||||
Rule::loop_stmt => Ok(Statement::Loop(inner.next().unwrap().try_into()?)),
|
||||
|
||||
Rule::c_for_stmt => Ok(Statement::CStyleFor {
|
||||
init: inner.next().unwrap().try_into()?,
|
||||
condition: inner.next().unwrap().try_into()?,
|
||||
update: inner.next().unwrap().try_into()?,
|
||||
body: inner.next().unwrap().try_into()?,
|
||||
}),
|
||||
|
||||
Rule::match_stmt => ast_expr!(Statement::Match(
|
||||
inner.next().unwrap().try_into(),
|
||||
collect_recovered(inner),
|
||||
Rule::for_stmt => Ok(Statement::For {
|
||||
pattern: inner.next().unwrap().try_into()?,
|
||||
iterator: inner.next().unwrap().try_into()?,
|
||||
body: inner.next().unwrap().try_into()?,
|
||||
}),
|
||||
|
||||
Rule::match_stmt => Ok(Statement::Match(
|
||||
inner.next().unwrap().try_into()?,
|
||||
collect_recovered(inner)?,
|
||||
)),
|
||||
|
||||
_ => AstError::bug_unimplemented(pair),
|
||||
@@ -99,14 +95,14 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Statement {
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for MatchItem {
|
||||
type Error = AstError<'a, Self>;
|
||||
type Error = AstError<'a>;
|
||||
|
||||
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
|
||||
let mut match_inner = pair.into_inner();
|
||||
|
||||
Ok(MatchItem(
|
||||
collect_recovered(match_inner.next().unwrap().into_inner()).get()?,
|
||||
Expression::try_from(match_inner.next().unwrap()).get()?,
|
||||
collect_recovered(match_inner.next().unwrap().into_inner())?,
|
||||
Expression::try_from(match_inner.next().unwrap())?,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
use crate::{
|
||||
Rule,
|
||||
ast::*,
|
||||
ast_ensure, ast_expr,
|
||||
error::{AstError, IntoErr, collect_recovered},
|
||||
ast_ensure,
|
||||
error::{AstError, collect_recovered},
|
||||
parser::{consume_rule, listen_rule},
|
||||
};
|
||||
|
||||
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TypeExpr {
|
||||
type Error = AstError<'a, Self>;
|
||||
type Error = AstError<'a>;
|
||||
|
||||
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
|
||||
let rule = pair.as_rule();
|
||||
@@ -27,8 +27,7 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TypeExpr {
|
||||
lifetime: consume_rule(&mut ref_inner, Rule::ref_lifetime)
|
||||
.map(|v| v.into_inner().next().map(Lifetime::try_from))
|
||||
.unwrap_or_default()
|
||||
.transpose()
|
||||
.get()?,
|
||||
.transpose()?,
|
||||
mutable: listen_rule(&mut ref_inner, Rule::mutable),
|
||||
ty: Box::new(ty),
|
||||
};
|
||||
@@ -36,21 +35,17 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TypeExpr {
|
||||
|
||||
Ok(ty)
|
||||
}
|
||||
Rule::lifetime => ast_expr!(TypeExpr::Lifetime(inner.next().unwrap().try_into())),
|
||||
Rule::lifetime => Ok(TypeExpr::Lifetime(inner.next().unwrap().try_into()?)),
|
||||
|
||||
Rule::tuple_type => ast_expr!(TypeExpr::Tuple(collect_recovered(inner))),
|
||||
Rule::path_type => {
|
||||
ast_expr!(TypeExpr::Path(
|
||||
Path::try_from(inner.next().unwrap()),
|
||||
inner.next().map(Generics::try_from).transpose()
|
||||
))
|
||||
}
|
||||
Rule::tuple_type => Ok(TypeExpr::Tuple(collect_recovered(inner)?)),
|
||||
Rule::path_type => Ok(TypeExpr::Path(
|
||||
Path::try_from(inner.next().unwrap())?,
|
||||
inner.next().map(Generics::try_from).transpose()?,
|
||||
)),
|
||||
|
||||
Rule::dyn_type => {
|
||||
ast_expr!(TypeExpr::Dyn(
|
||||
TypeExpr::try_from(inner.next().unwrap()).map(Box::new),
|
||||
))
|
||||
}
|
||||
Rule::dyn_type => Ok(TypeExpr::Dyn(
|
||||
TypeExpr::try_from(inner.next().unwrap()).map(Box::new)?,
|
||||
)),
|
||||
|
||||
_ => AstError::bug_unimplemented(pair),
|
||||
}
|
||||
@@ -58,32 +53,32 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TypeExpr {
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for GenericsDecl {
|
||||
type Error = AstError<'a, Self>;
|
||||
type Error = AstError<'a>;
|
||||
|
||||
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
|
||||
let inner = pair.clone().into_inner();
|
||||
|
||||
ast_ensure!(pair, Rule::generics_decl => {
|
||||
ast_expr!(GenericsDecl(collect_recovered(inner)))
|
||||
Ok(GenericsDecl(collect_recovered(inner)?))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for GenericDecl {
|
||||
type Error = AstError<'a, Self>;
|
||||
type Error = AstError<'a>;
|
||||
|
||||
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
|
||||
let mut inner = pair.clone().into_inner();
|
||||
|
||||
ast_ensure!(pair, Rule::generic_decl => {
|
||||
if let Some(pair) = consume_rule(&mut inner, Rule::lifetime) {
|
||||
ast_expr!(GenericDecl::Lifetime(
|
||||
pair.into_inner().next().unwrap().try_into(),
|
||||
Ok(GenericDecl::Lifetime(
|
||||
pair.into_inner().next().unwrap().try_into()?,
|
||||
))
|
||||
} else {
|
||||
ast_expr!(GenericDecl::Type(
|
||||
inner.next().unwrap().try_into(),
|
||||
collect_recovered(inner),
|
||||
Ok(GenericDecl::Type(
|
||||
inner.next().unwrap().try_into()?,
|
||||
collect_recovered(inner)?,
|
||||
))
|
||||
}
|
||||
})
|
||||
@@ -91,31 +86,31 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for GenericDecl {
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Generics {
|
||||
type Error = AstError<'a, Self>;
|
||||
type Error = AstError<'a>;
|
||||
|
||||
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
|
||||
let inner = pair.clone().into_inner();
|
||||
|
||||
ast_ensure!(pair, Rule::generics => {
|
||||
ast_expr!(Generics(collect_recovered(inner)))
|
||||
Ok(Generics(collect_recovered(inner)?))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Generic {
|
||||
type Error = AstError<'a, Self>;
|
||||
type Error = AstError<'a>;
|
||||
|
||||
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
|
||||
let mut inner = pair.clone().into_inner();
|
||||
|
||||
ast_ensure!(pair, Rule::generic => {
|
||||
if let Some(pair) = consume_rule(&mut inner, Rule::lifetime) {
|
||||
ast_expr!(Generic::Lifetime(
|
||||
pair.into_inner().next().unwrap().try_into(),
|
||||
Ok(Generic::Lifetime(
|
||||
pair.into_inner().next().unwrap().try_into()?,
|
||||
))
|
||||
} else {
|
||||
ast_expr!(Generic::Type(
|
||||
inner.next().unwrap().try_into()
|
||||
Ok(Generic::Type(
|
||||
inner.next().unwrap().try_into()?
|
||||
))
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use crate::{
|
||||
Rule,
|
||||
ast::*,
|
||||
error::{AstError, IntoErr, collect_recovered},
|
||||
error::{AstError, collect_recovered},
|
||||
};
|
||||
|
||||
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Attribute {
|
||||
type Error = AstError<'a, Self>;
|
||||
type Error = AstError<'a>;
|
||||
|
||||
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
|
||||
match pair.as_rule() {
|
||||
@@ -18,7 +18,7 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Attribute {
|
||||
let mut inner = pair.into_inner();
|
||||
|
||||
// first item is always the path
|
||||
let path = inner.next().unwrap().try_into().get()?;
|
||||
let path = inner.next().unwrap().try_into()?;
|
||||
|
||||
// check what comes next
|
||||
match inner.next() {
|
||||
@@ -32,7 +32,7 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Attribute {
|
||||
// #[path = literal]
|
||||
Ok(Attribute::NameValue {
|
||||
path,
|
||||
value: next.try_into().get()?,
|
||||
value: next.try_into()?,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Attribute {
|
||||
// #[path(...)]
|
||||
Ok(Attribute::List {
|
||||
path,
|
||||
items: collect_recovered(next.into_inner()).get()?,
|
||||
items: collect_recovered(next.into_inner())?,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1,48 +1,39 @@
|
||||
use crate::{
|
||||
Rule,
|
||||
ast::*,
|
||||
error::{AstError, IntoErr},
|
||||
parser::consume_rule,
|
||||
};
|
||||
use crate::{Rule, ast::*, error::AstError, parser::consume_rule};
|
||||
|
||||
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for ClassConstructor {
|
||||
type Error = AstError<'a, Self>;
|
||||
type Error = AstError<'a>;
|
||||
|
||||
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
|
||||
let mut inner = pair.into_inner();
|
||||
|
||||
Ok(Self {
|
||||
visibility: Visibility::try_from(&mut inner).get()?,
|
||||
visibility: Visibility::try_from(&mut inner)?,
|
||||
|
||||
generics: consume_rule(&mut inner, Rule::generics_decl)
|
||||
.map(GenericsDecl::try_from)
|
||||
.transpose()
|
||||
.get()?
|
||||
.transpose()?
|
||||
.unwrap_or_default(),
|
||||
|
||||
params: consume_rule(&mut inner, Rule::param_list)
|
||||
.map(ParamList::try_from)
|
||||
.transpose()
|
||||
.get()?
|
||||
.transpose()?
|
||||
.unwrap_or_default(),
|
||||
|
||||
body: inner.next().unwrap().try_into().get()?,
|
||||
body: inner.next().unwrap().try_into()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for ClassItem {
|
||||
type Error = AstError<'a, Self>;
|
||||
type Error = AstError<'a>;
|
||||
|
||||
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
|
||||
let rule = pair.as_rule();
|
||||
|
||||
match rule {
|
||||
Rule::impl_decl | Rule::impl_for_decl => {
|
||||
Ok(ClassItem::ImplDecl(pair.try_into().get()?))
|
||||
}
|
||||
Rule::impl_decl | Rule::impl_for_decl => Ok(ClassItem::ImplDecl(pair.try_into()?)),
|
||||
|
||||
Rule::function_decl => Ok(ClassItem::Method(pair.try_into().get()?)),
|
||||
Rule::function_decl => Ok(ClassItem::Method(pair.try_into()?)),
|
||||
|
||||
_ => AstError::bug_unimplemented(pair),
|
||||
}
|
||||
|
||||
@@ -1,31 +1,30 @@
|
||||
use crate::{
|
||||
Rule,
|
||||
ast::*,
|
||||
error::{AstError, IntoErr, collect_recovered},
|
||||
error::{AstError, collect_recovered},
|
||||
};
|
||||
|
||||
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for EnumItem {
|
||||
type Error = AstError<'a, Self>;
|
||||
type Error = AstError<'a>;
|
||||
|
||||
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
|
||||
let rule = pair.as_rule();
|
||||
let mut inner = pair.clone().into_inner();
|
||||
|
||||
match rule {
|
||||
Rule::enum_named => Ok(EnumItem::Named(inner.next().unwrap().try_into().get()?)),
|
||||
Rule::enum_named => Ok(EnumItem::Named(inner.next().unwrap().try_into()?)),
|
||||
|
||||
Rule::enum_tuple => Ok(EnumItem::Tuple(
|
||||
inner.next().unwrap().try_into().get()?,
|
||||
collect_recovered(inner.next().unwrap().into_inner()).get()?,
|
||||
inner.next().unwrap().try_into()?,
|
||||
collect_recovered(inner.next().unwrap().into_inner())?,
|
||||
)),
|
||||
|
||||
Rule::enum_struct => Ok(EnumItem::Struct(
|
||||
inner.next().unwrap().try_into().get()?,
|
||||
inner.next().unwrap().try_into()?,
|
||||
inner
|
||||
.next()
|
||||
.map(|pair| collect_recovered::<FieldDecl, FieldDecl>(pair.into_inner()))
|
||||
.transpose()
|
||||
.get()?
|
||||
.map(|pair| collect_recovered::<FieldDecl>(pair.into_inner()))
|
||||
.transpose()?
|
||||
.unwrap_or_default(),
|
||||
)),
|
||||
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
use crate::{
|
||||
Rule,
|
||||
ast::*,
|
||||
ast_ensure, ast_expr,
|
||||
error::{self, AstError, AstResult, IntoErr},
|
||||
ast_ensure,
|
||||
error::{self, AstError, AstResult},
|
||||
parser::{consume_rule, listen_rule},
|
||||
};
|
||||
|
||||
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for FunctionDecl {
|
||||
type Error = AstError<'a, Self>;
|
||||
type Error = AstError<'a>;
|
||||
|
||||
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
|
||||
ast_ensure!(pair, Rule::function_decl => {
|
||||
let mut inner = pair.into_inner();
|
||||
let visibility = Visibility::try_from(&mut inner);
|
||||
let visibility = Visibility::try_from(&mut inner)?;
|
||||
|
||||
let return_type = consume_rule(&mut inner, Rule::type_expr)
|
||||
.map(TypeExpr::try_from)
|
||||
.transpose();
|
||||
.transpose()?;
|
||||
|
||||
let name = Identifier::try_from(inner.next().unwrap());
|
||||
let name = Identifier::try_from(inner.next().unwrap())?;
|
||||
|
||||
let generics = consume_rule(&mut inner, Rule::generics_decl)
|
||||
.map(GenericsDecl::try_from)
|
||||
.transpose()
|
||||
.map(|v| v.unwrap_or_default());
|
||||
.map(|v| v.unwrap_or_default())?;
|
||||
|
||||
let self_param = consume_rule(&mut inner, Rule::self_param).map(|param| {
|
||||
let mut param_inner = param.into_inner();
|
||||
@@ -61,13 +61,13 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for FunctionDecl {
|
||||
Ok(params)
|
||||
}
|
||||
})
|
||||
.unwrap_or_else(|| Ok(ParamList(self_param.into_iter().collect())));
|
||||
.unwrap_or_else(|| Ok(ParamList(self_param.into_iter().collect())))?;
|
||||
|
||||
let is_override = consume_rule(&mut inner, Rule::override_kw).map(Override::try_from).transpose();
|
||||
let is_override = consume_rule(&mut inner, Rule::override_kw).map(Override::try_from).transpose()?;
|
||||
|
||||
let body = inner.next().map(Block::try_from).transpose();
|
||||
let body = inner.next().map(Block::try_from).transpose()?;
|
||||
|
||||
ast_expr!(Self {
|
||||
Ok(Self {
|
||||
visibility: visibility,
|
||||
is_override: is_override,
|
||||
return_type: return_type,
|
||||
@@ -81,24 +81,24 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for FunctionDecl {
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Override {
|
||||
type Error = AstError<'a, Self>;
|
||||
type Error = AstError<'a>;
|
||||
|
||||
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
|
||||
ast_ensure!(pair, Rule::override_kw => {
|
||||
ast_expr!(Override(pair.into_inner().next().map(ExprPath::try_from).transpose()))
|
||||
Ok(Override(pair.into_inner().next().map(ExprPath::try_from).transpose()?))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Lifetime {
|
||||
type Error = AstError<'a, Self>;
|
||||
type Error = AstError<'a>;
|
||||
|
||||
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
|
||||
let mut inner = pair.clone().into_inner();
|
||||
|
||||
match pair.as_rule() {
|
||||
Rule::ref_lifetime => inner.next().unwrap().try_into(),
|
||||
Rule::lifetime => ast_expr!(Lifetime::Lifetime(inner.next().unwrap().try_into())),
|
||||
Rule::lifetime => Ok(Lifetime::Lifetime(inner.next().unwrap().try_into()?)),
|
||||
Rule::unsafe_kw => Ok(Lifetime::Unsafe),
|
||||
_ => error::AstError::bug_unimplemented(pair),
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
use crate::{
|
||||
Rule,
|
||||
ast::*,
|
||||
error::{AstError, IntoErr, collect_recovered},
|
||||
error::{AstError, collect_recovered},
|
||||
parser::consume_rule,
|
||||
};
|
||||
|
||||
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for ImplDecl {
|
||||
type Error = AstError<'a, Self>;
|
||||
type Error = AstError<'a>;
|
||||
|
||||
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
|
||||
let rule = pair.as_rule();
|
||||
@@ -16,23 +16,21 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for ImplDecl {
|
||||
Rule::impl_for_decl => Ok(ImplDecl {
|
||||
generics: consume_rule(&mut inner, Rule::generics_decl)
|
||||
.map(GenericsDecl::try_from)
|
||||
.transpose()
|
||||
.get()?
|
||||
.transpose()?
|
||||
.unwrap_or_default(),
|
||||
trait_: Some(inner.next().unwrap().try_into().get()?),
|
||||
target: inner.next().unwrap().try_into().get()?,
|
||||
methods: collect_recovered(inner).get()?,
|
||||
trait_: Some(inner.next().unwrap().try_into()?),
|
||||
target: inner.next().unwrap().try_into()?,
|
||||
methods: collect_recovered(inner)?,
|
||||
}),
|
||||
|
||||
Rule::impl_decl => Ok(ImplDecl {
|
||||
generics: consume_rule(&mut inner, Rule::generics_decl)
|
||||
.map(GenericsDecl::try_from)
|
||||
.transpose()
|
||||
.get()?
|
||||
.transpose()?
|
||||
.unwrap_or_default(),
|
||||
trait_: None,
|
||||
target: inner.next().unwrap().try_into().get()?,
|
||||
methods: collect_recovered(inner).get()?,
|
||||
target: inner.next().unwrap().try_into()?,
|
||||
methods: collect_recovered(inner)?,
|
||||
}),
|
||||
|
||||
_ => AstError::bug_unimplemented(pair),
|
||||
|
||||
@@ -7,122 +7,119 @@ pub mod impl_decl;
|
||||
use crate::{
|
||||
Rule,
|
||||
ast::*,
|
||||
ast_expr,
|
||||
error::{AstError, IntoErr, collect_recovered},
|
||||
error::{AstError, collect_recovered},
|
||||
parser::consume_rule,
|
||||
};
|
||||
|
||||
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TopLevel {
|
||||
type Error = AstError<'a, Self>;
|
||||
type Error = AstError<'a>;
|
||||
|
||||
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
|
||||
let mut inner = pair.clone().into_inner();
|
||||
|
||||
let attributes = collect_recovered(inner.next().unwrap().into_inner());
|
||||
let attributes = collect_recovered(inner.next().unwrap().into_inner())?;
|
||||
|
||||
ast_expr!(TopLevel(
|
||||
Ok(TopLevel(
|
||||
inner
|
||||
.next()
|
||||
.map(Spanned::try_from)
|
||||
.unwrap_or_else(move || Ok(Spanned::new_pair(pair, TopLevelKind::ModAttribute))),
|
||||
.unwrap_or_else(move || Ok(Spanned::new_pair(pair, TopLevelKind::ModAttribute)))?,
|
||||
attributes,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TopLevelKind {
|
||||
type Error = AstError<'a, Self>;
|
||||
type Error = AstError<'a>;
|
||||
|
||||
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
|
||||
let rule = pair.as_rule();
|
||||
let mut inner = pair.clone().into_inner();
|
||||
|
||||
match rule {
|
||||
Rule::import => ast_expr!(TopLevelKind::Import(
|
||||
Visibility::try_from(&mut inner),
|
||||
Path::try_from(inner.next().unwrap()),
|
||||
Rule::import => Ok(TopLevelKind::Import(
|
||||
Visibility::try_from(&mut inner)?,
|
||||
Path::try_from(inner.next().unwrap())?,
|
||||
)),
|
||||
|
||||
Rule::function_decl => ast_expr!(TopLevelKind::FunctionDecl(pair.try_into())),
|
||||
Rule::function_decl => Ok(TopLevelKind::FunctionDecl(pair.try_into()?)),
|
||||
|
||||
Rule::struct_decl => ast_expr!(TopLevelKind::StructDecl {
|
||||
visibility: Visibility::try_from(&mut inner),
|
||||
Rule::struct_decl => Ok(TopLevelKind::StructDecl {
|
||||
visibility: Visibility::try_from(&mut inner)?,
|
||||
|
||||
name: inner.next().unwrap().try_into(),
|
||||
name: inner.next().unwrap().try_into()?,
|
||||
|
||||
generics: consume_rule(&mut inner, Rule::generics_decl)
|
||||
.map(GenericsDecl::try_from)
|
||||
.transpose()
|
||||
.map(|v| v.unwrap_or_default()),
|
||||
.map(|v| v.unwrap_or_default())?,
|
||||
|
||||
fields: inner
|
||||
.next()
|
||||
.map(|pair| collect_recovered(pair.into_inner()))
|
||||
.transpose()
|
||||
.map(|v| v.unwrap_or_default()),
|
||||
.map(|v| v.unwrap_or_default())?,
|
||||
}),
|
||||
|
||||
Rule::class_decl => ast_expr!(TopLevelKind::ClassDecl {
|
||||
visibility: Visibility::try_from(&mut inner),
|
||||
Rule::class_decl => Ok(TopLevelKind::ClassDecl {
|
||||
visibility: Visibility::try_from(&mut inner)?,
|
||||
|
||||
name: inner.next().unwrap().try_into(),
|
||||
name: inner.next().unwrap().try_into()?,
|
||||
|
||||
generics: consume_rule(&mut inner, Rule::generics_decl)
|
||||
.map(GenericsDecl::try_from)
|
||||
.transpose()
|
||||
.map(|v| v.unwrap_or_default()),
|
||||
.map(|v| v.unwrap_or_default())?,
|
||||
|
||||
inherits: consume_rule(&mut inner, Rule::expr_path)
|
||||
.map(ExprPath::try_from)
|
||||
.transpose(),
|
||||
.transpose()?,
|
||||
|
||||
fields: collect_recovered(inner.next().unwrap().into_inner()),
|
||||
fields: collect_recovered(inner.next().unwrap().into_inner())?,
|
||||
|
||||
constructor: consume_rule(&mut inner, Rule::class_constructor)
|
||||
.map(Spanned::try_from)
|
||||
.transpose(),
|
||||
.transpose()?,
|
||||
|
||||
items: collect_recovered(inner),
|
||||
items: collect_recovered(inner)?,
|
||||
}),
|
||||
|
||||
Rule::enum_decl => ast_expr!(TopLevelKind::EnumDecl {
|
||||
visibility: Visibility::try_from(&mut inner),
|
||||
Rule::enum_decl => Ok(TopLevelKind::EnumDecl {
|
||||
visibility: Visibility::try_from(&mut inner)?,
|
||||
|
||||
name: inner.next().unwrap().try_into(),
|
||||
name: inner.next().unwrap().try_into()?,
|
||||
|
||||
generics: consume_rule(&mut inner, Rule::generics_decl)
|
||||
.map(GenericsDecl::try_from)
|
||||
.transpose()
|
||||
.map(|v| v.unwrap_or_default()),
|
||||
.map(|v| v.unwrap_or_default())?,
|
||||
|
||||
fields: collect_recovered(inner),
|
||||
fields: collect_recovered(inner)?,
|
||||
}),
|
||||
|
||||
Rule::declare_module => ast_expr!(TopLevelKind::DeclareModule(
|
||||
Visibility::try_from(&mut inner),
|
||||
inner.next().unwrap().try_into(),
|
||||
Rule::declare_module => Ok(TopLevelKind::DeclareModule(
|
||||
Visibility::try_from(&mut inner)?,
|
||||
inner.next().unwrap().try_into()?,
|
||||
)),
|
||||
|
||||
Rule::impl_for_decl | Rule::impl_decl => {
|
||||
ast_expr!(TopLevelKind::ImplDecl(pair.try_into()))
|
||||
}
|
||||
Rule::impl_for_decl | Rule::impl_decl => Ok(TopLevelKind::ImplDecl(pair.try_into()?)),
|
||||
|
||||
Rule::trait_decl => ast_expr!(TopLevelKind::TraitDecl {
|
||||
visibility: Visibility::try_from(&mut inner),
|
||||
Rule::trait_decl => Ok(TopLevelKind::TraitDecl {
|
||||
visibility: Visibility::try_from(&mut inner)?,
|
||||
|
||||
name: inner.next().unwrap().try_into(),
|
||||
name: inner.next().unwrap().try_into()?,
|
||||
|
||||
generics: consume_rule(&mut inner, Rule::generics_decl)
|
||||
.map(GenericsDecl::try_from)
|
||||
.transpose()
|
||||
.map(|v| v.unwrap_or_default()),
|
||||
.map(|v| v.unwrap_or_default())?,
|
||||
|
||||
requirements: consume_rule(&mut inner, Rule::trait_requirements)
|
||||
.map(|pair| collect_recovered(pair.into_inner()))
|
||||
.transpose()
|
||||
.map(|v| v.unwrap_or_default()),
|
||||
.map(|v| v.unwrap_or_default())?,
|
||||
|
||||
items: collect_recovered(&mut inner),
|
||||
items: collect_recovered(&mut inner)?,
|
||||
}),
|
||||
|
||||
_ => AstError::bug_unimplemented(pair),
|
||||
|
||||
@@ -40,10 +40,10 @@ impl<T> Spanned<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: TryFrom<pest::iterators::Pair<'a, Rule>, Error = AstError<'a, T>>>
|
||||
impl<'a, T: TryFrom<pest::iterators::Pair<'a, Rule>, Error = AstError<'a>>>
|
||||
TryFrom<pest::iterators::Pair<'a, Rule>> for Spanned<T>
|
||||
{
|
||||
type Error = AstError<'a, Self>;
|
||||
type Error = AstError<'a>;
|
||||
|
||||
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
|
||||
let span = pair.as_span().start_pos().line_col();
|
||||
@@ -51,16 +51,7 @@ impl<'a, T: TryFrom<pest::iterators::Pair<'a, Rule>, Error = AstError<'a, T>>>
|
||||
Ok(Self {
|
||||
line: span.0,
|
||||
column: span.1,
|
||||
item: pair.try_into().map_err(|err: AstError<'_, T>| AstError {
|
||||
span: err.span,
|
||||
error_code: err.error_code,
|
||||
error_message: err.error_message,
|
||||
recovered: err.recovered.map(|v| Spanned {
|
||||
line: span.0,
|
||||
column: span.1,
|
||||
item: v,
|
||||
}),
|
||||
})?,
|
||||
item: pair.try_into()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user