scdlang/external.rs
1/*! Collection of Trait for extending core functionality.
2Useful for creating transpiler, codegen, or even compiler.
3
4# Examples
5
61. Implement trait [`Parser`] on struct with [`Scdlang`] field (or any type that implement [`Builder`]).
7```no_run
8#[derive(Default)]
9pub struct Machine<'a> {
10 builder: Scdlang<'a>, // or any type that implmenet trait `Builder`
11 schema: std::any::Any,
12}
13
14impl Machine<'_> {
15 pub fn new() -> Self {
16 let mut builder = Scdlang::new();
17 // insert any pre-configuration here. For example:
18 // builder.auto_clear_cache(false)
19 Self { builder, ..Default::default() }
20 }
21}
22
23impl<'a> Parser<'a> for Machine<'a> {
24 fn configure(&mut self) -> &mut Builder<'a> {
25 &mut self.builder
26 }
27
28 fn parse(&mut self, source: &str) -> Result<(), DynError> {
29 self.clean_cache()?;
30 unimplemented!();
31 }
32
33 fn insert_parse(&mut self, source: &str) -> Result<(), Box<dyn error::Error>> {
34 unimplemented!();
35 }
36
37 fn try_parse(source: &str, builder: Scdlang<'a>) -> Result<Self, Box<dyn error::Error>> {
38 unimplemented!();
39 }
40}
41```
42
432. Then it can be used like this:
44```ignore
45let parser: Box<dyn Parser> = Box::new(match args {
46 Some(text) => module_a::Machine::try_parse(text)?,
47 None => module_b::Machine::new(),
48});
49
50parser.configure()
51 .auto_clear_cache(false)
52 .with_err_path("my_fsm.scl");
53
54parser.parse("Off -> On")?;
55parser.insert_parse("Off <- On @ Shutdown")?;
56
57parser.configure().with_err_semantic(false);
58parser.parse("Off -> On @ Power")?;
59```
60
61[`Parser`]: trait.Parser.html
62[`Builder`]: trait.Builder.html
63[`Scdlang`]: ../struct.Scdlang.html */
64use crate::{cache, Scdlang};
65use std::{error::Error, fmt};
66
67#[rustfmt::skip]
68/** A Trait which external parser must implement.
69
70This trait was mean to be used outside the core.
71For example, to build a transpiler. */
72pub trait Parser<'t>: fmt::Display {
73 /// Parse `source` then replace the results.
74 fn parse(&mut self, source: &str) -> Result<(), BoxError>;
75 /// Parse `source` then insert/append the results.
76 fn insert_parse(&mut self, source: &str) -> Result<(), BoxError>;
77
78 /// Parse `source` while instantiate the Parser.
79 fn try_parse(source: &str, options: Scdlang<'t>) -> Result<Self, BoxError> where Self: Sized;
80 /// Configure the parser.
81 fn configure(&mut self) -> &mut dyn Builder<'t>;
82
83 /// Completely clear the caches which also deallocate the memory.
84 fn flush_cache<'e>(&'t self) -> Result<(), DynError<'e>> {
85 Ok(cache::clear()?.shrink()?)
86 }
87
88 /// Clear the caches while still retain the allocated memory.
89 fn clean_cache<'e>(&'t self) -> Result<(), DynError<'e>> {
90 cache::clear()?;
91 Ok(())
92 }
93}
94
95/// A Trait to configure the `Parser`.
96/// This is a config builder for [`Scdlang`](../struct.Scdlang.html) core parser.
97pub trait Builder<'t> {
98 /** Automatically clear cache when out of scope.
99 * `default` - set `false` to disable it. (default: `true`)
100
101 The cache is used for analyzing semantics error.
102 This can be handy when parsing in streaming fashion. */
103 fn auto_clear_cache(&mut self, default: bool) -> &mut dyn Builder<'t>;
104
105 /// Enable semantics error. (default: `true`).
106 fn with_err_semantic(&mut self, default: bool) -> &mut dyn Builder<'t>;
107 /// Set path that going to be printed in the error essages.
108 fn with_err_path(&mut self, path: &'t str) -> &mut dyn Builder<'t>;
109 /// Set the line_of_code offset of the error essages.
110 fn with_err_line(&mut self, line: usize) -> &mut dyn Builder<'t>;
111}
112
113type DynError<'t> = Box<dyn Error + 't>;
114type BoxError = Box<dyn Error>;