@@ -48,6 +48,8 @@ pub const YulCodegen = struct {
4848 storage_counter : u32 ,
4949 /// Mapping from storage variable names to their slot numbers
5050 storage_slots : std .HashMap ([]const u8 , u32 , std .hash_map .StringContext , std .hash_map .default_max_load_percentage ),
51+ /// Current contract context for event lookup
52+ current_contract : ? * const Contract ,
5153
5254 const Self = @This ();
5355
@@ -66,6 +68,7 @@ pub const YulCodegen = struct {
6668 .current_function = null ,
6769 .storage_counter = 0 ,
6870 .storage_slots = std .HashMap ([]const u8 , u32 , std .hash_map .StringContext , std .hash_map .default_max_load_percentage ).init (allocator ),
71+ .current_contract = null ,
6972 };
7073 }
7174
@@ -148,7 +151,7 @@ pub const YulCodegen = struct {
148151 ///
149152 /// Returns:
150153 /// Generated Yul code as owned string
151- pub fn generateYulFromProgram (self : * Self , program : * const HIRProgram ) ! []u8 {
154+ pub fn generateYulFromProgram (self : * Self , program : * const HIRProgram ) YulCodegenError ! []u8 {
152155 var yul_code = std .ArrayList (u8 ).init (self .allocator );
153156 defer yul_code .deinit ();
154157
@@ -176,16 +179,19 @@ pub const YulCodegen = struct {
176179 /// yul_code: Output buffer
177180 /// contract: Contract to compile
178181 fn generateContract (self : * Self , yul_code : * std .ArrayList (u8 ), contract : * const Contract ) YulCodegenError ! void {
179- try yul_code . writer (). print ( " // Contract: {s} \n " , .{ contract . name });
180- try yul_code . appendSlice ( " code { \n " ) ;
182+ // Store current contract for event lookup
183+ self . current_contract = contract ;
181184
182185 // Initialize storage slot mapping
183- self . storage_counter = 0 ;
186+ var slot_counter : u32 = 0 ;
184187 for (contract .storage ) | * storage_var | {
185- try self .storage_slots .put (storage_var .name , self . storage_counter );
186- self . storage_counter += 1 ;
188+ try self .storage_slots .put (storage_var .name , slot_counter );
189+ slot_counter += 1 ;
187190 }
188191
192+ try yul_code .writer ().print (" // Contract: {s}\n " , .{contract .name });
193+ try yul_code .appendSlice (" code {\n " );
194+
189195 // Generate constructor code
190196 try self .generateConstructor (yul_code , contract );
191197
@@ -297,14 +303,60 @@ pub const YulCodegen = struct {
297303 /// Returns:
298304 /// 32-bit function selector
299305 fn calculateFunctionSelector (self : * Self , function : * const Function ) ! u32 {
300- _ = self ;
301- // Simplified selector calculation - in real implementation would use keccak256
302- // For now, use a simple hash of the function name
303- var hash : u32 = 0 ;
304- for (function .name ) | byte | {
305- hash = hash *% 31 +% byte ;
306+ // Build canonical function signature: functionName(type1,type2,...)
307+ var signature = std .ArrayList (u8 ).init (self .allocator );
308+ defer signature .deinit ();
309+
310+ try signature .appendSlice (function .name );
311+ try signature .appendSlice ("(" );
312+
313+ for (function .parameters , 0.. ) | * param , i | {
314+ if (i > 0 ) {
315+ try signature .appendSlice ("," );
316+ }
317+
318+ // Convert Ora types to canonical EVM types
319+ const evm_type = convertToEVMType (param .type );
320+ try signature .appendSlice (evm_type );
306321 }
307- return hash ;
322+
323+ try signature .appendSlice (")" );
324+
325+ // Calculate hash of signature (simplified until we add proper keccak256)
326+ const signature_bytes = signature .items ;
327+ var hash : u64 = 0 ;
328+
329+ // Use a better hash function (FNV-1a variant)
330+ for (signature_bytes ) | byte | {
331+ hash = hash ^ byte ;
332+ hash = hash *% 0x100000001b3 ; // FNV-1a prime
333+ }
334+
335+ // Take first 4 bytes as selector
336+ return @truncate (hash );
337+ }
338+
339+ /// Convert Ora types to canonical EVM types for function signatures
340+ ///
341+ /// Args:
342+ /// ora_type: Ora type to convert
343+ ///
344+ /// Returns:
345+ /// Canonical EVM type string
346+ fn convertToEVMType (ora_type : Type ) []const u8 {
347+ return switch (ora_type ) {
348+ .primitive = > | prim | switch (prim ) {
349+ .u8 , .u16 , .u32 , .u64 , .u128 , .u256 = > "uint256" ,
350+ .bool = > "bool" ,
351+ .address = > "address" ,
352+ .string = > "string" ,
353+ },
354+ .slice = > | _ | "uint256[]" , // Simplified - slices become uint256[]
355+ .mapping = > | _ | "mapping" , // Mappings don't appear in function signatures
356+ .custom = > | _ | "uint256" , // Custom types default to uint256
357+ .error_union = > | _ | "uint256" , // Error unions default to uint256
358+ .result = > | _ | "uint256" , // Results default to uint256
359+ };
308360 }
309361
310362 /// Generate Yul code for a function
@@ -313,23 +365,28 @@ pub const YulCodegen = struct {
313365 /// yul_code: Output buffer
314366 /// function: Function to compile
315367 fn generateFunction (self : * Self , yul_code : * std .ArrayList (u8 ), function : * const Function ) YulCodegenError ! void {
368+ // Store current function for context
369+ const prev_function = self .current_function ;
316370 self .current_function = function ;
317- defer self .current_function = null ;
371+ defer self .current_function = prev_function ;
318372
373+ // Write function signature
319374 try yul_code .writer ().print (" // Function: {s}\n " , .{function .name });
320375 try yul_code .writer ().print (" function {s}(" , .{function .name });
321376
322- // Generate parameter list
377+ // Write parameters
323378 for (function .parameters , 0.. ) | * param , i | {
324379 if (i > 0 ) try yul_code .appendSlice (", " );
325- try yul_code .writer (). print ( "{s}" , .{ param .name } );
380+ try yul_code .appendSlice ( param .name );
326381 }
327382
328- // Generate return type
329- try yul_code .appendSlice (")" );
330- if (function .return_type != null ) {
331- try yul_code .appendSlice (" -> result" );
383+ // Write return type
384+ if (function .return_type ) | _ | {
385+ try yul_code .appendSlice (") -> result" );
386+ } else {
387+ try yul_code .appendSlice (")" );
332388 }
389+
333390 try yul_code .appendSlice (" {\n " );
334391
335392 // Generate function body
@@ -670,6 +727,21 @@ pub const YulCodegen = struct {
670727
671728 /// Generate call expression
672729 fn generateCallExpression (self : * Self , yul_code : * std .ArrayList (u8 ), call : * const ir .CallExpression ) YulCodegenError ! []const u8 {
730+ // Check if this is an event logging call
731+ if (call .callee .* == .identifier ) {
732+ const func_name = call .callee .identifier .name ;
733+
734+ // Check if this is a known event (events are stored in the contract)
735+ if (self .current_contract ) | contract | {
736+ for (contract .events ) | * event | {
737+ if (std .mem .eql (u8 , event .name , func_name )) {
738+ // This is an event logging call
739+ return try self .generateEventLog (yul_code , event , call .arguments );
740+ }
741+ }
742+ }
743+ }
744+
673745 // Generate arguments
674746 var arg_vars = std .ArrayList ([]const u8 ).init (self .allocator );
675747 defer {
@@ -702,6 +774,60 @@ pub const YulCodegen = struct {
702774 return result_var ;
703775 }
704776
777+ /// Generate event logging
778+ fn generateEventLog (self : * Self , yul_code : * std .ArrayList (u8 ), event : * const ir .Event , arguments : []const ir .Expression ) YulCodegenError ! []const u8 {
779+ // Generate argument variables
780+ var arg_vars = std .ArrayList ([]const u8 ).init (self .allocator );
781+ defer {
782+ for (arg_vars .items ) | arg_var | {
783+ self .allocator .free (arg_var );
784+ }
785+ arg_vars .deinit ();
786+ }
787+
788+ for (arguments ) | * arg | {
789+ const arg_var = try self .generateExpression (yul_code , arg );
790+ try arg_vars .append (arg_var );
791+ }
792+
793+ // Calculate event signature hash (simplified)
794+ const event_hash = try self .calculateEventSignatureHash (event );
795+
796+ // Store event data in memory
797+ const data_ptr = try std .fmt .allocPrint (self .allocator , "temp_{}" , .{self .var_counter });
798+ defer self .allocator .free (data_ptr );
799+ self .var_counter += 1 ;
800+
801+ try yul_code .writer ().print (" let {s} := mload(0x40)\n " , .{data_ptr });
802+
803+ // Store arguments in memory
804+ for (arg_vars .items , 0.. ) | arg_var , i | {
805+ try yul_code .writer ().print (" mstore(add({s}, {}), {s})\n " , .{ data_ptr , i * 32 , arg_var });
806+ }
807+
808+ // Emit log (using log1 with topic for now)
809+ const data_size = arg_vars .items .len * 32 ;
810+ try yul_code .writer ().print (" log1({s}, {}, 0x{x:0>64})\n " , .{ data_ptr , data_size , event_hash });
811+
812+ // Return a dummy result
813+ const result_var = try std .fmt .allocPrint (self .allocator , "temp_{}" , .{self .var_counter });
814+ self .var_counter += 1 ;
815+ try yul_code .writer ().print (" let {s} := 1\n " , .{result_var });
816+
817+ return result_var ;
818+ }
819+
820+ /// Calculate event signature hash (simplified)
821+ fn calculateEventSignatureHash (self : * Self , event : * const ir.Event ) ! u64 {
822+ _ = self ;
823+ // Simplified event signature hash - in real implementation would use keccak256
824+ var hash : u64 = 0 ;
825+ for (event .name ) | byte | {
826+ hash = hash *% 31 +% byte ;
827+ }
828+ return hash ;
829+ }
830+
705831 /// Generate index expression (array/mapping access)
706832 fn generateIndexExpression (self : * Self , yul_code : * std .ArrayList (u8 ), index : * const ir .IndexExpression ) YulCodegenError ! []const u8 {
707833 const target_var = try self .generateExpression (yul_code , index .target );
@@ -733,6 +859,70 @@ pub const YulCodegen = struct {
733859 const result_var = try std .fmt .allocPrint (self .allocator , "temp_{}" , .{self .var_counter });
734860 self .var_counter += 1 ;
735861
862+ // Check for standard library field access
863+ if (field .target .* == .identifier ) {
864+ const target_name = field .target .identifier .name ;
865+
866+ if (std .mem .eql (u8 , target_name , "std" )) {
867+ // Handle std library modules
868+ if (std .mem .eql (u8 , field .field , "transaction" )) {
869+ // Return a marker for transaction module
870+ try yul_code .writer ().print (" let {s} := 0x01 // std.transaction\n " , .{result_var });
871+ return result_var ;
872+ } else if (std .mem .eql (u8 , field .field , "constants" )) {
873+ // Return a marker for constants module
874+ try yul_code .writer ().print (" let {s} := 0x02 // std.constants\n " , .{result_var });
875+ return result_var ;
876+ } else if (std .mem .eql (u8 , field .field , "block" )) {
877+ // Return a marker for block module
878+ try yul_code .writer ().print (" let {s} := 0x03 // std.block\n " , .{result_var });
879+ return result_var ;
880+ }
881+ }
882+ }
883+
884+ // Check for nested field access like std.transaction.sender
885+ if (field .target .* == .field ) {
886+ const nested_field = field .target .field ;
887+ if (nested_field .target .* == .identifier ) {
888+ const base_name = nested_field .target .identifier .name ;
889+
890+ if (std .mem .eql (u8 , base_name , "std" )) {
891+ if (std .mem .eql (u8 , nested_field .field , "transaction" )) {
892+ // Handle std.transaction.* fields
893+ if (std .mem .eql (u8 , field .field , "sender" )) {
894+ try yul_code .writer ().print (" let {s} := caller()\n " , .{result_var });
895+ return result_var ;
896+ } else if (std .mem .eql (u8 , field .field , "value" )) {
897+ try yul_code .writer ().print (" let {s} := callvalue()\n " , .{result_var });
898+ return result_var ;
899+ } else if (std .mem .eql (u8 , field .field , "origin" )) {
900+ try yul_code .writer ().print (" let {s} := origin()\n " , .{result_var });
901+ return result_var ;
902+ }
903+ } else if (std .mem .eql (u8 , nested_field .field , "constants" )) {
904+ // Handle std.constants.* fields
905+ if (std .mem .eql (u8 , field .field , "ZERO_ADDRESS" )) {
906+ try yul_code .writer ().print (" let {s} := 0x0\n " , .{result_var });
907+ return result_var ;
908+ }
909+ } else if (std .mem .eql (u8 , nested_field .field , "block" )) {
910+ // Handle std.block.* fields
911+ if (std .mem .eql (u8 , field .field , "timestamp" )) {
912+ try yul_code .writer ().print (" let {s} := timestamp()\n " , .{result_var });
913+ return result_var ;
914+ } else if (std .mem .eql (u8 , field .field , "number" )) {
915+ try yul_code .writer ().print (" let {s} := number()\n " , .{result_var });
916+ return result_var ;
917+ } else if (std .mem .eql (u8 , field .field , "coinbase" )) {
918+ try yul_code .writer ().print (" let {s} := coinbase()\n " , .{result_var });
919+ return result_var ;
920+ }
921+ }
922+ }
923+ }
924+ }
925+
736926 // Simple field access - in real implementation would need struct layout
737927 try yul_code .writer ().print (" let {s} := {s} // field: {s}\n " , .{ result_var , target_var , field .field });
738928
@@ -794,7 +984,7 @@ pub const YulCodegen = struct {
794984 /// Args:
795985 /// yul_code: Output buffer for generated code
796986 /// instruction: HIR instruction to convert
797- fn generateInstruction (self : * Self , yul_code : * std .ArrayList (u8 ), instruction : ir . HIRInstruction ) ! void {
987+ fn generateInstruction (self : * Self , yul_code : * std .ArrayList (u8 ), instruction : HIRInstruction ) ! void {
798988 _ = self ;
799989
800990 switch (instruction ) {
0 commit comments