refactor: some modernization while computer was in shop
This commit is contained in:
parent
5d770d0d0a
commit
80fe2c6d83
4 changed files with 157 additions and 113 deletions
13
Cargo.toml
13
Cargo.toml
|
|
@ -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"
|
||||||
|
|
|
||||||
244
src/main.rs
244
src/main.rs
|
|
@ -16,13 +16,19 @@ 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 } => {
|
||||||
Arguments::Exec {
|
Arguments::Exec {
|
||||||
|
|
@ -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");
|
final_script.push_str("\n\n");
|
||||||
final_script.push_str(&format!("var worker = Elm.{}.init();\n", gen_module_name));
|
// I think that when I set this script to be the main module, I am skipping the
|
||||||
// add a short cut for invoking the function so I don't have to traverse so many object
|
// deno/runtime/js/99_main.js script that sets up a bunch of global variables. If I
|
||||||
// lookups using the rust v8 API.
|
// manually add the timer related code below then setTimeout works again.
|
||||||
match input_type {
|
// NB. there are 706 lines of setup code that add a bunch of apis to the global window
|
||||||
None => {
|
// scope. Figure out if I need to include all of them. For example, starmelon does not need
|
||||||
final_script.push_str(
|
// to perform http calls right now, but I eventually want to.
|
||||||
"globalThis.runOnInput = function() { worker.ports.onInput.send(null)) };\n",
|
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;");
|
||||||
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 {
|
final_script.push_str(&format!("var worker = Elm.{}.init();\n", &gen_module_name));
|
||||||
OutputType::Value => {
|
// add a short cut for invoking the function so I don't have to traverse so many object
|
||||||
final_script.push_str(
|
// lookups using the rust v8 API.
|
||||||
r#"
|
match input_type {
|
||||||
worker.ports.onOutput.subscribe(function(output){
|
None => {
|
||||||
if (output.ctor === "Ok") {
|
final_script.push_str(
|
||||||
const json = JSON.stringify(output.a);
|
"globalThis.runOnInput = function() { worker.ports.onInput.send(null)) };\n",
|
||||||
Deno.core.opSync('op_starmelon_string_output', output);
|
);
|
||||||
} else {
|
}
|
||||||
Deno.core.opSync('op_starmelon_problem', output.a);
|
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)
|
||||||
|
};
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
OutputType::Bytes => {
|
|
||||||
final_script.push_str(
|
match output_type {
|
||||||
r#"
|
OutputType::Value => {
|
||||||
// Elm will send a DataView
|
final_script.push_str(
|
||||||
worker.ports.onOutput.subscribe(function(output){
|
r#"
|
||||||
if (output.ctor === "Ok") {
|
worker.ports.onOutput.subscribe(function(output){
|
||||||
const ui8 = new Uint8Array(output.a.buffer);
|
if (output.ctor === "Ok") {
|
||||||
Deno.core.opSync('op_starmelon_bytes_output', ui8);
|
const json = JSON.stringify(output.a);
|
||||||
} else {
|
Deno.core.opSync('op_starmelon_string_output', output);
|
||||||
Deno.core.opSync('op_starmelon_problem', 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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
OutputType::String | OutputType::Html => {
|
|
||||||
final_script.push_str(
|
final_script
|
||||||
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;
|
||||||
|
|
@ -832,28 +862,36 @@ mod runtime {
|
||||||
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();
|
||||||
|
|
|
||||||
|
|
@ -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])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue