1use crate::model;
2use num_bigint::{ BigUint, BigInt, Sign };
3use num_traits::Zero;
4use std::collections::{HashMap};
5
6use nom::{
7 IResult,
8 branch::{alt},
9 multi::{many0, separated_list1, separated_list0},
10 character::complete::{multispace0, multispace1, alphanumeric1, one_of, none_of, char},
11 combinator::{map, opt, eof, value, cut},
12 bytes::complete::tag,
13 sequence::{preceded, terminated},
14};
15
16type PResult<I, A> = IResult<I, A>;
17
18type ImportMap = HashMap<String, model::ScopeLookup>;
19type LazyConstantValue = dyn FnOnce() -> Result<model::ConstantValue, model::ModelError>;
20type TopLevelDefinitionAdder = dyn FnOnce(&mut model::Verilization) -> Result<(), model::ModelError>;
21type TypeVersionAdder = dyn FnOnce(&mut model::VersionedTypeDefinitionBuilder) -> Result<(), model::ModelError>;
22type ExternLiteralAdder = dyn FnOnce(&mut model::ExternTypeDefinitionBuilder) -> Result<(), model::ModelError>;
23type LazyModel = dyn FnOnce() -> Result<model::Verilization, model::ModelError>;
24
25
26fn kw_version(input: &str) -> PResult<&str, ()> {
28 let (input, _) = multispace0(input)?;
29 let (input, _) = tag("version")(input)?;
30 let (input, _) = multispace1(input)?;
31 Ok((input, ()))
32}
33
34fn kw_package(input: &str) -> PResult<&str, ()> {
35 let (input, _) = multispace0(input)?;
36 let (input, _) = tag("package")(input)?;
37 let (input, _) = multispace1(input)?;
38 Ok((input, ()))
39}
40
41fn kw_const(input: &str) -> PResult<&str, ()> {
42 let (input, _) = multispace0(input)?;
43 let (input, _) = tag("const")(input)?;
44 let (input, _) = multispace1(input)?;
45 Ok((input, ()))
46}
47
48fn kw_enum(input: &str) -> PResult<&str, ()> {
49 let (input, _) = multispace0(input)?;
50 let (input, _) = tag("enum")(input)?;
51 let (input, _) = multispace1(input)?;
52 Ok((input, ()))
53}
54
55fn kw_struct(input: &str) -> PResult<&str, ()> {
56 let (input, _) = multispace0(input)?;
57 let (input, _) = tag("struct")(input)?;
58 let (input, _) = multispace1(input)?;
59 Ok((input, ()))
60}
61
62fn kw_extern(input: &str) -> PResult<&str, ()> {
63 let (input, _) = multispace0(input)?;
64 let (input, _) = tag("extern")(input)?;
65 let (input, _) = multispace1(input)?;
66 Ok((input, ()))
67}
68
69fn kw_final(input: &str) -> PResult<&str, ()> {
70 let (input, _) = multispace0(input)?;
71 let (input, _) = tag("final")(input)?;
72 let (input, _) = multispace1(input)?;
73 Ok((input, ()))
74}
75
76fn kw_literal(input: &str) -> PResult<&str, ()> {
77 let (input, _) = multispace0(input)?;
78 let (input, _) = tag("literal")(input)?;
79 let (input, _) = multispace1(input)?;
80 Ok((input, ()))
81}
82
83fn sym_semicolon(input: &str) -> PResult<&str, ()> {
85 let (input, _) = multispace0(input)?;
86 let (input, _) = char(';')(input)?;
87 Ok((input, ()))
88}
89
90fn sym_colon(input: &str) -> PResult<&str, ()> {
91 let (input, _) = multispace0(input)?;
92 let (input, _) = char(':')(input)?;
93 Ok((input, ()))
94}
95
96fn sym_dot(input: &str) -> PResult<&str, ()> {
97 let (input, _) = multispace0(input)?;
98 let (input, _) = char('.')(input)?;
99 Ok((input, ()))
100}
101
102fn sym_comma(input: &str) -> PResult<&str, ()> {
103 let (input, _) = multispace0(input)?;
104 let (input, _) = char(',')(input)?;
105 Ok((input, ()))
106}
107
108fn sym_eq(input: &str) -> PResult<&str, ()> {
109 let (input, _) = multispace0(input)?;
110 let (input, _) = char('=')(input)?;
111 Ok((input, ()))
112}
113
114fn sym_open_curly(input: &str) -> PResult<&str, ()> {
115 let (input, _) = multispace0(input)?;
116 let (input, _) = char('{')(input)?;
117 Ok((input, ()))
118}
119
120fn sym_close_curly(input: &str) -> PResult<&str, ()> {
121 let (input, _) = multispace0(input)?;
122 let (input, _) = char('}')(input)?;
123 Ok((input, ()))
124}
125
126fn sym_open_paren(input: &str) -> PResult<&str, ()> {
127 let (input, _) = multispace0(input)?;
128 let (input, _) = char('(')(input)?;
129 Ok((input, ()))
130}
131
132fn sym_close_paren(input: &str) -> PResult<&str, ()> {
133 let (input, _) = multispace0(input)?;
134 let (input, _) = char(')')(input)?;
135 Ok((input, ()))
136}
137
138fn sym_open_bracket(input: &str) -> PResult<&str, ()> {
139 let (input, _) = multispace0(input)?;
140 let (input, _) = char('[')(input)?;
141 Ok((input, ()))
142}
143
144fn sym_close_bracket(input: &str) -> PResult<&str, ()> {
145 let (input, _) = multispace0(input)?;
146 let (input, _) = char(']')(input)?;
147 Ok((input, ()))
148}
149
150
151fn dec_digit(input: &str) -> PResult<&str, u8> {
152 let (input, ch) = one_of("0123456789")(input)?;
153 let digit = ch.to_digit(10).unwrap() as u8;
154 Ok((input, digit))
155}
156
157
158fn biguint(input: &str) -> PResult<&str, BigUint> {
160 let (input, _) = multispace0(input)?;
161 let (input, first_dig) = dec_digit(input)?;
162
163 if first_dig == 0 {
164 Ok((input, Zero::zero()))
165 }
166 else {
167 let (input, mut digits) = many0(dec_digit)(input)?;
168 digits.insert(0, first_dig);
169 Ok((input, BigUint::from_radix_be(&digits, 10).unwrap()))
170 }
171}
172
173fn bigint(input: &str) -> PResult<&str, BigInt> {
175 let (input, _) = multispace0(input)?;
176 let (input, sign) = opt(one_of("+-"))(input)?;
177 let (input, n) = biguint(input)?;
178
179 let sign =
180 if n == Zero::zero() {
181 Sign::NoSign
182 } else {
183 match sign {
184 Some('-') => Sign::Minus,
185 _ => Sign::Plus,
186 }
187 };
188
189 Ok((input, BigInt::from_biguint(sign, n)))
190}
191
192fn string_literal(input: &str) -> PResult<&str, String> {
193 let (input, _) = multispace0(input)?;
194 let (input, _) = char('\"')(input)?;
195
196 let (input, chars) = many0(
197 alt((
198 none_of("\"\\\r\n"),
199 preceded(char('\\'),
200 alt((
201 value('\\', char('\\')),
202 value('\"', char('\"')),
203 value('n', char('\n')),
204 value('\r', char('\r')),
205 ))
206 )
207 ))
208 )(input)?;
209
210 let (input, _) = char('\"')(input)?;
211
212 Ok((input, chars.into_iter().collect()))
213}
214
215fn identifier(input: &str) -> PResult<&str, String> {
216 let (input, _) = multispace0(input)?;
217 let (input, str) = alphanumeric1(input)?;
218 Ok((input, str.to_string()))
219}
220
221fn version_directive(input: &str) -> PResult<&str, BigUint> {
223 let (input, _) = kw_version(input)?;
224 let (input, ver) = biguint(input)?;
225 let (input, _) = sym_semicolon(input)?;
226
227 Ok((input, ver))
228}
229
230fn package_directive(input: &str) -> PResult<&str, model::PackageName> {
232 let (input, _) = kw_package(input)?;
233 let (input, pkg) = separated_list1(sym_dot, identifier)(input)?;
234 let (input, _) = sym_semicolon(input)?;
235
236 Ok((input, model::PackageName { package: pkg }))
237}
238
239fn type_expr_args(input: &str) -> PResult<&str, Vec<model::Type>> {
240 let (input, _) = sym_open_paren(input)?;
241 let (input, args) = separated_list1(sym_comma, type_expr)(input)?;
242 let (input, _) = sym_close_paren(input)?;
243 Ok((input, args))
244}
245
246fn type_expr(input: &str) -> PResult<&str, model::Type> {
247 let (input, qual_name, args) = {
248 let (input, mut name) = identifier(input)?;
249 let (input, parts) = many0(preceded(sym_dot, identifier))(input)?;
250
251 let mut package: Vec<String> = Vec::new();
252 for part in parts.into_iter() {
253 package.push(name);
254 name = part;
255 }
256
257 let qual_name = model::QualifiedName {
258 package: model::PackageName {
259 package: package,
260 },
261 name: name,
262 };
263
264 let (input, args) = opt(type_expr_args)(input)?;
265
266 (input, qual_name, args.unwrap_or(Vec::new()))
267 };
268
269 Ok((input, model::Type { name: qual_name, args: args }))
270}
271
272fn constant_integer_literal(input: &str) -> PResult<&str, Box<LazyConstantValue>> {
273 let (input, n) = bigint(input)?;
274 Ok((input, Box::new(move || Ok(model::ConstantValue::Integer(n)))))
275}
276
277fn constant_string_literal(input: &str) -> PResult<&str, Box<LazyConstantValue>> {
278 let (input, s) = string_literal(input)?;
279 Ok((input, Box::new(move || Ok(model::ConstantValue::String(s)))))
280}
281
282fn sequence_literal(input: &str) -> PResult<&str, Box<LazyConstantValue>> {
283 let (input, _) = sym_open_bracket(input)?;
284 let (input, values) = opt(
285 terminated(
286 separated_list1(sym_comma, constant_value),
287 opt(sym_comma)
288 )
289 )(input)?;
290 let (input, _) = sym_close_bracket(input)?;
291
292 Ok((input, Box::new(move || {
293 let values = values
294 .unwrap_or_else(|| Vec::new())
295 .into_iter()
296 .map(|lazy_const| lazy_const())
297 .collect::<Result<Vec<_>, _>>()?;
298 Ok(model::ConstantValue::Sequence(values))
299 })))
300}
301
302fn case_literal(input: &str) -> PResult<&str, Box<LazyConstantValue>> {
303 let (input, name) = identifier(input)?;
304 let (input, _) = sym_open_paren(input)?;
305 let (input, args) = opt(separated_list1(sym_comma, constant_value))(input)?;
306 let (input, _) = sym_close_paren(input)?;
307
308 Ok((input, Box::new(move || {
309 let args = args
310 .unwrap_or_else(|| Vec::new())
311 .into_iter()
312 .map(|lazy_const| lazy_const())
313 .collect::<Result<Vec<_>, _>>()?;
314
315 Ok(model::ConstantValue::Case(name, args))
316 })))
317}
318
319fn record_field_literal(input: &str) -> PResult<&str, (String, Box<LazyConstantValue>)> {
320 let (input, name) = identifier(input)?;
321 let (input, _) = sym_eq(input)?;
322 let (input, value) = constant_value(input)?;
323 let (input, _) = sym_semicolon(input)?;
324 Ok((input, (name, value)))
325}
326
327fn record_literal(input: &str) -> PResult<&str, Box<LazyConstantValue>> {
328 let (input, _) = sym_open_curly(input)?;
329
330 let (input, fields) = many0(record_field_literal)(input)?;
331
332 let (input, _) = sym_close_curly(input)?;
333
334 Ok((input, Box::new(move || {
335 let mut record = model::ConstantValueRecordBuilder::new();
336 for (name, value) in fields {
337 record.add_field(name, value()?)?;
338 }
339
340 Ok(model::ConstantValue::Record(record.build()))
341 })))
342}
343
344fn other_constant(input: &str) -> PResult<&str, Box<LazyConstantValue>> {
345 let (input, parts) = separated_list1(sym_dot, identifier)(input)?;
346
347 let mut iter = parts.into_iter();
348
349 let mut package = Vec::new();
350 let mut name = iter.next().unwrap();
351
352 while let Some(part) = iter.next() {
353 package.push(name);
354 name = part;
355 }
356
357 Ok((input, Box::new(move || Ok(model::ConstantValue::Constant(
358 model::QualifiedName {
359 package: model::PackageName {
360 package: package,
361 },
362 name: name
363 }
364 )))))
365}
366
367
368fn constant_value(input: &str) -> PResult<&str, Box<LazyConstantValue>> {
369 alt((
370 constant_integer_literal,
371 constant_string_literal,
372 sequence_literal,
373 case_literal,
374 record_literal,
375 other_constant,
376 ))(input)
377}
378
379fn versioned_constant(input: &str) -> PResult<&str, (BigUint, Box<LazyConstantValue>)> {
380 let (input, _) = kw_version(input)?;
381 let (input, ver) = biguint(input)?;
382 let (input, _) = sym_eq(input)?;
383 let (input, value) = constant_value(input)?;
384 let (input, _) = sym_semicolon(input)?;
385 Ok((input, (ver, value)))
386}
387
388fn constant_defn(current_package: model::PackageName, imports: ImportMap) -> impl Fn(&str) -> PResult<&str, Box<TopLevelDefinitionAdder>> {
393 move |input| {
394 let (input, _) = kw_const(input)?;
395 let (input, name) = identifier(input)?;
396 let (input, _) = sym_colon(input)?;
397 let (input, t) = type_expr(input)?;
398 let (input, _) = multispace0(input)?;
399 let (input, _) = sym_open_curly(input)?;
400 let (input, versions) = many0(versioned_constant)(input)?;
401 let (input, _) = sym_close_curly(input)?;
402
403 let name = model::QualifiedName { package: current_package.clone(), name: name, };
404 let imports = imports.clone();
405
406 Ok((input, Box::new(|model| {
407 let mut constant = model::ConstantBuilder::new(name, t, imports);
408 for (ver, value) in versions {
409 constant.add_version(ver, value()?)?;
410 }
411
412 model.add_constant(constant)
413 })))
414 }
415}
416
417fn field_definition(input: &str) -> PResult<&str, (String, model::FieldInfo)> {
419 let (input, name) = identifier(input)?;
420 let (input, _) = cut(sym_colon)(input)?;
421 let (input, t) = cut(type_expr)(input)?;
422 let (input, _) = cut(sym_semicolon)(input)?;
423
424 Ok((input, (name, model::FieldInfo {
425 field_type: t,
426 })))
427}
428
429fn type_version_definition(input: &str) -> PResult<&str, Box<TypeVersionAdder>> {
434 let (input, _) = kw_version(input)?;
435 let (input, ver) = cut(biguint)(input)?;
436 let (input, _) = cut(sym_open_curly)(input)?;
437 let (input, fields_orig) = many0(field_definition)(input)?;
438 let (input, _) = cut(sym_close_curly)(input)?;
439
440 Ok((input, Box::new(|type_def| {
441 let mut ver_type = type_def.add_version(ver)?;
442 for (name, field) in fields_orig {
443 ver_type.add_field(name, field)?;
444 }
445 Ok(())
446 })))
447}
448
449fn type_param_list(input: &str) -> PResult<&str, Vec<String>> {
450 let (input, _) = sym_open_paren(input)?;
451 let (input, result) = separated_list1(sym_comma, identifier)(input)?;
452 let (input, _) = sym_close_paren(input)?;
453
454 Ok((input, result))
455}
456
457fn versioned_type_definition(current_package: model::PackageName, imports: ImportMap) -> impl Fn(&str) -> PResult<&str, Box<TopLevelDefinitionAdder>> {
467 move |input| {
468 let (input, is_final) = opt(kw_final)(input)?;
469 let is_final = is_final.is_some();
470
471 let (input, is_enum) = alt((
472 map(kw_enum, |_| true),
473 map(kw_struct, |_| false),
474 ))(input)?;
475
476 let (input, name) = cut(identifier)(input)?;
477 let (input, type_params) = opt(type_param_list)(input)?;
478 let type_params = type_params.unwrap_or(Vec::new());
479
480 let (input, _) = cut(sym_open_curly)(input)?;
481 let (input, versions) = many0(type_version_definition)(input)?;
482 let (input, _) = cut(sym_close_curly)(input)?;
483
484 let name = model::QualifiedName { package: current_package.clone(), name: name, };
485 let imports = imports.clone();
486
487
488 Ok((input, Box::new(move |model| {
489 let mut type_def = model::VersionedTypeDefinitionBuilder::new(name, type_params, is_final, imports);
490 for adder in versions {
491 adder(&mut type_def)?;
492 }
493
494 if is_enum {
495 model.add_enum_type(type_def)
496 }
497 else {
498 model.add_struct_type(type_def)
499 }
500 })))
501 }
502}
503
504fn extern_literal_integer(input: &str) -> PResult<&str, Box<ExternLiteralAdder>> {
505 let (input, _) = multispace0(input)?;
506 let (input, _) = tag("integer")(input)?;
507 let (input, _) = multispace0(input)?;
508 let (input, open) = one_of("[(")(input)?;
509 let (input, _) = multispace0(input)?;
510 let (input, lower) = opt(bigint)(input)?;
511 let (input, _) = sym_comma(input)?;
512 let (input, upper) = opt(bigint)(input)?;
513 let (input, _) = multispace0(input)?;
514 let (input, close) = one_of("])")(input)?;
515
516 let bound = |ch: char| if ch == '(' { model::ExternLiteralIntBound::Exclusive } else { model::ExternLiteralIntBound::Inclusive };
517
518 Ok((input, Box::new(move |type_def| type_def.add_integer_literal(bound(open), lower, bound(close), upper))))
519}
520
521fn extern_literal_string(input: &str) -> PResult<&str, Box<ExternLiteralAdder>> {
522 let (input, _) = multispace0(input)?;
523 let (input, _) = tag("string")(input)?;
524
525 Ok((input, Box::new(model::ExternTypeDefinitionBuilder::add_string_literal)))
526}
527
528fn extern_literal_sequence(input: &str) -> PResult<&str, Box<ExternLiteralAdder>> {
529 let (input, _) = multispace0(input)?;
530 let (input, _) = tag("sequence")(input)?;
531 let (input, _) = multispace1(input)?;
532 let (input, element_type) = type_expr(input)?;
533
534 Ok((input, Box::new(|type_def| type_def.add_sequence_literal(element_type))))
535}
536
537
538fn extern_literal_case(input: &str) -> PResult<&str, Box<ExternLiteralAdder>> {
539 let (input, _) = multispace0(input)?;
540 let (input, _) = tag("case")(input)?;
541 let (input, name) = identifier(input)?;
542 let (input, _) = sym_open_paren(input)?;
543 let (input, params) = separated_list0(sym_comma, type_expr)(input)?;
544 let (input, _) = sym_close_paren(input)?;
545
546 Ok((input, Box::new(|type_def| type_def.add_case_literal(name, params))))
547}
548
549
550fn extern_literal_record(input: &str) -> PResult<&str, Box<ExternLiteralAdder>> {
551 let (input, _) = multispace0(input)?;
552 let (input, _) = tag("record")(input)?;
553 let (input, _) = sym_open_curly(input)?;
554 let (input, fields) = many0(field_definition)(input)?;
555 let (input, _) = sym_close_curly(input)?;
556
557 Ok((input, Box::new(|type_def| {
558 let mut record = type_def.add_record_literal()?;
559 for (name, field) in fields {
560 record.add_field(name, field)?;
561 }
562 Ok(())
563 })))
564}
565
566fn extern_literal(input: &str) -> PResult<&str, Box<ExternLiteralAdder>> {
567 let (input, literal) = alt((extern_literal_integer, extern_literal_string, extern_literal_sequence, extern_literal_case, extern_literal_record))(input)?;
568 let (input, _) = sym_semicolon(input)?;
569
570 Ok((input, literal))
571}
572
573
574fn extern_literal_block(input: &str) -> PResult<&str, Vec<Box<ExternLiteralAdder>>> {
579 let (input, _) = kw_literal(input)?;
580 let (input, _) = sym_open_curly(input)?;
581
582 let (input, literals) = many0(extern_literal)(input)?;
583
584 let (input, _) = sym_close_curly(input)?;
585
586 Ok((input, literals))
587}
588
589
590fn extern_type_definition(current_package: model::PackageName, imports: ImportMap) -> impl Fn(&str) -> PResult<&str, Box<TopLevelDefinitionAdder>> {
595 move |input| {
596 let (input, _) = kw_extern(input)?;
597 let (input, name) = identifier(input)?;
598 let (input, type_params) = opt(type_param_list)(input)?;
599 let type_params = type_params.unwrap_or(Vec::new());
600
601 let (input, _) = sym_open_curly(input)?;
602
603 let (input, literals) = opt(extern_literal_block)(input)?;
604 let literals = literals.unwrap_or_else(|| Vec::new());
605
606 let (input, _) = sym_close_curly(input)?;
607
608 let name = model::QualifiedName { package: current_package.clone(), name: name, };
609 let imports = imports.clone();
610
611
612 Ok((input, Box::new(|model| {
613 let mut type_def = model::ExternTypeDefinitionBuilder::new(name, type_params, imports);
614 for literal_adder in literals {
615 literal_adder(&mut type_def)?;
616 }
617 model.add_extern_type(type_def)
618 })))
619 }
620}
621
622
623fn top_level_definition(current_package: model::PackageName, imports: ImportMap) -> impl Fn(&str) -> PResult<&str, Box<TopLevelDefinitionAdder>> {
624 move |input| alt((
625 constant_defn(current_package.clone(), imports.clone()),
626 versioned_type_definition(current_package.clone(), imports.clone()),
627 extern_type_definition(current_package.clone(), imports.clone())
628 ))(input)
629}
630
631
632pub fn parse_model(input: &str) -> PResult<&str, Box<LazyModel>> {
633 let (input, latest_ver) = version_directive(input)?;
634 let (input, package) = opt(package_directive)(input)?;
635 let package =
636 if let Some(pkg) = package { pkg }
637 else { model::PackageName { package: Vec::new() } };
638
639
640
641 let (input, defs) = many0(top_level_definition(package, HashMap::new()))(input)?;
642 let (input, _) = multispace0(input)?;
643 let (input, _) = eof(input)?;
644
645
646
647 Ok((input, Box::new(move || {
648 let mut model = model::Verilization::new(model::VerilizationMetadata {
649 latest_version: latest_ver,
650 });
651
652 for def_adder in defs.into_iter() {
653 def_adder(&mut model)?;
654 }
655
656 Ok(model)
657 })))
658}