1use anyhow::{anyhow, Result};
26use std::borrow::BorrowMut;
27use std::cell::{RefCell, RefMut};
28use std::path::PathBuf;
29use std::str::FromStr;
30use std::sync::Arc;
31
32use pest::iterators::{Pair, Pairs};
33use pest::Parser;
34
35use crate::commands::*;
36use crate::instance::*;
37use crate::semantics::*;
38
39#[derive(Parser)]
40#[grammar = "scroll.pest"]
41struct ScrollParser;
42
43pub fn parse_file(instance: &mut SandboxInstance, filename: PathBuf) -> Result<()> {
44 if let Ok(unparsed_file) = std::fs::read_to_string(filename.to_str().unwrap()) {
45 let filepath = match filename.parent() {
46 Some(parent) => parent.to_path_buf(),
47 None => PathBuf::from("./"),
48 };
49 parse_buffer(
50 instance,
51 &unparsed_file,
52 Some(filepath.to_str().unwrap()),
53 Some(filename.to_str().unwrap()),
54 )
55 } else {
56 Err(anyhow!(
57 "Failed reading scroll file {}",
58 filename.to_str().unwrap()
59 ))
60 }
61}
62
63pub fn parse_buffer(
64 instance: &mut SandboxInstance,
65 buffer: &str,
66 filepath: Option<&str>,
67 filename: Option<&str>,
68) -> Result<()> {
69 match ScrollParser::parse(Rule::file, buffer) {
70 Ok(pairs) => parse_scroll(instance, pairs, filepath.unwrap_or("")),
71 Err(e) => Err(anyhow!(
72 "Parsing {} failed! {:#}",
73 filename.unwrap_or("buffer"),
74 e.to_string()
75 )),
76 }
77}
78
79struct ProbabilityHelper {
87 multiplier: i32,
88}
89
90impl<'a> ProbabilityHelper {
91 pub fn new() -> Self {
92 ProbabilityHelper { multiplier: 1 }
93 }
94 pub fn parse_multiplier(&mut self, inner_pair: &Pair<'_, Rule>) {
95 if let Ok(p) = inner_pair.clone().into_inner().as_str().parse::<i32>() {
96 self.multiplier = p;
97 }
98 }
99 pub fn multiply<F: FnMut() + 'a>(&mut self, mut callback: F) {
100 for _ in 0..self.multiplier {
101 callback();
102 }
103 self.multiplier = 1;
104 }
105}
106
107fn upcast_string(input: &str) -> serde_json::Value {
108 if let Ok(parsed_i32) = input.parse::<i32>() {
109 serde_json::json!(parsed_i32)
110 } else if let Ok(parsed_f32) = input.parse::<f32>() {
111 serde_json::json!(parsed_f32)
112 } else if input == "true" || input == "false" {
113 serde_json::json!(input.parse::<bool>().unwrap())
114 } else {
115 serde_json::json!(input)
116 }
117}
118
119fn parse_attribute_spec(pair: Pair<Rule>) -> (&str, bool, bool) {
126 let mut is_public: bool = false;
127 let mut is_optional: bool = false;
128 let mut attr_decl_rule = pair.into_inner();
129
130 let attr_name = attr_decl_rule.next().unwrap().as_str();
131 for inner_pair in attr_decl_rule {
132 if let Rule::is_public = inner_pair.as_rule() {
133 is_public = true;
134 }
135 if let Rule::is_optional = inner_pair.as_rule() {
136 is_optional = true;
137 }
138 }
139
140 (attr_name, is_public, is_optional)
141}
142
143fn parse_injection_roll_from_list(inner_pair: Pair<Rule>) -> Arc<InjectCommandRollFromList> {
144 let mut iter = inner_pair.into_inner();
145 let (attr, _, _) = parse_attribute_spec(iter.next().unwrap());
146
147 let mut value: Vec<serde_json::Value> = vec![];
148
149 for inner_pair in iter {
150 match inner_pair.as_rule() {
151 Rule::free_text => value.push(serde_json::to_value(inner_pair.as_str()).expect("x")),
152 Rule::list_value => {
153 value.push(serde_json::to_value(inner_pair.as_str().trim()).expect("x"))
154 }
155 Rule::probability_spec => {}
156 _ => unreachable!(),
157 }
158 }
159
160 Arc::new(InjectCommandRollFromList {
161 name: attr.to_string(),
162 list: value,
163 })
164}
165
166fn parse_injection_dice_roll(inner_pair: Pair<Rule>) -> Arc<InjectCommandDiceRoll> {
167 let mut iter = inner_pair.into_inner();
168 let (attr, _, _) = parse_attribute_spec(iter.next().unwrap());
169
170 Arc::new(InjectCommandDiceRoll {
171 name: attr.to_string(),
172 number_of_dice: iter.next().unwrap().as_str().parse().unwrap(),
173 dice_type: iter.next().unwrap().as_str().parse().unwrap(),
174 dice_modifier: if let Some(val) = iter.next() {
175 val.as_str().parse().unwrap()
176 } else {
177 0
178 },
179 })
180}
181
182fn parse_injection_assign_by_ref<T: InjectCommand + RefInjectCommand + 'static>(
183 inner_pair: Pair<Rule>,
184) -> Arc<dyn InjectCommand + Send + Sync> {
185 let mut iter = inner_pair.into_inner();
186 let (attr, _, _) = parse_attribute_spec(iter.next().unwrap());
187 let mut path: Vec<String> = Vec::new();
188 let next = iter.next().unwrap();
189 match next.as_rule() {
190 Rule::attr_spec => path.push(next.as_str().to_string()),
191 Rule::attr_attr_spec => {
192 let mut attr_attr = next.into_inner();
193 path.push(attr_attr.next().unwrap().as_str().to_string());
194 path.push(attr_attr.next().unwrap().as_str().to_string());
195 }
196 _ => unreachable!(),
197 }
198 T::make(attr.to_string(), path)
199}
200
201fn parse_injections(pair: Pair<Rule>) -> anyhow::Result<Injectors> {
202 let mut prependers = Vec::<Arc<dyn InjectCommand + Send + Sync>>::new();
203 let mut appenders = Vec::<Arc<dyn InjectCommand + Send + Sync>>::new();
204 for inner_pair in pair.into_inner() {
205 match inner_pair.as_rule() {
206 Rule::prepend_copy_value => {
207 prependers.push(parse_injection_assign_by_ref::<InjectCommandCopyValue>(
208 inner_pair,
209 ));
210 }
211 Rule::append_copy_value => {
212 appenders.push(parse_injection_assign_by_ref::<InjectCommandCopyValue>(
213 inner_pair,
214 ));
215 }
216 Rule::prepend_ptr => {
217 prependers.push(parse_injection_assign_by_ref::<InjectCommandPtr>(
218 inner_pair,
219 ));
220 }
221 Rule::append_ptr => {
222 appenders.push(parse_injection_assign_by_ref::<InjectCommandPtr>(
223 inner_pair,
224 ));
225 }
226 Rule::prepend_assignment => {
227 prependers.push(parse_injection_assignment(inner_pair));
228 }
229 Rule::assignment => {
230 appenders.push(parse_injection_assignment(inner_pair));
231 }
232 Rule::roll_from_list => {
233 appenders.push(parse_injection_roll_from_list(inner_pair));
234 }
235 Rule::roll_a_dice => {
236 appenders.push(parse_injection_dice_roll(inner_pair));
237 }
238 _ => unreachable!(),
239 }
240 }
241 Ok(Injectors {
242 prependers,
243 appenders,
244 })
245}
246
247fn parse_dice_notation(name: String, mut pair: Pairs<Rule>) -> Arc<dyn AttrCommand + Send + Sync> {
248 Arc::new(AttrCommandDice {
249 name,
250 number_of_dice: pair.next().unwrap().as_str().parse().unwrap(),
251 dice_type: pair.next().unwrap().as_str().parse().unwrap(),
252 dice_modifier: if let Some(val) = pair.next() {
253 val.as_str().parse().unwrap()
254 } else {
255 0
256 },
257 })
258}
259
260fn parse_attribute_ex(
261 f: fn(String, Pairs<Rule>) -> std::sync::Arc<dyn AttrCommand + Send + Sync>,
262 pair: Pair<Rule>,
263 mut class: RefMut<ClassBuilder>,
264) {
265 let mut inner = pair.into_inner();
266 let (attr, is_public, is_optional) = parse_attribute_spec(inner.next().unwrap());
267 class.add_attr(
268 attr.to_string(),
269 Attr {
270 cmd: f(attr.to_string(), inner),
271 is_public,
272 is_optional,
273 is_array: false,
274 },
275 );
276}
277
278fn parse_subclasses(pair: Pair<Rule>, mut class: RefMut<ClassBuilder>) {
279 let inner_pair = pair.into_inner().next().unwrap();
280 match inner_pair.as_rule() {
281 Rule::global => {
282 class.subclass_var(inner_pair.as_str());
283 }
284 Rule::entities_list => {
285 let mut prob = ProbabilityHelper::new();
286 for ip in inner_pair.into_inner() {
287 if let Rule::probability_spec = ip.as_rule() {
288 prob.parse_multiplier(&ip);
289 }
290 if let Rule::entity_name = ip.as_rule() {
291 prob.multiply(|| class.subclass_item(ip.as_str().trim()));
292 }
293 }
294 }
295 _ => unreachable!(),
296 }
297}
298
299fn parse_number_or_variable(pair: Pair<Rule>) -> CardinalityValue {
300 let inner = pair.into_inner().next().unwrap();
301 if inner.as_rule() == Rule::number {
302 CardinalityValue::Number(inner.as_str().parse().unwrap())
303 } else {
304 let mut v = inner.as_str().to_string();
305 v.remove(0);
306 CardinalityValue::Variable(v)
307 }
308}
309
310fn parse_entity_attribute<CMD: AttrCommand + Send + Sync + EntityAssigner + 'static>(
311 pair: Pair<Rule>,
312 mut class: RefMut<ClassBuilder>,
313) {
314 let mut attr: Option<&str> = None;
315 let mut value: ClassNamesToRoll = ClassNamesToRoll::Unset();
316 let mut min: CardinalityValue = CardinalityValue::Undefined;
317 let mut max: CardinalityValue = CardinalityValue::Undefined;
318 let mut is_public: bool = false;
319 let mut is_optional: bool = false;
320 let mut injectors: Injectors = Injectors {
321 prependers: Vec::new(),
322 appenders: Vec::new(),
323 };
324
325 for inner_pair in pair.into_inner() {
326 match inner_pair.as_rule() {
327 Rule::property => {
328 (attr, is_public, is_optional) = {
329 let (a, b, c) = parse_attribute_spec(inner_pair);
330 (Some(a), b, c)
331 }
332 }
333 Rule::indirect => {
334 value = ClassNamesToRoll::Indirect(
335 inner_pair.into_inner().next().unwrap().as_str().to_string(),
336 );
337 }
338 Rule::array => {
339 let mut iter = inner_pair.into_inner();
340 min = parse_number_or_variable(iter.next().unwrap());
341 max = parse_number_or_variable(iter.next().unwrap());
342 (attr, is_public, is_optional) = {
343 let (a, b, c) = parse_attribute_spec(iter.next().unwrap());
344 (Some(a), b, c)
345 }
346 }
347 Rule::entity_name => {
348 value = ClassNamesToRoll::List(vec![]);
349 if let ClassNamesToRoll::List(l) = &mut value {
350 l.push(inner_pair.as_str().to_string())
351 }
352 }
353 Rule::entities_list => {
354 value = ClassNamesToRoll::List(vec![]);
355 if let ClassNamesToRoll::List(l) = &mut value {
356 for ip in inner_pair.into_inner() {
357 if let Rule::entity_name = ip.as_rule() {
358 l.push(ip.as_str().trim().to_string())
359 }
360 }
361 }
362 }
363 Rule::injections => {
364 injectors = parse_injections(inner_pair).unwrap();
365 }
366 _ => unreachable!(),
367 }
368 }
369 if let Some(attr) = attr {
370 if let ClassNamesToRoll::Unset() = value {
371 unreachable!()
372 }
373 let is_array = !matches!(min, CardinalityValue::Undefined)
374 && !matches!(max, CardinalityValue::Undefined);
375 class.add_attr(
376 attr.to_string(),
377 Attr {
378 cmd: std::sync::Arc::new(CMD::new(attr.to_string(), value, min, max, injectors)),
379 is_public,
380 is_optional,
381 is_array,
382 },
383 );
384 } else {
385 unreachable!();
386 }
387}
388
389fn parse_collection(pair: Pair<Rule>, mut class: RefMut<ClassBuilder>) {
390 let mut class_name: Option<String> = None;
391 let mut named_collection: Option<String> = None;
392 let mut is_optional = false;
393 let is_array = true;
394 let mut is_public = false;
395 for inner_pair in pair.into_inner() {
396 match inner_pair.as_rule() {
397 Rule::entity_name => class_name = Some(inner_pair.as_str().to_string()),
398 Rule::property => {
399 for property_pair in inner_pair.into_inner() {
400 match property_pair.as_rule() {
401 Rule::property_name => {
402 named_collection = Some(property_pair.as_str().to_string())
403 }
404 Rule::is_public => is_public = true,
405 Rule::is_optional => is_optional = true,
406 _ => {}
407 }
408 }
409 }
410 _ => {}
411 }
412 }
413
414 if let Some(class_name) = class_name {
415 let virtual_attribute = named_collection.map(|named_collection| CollectionAttribute {
416 attr_name: named_collection,
417 is_optional,
418 is_array,
419 is_public,
420 });
421 class.collect(CollectionSpecifier {
422 class_name,
423 virtual_attribute,
424 });
425 }
426}
427
428fn parse_roll_from_list(name: String, pair: Pairs<Rule>) -> Arc<dyn AttrCommand + Send + Sync> {
429 let mut value: Vec<serde_json::Value> = vec![];
430
431 let mut prob = ProbabilityHelper::new();
432 for inner_pair in pair {
433 match inner_pair.as_rule() {
434 Rule::probability_spec => {
435 prob.parse_multiplier(&inner_pair);
436 }
437 Rule::list_value => {
438 prob.multiply(|| value.push(upcast_string(inner_pair.as_str().trim())));
439 }
440 _ => unreachable!(),
441 }
442 }
443 Arc::new(AttrCommandRollFromList { name, list: value })
444}
445
446fn parse_roll_via_variable(
447 name: String,
448 mut pair: Pairs<Rule>,
449) -> Arc<dyn AttrCommand + Send + Sync> {
450 let mut var = pair.next().unwrap().as_str().to_string();
451 var.remove(0);
452 Arc::new(AttrCommandRollFromVariable { name, var })
453}
454
455fn parse_context(name: String, mut pair: Pairs<Rule>) -> Arc<dyn AttrCommand + Send + Sync> {
456 let next = pair.next().unwrap();
457 match next.as_rule() {
458 Rule::context | Rule::context_ptr => {
459 let mut context_rule = next.into_inner();
460 Arc::new(AttrCommandContext {
461 name,
462 context_parent: context_rule.next().unwrap().as_str().to_string(),
463 context_attr: context_rule.next().unwrap().as_str().to_string(),
464 })
465 }
466 _ => unreachable!(),
467 }
468}
469
470fn parse_value_token(token: Pair<Rule>) -> serde_json::Value {
471 match token.as_rule() {
472 Rule::null => serde_json::json!(false),
473 Rule::template_body => serde_json::json!(token.as_str()),
474 Rule::slim_template_body => serde_json::json!(token.as_str()),
475 Rule::string => serde_json::json!(token.as_str()),
476 Rule::free_text => upcast_string(token.as_str().trim()),
477 _ => upcast_string(token.as_str().trim()),
478 }
479}
480
481fn parse_simple_value(name: String, mut pair: Pairs<Rule>) -> Arc<dyn AttrCommand + Send + Sync> {
482 let next = pair.next().unwrap();
483 match next.as_rule() {
484 Rule::value => {
485 let token = next.into_inner().next().unwrap();
486 let value = parse_value_token(token);
487 Arc::new(AttrCommandAssigner { name, value })
488 }
489 _ => unreachable!(),
490 }
491}
492
493fn parse_injection_assignment(inner_pair: Pair<Rule>) -> Arc<InjectCommandSetValue> {
494 let mut iter = inner_pair.into_inner();
495 let (attr, _, _) = parse_attribute_spec(iter.next().unwrap());
496
497 let token = iter.next().unwrap().into_inner().next().unwrap();
498 let value = parse_value_token(token);
499
500 Arc::new(InjectCommandSetValue {
501 name: attr.to_string(),
502 value,
503 })
504}
505
506fn parse_weak_value(name: String, mut pair: Pairs<Rule>) -> Arc<dyn AttrCommand + Send + Sync> {
507 let value: serde_json::Value;
508 let next = pair.next().unwrap();
509 match next.as_rule() {
510 Rule::value => {
511 let as_str = next.as_str();
512 let token = next.into_inner().next().unwrap();
513 value = match token.as_rule() {
514 Rule::template_body => serde_json::json!(token.as_str()),
515 Rule::slim_template_body => {
516 serde_json::json!(token.as_str())
517 }
518 Rule::string => serde_json::json!(token.as_str()),
519 _ => upcast_string(as_str.trim()),
520 };
521 Arc::new(AttrCommandWeakAssigner { name, value })
522 }
523 _ => unreachable!(),
524 }
525}
526
527fn parse_prerendered_value(
528 name: String,
529 mut pair: Pairs<Rule>,
530) -> Arc<dyn AttrCommand + Send + Sync> {
531 let value: serde_json::Value;
532 let next = pair.next().unwrap();
533 match next.as_rule() {
534 Rule::value => {
535 let as_str = next.as_str();
536 let token = next.into_inner().next().unwrap();
537 value = match token.as_rule() {
538 Rule::template_body => serde_json::json!(token.as_str()),
539 Rule::slim_template_body => {
540 serde_json::json!(token.as_str())
541 }
542 Rule::string => serde_json::json!(token.as_str()),
543 _ => upcast_string(as_str.trim()),
544 };
545 Arc::new(AttrCommandPrerenderedAssigner { name, value })
546 }
547 _ => unreachable!(),
548 }
549}
550
551fn parse_entity_tags(pair: Pairs<Rule>, mut class_builder: RefMut<ClassBuilder>) {
552 for inner_pair in pair {
553 match inner_pair.as_rule() {
554 Rule::tag_body_body => {
555 class_builder
556 .borrow_mut()
557 .html_body(inner_pair.as_str().to_string());
558 }
559 Rule::tag_header_body => {
560 class_builder
561 .borrow_mut()
562 .html_header(inner_pair.as_str().to_string());
563 }
564 Rule::tag_html_body => {}
565 _ => {}
567 }
568 }
569}
570
571fn parse_entity(instance: &mut SandboxInstance, pair: Pair<Rule>) -> Result<Class> {
572 let class_builder = RefCell::new(ClassBuilder::new());
573 pair.into_inner()
574 .for_each(|inner_pair| match inner_pair.as_rule() {
575 Rule::entity_declaration => {
576 let mut inner = inner_pair.into_inner();
577 class_builder
578 .borrow_mut()
579 .name(inner.next().unwrap().as_str());
580 if let Some(parent) = inner.next() {
581 class_builder
582 .borrow_mut()
583 .extends(instance, parent.as_str());
584 }
585 }
586 Rule::subclasses => parse_subclasses(inner_pair, class_builder.borrow_mut()),
587 Rule::pop_an_entity => {
588 parse_entity_attribute::<AttrCommandUseEntity>(
589 inner_pair,
590 class_builder.borrow_mut(),
591 );
592 }
593 Rule::pick_an_entity => {
594 parse_entity_attribute::<AttrCommandPickEntity>(
595 inner_pair,
596 class_builder.borrow_mut(),
597 );
598 }
599 Rule::roll_an_entity => {
600 parse_entity_attribute::<AttrCommandRollEntity>(
601 inner_pair,
602 class_builder.borrow_mut(),
603 );
604 }
605 Rule::roll_one_of => {
606 parse_entity_attribute::<AttrCommandRollEntity>(
607 inner_pair,
608 class_builder.borrow_mut(),
609 );
610 }
611 Rule::roll_from_indirect => {
612 parse_entity_attribute::<AttrCommandRollEntity>(
613 inner_pair,
614 class_builder.borrow_mut(),
615 );
616 }
617 Rule::roll_a_dice => {
618 parse_attribute_ex(parse_dice_notation, inner_pair, class_builder.borrow_mut());
619 }
620 Rule::roll_from_list => {
621 parse_attribute_ex(parse_roll_from_list, inner_pair, class_builder.borrow_mut());
622 }
623 Rule::roll_from_global => {
624 parse_attribute_ex(
625 parse_roll_via_variable,
626 inner_pair,
627 class_builder.borrow_mut(),
628 );
629 }
630 Rule::context_assignment => {
631 parse_attribute_ex(parse_context, inner_pair, class_builder.borrow_mut());
632 }
633 Rule::assignment => {
634 parse_attribute_ex(parse_simple_value, inner_pair, class_builder.borrow_mut());
635 }
636 Rule::weak_assignment => {
637 parse_attribute_ex(parse_weak_value, inner_pair, class_builder.borrow_mut());
638 }
639 Rule::inheritance => {
640 class_builder.borrow_mut().expand(
641 instance,
642 inner_pair.into_inner().next().unwrap().as_str().trim(),
643 );
644 }
645 Rule::collect => {
646 parse_collection(inner_pair, class_builder.borrow_mut());
647 }
648 Rule::tags => {
649 parse_entity_tags(inner_pair.into_inner(), class_builder.borrow_mut());
650 }
651 Rule::prerendered_assignment => {
652 parse_attribute_ex(
653 parse_prerendered_value,
654 inner_pair,
655 class_builder.borrow_mut(),
656 );
657 }
658 Rule::declaration => {}
659 _ => unreachable!(),
660 });
661 class_builder.borrow_mut().conclude(instance);
662 Ok(class_builder.into_inner().build())
663}
664
665fn parse_scroll(
666 instance: &mut SandboxInstance,
667 pairs: Pairs<Rule>,
668 include_path: &str,
669) -> Result<()> {
670 for pair in pairs {
671 match pair.as_rule() {
672 Rule::variable_definition => {
673 let mut inner = pair.into_inner();
674 let var = inner.next().unwrap().as_str();
675 let mut val: Option<serde_json::Value> = None;
676
677 let mut list: Vec<serde_json::Value> = Vec::new();
678
679 let mut prob = ProbabilityHelper::new();
680 for inner_pair in inner {
681 match inner_pair.as_rule() {
682 Rule::value => val = Some(upcast_string(inner_pair.as_str().trim())),
683 Rule::probability_spec => {
684 prob.parse_multiplier(&inner_pair);
685 }
686 Rule::list_value => prob.multiply(|| {
687 list.push(serde_json::to_value(inner_pair.as_str().trim()).expect("x"))
688 }),
689 _ => unreachable!(),
690 }
691 }
692
693 if let Some(inner_val) = val {
694 instance.globals.insert(var.to_string(), inner_val);
695 } else {
696 instance
697 .globals
698 .insert(var.to_string(), serde_json::json!(list));
699 }
700 }
701 Rule::entity_definition => match parse_entity(instance, pair) {
702 Ok(ret) => {
703 instance.classes.insert(ret.name.to_owned(), ret);
704 }
705 Err(e) => return Err(e),
706 },
707 Rule::include_stmt => {
708 let mut ip = pair.into_inner();
709 let what = ip.next().unwrap().as_str();
710 let path = String::from_str(include_path).unwrap() + what + ".scroll";
711 log::info!("importing {}", path);
712 let unparsed_file = std::fs::read_to_string(path.clone())?;
713 parse_buffer(instance, &unparsed_file, Some(include_path), Some(&path))?;
714 }
715 Rule::EOI => {}
716 _ => unreachable!(),
717 }
718 }
719 Ok(())
720}