From b01c62e53425a1054aeb7f2690b19f2362a11c1e Mon Sep 17 00:00:00 2001 From: Camden Smallwood Date: Fri, 9 Jun 2023 12:31:00 -0400 Subject: [PATCH] Add yul function definitions, some cleanup --- solidity/src/ast/builder.rs | 69 ++++++++++-- solidity/src/ast/visitor.rs | 205 ++++++++++++++++++++++++++++++++++++ yul/src/ast/mod.rs | 17 +++ 3 files changed, 282 insertions(+), 9 deletions(-) diff --git a/solidity/src/ast/builder.rs b/solidity/src/ast/builder.rs index 1e77234..5e5d47e 100644 --- a/solidity/src/ast/builder.rs +++ b/solidity/src/ast/builder.rs @@ -662,10 +662,10 @@ impl AstBuilder { pub fn build_user_defined_value_type_definition(&mut self, input: &solang_parser::pt::TypeDefinition) -> UserDefinedValueTypeDefinition { UserDefinedValueTypeDefinition { - underlying_type: todo!(), - name: todo!(), - name_location: todo!(), - canonical_name: todo!(), + underlying_type: self.build_type_name(&input.ty), + name: input.name.name.clone(), + name_location: Some(self.loc_to_src(&input.name.loc)), + canonical_name: None, // TODO src: self.loc_to_src(&input.loc), id: self.next_node_id(), } @@ -1534,6 +1534,30 @@ impl AstBuilder { } } + pub fn build_index_range_access( + &mut self, + loc: &solang_parser::pt::Loc, + array: &solang_parser::pt::Expression, + start: Option<&solang_parser::pt::Expression>, + end: Option<&solang_parser::pt::Expression>, + ) -> IndexRangeAccess { + IndexRangeAccess { + base_expression: Box::new(self.build_expression(array)), + start_expression: start.as_ref().map(|x| Box::new(self.build_expression(x))), + end_expression: end.as_ref().map(|x| Box::new(self.build_expression(x))), + is_constant: false, // TODO + is_l_value: false, // TODO + is_pure: false, // TODO + l_value_requested: false, // TODO + type_descriptions: TypeDescriptions { + type_identifier: None, // TODO + type_string: None, // TODO + }, + src: self.loc_to_src(loc), + id: self.next_node_id(), + } + } + pub fn build_expression(&mut self, input: &solang_parser::pt::Expression) -> Expression { match input { solang_parser::pt::Expression::PostIncrement(loc, x) => { @@ -1552,7 +1576,9 @@ impl AstBuilder { Expression::IndexAccess(self.build_index_access(loc, array, index.as_ref().unwrap())) } - solang_parser::pt::Expression::ArraySlice(_, _, _, _) => todo!(), + solang_parser::pt::Expression::ArraySlice(loc, array, start, end) => { + Expression::IndexRangeAccess(self.build_index_range_access(loc, array, start.as_ref().map(|x| x.as_ref()), end.as_ref().map(|x| x.as_ref()))) + } solang_parser::pt::Expression::Parenthesis(_, expression) => { self.build_expression(expression) @@ -1862,11 +1888,23 @@ impl AstBuilder { YulStatement::YulSwitch(self.build_yul_switch(switch)) } - solang_parser::pt::YulStatement::Leave(_) => todo!(), - solang_parser::pt::YulStatement::Break(_) => todo!(), - solang_parser::pt::YulStatement::Continue(_) => todo!(), + solang_parser::pt::YulStatement::Leave(_) => { + YulStatement::YulLeave + } + + solang_parser::pt::YulStatement::Break(_) => { + YulStatement::YulBreak + } + + solang_parser::pt::YulStatement::Continue(_) => { + YulStatement::YulContinue + } + solang_parser::pt::YulStatement::Block(_) => todo!(), - solang_parser::pt::YulStatement::FunctionDefinition(_) => todo!(), + + solang_parser::pt::YulStatement::FunctionDefinition(function) => { + YulStatement::YulFunctionDefinition(self.build_yul_function_definition(function)) + } solang_parser::pt::YulStatement::FunctionCall(call) => { YulStatement::YulExpressionStatement(YulExpressionStatement { @@ -1949,6 +1987,19 @@ impl AstBuilder { } } + pub fn build_yul_function_definition(&mut self, function: &solang_parser::pt::YulFunctionDefinition) -> YulFunctionDefinition { + YulFunctionDefinition { + name: function.id.name.clone(), + parameters: function.params.iter() + .map(|param| self.build_yul_typed_name(param)) + .collect(), + return_parameters: function.returns.iter() + .map(|param| self.build_yul_typed_name(param)) + .collect(), + body: self.build_yul_block(&function.body), + } + } + pub fn build_yul_expression(&mut self, expression: &solang_parser::pt::YulExpression) -> YulExpression { match expression { solang_parser::pt::YulExpression::BoolLiteral(_, value, _) => YulExpression::YulLiteral(YulLiteral { diff --git a/solidity/src/ast/visitor.rs b/solidity/src/ast/visitor.rs index aa826ac..707870e 100644 --- a/solidity/src/ast/visitor.rs +++ b/solidity/src/ast/visitor.rs @@ -118,6 +118,32 @@ pub struct YulExpressionStatementContext<'a, 'b, 'c> { pub yul_expression_statement: &'a YulExpressionStatement, } +pub struct YulFunctionDefinitionContext<'a, 'b, 'c> { + pub source_units: &'a [SourceUnit], + pub current_source_unit: &'a SourceUnit, + pub contract_definition: &'a ContractDefinition, + pub definition_node: &'a ContractDefinitionNode, + pub blocks: &'b mut Vec<&'a Block>, + pub statement: &'a Statement, + pub inline_assembly: &'a InlineAssembly, + pub yul_blocks: &'c mut Vec<&'a YulBlock>, + pub yul_statement: &'a YulStatement, + pub yul_function_definition: &'a YulFunctionDefinition, +} + +pub struct YulTypedNameContext<'a, 'b, 'c> { + pub source_units: &'a [SourceUnit], + pub current_source_unit: &'a SourceUnit, + pub contract_definition: &'a ContractDefinition, + pub definition_node: &'a ContractDefinitionNode, + pub blocks: &'b mut Vec<&'a Block>, + pub statement: &'a Statement, + pub inline_assembly: &'a InlineAssembly, + pub yul_blocks: &'c mut Vec<&'a YulBlock>, + pub yul_statement: Option<&'a YulStatement>, + pub yul_typed_name: &'a YulTypedName, +} + pub struct YulExpressionContext<'a, 'b, 'c> { pub source_units: &'a [SourceUnit], pub current_source_unit: &'a SourceUnit, @@ -337,6 +363,21 @@ pub trait AstVisitor { fn visit_yul_expression_statement<'a, 'b, 'c>(&mut self, context: &mut YulExpressionStatementContext<'a, 'b, 'c>) -> io::Result<()> { Ok(()) } fn leave_yul_expression_statement<'a, 'b, 'c>(&mut self, context: &mut YulExpressionStatementContext<'a, 'b, 'c>) -> io::Result<()> { Ok(()) } + fn visit_yul_function_definition<'a, 'b, 'c>(&mut self, context: &mut YulFunctionDefinitionContext<'a, 'b, 'c>) -> io::Result<()> { Ok(()) } + fn leave_yul_function_definition<'a, 'b, 'c>(&mut self, context: &mut YulFunctionDefinitionContext<'a, 'b, 'c>) -> io::Result<()> { Ok(()) } + + fn visit_yul_leave<'a, 'b, 'c>(&mut self, context: &mut YulStatementContext<'a, 'b, 'c>) -> io::Result<()> { Ok(()) } + fn leave_yul_leave<'a, 'b, 'c>(&mut self, context: &mut YulStatementContext<'a, 'b, 'c>) -> io::Result<()> { Ok(()) } + + fn visit_yul_break<'a, 'b, 'c>(&mut self, context: &mut YulStatementContext<'a, 'b, 'c>) -> io::Result<()> { Ok(()) } + fn leave_yul_break<'a, 'b, 'c>(&mut self, context: &mut YulStatementContext<'a, 'b, 'c>) -> io::Result<()> { Ok(()) } + + fn visit_yul_continue<'a, 'b, 'c>(&mut self, context: &mut YulStatementContext<'a, 'b, 'c>) -> io::Result<()> { Ok(()) } + fn leave_yul_continue<'a, 'b, 'c>(&mut self, context: &mut YulStatementContext<'a, 'b, 'c>) -> io::Result<()> { Ok(()) } + + fn visit_yul_typed_name<'a, 'b, 'c>(&mut self, context: &mut YulTypedNameContext<'a, 'b, 'c>) -> io::Result<()> { Ok(()) } + fn leave_yul_typed_name<'a, 'b, 'c>(&mut self, context: &mut YulTypedNameContext<'a, 'b, 'c>) -> io::Result<()> { Ok(()) } + fn visit_yul_expression<'a, 'b, 'c>(&mut self, context: &mut YulExpressionContext<'a, 'b, 'c>) -> io::Result<()> { Ok(()) } fn leave_yul_expression<'a, 'b, 'c>(&mut self, context: &mut YulExpressionContext<'a, 'b, 'c>) -> io::Result<()> { Ok(()) } @@ -2306,6 +2347,39 @@ impl AstVisitor for AstVisitorData<'_> { self.visit_yul_expression_statement(&mut context)?; self.leave_yul_expression_statement(&mut context)?; } + + YulStatement::YulFunctionDefinition(yul_function_definition) => { + let mut context = YulFunctionDefinitionContext { + source_units: context.source_units, + current_source_unit: context.current_source_unit, + contract_definition: context.contract_definition, + definition_node: context.definition_node, + blocks: context.blocks, + statement: context.statement, + inline_assembly: context.inline_assembly, + yul_blocks: context.yul_blocks, + yul_statement: context.yul_statement, + yul_function_definition, + }; + + self.visit_yul_function_definition(&mut context)?; + self.leave_yul_function_definition(&mut context)?; + } + + YulStatement::YulLeave => { + self.visit_yul_leave(context)?; + self.leave_yul_leave(context)?; + } + + YulStatement::YulBreak => { + self.visit_yul_break(context)?; + self.leave_yul_break(context)?; + } + + YulStatement::YulContinue => { + self.visit_yul_continue(context)?; + self.leave_yul_continue(context)?; + } } Ok(()) @@ -2624,6 +2698,22 @@ impl AstVisitor for AstVisitorData<'_> { Ok(()) } + fn visit_yul_typed_name<'a, 'b, 'c>(&mut self, context: &mut YulTypedNameContext<'a, 'b, 'c>) -> io::Result<()> { + for visitor in self.visitors.iter_mut() { + visitor.visit_yul_typed_name(context)?; + } + + Ok(()) + } + + fn leave_yul_typed_name<'a, 'b, 'c>(&mut self, context: &mut YulTypedNameContext<'a, 'b, 'c>) -> io::Result<()> { + for visitor in self.visitors.iter_mut() { + visitor.leave_yul_typed_name(context)?; + } + + Ok(()) + } + fn visit_yul_expression_statement<'a, 'b, 'c>(&mut self, context: &mut YulExpressionStatementContext<'a, 'b, 'c>) -> io::Result<()> { for visitor in self.visitors.iter_mut() { visitor.visit_yul_expression_statement(context)?; @@ -2656,6 +2746,121 @@ impl AstVisitor for AstVisitorData<'_> { Ok(()) } + fn visit_yul_function_definition<'a, 'b, 'c>(&mut self, context: &mut YulFunctionDefinitionContext<'a, 'b, 'c>) -> io::Result<()> { + for visitor in self.visitors.iter_mut() { + visitor.visit_yul_function_definition(context)?; + } + + for parameter in context.yul_function_definition.parameters.iter() { + let mut context = YulTypedNameContext { + source_units: context.source_units, + current_source_unit: context.current_source_unit, + contract_definition: context.contract_definition, + definition_node: context.definition_node, + blocks: context.blocks, + statement: context.statement, + inline_assembly: context.inline_assembly, + yul_blocks: context.yul_blocks, + yul_statement: Some(context.yul_statement), + yul_typed_name: parameter, + }; + + self.visit_yul_typed_name(&mut context)?; + self.leave_yul_typed_name(&mut context)?; + } + + for parameter in context.yul_function_definition.return_parameters.iter() { + let mut context = YulTypedNameContext { + source_units: context.source_units, + current_source_unit: context.current_source_unit, + contract_definition: context.contract_definition, + definition_node: context.definition_node, + blocks: context.blocks, + statement: context.statement, + inline_assembly: context.inline_assembly, + yul_blocks: context.yul_blocks, + yul_statement: Some(context.yul_statement), + yul_typed_name: parameter, + }; + + self.visit_yul_typed_name(&mut context)?; + self.leave_yul_typed_name(&mut context)?; + } + + let mut context = YulBlockContext { + source_units: context.source_units, + current_source_unit: context.current_source_unit, + contract_definition: context.contract_definition, + definition_node: context.definition_node, + blocks: context.blocks, + statement: context.statement, + inline_assembly: context.inline_assembly, + yul_blocks: context.yul_blocks, + yul_block: &context.yul_function_definition.body, + }; + + self.visit_yul_block(&mut context)?; + self.leave_yul_block(&mut context)?; + + Ok(()) + } + + fn leave_yul_function_definition<'a, 'b, 'c>(&mut self, context: &mut YulFunctionDefinitionContext<'a, 'b, 'c>) -> io::Result<()> { + for visitor in self.visitors.iter_mut() { + visitor.leave_yul_function_definition(context)?; + } + + Ok(()) + } + + fn visit_yul_leave<'a, 'b, 'c>(&mut self, context: &mut YulStatementContext<'a, 'b, 'c>) -> io::Result<()> { + for visitor in self.visitors.iter_mut() { + visitor.visit_yul_leave(context)?; + } + + Ok(()) + } + + fn leave_yul_leave<'a, 'b, 'c>(&mut self, context: &mut YulStatementContext<'a, 'b, 'c>) -> io::Result<()> { + for visitor in self.visitors.iter_mut() { + visitor.leave_yul_leave(context)?; + } + + Ok(()) + } + + fn visit_yul_break<'a, 'b, 'c>(&mut self, context: &mut YulStatementContext<'a, 'b, 'c>) -> io::Result<()> { + for visitor in self.visitors.iter_mut() { + visitor.visit_yul_break(context)?; + } + + Ok(()) + } + + fn leave_yul_break<'a, 'b, 'c>(&mut self, context: &mut YulStatementContext<'a, 'b, 'c>) -> io::Result<()> { + for visitor in self.visitors.iter_mut() { + visitor.leave_yul_break(context)?; + } + + Ok(()) + } + + fn visit_yul_continue<'a, 'b, 'c>(&mut self, context: &mut YulStatementContext<'a, 'b, 'c>) -> io::Result<()> { + for visitor in self.visitors.iter_mut() { + visitor.visit_yul_continue(context)?; + } + + Ok(()) + } + + fn leave_yul_continue<'a, 'b, 'c>(&mut self, context: &mut YulStatementContext<'a, 'b, 'c>) -> io::Result<()> { + for visitor in self.visitors.iter_mut() { + visitor.leave_yul_continue(context)?; + } + + Ok(()) + } + fn visit_yul_expression<'a, 'b, 'c>(&mut self, context: &mut YulExpressionContext<'a, 'b, 'c>) -> io::Result<()> { for visitor in self.visitors.iter_mut() { visitor.visit_yul_expression(context)?; diff --git a/yul/src/ast/mod.rs b/yul/src/ast/mod.rs index 7676428..8215748 100644 --- a/yul/src/ast/mod.rs +++ b/yul/src/ast/mod.rs @@ -85,6 +85,10 @@ pub enum YulStatement { YulAssignment(YulAssignment), YulVariableDeclaration(YulVariableDeclaration), YulExpressionStatement(YulExpressionStatement), + YulFunctionDefinition(YulFunctionDefinition), + YulLeave, + YulBreak, + YulContinue, } impl<'de> Deserialize<'de> for YulStatement { @@ -99,6 +103,10 @@ impl<'de> Deserialize<'de> for YulStatement { "YulAssignment" => Ok(YulStatement::YulAssignment(serde_json::from_value(json).unwrap())), "YulVariableDeclaration" => Ok(YulStatement::YulVariableDeclaration(serde_json::from_value(json).unwrap())), "YulExpressionStatement" => Ok(YulStatement::YulExpressionStatement(serde_json::from_value(json).unwrap())), + "YulFunctionDefinition" => Ok(YulStatement::YulFunctionDefinition(serde_json::from_value(json).unwrap())), + "YulLeave" => Ok(YulStatement::YulLeave), + "YulBreak" => Ok(YulStatement::YulBreak), + "YulContinue" => Ok(YulStatement::YulContinue), _ => panic!("Invalid yul statement node type: {node_type}"), } } @@ -160,3 +168,12 @@ pub struct YulTypedName { pub struct YulExpressionStatement { pub expression: YulExpression, } + +#[derive(Clone, Debug, Deserialize, Eq, Serialize, PartialEq)] +#[serde(rename_all = "camelCase")] +pub struct YulFunctionDefinition { + pub name: String, + pub parameters: Vec, + pub return_parameters: Vec, + pub body: YulBlock, +}