From d9e1ca144e2e0de5ca7e439c271ae9f8242ca20a Mon Sep 17 00:00:00 2001 From: James Towle Date: Thu, 13 Jun 2019 14:22:02 -0700 Subject: [PATCH 1/9] Created the skeleton for the formatter --- src/codegen.rs | 204 ++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + src/main.rs | 10 ++- src/parse_4_25.rs | 2 +- 4 files changed, 213 insertions(+), 4 deletions(-) create mode 100644 src/codegen.rs diff --git a/src/codegen.rs b/src/codegen.rs new file mode 100644 index 0000000..d2fe64d --- /dev/null +++ b/src/codegen.rs @@ -0,0 +1,204 @@ +use super::lex_4_25; +use super::parse_4_25; + +/*** Top Level ***/ + +pub fn generate(tree: parse_4_25::ParseTree) -> String { + let mut result = String::new(); + for child in tree.children { + match child.node { + lex_4_25::Token::Pragma => result.push_str(&generate_pragma(child)), + lex_4_25::Token::Import => result.push_str(&generate_import(child)), + lex_4_25::Token::Library | + lex_4_25::Token::Contract | + lex_4_25::Token::Interface => result.push_str(&generate_contract(child)), + _ => panic!("Invalid top level tree") + } + } + result +} + +/*** Pragma ***/ + +fn generate_pragma(pragma: parse_4_25::ParseNode) -> String { + let mut result = String::new(); + if let lex_4_25::Token::Pragma = pragma.node { + result.push_str("pragma "); + } + if pragma.children.len() >= 2 { + if let lex_4_25::Token::Identifier(name) = &pragma.children[0].node { + result.push_str(&name); + result.push(' '); + } + if pragma.children.len() == 2 { + if let lex_4_25::Token::Version(version) = &pragma.children[1].node { + result.push_str(&version); + result.push_str(";"); + } + } else if pragma.children.len() == 3 { + if let lex_4_25::Token::BitwiseXor = &pragma.children[1].node { + result.push('^'); + } + if let lex_4_25::Token::Version(version) = &pragma.children[2].node { + result.push_str(&version); + result.push_str(";"); + } + } + } + result +} + +/*** Import ***/ + +fn generate_import(import: parse_4_25::ParseNode) -> String { String::new() } + +/*** Contract ***/ + +fn generate_contract(contract: parse_4_25::ParseNode) -> String { + let mut result = String::new(); + match contract.node { + lex_4_25::Token::Contract => result.push_str("\n\ncontract "), + lex_4_25::Token::Library => result.push_str("\n\nlibrary "), + lex_4_25::Token::Interface => result.push_str("\n\ninterface "), + _ => panic!("Invalid contract definition") + } + if contract.children.len() == 2 { + match &contract.children[0].node { + lex_4_25::Token::Identifier(name) => { + result.push_str(&name); + result.push(' '); + } + _ => panic!("Invalid contract definition") + } + match &contract.children[1].node { + lex_4_25::Token::OpenBrace => { + result.push_str(&generate_contract_part(&contract.children[1])); + } + _ => panic!("Invalid contract definition") + } + } else if contract.children.len() == 3 { + match &contract.children[0].node { + lex_4_25::Token::Identifier(name) => { + result.push_str(&name); + result.push(' '); + } + _ => panic!("Invalid contract definition") + } + match &contract.children[1].node { + lex_4_25::Token::Is => { + result.push_str(&generate_inheritance_specifier(&contract.children[1])); + } + _ => panic!("Invalid contract definition") + } + match &contract.children[2].node { + lex_4_25::Token::OpenBrace => { + result.push_str(&generate_contract_part(&contract.children[2])); + } + _ => panic!("Invalid contract definition") + } + } + result +} + +/*** Inheritance Specifier ***/ + +fn generate_inheritance_specifier(block: &parse_4_25::ParseNode) -> String { + let mut result = String::new(); + match block.node { + lex_4_25::Token::Is => result.push_str("is\n"), + _ => panic!("Invalid inheritance specifier") + } + match &block.children[0].node { + lex_4_25::Token::OpenParenthesis => (), + _ => panic!("Invalid inheritance specifier") + } + for i in 0..=block.children[0].children.len() { + result.push_str(&generate_user_defined_type_name(&block.children[0].children[i])); + if i != block.children[0].children.len() - 1 { + result.push_str(",\n"); + } else { + result.push('\n'); + } + } + result +} + +/*** Contract Part ***/ + +fn generate_contract_part(block: &parse_4_25::ParseNode) -> String { + let mut result = String::new(); + result +} + +/*** Types ***/ + +fn generate_user_defined_type_name(type_name: &parse_4_25::ParseNode) -> String { + let mut result = String::new(); + match type_name.node { + lex_4_25::Token::UserDefinedTypeName => (), + _ => panic!("Invalid user defined type name") + } + for i in 0..=type_name.children.len() - 1{ + println!("Got here"); + match &type_name.children[i].node { + lex_4_25::Token::Identifier(name) => result.push_str(&name), + _ => panic!("Invalid user defined type name") + } + if i != type_name.children.len() - 1 { + result.push('.'); + } + } + result +} + +/*** Testing ***/ + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn generate_pragma_test1() { + let tree = parse_4_25::ParseTree { + children: vec![ + parse_4_25::ParseNode { + node: lex_4_25::Token::Pragma, + children: vec![ + Box::new(lex_4_25::Token::Identifier("solidity".to_string()).to_leaf()), + Box::new(lex_4_25::Token::Version("0.4.25".to_string()).to_leaf()) + ] + } + ] + }; + let actual_generated = generate(tree); + let expected_generated = "pragma solidity 0.4.25;"; + assert_eq!(expected_generated, actual_generated); + } + + #[test] + fn generate_user_defined_type_name_test1() { + let node = parse_4_25::ParseNode { + node: lex_4_25::Token::UserDefinedTypeName, + children: vec![ + Box::new(lex_4_25::Token::Identifier("A".to_string()).to_leaf()) + ] + }; + let actual_generated = generate_user_defined_type_name(&node); + let expected_generated = String::from("A"); + assert_eq!(expected_generated, actual_generated); + } + + #[test] + fn generate_user_defined_type_name_test2() { + let node = parse_4_25::ParseNode { + node: lex_4_25::Token::UserDefinedTypeName, + children: vec![ + Box::new(lex_4_25::Token::Identifier("A".to_string()).to_leaf()), + Box::new(lex_4_25::Token::Identifier("b".to_string()).to_leaf()) + ] + }; + let actual_generated = generate_user_defined_type_name(&node); + let expected_generated = String::from("A.b"); + assert_eq!(expected_generated, actual_generated); + } +} diff --git a/src/lib.rs b/src/lib.rs index 09cf08d..6d775bf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,2 +1,3 @@ pub mod lex_4_25; pub mod parse_4_25; +pub mod codegen; diff --git a/src/main.rs b/src/main.rs index 12e7200..ff14d16 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,13 @@ use std::env; use std::fs; use solfix::parse_4_25::parse; +use solfix::codegen::generate; fn main() { - let name = env::args().nth(1).expect("Usage: solidity-fix FILE_NAME"); - let input = fs::read_to_string(name).expect("Unable to open input file"); - println!("{:?}", parse(input)); + let usage = "Usage: solidity-fix SOURCE TARGET"; + let source = env::args().nth(1).expect(usage); + let target = env::args().nth(2).expect(usage); + let input = fs::read_to_string(source).expect("Unable to open input file"); + let result = generate(parse(input)); + fs::write(target, result).expect("Unable to write file"); } diff --git a/src/parse_4_25.rs b/src/parse_4_25.rs index 1530f1f..c1a3c74 100644 --- a/src/parse_4_25.rs +++ b/src/parse_4_25.rs @@ -1268,4 +1268,4 @@ fn parse_function_type_parameter(chars: &Vec, cur: &mut usize) -> ParseNod _ => () } result -} \ No newline at end of file +} From 7756006fa47f463862b84fd6d23a2b68965b054a Mon Sep 17 00:00:00 2001 From: James Towle Date: Thu, 13 Jun 2019 14:36:55 -0700 Subject: [PATCH 2/9] Added a test for inheritance specifier formatting --- src/codegen.rs | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/codegen.rs b/src/codegen.rs index d2fe64d..642eada 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -112,7 +112,9 @@ fn generate_inheritance_specifier(block: &parse_4_25::ParseNode) -> String { lex_4_25::Token::OpenParenthesis => (), _ => panic!("Invalid inheritance specifier") } - for i in 0..=block.children[0].children.len() { + for i in 0..=block.children[0].children.len() - 1 { + // FIXME Replace with result.indent() + result.push_str(" "); result.push_str(&generate_user_defined_type_name(&block.children[0].children[i])); if i != block.children[0].children.len() - 1 { result.push_str(",\n"); @@ -139,7 +141,6 @@ fn generate_user_defined_type_name(type_name: &parse_4_25::ParseNode) -> String _ => panic!("Invalid user defined type name") } for i in 0..=type_name.children.len() - 1{ - println!("Got here"); match &type_name.children[i].node { lex_4_25::Token::Identifier(name) => result.push_str(&name), _ => panic!("Invalid user defined type name") @@ -175,6 +176,29 @@ mod tests { assert_eq!(expected_generated, actual_generated); } + #[test] + fn generate_inheritance_specifier_test1() { + let node = parse_4_25::ParseNode { + node: lex_4_25::Token::Is, + children: vec![ + Box::new(parse_4_25::ParseNode { + node: lex_4_25::Token::OpenParenthesis, + children: vec![ + Box::new(parse_4_25::ParseNode { + node: lex_4_25::Token::UserDefinedTypeName, + children: vec![ + Box::new(lex_4_25::Token::Identifier("A".to_string()).to_leaf()) + ] + }) + ] + }) + ] + }; + let actual_generated = generate_inheritance_specifier(&node); + let expected_generated = "is\n A\n"; + assert_eq!(actual_generated, expected_generated); + } + #[test] fn generate_user_defined_type_name_test1() { let node = parse_4_25::ParseNode { From 576f5bf4342474e2c4a7332e045a62e8cf5bcccf Mon Sep 17 00:00:00 2001 From: James Towle Date: Thu, 13 Jun 2019 15:36:07 -0700 Subject: [PATCH 3/9] Added support for enum defintions --- contracts/Empty.sol | 3 + src/codegen.rs | 168 ++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 7 +- 3 files changed, 175 insertions(+), 3 deletions(-) create mode 100644 contracts/Empty.sol diff --git a/contracts/Empty.sol b/contracts/Empty.sol new file mode 100644 index 0000000..06722b6 --- /dev/null +++ b/contracts/Empty.sol @@ -0,0 +1,3 @@ +pragma solidity ^0.4.25; + +contract Empty {} diff --git a/src/codegen.rs b/src/codegen.rs index 642eada..c4a46f4 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -129,9 +129,74 @@ fn generate_inheritance_specifier(block: &parse_4_25::ParseNode) -> String { fn generate_contract_part(block: &parse_4_25::ParseNode) -> String { let mut result = String::new(); + match block.node { + lex_4_25::Token::OpenBrace => result.push('{'), + _ => panic!("Invalid contract part") + } + for child in &block.children { + match child.node { + lex_4_25::Token::Enum => result.push_str(&generate_enum(&child)), + lex_4_25::Token::Event => result.push_str(&generate_event(&child)), + lex_4_25::Token::Function => result.push_str(&generate_function(&child)), + lex_4_25::Token::Modifier => result.push_str(&generate_modifier(&child)), + lex_4_25::Token::Using => result.push_str(&generate_using_for(&child)), + lex_4_25::Token::Struct => result.push_str(&generate_struct(&child)), + _ => panic!("Invalid contract part") + } + } + result.push('}'); result } +/*** Sub-contract Structures ***/ + +fn generate_enum(node: &parse_4_25::ParseNode) -> String { + let mut result = String::new(); + match node.node { + lex_4_25::Token::Enum => result.push_str("enum"), + _ => panic!("Invalid enum definition") + } + result.push(' '); + match &node.children[0].node { + lex_4_25::Token::Identifier(name) => result.push_str(&name), + _ => panic!("Invalid enum definition") + } + result.push(' '); + match &node.children[1].node { + lex_4_25::Token::OpenBrace => result.push_str("{"), + _ => panic!("Invalid enum definition") + } + if node.children[1].children.len() > 0 { + for i in 0..=node.children[1].children.len() - 1 { + result.push('\n'); + match &node.children[1].children[i].node { + lex_4_25::Token::Identifier(name) => { + result.push_str(" "); + result.push_str(&name); + } + _ => panic!("Invalid enum definition") + } + if i != node.children[1].children.len() - 1 { + result.push(','); + } else { + result.push('\n'); + } + } + } + result.push_str("}"); + result +} + +fn generate_event(node: &parse_4_25::ParseNode) -> String { String::new() } + +fn generate_function(node: &parse_4_25::ParseNode) -> String { String::new() } + +fn generate_modifier(node: &parse_4_25::ParseNode) -> String { String::new() } + +fn generate_using_for(node: &parse_4_25::ParseNode) -> String { String::new() } + +fn generate_struct(node: &parse_4_25::ParseNode) -> String { String::new() } + /*** Types ***/ fn generate_user_defined_type_name(type_name: &parse_4_25::ParseNode) -> String { @@ -199,6 +264,109 @@ mod tests { assert_eq!(actual_generated, expected_generated); } + #[test] + fn generate_inheritance_specifier_test2() { + let node = parse_4_25::ParseNode { + node: lex_4_25::Token::Is, + children: vec![ + Box::new(parse_4_25::ParseNode { + node: lex_4_25::Token::OpenParenthesis, + children: vec![ + Box::new(parse_4_25::ParseNode { + node: lex_4_25::Token::UserDefinedTypeName, + children: vec![ + Box::new(lex_4_25::Token::Identifier("A".to_string()).to_leaf()) + ] + }), + Box::new(parse_4_25::ParseNode { + node: lex_4_25::Token::UserDefinedTypeName, + children: vec![ + Box::new(lex_4_25::Token::Identifier("Bat".to_string()).to_leaf()), + Box::new(lex_4_25::Token::Identifier("Car".to_string()).to_leaf()) + ] + }) + ] + }) + ] + }; + let actual_generated = generate_inheritance_specifier(&node); + let expected_generated = "is\n A,\n Bat.Car\n"; + assert_eq!(actual_generated, expected_generated); + } + + #[test] + fn generate_inheritance_specifier_test3() { + let node = parse_4_25::ParseNode { + node: lex_4_25::Token::Is, + children: vec![ + Box::new(parse_4_25::ParseNode { + node: lex_4_25::Token::OpenParenthesis, + children: vec![ + Box::new(parse_4_25::ParseNode { + node: lex_4_25::Token::UserDefinedTypeName, + children: vec![ + Box::new(lex_4_25::Token::Identifier("A".to_string()).to_leaf()) + ] + }), + Box::new(parse_4_25::ParseNode { + node: lex_4_25::Token::UserDefinedTypeName, + children: vec![ + Box::new(lex_4_25::Token::Identifier("Bat".to_string()).to_leaf()), + Box::new(lex_4_25::Token::Identifier("Car".to_string()).to_leaf()) + ] + }), + Box::new(parse_4_25::ParseNode { + node: lex_4_25::Token::UserDefinedTypeName, + children: vec![ + Box::new(lex_4_25::Token::Identifier("foo".to_string()).to_leaf()), + Box::new(lex_4_25::Token::Identifier("bar".to_string()).to_leaf()), + Box::new(lex_4_25::Token::Identifier("baz".to_string()).to_leaf()) + ] + }) + ] + }) + ] + }; + let actual_generated = generate_inheritance_specifier(&node); + let expected_generated = "is\n A,\n Bat.Car,\n foo.bar.baz\n"; + assert_eq!(actual_generated, expected_generated); + } + + #[test] + fn generate_enum_test1() { + let node = parse_4_25::ParseNode { + node: lex_4_25::Token::Enum, + children: vec![ + Box::new(lex_4_25::Token::Identifier("empty".to_string()).to_leaf()), + Box::new(lex_4_25::Token::OpenBrace.to_leaf()) + ] + }; + let actual_generated = generate_enum(&node); + let expected_generated = String::from("enum empty {}"); + assert_eq!(expected_generated, actual_generated); + } + + #[test] + fn generate_enum_test2() { + let node = parse_4_25::ParseNode { + node: lex_4_25::Token::Enum, + children: vec![ + Box::new(lex_4_25::Token::Identifier("Letters".to_string()).to_leaf()), + Box::new(parse_4_25::ParseNode { + node: lex_4_25::Token::OpenBrace, + children: vec![ + Box::new(lex_4_25::Token::Identifier("A".to_string()).to_leaf()), + Box::new(lex_4_25::Token::Identifier("B".to_string()).to_leaf()), + Box::new(lex_4_25::Token::Identifier("C".to_string()).to_leaf()) + ] + }) + ] + }; + let actual_generated = generate_enum(&node); + let expected_generated = String::from("enum Letters {\n A,\n B,\n C\n}"); + assert_eq!(expected_generated, actual_generated); + } + #[test] fn generate_user_defined_type_name_test1() { let node = parse_4_25::ParseNode { diff --git a/src/main.rs b/src/main.rs index ff14d16..aec71a5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,8 +6,9 @@ use solfix::codegen::generate; fn main() { let usage = "Usage: solidity-fix SOURCE TARGET"; let source = env::args().nth(1).expect(usage); - let target = env::args().nth(2).expect(usage); +// let target = env::args().nth(2).expect(usage); let input = fs::read_to_string(source).expect("Unable to open input file"); - let result = generate(parse(input)); - fs::write(target, result).expect("Unable to write file"); + println!("{}", generate(parse(input))); +// let result = generate(parse(input)); +// fs::write(target, result).expect("Unable to write file"); } From d018d6588e0b114fdde75439cef1df486ad703e0 Mon Sep 17 00:00:00 2001 From: James Towle Date: Thu, 13 Jun 2019 16:31:36 -0700 Subject: [PATCH 4/9] Improved support for type name style-rules --- src/codegen.rs | 246 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 243 insertions(+), 3 deletions(-) diff --git a/src/codegen.rs b/src/codegen.rs index c4a46f4..3453208 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -163,7 +163,7 @@ fn generate_enum(node: &parse_4_25::ParseNode) -> String { } result.push(' '); match &node.children[1].node { - lex_4_25::Token::OpenBrace => result.push_str("{"), + lex_4_25::Token::OpenBrace => result.push('{'), _ => panic!("Invalid enum definition") } if node.children[1].children.len() > 0 { @@ -183,11 +183,69 @@ fn generate_enum(node: &parse_4_25::ParseNode) -> String { } } } - result.push_str("}"); + result.push('}'); + result +} + +fn generate_event(node: &parse_4_25::ParseNode) -> String { + let mut result = String::new(); + match node.node { + lex_4_25::Token::Event => result.push_str("event"), + _ => panic!("Invalid event definition") + } + result.push(' '); + match &node.children[0].node { + lex_4_25::Token::Identifier(name) => result.push_str(&name), + _ => panic!("Invalid event definition") + } + result.push(' '); + match &node.children[1].node { + lex_4_25::Token::OpenParenthesis => result.push('('), + _ => panic!("Invalid event definition") + } + if node.children[1].children.len() > 0 { + for i in 0..=node.children[1].children.len() - 1 { + result.push('\n'); + result.push_str(" "); + result.push_str(&generate_event_parameter(&node.children[1].children[i])); + if i != node.children[1].children.len() - 1 { + result.push(','); + } else { + result.push('\n'); + } + } + } + result.push(')'); result } -fn generate_event(node: &parse_4_25::ParseNode) -> String { String::new() } +fn generate_event_parameter(node: &parse_4_25::ParseNode) -> String { + let mut result = String::new(); + match node.node { + lex_4_25::Token::EventParameter => (), + _ => panic!("Invalid event parameter") + } + // Format the type name of the event parameter and append it to the result + result.push_str(&generate_type_name(&node.children[0])); + if node.children.len() == 2 { + match &node.children[0].node { + lex_4_25::Token::Indexed => result.push_str(" indexed"), + _ => panic!("Invalid event parameter") + } + } else if node.children.len() == 3 { + match &node.children[0].node { + lex_4_25::Token::Indexed => result.push_str(" indexed "), + _ => panic!("Invalid event parameter") + } + match &node.children[1].node { + lex_4_25::Token::Identifier(name) => result.push_str(&name), + _ => panic!("Invalid event parameter") + } + } else if node.children.len() != 1 { + panic!("Invalid event parameter"); + } + result +} fn generate_function(node: &parse_4_25::ParseNode) -> String { String::new() } @@ -199,6 +257,23 @@ fn generate_struct(node: &parse_4_25::ParseNode) -> String { String::new() } /*** Types ***/ +fn generate_type_name(type_name: &parse_4_25::ParseNode) -> String { + return match type_name.node { + lex_4_25::Token::Identifier(..) => generate_user_defined_type_name(type_name), + lex_4_25::Token::Function => generate_function_type(type_name), + lex_4_25::Token::Mapping => generate_mapping(type_name), + lex_4_25::Token::OpenBracket => generate_array_type_name(type_name), + ref elementary => { + if elementary.is_elementary_type() { + return generate_elementary_type(type_name); + } else { + panic!("Invalid type name"); + } + } + + } +} + fn generate_user_defined_type_name(type_name: &parse_4_25::ParseNode) -> String { let mut result = String::new(); match type_name.node { @@ -217,6 +292,131 @@ fn generate_user_defined_type_name(type_name: &parse_4_25::ParseNode) -> String result } +fn generate_array_type_name(function_type: &parse_4_25::ParseNode) -> String { + let mut result = String::new(); + result +} + +fn generate_function_type(function_type: &parse_4_25::ParseNode) -> String { + let mut result = String::new(); + result +} + +fn generate_mapping(function_type: &parse_4_25::ParseNode) -> String { + let mut result = String::new(); + result +} + +fn generate_elementary_type(elementary_type: &parse_4_25::ParseNode) -> String { + return match elementary_type.node { + lex_4_25::Token::Address => "address", + lex_4_25::Token::Bool => "bool", + lex_4_25::Token::Byte => "byte", + lex_4_25::Token::Bytes => "bytes", + lex_4_25::Token::Bytes1 => "bytes1", + lex_4_25::Token::Bytes2 => "bytes2", + lex_4_25::Token::Bytes3 => "bytes3", + lex_4_25::Token::Bytes4 => "bytes4", + lex_4_25::Token::Bytes5 => "bytes5", + lex_4_25::Token::Bytes6 => "bytes6", + lex_4_25::Token::Bytes7 => "bytes7", + lex_4_25::Token::Bytes8 => "bytes8", + lex_4_25::Token::Bytes9 => "bytes9", + lex_4_25::Token::Bytes10 => "bytes10", + lex_4_25::Token::Bytes11 => "bytes11", + lex_4_25::Token::Bytes12 => "bytes12", + lex_4_25::Token::Bytes13 => "bytes13", + lex_4_25::Token::Bytes14 => "bytes14", + lex_4_25::Token::Bytes15 => "bytes15", + lex_4_25::Token::Bytes16 => "bytes16", + lex_4_25::Token::Bytes17 => "bytes17", + lex_4_25::Token::Bytes18 => "bytes18", + lex_4_25::Token::Bytes19 => "bytes19", + lex_4_25::Token::Bytes20 => "bytes20", + lex_4_25::Token::Bytes21 => "bytes21", + lex_4_25::Token::Bytes22 => "bytes22", + lex_4_25::Token::Bytes23 => "bytes23", + lex_4_25::Token::Bytes24 => "bytes24", + lex_4_25::Token::Bytes25 => "bytes25", + lex_4_25::Token::Bytes26 => "bytes26", + lex_4_25::Token::Bytes27 => "bytes27", + lex_4_25::Token::Bytes28 => "bytes28", + lex_4_25::Token::Bytes29 => "bytes29", + lex_4_25::Token::Bytes30 => "bytes30", + lex_4_25::Token::Bytes31 => "bytes31", + lex_4_25::Token::Bytes32 => "bytes32", + lex_4_25::Token::Int => "int", + lex_4_25::Token::Int8 => "int8", + lex_4_25::Token::Int16 => "int16", + lex_4_25::Token::Int24 => "int24", + lex_4_25::Token::Int32 => "int32", + lex_4_25::Token::Int40 => "int40", + lex_4_25::Token::Int48 => "int48", + lex_4_25::Token::Int56 => "int56", + lex_4_25::Token::Int64 => "int64", + lex_4_25::Token::Int72 => "int72", + lex_4_25::Token::Int80 => "int80", + lex_4_25::Token::Int88 => "int88", + lex_4_25::Token::Int96 => "int96", + lex_4_25::Token::Int104 => "int104", + lex_4_25::Token::Int112 => "int112", + lex_4_25::Token::Int120 => "int120", + lex_4_25::Token::Int128 => "int128", + lex_4_25::Token::Int136 => "int136", + lex_4_25::Token::Int144 => "int144", + lex_4_25::Token::Int152 => "int152", + lex_4_25::Token::Int160 => "int160", + lex_4_25::Token::Int168 => "int168", + lex_4_25::Token::Int176 => "int176", + lex_4_25::Token::Int184 => "int184", + lex_4_25::Token::Int192 => "int192", + lex_4_25::Token::Int200 => "int200", + lex_4_25::Token::Int208 => "int208", + lex_4_25::Token::Int216 => "int216", + lex_4_25::Token::Int224 => "int224", + lex_4_25::Token::Int232 => "int232", + lex_4_25::Token::Int240 => "int240", + lex_4_25::Token::Int248 => "int248", + lex_4_25::Token::Int256 => "int256", + lex_4_25::Token::String => "string", + lex_4_25::Token::Var => "var", + lex_4_25::Token::Uint => "uint", + lex_4_25::Token::Uint8 => "uint8", + lex_4_25::Token::Uint16 => "uint16", + lex_4_25::Token::Uint24 => "uint24", + lex_4_25::Token::Uint32 => "uint32", + lex_4_25::Token::Uint40 => "uint40", + lex_4_25::Token::Uint48 => "uint48", + lex_4_25::Token::Uint56 => "uint56", + lex_4_25::Token::Uint64 => "uint64", + lex_4_25::Token::Uint72 => "uint72", + lex_4_25::Token::Uint80 => "uint80", + lex_4_25::Token::Uint88 => "uint88", + lex_4_25::Token::Uint96 => "uint96", + lex_4_25::Token::Uint104 => "uint104", + lex_4_25::Token::Uint112 => "uint112", + lex_4_25::Token::Uint120 => "uint120", + lex_4_25::Token::Uint128 => "uint128", + lex_4_25::Token::Uint136 => "uint136", + lex_4_25::Token::Uint144 => "uint144", + lex_4_25::Token::Uint152 => "uint152", + lex_4_25::Token::Uint160 => "uint160", + lex_4_25::Token::Uint168 => "uint168", + lex_4_25::Token::Uint176 => "uint176", + lex_4_25::Token::Uint184 => "uint184", + lex_4_25::Token::Uint192 => "uint192", + lex_4_25::Token::Uint200 => "uint200", + lex_4_25::Token::Uint208 => "uint208", + lex_4_25::Token::Uint216 => "uint216", + lex_4_25::Token::Uint224 => "uint224", + lex_4_25::Token::Uint232 => "uint232", + lex_4_25::Token::Uint240 => "uint240", + lex_4_25::Token::Uint248 => "uint248", + lex_4_25::Token::Uint256 => "uint256", + _ => panic!("Invalid elementary type") + }.to_string() +} + /*** Testing ***/ #[cfg(test)] @@ -393,4 +593,44 @@ mod tests { let expected_generated = String::from("A.b"); assert_eq!(expected_generated, actual_generated); } + + #[test] + fn generate_elementary_type_test1() { + let node = lex_4_25::Token::Address.to_leaf(); + let actual_generated = generate_elementary_type(&node); + let expected_generated = "address"; + assert_eq!(expected_generated, actual_generated); + } + + #[test] + fn generate_elementary_type_test2() { + let node = lex_4_25::Token::Bool.to_leaf(); + let actual_generated = generate_elementary_type(&node); + let expected_generated = "bool"; + assert_eq!(expected_generated, actual_generated); + } + + #[test] + fn generate_elementary_type_test3() { + let node = lex_4_25::Token::Byte.to_leaf(); + let actual_generated = generate_elementary_type(&node); + let expected_generated = "byte"; + assert_eq!(expected_generated, actual_generated); + } + + #[test] + fn generate_elementary_type_test4() { + let node = lex_4_25::Token::Bytes.to_leaf(); + let actual_generated = generate_elementary_type(&node); + let expected_generated = "bytes"; + assert_eq!(expected_generated, actual_generated); + } + + #[test] + fn generate_elementary_type_test5() { + let node = lex_4_25::Token::Bytes1.to_leaf(); + let actual_generated = generate_elementary_type(&node); + let expected_generated = "bytes1"; + assert_eq!(expected_generated, actual_generated); + } } From a24a6db106bef926b000fd7360193ee3d02c720c Mon Sep 17 00:00:00 2001 From: James Towle Date: Thu, 13 Jun 2019 17:18:15 -0700 Subject: [PATCH 5/9] Added support for event and struct definitions style-rules --- src/codegen.rs | 162 +++++++++++++++++++++++++++++++++++++++++++--- src/lex_4_25.rs | 1 + src/parse_4_25.rs | 56 +++++++++++++++- 3 files changed, 209 insertions(+), 10 deletions(-) diff --git a/src/codegen.rs b/src/codegen.rs index 3453208..25d47d1 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -198,7 +198,6 @@ fn generate_event(node: &parse_4_25::ParseNode) -> String { lex_4_25::Token::Identifier(name) => result.push_str(&name), _ => panic!("Invalid event definition") } - result.push(' '); match &node.children[1].node { lex_4_25::Token::OpenParenthesis => result.push('('), _ => panic!("Invalid event definition") @@ -216,6 +215,7 @@ fn generate_event(node: &parse_4_25::ParseNode) -> String { } } result.push(')'); + result.push(';'); result } @@ -228,16 +228,16 @@ fn generate_event_parameter(node: &parse_4_25::ParseNode) -> String { // Format the type name of the event parameter and append it to the result result.push_str(&generate_type_name(&node.children[0])); if node.children.len() == 2 { - match &node.children[0].node { + match &node.children[1].node { lex_4_25::Token::Indexed => result.push_str(" indexed"), _ => panic!("Invalid event parameter") } } else if node.children.len() == 3 { - match &node.children[0].node { + match &node.children[1].node { lex_4_25::Token::Indexed => result.push_str(" indexed "), _ => panic!("Invalid event parameter") } - match &node.children[1].node { + match &node.children[2].node { lex_4_25::Token::Identifier(name) => result.push_str(&name), _ => panic!("Invalid event parameter") } @@ -247,13 +247,79 @@ fn generate_event_parameter(node: &parse_4_25::ParseNode) -> String { result } -fn generate_function(node: &parse_4_25::ParseNode) -> String { String::new() } +fn generate_function(node: &parse_4_25::ParseNode) -> String { + let mut result = String::new(); + result +} -fn generate_modifier(node: &parse_4_25::ParseNode) -> String { String::new() } +fn generate_modifier(node: &parse_4_25::ParseNode) -> String { + let mut result = String::new(); + result +} -fn generate_using_for(node: &parse_4_25::ParseNode) -> String { String::new() } +fn generate_using_for(node: &parse_4_25::ParseNode) -> String { + let mut result = String::new(); + result +} + +fn generate_struct(node: &parse_4_25::ParseNode) -> String { + let mut result = String::new(); + match node.node { + lex_4_25::Token::Struct => result.push_str("struct"), + _ => panic!("Invalid struct definition") + } + result.push(' '); + match &node.children[0].node { + lex_4_25::Token::Identifier(name) => result.push_str(&name), + _ => panic!("Invalid struct definition") + } + result.push(' '); + match &node.children[1].node { + lex_4_25::Token::OpenBrace => result.push('{'), + _ => panic!("Invalid struct definition") + } + for i in 0..=node.children[1].children.len() - 1 { + result.push('\n'); + result.push_str(" "); + result.push_str(&generate_variable_declaration(&node.children[1].children[i])); + result.push(';'); + if i == node.children[1].children.len() - 1 { + result.push('\n'); + } + } + result.push('}'); + result +} -fn generate_struct(node: &parse_4_25::ParseNode) -> String { String::new() } +fn generate_variable_declaration(node: &parse_4_25::ParseNode) -> String { + let mut result = String::new(); + match node.node { + lex_4_25::Token::VariableDeclaration => (), + _ => panic!("Invalid variable declaration") + } + result.push_str(&generate_type_name(&node.children[0])); + result.push(' '); + if node.children.len() == 2 { + match &node.children[1].node { + lex_4_25::Token::Identifier(name) => result.push_str(&name), + _ => panic!("Invalid variable declaration") + } + } else if node.children.len() == 3 { + match &node.children[1].node { + lex_4_25::Token::Memory => result.push_str("memory"), + lex_4_25::Token::Storage => result.push_str("storage"), + _ => panic!("Invalid variable declaration") + } + result.push(' '); + match &node.children[1].node { + lex_4_25::Token::Identifier(name) => result.push_str(&name), + _ => panic!("Invalid variable declaration") + } + } else { + panic!("Invalid variable declaration"); + } + result +} /*** Types ***/ @@ -567,6 +633,86 @@ mod tests { assert_eq!(expected_generated, actual_generated); } + #[test] + fn generate_event_test1() { + let node = parse_4_25::ParseNode { + node: lex_4_25::Token::Event, + children: vec![ + Box::new(lex_4_25::Token::Identifier("empty".to_string()).to_leaf()), + Box::new(lex_4_25::Token::OpenParenthesis.to_leaf()) + ] + }; + let actual_generated = generate_event(&node); + let expected_generated = "event empty();"; + } + + #[test] + fn generate_event_test2() { + let node = parse_4_25::ParseNode { + node: lex_4_25::Token::Event, + children: vec![ + Box::new(lex_4_25::Token::Identifier("Transfer".to_string()).to_leaf()), + Box::new(parse_4_25::ParseNode { + node: lex_4_25::Token::OpenParenthesis, + children: vec![ + Box::new(parse_4_25::ParseNode { + node: lex_4_25::Token::EventParameter, + children: vec![ + Box::new(lex_4_25::Token::Address.to_leaf()), + Box::new(lex_4_25::Token::Indexed.to_leaf()), + Box::new(lex_4_25::Token::Identifier("owner".to_string()).to_leaf()) + ] + }), + Box::new(parse_4_25::ParseNode { + node: lex_4_25::Token::EventParameter, + children: vec![ + Box::new(lex_4_25::Token::Address.to_leaf()), + Box::new(lex_4_25::Token::Indexed.to_leaf()), + Box::new(lex_4_25::Token::Identifier("recipient".to_string()).to_leaf()) + ] + }), + Box::new(parse_4_25::ParseNode { + node: lex_4_25::Token::EventParameter, + children: vec![ + Box::new(lex_4_25::Token::Uint256.to_leaf()), + Box::new(lex_4_25::Token::Indexed.to_leaf()), + Box::new(lex_4_25::Token::Identifier("value".to_string()).to_leaf()) + ] + }) + ] + }) + ] + }; + let actual_generated = generate_event(&node); + let expected_generated = "event Transfer(\n address indexed owner,\n address indexed recipient,\n uint256 indexed value\n);"; + assert_eq!(expected_generated, actual_generated); + } + + #[test] + fn generate_struct_test1() { + let node = parse_4_25::ParseNode { + node: lex_4_25::Token::Struct, + children: vec![ + Box::new(lex_4_25::Token::Identifier("Value".to_string()).to_leaf()), + Box::new(parse_4_25::ParseNode { + node: lex_4_25::Token::OpenBrace, + children: vec![ + Box::new(parse_4_25::ParseNode { + node: lex_4_25::Token::VariableDeclaration, + children: vec![ + Box::new(lex_4_25::Token::Uint256.to_leaf()), + Box::new(lex_4_25::Token::Identifier("value".to_string()).to_leaf()) + ] + }) + ] + }) + ] + }; + let actual_generated = generate_struct(&node); + let expected_generated = "struct Value {\n uint256 value;\n}"; + assert_eq!(expected_generated, actual_generated); + } + #[test] fn generate_user_defined_type_name_test1() { let node = parse_4_25::ParseNode { diff --git a/src/lex_4_25.rs b/src/lex_4_25.rs index b525f46..e1ede36 100644 --- a/src/lex_4_25.rs +++ b/src/lex_4_25.rs @@ -219,6 +219,7 @@ pub enum Token { UserDefinedTypeName, Using, Var, + VariableDeclaration, Version(String), View, Weeks, diff --git a/src/parse_4_25.rs b/src/parse_4_25.rs index c1a3c74..8ef14c0 100644 --- a/src/parse_4_25.rs +++ b/src/parse_4_25.rs @@ -201,9 +201,61 @@ fn parse_contract_part(chars: &Vec, cur: &mut usize) -> ParseNode { result } -fn parse_struct_definition(chars: &Vec, cur: &mut usize) -> ParseNode { ParseNode::empty() } +fn parse_struct_definition(chars: &Vec, cur: &mut usize) -> ParseNode { + let mut result = lex_4_25::Token::Struct.to_leaf(); + match lex_4_25::next_token(chars, cur) { + lex_4_25::Token::Struct => (), + _ => panic!("Invalid struct definition") + } + match lex_4_25::next_token(chars, cur) { + id @ lex_4_25::Token::Identifier(..) => result.add_child(id), + _ => panic!("Invalid struct definition") + } + match lex_4_25::next_token(chars, cur) { + lex_4_25::Token::OpenBrace => result.add_child(lex_4_25::Token::OpenBrace), + _ => panic!("Invalid struct definition") + } + result.children.push(Box::new(parse_variable_declaration(chars, cur))); + match lex_4_25::next_token(chars, cur) { + lex_4_25::Token::Semicolon => (), + _ => panic!("Invalid struct definition") + } + let mut stop = false; + while !stop { + match lex_4_25::peek_token(chars, cur) { + lex_4_25::Token::CloseBrace => stop = true, + _ => result.children.push(Box::new(parse_variable_declaration(chars, cur))) + } + if !stop { + match lex_4_25::next_token(chars, cur) { + lex_4_25::Token::Semicolon => (), + _ => panic!("Invalid struct definition") + } + } + } + match lex_4_25::next_token(chars, cur) { + lex_4_25::Token::CloseBrace => (), + _ => panic!("Invalid struct definition") + } + result +} + +fn parse_variable_declaration(chars: &Vec, cur: &mut usize) -> ParseNode { + let mut result = lex_4_25::Token::VariableDeclaration.to_leaf(); + result.children.push(Box::new(parse_type_name(chars, cur))); + match lex_4_25::peek_token(chars, cur) { + lex_4_25::Token::Memory | + lex_4_25::Token::Storage => result.add_child(lex_4_25::next_token(chars, cur)), + _ => panic!("Invalid variable declaration") + } + match lex_4_25::next_token(chars, cur) { + id @ lex_4_25::Token::Identifier(..) => result.add_child(id), + _ => panic!("Invalid variable declaration") + } + result +} -fn parse_state_variable_declaration(chars: &Vec, cur: &mut usize) -> ParseNode { +fn parse_state_variable_declaration(chars: &Vec, cur: &mut usize) -> ParseNode { let mut result = lex_4_25::Token::StateVariable.to_leaf(); result.children.push(Box::new(parse_type_name(chars, cur))); let mut stop = false; From 6122e67ebe3b75c112345c0a80fed32bbf379685 Mon Sep 17 00:00:00 2001 From: James Towle Date: Thu, 13 Jun 2019 22:45:08 -0700 Subject: [PATCH 6/9] Sorry for the big commit: "It's a hackathon" --- contracts/BadEmpty.sol | 15 ++ contracts/Empty.sol | 1 + src/lib.rs | 2 +- src/main.rs | 4 +- src/parse_4_25.rs | 30 +++- src/{codegen.rs => style.rs} | 340 ++++++++++++++++++++++++----------- 6 files changed, 282 insertions(+), 110 deletions(-) create mode 100644 contracts/BadEmpty.sol rename src/{codegen.rs => style.rs} (66%) diff --git a/contracts/BadEmpty.sol b/contracts/BadEmpty.sol new file mode 100644 index 0000000..6b66e69 --- /dev/null +++ b/contracts/BadEmpty.sol @@ -0,0 +1,15 @@ +pragma solidity ^0.4.25 + + +; + + + + + + + +contract Empty { + + +} diff --git a/contracts/Empty.sol b/contracts/Empty.sol index 06722b6..9097001 100644 --- a/contracts/Empty.sol +++ b/contracts/Empty.sol @@ -1,3 +1,4 @@ pragma solidity ^0.4.25; + contract Empty {} diff --git a/src/lib.rs b/src/lib.rs index 6d775bf..13a94c5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,3 @@ pub mod lex_4_25; pub mod parse_4_25; -pub mod codegen; +pub mod style; diff --git a/src/main.rs b/src/main.rs index aec71a5..b28cfd5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,14 +1,14 @@ use std::env; use std::fs; use solfix::parse_4_25::parse; -use solfix::codegen::generate; +use solfix::style::stylize; fn main() { let usage = "Usage: solidity-fix SOURCE TARGET"; let source = env::args().nth(1).expect(usage); // let target = env::args().nth(2).expect(usage); let input = fs::read_to_string(source).expect("Unable to open input file"); - println!("{}", generate(parse(input))); + println!("{}", stylize(parse(input))); // let result = generate(parse(input)); // fs::write(target, result).expect("Unable to write file"); } diff --git a/src/parse_4_25.rs b/src/parse_4_25.rs index 8ef14c0..60748de 100644 --- a/src/parse_4_25.rs +++ b/src/parse_4_25.rs @@ -475,6 +475,21 @@ fn parse_parameter_list(chars: &Vec, cur: &mut usize) -> ParseNode { lex_4_25::Token::OpenParenthesis => (), _ => panic!("Invalid parameter list") } + let mut stop = false; + while !stop { + /* + match lex_4_25::peek_token(chars, cur) { + lex_4_25::Token::CloseParenthesis => stop = true, + _ => result.children.push(Box::new(parse_parameter(chars, cur))) + } + */ + if !stop { + match lex_4_25::peek_token(chars, cur) { + lex_4_25::Token::Comma => (), + _ => stop = true + } + } + } match lex_4_25::next_token(chars, cur) { lex_4_25::Token::CloseParenthesis => (), _ => panic!("Invalid parameter list") @@ -482,7 +497,20 @@ fn parse_parameter_list(chars: &Vec, cur: &mut usize) -> ParseNode { result } -fn parse_parameter(chars: &Vec, cur: &mut usize) -> ParseNode { ParseNode::empty() } +fn parse_parameter(chars: &Vec, cur: &mut usize) -> ParseNode { + let mut result = lex_4_25::Token::Parameter.to_leaf(); + result.children.push(Box::new(parse_type_name(chars, cur))); + match lex_4_25::peek_token(chars, cur) { + lex_4_25::Token::Memory | + lex_4_25::Token::Storage => result.add_child(lex_4_25::next_token(chars, cur)), + _ => () + } + match lex_4_25::peek_token(chars, cur) { + lex_4_25::Token::Identifier(..) => result.add_child(lex_4_25::next_token(chars, cur)), + _ => () + } + result +} fn parse_block(chars: &Vec, cur: &mut usize) -> ParseNode { let mut result = lex_4_25::Token::OpenBrace.to_leaf(); diff --git a/src/codegen.rs b/src/style.rs similarity index 66% rename from src/codegen.rs rename to src/style.rs index 25d47d1..87b2bc1 100644 --- a/src/codegen.rs +++ b/src/style.rs @@ -3,15 +3,15 @@ use super::parse_4_25; /*** Top Level ***/ -pub fn generate(tree: parse_4_25::ParseTree) -> String { +pub fn stylize(tree: parse_4_25::ParseTree) -> String { let mut result = String::new(); for child in tree.children { match child.node { - lex_4_25::Token::Pragma => result.push_str(&generate_pragma(child)), - lex_4_25::Token::Import => result.push_str(&generate_import(child)), + lex_4_25::Token::Pragma => result.push_str(&stylize_pragma(child)), + lex_4_25::Token::Import => result.push_str(&stylize_import(child)), lex_4_25::Token::Library | lex_4_25::Token::Contract | - lex_4_25::Token::Interface => result.push_str(&generate_contract(child)), + lex_4_25::Token::Interface => result.push_str(&stylize_contract(child)), _ => panic!("Invalid top level tree") } } @@ -20,10 +20,11 @@ pub fn generate(tree: parse_4_25::ParseTree) -> String { /*** Pragma ***/ -fn generate_pragma(pragma: parse_4_25::ParseNode) -> String { +fn stylize_pragma(pragma: parse_4_25::ParseNode) -> String { let mut result = String::new(); if let lex_4_25::Token::Pragma = pragma.node { - result.push_str("pragma "); + result.push_str("pragma"); + result.push(' '); } if pragma.children.len() >= 2 { if let lex_4_25::Token::Identifier(name) = &pragma.children[0].node { @@ -50,11 +51,11 @@ fn generate_pragma(pragma: parse_4_25::ParseNode) -> String { /*** Import ***/ -fn generate_import(import: parse_4_25::ParseNode) -> String { String::new() } +fn stylize_import(import: parse_4_25::ParseNode) -> String { String::new() } /*** Contract ***/ -fn generate_contract(contract: parse_4_25::ParseNode) -> String { +fn stylize_contract(contract: parse_4_25::ParseNode) -> String { let mut result = String::new(); match contract.node { lex_4_25::Token::Contract => result.push_str("\n\ncontract "), @@ -72,7 +73,7 @@ fn generate_contract(contract: parse_4_25::ParseNode) -> String { } match &contract.children[1].node { lex_4_25::Token::OpenBrace => { - result.push_str(&generate_contract_part(&contract.children[1])); + result.push_str(&stylize_contract_part(&contract.children[1])); } _ => panic!("Invalid contract definition") } @@ -86,13 +87,13 @@ fn generate_contract(contract: parse_4_25::ParseNode) -> String { } match &contract.children[1].node { lex_4_25::Token::Is => { - result.push_str(&generate_inheritance_specifier(&contract.children[1])); + result.push_str(&stylize_inheritance_specifier(&contract.children[1])); } _ => panic!("Invalid contract definition") } match &contract.children[2].node { lex_4_25::Token::OpenBrace => { - result.push_str(&generate_contract_part(&contract.children[2])); + result.push_str(&stylize_contract_part(&contract.children[2])); } _ => panic!("Invalid contract definition") } @@ -102,7 +103,7 @@ fn generate_contract(contract: parse_4_25::ParseNode) -> String { /*** Inheritance Specifier ***/ -fn generate_inheritance_specifier(block: &parse_4_25::ParseNode) -> String { +fn stylize_inheritance_specifier(block: &parse_4_25::ParseNode) -> String { let mut result = String::new(); match block.node { lex_4_25::Token::Is => result.push_str("is\n"), @@ -115,7 +116,7 @@ fn generate_inheritance_specifier(block: &parse_4_25::ParseNode) -> String { for i in 0..=block.children[0].children.len() - 1 { // FIXME Replace with result.indent() result.push_str(" "); - result.push_str(&generate_user_defined_type_name(&block.children[0].children[i])); + result.push_str(&stylize_user_defined_type_name(&block.children[0].children[i])); if i != block.children[0].children.len() - 1 { result.push_str(",\n"); } else { @@ -127,7 +128,7 @@ fn generate_inheritance_specifier(block: &parse_4_25::ParseNode) -> String { /*** Contract Part ***/ -fn generate_contract_part(block: &parse_4_25::ParseNode) -> String { +fn stylize_contract_part(block: &parse_4_25::ParseNode) -> String { let mut result = String::new(); match block.node { lex_4_25::Token::OpenBrace => result.push('{'), @@ -135,12 +136,12 @@ fn generate_contract_part(block: &parse_4_25::ParseNode) -> String { } for child in &block.children { match child.node { - lex_4_25::Token::Enum => result.push_str(&generate_enum(&child)), - lex_4_25::Token::Event => result.push_str(&generate_event(&child)), - lex_4_25::Token::Function => result.push_str(&generate_function(&child)), - lex_4_25::Token::Modifier => result.push_str(&generate_modifier(&child)), - lex_4_25::Token::Using => result.push_str(&generate_using_for(&child)), - lex_4_25::Token::Struct => result.push_str(&generate_struct(&child)), + lex_4_25::Token::Enum => result.push_str(&stylize_enum(&child)), + lex_4_25::Token::Event => result.push_str(&stylize_event(&child)), + lex_4_25::Token::Function => result.push_str(&stylize_function(&child)), + lex_4_25::Token::Modifier => result.push_str(&stylize_modifier(&child)), + lex_4_25::Token::Using => result.push_str(&stylize_using_for(&child)), + lex_4_25::Token::Struct => result.push_str(&stylize_struct(&child)), _ => panic!("Invalid contract part") } } @@ -150,7 +151,7 @@ fn generate_contract_part(block: &parse_4_25::ParseNode) -> String { /*** Sub-contract Structures ***/ -fn generate_enum(node: &parse_4_25::ParseNode) -> String { +fn stylize_enum(node: &parse_4_25::ParseNode) -> String { let mut result = String::new(); match node.node { lex_4_25::Token::Enum => result.push_str("enum"), @@ -187,7 +188,7 @@ fn generate_enum(node: &parse_4_25::ParseNode) -> String { result } -fn generate_event(node: &parse_4_25::ParseNode) -> String { +fn stylize_event(node: &parse_4_25::ParseNode) -> String { let mut result = String::new(); match node.node { lex_4_25::Token::Event => result.push_str("event"), @@ -206,7 +207,7 @@ fn generate_event(node: &parse_4_25::ParseNode) -> String { for i in 0..=node.children[1].children.len() - 1 { result.push('\n'); result.push_str(" "); - result.push_str(&generate_event_parameter(&node.children[1].children[i])); + result.push_str(&stylize_event_parameter(&node.children[1].children[i])); if i != node.children[1].children.len() - 1 { result.push(','); } else { @@ -219,14 +220,14 @@ fn generate_event(node: &parse_4_25::ParseNode) -> String { result } -fn generate_event_parameter(node: &parse_4_25::ParseNode) -> String { +fn stylize_event_parameter(node: &parse_4_25::ParseNode) -> String { let mut result = String::new(); match node.node { lex_4_25::Token::EventParameter => (), _ => panic!("Invalid event parameter") } // Format the type name of the event parameter and append it to the result - result.push_str(&generate_type_name(&node.children[0])); + result.push_str(&stylize_type_name(&node.children[0])); if node.children.len() == 2 { match &node.children[1].node { lex_4_25::Token::Indexed => result.push_str(" indexed"), @@ -247,22 +248,149 @@ fn generate_event_parameter(node: &parse_4_25::ParseNode) -> String { result } -fn generate_function(node: &parse_4_25::ParseNode) -> String { +fn stylize_function(node: &parse_4_25::ParseNode) -> String { + let mut result = String::new(); + match node.node { + lex_4_25::Token::Function => result.push_str("function"), + _ => panic!("Invalid function definition") + } + match &node.children[0].node { + lex_4_25::Token::Identifier(name) => result.push_str(&name), + _ => panic!("Invalid function definition") + } + match &node.children[1].node { + lex_4_25::Token::OpenParenthesis => result.push('('), + _ => panic!("Invalid function definition") + } + if node.children[1].children.len() > 0 { + for i in 0..=node.children[1].children.len() - 1 { + result.push_str(" \n"); + result.push_str(&stylize_parameter(&node.children[1].children[i])); + if i == node.children[1].children.len() - 1 { + result.push('\n'); + } else { + result.push_str(",\n"); + } + } + } + result.push_str(" )\n"); + if node.children.len() >= 3 { + for i in 2..=node.children.len() - 1 { + result.push_str(" \n"); + match &node.children[i].node { + lex_4_25::Token::External => { + result.push_str(" \n"); + result.push_str("external"); + } + lex_4_25::Token::Internal => { + result.push_str(" \n"); + result.push_str("internal"); + } + lex_4_25::Token::Pure => { + result.push_str(" \n"); + result.push_str("pure"); + } + lex_4_25::Token::Constant => { + result.push_str(" \n"); + result.push_str("constant"); + } + lex_4_25::Token::View => { + result.push_str(" \n"); + result.push_str("view"); + } + lex_4_25::Token::Payable => { + result.push_str(" \n"); + result.push_str("payable"); + } + lex_4_25::Token::Identifier(..) => { + result.push_str(" \n"); + result.push_str(&stylize_method_invocation(&node.children[i])); + } + lex_4_25::Token::Returns => break, + lex_4_25::Token::OpenBrace => break, + _ => panic!("Invalid function definition") + } + } + } else { + panic!("Invalid function definition"); + } + let last = node.children.len() - 1; + match &node.children[last - 1].node { + lex_4_25::Token::Returns => { + result.push_str("returns"); + match &node.children[last - 1].children[0].node { + lex_4_25::Token::OpenParenthesis => { + result.push('('); + for i in 0..=node.children[last - 1].children[0].children.len() - 1 { + if i != 0 { + result.push(' '); + } + result.push_str(&stylize_parameter(&node.children[last - 1].children[0].children[i])); + if i != node.children[last - 1].children[0].children.len() - 1 { + result.push_str(","); + } + } + result.push(')'); + } + _ => panic!("Invalid function definition") + } + } + _ => () + } + match &node.children[last].node { + lex_4_25::Token::OpenBrace => result.push_str(&stylize_block(&node.children[last])), + lex_4_25::Token::Semicolon => result.push(';'), + _ => panic!("Invalid function definition") + } + result.push('\n'); + result +} + +fn stylize_block(node: &parse_4_25::ParseNode) -> String { String::new() } + +fn stylize_method_invocation(node: &parse_4_25::ParseNode) -> String { String::new() } + +fn stylize_parameter(node: &parse_4_25::ParseNode) -> String { let mut result = String::new(); + match node.node { + lex_4_25::Token::Parameter => (), + _ => panic!("Invalid parameter") + } + result.push_str(&stylize_type_name(&node.children[0])); + result.push(' '); + if node.children.len() == 2 { + match &node.children[1].node { + lex_4_25::Token::Identifier(name) => result.push_str(&name), + lex_4_25::Token::Memory => result.push_str("memory"), + lex_4_25::Token::Storage => result.push_str("storage"), + _ => panic!("Invalid parameter") + } + } else if node.children.len() == 3 { + match &node.children[1].node { + lex_4_25::Token::Memory => result.push_str("memory"), + lex_4_25::Token::Storage => result.push_str("storage"), + _ => panic!("Invalid parameter") + } + result.push(' '); + match &node.children[2].node { + lex_4_25::Token::Identifier(name) => result.push_str(&name), + _ => panic!("Invalid parameter") + } + } result } -fn generate_modifier(node: &parse_4_25::ParseNode) -> String { +fn stylize_modifier(node: &parse_4_25::ParseNode) -> String { let mut result = String::new(); result } -fn generate_using_for(node: &parse_4_25::ParseNode) -> String { +fn stylize_using_for(node: &parse_4_25::ParseNode) -> String { let mut result = String::new(); result } -fn generate_struct(node: &parse_4_25::ParseNode) -> String { +fn stylize_struct(node: &parse_4_25::ParseNode) -> String { let mut result = String::new(); match node.node { lex_4_25::Token::Struct => result.push_str("struct"), @@ -281,7 +409,7 @@ fn generate_struct(node: &parse_4_25::ParseNode) -> String { for i in 0..=node.children[1].children.len() - 1 { result.push('\n'); result.push_str(" "); - result.push_str(&generate_variable_declaration(&node.children[1].children[i])); + result.push_str(&stylize_variable_declaration(&node.children[1].children[i])); result.push(';'); if i == node.children[1].children.len() - 1 { result.push('\n'); @@ -291,13 +419,13 @@ fn generate_struct(node: &parse_4_25::ParseNode) -> String { result } -fn generate_variable_declaration(node: &parse_4_25::ParseNode) -> String { +fn stylize_variable_declaration(node: &parse_4_25::ParseNode) -> String { let mut result = String::new(); match node.node { lex_4_25::Token::VariableDeclaration => (), _ => panic!("Invalid variable declaration") } - result.push_str(&generate_type_name(&node.children[0])); + result.push_str(&stylize_type_name(&node.children[0])); result.push(' '); if node.children.len() == 2 { match &node.children[1].node { @@ -323,15 +451,15 @@ fn generate_variable_declaration(node: &parse_4_25::ParseNode) -> String { /*** Types ***/ -fn generate_type_name(type_name: &parse_4_25::ParseNode) -> String { +fn stylize_type_name(type_name: &parse_4_25::ParseNode) -> String { return match type_name.node { - lex_4_25::Token::Identifier(..) => generate_user_defined_type_name(type_name), - lex_4_25::Token::Function => generate_function_type(type_name), - lex_4_25::Token::Mapping => generate_mapping(type_name), - lex_4_25::Token::OpenBracket => generate_array_type_name(type_name), + lex_4_25::Token::Identifier(..) => stylize_user_defined_type_name(type_name), + lex_4_25::Token::Function => stylize_function_type(type_name), + lex_4_25::Token::Mapping => stylize_mapping(type_name), + lex_4_25::Token::OpenBracket => stylize_array_type_name(type_name), ref elementary => { if elementary.is_elementary_type() { - return generate_elementary_type(type_name); + return stylize_elementary_type(type_name); } else { panic!("Invalid type name"); } @@ -340,7 +468,7 @@ fn generate_type_name(type_name: &parse_4_25::ParseNode) -> String { } } -fn generate_user_defined_type_name(type_name: &parse_4_25::ParseNode) -> String { +fn stylize_user_defined_type_name(type_name: &parse_4_25::ParseNode) -> String { let mut result = String::new(); match type_name.node { lex_4_25::Token::UserDefinedTypeName => (), @@ -358,22 +486,22 @@ fn generate_user_defined_type_name(type_name: &parse_4_25::ParseNode) -> String result } -fn generate_array_type_name(function_type: &parse_4_25::ParseNode) -> String { +fn stylize_array_type_name(function_type: &parse_4_25::ParseNode) -> String { let mut result = String::new(); result } -fn generate_function_type(function_type: &parse_4_25::ParseNode) -> String { +fn stylize_function_type(function_type: &parse_4_25::ParseNode) -> String { let mut result = String::new(); result } -fn generate_mapping(function_type: &parse_4_25::ParseNode) -> String { +fn stylize_mapping(function_type: &parse_4_25::ParseNode) -> String { let mut result = String::new(); result } -fn generate_elementary_type(elementary_type: &parse_4_25::ParseNode) -> String { +fn stylize_elementary_type(elementary_type: &parse_4_25::ParseNode) -> String { return match elementary_type.node { lex_4_25::Token::Address => "address", lex_4_25::Token::Bool => "bool", @@ -490,7 +618,7 @@ mod tests { use super::*; #[test] - fn generate_pragma_test1() { + fn stylize_pragma_test1() { let tree = parse_4_25::ParseTree { children: vec![ parse_4_25::ParseNode { @@ -502,13 +630,13 @@ mod tests { } ] }; - let actual_generated = generate(tree); - let expected_generated = "pragma solidity 0.4.25;"; - assert_eq!(expected_generated, actual_generated); + let actual_stylized = stylize(tree); + let expected_stylized = "pragma solidity 0.4.25;"; + assert_eq!(expected_stylized, actual_stylized); } #[test] - fn generate_inheritance_specifier_test1() { + fn stylize_inheritance_specifier_test1() { let node = parse_4_25::ParseNode { node: lex_4_25::Token::Is, children: vec![ @@ -525,13 +653,13 @@ mod tests { }) ] }; - let actual_generated = generate_inheritance_specifier(&node); - let expected_generated = "is\n A\n"; - assert_eq!(actual_generated, expected_generated); + let actual_stylized = stylize_inheritance_specifier(&node); + let expected_stylized = "is\n A\n"; + assert_eq!(actual_stylized, expected_stylized); } #[test] - fn generate_inheritance_specifier_test2() { + fn stylize_inheritance_specifier_test2() { let node = parse_4_25::ParseNode { node: lex_4_25::Token::Is, children: vec![ @@ -555,13 +683,13 @@ mod tests { }) ] }; - let actual_generated = generate_inheritance_specifier(&node); - let expected_generated = "is\n A,\n Bat.Car\n"; - assert_eq!(actual_generated, expected_generated); + let actual_stylized = stylize_inheritance_specifier(&node); + let expected_stylized = "is\n A,\n Bat.Car\n"; + assert_eq!(actual_stylized, expected_stylized); } #[test] - fn generate_inheritance_specifier_test3() { + fn stylize_inheritance_specifier_test3() { let node = parse_4_25::ParseNode { node: lex_4_25::Token::Is, children: vec![ @@ -593,13 +721,13 @@ mod tests { }) ] }; - let actual_generated = generate_inheritance_specifier(&node); - let expected_generated = "is\n A,\n Bat.Car,\n foo.bar.baz\n"; - assert_eq!(actual_generated, expected_generated); + let actual_stylized = stylize_inheritance_specifier(&node); + let expected_stylized = "is\n A,\n Bat.Car,\n foo.bar.baz\n"; + assert_eq!(actual_stylized, expected_stylized); } #[test] - fn generate_enum_test1() { + fn stylize_enum_test1() { let node = parse_4_25::ParseNode { node: lex_4_25::Token::Enum, children: vec![ @@ -607,13 +735,13 @@ mod tests { Box::new(lex_4_25::Token::OpenBrace.to_leaf()) ] }; - let actual_generated = generate_enum(&node); - let expected_generated = String::from("enum empty {}"); - assert_eq!(expected_generated, actual_generated); + let actual_stylized = stylize_enum(&node); + let expected_stylized = String::from("enum empty {}"); + assert_eq!(expected_stylized, actual_stylized); } #[test] - fn generate_enum_test2() { + fn stylize_enum_test2() { let node = parse_4_25::ParseNode { node: lex_4_25::Token::Enum, children: vec![ @@ -628,13 +756,13 @@ mod tests { }) ] }; - let actual_generated = generate_enum(&node); - let expected_generated = String::from("enum Letters {\n A,\n B,\n C\n}"); - assert_eq!(expected_generated, actual_generated); + let actual_stylized = stylize_enum(&node); + let expected_stylized = String::from("enum Letters {\n A,\n B,\n C\n}"); + assert_eq!(expected_stylized, actual_stylized); } #[test] - fn generate_event_test1() { + fn stylize_event_test1() { let node = parse_4_25::ParseNode { node: lex_4_25::Token::Event, children: vec![ @@ -642,12 +770,12 @@ mod tests { Box::new(lex_4_25::Token::OpenParenthesis.to_leaf()) ] }; - let actual_generated = generate_event(&node); - let expected_generated = "event empty();"; + let actual_stylized = stylize_event(&node); + let expected_stylized = "event empty();"; } #[test] - fn generate_event_test2() { + fn stylize_event_test2() { let node = parse_4_25::ParseNode { node: lex_4_25::Token::Event, children: vec![ @@ -683,13 +811,13 @@ mod tests { }) ] }; - let actual_generated = generate_event(&node); - let expected_generated = "event Transfer(\n address indexed owner,\n address indexed recipient,\n uint256 indexed value\n);"; - assert_eq!(expected_generated, actual_generated); + let actual_stylized = stylize_event(&node); + let expected_stylized = "event Transfer(\n address indexed owner,\n address indexed recipient,\n uint256 indexed value\n);"; + assert_eq!(expected_stylized, actual_stylized); } #[test] - fn generate_struct_test1() { + fn stylize_struct_test1() { let node = parse_4_25::ParseNode { node: lex_4_25::Token::Struct, children: vec![ @@ -708,26 +836,26 @@ mod tests { }) ] }; - let actual_generated = generate_struct(&node); - let expected_generated = "struct Value {\n uint256 value;\n}"; - assert_eq!(expected_generated, actual_generated); + let actual_stylized = stylize_struct(&node); + let expected_stylized = "struct Value {\n uint256 value;\n}"; + assert_eq!(expected_stylized, actual_stylized); } #[test] - fn generate_user_defined_type_name_test1() { + fn stylize_user_defined_type_name_test1() { let node = parse_4_25::ParseNode { node: lex_4_25::Token::UserDefinedTypeName, children: vec![ Box::new(lex_4_25::Token::Identifier("A".to_string()).to_leaf()) ] }; - let actual_generated = generate_user_defined_type_name(&node); - let expected_generated = String::from("A"); - assert_eq!(expected_generated, actual_generated); + let actual_stylized = stylize_user_defined_type_name(&node); + let expected_stylized = String::from("A"); + assert_eq!(expected_stylized, actual_stylized); } #[test] - fn generate_user_defined_type_name_test2() { + fn stylize_user_defined_type_name_test2() { let node = parse_4_25::ParseNode { node: lex_4_25::Token::UserDefinedTypeName, children: vec![ @@ -735,48 +863,48 @@ mod tests { Box::new(lex_4_25::Token::Identifier("b".to_string()).to_leaf()) ] }; - let actual_generated = generate_user_defined_type_name(&node); - let expected_generated = String::from("A.b"); - assert_eq!(expected_generated, actual_generated); + let actual_stylized = stylize_user_defined_type_name(&node); + let expected_stylized = String::from("A.b"); + assert_eq!(expected_stylized, actual_stylized); } #[test] - fn generate_elementary_type_test1() { + fn stylize_elementary_type_test1() { let node = lex_4_25::Token::Address.to_leaf(); - let actual_generated = generate_elementary_type(&node); - let expected_generated = "address"; - assert_eq!(expected_generated, actual_generated); + let actual_stylized = stylize_elementary_type(&node); + let expected_stylized = "address"; + assert_eq!(expected_stylized, actual_stylized); } #[test] - fn generate_elementary_type_test2() { + fn stylize_elementary_type_test2() { let node = lex_4_25::Token::Bool.to_leaf(); - let actual_generated = generate_elementary_type(&node); - let expected_generated = "bool"; - assert_eq!(expected_generated, actual_generated); + let actual_stylized = stylize_elementary_type(&node); + let expected_stylized = "bool"; + assert_eq!(expected_stylized, actual_stylized); } #[test] - fn generate_elementary_type_test3() { + fn stylize_elementary_type_test3() { let node = lex_4_25::Token::Byte.to_leaf(); - let actual_generated = generate_elementary_type(&node); - let expected_generated = "byte"; - assert_eq!(expected_generated, actual_generated); + let actual_stylized = stylize_elementary_type(&node); + let expected_stylized = "byte"; + assert_eq!(expected_stylized, actual_stylized); } #[test] - fn generate_elementary_type_test4() { + fn stylize_elementary_type_test4() { let node = lex_4_25::Token::Bytes.to_leaf(); - let actual_generated = generate_elementary_type(&node); - let expected_generated = "bytes"; - assert_eq!(expected_generated, actual_generated); + let actual_stylized = stylize_elementary_type(&node); + let expected_stylized = "bytes"; + assert_eq!(expected_stylized, actual_stylized); } #[test] - fn generate_elementary_type_test5() { + fn stylize_elementary_type_test5() { let node = lex_4_25::Token::Bytes1.to_leaf(); - let actual_generated = generate_elementary_type(&node); - let expected_generated = "bytes1"; - assert_eq!(expected_generated, actual_generated); + let actual_stylized = stylize_elementary_type(&node); + let expected_stylized = "bytes1"; + assert_eq!(expected_stylized, actual_stylized); } } From 38c8a61c7e882ba1fd43ddb9f41563eeed036f2c Mon Sep 17 00:00:00 2001 From: James Towle Date: Fri, 14 Jun 2019 09:40:00 -0700 Subject: [PATCH 7/9] Modularized the style module --- contracts/BadDemo.sol | 45 ++++ contracts/BadOwnable.sol | 84 ++++++++ contracts/BadValue.sol | 9 + contracts/Demo.sol | 16 ++ contracts/Empty.sol | 4 +- contracts/Ownable.sol | 2 + contracts/Value.sol | 7 + contracts/library.sol | 3 + src/main.rs | 26 ++- src/style.rs | 341 +++++++++++++++++++++++++++---- tests/style_integration_tests.rs | 39 ++++ 11 files changed, 527 insertions(+), 49 deletions(-) create mode 100644 contracts/BadDemo.sol create mode 100644 contracts/BadOwnable.sol create mode 100644 contracts/BadValue.sol create mode 100644 contracts/Demo.sol create mode 100644 contracts/Value.sol create mode 100644 contracts/library.sol create mode 100644 tests/style_integration_tests.rs diff --git a/contracts/BadDemo.sol b/contracts/BadDemo.sol new file mode 100644 index 0000000..06e1da9 --- /dev/null +++ b/contracts/BadDemo.sol @@ -0,0 +1,45 @@ +pragma solidity ^0.4.25; + +contract + + + +Demo + + + is + + + + A, + B, + + + C, + + + D + + + + + + + { + event Transfer( + address + indexed + owner, + address indexed recipient, + uint256 indexed value); + address public + constant a = 103414; + + + address + public constant b = 0x103414; + + modifier empty { + + } + } diff --git a/contracts/BadOwnable.sol b/contracts/BadOwnable.sol new file mode 100644 index 0000000..a1038f9 --- /dev/null +++ b/contracts/BadOwnable.sol @@ -0,0 +1,84 @@ + pragma solidity + + + + ^0.4.25 + + + + ; + + +contract Ownable + + + + + +{ + + address + + public owner; + + modifier + + + onlyOwner { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + require( + + msg.sender + + + + == owner + + ) ; + _; + + } } diff --git a/contracts/BadValue.sol b/contracts/BadValue.sol new file mode 100644 index 0000000..37f5620 --- /dev/null +++ b/contracts/BadValue.sol @@ -0,0 +1,9 @@ +pragma + + + solidity + + + ^0.4.25; + +contract Value { uint256 b = 351231; } diff --git a/contracts/Demo.sol b/contracts/Demo.sol new file mode 100644 index 0000000..c49b229 --- /dev/null +++ b/contracts/Demo.sol @@ -0,0 +1,16 @@ +pragma solidity ^0.4.25; + + +contract Demo is + A, + B, + C, + D +{ + + event Transfer(address indexed owner, address indexed recipient, uint256 indexed value); + + address public constant a = 103414; + + address public constant b = 0x103414; +} diff --git a/contracts/Empty.sol b/contracts/Empty.sol index 9097001..8f66833 100644 --- a/contracts/Empty.sol +++ b/contracts/Empty.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.4.25; +pragma solidity ^0.4.25; -contract Empty {} +contract Empty {} \ No newline at end of file diff --git a/contracts/Ownable.sol b/contracts/Ownable.sol index 6aec8d7..51e01f9 100644 --- a/contracts/Ownable.sol +++ b/contracts/Ownable.sol @@ -1,6 +1,8 @@ pragma solidity ^0.4.25; + contract Ownable { + address public owner; modifier onlyOwner { diff --git a/contracts/Value.sol b/contracts/Value.sol new file mode 100644 index 0000000..81050e6 --- /dev/null +++ b/contracts/Value.sol @@ -0,0 +1,7 @@ +pragma solidity ^0.4.25; + + +contract Value { + + uint256 b = 351231; +} \ No newline at end of file diff --git a/contracts/library.sol b/contracts/library.sol new file mode 100644 index 0000000..df2326c --- /dev/null +++ b/contracts/library.sol @@ -0,0 +1,3 @@ +pragma solidity ^0.4.25; + +library A {} diff --git a/src/main.rs b/src/main.rs index b28cfd5..6d732ec 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,11 +4,23 @@ use solfix::parse_4_25::parse; use solfix::style::stylize; fn main() { - let usage = "Usage: solidity-fix SOURCE TARGET"; - let source = env::args().nth(1).expect(usage); -// let target = env::args().nth(2).expect(usage); - let input = fs::read_to_string(source).expect("Unable to open input file"); - println!("{}", stylize(parse(input))); -// let result = generate(parse(input)); -// fs::write(target, result).expect("Unable to write file"); + let usage = "Usage: solfix style SOURCE [TARGET]\n ast SOURCE [TARGET]"; + match env::args().nth(1) { + Some(ref style) if style == "style" => { + let source = env::args().nth(2).expect(usage); + let input = fs::read_to_string(source).expect("Unable to find SOURCE"); + match env::args().nth(3) { + Some(target) => fs::write(target, stylize(parse(input))).expect("Unable to write file to TARGET"), + None => println!("{}", stylize(parse(input))) + } + } + Some(ref ast) if ast == "ast" => { + let source = env::args().nth(2).expect(usage); + let input = fs::read_to_string(source).expect("Unable to find SOURCE"); + match env::args().nth(3) { + _ => println!("{:?}", parse(input)) + } + } + _ => println!("{}", usage) + } } diff --git a/src/style.rs b/src/style.rs index 87b2bc1..102847f 100644 --- a/src/style.rs +++ b/src/style.rs @@ -1,6 +1,55 @@ use super::lex_4_25; use super::parse_4_25; +enum Style { + /*** Contract ***/ + BeforeContract, + Contract, + Interface, + Library, + AfterContract, + BeforeContractIdentifier, + AfterContractIdentifier, + /*** Pragma Keyword ***/ + BeforePragma, + Pragma, + AfterPragma, + /*** Pragma Identifier ***/ + BeforePragmaIdentifier, + AfterPragmaIdentifier, + /*** Pragma Version ***/ + BeforeVersion, + AfterVersion +} + +trait StyleResolver { + fn resolve(&mut self, style: Style); +} + +impl StyleResolver for String { + fn resolve(&mut self, style: Style) { + match style { + Style::BeforeContractIdentifier => (), + Style::AfterContractIdentifier => self.push_str(" "), + Style::BeforeContract => self.push_str("\n\n\n"), + Style::Contract => self.push_str("contract"), + Style::Interface => self.push_str("interface"), + Style::Library => self.push_str("library"), + Style::AfterContract => self.push_str(" "), + Style::BeforePragma => (), + Style::Pragma => self.push_str("pragma"), + Style::BeforePragma => (), + Style::AfterPragma => self.push_str(" "), + Style::BeforePragmaIdentifier => (), + Style::AfterPragmaIdentifier => self.push_str(" "), + Style::AfterPragma => self.push_str(" "), + Style::BeforeVersion => (), + Style::AfterVersion => self.push_str(";"), + _ => (), + } + } +} + /*** Top Level ***/ pub fn stylize(tree: parse_4_25::ParseTree) -> String { @@ -23,27 +72,31 @@ pub fn stylize(tree: parse_4_25::ParseTree) -> String { fn stylize_pragma(pragma: parse_4_25::ParseNode) -> String { let mut result = String::new(); if let lex_4_25::Token::Pragma = pragma.node { - result.push_str("pragma"); - result.push(' '); + result.resolve(Style::BeforePragma); + result.resolve(Style::Pragma); + result.resolve(Style::AfterPragma); } if pragma.children.len() >= 2 { if let lex_4_25::Token::Identifier(name) = &pragma.children[0].node { + result.resolve(Style::BeforePragmaIdentifier); result.push_str(&name); - result.push(' '); + result.resolve(Style::AfterPragmaIdentifier); } if pragma.children.len() == 2 { if let lex_4_25::Token::Version(version) = &pragma.children[1].node { + result.resolve(Style::BeforeVersion); result.push_str(&version); - result.push_str(";"); + result.resolve(Style::AfterVersion); } } else if pragma.children.len() == 3 { + result.resolve(Style::BeforeVersion); if let lex_4_25::Token::BitwiseXor = &pragma.children[1].node { result.push('^'); } if let lex_4_25::Token::Version(version) = &pragma.children[2].node { result.push_str(&version); - result.push_str(";"); } + result.resolve(Style::AfterVersion); } } result @@ -57,17 +110,20 @@ fn stylize_import(import: parse_4_25::ParseNode) -> String { String::new() } fn stylize_contract(contract: parse_4_25::ParseNode) -> String { let mut result = String::new(); + result.resolve(Style::BeforeContract); match contract.node { - lex_4_25::Token::Contract => result.push_str("\n\ncontract "), - lex_4_25::Token::Library => result.push_str("\n\nlibrary "), - lex_4_25::Token::Interface => result.push_str("\n\ninterface "), + lex_4_25::Token::Contract => result.resolve(Style::Contract), + lex_4_25::Token::Interface => result.resolve(Style::Interface), + lex_4_25::Token::Library => result.resolve(Style::Library), _ => panic!("Invalid contract definition") } + result.resolve(Style::AfterContract); if contract.children.len() == 2 { match &contract.children[0].node { lex_4_25::Token::Identifier(name) => { + result.resolve(Style::BeforeContractIdentifier); result.push_str(&name); - result.push(' '); + result.resolve(Style::AfterContractIdentifier); } _ => panic!("Invalid contract definition") } @@ -81,7 +137,7 @@ fn stylize_contract(contract: parse_4_25::ParseNode) -> String { match &contract.children[0].node { lex_4_25::Token::Identifier(name) => { result.push_str(&name); - result.push(' '); + result.push_str(" "); } _ => panic!("Invalid contract definition") } @@ -113,11 +169,11 @@ fn stylize_inheritance_specifier(block: &parse_4_25::ParseNode) -> String { lex_4_25::Token::OpenParenthesis => (), _ => panic!("Invalid inheritance specifier") } - for i in 0..=block.children[0].children.len() - 1 { + for i in 0..=block.children.len() - 1 { // FIXME Replace with result.indent() result.push_str(" "); - result.push_str(&stylize_user_defined_type_name(&block.children[0].children[i])); - if i != block.children[0].children.len() - 1 { + result.push_str(&stylize_user_defined_type_name(&block.children[i].children[0])); + if i != block.children.len() - 1 { result.push_str(",\n"); } else { result.push('\n'); @@ -131,27 +187,80 @@ fn stylize_inheritance_specifier(block: &parse_4_25::ParseNode) -> String { fn stylize_contract_part(block: &parse_4_25::ParseNode) -> String { let mut result = String::new(); match block.node { - lex_4_25::Token::OpenBrace => result.push('{'), + lex_4_25::Token::OpenBrace => result.push_str("{"), _ => panic!("Invalid contract part") } + if block.children.len() > 0 { + result.push_str("\n"); + } else { + result.push_str("}"); + return result + } for child in &block.children { match child.node { - lex_4_25::Token::Enum => result.push_str(&stylize_enum(&child)), - lex_4_25::Token::Event => result.push_str(&stylize_event(&child)), - lex_4_25::Token::Function => result.push_str(&stylize_function(&child)), - lex_4_25::Token::Modifier => result.push_str(&stylize_modifier(&child)), - lex_4_25::Token::Using => result.push_str(&stylize_using_for(&child)), - lex_4_25::Token::Struct => result.push_str(&stylize_struct(&child)), + lex_4_25::Token::Enum => result.push_str(&stylize_enum_definition(&child)), + lex_4_25::Token::Event => result.push_str(&stylize_event_declaration(&child)), + lex_4_25::Token::Function => result.push_str(&stylize_function_definition(&child)), + lex_4_25::Token::Modifier => result.push_str(&stylize_modifier_definition(&child)), + lex_4_25::Token::Using => result.push_str(&stylize_using_for_declaration(&child)), + lex_4_25::Token::Struct => result.push_str(&stylize_struct_definition(&child)), + lex_4_25::Token::StateVariable => result.push_str(&stylize_state_variable_declaration(&child)), _ => panic!("Invalid contract part") } } - result.push('}'); + result.push_str("}"); result } /*** Sub-contract Structures ***/ -fn stylize_enum(node: &parse_4_25::ParseNode) -> String { +fn stylize_state_variable_declaration(node: &parse_4_25::ParseNode) -> String { + let mut result = String::new(); + if node.children.len() < 2 { + panic!("Invalid state variable"); + } + result.push_str("\n "); + result.push_str(&stylize_elementary_type(&node.children[0])); + result.push(' '); + let mut i = 1; + let mut stop = false; + while !stop && i < node.children.len() { + match &node.children[i].node { + lex_4_25::Token::Constant => result.push_str("constant"), + lex_4_25::Token::Internal => result.push_str("internal"), + lex_4_25::Token::Private => result.push_str("private"), + lex_4_25::Token::Public => result.push_str("public"), + _ => stop = true + } + if !stop { + result.push(' '); + i += 1; + } + } + match &node.children[i].node { + lex_4_25::Token::Identifier(name) => result.push_str(&name), + _ => panic!("1Invalid state variable") + } + i += 1; + if i == node.children.len() { + result.push_str(";\n"); + return result; + } else { + result.push(' '); + match node.children[i].node { + lex_4_25::Token::Assignment => { + result.push_str("="); + result.push_str(" "); + result.push_str(&stylize_expression(&node.children[i].children[0])); + result.push_str(";\n"); + } + _ => panic!("Invalid state variable") + } + } + result +} + +fn stylize_enum_definition(node: &parse_4_25::ParseNode) -> String { let mut result = String::new(); match node.node { lex_4_25::Token::Enum => result.push_str("enum"), @@ -188,8 +297,9 @@ fn stylize_enum(node: &parse_4_25::ParseNode) -> String { result } -fn stylize_event(node: &parse_4_25::ParseNode) -> String { +fn stylize_event_declaration(node: &parse_4_25::ParseNode) -> String { let mut result = String::new(); + result.push_str(" "); match node.node { lex_4_25::Token::Event => result.push_str("event"), _ => panic!("Invalid event definition") @@ -206,7 +316,7 @@ fn stylize_event(node: &parse_4_25::ParseNode) -> String { if node.children[1].children.len() > 0 { for i in 0..=node.children[1].children.len() - 1 { result.push('\n'); - result.push_str(" "); + result.push_str(" "); result.push_str(&stylize_event_parameter(&node.children[1].children[i])); if i != node.children[1].children.len() - 1 { result.push(','); @@ -215,8 +325,9 @@ fn stylize_event(node: &parse_4_25::ParseNode) -> String { } } } + result.push_str(" "); result.push(')'); - result.push(';'); + result.push_str(";\n"); result } @@ -248,7 +359,7 @@ fn stylize_event_parameter(node: &parse_4_25::ParseNode) -> String { result } -fn stylize_function(node: &parse_4_25::ParseNode) -> String { +fn stylize_function_definition(node: &parse_4_25::ParseNode) -> String { let mut result = String::new(); match node.node { lex_4_25::Token::Function => result.push_str("function"), @@ -346,7 +457,55 @@ fn stylize_function(node: &parse_4_25::ParseNode) -> String { result } -fn stylize_block(node: &parse_4_25::ParseNode) -> String { String::new() } +fn stylize_block(block: &parse_4_25::ParseNode) -> String { + let mut result = String::new(); + match block.node { + lex_4_25::Token::OpenBrace => result.push_str("{"), + _ => panic!("Invalid block") + } + if block.children.len() == 0 { + result.push_str("}"); + } else { + for child in &block.children { + result.push_str(&stylize_statement(&child)); + } + } + result +} + +fn stylize_statement(statement: &parse_4_25::ParseNode) -> String { + return match statement.node { + lex_4_25::Token::If => stylize_if_statement(statement), + lex_4_25::Token::While => stylize_while_statement(statement), + lex_4_25::Token::For => stylize_for_statement(statement), + lex_4_25::Token::Assembly => stylize_inline_assembly_statement(statement), + lex_4_25::Token::Do => stylize_do_while_statement(statement), + lex_4_25::Token::Placeholder => String::from("\n\n_;"), + lex_4_25::Token::Emit => stylize_emit_statement(statement), + // TODO: This actually should be parse_variable_declaration | parse_expression + _ => { + let mut result = stylize_expression(statement); + match statement.node { + lex_4_25::Token::NoMatch => panic!("Invalid statement"), + _ => () + } + result.push_str(";"); + result + } + } +} + +fn stylize_if_statement(if_statement: &parse_4_25::ParseNode) -> String { String::new() } + +fn stylize_while_statement(if_statement: &parse_4_25::ParseNode) -> String { String::new() } + +fn stylize_for_statement(if_statement: &parse_4_25::ParseNode) -> String { String::new() } + +fn stylize_inline_assembly_statement(if_statement: &parse_4_25::ParseNode) -> String { String::new() } + +fn stylize_do_while_statement(if_statement: &parse_4_25::ParseNode) -> String { String::new() } + +fn stylize_emit_statement(if_statement: &parse_4_25::ParseNode) -> String { String::new() } fn stylize_method_invocation(node: &parse_4_25::ParseNode) -> String { String::new() } @@ -380,23 +539,59 @@ fn stylize_parameter(node: &parse_4_25::ParseNode) -> String { result } -fn stylize_modifier(node: &parse_4_25::ParseNode) -> String { +fn stylize_modifier_definition(node: &parse_4_25::ParseNode) -> String { let mut result = String::new(); + match node.node { + lex_4_25::Token::Modifier => { + result.push_str("\n "); + result.push_str("modifier"); + result.push_str(" "); + } + _ => panic!("Invalid modifier definition") + } + if node.children.len() == 2 { + match &node.children[0].node { + lex_4_25::Token::Identifier(name) => result.push_str(&name), + _ => panic!("Invalid modifier definition") + } + result.push_str(&stylize_block(&node.children[1])); + } else if node.children.len() == 3 { + match &node.children[0].node { + lex_4_25::Token::Identifier(name) => result.push_str(&name), + _ => panic!("Invalid modifier definition") + } + result.push_str(" "); + if node.children[1].children.len() > 0 { + for i in 0..=node.children[1].children.len() - 1 { + result.push_str(" \n"); + result.push_str(&stylize_parameter(&node.children[1].children[i])); + if i == node.children[1].children.len() - 1 { + result.push('\n'); + } else { + result.push_str(",\n"); + } + } + } + result.push_str(&stylize_block(&node.children[1])); + } else { + panic!("Invalid modifier definition"); + } + result.push_str("\n"); result } -fn stylize_using_for(node: &parse_4_25::ParseNode) -> String { +fn stylize_using_for_declaration(node: &parse_4_25::ParseNode) -> String { let mut result = String::new(); result } -fn stylize_struct(node: &parse_4_25::ParseNode) -> String { +fn stylize_struct_definition(node: &parse_4_25::ParseNode) -> String { let mut result = String::new(); match node.node { lex_4_25::Token::Struct => result.push_str("struct"), _ => panic!("Invalid struct definition") } - result.push(' '); + result.push_str(" "); match &node.children[0].node { lex_4_25::Token::Identifier(name) => result.push_str(&name), _ => panic!("Invalid struct definition") @@ -496,8 +691,15 @@ fn stylize_function_type(function_type: &parse_4_25::ParseNode) -> String { result } -fn stylize_mapping(function_type: &parse_4_25::ParseNode) -> String { +fn stylize_mapping(mapping: &parse_4_25::ParseNode) -> String { let mut result = String::new(); + match mapping.node { + lex_4_25::Token::Mapping => { + result.push_str("mapping"); + result.push_str(" "); + } + _ => panic!("Invalid mapping") + } result } @@ -611,6 +813,20 @@ fn stylize_elementary_type(elementary_type: &parse_4_25::ParseNode) -> String { }.to_string() } +/*** Sub-sub-statements ***/ + +fn stylize_expression(expression: &parse_4_25::ParseNode) -> String { + let mut result = String::new(); + // TODO: This needs to be expanded on significantly + match expression.node { + // This should do a lookahead parse to check more of an expression + lex_4_25::Token::DecimalNumber(ref number) => result.push_str(number), + lex_4_25::Token::HexNumber(ref number) => result.push_str(number), + _ => panic!("Invalid expression") + } + result +} + /*** Testing ***/ #[cfg(test)] @@ -726,6 +942,40 @@ mod tests { assert_eq!(actual_stylized, expected_stylized); } + #[test] + fn stylize_state_variable_declaration_test1() { + let node = parse_4_25::ParseNode { + node: lex_4_25::Token::StateVariable, + children: vec![ + Box::new(lex_4_25::Token::Uint256.to_leaf()), + Box::new(lex_4_25::Token::Identifier("nothing".to_string()).to_leaf()), + ] + }; + let actual_stylized = stylize_state_variable_declaration(&node); + let expected_stylized = String::from("\n uint256 nothing;"); + assert_eq!(expected_stylized, actual_stylized); + } + + #[test] + fn stylize_state_variable_declaration_test2() { + let node = parse_4_25::ParseNode { + node: lex_4_25::Token::StateVariable, + children: vec![ + Box::new(lex_4_25::Token::Uint256.to_leaf()), + Box::new(lex_4_25::Token::Identifier("total_supply".to_string()).to_leaf()), + Box::new(parse_4_25::ParseNode{ + node: lex_4_25::Token::Assignment, + children: vec![ + Box::new(lex_4_25::Token::DecimalNumber("10".to_string()).to_leaf()) + ] + }) + ] + }; + let actual_stylized = stylize_state_variable_declaration(&node); + let expected_stylized = String::from("\n uint256 total_supply = 10;"); + assert_eq!(expected_stylized, actual_stylized); + } + #[test] fn stylize_enum_test1() { let node = parse_4_25::ParseNode { @@ -735,7 +985,7 @@ mod tests { Box::new(lex_4_25::Token::OpenBrace.to_leaf()) ] }; - let actual_stylized = stylize_enum(&node); + let actual_stylized = stylize_enum_definition(&node); let expected_stylized = String::from("enum empty {}"); assert_eq!(expected_stylized, actual_stylized); } @@ -756,13 +1006,13 @@ mod tests { }) ] }; - let actual_stylized = stylize_enum(&node); + let actual_stylized = stylize_enum_definition(&node); let expected_stylized = String::from("enum Letters {\n A,\n B,\n C\n}"); assert_eq!(expected_stylized, actual_stylized); } #[test] - fn stylize_event_test1() { + fn stylize_event_declaration_test1() { let node = parse_4_25::ParseNode { node: lex_4_25::Token::Event, children: vec![ @@ -770,12 +1020,12 @@ mod tests { Box::new(lex_4_25::Token::OpenParenthesis.to_leaf()) ] }; - let actual_stylized = stylize_event(&node); + let actual_stylized = stylize_event_declaration(&node); let expected_stylized = "event empty();"; } #[test] - fn stylize_event_test2() { + fn stylize_event_declaration_test2() { let node = parse_4_25::ParseNode { node: lex_4_25::Token::Event, children: vec![ @@ -811,13 +1061,13 @@ mod tests { }) ] }; - let actual_stylized = stylize_event(&node); + let actual_stylized = stylize_event_declaration(&node); let expected_stylized = "event Transfer(\n address indexed owner,\n address indexed recipient,\n uint256 indexed value\n);"; assert_eq!(expected_stylized, actual_stylized); } #[test] - fn stylize_struct_test1() { + fn stylize_struct_definition_test1() { let node = parse_4_25::ParseNode { node: lex_4_25::Token::Struct, children: vec![ @@ -836,11 +1086,22 @@ mod tests { }) ] }; - let actual_stylized = stylize_struct(&node); + let actual_stylized = stylize_struct_definition(&node); let expected_stylized = "struct Value {\n uint256 value;\n}"; assert_eq!(expected_stylized, actual_stylized); } + #[test] + fn stylize_block_test1() { + let node = parse_4_25::ParseNode { + node: lex_4_25::Token::OpenBrace, + children: vec![] + }; + let actual_stylized = stylize_block(&node); + let expected_stylized = "{}"; + assert_eq!(expected_stylized, actual_stylized); + } + #[test] fn stylize_user_defined_type_name_test1() { let node = parse_4_25::ParseNode { diff --git a/tests/style_integration_tests.rs b/tests/style_integration_tests.rs new file mode 100644 index 0000000..a63ee54 --- /dev/null +++ b/tests/style_integration_tests.rs @@ -0,0 +1,39 @@ +extern crate solfix; + +#[cfg(test)] +mod style_integration_tests { + use solfix::lex_4_25; + use solfix::parse_4_25::{ parse, ParseNode, ParseTree }; + use solfix::style::stylize; + use std::fs; + + #[test] + fn empty_style_test() { + let input = fs::read_to_string("./contracts/BadEmpty.sol") + .expect("Test file not found: ./contracts/BadEmpty.sol"); + let expected = fs::read_to_string("./contracts/Empty.sol") + .expect("Test file not found: ./contracts/Empty.sol"); + let actual = stylize(parse(input)); + assert_eq!(expected, actual); + } + + #[test] + fn value_style_test() { + let input = fs::read_to_string("./contracts/BadValue.sol") + .expect("Test file not found: ./contracts/BadValue.sol"); + let expected = fs::read_to_string("./contracts/Value.sol") + .expect("Test file not found: ./contracts/Value.sol"); + let actual = stylize(parse(input)); + assert_eq!(expected, actual); + } + + #[test] + fn ownable_style_test() { + let input = fs::read_to_string("./contracts/BadOwnable.sol") + .expect("Test file not found: ./contracts/BadOwnable.sol"); + let expected = fs::read_to_string("./contracts/Ownable.sol") + .expect("Test file not found: ./contracts/Ownable.sol"); + let actual = stylize(parse(input)); + assert_eq!(expected, actual); + } +} From 9702807fced30a13fbde396bdf894b0006d4a6f8 Mon Sep 17 00:00:00 2001 From: James Towle Date: Fri, 14 Jun 2019 09:40:00 -0700 Subject: [PATCH 8/9] Modularized the style module --- contracts/BadDemo.sol | 45 +++ contracts/BadOwnable.sol | 84 ++++++ contracts/BadValue.sol | 9 + contracts/Demo.sol | 16 ++ contracts/Empty.sol | 4 +- contracts/Ownable.sol | 2 + contracts/Value.sol | 7 + contracts/library.sol | 3 + src/main.rs | 26 +- src/style.rs | 453 ++++++++++++++++++++++++++----- tests/style_integration_tests.rs | 39 +++ 11 files changed, 607 insertions(+), 81 deletions(-) create mode 100644 contracts/BadDemo.sol create mode 100644 contracts/BadOwnable.sol create mode 100644 contracts/BadValue.sol create mode 100644 contracts/Demo.sol create mode 100644 contracts/Value.sol create mode 100644 contracts/library.sol create mode 100644 tests/style_integration_tests.rs diff --git a/contracts/BadDemo.sol b/contracts/BadDemo.sol new file mode 100644 index 0000000..06e1da9 --- /dev/null +++ b/contracts/BadDemo.sol @@ -0,0 +1,45 @@ +pragma solidity ^0.4.25; + +contract + + + +Demo + + + is + + + + A, + B, + + + C, + + + D + + + + + + + { + event Transfer( + address + indexed + owner, + address indexed recipient, + uint256 indexed value); + address public + constant a = 103414; + + + address + public constant b = 0x103414; + + modifier empty { + + } + } diff --git a/contracts/BadOwnable.sol b/contracts/BadOwnable.sol new file mode 100644 index 0000000..a1038f9 --- /dev/null +++ b/contracts/BadOwnable.sol @@ -0,0 +1,84 @@ + pragma solidity + + + + ^0.4.25 + + + + ; + + +contract Ownable + + + + + +{ + + address + + public owner; + + modifier + + + onlyOwner { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + require( + + msg.sender + + + + == owner + + ) ; + _; + + } } diff --git a/contracts/BadValue.sol b/contracts/BadValue.sol new file mode 100644 index 0000000..37f5620 --- /dev/null +++ b/contracts/BadValue.sol @@ -0,0 +1,9 @@ +pragma + + + solidity + + + ^0.4.25; + +contract Value { uint256 b = 351231; } diff --git a/contracts/Demo.sol b/contracts/Demo.sol new file mode 100644 index 0000000..c49b229 --- /dev/null +++ b/contracts/Demo.sol @@ -0,0 +1,16 @@ +pragma solidity ^0.4.25; + + +contract Demo is + A, + B, + C, + D +{ + + event Transfer(address indexed owner, address indexed recipient, uint256 indexed value); + + address public constant a = 103414; + + address public constant b = 0x103414; +} diff --git a/contracts/Empty.sol b/contracts/Empty.sol index 9097001..8f66833 100644 --- a/contracts/Empty.sol +++ b/contracts/Empty.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.4.25; +pragma solidity ^0.4.25; -contract Empty {} +contract Empty {} \ No newline at end of file diff --git a/contracts/Ownable.sol b/contracts/Ownable.sol index 6aec8d7..51e01f9 100644 --- a/contracts/Ownable.sol +++ b/contracts/Ownable.sol @@ -1,6 +1,8 @@ pragma solidity ^0.4.25; + contract Ownable { + address public owner; modifier onlyOwner { diff --git a/contracts/Value.sol b/contracts/Value.sol new file mode 100644 index 0000000..81050e6 --- /dev/null +++ b/contracts/Value.sol @@ -0,0 +1,7 @@ +pragma solidity ^0.4.25; + + +contract Value { + + uint256 b = 351231; +} \ No newline at end of file diff --git a/contracts/library.sol b/contracts/library.sol new file mode 100644 index 0000000..df2326c --- /dev/null +++ b/contracts/library.sol @@ -0,0 +1,3 @@ +pragma solidity ^0.4.25; + +library A {} diff --git a/src/main.rs b/src/main.rs index b28cfd5..6d732ec 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,11 +4,23 @@ use solfix::parse_4_25::parse; use solfix::style::stylize; fn main() { - let usage = "Usage: solidity-fix SOURCE TARGET"; - let source = env::args().nth(1).expect(usage); -// let target = env::args().nth(2).expect(usage); - let input = fs::read_to_string(source).expect("Unable to open input file"); - println!("{}", stylize(parse(input))); -// let result = generate(parse(input)); -// fs::write(target, result).expect("Unable to write file"); + let usage = "Usage: solfix style SOURCE [TARGET]\n ast SOURCE [TARGET]"; + match env::args().nth(1) { + Some(ref style) if style == "style" => { + let source = env::args().nth(2).expect(usage); + let input = fs::read_to_string(source).expect("Unable to find SOURCE"); + match env::args().nth(3) { + Some(target) => fs::write(target, stylize(parse(input))).expect("Unable to write file to TARGET"), + None => println!("{}", stylize(parse(input))) + } + } + Some(ref ast) if ast == "ast" => { + let source = env::args().nth(2).expect(usage); + let input = fs::read_to_string(source).expect("Unable to find SOURCE"); + match env::args().nth(3) { + _ => println!("{:?}", parse(input)) + } + } + _ => println!("{}", usage) + } } diff --git a/src/style.rs b/src/style.rs index 87b2bc1..5063126 100644 --- a/src/style.rs +++ b/src/style.rs @@ -1,6 +1,68 @@ use super::lex_4_25; use super::parse_4_25; +enum Style { + /*** Contract ***/ + BeforeContract, + Contract, + Interface, + Library, + AfterContract, + BeforeContractIdentifier, + AfterContractIdentifier, + /*** Pragma Keyword ***/ + BeforePragma, + Pragma, + AfterPragma, + /*** Pragma Identifier ***/ + BeforePragmaIdentifier, + AfterPragmaIdentifier, + /*** Pragma Version ***/ + BeforeVersion, + AfterVersion +} + +trait StyleResolver { + fn resolve(&mut self, style: Style); +} + +impl StyleResolver for String { + fn resolve(&mut self, style: Style) { + match style { + /*** Contract ***/ + Style::BeforeContractIdentifier => (), + Style::AfterContractIdentifier => self.push_str(" "), + /*** Contract Part ***/ + Style::BeforeContractPartOpenBrace => (), + Style::ContractPartOpenBrace => self.push_str("{"), + Style::AfterContractPartOpenBrace => (), + + Style::BeforeIs => self.push_str(" "), + Style::Is => self.push_str("is"), + Style::AfterIs => self.push_str("\n"), + + Style::BeforeInheritanceName => self.push_str(" "), + Style::AfterInheritanceName => self.push_str(",\n"), + Style::AfterInheritanceNameLast => self.push_str(",\n"), + Style::BeforeContract => self.push_str("\n\n\n"), + Style::Contract => self.push_str("contract"), + Style::Interface => self.push_str("interface"), + Style::Library => self.push_str("library"), + Style::AfterContract => self.push_str(" "), + Style::BeforePragma => (), + Style::Pragma => self.push_str("pragma"), + Style::BeforePragma => (), + Style::AfterPragma => self.push_str(" "), + Style::BeforePragmaIdentifier => (), + Style::AfterPragmaIdentifier => self.push_str(" "), + Style::AfterPragma => self.push_str(" "), + Style::BeforeVersion => (), + Style::AfterVersion => self.push_str(";"), + _ => (), + } + } +} + /*** Top Level ***/ pub fn stylize(tree: parse_4_25::ParseTree) -> String { @@ -23,27 +85,31 @@ pub fn stylize(tree: parse_4_25::ParseTree) -> String { fn stylize_pragma(pragma: parse_4_25::ParseNode) -> String { let mut result = String::new(); if let lex_4_25::Token::Pragma = pragma.node { - result.push_str("pragma"); - result.push(' '); + result.resolve(Style::BeforePragma); + result.resolve(Style::Pragma); + result.resolve(Style::AfterPragma); } if pragma.children.len() >= 2 { if let lex_4_25::Token::Identifier(name) = &pragma.children[0].node { + result.resolve(Style::BeforePragmaIdentifier); result.push_str(&name); - result.push(' '); + result.resolve(Style::AfterPragmaIdentifier); } if pragma.children.len() == 2 { if let lex_4_25::Token::Version(version) = &pragma.children[1].node { + result.resolve(Style::BeforeVersion); result.push_str(&version); - result.push_str(";"); + result.resolve(Style::AfterVersion); } } else if pragma.children.len() == 3 { + result.resolve(Style::BeforeVersion); if let lex_4_25::Token::BitwiseXor = &pragma.children[1].node { result.push('^'); } if let lex_4_25::Token::Version(version) = &pragma.children[2].node { result.push_str(&version); - result.push_str(";"); } + result.resolve(Style::AfterVersion); } } result @@ -57,44 +123,42 @@ fn stylize_import(import: parse_4_25::ParseNode) -> String { String::new() } fn stylize_contract(contract: parse_4_25::ParseNode) -> String { let mut result = String::new(); + result.resolve(Style::BeforeContract); match contract.node { - lex_4_25::Token::Contract => result.push_str("\n\ncontract "), - lex_4_25::Token::Library => result.push_str("\n\nlibrary "), - lex_4_25::Token::Interface => result.push_str("\n\ninterface "), + lex_4_25::Token::Contract => result.resolve(Style::Contract), + lex_4_25::Token::Interface => result.resolve(Style::Interface), + lex_4_25::Token::Library => result.resolve(Style::Library), _ => panic!("Invalid contract definition") } + result.resolve(Style::AfterContract); if contract.children.len() == 2 { match &contract.children[0].node { lex_4_25::Token::Identifier(name) => { + result.resolve(Style::BeforeContractIdentifier); result.push_str(&name); - result.push(' '); + result.resolve(Style::AfterContractIdentifier); } _ => panic!("Invalid contract definition") } match &contract.children[1].node { - lex_4_25::Token::OpenBrace => { - result.push_str(&stylize_contract_part(&contract.children[1])); - } + lex_4_25::Token::OpenBrace => result.push_str(&stylize_contract_part(&contract.children[1])), _ => panic!("Invalid contract definition") } } else if contract.children.len() == 3 { match &contract.children[0].node { lex_4_25::Token::Identifier(name) => { + result.resolve(Style::BeforeContractIdentifier); result.push_str(&name); - result.push(' '); + result.resolve(Style::AfterContractIdentifier); } _ => panic!("Invalid contract definition") } match &contract.children[1].node { - lex_4_25::Token::Is => { - result.push_str(&stylize_inheritance_specifier(&contract.children[1])); - } + lex_4_25::Token::Is => result.push_str(&stylize_inheritance_specifier(&contract.children[1])), _ => panic!("Invalid contract definition") } match &contract.children[2].node { - lex_4_25::Token::OpenBrace => { - result.push_str(&stylize_contract_part(&contract.children[2])); - } + lex_4_25::Token::OpenBrace => result.push_str(&stylize_contract_part(&contract.children[2])), _ => panic!("Invalid contract definition") } } @@ -106,21 +170,24 @@ fn stylize_contract(contract: parse_4_25::ParseNode) -> String { fn stylize_inheritance_specifier(block: &parse_4_25::ParseNode) -> String { let mut result = String::new(); match block.node { - lex_4_25::Token::Is => result.push_str("is\n"), + lex_4_25::Token::Is => { + result.resolve(Style::BeforeIs); + result.resolve(Style::Is); + result.resolve(Style::AfterIs); + } _ => panic!("Invalid inheritance specifier") } match &block.children[0].node { lex_4_25::Token::OpenParenthesis => (), _ => panic!("Invalid inheritance specifier") } - for i in 0..=block.children[0].children.len() - 1 { - // FIXME Replace with result.indent() - result.push_str(" "); - result.push_str(&stylize_user_defined_type_name(&block.children[0].children[i])); - if i != block.children[0].children.len() - 1 { - result.push_str(",\n"); + for i in 0..=block.children.len() - 1 { + result.resolve(Style::BeforeInheritanceName); + result.push_str(&stylize_user_defined_type_name(&block.children[i].children[0])); + if i != block.children.len() - 1 { + result.resolve(Style::AfterInheritanceName); } else { - result.push('\n'); + result.resolve(Style::AfterInheritanceNameLast); } } result @@ -130,28 +197,84 @@ fn stylize_inheritance_specifier(block: &parse_4_25::ParseNode) -> String { fn stylize_contract_part(block: &parse_4_25::ParseNode) -> String { let mut result = String::new(); + result.resolve(Style::BeforeContractPartOpenBrace); match block.node { - lex_4_25::Token::OpenBrace => result.push('{'), + lex_4_25::Token::OpenBrace => { + result.resolve(Style::ContractPartOpenBrace); + } _ => panic!("Invalid contract part") } + if block.children.len() > 0 { + result.resolve(Style::AfterContractPartOpenBrace); + } else { + result.resolve(Style::ContractPartCloseBrace); + return result + } for child in &block.children { match child.node { - lex_4_25::Token::Enum => result.push_str(&stylize_enum(&child)), - lex_4_25::Token::Event => result.push_str(&stylize_event(&child)), - lex_4_25::Token::Function => result.push_str(&stylize_function(&child)), - lex_4_25::Token::Modifier => result.push_str(&stylize_modifier(&child)), - lex_4_25::Token::Using => result.push_str(&stylize_using_for(&child)), - lex_4_25::Token::Struct => result.push_str(&stylize_struct(&child)), + lex_4_25::Token::Enum => result.push_str(&stylize_enum_definition(&child)), + lex_4_25::Token::Event => result.push_str(&stylize_event_declaration(&child)), + lex_4_25::Token::Function => result.push_str(&stylize_function_definition(&child)), + lex_4_25::Token::Modifier => result.push_str(&stylize_modifier_definition(&child)), + lex_4_25::Token::Using => result.push_str(&stylize_using_for_declaration(&child)), + lex_4_25::Token::Struct => result.push_str(&stylize_struct_definition(&child)), + lex_4_25::Token::StateVariable => result.push_str(&stylize_state_variable_declaration(&child)), _ => panic!("Invalid contract part") } } - result.push('}'); + result.resolve(Style::ContractPartCloseBrace); result } /*** Sub-contract Structures ***/ -fn stylize_enum(node: &parse_4_25::ParseNode) -> String { +fn stylize_state_variable_declaration(node: &parse_4_25::ParseNode) -> String { + let mut result = String::new(); + if node.children.len() < 2 { + panic!("Invalid state variable"); + } + result.resolve(Style::BeforeStateVariableElementaryType); + result.push_str(&stylize_elementary_type(&node.children[0])); + result.resolve(Style::AfterStateVariableElementaryType); + let mut i = 1; + let mut stop = false; + while !stop && i < node.children.len() { + match &node.children[i].node { + lex_4_25::Token::Constant => result.push_str("constant"), + lex_4_25::Token::Internal => result.push_str("internal"), + lex_4_25::Token::Private => result.push_str("private"), + lex_4_25::Token::Public => result.push_str("public"), + _ => stop = true + } + if !stop { + result.push(' '); + i += 1; + } + } + match &node.children[i].node { + lex_4_25::Token::Identifier(name) => result.push_str(&name), + _ => panic!("1Invalid state variable") + } + i += 1; + if i == node.children.len() { + result.push_str(";\n"); + return result; + } else { + result.push(' '); + match node.children[i].node { + lex_4_25::Token::Assignment => { + result.push_str("="); + result.push_str(" "); + result.push_str(&stylize_expression(&node.children[i].children[0])); + result.push_str(";\n"); + } + _ => panic!("Invalid state variable") + } + } + result +} + +fn stylize_enum_definition(node: &parse_4_25::ParseNode) -> String { let mut result = String::new(); match node.node { lex_4_25::Token::Enum => result.push_str("enum"), @@ -188,8 +311,9 @@ fn stylize_enum(node: &parse_4_25::ParseNode) -> String { result } -fn stylize_event(node: &parse_4_25::ParseNode) -> String { +fn stylize_event_declaration(node: &parse_4_25::ParseNode) -> String { let mut result = String::new(); + result.push_str(" "); match node.node { lex_4_25::Token::Event => result.push_str("event"), _ => panic!("Invalid event definition") @@ -206,7 +330,7 @@ fn stylize_event(node: &parse_4_25::ParseNode) -> String { if node.children[1].children.len() > 0 { for i in 0..=node.children[1].children.len() - 1 { result.push('\n'); - result.push_str(" "); + result.push_str(" "); result.push_str(&stylize_event_parameter(&node.children[1].children[i])); if i != node.children[1].children.len() - 1 { result.push(','); @@ -215,8 +339,9 @@ fn stylize_event(node: &parse_4_25::ParseNode) -> String { } } } + result.push_str(" "); result.push(')'); - result.push(';'); + result.push_str(";\n"); result } @@ -248,7 +373,7 @@ fn stylize_event_parameter(node: &parse_4_25::ParseNode) -> String { result } -fn stylize_function(node: &parse_4_25::ParseNode) -> String { +fn stylize_function_definition(node: &parse_4_25::ParseNode) -> String { let mut result = String::new(); match node.node { lex_4_25::Token::Function => result.push_str("function"), @@ -346,7 +471,55 @@ fn stylize_function(node: &parse_4_25::ParseNode) -> String { result } -fn stylize_block(node: &parse_4_25::ParseNode) -> String { String::new() } +fn stylize_block(block: &parse_4_25::ParseNode) -> String { + let mut result = String::new(); + match block.node { + lex_4_25::Token::OpenBrace => result.push_str("{"), + _ => panic!("Invalid block") + } + if block.children.len() == 0 { + result.push_str("}"); + } else { + for child in &block.children { + result.push_str(&stylize_statement(&child)); + } + } + result +} + +fn stylize_statement(statement: &parse_4_25::ParseNode) -> String { + return match statement.node { + lex_4_25::Token::If => stylize_if_statement(statement), + lex_4_25::Token::While => stylize_while_statement(statement), + lex_4_25::Token::For => stylize_for_statement(statement), + lex_4_25::Token::Assembly => stylize_inline_assembly_statement(statement), + lex_4_25::Token::Do => stylize_do_while_statement(statement), + lex_4_25::Token::Placeholder => String::from("\n\n_;"), + lex_4_25::Token::Emit => stylize_emit_statement(statement), + // TODO: This actually should be parse_variable_declaration | parse_expression + _ => { + let mut result = stylize_expression(statement); + match statement.node { + lex_4_25::Token::NoMatch => panic!("Invalid statement"), + _ => () + } + result.push_str(";"); + result + } + } +} + +fn stylize_if_statement(if_statement: &parse_4_25::ParseNode) -> String { String::new() } + +fn stylize_while_statement(if_statement: &parse_4_25::ParseNode) -> String { String::new() } + +fn stylize_for_statement(if_statement: &parse_4_25::ParseNode) -> String { String::new() } + +fn stylize_inline_assembly_statement(if_statement: &parse_4_25::ParseNode) -> String { String::new() } + +fn stylize_do_while_statement(if_statement: &parse_4_25::ParseNode) -> String { String::new() } + +fn stylize_emit_statement(if_statement: &parse_4_25::ParseNode) -> String { String::new() } fn stylize_method_invocation(node: &parse_4_25::ParseNode) -> String { String::new() } @@ -380,42 +553,93 @@ fn stylize_parameter(node: &parse_4_25::ParseNode) -> String { result } -fn stylize_modifier(node: &parse_4_25::ParseNode) -> String { +fn stylize_modifier_definition(node: &parse_4_25::ParseNode) -> String { let mut result = String::new(); + match node.node { + lex_4_25::Token::Modifier => { + result.resolve(Style::BeforeModifier); + result.resolve(Style::Modifier); + result.resolve(Style::AfterModifier); + } + _ => panic!("Invalid modifier definition") + } + if node.children.len() == 2 { + match &node.children[0].node { + lex_4_25::Token::Identifier(name) => { + result.resolve(Style::BeforeModifierIdentifier); + result.push_str(&name); + result.resolve(Style::AfterModifierIdentifier); + } + _ => panic!("Invalid modifier definition") + } + result.push_str(&stylize_block(&node.children[1])); + } else if node.children.len() == 3 { + match &node.children[0].node { + lex_4_25::Token::Identifier(name) => { + result.resolve(Style::BeforeModifierIdentifier); + result.push_str(&name); + result.resolve(Style::AfterModifierIdentifier); + } + _ => panic!("Invalid modifier definition") + } + result.push_str(" "); + if node.children[1].children.len() > 0 { + for i in 0..=node.children[1].children.len() - 1 { + result.push_str(" \n"); + result.push_str(&stylize_parameter(&node.children[1].children[i])); + if i == node.children[1].children.len() - 1 { + result.push('\n'); + } else { + result.push_str(",\n"); + } + } + } + result.push_str(&stylize_block(&node.children[1])); + } else { + panic!("Invalid modifier definition"); + } + result.push_str("\n"); result } -fn stylize_using_for(node: &parse_4_25::ParseNode) -> String { +fn stylize_using_for_declaration(node: &parse_4_25::ParseNode) -> String { let mut result = String::new(); result } -fn stylize_struct(node: &parse_4_25::ParseNode) -> String { +fn stylize_struct_definition(node: &parse_4_25::ParseNode) -> String { let mut result = String::new(); match node.node { - lex_4_25::Token::Struct => result.push_str("struct"), + lex_4_25::Token::Struct => { + result.resolve(Style::BeforeStruct); + result.resolve(Style::Struct); + result.resolve(Style::AfterStruct); + } _ => panic!("Invalid struct definition") } - result.push(' '); match &node.children[0].node { - lex_4_25::Token::Identifier(name) => result.push_str(&name), + lex_4_25::Token::Identifier(name) => { + result.resolve(BeforeStructIdentifier); + result.push_str(&name); + result.resolve(AfterStructIdentifier); + } _ => panic!("Invalid struct definition") } - result.push(' '); match &node.children[1].node { - lex_4_25::Token::OpenBrace => result.push('{'), + lex_4_25::Token::OpenBrace => { + result.resolve(BeforeStructOpenBrace); + result.resolve(StructOpenBrace); + result.resolve(AfterStructOpenBrace); + } _ => panic!("Invalid struct definition") } for i in 0..=node.children[1].children.len() - 1 { - result.push('\n'); - result.push_str(" "); + result.resolve(Style::BeforeStructVariableDeclaration); result.push_str(&stylize_variable_declaration(&node.children[1].children[i])); - result.push(';'); - if i == node.children[1].children.len() - 1 { - result.push('\n'); - } + result.resolve(Style::Semicolon); + result.resolve(Style::AfterStructVariableDeclaration); } - result.push('}'); + result.resolve(Style::StructCloseBrace); result } @@ -425,22 +649,38 @@ fn stylize_variable_declaration(node: &parse_4_25::ParseNode) -> String { lex_4_25::Token::VariableDeclaration => (), _ => panic!("Invalid variable declaration") } + result.resolve(Style::BeforeVariableDeclarationTypeName); result.push_str(&stylize_type_name(&node.children[0])); - result.push(' '); + result.resolve(Style::AfterVariableDeclarationTypeName); if node.children.len() == 2 { match &node.children[1].node { - lex_4_25::Token::Identifier(name) => result.push_str(&name), + lex_4_25::Token::Identifier(name) => { + result.resolve(Style::BeforeVariableDeclarationIdentifier); + result.push_str(&name); + result.resolve(Style::AfterVariableDeclarationIdentifier); + } _ => panic!("Invalid variable declaration") } } else if node.children.len() == 3 { match &node.children[1].node { - lex_4_25::Token::Memory => result.push_str("memory"), - lex_4_25::Token::Storage => result.push_str("storage"), + lex_4_25::Token::Memory => { + result.resolve(Style::BeforeMemory); + result.resolve(Style::Memory); + result.resolve(Style::AfterMemory); + } + lex_4_25::Token::Storage => { + result.resolve(Style::BeforeStorage); + result.resolve(Style::Storage); + result.resolve(Style::AfterStorage); + } _ => panic!("Invalid variable declaration") } - result.push(' '); match &node.children[1].node { - lex_4_25::Token::Identifier(name) => result.push_str(&name), + lex_4_25::Token::Identifier(name) => { + result.resolve(Style::BeforeVariableDeclarationIdentifier); + result.push_str(&name); + result.resolve(Style::AfterVariableDeclarationIdentifier); + } _ => panic!("Invalid variable declaration") } } else { @@ -474,15 +714,17 @@ fn stylize_user_defined_type_name(type_name: &parse_4_25::ParseNode) -> String { lex_4_25::Token::UserDefinedTypeName => (), _ => panic!("Invalid user defined type name") } + result.resolve(Style::BeforeUserDefinedTypeName); for i in 0..=type_name.children.len() - 1{ match &type_name.children[i].node { lex_4_25::Token::Identifier(name) => result.push_str(&name), _ => panic!("Invalid user defined type name") } if i != type_name.children.len() - 1 { - result.push('.'); + result.resolve(Style::Dot); } } + result.resolve(Style::AfterUserDefinedTypeName); result } @@ -496,8 +738,16 @@ fn stylize_function_type(function_type: &parse_4_25::ParseNode) -> String { result } -fn stylize_mapping(function_type: &parse_4_25::ParseNode) -> String { +fn stylize_mapping(mapping: &parse_4_25::ParseNode) -> String { let mut result = String::new(); + match mapping.node { + lex_4_25::Token::Mapping => { + result.resolve(Style::BeforeMapping); + result.resolve(Style::Mapping); + result.resolve(Style::AfterMapping); + } + _ => panic!("Invalid mapping") + } result } @@ -611,6 +861,20 @@ fn stylize_elementary_type(elementary_type: &parse_4_25::ParseNode) -> String { }.to_string() } +/*** Sub-sub-statements ***/ + +fn stylize_expression(expression: &parse_4_25::ParseNode) -> String { + let mut result = String::new(); + // TODO: This needs to be expanded on significantly + match expression.node { + // This should do a lookahead parse to check more of an expression + lex_4_25::Token::DecimalNumber(ref number) => result.push_str(number), + lex_4_25::Token::HexNumber(ref number) => result.push_str(number), + _ => panic!("Invalid expression") + } + result +} + /*** Testing ***/ #[cfg(test)] @@ -726,6 +990,40 @@ mod tests { assert_eq!(actual_stylized, expected_stylized); } + #[test] + fn stylize_state_variable_declaration_test1() { + let node = parse_4_25::ParseNode { + node: lex_4_25::Token::StateVariable, + children: vec![ + Box::new(lex_4_25::Token::Uint256.to_leaf()), + Box::new(lex_4_25::Token::Identifier("nothing".to_string()).to_leaf()), + ] + }; + let actual_stylized = stylize_state_variable_declaration(&node); + let expected_stylized = String::from("\n uint256 nothing;"); + assert_eq!(expected_stylized, actual_stylized); + } + + #[test] + fn stylize_state_variable_declaration_test2() { + let node = parse_4_25::ParseNode { + node: lex_4_25::Token::StateVariable, + children: vec![ + Box::new(lex_4_25::Token::Uint256.to_leaf()), + Box::new(lex_4_25::Token::Identifier("total_supply".to_string()).to_leaf()), + Box::new(parse_4_25::ParseNode{ + node: lex_4_25::Token::Assignment, + children: vec![ + Box::new(lex_4_25::Token::DecimalNumber("10".to_string()).to_leaf()) + ] + }) + ] + }; + let actual_stylized = stylize_state_variable_declaration(&node); + let expected_stylized = String::from("\n uint256 total_supply = 10;"); + assert_eq!(expected_stylized, actual_stylized); + } + #[test] fn stylize_enum_test1() { let node = parse_4_25::ParseNode { @@ -735,7 +1033,7 @@ mod tests { Box::new(lex_4_25::Token::OpenBrace.to_leaf()) ] }; - let actual_stylized = stylize_enum(&node); + let actual_stylized = stylize_enum_definition(&node); let expected_stylized = String::from("enum empty {}"); assert_eq!(expected_stylized, actual_stylized); } @@ -756,13 +1054,13 @@ mod tests { }) ] }; - let actual_stylized = stylize_enum(&node); + let actual_stylized = stylize_enum_definition(&node); let expected_stylized = String::from("enum Letters {\n A,\n B,\n C\n}"); assert_eq!(expected_stylized, actual_stylized); } #[test] - fn stylize_event_test1() { + fn stylize_event_declaration_test1() { let node = parse_4_25::ParseNode { node: lex_4_25::Token::Event, children: vec![ @@ -770,12 +1068,12 @@ mod tests { Box::new(lex_4_25::Token::OpenParenthesis.to_leaf()) ] }; - let actual_stylized = stylize_event(&node); + let actual_stylized = stylize_event_declaration(&node); let expected_stylized = "event empty();"; } #[test] - fn stylize_event_test2() { + fn stylize_event_declaration_test2() { let node = parse_4_25::ParseNode { node: lex_4_25::Token::Event, children: vec![ @@ -811,13 +1109,13 @@ mod tests { }) ] }; - let actual_stylized = stylize_event(&node); + let actual_stylized = stylize_event_declaration(&node); let expected_stylized = "event Transfer(\n address indexed owner,\n address indexed recipient,\n uint256 indexed value\n);"; assert_eq!(expected_stylized, actual_stylized); } #[test] - fn stylize_struct_test1() { + fn stylize_struct_definition_test1() { let node = parse_4_25::ParseNode { node: lex_4_25::Token::Struct, children: vec![ @@ -836,11 +1134,22 @@ mod tests { }) ] }; - let actual_stylized = stylize_struct(&node); + let actual_stylized = stylize_struct_definition(&node); let expected_stylized = "struct Value {\n uint256 value;\n}"; assert_eq!(expected_stylized, actual_stylized); } + #[test] + fn stylize_block_test1() { + let node = parse_4_25::ParseNode { + node: lex_4_25::Token::OpenBrace, + children: vec![] + }; + let actual_stylized = stylize_block(&node); + let expected_stylized = "{}"; + assert_eq!(expected_stylized, actual_stylized); + } + #[test] fn stylize_user_defined_type_name_test1() { let node = parse_4_25::ParseNode { diff --git a/tests/style_integration_tests.rs b/tests/style_integration_tests.rs new file mode 100644 index 0000000..a63ee54 --- /dev/null +++ b/tests/style_integration_tests.rs @@ -0,0 +1,39 @@ +extern crate solfix; + +#[cfg(test)] +mod style_integration_tests { + use solfix::lex_4_25; + use solfix::parse_4_25::{ parse, ParseNode, ParseTree }; + use solfix::style::stylize; + use std::fs; + + #[test] + fn empty_style_test() { + let input = fs::read_to_string("./contracts/BadEmpty.sol") + .expect("Test file not found: ./contracts/BadEmpty.sol"); + let expected = fs::read_to_string("./contracts/Empty.sol") + .expect("Test file not found: ./contracts/Empty.sol"); + let actual = stylize(parse(input)); + assert_eq!(expected, actual); + } + + #[test] + fn value_style_test() { + let input = fs::read_to_string("./contracts/BadValue.sol") + .expect("Test file not found: ./contracts/BadValue.sol"); + let expected = fs::read_to_string("./contracts/Value.sol") + .expect("Test file not found: ./contracts/Value.sol"); + let actual = stylize(parse(input)); + assert_eq!(expected, actual); + } + + #[test] + fn ownable_style_test() { + let input = fs::read_to_string("./contracts/BadOwnable.sol") + .expect("Test file not found: ./contracts/BadOwnable.sol"); + let expected = fs::read_to_string("./contracts/Ownable.sol") + .expect("Test file not found: ./contracts/Ownable.sol"); + let actual = stylize(parse(input)); + assert_eq!(expected, actual); + } +} From 8e5eba155c74593a65e5b6bdf53b898f035a90bb Mon Sep 17 00:00:00 2001 From: James Towle Date: Sun, 14 Jul 2019 02:36:59 -0500 Subject: [PATCH 9/9] Fixed all tests --- contracts/Empty.sol | 2 +- contracts/Value.sol | 2 +- src/style.rs | 290 +++++++++++++++++++++++-------- tests/style_integration_tests.rs | 6 +- 4 files changed, 222 insertions(+), 78 deletions(-) diff --git a/contracts/Empty.sol b/contracts/Empty.sol index 8f66833..da8d234 100644 --- a/contracts/Empty.sol +++ b/contracts/Empty.sol @@ -1,4 +1,4 @@ pragma solidity ^0.4.25; -contract Empty {} \ No newline at end of file +contract Empty {} diff --git a/contracts/Value.sol b/contracts/Value.sol index 81050e6..4d2c315 100644 --- a/contracts/Value.sol +++ b/contracts/Value.sol @@ -4,4 +4,4 @@ pragma solidity ^0.4.25; contract Value { uint256 b = 351231; -} \ No newline at end of file +} diff --git a/src/style.rs b/src/style.rs index 96f1571..ae4c9f1 100644 --- a/src/style.rs +++ b/src/style.rs @@ -1,6 +1,8 @@ use super::lex_4_25; use super::parse_4_25; +// TODO(jalextowle): These will probably need to be more granular. It would +// be great to create a BNF grammar for style rules, if it is possible. enum Style { /*** Contract ***/ BeforeContract, @@ -10,6 +12,20 @@ enum Style { AfterContract, BeforeContractIdentifier, AfterContractIdentifier, + AfterContractPartCloseBrace, + BeforeContractPartCloseBrace, + AfterContractPartOpenBrace, + BeforeContractPartOpenBrace, + ContractPartOpenBrace, + ContractPartCloseBrace, + /*** Inheritance ***/ + AfterInheritanceName, + AfterInheritanceNameLast, + BeforeInheritanceName, + BeforeInheritanceNameLast, + AfterIs, + BeforeIs, + Is, /*** Pragma Keyword ***/ BeforePragma, Pragma, @@ -19,7 +35,56 @@ enum Style { AfterPragmaIdentifier, /*** Pragma Version ***/ BeforeVersion, - AfterVersion + AfterVersion, + /*** Struct ***/ + AfterStruct, + AfterStructCloseBrace, + AfterStructIdentifier, + AfterStructOpenBrace, + AfterStructVariableDeclaration, + BeforeStruct, + BeforeStructCloseBrace, + BeforeStructIdentifier, + BeforeStructOpenBrace, + BeforeStructVariableDeclaration, + Struct, + StructCloseBrace, + StructOpenBrace, + StructVariableDeclaration, + /*** State Variable ***/ + AfterStateVariableElementaryType, + BeforeStateVariableElementaryType, + /*** Mapping ***/ + Mapping, + AfterMapping, + BeforeMapping, + /*** Modifier ***/ + AfterModifier, + AfterModifierIdentifier, + BeforeModifier, + BeforeModifierIdentifier, + Modifier, + /*** User Defined Type Name ***/ + BeforeUserDefinedTypeName, + UserDefinedTypeName, + AfterUserDefinedTypeName, + /*** Storage ***/ + Storage, + AfterStorage, + BeforeStorage, + /*** Memory ***/ + Memory, + AfterMemory, + BeforeMemory, + /*** Variable Declaration ***/ + AfterVariableDeclarationIdentifier, + AfterVariableDeclarationTypeName, + BeforeVariableDeclarationIdentifier, + BeforeVariableDeclarationTypeName, + /*** Operations ***/ + Dot, + /*** Terminators ***/ + Semicolon, } trait StyleResolver { @@ -40,10 +105,11 @@ impl StyleResolver for String { Style::BeforeIs => self.push_str(" "), Style::Is => self.push_str("is"), Style::AfterIs => self.push_str("\n"), + Style::ContractPartCloseBrace => self.push_str("}"), Style::BeforeInheritanceName => self.push_str(" "), Style::AfterInheritanceName => self.push_str(",\n"), - Style::AfterInheritanceNameLast => self.push_str(",\n"), + Style::AfterInheritanceNameLast => self.push_str("\n"), Style::BeforeContract => self.push_str("\n\n\n"), Style::Contract => self.push_str("contract"), Style::Interface => self.push_str("interface"), @@ -58,6 +124,39 @@ impl StyleResolver for String { Style::AfterPragma => self.push_str(" "), Style::BeforeVersion => (), Style::AfterVersion => self.push_str(";"), + + Style::AfterStateVariableElementaryType => self.push_str(" "), + Style::BeforeStateVariableElementaryType => self.push_str("\n "), + + /*** Struct ***/ + Style::AfterStruct => self.push_str(" "), + Style::BeforeStruct => self.push_str("\n "), + Style::Struct => self.push_str("struct"), + Style::BeforeStructIdentifier => (), + Style::AfterStructIdentifier => self.push_str(" "), + Style::BeforeStructOpenBrace => (), + Style::StructOpenBrace => self.push_str("{"), + Style::AfterStructOpenBrace => self.push_str("\n"), + Style::BeforeStructVariableDeclaration => self.push_str(" "), + Style::Semicolon => self.push_str(";"), + Style::AfterStructVariableDeclaration => self.push_str("\n"), + Style::StructCloseBrace => self.push_str("}"), + + Style::AfterVariableDeclarationIdentifier => self.push_str(""), + Style::AfterVariableDeclarationTypeName => self.push_str(" "), + Style::BeforeVariableDeclarationIdentifier => self.push_str(""), + Style::BeforeVariableDeclarationTypeName => self.push_str(""), + + Style::BeforeUserDefinedTypeName => self.push_str(""), + Style::AfterUserDefinedTypeName => self.push_str(""), + + /*** Modifier ***/ + Style::BeforeModifier => self.push_str("\n "), + Style::Modifier => self.push_str("modifier"), + Style::AfterModifier => self.push_str(" "), + + /*** Operators ***/ + Style::Dot => self.push_str("."), _ => (), } } @@ -77,6 +176,8 @@ pub fn stylize(tree: parse_4_25::ParseTree) -> String { _ => panic!("Invalid top level tree") } } + // Add a newline at the end of the file + result.push_str("\n"); result } @@ -141,7 +242,7 @@ fn stylize_contract(contract: parse_4_25::ParseNode) -> String { _ => panic!("Invalid contract definition") } match &contract.children[1].node { - lex_4_25::Token::OpenBrace => result.push_str(&stylize_contract_part(&contract.children[1])), + lex_4_25::Token::OpenBrace => result.push_str(&stylize_contract_part(&contract.children[1], false)), _ => panic!("Invalid contract definition") } } else if contract.children.len() == 3 { @@ -158,7 +259,7 @@ fn stylize_contract(contract: parse_4_25::ParseNode) -> String { _ => panic!("Invalid contract definition") } match &contract.children[2].node { - lex_4_25::Token::OpenBrace => result.push_str(&stylize_contract_part(&contract.children[2])), + lex_4_25::Token::OpenBrace => result.push_str(&stylize_contract_part(&contract.children[2], true)), _ => panic!("Invalid contract definition") } } @@ -181,10 +282,10 @@ fn stylize_inheritance_specifier(block: &parse_4_25::ParseNode) -> String { lex_4_25::Token::OpenParenthesis => (), _ => panic!("Invalid inheritance specifier") } - for i in 0..=block.children.len() - 1 { + for i in 0..=block.children[0].children.len() - 1 { result.resolve(Style::BeforeInheritanceName); - result.push_str(&stylize_user_defined_type_name(&block.children[i].children[0])); - if i != block.children.len() - 1 { + result.push_str(&stylize_user_defined_type_name(&block.children[0].children[i])); + if i != block.children[0].children.len() - 1 { result.resolve(Style::AfterInheritanceName); } else { result.resolve(Style::AfterInheritanceNameLast); @@ -195,8 +296,19 @@ fn stylize_inheritance_specifier(block: &parse_4_25::ParseNode) -> String { /*** Contract Part ***/ -fn stylize_contract_part(block: &parse_4_25::ParseNode) -> String { +fn stylize_contract_part(block: &parse_4_25::ParseNode, is_preceded_by_inheritance: bool) -> String { let mut result = String::new(); + // Short circuit if the block contains zero children + if block.children.len() == 0 { + match block.node { + lex_4_25::Token::OpenBrace => { + result.resolve(Style::ContractPartOpenBrace); + } + _ => panic!("Invalid contract part") + } + result.resolve(Style::ContractPartCloseBrace); + return result + } result.resolve(Style::BeforeContractPartOpenBrace); match block.node { lex_4_25::Token::OpenBrace => { @@ -204,37 +316,34 @@ fn stylize_contract_part(block: &parse_4_25::ParseNode) -> String { } _ => panic!("Invalid contract part") } - if block.children.len() > 0 { - result.resolve(Style::AfterContractPartOpenBrace); - } else { - result.resolve(Style::ContractPartCloseBrace); - return result - } - for child in &block.children { - match child.node { - lex_4_25::Token::Enum => result.push_str(&stylize_enum_definition(&child)), - lex_4_25::Token::Event => result.push_str(&stylize_event_declaration(&child)), - lex_4_25::Token::Function => result.push_str(&stylize_function_definition(&child)), - lex_4_25::Token::Modifier => result.push_str(&stylize_modifier_definition(&child)), - lex_4_25::Token::Using => result.push_str(&stylize_using_for_declaration(&child)), - lex_4_25::Token::Struct => result.push_str(&stylize_struct_definition(&child)), - lex_4_25::Token::StateVariable => result.push_str(&stylize_state_variable_declaration(&child)), + result.resolve(Style::AfterContractPartOpenBrace); + for i in 0..=block.children.len() - 1 { + let after_inheritance = i == 0 && is_preceded_by_inheritance; + match &block.children[i].node { + lex_4_25::Token::Enum => result.push_str(&stylize_enum_definition(&block.children[i], is_preceded_by_inheritance)), + lex_4_25::Token::Event => result.push_str(&stylize_event_declaration(&block.children[i], is_preceded_by_inheritance)), + lex_4_25::Token::Function => result.push_str(&stylize_function_definition(&block.children[i], is_preceded_by_inheritance)), + lex_4_25::Token::Modifier => result.push_str(&stylize_modifier_definition(&block.children[i], is_preceded_by_inheritance)), + lex_4_25::Token::Using => result.push_str(&stylize_using_for_declaration(&block.children[i], is_preceded_by_inheritance)), + lex_4_25::Token::Struct => result.push_str(&stylize_struct_definition(&block.children[i], is_preceded_by_inheritance)), + lex_4_25::Token::StateVariable => result.push_str(&stylize_state_variable_declaration(&block.children[i], is_preceded_by_inheritance)), _ => panic!("Invalid contract part") } } + result.push_str("\n"); result.resolve(Style::ContractPartCloseBrace); - result.push_str("}"); result } /*** Sub-contract Structures ***/ -fn stylize_state_variable_declaration(node: &parse_4_25::ParseNode) -> String { +fn stylize_state_variable_declaration(node: &parse_4_25::ParseNode, is_preceded_by_inheritance: bool) -> String { let mut result = String::new(); - if node.children.len() < 2 { - panic!("Invalid state variable"); + if is_preceded_by_inheritance { + result.push_str("\n "); + } else { + result.push_str("\n\n "); } - result.resolve(Style::BeforeStateVariableElementaryType); result.push_str(&stylize_elementary_type(&node.children[0])); result.resolve(Style::AfterStateVariableElementaryType); let mut i = 1; @@ -258,7 +367,7 @@ fn stylize_state_variable_declaration(node: &parse_4_25::ParseNode) -> String { } i += 1; if i == node.children.len() { - result.push_str(";\n"); + result.push_str(";"); return result; } else { result.push(' '); @@ -267,7 +376,7 @@ fn stylize_state_variable_declaration(node: &parse_4_25::ParseNode) -> String { result.push_str("="); result.push_str(" "); result.push_str(&stylize_expression(&node.children[i].children[0])); - result.push_str(";\n"); + result.push_str(";"); } _ => panic!("Invalid state variable") } @@ -275,7 +384,7 @@ fn stylize_state_variable_declaration(node: &parse_4_25::ParseNode) -> String { result } -fn stylize_enum_definition(node: &parse_4_25::ParseNode) -> String { +fn stylize_enum_definition(node: &parse_4_25::ParseNode, is_preceded_by_inheritance: bool) -> String { let mut result = String::new(); match node.node { lex_4_25::Token::Enum => result.push_str("enum"), @@ -312,9 +421,8 @@ fn stylize_enum_definition(node: &parse_4_25::ParseNode) -> String { result } -fn stylize_event_declaration(node: &parse_4_25::ParseNode) -> String { +fn stylize_event_declaration(node: &parse_4_25::ParseNode, is_preceded_by_inheritance: bool) -> String { let mut result = String::new(); - result.push_str(" "); match node.node { lex_4_25::Token::Event => result.push_str("event"), _ => panic!("Invalid event definition") @@ -331,7 +439,7 @@ fn stylize_event_declaration(node: &parse_4_25::ParseNode) -> String { if node.children[1].children.len() > 0 { for i in 0..=node.children[1].children.len() - 1 { result.push('\n'); - result.push_str(" "); + result.push_str(" "); result.push_str(&stylize_event_parameter(&node.children[1].children[i])); if i != node.children[1].children.len() - 1 { result.push(','); @@ -340,9 +448,9 @@ fn stylize_event_declaration(node: &parse_4_25::ParseNode) -> String { } } } - result.push_str(" "); + result.push_str(""); result.push(')'); - result.push_str(";\n"); + result.push_str(";"); result } @@ -374,7 +482,7 @@ fn stylize_event_parameter(node: &parse_4_25::ParseNode) -> String { result } -fn stylize_function_definition(node: &parse_4_25::ParseNode) -> String { +fn stylize_function_definition(node: &parse_4_25::ParseNode, is_preceded_by_inheritance: bool) -> String { let mut result = String::new(); match node.node { lex_4_25::Token::Function => result.push_str("function"), @@ -481,9 +589,11 @@ fn stylize_block(block: &parse_4_25::ParseNode) -> String { if block.children.len() == 0 { result.push_str("}"); } else { + result.push_str("\n"); for child in &block.children { result.push_str(&stylize_statement(&child)); } + result.push_str("\n }"); } result } @@ -495,11 +605,13 @@ fn stylize_statement(statement: &parse_4_25::ParseNode) -> String { lex_4_25::Token::For => stylize_for_statement(statement), lex_4_25::Token::Assembly => stylize_inline_assembly_statement(statement), lex_4_25::Token::Do => stylize_do_while_statement(statement), - lex_4_25::Token::Placeholder => String::from("\n\n_;"), + lex_4_25::Token::Placeholder => String::from("\n _;"), lex_4_25::Token::Emit => stylize_emit_statement(statement), // TODO: This actually should be parse_variable_declaration | parse_expression _ => { - let mut result = stylize_expression(statement); + let mut result = String::from(""); + result.push_str(" "); + result.push_str(&stylize_expression(statement)); match statement.node { lex_4_25::Token::NoMatch => panic!("Invalid statement"), _ => () @@ -554,11 +666,16 @@ fn stylize_parameter(node: &parse_4_25::ParseNode) -> String { result } -fn stylize_modifier_definition(node: &parse_4_25::ParseNode) -> String { +// TODO(jalextowle): Replace style with resolve pattern +fn stylize_modifier_definition(node: &parse_4_25::ParseNode, is_preceded_by_inheritance: bool) -> String { let mut result = String::new(); + if is_preceded_by_inheritance { + result.push_str("\n "); + } else { + result.push_str("\n\n "); + } match node.node { lex_4_25::Token::Modifier => { - result.resolve(Style::BeforeModifier); result.resolve(Style::Modifier); result.resolve(Style::AfterModifier); } @@ -567,9 +684,8 @@ fn stylize_modifier_definition(node: &parse_4_25::ParseNode) -> String { if node.children.len() == 2 { match &node.children[0].node { lex_4_25::Token::Identifier(name) => { - result.resolve(Style::BeforeModifierIdentifier); result.push_str(&name); - result.resolve(Style::AfterModifierIdentifier); + result.push_str(" "); } _ => panic!("Invalid modifier definition") } @@ -577,9 +693,8 @@ fn stylize_modifier_definition(node: &parse_4_25::ParseNode) -> String { } else if node.children.len() == 3 { match &node.children[0].node { lex_4_25::Token::Identifier(name) => { - result.resolve(Style::BeforeModifierIdentifier); result.push_str(&name); - result.resolve(Style::AfterModifierIdentifier); + result.push_str(" "); } _ => panic!("Invalid modifier definition") } @@ -599,16 +714,15 @@ fn stylize_modifier_definition(node: &parse_4_25::ParseNode) -> String { } else { panic!("Invalid modifier definition"); } - result.push_str("\n"); result } -fn stylize_using_for_declaration(node: &parse_4_25::ParseNode) -> String { +fn stylize_using_for_declaration(node: &parse_4_25::ParseNode, is_preceded_by_inheritance: bool) -> String { let mut result = String::new(); result } -fn stylize_struct_definition(node: &parse_4_25::ParseNode) -> String { +fn stylize_struct_definition(node: &parse_4_25::ParseNode, is_preceded_by_inheritance: bool) -> String { let mut result = String::new(); match node.node { lex_4_25::Token::Struct => { @@ -620,17 +734,17 @@ fn stylize_struct_definition(node: &parse_4_25::ParseNode) -> String { } match &node.children[0].node { lex_4_25::Token::Identifier(name) => { - result.resolve(BeforeStructIdentifier); + result.resolve(Style::BeforeStructIdentifier); result.push_str(&name); - result.resolve(AfterStructIdentifier); + result.resolve(Style::AfterStructIdentifier); } _ => panic!("Invalid struct definition") } match &node.children[1].node { lex_4_25::Token::OpenBrace => { - result.resolve(BeforeStructOpenBrace); - result.resolve(StructOpenBrace); - result.resolve(AfterStructOpenBrace); + result.resolve(Style::BeforeStructOpenBrace); + result.resolve(Style::StructOpenBrace); + result.resolve(Style::AfterStructOpenBrace); } _ => panic!("Invalid struct definition") } @@ -866,12 +980,42 @@ fn stylize_elementary_type(elementary_type: &parse_4_25::ParseNode) -> String { fn stylize_expression(expression: &parse_4_25::ParseNode) -> String { let mut result = String::new(); - // TODO: This needs to be expanded on significantly - match expression.node { - // This should do a lookahead parse to check more of an expression + match &expression.node { + // TODO(jalextowle): Switch this to resolve instead + lex_4_25::Token::Equals => { + result.push_str(&stylize_expression(&*expression.children[0])); + result.push_str(" == "); + result.push_str(&stylize_expression(&*expression.children[1])); + } + lex_4_25::Token::Plus => { + result.push_str(&stylize_expression(&*expression.children[0])); + result.push_str(" + "); + result.push_str(&stylize_expression(&*expression.children[1])); + } + lex_4_25::Token::OpenParenthesis => { + result.push_str(&stylize_expression(&*expression.children[0])); + result.push_str("("); + result.push_str(&stylize_function_call_arguments(&*expression.children[1])); + result.push_str(")"); + } + lex_4_25::Token::Dot => { + result.push_str(&stylize_expression(&*expression.children[0])); + result.push_str("."); + result.push_str(&stylize_expression(&*expression.children[1])); + } + lex_4_25::Token::Identifier(ref name) => result.push_str(name), lex_4_25::Token::DecimalNumber(ref number) => result.push_str(number), lex_4_25::Token::HexNumber(ref number) => result.push_str(number), - _ => panic!("Invalid expression") + // TODO: Change Me! + actual => panic!("Invalid expression {:#?}", actual) + } + result +} + +fn stylize_function_call_arguments(arguments: &parse_4_25::ParseNode) -> String { + let mut result = String::new(); + for i in 0..=arguments.children.len() - 1 { + result.push_str(&stylize_expression(&*arguments.children[i])); } result } @@ -896,7 +1040,7 @@ mod tests { ] }; let actual_stylized = stylize(tree); - let expected_stylized = "pragma solidity 0.4.25;"; + let expected_stylized = "pragma solidity 0.4.25;\n"; assert_eq!(expected_stylized, actual_stylized); } @@ -919,8 +1063,8 @@ mod tests { ] }; let actual_stylized = stylize_inheritance_specifier(&node); - let expected_stylized = "is\n A\n"; - assert_eq!(actual_stylized, expected_stylized); + let expected_stylized = " is\n A\n"; + assert_eq!(expected_stylized, actual_stylized); } #[test] @@ -949,7 +1093,7 @@ mod tests { ] }; let actual_stylized = stylize_inheritance_specifier(&node); - let expected_stylized = "is\n A,\n Bat.Car\n"; + let expected_stylized = " is\n A,\n Bat.Car\n"; assert_eq!(actual_stylized, expected_stylized); } @@ -987,8 +1131,8 @@ mod tests { ] }; let actual_stylized = stylize_inheritance_specifier(&node); - let expected_stylized = "is\n A,\n Bat.Car,\n foo.bar.baz\n"; - assert_eq!(actual_stylized, expected_stylized); + let expected_stylized = " is\n A,\n Bat.Car,\n foo.bar.baz\n"; + assert_eq!(expected_stylized, actual_stylized); } #[test] @@ -1000,8 +1144,8 @@ mod tests { Box::new(lex_4_25::Token::Identifier("nothing".to_string()).to_leaf()), ] }; - let actual_stylized = stylize_state_variable_declaration(&node); - let expected_stylized = String::from("\n uint256 nothing;"); + let actual_stylized = stylize_state_variable_declaration(&node, false); + let expected_stylized = String::from("\n\n uint256 nothing;"); assert_eq!(expected_stylized, actual_stylized); } @@ -1020,8 +1164,8 @@ mod tests { }) ] }; - let actual_stylized = stylize_state_variable_declaration(&node); - let expected_stylized = String::from("\n uint256 total_supply = 10;"); + let actual_stylized = stylize_state_variable_declaration(&node, false); + let expected_stylized = String::from("\n\n uint256 total_supply = 10;"); assert_eq!(expected_stylized, actual_stylized); } @@ -1034,7 +1178,7 @@ mod tests { Box::new(lex_4_25::Token::OpenBrace.to_leaf()) ] }; - let actual_stylized = stylize_enum_definition(&node); + let actual_stylized = stylize_enum_definition(&node, false); let expected_stylized = String::from("enum empty {}"); assert_eq!(expected_stylized, actual_stylized); } @@ -1055,7 +1199,7 @@ mod tests { }) ] }; - let actual_stylized = stylize_enum_definition(&node); + let actual_stylized = stylize_enum_definition(&node, false); let expected_stylized = String::from("enum Letters {\n A,\n B,\n C\n}"); assert_eq!(expected_stylized, actual_stylized); } @@ -1069,7 +1213,7 @@ mod tests { Box::new(lex_4_25::Token::OpenParenthesis.to_leaf()) ] }; - let actual_stylized = stylize_event_declaration(&node); + let actual_stylized = stylize_event_declaration(&node, false); let expected_stylized = "event empty();"; } @@ -1110,7 +1254,7 @@ mod tests { }) ] }; - let actual_stylized = stylize_event_declaration(&node); + let actual_stylized = stylize_event_declaration(&node, false); let expected_stylized = "event Transfer(\n address indexed owner,\n address indexed recipient,\n uint256 indexed value\n);"; assert_eq!(expected_stylized, actual_stylized); } @@ -1135,8 +1279,8 @@ mod tests { }) ] }; - let actual_stylized = stylize_struct_definition(&node); - let expected_stylized = "struct Value {\n uint256 value;\n}"; + let actual_stylized = stylize_struct_definition(&node, false); + let expected_stylized = "\n struct Value {\n uint256 value;\n}"; assert_eq!(expected_stylized, actual_stylized); } diff --git a/tests/style_integration_tests.rs b/tests/style_integration_tests.rs index a63ee54..9d29776 100644 --- a/tests/style_integration_tests.rs +++ b/tests/style_integration_tests.rs @@ -8,7 +8,7 @@ mod style_integration_tests { use std::fs; #[test] - fn empty_style_test() { + fn empty_style_test() { let input = fs::read_to_string("./contracts/BadEmpty.sol") .expect("Test file not found: ./contracts/BadEmpty.sol"); let expected = fs::read_to_string("./contracts/Empty.sol") @@ -18,7 +18,7 @@ mod style_integration_tests { } #[test] - fn value_style_test() { + fn value_style_test() { let input = fs::read_to_string("./contracts/BadValue.sol") .expect("Test file not found: ./contracts/BadValue.sol"); let expected = fs::read_to_string("./contracts/Value.sol") @@ -28,7 +28,7 @@ mod style_integration_tests { } #[test] - fn ownable_style_test() { + fn ownable_style_test() { let input = fs::read_to_string("./contracts/BadOwnable.sol") .expect("Test file not found: ./contracts/BadOwnable.sol"); let expected = fs::read_to_string("./contracts/Ownable.sol")