Skip to content

Commit

Permalink
#95 - check for correct patterns where allowed, forbid them where not…
Browse files Browse the repository at this point in the history
… allowed

remove the pattern type, I prefer to keep the same interface for everything (for now)
  • Loading branch information
danilopedraza committed Jan 29, 2025
1 parent 221bc59 commit 976cfc7
Show file tree
Hide file tree
Showing 3 changed files with 185 additions and 28 deletions.
5 changes: 0 additions & 5 deletions core/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,11 +220,6 @@ pub enum Declaration {
},
}

#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum Pattern {

}

#[cfg(test)]
pub mod tests {
use cst::{DeclarationKind, PrefixOperator};
Expand Down
22 changes: 22 additions & 0 deletions core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,12 @@ fn parser_error_msg(err: &ParserError) -> String {

fn weeder_error_msg(err: &WeederError) -> String {
match err {
WeederError::AdInfinitumAsExpression => unindent(
"
The `..` operator cannot be used as an expression alone.
It can be used as an operator and inside patterns
",
),
WeederError::BadDeclaration => unindent(
"
Expressions inside a declaration must be symbols with properties or assignments.
Expand All @@ -273,6 +279,11 @@ fn weeder_error_msg(err: &WeederError) -> String {
The dot is allowed for decimal numbers and calls only.
At the right of the dot there should be a function call or a decimal number",
),
WeederError::BadForLoop => unindent(
"
For loops must be of the form `for <value> in <iterable>.
Replace this with an expression with that form",
),
WeederError::BadImportOrigin => {
"The module from where you want to import can only be represented with a name".into()
}
Expand All @@ -281,6 +292,14 @@ fn weeder_error_msg(err: &WeederError) -> String {
The thing you want to import must be represented with a name or a tuple of names.
Replace this with a name or a tuple of names",
),
WeederError::BadInfixPattern => unindent(
"
You are using using an operator not allowed inside patterns.
You can only use the range operator `..` and the or operator `||`",
),
WeederError::BadPattern => {
"The code here must be a pattern, and this is not a pattern".into()
}
WeederError::BadSymbolicDeclaration => {
"Only names can be declared without a value. Replace this with a name".into()
}
Expand All @@ -305,6 +324,9 @@ fn weeder_error_msg(err: &WeederError) -> String {
WeederError::MemoizedNonFunctionDeclaration => {
"You can only memoize functions. Remove the `memoize` from the declaration".into()
}
WeederError::WildcardAsExpression => {
"The wildcard `_` generates patterns, which are only allowed in certain places".into()
}
}
}

Expand Down
186 changes: 163 additions & 23 deletions core/src/weeder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,14 @@ use crate::{

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum WeederError {
AdInfinitumAsExpression,
BadDeclaration,
BadDot,
BadForLoop,
BadImportOrigin,
BadImportSymbol,
BadInfixPattern,
BadPattern,
BadSymbolicDeclaration,
BadSymbolInImportTuple,
BadAnonFunctionLHS,
Expand All @@ -22,6 +26,7 @@ pub enum WeederError {
MemoizedNonFunctionDeclaration,
MutableFunctionDeclaration,
PlainImportNotImplemented,
WildcardAsExpression,
}

type WeederResult<T> = Result<T, (WeederError, Position)>;
Expand All @@ -41,9 +46,9 @@ pub fn rewrite(node: CSTNode) -> WeederResult<ASTNode> {
CSTNodeKind::String(str) => string(str),
CSTNodeKind::Symbol(name) => symbol(name),
CSTNodeKind::Tuple(values) => tuple(values),
CSTNodeKind::Wildcard => wildcard(),
CSTNodeKind::Wildcard => Err((WeederError::WildcardAsExpression, node.position)),
CSTNodeKind::Dictionary { pairs, complete } => dictionary(pairs, complete),
CSTNodeKind::AdInfinitum => ad_infinitum(),
CSTNodeKind::AdInfinitum => Err((WeederError::AdInfinitumAsExpression, node.position)),
CSTNodeKind::SetCons { some, most } => set_cons(*some, *most),
CSTNodeKind::Import { name: _, alias: _ } => {
Err((WeederError::PlainImportNotImplemented, node.position))
Expand All @@ -63,6 +68,126 @@ pub fn rewrite(node: CSTNode) -> WeederResult<ASTNode> {
Ok(ASTNode::new(tp, node.position))
}

fn rewrite_pattern(node: CSTNode) -> WeederResult<ASTNode> {
let tp = match node.kind {
CSTNodeKind::Wildcard => wildcard(),
CSTNodeKind::Boolean(bool) => boolean(bool),
CSTNodeKind::Char(chr) => char(chr),
CSTNodeKind::Integer(dec, radix) => integer(dec, radix, node.position),
CSTNodeKind::String(str) => string(str),
CSTNodeKind::Symbol(name) => symbol(name),
CSTNodeKind::Tuple(values) => tuple_pattern(values),
CSTNodeKind::ExtensionList(list) => list_pattern(list),
CSTNodeKind::ExtensionSet(values) => set_pattern(values),
CSTNodeKind::Cons(first, tail) => cons_pattern(*first, *tail),
CSTNodeKind::Dictionary { pairs, complete } => dictionary_pattern(pairs, complete),
CSTNodeKind::Infix(InfixOperator::Constraint, exp, constraint) => {
tagged_expression_pattern(*exp, *constraint)
}
CSTNodeKind::Infix(InfixOperator::Fraction, numer, denom) => {
fraction_pattern(*numer, *denom)
}
CSTNodeKind::Infix(op, lhs, rhs) => infix_pattern(op, *lhs, *rhs),
CSTNodeKind::SetCons { some, most } => set_cons_pattern(*some, *most),
_ => Err((WeederError::BadPattern, node.position)),
}?;

Ok(ASTNode::new(tp, node.position))
}

fn rewrite_patterns(patterns: Vec<CSTNode>) -> WeederResult<Vec<ASTNode>> {
patterns.into_iter().map(rewrite_pattern).collect()
}

fn tuple_pattern(values: Vec<CSTNode>) -> WeederResult<ASTNodeKind> {
let list = rewrite_patterns(values)?;
Ok(ASTNodeKind::Tuple { list })
}

fn list_pattern(values: Vec<CSTNode>) -> WeederResult<ASTNodeKind> {
let list: WeederResult<Vec<ASTNode>> = values
.into_iter()
.map(|node| match node {
CSTNode {
kind: CSTNodeKind::AdInfinitum,
position,
} => Ok(ASTNode::new(ASTNodeKind::AdInfinitum, position)),
node => rewrite(node),
})
.collect();

Ok(ASTNodeKind::List { list: list? })
}

fn set_pattern(values: Vec<CSTNode>) -> WeederResult<ASTNodeKind> {
let list: WeederResult<Vec<ASTNode>> = values
.into_iter()
.map(|node| match node {
CSTNode {
kind: CSTNodeKind::AdInfinitum,
position,
} => Ok(ASTNode::new(ASTNodeKind::AdInfinitum, position)),
node => rewrite(node),
})
.collect();

Ok(ASTNodeKind::Set { list: list? })
}

fn cons_pattern(first: CSTNode, tail: CSTNode) -> WeederResult<ASTNodeKind> {
let first = Box::new(rewrite_pattern(first)?);
let tail = Box::new(rewrite_pattern(tail)?);
Ok(ASTNodeKind::Cons { first, tail })
}

fn dictionary_pattern(pairs: Vec<(CSTNode, CSTNode)>, complete: bool) -> WeederResult<ASTNodeKind> {
let pairs: WeederResult<Vec<(ASTNode, ASTNode)>> =
pairs.into_iter().map(rewrite_pattern_pair).collect();
Ok(ASTNodeKind::Dictionary {
pairs: pairs?,
complete,
})
}

fn tagged_expression_pattern(exp: CSTNode, constraint: CSTNode) -> WeederResult<ASTNodeKind> {
let exp = Box::new(rewrite_pattern(exp)?);
let constraint = Some(Box::new(rewrite_pattern(constraint)?));

Ok(ASTNodeKind::TaggedExpression { exp, constraint })
}

fn fraction_pattern(numer: CSTNode, denom: CSTNode) -> WeederResult<ASTNodeKind> {
let numer = Box::new(rewrite_pattern(numer)?);
let denom = Box::new(rewrite_pattern(denom)?);

Ok(ASTNodeKind::Fraction { numer, denom })
}

fn infix_pattern(op: InfixOperator, lhs: CSTNode, rhs: CSTNode) -> WeederResult<ASTNodeKind> {
let lhs = Box::new(rewrite_pattern(lhs)?);
let rhs = Box::new(rewrite_pattern(rhs)?);

let op = match op {
InfixOperator::Or => ast::InfixOperator::Or,
InfixOperator::Range => ast::InfixOperator::Range,
_ => {
return Err((
WeederError::BadInfixPattern,
lhs.position.join(rhs.position),
))
}
};

Ok(ASTNodeKind::Infix { op, lhs, rhs })
}

fn set_cons_pattern(some: CSTNode, most: CSTNode) -> WeederResult<ASTNodeKind> {
let some = Box::new(rewrite_pattern(some)?);
let most = Box::new(rewrite_pattern(most)?);

Ok(ASTNodeKind::SetCons { some, most })
}

fn rewrite_vec(vec: Vec<CSTNode>) -> WeederResult<Vec<ASTNode>> {
vec.into_iter().map(rewrite).collect()
}
Expand All @@ -74,6 +199,13 @@ fn rewrite_pair((left, right): (CSTNode, CSTNode)) -> WeederResult<(ASTNode, AST
Ok((left, right))
}

fn rewrite_pattern_pair((left, right): (CSTNode, CSTNode)) -> WeederResult<(ASTNode, ASTNode)> {
let left = rewrite_pattern(left)?;
let right = rewrite_pattern(right)?;

Ok((left, right))
}

fn boolean(val: bool) -> WeederResult<ASTNodeKind> {
Ok(ASTNodeKind::Boolean(val))
}
Expand Down Expand Up @@ -114,15 +246,15 @@ fn extension_set(list: Vec<CSTNode>) -> WeederResult<ASTNodeKind> {
}

fn _for(expr: CSTNode, proc: CSTNode) -> WeederResult<ASTNodeKind> {
let (val, iter) = match expr.kind {
match expr.kind {
CSTNodeKind::Infix(InfixOperator::In, val, iter) => {
(Box::new(rewrite(*val)?), Box::new(rewrite(*iter)?))
let val = Box::new(rewrite_pattern(*val)?);
let iter = Box::new(rewrite(*iter)?);
let proc = Box::new(rewrite(proc)?);
Ok(ASTNodeKind::For { val, iter, proc })
}
_ => todo!(),
};

let proc = Box::new(rewrite(proc)?);
Ok(ASTNodeKind::For { val, iter, proc })
_ => Err((WeederError::BadForLoop, expr.position)),
}
}

fn function(params: Vec<String>, result: CSTNode) -> WeederResult<ASTNodeKind> {
Expand Down Expand Up @@ -215,12 +347,12 @@ fn infix(cst_op: InfixOperator, lhs: CSTNode, rhs: CSTNode) -> WeederResult<ASTN
InfixOperator::Sum => infix_node(ast::InfixOperator::Sum, lhs, rhs),
InfixOperator::Element => container_element(lhs, rhs),
InfixOperator::Assignment => assignment(lhs, rhs),
InfixOperator::Constraint => pattern(lhs, rhs),
InfixOperator::Constraint => tagged_expression(lhs, rhs),
}
}

fn assignment(left: CSTNode, right: CSTNode) -> WeederResult<ASTNodeKind> {
let left = Box::new(rewrite(left)?);
let left = Box::new(rewrite_pattern(left)?);
let right = Box::new(rewrite(right)?);

Ok(ASTNodeKind::Assignment { left, right })
Expand Down Expand Up @@ -263,9 +395,9 @@ fn declaration(node: CSTNode, kind: DeclarationKind) -> WeederResult<ASTNodeKind
CSTNode {
kind: CSTNodeKind::Infix(InfixOperator::Assignment, left, right),
..
} => match (destructure_call(&left), kind) {
} => match (destructure_signature(&left), kind) {
(Some((name, params)), DeclarationKind::Inmutable) => {
let params = rewrite_vec(params)?;
let params = rewrite_patterns(params)?;
let result = Box::new(rewrite(*right)?);
Ok(ASTNodeKind::Declaration(Declaration::Function {
name,
Expand All @@ -274,7 +406,7 @@ fn declaration(node: CSTNode, kind: DeclarationKind) -> WeederResult<ASTNodeKind
}))
}
(Some((name, params)), DeclarationKind::InmutableMemoized) => {
let params = rewrite_vec(params)?;
let params = rewrite_patterns(params)?;
let result = Box::new(rewrite(*right)?);
Ok(ASTNodeKind::Declaration(Declaration::MemoizedFunction {
name,
Expand All @@ -286,7 +418,7 @@ fn declaration(node: CSTNode, kind: DeclarationKind) -> WeederResult<ASTNodeKind
Err((WeederError::MutableFunctionDeclaration, left.position))
}
(None, kind) => {
let left = Box::new(rewrite(*left)?);
let left = Box::new(rewrite_pattern(*left)?);
let right = Box::new(rewrite(*right)?);
match kind {
DeclarationKind::Inmutable => {
Expand Down Expand Up @@ -325,15 +457,17 @@ fn declaration(node: CSTNode, kind: DeclarationKind) -> WeederResult<ASTNodeKind

fn case(expr: CSTNode, pairs: Vec<(CSTNode, CSTNode)>) -> WeederResult<ASTNodeKind> {
let expr = Box::new(rewrite(expr)?);
let pairs: WeederResult<Vec<(ASTNode, ASTNode)>> =
pairs.into_iter().map(rewrite_pair).collect();
let pairs: WeederResult<Vec<(ASTNode, ASTNode)>> = pairs
.into_iter()
.map(|(lhs, rhs)| Ok((rewrite_pattern(lhs)?, rewrite(rhs)?)))
.collect();
Ok(ASTNodeKind::Case {
expr,
pairs: pairs?,
})
}

fn destructure_call(node: &CSTNode) -> Option<(String, Vec<CSTNode>)> {
fn destructure_signature(node: &CSTNode) -> Option<(String, Vec<CSTNode>)> {
match node {
CSTNode {
kind: CSTNodeKind::Infix(InfixOperator::Call, left, right),
Expand All @@ -359,7 +493,7 @@ fn cons(first: CSTNode, tail: CSTNode) -> WeederResult<ASTNodeKind> {
Ok(ASTNodeKind::Cons { first, tail })
}

fn pattern(exp: CSTNode, constraint: CSTNode) -> WeederResult<ASTNodeKind> {
fn tagged_expression(exp: CSTNode, constraint: CSTNode) -> WeederResult<ASTNodeKind> {
let exp = Box::new(rewrite(exp)?);
let constraint = Some(Box::new(rewrite(constraint)?));
Ok(ASTNodeKind::TaggedExpression { exp, constraint })
Expand Down Expand Up @@ -403,10 +537,6 @@ fn dictionary(pairs: Vec<(CSTNode, CSTNode)>, complete: bool) -> WeederResult<AS
})
}

fn ad_infinitum() -> WeederResult<ASTNodeKind> {
Ok(ASTNodeKind::AdInfinitum)
}

fn set_cons(some: CSTNode, most: CSTNode) -> WeederResult<ASTNodeKind> {
let some = Box::new(rewrite(some)?);
let most = Box::new(rewrite(most)?);
Expand Down Expand Up @@ -643,4 +773,14 @@ mod tests {
))
);
}

#[test]
fn wildcard_as_exp() {
let node = cst::tests::wildcard(dummy_pos());

assert_eq!(
rewrite(node),
Err((WeederError::WildcardAsExpression, dummy_pos())),
);
}
}

0 comments on commit 976cfc7

Please sign in to comment.