lexigram_core/
fixed_sym_table.rs1use crate::parser::Symbol;
4use crate::{TokenId, VarId};
5
6#[derive(Clone, Debug)]
39pub struct FixedSymTable {
40 t: Vec<(String, Option<String>)>, nt: Vec<String>, }
43
44impl FixedSymTable {
45 pub fn new(t: Vec<(String, Option<String>)>, nt: Vec<String>) -> Self {
46 FixedSymTable { t, nt }
47 }
48
49 pub fn get_terminals(&self) -> impl Iterator<Item = &(String, Option<String>)> {
52 self.t.iter()
53 }
54
55 pub fn get_num_t(&self) -> usize {
56 self.t.len()
57 }
58
59 pub fn get_nonterminals(&self) -> impl Iterator<Item = &String> {
62 self.nt.iter()
63 }
64
65 pub fn get_num_nt(&self) -> usize {
66 self.nt.len()
67 }
68
69 #[cfg(test)]
72 pub fn dump(&self, title: &str) {
73 if !title.is_empty() {
74 println!("{title}");
75 }
76 println!(
77 "- nonterminals:\n{}",
78 self.get_nonterminals().enumerate().map(|(v, s)| format!(" - NT[{v}]: {s}")).collect::<Vec<_>>().join("\n"));
79 println!(
80 "- terminals:\n{}",
81 self.get_terminals().enumerate()
82 .map(|(t, (n, v_maybe))| format!(" - T[{t}]: {n}{}", if let Some(v) = v_maybe { format!(" = {v:?}") } else { String::new() }))
83 .collect::<Vec<_>>().join("\n"));
84 }
85}
86
87pub trait SymInfoTable {
88 fn is_token_data(&self, token: TokenId) -> bool;
94
95 fn is_symbol_t_data(&self, symbol: &Symbol) -> bool;
101
102 fn is_symbol_t_fixed(&self, symbol: &Symbol) -> bool;
103
104 fn get_t_str(&self, token: TokenId) -> String;
105
106 fn get_t_name(&self, token: TokenId) -> String;
107
108 fn get_nt_name(&self, var: VarId) -> String;
109
110 fn get_name(&self, symbol: &Symbol) -> String;
113
114 fn get_str(&self, symbol: &Symbol) -> String;
117
118 fn get_name_quote(&self, symbol: &Symbol) -> String;
119}
120
121impl SymInfoTable for FixedSymTable {
122 fn is_token_data(&self, token: TokenId) -> bool {
123 self.t[token as usize].1.is_none()
124 }
125
126 fn is_symbol_t_data(&self, symbol: &Symbol) -> bool {
127 if let Symbol::T(token) = symbol {
128 self.t.get(*token as usize).map(|t| t.1.is_none()).unwrap_or(false)
129 } else {
130 false
131 }
132 }
133
134 fn is_symbol_t_fixed(&self, symbol: &Symbol) -> bool {
135 if let Symbol::T(token) = symbol {
136 self.t.get(*token as usize).map(|t| t.1.is_some()).unwrap_or(false)
137 } else {
138 false
139 }
140 }
141
142 fn get_t_str(&self, token: TokenId) -> String {
143 match token {
144 _ if (token as usize) < self.t.len() => {
145 let (name, literal) = &self.t[token as usize];
146 literal.as_ref().unwrap_or(name).clone()
147 }
148 TokenId::MAX => "<bad character>".to_string(),
149 _ => format!("T({token}?)")
150 }
151 }
152
153 fn get_t_name(&self, token: TokenId) -> String {
154 if token as usize >= self.t.len() {
155 format!("T({token}?)")
156 } else {
157 self.t[token as usize].0.clone()
158 }
159 }
160
161 fn get_nt_name(&self, var: VarId) -> String {
162 if var as usize >= self.nt.len() { return format!("NT({var}?)") }
163 self.nt[var as usize].clone()
164 }
165
166 fn get_name(&self, symbol: &Symbol) -> String {
167 match symbol {
168 Symbol::Empty | Symbol::End => symbol.to_string(),
169 Symbol::T(token) => self.get_t_name(*token),
170 Symbol::NT(var) => self.get_nt_name(*var),
171 }
172 }
173
174 fn get_str(&self, symbol: &Symbol) -> String {
175 match symbol {
176 Symbol::Empty | Symbol::End => symbol.to_string(),
177 Symbol::T(token) => self.get_t_str(*token),
178 Symbol::NT(var) => self.get_nt_name(*var),
179 }
180 }
181
182 fn get_name_quote(&self, symbol: &Symbol) -> String {
183 match symbol {
184 Symbol::Empty | Symbol::End => symbol.to_string(),
185 Symbol::T(token) => if self.is_symbol_t_fixed(symbol) { format!("{:?}", self.get_t_str(*token)) } else { self.get_t_str(*token) },
186 Symbol::NT(var) => self.get_nt_name(*var),
187 }
188 }
189}