From 99eef56a7358849bc45df4057957f7f92fd3514a Mon Sep 17 00:00:00 2001 From: Prajwal S N Date: Thu, 21 Dec 2023 00:54:12 +0530 Subject: [PATCH] fix: simplify playground No more weird global static mutable variables. Signed-off-by: Prajwal S N --- Cargo.toml | 2 +- lost_compile/src/lib.rs | 27 ++++++++ lost_compile/src/main.rs | 25 +------- lost_playground/Cargo.toml | 1 - lost_playground/src/lib.rs | 124 ++++++++++++++++++------------------- www/index.js | 3 +- 6 files changed, 90 insertions(+), 92 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f258ace..3e41b59 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["lost_syntax", "lost_compile", "lost_playground"] +members = ["lost_*"] resolver = "2" [profile.release] diff --git a/lost_compile/src/lib.rs b/lost_compile/src/lib.rs index 56125dc..7ec10e6 100644 --- a/lost_compile/src/lib.rs +++ b/lost_compile/src/lib.rs @@ -3,3 +3,30 @@ pub mod error; pub mod interpret; pub mod stdlib; pub mod types; + +use crate::error::Exception; +use interpret::Interpreter; +use log::trace; +use lost_syntax::{lex::Lexer, parse::Parser}; + +pub fn run(source: &str, interpreter: &mut Interpreter) -> Result<(), Vec> { + let lexer = Lexer::new(source); + trace!("Lexing {source}"); + let tokens = lexer.lex_all_sanitised().map_err(|e| { + e.into_iter() + .map(Exception::Error) + .collect::>() + })?; + trace!("Parsing {tokens:#?}"); + let parser = Parser::new(&tokens); + let root = parser.parse_all().map_err(|e| { + e.into_iter() + .map(Exception::Error) + .collect::>() + })?; + trace!("Interpreting {root:#?}"); + match interpreter.interpret_all(root.items) { + Ok(()) => Ok(()), + Err(e) => Err(vec![e]), + } +} diff --git a/lost_compile/src/main.rs b/lost_compile/src/main.rs index 42ed66f..1342b14 100644 --- a/lost_compile/src/main.rs +++ b/lost_compile/src/main.rs @@ -1,8 +1,7 @@ #[macro_use] extern crate log; -use lost_compile::{error::Exception, interpret::Interpreter}; -use lost_syntax::{lex::Lexer, parse::Parser}; +use lost_compile::{interpret::Interpreter, run}; use std::{ env, fs, io::{self, Write}, @@ -62,25 +61,3 @@ fn run_repl() { } } } - -fn run(source: &str, interpreter: &mut Interpreter) -> Result<(), Vec> { - let lexer = Lexer::new(source); - trace!("Lexing {source}"); - let tokens = lexer.lex_all_sanitised().map_err(|e| { - e.into_iter() - .map(Exception::Error) - .collect::>() - })?; - trace!("Parsing {tokens:#?}"); - let parser = Parser::new(&tokens); - let root = parser.parse_all().map_err(|e| { - e.into_iter() - .map(Exception::Error) - .collect::>() - })?; - trace!("Interpreting {root:#?}"); - match interpreter.interpret_all(root.items) { - Ok(()) => Ok(()), - Err(e) => Err(vec![e]), - } -} diff --git a/lost_playground/Cargo.toml b/lost_playground/Cargo.toml index 49d0c7b..354bbd8 100644 --- a/lost_playground/Cargo.toml +++ b/lost_playground/Cargo.toml @@ -16,4 +16,3 @@ console_error_panic_hook = { version = "0.1.6", optional = true } wee_alloc = { version = "0.4.5", optional = true } lost_compile = { path = "../lost_compile" } lost_syntax = { path = "../lost_syntax" } -once_cell = "1.17.1" diff --git a/lost_playground/src/lib.rs b/lost_playground/src/lib.rs index fcb8fea..3c2268e 100644 --- a/lost_playground/src/lib.rs +++ b/lost_playground/src/lib.rs @@ -1,16 +1,13 @@ -use std::{env, sync::Mutex}; - use lost_compile::{ environment::Env, - error::Exception, interpret::Interpreter, + run, types::{ self, Type::{self, NativeFunc}, }, }; -use lost_syntax::{lex::Lexer, parse::Parser}; -use once_cell::sync::Lazy; +use std::env; use wasm_bindgen::prelude::*; #[cfg(feature = "wee_alloc")] @@ -23,7 +20,7 @@ pub fn init() -> String { console_error_panic_hook::set_once(); format!( - "Lost REPL v{} on {} ({}), Copyright (c) {}", + "Lost v{} on {} ({}), Copyright (c) {}", env!("CARGO_PKG_VERSION"), env::consts::OS, env::consts::ARCH, @@ -31,22 +28,59 @@ pub fn init() -> String { ) } -struct World { - env: Env, - output: String, +#[wasm_bindgen] +#[derive(Default)] +pub struct World { + interpreter: Interpreter, } -static WORLD: Lazy> = Lazy::new(|| { - let mut env = Env::default(); - init_io(&mut env); - Mutex::new(World { - env, - output: String::default(), - }) -}); +const REPL_OUTPUT_VAR: &str = "REPL_OUTPUT"; + +#[wasm_bindgen] +impl World { + #[wasm_bindgen(constructor)] + pub fn new() -> Self { + let world = Self::default(); + let mut env = Env::default(); + // Initialise output variable. This is a hack + // to print to JS since stdout itself can't be + // captured and piped into a JS value. + env.set(REPL_OUTPUT_VAR.to_string(), Type::Str(String::default())); + // Add stdlib functions + init_io(&mut env); + world.interpreter.env.replace(env); + world + } + + pub fn run(&mut self, src: &str) -> Result { + clear_output(&self.interpreter); + match run(src, &mut self.interpreter) { + Ok(()) => Ok(self + .interpreter + .env + .borrow() + .get(REPL_OUTPUT_VAR.to_string()) + .unwrap() + .to_string()), + Err(errors) => Err(errors + .into_iter() + .fold(String::default(), |a, b| a + &b.to_string() + "\n") + .trim() + .to_string()), + } + } +} -// Override the default init_io from stdlib -// since `println!` cannot be used with wasm +fn clear_output(interpreter: &Interpreter) { + interpreter + .env + .borrow_mut() + .assign(REPL_OUTPUT_VAR.to_string(), Type::Str(String::default())) + .expect("no output variable present"); +} + +/// Override the default init_io from stdlib +/// since `println!` cannot be used with wasm fn init_io(env: &mut Env) { // print(args) env.set( @@ -54,55 +88,15 @@ fn init_io(env: &mut Env) { NativeFunc(types::NativeFunc { name: "print".to_string(), args: vec!["arg".to_string()], - body: |_, args| { + body: |interpreter, args| { let arg = args.first().expect("argument not present"); - WORLD.lock().unwrap().output.push_str(&arg.to_string()); + interpreter + .env + .borrow_mut() + .assign(REPL_OUTPUT_VAR.to_string(), Type::Str(arg.to_string())) + .expect("no output variable present"); Ok(Type::Number(arg.to_string().len() as f64)) }, }), ); } - -#[wasm_bindgen] -pub fn run_repl(line: &str) -> Result { - let mut code = String::default(); - let mut world = WORLD.lock().unwrap(); - let env = world.env.to_owned(); - // Clear the output buffer - world.output = String::default(); - // Unlock the mutex since we've cloned the value - drop(world); - match run(&line, env) { - Ok(new_env) => { - code.push_str(&line); - let mut world = WORLD.lock().unwrap(); - world.env = new_env; - Ok(world.output.to_owned()) - } - Err(errors) => Err(errors - .into_iter() - .fold(String::default(), |a, b| a + &b.to_string() + "\n") - .trim() - .to_string()), - } -} - -fn run(source: &str, env: Env) -> Result> { - let lexer = Lexer::new(source); - let tokens = lexer.lex_all_sanitised().map_err(|e| { - e.into_iter() - .map(Exception::Error) - .collect::>() - })?; - let parser = Parser::new(&tokens); - let root = parser.parse_all().map_err(|e| { - e.into_iter() - .map(Exception::Error) - .collect::>() - })?; - let mut interpreter = Interpreter::new(Some(env)); - match interpreter.interpret_all(root.items) { - Ok(()) => Ok(interpreter.env), - Err(e) => Err(vec![e]), - } -} diff --git a/www/index.js b/www/index.js index 77ee46b..9ff6f1e 100644 --- a/www/index.js +++ b/www/index.js @@ -15,6 +15,7 @@ const repl = { // Initialise // ---------------------------------------------------------------------------- +const world = new wasm.World(); repl.elemSourceInput.addEventListener("change", onInputChange); repl.elemSourceInput.addEventListener("keyup", onInputKeyup); repl.elemHistory.querySelector("#loading-message").remove(); @@ -105,7 +106,7 @@ async function processInputQueue() { let ok = true; if (inputText) { try { - outputText = wasm.run_repl(inputText); + outputText = world.run(inputText); } catch (e) { outputText = `${e}`; ok = false;