Skip to content

Commit

Permalink
More parser fixes, private fields, static blocks and others (#49)
Browse files Browse the repository at this point in the history
  • Loading branch information
kaleidawave authored Aug 24, 2023
1 parent 2333e8f commit ada01b2
Show file tree
Hide file tree
Showing 19 changed files with 403 additions and 335 deletions.
5 changes: 4 additions & 1 deletion parser/fuzz/fuzz_targets/module_roundtrip_naive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@ fn do_fuzz(data: &str) -> Corpus {
};

let output2 =
module.to_string(&ToStringOptions::default());
module.to_string(&ToStringOptions {
trailing_semicolon: true,
..ToStringOptions::default()
});

assert_eq!(output1, output2);

Expand Down
5 changes: 4 additions & 1 deletion parser/fuzz/fuzz_targets/module_roundtrip_structured.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ fn do_fuzz(data: common::FuzzSource) -> Corpus {
};

let output2 =
module.to_string(&ToStringOptions::default());
module.to_string(&ToStringOptions {
trailing_semicolon: true,
..ToStringOptions::default()
});

assert_eq!(output1, output2);

Expand Down
9 changes: 6 additions & 3 deletions parser/generator/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ fn token_stream_to_ast_node<T: parser::ASTNode + self_rust_tokenize::SelfRustTok
})
.collect();

// eprintln!("string input: {string:?}");

let parse_result = T::from_string(
string,
parser::ParseOptions::default(),
Expand Down Expand Up @@ -75,7 +77,7 @@ fn token_stream_to_ast_node<T: parser::ASTNode + self_rust_tokenize::SelfRustTok
}
};

// eprintln!("{tokens}");
// eprintln!("output: {tokens}");

tokens.into()
}
Expand Down Expand Up @@ -119,8 +121,9 @@ fn parse_token_stream(
panic!("Expected ident")
}
} else {
let spacing = matches!(punctuation.spacing(), Spacing::Alone);
if spacing && !(string.ends_with("<") && chr == '/') {
let spacing = matches!(punctuation.spacing(), Spacing::Alone)
&& !matches!(chr, '<' | '>' | '/');
if spacing && !string.ends_with("</") {
string.push(' ');
}
string.push(chr);
Expand Down
14 changes: 6 additions & 8 deletions parser/src/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -287,14 +287,12 @@ pub fn statements_and_declarations_to_string<T: source_map::ToString>(
for (at_end, item) in items.iter().endiate() {
settings.add_indent(depth, buf);
item.to_string_from_buffer(buf, settings, depth);
if !at_end {
// TODO only append new line if something added
if item.requires_semi_colon() {
buf.push(';');
}
if settings.pretty {
buf.push_new_line();
}
if (!at_end || settings.trailing_semicolon) && item.requires_semi_colon() {
buf.push(';');
}
// TODO only append new line if something added
if !at_end && settings.pretty {
buf.push_new_line();
}
}
}
24 changes: 23 additions & 1 deletion parser/src/comments.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Contains wrappers for AST with comments

use super::{ASTNode, ParseError, Span, TSXToken, TokenReader};
use crate::ParseOptions;
use crate::{ParseOptions, Visitable};
use std::{borrow::Cow, mem};
use tokenizer_lib::Token;

Expand Down Expand Up @@ -33,6 +33,28 @@ where
}
}

impl<T: Visitable> Visitable for WithComment<T> {
fn visit<TData>(
&self,
visitors: &mut (impl crate::VisitorReceiver<TData> + ?Sized),
data: &mut TData,
settings: &crate::VisitSettings,
chain: &mut temporary_annex::Annex<crate::Chain>,
) {
self.get_ast().visit(visitors, data, settings, chain)
}

fn visit_mut<TData>(
&mut self,
visitors: &mut (impl crate::VisitorMutReceiver<TData> + ?Sized),
data: &mut TData,
settings: &crate::VisitSettings,
chain: &mut temporary_annex::Annex<crate::Chain>,
) {
self.get_ast_mut().visit_mut(visitors, data, settings, chain)
}
}

impl<T: PartialEq> PartialEq for WithComment<T> {
fn eq(&self, other: &Self) -> bool {
self.get_ast() == other.get_ast()
Expand Down
163 changes: 45 additions & 118 deletions parser/src/declarations/classes/class_member.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
use std::{borrow::Cow, fmt::Debug};

use crate::{errors::parse_lexing_error, tsx_keywords};
use crate::{errors::parse_lexing_error, property_key::PublicOrPrivate, tsx_keywords};
use source_map::Span;
use tokenizer_lib::{Token, TokenReader};
use visitable_derive::Visitable;

use crate::{
functions::FunctionBased, ASTNode, Block, Expression, FunctionBase, GetSetGeneratorOrNone,
Keyword, ParseError, ParseErrors, ParseOptions, ParseResult, PropertyKey, TSXKeyword, TSXToken,
TypeAnnotation, VisitSettings, WithComment,
TypeAnnotation, WithComment,
};

/// The variable id's of these is handled by their [PropertyKey]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ClassMember {
Constructor(ClassConstructor),
Function(Option<Keyword<tsx_keywords::Static>>, ClassFunction),
Method(Option<Keyword<tsx_keywords::Static>>, ClassFunction),
Property(Option<Keyword<tsx_keywords::Static>>, ClassProperty),
StaticBlock(Block),
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
Expand All @@ -26,21 +28,23 @@ pub type ClassConstructor = FunctionBase<ClassConstructorBase>;
pub struct ClassFunctionBase;
pub type ClassFunction = FunctionBase<ClassFunctionBase>;

#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, Visitable)]
pub struct ClassProperty {
pub key: WithComment<PropertyKey>,
pub readonly_keyword: Option<Keyword<tsx_keywords::Readonly>>,
pub key: WithComment<PropertyKey<PublicOrPrivate>>,
pub type_annotation: Option<TypeAnnotation>,
pub value: Option<Box<Expression>>,
pub position: Span,
}

impl ASTNode for ClassMember {
fn get_position(&self) -> Cow<Span> {
todo!()
// match self {
// Self::Constructor { position, .. }
// | Self::Method { position, .. }
// | Self::Property { position, .. } => position.as_ref(),
// }
match self {
Self::Constructor(cst) => cst.get_position(),
Self::Method(_, mtd) => mtd.get_position(),
Self::Property(_, prop) => Cow::Owned(prop.position.clone()),
Self::StaticBlock(blk) => blk.get_position(),
}
}

fn from_reader(
Expand All @@ -56,24 +60,32 @@ impl ASTNode for ClassMember {
let is_static = reader
.conditional_next(|tok| *tok == TSXToken::Keyword(TSXKeyword::Static))
.map(|Token(_, span)| Keyword::new(span));
let is_async = reader

if let Some(Token(TSXToken::OpenBrace, _)) = reader.peek() {
return Ok(ClassMember::StaticBlock(Block::from_reader(reader, state, settings)?));
}

let async_keyword = reader
.conditional_next(|tok| *tok == TSXToken::Keyword(TSXKeyword::Async))
.map(|Token(_, span)| Keyword::new(span));
let readonly_keyword = reader
.conditional_next(|tok| *tok == TSXToken::Keyword(TSXKeyword::Async))
.map(|Token(_, span)| Keyword::new(span));
let get_set_generator_or_none = GetSetGeneratorOrNone::from_reader(reader);

let key = WithComment::<PropertyKey>::from_reader(reader, state, settings)?;
let key = WithComment::<PropertyKey<_>>::from_reader(reader, state, settings)?;

match reader.peek() {
Some(Token(TSXToken::OpenParentheses, _)) => {
let function = ClassFunction::from_reader_with_config(
reader,
state,
settings,
is_async,
async_keyword,
get_set_generator_or_none,
key,
)?;
Ok(ClassMember::Function(is_static, function))
Ok(ClassMember::Method(is_static, function))
}
Some(Token(token, _)) => {
if get_set_generator_or_none != GetSetGeneratorOrNone::None {
Expand Down Expand Up @@ -105,9 +117,12 @@ impl ASTNode for ClassMember {
Ok(Self::Property(
is_static,
ClassProperty {
readonly_keyword,
position: key.get_position().into_owned(),
key,
type_annotation: member_type,
value: member_expression.map(Box::new),
// TODO
},
))
}
Expand All @@ -122,10 +137,16 @@ impl ASTNode for ClassMember {
depth: u8,
) {
match self {
Self::Property(is_static, ClassProperty { key, type_annotation, value }) => {
Self::Property(
is_static,
ClassProperty { readonly_keyword, key, type_annotation, value, position: _ },
) => {
if is_static.is_some() {
buf.push_str("static ");
}
if readonly_keyword.is_some() {
buf.push_str("readonly ");
}
key.to_string_from_buffer(buf, settings, depth);
if let (true, Some(type_annotation)) = (settings.include_types, type_annotation) {
buf.push_str(": ");
Expand All @@ -136,7 +157,7 @@ impl ASTNode for ClassMember {
value.to_string_from_buffer(buf, settings, depth);
}
}
Self::Function(is_static, function) => {
Self::Method(is_static, function) => {
if is_static.is_some() {
buf.push_str("static ");
}
Expand All @@ -145,6 +166,10 @@ impl ASTNode for ClassMember {
Self::Constructor(constructor) => {
constructor.to_string_from_buffer(buf, settings, depth + 1)
}
Self::StaticBlock(block) => {
buf.push_str("static ");
block.to_string_from_buffer(buf, settings, depth + 1);
}
}
}
}
Expand All @@ -159,112 +184,14 @@ impl ClassMember {
// }
}

#[allow(unused)]
impl ClassMember {
pub fn visit<TData>(
&self,
visitors: &mut (impl crate::VisitorReceiver<TData> + ?Sized),
data: &mut TData,
settings: &VisitSettings,
chain: &mut temporary_annex::Annex<crate::visiting::Chain>,
) {
match self {
ClassMember::Constructor(..) => {
todo!()
// decorators.visit(visitors, data, settings, chain);
// function.visit(
// visitors,
// data,
// settings,
// &mut chain.push_annex(ChainVariable::UnderClassMethod(
// function.body.1,
// class_variable_id,
// )),
// );
}
ClassMember::Function(..) => {
todo!()
// { decorators, function, key, .. }
// key.visit(visitors, data, chain, PropertyKeyLocation::Class(class_variable_id));
// decorators.visit(visitors, data, settings, chain);
// function.visit(
// visitors,
// data,
// settings,
// &mut chain.push_annex(ChainVariable::UnderClassMethod(
// function.body.1,
// class_variable_id,
// )),
// );
}
ClassMember::Property(_, ClassProperty { value, key, .. }) => {
todo!()
// key.visit(visitors, data, chain, PropertyKeyLocation::Class(class_variable_id));
// value.visit(visitors, data, settings, chain);
}
}
}

pub fn visit_mut<TData>(
&mut self,
visitors: &mut (impl crate::VisitorMutReceiver<TData> + ?Sized),
data: &mut TData,
settings: &VisitSettings,
chain: &mut temporary_annex::Annex<crate::visiting::Chain>,
) {
match self {
ClassMember::Constructor(..) => {
todo!()
// { decorators, function, .. }
// decorators
// .iter_mut()
// .for_each(|decorator| decorator.visit_mut(visitors, data, settings, chain));
// function.visit_mut(
// visitors,
// data,
// settings,
// &mut chain.push_annex(ChainVariable::UnderClassMethod(
// function.body.1,
// class_variable_id,
// )),
// );
}
ClassMember::Function(..) => {
todo!()
// { decorators, function, key, .. }
// key.visit_mut(visitors, data, chain, PropertyKeyLocation::Class(class_variable_id));
// decorators
// .iter_mut()
// .for_each(|decorator| decorator.visit_mut(visitors, data, settings, chain));
// function.visit_mut(
// visitors,
// data,
// settings,
// &mut chain.push_annex(ChainVariable::UnderClassMethod(
// function.body.1,
// class_variable_id,
// )),
// );
}
ClassMember::Property(_, ClassProperty { value, key, .. }) => {
todo!()
// key.visit_mut(visitors, data, chain, PropertyKeyLocation::Class(class_variable_id));
// if let Some(value) = value {
// value.visit_mut(visitors, data, settings, chain);
// }
}
}
}
}

impl ClassFunction {
fn from_reader_with_config(
reader: &mut impl TokenReader<TSXToken, Span>,
state: &mut crate::ParsingState,
settings: &ParseOptions,
is_async: Option<Keyword<tsx_keywords::Async>>,
get_set_generator_or_none: GetSetGeneratorOrNone,
key: WithComment<PropertyKey>,
key: WithComment<PropertyKey<PublicOrPrivate>>,
) -> ParseResult<Self> {
FunctionBase::from_reader_with_header_and_name(
reader,
Expand All @@ -279,7 +206,7 @@ impl ClassFunction {
impl FunctionBased for ClassFunctionBase {
type Body = Block;
type Header = (Option<Keyword<tsx_keywords::Async>>, GetSetGeneratorOrNone);
type Name = WithComment<PropertyKey>;
type Name = WithComment<PropertyKey<PublicOrPrivate>>;

// fn get_chain_variable(this: &FunctionBase<Self>) -> ChainVariable {
// ChainVariable::UnderClassMethod(this.body.1)
Expand All @@ -294,7 +221,7 @@ impl FunctionBased for ClassFunctionBase {
.conditional_next(|tok| matches!(tok, TSXToken::Keyword(TSXKeyword::Async)))
.map(|Token(_, span)| Keyword::new(span));
let header = GetSetGeneratorOrNone::from_reader(reader);
let name = WithComment::<PropertyKey>::from_reader(reader, state, settings)?;
let name = WithComment::<PropertyKey<_>>::from_reader(reader, state, settings)?;
Ok(((async_keyword, header), name))
}

Expand Down
Loading

0 comments on commit ada01b2

Please sign in to comment.