From 80fe2c6d839eaa85166aefc5364304f07ff9d7c0 Mon Sep 17 00:00:00 2001 From: YetAnotherMinion Date: Sat, 23 Oct 2021 05:28:49 +0100 Subject: [PATCH] refactor: some modernization while computer was in shop --- Cargo.toml | 13 ++- src/main.rs | 244 +++++++++++++++++++++++++------------------- src/reporting.rs | 11 +- starmelon-binary.do | 2 +- 4 files changed, 157 insertions(+), 113 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bd11e48..442f2dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,8 +3,6 @@ name = "starmelon" version = "0.1.0" edition = "2018" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - # I decided to use os_pipe becaues I want to pipe stdout of a subprocess into # stderr in real time. I want the outupt of the process to stderr and stdout # show up in the original order. I looked an os_pipe uses some unsafe code to @@ -21,14 +19,15 @@ serde = { version = "1.0", features = [ "derive" ] } serde_json = { version ="1.0", features = [] } structopt = { version = "0.3" } elm-project-utils = { path = "../../../infra/rust-elm-project-utils" } +tracing = "0.1" # All of these are required for deno's javascript runtime. We need to keep the # same versions as other projects in our cargo workspace. Multiple different # versions of rust_v8 seem to break its build script. -deno_runtime = "0.21.0" +deno_runtime = "0.29.0" tokio = { version = "1.6", features = ["full"] } -deno_core = "0.95.0" -deno_web = "0.44" -rusty_v8 = "0.25.3" +deno_core = "0.103.0" +deno_web = "0.52" +rusty_v8 = "0.32" futures = "0.3.15" -serde_v8 = "0.8" +serde_v8 = "0.15" diff --git a/src/main.rs b/src/main.rs index 9a8aa5d..7ae6435 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,12 +16,18 @@ use std::time::Instant; use structopt::StructOpt; use elm_project_utils::ChecksumConstraint; use tokio; +use tracing::{span, info_span}; +use crate::timings::Timings; mod reporting; mod fixture; +mod timings; fn main() { let args = Arguments::from_args(); + + let span_subscriber = Timings::new(); + tracing::subscriber::set_global_default(span_subscriber).unwrap(); match args { // Arguments::Make { file, debug, output } => { @@ -33,6 +39,8 @@ fn main() { output, verbosity, } => { + let run_program = info_span!("run_program_span"); + run_program.enter(); let start = Instant::now(); if let Err(problem) = exec(file, debug, function, input, output, verbosity) { eprintln!( @@ -63,6 +71,7 @@ fn exec( output: Option, verbosity: u64, ) -> Result<(), Problem> { + info_span!("another_span").enter(); // Our first elm make call is where we build the users program. There is a pretty good chance // this won't work. let mut command = Command::new("elm"); @@ -242,93 +251,108 @@ fn exec( // `"REPLACE_ME" + "abc" * 2000` we would have over 6k bytes to write out the new code. We // will have to do some extra book keeping to make sure the buffer space is big enough // for the replacement code. - let mut final_script = data - .replace("'REPLACE_ME_WITH_JSON_STRINGIFY'", "JSON.stringify(x)") - .replace( - "$elm$json$Json$Decode$fail('REPLACE_ME_WITH_BYTES_DECODER');", - r#" _Json_decodePrim(function(value) { - return (typeof value === 'object' && value instanceof DataView) - ? $elm$core$Result$Ok(value) - : _Json_expecting('a DataView', value); -});"#, - ) - .replace(";}(this));", ";}(globalThis));"); + let mut final_script = ( || { + let mut final_script = data + .replace("'REPLACE_ME_WITH_JSON_STRINGIFY'", "JSON.stringify(x)") + //.replace("setTimeout", "(function(x, y) { globalThis.__bootstrap.timers.setTimeout(x, y)})") + .replace( + "$elm$json$Json$Decode$fail('REPLACE_ME_WITH_BYTES_DECODER');", + r#" _Json_decodePrim(function(value) { + return (typeof value === 'object' && value instanceof DataView) + ? $elm$core$Result$Ok(value) + : _Json_expecting('a DataView', value); + });"#, + ) + .replace(";}(this));", ";}(globalThis));"); + + final_script.push_str("\n\n"); + // I think that when I set this script to be the main module, I am skipping the + // deno/runtime/js/99_main.js script that sets up a bunch of global variables. If I + // manually add the timer related code below then setTimeout works again. + // NB. there are 706 lines of setup code that add a bunch of apis to the global window + // scope. Figure out if I need to include all of them. For example, starmelon does not need + // to perform http calls right now, but I eventually want to. + final_script.push_str("const { setTimeout } = globalThis.__bootstrap.timers;"); + final_script.push_str("Deno.core.setMacrotaskCallback(globalThis.__bootstrap.timers.handleTimerMacrotask);\n"); + final_script.push_str("globalThis.setTimeout = setTimeout;"); - final_script.push_str("\n\n"); - final_script.push_str(&format!("var worker = Elm.{}.init();\n", gen_module_name)); - // add a short cut for invoking the function so I don't have to traverse so many object - // lookups using the rust v8 API. - match input_type { - None => { - final_script.push_str( - "globalThis.runOnInput = function() { worker.ports.onInput.send(null)) };\n", - ); + final_script.push_str(&format!("var worker = Elm.{}.init();\n", &gen_module_name)); + // add a short cut for invoking the function so I don't have to traverse so many object + // lookups using the rust v8 API. + match input_type { + None => { + final_script.push_str( + "globalThis.runOnInput = function() { worker.ports.onInput.send(null)) };\n", + ); + } + Some(InputType::Value) => { + final_script + .push_str("globalThis.runOnInput = function(data) { worker.ports.onInput.send(JSON.parse(data)) };\n"); + } + Some(InputType::String) => { + final_script.push_str( + "globalThis.runOnInput = function(data) { worker.ports.onInput.send(data) };", + ); + } + Some(InputType::Bytes) => { + final_script.push_str( + r#" + globalThis.runOnInput = function(data) { + const dv = new DataView(data.buffer) + worker.ports.onInput.send(dv) + }; + "#, + ); + } } - Some(InputType::Value) => { - final_script - .push_str("globalThis.runOnInput = function(data) { worker.ports.onInput.send(JSON.parse(data)) };\n"); - } - Some(InputType::String) => { - final_script.push_str( - "globalThis.runOnInput = function(data) { worker.ports.onInput.send(data) };", - ); - } - Some(InputType::Bytes) => { - final_script.push_str( - r#" -globalThis.runOnInput = function(data) { - const dv = new DataView(data.buffer) - worker.ports.onInput.send(dv) -}; -"#, - ); - } - } - match output_type { - OutputType::Value => { - final_script.push_str( - r#" - worker.ports.onOutput.subscribe(function(output){ - if (output.ctor === "Ok") { - const json = JSON.stringify(output.a); - Deno.core.opSync('op_starmelon_string_output', output); - } else { - Deno.core.opSync('op_starmelon_problem', output.a); - } - }); - "#, - ); + match output_type { + OutputType::Value => { + final_script.push_str( + r#" + worker.ports.onOutput.subscribe(function(output){ + if (output.ctor === "Ok") { + const json = JSON.stringify(output.a); + Deno.core.opSync('op_starmelon_string_output', output); + } else { + Deno.core.opSync('op_starmelon_problem', output.a); + } + }); + "#, + ); + } + OutputType::Bytes => { + final_script.push_str( + r#" + // Elm will send a DataView + worker.ports.onOutput.subscribe(function(output){ + if (output.ctor === "Ok") { + const ui8 = new Uint8Array(output.a.buffer); + Deno.core.opSync('op_starmelon_bytes_output', ui8); + } else { + Deno.core.opSync('op_starmelon_problem', output.a); + } + }); + "#, + ); + } + OutputType::String | OutputType::Html => { + final_script.push_str( + r#" + worker.ports.onOutput.subscribe(function(output){ + if (output.ctor === "Ok") { + Deno.core.opSync('op_starmelon_string_output', output.a); + } else { + Deno.core.opSync('op_starmelon_problem', output.a); + } + }); + "#, + ); + } } - OutputType::Bytes => { - final_script.push_str( - r#" - // Elm will send a DataView - worker.ports.onOutput.subscribe(function(output){ - if (output.ctor === "Ok") { - const ui8 = new Uint8Array(output.a.buffer); - Deno.core.opSync('op_starmelon_bytes_output', ui8); - } else { - Deno.core.opSync('op_starmelon_problem', output.a); - } - }); - "#, - ); - } - OutputType::String | OutputType::Html => { - final_script.push_str( - r#" - worker.ports.onOutput.subscribe(function(output){ - if (output.ctor === "Ok") { - Deno.core.opSync('op_starmelon_string_output', output.a); - } else { - Deno.core.opSync('op_starmelon_problem', output.a); - } - }); - "#, - ); - } - } + + final_script + })(); let mut final_file = generator_dir.join("bin").join(&gen_module_name); final_file.set_extension("js"); @@ -715,10 +739,14 @@ fn setup_generator_project(verbosity: u64, elm_project_dir: PathBuf) -> Result

, S: AsRef>( our_temp_dir: P, package: S, ) -> Result<(), Problem> { + info_span!("elm_install").enter(); let mut command = Command::new("elm"); command @@ -812,6 +841,7 @@ mod runtime { use deno_runtime::permissions::Permissions; use deno_runtime::worker::MainWorker; use deno_runtime::worker::WorkerOptions; + use deno_runtime::BootstrapOptions; use deno_web::BlobStore; use rusty_v8 as v8; use std::cell::RefCell; @@ -831,29 +861,37 @@ mod runtime { let create_web_worker_cb = Arc::new(|_| { todo!("Web workers are not supported in the example"); }); + let options = WorkerOptions { - apply_source_maps: false, - args: vec![], - debug_flag: false, - unstable: false, - ca_data: None, + bootstrap: BootstrapOptions { + args: vec![], + apply_source_maps: false, + cpu_count: 1, + debug_flag: false, + enable_testing_features: false, + location: None, + no_color: false, + runtime_version: "0.29.0".to_string(), + ts_version: "2.0.0".to_string(), + unstable: false, + }, + extensions: vec![], + unsafely_ignore_certificate_errors: None, + root_cert_store: None, user_agent: "hello_runtime".to_string(), seed: None, - js_error_create_fn: None, + module_loader, create_web_worker_cb, + js_error_create_fn: None, maybe_inspector_server: None, should_break_on_first_statement: false, - module_loader, - runtime_version: "x".to_string(), - ts_version: "x".to_string(), - no_color: false, get_error_class_fn: Some(&get_error_class_name), - location: None, origin_storage_dir: None, blob_store: BlobStore::default(), broadcast_channel: InMemoryBroadcastChannel::default(), shared_array_buffer_store: None, + compiled_wasm_module_store: None, }; let main_module = deno_core::resolve_path(path_str)?; @@ -861,8 +899,8 @@ mod runtime { // let main_module = resolve_url(SPECIFIER)?; let permissions = Permissions::allow_all(); - let mut worker = MainWorker::from_options(main_module.clone(), permissions, &options); - worker.bootstrap(&options); + let mut worker = MainWorker::from_options(main_module.clone(), permissions, options); + //worker.bootstrap(&options); Ok((worker, main_module)) } @@ -874,7 +912,7 @@ mod runtime { ) -> Result<(), InterpreterError> { let wait_for_inspector = false; // step 10 load the module into our v8 isolate - worker.execute_module(&main_module).await?; + worker.execute_main_module(&main_module).await?; worker.run_event_loop(wait_for_inspector).await?; { @@ -950,7 +988,6 @@ mod runtime { impl ModuleLoader for EmbeddedModuleLoader { fn resolve( &self, - _op_state: Rc>, specifier: &str, _referrer: &str, _is_main: bool, @@ -969,10 +1006,9 @@ mod runtime { fn load( &self, - _op_state: Rc>, module_specifier: &ModuleSpecifier, _maybe_referrer: Option, - _is_dynamic: bool, + _is_dyn_import: bool, ) -> Pin> { let module_specifier = module_specifier.clone(); //let is_data_uri = get_source_from_data_url(&module_specifier).ok(); diff --git a/src/reporting.rs b/src/reporting.rs index d28bb11..c67b7ac 100644 --- a/src/reporting.rs +++ b/src/reporting.rs @@ -177,7 +177,16 @@ impl CompilerError { impl InterpreterError { pub fn to_doc(&self) -> Doc { - Doc::text("interpreter error") + let mut title = "COMPILER ERROR"; + use InterpreterError::*; + let message = match self { + Setup(data_error) => Doc::text(format!("{:?}", data_error)), + EventLoop(event_loop_error) => Doc::text(format!("{:?}", event_loop_error)), + AllocationFailed => Doc::text("allocation failed"), + ReferenceError => Doc::text("reference error"), + }; + + vcat([to_message_bar(title, ""), Doc::text(""), message]) } } diff --git a/starmelon-binary.do b/starmelon-binary.do index 43a6053..b1f9d66 100644 --- a/starmelon-binary.do +++ b/starmelon-binary.do @@ -1,4 +1,4 @@ -if test -f ../../target/debug/gen-css-selectors; then +if test -f ../../target/release/starmelon; then redo-ifchange always-rebuild ls -al ../../../target/release/starmelon | redo-stamp else;