feat(llvm): Complete function call system implementation by ChatGPT5

Major improvements to LLVM backend function call infrastructure:

## Key Changes

### Function Call System Complete
- All MIR functions now properly lowered to LLVM (not just entry)
- Function parameter binding to LLVM arguments implemented
- ny_main() wrapper added for proper entry point handling
- Callee resolution from ValueId to function symbols working

### Call Instruction Analysis
- MirInstruction::Call was implemented but system was incomplete
- Fixed "rhs missing" errors caused by undefined Call return values
- Function calls now properly return values through the system

### Code Modularization (Ongoing)
- BoxCall → instructions/boxcall.rs ✓
- ExternCall → instructions/externcall.rs ✓
- Call remains in mod.rs (to be refactored)

### Phase 21 Documentation
- Added comprehensive AI evaluation from Gemini and Codex
- Both AIs confirm academic paper potential for self-parsing AST DB approach
- "Code as Database" concept validated as novel contribution

Co-authored-by: ChatGPT5 <noreply@openai.com>

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Selfhosting Dev
2025-09-12 01:45:00 +09:00
parent 4f4c6397a9
commit 40d0cac0f1
17 changed files with 2219 additions and 608 deletions

View File

@ -0,0 +1,126 @@
use std::collections::HashMap;
use inkwell::values::BasicValueEnum as BVE;
use inkwell::AddressSpace;
use crate::backend::llvm::context::CodegenContext;
use crate::mir::ValueId;
pub(super) fn lower_log_or_trace<'ctx>(
codegen: &CodegenContext<'ctx>,
vmap: &mut HashMap<ValueId, BVE<'ctx>>,
dst: &Option<ValueId>,
iface_name: &str,
method_name: &str,
args: &[ValueId],
) -> Result<(), String> {
if args.len() != 1 {
return Err(format!("{}.{} expects 1 arg", iface_name, method_name));
}
let av = *vmap.get(&args[0]).ok_or("extern arg missing")?;
match av {
// If argument is i8* (string), call string variant
BVE::PointerValue(pv) => {
let i8p = codegen.context.ptr_type(AddressSpace::from(0));
let fnty = codegen.context.i64_type().fn_type(&[i8p.into()], false);
let fname = if iface_name == "env.console" {
match method_name {
"log" => "nyash.console.log",
"warn" => "nyash.console.warn",
_ => "nyash.console.error",
}
} else {
"nyash.debug.trace"
};
let callee = codegen
.module
.get_function(fname)
.unwrap_or_else(|| codegen.module.add_function(fname, fnty, None));
let _ = codegen
.builder
.build_call(callee, &[pv.into()], "console_log_p")
.map_err(|e| e.to_string())?;
if let Some(d) = dst {
vmap.insert(*d, codegen.context.i64_type().const_zero().into());
}
Ok(())
}
// Otherwise, convert to i64 and call handle variant
_ => {
let arg_val = match av {
BVE::IntValue(iv) => {
if iv.get_type() == codegen.context.bool_type() {
codegen
.builder
.build_int_z_extend(iv, codegen.context.i64_type(), "bool2i64")
.map_err(|e| e.to_string())?
} else if iv.get_type() == codegen.context.i64_type() {
iv
} else {
codegen
.builder
.build_int_s_extend(iv, codegen.context.i64_type(), "int2i64")
.map_err(|e| e.to_string())?
}
}
BVE::PointerValue(_) => unreachable!(),
_ => return Err("console.log arg conversion failed".to_string()),
};
let fnty = codegen
.context
.i64_type()
.fn_type(&[codegen.context.i64_type().into()], false);
let fname = if iface_name == "env.console" {
match method_name {
"log" => "nyash.console.log_handle",
"warn" => "nyash.console.warn_handle",
_ => "nyash.console.error_handle",
}
} else {
"nyash.debug.trace_handle"
};
let callee = codegen
.module
.get_function(fname)
.unwrap_or_else(|| codegen.module.add_function(fname, fnty, None));
let _ = codegen
.builder
.build_call(callee, &[arg_val.into()], "console_log_h")
.map_err(|e| e.to_string())?;
if let Some(d) = dst {
vmap.insert(*d, codegen.context.i64_type().const_zero().into());
}
Ok(())
}
}
}
pub(super) fn lower_readline<'ctx>(
codegen: &CodegenContext<'ctx>,
vmap: &mut HashMap<ValueId, BVE<'ctx>>,
dst: &Option<ValueId>,
args: &[ValueId],
) -> Result<(), String> {
if !args.is_empty() {
return Err("console.readLine expects 0 args".to_string());
}
let i8p = codegen.context.ptr_type(AddressSpace::from(0));
let fnty = i8p.fn_type(&[], false);
let callee = codegen
.module
.get_function("nyash.console.readline")
.unwrap_or_else(|| codegen.module.add_function("nyash.console.readline", fnty, None));
let call = codegen
.builder
.build_call(callee, &[], "readline")
.map_err(|e| e.to_string())?;
if let Some(d) = dst {
let rv = call
.try_as_basic_value()
.left()
.ok_or("readline returned void".to_string())?;
vmap.insert(*d, rv);
}
Ok(())
}