feat: capture-less anonymous functions (closures)

Implement MVP closures — anonymous functions without captures.

Syntax:
  |a: int, b: int| -> int { return a + b; }

Changes:
- ast.bux + ast.nim: add ekClosure AST node
- parser.bux + parser.nim: parse |params| -> Ret { body }
- sema.bux + sema.nim: type-check closure params/body, return tyFunc
- hir_lower.bux + hir_lower.nim: generate __closure_N function + hAddrOf
- lir_c_backend.nim: fix function-pointer variable declaration (cParamDecl)
- C backend: closures compile to global functions with unique names

Test: _test_closure/src/Main.bux
- Closure as variable
- Closure passed to higher-order function
- Address of named function as function pointer

Both bootstrap and selfhost compilers build and pass the test.
This commit is contained in:
2026-06-09 20:24:10 +03:00
parent 34504d1647
commit c83f6d5994
16 changed files with 2290 additions and 8 deletions
BIN
View File
Binary file not shown.
+54
View File
@@ -0,0 +1,54 @@
/* Bux Standard Library - I/O functions */
#include <stdio.h>
#include <stdint.h>
#include <string.h>
/* PrintLine - print string with newline */
void PrintLine(const char* s) {
if (s != NULL) {
puts(s);
} else {
puts("");
}
}
/* Print - print string without newline */
void Print(const char* s) {
if (s != NULL) {
printf("%s", s);
}
}
/* PrintInt - print integer */
void PrintInt(int n) {
printf("%d", n);
}
/* PrintInt64 - print 64-bit integer */
void PrintInt64(int64_t n) {
printf("%lld", (long long)n);
}
/* PrintFloat - print float */
void PrintFloat(double f) {
printf("%g", f);
}
/* PrintBool - print boolean */
void PrintBool(int b) {
printf("%s", b ? "true" : "false");
}
/* ReadLine - read line from stdin (simplified) */
const char* ReadLine(void) {
static char buffer[1024];
if (fgets(buffer, sizeof(buffer), stdin) != NULL) {
size_t len = strlen(buffer);
if (len > 0 && buffer[len-1] == '\n') {
buffer[len-1] = '\0';
}
return buffer;
}
return "";
}
BIN
View File
Binary file not shown.
+67
View File
@@ -0,0 +1,67 @@
// Generated by Bux C Backend v2
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
typedef const char* String;
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;
typedef unsigned long long uint64;
typedef signed char int8;
typedef short int16;
typedef long long int64;
typedef float float32;
typedef double float64;
typedef char char8;
void* bux_alloc(unsigned int size);
void bux_free(void* ptr);
int Apply(int x, int (*op)(int));
int Double(int x);
int __closure_2(int a, int b);
int __closure_3(int x);
int main();
void PrintInt(int x);
void PrintLine(String msg);
int Apply(int x, int (*op)(int)) {
return op(x);
}
int Double(int x) {
return x * 2;
}
int __closure_2(int a, int b) {
return a + b;
}
int __closure_3(int x) {
return x * 3;
}
int main() {
int (*add)(int, int) = &__closure_2;
int sum = add(3, 4);
PrintInt(sum);
PrintLine("");
int result = Apply(5, &__closure_3);
PrintInt(result);
PrintLine("");
int (*d)(int) = &Double;
PrintInt(d(7));
PrintLine("");
return 0;
}
File diff suppressed because it is too large Load Diff
+7
View File
@@ -0,0 +1,7 @@
[Package]
Name = "closure_test"
Version = "0.1.0"
Type = "bin"
[Build]
Output = "Bin"
+34
View File
@@ -0,0 +1,34 @@
module Main {
extern func PrintInt(x: int);
extern func PrintLine(msg: String);
func Apply(x: int, op: func(int) -> int) -> int {
return op(x);
}
func Double(x: int) -> int {
return x * 2;
}
func main() -> int {
// Closure as variable
let add: func(int, int) -> int = |a: int, b: int| -> int { return a + b; };
let sum: int = add(3, 4);
PrintInt(sum);
PrintLine("");
// Closure passed to function
let result: int = Apply(5, |x: int| -> int { return x * 3; });
PrintInt(result);
PrintLine("");
// Address of named function as function pointer
let d: func(int) -> int = &Double;
PrintInt(d(7));
PrintLine("");
return 0;
}
}