Skip to content
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
8 changes: 8 additions & 0 deletions compiler/noirc_frontend/src/lexer/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ pub enum LexerErrorKind {
NotADoubleChar { span: Span, found: Token },
#[error("Invalid integer literal, {:?} is not a integer", found)]
InvalidIntegerLiteral { span: Span, found: String },
#[error("Integer literal is too large")]
IntegerLiteralTooLarge { span: Span, limit: String },
#[error("{:?} is not a valid attribute", found)]
MalformedFuncAttribute { span: Span, found: String },
#[error("Logical and used instead of bitwise and")]
Expand Down Expand Up @@ -46,6 +48,7 @@ impl LexerErrorKind {
LexerErrorKind::UnexpectedCharacter { span, .. } => *span,
LexerErrorKind::NotADoubleChar { span, .. } => *span,
LexerErrorKind::InvalidIntegerLiteral { span, .. } => *span,
LexerErrorKind::IntegerLiteralTooLarge { span, .. } => *span,
LexerErrorKind::MalformedFuncAttribute { span, .. } => *span,
LexerErrorKind::LogicalAnd { span } => *span,
LexerErrorKind::UnterminatedBlockComment { span } => *span,
Expand Down Expand Up @@ -83,6 +86,11 @@ impl LexerErrorKind {
format!(" {found} is not an integer"),
*span,
),
LexerErrorKind::IntegerLiteralTooLarge { span, limit } => (
"Integer literal is too large".to_string(),
format!("value exceeds limit of {limit}"),
*span,
),
LexerErrorKind::MalformedFuncAttribute { span, found } => (
"Malformed function attribute".to_string(),
format!(" {found} is not a valid attribute"),
Expand Down
42 changes: 37 additions & 5 deletions compiler/noirc_frontend/src/lexer/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ use super::{
token_to_borrowed_token, BorrowedToken, IntType, Keyword, SpannedToken, Token, Tokens,
},
};
use acvm::FieldElement;
use acvm::{AcirField, FieldElement};
use noirc_errors::{Position, Span};
use std::str::CharIndices;
use num_bigint::BigInt;
use num_traits::{Num, One};
use std::str::{CharIndices, FromStr};

/// The job of the lexer is to transform an iterator of characters (`char_iter`)
/// into an iterator of `SpannedToken`. Each `Token` corresponds roughly to 1 word or operator.
Expand All @@ -19,6 +21,7 @@ pub struct Lexer<'a> {
done: bool,
skip_comments: bool,
skip_whitespaces: bool,
max_integer: BigInt,
}

pub type SpannedTokenResult = Result<SpannedToken, LexerErrorKind>;
Expand Down Expand Up @@ -61,6 +64,8 @@ impl<'a> Lexer<'a> {
done: false,
skip_comments: true,
skip_whitespaces: true,
max_integer: BigInt::from_biguint(num_bigint::Sign::Plus, FieldElement::modulus())
- BigInt::one(),
}
}

Expand Down Expand Up @@ -376,14 +381,28 @@ impl<'a> Lexer<'a> {
// Underscores needs to be stripped out before the literal can be converted to a `FieldElement.
let integer_str = integer_str.replace('_', "");

let integer = match FieldElement::try_from_str(&integer_str) {
None => {
let bigint_result = match integer_str.strip_prefix("0x") {
Some(integer_str) => BigInt::from_str_radix(integer_str, 16),
None => BigInt::from_str(&integer_str),
};

let integer = match bigint_result {
Ok(bigint) => {
if bigint > self.max_integer {
return Err(LexerErrorKind::IntegerLiteralTooLarge {
span: Span::inclusive(start, end),
limit: self.max_integer.to_string(),
});
}
let big_uint = bigint.magnitude();
FieldElement::from_be_bytes_reduce(&big_uint.to_bytes_be())
}
Err(_) => {
return Err(LexerErrorKind::InvalidIntegerLiteral {
span: Span::inclusive(start, end),
found: integer_str,
})
}
Some(integer) => integer,
};

let integer_token = Token::Int(integer);
Expand Down Expand Up @@ -899,6 +918,19 @@ mod tests {
}
}

#[test]
fn test_int_too_large() {
let modulus = FieldElement::modulus();
let input = modulus.to_string();

let mut lexer = Lexer::new(&input);
let token = lexer.next_token();
assert!(
matches!(token, Err(LexerErrorKind::IntegerLiteralTooLarge { .. })),
"expected {input} to throw error"
);
}

#[test]
fn test_arithmetic_sugar() {
let input = "+= -= *= /= %=";
Expand Down
5 changes: 5 additions & 0 deletions test_programs/compile_failure/integer_too_large/Nargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[package]
name = "integer_too_large"
type = "bin"
authors = [""]
[dependencies]
4 changes: 4 additions & 0 deletions test_programs/compile_failure/integer_too_large/src/main.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
fn main(x: Field) {
let too_large: Field = 233149999999999999999999999999999999999999999999999999999999923314999999999999999999999999999999999999999999999999999999999923314999999999999999999999999999999999999999999999999999999999;
assert(x == too_large);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ use std::ec::swcurve::curvegroup::Point as SWG;

use std::ec::montcurve::affine::Point as MGaffine;
use std::ec::montcurve::curvegroup::Point as MG;
use std::compat;

fn main() {
// This test only makes sense if Field is the right prime field.
if 21888242871839275222246405745257275088548364400416034343698204186575808495617 == 0 {
if compat::is_bn254() {
Comment thread
asterite marked this conversation as resolved.
// Define Baby Jubjub (ERC-2494) parameters in affine representation
let bjj_affine = AffineCurve::new(
168700,
Expand Down