byteorm_lib/
parser.rs

1// src/parser.rs
2use pest::iterators::Pair;
3use crate::ast::*;
4use crate::{Rule, SchemaParser};
5use pest::Parser;
6
7pub fn parse_schema(src: &str) -> Result<Schema, String> {
8    SchemaParser::parse(Rule::schema, src)
9        .map_err(|e| format!("Parse error: {}", e))
10        .and_then(|mut pairs| {
11            let schema_pair = pairs.next().ok_or("Empty schema")?;
12            Ok(build_ast(schema_pair))
13        })
14}
15
16pub(crate) fn build_ast(pair: Pair<Rule>) -> Schema {
17    let mut models = Vec::new();
18    for inner in pair.into_inner() {
19        match inner.as_rule() {
20            Rule::model_decl => models.push(parse_model(inner)),
21            _ => (),
22        }
23    }
24    Schema { models }
25}
26
27fn parse_model(pair: Pair<Rule>) -> Model {
28    let mut pairs = pair.into_inner();
29    let name = pairs.next().unwrap().as_str().to_string();
30    let mut fields = Vec::new();
31    for pair in pairs {
32        if matches!(pair.as_rule(), Rule::field_decl) {
33            fields.push(parse_field(pair));
34        }
35    }
36    Model { name, fields }
37}
38
39fn parse_field(pair: Pair<Rule>) -> Field {
40    let mut pairs = pair.into_inner();
41    let name = pairs.next().unwrap().as_str().to_string();
42    let mut raw_type_name = pairs.next().unwrap().as_str().to_string();
43
44    let mut modifiers = Vec::new();
45    let mut attributes = Vec::new();
46
47    let mut is_nullable = false;
48    if raw_type_name.ends_with('?') {
49        is_nullable = true;
50        raw_type_name = raw_type_name.trim_end_matches('?').to_string();
51    }
52
53    for pair in pairs {
54        match pair.as_rule() {
55            Rule::modifier => {
56                if let Ok(m) = parse_modifier(pair) {
57                    modifiers.push(m);
58                }
59            }
60            Rule::attr => attributes.push(parse_attribute(pair)),
61            _ => (),
62        }
63    }
64
65    if is_nullable {
66        modifiers.push(Modifier::Nullable);
67    } else if !modifiers.iter().any(|m| matches!(m, Modifier::NotNull | Modifier::PrimaryKey)) {
68        modifiers.push(Modifier::NotNull);
69    }
70
71    Field {
72        name,
73        type_name: raw_type_name,
74        modifiers,
75        attributes,
76    }
77}
78
79fn parse_modifier(pair: Pair<Rule>) -> Result<Modifier, String> {
80    let mut inner = pair.into_inner();
81    let mod_name = inner.next().unwrap().as_str();
82    let args = inner.next().map(|p| {
83        p.into_inner()
84            .next()
85            .map(|ac| ac.as_str().trim().to_string())
86            .unwrap_or_default()
87    });
88
89    match mod_name {
90        "PrimaryKey" => Ok(Modifier::PrimaryKey),
91        "NotNull" => Ok(Modifier::NotNull),
92        "Nullable" => Ok(Modifier::Nullable),
93        "Unique" => Ok(Modifier::Unique),
94        "ForeignKey" => parse_foreign_key(args),
95        _ => Err(format!("Unknown modifier: {}", mod_name)),
96    }
97}
98
99fn parse_foreign_key(args: Option<String>) -> Result<Modifier, String> {
100    let arg_str = args.ok_or("ForeignKey requires arguments")?;
101    
102    if let Some(dot_pos) = arg_str.find('.') {
103        let model = arg_str[..dot_pos].trim().to_string();
104        let field = arg_str[dot_pos + 1..].trim().to_string();
105        return Ok(Modifier::ForeignKey {
106            model,
107            field: Some(field),
108        });
109    }
110
111    if let Some(paren_pos) = arg_str.find('(') {
112        let model = arg_str[..paren_pos].trim().to_string();
113        if let Some(close_pos) = arg_str.find(')') {
114            let field = arg_str[paren_pos + 1..close_pos].trim().to_string();
115            return Ok(Modifier::ForeignKey {
116                model,
117                field: Some(field),
118            });
119        }
120    }
121
122    Ok(Modifier::ForeignKey {
123        model: arg_str,
124        field: None,
125    })
126}
127
128fn parse_attribute(pair: Pair<Rule>) -> Attribute {
129    let mut inner = pair.into_inner();
130    let name = inner.next().unwrap().as_str().to_string();
131    let args = inner.next().map(|p| {
132        p.as_str().to_string()
133    });
134    Attribute { name, args }
135}
136