verilization_compiler/
parser.rs

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
26// Keywords
27fn 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
83// Symbols
84fn 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
158// Integer literal (no signs)
159fn 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
173// Allows an optional sign before the integer literal
174fn 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
221// Ex: version 5;
222fn 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
230// Ex: package hello.world;
231fn 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
388// Ex:
389// const name: Type {
390//     version 1 = ...;
391//}
392fn 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
417// Ex: name: Type;
418fn 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
429// Ex:
430// version 5 {
431//   ...	
432// }
433fn 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
457// Ex:
458// struct Name {
459//   version 5 {...}
460//   ...
461// }
462// enum Name {
463//   version 5 {...}
464//   ...
465// }
466fn 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
574// Ex:
575// literal {
576//   ...
577// }
578fn 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
590// Ex:
591// extern Name {
592//   ...
593// }
594fn 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}