Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for including minus in literals. #3619

Merged
merged 1 commit into from
Jul 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion corelib/src/lib.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ extern fn felt252_mul(lhs: felt252, rhs: felt252) -> felt252 nopanic;
impl Felt252Neg of Neg<felt252> {
#[inline(always)]
fn neg(a: felt252) -> felt252 {
a * felt252_const::<-1>()
a * -1
}
}

Expand Down
31 changes: 17 additions & 14 deletions corelib/src/test/integer_test.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -1127,9 +1127,8 @@ fn test_i8_operators() {
assert_eq(@0x7f_felt252.try_into().unwrap(), @0x7f_i8, '0x7f is not i8');
let v: Option<i8> = 0x80_felt252.try_into();
assert(v.is_none(), '0x80 is i8');
let v: Option<i8> = (-0x80_felt252).try_into();
assert(v.is_some(), '-0x80 is not i8');
let v: Option<i8> = (-0x81_felt252).try_into();
assert_eq(@-0x80_felt252.try_into().unwrap(), @-0x80_i8, '-0x80 is not i8');
let v: Option<i8> = -0x81_felt252.try_into();
assert(v.is_none(), '-0x81 is i8');
}

Expand All @@ -1141,9 +1140,8 @@ fn test_i16_operators() {
assert_eq(@0x7fff_felt252.try_into().unwrap(), @0x7fff_i16, '0x7fff is not i16');
let v: Option<i16> = 0x8000_felt252.try_into();
assert(v.is_none(), '0x8000 is i16');
let v: Option<i16> = (-0x8000_felt252).try_into();
assert(v.is_some(), '-0x8000 is not i16');
let v: Option<i16> = (-0x8001_felt252).try_into();
assert_eq(@-0x8000_felt252.try_into().unwrap(), @-0x8000_i16, '-0x8000 is not i16');
let v: Option<i16> = -0x8001_felt252.try_into();
assert(v.is_none(), '-0x8001 is i16');
}

Expand All @@ -1155,9 +1153,8 @@ fn test_i32_operators() {
assert_eq(@0x7fffffff_felt252.try_into().unwrap(), @0x7fffffff_i32, '0x7fffffff is not i32');
let v: Option<i32> = 0x80000000_felt252.try_into();
assert(v.is_none(), '0x80000000 is i32');
let v: Option<i32> = (-0x80000000_felt252).try_into();
assert(v.is_some(), '-0x80000000 is not i32');
let v: Option<i32> = (-0x80000001_felt252).try_into();
assert_eq(@-0x80000000_felt252.try_into().unwrap(), @-0x80000000_i32, '-0x8000 is not i32');
let v: Option<i32> = -0x80000001_felt252.try_into();
assert(v.is_none(), '-0x80000001 is i32');
}

Expand All @@ -1169,12 +1166,15 @@ fn test_i64_operators() {
assert_eq(
@0x7fffffffffffffff_felt252.try_into().unwrap(),
@0x7fffffffffffffff_i64,
'-0x7fffffffffffffff is not i64'
'0x7fffffffffffffff is not i64'
);
let v: Option<i64> = 0x8000000000000000_felt252.try_into();
assert(v.is_none(), '0x8000000000000000 is i64');
let v: Option<i64> = (-0x8000000000000000_felt252).try_into();
assert(v.is_some(), '-0x8000000000000000 is not i64');
assert_eq(
@-0x8000000000000000_felt252.try_into().unwrap(),
@-0x8000000000000000_i64,
'-0x8000000000000000 is not i64'
);
let v: Option<i64> = (-0x8000000000000001_felt252).try_into();
assert(v.is_none(), '-0x8000000000000001 is i64');
}
Expand All @@ -1191,8 +1191,11 @@ fn test_i128_operators() {
);
let v: Option<i128> = 0x80000000000000000000000000000000_felt252.try_into();
assert(v.is_none(), '0x80..0 is i128');
let v: Option<i128> = (-0x80000000000000000000000000000000_felt252).try_into();
assert(v.is_some(), '-0x80..0 is not i128');
assert_eq(
@-0x80000000000000000000000000000000_felt252.try_into().unwrap(),
@-0x80000000000000000000000000000000_i128,
'-0x80..0 is not i128'
);
let v: Option<i128> = (-0x80000000000000000000000000000001_felt252).try_into();
assert(v.is_none(), '-0x80..01 is i128');
}
10 changes: 8 additions & 2 deletions crates/cairo-lang-formatter/src/node_properties.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,10 @@ impl SyntaxNodeFormat for SyntaxNode {
true
}
SyntaxKind::TokenMinus | SyntaxKind::TokenMul => {
matches!(grandparent_kind(db, self), Some(SyntaxKind::ExprUnary))
matches!(
grandparent_kind(db, self),
Some(SyntaxKind::ExprUnary | SyntaxKind::LiteralNumber)
)
}
SyntaxKind::TokenLT
if matches!(
Expand Down Expand Up @@ -546,7 +549,10 @@ impl SyntaxNodeFormat for SyntaxNode {
trailing: None,
},
SyntaxKind::TerminalMinus
if parent_kind(db, self) != Some(SyntaxKind::ExprUnary) =>
if !matches!(
parent_kind(db, self),
Some(SyntaxKind::ExprUnary | SyntaxKind::LiteralNumber)
) =>
{
WrappingBreakLinePoints {
leading: Some(BreakLinePointProperties::new(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ impl SemanticTokenKind {
Some(match kind {
_ if kind.is_keyword_token() => SemanticTokenKind::Keyword,
SyntaxKind::TokenIdentifier => SemanticTokenKind::Variable,
SyntaxKind::TokenLiteralNumber => SemanticTokenKind::Number,
SyntaxKind::TokenNumber => SemanticTokenKind::Number,
SyntaxKind::TokenAnd
| SyntaxKind::TokenAndAnd
| SyntaxKind::TokenOr
Expand Down
2 changes: 1 addition & 1 deletion crates/cairo-lang-lowering/src/inline/test_data/inline
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ End:

blk2:
Statements:
(v2: core::felt252) <- core::felt252_const::<LiteralLongId { value: -1 }>()
(v2: core::felt252) <- -1u
End:
Goto(blk4, {})

Expand Down
2 changes: 1 addition & 1 deletion crates/cairo-lang-parser/src/colored_printer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ fn set_color(text: SmolStr, kind: SyntaxKind) -> ColoredString {
| SyntaxKind::TokenDiv
| SyntaxKind::TokenMod
| SyntaxKind::TokenDot => text.bright_magenta(),
SyntaxKind::TokenLiteralNumber
SyntaxKind::TokenNumber
| SyntaxKind::TokenFalse
| SyntaxKind::TokenTrue
| SyntaxKind::TokenShortString => text.bright_cyan(),
Expand Down
6 changes: 3 additions & 3 deletions crates/cairo-lang-parser/src/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ impl<'a> Lexer<'a> {
if self.peek() == Some('_') {
self.take_while(|c| c.is_ascii_alphanumeric() || c == '_');
}
TokenKind::LiteralNumber
TokenKind::Number
}

/// Takes a short string.
Expand Down Expand Up @@ -326,7 +326,7 @@ enum TokenKind {
Identifier,

// Literals.
LiteralNumber,
Number,
ShortString,

// Keywords.
Expand Down Expand Up @@ -414,7 +414,7 @@ fn token_kind_to_terminal_syntax_kind(kind: TokenKind) -> SyntaxKind {
TokenKind::As => SyntaxKind::TerminalAs,
TokenKind::Const => SyntaxKind::TerminalConst,
TokenKind::Identifier => SyntaxKind::TerminalIdentifier,
TokenKind::LiteralNumber => SyntaxKind::TerminalLiteralNumber,
TokenKind::Number => SyntaxKind::TerminalNumber,
TokenKind::ShortString => SyntaxKind::TerminalShortString,
TokenKind::False => SyntaxKind::TerminalFalse,
TokenKind::True => SyntaxKind::TerminalTrue,
Expand Down
12 changes: 6 additions & 6 deletions crates/cairo-lang-parser/src/lexer_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use crate::utils::SimpleParserDatabase;
fn terminal_kind_to_text(kind: SyntaxKind) -> Vec<&'static str> {
match kind {
SyntaxKind::TerminalIdentifier => vec!["abc", "_az12f", "A90g5__"],
SyntaxKind::TerminalLiteralNumber => {
SyntaxKind::TerminalNumber => {
vec![
"0",
"0xA2",
Expand Down Expand Up @@ -104,7 +104,7 @@ fn terminal_kind_to_text(kind: SyntaxKind) -> Vec<&'static str> {
fn terminal_kinds() -> Vec<SyntaxKind> {
vec![
SyntaxKind::TerminalIdentifier,
SyntaxKind::TerminalLiteralNumber,
SyntaxKind::TerminalNumber,
SyntaxKind::TerminalFalse,
SyntaxKind::TerminalTrue,
SyntaxKind::TerminalExtern,
Expand Down Expand Up @@ -183,11 +183,11 @@ fn need_separator(
text1: &'static str,
) -> bool {
if is_identifier_like(kind0)
&& (is_identifier_like(kind1) || matches!(kind1, SyntaxKind::TerminalLiteralNumber))
&& (is_identifier_like(kind1) || matches!(kind1, SyntaxKind::TerminalNumber))
{
return true;
}
if kind0 == SyntaxKind::TerminalLiteralNumber && (kind0 == kind1 || is_identifier_like(kind1)) {
if kind0 == SyntaxKind::TerminalNumber && (kind0 == kind1 || is_identifier_like(kind1)) {
return true;
}
if kind0 == SyntaxKind::TerminalShortString
Expand All @@ -206,7 +206,7 @@ fn need_separator(
|| (text0 == "-" && (text1.starts_with('>') || text1.starts_with('=')))
|| ((text0 == "+" || text0 == "*" || text0 == "/" || text0 == "%")
&& text1.starts_with('='))
|| (kind0 == SyntaxKind::TerminalLiteralNumber && kind0 == kind1)
|| (kind0 == SyntaxKind::TerminalNumber && kind0 == kind1)
{
return true;
}
Expand Down Expand Up @@ -401,7 +401,7 @@ fn test_cases() {
},
LexerTerminal {
text: "6".into(),
kind: SyntaxKind::TerminalLiteralNumber,
kind: SyntaxKind::TerminalNumber,
leading_trivia: vec![],
trailing_trivia: vec![]
},
Expand Down
68 changes: 53 additions & 15 deletions crates/cairo-lang-parser/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -774,13 +774,7 @@ impl<'a> Parser<'a> {
parent_precedence: usize,
lbrace_allowed: LbraceAllowed,
) -> Option<ExprGreen> {
let mut expr = if let Some(precedence) = get_unary_operator_precedence(self.peek().kind) {
let op = self.expect_unary_operator();
let expr = self.parse_expr_limited(precedence, lbrace_allowed);
ExprUnary::new_green(self.db, op, expr).into()
} else {
self.try_parse_atom(lbrace_allowed)?
};
let mut expr = self.try_parse_atom_or_unary(lbrace_allowed)?;

while let Some(precedence) = get_post_operator_precedence(self.peek().kind) {
if precedence >= parent_precedence {
Expand All @@ -807,6 +801,32 @@ impl<'a> Parser<'a> {
}
Some(expr)
}

/// Returns a GreenId of a node with ExprPath, ExprFunctionCall, ExprStructCtorCall,
/// ExprParenthesized, ExprTuple, LiteralNumber or ExprUnary kind, or None if such an expression
/// can't be parsed.
///
/// `lbrace_allowed` - See [LbraceAllowed].
fn try_parse_atom_or_unary(&mut self, lbrace_allowed: LbraceAllowed) -> Option<ExprGreen> {
let Some(precedence) = get_unary_operator_precedence(self.peek().kind) else {
return self.try_parse_atom(lbrace_allowed);
};
let op = if self.peek().kind == SyntaxKind::TerminalMinus {
let minus = self.take::<TerminalMinus>();
if self.peek().kind == SyntaxKind::TerminalNumber {
return Some(
LiteralNumber::new_green(self.db, minus.into(), self.take::<TerminalNumber>())
.into(),
);
}
minus.into()
} else {
self.expect_unary_operator()
};
let expr = self.parse_expr_limited(precedence, lbrace_allowed);
Some(ExprUnary::new_green(self.db, op, expr).into())
}

/// Returns a GreenId of a node with an Expr.* kind (see [syntax::node::ast::Expr]),
/// excluding ExprBlock, or ExprMissing if such an expression can't be parsed.
///
Expand Down Expand Up @@ -844,7 +864,14 @@ impl<'a> Parser<'a> {
}
SyntaxKind::TerminalFalse => Some(self.take::<TerminalFalse>().into()),
SyntaxKind::TerminalTrue => Some(self.take::<TerminalTrue>().into()),
SyntaxKind::TerminalLiteralNumber => Some(self.take::<TerminalLiteralNumber>().into()),
SyntaxKind::TerminalNumber => Some(
LiteralNumber::new_green(
self.db,
OptionTerminalMinusEmpty::new_green(self.db).into(),
self.take::<TerminalNumber>(),
)
.into(),
),
SyntaxKind::TerminalShortString => Some(self.take::<TerminalShortString>().into()),
SyntaxKind::TerminalLParen => {
// Note that LBrace is allowed inside parenthesis, even if `lbrace_allowed` is
Expand Down Expand Up @@ -1315,7 +1342,12 @@ impl<'a> Parser<'a> {

// TODO(yuval): Support "Or" patterns.
Some(match self.peek().kind {
SyntaxKind::TerminalLiteralNumber => self.take::<TerminalLiteralNumber>().into(),
SyntaxKind::TerminalNumber => LiteralNumber::new_green(
self.db,
OptionTerminalMinusEmpty::new_green(self.db).into(),
self.take::<TerminalNumber>(),
)
.into(),
SyntaxKind::TerminalShortString => self.take::<TerminalShortString>().into(),
SyntaxKind::TerminalUnderscore => self.take::<TerminalUnderscore>().into(),
SyntaxKind::TerminalIdentifier => {
Expand Down Expand Up @@ -1778,12 +1810,18 @@ impl<'a> Parser<'a> {
}

let expr = match self.peek().kind {
SyntaxKind::TerminalLiteralNumber => self.take::<TerminalLiteralNumber>().into(),
SyntaxKind::TerminalMinus => {
let minus = self.take::<TerminalMinus>().into();
let literal = self.parse_token::<TerminalLiteralNumber>().into();
ExprUnary::new_green(self.db, minus, literal).into()
}
SyntaxKind::TerminalNumber => LiteralNumber::new_green(
self.db,
OptionTerminalMinusEmpty::new_green(self.db).into(),
self.take::<TerminalNumber>(),
)
.into(),
SyntaxKind::TerminalMinus => LiteralNumber::new_green(
self.db,
self.take::<TerminalMinus>().into(),
self.take::<TerminalNumber>(),
)
.into(),
SyntaxKind::TerminalShortString => self.take::<TerminalShortString>().into(),
SyntaxKind::TerminalLBrace => self.parse_block().into(),
_ => self.try_parse_type_expr()?,
Expand Down
8 changes: 6 additions & 2 deletions crates/cairo-lang-parser/src/parser_test_data/array
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ ExprPath
└── Top level kind: ExprIndexed
├── expr (kind: ExprPath) <ignored>
├── lbrack (kind: TokenLBrack): '['
├── index_expr (kind: TokenLiteralNumber): '1'
├── index_expr (kind: LiteralNumber)
│ ├── sign (kind: OptionTerminalMinusEmpty) []
│ └── number (kind: TokenNumber): '1'
└── rbrack (kind: TokenRBrack): ']'

//! > ==========================================================================
Expand Down Expand Up @@ -107,6 +109,8 @@ ExprPath
├── index_expr (kind: ExprIndexed)
│ ├── expr (kind: ExprPath) <ignored>
│ ├── lbrack (kind: TokenLBrack): '['
│ ├── index_expr (kind: TokenLiteralNumber): '1'
│ ├── index_expr (kind: LiteralNumber)
│ │ ├── sign (kind: OptionTerminalMinusEmpty) []
│ │ └── number (kind: TokenNumber): '1'
│ └── rbrack (kind: TokenRBrack): ']'
└── rbrack (kind: TokenRBrack): ']'
8 changes: 6 additions & 2 deletions crates/cairo-lang-parser/src/parser_test_data/constant
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ ItemConstant
│ │ └── ident (kind: TokenIdentifier): 'felt252'
│ └── rangle (kind: TokenGT): '>'
├── eq (kind: TokenEq): '='
├── value (kind: TokenLiteralNumber): '0x1234'
├── value (kind: LiteralNumber)
│ ├── sign (kind: OptionTerminalMinusEmpty) []
│ └── number (kind: TokenNumber): '0x1234'
└── semicolon (kind: TokenSemicolon): ';'

//! > ==========================================================================
Expand Down Expand Up @@ -66,5 +68,7 @@ const X = 0x1234;
│ ├── colon: Missing
│ └── ty: Missing []
├── eq (kind: TokenEq): '='
├── value (kind: TokenLiteralNumber): '0x1234'
├── value (kind: LiteralNumber)
│ ├── sign (kind: OptionTerminalMinusEmpty) []
│ └── number (kind: TokenNumber): '0x1234'
└── semicolon (kind: TokenSemicolon): ';'
Loading