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>),
|
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"),
|
||||||
}
|
}
|
||||||
|
|
|
@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue