lumen_compiler/compiler/
constraints.rs1use crate::compiler::ast::*;
4
5use thiserror::Error;
6
7#[derive(Debug, Error)]
8pub enum ConstraintError {
9 #[error("invalid constraint on field '{field}' at line {line}: {message}")]
10 Invalid {
11 field: String,
12 line: usize,
13 message: String,
14 },
15}
16
17pub fn validate_constraints(program: &Program) -> Result<(), Vec<ConstraintError>> {
20 let mut errors = Vec::new();
21
22 for item in &program.items {
23 if let Item::Record(r) = item {
24 for field in &r.fields {
25 if let Some(ref constraint) = field.constraint {
26 validate_constraint_expr(constraint, &field.name, &mut errors);
27 }
28 }
29 }
30 }
31
32 if errors.is_empty() {
33 Ok(())
34 } else {
35 Err(errors)
36 }
37}
38
39fn validate_constraint_expr(expr: &Expr, field: &str, errors: &mut Vec<ConstraintError>) {
40 match expr {
41 Expr::BinOp(lhs, op, rhs, _) => match op {
42 BinOp::And
43 | BinOp::Or
44 | BinOp::Eq
45 | BinOp::NotEq
46 | BinOp::Lt
47 | BinOp::LtEq
48 | BinOp::Gt
49 | BinOp::GtEq
50 | BinOp::Add
51 | BinOp::Sub
52 | BinOp::Mul
53 | BinOp::Div
54 | BinOp::FloorDiv
55 | BinOp::Mod
56 | BinOp::Pow
57 | BinOp::Concat
58 | BinOp::In
59 | BinOp::BitAnd
60 | BinOp::BitOr
61 | BinOp::BitXor
62 | BinOp::Shl
63 | BinOp::Shr => {
64 validate_constraint_expr(lhs, field, errors);
65 validate_constraint_expr(rhs, field, errors);
66 }
67 _ => {
68 errors.push(ConstraintError::Invalid {
69 field: field.to_string(),
70 line: expr.span().line,
71 message: format!("unsupported operator '{}' in constraint", op),
72 });
73 }
74 },
75 Expr::UnaryOp(UnaryOp::Not, inner, _) => {
76 validate_constraint_expr(inner, field, errors);
77 }
78 Expr::Call(callee, _args, span) => {
79 if let Expr::Ident(name, _) = callee.as_ref() {
81 match name.as_str() {
82 "length" | "count" | "matches" | "is_valid_email" => {}
83 _ => {
84 errors.push(ConstraintError::Invalid {
85 field: field.to_string(),
86 line: span.line,
87 message: format!("unknown constraint function '{}'", name),
88 });
89 }
90 }
91 }
92 }
93 Expr::Ident(_, _)
94 | Expr::IntLit(_, _)
95 | Expr::FloatLit(_, _)
96 | Expr::StringLit(_, _)
97 | Expr::BoolLit(_, _)
98 | Expr::ListLit(_, _) => {}
99 _ => {
100 errors.push(ConstraintError::Invalid {
101 field: field.to_string(),
102 line: expr.span().line,
103 message: "unsupported expression in constraint".to_string(),
104 });
105 }
106 }
107}