#![warn(missing_docs)]
#![doc(html_favicon_url = "https://buxogabriel.vercel.app/favicon.ico")]
#![doc(html_logo_url = "https://buxogabriel.vercel.app/apple-touch-icon.png")]
#[cfg(feature="wasm")]
use wasm_bindgen::prelude::*;
use std::{collections::HashMap, fs, io};
mod ast;
pub mod repl;
pub mod lexer;
pub mod parser;
pub mod evaluator;
use evaluator::Runtime;
use parser::Parser;
#[derive(Default)]
pub struct Config {
flags: HashMap<String, String>
}
impl Config {
pub fn build(args: &[String]) -> Result<Config, &'static str> {
let flags = Self::parse_flags(args);
Ok(Config { flags })
}
fn parse_flags(args: &[String]) -> HashMap<String, String> {
let mut map = HashMap::<String, String>::new();
args.windows(2).for_each(|pair| {
match pair[0].clone().split_once("--") {
Some((_, flag)) => {
map.insert(flag.to_string(), pair[1].clone());
},
None => {},
}
});
map
}
fn get_flag(&self, flag: &str) -> Option<String> {
self.flags.get(flag).map(|f| f.clone())
}
}
pub fn run(config: Config) -> io::Result<()> {
if let Some(file_name) = config.get_flag("file") {
let contents = fs::read_to_string(&file_name)?;
println!("parsing {}", &file_name);
let program = Parser::new(&contents).parse_program();
match program {
Ok(program) => {
println!("parsing complete! Running {}", &file_name);
let mut runtime = Runtime::new();
match runtime.run_program(&program) {
Ok(res) => println!("{res}"),
Err(err) => println!("Execution Failed: {err}")
}
},
Err(e) => println!("{e}"),
};
return Ok(())
}
repl::start();
Ok(())
}
#[cfg_attr(feature = "wasm", wasm_bindgen)]
pub struct Gabelang {
runtime: Runtime,
}
#[cfg_attr(feature = "wasm", wasm_bindgen)]
impl Gabelang {
#[cfg_attr(feature = "wasm", wasm_bindgen(constructor))]
pub fn new() -> Self {
Self {
runtime: Runtime::new()
}
}
#[cfg_attr(feature = "wasm", wasm_bindgen)]
pub fn repl_greeting() -> String {
repl::REPLGREETING.to_string()
}
#[cfg_attr(feature = "wasm", wasm_bindgen)]
pub fn run_program(&mut self, program: &str) -> String {
let program = match Parser::new(program).parse_program() {
Ok(program) => program,
Err(e) => return format!("Error: {e}"),
};
self.runtime.reset_stack();
self.runtime.run_program(&program)
.map(|val| format!("{}", val))
.unwrap_or_else(|e| format!("Error: {e}"))
}
#[cfg_attr(feature="wasm", wasm_bindgen)]
pub fn execute(&mut self, code: &str) -> String {
let code = match Parser::new(code).parse_program() {
Ok(program) => program,
Err(e) => return format!("Error: {e}"),
};
self.runtime.run_program(&code)
.map(|val| format!("{}", val))
.unwrap_or_else(|e| format!("Error: {e}"))
}
#[cfg_attr(feature="wasm", wasm_bindgen)]
pub fn reset_stack(&mut self) {
self.runtime.reset_stack();
}
#[cfg_attr(feature="wasm", wasm_bindgen)]
pub fn push_frame(&mut self) {
self.runtime.current_context().push_scope();
}
#[cfg_attr(feature="wasm", wasm_bindgen)]
pub fn pop_frame(&mut self) -> bool {
match self.runtime.current_context().pop_scope() {
Ok(_) => true,
Err(_) => false
}
}
}