1use crate::error::{Error, Result};
36use crate::schema::{Dt, Schema, SchemaBuilder};
37use crate::value::Value;
38
39fn err(msg: impl Into<String>) -> Error {
40 Error::BadSchema(format!("idl: {}", msg.into()))
41}
42
43#[derive(Debug, PartialEq)]
48enum Tok {
49 Ident(String), Int(u64),
51 LBrace,
52 RBrace,
53 Lt,
54 Gt,
55 Colon,
56 Eq,
57 Minus,
58}
59
60fn tokenize(src: &str) -> Result<Vec<Tok>> {
61 let b = src.as_bytes();
62 let mut i = 0;
63 let mut out = Vec::new();
64 while i < b.len() {
65 let c = b[i];
66 match c {
67 b' ' | b'\t' | b'\r' | b'\n' | b',' => i += 1, b'/' if i + 1 < b.len() && b[i + 1] == b'/' => {
69 while i < b.len() && b[i] != b'\n' {
70 i += 1;
71 }
72 }
73 b'{' => {
74 out.push(Tok::LBrace);
75 i += 1;
76 }
77 b'}' => {
78 out.push(Tok::RBrace);
79 i += 1;
80 }
81 b'<' => {
82 out.push(Tok::Lt);
83 i += 1;
84 }
85 b'>' => {
86 out.push(Tok::Gt);
87 i += 1;
88 }
89 b':' => {
90 out.push(Tok::Colon);
91 i += 1;
92 }
93 b'=' => {
94 out.push(Tok::Eq);
95 i += 1;
96 }
97 b'-' => {
98 out.push(Tok::Minus);
99 i += 1;
100 }
101 c if c.is_ascii_digit() => {
102 let start = i;
103 while i < b.len() && b[i].is_ascii_digit() {
104 i += 1;
105 }
106 let n: u64 = src[start..i]
107 .parse()
108 .map_err(|_| err(format!("number too large: {}", &src[start..i])))?;
109 out.push(Tok::Int(n));
110 }
111 c if c.is_ascii_alphabetic() || c == b'_' => {
112 let start = i;
113 while i < b.len() && (b[i].is_ascii_alphanumeric() || b[i] == b'_') {
114 i += 1;
115 }
116 out.push(Tok::Ident(src[start..i].to_string()));
117 }
118 other => return Err(err(format!("unexpected character {:?}", other as char))),
119 }
120 }
121 Ok(out)
122}
123
124enum Mode {
129 Sparse,
130 Dense,
131 Packed,
132}
133
134struct StructAst {
135 name: String,
136 mode: Mode,
137 fields: Vec<(u16, String, Dt)>,
138 defaults: Vec<(u16, Value)>,
139}
140struct EnumAst {
141 name: String,
142 variants: Vec<(u32, String)>,
143}
144
145struct Parser<'t> {
146 toks: &'t [Tok],
147 pos: usize,
148}
149
150impl<'t> Parser<'t> {
151 fn peek(&self) -> Option<&'t Tok> {
152 self.toks.get(self.pos)
153 }
154 fn next(&mut self) -> Result<&'t Tok> {
155 let t = self
156 .toks
157 .get(self.pos)
158 .ok_or_else(|| err("unexpected end of input"))?;
159 self.pos += 1;
160 Ok(t)
161 }
162 fn ident(&mut self) -> Result<String> {
163 match self.next()? {
164 Tok::Ident(s) => Ok(s.clone()),
165 other => Err(err(format!("expected a name, found {other:?}"))),
166 }
167 }
168 fn expect(&mut self, want: &Tok) -> Result<()> {
169 let got = self.next()?;
170 if got == want {
171 Ok(())
172 } else {
173 Err(err(format!("expected {want:?}, found {got:?}")))
174 }
175 }
176
177 fn type_expr(&mut self) -> Result<Dt> {
179 let name = self.ident()?;
180 if name == "list" {
181 self.expect(&Tok::Lt)?;
182 let elem = self.type_expr()?;
183 self.expect(&Tok::Gt)?;
184 return Ok(Dt::list(elem));
185 }
186 if name == "map" {
187 self.expect(&Tok::Lt)?;
189 let key = self.type_expr()?;
190 let value = self.type_expr()?;
191 self.expect(&Tok::Gt)?;
192 return Ok(Dt::map(key, value));
193 }
194 if name == "union" {
195 self.expect(&Tok::Lt)?;
197 let mut variants = Vec::new();
198 while self.peek() != Some(&Tok::Gt) {
199 variants.push(self.type_expr()?);
200 }
201 self.expect(&Tok::Gt)?;
202 return Ok(Dt::union(variants));
203 }
204 Ok(match name.as_str() {
205 "bool" => Dt::Bool,
206 "u8" => Dt::U8,
207 "u16" => Dt::U16,
208 "u32" => Dt::U32,
209 "u64" => Dt::U64,
210 "i8" => Dt::I8,
211 "i16" => Dt::I16,
212 "i32" => Dt::I32,
213 "i64" => Dt::I64,
214 "f32" => Dt::F32,
215 "f64" => Dt::F64,
216 "string" | "str" => Dt::Str,
217 "bytes" => Dt::Bytes,
218 _ => Dt::named(&name),
220 })
221 }
222
223 fn struct_def(&mut self, mode: Mode) -> Result<StructAst> {
224 let name = self.ident()?;
225 self.expect(&Tok::LBrace)?;
226 let mut fields = Vec::new();
227 let mut defaults = Vec::new();
228 while self.peek() != Some(&Tok::RBrace) {
229 let id = match self.next()? {
230 Tok::Int(n) if *n <= u16::MAX as u64 => *n as u16,
231 Tok::Int(n) => return Err(err(format!("field id {n} exceeds u16 in {name}"))),
232 other => {
233 return Err(err(format!(
234 "expected a field id in {name}, found {other:?}"
235 )))
236 }
237 };
238 self.expect(&Tok::Colon)?;
239 let fname = self.ident()?;
240 let ty = self.type_expr()?;
241 if self.peek() == Some(&Tok::Eq) {
243 self.next()?;
244 defaults.push((id, self.default_literal(&ty)?));
245 }
246 fields.push((id, fname, ty));
247 }
248 self.expect(&Tok::RBrace)?;
249 Ok(StructAst {
250 name,
251 mode,
252 fields,
253 defaults,
254 })
255 }
256
257 fn default_literal(&mut self, ty: &Dt) -> Result<Value> {
260 if let Some(Tok::Ident(s)) = self.peek() {
261 if s == "true" || s == "false" {
262 let b = s == "true";
263 self.next()?;
264 return Ok(Value::Bool(b));
265 }
266 }
267 let neg = if self.peek() == Some(&Tok::Minus) {
268 self.next()?;
269 true
270 } else {
271 false
272 };
273 let n = match self.next()? {
274 Tok::Int(n) => *n,
275 other => return Err(err(format!("expected a default literal, found {other:?}"))),
276 };
277 let s = |n: u64| -> i64 {
278 if neg {
279 -(n as i64)
280 } else {
281 n as i64
282 }
283 };
284 Ok(match ty {
285 Dt::U8 => Value::U8(n as u8),
286 Dt::U16 => Value::U16(n as u16),
287 Dt::U32 => Value::U32(n as u32),
288 Dt::U64 => Value::U64(n),
289 Dt::I8 => Value::I8(s(n) as i8),
290 Dt::I16 => Value::I16(s(n) as i16),
291 Dt::I32 => Value::I32(s(n) as i32),
292 Dt::I64 => Value::I64(s(n)),
293 Dt::F32 => Value::F32(if neg { -(n as f32) } else { n as f32 }),
294 Dt::F64 => Value::F64(if neg { -(n as f64) } else { n as f64 }),
295 Dt::Named(_) => Value::Enum(n as u32),
297 _ => return Err(err("a default is only allowed on a scalar field")),
298 })
299 }
300
301 fn enum_def(&mut self) -> Result<EnumAst> {
302 let name = self.ident()?;
303 self.expect(&Tok::LBrace)?;
304 let mut variants = Vec::new();
305 while self.peek() != Some(&Tok::RBrace) {
306 let value = match self.next()? {
307 Tok::Int(n) if *n <= u32::MAX as u64 => *n as u32,
308 Tok::Int(n) => return Err(err(format!("enum value {n} exceeds u32 in {name}"))),
309 other => {
310 return Err(err(format!(
311 "expected an enum value in {name}, found {other:?}"
312 )))
313 }
314 };
315 self.expect(&Tok::Colon)?;
316 let vname = self.ident()?;
317 variants.push((value, vname));
318 }
319 self.expect(&Tok::RBrace)?;
320 Ok(EnumAst { name, variants })
321 }
322}
323
324pub fn parse(src: &str) -> Result<Schema> {
327 let toks = tokenize(src)?;
328 let mut p = Parser {
329 toks: &toks,
330 pos: 0,
331 };
332
333 let mut structs: Vec<StructAst> = Vec::new();
334 let mut enums: Vec<EnumAst> = Vec::new();
335 let mut root: Option<String> = None;
336
337 while let Some(t) = p.peek() {
338 let kw = match t {
339 Tok::Ident(s) => s.clone(),
340 other => {
341 return Err(err(format!(
342 "expected a top-level declaration, found {other:?}"
343 )))
344 }
345 };
346 p.pos += 1; match kw.as_str() {
348 "struct" => structs.push(p.struct_def(Mode::Sparse)?),
349 "dense" => {
350 if p.ident()? != "struct" {
351 return Err(err("`dense` must be followed by `struct`"));
352 }
353 structs.push(p.struct_def(Mode::Dense)?);
354 }
355 "packed" => {
356 if p.ident()? != "struct" {
357 return Err(err("`packed` must be followed by `struct`"));
358 }
359 structs.push(p.struct_def(Mode::Packed)?);
360 }
361 "enum" => enums.push(p.enum_def()?),
362 "root" => {
363 if root.is_some() {
364 return Err(err("more than one `root` declaration"));
365 }
366 root = Some(p.ident()?);
367 }
368 other => return Err(err(format!("unknown top-level keyword `{other}`"))),
369 }
370 }
371
372 let root = root.ok_or_else(|| err("missing `root <TypeName>` declaration"))?;
373
374 let mut b = SchemaBuilder::new();
376 for s in &structs {
377 let fields: Vec<(u16, &str, Dt)> = s
378 .fields
379 .iter()
380 .map(|(id, n, ty)| (*id, n.as_str(), ty.clone()))
381 .collect();
382 b = match s.mode {
383 Mode::Sparse => b.add_struct(&s.name, fields),
384 Mode::Dense => b.add_dense_struct(&s.name, fields),
385 Mode::Packed => b.add_packed_struct(&s.name, fields),
386 };
387 }
388 for e in &enums {
389 let variants: Vec<(u32, &str)> = e.variants.iter().map(|(v, n)| (*v, n.as_str())).collect();
390 b = b.add_enum(&e.name, variants);
391 }
392 for s in &structs {
393 for (fid, value) in &s.defaults {
394 b = b.set_default(&s.name, *fid, value.clone());
395 }
396 }
397 b.build(&root)
398}
399
400#[cfg(test)]
401mod tests {
402 use super::*;
403
404 #[test]
405 fn idl_matches_hand_built_schema_id() {
406 let src = r#"
407 // an order record
408 dense struct Point { 1: x f64 2: y f64 }
409 enum Level { 0: Debug 1: Info 2: Error }
410 struct Order {
411 1: id u64
412 2: item string
413 3: qty u32
414 4: tags list<string>
415 5: origin Point
416 6: level Level
417 7: grid list<list<u16>>
418 }
419 root Order
420 "#;
421 let from_idl = parse(src).unwrap();
422
423 let hand = SchemaBuilder::new()
424 .add_dense_struct("Point", vec![(1, "x", Dt::F64), (2, "y", Dt::F64)])
425 .add_enum("Level", vec![(0, "Debug"), (1, "Info"), (2, "Error")])
426 .add_struct(
427 "Order",
428 vec![
429 (1, "id", Dt::U64),
430 (2, "item", Dt::Str),
431 (3, "qty", Dt::U32),
432 (4, "tags", Dt::list(Dt::Str)),
433 (5, "origin", Dt::named("Point")),
434 (6, "level", Dt::named("Level")),
435 (7, "grid", Dt::list(Dt::list(Dt::U16))),
436 ],
437 )
438 .build("Order")
439 .unwrap();
440
441 assert_eq!(from_idl.id(), hand.id());
443 assert_eq!(from_idl.canonical_bytes(), hand.canonical_bytes());
444 }
445
446 #[test]
447 fn declaration_order_is_irrelevant() {
448 let a = parse("struct A { 1: x u8 } root A").unwrap();
449 let b = parse(" root A\nstruct A {1:x u8}").unwrap();
450 assert_eq!(a.id(), b.id());
451 }
452
453 #[test]
454 fn errors_are_typed_not_panics() {
455 assert!(parse("struct {").is_err()); assert!(parse("struct A { 1 x u8 } root A").is_err()); assert!(parse("struct A { 1: x u8 }").is_err()); assert!(parse("root Missing").is_err()); assert!(parse("struct A { 99999999: x u8 } root A").is_err()); }
461}