call it a night
This commit is contained in:
parent
96df945dbc
commit
0daf13f066
4 changed files with 70 additions and 35 deletions
|
@ -160,6 +160,7 @@ pub enum Rsx {
|
|||
Elem(Elem<Rsx>),
|
||||
Code(Expr),
|
||||
Text(String),
|
||||
ForLoop(),
|
||||
|
||||
#[doc(hidden)]
|
||||
_Nonexhaustive,
|
||||
|
@ -184,15 +185,18 @@ impl ToTokens for Rsx {
|
|||
fn to_tokens(&self, stream: &mut TokenStream) {
|
||||
match self {
|
||||
Rsx::Elem(elem) => {
|
||||
stream.extend(quote! { #elem });
|
||||
stream.extend(quote!(#elem));
|
||||
}
|
||||
Rsx::Code(expr) => {
|
||||
let expr = syn::Expr::from_adapter(expr);
|
||||
stream.extend(quote! { { #expr } });
|
||||
stream.extend(quote!({ #expr }));
|
||||
}
|
||||
Rsx::Text(string) => {
|
||||
let string = syn::Lit::Str(syn::LitStr::new(string.as_ref(), Span::call_site()));
|
||||
stream.extend(quote! { #string });
|
||||
stream.extend(quote!(#string));
|
||||
}
|
||||
Rsx::ForLoop() => {
|
||||
stream.extend(quote!({ for } { / for }));
|
||||
}
|
||||
Rsx::_Nonexhaustive => unreachable!("should never be constructed"),
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::collections::BTreeMap;
|
|||
use std::iter::FromIterator;
|
||||
use std::iter::Peekable;
|
||||
|
||||
use enterprise_compiler::model::{Component, Elem, ModelMap, Rsx};
|
||||
use enterprise_compiler::model::{Component, Elem, ModelMap, Rsx, TagLhs, TagRhs};
|
||||
use proc_macro2::{
|
||||
token_stream::IntoIter, Delimiter, Group, Ident, Punct, Spacing, TokenStream, TokenTree,
|
||||
};
|
||||
|
@ -183,6 +183,11 @@ impl Visitor {
|
|||
}
|
||||
|
||||
fn consume_view(&mut self) -> Result<Vec<Rsx>, ParseError> {
|
||||
enum Container {
|
||||
Tag(String, BTreeMap<TagLhs, TagRhs>),
|
||||
ForLoop(),
|
||||
}
|
||||
|
||||
let mut rsx_parser = RsxParser::new(self.0.clone());
|
||||
let mut result = Vec::new();
|
||||
let mut tag_stack = Vec::new();
|
||||
|
@ -199,11 +204,13 @@ impl Visitor {
|
|||
result.push(el);
|
||||
}
|
||||
RsxToken::OpeningTag(tag, attrs) => {
|
||||
tag_stack.push((tag, attrs, result.clone()));
|
||||
tag_stack.push((Container::Tag(tag.to_string(), attrs), result.clone()));
|
||||
result.clear();
|
||||
}
|
||||
RsxToken::ClosingTag(tag) => {
|
||||
if let Some((last_tag, attrs, mut last_result)) = tag_stack.pop() {
|
||||
if let Some((Container::Tag(last_tag, attrs), mut last_result)) =
|
||||
tag_stack.pop()
|
||||
{
|
||||
if tag.as_str() == last_tag.as_str() {
|
||||
last_result.push(Rsx::Elem(Elem {
|
||||
tag: tag.to_string(),
|
||||
|
@ -227,6 +234,17 @@ impl Visitor {
|
|||
RsxToken::Str(string) => {
|
||||
result.push(Rsx::Text(string));
|
||||
}
|
||||
RsxToken::OpeningFor() => {
|
||||
tag_stack.push((Container::ForLoop(), result.clone()));
|
||||
}
|
||||
RsxToken::ClosingFor => {
|
||||
if let Some((Container::ForLoop(), mut last_result)) = tag_stack.pop() {
|
||||
last_result.push(Rsx::ForLoop());
|
||||
result = last_result;
|
||||
} else {
|
||||
return Err(ParseError::ClosedTooFar);
|
||||
}
|
||||
}
|
||||
unknown => unimplemented!("rsx token: {:?}", unknown),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,10 @@ use std::iter::Peekable;
|
|||
use enterprise_compiler::model::{TagLhs, TagRhs};
|
||||
use proc_macro2::{token_stream::IntoIter, Delimiter, Ident, TokenStream, TokenTree};
|
||||
use symbol::Symbol;
|
||||
use syn::{Expr, Lit};
|
||||
use syn::{
|
||||
parse::{Parse, ParseStream},
|
||||
Expr, Lit, Pat, Result as SynResult, Token,
|
||||
};
|
||||
use syn_serde::Syn;
|
||||
|
||||
use crate::parser::{consume_ident, consume_punct, ParseError};
|
||||
|
@ -148,34 +151,43 @@ impl RsxParser {
|
|||
}
|
||||
}
|
||||
TokenTree::Group(group) if group.delimiter() == Delimiter::Brace => {
|
||||
let mut stream = group.stream().into_iter();
|
||||
|
||||
enum GroupType {
|
||||
Pound,
|
||||
Slash,
|
||||
None,
|
||||
let expr = syn::parse2::<Expr>(group.stream())?;
|
||||
Ok(Some(RsxToken::Code(expr)))
|
||||
}
|
||||
TokenTree::Group(group) if group.delimiter() == Delimiter::Bracket => {
|
||||
// for loop syntax
|
||||
#[derive(Debug)]
|
||||
struct ForLoopHeader {
|
||||
kw_for: Token![for],
|
||||
pat: Pat,
|
||||
kw_in: Token![in],
|
||||
iter: Expr,
|
||||
}
|
||||
|
||||
// based on svelte for now, we'll probably change up the syntax a bit later
|
||||
let is_special = match stream.next() {
|
||||
Some(TokenTree::Punct(punct)) if punct.as_char() == '#' => GroupType::Pound,
|
||||
Some(TokenTree::Punct(punct)) if punct.as_char() == '/' => GroupType::Slash,
|
||||
_ => GroupType::None,
|
||||
};
|
||||
|
||||
if let GroupType::None = is_special {
|
||||
let expr = syn::parse2::<Expr>(group.stream())?;
|
||||
Ok(Some(RsxToken::Code(expr)))
|
||||
} else {
|
||||
match stream.next() {
|
||||
Some(TokenTree::Ident(ident)) if ident == "for" => {
|
||||
// syntax: {#for pattern in expr} {/for}
|
||||
Ok(Some(RsxToken::StartFor()))
|
||||
}
|
||||
Some(other) => Err(ParseError::ExpectedIdent(other)),
|
||||
None => Err(ParseError::UnexpectedEOF),
|
||||
impl Parse for ForLoopHeader {
|
||||
fn parse(input: ParseStream) -> SynResult<Self> {
|
||||
Ok(ForLoopHeader {
|
||||
kw_for: input.parse()?,
|
||||
pat: input.parse()?,
|
||||
kw_in: input.parse()?,
|
||||
iter: input.parse()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
let mut stream = group.stream().into_iter().peekable();
|
||||
match stream.peek() {
|
||||
Some(TokenTree::Ident(ident)) if &ident.to_string() == "for" => {
|
||||
let for_loop = syn::parse2::<ForLoopHeader>(group.stream())?;
|
||||
Ok(Some(RsxToken::OpeningFor()))
|
||||
}
|
||||
Some(TokenTree::Punct(punct)) if punct.as_char() == '/' => {
|
||||
stream.next();
|
||||
Ok(Some(RsxToken::ClosingFor))
|
||||
}
|
||||
Some(token) => Err(ParseError::UnexpectedToken(token.clone())),
|
||||
None => Err(ParseError::UnexpectedEOF),
|
||||
}
|
||||
}
|
||||
token => Err(ParseError::UnexpectedToken(token)),
|
||||
}
|
||||
|
@ -203,7 +215,8 @@ pub(crate) enum RsxToken {
|
|||
ClosingTag(Symbol),
|
||||
Str(String),
|
||||
Code(Expr),
|
||||
StartFor(),
|
||||
OpeningFor(),
|
||||
ClosingFor,
|
||||
}
|
||||
|
||||
impl Iterator for RsxParser {
|
||||
|
|
|
@ -10,9 +10,9 @@ component! {
|
|||
view {
|
||||
<input on:submit={|evt| { todos.push(evt.name); }} />
|
||||
<ul>
|
||||
{#for (key, todo) in todos }
|
||||
<li>{todo} <a on:click={|_| { todos.remove(key); }}>[x]</a></li>
|
||||
{/for}
|
||||
[for (key, todo) in todos]
|
||||
<li>{todo} <a on:click={|_| { todos.remove(key); }}>"[x]"</a></li>
|
||||
[/for]
|
||||
</ul>
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue