From 64c73baee917e0c9e3682ae9ff62dd5a64b8d032 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Wed, 29 Jul 2020 14:20:59 +0100 Subject: [PATCH 1/6] Use only advance() and not with a mix of m_scanner->next() --- libyul/AsmParser.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libyul/AsmParser.cpp b/libyul/AsmParser.cpp index 83f17a0d3..1e3b563d7 100644 --- a/libyul/AsmParser.cpp +++ b/libyul/AsmParser.cpp @@ -116,14 +116,14 @@ Statement Parser::parseStatement() { Statement stmt{createWithLocation()}; checkBreakContinuePosition("break"); - m_scanner->next(); + advance(); return stmt; } case Token::Continue: { Statement stmt{createWithLocation()}; checkBreakContinuePosition("continue"); - m_scanner->next(); + advance(); return stmt; } case Token::Identifier: @@ -132,7 +132,7 @@ Statement Parser::parseStatement() Statement stmt{createWithLocation()}; if (!m_insideFunction) m_errorReporter.syntaxError(8149_error, currentLocation(), "Keyword \"leave\" can only be used inside a function."); - m_scanner->next(); + advance(); return stmt; } break; From bd7283ad22d51622c1c43bea2356748bf8277205 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Mon, 27 Jul 2020 18:34:24 +0100 Subject: [PATCH 2/6] Add scanner test for specially handled keywords in Yul --- test/liblangutil/Scanner.cpp | 65 ++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/test/liblangutil/Scanner.cpp b/test/liblangutil/Scanner.cpp index 755f59c2f..862b19c00 100644 --- a/test/liblangutil/Scanner.cpp +++ b/test/liblangutil/Scanner.cpp @@ -819,6 +819,71 @@ BOOST_AUTO_TEST_CASE(irregular_line_breaks_in_strings) } } +BOOST_AUTO_TEST_CASE(solidity_keywords) +{ + // These are tokens which have a different meaning in Yul. + string keywords = "return byte bool address var in true false leave switch case default"; + Scanner scanner(CharStream(keywords, "")); + BOOST_CHECK_EQUAL(scanner.currentToken(), Token::Return); + BOOST_CHECK_EQUAL(scanner.next(), Token::Byte); + BOOST_CHECK_EQUAL(scanner.next(), Token::Bool); + BOOST_CHECK_EQUAL(scanner.next(), Token::Address); + BOOST_CHECK_EQUAL(scanner.next(), Token::Var); + BOOST_CHECK_EQUAL(scanner.next(), Token::In); + BOOST_CHECK_EQUAL(scanner.next(), Token::TrueLiteral); + BOOST_CHECK_EQUAL(scanner.next(), Token::FalseLiteral); + BOOST_CHECK_EQUAL(scanner.next(), Token::Identifier); + BOOST_CHECK_EQUAL(scanner.next(), Token::Switch); + BOOST_CHECK_EQUAL(scanner.next(), Token::Case); + BOOST_CHECK_EQUAL(scanner.next(), Token::Default); + BOOST_CHECK_EQUAL(scanner.next(), Token::EOS); + scanner.reset(CharStream(keywords, "")); + scanner.setScannerMode(ScannerKind::Yul); + BOOST_CHECK_EQUAL(scanner.currentToken(), Token::Return); + BOOST_CHECK_EQUAL(scanner.next(), Token::Byte); + BOOST_CHECK_EQUAL(scanner.next(), Token::Bool); + BOOST_CHECK_EQUAL(scanner.next(), Token::Address); + BOOST_CHECK_EQUAL(scanner.next(), Token::Var); + BOOST_CHECK_EQUAL(scanner.next(), Token::In); + BOOST_CHECK_EQUAL(scanner.next(), Token::TrueLiteral); + BOOST_CHECK_EQUAL(scanner.next(), Token::FalseLiteral); + BOOST_CHECK_EQUAL(scanner.next(), Token::Identifier); + BOOST_CHECK_EQUAL(scanner.next(), Token::Switch); + BOOST_CHECK_EQUAL(scanner.next(), Token::Case); + BOOST_CHECK_EQUAL(scanner.next(), Token::Default); + BOOST_CHECK_EQUAL(scanner.next(), Token::EOS); +} + +BOOST_AUTO_TEST_CASE(yul_keyword_like) +{ + Scanner scanner(CharStream("leave.function", "")); + BOOST_CHECK_EQUAL(scanner.currentToken(), Token::Identifier); + BOOST_CHECK_EQUAL(scanner.next(), Token::Period); + BOOST_CHECK_EQUAL(scanner.next(), Token::Function); + BOOST_CHECK_EQUAL(scanner.next(), Token::EOS); + scanner.reset(CharStream("leave.function", "")); + scanner.setScannerMode(ScannerKind::Yul); + BOOST_CHECK_EQUAL(scanner.currentToken(), Token::Identifier); + BOOST_CHECK_EQUAL(scanner.next(), Token::EOS); +} + +BOOST_AUTO_TEST_CASE(yul_identifier_with_dots) +{ + Scanner scanner(CharStream("mystorage.slot := 1", "")); + BOOST_CHECK_EQUAL(scanner.currentToken(), Token::Identifier); + BOOST_CHECK_EQUAL(scanner.next(), Token::Period); + BOOST_CHECK_EQUAL(scanner.next(), Token::Identifier); + BOOST_CHECK_EQUAL(scanner.next(), Token::AssemblyAssign); + BOOST_CHECK_EQUAL(scanner.next(), Token::Number); + BOOST_CHECK_EQUAL(scanner.next(), Token::EOS); + scanner.reset(CharStream("mystorage.slot := 1", "")); + scanner.setScannerMode(ScannerKind::Yul); + BOOST_CHECK_EQUAL(scanner.currentToken(), Token::Identifier); + BOOST_CHECK_EQUAL(scanner.next(), Token::AssemblyAssign); + BOOST_CHECK_EQUAL(scanner.next(), Token::Number); + BOOST_CHECK_EQUAL(scanner.next(), Token::EOS); +} + BOOST_AUTO_TEST_CASE(yul_function) { string sig = "function f(a, b) -> x, y"; From caa329066e800680c1c70c781a57adfde1daf05e Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Fri, 10 Jul 2020 16:20:04 +0100 Subject: [PATCH 3/6] Do not emit Solidity-only tokens in the Scanner for Yul And simplfiy AsmParser greatly. --- liblangutil/Scanner.cpp | 13 +++++-- liblangutil/Token.h | 7 ++++ libyul/AsmParser.cpp | 26 ++------------ test/liblangutil/Scanner.cpp | 36 +++++++++++++++---- .../inlineAssembly/hex_assignment.sol | 2 +- .../inlineAssembly/hex_expression.sol | 2 +- .../inlineAssembly/hex_switch_case.sol | 2 +- test/libyul/yulSyntaxTests/hex_assignment.yul | 2 +- test/libyul/yulSyntaxTests/hex_expression.yul | 2 +- .../libyul/yulSyntaxTests/hex_switch_case.yul | 2 +- 10 files changed, 56 insertions(+), 38 deletions(-) diff --git a/liblangutil/Scanner.cpp b/liblangutil/Scanner.cpp index 0b17a0883..2fdb181ac 100644 --- a/liblangutil/Scanner.cpp +++ b/liblangutil/Scanner.cpp @@ -668,7 +668,7 @@ void Scanner::scanToken() tie(token, m, n) = scanIdentifierOrKeyword(); // Special case for hexadecimal literals - if (token == Token::Hex) + if (token == Token::Hex && m_kind != ScannerKind::Yul) { // reset m = 0; @@ -680,7 +680,7 @@ void Scanner::scanToken() else token = setError(ScannerError::IllegalToken); } - else if (token == Token::Unicode) + else if (token == Token::Unicode && m_kind != ScannerKind::Yul) { // reset m = 0; @@ -969,7 +969,14 @@ tuple Scanner::scanIdentifierOrKeyword() while (isIdentifierPart(m_char) || (m_char == '.' && m_kind == ScannerKind::Yul)) addLiteralCharAndAdvance(); literal.complete(); - return TokenTraits::fromIdentifierOrKeyword(m_tokens[NextNext].literal); + auto const token = TokenTraits::fromIdentifierOrKeyword(m_tokens[NextNext].literal); + if (m_kind == ScannerKind::Yul) + { + // Turn non-Yul keywords into identifiers. + if (!TokenTraits::isYulKeyword(std::get<0>(token))) + return std::make_tuple(Token::Identifier, 0, 0); + } + return token; } } // namespace solidity::langutil diff --git a/liblangutil/Token.h b/liblangutil/Token.h index 53d8131f1..fecd3acbb 100644 --- a/liblangutil/Token.h +++ b/liblangutil/Token.h @@ -317,6 +317,13 @@ namespace TokenTraits constexpr bool isTimeSubdenomination(Token op) { return op == Token::SubSecond || op == Token::SubMinute || op == Token::SubHour || op == Token::SubDay || op == Token::SubWeek || op == Token::SubYear; } constexpr bool isReservedKeyword(Token op) { return (Token::After <= op && op <= Token::Unchecked); } + constexpr bool isYulKeyword(Token tok) + { + return tok == Token::Function || tok == Token::Let || tok == Token::If || tok == Token::Switch || tok == Token::Case || + tok == Token::Default || tok == Token::For || tok == Token::Break || tok == Token::Continue /* || tok == Token::Leave */ || + tok == Token::TrueLiteral || tok == Token::FalseLiteral; + } + inline Token AssignmentToBinaryOp(Token op) { solAssert(isAssignmentOp(op) && op != Token::Assign, ""); diff --git a/libyul/AsmParser.cpp b/libyul/AsmParser.cpp index 1e3b563d7..43323c825 100644 --- a/libyul/AsmParser.cpp +++ b/libyul/AsmParser.cpp @@ -284,12 +284,6 @@ Parser::ElementaryOperation Parser::parseElementaryOperation() switch (currentToken()) { case Token::Identifier: - case Token::Return: - case Token::Byte: - case Token::Bool: - case Token::Address: - case Token::Var: - case Token::In: { YulString literal{currentLiteral()}; if (m_dialect.builtin(literal)) @@ -472,24 +466,10 @@ TypedName Parser::parseTypedName() YulString Parser::expectAsmIdentifier() { YulString name{currentLiteral()}; - switch (currentToken()) - { - case Token::Return: - case Token::Byte: - case Token::Address: - case Token::Bool: - case Token::Identifier: - case Token::Var: - case Token::In: - break; - default: - expectToken(Token::Identifier); - break; - } - - if (m_dialect.builtin(name)) + if (currentToken() == Token::Identifier && m_dialect.builtin(name)) fatalParserError(5568_error, "Cannot use builtin function name \"" + name.str() + "\" as identifier name."); - advance(); + // NOTE: We keep the expectation here to ensure the correct source location for the error above. + expectToken(Token::Identifier); return name; } diff --git a/test/liblangutil/Scanner.cpp b/test/liblangutil/Scanner.cpp index 862b19c00..c336d5e0b 100644 --- a/test/liblangutil/Scanner.cpp +++ b/test/liblangutil/Scanner.cpp @@ -595,6 +595,11 @@ BOOST_AUTO_TEST_CASE(unicode_prefix_only) BOOST_CHECK_EQUAL(scanner.currentToken(), Token::LBrace); BOOST_CHECK_EQUAL(scanner.next(), Token::Illegal); BOOST_CHECK_EQUAL(scanner.currentError(), ScannerError::IllegalToken); + scanner.reset(CharStream("{ unicode", "")); + scanner.setScannerMode(ScannerKind::Yul); + BOOST_CHECK_EQUAL(scanner.currentToken(), Token::LBrace); + BOOST_CHECK_EQUAL(scanner.next(), Token::Identifier); + BOOST_CHECK_EQUAL(scanner.currentLiteral(), "unicode"); } BOOST_AUTO_TEST_CASE(unicode_invalid_space) @@ -611,6 +616,13 @@ BOOST_AUTO_TEST_CASE(unicode_invalid_token) BOOST_CHECK_EQUAL(scanner.currentToken(), Token::LBrace); BOOST_CHECK_EQUAL(scanner.next(), Token::Illegal); BOOST_CHECK_EQUAL(scanner.currentError(), ScannerError::IllegalToken); + scanner.reset(CharStream("{ unicode test", "")); + scanner.setScannerMode(ScannerKind::Yul); + BOOST_CHECK_EQUAL(scanner.currentToken(), Token::LBrace); + BOOST_CHECK_EQUAL(scanner.next(), Token::Identifier); + BOOST_CHECK_EQUAL(scanner.currentLiteral(), "unicode"); + BOOST_CHECK_EQUAL(scanner.next(), Token::Identifier); + BOOST_CHECK_EQUAL(scanner.currentLiteral(), "test"); } BOOST_AUTO_TEST_CASE(valid_unicode_literal) @@ -638,6 +650,11 @@ BOOST_AUTO_TEST_CASE(hex_prefix_only) BOOST_CHECK_EQUAL(scanner.currentToken(), Token::LBrace); BOOST_CHECK_EQUAL(scanner.next(), Token::Illegal); BOOST_CHECK_EQUAL(scanner.currentError(), ScannerError::IllegalToken); + scanner.reset(CharStream("{ hex", "")); + scanner.setScannerMode(ScannerKind::Yul); + BOOST_CHECK_EQUAL(scanner.currentToken(), Token::LBrace); + BOOST_CHECK_EQUAL(scanner.next(), Token::Identifier); + BOOST_CHECK_EQUAL(scanner.currentLiteral(), "hex"); } BOOST_AUTO_TEST_CASE(hex_invalid_space) @@ -654,6 +671,13 @@ BOOST_AUTO_TEST_CASE(hex_invalid_token) BOOST_CHECK_EQUAL(scanner.currentToken(), Token::LBrace); BOOST_CHECK_EQUAL(scanner.next(), Token::Illegal); BOOST_CHECK_EQUAL(scanner.currentError(), ScannerError::IllegalToken); + scanner.reset(CharStream("{ hex test", "")); + scanner.setScannerMode(ScannerKind::Yul); + BOOST_CHECK_EQUAL(scanner.currentToken(), Token::LBrace); + BOOST_CHECK_EQUAL(scanner.next(), Token::Identifier); + BOOST_CHECK_EQUAL(scanner.currentLiteral(), "hex"); + BOOST_CHECK_EQUAL(scanner.next(), Token::Identifier); + BOOST_CHECK_EQUAL(scanner.currentLiteral(), "test"); } BOOST_AUTO_TEST_CASE(valid_hex_literal) @@ -839,12 +863,12 @@ BOOST_AUTO_TEST_CASE(solidity_keywords) BOOST_CHECK_EQUAL(scanner.next(), Token::EOS); scanner.reset(CharStream(keywords, "")); scanner.setScannerMode(ScannerKind::Yul); - BOOST_CHECK_EQUAL(scanner.currentToken(), Token::Return); - BOOST_CHECK_EQUAL(scanner.next(), Token::Byte); - BOOST_CHECK_EQUAL(scanner.next(), Token::Bool); - BOOST_CHECK_EQUAL(scanner.next(), Token::Address); - BOOST_CHECK_EQUAL(scanner.next(), Token::Var); - BOOST_CHECK_EQUAL(scanner.next(), Token::In); + BOOST_CHECK_EQUAL(scanner.currentToken(), Token::Identifier); + BOOST_CHECK_EQUAL(scanner.next(), Token::Identifier); + BOOST_CHECK_EQUAL(scanner.next(), Token::Identifier); + BOOST_CHECK_EQUAL(scanner.next(), Token::Identifier); + BOOST_CHECK_EQUAL(scanner.next(), Token::Identifier); + BOOST_CHECK_EQUAL(scanner.next(), Token::Identifier); BOOST_CHECK_EQUAL(scanner.next(), Token::TrueLiteral); BOOST_CHECK_EQUAL(scanner.next(), Token::FalseLiteral); BOOST_CHECK_EQUAL(scanner.next(), Token::Identifier); diff --git a/test/libsolidity/syntaxTests/inlineAssembly/hex_assignment.sol b/test/libsolidity/syntaxTests/inlineAssembly/hex_assignment.sol index 18107e044..3821a5073 100644 --- a/test/libsolidity/syntaxTests/inlineAssembly/hex_assignment.sol +++ b/test/libsolidity/syntaxTests/inlineAssembly/hex_assignment.sol @@ -6,4 +6,4 @@ contract C { } } // ---- -// ParserError 1856: (72-81): Literal or identifier expected. +// ParserError 6913: (86-87): Call or assignment expected. diff --git a/test/libsolidity/syntaxTests/inlineAssembly/hex_expression.sol b/test/libsolidity/syntaxTests/inlineAssembly/hex_expression.sol index 53cd23a29..d4cbe810b 100644 --- a/test/libsolidity/syntaxTests/inlineAssembly/hex_expression.sol +++ b/test/libsolidity/syntaxTests/inlineAssembly/hex_expression.sol @@ -6,4 +6,4 @@ contract C { } } // ---- -// ParserError 1856: (67-76): Literal or identifier expected. +// ParserError 2314: (70-76): Expected ',' but got 'StringLiteral' diff --git a/test/libsolidity/syntaxTests/inlineAssembly/hex_switch_case.sol b/test/libsolidity/syntaxTests/inlineAssembly/hex_switch_case.sol index bc0ff56fe..38f1f9637 100644 --- a/test/libsolidity/syntaxTests/inlineAssembly/hex_switch_case.sol +++ b/test/libsolidity/syntaxTests/inlineAssembly/hex_switch_case.sol @@ -8,4 +8,4 @@ contract C { } } // ---- -// ParserError 1856: (92-99): Literal or identifier expected. +// ParserError 4805: (95-99): Literal expected. diff --git a/test/libyul/yulSyntaxTests/hex_assignment.yul b/test/libyul/yulSyntaxTests/hex_assignment.yul index c9af448c1..9305cd3f2 100644 --- a/test/libyul/yulSyntaxTests/hex_assignment.yul +++ b/test/libyul/yulSyntaxTests/hex_assignment.yul @@ -2,4 +2,4 @@ let x := hex"0011" } // ---- -// ParserError 1856: (15-24): Literal or identifier expected. +// ParserError 6913: (25-26): Call or assignment expected. diff --git a/test/libyul/yulSyntaxTests/hex_expression.yul b/test/libyul/yulSyntaxTests/hex_expression.yul index f9c1cb52d..02c8d78e6 100644 --- a/test/libyul/yulSyntaxTests/hex_expression.yul +++ b/test/libyul/yulSyntaxTests/hex_expression.yul @@ -2,4 +2,4 @@ pop(hex"2233") } // ---- -// ParserError 1856: (10-19): Literal or identifier expected. +// ParserError 2314: (13-19): Expected ',' but got 'StringLiteral' diff --git a/test/libyul/yulSyntaxTests/hex_switch_case.yul b/test/libyul/yulSyntaxTests/hex_switch_case.yul index 0f3636b4f..4034b4797 100644 --- a/test/libyul/yulSyntaxTests/hex_switch_case.yul +++ b/test/libyul/yulSyntaxTests/hex_switch_case.yul @@ -4,4 +4,4 @@ case hex"1122" {} } // ---- -// ParserError 1856: (33-40): Literal or identifier expected. +// ParserError 4805: (36-40): Literal expected. From 4366ede889be684d62e9f2595d89b7ae9af82e83 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Mon, 27 Jul 2020 19:11:38 +0100 Subject: [PATCH 4/6] Introduce Leave as a keyword for Yul --- liblangutil/Scanner.cpp | 3 +++ liblangutil/Token.h | 5 ++++- libyul/AsmParser.cpp | 18 ++++++++---------- test/liblangutil/Scanner.cpp | 2 +- 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/liblangutil/Scanner.cpp b/liblangutil/Scanner.cpp index 2fdb181ac..b6011342d 100644 --- a/liblangutil/Scanner.cpp +++ b/liblangutil/Scanner.cpp @@ -972,6 +972,9 @@ tuple Scanner::scanIdentifierOrKeyword() auto const token = TokenTraits::fromIdentifierOrKeyword(m_tokens[NextNext].literal); if (m_kind == ScannerKind::Yul) { + // Turn Solidity identifier into a Yul keyword + if (m_tokens[NextNext].literal == "leave") + return std::make_tuple(Token::Leave, 0, 0); // Turn non-Yul keywords into identifiers. if (!TokenTraits::isYulKeyword(std::get<0>(token))) return std::make_tuple(Token::Identifier, 0, 0); diff --git a/liblangutil/Token.h b/liblangutil/Token.h index fecd3acbb..ecebe0cf5 100644 --- a/liblangutil/Token.h +++ b/liblangutil/Token.h @@ -269,6 +269,9 @@ namespace solidity::langutil K(Unchecked, "unchecked", 0) \ K(Var, "var", 0) \ \ + /* Yul-specific tokens, but not keywords. */ \ + T(Leave, "leave", 0) \ + \ /* Illegal token - not able to scan. */ \ T(Illegal, "ILLEGAL", 0) \ \ @@ -320,7 +323,7 @@ namespace TokenTraits constexpr bool isYulKeyword(Token tok) { return tok == Token::Function || tok == Token::Let || tok == Token::If || tok == Token::Switch || tok == Token::Case || - tok == Token::Default || tok == Token::For || tok == Token::Break || tok == Token::Continue /* || tok == Token::Leave */ || + tok == Token::Default || tok == Token::For || tok == Token::Break || tok == Token::Continue || tok == Token::Leave || tok == Token::TrueLiteral || tok == Token::FalseLiteral; } diff --git a/libyul/AsmParser.cpp b/libyul/AsmParser.cpp index 43323c825..e85bafb67 100644 --- a/libyul/AsmParser.cpp +++ b/libyul/AsmParser.cpp @@ -126,16 +126,14 @@ Statement Parser::parseStatement() advance(); return stmt; } - case Token::Identifier: - if (currentLiteral() == "leave") - { - Statement stmt{createWithLocation()}; - if (!m_insideFunction) - m_errorReporter.syntaxError(8149_error, currentLocation(), "Keyword \"leave\" can only be used inside a function."); - advance(); - return stmt; - } - break; + case Token::Leave: + { + Statement stmt{createWithLocation()}; + if (!m_insideFunction) + m_errorReporter.syntaxError(8149_error, currentLocation(), "Keyword \"leave\" can only be used inside a function."); + advance(); + return stmt; + } default: break; } diff --git a/test/liblangutil/Scanner.cpp b/test/liblangutil/Scanner.cpp index c336d5e0b..2bb934fee 100644 --- a/test/liblangutil/Scanner.cpp +++ b/test/liblangutil/Scanner.cpp @@ -871,7 +871,7 @@ BOOST_AUTO_TEST_CASE(solidity_keywords) BOOST_CHECK_EQUAL(scanner.next(), Token::Identifier); BOOST_CHECK_EQUAL(scanner.next(), Token::TrueLiteral); BOOST_CHECK_EQUAL(scanner.next(), Token::FalseLiteral); - BOOST_CHECK_EQUAL(scanner.next(), Token::Identifier); + BOOST_CHECK_EQUAL(scanner.next(), Token::Leave); BOOST_CHECK_EQUAL(scanner.next(), Token::Switch); BOOST_CHECK_EQUAL(scanner.next(), Token::Case); BOOST_CHECK_EQUAL(scanner.next(), Token::Default); From 26a76c18d43f578c607c40ddf797e8abaf4a3698 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Wed, 29 Jul 2020 14:40:34 +0100 Subject: [PATCH 5/6] Add Yul syntax test for every Solidity keyword --- .../inlineAssembly/solidity_keywords.sol | 113 ++++++++++++++++++ .../yulSyntaxTests/solidity_keywords.yul | 109 +++++++++++++++++ 2 files changed, 222 insertions(+) create mode 100644 test/libsolidity/syntaxTests/inlineAssembly/solidity_keywords.sol create mode 100644 test/libyul/yulSyntaxTests/solidity_keywords.yul diff --git a/test/libsolidity/syntaxTests/inlineAssembly/solidity_keywords.sol b/test/libsolidity/syntaxTests/inlineAssembly/solidity_keywords.sol new file mode 100644 index 000000000..9b5e570be --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/solidity_keywords.sol @@ -0,0 +1,113 @@ +contract C { + function f() view public { + assembly { + // These are keywords of Solidity -- a copy from liblangutil/Token.h. + let abstract := 1 + let anonymous := 1 + let as := 1 + let assembly := 1 + // break is Yul keyword + let catch := 1 + let constant := 1 + let constructor := 1 + // continue is Yul keyword + let contract := 1 + let do := 1 + let else := 1 + let enum := 1 + let emit := 1 + let event := 1 + let external := 1 + let fallback := 1 + // for is a Yul keyword + // function is a Yul keyword + let hex := 1 + // if is a Yul keyword + let indexed := 1 + let interface := 1 + let internal := 1 + let immutable := 1 + let import := 1 + let is := 1 + let library := 1 + let mapping := 1 + let memory := 1 + let modifier := 1 + let new := 1 + let override := 1 + let payable := 1 + let public := 1 + let pragma := 1 + let private := 1 + let pure := 1 + let receive := 1 + // return is a builtin in EVMDialect + return(0, 0) + let returns := 1 + let storage := 1 + let calldata := 1 + let struct := 1 + let throw := 1 + let try := 1 + // type shadows the Solidity function + let unicode := 1 + let using := 1 + let view := 1 + let virtual := 1 + let while := 1 + let wei := 1 + let gwei := 1 + let ether := 1 + let seconds := 1 + let minutes := 1 + let hours := 1 + let days := 1 + let weeks := 1 + let years := 1 + let int := 1 + let uint := 1 + let bytes := 1 + // byte is a builtin in EVMDialect + pop(byte(1, 1)) + let string := 1 + // address is a builtin in EVMDialect + pop(address()) + let bool := 1 + let fixed := 1 + let ufixed := 1 + let after := 1 + let alias := 1 + let apply := 1 + let auto := 1 + // case is a Yul keyword + let copyof := 1 + // default is a Yul keyword + let define := 1 + let final := 1 + let implements := 1 + let in := 1 + let inline := 1 + // let is a Yul keyword + let macro := 1 + let match := 1 + let mutable := 1 + let null := 1 + let of := 1 + let partial := 1 + let promise := 1 + let reference := 1 + let relocatable := 1 + let sealed := 1 + let sizeof := 1 + let static := 1 + let supports := 1 + // switch is a Yul keyword + let typedef := 1 + let typeof := 1 + let unchecked := 1 + let var := 1 + } + } +} +// ---- +// Warning 5740: (944-2157): Unreachable code. diff --git a/test/libyul/yulSyntaxTests/solidity_keywords.yul b/test/libyul/yulSyntaxTests/solidity_keywords.yul new file mode 100644 index 000000000..4868fadad --- /dev/null +++ b/test/libyul/yulSyntaxTests/solidity_keywords.yul @@ -0,0 +1,109 @@ +{ + // These are keywords of Solidity -- a copy from liblangutil/Token.h. + let abstract := 1 + let anonymous := 1 + let as := 1 + let assembly := 1 + // break is Yul keyword + let catch := 1 + let constant := 1 + let constructor := 1 + // continue is Yul keyword + let contract := 1 + let do := 1 + let else := 1 + let enum := 1 + let emit := 1 + let event := 1 + let external := 1 + let fallback := 1 + // for is a Yul keyword + // function is a Yul keyword + let hex := 1 + // if is a Yul keyword + let indexed := 1 + let interface := 1 + let internal := 1 + let immutable := 1 + let import := 1 + let is := 1 + let library := 1 + let mapping := 1 + let memory := 1 + let modifier := 1 + let new := 1 + let override := 1 + let payable := 1 + let public := 1 + let pragma := 1 + let private := 1 + let pure := 1 + let receive := 1 + // return is a builtin in EVMDialect + return(0, 0) + let returns := 1 + let storage := 1 + let calldata := 1 + let struct := 1 + let throw := 1 + let try := 1 + let type := 1 + let unicode := 1 + let using := 1 + let view := 1 + let virtual := 1 + let while := 1 + let wei := 1 + let gwei := 1 + let ether := 1 + let seconds := 1 + let minutes := 1 + let hours := 1 + let days := 1 + let weeks := 1 + let years := 1 + let int := 1 + let uint := 1 + let bytes := 1 + // byte is a builtin in EVMDialect + pop(byte(1, 1)) + let string := 1 + // address is a builtin in EVMDialect + pop(address()) + let bool := 1 + let fixed := 1 + let ufixed := 1 + let after := 1 + let alias := 1 + let apply := 1 + let auto := 1 + // case is a Yul keyword + let copyof := 1 + // default is a Yul keyword + let define := 1 + let final := 1 + let implements := 1 + let in := 1 + let inline := 1 + // let is a Yul keyword + let macro := 1 + let match := 1 + let mutable := 1 + let null := 1 + let of := 1 + let partial := 1 + let promise := 1 + let reference := 1 + let relocatable := 1 + let sealed := 1 + let sizeof := 1 + let static := 1 + let supports := 1 + // switch is a Yul keyword + let typedef := 1 + let typeof := 1 + let unchecked := 1 + let var := 1 +} +// ==== +// dialect: evm From 7ef9591e645c5780f82d676418e6257f0b0c09b2 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Thu, 27 Aug 2020 15:53:45 +0100 Subject: [PATCH 6/6] Expose hex literal to the Yul parser This allows nicer error messages. --- liblangutil/Scanner.cpp | 2 +- liblangutil/Token.h | 2 +- libyul/AsmParser.cpp | 3 +++ test/liblangutil/Scanner.cpp | 11 ++++------- .../syntaxTests/inlineAssembly/hex_assignment.sol | 2 +- .../syntaxTests/inlineAssembly/hex_expression.sol | 2 +- .../syntaxTests/inlineAssembly/hex_switch_case.sol | 2 +- .../syntaxTests/inlineAssembly/solidity_keywords.sol | 4 ++-- test/libyul/yulSyntaxTests/hex_assignment.yul | 2 +- test/libyul/yulSyntaxTests/hex_expression.yul | 2 +- test/libyul/yulSyntaxTests/hex_switch_case.yul | 2 +- test/libyul/yulSyntaxTests/solidity_keywords.yul | 2 +- 12 files changed, 18 insertions(+), 18 deletions(-) diff --git a/liblangutil/Scanner.cpp b/liblangutil/Scanner.cpp index b6011342d..1a3903d5c 100644 --- a/liblangutil/Scanner.cpp +++ b/liblangutil/Scanner.cpp @@ -668,7 +668,7 @@ void Scanner::scanToken() tie(token, m, n) = scanIdentifierOrKeyword(); // Special case for hexadecimal literals - if (token == Token::Hex && m_kind != ScannerKind::Yul) + if (token == Token::Hex) { // reset m = 0; diff --git a/liblangutil/Token.h b/liblangutil/Token.h index ecebe0cf5..2bfc58e44 100644 --- a/liblangutil/Token.h +++ b/liblangutil/Token.h @@ -324,7 +324,7 @@ namespace TokenTraits { return tok == Token::Function || tok == Token::Let || tok == Token::If || tok == Token::Switch || tok == Token::Case || tok == Token::Default || tok == Token::For || tok == Token::Break || tok == Token::Continue || tok == Token::Leave || - tok == Token::TrueLiteral || tok == Token::FalseLiteral; + tok == Token::TrueLiteral || tok == Token::FalseLiteral || tok == Token::HexStringLiteral || tok == Token::Hex; } inline Token AssignmentToBinaryOp(Token op) diff --git a/libyul/AsmParser.cpp b/libyul/AsmParser.cpp index e85bafb67..2baefa16f 100644 --- a/libyul/AsmParser.cpp +++ b/libyul/AsmParser.cpp @@ -337,6 +337,9 @@ Parser::ElementaryOperation Parser::parseElementaryOperation() ret = std::move(literal); break; } + case Token::HexStringLiteral: + fatalParserError(3772_error, "Hex literals are not valid in this context."); + break; default: fatalParserError(1856_error, "Literal or identifier expected."); } diff --git a/test/liblangutil/Scanner.cpp b/test/liblangutil/Scanner.cpp index 2bb934fee..2110cb2b6 100644 --- a/test/liblangutil/Scanner.cpp +++ b/test/liblangutil/Scanner.cpp @@ -652,9 +652,8 @@ BOOST_AUTO_TEST_CASE(hex_prefix_only) BOOST_CHECK_EQUAL(scanner.currentError(), ScannerError::IllegalToken); scanner.reset(CharStream("{ hex", "")); scanner.setScannerMode(ScannerKind::Yul); - BOOST_CHECK_EQUAL(scanner.currentToken(), Token::LBrace); - BOOST_CHECK_EQUAL(scanner.next(), Token::Identifier); - BOOST_CHECK_EQUAL(scanner.currentLiteral(), "hex"); + BOOST_CHECK_EQUAL(scanner.next(), Token::Illegal); + BOOST_CHECK_EQUAL(scanner.currentError(), ScannerError::IllegalToken); } BOOST_AUTO_TEST_CASE(hex_invalid_space) @@ -674,10 +673,8 @@ BOOST_AUTO_TEST_CASE(hex_invalid_token) scanner.reset(CharStream("{ hex test", "")); scanner.setScannerMode(ScannerKind::Yul); BOOST_CHECK_EQUAL(scanner.currentToken(), Token::LBrace); - BOOST_CHECK_EQUAL(scanner.next(), Token::Identifier); - BOOST_CHECK_EQUAL(scanner.currentLiteral(), "hex"); - BOOST_CHECK_EQUAL(scanner.next(), Token::Identifier); - BOOST_CHECK_EQUAL(scanner.currentLiteral(), "test"); + BOOST_CHECK_EQUAL(scanner.next(), Token::Illegal); + BOOST_CHECK_EQUAL(scanner.currentError(), ScannerError::IllegalToken); } BOOST_AUTO_TEST_CASE(valid_hex_literal) diff --git a/test/libsolidity/syntaxTests/inlineAssembly/hex_assignment.sol b/test/libsolidity/syntaxTests/inlineAssembly/hex_assignment.sol index 3821a5073..b51dd8604 100644 --- a/test/libsolidity/syntaxTests/inlineAssembly/hex_assignment.sol +++ b/test/libsolidity/syntaxTests/inlineAssembly/hex_assignment.sol @@ -6,4 +6,4 @@ contract C { } } // ---- -// ParserError 6913: (86-87): Call or assignment expected. +// ParserError 3772: (72-81): Hex literals are not valid in this context. diff --git a/test/libsolidity/syntaxTests/inlineAssembly/hex_expression.sol b/test/libsolidity/syntaxTests/inlineAssembly/hex_expression.sol index d4cbe810b..2f4f69174 100644 --- a/test/libsolidity/syntaxTests/inlineAssembly/hex_expression.sol +++ b/test/libsolidity/syntaxTests/inlineAssembly/hex_expression.sol @@ -6,4 +6,4 @@ contract C { } } // ---- -// ParserError 2314: (70-76): Expected ',' but got 'StringLiteral' +// ParserError 3772: (67-76): Hex literals are not valid in this context. diff --git a/test/libsolidity/syntaxTests/inlineAssembly/hex_switch_case.sol b/test/libsolidity/syntaxTests/inlineAssembly/hex_switch_case.sol index 38f1f9637..de64567d7 100644 --- a/test/libsolidity/syntaxTests/inlineAssembly/hex_switch_case.sol +++ b/test/libsolidity/syntaxTests/inlineAssembly/hex_switch_case.sol @@ -8,4 +8,4 @@ contract C { } } // ---- -// ParserError 4805: (95-99): Literal expected. +// ParserError 3772: (92-99): Hex literals are not valid in this context. diff --git a/test/libsolidity/syntaxTests/inlineAssembly/solidity_keywords.sol b/test/libsolidity/syntaxTests/inlineAssembly/solidity_keywords.sol index 9b5e570be..5467d045a 100644 --- a/test/libsolidity/syntaxTests/inlineAssembly/solidity_keywords.sol +++ b/test/libsolidity/syntaxTests/inlineAssembly/solidity_keywords.sol @@ -21,7 +21,7 @@ contract C { let fallback := 1 // for is a Yul keyword // function is a Yul keyword - let hex := 1 + // hex is a Yul keyword // if is a Yul keyword let indexed := 1 let interface := 1 @@ -110,4 +110,4 @@ contract C { } } // ---- -// Warning 5740: (944-2157): Unreachable code. +// Warning 5740: (955-2168): Unreachable code. diff --git a/test/libyul/yulSyntaxTests/hex_assignment.yul b/test/libyul/yulSyntaxTests/hex_assignment.yul index 9305cd3f2..213163916 100644 --- a/test/libyul/yulSyntaxTests/hex_assignment.yul +++ b/test/libyul/yulSyntaxTests/hex_assignment.yul @@ -2,4 +2,4 @@ let x := hex"0011" } // ---- -// ParserError 6913: (25-26): Call or assignment expected. +// ParserError 3772: (15-24): Hex literals are not valid in this context. diff --git a/test/libyul/yulSyntaxTests/hex_expression.yul b/test/libyul/yulSyntaxTests/hex_expression.yul index 02c8d78e6..191fdf085 100644 --- a/test/libyul/yulSyntaxTests/hex_expression.yul +++ b/test/libyul/yulSyntaxTests/hex_expression.yul @@ -2,4 +2,4 @@ pop(hex"2233") } // ---- -// ParserError 2314: (13-19): Expected ',' but got 'StringLiteral' +// ParserError 3772: (10-19): Hex literals are not valid in this context. diff --git a/test/libyul/yulSyntaxTests/hex_switch_case.yul b/test/libyul/yulSyntaxTests/hex_switch_case.yul index 4034b4797..87ba6a4a9 100644 --- a/test/libyul/yulSyntaxTests/hex_switch_case.yul +++ b/test/libyul/yulSyntaxTests/hex_switch_case.yul @@ -4,4 +4,4 @@ case hex"1122" {} } // ---- -// ParserError 4805: (36-40): Literal expected. +// ParserError 3772: (33-40): Hex literals are not valid in this context. diff --git a/test/libyul/yulSyntaxTests/solidity_keywords.yul b/test/libyul/yulSyntaxTests/solidity_keywords.yul index 4868fadad..1f1dafc53 100644 --- a/test/libyul/yulSyntaxTests/solidity_keywords.yul +++ b/test/libyul/yulSyntaxTests/solidity_keywords.yul @@ -19,7 +19,7 @@ let fallback := 1 // for is a Yul keyword // function is a Yul keyword - let hex := 1 + // hex is a Yul keyword // if is a Yul keyword let indexed := 1 let interface := 1