From 6a5e1dee7bf0458e866580a9600fb9b6a320c1d9 Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Tue, 20 Aug 2024 16:10:41 +0200 Subject: [PATCH] feat: parse some more doc comments --- crates/parse/src/parser/item.rs | 6 +- crates/parse/src/parser/mod.rs | 39 ++- crates/parse/src/parser/yul.rs | 14 +- tests/ui/parser/yul/solc_generated.opt.yul | 194 +++++++++++++++ tests/ui/parser/yul/solc_generated.yul | 263 +++++++++++++++++++++ 5 files changed, 503 insertions(+), 13 deletions(-) create mode 100644 tests/ui/parser/yul/solc_generated.opt.yul create mode 100644 tests/ui/parser/yul/solc_generated.yul diff --git a/crates/parse/src/parser/item.rs b/crates/parse/src/parser/item.rs index 527eeb78..82622e82 100644 --- a/crates/parse/src/parser/item.rs +++ b/crates/parse/src/parser/item.rs @@ -331,8 +331,7 @@ impl<'sess, 'ast> Parser<'sess, 'ast> { fn parse_enum(&mut self) -> PResult<'sess, ItemEnum<'ast>> { let name = self.parse_ident()?; let (variants, _) = self.parse_delim_comma_seq(Delimiter::Brace, false, |this| { - // Ignore doc-comments. - let _ = this.parse_doc_comments()?; + this.ignore_doc_comments(); this.parse_ident() })?; Ok(ItemEnum { name, variants }) @@ -706,8 +705,7 @@ impl<'sess, 'ast> Parser<'sess, 'ast> { ty } None => { - // Ignore doc-comments. - let _ = self.parse_doc_comments()?; + self.ignore_doc_comments(); self.parse_type()? } }; diff --git a/crates/parse/src/parser/mod.rs b/crates/parse/src/parser/mod.rs index a012efec..67294d76 100644 --- a/crates/parse/src/parser/mod.rs +++ b/crates/parse/src/parser/mod.rs @@ -713,6 +713,10 @@ impl<'sess, 'ast> Parser<'sess, 'ast> { /// This always-inlined version should only be used on hot code paths. #[inline(always)] fn inlined_bump_with(&mut self, next_token: Token) { + #[cfg(debug_assertions)] + if next_token.is_comment() { + self.comment_in_stream(next_token.span); + } self.prev_token = std::mem::replace(&mut self.token, next_token); self.expected_tokens.clear(); } @@ -773,12 +777,40 @@ impl<'sess, 'ast> Parser<'sess, 'ast> { } } + /// Parses and ignores contiguous doc comments. + #[inline] + pub fn ignore_doc_comments(&mut self) { + if matches!(self.token.kind, TokenKind::Comment(..)) { + self.ignore_doc_comments_inner(); + } + } + + #[cold] + fn ignore_doc_comments_inner(&mut self) { + while let Token { span, kind: TokenKind::Comment(is_doc, _kind, _symbol) } = self.token { + if !is_doc { + self.comment_in_stream(span); + } + self.bump(); + } + } + /// Parses contiguous doc comments. Can be empty. + #[inline] pub fn parse_doc_comments(&mut self) -> PResult<'sess, DocComments<'ast>> { + if matches!(self.token.kind, TokenKind::Comment(..)) { + self.parse_doc_comments_inner() + } else { + Ok(Default::default()) + } + } + + #[cold] + fn parse_doc_comments_inner(&mut self) -> PResult<'sess, DocComments<'ast>> { let mut doc_comments = SmallVec::<[_; 4]>::new(); while let Token { span, kind: TokenKind::Comment(is_doc, kind, symbol) } = self.token { if !is_doc { - self.dcx().bug("comments should not be in the token stream").span(span).emit(); + self.comment_in_stream(span); } doc_comments.push(DocComment { kind, span, symbol }); self.bump(); @@ -786,6 +818,11 @@ impl<'sess, 'ast> Parser<'sess, 'ast> { Ok(self.alloc_smallvec(doc_comments)) } + #[cold] + fn comment_in_stream(&self, span: Span) -> ! { + self.dcx().bug("comments should not be in the token stream").span(span).emit() + } + /// Parses a qualified identifier: `foo.bar.baz`. #[track_caller] pub fn parse_path(&mut self) -> PResult<'sess, AstPath<'ast>> { diff --git a/crates/parse/src/parser/yul.rs b/crates/parse/src/parser/yul.rs index 7e553a86..eada98d8 100644 --- a/crates/parse/src/parser/yul.rs +++ b/crates/parse/src/parser/yul.rs @@ -2,7 +2,7 @@ use super::SeqSep; use crate::{PResult, Parser}; use smallvec::SmallVec; use sulk_ast::{ - ast::{yul::*, AstPath, Box, LitKind, PathSlice, StrKind, StrLit}, + ast::{yul::*, AstPath, Box, DocComments, LitKind, PathSlice, StrKind, StrLit}, token::*, }; use sulk_interface::{error_code, kw, sym, Ident}; @@ -16,10 +16,7 @@ impl<'sess, 'ast> Parser<'sess, 'ast> { pub fn parse_yul_file_object(&mut self) -> PResult<'sess, Object<'ast>> { let docs = self.parse_doc_comments()?; let object = if self.check_keyword(sym::object) { - self.parse_yul_object().map(|mut obj| { - obj.docs = docs; - obj - }) + self.parse_yul_object(docs) } else { let lo = self.token.span; self.parse_yul_block().map(|code| { @@ -36,8 +33,7 @@ impl<'sess, 'ast> Parser<'sess, 'ast> { /// Parses a Yul object. /// /// Reference: - pub fn parse_yul_object(&mut self) -> PResult<'sess, Object<'ast>> { - let docs = self.parse_doc_comments()?; + pub fn parse_yul_object(&mut self, docs: DocComments<'ast>) -> PResult<'sess, Object<'ast>> { let lo = self.token.span; self.expect_keyword(sym::object)?; let name = self.parse_str_lit()?; @@ -47,8 +43,9 @@ impl<'sess, 'ast> Parser<'sess, 'ast> { let mut children = Vec::new(); let mut data = Vec::new(); loop { + let docs = self.parse_doc_comments()?; if self.check_keyword(sym::object) { - children.push(self.parse_yul_object()?); + children.push(self.parse_yul_object(docs)?); } else if self.check_keyword(sym::data) { data.push(self.parse_yul_data()?); } else { @@ -242,6 +239,7 @@ impl<'sess, 'ast> Parser<'sess, 'ast> { /// Parses a Yul expression. fn parse_yul_expr(&mut self) -> PResult<'sess, Expr<'ast>> { + self.ignore_doc_comments(); self.parse_spanned(Self::parse_yul_expr_kind).map(|(span, kind)| Expr { span, kind }) } diff --git a/tests/ui/parser/yul/solc_generated.opt.yul b/tests/ui/parser/yul/solc_generated.opt.yul new file mode 100644 index 00000000..a6e8da31 --- /dev/null +++ b/tests/ui/parser/yul/solc_generated.opt.yul @@ -0,0 +1,194 @@ +/* +// solc +0.8.26 --ir-optimized ./c.sol +contract C { + function f(uint256 x) public returns (uint256) { + uint256 y = 1; + y += 69; + unchecked { + y *= x; + } + y /= 64; + return y; + } +} +*/ + +/// @use-src 0:"c.sol" +object "C_28" { + code { + { + /// @src 0:0:198 "contract C {..." + mstore(64, memoryguard(0x80)) + if callvalue() + { + revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() + } + let _1 := allocate_unbounded() + codecopy(_1, dataoffset("C_28_deployed"), datasize("C_28_deployed")) + return(_1, datasize("C_28_deployed")) + } + function allocate_unbounded() -> memPtr + { memPtr := mload(64) } + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() + { revert(0, 0) } + } + /// @use-src 0:"c.sol" + object "C_28_deployed" { + code { + { + /// @src 0:0:198 "contract C {..." + mstore(64, memoryguard(0x80)) + if iszero(lt(calldatasize(), 4)) + { + let selector := shift_right_unsigned(calldataload(0)) + switch selector + case 0xb3de648b { external_fun_f() } + default { } + } + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + } + function shift_right_unsigned(value) -> newValue + { newValue := shr(224, value) } + function allocate_unbounded() -> memPtr + { memPtr := mload(64) } + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() + { revert(0, 0) } + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() + { revert(0, 0) } + function cleanup_uint256(value) -> cleaned + { cleaned := value } + function validator_revert_uint256(value) + { + if iszero(eq(value, cleanup_uint256(value))) { revert(0, 0) } + } + function abi_decode_uint256(offset, end) -> value + { + value := calldataload(offset) + validator_revert_uint256(value) + } + function abi_decode_tuple_uint256(headStart, dataEnd) -> value0 + { + if slt(sub(dataEnd, headStart), 32) + { + revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() + } + let offset := 0 + value0 := abi_decode_uint256(add(headStart, offset), dataEnd) + } + function abi_encode_uint256_to_uint256(value, pos) + { + mstore(pos, cleanup_uint256(value)) + } + function abi_encode_uint256(headStart, value0) -> tail + { + tail := add(headStart, 32) + abi_encode_uint256_to_uint256(value0, add(headStart, 0)) + } + function external_fun_f() + { + if callvalue() + { + revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() + } + let param := abi_decode_tuple_uint256(4, calldatasize()) + let ret := fun_f(param) + let memPos := allocate_unbounded() + let memEnd := abi_encode_uint256(memPos, ret) + return(memPos, sub(memEnd, memPos)) + } + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + { revert(0, 0) } + function zero_value_for_split_uint256() -> ret + { ret := 0 } + function cleanup_rational_by(value) -> cleaned + { cleaned := value } + function identity(value) -> ret + { ret := value } + function convert_rational_1_by_1_to_uint256(value) -> converted + { + converted := cleanup_uint256(identity(cleanup_rational_by(value))) + } + function cleanup_t_rational_by(value) -> cleaned + { cleaned := value } + function convert_t_rational_by_to_t_uint256(value) -> converted + { + converted := cleanup_uint256(identity(cleanup_t_rational_by(value))) + } + function panic_error_0x11() + { + mstore(0, shl(224, 0x4e487b71)) + mstore(4, 0x11) + revert(0, 0x24) + } + function checked_add_uint256(x, y) -> sum + { + x := cleanup_uint256(x) + y := cleanup_uint256(y) + sum := add(x, y) + if gt(x, sum) { panic_error_0x11() } + } + function wrapping_mul_uint256(x, y) -> product + { + product := cleanup_uint256(mul(x, y)) + } + function cleanup_rational_by_1(value) -> cleaned + { cleaned := value } + function convert_rational_by_to_uint256(value) -> converted + { + converted := cleanup_uint256(identity(cleanup_rational_by_1(value))) + } + function panic_error_0x12() + { + mstore(0, shl(224, 0x4e487b71)) + mstore(4, 0x12) + revert(0, 0x24) + } + function checked_div_uint256(x, y) -> r + { + x := cleanup_uint256(x) + y := cleanup_uint256(y) + if iszero(y) { panic_error_0x12() } + r := div(x, y) + } + /// @ast-id 27 @src 0:17:196 "function f(uint256 x) public returns (uint256) {..." + function fun_f(var_x) -> var + { + /// @src 0:55:62 "uint256" + let zero_uint256 := zero_value_for_split_uint256() + var := zero_uint256 + /// @src 0:86:87 "1" + let expr := 0x01 + /// @src 0:74:87 "uint256 y = 1" + let var_y := convert_rational_1_by_1_to_uint256(expr) + /// @src 0:102:104 "69" + let expr_1 := 0x45 + /// @src 0:97:104 "y += 69" + let _1 := convert_t_rational_by_to_t_uint256(expr_1) + let _2 := var_y + let expr_2 := checked_add_uint256(_2, _1) + var_y := expr_2 + /// @src 0:143:144 "x" + let _3 := var_x + let expr_3 := _3 + /// @src 0:138:144 "y *= x" + let _4 := var_y + let expr_4 := wrapping_mul_uint256(_4, expr_3) + var_y := expr_4 + /// @src 0:169:171 "64" + let expr_5 := 0x40 + /// @src 0:164:171 "y /= 64" + let _5 := convert_rational_by_to_uint256(expr_5) + let _6 := var_y + let expr_6 := checked_div_uint256(_6, _5) + var_y := expr_6 + /// @src 0:188:189 "y" + let _7 := var_y + let expr_7 := _7 + /// @src 0:181:189 "return y" + var := expr_7 + leave + } + } + data ".metadata" hex"a2646970667358221220cb9774dc0239e8b062f7fc217650f80938f632767d6cc747e42e316bf835731064736f6c634300081a0033" + } +} diff --git a/tests/ui/parser/yul/solc_generated.yul b/tests/ui/parser/yul/solc_generated.yul new file mode 100644 index 00000000..1fd10eac --- /dev/null +++ b/tests/ui/parser/yul/solc_generated.yul @@ -0,0 +1,263 @@ +/* +// solc +0.8.26 --ir ./c.sol +contract C { + function f(uint256 x) public returns (uint256) { + uint256 y = 1; + y += 69; + unchecked { + y *= x; + } + y /= 64; + return y; + } +} +*/ + + +/// @use-src 0:"c.sol" +object "C_28" { + code { + /// @src 0:0:198 "contract C {..." + mstore(64, memoryguard(128)) + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + + constructor_C_28() + + let _1 := allocate_unbounded() + codecopy(_1, dataoffset("C_28_deployed"), datasize("C_28_deployed")) + + return(_1, datasize("C_28_deployed")) + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + /// @src 0:0:198 "contract C {..." + function constructor_C_28() { + + // TODO + // /// @src 0:0:198 "contract C {..." + + } + // TODO + // /// @src 0:0:198 "contract C {..." + + } + /// @use-src 0:"c.sol" + object "C_28_deployed" { + code { + /// @src 0:0:198 "contract C {..." + mstore(64, memoryguard(128)) + + if iszero(lt(calldatasize(), 4)) + { + let selector := shift_right_224_unsigned(calldataload(0)) + switch selector + + case 0xb3de648b + { + // f(uint256) + + external_fun_f_27() + } + + default {} + } + + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + + function revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() { + revert(0, 0) + } + + function cleanup_t_uint256(value) -> cleaned { + cleaned := value + } + + function validator_revert_t_uint256(value) { + if iszero(eq(value, cleanup_t_uint256(value))) { revert(0, 0) } + } + + function abi_decode_t_uint256(offset, end) -> value { + value := calldataload(offset) + validator_revert_t_uint256(value) + } + + function abi_decode_tuple_t_uint256(headStart, dataEnd) -> value0 { + if slt(sub(dataEnd, headStart), 32) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + + { + + let offset := 0 + + value0 := abi_decode_t_uint256(add(headStart, offset), dataEnd) + } + + } + + function abi_encode_t_uint256_to_t_uint256_fromStack(value, pos) { + mstore(pos, cleanup_t_uint256(value)) + } + + function abi_encode_tuple_t_uint256__to_t_uint256__fromStack(headStart , value0) -> tail { + tail := add(headStart, 32) + + abi_encode_t_uint256_to_t_uint256_fromStack(value0, add(headStart, 0)) + + } + + function external_fun_f_27() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + let param_0 := abi_decode_tuple_t_uint256(4, calldatasize()) + let ret_0 := fun_f_27(param_0) + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple_t_uint256__to_t_uint256__fromStack(memPos , ret_0) + return(memPos, sub(memEnd, memPos)) + + } + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { + revert(0, 0) + } + + function zero_value_for_split_t_uint256() -> ret { + ret := 0 + } + + function cleanup_t_rational_1_by_1(value) -> cleaned { + cleaned := value + } + + function identity(value) -> ret { + ret := value + } + + function convert_t_rational_1_by_1_to_t_uint256(value) -> converted { + converted := cleanup_t_uint256(identity(cleanup_t_rational_1_by_1(value))) + } + + function cleanup_t_rational_69_by_1(value) -> cleaned { + cleaned := value + } + + function convert_t_rational_69_by_1_to_t_uint256(value) -> converted { + converted := cleanup_t_uint256(identity(cleanup_t_rational_69_by_1(value))) + } + + function panic_error_0x11() { + mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) + mstore(4, 0x11) + revert(0, 0x24) + } + + function checked_add_t_uint256(x, y) -> sum { + x := cleanup_t_uint256(x) + y := cleanup_t_uint256(y) + sum := add(x, y) + + if gt(x, sum) { panic_error_0x11() } + + } + + function wrapping_mul_t_uint256(x, y) -> product { + product := cleanup_t_uint256(mul(x, y)) + } + + function cleanup_t_rational_64_by_1(value) -> cleaned { + cleaned := value + } + + function convert_t_rational_64_by_1_to_t_uint256(value) -> converted { + converted := cleanup_t_uint256(identity(cleanup_t_rational_64_by_1(value))) + } + + function panic_error_0x12() { + mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) + mstore(4, 0x12) + revert(0, 0x24) + } + + function checked_div_t_uint256(x, y) -> r { + x := cleanup_t_uint256(x) + y := cleanup_t_uint256(y) + if iszero(y) { panic_error_0x12() } + + r := div(x, y) + } + + /// @ast-id 27 + /// @src 0:17:196 "function f(uint256 x) public returns (uint256) {..." + function fun_f_27(var_x_2) -> var__5 { + /// @src 0:55:62 "uint256" + let zero_t_uint256_1 := zero_value_for_split_t_uint256() + var__5 := zero_t_uint256_1 + + /// @src 0:86:87 "1" + let expr_9 := 0x01 + /// @src 0:74:87 "uint256 y = 1" + let var_y_8 := convert_t_rational_1_by_1_to_t_uint256(expr_9) + /// @src 0:102:104 "69" + let expr_12 := 0x45 + /// @src 0:97:104 "y += 69" + let _2 := convert_t_rational_69_by_1_to_t_uint256(expr_12) + let _3 := var_y_8 + let expr_13 := checked_add_t_uint256(_3, _2) + + var_y_8 := expr_13 + /// @src 0:143:144 "x" + let _4 := var_x_2 + let expr_16 := _4 + /// @src 0:138:144 "y *= x" + let _5 := var_y_8 + let expr_17 := wrapping_mul_t_uint256(_5, expr_16) + + var_y_8 := expr_17 + /// @src 0:169:171 "64" + let expr_21 := 0x40 + /// @src 0:164:171 "y /= 64" + let _6 := convert_t_rational_64_by_1_to_t_uint256(expr_21) + let _7 := var_y_8 + let expr_22 := checked_div_t_uint256(_7, _6) + + var_y_8 := expr_22 + /// @src 0:188:189 "y" + let _8 := var_y_8 + let expr_24 := _8 + /// @src 0:181:189 "return y" + var__5 := expr_24 + leave + + } + // TODO: + // /// @src 0:0:198 "contract C {..." + + } + + data ".metadata" hex"a2646970667358221220cb9774dc0239e8b062f7fc217650f80938f632767d6cc747e42e316bf835731064736f6c634300081a0033" + } + +}