refactor: some modernization while computer was in shop

This commit is contained in:
YetAnotherMinion 2021-10-23 05:28:49 +01:00 committed by nobody
commit 80fe2c6d83
Signed by: GrocerPublishAgent
GPG key ID: D460CD54A9E3AB86
4 changed files with 157 additions and 113 deletions

View file

@ -3,8 +3,6 @@ name = "starmelon"
version = "0.1.0" version = "0.1.0"
edition = "2018" 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 # 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 # 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 # 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 = [] } serde_json = { version ="1.0", features = [] }
structopt = { version = "0.3" } structopt = { version = "0.3" }
elm-project-utils = { path = "../../../infra/rust-elm-project-utils" } 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 # 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 # same versions as other projects in our cargo workspace. Multiple different
# versions of rust_v8 seem to break its build script. # 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"] } tokio = { version = "1.6", features = ["full"] }
deno_core = "0.95.0" deno_core = "0.103.0"
deno_web = "0.44" deno_web = "0.52"
rusty_v8 = "0.25.3" rusty_v8 = "0.32"
futures = "0.3.15" futures = "0.3.15"
serde_v8 = "0.8" serde_v8 = "0.15"

View file

@ -16,12 +16,18 @@ use std::time::Instant;
use structopt::StructOpt; use structopt::StructOpt;
use elm_project_utils::ChecksumConstraint; use elm_project_utils::ChecksumConstraint;
use tokio; use tokio;
use tracing::{span, info_span};
use crate::timings::Timings;
mod reporting; mod reporting;
mod fixture; mod fixture;
mod timings;
fn main() { fn main() {
let args = Arguments::from_args(); let args = Arguments::from_args();
let span_subscriber = Timings::new();
tracing::subscriber::set_global_default(span_subscriber).unwrap();
match args { match args {
// Arguments::Make { file, debug, output } => { // Arguments::Make { file, debug, output } => {
@ -33,6 +39,8 @@ fn main() {
output, output,
verbosity, verbosity,
} => { } => {
let run_program = info_span!("run_program_span");
run_program.enter();
let start = Instant::now(); let start = Instant::now();
if let Err(problem) = exec(file, debug, function, input, output, verbosity) { if let Err(problem) = exec(file, debug, function, input, output, verbosity) {
eprintln!( eprintln!(
@ -63,6 +71,7 @@ fn exec(
output: Option<PathBuf>, output: Option<PathBuf>,
verbosity: u64, verbosity: u64,
) -> Result<(), Problem> { ) -> 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 // Our first elm make call is where we build the users program. There is a pretty good chance
// this won't work. // this won't work.
let mut command = Command::new("elm"); 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 // `"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 // will have to do some extra book keeping to make sure the buffer space is big enough
// for the replacement code. // for the replacement code.
let mut final_script = data let mut final_script = ( || {
.replace("'REPLACE_ME_WITH_JSON_STRINGIFY'", "JSON.stringify(x)") let mut final_script = data
.replace( .replace("'REPLACE_ME_WITH_JSON_STRINGIFY'", "JSON.stringify(x)")
"$elm$json$Json$Decode$fail('REPLACE_ME_WITH_BYTES_DECODER');", //.replace("setTimeout", "(function(x, y) { globalThis.__bootstrap.timers.setTimeout(x, y)})")
r#" _Json_decodePrim(function(value) { .replace(
return (typeof value === 'object' && value instanceof DataView) "$elm$json$Json$Decode$fail('REPLACE_ME_WITH_BYTES_DECODER');",
? $elm$core$Result$Ok(value) r#" _Json_decodePrim(function(value) {
: _Json_expecting('a DataView', value); return (typeof value === 'object' && value instanceof DataView)
});"#, ? $elm$core$Result$Ok(value)
) : _Json_expecting('a DataView', value);
.replace(";}(this));", ";}(globalThis));"); });"#,
)
.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));
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
// add a short cut for invoking the function so I don't have to traverse so many object // lookups using the rust v8 API.
// lookups using the rust v8 API. match input_type {
match input_type { None => {
None => { final_script.push_str(
final_script.push_str( "globalThis.runOnInput = function() { worker.ports.onInput.send(null)) };\n",
"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 { match output_type {
OutputType::Value => { OutputType::Value => {
final_script.push_str( final_script.push_str(
r#" r#"
worker.ports.onOutput.subscribe(function(output){ worker.ports.onOutput.subscribe(function(output){
if (output.ctor === "Ok") { if (output.ctor === "Ok") {
const json = JSON.stringify(output.a); const json = JSON.stringify(output.a);
Deno.core.opSync('op_starmelon_string_output', output); Deno.core.opSync('op_starmelon_string_output', output);
} else { } else {
Deno.core.opSync('op_starmelon_problem', output.a); 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( final_script
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);
}
});
"#,
);
}
}
let mut final_file = generator_dir.join("bin").join(&gen_module_name); let mut final_file = generator_dir.join("bin").join(&gen_module_name);
final_file.set_extension("js"); final_file.set_extension("js");
@ -715,10 +739,14 @@ fn setup_generator_project(verbosity: u64, elm_project_dir: PathBuf) -> Result<P
new_src_directories.push(dir.to_string_lossy().to_string()); new_src_directories.push(dir.to_string_lossy().to_string());
} }
std::fs::create_dir(&source_dir) if !source_dir.exists() {
.map_err(|io_err| CompilerError::WriteOutputFailed(io_err, source_dir.clone()))?; std::fs::create_dir(&source_dir)
std::fs::create_dir(&bin_dir) .map_err(|io_err| CompilerError::WriteOutputFailed(io_err, source_dir.clone()))?;
.map_err(|io_err| CompilerError::WriteOutputFailed(io_err, bin_dir.clone()))?; }
if !bin_dir.exists() {
std::fs::create_dir(&bin_dir)
.map_err(|io_err| CompilerError::WriteOutputFailed(io_err, bin_dir.clone()))?;
}
new_src_directories.push( new_src_directories.push(
canonicalize(our_temp_dir.join("src")) canonicalize(our_temp_dir.join("src"))
@ -763,6 +791,7 @@ fn elm_install<P: AsRef<Path>, S: AsRef<str>>(
our_temp_dir: P, our_temp_dir: P,
package: S, package: S,
) -> Result<(), Problem> { ) -> Result<(), Problem> {
info_span!("elm_install").enter();
let mut command = Command::new("elm"); let mut command = Command::new("elm");
command command
@ -812,6 +841,7 @@ mod runtime {
use deno_runtime::permissions::Permissions; use deno_runtime::permissions::Permissions;
use deno_runtime::worker::MainWorker; use deno_runtime::worker::MainWorker;
use deno_runtime::worker::WorkerOptions; use deno_runtime::worker::WorkerOptions;
use deno_runtime::BootstrapOptions;
use deno_web::BlobStore; use deno_web::BlobStore;
use rusty_v8 as v8; use rusty_v8 as v8;
use std::cell::RefCell; use std::cell::RefCell;
@ -831,29 +861,37 @@ mod runtime {
let create_web_worker_cb = Arc::new(|_| { let create_web_worker_cb = Arc::new(|_| {
todo!("Web workers are not supported in the example"); todo!("Web workers are not supported in the example");
}); });
let options = WorkerOptions { let options = WorkerOptions {
apply_source_maps: false, bootstrap: BootstrapOptions {
args: vec![], args: vec![],
debug_flag: false, apply_source_maps: false,
unstable: false, cpu_count: 1,
ca_data: None, 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(), user_agent: "hello_runtime".to_string(),
seed: None, seed: None,
js_error_create_fn: None, module_loader,
create_web_worker_cb, create_web_worker_cb,
js_error_create_fn: None,
maybe_inspector_server: None, maybe_inspector_server: None,
should_break_on_first_statement: false, 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), get_error_class_fn: Some(&get_error_class_name),
location: None,
origin_storage_dir: None, origin_storage_dir: None,
blob_store: BlobStore::default(), blob_store: BlobStore::default(),
broadcast_channel: InMemoryBroadcastChannel::default(), broadcast_channel: InMemoryBroadcastChannel::default(),
shared_array_buffer_store: None, shared_array_buffer_store: None,
compiled_wasm_module_store: None,
}; };
let main_module = deno_core::resolve_path(path_str)?; let main_module = deno_core::resolve_path(path_str)?;
@ -861,8 +899,8 @@ mod runtime {
// let main_module = resolve_url(SPECIFIER)?; // let main_module = resolve_url(SPECIFIER)?;
let permissions = Permissions::allow_all(); let permissions = Permissions::allow_all();
let mut worker = MainWorker::from_options(main_module.clone(), permissions, &options); let mut worker = MainWorker::from_options(main_module.clone(), permissions, options);
worker.bootstrap(&options); //worker.bootstrap(&options);
Ok((worker, main_module)) Ok((worker, main_module))
} }
@ -874,7 +912,7 @@ mod runtime {
) -> Result<(), InterpreterError> { ) -> Result<(), InterpreterError> {
let wait_for_inspector = false; let wait_for_inspector = false;
// step 10 load the module into our v8 isolate // 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?; worker.run_event_loop(wait_for_inspector).await?;
{ {
@ -950,7 +988,6 @@ mod runtime {
impl ModuleLoader for EmbeddedModuleLoader { impl ModuleLoader for EmbeddedModuleLoader {
fn resolve( fn resolve(
&self, &self,
_op_state: Rc<RefCell<OpState>>,
specifier: &str, specifier: &str,
_referrer: &str, _referrer: &str,
_is_main: bool, _is_main: bool,
@ -969,10 +1006,9 @@ mod runtime {
fn load( fn load(
&self, &self,
_op_state: Rc<RefCell<OpState>>,
module_specifier: &ModuleSpecifier, module_specifier: &ModuleSpecifier,
_maybe_referrer: Option<ModuleSpecifier>, _maybe_referrer: Option<ModuleSpecifier>,
_is_dynamic: bool, _is_dyn_import: bool,
) -> Pin<Box<deno_core::ModuleSourceFuture>> { ) -> Pin<Box<deno_core::ModuleSourceFuture>> {
let module_specifier = module_specifier.clone(); let module_specifier = module_specifier.clone();
//let is_data_uri = get_source_from_data_url(&module_specifier).ok(); //let is_data_uri = get_source_from_data_url(&module_specifier).ok();

View file

@ -177,7 +177,16 @@ impl CompilerError {
impl InterpreterError { impl InterpreterError {
pub fn to_doc(&self) -> Doc { 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])
} }
} }

View file

@ -1,4 +1,4 @@
if test -f ../../target/debug/gen-css-selectors; then if test -f ../../target/release/starmelon; then
redo-ifchange always-rebuild redo-ifchange always-rebuild
ls -al ../../../target/release/starmelon | redo-stamp ls -al ../../../target/release/starmelon | redo-stamp
else; else;