orion_lib/
lib.rs

1//! > **Lexer, parser and runner for the Orion Programming Language.**
2//!
3//! ## Aspirations
4//!
5//! Out of the box, users get a polished lexer, parser and runner for Orion.
6//!
7//! ## Example
8//!
9//! Run
10//! ```console
11//! $ cargo add orion_lib
12//! ```
13//! Then use the functions
14//! ```rust
15//! use orion_lib::run_contents;
16//! use color_eyre::Result;
17//!
18//! fn main() -> Result<()> {
19//!     run_contents("$say(\"Hello, world!\")".to_string(), false)?;
20//!     Ok(())
21//! }
22//! ```
23
24#![deny(missing_docs)]
25#![deny(rustdoc::invalid_rust_codeblocks)]
26
27use std::iter::zip;
28
29use lalrpop_util::{lalrpop_mod, ParseError};
30
31use prelude::*;
32use utils::ast::Expr;
33use utils::orion::{setup_functions, setup_variables, Metadata, Variables};
34
35use crate::utils::ast::{CompCode, OpCode, ReassignCode, Type};
36use crate::utils::orion::{CustomFunctions, Function, Variable};
37
38pub use color_eyre::install as setup_error_hooks;
39pub use utils::jit::{decode, encode};
40
41mod error;
42mod prelude;
43mod types;
44mod utils;
45
46pub use utils::idle::IdleRunner;
47
48lalrpop_mod!(
49    #[allow(missing_docs)]
50    #[allow(clippy::type_complexity)]
51    lrparser
52);
53
54lalrpop_mod!(
55    #[allow(missing_docs)]
56    #[allow(clippy::type_complexity)]
57    lrbraces
58);
59
60/// Run the contents of an Orion file.
61///
62/// NOTE: The file's CONTENT must be provided, not its PATH.
63///
64/// ## Example
65///
66/// ```rust
67/// use orion_lib::run_contents;
68/// use color_eyre::Result;
69///
70/// fn main() -> Result<()> {
71///     run_contents("$say(\"Hello, world!\")".to_string(), false)?;
72///     Ok(())
73/// }
74/// ```
75pub fn run_contents<S: ToString>(contents: S, use_braces: bool) -> Result<()> {
76    let contents = contents.to_string();
77
78    if contents.is_empty() {
79        return Ok(());
80    }
81
82    let mut metadata = Metadata {
83        functions: setup_functions(),
84        ..Default::default()
85    };
86
87    let mut variables = setup_variables();
88
89    let mut custom_functions = CustomFunctions::new();
90
91    let lib = f!("{}\n", include_str!("./lib/std.or"));
92
93    let result = lrparser::StatementsParser::new()
94        .parse(lib.leak())
95        .with_context(|| "Error in standard file.")?;
96
97    for expr in result {
98        run(expr, &metadata, &mut variables, &mut custom_functions).with_context(|| {
99            "Error in \
100        standard file."
101        })?;
102    }
103
104    let result = if use_braces {
105        lrbraces::StatementsParser::new().parse(contents.clone().leak())
106    } else {
107        lrparser::StatementsParser::new().parse(contents.clone().leak())
108    };
109
110    let result = if result.is_err() {
111        Err(match result.err().unwrap() {
112            ParseError::InvalidToken { location } => {
113                let loc = utils::location::location(location, contents);
114                ParseError::InvalidToken { location: loc }
115            }
116
117            ParseError::UnrecognizedEof { location, expected } => {
118                let loc = utils::location::location(location, contents);
119                ParseError::UnrecognizedEof {
120                    location: loc,
121                    expected,
122                }
123            }
124
125            ParseError::UnrecognizedToken { token, expected } => {
126                let (loc1, token, loc2) = token;
127                let loc1 = utils::location::location(loc1, &contents);
128                let loc2 = utils::location::location(loc2, contents);
129
130                ParseError::UnrecognizedToken {
131                    token: (loc1, token, loc2),
132                    expected,
133                }
134            }
135
136            ParseError::ExtraToken { token } => {
137                let (loc1, token, loc2) = token;
138                let loc1 = utils::location::location(loc1, &contents);
139                let loc2 = utils::location::location(loc2, contents);
140
141                ParseError::ExtraToken {
142                    token: (loc1, token, loc2),
143                }
144            }
145
146            ParseError::User { error } => ParseError::User { error }, // ParseError::User
147        })
148    } else {
149        result.map_err(|_| ParseError::User {
150            error: "impossible",
151        })
152    };
153
154    let ast: Vec<Option<Expr>> = result.unwrap_or_else(|e| {
155        #[cfg(debug_assertions)]
156        {
157            panic!("\x1b[31m{e}\x1b[0m");
158        }
159        #[cfg(not(debug_assertions))]
160        {
161            eprintln!("\x1b[31m{e}\x1b[0m");
162            std::process::exit(1)
163        }
164    });
165
166    for (count, expr) in ast.iter().enumerate() {
167        metadata.line = count + 1;
168
169        run(
170            expr.to_owned(),
171            &metadata,
172            &mut variables,
173            &mut custom_functions,
174        )?;
175    }
176
177    Ok(())
178}
179
180/// Run an Abstract Syntax Tree.
181pub fn run_ast(ast: Vec<Option<Expr>>) -> Result<()> {
182    let mut metadata = Metadata {
183        functions: setup_functions(),
184        ..Default::default()
185    };
186
187    let mut variables = setup_variables();
188
189    let mut custom_functions = CustomFunctions::new();
190
191    let lib = f!("{}\n", include_str!("./lib/std.or"));
192
193    let result = lrparser::StatementsParser::new()
194        .parse(lib.leak())
195        .with_context(|| "Error in standard file.")?;
196
197    for expr in result {
198        run(expr, &metadata, &mut variables, &mut custom_functions).with_context(|| {
199            "Error in \
200        standard file."
201        })?;
202    }
203
204    for (count, expr) in ast.iter().enumerate() {
205        metadata.line = count + 1;
206
207        run(
208            expr.to_owned(),
209            &metadata,
210            &mut variables,
211            &mut custom_functions,
212        )?;
213    }
214
215    Ok(())
216}
217
218fn run(
219    ast: Option<Expr>,
220    meta: &Metadata,
221    variables: &mut Variables,
222    custom_functions: &mut CustomFunctions,
223) -> Result<Option<Expr>> {
224    let functions = &meta.functions;
225    let line = meta.line;
226
227    if ast.is_none() {
228        return Ok(None);
229    }
230
231    match ast.unwrap() {
232        Expr::FuncCall(func, args) => {
233            if custom_functions.contains_key(&func) {
234                let customs = custom_functions.clone();
235                let (f_args, body) = customs.get(&func).unwrap();
236
237                if args.len() != f_args.len() {
238                    bail!(Errors::LineError {
239                        line,
240                        msg: f!(
241                            "Invalid number of arguments! Expected: {}; Found: {}",
242                            f_args.len(),
243                            args.len()
244                        )
245                    })
246                }
247
248                let mut overrides = vec![];
249                let vars = variables.clone();
250
251                for (arg, f_arg) in zip(args, f_args) {
252                    let arg = arg.eval(meta, variables, custom_functions)?;
253
254                    if variables.contains_key(f_arg) {
255                        overrides.push(vars.get_key_value(f_arg).unwrap());
256                    }
257
258                    variables.insert(f_arg.to_owned(), variable_expr_eq(arg, meta.scope + 1));
259                }
260
261                let res = body.to_owned().eval(meta, variables, custom_functions)?;
262
263                for (key, over) in overrides {
264                    variables.insert(key.to_owned(), over.to_owned());
265                }
266
267                return Ok(res);
268            }
269
270            let func: &Function =
271                functions
272                    .get(func.as_str())
273                    .with_context(|| Errors::LineError {
274                        line,
275                        msg: f!("Could not find function `{func}`"),
276                    })?;
277
278            Ok(match func {
279                Function::Void(f) => {
280                    f(args, meta, variables, custom_functions)
281                        .with_context(|| f!("Error on line {}", meta.line))?;
282                    return Ok(None);
283                }
284                Function::String(f) => Some(Expr::String(
285                    f(args, meta, variables, custom_functions)
286                        .with_context(|| f!("Error on line {}", meta.line))?
287                        .to_string(),
288                )),
289            })
290        }
291
292        Expr::Let(name, value) => {
293            let value = value.eval(meta, variables, custom_functions)?;
294
295            if variables.contains_key(&name) {
296                bail!(Errors::LineError {
297                    line,
298                    msg: f!("Variable already exists. \
299                    Maybe you meant to overwrite it? `{name} = value`"),
300                })
301            }
302
303            variables.insert(name, variable_expr_eq(value, meta.scope));
304
305            Ok(None)
306        }
307        Expr::TypeLet(ty, name, value) => {
308            let value = value.eval(meta, variables, custom_functions)?;
309
310            if let Some(ref value) = value {
311                check_type(value, &ty, line)?;
312            } else {
313                bail!(Errors::LineError {
314                    line,
315                    msg: "Type does not match declaration.".to_string(),
316                })
317            }
318
319            if variables.contains_key(&name) {
320                bail!(Errors::LineError {
321                    line,
322                    msg: f!("Variable already exists. \
323                    Maybe you meant to overwrite it? `{name} = value`"),
324                })
325            }
326
327            variables.insert(name, variable_expr_eq(value, meta.scope));
328
329            Ok(None)
330        }
331        Expr::Ident(ident) => {
332            let var = variables.get(&ident).with_context(|| Errors::LineError {
333                line,
334                msg: f!("Could not find variable `{ident}`"),
335            })?;
336
337            let var = match var {
338                Variable::String(s, _) => Some(Expr::String(s.to_string())),
339                Variable::Int8(n, _) => Some(Expr::Int8(*n)),
340                Variable::Int16(n, _) => Some(Expr::Int16(*n)),
341                Variable::Int32(n, _) => Some(Expr::Int32(*n)),
342                Variable::Int64(n, _) => Some(Expr::Int64(*n)),
343                Variable::Uint8(n, _) => Some(Expr::Uint8(*n)),
344                Variable::Uint16(n, _) => Some(Expr::Uint16(*n)),
345                Variable::Uint32(n, _) => Some(Expr::Uint32(*n)),
346                Variable::Uint64(n, _) => Some(Expr::Uint64(*n)),
347                Variable::None(_) => None,
348                Variable::Array(array, _) => Some(Expr::Array(array.to_vec())),
349                Variable::Char(c, _) => Some(Expr::Char(*c)),
350                Variable::Float(f, _) => Some(Expr::Float(*f)),
351            };
352
353            Ok(var)
354        }
355        Expr::Op(a, opcode, b) => {
356            let a = a.eval(meta, variables, custom_functions)?;
357            let b = b.eval(meta, variables, custom_functions)?;
358
359            match opcode {
360                OpCode::Add => W(a) + W(b),
361                OpCode::Subtract => W(a) - W(b),
362                OpCode::Multiply => W(a) * W(b),
363                OpCode::Divide => W(a) / W(b),
364            }
365        }
366        Expr::Compare(a, opcode, b) => {
367            let a = W(a.eval(meta, variables, custom_functions)?);
368            let b = W(b.eval(meta, variables, custom_functions)?);
369
370            Ok(Some(match opcode {
371                CompCode::Greater => Expr::Bool(a > b),
372                CompCode::Lesser => Expr::Bool(a < b),
373                CompCode::Equals => Expr::Bool(a == b),
374                CompCode::NotEquals => Expr::Bool(a != b),
375                CompCode::GreaterEquals => Expr::Bool(a >= b),
376                CompCode::LesserEquals => Expr::Bool(a <= b),
377            }))
378        }
379        Expr::Scope(lines) => {
380            let mut value = None;
381            let meta = Metadata {
382                scope: meta.scope + 1,
383                ..meta.to_owned()
384            };
385
386            for line in lines {
387                value = run(line, &meta, variables, custom_functions)?;
388            }
389
390            garbage(variables, &(meta.scope - 1));
391
392            Ok(value)
393        }
394        Expr::If(condition, scope) => {
395            let condition = run(Some(*condition), meta, variables, custom_functions)?;
396
397            let value = if match condition {
398                Some(Expr::Bool(b)) => b,
399                _ => bail!("Invalid type for conditioning."),
400            } {
401                run(Some(*scope), meta, variables, custom_functions)?
402            } else {
403                None
404            };
405
406            Ok(value)
407        }
408        Expr::IfElse(condition, if_code, else_code) => {
409            let condition = run(Some(*condition), meta, variables, custom_functions)?;
410
411            let value = if match condition {
412                Some(Expr::Bool(b)) => b,
413                _ => bail!("Invalid type for conditioning."),
414            } {
415                run(Some(*if_code), meta, variables, custom_functions)?
416            } else {
417                run(Some(*else_code), meta, variables, custom_functions)?
418            };
419
420            Ok(value)
421        }
422        Expr::Property(_, _) => todo!(),
423        Expr::Method(expr, method, args) => {
424            let expr = expr.eval(meta, variables, custom_functions)?;
425            let methodical = match expr {
426                Some(expr) => expr,
427                None => bail!(Errors::LineError {
428                    line,
429                    msg: "No methods belong to type `None`.".to_string()
430                }),
431            }
432            .to_methodical(meta, variables, custom_functions)
433            .with_context(|| Errors::GeneralError(f!("Error on line {line}")))?;
434
435            let res = methodical
436                .0
437                .call(&method, args)
438                .with_context(|| Errors::LineError {
439                    line,
440                    msg: f!("Failed to run method `{method}`"),
441                })?;
442
443            Ok(res)
444        }
445        Expr::For(ident, iterable, code) => {
446            match iterable.eval(meta, variables, custom_functions)? {
447                Some(Expr::String(_)) => {
448                    bail!(Errors::LineError {
449                    line,
450                    msg: "String is not an iterable. Maybe you meant to iterate on its characters? \
451                    `s.chars()`".to_string()
452                })
453                }
454                Some(Expr::Array(array)) => {
455                    for expr in array {
456                        let variable = variable_expr_eq(
457                            expr.eval(meta, variables, custom_functions)?,
458                            meta.scope,
459                        );
460
461                        variables.insert(ident.to_string(), variable);
462
463                        code.clone().eval(meta, variables, custom_functions)?;
464                    }
465
466                    variables.remove(&ident);
467                }
468                _ => bail!("for: Type is not an iterable."),
469            }
470
471            Ok(None)
472        }
473        Expr::ForComplex(initializer, condition, eoi, code) => {
474            initializer.eval(meta, variables, custom_functions)?;
475
476            loop {
477                let condition_ = condition.clone().eval(meta, variables, custom_functions)?;
478
479                match condition_ {
480                    Some(Expr::Bool(b)) => {
481                        if !b {
482                            break;
483                        }
484                    }
485                    _ => bail!(Errors::LineError {
486                        line,
487                        msg: "Expected boolean".to_string()
488                    }),
489                }
490
491                code.clone().eval(meta, variables, custom_functions)?;
492
493                eoi.clone().eval(meta, variables, custom_functions)?;
494            }
495
496            Ok(None)
497        }
498        Expr::Reassign(var, operation, expr) => {
499            let val = expr.clone().eval(meta, variables, custom_functions)?;
500
501            match variables.get_mut(&var) {
502                Some(v) => {
503                    let (var_expr, scope) = expr_variable_eq(v);
504                    *v = match operation {
505                        ReassignCode::Re => variable_expr_eq(val, scope),
506                        ReassignCode::Plus => {
507                            let res = (W(var_expr) + W(val)).with_context(|| {
508                                Errors::GeneralError(f!("Error on line {line}"))
509                            })?;
510
511                            variable_expr_eq(res, scope)
512                        }
513                        ReassignCode::Minus => {
514                            let res = (W(var_expr) - W(val)).with_context(|| {
515                                Errors::GeneralError(f!("Error on line {line}"))
516                            })?;
517
518                            variable_expr_eq(res, scope)
519                        }
520                        ReassignCode::Multiply => {
521                            let res = (W(var_expr) * W(val)).with_context(|| {
522                                Errors::GeneralError(f!("Error on line {line}"))
523                            })?;
524
525                            variable_expr_eq(res, scope)
526                        }
527                        ReassignCode::Divide => {
528                            let res = (W(var_expr) / W(val)).with_context(|| {
529                                Errors::GeneralError(f!("Error on line {line}"))
530                            })?;
531
532                            variable_expr_eq(res, scope)
533                        }
534                    };
535                }
536                None => bail!(f!("Variable {var} not found")),
537            }
538
539            Ok(None)
540        }
541        Expr::Slice(e, slice) => {
542            let slice = slice.eval(meta, variables, custom_functions)?;
543            let slice: usize = match slice {
544                Some(slice) => match slice {
545                    Expr::Int8(n) => n.try_into()?,
546                    Expr::Int16(n) => n.try_into()?,
547                    Expr::Int32(n) => n.try_into()?,
548                    Expr::Int64(n) => n.try_into()?,
549                    Expr::Uint8(n) => n.into(),
550                    Expr::Uint16(n) => n.into(),
551                    Expr::Uint32(n) => n.try_into()?,
552                    Expr::Uint64(n) => n.try_into()?,
553                    _ => bail!(Errors::LineError {
554                        line,
555                        msg: "Cannot use this type as slicer.".to_string()
556                    }),
557                },
558                None => bail!(Errors::LineError {
559                    line,
560                    msg: "Cannot use None as slicer.".to_string()
561                }),
562            };
563
564            Ok(match e.eval(meta, variables, custom_functions)? {
565                Some(expr) => match expr {
566                    Expr::String(s) => Some(Expr::Char(
567                        s.get(slice..slice + 1)
568                            .with_context(|| Errors::LineError {
569                                line,
570                                msg: f!("Could not slice string at index {slice}"),
571                            })?
572                            .chars()
573                            .next()
574                            .with_context(|| Errors::LineError {
575                                line,
576                                msg: f!("Could not slice string at index {slice}"),
577                            })?,
578                    )),
579                    Expr::Array(array) => {
580                        let item = array.get(slice).with_context(|| Errors::LineError {
581                            line,
582                            msg: f!("Could not slice array at index {slice}"),
583                        })?;
584
585                        item.to_owned().eval(meta, variables, custom_functions)?
586                    }
587                    _ => bail!(Errors::LineError {
588                        line,
589                        msg: "Cannot slice this object.".to_string()
590                    }),
591                },
592                None => bail!(Errors::LineError {
593                    line,
594                    msg: "Cannot slice a None object.".to_string()
595                }),
596            })
597        }
598        Expr::Func(name, args, body) => {
599            if name.starts_with('$') {
600                bail!(Errors::LineError {
601                    line,
602                    msg: f!("Cannot create inner functions! `{name}`")
603                })
604            }
605
606            custom_functions.insert(name.to_string(), (args, body));
607
608            Ok(None)
609        }
610        e => Ok(Some(e)),
611    }
612}
613
614fn garbage(variables: &mut Variables, scope_: &usize) {
615    variables.retain(|_, v| match v {
616        Variable::String(_, scope) => scope_ >= scope,
617        Variable::Int8(_, scope) => scope_ >= scope,
618        Variable::Int16(_, scope) => scope_ >= scope,
619        Variable::Int32(_, scope) => scope_ >= scope,
620        Variable::Int64(_, scope) => scope_ >= scope,
621        Variable::Uint8(_, scope) => scope_ >= scope,
622        Variable::Uint16(_, scope) => scope_ >= scope,
623        Variable::Uint32(_, scope) => scope_ >= scope,
624        Variable::Uint64(_, scope) => scope_ >= scope,
625        Variable::Float(_, scope) => scope_ >= scope,
626        Variable::None(scope) => scope_ >= scope,
627        Variable::Array(_, scope) => scope_ >= scope,
628        Variable::Char(_, scope) => scope_ >= scope,
629    });
630}
631
632fn variable_expr_eq(expr: Option<Expr>, scope: usize) -> Variable {
633    let expr = if let Some(expr) = expr {
634        expr
635    } else {
636        return Variable::None(scope);
637    };
638
639    match expr {
640        Expr::Int8(n) => Variable::Int8(n, scope),
641        Expr::Int16(n) => Variable::Int16(n, scope),
642        Expr::Int32(n) => Variable::Int32(n, scope),
643        Expr::Int64(n) => Variable::Int64(n, scope),
644        Expr::Uint8(n) => Variable::Uint8(n, scope),
645        Expr::Uint16(n) => Variable::Uint16(n, scope),
646        Expr::Uint32(n) => Variable::Uint32(n, scope),
647        Expr::Uint64(n) => Variable::Uint64(n, scope),
648        Expr::String(s) => Variable::String(s, scope),
649        Expr::Array(array) => Variable::Array(array, scope),
650        Expr::Char(c) => Variable::Char(c, scope),
651        Expr::Float(f) => Variable::Float(f, scope),
652        _ => unimplemented!(),
653    }
654}
655
656fn expr_variable_eq(var: &Variable) -> (Option<Expr>, usize) {
657    match var {
658        Variable::Int8(n, scope) => (Some(Expr::Int8(*n)), *scope),
659        Variable::Int16(n, scope) => (Some(Expr::Int16(*n)), *scope),
660        Variable::Int32(n, scope) => (Some(Expr::Int32(*n)), *scope),
661        Variable::Int64(n, scope) => (Some(Expr::Int64(*n)), *scope),
662        Variable::Uint8(n, scope) => (Some(Expr::Uint8(*n)), *scope),
663        Variable::Uint16(n, scope) => (Some(Expr::Uint16(*n)), *scope),
664        Variable::Uint32(n, scope) => (Some(Expr::Uint32(*n)), *scope),
665        Variable::Uint64(n, scope) => (Some(Expr::Uint64(*n)), *scope),
666        Variable::String(s, scope) => (Some(Expr::String(s.to_string())), *scope),
667        Variable::Array(array, scope) => (Some(Expr::Array(array.to_vec())), *scope),
668        Variable::Char(c, scope) => (Some(Expr::Char(*c)), *scope),
669        Variable::Float(f, scope) => (Some(Expr::Float(*f)), *scope),
670        _ => unimplemented!(),
671    }
672}
673
674fn check_type(expr: &Expr, ty: &Type, line: usize) -> Result<()> {
675    match (expr, ty) {
676        (Expr::Int8(_), Type::Int8) | (Expr::Int8(_), Type::DynInt) => {}
677        (Expr::Int16(_), Type::Int16) | (Expr::Int16(_), Type::DynInt) => {}
678        (Expr::Int32(_), Type::Int32) | (Expr::Int32(_), Type::DynInt) => {}
679        (Expr::Int64(_), Type::Int64) | (Expr::Int64(_), Type::DynInt) => {}
680        (Expr::Uint8(_), Type::Uint8) | (Expr::Uint8(_), Type::DynInt) => {}
681        (Expr::Uint16(_), Type::Uint16) | (Expr::Uint16(_), Type::DynInt) => {}
682        (Expr::Uint32(_), Type::Uint32) | (Expr::Uint32(_), Type::DynInt) => {}
683        (Expr::Uint64(_), Type::Uint64) | (Expr::Uint64(_), Type::DynInt) => {}
684        (Expr::String(_), Type::String) => {}
685        (Expr::Float(_), Type::Float) => {}
686        (Expr::Bool(_), Type::Bool) => {}
687        (Expr::Char(_), Type::Char) => {}
688        (Expr::Array(array), Type::Array(ty)) => {
689            if let Some(ty) = &**ty {
690                for expr in array {
691                    check_type(expr, ty, line)?;
692                }
693            }
694        }
695        (_, _) => bail!(Errors::LineError {
696            line,
697            msg: "Type does not match declaration".to_string()
698        }),
699    }
700
701    Ok(())
702}