@@ -49,7 +49,7 @@ pub use zyntax_typed_ast::{
4949 TypedASTBuilder , TypedProgram , TypedNode , TypedDeclaration , TypedExpression ,
5050 TypedStatement , TypedBlock , BinaryOp , UnaryOp , Span , InternedString ,
5151 TypedClass , TypedEnum , TypedField , TypedVariant ,
52- typed_ast:: { TypedVariantFields , TypedMatchExpr , TypedMatchArm , TypedPattern , TypedLiteralPattern , TypedLiteral , TypedFieldPattern , TypedMethod , TypedMethodParam , TypedTypeParam , ParameterKind , ParameterAttribute , TypedRange } ,
52+ typed_ast:: { TypedVariantFields , TypedMatchExpr , TypedMatchArm , TypedPattern , TypedLiteralPattern , TypedLiteral , TypedFieldPattern , TypedMethod , TypedMethodParam , TypedTypeParam , ParameterKind , ParameterAttribute , TypedRange , TypedExtern , TypedExternStruct } ,
5353 type_registry:: { Type , PrimitiveType , Mutability , Visibility , ConstValue } ,
5454} ;
5555
@@ -291,6 +291,9 @@ pub trait AstHostFunctions {
291291 items : Vec < NodeHandle > ,
292292 ) -> NodeHandle ;
293293
294+ /// Create an opaque type declaration (@opaque("$ExternName") type TypeName)
295+ fn create_opaque_type ( & mut self , name : & str , external_name : & str ) -> NodeHandle ;
296+
294297 /// Create a function parameter
295298 fn create_param ( & mut self , name : & str , ty : NodeHandle ) -> NodeHandle ;
296299
@@ -374,6 +377,11 @@ pub trait AstHostFunctions {
374377 None // Default implementation returns None
375378 }
376379
380+ /// Get the value of a string literal node, if it is one
381+ fn get_string_literal_value ( & self , handle : NodeHandle ) -> Option < String > {
382+ None // Default implementation returns None
383+ }
384+
377385 /// Allocate a new node handle
378386 fn alloc_handle ( & mut self ) -> NodeHandle ;
379387
@@ -1105,6 +1113,8 @@ pub struct TypedAstBuilder {
11051113 variable_types : HashMap < String , Type > ,
11061114 /// Enum type name to variant names (in order, for discriminant calculation)
11071115 enum_types : HashMap < String , Vec < String > > ,
1116+ /// Opaque/extern type name to external name mapping (e.g., "Tensor" -> "$Tensor")
1117+ opaque_types : HashMap < String , InternedString > ,
11081118 /// Program declaration handles (in order)
11091119 program_decls : Vec < NodeHandle > ,
11101120 /// Current span being processed (start, end)
@@ -1137,6 +1147,7 @@ impl TypedAstBuilder {
11371147 types : HashMap :: new ( ) ,
11381148 variable_types : HashMap :: new ( ) ,
11391149 enum_types : HashMap :: new ( ) ,
1150+ opaque_types : HashMap :: new ( ) ,
11401151 program_decls : Vec :: new ( ) ,
11411152 current_span : ( 0 , 0 ) ,
11421153 }
@@ -1366,6 +1377,9 @@ impl AstHostFunctions for TypedAstBuilder {
13661377 let typed_params: Vec < _ > = params. iter ( )
13671378 . map ( |h| {
13681379 if let Some ( ( name, ty) ) = self . params . get ( h) {
1380+ // Register parameter type in variable_types for later variable references
1381+ self . variable_types . insert ( name. clone ( ) , ty. clone ( ) ) ;
1382+ eprintln ! ( "[DEBUG create_function] Registered parameter '{}' with type {:?}" , name, ty) ;
13691383 self . inner . parameter ( name, ty. clone ( ) , Mutability :: Immutable , span)
13701384 } else {
13711385 // Fallback for unknown params
@@ -1590,11 +1604,42 @@ impl AstHostFunctions for TypedAstBuilder {
15901604 self . store_decl ( impl_decl)
15911605 }
15921606
1607+ fn create_opaque_type ( & mut self , name : & str , external_name : & str ) -> NodeHandle {
1608+ // Create an external struct declaration for the opaque type
1609+ // This declares a type like: extern struct Tensor (backed by $Tensor)
1610+ let name_interned = self . inner . intern ( name) ;
1611+ let runtime_prefix = self . inner . intern ( external_name) ;
1612+
1613+ // Register the opaque type mapping for later type resolution
1614+ self . opaque_types . insert ( name. to_string ( ) , runtime_prefix) ;
1615+ eprintln ! ( "[DEBUG create_opaque_type] Registered opaque type: '{}' -> '{}'" , name, external_name) ;
1616+
1617+ let extern_struct = TypedExternStruct {
1618+ name : name_interned,
1619+ runtime_prefix,
1620+ type_params : vec ! [ ] , // No type parameters for now
1621+ } ;
1622+
1623+ let decl = TypedDeclaration :: Extern ( TypedExtern :: Struct ( extern_struct) ) ;
1624+ let decl_node = TypedNode {
1625+ node : decl,
1626+ span : self . default_span ( ) ,
1627+ ty : Type :: Never , // Declarations don't have a type
1628+ } ;
1629+
1630+ self . store_decl ( decl_node)
1631+ }
1632+
15931633 fn create_param ( & mut self , name : & str , ty : NodeHandle ) -> NodeHandle {
15941634 // Store parameter name and type for later use in create_function
15951635 let handle = self . alloc_handle ( ) ;
15961636 // Get the type from the type handle, default to i32 if not found
15971637 let param_type = self . get_type_from_handle ( ty) . unwrap_or ( Type :: Primitive ( PrimitiveType :: I32 ) ) ;
1638+ // IMPORTANT: Register parameter type IMMEDIATELY so that variable references
1639+ // in the function body (which is parsed after params but before create_function is called)
1640+ // can find the correct type
1641+ self . variable_types . insert ( name. to_string ( ) , param_type. clone ( ) ) ;
1642+ eprintln ! ( "[DEBUG create_param] Registered parameter '{}' with type {:?}" , name, param_type) ;
15981643 self . params . insert ( handle, ( name. to_string ( ) , param_type) ) ;
15991644 handle
16001645 }
@@ -1673,7 +1718,22 @@ impl AstHostFunctions for TypedAstBuilder {
16731718
16741719 fn create_identifier ( & mut self , name : & str ) -> NodeHandle {
16751720 let span = self . default_span ( ) ;
1676- let expr = self . inner . variable ( name, Type :: Primitive ( PrimitiveType :: I32 ) , span) ;
1721+
1722+ // Look up the variable's actual type from our tracking map
1723+ // If not found, check opaque types, then default to I32
1724+ let var_type = if let Some ( ty) = self . variable_types . get ( name) {
1725+ ty. clone ( )
1726+ } else if let Some ( runtime_prefix) = self . opaque_types . get ( name) {
1727+ Type :: Extern {
1728+ name : * runtime_prefix,
1729+ layout : None ,
1730+ }
1731+ } else {
1732+ Type :: Primitive ( PrimitiveType :: I32 )
1733+ } ;
1734+
1735+ eprintln ! ( "[DEBUG create_identifier] Variable '{}' has type {:?}" , name, var_type) ;
1736+ let expr = self . inner . variable ( name, var_type, span) ;
16771737 self . store_expr ( expr)
16781738 }
16791739
@@ -2043,7 +2103,19 @@ impl AstHostFunctions for TypedAstBuilder {
20432103 "f64" => Type :: Primitive ( PrimitiveType :: F64 ) ,
20442104 "bool" => Type :: Primitive ( PrimitiveType :: Bool ) ,
20452105 "void" | "unit" => Type :: Primitive ( PrimitiveType :: Unit ) ,
2046- _ => Type :: Primitive ( PrimitiveType :: I32 ) , // Default to i32
2106+ _ => {
2107+ // Check if this is a registered opaque/extern type
2108+ if let Some ( runtime_prefix) = self . opaque_types . get ( name) {
2109+ eprintln ! ( "[DEBUG create_primitive_type] Found opaque type '{}' -> '{}'" , name, runtime_prefix. resolve_global( ) . unwrap_or_default( ) ) ;
2110+ Type :: Extern {
2111+ name : * runtime_prefix,
2112+ layout : None ,
2113+ }
2114+ } else {
2115+ eprintln ! ( "[DEBUG create_primitive_type] Type '{}' not found in opaque types, defaulting to I32" , name) ;
2116+ Type :: Primitive ( PrimitiveType :: I32 ) // Default to i32
2117+ }
2118+ }
20472119 } ;
20482120 self . types . insert ( handle, ty) ;
20492121 handle
@@ -2065,8 +2137,31 @@ impl AstHostFunctions for TypedAstBuilder {
20652137 self . alloc_handle ( )
20662138 }
20672139
2068- fn create_named_type ( & mut self , _name : & str ) -> NodeHandle {
2069- self . alloc_handle ( )
2140+ fn create_named_type ( & mut self , name : & str ) -> NodeHandle {
2141+ let handle = self . alloc_handle ( ) ;
2142+
2143+ // Check if this is a registered opaque/extern type
2144+ let ty = if let Some ( runtime_prefix) = self . opaque_types . get ( name) {
2145+ eprintln ! ( "[DEBUG create_named_type] Found opaque type '{}' -> '{}'" , name, runtime_prefix. resolve_global( ) . unwrap_or_default( ) ) ;
2146+ Type :: Extern {
2147+ name : * runtime_prefix,
2148+ layout : None ,
2149+ }
2150+ } else {
2151+ eprintln ! ( "[DEBUG create_named_type] Type '{}' not found in opaque types, using Named with placeholder ID" , name) ;
2152+ // Create a named type with placeholder ID (0)
2153+ // Type inference will resolve this to the actual TypeId
2154+ Type :: Named {
2155+ id : zyntax_typed_ast:: TypeId :: new ( 0 ) ,
2156+ type_args : vec ! [ ] ,
2157+ const_args : vec ! [ ] ,
2158+ variance : vec ! [ ] ,
2159+ nullability : zyntax_typed_ast:: type_registry:: NullabilityKind :: NonNull ,
2160+ }
2161+ } ;
2162+
2163+ self . types . insert ( handle, ty) ;
2164+ handle
20702165 }
20712166
20722167 fn create_struct ( & mut self , name : & str , field_handles : Vec < NodeHandle > ) -> NodeHandle {
@@ -2410,6 +2505,7 @@ impl AstHostFunctions for TypedAstBuilder {
24102505 let var_type = self . variable_types . get ( name)
24112506 . cloned ( )
24122507 . unwrap_or ( Type :: Primitive ( PrimitiveType :: I32 ) ) ;
2508+ eprintln ! ( "[DEBUG create_variable] Variable '{}' has type {:?}" , name, var_type) ;
24132509 let expr = self . inner . variable ( name, var_type, span) ;
24142510 self . store_expr ( expr)
24152511 }
@@ -2921,6 +3017,17 @@ impl AstHostFunctions for TypedAstBuilder {
29213017 }
29223018 None
29233019 }
3020+
3021+ fn get_string_literal_value ( & self , handle : NodeHandle ) -> Option < String > {
3022+ // Get the expression and check if it's a string literal
3023+ if let Some ( expr_node) = self . get_expr ( handle) {
3024+ if let TypedExpression :: Literal ( TypedLiteral :: String ( value) ) = & expr_node. node {
3025+ // Use resolve_global() to get the actual string value
3026+ return value. resolve_global ( ) ;
3027+ }
3028+ }
3029+ None
3030+ }
29243031}
29253032
29263033// ============================================================================
@@ -5254,6 +5361,49 @@ impl<'a, H: AstHostFunctions> CommandInterpreter<'a, H> {
52545361 Ok ( RuntimeValue :: Node ( handle) )
52555362 }
52565363
5364+ "opaque_type" => {
5365+ // @opaque("$Tensor") type Tensor
5366+ // Declares an opaque/extern type backed by external implementation
5367+
5368+ // Get the full matched text to extract both external name and type name
5369+ let text = match args. get ( "text" ) {
5370+ Some ( RuntimeValue :: String ( s) ) => s. clone ( ) ,
5371+ _ => {
5372+ return Err ( crate :: error:: ZynPegError :: CodeGenError ( "opaque_type: missing text" . into ( ) ) ) ;
5373+ }
5374+ } ;
5375+
5376+ // Parse text like: @opaque("$Tensor") type Tensor
5377+ // Extract the string between quotes for external_name
5378+ let external_name = if let Some ( start) = text. find ( '"' ) {
5379+ if let Some ( end) = text[ start + 1 ..] . find ( '"' ) {
5380+ text[ start + 1 ..start + 1 + end] . to_string ( )
5381+ } else {
5382+ return Err ( crate :: error:: ZynPegError :: CodeGenError ( "opaque_type: malformed external_name" . into ( ) ) ) ;
5383+ }
5384+ } else {
5385+ return Err ( crate :: error:: ZynPegError :: CodeGenError ( "opaque_type: missing external_name" . into ( ) ) ) ;
5386+ } ;
5387+
5388+ // Extract the identifier after "type"
5389+ let name = text. split_whitespace ( )
5390+ . last ( )
5391+ . unwrap_or ( "Unknown" )
5392+ . to_string ( ) ;
5393+
5394+ // FIXME: The grammar only captures the string literal text, not the full match
5395+ // For "@opaque("$Tensor") type Tensor", text is just "$Tensor"
5396+ // Since we can't get the actual type name, use the external_name without "$" prefix
5397+ let actual_name = external_name. trim_start_matches ( '$' ) ;
5398+ let actual_external_name = external_name. clone ( ) ;
5399+
5400+ eprintln ! ( "[DEBUG opaque_type] Using derived name='{}', external_name='{}'" , actual_name, actual_external_name) ;
5401+ log:: debug!( "[opaque_type] Creating opaque type: name='{}', external_name='{}'" , actual_name, actual_external_name) ;
5402+ let handle = self . host . create_opaque_type ( actual_name, & actual_external_name) ;
5403+ log:: debug!( "[opaque_type] Created opaque type with handle: {:?}" , handle) ;
5404+ Ok ( RuntimeValue :: Node ( handle) )
5405+ }
5406+
52575407 _ => {
52585408 Err ( crate :: error:: ZynPegError :: CodeGenError ( format ! ( "Unknown node type: {}" , node_type) ) )
52595409 }
0 commit comments