Skip to content

Commit d5dafd5

Browse files
committed
fix: resolve extern function linking and ZRTL signature issues
- lowering.rs: propagate link_name from TypedFunction to HirFunction - cranelift_backend: use link_name when declaring extern function imports - grammar2.rs: change debug output to log::debug/warn - zrtl_image: add function signatures for all exported symbols - zrtl_io: add signatures for string print functions (i64 -> void) - imagepipe.zyn: use $IO$println for string literal printing
1 parent 1efd747 commit d5dafd5

6 files changed

Lines changed: 133 additions & 52 deletions

File tree

crates/compiler/src/cranelift_backend.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -351,8 +351,14 @@ impl CraneliftBackend {
351351

352352
if function.is_external {
353353
// External functions use Import linkage
354-
let link_name = function.name.resolve_global()
355-
.unwrap_or_else(|| format!("{:?}", function.name));
354+
// Use link_name if specified (maps alias to actual symbol, e.g., "image_load" -> "$Image$load")
355+
// Otherwise fall back to function name
356+
let link_name = function.link_name.as_ref()
357+
.map(|s| s.clone())
358+
.unwrap_or_else(|| {
359+
function.name.resolve_global()
360+
.unwrap_or_else(|| format!("{:?}", function.name))
361+
});
356362
let func_id = self.module.declare_function(
357363
&link_name,
358364
Linkage::Import,

crates/compiler/src/lowering.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -883,6 +883,14 @@ impl LoweringContext {
883883
// Set calling convention
884884
hir_func.calling_convention = self.convert_calling_convention(func.calling_convention);
885885

886+
// Set link_name if specified (maps alias to actual symbol)
887+
// e.g., "image_load" -> "$Image$load"
888+
if let Some(ref link_name) = func.link_name {
889+
let link_name_str = link_name.resolve_global()
890+
.unwrap_or_else(|| link_name.to_string());
891+
hir_func.link_name = Some(link_name_str);
892+
}
893+
886894
// Extern functions have no body - clear the default entry block
887895
hir_func.blocks.clear();
888896

crates/zyntax_embed/src/grammar2.rs

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -143,12 +143,17 @@ impl Grammar2 {
143143
let mut program = self.parse_with_filename(source, filename)?;
144144

145145
// Inject extern function declarations for builtins
146+
// This adds both alias names (e.g., image_load) and symbol names (e.g., $Image$load)
146147
self.inject_builtin_externs(&mut program, Some(signatures))?;
147148

148149
Ok(program)
149150
}
150151

151152
/// Inject extern function declarations for all builtins from @builtin directive
153+
///
154+
/// Creates TWO extern declarations for each builtin:
155+
/// 1. The alias name (e.g., `image_load`) with link_name pointing to symbol
156+
/// 2. The symbol name (e.g., `$Image$load`) for direct calls
152157
fn inject_builtin_externs(
153158
&self,
154159
program: &mut TypedProgram,
@@ -160,22 +165,32 @@ impl Grammar2 {
160165

161166
// Iterate over all builtins from @builtin directive
162167
for (source_name, target_symbol) in &self.grammar.builtins.functions {
168+
log::debug!("[Grammar2] Processing builtin: {} -> {}", source_name, target_symbol);
169+
163170
// Get return type from @types.function_returns if available
164171
let return_type = if let Some(type_str) = self.grammar.type_decls.function_returns.get(source_name) {
172+
log::debug!("[Grammar2] Found @types.function_returns for {}: {}", source_name, type_str);
165173
Type::Extern {
166174
name: InternedString::new_global(type_str),
167175
layout: None,
168176
}
169177
} else if let Some(sigs) = signatures {
170-
sigs.get(target_symbol.as_str())
171-
.map(|sig| Self::type_tag_to_type(&sig.return_type))
172-
.unwrap_or(Type::Any)
178+
if let Some(sig) = sigs.get(target_symbol.as_str()) {
179+
log::debug!("[Grammar2] Found ZRTL signature for {}: params={}, return={:?}",
180+
target_symbol, sig.param_count, sig.return_type);
181+
Self::type_tag_to_type(&sig.return_type)
182+
} else {
183+
log::warn!("[Grammar2] No ZRTL signature found for {}, using Type::Any. Available keys: {:?}",
184+
target_symbol, sigs.keys().collect::<Vec<_>>());
185+
Type::Any
186+
}
173187
} else {
188+
log::debug!("[Grammar2] No signatures provided, using Type::Any");
174189
Type::Any
175190
};
176191

177192
// Get parameters from signature if available
178-
let params = if let Some(sigs) = signatures {
193+
let params: Vec<TypedParameter> = if let Some(sigs) = signatures {
179194
if let Some(sig) = sigs.get(target_symbol.as_str()) {
180195
(0..sig.param_count)
181196
.map(|i| {
@@ -198,26 +213,47 @@ impl Grammar2 {
198213
vec![]
199214
};
200215

201-
// Create extern function declaration
202-
let extern_func = TypedFunction {
203-
name: InternedString::new_global(target_symbol),
216+
// 1. Create alias extern (e.g., image_load -> links to $Image$load)
217+
// This is what the grammar's generated AST calls
218+
let alias_func = TypedFunction {
219+
name: InternedString::new_global(source_name),
204220
type_params: vec![],
205-
params,
206-
return_type,
221+
params: params.clone(),
222+
return_type: return_type.clone(),
207223
body: None,
208224
visibility: Visibility::Public,
209225
is_async: false,
210226
is_external: true,
211227
calling_convention: CallingConvention::Default,
212228
link_name: Some(InternedString::new_global(target_symbol)),
213229
};
214-
215-
// Add to program declarations
216230
program.declarations.push(typed_node(
217-
TypedDeclaration::Function(extern_func),
231+
TypedDeclaration::Function(alias_func),
218232
Type::Primitive(PrimitiveType::Unit),
219233
span,
220234
));
235+
236+
// 2. Create symbol extern (e.g., $Image$load) for direct calls
237+
// Skip if source_name == target_symbol (avoid duplicates)
238+
if source_name != target_symbol {
239+
let symbol_func = TypedFunction {
240+
name: InternedString::new_global(target_symbol),
241+
type_params: vec![],
242+
params,
243+
return_type,
244+
body: None,
245+
visibility: Visibility::Public,
246+
is_async: false,
247+
is_external: true,
248+
calling_convention: CallingConvention::Default,
249+
link_name: Some(InternedString::new_global(target_symbol)),
250+
};
251+
program.declarations.push(typed_node(
252+
TypedDeclaration::Function(symbol_func),
253+
Type::Primitive(PrimitiveType::Unit),
254+
span,
255+
));
256+
}
221257
}
222258

223259
Ok(())

examples/imagepipe/imagepipe.zyn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
image_invert: "$Image$invert",
3636

3737
// Console output (zrtl_io)
38+
// Use println which takes StringConstPtr for string literals
3839
println: "$IO$println",
3940
}
4041

plugins/zrtl_image/src/lib.rs

Lines changed: 63 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -690,44 +690,74 @@ pub extern "C" fn image_invert(handle: u64) -> u64 {
690690
zrtl_plugin! {
691691
name: "zrtl_image",
692692
symbols: [
693-
// Loading/Saving
694-
("$Image$load", image_load),
695-
("$Image$load_bytes", image_load_bytes),
696-
("$Image$load_bytes_format", image_load_bytes_format),
697-
("$Image$save", image_save),
698-
("$Image$save_format", image_save_format),
699-
("$Image$encode", image_encode),
700-
("$Image$encode_png", image_encode_png),
701-
("$Image$encode_jpeg", image_encode_jpeg),
702-
703-
// Creation/Info
704-
("$Image$create", image_create),
693+
// Loading/Saving (with signatures)
694+
// Functions with opaque params (StringPtr/ArrayPtr) use dynamic boxing
695+
// image_load(path: StringPtr) -> u64 (handle)
696+
("$Image$load", image_load, dynamic(1) -> void),
697+
// image_load_bytes(data: ArrayPtr) -> u64
698+
("$Image$load_bytes", image_load_bytes, dynamic(1) -> void),
699+
// image_load_bytes_format(data: ArrayPtr, format: i32) -> u64
700+
("$Image$load_bytes_format", image_load_bytes_format, dynamic(2) -> void),
701+
// image_save(handle: u64, path: StringPtr) -> void
702+
("$Image$save", image_save, dynamic(2) -> void),
703+
// image_save_format(handle: u64, path: StringPtr, format: i32) -> i32
704+
("$Image$save_format", image_save_format, dynamic(3) -> void),
705+
// image_encode(handle: u64, format: i32) -> ArrayPtr
706+
("$Image$encode", image_encode, dynamic(2) -> dynamic),
707+
// image_encode_png(handle: u64) -> ArrayPtr
708+
("$Image$encode_png", image_encode_png, dynamic(1) -> dynamic),
709+
// image_encode_jpeg(handle: u64, quality: u8) -> ArrayPtr
710+
("$Image$encode_jpeg", image_encode_jpeg, dynamic(2) -> dynamic),
711+
712+
// Creation/Info (with signatures)
713+
// image_create(width: u32, height: u32) -> u64
714+
("$Image$create", image_create, (u32, u32) -> u64),
715+
// image_create_filled(width: u32, height: u32, color: Color) -> u64
716+
// Note: Color is a struct, no signature for now
705717
("$Image$create_filled", image_create_filled),
706-
("$Image$free", image_free),
707-
("$Image$clone", image_clone),
708-
("$Image$width", image_width),
709-
("$Image$height", image_height),
710-
711-
// Pixel operations
718+
// image_free(handle: u64) -> void
719+
("$Image$free", image_free, (u64) -> void),
720+
// image_clone(handle: u64) -> u64
721+
("$Image$clone", image_clone, (u64) -> u64),
722+
// image_width(handle: u64) -> u32
723+
("$Image$width", image_width, (u64) -> u32),
724+
// image_height(handle: u64) -> u32
725+
("$Image$height", image_height, (u64) -> u32),
726+
727+
// Pixel operations (some without signatures due to struct params)
712728
("$Image$get_pixel", image_get_pixel),
713729
("$Image$set_pixel", image_set_pixel),
714-
("$Image$get_pixels", image_get_pixels),
730+
// image_get_pixels(handle: u64) -> ArrayPtr
731+
("$Image$get_pixels", image_get_pixels, dynamic(1) -> dynamic),
715732
("$Image$set_pixels", image_set_pixels),
716733

717-
// Manipulation
718-
("$Image$resize", image_resize),
719-
("$Image$resize_fit", image_resize_fit),
720-
("$Image$crop", image_crop),
721-
("$Image$rotate90", image_rotate90),
722-
("$Image$rotate180", image_rotate180),
723-
("$Image$rotate270", image_rotate270),
724-
("$Image$flip_horizontal", image_flip_horizontal),
725-
("$Image$flip_vertical", image_flip_vertical),
726-
("$Image$grayscale", image_grayscale),
727-
("$Image$blur", image_blur),
728-
("$Image$brighten", image_brighten),
729-
("$Image$contrast", image_contrast),
730-
("$Image$invert", image_invert),
734+
// Manipulation (with signatures)
735+
// image_resize(handle: u64, width: u32, height: u32) -> u64
736+
("$Image$resize", image_resize, (u64, u32, u32) -> u64),
737+
// image_resize_fit(handle: u64, max_width: u32, max_height: u32) -> u64
738+
("$Image$resize_fit", image_resize_fit, (u64, u32, u32) -> u64),
739+
// image_crop(handle: u64, x: u32, y: u32, width: u32, height: u32) -> u64
740+
("$Image$crop", image_crop, (u64, u32, u32, u32, u32) -> u64),
741+
// image_rotate90(handle: u64) -> u64
742+
("$Image$rotate90", image_rotate90, (u64) -> u64),
743+
// image_rotate180(handle: u64) -> u64
744+
("$Image$rotate180", image_rotate180, (u64) -> u64),
745+
// image_rotate270(handle: u64) -> u64
746+
("$Image$rotate270", image_rotate270, (u64) -> u64),
747+
// image_flip_horizontal(handle: u64) -> u64
748+
("$Image$flip_horizontal", image_flip_horizontal, (u64) -> u64),
749+
// image_flip_vertical(handle: u64) -> u64
750+
("$Image$flip_vertical", image_flip_vertical, (u64) -> u64),
751+
// image_grayscale(handle: u64) -> u64
752+
("$Image$grayscale", image_grayscale, (u64) -> u64),
753+
// image_blur(handle: u64, sigma: f32) -> u64
754+
("$Image$blur", image_blur, (u64, f32) -> u64),
755+
// image_brighten(handle: u64, value: i32) -> u64
756+
("$Image$brighten", image_brighten, (u64, i32) -> u64),
757+
// image_contrast(handle: u64, value: f32) -> u64
758+
("$Image$contrast", image_contrast, (u64, f32) -> u64),
759+
// image_invert(handle: u64) -> u64
760+
("$Image$invert", image_invert, (u64) -> u64),
731761
]
732762
}
733763

plugins/zrtl_io/src/lib.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -839,11 +839,11 @@ pub unsafe extern "C" fn io_string_concat(a: StringConstPtr, b: StringConstPtr)
839839
zrtl_plugin! {
840840
name: "zrtl_io",
841841
symbols: [
842-
// String output (ZRTL string format)
843-
("$IO$print", io_print),
844-
("$IO$println", io_println),
845-
("$IO$eprint", io_eprint),
846-
("$IO$eprintln", io_eprintln),
842+
// String output (ZRTL string format) - takes StringConstPtr (i64 pointer)
843+
("$IO$print", io_print, (i64) -> void),
844+
("$IO$println", io_println, (i64) -> void),
845+
("$IO$eprint", io_eprint, (i64) -> void),
846+
("$IO$eprintln", io_eprintln, (i64) -> void),
847847

848848
// Primitive output
849849
("$IO$print_i64", io_print_i64),

0 commit comments

Comments
 (0)