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
58 .consume("id", None)?
59 .value
60 .trim_start_matches('$')
61 .to_string();
62 if key == "pipeline" {
65 return Err(
66 "$pipeline 直通已移除:请改用标准 GQL($condition/$sort/$skip/$limit + 关系字段)"
67 .to_string(),
68 );
69 }
70 self.consume("p", Some(":"))?;
71 let val = self.peek().cloned();
72 if let Some(v) = &val {
73 if v.kind == "ref" || v.kind == "id" {
74 p.insert(key, v.value.clone());
75 }
76 }
77 self.pos += 1;
78 if matches!(self.peek(), Some(t) if t.value == ",") {
79 self.consume("p", Some(","))?;
80 }
81 }
82 self.consume("p", Some(")"))?;
83 Ok(p)
84 }
85
86 fn parse_body(&mut self) -> Result<BodyParts, String> {
87 let mut fields = Vec::new();
88 let mut relations = Vec::new();
89 let has_brace = matches!(self.peek(), Some(t) if t.kind == "p" && t.value == "{");
90 if !has_brace {
91 return Ok((fields, relations));
92 }
93 self.consume("p", Some("{"))?;
94 loop {
95 match self.peek() {
96 None => break,
97 Some(t) if t.value == "}" => break,
98 Some(t) if t.value == "," => {
99 self.consume("p", Some(","))?;
100 continue;
101 }
102 _ => {}
103 }
104 let name = self.consume("id", None)?.value;
105 let has_paren = matches!(self.peek(), Some(t) if t.kind == "p" && t.value == "(");
106 let prm = if has_paren {
110 self.parse_params()?
111 } else {
112 HashMap::new()
113 };
114 let has_brace = matches!(self.peek(), Some(t) if t.kind == "p" && t.value == "{");
115 if has_paren || has_brace {
116 let (f, r) = if has_brace {
117 self.parse_body()?
118 } else {
119 (Vec::new(), Vec::new())
120 };
121 relations.push((
122 name,
123 RelAst {
124 fields: f,
125 relations: r,
126 params: prm,
127 },
128 ));
129 } else {
130 fields.push(name);
131 }
132 if matches!(self.peek(), Some(t) if t.value == ",") {
133 self.consume("p", Some(","))?;
134 }
135 }
136 self.consume("p", Some("}"))?;
137 Ok((fields, relations))
138 }
139}
140
141pub fn parse(tokens: &[Token]) -> Result<Ast, String> {
142 let mut p = Parser {
143 tokens: tokens.to_vec(),
144 pos: 0,
145 };
146 let model = p.consume("id", None)?.value;
147 let params = p.parse_params()?;
148 let (fields, relations) = p.parse_body()?;
149 Ok(Ast {
150 model,
151 params,
152 fields,
153 relations,
154 })
155}
156
157pub fn parse_gql(gql: &str) -> Result<Ast, String> {
159 parse(&tokenize(gql))
160}