From 9777e29b37b47e8fa009355b4e4af07d68b34696 Mon Sep 17 00:00:00 2001 From: Serena Duncan <57880238+smd21@users.noreply.github.com> Date: Wed, 31 Jul 2024 15:11:11 -0400 Subject: [PATCH] Cider DAP State Inspection + Metadata Update (#2238) This branch provides groundwork for state inspection while debugging Calyx programs in VSCode. It currently displays all the cells in the program and provides methods used to obtain port information. Port information is not currently displayed due to a still unclear issue. This branch also updates the metadata table so that each entry takes on the following form: component_name.group_name : path/to/file start-end this update fixes an issue where the metadata pass was not recognizing Calyx programs where two unique components each have a group with the same name and displays the range the group is on rather than just the start line. --------- Co-authored-by: Serena --- calyx-opt/src/passes/metadata_table_gen.rs | 37 +++++-- calyx-utils/src/position.rs | 10 +- cider-dap/calyxDebug/built/extension.js | 5 +- cider-dap/calyxDebug/extension.ts | 7 +- cider-dap/src/adapter.rs | 77 ++++++++++++++- cider-dap/src/main.rs | 99 +++++++++++++++---- interp/src/debugger/debugger_core.rs | 26 +++-- interp/src/debugger/source/new_metadata.pest | 2 +- interp/src/debugger/source/new_parser.rs | 19 ++-- interp/src/debugger/source/structures.rs | 5 +- interp/src/flatten/setup.rs | 7 ++ .../src/flatten/structures/environment/env.rs | 58 +++++++++++ tests/passes/metadata-table-gen.expect | 6 +- 13 files changed, 291 insertions(+), 67 deletions(-) diff --git a/calyx-opt/src/passes/metadata_table_gen.rs b/calyx-opt/src/passes/metadata_table_gen.rs index d3ba24be90..b63130a4f8 100644 --- a/calyx-opt/src/passes/metadata_table_gen.rs +++ b/calyx-opt/src/passes/metadata_table_gen.rs @@ -8,7 +8,7 @@ use std::path::PathBuf; /// Metadata stores a Map between each group name and data used in the metadata table (specified in PR #2022) #[derive(Default)] pub struct Metadata { - groups: LinkedHashMap, + groups: LinkedHashMap<(Id, Id), ((usize, usize), PathBuf)>, } impl Metadata { @@ -18,8 +18,14 @@ impl Metadata { } /// Add a new entry to the metadata table - fn add_entry(&mut self, name: Id, line: usize, path: PathBuf) { - let ins = self.groups.insert(name, (line, path)); + fn add_entry( + &mut self, + comp_name: Id, + name: Id, + span: (usize, usize), + path: PathBuf, + ) { + let ins = self.groups.insert((comp_name, name), (span, path)); if let Some(_v) = ins { panic!("Two of same group name found") } @@ -30,9 +36,10 @@ impl fmt::Display for Metadata { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let grps = &self.groups; - for (name, (line_num, file)) in grps { + for ((comp, name), ((start, end), file)) in grps { let file = file.to_str().unwrap(); - writeln!(f, " {name}: {file} {line_num}")?; + + writeln!(f, "{comp}.{name}: {file} {start}-{end}")?; } Ok(()) @@ -58,8 +65,13 @@ impl Visitor for Metadata { for rcc_grp in cmpt_iter { let grp = rcc_grp.borrow_mut(); let pos_data = grp.attributes.copy_span(); - let (file, line_num) = pos_data.get_line_num(); - table.add_entry(grp.name(), line_num, PathBuf::from(file)); + let (file, span) = pos_data.get_line_num(); + table.add_entry( + component.name, + grp.name(), + span, + PathBuf::from(file), + ); //hm may need to actually use the full name of the group } ctx.metadata = Some(table.to_string()); @@ -83,9 +95,14 @@ mod tests { assert_eq!(empt_string, ""); let path = PathBuf::from("/temp/path/for/testing.futil"); - data.add_entry(Id::from("group_1"), 12, path.clone()); - data.add_entry(Id::from("group_2"), 23, path); + data.add_entry( + Id::from("main"), + Id::from("group_1"), + (12, 16), + path.clone(), + ); + data.add_entry(Id::from("main"), Id::from("group_2"), (23, 28), path); let test_string = data.to_string(); - assert_eq!(test_string, " group_1: /temp/path/for/testing.futil 12\n group_2: /temp/path/for/testing.futil 23\n") + assert_eq!(test_string, "main.group_1: /temp/path/for/testing.futil 12-16\nmain.group_2: /temp/path/for/testing.futil 23-28\n") } } diff --git a/calyx-utils/src/position.rs b/calyx-utils/src/position.rs index bf660783cd..2b74e99a24 100644 --- a/calyx-utils/src/position.rs +++ b/calyx-utils/src/position.rs @@ -186,13 +186,15 @@ impl GPosIdx { /// returns: /// 1. the name of the file the span is in - /// 2. the starting line of a span - pub fn get_line_num(&self) -> (&String, usize) { + /// 2. the (inclusive) range of lines within the span + pub fn get_line_num(&self) -> (&String, (usize, usize)) { let table = GlobalPositionTable::as_ref(); let pos_data = table.get_pos(self.0); let file_name = &table.get_file_data(pos_data.file).name; - let (_, _, line_num) = self.get_lines(); - (file_name, line_num) + let (buf, _, line_num) = self.get_lines(); + //reformat to return the range (inclusive) + let rng = (line_num, line_num + buf.len() - 1); + (file_name, rng) } /// Format this position with the error message `err_msg` diff --git a/cider-dap/calyxDebug/built/extension.js b/cider-dap/calyxDebug/built/extension.js index c79a7650f8..2aad60c671 100644 --- a/cider-dap/calyxDebug/built/extension.js +++ b/cider-dap/calyxDebug/built/extension.js @@ -80,7 +80,7 @@ var CiderDebugAdapter = /** @class */ (function () { }); _this.adapterProcess.on("spawn", function () { logToPanel("Debugger started on port " + port + "!"); - setTimeout(function () { return resolve(port); }, 200); //short wait to let the thing start running + setTimeout(function () { return resolve(port); }, 700); //short wait to let the thing start running }); _this.adapterProcess.on("error", function () { logToPanel("Debugger failed to start"); @@ -116,9 +116,10 @@ function activate(context) { break; } context.subscriptions.push(vscode.debug.registerDebugAdapterDescriptorFactory("cider-dap", factory)); + logToPanel("before disposables push"); disposables.push(vscode.debug.registerDebugAdapterDescriptorFactory("cider-dap", factory)); // Update the adapter path with the serverPort and use it for starting the debug adapter - ?? - logToPanel("Hello, your extension is now activated!"); + logToPanel("Hello, your extension is now activated! after disposables push"); } function stopDebugging() { if (debugAdapter) { diff --git a/cider-dap/calyxDebug/extension.ts b/cider-dap/calyxDebug/extension.ts index fea8d5e414..727389ebab 100644 --- a/cider-dap/calyxDebug/extension.ts +++ b/cider-dap/calyxDebug/extension.ts @@ -98,7 +98,7 @@ class CiderDebugAdapter { }); this.adapterProcess.on("spawn", () => { logToPanel("Debugger started on port " + port + "!"); - setTimeout(() => resolve(port), 200) //short wait to let the thing start running + setTimeout(() => resolve(port), 700) //short wait to let the thing start running }); this.adapterProcess.on("error", () => { logToPanel("Debugger failed to start"); @@ -141,9 +141,12 @@ function activate(context) { context.subscriptions.push( vscode.debug.registerDebugAdapterDescriptorFactory("cider-dap", factory) ); + logToPanel("before disposables push") disposables.push(vscode.debug.registerDebugAdapterDescriptorFactory("cider-dap", factory)) // Update the adapter path with the serverPort and use it for starting the debug adapter - ?? - logToPanel("Hello, your extension is now activated!"); + logToPanel("Hello, your extension is now activated! after disposables push"); + + } function stopDebugging() { diff --git a/cider-dap/src/adapter.rs b/cider-dap/src/adapter.rs index ed85191985..853a31be37 100644 --- a/cider-dap/src/adapter.rs +++ b/cider-dap/src/adapter.rs @@ -1,7 +1,10 @@ use crate::error::AdapterResult; -use dap::types::{Breakpoint, Source, SourceBreakpoint, StackFrame, Thread}; +use dap::types::{ + Breakpoint, Scope, Source, SourceBreakpoint, StackFrame, Thread, Variable, +}; use interp::debugger::source::structures::NewSourceMap; use interp::debugger::OwnedDebugger; +use std::collections::HashMap; use std::path::PathBuf; pub struct MyAdapter { @@ -13,6 +16,7 @@ pub struct MyAdapter { breakpoints: Vec<(Source, i64)>, // This field is a placeholder stack_frames: Vec, // This field is a placeholder threads: Vec, // This field is a placeholder + object_references: HashMap>, source: String, ids: NewSourceMap, } @@ -29,10 +33,12 @@ impl MyAdapter { breakpoints: Vec::new(), stack_frames: Vec::new(), threads: Vec::new(), + object_references: HashMap::new(), source: path.to_string(), ids: metadata, }) } + ///Set breakpoints for adapter pub fn set_breakpoint( &mut self, @@ -42,7 +48,7 @@ impl MyAdapter { //Keep all the new breakpoints made let mut out_vec: Vec = vec![]; - //Loop over all breakpoints + //Loop over all breakpoints - why do we need to loop over all of them? is it bc input vec isnt mutable? for source_point in source { self.breakpoints.push((path.clone(), source_point.line)); //Create new Breakpoint instance @@ -55,12 +61,13 @@ impl MyAdapter { out_vec.push(breakpoint); } - + //push breakpoints to cider debugger once have go ahead out_vec } ///Creates a thread using the parameter name. pub fn create_thread(&mut self, name: String) -> Thread { + //how do we attach the thread to the program let thread = Thread { id: self.thread_count.increment(), name, @@ -109,8 +116,10 @@ impl MyAdapter { } pub fn next_line(&mut self, _thread: i64) -> bool { + self.object_references.clear(); + //return a more informative enum // Step through once - let status = self.debugger.step(1).unwrap(); + let status = self.debugger.step(1).unwrap(); //need to unwrap a different way // Check if done: if status.get_done() { @@ -123,7 +132,7 @@ impl MyAdapter { // the code for now goes to the line of the last group running in the map, should deal // with this in the future for when groups run in parallel. for id in map { - let value = self.ids.lookup(id.to_string()).unwrap().line; + let value = self.ids.lookup(id.to_string()).unwrap().start_line; line_number = value; } // Set line of the stack frame and tell debugger we're not finished. @@ -131,6 +140,62 @@ impl MyAdapter { false } } + + //display ports of each cell + pub fn get_variables(&self, var_ref: i64) -> Vec { + let ports = self.object_references.get(&var_ref); + match ports { + None => Vec::default(), + Some(p) => { + let out: Vec = p + .iter() + .map(|x| Variable { + name: String::from(x), + value: String::from("1"), + type_field: None, + presentation_hint: None, + evaluate_name: None, + variables_reference: 0, + named_variables: None, + indexed_variables: None, + memory_reference: None, + }) + .collect(); + out + } + } + } + // return cells in calyx context (later should hopefully just return ones w current component) + pub fn get_scopes(&mut self, _frame: i64) -> Vec { + let mut out_vec = vec![]; + let cell_names = self.debugger.get_cells(); + let mut var_ref_count = 1; + for (name, ports) in cell_names { + self.object_references.insert(var_ref_count, ports); + let scope = Scope { + name, + presentation_hint: Some( + dap::types::ScopePresentationhint::Locals, + ), + variables_reference: var_ref_count, + named_variables: None, + indexed_variables: None, + expensive: false, + source: None, + line: None, + column: None, + end_line: None, + end_column: None, + }; + var_ref_count += 1; + out_vec.push(scope); + } + out_vec + } + + pub fn on_pause(&mut self) { + self.object_references.clear(); + } } /// Simple struct used to keep an index of the breakpoints used. @@ -156,11 +221,13 @@ impl Counter { /// This function takes in relevant fields in Breakpoint that are used /// by the adapter. This is subject to change. pub fn make_breakpoint( + //probably add debugger call here? id: Option, verified: bool, source: Option, line: Option, ) -> Breakpoint { + println!("bkpt"); Breakpoint { id, verified, diff --git a/cider-dap/src/main.rs b/cider-dap/src/main.rs index 44598b87d8..fae32fbebd 100644 --- a/cider-dap/src/main.rs +++ b/cider-dap/src/main.rs @@ -11,7 +11,9 @@ use error::MyAdapterError; use dap::prelude::*; use error::AdapterResult; +use responses::VariablesResponse; use slog::{info, Drain}; +//use std::default; use std::fs::OpenOptions; use std::io::{stdin, stdout, BufReader, BufWriter, Read, Write}; use std::net::TcpListener; @@ -70,18 +72,15 @@ fn main() -> Result<(), MyAdapterError> { let read_stream = BufReader::new(stream.try_clone()?); let write_stream = BufWriter::new(stream); let mut server = Server::new(read_stream, write_stream); - // Get the adapter from the init function let adapter = multi_session_init(&mut server, &logger, opts.path)?; - - // Run the server using the adapter run_server(&mut server, adapter, &logger)?; } else { info!(logger, "running single-session"); let write = BufWriter::new(stdout()); let read = BufReader::new(stdin()); let mut server = Server::new(read, write); - let adapter = multi_session_init(&mut server, &logger, opts.path)?; + let adapter = multi_session_init(&mut server, &logger, opts.path)?; //i dont think this is right run_server(&mut server, adapter, &logger)?; } info!(logger, "exited run_Server"); @@ -109,6 +108,7 @@ where // Not sure if we need it // Make VSCode send disassemble request supports_stepping_granularity: Some(true), + supports_single_thread_execution_requests: Some(true), ..Default::default() })); server.respond(rsp)?; @@ -123,6 +123,7 @@ where } // handle the second request (Launch) + //seems like second request doesn't necessarily need to be a launch request let req = match server.poll_request()? { Some(req) => req, None => return Err(MyAdapterError::MissingCommandError), @@ -150,7 +151,7 @@ where // Currently, we need two threads to run the debugger and step through, // not sure why but would be good to look into for the future. - let thread = &adapter.create_thread(String::from("Main")); + let thread = &adapter.create_thread(String::from("Main")); //does not seem as though this does anything let thread2 = &adapter.create_thread(String::from("Thread 1")); // Notify server of first thread @@ -174,14 +175,25 @@ fn run_server( mut adapter: MyAdapter, logger: &slog::Logger, ) -> AdapterResult<()> { + let stopped = create_stopped( + types::StoppedEventReason::Entry, + String::from("Debugger has started"), + 0, + true, + ); + server.send_event(stopped)?; + info!(logger, "sent stopped event (initialization)"); + loop { // Start looping here let req = match server.poll_request()? { Some(req) => req, None => return Err(MyAdapterError::MissingCommandError), }; + info!(logger, "{req:?}"); match &req.command { Command::Launch(_) => { + //why is this listed a second time let rsp = req.success(ResponseBody::Launch); server.respond(rsp)?; } @@ -244,6 +256,8 @@ fn run_server( } // Continue the debugger Command::Continue(_args) => { + // need to run debugger, ngl not really sure how to implement this functionality + // run debugger until breakpoint or paused -> maybe have a process to deal w running debugger? let rsp = req.success(ResponseBody::Continue(ContinueResponse { all_threads_continued: None, @@ -252,13 +266,22 @@ fn run_server( } // Send a Stopped event with reason Pause Command::Pause(args) => { + //necessary to clear out object references + adapter.on_pause(); + // Get ID before rsp takes ownership + // need to communicate pause to debugger let thread_id = args.thread_id; let rsp = req.success(ResponseBody::Pause); // Send response first server.respond(rsp)?; // Send event - let stopped = create_stopped(String::from("Paused"), thread_id); + let stopped = create_stopped( + types::StoppedEventReason::Pause, + String::from("Paused"), + thread_id, + false, + ); server.send_event(stopped)?; } // Step over @@ -283,8 +306,12 @@ fn run_server( // Send response first server.respond(rsp)?; // Send event - let stopped = - create_stopped(String::from("Continue"), thread_id); + let stopped = create_stopped( + types::StoppedEventReason::Step, + String::from("Continue"), + thread_id, + false, + ); server.send_event(stopped)?; } // Step in @@ -295,8 +322,12 @@ fn run_server( let rsp = req.success(ResponseBody::StepIn); server.respond(rsp)?; // Send event - let stopped = - create_stopped(String::from("Paused on step"), thread_id); + let stopped = create_stopped( + types::StoppedEventReason::Step, + String::from("Paused on step"), + thread_id, + false, + ); server.send_event(stopped)?; } // Step out @@ -307,14 +338,33 @@ fn run_server( let rsp = req.success(ResponseBody::StepOut); server.respond(rsp)?; // Send event - let stopped = - create_stopped(String::from("Paused on step"), thread_id); + let stopped = create_stopped( + types::StoppedEventReason::Step, + String::from("Paused on step"), + thread_id, + false, + ); server.send_event(stopped)?; } - Command::Scopes(_) => { + Command::Scopes(args) => { + //variables go in here most likely + //just get stuff displaying then figure out how to pretty it up + + let frame_id = args.frame_id; let rsp = req.success(ResponseBody::Scopes(ScopesResponse { - scopes: vec![], + scopes: adapter.get_scopes(frame_id), })); + info!(logger, "responded with {rsp:?}"); + server.respond(rsp)?; + } + Command::Variables(args) => { + info!(logger, "variables req"); + // never happening idk why + let var_ref = args.variables_reference; + let rsp = + req.success(ResponseBody::Variables(VariablesResponse { + variables: adapter.get_variables(var_ref), + })); server.respond(rsp)?; } @@ -327,15 +377,24 @@ fn run_server( } } -/// Helper function used to create a Stopped event -fn create_stopped(reason: String, thread_id: i64) -> Event { +///Helper function used to create a Stopped event +fn create_stopped( + reason: types::StoppedEventReason, + desc: String, + thread_id: i64, + all_threads: bool, +) -> Event { + let thread = match all_threads { + true => None, + false => Some(thread_id), + }; Event::Stopped(StoppedEventBody { - reason: types::StoppedEventReason::Step, - description: Some(reason), - thread_id: Some(thread_id), + reason, + description: Some(desc), + thread_id: thread, preserve_focus_hint: None, text: None, - all_threads_stopped: None, + all_threads_stopped: Some(all_threads), hit_breakpoint_ids: None, }) } diff --git a/interp/src/debugger/debugger_core.rs b/interp/src/debugger/debugger_core.rs index 230f67d136..c1f89de7a7 100644 --- a/interp/src/debugger/debugger_core.rs +++ b/interp/src/debugger/debugger_core.rs @@ -20,8 +20,6 @@ use crate::{ use std::{collections::HashSet, path::PathBuf, rc::Rc}; -use calyx_ir::Id; - use owo_colors::OwoColorize; use std::path::Path as FilePath; @@ -33,19 +31,14 @@ pub(super) const SPACING: &str = " "; /// is finished or not. If program is done then the debugger is exited pub struct ProgramStatus { /// all groups currently running - status: HashSet, + status: HashSet, /// states whether the program has finished done: bool, } impl ProgramStatus { - /// Create a new program status on the fly - pub fn generate() -> Self { - todo!() - } - /// get status - pub fn get_status(&self) -> &HashSet { + pub fn get_status(&self) -> &HashSet { &self.status } @@ -116,7 +109,20 @@ impl + Clone> Debugger { } pub fn status(&self) -> ProgramStatus { - todo!() + ProgramStatus { + status: self + .interpreter + .get_currently_running_groups() + .map(|x| self.program_context.as_ref().lookup_name(x).clone()) + .collect(), + done: self.interpreter.is_done(), + } + } + + pub fn get_cells( + &self, + ) -> impl Iterator)> + '_ { + self.interpreter.env().iter_cells() } // Go to next step diff --git a/interp/src/debugger/source/new_metadata.pest b/interp/src/debugger/source/new_metadata.pest index b1c72cbac2..a873c460c5 100644 --- a/interp/src/debugger/source/new_metadata.pest +++ b/interp/src/debugger/source/new_metadata.pest @@ -6,7 +6,7 @@ num = @{ ASCII_DIGIT+ } group_name = @{ (ASCII_ALPHA | ASCII_DIGIT | ident_syms | dot)+ } path = @{ (ASCII_ALPHA | ASCII_DIGIT | ident_syms | dot | "/")+ } -entry = { group_name ~ colon ~ WHITE_SPACE ~ path ~ WHITE_SPACE ~ num ~ (",")* ~ WHITE_SPACE* } +entry = { WHITE_SPACE* ~ group_name ~ colon ~ WHITE_SPACE ~ path ~ WHITE_SPACE ~ num ~ ("-") ~ num ~ (",")* ~ WHITE_SPACE* } metadata = { SOI ~ entry* ~ EOI diff --git a/interp/src/debugger/source/new_parser.rs b/interp/src/debugger/source/new_parser.rs index 2eb3b2b979..7a8c79fa5a 100644 --- a/interp/src/debugger/source/new_parser.rs +++ b/interp/src/debugger/source/new_parser.rs @@ -33,7 +33,7 @@ impl MetadataParser { fn entry(input: Node) -> ParseResult<(String, GroupContents)> { Ok(match_nodes!(input.into_children(); - [group_name(g), path(p),num(n)] => (g,GroupContents {path:p, line: n}) + [group_name(g), path(p),num(st), num(end)] => (g,GroupContents {path:p, start_line: st, end_line:end}) )) } @@ -63,23 +63,24 @@ pub fn parse_metadata(input_str: &str) -> InterpreterResult { #[cfg(test)] #[test] fn one_entry() { - let entry = parse_metadata("hello: your/mom 5").unwrap(); + let entry = parse_metadata("hello: your/mom 6-9").unwrap(); dbg!(&entry); let tup = entry.lookup(String::from("hello")); assert_eq!( tup.unwrap().clone(), GroupContents { path: String::from("your/mom"), - line: 5 + start_line: 6, + end_line: 9 } ) } #[test] -fn mult_entires() { +fn mult_entries() { let entry = parse_metadata( - "wr_reg0: calyx/interp/test/control/reg_seq.futil 10, - wr_reg1: calyx/interp/test/control/reg_seq.futil 15", + "wr_reg0: calyx/interp/test/control/reg_seq.futil 10-13, + wr_reg1: calyx/interp/test/control/reg_seq.futil 15-19", ) .unwrap(); let tup = entry.lookup(String::from("wr_reg0")); @@ -88,14 +89,16 @@ fn mult_entires() { tup.unwrap().clone(), GroupContents { path: String::from("calyx/interp/test/control/reg_seq.futil"), - line: 10 + start_line: 10, + end_line: 13 } ); assert_eq!( tup2.unwrap().clone(), GroupContents { path: String::from("calyx/interp/test/control/reg_seq.futil"), - line: 15 + start_line: 15, + end_line: 19 } ) } diff --git a/interp/src/debugger/source/structures.rs b/interp/src/debugger/source/structures.rs index 70e984788e..e93205799a 100644 --- a/interp/src/debugger/source/structures.rs +++ b/interp/src/debugger/source/structures.rs @@ -18,12 +18,13 @@ impl From<(u64, String)> for NamedTag { } } -/// GroupContents contains the file path of the group and the line number the +/// GroupContents contains the file path of the group and the line numbers the /// group is on. #[derive(Debug, Clone, PartialEq)] pub struct GroupContents { pub path: String, - pub line: u64, + pub start_line: u64, + pub end_line: u64, } /// impl struct with path and number diff --git a/interp/src/flatten/setup.rs b/interp/src/flatten/setup.rs index 73e84ae73d..08b8e6638d 100644 --- a/interp/src/flatten/setup.rs +++ b/interp/src/flatten/setup.rs @@ -23,6 +23,13 @@ fn do_setup( if !skip_verification { pm.execute_plan(&mut ctx, &["validate".to_string()], &[], &[], false)?; } + pm.execute_plan( + &mut ctx, + &["metadata-table-generation".to_string()], + &[], + &[], + false, + )?; let mapping = ctx .metadata diff --git a/interp/src/flatten/structures/environment/env.rs b/interp/src/flatten/structures/environment/env.rs index 092735b96a..7599726457 100644 --- a/interp/src/flatten/structures/environment/env.rs +++ b/interp/src/flatten/structures/environment/env.rs @@ -23,6 +23,7 @@ use crate::{ }, primitives::{self, prim_trait::UpdateStatus, Primitive}, structures::{ + context::LookupName, environment::{ program_counter::ControlPoint, traverser::Traverser, }, @@ -249,6 +250,63 @@ impl + Clone> Environment { pub fn ctx(&self) -> &Context { self.ctx.as_ref() } + /// Returns the full name and port list of each cell in the context + pub fn iter_cells( + &self, + ) -> impl Iterator)> + '_ { + let env = self; + let cell_names = self.cells.iter().map(|(idx, _ledger)| { + (idx.get_full_name(env), self.get_ports_for_cell(idx)) + }); + + cell_names + // get parent from cell, if not exist then lookup component ledger get base idxs, go to context and get signature to get ports + // for cells, same thing but in the cell ledger, subtract child offset from parent offset to get local offset, lookup in cell offset in component info + } + + //not sure if beneficial to change this to be impl iterator as well + fn get_ports_for_cell(&self, cell: GlobalCellIdx) -> Vec { + let parent = self.get_parent_cell_from_cell(cell); + match parent { + None => { + let comp_ledger = self.cells[cell].as_comp().unwrap(); + let comp_info = + self.ctx().secondary.comp_aux_info.get(comp_ledger.comp_id); + let port_ids = comp_info.signature.into_iter().map(|x| { + &self.ctx().secondary.local_port_defs + [comp_info.port_offset_map[x]] + .name + }); + let port_names = port_ids + .map(|x| String::from(x.lookup_name(self.ctx()))) + .collect_vec(); + port_names + } + Some(parent_cell) => { + let parent_comp_ledger = self.cells[parent_cell].unwrap_comp(); + let comp_info = self + .ctx() + .secondary + .comp_aux_info + .get(parent_comp_ledger.comp_id); + let local_offset = cell - &parent_comp_ledger.index_bases; + + let port_ids = self.ctx().secondary.local_cell_defs + [comp_info.cell_offset_map[local_offset]] + .ports + .into_iter() + .map(|x| { + &self.ctx().secondary.local_port_defs + [comp_info.port_offset_map[x]] + .name + }); + let names = port_ids + .map(|x| String::from(x.lookup_name(self.ctx()))) + .collect_vec(); + names + } + } + } pub fn new(ctx: C, data_map: Option) -> Self { let root = ctx.as_ref().entry_point; diff --git a/tests/passes/metadata-table-gen.expect b/tests/passes/metadata-table-gen.expect index 58c35caeaf..45cc035ecc 100644 --- a/tests/passes/metadata-table-gen.expect +++ b/tests/passes/metadata-table-gen.expect @@ -12,8 +12,8 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { control {} } metadata #{ - g1: tests/passes/metadata-table-gen.futil 8 - g2: tests/passes/metadata-table-gen.futil 9 - g3: tests/passes/metadata-table-gen.futil 10 +main.g1: tests/passes/metadata-table-gen.futil 8-8 +main.g2: tests/passes/metadata-table-gen.futil 9-9 +main.g3: tests/passes/metadata-table-gen.futil 10-10 }#