diff --git a/.gitignore b/.gitignore index 6240da8..25d7ed5 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,5 @@ pnpm-debug.log* # macOS-specific files .DS_Store + +/wasm-pkg/ \ No newline at end of file diff --git a/package.json b/package.json index efc74e8..0116099 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "", + "name": "shulkerscript-webpage", "type": "module", "version": "0.0.1", "scripts": { @@ -7,7 +7,8 @@ "start": "astro dev", "build": "astro check && astro build", "preview": "astro preview", - "astro": "astro" + "astro": "astro", + "build-wasm": "cargo build -r && wasm-bindgen --target web --out-dir ./wasm-pkg --out-name shulkerscript ./wasm/target/wasm32-unknown-unknown/release/shulkerscript_wasm.wasm" }, "dependencies": { "@astrojs/check": "^0.5.10", diff --git a/src/content/docs/guides/syntax.md b/src/content/docs/guides/syntax.md index 43d7220..420b165 100644 --- a/src/content/docs/guides/syntax.md +++ b/src/content/docs/guides/syntax.md @@ -139,7 +139,7 @@ group { ## Run The `run` keyword is used to evaluate the following expression and include the resulting command in the output. ```shulkerscript -run "say Hello, world!" +run "say Hello, world!"; ``` :::tip diff --git a/wasm/.cargo/config.toml b/wasm/.cargo/config.toml new file mode 100644 index 0000000..65367ca --- /dev/null +++ b/wasm/.cargo/config.toml @@ -0,0 +1,3 @@ +[build] +target = "wasm32-unknown-unknown" +target-dir = "target" \ No newline at end of file diff --git a/wasm/.gitignore b/wasm/.gitignore new file mode 100644 index 0000000..1de5659 --- /dev/null +++ b/wasm/.gitignore @@ -0,0 +1 @@ +target \ No newline at end of file diff --git a/wasm/Cargo.toml b/wasm/Cargo.toml new file mode 100644 index 0000000..a257997 --- /dev/null +++ b/wasm/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "shulkerscript-wasm" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib"] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +wasm-bindgen = "0.2.92" +shulkerscript-lang ={ path = "../../shulkerscript-lang", default-features = false, features = ["shulkerbox", "serde", "wasm"]} +serde = "1.0" +serde-wasm-bindgen = "0.6.5" diff --git a/wasm/src/lib.rs b/wasm/src/lib.rs new file mode 100644 index 0000000..64b18d9 --- /dev/null +++ b/wasm/src/lib.rs @@ -0,0 +1,98 @@ +use std::{cell::Cell, fmt::Display, path::Path}; + +use shulkerscript_lang::{ + base::{file_provider::FileProvider, source_file::SourceFile, Error, Handler, Result}, + lexical::token_stream::TokenStream, + shulkerbox::{util::compile::CompileOptions, virtual_fs::VFolder}, + syntax::parser::Parser, + transpile::transpiler::Transpiler, +}; +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +extern "C" { + #[wasm_bindgen(js_namespace = console)] + fn log(s: &str); +} + +#[wasm_bindgen] +pub fn compile(source_text: &str) -> JsValue { + let datapack = internal_compile(source_text).ok().map(|folder| { + folder + .flatten() + .into_iter() + .map(|(path, file)| (path, file.clone())) + .collect::>() + }); + + serde_wasm_bindgen::to_value(&datapack).unwrap() +} + +struct DummyFileProvider { + content: String, +} +impl DummyFileProvider { + pub fn new(content: String) -> Self { + Self { content } + } +} +impl FileProvider for DummyFileProvider { + fn load(&self, _path: &Path) -> Option { + Some(self.content.clone()) + } +} + +struct Printer { + printed: Cell, +} +impl Handler for Printer { + fn receive(&self, error: E) { + log(&error.to_string()); + self.printed.set(true); + } +} +impl Printer { + /// Creates a new [`Printer`]. + fn new() -> Self { + Self { + printed: Cell::new(false), + } + } + + fn has_printed(&self) -> bool { + self.printed.get() + } +} + +fn internal_compile(source_text: &str) -> Result { + let file_provider = DummyFileProvider::new(source_text.to_string()); + + let source_file = SourceFile::load(&file_provider, Path::new("input.shu"))?; + + let printer = Printer::new(); + + let tokens = TokenStream::tokenize(&source_file, &printer); + + if printer.has_printed() { + return Err(Error::Other( + "An error occurred while tokenizing the source code.", + )); + } + + let mut parser = Parser::new(&tokens); + let program = parser.parse_program(&printer).ok_or(Error::Other( + "An error occured while parsing the source code.", + ))?; + + if printer.has_printed() { + return Err(Error::Other( + "An error occurred while parsing the source code.", + )); + } + + let mut transpiler = Transpiler::new("shulkerscript-pack", 27); + transpiler.transpile(&program, &printer)?; + let datapack = transpiler.into_datapack(); + + Ok(datapack.compile(&CompileOptions::default())) +}