call it a night

This commit is contained in:
Michael Zhang 2020-02-21 03:25:27 -06:00
parent 96df945dbc
commit 0daf13f066
Signed by: michael
GPG key ID: BDA47A31A3C8EE6B
4 changed files with 70 additions and 35 deletions

View file

@ -160,6 +160,7 @@ pub enum Rsx {
Elem(Elem<Rsx>), Elem(Elem<Rsx>),
Code(Expr), Code(Expr),
Text(String), Text(String),
ForLoop(),
#[doc(hidden)] #[doc(hidden)]
_Nonexhaustive, _Nonexhaustive,
@ -184,15 +185,18 @@ impl ToTokens for Rsx {
fn to_tokens(&self, stream: &mut TokenStream) { fn to_tokens(&self, stream: &mut TokenStream) {
match self { match self {
Rsx::Elem(elem) => { Rsx::Elem(elem) => {
stream.extend(quote! { #elem }); stream.extend(quote!(#elem));
} }
Rsx::Code(expr) => { Rsx::Code(expr) => {
let expr = syn::Expr::from_adapter(expr); let expr = syn::Expr::from_adapter(expr);
stream.extend(quote! { { #expr } }); stream.extend(quote!({ #expr }));
} }
Rsx::Text(string) => { Rsx::Text(string) => {
let string = syn::Lit::Str(syn::LitStr::new(string.as_ref(), Span::call_site())); 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"), Rsx::_Nonexhaustive => unreachable!("should never be constructed"),
} }

View file

@ -2,7 +2,7 @@ use std::collections::BTreeMap;
use std::iter::FromIterator; use std::iter::FromIterator;
use std::iter::Peekable; 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::{ use proc_macro2::{
token_stream::IntoIter, Delimiter, Group, Ident, Punct, Spacing, TokenStream, TokenTree, 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> { 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 rsx_parser = RsxParser::new(self.0.clone());
let mut result = Vec::new(); let mut result = Vec::new();
let mut tag_stack = Vec::new(); let mut tag_stack = Vec::new();
@ -199,11 +204,13 @@ impl Visitor {
result.push(el); result.push(el);
} }
RsxToken::OpeningTag(tag, attrs) => { RsxToken::OpeningTag(tag, attrs) => {
tag_stack.push((tag, attrs, result.clone())); tag_stack.push((Container::Tag(tag.to_string(), attrs), result.clone()));
result.clear(); result.clear();
} }
RsxToken::ClosingTag(tag) => { 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() { if tag.as_str() == last_tag.as_str() {
last_result.push(Rsx::Elem(Elem { last_result.push(Rsx::Elem(Elem {
tag: tag.to_string(), tag: tag.to_string(),
@ -227,6 +234,17 @@ impl Visitor {
RsxToken::Str(string) => { RsxToken::Str(string) => {
result.push(Rsx::Text(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), unknown => unimplemented!("rsx token: {:?}", unknown),
} }
} }

View file

@ -5,7 +5,10 @@ use std::iter::Peekable;
use enterprise_compiler::model::{TagLhs, TagRhs}; use enterprise_compiler::model::{TagLhs, TagRhs};
use proc_macro2::{token_stream::IntoIter, Delimiter, Ident, TokenStream, TokenTree}; use proc_macro2::{token_stream::IntoIter, Delimiter, Ident, TokenStream, TokenTree};
use symbol::Symbol; use symbol::Symbol;
use syn::{Expr, Lit}; use syn::{
parse::{Parse, ParseStream},
Expr, Lit, Pat, Result as SynResult, Token,
};
use syn_serde::Syn; use syn_serde::Syn;
use crate::parser::{consume_ident, consume_punct, ParseError}; use crate::parser::{consume_ident, consume_punct, ParseError};
@ -148,35 +151,44 @@ impl RsxParser {
} }
} }
TokenTree::Group(group) if group.delimiter() == Delimiter::Brace => { TokenTree::Group(group) if group.delimiter() == Delimiter::Brace => {
let mut stream = group.stream().into_iter();
enum GroupType {
Pound,
Slash,
None,
}
// 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())?; let expr = syn::parse2::<Expr>(group.stream())?;
Ok(Some(RsxToken::Code(expr))) 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)), 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,
}
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), None => Err(ParseError::UnexpectedEOF),
} }
} }
}
token => Err(ParseError::UnexpectedToken(token)), token => Err(ParseError::UnexpectedToken(token)),
} }
} }
@ -203,7 +215,8 @@ pub(crate) enum RsxToken {
ClosingTag(Symbol), ClosingTag(Symbol),
Str(String), Str(String),
Code(Expr), Code(Expr),
StartFor(), OpeningFor(),
ClosingFor,
} }
impl Iterator for RsxParser { impl Iterator for RsxParser {

View file

@ -10,9 +10,9 @@ component! {
view { view {
<input on:submit={|evt| { todos.push(evt.name); }} /> <input on:submit={|evt| { todos.push(evt.name); }} />
<ul> <ul>
{#for (key, todo) in todos } [for (key, todo) in todos]
<li>{todo} <a on:click={|_| { todos.remove(key); }}>[x]</a></li> <li>{todo} <a on:click={|_| { todos.remove(key); }}>"[x]"</a></li>
{/for} [/for]
</ul> </ul>
} }
} }