Skip to content

Commit

Permalink
Added window! and document! macros, refactored JsValue typing
Browse files Browse the repository at this point in the history
  • Loading branch information
sfisol committed Mar 29, 2024
1 parent 195565a commit 2cd7f76
Show file tree
Hide file tree
Showing 30 changed files with 733 additions and 318 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

### Added

* `window!` and `document!` macro to allow invoking simple JavaScript commands
* `Driver::plains` method to allow responding with plaintext pages
* In `css!` macro there is now possibility to reference a class created by another `css!` using `[]` brackets
* Enums nad newtypes support in `AutoJsJson`
Expand Down
7 changes: 3 additions & 4 deletions Makefile.toml
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ script = [

# JavaScript dev builds

[tasks.build-js-run-ts]
[tasks.internal-run-ts]
private = true
command = "npx"
args = [ "-p", "typescript", "tsc",
"--strict",
Expand All @@ -86,10 +87,8 @@ args = [ "-p", "typescript", "tsc",
]

[tasks.build-js]
dependencies = [ "build-js-run-ts" ]
dependencies = [ "internal-run-ts" ]
script = [
"rm -Rf crates/vertigo-cli/src/serve/js_value",
"cp -R crates/vertigo/src/driver_module/js_value crates/vertigo-cli/src/serve/js_value",
"npx rollup crates/vertigo/src/driver_module/src_js_build/index.js --file crates/vertigo/src/driver_module/wasm_run.js",
"rm -rf crates/vertigo/src/driver_module/src_js_build",
]
Expand Down
67 changes: 67 additions & 0 deletions crates/vertigo-macro/src/api_access.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use syn::{spanned::Spanned, Expr, Lit};

pub(crate) fn api_access_inner(root: &str, input: TokenStream) -> TokenStream {
let input: TokenStream2 = input.into();

use syn::parse::Parser;
let data = syn::punctuated::Punctuated::<syn::Expr, syn::Token![,]>::parse_terminated
.parse2(input)
.unwrap();

let mut param_iter = data.into_iter();
let first_param = param_iter.next().unwrap();
let first_param_span = first_param.span();

let inner = match first_param {
Expr::Lit(expr_lit) => {
match expr_lit.lit {
Lit::Str(param_lit) => {
let param_repr = param_lit.token().to_string();
let param_str = param_repr.trim_matches('"');
if let Some(func_name) = param_str.strip_suffix("()") {
// Function call
let mut args = vec![];

for arg in param_iter {
args.push(quote! { vertigo::JsValue::from(#arg) })
}

quote! { .call(#func_name, vec![ #(#args,)* ]) }
} else {
// Property get
if let Some(arg) = param_iter.next() {
diagnostic!(
arg.span(),
proc_macro_error::Level::Error,
"Properties don't accept arguments, missing () in func name?"
)
.span_suggestion(first_param_span, "hint", format!("Try `{}()`", param_str))
.emit()
}

quote! { .get(#param_str) }
}
}
_ => {
emit_error!(expr_lit.span(), "Expected literal string as first parameter (property or function name) (1)");
quote! {}
}
}
}
_ => {
emit_error!(first_param_span, "Expected literal string as first parameter (property or function name) (2)");
quote! {}
}
};

quote! {
vertigo::get_driver()
.dom_access()
.root(#root)
#inner
.fetch()
}.into()
}
16 changes: 10 additions & 6 deletions crates/vertigo-macro/src/bind.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
use std::collections::HashSet;
use std::collections::VecDeque;

use proc_macro::{Span, TokenStream, TokenTree};
use proc_macro2::Ident as Ident2;
use proc_macro::{Span, TokenStream};
use proc_macro2::Ident;
use proc_macro2::TokenStream as TokenStream2;
use proc_macro2::TokenTree;
use quote::quote;
use syn::__private::quote::format_ident;

pub(crate) fn bind_inner(input: TokenStream) -> Result<TokenStream, String> {
let input: TokenStream2 = input.into();
let tokens = input.into_iter().collect::<Vec<_>>();

let TokensParamsBody {
Expand All @@ -18,7 +20,7 @@ pub(crate) fn bind_inner(input: TokenStream) -> Result<TokenStream, String> {

let mut clone_stm = Vec::<TokenStream2>::new();
let first_pipe = is_first_pipe_char(body.as_slice());
let body: TokenStream2 = body.iter().cloned().collect::<TokenStream>().into();
let body = body.iter().cloned().collect::<TokenStream2>();

let mut idents_seen = HashSet::new();

Expand All @@ -31,7 +33,7 @@ pub(crate) fn bind_inner(input: TokenStream) -> Result<TokenStream, String> {
emit_error!(item.last().unwrap().span(), "Conflicting variable name: {}", param_name);
}

let item_expr: TokenStream2 = item.iter().cloned().collect::<TokenStream>().into();
let item_expr = item.iter().cloned().collect::<TokenStream2>();

clone_stm.push(quote! {
let #param_name = #item_expr.clone();
Expand Down Expand Up @@ -60,6 +62,7 @@ pub(crate) fn bind_inner(input: TokenStream) -> Result<TokenStream, String> {
}

pub(crate) fn bind_spawn_inner(input: TokenStream) -> Result<TokenStream, String> {
let input: TokenStream2 = input.into();
let tokens = input.into_iter().collect::<Vec<_>>();

let TokensParamsBody {
Expand All @@ -86,6 +89,7 @@ pub(crate) fn bind_spawn_inner(input: TokenStream) -> Result<TokenStream, String
}

pub(crate) fn bind_rc_inner(input: TokenStream) -> Result<TokenStream, String> {
let input: TokenStream2 = input.into();
let tokens = input.into_iter().collect::<Vec<_>>();

let TokensParamsBody {
Expand Down Expand Up @@ -134,7 +138,7 @@ fn is_char(token: &TokenTree, char: char) -> bool {
}
}

fn find_param_name(params: &[TokenTree]) -> Option<Ident2> {
fn find_param_name(params: &[TokenTree]) -> Option<Ident> {
if let Some(last) = params.last() {
if let TokenTree::Ident(value) = &last {
Some(format_ident!("{}", value.to_string()))
Expand Down Expand Up @@ -255,7 +259,7 @@ fn split_params_and_body(tokens: &[TokenTree]) -> Result<TokensParamsBody, Strin
}

fn convert_tokens_to_stream(tokens: &[TokenTree]) -> TokenStream2 {
tokens.iter().cloned().collect::<TokenStream>().into()
tokens.iter().cloned().collect::<TokenStream2>()
}

fn get_type(tokens: &[TokenTree]) -> Result<&[TokenTree], String> {
Expand Down
14 changes: 14 additions & 0 deletions crates/vertigo-macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ extern crate pest_derive;
#[macro_use]
extern crate proc_macro_error;

mod api_access;
mod bind;
mod component;
mod css_parser;
Expand All @@ -18,6 +19,7 @@ use proc_macro::{Span, TokenStream};
use quote::quote;

use crate::{
api_access::api_access_inner,
bind::{bind_inner, bind_rc_inner, bind_spawn_inner},
component::component_inner,
css_parser::generate_css_string,
Expand Down Expand Up @@ -125,6 +127,18 @@ pub fn component(_attr: TokenStream, input: TokenStream) -> TokenStream {
component_inner(input)
}

#[proc_macro]
#[proc_macro_error]
pub fn window(input: TokenStream) -> TokenStream {
api_access_inner("window", input)
}

#[proc_macro]
#[proc_macro_error]
pub fn document(input: TokenStream) -> TokenStream {
api_access_inner("document", input)
}

fn convert_to_tokens(input: Result<TokenStream, String>) -> TokenStream {
match input {
Ok(body) => body,
Expand Down
1 change: 0 additions & 1 deletion crates/vertigo/src/driver_module/api/api_dom_access.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,6 @@ impl DomAccess {
}
}

#[must_use]
pub fn fetch(self) -> JsValue {
let memory = JsValue::List(self.builder).to_snapshot();
let (ptr, size) = memory.get_ptr_and_size();
Expand Down
18 changes: 12 additions & 6 deletions crates/vertigo/src/driver_module/api/api_import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,12 +264,18 @@ impl ApiImport {
.call("now", vec![])
.fetch();

if let JsValue::I64(time) = result {
time as u64 as InstantType
} else {
self.panic_message
.show(format!("api.instant_now -> incorrect result {result:?}"));
0_u64
match result {
JsValue::I64(time) => {
time as u64 as InstantType
}
JsValue::F64(time) => {
time as u64 as InstantType
}
_ => {
self.panic_message
.show(format!("api.instant_now -> incorrect result {result:?}"));
0_u64
}
}
}

Expand Down
30 changes: 12 additions & 18 deletions crates/vertigo/src/driver_module/js_value/js_json_struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ const LIST_COUNT: u32 = 4;
const OBJECT_COUNT: u32 = 2;

enum JsJsonConst {
True,
False,
Null,

String,
Number,
List,
Object,
True = 1,
False = 2,
Null = 3,

String = 4,
Number = 5,
List = 6,
Object = 7,
}

impl JsJsonConst {
Expand All @@ -37,15 +37,7 @@ impl JsJsonConst {

impl From<JsJsonConst> for u8 {
fn from(value: JsJsonConst) -> Self {
match value {
JsJsonConst::True => 1,
JsJsonConst::False => 2,
JsJsonConst::Null => 3,
JsJsonConst::String => 4,
JsJsonConst::Number => 5,
JsJsonConst::List => 6,
JsJsonConst::Object => 7,
}
value as u8
}
}

Expand All @@ -54,7 +46,9 @@ impl From<JsJsonConst> for u8 {
/*
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number#number_encoding
The JavaScript Number type is a double-precision 64-bit binary format IEEE 754 value, like double in Java or C#. This means it can represent fractional values, but there are some limits to the stored number's magnitude and precision. Very briefly, an IEEE 754 double-precision number uses 64 bits to represent 3 parts:
The JavaScript Number type is a double-precision 64-bit binary format IEEE 754 value, like double in Java or C#.
This means it can represent fractional values, but there are some limits to the stored number's magnitude
and precision. Very briefly, an IEEE 754 double-precision number uses 64 bits to represent 3 parts:
1 bit for the sign (positive or negative)
11 bits for the exponent (-1022 to 1023)
Expand Down
Loading

0 comments on commit 2cd7f76

Please sign in to comment.