mirror of
https://github.com/voltrevo/ValueScript.git
synced 2026-04-18 03:00:27 -04:00
Reorganize using workspaces
This commit is contained in:
36
Cargo.lock
generated
36
Cargo.lock
generated
@@ -1446,6 +1446,16 @@ dependencies = [
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "swc_demo"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"swc",
|
||||
"swc_common",
|
||||
"swc_ecma_ast",
|
||||
"swc_ecma_parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "swc_ecma_ast"
|
||||
version = "0.76.0"
|
||||
@@ -2147,10 +2157,9 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "value_script"
|
||||
name = "valuescript_compiler"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"console_error_panic_hook",
|
||||
"queues",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -2159,6 +2168,21 @@ dependencies = [
|
||||
"swc_common",
|
||||
"swc_ecma_ast",
|
||||
"swc_ecma_parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "valuescript_vm"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "valuescript_wasm"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"console_error_panic_hook",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"valuescript_compiler",
|
||||
"valuescript_vm",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-test",
|
||||
"wee_alloc",
|
||||
@@ -2176,6 +2200,14 @@ version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
|
||||
[[package]]
|
||||
name = "vstc"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"valuescript_compiler",
|
||||
"valuescript_vm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.10.2+wasi-snapshot-preview1"
|
||||
|
||||
48
Cargo.toml
48
Cargo.toml
@@ -1,41 +1,9 @@
|
||||
[package]
|
||||
name = "value_script"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
[workspace]
|
||||
|
||||
[[bin]]
|
||||
name = "vstc"
|
||||
path = "src/vstc/main.rs"
|
||||
test = false
|
||||
bench = false
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[dependencies]
|
||||
queues = "1.0.2"
|
||||
serde = "1.0"
|
||||
serde_json = "1.0"
|
||||
swc_common = { version = "0.17.22", features=["tty-emitter"] }
|
||||
swc_ecma_parser = "0.102.2"
|
||||
swc = "0.168.3"
|
||||
swc_ecma_ast = "0.76.0"
|
||||
swc_atoms = "0.2"
|
||||
|
||||
# wasm-related
|
||||
|
||||
wasm-bindgen = "0.2.63"
|
||||
|
||||
# The `console_error_panic_hook` crate provides better debugging of panics by
|
||||
# logging them with `console.error`. This is great for development, but requires
|
||||
# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
|
||||
# code size when deploying.
|
||||
console_error_panic_hook = { version = "0.1.6", optional = true }
|
||||
|
||||
# `wee_alloc` is a tiny allocator for wasm that is only ~1K in code size
|
||||
# compared to the default allocator's ~10K. It is slower than the default
|
||||
# allocator, however.
|
||||
wee_alloc = { version = "0.4.5", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
wasm-bindgen-test = "0.3.13"
|
||||
members = [
|
||||
"valuescript_vm",
|
||||
"valuescript_compiler",
|
||||
"valuescript_wasm",
|
||||
"vstc",
|
||||
"swc_demo",
|
||||
]
|
||||
|
||||
21
src/lib.rs
21
src/lib.rs
@@ -1,21 +0,0 @@
|
||||
mod vstc;
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
|
||||
// allocator.
|
||||
#[cfg(feature = "wee_alloc")]
|
||||
#[global_allocator]
|
||||
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn compile(source: &str) -> String {
|
||||
let output = vstc::compile::compile(source);
|
||||
return serde_json::to_string(&output).expect("Failed json serialization");
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn run(source: &str) -> String {
|
||||
let run_result = vstc::run::run(source);
|
||||
return serde_json::to_string(&run_result).expect("Failed json serialization");
|
||||
}
|
||||
42
src/main.rs
42
src/main.rs
@@ -1,42 +0,0 @@
|
||||
use std::{path::Path, sync::Arc};
|
||||
use swc_ecma_ast::{EsVersion};
|
||||
use swc_common::{
|
||||
errors::{ColorConfig, Handler},
|
||||
SourceMap, FileName,
|
||||
};
|
||||
use swc_ecma_parser::{TsConfig, Syntax};
|
||||
|
||||
fn main() {
|
||||
let cm = Arc::<SourceMap>::default();
|
||||
let handler = Handler::with_tty_emitter(
|
||||
ColorConfig::Auto,
|
||||
true,
|
||||
false,
|
||||
Some(cm.clone()),
|
||||
);
|
||||
let c = swc::Compiler::new(cm.clone());
|
||||
// let fm = cm
|
||||
// .load_file(Path::new("foo.js"))
|
||||
// .expect("failed to load file");
|
||||
let fm = cm.new_source_file(
|
||||
FileName::Custom("test.js".into()),
|
||||
"
|
||||
function foo(x: number) {
|
||||
if (x < 3) {
|
||||
return 'lt3';
|
||||
}
|
||||
|
||||
return 'nlt3';
|
||||
}
|
||||
".into(),
|
||||
);
|
||||
let result = c.parse_js(
|
||||
fm,
|
||||
&handler,
|
||||
EsVersion::Es2020,
|
||||
Syntax::Typescript(TsConfig::default()),
|
||||
swc::config::IsModule::Bool(true),
|
||||
None,
|
||||
);
|
||||
dbg!(result);
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
mod assemble;
|
||||
mod capture_finder;
|
||||
pub mod compile;
|
||||
pub mod diagnostic;
|
||||
mod expression_compiler;
|
||||
mod function_compiler;
|
||||
mod name_allocator;
|
||||
pub mod run;
|
||||
mod scope;
|
||||
pub mod scope_analysis;
|
||||
pub mod virtual_machine;
|
||||
12
swc_demo/Cargo.toml
Normal file
12
swc_demo/Cargo.toml
Normal file
@@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "swc_demo"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
swc_common = { version = "0.17.22", features=["tty-emitter"] }
|
||||
swc_ecma_parser = "0.102.2"
|
||||
swc = "0.168.3"
|
||||
swc_ecma_ast = "0.76.0"
|
||||
41
swc_demo/src/main.rs
Normal file
41
swc_demo/src/main.rs
Normal file
@@ -0,0 +1,41 @@
|
||||
use std::sync::Arc;
|
||||
use swc_common::{
|
||||
errors::{ColorConfig, Handler},
|
||||
FileName, SourceMap,
|
||||
};
|
||||
use swc_ecma_ast::EsVersion;
|
||||
use swc_ecma_parser::{Syntax, TsConfig};
|
||||
|
||||
fn main() {
|
||||
let cm = Arc::<SourceMap>::default();
|
||||
let handler = Handler::with_tty_emitter(ColorConfig::Auto, true, false, Some(cm.clone()));
|
||||
let c = swc::Compiler::new(cm.clone());
|
||||
// let fm = cm
|
||||
// .load_file(Path::new("foo.js"))
|
||||
// .expect("failed to load file");
|
||||
let fm = cm.new_source_file(
|
||||
FileName::Custom("test.js".into()),
|
||||
"
|
||||
function foo(x: number) {
|
||||
if (x < 3) {
|
||||
return 'lt3';
|
||||
}
|
||||
|
||||
return 'nlt3';
|
||||
}
|
||||
"
|
||||
.into(),
|
||||
);
|
||||
let result = c.parse_js(
|
||||
fm,
|
||||
&handler,
|
||||
EsVersion::Es2020,
|
||||
Syntax::Typescript(TsConfig::default()),
|
||||
swc::config::IsModule::Bool(true),
|
||||
None,
|
||||
);
|
||||
|
||||
dbg!(&result);
|
||||
|
||||
drop(result);
|
||||
}
|
||||
16
valuescript_compiler/Cargo.toml
Normal file
16
valuescript_compiler/Cargo.toml
Normal file
@@ -0,0 +1,16 @@
|
||||
[package]
|
||||
name = "valuescript_compiler"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
serde = "1.0"
|
||||
serde_json = "1.0"
|
||||
swc_atoms = "0.2"
|
||||
swc_common = { version = "0.17.22", features=["tty-emitter"] }
|
||||
swc_ecma_parser = "0.102.2"
|
||||
swc = "0.168.3"
|
||||
swc_ecma_ast = "0.76.0"
|
||||
queues = "1.0.2"
|
||||
@@ -1,48 +1,7 @@
|
||||
use std::rc::Rc;
|
||||
use std::process::exit;
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
use std::str::FromStr;
|
||||
|
||||
pub fn command(args: &Vec<String>) {
|
||||
if args.len() != 3 {
|
||||
println!("ERROR: Unrecognized command\n");
|
||||
show_help();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if args[2] == "-h" || args[2] == "--help" {
|
||||
show_help();
|
||||
return;
|
||||
}
|
||||
|
||||
let read_result = std::fs::read_to_string(&args[2]);
|
||||
|
||||
if read_result.is_err() {
|
||||
println!("Failed to read file {}", args[2]);
|
||||
return;
|
||||
}
|
||||
|
||||
let content = read_result.expect("");
|
||||
let output_filename = "out.vsb";
|
||||
let bytecode = assemble(&content);
|
||||
|
||||
let write_result = std::fs::write(output_filename, &*bytecode);
|
||||
|
||||
if write_result.is_err() {
|
||||
println!("Failed to write file {}", output_filename);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
fn show_help() {
|
||||
println!("vstc assemble");
|
||||
println!("");
|
||||
println!("Convert ValueScript assembly to bytecode");
|
||||
println!("");
|
||||
println!("USAGE:");
|
||||
println!(" vstc assemble <file>");
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct LocationMap {
|
||||
references: HashMap<String, Vec<usize>>,
|
||||
@@ -55,8 +14,9 @@ trait LocationMapper {
|
||||
}
|
||||
|
||||
impl LocationMapper for LocationMap {
|
||||
fn add_unresolved(&mut self, name: &String, output: &mut Vec<u8>){
|
||||
self.references
|
||||
fn add_unresolved(&mut self, name: &String, output: &mut Vec<u8>) {
|
||||
self
|
||||
.references
|
||||
.entry(name.clone())
|
||||
.or_default()
|
||||
.push(output.len());
|
||||
@@ -70,11 +30,7 @@ impl LocationMapper for LocationMap {
|
||||
let location_optional = self.found_locations.get(name);
|
||||
|
||||
if location_optional.is_none() {
|
||||
std::panic!(
|
||||
"Unresolved reference to {} at {}",
|
||||
name,
|
||||
ref_locations[0],
|
||||
);
|
||||
std::panic!("Unresolved reference to {} at {}", name, ref_locations[0],);
|
||||
}
|
||||
|
||||
let location = location_optional.unwrap();
|
||||
@@ -146,9 +102,11 @@ impl<'a> Assembler<'a> {
|
||||
fn parse_optional_whitespace(&mut self) {
|
||||
loop {
|
||||
match self.pos.peek() {
|
||||
Some(' ') => {},
|
||||
Some('\n') => {},
|
||||
_ => { return; }
|
||||
Some(' ') => {}
|
||||
Some('\n') => {}
|
||||
_ => {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
self.pos.next();
|
||||
@@ -158,7 +116,10 @@ impl<'a> Assembler<'a> {
|
||||
fn assemble_definition(&mut self) {
|
||||
self.parse_exact("@");
|
||||
let def_name = self.parse_identifier();
|
||||
self.definitions_map.found_locations.insert(def_name, self.output.len());
|
||||
self
|
||||
.definitions_map
|
||||
.found_locations
|
||||
.insert(def_name, self.output.len());
|
||||
self.parse_optional_whitespace();
|
||||
self.parse_exact("=");
|
||||
self.parse_optional_whitespace();
|
||||
@@ -257,7 +218,9 @@ impl<'a> Assembler<'a> {
|
||||
let mut res = "".to_string();
|
||||
|
||||
let leading_char = match pos.next() {
|
||||
None => { return None; },
|
||||
None => {
|
||||
return None;
|
||||
}
|
||||
Some(c) => c,
|
||||
};
|
||||
|
||||
@@ -269,7 +232,9 @@ impl<'a> Assembler<'a> {
|
||||
|
||||
loop {
|
||||
match pos.next() {
|
||||
None => { break; }
|
||||
None => {
|
||||
break;
|
||||
}
|
||||
Some(c) => {
|
||||
if !is_identifier_char(c) {
|
||||
break;
|
||||
@@ -382,7 +347,9 @@ impl<'a> Assembler<'a> {
|
||||
if next == ")" {
|
||||
self.fn_data.register_count_pos = self.output.len();
|
||||
self.output.push(0xff);
|
||||
self.output.push((self.fn_data.register_map.len() - 3) as u8); // TODO: Handle >255
|
||||
self
|
||||
.output
|
||||
.push((self.fn_data.register_map.len() - 3) as u8); // TODO: Handle >255
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -393,7 +360,10 @@ impl<'a> Assembler<'a> {
|
||||
let param_name = self.parse_identifier();
|
||||
|
||||
if self.fn_data.register_map.contains_key(param_name.as_str()) {
|
||||
std::panic!("Unexpected duplicate parameter name at {}", self.get_pos_index());
|
||||
std::panic!(
|
||||
"Unexpected duplicate parameter name at {}",
|
||||
self.get_pos_index()
|
||||
);
|
||||
}
|
||||
|
||||
self.get_register_index(param_name.as_str());
|
||||
@@ -404,7 +374,9 @@ impl<'a> Assembler<'a> {
|
||||
if next == ")" {
|
||||
self.fn_data.register_count_pos = self.output.len();
|
||||
self.output.push(0xff);
|
||||
self.output.push((self.fn_data.register_map.len() - 3) as u8); // TODO: Handle >255
|
||||
self
|
||||
.output
|
||||
.push((self.fn_data.register_map.len() - 3) as u8); // TODO: Handle >255
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -415,7 +387,10 @@ impl<'a> Assembler<'a> {
|
||||
loop {
|
||||
self.parse_optional_whitespace();
|
||||
|
||||
let c = *self.pos.peek().expect("Expected instruction, label, or end of function");
|
||||
let c = *self
|
||||
.pos
|
||||
.peek()
|
||||
.expect("Expected instruction, label, or end of function");
|
||||
|
||||
if c == '}' {
|
||||
self.output.push(Instruction::End as u8);
|
||||
@@ -459,7 +434,7 @@ impl<'a> Assembler<'a> {
|
||||
let instr = self.parse_instruction_word();
|
||||
|
||||
self.output.push(instr.clone() as u8);
|
||||
|
||||
|
||||
for arg in get_instruction_layout(instr) {
|
||||
match arg {
|
||||
InstructionArg::Value => self.assemble_value(),
|
||||
@@ -477,49 +452,44 @@ impl<'a> Assembler<'a> {
|
||||
Some('%') => {
|
||||
self.output.push(ValueType::Register as u8);
|
||||
self.assemble_register();
|
||||
},
|
||||
}
|
||||
Some('@') => {
|
||||
self.parse_exact("@");
|
||||
self.output.push(ValueType::Pointer as u8);
|
||||
let definition_name = self.parse_identifier();
|
||||
self.definitions_map.add_unresolved(&definition_name, &mut self.output);
|
||||
},
|
||||
self
|
||||
.definitions_map
|
||||
.add_unresolved(&definition_name, &mut self.output);
|
||||
}
|
||||
Some('$') => {
|
||||
self.parse_exact("$");
|
||||
self.output.push(ValueType::Builtin as u8);
|
||||
self.assemble_builtin();
|
||||
},
|
||||
}
|
||||
Some('[') => {
|
||||
self.assemble_array();
|
||||
},
|
||||
Some('-' | '.' | '0' ..= '9') => {
|
||||
}
|
||||
Some('-' | '.' | '0'..='9') => {
|
||||
self.assemble_number();
|
||||
},
|
||||
}
|
||||
Some('"') => {
|
||||
self.assemble_string();
|
||||
},
|
||||
}
|
||||
Some('{') => {
|
||||
self.assemble_object();
|
||||
},
|
||||
}
|
||||
Some(ref_c) => {
|
||||
let c = *ref_c;
|
||||
|
||||
let parsed = self.parse_one_of(&[
|
||||
"void",
|
||||
"undefined",
|
||||
"null",
|
||||
"false",
|
||||
"true",
|
||||
"",
|
||||
]);
|
||||
|
||||
let parsed = self.parse_one_of(&["void", "undefined", "null", "false", "true", ""]);
|
||||
|
||||
match parsed.as_str() {
|
||||
"void" => self.output.push(ValueType::Void as u8),
|
||||
"undefined" => self.output.push(ValueType::Undefined as u8),
|
||||
"null" => self.output.push(ValueType::Null as u8),
|
||||
"false" => self.output.push(ValueType::False as u8),
|
||||
"true" => self.output.push(ValueType::True as u8),
|
||||
|
||||
|
||||
// TODO: Finish implementing the different values
|
||||
_ => std::panic!(
|
||||
"Unimplemented value type or unexpected character {} at {}",
|
||||
@@ -527,7 +497,7 @@ impl<'a> Assembler<'a> {
|
||||
self.get_pos_index(),
|
||||
),
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -546,8 +516,8 @@ impl<'a> Assembler<'a> {
|
||||
self.pos.next();
|
||||
self.output.push(ValueType::End as u8);
|
||||
break;
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.assemble_value();
|
||||
@@ -610,17 +580,21 @@ impl<'a> Assembler<'a> {
|
||||
|
||||
advance_chars(&mut self.pos, label_name.len() + 1);
|
||||
|
||||
self.fn_data.labels_map.found_locations.insert(
|
||||
label_name,
|
||||
self.output.len(),
|
||||
);
|
||||
self
|
||||
.fn_data
|
||||
.labels_map
|
||||
.found_locations
|
||||
.insert(label_name, self.output.len());
|
||||
}
|
||||
|
||||
fn assemble_label_read(&mut self) {
|
||||
self.parse_optional_whitespace();
|
||||
self.parse_exact(":");
|
||||
let label_name = self.parse_identifier();
|
||||
self.fn_data.labels_map.add_unresolved(&label_name, &mut self.output);
|
||||
self
|
||||
.fn_data
|
||||
.labels_map
|
||||
.add_unresolved(&label_name, &mut self.output);
|
||||
}
|
||||
|
||||
fn assemble_number(&mut self) {
|
||||
@@ -628,10 +602,12 @@ impl<'a> Assembler<'a> {
|
||||
|
||||
loop {
|
||||
match self.pos.peek() {
|
||||
Some('-' | '.' | 'e' | '0' ..= '9') => {
|
||||
Some('-' | '.' | 'e' | '0'..='9') => {
|
||||
num_string.push(self.pos.next().unwrap());
|
||||
}
|
||||
_ => { break; }
|
||||
_ => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -686,7 +662,9 @@ impl<'a> Assembler<'a> {
|
||||
self.parse_exact("@");
|
||||
self.output.push(ValueType::Pointer as u8);
|
||||
let definition_name = self.parse_identifier();
|
||||
self.definitions_map.add_unresolved(&definition_name, &mut self.output);
|
||||
self
|
||||
.definitions_map
|
||||
.add_unresolved(&definition_name, &mut self.output);
|
||||
} else if c == '}' {
|
||||
self.output.push(ValueType::End as u8);
|
||||
self.pos.next();
|
||||
@@ -721,7 +699,10 @@ impl<'a> Assembler<'a> {
|
||||
if get_result.is_none() {
|
||||
// TODO: Support >255 registers
|
||||
result = (self.fn_data.register_map.len() - 1) as u8;
|
||||
self.fn_data.register_map.insert(register_name.to_string(), result);
|
||||
self
|
||||
.fn_data
|
||||
.register_map
|
||||
.insert(register_name.to_string(), result);
|
||||
} else {
|
||||
result = *get_result.unwrap();
|
||||
}
|
||||
@@ -766,8 +747,7 @@ pub fn assemble(content: &str) -> Rc<Vec<u8>> {
|
||||
return Rc::new(assembler.output);
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Clone)]
|
||||
#[derive(Debug, Clone)]
|
||||
enum Instruction {
|
||||
End = 0x00,
|
||||
Mov = 0x01,
|
||||
@@ -874,20 +854,11 @@ fn get_instruction_layout(instruction: Instruction) -> Vec<InstructionArg> {
|
||||
}
|
||||
|
||||
fn is_leading_identifier_char(c: char) -> bool {
|
||||
return
|
||||
c == '_' ||
|
||||
('a' <= c && c <= 'z') ||
|
||||
('A' <= c && c <= 'Z')
|
||||
;
|
||||
return c == '_' || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
|
||||
}
|
||||
|
||||
fn is_identifier_char(c: char) -> bool {
|
||||
return
|
||||
c == '_' ||
|
||||
('0' <= c && c <= '9') ||
|
||||
('a' <= c && c <= 'z') ||
|
||||
('A' <= c && c <= 'Z')
|
||||
;
|
||||
return c == '_' || ('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
|
||||
}
|
||||
|
||||
enum ValueType {
|
||||
@@ -1,7 +1,4 @@
|
||||
use std::cell::RefCell;
|
||||
use std::fs::File;
|
||||
use std::io::prelude::*;
|
||||
use std::process::exit;
|
||||
use std::rc::Rc;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
@@ -10,53 +7,13 @@ use swc_common::{errors::Handler, FileName, SourceMap, Spanned};
|
||||
use swc_ecma_ast::EsVersion;
|
||||
use swc_ecma_parser::{Syntax, TsConfig};
|
||||
|
||||
use super::diagnostic::{handle_diagnostics_cli, Diagnostic, DiagnosticLevel};
|
||||
use super::diagnostic::{Diagnostic, DiagnosticLevel};
|
||||
use super::expression_compiler::{string_literal, CompiledExpression, ExpressionCompiler};
|
||||
use super::function_compiler::{FunctionCompiler, Functionish};
|
||||
use super::name_allocator::NameAllocator;
|
||||
use super::scope::{init_std_scope, MappedName, Scope, ScopeTrait};
|
||||
use super::scope_analysis::ScopeAnalysis;
|
||||
|
||||
pub fn command(args: &Vec<String>) {
|
||||
if args.len() != 3 {
|
||||
println!("ERROR: Unrecognized command\n");
|
||||
show_help();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
let source = std::fs::read_to_string(&args[2]).expect("Failed to read file");
|
||||
let (program_optional, parse_diagnostics) = parse(&source);
|
||||
|
||||
handle_diagnostics_cli(&args[2], &parse_diagnostics);
|
||||
|
||||
let program = match program_optional {
|
||||
Some(program) => program,
|
||||
None => exit(1),
|
||||
};
|
||||
|
||||
let compiler_output = compile_program(&program);
|
||||
|
||||
handle_diagnostics_cli(&args[2], &compiler_output.diagnostics);
|
||||
|
||||
let mut file = File::create("out.vsm").expect("Couldn't create out.vsm");
|
||||
|
||||
for line in compiler_output.assembly {
|
||||
file
|
||||
.write_all(line.as_bytes())
|
||||
.expect("Failed to write line");
|
||||
file.write_all(b"\n").expect("Failed to write line");
|
||||
}
|
||||
}
|
||||
|
||||
fn show_help() {
|
||||
println!("vstc compile");
|
||||
println!("");
|
||||
println!("Compile ValueScript");
|
||||
println!("");
|
||||
println!("USAGE:");
|
||||
println!(" vstc compile <entry point>");
|
||||
}
|
||||
|
||||
struct DiagnosticCollector {
|
||||
diagnostics: Arc<Mutex<Vec<Diagnostic>>>,
|
||||
}
|
||||
@@ -52,50 +52,3 @@ impl Diagnostic {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_diagnostics_cli(file_path: &String, diagnostics: &Vec<Diagnostic>) {
|
||||
let mut has_error = false;
|
||||
|
||||
let text = std::fs::read_to_string(file_path).unwrap();
|
||||
|
||||
for diagnostic in diagnostics {
|
||||
let (line, col) = pos_to_line_col(&text, diagnostic.span.lo.0);
|
||||
|
||||
println!(
|
||||
"{}:{}:{}: {}: {}",
|
||||
file_path, line, col, diagnostic.level, diagnostic.message
|
||||
);
|
||||
|
||||
match diagnostic.level {
|
||||
DiagnosticLevel::Error | DiagnosticLevel::InternalError => {
|
||||
has_error = true;
|
||||
}
|
||||
DiagnosticLevel::Lint => {}
|
||||
DiagnosticLevel::CompilerDebug => {}
|
||||
}
|
||||
}
|
||||
|
||||
if has_error {
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
fn pos_to_line_col(text: &String, pos: u32) -> (u32, u32) {
|
||||
let mut line = 1u32;
|
||||
let mut col = 1u32;
|
||||
|
||||
for (i, c) in text.chars().enumerate() {
|
||||
if i as u32 == pos {
|
||||
break;
|
||||
}
|
||||
|
||||
if c == '\n' {
|
||||
line += 1;
|
||||
col = 1;
|
||||
} else {
|
||||
col += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return (line, col);
|
||||
}
|
||||
14
valuescript_compiler/src/lib.rs
Normal file
14
valuescript_compiler/src/lib.rs
Normal file
@@ -0,0 +1,14 @@
|
||||
mod assemble;
|
||||
mod capture_finder;
|
||||
mod compile;
|
||||
mod diagnostic;
|
||||
mod expression_compiler;
|
||||
mod function_compiler;
|
||||
mod name_allocator;
|
||||
mod scope;
|
||||
mod scope_analysis;
|
||||
|
||||
pub use assemble::assemble;
|
||||
pub use compile::compile;
|
||||
pub use diagnostic::Diagnostic;
|
||||
pub use diagnostic::DiagnosticLevel;
|
||||
@@ -11,9 +11,14 @@ pub enum NameId {
|
||||
Builtin(Builtin),
|
||||
}
|
||||
|
||||
// TODO: Make use of these in the next phase of the compiler, remove the
|
||||
// allow(dead_code) attributes
|
||||
#[derive(Clone)]
|
||||
pub struct Capture {
|
||||
#[allow(dead_code)]
|
||||
ref_: swc_common::Span,
|
||||
|
||||
#[allow(dead_code)]
|
||||
captor_id: OwnerId,
|
||||
}
|
||||
|
||||
8
valuescript_vm/Cargo.toml
Normal file
8
valuescript_vm/Cargo.toml
Normal file
@@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "valuescript_vm"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
@@ -1,22 +1,22 @@
|
||||
mod vs_value;
|
||||
mod vs_function;
|
||||
mod vs_pointer;
|
||||
mod operations;
|
||||
mod bytecode_decoder;
|
||||
mod virtual_machine;
|
||||
mod instruction;
|
||||
mod vs_object;
|
||||
mod vs_array;
|
||||
mod native_function;
|
||||
mod builtins;
|
||||
mod math;
|
||||
mod vs_class;
|
||||
mod bytecode_stack_frame;
|
||||
mod stack_frame;
|
||||
mod first_stack_frame;
|
||||
mod array_higher_functions;
|
||||
mod native_frame_function;
|
||||
mod builtins;
|
||||
mod bytecode_decoder;
|
||||
mod bytecode_stack_frame;
|
||||
mod debug;
|
||||
mod first_stack_frame;
|
||||
mod instruction;
|
||||
mod math;
|
||||
mod native_frame_function;
|
||||
mod native_function;
|
||||
mod operations;
|
||||
mod stack_frame;
|
||||
mod virtual_machine;
|
||||
mod vs_array;
|
||||
mod vs_class;
|
||||
mod vs_function;
|
||||
mod vs_object;
|
||||
mod vs_pointer;
|
||||
mod vs_value;
|
||||
|
||||
pub use virtual_machine::VirtualMachine;
|
||||
pub use vs_value::ValTrait;
|
||||
@@ -1,9 +1,9 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use super::vs_value::{Val, ValTrait, LoadFunctionResult};
|
||||
use super::bytecode_decoder::BytecodeDecoder;
|
||||
use super::stack_frame::{StackFrame, FrameStepResult};
|
||||
use super::first_stack_frame::FirstStackFrame;
|
||||
use super::stack_frame::{FrameStepResult, StackFrame};
|
||||
use super::vs_value::{LoadFunctionResult, Val, ValTrait};
|
||||
|
||||
pub struct VirtualMachine {
|
||||
pub frame: StackFrame,
|
||||
@@ -50,14 +50,14 @@ impl VirtualMachine {
|
||||
|
||||
pub fn step(&mut self) {
|
||||
match self.frame.step() {
|
||||
FrameStepResult::Continue => {},
|
||||
FrameStepResult::Continue => {}
|
||||
FrameStepResult::Pop(call_result) => {
|
||||
self.pop();
|
||||
self.frame.apply_call_result(call_result);
|
||||
},
|
||||
}
|
||||
FrameStepResult::Push(new_frame) => {
|
||||
self.push(new_frame);
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
use std::rc::Rc;
|
||||
use std::str::FromStr;
|
||||
|
||||
use super::vs_function::VsFunction;
|
||||
use super::vs_object::VsObject;
|
||||
use super::vs_array::VsArray;
|
||||
use super::vs_class::VsClass;
|
||||
use super::operations::{op_sub, op_submov};
|
||||
use super::stack_frame::StackFrame;
|
||||
use super::vs_array::VsArray;
|
||||
use super::vs_class::VsClass;
|
||||
use super::vs_function::VsFunction;
|
||||
use super::vs_object::VsObject;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Val {
|
||||
@@ -111,14 +111,16 @@ impl ValTrait for Val {
|
||||
res += ",";
|
||||
|
||||
match val.typeof_() {
|
||||
VsType::Undefined => {},
|
||||
_ => { res += &val.val_to_string(); },
|
||||
VsType::Undefined => {}
|
||||
_ => {
|
||||
res += &val.val_to_string();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
},
|
||||
}
|
||||
Object(_) => "[object Object]".to_string(),
|
||||
Function(_) => "[function]".to_string(),
|
||||
Class(_) => "[class]".to_string(),
|
||||
@@ -188,7 +190,7 @@ impl ValTrait for Val {
|
||||
Class(_) => false,
|
||||
Static(val) => val.is_primitive(), // TODO: false?
|
||||
Custom(val) => val.is_primitive(),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn to_primitive(&self) -> Val {
|
||||
@@ -333,7 +335,7 @@ impl ValTrait for Val {
|
||||
|
||||
res
|
||||
}
|
||||
},
|
||||
}
|
||||
Val::Object(object) => {
|
||||
if object.string_map.len() == 0 {
|
||||
return "{}".into();
|
||||
@@ -357,7 +359,7 @@ impl ValTrait for Val {
|
||||
res += "}";
|
||||
|
||||
res
|
||||
},
|
||||
}
|
||||
Val::Function(_) => "() => { [unavailable] }".to_string(),
|
||||
Val::Class(_) => "class { [unavailable] }".to_string(),
|
||||
Val::Static(val) => val.codify(),
|
||||
@@ -395,15 +397,17 @@ impl std::fmt::Display for Val {
|
||||
}
|
||||
|
||||
write!(f, " ]")
|
||||
},
|
||||
}
|
||||
Val::Object(object) => {
|
||||
if object.string_map.len() == 0 {
|
||||
return f.write_str("{}");
|
||||
}
|
||||
|
||||
match f.write_str("{ ") {
|
||||
Ok(_) => {},
|
||||
Err(e) => { return Err(e); },
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
|
||||
let mut first = true;
|
||||
@@ -419,7 +423,7 @@ impl std::fmt::Display for Val {
|
||||
}
|
||||
|
||||
f.write_str(" }")
|
||||
},
|
||||
}
|
||||
Val::Function(_) => write!(f, "\x1b[36m[Function]\x1b[39m"),
|
||||
Val::Class(_) => write!(f, "\x1b[36m[Class]\x1b[39m"),
|
||||
|
||||
@@ -432,7 +436,7 @@ impl std::fmt::Display for Val {
|
||||
|
||||
fn number_to_index(x: f64) -> Option<usize> {
|
||||
if x < 0_f64 || x != x.floor() {
|
||||
return None
|
||||
return None;
|
||||
}
|
||||
|
||||
return Some(x as usize);
|
||||
@@ -451,8 +455,12 @@ fn stringify_string(str: &String) -> String {
|
||||
};
|
||||
|
||||
match escape_seq {
|
||||
Some(seq) => { res += seq; },
|
||||
None => { res.push(c); }
|
||||
Some(seq) => {
|
||||
res += seq;
|
||||
}
|
||||
None => {
|
||||
res.push(c);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
33
valuescript_wasm/Cargo.toml
Normal file
33
valuescript_wasm/Cargo.toml
Normal file
@@ -0,0 +1,33 @@
|
||||
[package]
|
||||
name = "valuescript_wasm"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
serde = "1.0"
|
||||
serde_json = "1.0"
|
||||
valuescript_compiler = { path = "../valuescript_compiler" }
|
||||
valuescript_vm = { path = "../valuescript_vm" }
|
||||
|
||||
# wasm-related
|
||||
|
||||
wasm-bindgen = "0.2.63"
|
||||
|
||||
# The `console_error_panic_hook` crate provides better debugging of panics by
|
||||
# logging them with `console.error`. This is great for development, but requires
|
||||
# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
|
||||
# code size when deploying.
|
||||
console_error_panic_hook = { version = "0.1.6", optional = true }
|
||||
|
||||
# `wee_alloc` is a tiny allocator for wasm that is only ~1K in code size
|
||||
# compared to the default allocator's ~10K. It is slower than the default
|
||||
# allocator, however.
|
||||
wee_alloc = { version = "0.4.5", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
wasm-bindgen-test = "0.3.13"
|
||||
59
valuescript_wasm/src/lib.rs
Normal file
59
valuescript_wasm/src/lib.rs
Normal file
@@ -0,0 +1,59 @@
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
use valuescript_compiler::DiagnosticLevel;
|
||||
use valuescript_vm::ValTrait;
|
||||
|
||||
// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
|
||||
// allocator.
|
||||
#[cfg(feature = "wee_alloc")]
|
||||
#[global_allocator]
|
||||
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
|
||||
|
||||
#[derive(serde::Serialize)]
|
||||
struct RunResult {
|
||||
diagnostics: Vec<valuescript_compiler::Diagnostic>,
|
||||
output: Result<String, String>,
|
||||
}
|
||||
|
||||
fn run_to_result(source: &str) -> RunResult {
|
||||
let compiler_output = valuescript_compiler::compile(source);
|
||||
|
||||
let mut have_compiler_errors = false;
|
||||
|
||||
for diagnostic in &compiler_output.diagnostics {
|
||||
match diagnostic.level {
|
||||
DiagnosticLevel::Error => have_compiler_errors = true,
|
||||
DiagnosticLevel::InternalError => have_compiler_errors = true,
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
if have_compiler_errors {
|
||||
return RunResult {
|
||||
diagnostics: compiler_output.diagnostics,
|
||||
output: Err("Compile failed".into()),
|
||||
};
|
||||
}
|
||||
|
||||
let bytecode = valuescript_compiler::assemble(compiler_output.assembly.join("\n").as_str());
|
||||
|
||||
let mut vm = valuescript_vm::VirtualMachine::new();
|
||||
let result = vm.run(&bytecode, &[]);
|
||||
|
||||
return RunResult {
|
||||
diagnostics: compiler_output.diagnostics,
|
||||
output: Ok(result.codify()),
|
||||
};
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn compile(source: &str) -> String {
|
||||
let output = valuescript_compiler::compile(source);
|
||||
return serde_json::to_string(&output).expect("Failed json serialization");
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn run(source: &str) -> String {
|
||||
let result = run_to_result(source);
|
||||
return serde_json::to_string(&result).expect("Failed json serialization");
|
||||
}
|
||||
10
vstc/Cargo.toml
Normal file
10
vstc/Cargo.toml
Normal file
@@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "vstc"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
valuescript_compiler = { path = "../valuescript_compiler" }
|
||||
valuescript_vm = { path = "../valuescript_vm" }
|
||||
43
vstc/src/assemble_command.rs
Normal file
43
vstc/src/assemble_command.rs
Normal file
@@ -0,0 +1,43 @@
|
||||
use std::process::exit;
|
||||
|
||||
use valuescript_compiler::assemble;
|
||||
|
||||
pub fn assemble_command(args: &Vec<String>) {
|
||||
if args.len() != 3 {
|
||||
println!("ERROR: Unrecognized command\n");
|
||||
show_help();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if args[2] == "-h" || args[2] == "--help" {
|
||||
show_help();
|
||||
return;
|
||||
}
|
||||
|
||||
let read_result = std::fs::read_to_string(&args[2]);
|
||||
|
||||
if read_result.is_err() {
|
||||
println!("Failed to read file {}", args[2]);
|
||||
return;
|
||||
}
|
||||
|
||||
let content = read_result.expect("");
|
||||
let output_filename = "out.vsb";
|
||||
let bytecode = assemble(&content);
|
||||
|
||||
let write_result = std::fs::write(output_filename, &*bytecode);
|
||||
|
||||
if write_result.is_err() {
|
||||
println!("Failed to write file {}", output_filename);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
fn show_help() {
|
||||
println!("vstc assemble");
|
||||
println!("");
|
||||
println!("Convert ValueScript assembly to bytecode");
|
||||
println!("");
|
||||
println!("USAGE:");
|
||||
println!(" vstc assemble <file>");
|
||||
}
|
||||
37
vstc/src/compile_command.rs
Normal file
37
vstc/src/compile_command.rs
Normal file
@@ -0,0 +1,37 @@
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::process::exit;
|
||||
|
||||
use super::handle_diagnostics_cli::handle_diagnostics_cli;
|
||||
use valuescript_compiler::compile;
|
||||
|
||||
pub fn compile_command(args: &Vec<String>) {
|
||||
if args.len() != 3 {
|
||||
println!("ERROR: Unrecognized command\n");
|
||||
show_help();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
let source = std::fs::read_to_string(&args[2]).expect("Failed to read file");
|
||||
let compiler_output = compile(&source);
|
||||
|
||||
handle_diagnostics_cli(&args[2], &compiler_output.diagnostics);
|
||||
|
||||
let mut file = File::create("out.vsm").expect("Couldn't create out.vsm");
|
||||
|
||||
for line in compiler_output.assembly {
|
||||
file
|
||||
.write_all(line.as_bytes())
|
||||
.expect("Failed to write line");
|
||||
file.write_all(b"\n").expect("Failed to write line");
|
||||
}
|
||||
}
|
||||
|
||||
fn show_help() {
|
||||
println!("vstc compile");
|
||||
println!("");
|
||||
println!("Compile ValueScript");
|
||||
println!("");
|
||||
println!("USAGE:");
|
||||
println!(" vstc compile <entry point>");
|
||||
}
|
||||
48
vstc/src/handle_diagnostics_cli.rs
Normal file
48
vstc/src/handle_diagnostics_cli.rs
Normal file
@@ -0,0 +1,48 @@
|
||||
use valuescript_compiler::{Diagnostic, DiagnosticLevel};
|
||||
|
||||
pub fn handle_diagnostics_cli(file_path: &String, diagnostics: &Vec<Diagnostic>) {
|
||||
let mut has_error = false;
|
||||
|
||||
let text = std::fs::read_to_string(file_path).unwrap();
|
||||
|
||||
for diagnostic in diagnostics {
|
||||
let (line, col) = pos_to_line_col(&text, diagnostic.span.lo.0);
|
||||
|
||||
println!(
|
||||
"{}:{}:{}: {}: {}",
|
||||
file_path, line, col, diagnostic.level, diagnostic.message
|
||||
);
|
||||
|
||||
match diagnostic.level {
|
||||
DiagnosticLevel::Error | DiagnosticLevel::InternalError => {
|
||||
has_error = true;
|
||||
}
|
||||
DiagnosticLevel::Lint => {}
|
||||
DiagnosticLevel::CompilerDebug => {}
|
||||
}
|
||||
}
|
||||
|
||||
if has_error {
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
fn pos_to_line_col(text: &String, pos: u32) -> (u32, u32) {
|
||||
let mut line = 1u32;
|
||||
let mut col = 1u32;
|
||||
|
||||
for (i, c) in text.chars().enumerate() {
|
||||
if i as u32 == pos {
|
||||
break;
|
||||
}
|
||||
|
||||
if c == '\n' {
|
||||
line += 1;
|
||||
col = 1;
|
||||
} else {
|
||||
col += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return (line, col);
|
||||
}
|
||||
@@ -1,18 +1,15 @@
|
||||
mod assemble;
|
||||
mod capture_finder;
|
||||
mod compile;
|
||||
mod diagnostic;
|
||||
mod expression_compiler;
|
||||
mod function_compiler;
|
||||
mod name_allocator;
|
||||
mod run;
|
||||
mod scope;
|
||||
mod scope_analysis;
|
||||
mod virtual_machine;
|
||||
mod assemble_command;
|
||||
mod compile_command;
|
||||
mod handle_diagnostics_cli;
|
||||
mod run_command;
|
||||
|
||||
use std::env;
|
||||
use std::process::exit;
|
||||
|
||||
use assemble_command::assemble_command;
|
||||
use compile_command::compile_command;
|
||||
use run_command::run_command;
|
||||
|
||||
fn main() {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
|
||||
@@ -26,17 +23,17 @@ fn main() {
|
||||
}
|
||||
|
||||
if args.len() >= 2 && args[1] == "assemble" {
|
||||
assemble::command(&args);
|
||||
assemble_command(&args);
|
||||
return;
|
||||
}
|
||||
|
||||
if args.len() >= 2 && args[1] == "run" {
|
||||
run::command(&args);
|
||||
run_command(&args);
|
||||
return;
|
||||
}
|
||||
|
||||
if args.len() >= 2 && args[1] == "compile" {
|
||||
compile::command(&args);
|
||||
compile_command(&args);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,17 +1,12 @@
|
||||
use std::ffi::OsStr;
|
||||
use std::path::Path;
|
||||
use std::process::exit;
|
||||
use std::rc::Rc;
|
||||
use std::{ffi::OsStr, path::Path, process::exit};
|
||||
|
||||
use super::assemble::assemble;
|
||||
use super::compile::compile;
|
||||
use super::diagnostic::handle_diagnostics_cli;
|
||||
use super::diagnostic::Diagnostic;
|
||||
use super::diagnostic::DiagnosticLevel;
|
||||
use super::virtual_machine::ValTrait;
|
||||
use super::virtual_machine::VirtualMachine;
|
||||
use valuescript_compiler::{assemble, compile};
|
||||
use valuescript_vm::VirtualMachine;
|
||||
|
||||
pub fn command(args: &Vec<String>) {
|
||||
use super::handle_diagnostics_cli::handle_diagnostics_cli;
|
||||
|
||||
pub fn run_command(args: &Vec<String>) {
|
||||
if args.len() < 3 {
|
||||
println!("ERROR: Unrecognized command\n");
|
||||
show_help();
|
||||
@@ -45,43 +40,6 @@ pub fn command(args: &Vec<String>) {
|
||||
println!("{}", result);
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize)]
|
||||
pub struct RunResult {
|
||||
pub diagnostics: Vec<Diagnostic>,
|
||||
pub output: Result<String, String>,
|
||||
}
|
||||
|
||||
pub fn run(source: &str) -> RunResult {
|
||||
let compiler_output = compile(source);
|
||||
|
||||
let mut have_compiler_errors = false;
|
||||
|
||||
for diagnostic in &compiler_output.diagnostics {
|
||||
match diagnostic.level {
|
||||
DiagnosticLevel::Error => have_compiler_errors = true,
|
||||
DiagnosticLevel::InternalError => have_compiler_errors = true,
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
if have_compiler_errors {
|
||||
return RunResult {
|
||||
diagnostics: compiler_output.diagnostics,
|
||||
output: Err("Compile failed".into()),
|
||||
};
|
||||
}
|
||||
|
||||
let bytecode = assemble(compiler_output.assembly.join("\n").as_str());
|
||||
|
||||
let mut vm = VirtualMachine::new();
|
||||
let result = vm.run(&bytecode, &[]);
|
||||
|
||||
return RunResult {
|
||||
diagnostics: compiler_output.diagnostics,
|
||||
output: Ok(result.codify()),
|
||||
};
|
||||
}
|
||||
|
||||
enum RunFormat {
|
||||
TypeScript,
|
||||
Assembly,
|
||||
@@ -2,6 +2,9 @@ export async function initVslib() {
|
||||
// deno-lint-ignore no-explicit-any
|
||||
const wasm: Record<string, any> = (await WebAssembly.instantiateStreaming(
|
||||
fetch(`${location.origin}/value_script_bg.wasm`),
|
||||
{
|
||||
"./valuescript_wasm_bg.js": { __wbindgen_throw },
|
||||
},
|
||||
)).instance.exports;
|
||||
|
||||
let WASM_VECTOR_LEN = 0;
|
||||
@@ -128,6 +131,10 @@ export async function initVslib() {
|
||||
}
|
||||
}
|
||||
|
||||
function __wbindgen_throw(arg0: number, arg1: number) {
|
||||
throw new Error(getStringFromWasm0(arg0, arg1));
|
||||
}
|
||||
|
||||
return {
|
||||
compile,
|
||||
run,
|
||||
|
||||
Reference in New Issue
Block a user