Skip to content

Commit 0a36ebc

Browse files
authored
[scarb-doc] Add initial crate structures (#1309)
Next PR will add nested attributes to the structures: - struct members - enum variants - impl items - trait items
1 parent 43f76f4 commit 0a36ebc

File tree

6 files changed

+573
-199
lines changed

6 files changed

+573
-199
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

extensions/scarb-doc/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ clap.workspace = true
1515
cairo-lang-compiler.workspace = true
1616
cairo-lang-defs.workspace = true
1717
cairo-lang-semantic.workspace = true
18+
cairo-lang-syntax.workspace = true
1819
cairo-lang-filesystem.workspace = true
1920
cairo-lang-utils.workspace = true
2021
scarb-metadata = { path = "../../scarb-metadata" }
+137
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
use scarb_metadata::{
2+
CompilationUnitComponentMetadata, CompilationUnitMetadata, Metadata, PackageId, PackageMetadata,
3+
};
4+
use smol_str::{SmolStr, ToSmolStr};
5+
use std::path::PathBuf;
6+
7+
use cairo_lang_compiler::project::{AllCratesConfig, ProjectConfig, ProjectConfigContent};
8+
use cairo_lang_filesystem::cfg::{Cfg, CfgSet};
9+
use cairo_lang_filesystem::db::{CrateSettings, Edition, ExperimentalFeaturesConfig};
10+
use cairo_lang_filesystem::ids::Directory;
11+
use cairo_lang_utils::ordered_hash_map::OrderedHashMap;
12+
13+
const LIB_TARGET_KIND: &str = "lib";
14+
const CORELIB_CRATE_NAME: &str = "core";
15+
16+
pub fn get_project_config(
17+
metadata: &Metadata,
18+
package_metadata: &PackageMetadata,
19+
) -> ProjectConfig {
20+
let compilation_unit_metadata =
21+
package_lib_compilation_unit(metadata, package_metadata.id.clone())
22+
.expect("failed to find compilation unit for package");
23+
let corelib = get_corelib(compilation_unit_metadata);
24+
let dependencies = get_dependencies(compilation_unit_metadata);
25+
let crates_config = get_crates_config(metadata, compilation_unit_metadata);
26+
27+
ProjectConfig {
28+
base_path: package_metadata.root.clone().into(),
29+
corelib: Some(Directory::Real(corelib.source_root().into())),
30+
content: ProjectConfigContent {
31+
crate_roots: dependencies,
32+
crates_config,
33+
},
34+
}
35+
}
36+
37+
fn package_lib_compilation_unit(
38+
metadata: &Metadata,
39+
package_id: PackageId,
40+
) -> Option<&CompilationUnitMetadata> {
41+
metadata
42+
.compilation_units
43+
.iter()
44+
.find(|m| m.package == package_id && m.target.kind == LIB_TARGET_KIND)
45+
}
46+
47+
fn get_corelib(
48+
compilation_unit_metadata: &CompilationUnitMetadata,
49+
) -> &CompilationUnitComponentMetadata {
50+
compilation_unit_metadata
51+
.components
52+
.iter()
53+
.find(|du| du.name == CORELIB_CRATE_NAME)
54+
.expect("Corelib could not be found")
55+
}
56+
57+
fn get_dependencies(
58+
compilation_unit_metadata: &CompilationUnitMetadata,
59+
) -> OrderedHashMap<SmolStr, PathBuf> {
60+
compilation_unit_metadata
61+
.components
62+
.iter()
63+
.filter(|du| du.name != CORELIB_CRATE_NAME)
64+
.map(|cu| {
65+
(
66+
cu.name.to_smolstr(),
67+
cu.source_root().to_owned().into_std_path_buf(),
68+
)
69+
})
70+
.collect()
71+
}
72+
73+
fn get_crates_config(
74+
metadata: &Metadata,
75+
compilation_unit_metadata: &CompilationUnitMetadata,
76+
) -> AllCratesConfig {
77+
let crates_config: OrderedHashMap<SmolStr, CrateSettings> = compilation_unit_metadata
78+
.components
79+
.iter()
80+
.map(|component| {
81+
let pkg = metadata.get_package(&component.package).unwrap_or_else(|| {
82+
panic!(
83+
"failed to find = {} package",
84+
&component.package.to_string()
85+
)
86+
});
87+
(
88+
SmolStr::from(&component.name),
89+
get_crate_settings_for_package(
90+
pkg,
91+
component.cfg.as_ref().map(|cfg_vec| build_cfg_set(cfg_vec)),
92+
),
93+
)
94+
})
95+
.collect();
96+
97+
AllCratesConfig {
98+
override_map: crates_config,
99+
..Default::default()
100+
}
101+
}
102+
103+
fn get_crate_settings_for_package(
104+
package: &PackageMetadata,
105+
cfg_set: Option<CfgSet>,
106+
) -> CrateSettings {
107+
let edition = package
108+
.edition
109+
.clone()
110+
.map_or(Edition::default(), |edition| {
111+
let edition_value = serde_json::Value::String(edition);
112+
serde_json::from_value(edition_value).unwrap()
113+
});
114+
115+
let experimental_features = ExperimentalFeaturesConfig {
116+
negative_impls: package
117+
.experimental_features
118+
.contains(&String::from("negative_impls")),
119+
coupons: package
120+
.experimental_features
121+
.contains(&String::from("coupons")),
122+
};
123+
124+
CrateSettings {
125+
edition,
126+
cfg_set,
127+
experimental_features,
128+
}
129+
}
130+
131+
fn build_cfg_set(cfg: &[scarb_metadata::Cfg]) -> CfgSet {
132+
CfgSet::from_iter(cfg.iter().map(|cfg| {
133+
serde_json::to_value(cfg)
134+
.and_then(serde_json::from_value::<Cfg>)
135+
.expect("Cairo's `Cfg` must serialize identically as Scarb Metadata's `Cfg`.")
136+
}))
137+
}

extensions/scarb-doc/src/main.rs

+46-171
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,18 @@
11
use anyhow::Result;
2-
use cairo_lang_compiler::project::{AllCratesConfig, ProjectConfig, ProjectConfigContent};
3-
use cairo_lang_filesystem::cfg::{Cfg, CfgSet};
4-
use cairo_lang_filesystem::db::{CrateSettings, Edition, ExperimentalFeaturesConfig, FilesGroup};
52
use clap::Parser;
6-
use scarb_metadata::{
7-
CompilationUnitComponentMetadata, CompilationUnitMetadata, Metadata, MetadataCommand,
8-
PackageId, PackageMetadata,
9-
};
3+
4+
use scarb_metadata::MetadataCommand;
105
use scarb_ui::args::PackagesFilter;
11-
use smol_str::{SmolStr, ToSmolStr};
12-
use std::collections::HashMap;
13-
use std::path::PathBuf;
146

157
use cairo_lang_compiler::db::RootDatabase;
16-
use cairo_lang_utils::ordered_hash_map::OrderedHashMap;
8+
use cairo_lang_filesystem::db::FilesGroup;
9+
use cairo_lang_filesystem::ids::CrateLongId;
1710

18-
use cairo_lang_defs::db::DefsGroup;
19-
use cairo_lang_defs::ids::{LookupItemId, ModuleItemId, NamedLanguageElementId};
11+
use compilation::get_project_config;
12+
use types::Crate;
2013

21-
use cairo_lang_filesystem::ids::{CrateLongId, Directory};
22-
use cairo_lang_semantic::db::SemanticGroup;
14+
mod compilation;
15+
mod types;
2316

2417
#[derive(Parser, Debug)]
2518
#[command(version, about, long_about = None)]
@@ -28,6 +21,16 @@ struct Args {
2821
packages_filter: PackagesFilter,
2922
}
3023

24+
macro_rules! print_names {
25+
($label:expr, $var:expr) => {
26+
println!(
27+
"{}: {:?}",
28+
$label,
29+
$var.iter().map(|x| &x.item_data.name).collect::<Vec<_>>()
30+
);
31+
};
32+
}
33+
3134
fn main() -> Result<()> {
3235
let args = Args::parse();
3336

@@ -42,166 +45,38 @@ fn main() -> Result<()> {
4245
b.build()?
4346
};
4447

45-
let main_crate_id = db.intern_crate(CrateLongId::Real(package_metadata.name.into()));
46-
47-
let crate_modules = db.crate_modules(main_crate_id);
48-
49-
let mut item_documentation = HashMap::new();
50-
51-
for module_id in crate_modules.iter() {
52-
let module_items = db.module_items(*module_id).unwrap();
53-
54-
for item in module_items.iter() {
55-
let item_doc = db.get_item_documentation(LookupItemId::ModuleItem(*item));
56-
item_documentation.insert(LookupItemId::ModuleItem(*item), item_doc);
57-
58-
if let ModuleItemId::Trait(trait_id) = *item {
59-
let trait_items_names = db.trait_required_item_names(trait_id).unwrap();
48+
let main_crate_id = db.intern_crate(CrateLongId::Real(package_metadata.name.clone().into()));
49+
let crate_ = Crate::new(db, main_crate_id);
6050

61-
for trait_item_name in trait_items_names.into_iter() {
62-
let trait_item_id = db
63-
.trait_item_by_name(trait_id, trait_item_name)
64-
.unwrap()
65-
.unwrap();
66-
67-
let doc = db.get_item_documentation(LookupItemId::TraitItem(trait_item_id));
68-
item_documentation.insert(LookupItemId::TraitItem(trait_item_id), doc);
69-
}
70-
}
71-
}
72-
}
73-
74-
for (item_id, doc) in item_documentation.iter() {
75-
let name = match item_id {
76-
LookupItemId::ModuleItem(item_id) => item_id.name(db),
77-
LookupItemId::TraitItem(item_id) => item_id.name(db),
78-
LookupItemId::ImplItem(item_id) => item_id.name(db),
79-
};
80-
println!("{:?}: {:?} -> {:?}", name, item_id, doc);
81-
}
51+
print_module(&crate_.root_module);
8252

8353
Ok(())
8454
}
8555

86-
fn get_project_config(metadata: &Metadata, package_metadata: &PackageMetadata) -> ProjectConfig {
87-
let compilation_unit_metadata =
88-
package_lib_compilation_unit(metadata, package_metadata.id.clone())
89-
.expect("failed to find compilation unit for package");
90-
let corelib = get_corelib(compilation_unit_metadata);
91-
let dependencies = get_dependencies(compilation_unit_metadata);
92-
let crates_config = get_crates_config(metadata, compilation_unit_metadata);
93-
94-
ProjectConfig {
95-
base_path: package_metadata.root.clone().into(),
96-
corelib: Some(Directory::Real(corelib.source_root().into())),
97-
content: ProjectConfigContent {
98-
crate_roots: dependencies,
99-
crates_config,
100-
},
56+
fn print_module(module: &types::Module) {
57+
println!("Module: {}", module.full_path);
58+
println!(
59+
"Submodules : {:?}",
60+
module
61+
.submodules
62+
.iter()
63+
.map(|x| &x.full_path)
64+
.collect::<Vec<_>>()
65+
);
66+
print_names!("Constants ", module.constants);
67+
print_names!("Uses ", module.uses);
68+
print_names!("Free Functions ", module.free_functions);
69+
print_names!("Structs ", module.structs);
70+
print_names!("Enums ", module.enums);
71+
print_names!("Type Aliases ", module.type_aliases);
72+
print_names!("Impl Aliases ", module.impl_aliases);
73+
print_names!("Traits ", module.traits);
74+
print_names!("Impls ", module.impls);
75+
print_names!("Extern Types ", module.extern_types);
76+
print_names!("Extern Functions", module.extern_functions);
77+
78+
for submodule in &module.submodules {
79+
println!();
80+
print_module(submodule);
10181
}
10282
}
103-
104-
fn package_lib_compilation_unit(
105-
metadata: &Metadata,
106-
package_id: PackageId,
107-
) -> Option<&CompilationUnitMetadata> {
108-
metadata
109-
.compilation_units
110-
.iter()
111-
.find(|m| m.package == package_id && m.target.kind == LIB_TARGET_KIND)
112-
}
113-
114-
fn get_corelib(
115-
compilation_unit_metadata: &CompilationUnitMetadata,
116-
) -> &CompilationUnitComponentMetadata {
117-
compilation_unit_metadata
118-
.components
119-
.iter()
120-
.find(|du| du.name == CORELIB_CRATE_NAME)
121-
.expect("Corelib could not be found")
122-
}
123-
124-
fn get_dependencies(
125-
compilation_unit_metadata: &CompilationUnitMetadata,
126-
) -> OrderedHashMap<SmolStr, PathBuf> {
127-
compilation_unit_metadata
128-
.components
129-
.iter()
130-
.filter(|du| du.name != CORELIB_CRATE_NAME)
131-
.map(|cu| {
132-
(
133-
cu.name.to_smolstr(),
134-
cu.source_root().to_owned().into_std_path_buf(),
135-
)
136-
})
137-
.collect()
138-
}
139-
140-
fn get_crates_config(
141-
metadata: &Metadata,
142-
compilation_unit_metadata: &CompilationUnitMetadata,
143-
) -> AllCratesConfig {
144-
let crates_config: OrderedHashMap<SmolStr, CrateSettings> = compilation_unit_metadata
145-
.components
146-
.iter()
147-
.map(|component| {
148-
let pkg = metadata.get_package(&component.package).unwrap_or_else(|| {
149-
panic!(
150-
"failed to find = {} package",
151-
&component.package.to_string()
152-
)
153-
});
154-
(
155-
SmolStr::from(&component.name),
156-
get_crate_settings_for_package(
157-
pkg,
158-
component.cfg.as_ref().map(|cfg_vec| build_cfg_set(cfg_vec)),
159-
),
160-
)
161-
})
162-
.collect();
163-
164-
AllCratesConfig {
165-
override_map: crates_config,
166-
..Default::default()
167-
}
168-
}
169-
170-
fn get_crate_settings_for_package(
171-
package: &PackageMetadata,
172-
cfg_set: Option<CfgSet>,
173-
) -> CrateSettings {
174-
let edition = package
175-
.edition
176-
.clone()
177-
.map_or(Edition::default(), |edition| {
178-
let edition_value = serde_json::Value::String(edition);
179-
serde_json::from_value(edition_value).unwrap()
180-
});
181-
182-
let experimental_features = ExperimentalFeaturesConfig {
183-
negative_impls: package
184-
.experimental_features
185-
.contains(&String::from("negative_impls")),
186-
coupons: package
187-
.experimental_features
188-
.contains(&String::from("coupons")),
189-
};
190-
191-
CrateSettings {
192-
edition,
193-
cfg_set,
194-
experimental_features,
195-
}
196-
}
197-
198-
fn build_cfg_set(cfg: &[scarb_metadata::Cfg]) -> CfgSet {
199-
CfgSet::from_iter(cfg.iter().map(|cfg| {
200-
serde_json::to_value(cfg)
201-
.and_then(serde_json::from_value::<Cfg>)
202-
.expect("Cairo's `Cfg` must serialize identically as Scarb Metadata's `Cfg`.")
203-
}))
204-
}
205-
206-
const LIB_TARGET_KIND: &str = "lib";
207-
const CORELIB_CRATE_NAME: &str = "core";

0 commit comments

Comments
 (0)