diff options
author | Matthias Schiffer <mschiffer@universe-factory.net> | 2024-04-28 23:55:22 +0200 |
---|---|---|
committer | Matthias Schiffer <mschiffer@universe-factory.net> | 2024-04-29 00:26:59 +0200 |
commit | cee9711ba84e3c7ed8e45bd8364100955cf2b4e0 (patch) | |
tree | d4ed5d200f9d47026d700ec8fa7dddafce893354 | |
parent | fac5b015b92ea06eaff4be6c8a2a20d90e770ebb (diff) | |
download | rebel-cee9711ba84e3c7ed8e45bd8364100955cf2b4e0.tar rebel-cee9711ba84e3c7ed8e45bd8364100955cf2b4e0.zip |
rebel-parse: create separate types to represent types
-rw-r--r-- | crates/rebel-parse/src/ast/expr.rs | 15 | ||||
-rw-r--r-- | crates/rebel-parse/src/ast/mod.rs | 6 | ||||
-rw-r--r-- | crates/rebel-parse/src/ast/typ.rs | 22 | ||||
-rw-r--r-- | crates/rebel-parse/src/grammar/recipe.rs | 58 |
4 files changed, 77 insertions, 24 deletions
diff --git a/crates/rebel-parse/src/ast/expr.rs b/crates/rebel-parse/src/ast/expr.rs index 69c4407..4e386e7 100644 --- a/crates/rebel-parse/src/ast/expr.rs +++ b/crates/rebel-parse/src/ast/expr.rs @@ -157,21 +157,6 @@ pub enum Literal<'a> { } impl<'a> Literal<'a> { - pub(crate) fn number(s: &'a str) -> Result<Self, &'static str> { - let (radix, rest) = if let Some(rest) = s.strip_prefix("0x") { - (16, rest) - } else if let Some(rest) = s.strip_prefix("0o") { - (8, rest) - } else if let Some(rest) = s.strip_prefix("0b") { - (2, rest) - } else { - (10, s) - }; - let digits = rest.replace('_', ""); - let value = u64::from_str_radix(&digits, radix).or(Err("number"))?; - Ok(Literal::Int(value)) - } - fn validate(&self) -> Result<(), ValidationError> { match self { Literal::Unit => Ok(()), diff --git a/crates/rebel-parse/src/ast/mod.rs b/crates/rebel-parse/src/ast/mod.rs index 9db7630..14233dc 100644 --- a/crates/rebel-parse/src/ast/mod.rs +++ b/crates/rebel-parse/src/ast/mod.rs @@ -1,6 +1,8 @@ pub mod expr; +pub mod typ; use expr::*; +use typ::Type; pub type Recipe<'a> = Vec<RecipeStmt<'a>>; @@ -99,13 +101,13 @@ impl<'a> BodyStmt<'a> { #[derive(Debug, Clone, PartialEq, Eq)] pub struct TypedExpr<'a> { pub expr: Expr<'a>, - pub typ: Option<Expr<'a>>, + pub typ: Option<Type<'a>>, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct FuncParam<'a> { pub name: Ident<'a>, - pub typ: Expr<'a>, + pub typ: Type<'a>, } #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/crates/rebel-parse/src/ast/typ.rs b/crates/rebel-parse/src/ast/typ.rs new file mode 100644 index 0000000..4b509e6 --- /dev/null +++ b/crates/rebel-parse/src/ast/typ.rs @@ -0,0 +1,22 @@ +use super::Path; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum Type<'a> { + Paren(Box<Type<'a>>), + Path(Path<'a>), + Literal(Literal<'a>), +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum Literal<'a> { + Unit, + Tuple(Vec<Type<'a>>), + Array(Box<Type<'a>>, Option<usize>), + Struct(Vec<StructField<'a>>), +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct StructField<'a> { + pub name: &'a str, + pub typ: Type<'a>, +} diff --git a/crates/rebel-parse/src/grammar/recipe.rs b/crates/rebel-parse/src/grammar/recipe.rs index c0c0ccf..d00c672 100644 --- a/crates/rebel-parse/src/grammar/recipe.rs +++ b/crates/rebel-parse/src/grammar/recipe.rs @@ -1,5 +1,11 @@ -use crate::ast::{self, expr, expr::Expr}; -use crate::token::*; +use crate::{ + ast::{ + self, + expr::{self, Expr}, + typ::{self, Type}, + }, + token::*, +}; pub use rules::*; @@ -47,7 +53,32 @@ peg::parser! { / p2('%', '=') { Some(Rem) } rule typed_expr() -> ast::TypedExpr<'a> - = expr:expr() typ:tagged(<p(':')>, <expr()>)? { ast::TypedExpr { expr, typ } } + = expr:expr() typ:tagged(<p(':')>, <typ()>)? { ast::TypedExpr { expr, typ } } + + rule typ() -> Type<'a> + = lit:typ_literal() { Type::Literal(lit) } + / path:path() { Type::Path(path) } + / p('(') t:typ() p(')') { Type::Paren(Box::new(t)) } + + rule typ_literal() -> typ::Literal<'a> + = p('(') p(')') { typ::Literal::Unit } + / p('(') elements:(typ() ** p(',')) p(',')? p(')') { + typ::Literal::Tuple(elements) + } + / p('[') typ:typ() len:tagged(<p(';')>, <number()>)? p(']') { ? + let len = len + .map(|n| usize::try_from(n).or(Err("Invalid array length"))) + .transpose()?; + Ok(typ::Literal::Array(Box::new(typ), len)) + } + / p('{') entries:delimited(<struct_field_typ()>, <p(',')>) p('}') { + typ::Literal::Struct(entries) + } + + rule struct_field_typ() -> typ::StructField<'a> + = field:field() p(':') typ:typ() { + typ::StructField { name: field.name, typ } + } pub rule expr() -> Expr<'a> = precedence! { left:(@) p2('|', '|') right:@ { Expr::binary(left, Or, right) } @@ -96,14 +127,12 @@ peg::parser! { = params:delimited(<func_param()>, <p(',')>) { params } rule func_param() -> ast::FuncParam<'a> - = name:ident() p(':') typ:expr() { ast::FuncParam { name, typ } } + = name:ident() p(':') typ:typ() { ast::FuncParam { name, typ } } rule literal() -> expr::Literal<'a> = [Token::Keyword(Keyword::True)] { expr::Literal::Bool(true) } / [Token::Keyword(Keyword::False)] { expr::Literal::Bool(false) } - / [Token::Number(content)] { ? - expr::Literal::number(content) - } + / n:number() { expr::Literal::Int(n) } / [Token::Str(Str { pieces, kind })] { ? let pieces = pieces .iter() @@ -136,6 +165,21 @@ peg::parser! { ast::Ident { name: content } } + rule number() -> u64 + = [Token::Number(s)] { ? + let (radix, rest) = if let Some(rest) = s.strip_prefix("0x") { + (16, rest) + } else if let Some(rest) = s.strip_prefix("0o") { + (8, rest) + } else if let Some(rest) = s.strip_prefix("0b") { + (2, rest) + } else { + (10, *s) + }; + let digits = rest.replace('_', ""); + u64::from_str_radix(&digits, radix).or(Err("number")) + } + rule p_(ch: char) = [Token::Punct(Punct(c, Spacing::Joint)) if *c == ch] {} |