diff --git a/crates/ast/src/token.rs b/crates/ast/src/token.rs index 62f344b1..b7b92e74 100644 --- a/crates/ast/src/token.rs +++ b/crates/ast/src/token.rs @@ -327,9 +327,11 @@ impl TokenKind { match self { Eq | Lt | Le | EqEq | Ne | Ge | Gt | AndAnd | OrOr | Not | Tilde | Walrus | PlusPlus | MinusMinus | StarStar | BinOp(_) | BinOpEq(_) | At | Dot | Comma - | Semi | Colon | Arrow | FatArrow | Question => true, + | Colon | Arrow | FatArrow | Question => true, - OpenDelim(..) | CloseDelim(..) | Literal(..) | Comment(..) | Ident(..) | Eof => false, + OpenDelim(..) | CloseDelim(..) | Literal(..) | Comment(..) | Ident(..) | Semi | Eof => { + false + } } } diff --git a/crates/parse/src/lexer/cursor/mod.rs b/crates/parse/src/lexer/cursor/mod.rs index 9cd6f6fb..42c12c6a 100644 --- a/crates/parse/src/lexer/cursor/mod.rs +++ b/crates/parse/src/lexer/cursor/mod.rs @@ -265,7 +265,7 @@ impl<'a> Cursor<'a> { // by field/method access (`12.foo()`) '.' if !is_id_start(self.second()) => { self.bump(); - let empty_fraction = !self.eat_decimal_digits(); + self.eat_decimal_digits(); let empty_exponent = match self.first() { 'e' | 'E' => { self.bump(); @@ -273,12 +273,12 @@ impl<'a> Cursor<'a> { } _ => false, }; - RawLiteralKind::Rational { base, empty_fraction, empty_exponent } + RawLiteralKind::Rational { base, empty_exponent } } 'e' | 'E' => { self.bump(); let empty_exponent = !self.eat_exponent(); - RawLiteralKind::Rational { base, empty_fraction: false, empty_exponent } + RawLiteralKind::Rational { base, empty_exponent } } _ => RawLiteralKind::Int { base, empty_int: false }, } diff --git a/crates/parse/src/lexer/cursor/token.rs b/crates/parse/src/lexer/cursor/token.rs index 857ffc2a..56b2c6d2 100644 --- a/crates/parse/src/lexer/cursor/token.rs +++ b/crates/parse/src/lexer/cursor/token.rs @@ -122,8 +122,8 @@ pub enum RawTokenKind { pub enum RawLiteralKind { /// `123`, `0x123`; empty_int: `0x` Int { base: Base, empty_int: bool }, - /// `123.321`, `1.2e3`; empty_fraction: `1.`, `1.e2`; empty_exponent: `2e`, `2.3e` - Rational { base: Base, empty_fraction: bool, empty_exponent: bool }, + /// `123.321`, `1.2e3`; empty_exponent: `2e`, `2.3e` + Rational { base: Base, empty_exponent: bool }, /// `"abc"`, `"abc`; `unicode"abc"`, `unicode"abc` Str { terminated: bool, unicode: bool }, /// `hex"abc"`, `hex"abc` diff --git a/crates/parse/src/lexer/mod.rs b/crates/parse/src/lexer/mod.rs index 428aef3b..c2d9748b 100644 --- a/crates/parse/src/lexer/mod.rs +++ b/crates/parse/src/lexer/mod.rs @@ -345,12 +345,7 @@ impl<'sess, 'src> Lexer<'sess, 'src> { (TokenLitKind::Integer, self.symbol_from_to(start, end)) } } - RawLiteralKind::Rational { base, empty_fraction, empty_exponent } => { - if empty_fraction { - let span = self.new_span(start, self.pos); - self.dcx().err("expected at least one digit in fraction").span(span).emit(); - } - + RawLiteralKind::Rational { base, empty_exponent } => { if empty_exponent { let span = self.new_span(start, self.pos); self.dcx().err("expected at least one digit in exponent").span(span).emit(); diff --git a/crates/parse/src/parser/item.rs b/crates/parse/src/parser/item.rs index 35df7e81..8fc32c59 100644 --- a/crates/parse/src/parser/item.rs +++ b/crates/parse/src/parser/item.rs @@ -1,8 +1,9 @@ use super::{ExpectedToken, SeqSep}; use crate::{PResult, Parser}; use itertools::Itertools; +use std::num::IntErrorKind; use sulk_ast::{ast::*, token::*}; -use sulk_interface::{error_code, kw, sym, Ident}; +use sulk_interface::{error_code, kw, sym, Ident, Span}; impl<'a> Parser<'a> { /// Parses a source unit. @@ -500,8 +501,8 @@ impl<'a> Parser<'a> { // 0.1 .2 let lit = self.token.lit().unwrap(); let (mj, mn) = lit.symbol.as_str().split_once('.').unwrap(); - major = SemverVersionNumber::Number(self.parse_u32(mj)?); - minor = Some(SemverVersionNumber::Number(self.parse_u32(mn)?)); + major = SemverVersionNumber::Number(self.parse_u32(mj, self.token.span)); + minor = Some(SemverVersionNumber::Number(self.parse_u32(mn, self.token.span))); self.bump(); patch = @@ -514,8 +515,8 @@ impl<'a> Parser<'a> { // *. 1.2 let lit = self.token.lit().unwrap(); let (mn, p) = lit.symbol.as_str().split_once('.').unwrap(); - minor = Some(SemverVersionNumber::Number(self.parse_u32(mn)?)); - patch = Some(SemverVersionNumber::Number(self.parse_u32(p)?)); + minor = Some(SemverVersionNumber::Number(self.parse_u32(mn, self.token.span))); + patch = Some(SemverVersionNumber::Number(self.parse_u32(p, self.token.span))); self.bump(); } else { // *.1 .2 @@ -548,13 +549,22 @@ impl<'a> Parser<'a> { self.expected_tokens.push(ExpectedToken::VersionNumber); return self.unexpected(); }; - let value = self.parse_u32(symbol.as_str()).map_err(|e| e.span(span))?; + let value = self.parse_u32(symbol.as_str(), span); self.bump(); Ok(SemverVersionNumber::Number(value)) } - fn parse_u32(&mut self, s: &str) -> PResult<'a, u32> { - s.parse::().map_err(|e| self.dcx().err(e.to_string())) + fn parse_u32(&mut self, s: &str, span: Span) -> u32 { + match s.parse::() { + Ok(n) => n, + Err(e) => match e.kind() { + IntErrorKind::Empty => 0, + _ => { + self.dcx().err(e.to_string()).span(span).emit(); + u32::MAX + } + }, + } } /// Parses an import directive. diff --git a/crates/sema/src/ast_validation.rs b/crates/sema/src/ast_validation.rs index 257d0ccf..6093df6f 100644 --- a/crates/sema/src/ast_validation.rs +++ b/crates/sema/src/ast_validation.rs @@ -40,9 +40,7 @@ impl<'ast, 'sess> Visit<'ast> for AstValidator<'sess> { if name.name != sym::solidity { let msg = "only `solidity` is supported as a version pragma"; self.dcx().err(msg).span(name.span).emit(); - // return; } - // TODO: Check or ignore version? } ast::PragmaTokens::Custom(name, value) => { let name = name.as_str(); diff --git a/tests/ui/parser/pragma_unknown.sol b/tests/ui/parser/pragma_unknown.sol new file mode 100644 index 00000000..bf917154 --- /dev/null +++ b/tests/ui/parser/pragma_unknown.sol @@ -0,0 +1,11 @@ + +pragma foo bar; +//~^ ERROR unknown pragma +pragma amogus; +//~^ ERROR unknown pragma +pragma amogus sus; +//~^ ERROR unknown pragma +pragma amogus 69; +//~^ ERROR unknown pragma +pragma amogus 69 diwqbn9ru3b2q945 390ru31290r 0qjr09wadm; +//~^ ERROR unknown pragma diff --git a/tests/ui/parser/pragma_unknown.stderr b/tests/ui/parser/pragma_unknown.stderr new file mode 100644 index 00000000..18ee89f2 --- /dev/null +++ b/tests/ui/parser/pragma_unknown.stderr @@ -0,0 +1,37 @@ +error: unknown pragma + --> $DIR/pragma_unknown.sol:2:1 + | +LL | pragma foo bar; + | ^^^^^^^^^^^^^^^ + | + +error: unknown pragma + --> $DIR/pragma_unknown.sol:4:1 + | +LL | pragma amogus; + | ^^^^^^^^^^^^^^ + | + +error: unknown pragma + --> $DIR/pragma_unknown.sol:6:1 + | +LL | pragma amogus sus; + | ^^^^^^^^^^^^^^^^^^ + | + +error: unknown pragma + --> $DIR/pragma_unknown.sol:8:1 + | +LL | pragma amogus 69; + | ^^^^^^^^^^^^^^^^^ + | + +error: unknown pragma + --> $DIR/pragma_unknown.sol:10:1 + | +LL | pragma amogus 69 diwqbn9ru3b2q945 390ru31290r 0qjr09wadm; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + +error: aborting due to 5 previous errors + diff --git a/tests/ui/parser/pragma_valid.sol b/tests/ui/parser/pragma_valid.sol new file mode 100644 index 00000000..8f7a026d --- /dev/null +++ b/tests/ui/parser/pragma_valid.sol @@ -0,0 +1,21 @@ +pragma abicoder v1; +pragma abicoder v2; +pragma abicoder "v1"; +pragma abicoder "v2"; + +// These aren't accepted by solc. +pragma "abicoder" v1; +pragma "abicoder" v2; +pragma "abicoder" "v1"; +pragma "abicoder" "v2"; + +pragma experimental ABIEncoderV2; +pragma experimental "ABIEncoderV2"; +pragma experimental SMTChecker; +pragma experimental "SMTChecker"; + +// These aren't accepted by solc. +pragma "experimental" ABIEncoderV2; +pragma "experimental" "ABIEncoderV2"; +pragma "experimental" SMTChecker; +pragma "experimental" "SMTChecker"; diff --git a/tests/ui/parser/pragmas.sol b/tests/ui/parser/pragma_versions.sol similarity index 73% rename from tests/ui/parser/pragmas.sol rename to tests/ui/parser/pragma_versions.sol index 38635a43..e08a6009 100644 --- a/tests/ui/parser/pragmas.sol +++ b/tests/ui/parser/pragma_versions.sol @@ -1,4 +1,3 @@ -// Commented out are lexed as empty literals "0." pragma solidity *.*.*; pragma solidity *.*.0 ; pragma solidity *.*.0; @@ -7,7 +6,7 @@ pragma solidity *.0 .*; pragma solidity *.0 .0 ; pragma solidity *.0 .0; pragma solidity *.0 ; -// pragma solidity *.0.*; +pragma solidity *.0.*; pragma solidity *.0.0 ; pragma solidity *.0.0; pragma solidity *.0; @@ -20,15 +19,15 @@ pragma solidity 0 .0 .*; pragma solidity 0 .0 .0 ; pragma solidity 0 .0 .0; pragma solidity 0 .0 ; -// pragma solidity 0 .0.*; +pragma solidity 0 .0.*; pragma solidity 0 .0.0 ; pragma solidity 0 .0.0; pragma solidity 0 .0; pragma solidity 0 ; -// pragma solidity 0.*.*; -// pragma solidity 0.*.0 ; -// pragma solidity 0.*.0; -// pragma solidity 0.*; +pragma solidity 0.*.*; +pragma solidity 0.*.0 ; +pragma solidity 0.*.0; +pragma solidity 0.*; pragma solidity 0.0 .*; pragma solidity 0.0 .0 ; pragma solidity 0.0 .0; @@ -39,13 +38,17 @@ pragma solidity 0.0.0; pragma solidity 0.0; pragma solidity 0; -// pragma foo bar; -// ~^ ERROR unknown pragma -pragma abicoder v2; -// pragma solidity ^4294967295; -// ~^ ERROR too large -pragma solidity 0 - 1 0 - 2; -//~^ ERROR ranges can only be combined using the || operator -pragma abicoder "v2"; pragma solidity ^0.5.16 =0.8.22 || >=0.8.21 <=2 ~1 0.6.2; pragma solidity 0.4 - 1 || 0.3 - 0.5.16; + +pragma solidity ^4294967295; +pragma solidity ^4294967296; +//~^ ERROR too large +pragma solidity ^0.4294967296; +//~^ ERROR too large + +pragma solidity 88_; +//~^ ERROR invalid digit + +pragma solidity 0 - 1 0 - 2; +//~^ ERROR ranges can only be combined using the || operator diff --git a/tests/ui/parser/pragma_versions.stderr b/tests/ui/parser/pragma_versions.stderr new file mode 100644 index 00000000..a60326c3 --- /dev/null +++ b/tests/ui/parser/pragma_versions.stderr @@ -0,0 +1,30 @@ +error: number too large to fit in target type + --> $DIR/pragma_versions.sol:45:18 + | +LL | pragma solidity ^4294967296; + | ^^^^^^^^^^ + | + +error: number too large to fit in target type + --> $DIR/pragma_versions.sol:47:18 + | +LL | pragma solidity ^0.4294967296; + | ^^^^^^^^^^^^ + | + +error: invalid digit found in string + --> $DIR/pragma_versions.sol:50:17 + | +LL | pragma solidity 88_; + | ^^^ + | + +error: ranges can only be combined using the || operator + --> $DIR/pragma_versions.sol:53:1 + | +LL | pragma solidity 0 - 1 0 - 2; + | ^^^^^^^^^^^^^^^^^^^^^ + | + +error: aborting due to 4 previous errors + diff --git a/tests/ui/parser/pragmas.stderr b/tests/ui/parser/pragmas.stderr deleted file mode 100644 index 10a616d8..00000000 --- a/tests/ui/parser/pragmas.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error: ranges can only be combined using the || operator - --> $DIR/pragmas.sol:47:1 - | -LL | pragma solidity 0 - 1 0 - 2; - | ^^^^^^^^^^^^^^^^^^^^^ - | - -error: aborting due to 1 previous error -