Skip to content

Commit 8ff9082

Browse files
committed
wip
Signed-off-by: Cyrill Leutwiler <[email protected]>
1 parent 1a2344c commit 8ff9082

File tree

12 files changed

+221
-123
lines changed

12 files changed

+221
-123
lines changed

Cargo.lock

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ tar = "0.4"
7171
toml = "0.8"
7272
assert_cmd = "2.0"
7373
assert_fs = "1.1"
74+
normpath = "1.3"
7475

7576
# polkadot-sdk and friends
7677
codec = { version = "3.7.5", default-features = false, package = "parity-scale-codec" }

crates/resolc/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ serde = { workspace = true }
3030
serde_json = { workspace = true }
3131
sha3 = { workspace = true }
3232
which = { workspace = true }
33+
normpath = { workspace = true }
3334

3435
revive-common = { workspace = true }
3536
revive-llvm-context = { workspace = true }

crates/resolc/src/build/contract.rs

Lines changed: 17 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use std::collections::BTreeSet;
55
use std::fs::File;
66
use std::io::Write;
77
use std::path::Path;
8+
use std::path::PathBuf;
89

910
use revive_solc_json_interface::CombinedJsonContract;
1011
use revive_solc_json_interface::SolcStandardJsonOutputContract;
@@ -14,10 +15,8 @@ use serde::Serialize;
1415
/// The Solidity contract build.
1516
#[derive(Debug, Serialize, Deserialize)]
1617
pub struct Contract {
17-
/// The contract path.
18-
pub path: String,
19-
/// The auxiliary identifier. Used to identify Yul objects.
20-
pub identifier: String,
18+
/// The contract identifier.
19+
pub identifier: revive_common::ContractIdentifier,
2120
/// The LLVM module build.
2221
pub build: revive_llvm_context::PolkaVMBuild,
2322
/// The metadata JSON.
@@ -35,16 +34,14 @@ pub struct Contract {
3534
impl Contract {
3635
/// A shortcut constructor.
3736
pub fn new(
38-
path: String,
39-
identifier: String,
37+
identifier: revive_common::ContractIdentifier,
4038
build: revive_llvm_context::PolkaVMBuild,
4139
metadata_json: serde_json::Value,
4240
missing_libraries: BTreeSet<String>,
4341
factory_dependencies: BTreeSet<String>,
4442
object_format: revive_common::ObjectFormat,
4543
) -> Self {
4644
Self {
47-
path,
4845
identifier,
4946
build,
5047
metadata_json,
@@ -63,14 +60,15 @@ impl Contract {
6360
output_binary: bool,
6461
overwrite: bool,
6562
) -> anyhow::Result<()> {
66-
let file_name = Self::short_path(self.path.as_str());
63+
let file_path = PathBuf::from(self.identifier.path);
64+
let file_name = file_path
65+
.file_name()
66+
.expect("Always exists")
67+
.to_str()
68+
.expect("Always valid");
6769

6870
if output_assembly {
69-
let file_name = format!(
70-
"{}.{}",
71-
file_name,
72-
revive_common::EXTENSION_POLKAVM_ASSEMBLY
73-
);
71+
let file_name = format!("{file_name}.{}", revive_common::EXTENSION_POLKAVM_ASSEMBLY);
7472
let mut file_path = path.to_owned();
7573
file_path.push(file_name);
7674

@@ -79,21 +77,17 @@ impl Contract {
7977
"Refusing to overwrite an existing file {file_path:?} (use --overwrite to force)."
8078
);
8179
} else {
82-
let assembly_text = self.build.assembly_text;
83-
8480
File::create(&file_path)
81+
.map_err(|error| anyhow::anyhow!("File {file_path:?} creating error: {error}"))?
82+
.write_all(self.build.assembly_text.as_bytes())
8583
.map_err(|error| {
86-
anyhow::anyhow!("File {:?} creating error: {}", file_path, error)
87-
})?
88-
.write_all(assembly_text.as_bytes())
89-
.map_err(|error| {
90-
anyhow::anyhow!("File {:?} writing error: {}", file_path, error)
84+
anyhow::anyhow!("File {file_path:?} writing error: {error}")
9185
})?;
9286
}
9387
}
9488

9589
if output_binary {
96-
let file_name = format!("{}.{}", file_name, revive_common::EXTENSION_POLKAVM_BINARY);
90+
let file_name = format!("{file_name}.{}", revive_common::EXTENSION_POLKAVM_BINARY);
9791
let mut file_path = path.to_owned();
9892
file_path.push(file_name);
9993

@@ -103,12 +97,10 @@ impl Contract {
10397
);
10498
} else {
10599
File::create(&file_path)
106-
.map_err(|error| {
107-
anyhow::anyhow!("File {:?} creating error: {}", file_path, error)
108-
})?
100+
.map_err(|error| anyhow::anyhow!("File {file_path:?} creating error: {error}"))?
109101
.write_all(self.build.bytecode.as_slice())
110102
.map_err(|error| {
111-
anyhow::anyhow!("File {:?} writing error: {}", file_path, error)
103+
anyhow::anyhow!("File {file_path:?} writing error: {error}")
112104
})?;
113105
}
114106
}

crates/resolc/src/build/mod.rs

Lines changed: 70 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,19 @@ pub mod contract;
55
use std::collections::BTreeMap;
66
use std::io::Write;
77
use std::path::Path;
8+
use std::path::PathBuf;
9+
10+
use normpath::PathExt;
811

912
use revive_solc_json_interface::combined_json::CombinedJson;
13+
use revive_solc_json_interface::CombinedJsonContract;
1014
use revive_solc_json_interface::SolcStandardJsonOutput;
15+
use revive_solc_json_interface::SolcStandardJsonOutputContract;
1116
use revive_solc_json_interface::SolcStandardJsonOutputError;
1217
use revive_solc_json_interface::SolcStandardJsonOutputErrorHandler;
1318

19+
use crate::build::contract::Contract;
1420
use crate::solc::version::Version as SolcVersion;
15-
use crate::ResolcVersion;
16-
17-
use self::contract::Contract;
1821

1922
/// The Solidity project PVM build.
2023
#[derive(Debug, Default)]
@@ -82,20 +85,23 @@ impl Build {
8285
}
8386

8487
/// Writes all contracts assembly and bytecode to the combined JSON.
85-
pub fn write_to_combined_json(self, combined_json: &mut CombinedJson) -> anyhow::Result<()> {
88+
pub fn write_to_combined_json(
89+
mut self,
90+
combined_json: &mut CombinedJson,
91+
) -> anyhow::Result<()> {
8692
self.take_and_write_warnings();
8793
self.exit_on_error();
8894

8995
for result in self.results.into_values() {
9096
let build = result.expect("Exits on an error above");
91-
let name = build.name.clone();
97+
let identifier = build.identifier.clone();
9298

9399
let combined_json_contract =
94100
match combined_json
95101
.contracts
96102
.iter_mut()
97103
.find_map(|(json_path, contract)| {
98-
if Self::normalize_full_path(name.full_path.as_str())
104+
if Self::normalize_full_path(identifier.full_path.as_str())
99105
.ends_with(Self::normalize_full_path(json_path).as_str())
100106
{
101107
Some(contract)
@@ -106,12 +112,12 @@ impl Build {
106112
Some(contract) => contract,
107113
None => {
108114
combined_json.contracts.insert(
109-
name.full_path.clone(),
110-
era_solc::CombinedJsonContract::default(),
115+
identifier.full_path.clone(),
116+
CombinedJsonContract::default(),
111117
);
112118
combined_json
113119
.contracts
114-
.get_mut(name.full_path.as_str())
120+
.get_mut(identifier.full_path.as_str())
115121
.expect("Always exists")
116122
}
117123
};
@@ -124,31 +130,73 @@ impl Build {
124130

125131
/// Writes all contracts assembly and bytecode to the standard JSON.
126132
pub fn write_to_standard_json(
127-
mut self,
133+
self,
128134
standard_json: &mut SolcStandardJsonOutput,
129135
solc_version: &SolcVersion,
130136
) -> anyhow::Result<()> {
131-
let contracts = match standard_json.contracts.as_mut() {
132-
Some(contracts) => contracts,
133-
None => return Ok(()),
134-
};
135-
136-
for (path, contracts) in contracts.iter_mut() {
137-
for (name, contract) in contracts.iter_mut() {
138-
let full_name = format!("{path}:{name}");
139-
140-
if let Some(contract_data) = self.contracts.remove(full_name.as_str()) {
141-
contract_data.write_to_standard_json(contract)?;
137+
let mut errors = Vec::with_capacity(self.results.len());
138+
for result in self.results.into_values() {
139+
let build = match result {
140+
Ok(build) => build,
141+
Err(error) => {
142+
errors.push(error);
143+
continue;
144+
}
145+
};
146+
let identifier = build.identifier.clone();
147+
148+
match standard_json
149+
.contracts
150+
.get_mut(identifier.path.as_str())
151+
.and_then(|contracts| {
152+
contracts.get_mut(
153+
identifier
154+
.name
155+
.as_deref()
156+
.unwrap_or(identifier.path.as_str()),
157+
)
158+
}) {
159+
Some(contract) => {
160+
build.write_to_standard_json(contract)?;
161+
}
162+
None => {
163+
let contracts = standard_json
164+
.contracts
165+
.entry(identifier.path.clone())
166+
.or_default();
167+
let mut contract = SolcStandardJsonOutputContract::default();
168+
build.write_to_standard_json(&mut contract)?;
169+
contracts.insert(identifier.name.unwrap_or(identifier.path), contract);
142170
}
143171
}
144172
}
145173

174+
standard_json.errors.extend(errors);
146175
standard_json.version = Some(solc_version.default.to_string());
147176
standard_json.long_version = Some(solc_version.long.to_owned());
148-
standard_json.revive_version = Some(ResolcVersion::default().long);
149177

150178
Ok(())
151179
}
180+
181+
/// Normalizes the full contract path.
182+
///
183+
/// # Panics
184+
/// If the path does not contain a colon.
185+
fn normalize_full_path(path: &str) -> String {
186+
let mut iterator = path.split(':');
187+
let path = iterator.next().expect("Always exists");
188+
let name = iterator.next().expect("Always exists");
189+
190+
let mut full_path = PathBuf::from(path)
191+
.normalize()
192+
.expect("Path normalization error")
193+
.as_os_str()
194+
.to_string_lossy()
195+
.into_owned();
196+
full_path.push(':');
197+
full_path.push_str(name);
198+
full_path
199+
}
152200
}
153201

154202
impl revive_solc_json_interface::SolcStandardJsonOutputErrorHandler for Build {

crates/resolc/src/process/native_process.rs

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,6 @@ impl Process for NativeProcess {
3333
anyhow::anyhow!("{:?} subprocess spawning error: {:?}", executable, error)
3434
})?;
3535

36-
#[cfg(debug_assertions)]
37-
input
38-
.debug_config
39-
.dump_stage_output(&input.contract.path, Some("stage"), &input_json)
40-
.map_err(|error| {
41-
anyhow::anyhow!(
42-
"{:?} failed to log the recursive process output: {:?}",
43-
executable,
44-
error,
45-
)
46-
})?;
47-
4836
process
4937
.stdin
5038
.as_ref()

crates/resolc/src/project/contract/ir/yul.rs

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,39 @@
22
33
use std::collections::BTreeSet;
44

5+
use revive_yul::lexer::Lexer;
56
use serde::Deserialize;
67
use serde::Serialize;
78

89
use revive_yul::parser::statement::object::Object;
910

10-
/// The contract Yul source code.
11+
/// he contract Yul source code.
1112
#[derive(Debug, Serialize, Deserialize, Clone)]
1213
pub struct Yul {
13-
/// The Yul source code.
14-
pub source_code: String,
1514
/// The Yul AST object.
1615
pub object: Object,
1716
}
1817

1918
impl Yul {
20-
/// A shortcut constructor.
21-
pub fn new(source_code: String, object: Object) -> Self {
22-
Self {
23-
source_code,
24-
object,
19+
/// Transforms the `solc` standard JSON output contract into a Yul object.
20+
pub fn try_from_source(
21+
path: &str,
22+
source_code: &str,
23+
debug_config: Option<&revive_llvm_context::DebugConfig>,
24+
) -> anyhow::Result<Option<Self>> {
25+
if source_code.is_empty() {
26+
return Ok(None);
27+
};
28+
29+
if let Some(debug_config) = debug_config {
30+
debug_config.dump_yul(path, source_code)?;
2531
}
32+
33+
let mut lexer = Lexer::new(source_code.to_owned());
34+
let object = Object::parse(&mut lexer, None)
35+
.map_err(|error| anyhow::anyhow!("Yul parsing: {error:?}"))?;
36+
37+
Ok(Some(Self { object }))
2638
}
2739

2840
/// Get the list of missing deployable libraries.

crates/resolc/src/project/contract/mod.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use self::metadata::Metadata;
2525
#[derive(Debug, Serialize, Deserialize, Clone)]
2626
pub struct Contract {
2727
/// The absolute file path.
28-
pub path: String,
28+
pub identifier: revive_common::ContractIdentifier,
2929
/// The IR source code data.
3030
pub ir: IR,
3131
/// The metadata JSON.
@@ -35,7 +35,7 @@ pub struct Contract {
3535
impl Contract {
3636
/// A shortcut constructor.
3737
pub fn new(
38-
path: String,
38+
identifier: revive_common::ContractIdentifier,
3939
source_hash: [u8; revive_common::BYTE_LENGTH_WORD],
4040
source_version: SolcVersion,
4141
ir: IR,
@@ -49,7 +49,7 @@ impl Contract {
4949
});
5050

5151
Self {
52-
path,
52+
identifier,
5353
ir,
5454
metadata_json,
5555
}
@@ -156,8 +156,7 @@ impl Contract {
156156
let build = context.build(self.path.as_str(), metadata_hash)?;
157157

158158
Ok(ContractBuild::new(
159-
self.path,
160-
identifier,
159+
self.identifier,
161160
build,
162161
metadata_json,
163162
missing_libraries,

0 commit comments

Comments
 (0)