1use crate::core::{Rule, TokenDef, TokenRule};
4use crate::grammar::pt;
5use crate::sdk::Error;
6use std::collections::BTreeMap;
7
8mod validate;
9
10#[derive(Debug, Clone, Default)]
21pub struct Language {
22 pub context: Option<String>,
26 pub target: String,
28 pub tokens: Vec<TokenDef>,
30 pub token_rules: Vec<TokenRule>,
32 pub semantics: Vec<String>,
34 pub rules: BTreeMap<String, Rule>,
36 pub includes: Vec<String>,
38}
39
40#[derive(Default)]
45pub struct LangBuilder {
46 context: Option<String>,
47 target: Option<String>,
48 tokens: Vec<TokenDef>,
49 token_rules: Vec<TokenRule>,
50 semantics: Vec<String>,
51 rules: BTreeMap<String, Rule>,
52 includes: Vec<String>,
53}
54
55impl LangBuilder {
56 pub fn new() -> Self {
58 Default::default()
59 }
60
61 #[inline]
65 pub fn set_context(&mut self, context: String) -> bool {
66 if self.context.is_some() {
67 false
68 } else {
69 self.context = Some(context);
70 true
71 }
72 }
73
74 #[inline]
78 pub fn add_token(&mut self, token: TokenDef) -> bool {
79 if self.tokens.iter().any(|t| t.name == token.name) {
80 false
81 } else {
82 self.tokens.push(token);
83 true
84 }
85 }
86
87 #[inline]
89 pub fn add_token_rule(&mut self, token_rule: TokenRule) {
90 self.token_rules.push(token_rule);
91 }
92
93 #[inline]
97 pub fn add_semantic(&mut self, semantic: String) -> bool {
98 if self.semantics.iter().any(|s| s == &semantic) {
99 false
100 } else {
101 self.semantics.push(semantic);
102 true
103 }
104 }
105
106 #[inline]
110 pub fn add_rule(&mut self, rule: Rule) -> bool {
111 if self.rules.is_empty() {
112 self.target = Some(rule.name.clone());
113 }
114 if self.rules.contains_key(&rule.name) {
115 false
116 } else {
117 self.rules.insert(rule.name.clone(), rule);
118 true
119 }
120 }
121
122 #[inline]
124 pub fn add_include(&mut self, path: String) {
125 self.includes.push(path);
126 }
127
128 pub fn build(&mut self, pt: &[pt::TopLevelStatement]) -> Result<Language, Vec<Error>> {
132 if self.rules.is_empty() {
133 return Err(vec![Error::global(
134 "No rule defined.".to_owned(),
135 "Define a rule with the \"rule\" keyword.".to_owned(),
136 )]);
137 }
138 let lang = Language {
139 context: self.context.take(),
140 target: self.target.take().unwrap(),
141 tokens: std::mem::take(&mut self.tokens),
142 token_rules: std::mem::take(&mut self.token_rules),
143 semantics: std::mem::take(&mut self.semantics),
144 rules: std::mem::take(&mut self.rules),
145 includes: std::mem::take(&mut self.includes),
146 };
147
148 validate::validate_references(pt, lang)
150 }
151}