hexroll3_scroll/
parser.rs

1/*
2// Copyright (C) 2020-2025 Pen, Dice & Paper
3//
4// This program is dual-licensed under the following terms:
5//
6// Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7// This program is free software: you can redistribute it and/or modify
8// it under the terms of the GNU Affero General Public License as
9// published by the Free Software Foundation, either version 3 of the
10// License, or (at your option) any later version.
11//
12// This program is distributed in the hope that it will be useful,
13// but WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15// GNU Affero General Public License for more details.
16//
17// You should have received a copy of the GNU Affero General Public License
18// along with this program. If not, see <http://www.gnu.org/licenses/>.
19//
20// Option 2: Commercial License
21// For commercial use, you are required to obtain a separate commercial
22// license. Please contact ithai at pendicepaper.com
23// for more information about commercial licensing terms.
24*/
25use 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
79/// Helper structure to manage probability parsing and execution.
80///
81/// The `ProbabilityHelper` is designed to parse a probability specifier
82/// in the form of "(xN)", where N is any integer number indicating the
83/// multiplier to be used. It is used in conjunction with a parser that
84/// interprets these specifiers and executes a callback function
85/// multiple times based on the parsed multiplier.
86struct 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
119// Helper function to parse attribute specifiers.
120//
121// Scroll attributes have a name and an optional visibility
122// specifier. This function parses the attribute name and
123// visibility specifiers and returns a tuple with:
124// (attr_name, is_public, is_optional)
125fn 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            // TODO: implement all tags
566            _ => {}
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}