Skip to content

Commit 373b8c9

Browse files
committed
code gen fixes
1 parent e610bf0 commit 373b8c9

File tree

3 files changed

+329
-61
lines changed

3 files changed

+329
-61
lines changed

src/codegen_yul.zig

Lines changed: 211 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)