http server

This commit is contained in:
agra
2026-02-17 16:57:12 +02:00
parent 66034b4fec
commit 4fd87309d9
17 changed files with 437 additions and 113 deletions

View File

@@ -10,26 +10,26 @@ sum :: (args: ..s32) -> s32 {
print_all :: (args: ..s32) {
for args: (it) {
write(int_to_string(it));
write(" ");
out(int_to_string(it));
out(" ");
}
write("\n");
out("\n");
}
main :: () -> s32 {
write(int_to_string(sum(10, 20, 30)));
write("\n");
out(int_to_string(sum(10, 20, 30)));
out("\n");
print_all(1, 2, 3, 4, 5);
arr : [3]s32 = .[10, 20, 30];
write(int_to_string(sum(..arr)));
write("\n");
out(int_to_string(sum(..arr)));
out("\n");
for arr: (it) {
write(int_to_string(it));
write(" ");
out(int_to_string(it));
out(" ");
}
write("\n");
out("\n");
0;
}

View File

@@ -10,22 +10,22 @@ print_any :: (args: ..Any) {
for args: (it) {
type := type_of(it);
if type == {
case int: write(int_to_string(cast(s32) it));
case string: write(cast(string) it);
case bool: write(bool_to_string(cast(bool) it));
case float: write(float_to_string(cast(f64) it));
case int: out(int_to_string(cast(s32) it));
case string: out(cast(string) it);
case bool: out(bool_to_string(cast(bool) it));
case float: out(float_to_string(cast(f64) it));
case Point: {
p := cast(Point) it;
write("(");
write(int_to_string(p.x));
write(",");
write(int_to_string(p.y));
write(")");
out("(");
out(int_to_string(p.x));
out(",");
out(int_to_string(p.y));
out(")");
}
}
write(" ");
out(" ");
}
write("\n");
out("\n");
}
count :: (args: ..Any) -> s32 {
@@ -40,8 +40,8 @@ main :: () -> s32 {
print_any("point:", p, 99);
// Test count
write(int_to_string(count(1, 2, 3)));
write("\n");
out(int_to_string(count(1, 2, 3)));
out("\n");
0;
}

View File

@@ -0,0 +1,63 @@
// HTTP server example (macOS only)
#import "modules/std.sx";
#import "modules/socket.sx";
main :: () -> s32 {
PORT :: 8080;
fd := socket(AF_INET, SOCK_STREAM, 0);
if fd < 0 {
print("error: socket()\n");
return 1;
}
opt : s32 = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, @opt, 4);
addr := SockAddr.{
sin_len = 16,
sin_family = 2,
sin_port = htons(PORT),
sin_addr = 0,
sin_zero = 0
};
if bind(fd, @addr, 16) < 0 {
print("error: bind()\n");
return 1;
}
if listen(fd, 10) < 0 {
print("error: listen()\n");
return 1;
}
print("listening on http://localhost:{}\n", PORT);
while true {
client := accept(fd, null, null);
if client < 0 { continue; }
// Read request
buf := alloc(4096);
read(client, buf, 4096);
// Send response
body := "<html><body><h1>Hello from sx!</h1></body></html>";
response := format("HTTP/1.1 200 OK\r
Content-Type: text/html\r
Connection: close\r
Content-Length: {}\r
\r
{}", body.len, body);
write(client, response, response.len);
close(client);
print(" served request\n");
}
close(fd);
0;
}

View File

@@ -91,6 +91,10 @@ gen_val :: () -> string {
return "print(\"insert-gen: {}\\n\", 42);";
}
// --- Foreign function binding ---
libc :: #library "c";
c_abs :: (n: s32) -> s32 #foreign libc "abs";
// ============================================================
main :: {
@@ -634,76 +638,76 @@ END;
// For loop basic
farr : [4]s32 = .[10, 20, 30, 40];
write("for:");
out("for:");
for farr: (it) {
write(" ");
write(int_to_string(it));
out(" ");
out(int_to_string(it));
}
write("\n");
out("\n");
// For with print
write("for-print:");
out("for-print:");
for farr: (it) {
print(" {}", it);
}
write("\n");
out("\n");
// For with index
write("for-idx:");
out("for-idx:");
for farr: (_, ix) {
write(" ");
write(int_to_string(ix));
out(" ");
out(int_to_string(ix));
}
write("\n");
out("\n");
// For with print two args
write("for-2arg:");
out("for-2arg:");
for farr: (it, ix) {
print(" {}@{}", it, ix);
}
write("\n");
out("\n");
// For with break
write("for-break:");
out("for-break:");
for farr: (it) {
if it == 30 { break; }
print(" {}", it);
}
write("\n");
out("\n");
// For with continue
write("for-continue:");
out("for-continue:");
for farr: (it) {
if it == 20 { continue; }
print(" {}", it);
}
write("\n");
out("\n");
// For on slice
fsl : []s32 = .[10, 20, 30];
write("for-slice:");
out("for-slice:");
for fsl: (it) {
print(" {}", it);
}
write("\n");
out("\n");
// For on slice with index
write("for-slice-idx:");
out("for-slice-idx:");
for fsl: (it, ix) {
print(" {}:{}", ix, it);
}
write("\n");
out("\n");
// Nested for
nf_a : [2]s32 = .[0, 1];
nf_b : [2]s32 = .[0, 1];
write("for-nested:");
out("for-nested:");
for nf_a: (oa) {
for nf_b: (ob) {
print(" ({},{})", oa, ob);
}
}
write("\n");
out("\n");
// For with break preserving index
fbi : [5]s32 = .[10, 20, 30, 40, 50];
@@ -857,8 +861,8 @@ END;
// ========================================================
print("=== 7. Builtins ===\n");
// write
write("write-ok\n");
// out
out("out-ok\n");
// sqrt
print("sqrt: {}\n", sqrt(9.0));
@@ -932,12 +936,12 @@ END;
// field_value (use any_to_string to avoid sext-on-Any bug)
fv_pt := Point.{ 11, 22 };
write("fieldval0: ");
write(any_to_string(field_value(fv_pt, 0)));
write("\n");
write("fieldval1: ");
write(any_to_string(field_value(fv_pt, 1)));
write("\n");
out("fieldval0: ");
out(any_to_string(field_value(fv_pt, 0)));
out("\n");
out("fieldval1: ");
out(any_to_string(field_value(fv_pt, 1)));
out("\n");
// field_index on plain enum
fi_c : Color = .green;
@@ -1039,5 +1043,13 @@ END;
print("3-way: {} {} {}\n", ra, rb, rc);
}
// ========================================================
// 15. FOREIGN FUNCTION BINDING
// ========================================================
print("=== 15. Foreign ===\n");
// Symbol rename: c_abs maps to C's abs()
print("foreign-rename: {}\n", c_abs(xx -42));
print("=== DONE ===\n");
}

View File

@@ -1,4 +1,4 @@
#library "raylib";
raylib :: #library "raylib";
Color :: struct {
r, g, b, a: u8;
@@ -8,10 +8,10 @@ Vector2 :: struct {
x, y: f32;
}
InitWindow :: (width: s32, height: s32, title: [:0]u8) -> void #foreign;
CloseWindow :: () -> void #foreign;
WindowShouldClose :: () -> bool #foreign;
BeginDrawing :: () -> void #foreign;
EndDrawing :: () -> void #foreign;
ClearBackground :: (color: Color) -> void #foreign;
DrawTriangle :: (v1: Vector2, v2: Vector2, v3: Vector2, color: Color) -> void #foreign;
InitWindow :: (width: s32, height: s32, title: [:0]u8) -> void #foreign raylib;
CloseWindow :: () -> void #foreign raylib;
WindowShouldClose :: () -> bool #foreign raylib;
BeginDrawing :: () -> void #foreign raylib;
EndDrawing :: () -> void #foreign raylib;
ClearBackground :: (color: Color) -> void #foreign raylib;
DrawTriangle :: (v1: Vector2, v2: Vector2, v3: Vector2, color: Color) -> void #foreign raylib;

View File

@@ -1,4 +1,4 @@
#library "SDL3";
sdl3 :: #library "SDL3";
// SDL_InitFlags
SDL_INIT_VIDEO :u32: 0x20;
@@ -317,17 +317,17 @@ SDL_Event :: enum struct { tag: u32; _: u32; payload: [30]u32; } {
}
// Functions
SDL_Init :: (flags: u32) -> bool #foreign;
SDL_Quit :: () -> void #foreign;
SDL_CreateWindow :: (title: [:0]u8, w: s32, h: s32, flags: u64) -> *void #foreign;
SDL_DestroyWindow :: (window: *void) -> void #foreign;
SDL_GL_SetAttribute :: (attr: s32, value: s32) -> bool #foreign;
SDL_GL_CreateContext :: (window: *void) -> *void #foreign;
SDL_GL_DestroyContext :: (context: *void) -> bool #foreign;
SDL_GL_MakeCurrent :: (window: *void, context: *void) -> bool #foreign;
SDL_GL_SwapWindow :: (window: *void) -> bool #foreign;
SDL_GL_SetSwapInterval :: (interval: s32) -> bool #foreign;
SDL_GL_GetProcAddress :: (proc: [:0]u8) -> *void #foreign;
SDL_PollEvent :: (event: *SDL_Event) -> bool #foreign;
SDL_GetTicks :: () -> u64 #foreign;
SDL_Delay :: (ms: u32) -> void #foreign;
SDL_Init :: (flags: u32) -> bool #foreign sdl3;
SDL_Quit :: () -> void #foreign sdl3;
SDL_CreateWindow :: (title: [:0]u8, w: s32, h: s32, flags: u64) -> *void #foreign sdl3;
SDL_DestroyWindow :: (window: *void) -> void #foreign sdl3;
SDL_GL_SetAttribute :: (attr: s32, value: s32) -> bool #foreign sdl3;
SDL_GL_CreateContext :: (window: *void) -> *void #foreign sdl3;
SDL_GL_DestroyContext :: (context: *void) -> bool #foreign sdl3;
SDL_GL_MakeCurrent :: (window: *void, context: *void) -> bool #foreign sdl3;
SDL_GL_SwapWindow :: (window: *void) -> bool #foreign sdl3;
SDL_GL_SetSwapInterval :: (interval: s32) -> bool #foreign sdl3;
SDL_GL_GetProcAddress :: (proc: [:0]u8) -> *void #foreign sdl3;
SDL_PollEvent :: (event: *SDL_Event) -> bool #foreign sdl3;
SDL_GetTicks :: () -> u64 #foreign sdl3;
SDL_Delay :: (ms: u32) -> void #foreign sdl3;

View File

@@ -0,0 +1,33 @@
// POSIX socket module (macOS only)
// sockaddr_in layout and constants are platform-specific.
libc :: #library "c";
// POSIX socket API
socket :: (domain: s32, kind: s32, protocol: s32) -> s32 #foreign libc;
setsockopt :: (fd: s32, level: s32, optname: s32, optval: *s32, optlen: u32) -> s32 #foreign libc;
bind :: (fd: s32, addr: *SockAddr, addrlen: u32) -> s32 #foreign libc;
listen :: (fd: s32, backlog: s32) -> s32 #foreign libc;
accept :: (fd: s32, addr: *SockAddr, addrlen: *u32) -> s32 #foreign libc;
read :: (fd: s32, buf: [:0]u8, count: s64) -> s64 #foreign libc;
write :: (fd: s32, buf: [:0]u8, count: s64) -> s64 #foreign libc;
close :: (fd: s32) -> s32 #foreign libc;
// Constants (macOS)
AF_INET :s32: 2;
SOCK_STREAM :s32: 1;
SOL_SOCKET :s32: 0xFFFF;
SO_REUSEADDR :s32: 0x4;
// macOS sockaddr_in (16 bytes, has sin_len field)
SockAddr :: struct {
sin_len: u8;
sin_family: u8;
sin_port: u16;
sin_addr: u32;
sin_zero: u64;
}
htons :: (port: s64) -> u16 {
cast(u16) ((port / 256) | ((port % 256) * 256));
}

View File

@@ -1,5 +1,5 @@
Vector :: ($N: int, $T: Type) -> Type #builtin;
write :: (str: string) -> void #builtin;
out :: (str: string) -> void #builtin;
sqrt :: (x: $T) -> T #builtin;
sin :: (x: $T) -> T #builtin;
cos :: (x: $T) -> T #builtin;
@@ -315,10 +315,81 @@ build_print :: (fmt: string) -> string {
code = concat(code, int_to_string(fmt.len - seg_start));
code = concat(code, ")); ");
}
code = concat(code, "write(result);");
code = concat(code, "out(result);");
code;
}
build_format :: (fmt: string) -> string {
code := "result := \"\"; ";
seg_start := 0;
i := 0;
arg_idx := 0;
while i < fmt.len {
if fmt[i] == 123 {
if i + 1 < fmt.len {
if fmt[i + 1] == 125 {
if i > seg_start {
code = concat(code, "result = concat(result, substr(fmt, ");
code = concat(code, int_to_string(seg_start));
code = concat(code, ", ");
code = concat(code, int_to_string(i - seg_start));
code = concat(code, ")); ");
}
code = concat(code, "result = concat(result, any_to_string(args[");
code = concat(code, int_to_string(arg_idx));
code = concat(code, "])); ");
arg_idx += 1;
i += 2;
seg_start = i;
} else if fmt[i + 1] == 123 {
code = concat(code, "result = concat(result, substr(fmt, ");
code = concat(code, int_to_string(seg_start));
code = concat(code, ", ");
code = concat(code, int_to_string(i - seg_start + 1));
code = concat(code, ")); ");
i += 2;
seg_start = i;
} else {
i += 1;
}
} else {
i += 1;
}
} else if fmt[i] == 125 {
if i + 1 < fmt.len {
if fmt[i + 1] == 125 {
code = concat(code, "result = concat(result, substr(fmt, ");
code = concat(code, int_to_string(seg_start));
code = concat(code, ", ");
code = concat(code, int_to_string(i - seg_start + 1));
code = concat(code, ")); ");
i += 2;
seg_start = i;
} else {
i += 1;
}
} else {
i += 1;
}
} else {
i += 1;
}
}
if seg_start < fmt.len {
code = concat(code, "result = concat(result, substr(fmt, ");
code = concat(code, int_to_string(seg_start));
code = concat(code, ", ");
code = concat(code, int_to_string(fmt.len - seg_start));
code = concat(code, ")); ");
}
code = concat(code, "result;");
code;
}
format :: ($fmt: string, args: ..Any) -> string {
#insert build_format(fmt);
}
print :: ($fmt: string, args: ..Any) {
#insert build_print(fmt);
}