Skip to content

Commit

Permalink
Small fixes (#79)
Browse files Browse the repository at this point in the history
  • Loading branch information
kaleidawave authored Nov 10, 2023
1 parent 3016951 commit bedb2b5
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 104 deletions.
4 changes: 2 additions & 2 deletions checker/specification/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ publish = false
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

# Prevent this from interfering with workspaces
# [workspace]
# members = ["."]
[workspace]
members = ["."]

[[test]]
name = "specification_test"
Expand Down
21 changes: 3 additions & 18 deletions parser/src/declarations/classes/class_member.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,11 @@ impl ASTNode for ClassMember {
state: &mut crate::ParsingState,
options: &ParseOptions,
) -> ParseResult<Self> {
if let Some(Token(TSXToken::MultiLineComment(_), _)) = reader.peek() {
let Some(Token(TSXToken::MultiLineComment(c), start)) = reader.next() else {
if reader.peek().map_or(false, |t| t.0.is_comment()) {
let Ok((comment, span)) = TSXToken::try_into_comment(reader.next().unwrap()) else {
unreachable!()
};
let with_length = start.with_length(c.len() + 2);
return Ok(Self::Comment(c, with_length));
return Ok(Self::Comment(comment, span));
}

if let Some(Token(TSXToken::Keyword(TSXKeyword::Constructor), _)) = reader.peek() {
Expand Down Expand Up @@ -177,16 +176,6 @@ impl ASTNode for ClassMember {
}
}

impl ClassMember {
// pub fn get_property_id(&self) -> Option<PropertyId> {
// match self {
// ClassMember::Method(_, ClassMethod { key, .. })
// | ClassMember::Property(_, ClassProperty { key, .. }) => Some(key.get_ast().get_property_id()),
// ClassMember::Constructor { .. } => None,
// }
// }
}

impl ClassFunction {
fn from_reader_with_config(
reader: &mut impl TokenReader<TSXToken, crate::TokenStart>,
Expand All @@ -210,10 +199,6 @@ impl FunctionBased for ClassFunctionBase {
type Header = Option<MethodHeader>;
type Name = WithComment<PropertyKey<PublicOrPrivate>>;

// fn get_chain_variable(this: &FunctionBase<Self>) -> ChainVariable {
// ChainVariable::UnderClassMethod(this.body.1)
// }

fn header_and_name_from_reader(
reader: &mut impl TokenReader<TSXToken, crate::TokenStart>,
state: &mut crate::ParsingState,
Expand Down
99 changes: 24 additions & 75 deletions parser/src/expressions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -465,7 +465,7 @@ impl Expression {
};

let (arguments, end) = if reader
.conditional_next(|token| *token == TSXToken::OpenChevron)
.conditional_next(|token| *token == TSXToken::OpenParentheses)
.is_some()
{
parse_bracketed(reader, state, options, None, TSXToken::CloseParentheses)
Expand Down Expand Up @@ -826,13 +826,14 @@ impl Expression {
falsy_result: Box::new(rhs),
};
}
TSXToken::OpenParentheses => {
TSXToken::OpenParentheses | TSXToken::OptionalCall => {
if AssociativityDirection::LeftToRight
.should_return(parent_precedence, FUNCTION_CALL_PRECEDENCE)
{
return Ok(top);
}
reader.next();
let next = reader.next().unwrap();
let is_optional = matches!(next.0, TSXToken::OptionalCall);
let (arguments, end) =
parse_bracketed(reader, state, options, None, TSXToken::CloseParentheses)?;
let position = top.get_position().union(end);
Expand All @@ -841,24 +842,26 @@ impl Expression {
type_arguments: None,
arguments,
position,
is_optional: false,
is_optional,
};
}
TSXToken::OpenBracket => {
TSXToken::OpenBracket | TSXToken::OptionalIndex => {
if AssociativityDirection::LeftToRight
.should_return(parent_precedence, INDEX_PRECEDENCE)
{
return Ok(top);
}
reader.next();
let next = reader.next().unwrap();
let is_optional = matches!(next.0, TSXToken::OptionalIndex);

let indexer = MultipleExpression::from_reader(reader, state, options)?;
let end = reader.expect_next_get_end(TSXToken::CloseBracket)?;
let position = top.get_position().union(end);
top = Expression::Index {
position,
indexee: Box::new(top),
indexer: Box::new(indexer),
is_optional: false,
is_optional,
};
}
TSXToken::TemplateLiteralStart => {
Expand All @@ -877,75 +880,15 @@ impl Expression {
);
top = template_lit.map(Expression::TemplateLiteral)?;
}
TSXToken::OptionalChain => {
if AssociativityDirection::LeftToRight
.should_return(parent_precedence, MEMBER_ACCESS_PRECEDENCE)
{
return Ok(top);
}
let _ = reader.next().unwrap();
let token = reader.next().ok_or_else(parse_lexing_error)?;
top = match token {
Token(TSXToken::OpenBracket, _start) => {
let indexer = MultipleExpression::from_reader(reader, state, options)?;
let end = reader.expect_next_get_end(TSXToken::CloseBracket)?;
let position = top.get_position().union(end);
Expression::Index {
position,
indexee: Box::new(top),
indexer: Box::new(indexer),
is_optional: false,
}
}
Token(TSXToken::OpenParentheses, _start) => {
let (arguments, end) = parse_bracketed(
reader,
state,
options,
Some(TSXToken::CloseParentheses),
TSXToken::CloseParentheses,
)?;
let position = top.get_position().union(end);
Expression::FunctionCall {
function: Box::new(top),
type_arguments: None,
arguments,
position,
is_optional: true,
}
}
token => {
let (property, position) =
if let Token(TSXToken::Cursor(cursor_id), start) = token {
(
PropertyReference::Cursor(cursor_id.into_cursor()),
start.with_length(1),
)
} else {
let is_private = reader
.conditional_next(|t| matches!(t, TSXToken::HashTag))
.is_some();
let (property, position) =
token_as_identifier(token, "variable reference")?;
(PropertyReference::Standard { property, is_private }, position)
};
let position = top.get_position().union(&position);
Expression::PropertyAccess {
parent: Box::new(top),
property,
position,
is_optional: true,
}
}
}
}
TSXToken::Dot => {
TSXToken::Dot | TSXToken::OptionalChain => {
if AssociativityDirection::LeftToRight
.should_return(parent_precedence, MEMBER_ACCESS_PRECEDENCE)
{
return Ok(top);
}
let _ = reader.next().unwrap();
let next = reader.next().unwrap();
let is_optional = matches!(next.0, TSXToken::OptionalChain);

let token = reader.next().ok_or_else(parse_lexing_error)?;
let (property, position) = if let Token(TSXToken::Cursor(cursor_id), start) =
token
Expand All @@ -963,7 +906,7 @@ impl Expression {
parent: Box::new(top),
property,
position,
is_optional: false,
is_optional,
};
}
TSXToken::Assign => {
Expand Down Expand Up @@ -1376,13 +1319,16 @@ impl Expression {
buf.push(')');
}
}
Self::Index { indexee: expression, indexer, .. } => {
Self::Index { indexee: expression, indexer, is_optional, .. } => {
expression.to_string_from_buffer(buf, options, depth);
if *is_optional {
buf.push_str("?.");
}
buf.push('[');
indexer.to_string_from_buffer(buf, options, depth);
buf.push(']');
}
Self::FunctionCall { function, type_arguments, arguments, .. } => {
Self::FunctionCall { function, type_arguments, arguments, is_optional, .. } => {
// TODO is this okay?
if let Some(ExpressionOrBlock::Expression(expression)) = self.is_iife() {
expression.to_string_from_buffer(buf, options, depth);
Expand All @@ -1392,6 +1338,7 @@ impl Expression {
&**function,
Expression::ArrowFunction(..) | Expression::ExpressionFunction(..)
);
// Fixes precedence from badly created ASTs
if is_raw_function {
buf.push('(');
}
Expand All @@ -1402,6 +1349,9 @@ impl Expression {
if let (true, Some(type_arguments)) = (options.include_types, type_arguments) {
to_string_bracketed(type_arguments, ('<', '>'), buf, options, depth);
}
if *is_optional {
buf.push_str("?.");
}
arguments_to_string(arguments, buf, options, depth);
}
Self::ConstructorCall { constructor, type_arguments, arguments, .. } => {
Expand Down Expand Up @@ -1597,7 +1547,6 @@ fn is_generic_arguments(reader: &mut impl TokenReader<TSXToken, crate::TokenStar
| TSXToken::LogicalAnd
| TSXToken::LogicalOr
| TSXToken::SemiColon
| TSXToken::QuestionMark
) {
true
} else {
Expand Down
14 changes: 9 additions & 5 deletions parser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,8 @@ pub enum NumberRepresentation {
NaN,
Hex(NumberSign, u64),
Bin(NumberSign, u64),
Octal(NumberSign, u64),
// Last one is whether it was specified with a leading zero (boo)
Octal(NumberSign, u64, bool),
Number {
elided_zero_before_point: bool,
trailing_point: bool,
Expand All @@ -487,7 +488,7 @@ impl From<NumberRepresentation> for f64 {
NumberRepresentation::Number { internal, .. } => internal,
NumberRepresentation::Hex(sign, nat)
| NumberRepresentation::Bin(sign, nat)
| NumberRepresentation::Octal(sign, nat) => sign.apply(nat as f64),
| NumberRepresentation::Octal(sign, nat, _) => sign.apply(nat as f64),
NumberRepresentation::BigInt(..) => todo!(),
}
}
Expand Down Expand Up @@ -592,7 +593,7 @@ impl FromStr for NumberRepresentation {
return Err(s.to_owned());
}
}
Ok(Self::Octal(sign, number))
Ok(Self::Octal(sign, number, !uses_character))
}
None => Ok(Self::Number {
internal: 0f64,
Expand Down Expand Up @@ -645,7 +646,7 @@ impl PartialEq for NumberRepresentation {
// TODO needs to do conversion
(Self::Hex(l0, l1), Self::Hex(r0, r1)) => l0 == r0 && l1 == r1,
(Self::Bin(l0, l1), Self::Bin(r0, r1)) => l0 == r0 && l1 == r1,
(Self::Octal(l0, l1), Self::Octal(r0, r1)) => l0 == r0 && l1 == r1,
(Self::Octal(l0, l1, _), Self::Octal(r0, r1, _)) => l0 == r0 && l1 == r1,
(Self::Number { internal: l0, .. }, Self::Number { internal: r0, .. }) => l0 == r0,
_ => core::mem::discriminant(self) == core::mem::discriminant(other),
}
Expand All @@ -668,7 +669,10 @@ impl NumberRepresentation {
NumberRepresentation::Bin(sign, value) => {
format!("{sign}0b{value:#b}")
}
NumberRepresentation::Octal(sign, value) => {
NumberRepresentation::Octal(sign, value, true) => {
format!("{sign}0{value:o}")
}
NumberRepresentation::Octal(sign, value, false) => {
format!("{sign}0o{value:o}")
}
NumberRepresentation::Number { internal, elided_zero_before_point, trailing_point } => {
Expand Down
26 changes: 22 additions & 4 deletions parser/src/tokens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ use crate::ParseError;
"?" => TSXToken::QuestionMark,
"?:" => TSXToken::OptionalMember,
"?." => TSXToken::OptionalChain,
"?.(" => TSXToken::OptionalCall,
"?.[" => TSXToken::OptionalIndex,
"-?:" => TSXToken::NonOptionalMember,
"??" => TSXToken::NullishCoalescing,
"??=" => TSXToken::NullishCoalescingAssign,
Expand Down Expand Up @@ -131,7 +133,7 @@ pub enum TSXToken {
LogicalOrAssign, LogicalAndAssign,
Equal, NotEqual, StrictEqual, StrictNotEqual,
GreaterThanEqual, LessThanEqual,
OptionalChain, NullishCoalescing, NullishCoalescingAssign,
OptionalChain, OptionalCall, OptionalIndex, NullishCoalescing, NullishCoalescingAssign,
/// `?:`
OptionalMember,
/// '!:`
Expand Down Expand Up @@ -255,13 +257,15 @@ impl tokenizer_lib::sized_tokens::SizedToken for TSXToken {
| TSXToken::LogicalAnd
| TSXToken::LogicalNot
| TSXToken::Arrow
| TSXToken::BitwiseShiftLeft
| TSXToken::BitwiseShiftRight
| TSXToken::TemplateLiteralExpressionStart
| TSXToken::JSXFragmentStart => 2,

TSXToken::BitwiseShiftLeft
| TSXToken::BitwiseShiftRight
| TSXToken::Spread
TSXToken::Spread
| TSXToken::StrictEqual
| TSXToken::OptionalCall
| TSXToken::OptionalIndex
| TSXToken::NullishCoalescingAssign
| TSXToken::LogicalOrAssign
| TSXToken::LogicalAndAssign
Expand Down Expand Up @@ -369,6 +373,20 @@ impl TSXToken {
matches!(self, TSXToken::Comment(_) | TSXToken::MultiLineComment(_))
}

pub fn try_into_comment(
token: Token<TSXToken, TokenStart>,
) -> Result<(String, Span), Token<TSXToken, TokenStart>> {
if let Token(TSXToken::MultiLineComment(c), d) = token {
let len = c.len();
Ok((c, d.with_length(len + 4)))
} else if let Token(TSXToken::Comment(c), d) = token {
let len = c.len();
Ok((c, d.with_length(len + 2)))
} else {
Err(token)
}
}

pub fn is_string_literal(&self) -> bool {
matches!(
self,
Expand Down
22 changes: 22 additions & 0 deletions parser/tests/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,25 @@ param => {
// let output = module.to_string(&ToStringOptions::typescript());
// assert_eq!(output, input);
}

#[test]
fn function_calls() {
let input = r#"
x(4, 5);
y.t(2, 3);
y.t<4, 2>(3);
y.t<4, Array<5>>(3);
a(y<2>(4));
a.a?.(y<2>(4));
a.a(...expr, y)
"#
.trim();

let module =
Module::from_string(input.to_owned(), Default::default(), SourceId::NULL, None).unwrap();

eprintln!("Module: {:#?}", module);

let output = module.to_string(&ezno_parser::ToStringOptions::typescript());
assert_eq!(output, input);
}

0 comments on commit bedb2b5

Please sign in to comment.