Skip to content

Commit

Permalink
supports slice new syntax &[T]
Browse files Browse the repository at this point in the history
  • Loading branch information
xunilrj committed Jul 29, 2024
1 parent ec01af4 commit 09a1b34
Show file tree
Hide file tree
Showing 12 changed files with 108 additions and 35 deletions.
7 changes: 5 additions & 2 deletions sway-ast/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub enum Ty {
ty: SquareBrackets<Box<Ty>>,
},
Slice {
slice_token: SliceToken,
slice_token: Option<SliceToken>,
ty: SquareBrackets<Box<Ty>>,
},
Ref {
Expand All @@ -42,7 +42,10 @@ impl Spanned for Ty {
Ty::StringArray { str_token, length } => Span::join(str_token.span(), &length.span()),
Ty::Infer { underscore_token } => underscore_token.span(),
Ty::Ptr { ptr_token, ty } => Span::join(ptr_token.span(), &ty.span()),
Ty::Slice { slice_token, ty } => Span::join(slice_token.span(), &ty.span()),
Ty::Slice { slice_token, ty } => {
let span = slice_token.as_ref().map(|s| Span::join(s.span(), &ty.span()));
span.unwrap_or_else(|| ty.span())
},
Ty::Ref {
ampersand_token,
mut_token: _,
Expand Down
16 changes: 10 additions & 6 deletions sway-parse/src/item/item_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,16 @@ mod tests {

#[test]
fn parse_impl_slice() {
let item = parse::<ItemImpl>(
r#"
impl __slice[T] {}
"#,
);
assert_matches!(item.ty, Ty::Slice { .. });
// deprecated syntax
let item = parse::<ItemImpl>("impl __slice[T] {}");
assert_matches!(item.ty, Ty::Slice { slice_token: Some(..), ty: _ });

// "new" syntax
let item = parse::<ItemImpl>("impl [T] {}");
assert_matches!(item.ty, Ty::Slice { slice_token: None, ty: _ });

let item = parse::<ItemImpl>("impl &[T] {}");
assert_matches!(item.ty, Ty::Ref { ty, .. } if matches!(&*ty, Ty::Slice { .. }));
}

#[test]
Expand Down
33 changes: 27 additions & 6 deletions sway-parse/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,15 @@ impl<'a, 'e> Parser<'a, 'e> {
r
}

/// This method is useful if `T` does not impl `ParseToEnd`
pub fn try_parse_and_check_empty<T: Parse>(mut self, append_diagnostics: bool) -> ParseResult<Option<(T, ParserConsumed<'a>)>> {
let value = self.try_parse(append_diagnostics)?;
match self.check_empty() {
Some(consumed) => Ok(Some((value, consumed))),
None => return Ok(None),
}
}

/// Parses a `T` in its canonical way.
pub fn parse<T: Parse>(&mut self) -> ParseResult<T> {
T::parse(self)
Expand All @@ -223,13 +232,25 @@ impl<'a, 'e> Parser<'a, 'e> {
T::parse_to_end(self)
}

pub fn try_parse_to_end<T: Parse>(mut self) -> ParseResult<Option<(T, ParserConsumed<'a>)>> {
let value = self.parse()?;
let consumed = match self.check_empty() {
Some(consumed) => consumed,
None => return Ok(None),
/// Do not advance the parser on failure
pub fn try_parse_to_end<T: ParseToEnd>(&mut self, append_diagnostics: bool) -> ParseResult<(T, ParserConsumed<'a>)> {
let handler = Handler::default();
let fork = Parser {
token_trees: self.token_trees,
full_span: self.full_span.clone(),
handler: &handler,
check_double_underscore: self.check_double_underscore,
};
let r = match T::parse_to_end(fork) {
Ok(result) => {
Ok(result)
}
Err(err) => Err(err),
};
Ok(Some((value, consumed)))
if append_diagnostics {
self.handler.append(handler);
}
r
}

pub fn enter_delimited(
Expand Down
25 changes: 18 additions & 7 deletions sway-parse/src/test_utils.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
use sway_error::handler::Handler;

use crate::{priv_prelude::ParseToEnd, Parse, Parser};
use std::sync::Arc;

pub fn parse<T>(input: &str) -> T
where
T: Parse,
{
let handler = <_>::default();
let handler = Handler::default();
let ts = crate::token::lex(&handler, &Arc::from(input), 0, input.len(), None).unwrap();
Parser::new(&handler, &ts)
.parse()
.unwrap_or_else(|_| panic!("Parse error: {:?}", handler.consume().0))
let r = Parser::new(&handler, &ts).parse();

if handler.has_errors() || handler.has_warnings() {
panic!("{:?}", handler.consume());
}

r.unwrap_or_else(|_| panic!("Parse error: {:?}", handler.consume().0))
}

pub fn parse_to_end<T>(input: &str) -> T
Expand All @@ -18,8 +24,13 @@ where
{
let handler = <_>::default();
let ts = crate::token::lex(&handler, &Arc::from(input), 0, input.len(), None).unwrap();
Parser::new(&handler, &ts)
let r = Parser::new(&handler, &ts)
.parse_to_end()
.map(|(m, _)| m)
.unwrap_or_else(|_| panic!("Parse error: {:?}", handler.consume().0))
.map(|(m, _)| m);

if handler.has_errors() || handler.has_warnings() {
panic!("{:?}", handler.consume());
}

r.unwrap_or_else(|_| panic!("Parse error: {:?}", handler.consume().0))
}
62 changes: 48 additions & 14 deletions sway-parse/src/ty/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use crate::{Parse, ParseBracket, ParseResult, ParseToEnd, Parser, ParserConsumed};

use sway_ast::brackets::{Parens, SquareBrackets};
use sway_ast::keywords::{DoubleColonToken, OpenAngleBracketToken};
use sway_ast::keywords::{DoubleColonToken, OpenAngleBracketToken, PtrToken, SliceToken};
use sway_ast::ty::{Ty, TyArrayDescriptor, TyTupleDescriptor};
use sway_error::parser_error::ParseErrorKind;
use sway_types::{ast::Delimiter, Ident};
Expand Down Expand Up @@ -30,9 +29,27 @@ impl Parse for Ty {
return Err(parser
.emit_error(ParseErrorKind::ExpectedCommaOrCloseParenInTupleOrParenExpression));
}
if let Some(descriptor) = SquareBrackets::try_parse(parser)? {
return Ok(Ty::Array(descriptor));
};

if let Some((mut inner_parser, span)) = parser.enter_delimited(Delimiter::Bracket) {
// array like [type; len]
if let Ok((array, _)) = inner_parser.try_parse_to_end::<TyArrayDescriptor>(false) {
return Ok(Ty::Array(SquareBrackets {
inner: array,
span
}));
}

// slice like [type]
if let Ok(Some((ty, _))) = inner_parser.try_parse_and_check_empty::<Ty>(false) {
return Ok(Ty::Slice {
slice_token: None,
ty: SquareBrackets{
inner: Box::new(ty),
span,
}
});
}
}

if let Some(str_token) = parser.take() {
let length = SquareBrackets::try_parse_all_inner(parser, |mut parser| {
Expand All @@ -48,18 +65,22 @@ impl Parse for Ty {
if let Some(underscore_token) = parser.take() {
return Ok(Ty::Infer { underscore_token });
}
if let Some(ptr_token) = parser.take() {

if let Some(ptr_token) = parser.take::<PtrToken>() {
let ty = SquareBrackets::parse_all_inner(parser, |mut parser| {
parser.emit_error(ParseErrorKind::UnexpectedTokenAfterPtrType)
})?;
return Ok(Ty::Ptr { ptr_token, ty });
}
if let Some(slice_token) = parser.take() {
let ty = SquareBrackets::parse_all_inner(parser, |mut parser| {

// slice like __slice[ty]
if let Some(slice_token) = parser.take::<SliceToken>() {
let ty = SquareBrackets::<Box<Ty>>::parse_all_inner(parser, |mut parser| {
parser.emit_error(ParseErrorKind::UnexpectedTokenAfterSliceType)
})?;
return Ok(Ty::Slice { slice_token, ty });
return Ok(Ty::Slice { slice_token: Some(slice_token), ty });
}

if let Some(ampersand_token) = parser.take() {
let mut_token = parser.take();
let ty = Box::new(parser.parse()?);
Expand All @@ -69,16 +90,19 @@ impl Parse for Ty {
ty,
});
}

if let Some(bang_token) = parser.take() {
return Ok(Ty::Never { bang_token });
}

if parser.peek::<OpenAngleBracketToken>().is_some()
|| parser.peek::<DoubleColonToken>().is_some()
|| parser.peek::<Ident>().is_some()
{
let path_type = parser.parse()?;
return Ok(Ty::Path(path_type));
}

Err(parser.emit_error(ParseErrorKind::ExpectedType))
}
}
Expand Down Expand Up @@ -121,14 +145,24 @@ mod tests {
assert_matches!(item, Ty::Ptr { .. });
}

#[test]
fn parse_array() {
let item = parse::<Ty>("[T; 1]");
assert_matches!(item, Ty::Array { .. });
}

#[test]
fn parse_slice() {
let item = parse::<Ty>(
r#"
__slice[T]
"#,
);
// deprecated syntax
let item = parse::<Ty>("__slice[T]");
assert_matches!(item, Ty::Slice { .. });

// " new" syntax
let item = parse::<Ty>("[T]");
assert_matches!(item, Ty::Slice { .. });

let item = parse::<Ty>("&[T]");
assert_matches!(item, Ty::Ref { ty, .. } if matches!(&*ty, Ty::Slice { .. }));
}

#[test]
Expand Down
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.

0 comments on commit 09a1b34

Please sign in to comment.