summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Schiffer <mschiffer@universe-factory.net>2024-04-28 23:55:22 +0200
committerMatthias Schiffer <mschiffer@universe-factory.net>2024-04-29 00:26:59 +0200
commitcee9711ba84e3c7ed8e45bd8364100955cf2b4e0 (patch)
treed4ed5d200f9d47026d700ec8fa7dddafce893354
parentfac5b015b92ea06eaff4be6c8a2a20d90e770ebb (diff)
downloadrebel-cee9711ba84e3c7ed8e45bd8364100955cf2b4e0.tar
rebel-cee9711ba84e3c7ed8e45bd8364100955cf2b4e0.zip
rebel-parse: create separate types to represent types
-rw-r--r--crates/rebel-parse/src/ast/expr.rs15
-rw-r--r--crates/rebel-parse/src/ast/mod.rs6
-rw-r--r--crates/rebel-parse/src/ast/typ.rs22
-rw-r--r--crates/rebel-parse/src/grammar/recipe.rs58
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] {}