1#![warn(missing_docs)]
2#![doc(html_favicon_url = "https://buxogabriel.vercel.app/favicon.ico")]
3#![doc(html_logo_url = "https://buxogabriel.vercel.app/apple-touch-icon.png")]
4
5#[cfg(feature="wasm")]
6use wasm_bindgen::prelude::*;
7
8use std::{collections::HashMap, fs, io};
9
10mod ast;
11pub mod repl;
13pub mod lexer;
16pub mod parser;
18pub mod evaluator;
20
21use evaluator::Runtime;
22use parser::Parser;
23
24#[derive(Default)]
26pub struct Config {
27 flags: HashMap<String, String>
28}
29
30impl Config {
31 pub fn build(args: &[String]) -> Result<Config, &'static str> {
55 let flags = Self::parse_flags(args);
56 Ok(Config { flags })
57 }
58
59 fn parse_flags(args: &[String]) -> HashMap<String, String> {
60 let mut map = HashMap::<String, String>::new();
61 args.windows(2).for_each(|pair| {
62 match pair[0].clone().split_once("--") {
63 Some((_, flag)) => {
64 map.insert(flag.to_string(), pair[1].clone());
65 },
66 None => {},
67 }
68 });
69 map
70 }
71
72 fn get_flag(&self, flag: &str) -> Option<String> {
73 self.flags.get(flag).map(|f| f.clone())
74 }
75}
76
77pub fn run(config: Config) -> io::Result<()> {
92 if let Some(file_name) = config.get_flag("file") {
93 let contents = fs::read_to_string(&file_name)?;
94 println!("parsing {}", &file_name);
95 let program = Parser::new(&contents).parse_program();
96 match program {
97 Ok(program) => {
98 println!("parsing complete! Running {}", &file_name);
99 let mut runtime = Runtime::new();
100 match runtime.run_program(&program) {
101 Ok(res) => println!("{res}"),
102 Err(err) => println!("Execution Failed: {err}")
103 }
104 },
105 Err(e) => println!("{e}"),
106 };
107 return Ok(())
108 }
109 repl::start();
110 Ok(())
111}
112
113#[cfg_attr(feature = "wasm", wasm_bindgen)]
115pub struct Gabelang {
116 runtime: Runtime,
117}
118
119#[cfg_attr(feature = "wasm", wasm_bindgen)]
120impl Gabelang {
121 #[cfg_attr(feature = "wasm", wasm_bindgen(constructor))]
123 pub fn new() -> Self {
124 Self {
125 runtime: Runtime::new()
126 }
127 }
128
129 #[cfg_attr(feature = "wasm", wasm_bindgen)]
131 pub fn repl_greeting() -> String {
132 repl::REPLGREETING.to_string()
133 }
134
135 #[cfg_attr(feature = "wasm", wasm_bindgen)]
137 pub fn run_program(&mut self, program: &str) -> String {
138 let program = match Parser::new(program).parse_program() {
139 Ok(program) => program,
140 Err(e) => return format!("Error: {e}"),
141 };
142 self.runtime.reset_stack();
143 self.runtime.run_program(&program)
144 .map(|val| format!("{}", val))
145 .unwrap_or_else(|e| format!("Error: {e}"))
146 }
147
148 #[cfg_attr(feature="wasm", wasm_bindgen)]
150 pub fn execute(&mut self, code: &str) -> String {
151 let code = match Parser::new(code).parse_program() {
152 Ok(program) => program,
153 Err(e) => return format!("Error: {e}"),
154 };
155 self.runtime.run_program(&code)
156 .map(|val| format!("{}", val))
157 .unwrap_or_else(|e| format!("Error: {e}"))
158 }
159
160 #[cfg_attr(feature="wasm", wasm_bindgen)]
162 pub fn reset_stack(&mut self) {
163 self.runtime.reset_stack();
164 }
165
166 #[cfg_attr(feature="wasm", wasm_bindgen)]
168 pub fn push_frame(&mut self) {
169 self.runtime.current_context().push_scope();
170 }
171
172 #[cfg_attr(feature="wasm", wasm_bindgen)]
174 pub fn pop_frame(&mut self) -> bool {
175 match self.runtime.current_context().pop_scope() {
176 Ok(_) => true,
177 Err(_) => false
178 }
179 }
180}