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>;