Skip to content

Commit 78cbc0f

Browse files
Haofeiclaude
andcommitted
feat(symbols): source-qualified symbol inventory with lowered names
Add `symbol_inventory(file, source)` returning, per item-level declaration (functions incl. `Type.method`, types, consts, sum variants), its `module`, `qualname`, `kind`, `source span`, and `lowered_name` — the Rust symbol it lowers to. Backed by a new public `lowered_symbol_name` in the lowerer (`helpers.count` -> `helpers_count`, `async` -> `r#async`). Addresses the tinygrad-port "stable source-qualified symbol identity" item: portman can now map `helpers.rss::count` to its backend symbol without guessing, instead of comparing bare names. Additive (new public API + unit test); no existing behavior changes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent ebfb803 commit 78cbc0f

3 files changed

Lines changed: 84 additions & 2 deletions

File tree

crates/rsscript/src/lib.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ pub use review::{
107107
format_review_human, format_review_json, format_review_map_human, format_review_map_json,
108108
review_map_sources, review_sources,
109109
};
110+
pub use rust_lower::lowered_symbol_name;
110111
pub use rust_lower::{
111112
GeneratedRustPackage, LowerCoverageReport, LoweredRust, NativeRustDependency,
112113
RemappedRustcDiagnostic, RustBackendCheckResult, RustSourceMapEntry,
@@ -118,7 +119,7 @@ pub use rust_lower::{
118119
remap_rustc_diagnostic_json_lines, write_generated_rust_package,
119120
};
120121
pub use symbols::{
121-
Definition, Reference, RssDocumentSymbol, SymbolIndex, SymbolInfo, SymbolKind, SymbolLookup,
122-
document_symbols, symbol_index,
122+
Definition, Reference, RssDocumentSymbol, SymbolIndex, SymbolInfo, SymbolInventoryEntry,
123+
SymbolKind, SymbolLookup, document_symbols, symbol_index, symbol_inventory,
123124
};
124125
pub use vm_coverage::{VmCoverageReport, vm_coverage_report};

crates/rsscript/src/rust_lower/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,14 @@ use helpers::{
3333
};
3434
use lowerer::RustLowerer;
3535

36+
/// The Rust symbol name a source-qualified RSScript name lowers to (dotted
37+
/// member names are flattened and Rust keywords are raw-escaped) — e.g.
38+
/// `helpers.count` → `helpers_count`, `async` → `r#async`. Exposed so port
39+
/// tooling can map an RSScript symbol to its backend identity without guessing.
40+
pub fn lowered_symbol_name(qualified_name: &str) -> String {
41+
helpers::rust_function_ident(qualified_name)
42+
}
43+
3644
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize)]
3745
pub struct LowerCoverageReport {
3846
pub runtime_intrinsics: CoverageBucket,

crates/rsscript/src/symbols.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,48 @@ pub fn symbol_index(file: &str, source: &str) -> SymbolIndex {
9898
}
9999
}
100100

101+
/// One entry in the source-qualified symbol inventory: a declaration's module,
102+
/// source-qualified name, kind, span, and the Rust symbol it lowers to. This is
103+
/// the "stable source-qualified symbol identity" the port tooling (portman)
104+
/// needs to map `helpers.rss::count` to its backend symbol without guessing.
105+
#[derive(Debug, Clone)]
106+
pub struct SymbolInventoryEntry {
107+
pub module: String,
108+
pub qualname: String,
109+
pub kind: SymbolKind,
110+
pub span: Span,
111+
pub lowered_name: String,
112+
}
113+
114+
/// Build the source-qualified symbol inventory for `file`: every item-level
115+
/// declaration (functions incl. `Type.method`, types, consts, sum variants) with
116+
/// its module path and lowered Rust name.
117+
pub fn symbol_inventory(file: &str, source: &str) -> Vec<SymbolInventoryEntry> {
118+
let module = std::path::Path::new(file)
119+
.file_stem()
120+
.and_then(|stem| stem.to_str())
121+
.unwrap_or(file)
122+
.to_string();
123+
let index = symbol_index(file, source);
124+
index
125+
.definitions()
126+
.iter()
127+
.filter(|definition| {
128+
matches!(
129+
definition.kind,
130+
SymbolKind::Function | SymbolKind::Type | SymbolKind::Const | SymbolKind::Variant
131+
)
132+
})
133+
.map(|definition| SymbolInventoryEntry {
134+
module: module.clone(),
135+
qualname: definition.name.clone(),
136+
kind: definition.kind,
137+
span: definition.span.clone(),
138+
lowered_name: crate::rust_lower::lowered_symbol_name(&definition.name),
139+
})
140+
.collect()
141+
}
142+
101143
/// Parse `source` and return a top-level document outline.
102144
pub fn document_symbols(file: &str, source: &str) -> Vec<RssDocumentSymbol> {
103145
let program = parse_source(file, source);
@@ -903,6 +945,37 @@ impl Builder<'_> {
903945
mod tests {
904946
use super::*;
905947

948+
#[test]
949+
fn symbol_inventory_carries_module_qualname_and_lowered_name() {
950+
let source = concat!(
951+
"const MAX_RETRIES: Int = 3\n",
952+
"struct Device { id: Int }\n",
953+
"fn Device.open(id: Int) -> fresh Device {\n",
954+
" return Device(id: id)\n",
955+
"}\n",
956+
);
957+
let inventory = symbol_inventory("helpers.rss", source);
958+
let find = |qualname: &str| {
959+
inventory
960+
.iter()
961+
.find(|entry| entry.qualname == qualname)
962+
.unwrap_or_else(|| panic!("missing `{qualname}` in inventory: {inventory:?}"))
963+
};
964+
965+
// Every entry is tagged with the source module.
966+
assert!(inventory.iter().all(|entry| entry.module == "helpers"));
967+
968+
// A dotted member function lowers to a flattened Rust symbol.
969+
let open = find("Device.open");
970+
assert_eq!(open.kind, SymbolKind::Function);
971+
assert_eq!(open.lowered_name, "Device_open");
972+
973+
// Const and type symbols keep their (keyword-safe) names.
974+
assert_eq!(find("MAX_RETRIES").kind, SymbolKind::Const);
975+
assert_eq!(find("MAX_RETRIES").lowered_name, "MAX_RETRIES");
976+
assert_eq!(find("Device").kind, SymbolKind::Type);
977+
}
978+
906979
const SOURCE: &str = concat!(
907980
"fn helper(value: read Int) -> Int {\n",
908981
" return value\n",

0 commit comments

Comments
 (0)