Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(fmt): WIP update to latest solang-parser #1612

Merged
merged 13 commits into from
May 20, 2022

Conversation

jpopesculian
Copy link
Contributor

Motivation

Build fails with the newest version of solang-parser if dependencies are not locked

Solution

Update to use the latest version of solang-parser and also lock the solang-parser version

@gakonst gakonst mentioned this pull request May 13, 2022
2 tasks
@onbjerg onbjerg added the L-ignore Log: ignore PR in changelog label May 14, 2022
Copy link
Member

@mattsse mattsse left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looking good so far,

we can merge this once fmt command module in the cli crate is reenabled and compiles

@gakonst
Copy link
Member

gakonst commented May 16, 2022

As discussed, let's go with the following plan:

  1. get this ASAP to a mergeable state so that we can re-enable the fmt code
  2. make forge fmt reconstruct all of the source code incl. comments, so that people can at least use it in CI etc.
  3. iterate on adding support for formatting more nodes

Copy link
Member

@gakonst gakonst left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good so far, some thoughts/nits..

what remains to get this over the line?

Comment on lines 261 to 264
Pure(),
View(),
Constant(),
Payable(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should these be Pure instead of Pure()? Given it's an enum with no internal value? @seanyoung maybe a Solang thing

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see why they can't be Pure rather than Pure().

In the solang parse tree, pure has a has a source file location value: Pure(Loc) but I don't see how that is relevant

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just related to the way I wrote the macro here. There's a hidden .. that covers the Loc in the enum. I'll pull it out to make it unhidden and more clear.

use itertools::Itertools;
use solang_parser::pt::*;

pub trait AstEq {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the reason why this trait exists because we cannot derive on the larpop code-gened files? https://github.com/hyperledger-labs/solang/blob/c63b552373f9660027568e0af4040a82d8821de7/solang-parser/src/solidity.lalrpop#L20

@seanyoung is there a way for us to do that?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if a #[derive(Eq)] or something like that can be done in the solang-parser, by all means.

However, I think here there is a specific type of equality is required here, with sorted function attributes for example. I'm not sure how else we could deal with this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, agree. A derive macro would definitely make this more succinct, but we would have to cover the cases where order matters and cases where they don't which means making the proc_macro a little more complicated. In the end, because I just use this for writing tests to make sure the formatted parse tree matches, its not super critical I think. Its more just a convenience and double checking my work

@@ -2,11 +2,13 @@

use std::fmt::Write;

// use crate::operators::Operator;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// use crate::operators::Operator;

Comment on lines 500 to 514
// let op = Operator::for_expr(expr);
// let is_literal = |exp: &Expression| {
// matches!(
// exp,
// Expression::AddressLiteral(..)
// | Expression::ArrayLiteral(..)
// | Expression::BoolLiteral(..)
// | Expression::HexLiteral(..)
// | Expression::HexNumberLiteral(..)
// | Expression::NumberLiteral(..)
// | Expression::RationalNumberLiteral(..)
// | Expression::StringLiteral(..)
// )
// };

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be removed? or do we need it elsewhere and still WIP?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can remove it, I've decided to go with a different method for handling unary / binary operators and operator precedence anyways since

write!(self, "]")?;
}
// Expression::Assign(_, var_expr, value_expr) => {
// // TODO handle with operators?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what do we need to handle here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll get rid of this section as per my comment above for right now

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there are a lot of expressions we need to handle here, but they basically get split up into a few categories, binary operators, unary operators and literal expresions and a bunch of one off stuff like assigning, identifiers, member access, function calls etc. My plan was to start with binary operators and build up the correct parentheses management / operator precedence, indentation etc after I get comments working

Comment on lines -923 to -925
if !event.doc.is_empty() {
event.doc.visit(self)?;
writeln!(self)?;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is it OK to remove all these?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The doc comments are no longer attached to individual elements and exist as their own nodes

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We made that change because solc accepts doc comments anywhere in a file. This is valid solidity:

contract c {}
/** foo */

"(formatted Parse Tree == expected Parse Tree) in {}",
filename
);
// panic!("(formatted Parse Tree == expected Parse Tree) in {}", filename)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// panic!("(formatted Parse Tree == expected Parse Tree) in {}", filename)

test_directory! { EnumDefinition }
test_directory! { ErrorDefinition }
test_directory! { EventDefinition }
// test_directory! { ExpressionPrecedence }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we re-enable this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this was an experiment related to the operator precedence as mentioned above. i'll also remove

Comment on lines 6 to 7
// TODO handle me
todo!()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what needs to go here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'll expand the todo message here and return false. it shouldn't panic either way

fmt/src/visit.rs Outdated
Comment on lines 319 to 320
// TODO implement me
Ok(())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this log trace::warn!("Formatting not yet implemented for Using") or something? Same for all our other unimplemented stuff?

@jpopesculian
Copy link
Contributor Author

Okay, I cleaned up the PR, sorry a lot of work in progress stuff got mixed in because I wasn't sure if this was just here as feedback or if it was going to be merged in before comments were done. I probably should have submitted it as a draft, but this at least fixes the update for solang_parser and doc comments, using statements and a few other small things. I'll hopefully have the comments done soon and I'll open that in a separate PR. And then started working on expressions which I think is the next hardest thing to tackle here. After that, there's the Yul stuff, and incremental improvements I think

Copy link
Collaborator

@rkrasiuk rkrasiuk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good stuff!

Comment on lines 274 to 282
let mut lines = doc_comment
.comment
.lines()
.map(|line| line.trim_start())
.peekable()
.collect::<Vec<_>>();
if lines.last() == Some(&"") {
lines.pop();
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let mut lines = doc_comment
.comment
.lines()
.map(|line| line.trim_start())
.peekable()
.collect::<Vec<_>>();
if lines.last() == Some(&"") {
lines.pop();
}
let mut lines = doc_comment
.comment
.trim_end()
.lines()
.map(|line| line.trim_start())
.peekable()
.collect::<Vec<_>>();

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

much cleaner and correcter! thanks!

Copy link
Member

@mattsse mattsse left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm!

Copy link

@seanyoung seanyoung left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This pr updates the solang-parser crate in fmt, but cli still using an old version: https://github.com/jpopesculian/foundry/blob/fmt/cli/Cargo.toml#L29

This means the formattter could re-format something that the cli code then cannot parse.

@gakonst gakonst merged commit 0e6c8fb into foundry-rs:master May 20, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
L-ignore Log: ignore PR in changelog
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants