1extern crate core;
2#[macro_use]
3extern crate lalrpop_util;
4
5use std::cmp;
6use std::collections::HashMap;
7use std::fmt::{Debug, Formatter};
8
9use itertools::Itertools;
10use lalrpop_util::ParseError;
11
12use crate::ast::{ParserState, Template};
13use crate::data_types::{InterpretError, InterpretVal};
14use crate::external_operators::{
15 CustomBinOp, CustomBuiltIn, CustomType, CustomUnaryOp, OperatorChars,
16};
17use crate::interpreter::{interpret, Customs};
18use crate::parser::language_definition::TemplateParser;
19
20mod ast;
21mod data_types;
22mod interpreter;
23mod parser;
24mod test;
25
26pub mod external_operators;
27
28pub struct Language<C: CustomType> {
30 unary_operators: HashMap<OperatorChars, CustomUnaryOp<C>>,
31 binary_operators: HashMap<OperatorChars, CustomBinOp<C>>,
32 built_ins: HashMap<String, CustomBuiltIn<C>>,
33}
34
35#[derive(Debug)]
37pub struct ParsedTemplate<C: CustomType> {
38 lang: String,
39 temp: Template,
40 unary_operators: HashMap<OperatorChars, CustomUnaryOp<C>>,
41 binary_operators: HashMap<OperatorChars, CustomBinOp<C>>,
42 built_ins: HashMap<String, CustomBuiltIn<C>>,
43}
44
45pub enum Argument<C: CustomType> {
47 Int(i32),
48 String(String),
49 Tuple(Vec<Argument<C>>),
50 Custom(C),
51}
52
53impl<C: CustomType> Clone for Argument<C> {
54 fn clone(&self) -> Self {
55 match &self {
56 Argument::Int(i) => Argument::Int(*i),
57 Argument::String(s) => Argument::String(s.clone()),
58 Argument::Tuple(t) => Argument::Tuple(t.clone()),
59 Argument::Custom(c) => Argument::Custom(c.clone()),
60 }
61 }
62}
63
64pub struct LangFunc<'a, C: CustomType> {
67 lang: &'a ParsedTemplate<C>,
68 name: String,
69 arg: Option<Argument<C>>,
70 text: String,
71}
72
73impl<C: CustomType> Default for Language<C> {
74 fn default() -> Self {
75 Self::new()
76 }
77}
78
79impl<C: CustomType> Language<C> {
80 pub fn new() -> Self {
81 Self {
82 unary_operators: Default::default(),
83 binary_operators: Default::default(),
84 built_ins: Default::default(),
85 }
86 }
87
88 pub fn add_bin_op(&mut self, char: OperatorChars, op: CustomBinOp<C>) -> &Self {
89 self.binary_operators.entry(char).or_insert(op);
90 self
91 }
92
93 pub fn add_unary_op(&mut self, char: OperatorChars, op: CustomUnaryOp<C>) -> &Self {
94 self.unary_operators.entry(char).or_insert(op);
95 self
96 }
97
98 pub fn add_custom_function(&mut self, name: String, func: CustomBuiltIn<C>) -> &Self {
99 self.built_ins.entry(name).or_insert(func);
100 self
101 }
102
103 pub fn parse(&self, code: String) -> Result<ParsedTemplate<C>, LanguageErr> {
104 let parser = TemplateParser::new();
105 let parser_state = ParserState {
106 unary_ops: self.unary_operators.keys().cloned().collect(),
107 binary_ops: self.binary_operators.keys().cloned().collect(),
108 };
109 let res: Result<Template, ParseError<usize, _, (usize, String, usize)>> =
110 parser.parse(&parser_state, &code);
111
112 match res {
113 Ok(l) => Ok(ParsedTemplate {
114 temp: l,
115 lang: code,
116 unary_operators: self.unary_operators.clone(),
117 binary_operators: self.binary_operators.clone(),
118 built_ins: self.built_ins.clone(),
119 }),
120 Err(e) => Err(LanguageErr::new_from_parser_err(
121 e.map_token(|_| "".to_string()),
122 code,
123 )),
124 }
125 }
126}
127
128impl<C: CustomType> ParsedTemplate<C> {
129 pub fn from_text(lang: &str) -> Result<Self, LanguageErr> {
137 let parser: TemplateParser = TemplateParser::new();
138 let res = parser.parse(&ParserState::new(), lang);
139 match res {
140 Ok(l) => Ok(Self {
141 temp: l,
142 lang: lang.to_string(),
143 unary_operators: Default::default(),
144 binary_operators: Default::default(),
145 built_ins: Default::default(),
146 }),
147 Err(e) => {
148 Err(LanguageErr::new_from_parser_err(
150 e.map_token(|_| "".to_string()),
151 lang.to_string(),
152 ))
153 }
154 }
155 }
156
157 pub fn list(&self) -> Vec<String> {
166 return self.temp.env.keys().map(|s| s.to_string()).collect();
167 }
168
169 pub fn function(&self, name: &str) -> Result<LangFunc<C>, LanguageErr> {
178 if self.temp.env.contains_key(name) {
179 Ok(LangFunc {
180 lang: self,
181 name: name.to_string(),
182 arg: None,
183 text: self.lang.clone(),
184 })
185 } else {
186 Err(LanguageErr::new_no_loc(format!(
187 "Cannot find function \"{}\".",
188 name
189 )))
190 }
191 }
192}
193
194pub enum ReturnVal<T> {
196 String(String),
197 Int(i32),
198 Bool(bool),
199 Tuple(Vec<ReturnVal<T>>),
200 List(Vec<ReturnVal<T>>),
201 Custom(T),
202}
203
204impl<'a, C: CustomType> LangFunc<'a, C> {
205 pub fn arg(mut self, arg: Argument<C>) -> Self {
216 self.arg = Some(arg);
217 self
218 }
219 pub fn call(&self) -> Result<ReturnVal<C>, LanguageErr> {
230 if let Some(x) = &self.arg {
231 interpret(
232 &self.lang.temp,
233 self.name.as_str(),
234 InterpretVal::from_arg(x),
235 &Customs::new_from_hash(
236 self.lang.binary_operators.clone(),
237 self.lang.unary_operators.clone(),
238 self.lang.built_ins.clone(),
239 ),
240 )
241 } else {
242 interpret(
243 &self.lang.temp,
244 self.name.as_str(),
245 InterpretVal::Tuple(vec![]),
246 &Customs::new_from_hash(Default::default(), Default::default(), Default::default()),
247 )
248 }
249 .map_err(|e| LanguageErr::new_from_int_err(e, self.text.clone()))
250 }
251}
252
253pub struct LocationLangErr {
255 message: String,
256 lines: (usize, usize),
257 char: (usize, usize),
258 section: String,
259}
260
261pub enum LanguageErr {
263 NoLoc(String),
264 Loc(LocationLangErr),
265}
266
267impl LanguageErr {
268 fn new_loc(message: String, location: (usize, usize), lang: String) -> Self {
271 let (start_line, start_char) = get_lang_pos(&lang, location.0);
272 let (end_line, end_char) = get_lang_pos(&lang, location.1);
273 LanguageErr::Loc(LocationLangErr {
274 lines: (start_line, end_line),
275 section: lang[location.0..location.1].to_string(),
276 char: (start_char, end_char),
277 message,
278 })
279 }
280
281 fn new_no_loc(message: String) -> Self {
283 LanguageErr::NoLoc(message)
284 }
285
286 fn new_from_int_err(err: InterpretError, lang: String) -> Self {
288 if err.location.is_some() {
289 Self::new_loc(err.message, err.location.unwrap(), lang)
290 } else {
291 Self::new_no_loc(err.message)
292 }
293 }
294
295 fn new_from_parser_err(
297 err: ParseError<usize, String, (usize, String, usize)>,
298 lang: String,
299 ) -> Self {
300 match err {
301 ParseError::InvalidToken { location } => {
302 let (line, char) = get_lang_pos(&lang, location);
303 Self::Loc(LocationLangErr {
304 message: "Invalid token".to_string(),
305 lines: (line, line),
306 char: (char, char),
307 section: lang[location..location + 10].to_string(),
308 })
309 }
310 ParseError::UnrecognizedEOF { location, .. } => {
311 let (line, char) = get_lang_pos(&lang, location);
312 Self::Loc(LocationLangErr {
313 message: "Unexpected End of File".to_string(),
314 lines: (line, line),
315 char: (char, char),
316 section: lang[cmp::min(location - 10, 0)..].to_string(),
317 })
318 }
319 ParseError::UnrecognizedToken {
320 token: (l, _, r), ..
321 } => {
322 let (start_line, start_char) = get_lang_pos(&lang, l);
323 let (end_line, end_char) = get_lang_pos(&lang, r);
324 Self::Loc(LocationLangErr {
325 message: "Unrecognised token".to_string(),
326 lines: (start_line, end_line),
327 char: (start_char, end_char),
328 section: lang[l..r].to_string(),
329 })
330 }
331 ParseError::ExtraToken {
332 token: (l, _, r), ..
333 } => {
334 let (start_line, start_char) = get_lang_pos(&lang, l);
335 let (end_line, end_char) = get_lang_pos(&lang, r);
336 Self::Loc(LocationLangErr {
337 message: "Extra token".to_string(),
338 lines: (start_line, end_line),
339 char: (start_char, end_char),
340 section: lang[l..r].to_string(),
341 })
342 }
343 ParseError::User { error: (l, m, r) } => {
344 let (start_line, start_char) = get_lang_pos(&lang, l);
345 let (end_line, end_char) = get_lang_pos(&lang, r);
346 Self::Loc(LocationLangErr {
347 message: m,
348 lines: (start_line, end_line),
349 char: (start_char, end_char),
350 section: lang[l..r].to_string(),
351 })
352 }
353 }
354 }
355}
356
357fn get_lang_pos(lang: &str, pos: usize) -> (usize, usize) {
358 let new_lines = lang[0..pos]
359 .as_bytes()
360 .iter()
361 .enumerate()
362 .filter(|(_, c)| **c == b'\n');
363 let line_num = new_lines.clone().count();
364 let char = pos - new_lines.last().unwrap_or((0, &b'x')).0;
365
366 (line_num, char)
367}
368
369impl Debug for LanguageErr {
370 fn fmt(&self, fmt: &mut Formatter<'_>) -> std::fmt::Result {
371 match self {
372 LanguageErr::Loc(l) => {
373 write!(
374 fmt,
375 "Error: \"{}\"\nAt lines: {}:{} - {}:{}\nCode: `{}`",
376 l.message,
377 l.lines.0 + 1,
378 l.char.0,
379 l.lines.1 + 1,
380 l.char.1,
381 l.section
382 )
383 }
384 LanguageErr::NoLoc(l) => {
385 write!(fmt, "Error: {}", l)
386 }
387 }
388 }
389}
390
391impl<C: CustomType> Debug for ReturnVal<C> {
392 fn fmt(&self, fmt: &mut Formatter<'_>) -> std::fmt::Result {
393 match self {
394 ReturnVal::Bool(b) => write!(fmt, "Bool({})", b),
395 ReturnVal::Int(i) => write!(fmt, "Int({})", i),
396 ReturnVal::String(s) => write!(fmt, "String({})", s),
397 ReturnVal::Tuple(v) => write!(
398 fmt,
399 "Tuple({})",
400 v.iter().map(|i| format!("{:?}", i)).join(", ")
401 ),
402 ReturnVal::List(v) => write!(
403 fmt,
404 "List({})",
405 v.iter().map(|i| format!("{:?}", i)).join(", ")
406 ),
407 ReturnVal::Custom(v) => write!(fmt, "Custom({:?})", v),
408 }
409 }
410}
411
412impl<C: CustomType> ToString for ReturnVal<C> {
413 fn to_string(&self) -> String {
414 match self {
415 ReturnVal::Bool(b) => b.to_string(),
416 ReturnVal::Int(i) => i.to_string(),
417 ReturnVal::String(s) => s.to_string(),
418 ReturnVal::Tuple(v) => format!("({})", v.iter().map(|i| i.to_string()).join(", ")),
419 ReturnVal::List(v) => format!("[{}]", v.iter().map(|i| i.to_string()).join(", ")),
420 ReturnVal::Custom(v) => v.to_string(),
421 }
422 }
423}
424
425#[derive(Clone, Debug, PartialEq)]
427pub struct BlankCustom {}
428
429impl ToString for BlankCustom {
430 fn to_string(&self) -> String {
431 "Blank".to_string()
432 }
433}
434
435impl CustomType for BlankCustom {}