Skip to content

Commit

Permalink
Merge pull request #1 from dtolnay/stable
Browse files Browse the repository at this point in the history
Stable support
  • Loading branch information
bodil committed Nov 19, 2018
2 parents c036b7c + 345b844 commit a1a4f8f
Show file tree
Hide file tree
Showing 21 changed files with 344 additions and 212 deletions.
14 changes: 10 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
language: rust
rust:
- nightly

cache:
directories:
- /home/travis/.cargo
script:
- cargo test

matrix:
include:
- rust: nightly
script: cargo test
- rust: beta
script: cargo check --manifest-path examples/wasm/Cargo.toml
- rust: stable
script: cargo check --manifest-path examples/wasm/Cargo.toml
7 changes: 0 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,6 @@
This crate provides the `html!` macro for building HTML documents inside your
Rust code using roughly [JSX] compatible syntax.

## Nightly Warning!

This crate currently needs nightly rustc, and in order to use it you'll need to
add `#![feature(proc_macro_hygiene)]` to the top of your crate. The compiler
will tell you to do this if you forget. When this feature stabilises, the crate
should work on stable rustc without issues.

## Quick Preview

```rust
Expand Down
1 change: 1 addition & 0 deletions examples/rocket/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![recursion_limit = "256"]
#![feature(proc_macro_hygiene, decl_macro)]

extern crate rocket;
Expand Down
2 changes: 1 addition & 1 deletion examples/wasm/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![feature(proc_macro_hygiene)]
#![recursion_limit = "256"]

extern crate stdweb;
extern crate typed_html;
Expand Down
4 changes: 4 additions & 0 deletions macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ proc-macro = true
[dependencies]
lalrpop-util = "0.16.1"
ansi_term = "0.11.0"
proc-macro2 = { version = "0.4.24", features = ["nightly"] }
proc-macro-hack = "0.5.2"
quote = "0.6.10"

[build-dependencies]
lalrpop = "0.16.1"
version_check = "0.1.5"
6 changes: 6 additions & 0 deletions macros/build.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
extern crate lalrpop;
extern crate version_check;

fn main() {
lalrpop::process_root().unwrap();

if version_check::is_nightly().unwrap_or(false) {
println!("cargo:rustc-cfg=can_join_spans");
println!("cargo:rustc-cfg=can_show_location_of_runtime_parse_error");
}
}
2 changes: 1 addition & 1 deletion macros/src/config.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use proc_macro::{Ident, Span, TokenStream};
use proc_macro2::{Ident, Span, TokenStream};

use map::StringyMap;

Expand Down
106 changes: 54 additions & 52 deletions macros/src/declare.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use proc_macro::{quote, Ident, Literal, Span, TokenStream, TokenTree};
use proc_macro2::{Ident, Literal, Span, TokenStream, TokenTree};
use quote::quote;

use config::{global_attrs, ATTR_EVENTS};
use error::ParseError;
use ident;
use lexer::{Lexer, Token};
use map::StringyMap;
use parser;
Expand Down Expand Up @@ -41,7 +43,7 @@ impl Declare {

fn attrs(&self) -> impl Iterator<Item = (TokenTree, TokenStream, TokenTree)> + '_ {
self.attrs.iter().map(|(key, value)| {
let attr_name: TokenTree = Ident::new_raw(&key.to_string(), key.span()).into();
let attr_name: TokenTree = ident::new_raw(&key.to_string(), key.span()).into();
let attr_type = value.clone();
let attr_str = Literal::string(&key.to_string()).into();
(attr_name, attr_type, attr_str)
Expand Down Expand Up @@ -73,13 +75,13 @@ impl Declare {
fn attr_struct(&self) -> TokenStream {
let mut body = TokenStream::new();
for (attr_name, attr_type, _) in self.attrs() {
body.extend(quote!( pub $attr_name: Option<$attr_type>, ));
body.extend(quote!( pub #attr_name: Option<#attr_type>, ));
}

let attr_type_name = self.attr_type_name();
quote!(
pub struct $attr_type_name {
$body
pub struct #attr_type_name {
#body
}
)
}
Expand All @@ -91,21 +93,21 @@ impl Declare {
let mut body = TokenStream::new();

for (child_name, child_type, _) in self.req_children() {
body.extend(quote!( pub $child_name: Box<$child_type<T>>, ));
body.extend(quote!( pub #child_name: Box<#child_type<T>>, ));
}

if let Some(child_constraint) = &self.opt_children {
let child_constraint = child_constraint.clone();
body.extend(quote!(pub children: Vec<Box<$child_constraint<T>>>,));
body.extend(quote!(pub children: Vec<Box<#child_constraint<T>>>,));
}

quote!(
pub struct $elem_name<T> where T: ::OutputType {
pub struct #elem_name<T> where T: ::OutputType {
phantom_output: std::marker::PhantomData<T>,
pub attrs: $attr_type_name,
pub attrs: #attr_type_name,
pub data_attributes: Vec<(&'static str, String)>,
pub events: ::events::Events<T>,
$body
#body
}
)
}
Expand All @@ -116,34 +118,34 @@ impl Declare {

let mut args = TokenStream::new();
for (child_name, child_type, _) in self.req_children() {
args.extend(quote!( $child_name: Box<$child_type<T>>, ));
args.extend(quote!( #child_name: Box<#child_type<T>>, ));
}

let mut attrs = TokenStream::new();
for (attr_name, _, _) in self.attrs() {
attrs.extend(quote!( $attr_name: None, ));
attrs.extend(quote!( #attr_name: None, ));
}

let mut body = TokenStream::new();
body.extend(quote!(
attrs: $attr_type_name { $attrs },
attrs: #attr_type_name { #attrs },
));
body.extend(quote!(data_attributes: Vec::new(),));

for (child_name, _, _) in self.req_children() {
body.extend(quote!( $child_name, ));
body.extend(quote!( #child_name, ));
}
if self.opt_children.is_some() {
body.extend(quote!(children: Vec::new()));
}

quote!(
impl<T> $elem_name<T> where T: ::OutputType {
pub fn new($args) -> Self {
$elem_name {
impl<T> #elem_name<T> where T: ::OutputType {
pub fn new(#args) -> Self {
#elem_name {
phantom_output: std::marker::PhantomData,
events: ::events::Events::default(),
$body
#body
}
}
}
Expand All @@ -155,7 +157,7 @@ impl Declare {
let mut req_children = TokenStream::new();
for (child_name, _, _) in self.req_children() {
req_children.extend(quote!(
children.push(self.$child_name.vnode());
children.push(self.#child_name.vnode());
));
}
let mut opt_children = TokenStream::new();
Expand All @@ -168,23 +170,23 @@ impl Declare {
let mut push_attrs = TokenStream::new();
for (attr_name, _, attr_str) in self.attrs() {
push_attrs.extend(quote!(
if let Some(ref value) = self.attrs.$attr_name {
attributes.push(($attr_str, value.to_string()));
if let Some(ref value) = self.attrs.#attr_name {
attributes.push((#attr_str, value.to_string()));
}
));
}

quote!(
let mut attributes = Vec::new();
$push_attrs
#push_attrs
attributes.extend(self.data_attributes.clone());

let mut children = Vec::new();
$req_children
$opt_children
#req_children
#opt_children

::dom::VNode::Element(::dom::VElement {
name: $elem_name,
name: #elem_name,
attributes,
events: &mut self.events,
children
Expand All @@ -196,9 +198,9 @@ impl Declare {
let elem_name = self.elem_name();
let vnode = self.impl_vnode();
quote!(
impl<T> ::dom::Node<T> for $elem_name<T> where T: ::OutputType {
impl<T> ::dom::Node<T> for #elem_name<T> where T: ::OutputType {
fn vnode(&'_ mut self) -> ::dom::VNode<'_, T> {
$vnode
#vnode
}
}
)
Expand All @@ -208,38 +210,38 @@ impl Declare {
let name: TokenTree = Literal::string(&self.name.to_string()).into();
let elem_name = self.elem_name();

let attrs: TokenStream = self.attrs().map(|(_, _, name)| quote!( $name, )).collect();
let attrs: TokenStream = self.attrs().map(|(_, _, name)| quote!( #name, )).collect();
let reqs: TokenStream = self
.req_children()
.map(|(_, _, name)| quote!( $name, ))
.map(|(_, _, name)| quote!( #name, ))
.collect();

let mut push_attrs = TokenStream::new();
for (attr_name, _, attr_str) in self.attrs() {
push_attrs.extend(quote!(
if let Some(ref value) = self.attrs.$attr_name {
out.push(($attr_str, value.to_string()));
if let Some(ref value) = self.attrs.#attr_name {
out.push((#attr_str, value.to_string()));
}
));
}

quote!(
impl<T> ::dom::Element<T> for $elem_name<T> where T: ::OutputType {
impl<T> ::dom::Element<T> for #elem_name<T> where T: ::OutputType {
fn name() -> &'static str {
$name
#name
}

fn attribute_names() -> &'static [&'static str] {
&[ $attrs ]
&[ #attrs ]
}

fn required_children() -> &'static [&'static str] {
&[ $reqs ]
&[ #reqs ]
}

fn attributes(&self) -> Vec<(&'static str, String)> {
let mut out = Vec::new();
$push_attrs
#push_attrs
for (key, value) in &self.data_attributes {
out.push((key, value.to_string()));
}
Expand All @@ -255,7 +257,7 @@ impl Declare {
for t in &self.traits {
let name = t.clone();
body.extend(quote!(
impl<T> $name<T> for $elem_name<T> where T: ::OutputType {}
impl<T> #name<T> for #elem_name<T> where T: ::OutputType {}
));
}
body
Expand All @@ -276,7 +278,7 @@ impl Declare {
let mut print_req_children = TokenStream::new();
for (child_name, _, _) in self.req_children() {
print_req_children.extend(quote!(
self.$child_name.fmt(f)?;
self.#child_name.fmt(f)?;
));
}

Expand All @@ -286,26 +288,26 @@ impl Declare {
write!(f, "/>")
} else {
write!(f, ">")?;
$print_opt_children
write!(f, "</{}>", $name)
#print_opt_children
write!(f, "</{}>", #name)
})
} else {
quote!(write!(f, "/>"))
}
} else {
quote!(
write!(f, ">")?;
$print_req_children
$print_opt_children
write!(f, "</{}>", $name)
#print_req_children
#print_opt_children
write!(f, "</{}>", #name)
)
};

let mut print_attrs = TokenStream::new();
for (attr_name, _, attr_str) in self.attrs() {
print_attrs.extend(quote!(
if let Some(ref value) = self.attrs.$attr_name {
write!(f, " {}=\"{}\"", $attr_str,
if let Some(ref value) = self.attrs.#attr_name {
write!(f, " {}=\"{}\"", #attr_str,
::htmlescape::encode_attribute(&value.to_string()))?;
}
));
Expand All @@ -316,24 +318,24 @@ impl Declare {
let event_name = TokenTree::Ident(Ident::new(event, Span::call_site()));
let event_str = TokenTree::Literal(Literal::string(event));
print_events.extend(quote!(
if let Some(ref value) = self.events.$event_name {
write!(f, " on{}=\"{}\"", $event_str,
if let Some(ref value) = self.events.#event_name {
write!(f, " on{}=\"{}\"", #event_str,
::htmlescape::encode_attribute(value.render().unwrap().as_str()))?;
}
));
}

quote!(
impl<T> std::fmt::Display for $elem_name<T> where T: ::OutputType {
impl<T> std::fmt::Display for #elem_name<T> where T: ::OutputType {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
write!(f, "<{}", $name)?;
$print_attrs
write!(f, "<{}", #name)?;
#print_attrs
for (key, value) in &self.data_attributes {
write!(f, " data-{}=\"{}\"", key,
::htmlescape::encode_attribute(&value))?;
}
$print_events
$print_children
#print_events
#print_children
}
}
)
Expand Down
Loading

0 comments on commit a1a4f8f

Please sign in to comment.