Browse Source

string literals can use single quotes as well

The same is true for hex'ff' and unicode'😷'

Signed-off-by: Sean Young <sean@mess.org>
Sean Young 4 years ago
parent
commit
f6f1b5aa63

+ 42 - 31
src/parser/lexer.rs

@@ -598,10 +598,11 @@ impl<'input> Lexer<'input> {
         Some(Ok((start, Token::Number(base, exp), end + 1)))
     }
 
-    fn lex_string(
+    fn string(
         &mut self,
         token_start: usize,
         string_start: usize,
+        quote_char: char,
     ) -> Option<Result<(usize, Token<'input>, usize), LexicalError>> {
         let mut end;
 
@@ -611,7 +612,7 @@ impl<'input> Lexer<'input> {
             if let Some((i, ch)) = self.chars.next() {
                 end = i;
                 if !last_was_escape {
-                    if ch == '"' {
+                    if ch == quote_char {
                         break;
                     }
                     last_was_escape = ch == '\\';
@@ -655,44 +656,54 @@ impl<'input> Lexer<'input> {
                     let id = &self.input[start..end];
 
                     if id == "unicode" {
-                        if let Some((_, '"')) = self.chars.peek() {
-                            self.chars.next();
+                        match self.chars.peek() {
+                            Some((_, quote_char @ '"')) | Some((_, quote_char @ '\'')) => {
+                                let quote_char = *quote_char;
+
+                                self.chars.next();
 
-                            return self.lex_string(start, start + 8);
+                                return self.string(start, start + 8, quote_char);
+                            }
+                            _ => (),
                         }
                     }
 
                     if id == "hex" {
-                        if let Some((_, '"')) = self.chars.peek() {
-                            self.chars.next();
+                        match self.chars.peek() {
+                            Some((_, quote_char @ '"')) | Some((_, quote_char @ '\'')) => {
+                                let quote_char = *quote_char;
 
-                            while let Some((i, ch)) = self.chars.next() {
-                                if ch == '"' {
-                                    return Some(Ok((
-                                        start,
-                                        Token::HexLiteral(&self.input[start..=i]),
-                                        i + 1,
-                                    )));
-                                }
+                                self.chars.next();
 
-                                if !ch.is_ascii_hexdigit() && ch != '_' {
-                                    // Eat up the remainer of the string
-                                    while let Some((_, ch)) = self.chars.next() {
-                                        if ch == '"' {
-                                            break;
-                                        }
+                                while let Some((i, ch)) = self.chars.next() {
+                                    if ch == quote_char {
+                                        return Some(Ok((
+                                            start,
+                                            Token::HexLiteral(&self.input[start..=i]),
+                                            i + 1,
+                                        )));
                                     }
 
-                                    return Some(Err(LexicalError::InvalidCharacterInHexLiteral(
-                                        i, ch,
-                                    )));
+                                    if !ch.is_ascii_hexdigit() && ch != '_' {
+                                        // Eat up the remainer of the string
+                                        while let Some((_, ch)) = self.chars.next() {
+                                            if ch == quote_char {
+                                                break;
+                                            }
+                                        }
+
+                                        return Some(Err(
+                                            LexicalError::InvalidCharacterInHexLiteral(i, ch),
+                                        ));
+                                    }
                                 }
-                            }
 
-                            return Some(Err(LexicalError::EndOfFileInString(
-                                start,
-                                self.input.len(),
-                            )));
+                                return Some(Err(LexicalError::EndOfFileInString(
+                                    start,
+                                    self.input.len(),
+                                )));
+                            }
+                            _ => (),
                         }
                     }
 
@@ -702,8 +713,8 @@ impl<'input> Lexer<'input> {
                         Some(Ok((start, Token::Identifier(id), end)))
                     };
                 }
-                Some((start, '"')) => {
-                    return self.lex_string(start, start + 1);
+                Some((start, quote_char @ '"')) | Some((start, quote_char @ '\'')) => {
+                    return self.string(start, start + 1, quote_char);
                 }
                 Some((start, '/')) => {
                     match self.chars.peek() {

+ 1 - 1
src/parser/solidity.lalrpop

@@ -425,7 +425,7 @@ HexLiteral: HexLiteral = {
         let v = s.to_string();
         let hex_len = v.len() - 5;
 
-        HexLiteral{ loc: Loc(file_no, l, r), hex: v.chars().skip(4).filter(|c| *c != '_' && *c != '"').collect() }
+        HexLiteral{ loc: Loc(file_no, l, r), hex: v.chars().skip(4).filter(|c| *c != '_' && *c != '"' && *c != '\'').collect() }
     }
 }
 

+ 2 - 2
src/parser/solidity.rs

@@ -1,5 +1,5 @@
 // auto-generated: "lalrpop 0.19.1"
-// sha256: 301a78dcee7a1c40911379dbd9ba0fead851bbd638abbf920149fba1c7f64e8
+// sha256: d824f953338687a3744ed9d105f23e9a8beceb63c77096a3b451dbd91283a1
 use std::str::FromStr;
 use num_bigint::BigInt;
 use num_bigint::BigUint;
@@ -15932,7 +15932,7 @@ fn __action160<
         let v = s.to_string();
         let hex_len = v.len() - 5;
 
-        HexLiteral{ loc: Loc(file_no, l, r), hex: v.chars().skip(4).filter(|c| *c != '_' && *c != '"').collect() }
+        HexLiteral{ loc: Loc(file_no, l, r), hex: v.chars().skip(4).filter(|c| *c != '_' && *c != '"' && *c != '\'').collect() }
     }
 }
 

+ 1 - 1
tests/substrate_tests/primitives.rs

@@ -684,7 +684,7 @@ fn literal_bytes_cast() {
             function foo() public {
                 bytes4 x = bytes4(hex"acaf3289d7b601cbd114fb36c4d29c85bbfd5e133f14cb355c3fd8d99367964f");
 
-                assert(x == hex"acaf_3289");
+                assert(x == hex'acaf_3289');
 
 
                 bytes32 y = hex"acaf3289d7b601cbd114fb36c4d29c85bbfd5e133f14cb355c3fd8d99367964f";

+ 4 - 4
tests/substrate_tests/strings.rs

@@ -168,9 +168,9 @@ fn string_compare() {
         r##"
         contract foo {
             function test() public {
-                assert(hex"414243" == "ABC");
+                assert(hex"414243" == 'ABC');
 
-                assert(hex"414243" != "ABD");
+                assert(hex'414243' != "ABD");
             }
         }"##,
     );
@@ -181,11 +181,11 @@ fn string_compare() {
         r##"
         contract foo {
             function lets_compare1(string s) private returns (bool) {
-                return s == "the quick brown fox jumps over the lazy dog";
+                return s == unicode'the quick brown fox jumps over the lazy dog';
             }
 
             function lets_compare2(string s) private returns (bool) {
-                return "the quick brown fox jumps over the lazy dog" == s;
+                return unicode"the quick brown fox jumps over the lazy dog" == s;
             }
 
             function test() public {