11//! Exporting HUGR graphs to their `hugr-model` representation.
2+ use crate :: Visibility ;
23use crate :: extension:: ExtensionRegistry ;
34use crate :: hugr:: internal:: HugrInternals ;
45use crate :: types:: type_param:: Term ;
@@ -20,13 +21,14 @@ use crate::{
2021} ;
2122
2223use fxhash:: { FxBuildHasher , FxHashMap } ;
23- use hugr_model:: v0:: Visibility ;
24+ use hugr_model:: v0:: bumpalo ;
2425use hugr_model:: v0:: {
2526 self as model,
2627 bumpalo:: { Bump , collections:: String as BumpString , collections:: Vec as BumpVec } ,
2728 table,
2829} ;
2930use petgraph:: unionfind:: UnionFind ;
31+ use smol_str:: ToSmolStr ;
3032use std:: fmt:: Write ;
3133
3234/// Exports a deconstructed `Package` to its representation in the model.
@@ -95,7 +97,7 @@ struct Context<'a> {
9597 // that ensures that the `node_to_id` and `id_to_node` maps stay in sync.
9698}
9799
98- const NO_VIS : Option < Visibility > = None ;
100+ const NO_VIS : Option < model :: Visibility > = None ;
99101
100102impl < ' a > Context < ' a > {
101103 pub fn new ( hugr : & ' a Hugr , bump : & ' a Bump ) -> Self {
@@ -261,8 +263,12 @@ impl<'a> Context<'a> {
261263
262264 // We record the name of the symbol defined by the node, if any.
263265 let symbol = match optype {
264- OpType :: FuncDefn ( func_defn) => Some ( func_defn. func_name ( ) . as_str ( ) ) ,
265- OpType :: FuncDecl ( func_decl) => Some ( func_decl. func_name ( ) . as_str ( ) ) ,
266+ OpType :: FuncDefn ( _) | OpType :: FuncDecl ( _) => {
267+ // Functions aren't exported using their core name but with a mangled
268+ // name derived from their id. The function's core name will be recorded
269+ // using `core.title` metadata.
270+ Some ( self . mangled_name ( node) )
271+ }
266272 OpType :: AliasDecl ( alias_decl) => Some ( alias_decl. name . as_str ( ) ) ,
267273 OpType :: AliasDefn ( alias_defn) => Some ( alias_defn. name . as_str ( ) ) ,
268274 _ => None ,
@@ -282,6 +288,7 @@ impl<'a> Context<'a> {
282288 // the node id. This is necessary to establish the correct node id for the
283289 // local scope introduced by some operations. We will overwrite this node later.
284290 let mut regions: & [ _ ] = & [ ] ;
291+ let mut meta = Vec :: new ( ) ;
285292
286293 let node = self . id_to_node [ & node_id] ;
287294 let optype = self . hugr . get_optype ( node) ;
@@ -331,8 +338,10 @@ impl<'a> Context<'a> {
331338 }
332339
333340 OpType :: FuncDefn ( func) => self . with_local_scope ( node_id, |this| {
341+ let symbol_name = this. export_func_name ( node, & mut meta) ;
342+
334343 let symbol = this. export_poly_func_type (
335- func . func_name ( ) ,
344+ symbol_name ,
336345 Some ( func. visibility ( ) . clone ( ) . into ( ) ) ,
337346 func. signature ( ) ,
338347 ) ;
@@ -345,8 +354,10 @@ impl<'a> Context<'a> {
345354 } ) ,
346355
347356 OpType :: FuncDecl ( func) => self . with_local_scope ( node_id, |this| {
357+ let symbol_name = this. export_func_name ( node, & mut meta) ;
358+
348359 let symbol = this. export_poly_func_type (
349- func . func_name ( ) ,
360+ symbol_name ,
350361 Some ( func. visibility ( ) . clone ( ) . into ( ) ) ,
351362 func. signature ( ) ,
352363 ) ;
@@ -502,12 +513,9 @@ impl<'a> Context<'a> {
502513 let inputs = self . make_ports ( node, Direction :: Incoming , num_inputs) ;
503514 let outputs = self . make_ports ( node, Direction :: Outgoing , num_outputs) ;
504515
505- let meta = {
506- let mut meta = Vec :: new ( ) ;
507- self . export_node_json_metadata ( node, & mut meta) ;
508- self . export_node_order_metadata ( node, & mut meta) ;
509- self . bump . alloc_slice_copy ( & meta)
510- } ;
516+ self . export_node_json_metadata ( node, & mut meta) ;
517+ self . export_node_order_metadata ( node, & mut meta) ;
518+ let meta = self . bump . alloc_slice_copy ( & meta) ;
511519
512520 self . module . nodes [ node_id. index ( ) ] = table:: Node {
513521 operation,
@@ -803,7 +811,7 @@ impl<'a> Context<'a> {
803811 pub fn export_poly_func_type < RV : MaybeRV > (
804812 & mut self ,
805813 name : & ' a str ,
806- visibility : Option < Visibility > ,
814+ visibility : Option < model :: Visibility > ,
807815 t : & PolyFuncTypeBase < RV > ,
808816 ) -> & ' a table:: Symbol < ' a > {
809817 let mut params = BumpVec :: with_capacity_in ( t. params ( ) . len ( ) , self . bump ) ;
@@ -1121,6 +1129,33 @@ impl<'a> Context<'a> {
11211129 }
11221130 }
11231131
1132+ /// Used when exporting function definitions or declarations. When the
1133+ /// function is public, its symbol name will be the core name. For private
1134+ /// functions, the symbol name is derived from the node id and the core name
1135+ /// is exported as `core.title` metadata.
1136+ ///
1137+ /// This is a hack, necessary due to core names for functions being
1138+ /// non-functional. Once functions have a "link name", that should be used as the symbol name here.
1139+ fn export_func_name ( & mut self , node : Node , meta : & mut Vec < table:: TermId > ) -> & ' a str {
1140+ let ( name, vis) = match self . hugr . get_optype ( node) {
1141+ OpType :: FuncDefn ( func_defn) => ( func_defn. func_name ( ) , func_defn. visibility ( ) ) ,
1142+ OpType :: FuncDecl ( func_decl) => ( func_decl. func_name ( ) , func_decl. visibility ( ) ) ,
1143+ _ => panic ! (
1144+ "`export_func_name` is only supposed to be used on function declarations and definitions"
1145+ ) ,
1146+ } ;
1147+
1148+ match vis {
1149+ Visibility :: Public => name,
1150+ Visibility :: Private => {
1151+ let literal =
1152+ self . make_term ( table:: Term :: Literal ( model:: Literal :: Str ( name. to_smolstr ( ) ) ) ) ;
1153+ meta. push ( self . make_term_apply ( model:: CORE_TITLE , & [ literal] ) ) ;
1154+ self . mangled_name ( node)
1155+ }
1156+ }
1157+ }
1158+
11241159 pub fn make_json_meta ( & mut self , name : & str , value : & serde_json:: Value ) -> table:: TermId {
11251160 let value = serde_json:: to_string ( value) . expect ( "json values are always serializable" ) ;
11261161 let value = self . make_term ( model:: Literal :: Str ( value. into ( ) ) . into ( ) ) ;
@@ -1147,6 +1182,11 @@ impl<'a> Context<'a> {
11471182 let args = self . bump . alloc_slice_copy ( args) ;
11481183 self . make_term ( table:: Term :: Apply ( symbol, args) )
11491184 }
1185+
1186+ /// Creates a mangled name for a particular node.
1187+ fn mangled_name ( & self , node : Node ) -> & ' a str {
1188+ bumpalo:: format!( in & self . bump, "_{}" , node. index( ) ) . into_bump_str ( )
1189+ }
11501190}
11511191
11521192type FxIndexSet < T > = indexmap:: IndexSet < T , FxBuildHasher > ;
0 commit comments