Skip to content

Commit

Permalink
Merge branch 'main' into az-cpr-1727-implement-the-ipfs-hash-algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
hedgar2017 committed Sep 3, 2024
2 parents 8d6a8d0 + ea067e5 commit b97fae7
Show file tree
Hide file tree
Showing 80 changed files with 4,020 additions and 2,337 deletions.
11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[workspace]
members = [
"era-compiler-solidity",
"era-yul",
]
resolver = "2"

Expand Down
1 change: 1 addition & 0 deletions era-compiler-solidity/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ sha3 = "0.10"

era-compiler-common = { git = "https://github.com/matter-labs/era-compiler-common", branch = "main" }
era-compiler-llvm-context = { git = "https://github.com/matter-labs/era-compiler-llvm-context", branch = "az-cpr-1727-implement-the-ipfs-hash-algorithm" }
era-yul = { path = "../era-yul" }

[dev-dependencies]
assert_cmd = "2.0.16"
Expand Down
8 changes: 5 additions & 3 deletions era-compiler-solidity/src/project/contract/ir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ use std::collections::HashSet;

use crate::evmla::assembly::Assembly;
use crate::solc::standard_json::output::contract::evm::extra_metadata::ExtraMetadata;
use crate::yul::parser::statement::object::Object;
use crate::yul::parser::dialect::era::EraDialect;
use crate::yul::parser::wrapper::Wrap;
use era_yul::yul::parser::statement::object::Object;

use self::eravm_assembly::EraVMAssembly;
use self::evmla::EVMLA;
Expand All @@ -37,8 +39,8 @@ impl IR {
///
/// A shortcut constructor.
///
pub fn new_yul(object: Object) -> Self {
Self::Yul(Yul::new(object))
pub fn new_yul(object: Object<EraDialect>) -> Self {
Self::Yul(Yul::new(object.wrap()))
}

///
Expand Down
13 changes: 7 additions & 6 deletions era-compiler-solidity/src/project/contract/ir/yul.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,38 @@

use std::collections::HashSet;

use crate::yul::parser::statement::object::Object;
use crate::yul::parser::dialect::era::EraDialect;
use era_yul::yul::parser::statement::object::Object;

///
/// The contract Yul source code.
///
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct Yul {
/// The Yul AST object.
pub object: Object,
pub object: crate::yul::parser::statement::object::Object,
}

impl Yul {
///
/// A shortcut constructor.
///
pub fn new(object: Object) -> Self {
pub fn new(object: crate::yul::parser::statement::object::Object) -> Self {
Self { object }
}

///
/// Extracts the runtime code from the Yul object.
///
pub fn take_runtime_code(&mut self) -> Option<Object> {
self.object.inner_object.take().map(|object| *object)
pub fn take_runtime_code(&mut self) -> Option<Object<EraDialect>> {
self.object.0.inner_object.take().map(|object| *object)
}

///
/// Get the list of missing deployable libraries.
///
pub fn get_missing_libraries(&self) -> HashSet<String> {
self.object.get_missing_libraries()
self.object.0.get_missing_libraries()
}
}

Expand Down
12 changes: 9 additions & 3 deletions era-compiler-solidity/src/project/contract/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use crate::build_eravm::contract::Contract as EraVMContractBuild;
use crate::build_evm::contract::Contract as EVMContractBuild;
use crate::process::input_eravm::dependency_data::DependencyData as EraVMProcessInputDependencyData;
use crate::process::input_evm::dependency_data::DependencyData as EVMProcessInputDependencyData;
use crate::yul::parser::wrapper::Wrap;

use self::factory_dependency::FactoryDependency;
use self::ir::IR;
Expand Down Expand Up @@ -52,7 +53,7 @@ impl Contract {
///
pub fn identifier(&self) -> &str {
match self.ir {
IR::Yul(ref yul) => yul.object.identifier.as_str(),
IR::Yul(ref yul) => yul.object.0.identifier.as_str(),
IR::EVMLA(ref evm) => evm.assembly.full_path(),
IR::LLVMIR(ref llvm_ir) => llvm_ir.path.as_str(),
IR::EraVMAssembly(ref eravm_assembly) => eravm_assembly.path.as_str(),
Expand Down Expand Up @@ -252,7 +253,10 @@ impl Contract {
era_compiler_llvm_context::EVMBuild,
>; 2] = [
(era_compiler_llvm_context::CodeType::Deploy, deploy_code),
(era_compiler_llvm_context::CodeType::Runtime, runtime_code),
(
era_compiler_llvm_context::CodeType::Runtime,
runtime_code.wrap(),
),
]
.into_iter()
.map(|(code_type, mut code)| {
Expand Down Expand Up @@ -401,6 +405,7 @@ impl FactoryDependency for Contract {
match self.ir {
IR::Yul(ref yul) => yul
.object
.0
.factory_dependencies
.iter()
.map(|path| path.as_str())
Expand All @@ -418,7 +423,7 @@ impl FactoryDependency for Contract {

fn drain_factory_dependencies(&mut self) -> HashSet<String> {
match self.ir {
IR::Yul(ref mut yul) => yul.object.factory_dependencies.drain().collect(),
IR::Yul(ref mut yul) => yul.object.0.factory_dependencies.drain().collect(),
IR::EVMLA(ref mut evm) => evm.assembly.factory_dependencies.drain().collect(),
IR::LLVMIR(_) => HashSet::new(),
IR::EraVMAssembly(_) => HashSet::new(),
Expand All @@ -436,6 +441,7 @@ impl FactoryDependency for Contract {
match self.ir {
IR::Yul(ref yul) => yul
.object
.0
.factory_dependencies
.iter()
.map(|identifier| {
Expand Down
4 changes: 2 additions & 2 deletions era-compiler-solidity/src/project/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ use crate::solc::standard_json::output::error::Error as SolcStandardJsonOutputEr
use crate::solc::standard_json::output::Output as SolcStandardJsonOutput;
use crate::solc::version::Version as SolcVersion;
use crate::solc::Compiler as SolcCompiler;
use crate::yul::lexer::Lexer;
use crate::yul::parser::statement::object::Object;
use era_yul::yul::lexer::Lexer;
use era_yul::yul::parser::statement::object::Object;

use self::contract::ir::IR as ContractIR;
use self::contract::Contract;
Expand Down
2 changes: 0 additions & 2 deletions era-compiler-solidity/src/yul/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,4 @@
//! The Yul IR compiling tools.
//!

pub mod error;
pub mod lexer;
pub mod parser;
140 changes: 140 additions & 0 deletions era-compiler-solidity/src/yul/parser/dialect/era/attributes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
//!
//! Parser of LLVM attributes encoded in the function identifier.
//!

use std::collections::BTreeSet;

use era_yul::yul::error::Error as YulError;
use era_yul::yul::parser::error::Error as ParserError;
use era_yul::yul::parser::identifier::Identifier;

/// The LLVM attribute section prefix.
pub const LLVM_ATTRIBUTE_PREFIX: &str = "$llvm_";

/// The LLVM attribute section suffix.
pub const LLVM_ATTRIBUTE_SUFFIX: &str = "_llvm$";

///
/// Gets the list of LLVM attributes provided in the function name.
///
pub(crate) fn get_llvm_attributes(
identifier: &Identifier,
) -> Result<BTreeSet<era_compiler_llvm_context::Attribute>, YulError> {
let mut valid_attributes = BTreeSet::new();

let llvm_begin = identifier.inner.find(LLVM_ATTRIBUTE_PREFIX);
let llvm_end = identifier.inner.find(LLVM_ATTRIBUTE_SUFFIX);
let attribute_string = if let (Some(llvm_begin), Some(llvm_end)) = (llvm_begin, llvm_end) {
if llvm_begin < llvm_end {
&identifier.inner[llvm_begin + LLVM_ATTRIBUTE_PREFIX.len()..llvm_end]
} else {
return Ok(valid_attributes);
}
} else {
return Ok(valid_attributes);
};

let mut invalid_attributes = BTreeSet::new();
for value in attribute_string.split('_') {
match era_compiler_llvm_context::Attribute::try_from(value) {
Ok(attribute) => valid_attributes.insert(attribute),
Err(value) => invalid_attributes.insert(value),
};
}

if !invalid_attributes.is_empty() {
return Err(ParserError::InvalidAttributes {
location: identifier.location,
values: invalid_attributes,
}
.into());
}

Ok(valid_attributes)
}

#[cfg(test)]
mod tests {
use std::collections::BTreeSet;

use era_yul::yul::error::Error as YulError;
use era_yul::yul::lexer::token::location::Location;
use era_yul::yul::parser::error::Error as ParserError;
use era_yul::yul::parser::identifier::Identifier;

use super::get_llvm_attributes;

fn identifier_of(name: &str) -> Identifier {
Identifier {
location: Location { line: 0, column: 0 },
inner: name.to_string(),
r#type: None,
}
}

fn attribute_helper(s: &&str) -> era_compiler_llvm_context::Attribute {
era_compiler_llvm_context::Attribute::try_from(*s).expect(
"Internal error in test: trying to create an instance of `era_compiler_llvm_context::Attribute` from an invalid string representation.",
)
}
fn immediate_attributes(
representations: &[&str],
) -> BTreeSet<era_compiler_llvm_context::Attribute> {
representations.iter().map(attribute_helper).collect()
}

#[test]
fn parse_single_attribute() {
let input = r#"
$llvm_Hot_llvm$
"#;
let expected = immediate_attributes(&["Hot"]);
let result = get_llvm_attributes(&identifier_of(input)).unwrap_or_else(|_| {
panic!(
"LLVM attribute parser should be able to parse a valid input: \"{}\"",
input
)
});
assert_eq!(result, expected)
}

#[test]
fn parse_multiple_attributes() {
let input = r#"
$llvm_Hot_Cold_MinSize_llvm$
"#;
let expected = immediate_attributes(&["Cold", "Hot", "MinSize"]);
let result = get_llvm_attributes(&identifier_of(input)).unwrap_or_else(|_| {
panic!(
"LLVM attribute parser should be able to parse a valid input: \"{}\"",
input
)
});
assert_eq!(result, expected)
}
#[test]
fn parse_malformed_attributes() {
let input = r#"
$llvm____*&@_llvm$
"#;
get_llvm_attributes(&identifier_of(input)).expect_err(&format!(
"LLVM attributes parser should not parse attributes from the malformed input \"{}\"",
input
));
}

#[test]
fn parse_invalid_attributes() {
let input = r#"
$llvm_Hot_Cold_MinSize_BogusAttr_llvm$
"#;

let values = BTreeSet::from(["BogusAttr".into()]);
let location = Location { line: 0, column: 0 };
let expected = YulError::Parser(ParserError::InvalidAttributes { location, values });
let result = get_llvm_attributes(&identifier_of(input))
.expect_err("LLVM attributes parser should not mask unknown attributes");

assert_eq!(result, expected);
}
}
69 changes: 69 additions & 0 deletions era-compiler-solidity/src/yul/parser/dialect/era/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
//!
//! LLVM-specific part of the parser.
//!

pub mod attributes;

use std::collections::BTreeSet;

use era_yul::yul::error::Error;
use era_yul::yul::lexer::token::location::Location;
use era_yul::yul::lexer::Lexer;
use era_yul::yul::parser::error::Error as ParserError;
use era_yul::yul::parser::identifier::Identifier;

use self::attributes::get_llvm_attributes;

use era_yul::yul::parser::dialect::Dialect;

/// Era-specific part of the parser.
#[derive(serde::Serialize, serde::Deserialize, PartialEq, Eq, Clone, Debug)]
pub struct EraDialect {}

impl Dialect for EraDialect {
type FunctionAttribute = era_compiler_llvm_context::Attribute;

fn extract_attributes(
identifier: &Identifier,
_: &mut Lexer,
) -> Result<BTreeSet<Self::FunctionAttribute>, era_yul::yul::error::Error> {
get_llvm_attributes(identifier)
}

fn sanitize_function(
identifier: &Identifier,
arguments: &mut Vec<Identifier>,
location: Location,
_lexer: &mut Lexer,
) -> Result<(), Error> {
if identifier
.inner
.contains(era_compiler_llvm_context::EraVMFunction::ZKSYNC_NEAR_CALL_ABI_PREFIX)
{
if arguments.is_empty() {
return Err(ParserError::InvalidNumberOfArguments {
location,
identifier: identifier.inner.clone(),
expected: 1,
found: arguments.len(),
}
.into());
}

arguments.remove(0);
}
if identifier.inner.contains(
era_compiler_llvm_context::EraVMFunction::ZKSYNC_NEAR_CALL_ABI_EXCEPTION_HANDLER,
) && !arguments.is_empty()
{
return Err(ParserError::InvalidNumberOfArguments {
location,
identifier: identifier.inner.clone(),
expected: 0,
found: arguments.len(),
}
.into());
}
Ok(())
}
}
Loading

0 comments on commit b97fae7

Please sign in to comment.