Skip to content

Commit

Permalink
Merge branch 'master' into symbol-resolve-ctx
Browse files Browse the repository at this point in the history
  • Loading branch information
tritao committed Aug 5, 2024
2 parents 2c8dc64 + 68b7b34 commit a5cb793
Show file tree
Hide file tree
Showing 15 changed files with 146 additions and 52 deletions.
9 changes: 7 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,12 @@ 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
7 changes: 4 additions & 3 deletions sway-lib-std/src/call_frames.sw
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,11 @@ pub fn msg_asset_id() -> AssetId {
/// }
/// ```
pub fn code_size() -> u64 {
asm(size, ptr, offset: 576) {
let ptr = asm(size, ptr, offset: 576) {
add size fp offset;
size: u64
}
size: raw_ptr
};
ptr.read::<u64>()
}

/// Get the first parameter from the current call frame.
Expand Down
26 changes: 21 additions & 5 deletions sway-parse/src/item/item_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,28 @@ mod tests {

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

// "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
34 changes: 28 additions & 6 deletions sway-parse/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,18 @@ 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 => 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 +235,23 @@ 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,
};
Ok(Some((value, consumed)))
let r = T::parse_to_end(fork);
if append_diagnostics {
self.handler.append(handler);
}
r
}

pub fn enter_delimited(
Expand Down
25 changes: 17 additions & 8 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,11 @@ where
{
let handler = <_>::default();
let ts = crate::token::lex(&handler, &Arc::from(input), 0, input.len(), None).unwrap();
Parser::new(&handler, &ts)
.parse_to_end()
.map(|(m, _)| m)
.unwrap_or_else(|_| panic!("Parse error: {:?}", handler.consume().0))
let r = Parser::new(&handler, &ts).parse_to_end().map(|(m, _)| m);

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

r.unwrap_or_else(|_| panic!("Parse error: {:?}", handler.consume().0))
}
63 changes: 49 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,24 @@ 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 +62,26 @@ 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[type]
// TODO: deprecate this syntax (see https://github.com/FuelLabs/sway/issues/5110)
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 +91,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 +146,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
25 changes: 17 additions & 8 deletions swayfmt/src/utils/language/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,15 +117,20 @@ fn format_ptr(

fn format_slice(
formatted_code: &mut FormattedCode,
slice_token: SliceToken,
slice_token: Option<SliceToken>,
ty: SquareBrackets<Box<Ty>>,
) -> Result<(), FormatterError> {
write!(
formatted_code,
"{}[{}]",
slice_token.span().as_str(),
ty.into_inner().span().as_str()
)?;
if let Some(slice_token) = slice_token {
write!(
formatted_code,
"{}[{}]",
slice_token.span().as_str(),
ty.into_inner().span().as_str()
)?;
} else {
write!(formatted_code, "[{}]", ty.into_inner().span().as_str())?;
}

Ok(())
}

Expand Down Expand Up @@ -202,7 +207,11 @@ impl LeafSpans for Ty {
collected_spans
}
Ty::Slice { slice_token, ty } => {
let mut collected_spans = vec![ByteSpan::from(slice_token.span())];
let mut collected_spans = if let Some(slice_token) = slice_token {
vec![ByteSpan::from(slice_token.span())]
} else {
vec![]
};
collected_spans.append(&mut ty.leaf_spans());
collected_spans
}
Expand Down
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
9 changes: 3 additions & 6 deletions test/src/sdk-harness/test_projects/call_frames/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use fuel_vm::consts::VM_MAX_RAM;
use fuels::{accounts::wallet::WalletUnlocked, prelude::*, types::ContractId};

abigen!(Contract(
Expand Down Expand Up @@ -36,7 +35,9 @@ async fn can_get_id_contract_id_this() {
async fn can_get_code_size() {
let (instance, _id) = get_call_frames_instance().await;
let result = instance.methods().get_code_size().call().await.unwrap();
assert!(is_within_range(result.value));
// Check if codesize is between 1000 and 7000. Arbitrary endpoints, current codesize is 6816
// but the lower bound future proofs against compiler optimizations
assert!(result.value > 1000 && result.value < 7000);
}

#[tokio::test]
Expand Down Expand Up @@ -110,7 +111,3 @@ async fn can_get_second_param_multiple_params2() {
.unwrap();
assert_eq!(result.value, (300, expected_struct, expected_struct2));
}

fn is_within_range(n: u64) -> bool {
n > 0 && n <= VM_MAX_RAM
}

0 comments on commit a5cb793

Please sign in to comment.