From d5a363aa1dbbf44e64c78330232bed780b6b95ec Mon Sep 17 00:00:00 2001 From: LunaStev Date: Sun, 18 Jan 2026 16:16:30 +0900 Subject: [PATCH] Move example-worthy tests into examples/ --- examples/control_flow_full.wave | 77 ++++++++ examples/graph_dfs_bfs_with_queue.wave | 96 +++++++++ examples/hello.wave | 3 + examples/if.wave | 19 ++ examples/star.wave | 15 ++ examples/string_placeholder_scanner.wave | 64 ++++++ examples/struct_proto_semantics.wave | 206 ++++++++++++++++++++ examples/tcp.wave | 236 +++++++++++++++++++++++ examples/udp.wave | 99 ++++++++++ std/net/udp.wave | 2 +- 10 files changed, 816 insertions(+), 1 deletion(-) create mode 100644 examples/control_flow_full.wave create mode 100644 examples/graph_dfs_bfs_with_queue.wave create mode 100644 examples/hello.wave create mode 100644 examples/if.wave create mode 100644 examples/star.wave create mode 100644 examples/string_placeholder_scanner.wave create mode 100644 examples/struct_proto_semantics.wave create mode 100644 examples/tcp.wave create mode 100644 examples/udp.wave diff --git a/examples/control_flow_full.wave b/examples/control_flow_full.wave new file mode 100644 index 00000000..ca51ed4c --- /dev/null +++ b/examples/control_flow_full.wave @@ -0,0 +1,77 @@ +fun transform(x: i32, y: i32, scale: f32) -> f32 { + println("inside transform"); + var base: i32 = x * 2; + base += y; + var result: f32 = base; + result *= scale; + return result; +} + +fun display_pattern(levels: i32) -> i32 { + var i: i32 = 1; + while (i <= levels) { + var j: i32 = 1; + while (j <= i) { + print("#"); + j += 1; + } + println(" "); + i += 1; + } + return 0; +} + +fun process(a: i32, b: i32, note: str) -> i32 { + var v: i32 = a; + v += b; + println("Initial v: {}", v); + + v *= 2; + v /= 3; + println("After scaling: {}", v); + + if (v % 2 == 0) { + println("{} is even", v); + } else { + println("{} is odd", v); + } + + var acc: i32 = 0; + var i: i32 = 0; + while (i < v) { + if (i == 5) { + i += 1; + continue; + } + acc += i; + println("Looping i: {}, acc: {}", i, acc); + i += 1; + } + + display_pattern(4); + println("Note: {}", note); + return 0; +} + +fun main() { + + var a: i32 = 8; + var b: i32 = 4; + var f: f32 = 3.0; + var g: f32 = 1.5; + + a += b; + b *= 2; + f += g; + + println("a: {}, b: {}, f: {}", a, b, f); + + if (a != b) { + println("{} != {}", a, b); + } + + var result: f32 = transform(a, b, f); + println("Final result: {}", result); + + process(a, b, "Wave language engaged!"); +} diff --git a/examples/graph_dfs_bfs_with_queue.wave b/examples/graph_dfs_bfs_with_queue.wave new file mode 100644 index 00000000..025dd541 --- /dev/null +++ b/examples/graph_dfs_bfs_with_queue.wave @@ -0,0 +1,96 @@ +fun set_insert(visited: ptr>, x: i32) { + deref visited[x] = 1; +} + +fun set_contains(visited: ptr>, x: i32) -> bool { + if (deref visited[x] == 1) { + return true; + } + return false; +} + +struct Queue { + data: array; + front: i32; + rear: i32; +} + +fun queue_new() -> Queue { + var q: Queue; + q.front = 0; + q.rear = 0; + return q; +} + +fun queue_push(q: ptr, x: i32) { + deref q.data[deref q.rear] = x; + deref q.rear += 1; +} + +fun queue_pop(q: ptr) -> i32 { + var x: i32 = deref q.data[deref q.front]; + deref q.front += 1; + return x; +} + +fun queue_empty(q: ptr) -> bool { + if (deref q.front >= deref q.rear) { + return true; + } + return false; +} + +// DFS +fun dfs(v: i32, graph: array, 5>, visited: ptr>) { + set_insert(visited, v); + println("DFS visit {}", v); + + var i: i32 = 0; + while (i < 5) { + if (graph[v][i] == 1 && !set_contains(visited, i)) { + dfs(i, graph, visited); + } + i += 1; + } +} + +// BFS +fun bfs(start: i32, graph: array, 5>) { + var visited: array = [0,0,0,0,0]; + var q: Queue = queue_new(); + + set_insert(&visited, start); + queue_push(&q, start); + + while (!queue_empty(&q)) { + var v: i32 = queue_pop(&q); + println("BFS visit {}", v); + + var i: i32 = 0; + while (i < 5) { + if (graph[v][i] == 1 && !set_contains(&visited, i)) { + set_insert(&visited, i); + queue_push(&q, i); + } + i += 1; + } + } +} + +fun main() { + var graph: array, 5> = [ + [0,1,1,0,0], + [1,0,0,1,0], + [1,0,0,0,1], + [0,1,0,0,0], + [0,0,1,0,0] + ]; + + var visited: array = [0,0,0,0,0]; + + println("=== DFS ==="); + dfs(0, graph, &visited); + + println("=== BFS ==="); + bfs(0, graph); +} diff --git a/examples/hello.wave b/examples/hello.wave new file mode 100644 index 00000000..9e5f0bbb --- /dev/null +++ b/examples/hello.wave @@ -0,0 +1,3 @@ +fun main() { + println("Hello World"); +} \ No newline at end of file diff --git a/examples/if.wave b/examples/if.wave new file mode 100644 index 00000000..50db1753 --- /dev/null +++ b/examples/if.wave @@ -0,0 +1,19 @@ +fun main() { + var a :i32 = 20; + var b :i32 = 20; + + if (a > 30) { + println("a is greater than 30"); + } else { + println("a is less than or equal to 30"); + } + + if (b < a) { + println("b is less than a"); + } else if (b == a) { + println("b is equal to a"); + } else { + println("b is greater than a"); + } + +} \ No newline at end of file diff --git a/examples/star.wave b/examples/star.wave new file mode 100644 index 00000000..587479f9 --- /dev/null +++ b/examples/star.wave @@ -0,0 +1,15 @@ +fun main() { + var i: i32 = 1; + + while (i <= 5) { + var j: i32 = 1; + + while (j <= i) { + print("*"); + j = j + 1; + } + + println(" "); + i = i + 1; + } +} \ No newline at end of file diff --git a/examples/string_placeholder_scanner.wave b/examples/string_placeholder_scanner.wave new file mode 100644 index 00000000..ea8ed473 --- /dev/null +++ b/examples/string_placeholder_scanner.wave @@ -0,0 +1,64 @@ +struct Bytes { + data: ptr; + len: i32; +} + +fun string_bytes(s: str) -> Bytes { + var p: ptr = s; + var len: i32 = 0; + + while (p[len] != 0) { + len = len + 1; + } + + var b: Bytes; + b.data = p; + b.len = len; + return b; +} + +fun count_placeholders(text: str) -> i32 { + var bytes: Bytes = string_bytes(text); + var i: i32 = 0; + var count: i32 = 0; + + while (i < bytes.len) { + if (bytes.data[i] == '{') { + var start: i32 = i; + i = i + 1; + + while (i < bytes.len) { + if (bytes.data[i] == '}') { + count = count + 1; + i = i + 1; + break; + } + i = i + 1; + } + + if (i >= bytes.len && bytes.data[start] == '{') { + break; + } + } else { + i = i + 1; + } + } + + return count; +} + +fun main() { + var s1: str = "hello {} world"; + var s2: str = "{} {} {}"; + var s3: str = "{ hello } { world }"; + var s4: str = "{ { }"; + var s5: str = "no placeholders here"; + var s6: str = "{}{}}{"; + + println("s1 = {}", count_placeholders(s1)); + println("s2 = {}", count_placeholders(s2)); + println("s3 = {}", count_placeholders(s3)); + println("s4 = {}", count_placeholders(s4)); + println("s5 = {}", count_placeholders(s5)); + println("s6 = {}", count_placeholders(s6)); +} diff --git a/examples/struct_proto_semantics.wave b/examples/struct_proto_semantics.wave new file mode 100644 index 00000000..68e5737f --- /dev/null +++ b/examples/struct_proto_semantics.wave @@ -0,0 +1,206 @@ +struct Data { + value: i32; +} + +proto Data { + fun inc(self: Data) -> Data { + return Data { value: self.value + 1 }; + } + + fun print_s(self: Data) { + println("Data(value={})", self.value); + } +} + +fun test_basic_copy() { + println("[1] Basic Copy"); + var a: Data = Data { value: 10 }; + var b: Data = a; + b.value = 99; + println("a.value = {}", a.value); + println("b.value = {}", b.value); + a.inc().print_s(); +} + + +struct Vec2 { + x: f32; + y: f32; +} + +struct Transform { + pos: Vec2; + scale: f32; +} + +proto Transform { + fun describe(self: Transform) { + println("Transform({}, {}, {})", self.pos.x, self.pos.y, self.scale); + } +} + +fun test_nested_struct() { + println("[2] Nested Struct"); + var t: Transform = Transform { + pos: Vec2 { x: 1.5, y: 2.5 }, + scale: 3.0 + }; + t.describe(); +} + + +struct Inventory { + items: array; +} + +proto Inventory { + fun print_all(self: Inventory) { + var i: i32 = 0; + while (i < 5) { + println("Item[{}] = {}", i, self.items[i]); + i += 1; + } + } +} + +fun test_struct_array() { + println("[3] Struct + Array"); + var inv: Inventory = Inventory { + items: [10, 20, 30, 40, 50] + }; + inv.print_all(); +} + + +struct Node { + value: i32; + next: ptr; +} + +proto Node { + fun print_chain(self: Node) { + var cur: ptr = &self; + var i: i32 = 0; + while (cur != 0 && i < 10) { + println("Node {} = {}", i, (deref cur).value); + cur = (deref cur).next; + i += 1; + } + } +} + +fun test_recursive() { + println("[4] Recursive Struct"); + var n3: Node = Node { value: 300, next: 0 }; + var n2: Node = Node { value: 200, next: &n3 }; + var n1: Node = Node { value: 100, next: &n2 }; + n1.print_chain(); +} + + +struct Number { + v: i32; +} + +proto Number { + fun add(self: Number, x: i32) -> Number { + return Number { v: self.v + x }; + } + fun mul(self: Number, x: i32) -> Number { + return Number { v: self.v * x }; + } + fun print_n(self: Number) { + println("Number = {}", self.v); + } +} + +fun test_chain() { + println("[5] Method Chain"); + var n: Number = Number { v: 5 }; + n.add(3).mul(2).add(10).print_n(); +} + + +struct Stats { + hp: i32; + mp: i32; +} + +struct Player { + name: str; + stats: Stats; +} + +struct GameState { + p: Player; + level: i32; +} + +proto GameState { + fun summary(self: GameState) { + println("Player '{}' HP={} MP={} Lv={}", + self.p.name, self.p.stats.hp, self.p.stats.mp, self.level); + } +} + +fun test_deep_nested() { + println("[6] Deep Nested Struct"); + var gs: GameState = GameState { + p: Player { + name: "LunaStev", + stats: Stats { hp: 120, mp: 80 } + }, + level: 7 + }; + gs.summary(); +} + + +fun upgrade_stats(s: Stats) -> Stats { + return Stats { hp: s.hp + 50, mp: s.mp + 20 }; +} + +fun test_return_struct() { + println("[7] Struct Return"); + var s: Stats = Stats { hp: 100, mp: 40 }; + var u: Stats = upgrade_stats(s); + println("Original = {} {}", s.hp, s.mp); + println("Upgraded = {} {}", u.hp, u.mp); +} + +fun test_mutability() { + println("[8] Mutability Test"); + + var a: i32 = 10; + a = 20; + println("var a = {}", a); + + let b: i32 = 30; + println("let b = {}", b); + + let mut c: Data = Data { value: 5 }; + c.value = 77; + println("let mut c.value = {}", c.value); + + let mut t: Transform = Transform { + pos: Vec2 { x: 3.0, y: 4.0 }, + scale: 1.0 + }; + t.pos.x = 10.0; + t.scale = 5.0; + println("let mut Transform({}, {}, {})", t.pos.x, t.pos.y, t.scale); + + let p: Stats = Stats { hp: 50, mp: 25 }; + println("let p.hp = {}", p.hp); +} + +fun main() { + test_basic_copy(); + test_nested_struct(); + test_struct_array(); + test_recursive(); + test_chain(); + test_deep_nested(); + test_return_struct(); + test_mutability(); +} diff --git a/examples/tcp.wave b/examples/tcp.wave new file mode 100644 index 00000000..73a2f062 --- /dev/null +++ b/examples/tcp.wave @@ -0,0 +1,236 @@ +// ========================= +// Linux x86_64 syscalls +// args: rax, rdi, rsi, rdx, r10, r8, r9 +// ========================= + +fun len(s: str) -> i32 { + let mut i: i32 = 0; + while (s[i] != 0) { + i += 1; + } + return i; +} + +fun syscall0(id: i64) -> i64 { + var ret: i64; + asm { + "syscall" + in("rax") id + out("rax") ret + } + return ret; +} + +fun syscall1(id: i64, a1: i64) -> i64 { + var ret: i64; + asm { + "syscall" + in("rax") id + in("rdi") a1 + out("rax") ret + } + return ret; +} + +fun syscall2(id: i64, a1: i64, a2: i64) -> i64 { + var ret: i64; + asm { + "syscall" + in("rax") id + in("rdi") a1 + in("rsi") a2 + out("rax") ret + } + return ret; +} + +fun syscall3(id: i64, a1: i64, a2: i64, a3: i64) -> i64 { + var ret: i64; + asm { + "syscall" + in("rax") id + in("rdi") a1 + in("rsi") a2 + in("rdx") a3 + out("rax") ret + } + return ret; +} + +fun syscall3pi(id: i64, a1: i64, p2: ptr, a3: i64) -> i64 { + var ret: i64; + asm { + "syscall" + in("rax") id + in("rdi") a1 + in("rsi") p2 + in("rdx") a3 + out("rax") ret + } + return ret; +} + +fun syscall4(id: i64, a1: i64, a2: i64, a3: i64, a4: i64) -> i64 { + var ret: i64; + asm { + "syscall" + in("rax") id + in("rdi") a1 + in("rsi") a2 + in("rdx") a3 + in("r10") a4 + out("rax") ret + } + return ret; +} + +fun syscall5(id: i64, a1: i64, a2: i64, a3: i64, p4: ptr, a5: i64) -> i64 { + var ret: i64; + asm { + "syscall" + in("rax") id + in("rdi") a1 + in("rsi") a2 + in("rdx") a3 + in("r10") p4 + in("r8") a5 + out("rax") ret + } + return ret; +} + + +// ========================= +// socket helpers +// ========================= + +fun htons(x: i16) -> i16 { + var a: i32 = x; + var y: i32 = ((a & 255) << 8) | ((a >> 8) & 255); + return y; +} + +fun _setsockopt_reuseaddr(sockfd: i64) { + // SOL_SOCKET = 1, SO_REUSEADDR = 2 + var one: i32 = 1; + syscall5(54, sockfd, 1, 2, &one, 4); +} + +struct SockAddrIn { + sin_family: i16; // AF_INET = 2 + sin_port: i16; // network byte order + sin_addr: i32; // INADDR_ANY = 0 + sin_zero: array; +} + +// bind needs sockaddr* typed pointer. +// If your compiler cannot pass ptr into ptr, +// keep this specialized syscall for sockaddr. +fun syscall3p_sockaddr(id: i64, a1: i64, p2: ptr, a3: i64) -> i64 { + var ret: i64; + asm { + "syscall" + in("rax") id + in("rdi") a1 + in("rsi") p2 + in("rdx") a3 + out("rax") ret + } + return ret; +} + +fun _socket_create_tcp() -> i64 { + return syscall3(41, 2, 1, 0); +} + +fun _socket_bind_any(sockfd: i64, port: i16) -> i64 { + let mut addr: SockAddrIn = SockAddrIn { + sin_family: 2, + sin_port: htons(port), + sin_addr: 0, + sin_zero: [0,0,0,0,0,0,0,0] + }; + + return syscall3p_sockaddr(49, sockfd, &addr, 16); +} + +fun _socket_listen(sockfd: i64, backlog: i64) -> i64 { + return syscall2(50, sockfd, backlog); +} + +fun _socket_accept(sockfd: i64) -> i64 { + return syscall3(43, sockfd, 0, 0); +} + +fun _socket_close(fd: i64) { + syscall1(3, fd); +} + +fun _write(fd: i64, buf: str, len: i64) -> i64 { + // If your compiler represents `str` as i8*, this will work with syscall3pi. + return syscall3pi(1, fd, buf, len); +} + +// ========================= +// server logic +// ========================= + +fun new_server(port: i16) -> i64 { + var sockfd: i64 = _socket_create_tcp(); + _setsockopt_reuseaddr(sockfd); + if (sockfd < 0) { return -1; } + + var b: i64 = _socket_bind_any(sockfd, port); + println("bind ret = {}", b); + + if (b < 0) { + _socket_close(sockfd); + return -1; + } + + return sockfd; +} + +fun listen(server_fd: i64, backlog: i64) -> i64 { + if (_socket_listen(server_fd, backlog) < 0) { + println("Error: Failed to listen on socket."); + return -1; + } + println("Server is listening..."); + return server_fd; +} + +fun start(server_fd: i64) { + println("Server accepting connections..."); + + while (true) { + var client_fd: i64 = _socket_accept(server_fd); + + if (client_fd < 0) { + println("accept failed: {}", client_fd); + continue; + } + + println("Client connected! fd: {}", client_fd); + + var response: str = "HTTP/1.1 200 OK\r\nContent-Type: text/plain; charset=utf-8\r\nContent-Length: 33\r\nConnection: close\r\n\r\nWelcome to the Wave HTTP Server!"; + + + _write(client_fd, response, len(response)); + + _socket_close(client_fd); + println("Client disconnected."); + } +} + +fun main() { + println("--- Wave HTTP Server Application ---"); + + var server_instance: i64 = new_server(8080).listen(10); + + if (server_instance >= 0) { + server_instance.start(); + } else { + println("Server failed to start."); + } +} diff --git a/examples/udp.wave b/examples/udp.wave new file mode 100644 index 00000000..1ebf1751 --- /dev/null +++ b/examples/udp.wave @@ -0,0 +1,99 @@ +const SYS_WRITE: i32 = 1; + +const SYS_READ: i32 = 0; + +const SYS_MMAP: i32 = 9; +const SYS_MUNMAP: i32 = 11; +const SYS_CLOSE: i32 = 3; +const SYS_SOCKET: i32 = 41; +const SYS_CONNECT: i32 = 42; +const SYS_BIND: i32 = 49; +const SYS_LISTEN: i32 = 50; +const SYS_ACCEPT: i32 = 43; +const SYS_SENDTO: i32 = 44; +const SYS_RECVFROM: i32 = 45; + +const PROT_READ: i32 = 1; +const PROT_WRITE: i32 = 2; +const MAP_PRIVATE: i32 = 2; +const MAP_ANONYMOUS: i32 = 32; + +fun syscall_write(fd: i32, buf: ptr, len: i32) { + let r: i32; + asm { + "mov rax, 1" + "syscall" + in("rdi") fd + in("rsi") buf + in("rdx") len + out("rax") r + } +} + +fun syscall_read(fd: i32, buf: ptr, len:i32) -> i32 { + let r: i32; + asm { + "mov rax, 0" + "syscall" + in("rdi") fd + in("rsi") buf + in("rdx") len + out("rax") r + } + return r; +} + +fun syscall_close(fd: i32) -> i32 { + let r: i32; + asm { + "mov rax, 3" + "syscall" + in("rdi") fd + out("rax") r + } + return r; +} + +fun syscall_mmap(addr: ptr, length: i32, prot: i32, flags: i32, fd: i32, offset: i32) -> ptr { + let r: ptr; + asm { + "mov rax, 9" + "syscall" + in("rdi") addr + in("rsi") length + in("rdx") prot + in("r10") flags + in("r8") fd + in("r9") offset + out("rax") r + } + return r; +} + +fun syscall_munmap(addr: ptr, length: i32) -> i32 { + let r: i32; + asm { + "mov rax, 11" + "syscall" + in("rdi") addr + in("rsi") length + out("rax") r + } + return r; +} + +fun main() { + let length: i32 = 4096; + var mem: ptr = syscall_mmap( + null, length, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, + -1, 0 + ); + + var msg: str = "Hello from Wave syscall!\n"; + var msg_ptr: ptr = msg; + + syscall_write(1, msg_ptr, 24); + syscall_munmap(mem, length); +} diff --git a/std/net/udp.wave b/std/net/udp.wave index 50b9096a..f447347c 100644 --- a/std/net/udp.wave +++ b/std/net/udp.wave @@ -1,4 +1,4 @@ -import("../sys/linux/syscall"); +import("std::sys::linux::syscall"); const AF_INET: i64 = 2; const SOCK_DGRAM: i64 = 2;