rust_store_core/pipeline/
parse.rs1use std::collections::HashMap;
4
5use super::ast::{Ast, RelAst};
6use super::token::{tokenize, Token};
7
8struct Parser {
9 tokens: Vec<Token>,
10 pos: usize,
11}
12
13type BodyParts = (Vec<String>, Vec<(String, RelAst)>);
15
16impl Parser {
17 fn peek(&self) -> Option<&Token> {
18 self.tokens.get(self.pos)
19 }
20
21 fn consume(&mut self, kind: &str, value: Option<&str>) -> Result<Token, String> {
22 let tk = match self.peek() {
23 None => {
24 return Err(format!(
25 "期望 {}({}) 但已到达末尾",
26 kind,
27 value.unwrap_or("undefined")
28 ))
29 }
30 Some(t) => t.clone(),
31 };
32 if tk.kind != kind || value.map(|v| tk.value != v).unwrap_or(false) {
33 return Err(format!(
34 "期望 {}({}) 实际 {}({}) 位置 {}",
35 kind,
36 value.unwrap_or("undefined"),
37 tk.kind,
38 tk.value,
39 self.pos
40 ));
41 }
42 self.pos += 1;
43 Ok(tk)
44 }
45
46 fn parse_params(&mut self) -> Result<HashMap<String, String>, String> {
47 let mut p = HashMap::new();
48 let has_paren = matches!(self.peek(), Some(t) if t.kind == "p" && t.value == "(");
49 if !has_paren {
50 return Ok(p);
51 }
52 self.consume("p", Some("("))?;
53 loop {
54 if matches!(self.peek(), Some(t) if t.value == ")") {
55 break;
56 }
57 let key = self
60 .consume("id", None)?
61 .value
62 .trim_start_matches('$')
63 .to_string();
64 self.consume("p", Some(":"))?;
65 let val = self.peek().cloned();
66 if let Some(v) = &val {
67 if v.kind == "ref" || v.kind == "id" {
68 p.insert(key, v.value.clone());
69 }
70 }
71 self.pos += 1;
72 if matches!(self.peek(), Some(t) if t.value == ",") {
73 self.consume("p", Some(","))?;
74 }
75 }
76 self.consume("p", Some(")"))?;
77 Ok(p)
78 }
79
80 fn parse_body(&mut self) -> Result<BodyParts, String> {
81 let mut fields = Vec::new();
82 let mut relations = Vec::new();
83 let has_brace = matches!(self.peek(), Some(t) if t.kind == "p" && t.value == "{");
84 if !has_brace {
85 return Ok((fields, relations));
86 }
87 self.consume("p", Some("{"))?;
88 loop {
89 match self.peek() {
90 None => break,
91 Some(t) if t.value == "}" => break,
92 Some(t) if t.value == "," => {
93 self.consume("p", Some(","))?;
94 continue;
95 }
96 _ => {}
97 }
98 let name = self.consume("id", None)?.value;
99 let has_paren = matches!(self.peek(), Some(t) if t.kind == "p" && t.value == "(");
100 let prm = if has_paren {
104 self.parse_params()?
105 } else {
106 HashMap::new()
107 };
108 if prm.contains_key("pipeline") {
111 return Err(format!(
112 "关系 \"{name}\" 的参数不支持 $pipeline($pipeline 直通仅限根级 GQL)"
113 ));
114 }
115 let has_brace = matches!(self.peek(), Some(t) if t.kind == "p" && t.value == "{");
116 if has_paren || has_brace {
117 let (f, r) = if has_brace {
118 self.parse_body()?
119 } else {
120 (Vec::new(), Vec::new())
121 };
122 relations.push((
123 name,
124 RelAst {
125 fields: f,
126 relations: r,
127 params: prm,
128 },
129 ));
130 } else {
131 fields.push(name);
132 }
133 if matches!(self.peek(), Some(t) if t.value == ",") {
134 self.consume("p", Some(","))?;
135 }
136 }
137 self.consume("p", Some("}"))?;
138 Ok((fields, relations))
139 }
140}
141
142pub fn parse(tokens: &[Token]) -> Result<Ast, String> {
143 let mut p = Parser {
144 tokens: tokens.to_vec(),
145 pos: 0,
146 };
147 let model = p.consume("id", None)?.value;
148 let params = p.parse_params()?;
149 let (fields, relations) = p.parse_body()?;
150 Ok(Ast {
151 model,
152 params,
153 fields,
154 relations,
155 })
156}
157
158pub fn parse_gql(gql: &str) -> Result<Ast, String> {
160 parse(&tokenize(gql))
161}