diff --git a/CMakeLists.txt b/CMakeLists.txt index dd7dbf9..473099d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.10) -project(fun VERSION 0.37.32 LANGUAGES C) +project(fun VERSION 0.37.22 LANGUAGES C) set(CMAKE_C_STANDARD 99) set(CMAKE_C_STANDARD_REQUIRED ON) @@ -378,12 +378,10 @@ target_include_directories(fun_core PUBLIC # Apply options to core if(FUN_DEBUG) message(STATUS "FUN_DEBUG enabled: building with verbose debug logging") - target_compile_definitions(fun_core PUBLIC FUN_VERSION="${PROJECT_VERSION}") target_compile_definitions(fun_core PUBLIC FUN_DEBUG=1) endif() # Provide default stdlib directory to the runtime -target_compile_definitions(fun_core PUBLIC FUN_VERSION="${PROJECT_VERSION}") target_compile_definitions(fun_core PUBLIC DEFAULT_LIB_DIR="${DEFAULT_LIB_DIR}") # PCSC include and link (if enabled) @@ -474,6 +472,7 @@ add_executable(fun src/fun.c ) # Provide version string to the CLI +target_compile_definitions(fun PRIVATE FUN_VERSION=\"${PROJECT_VERSION}\") if(FUN_WITH_REPL) # Enable REPL compilation path and add the REPL source target_compile_definitions(fun PRIVATE FUN_WITH_REPL=1) diff --git a/README.md b/README.md index 0c26be1..8e2a0d6 100644 --- a/README.md +++ b/README.md @@ -75,47 +75,9 @@ Fun may not change the world — but it will make programming a little more fun. - if/else if/else - try/catch/finally -### Lib (./lib/) +### Lib -``` -arrays.fun -crypt/ - crc32c.fun - crc32.fun - md5.fun - md5_legacy.fun - ripemd160.fun - Broken! - sha1.fun - sha256.fun - sha384.fun - sha512.fun -encoding/ - base64.fun -hello.fun -hex.fun -io/ - console.fun - ini.fun - json.fun - pcsc2.fun - pcsc.fun - process.fun - serial.fun - socket.fun - thread.fun - xml.fun -math.fun -regex - pcre2.fun -regex.fun -strings.fun -ui/ - tk.fun -utils/ - datetime.fun - math.fun - range.fun -``` +... ### Extensions (only Linux actually) diff --git a/examples/class_test.fun b/examples/class_test.fun deleted file mode 100755 index 6be0286..0000000 --- a/examples/class_test.fun +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env fun - -/* - * This file is part of the Fun programming language. - * https://fun-lang.xyz/ - * - * Copyright 2025 Johannes Findeisen - * Licensed under the terms of the Apache-2.0 license. - * https://opensource.org/license/apache-2-0 - * - * Added: 2025-12-28 - */ - -class Other(number val) - fun _construct(this, val) - this.v = val - -class Test() - fun _construct(this) - val = Other(123) - this.a = val - print("a set") - -t = Test() -print(t.a.v) - -/* Expected output: -a set -123 -*/ diff --git a/examples/data/htdocs/index.html b/examples/data/htdocs/index.html deleted file mode 100644 index df339a0..0000000 --- a/examples/data/htdocs/index.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - Fun HTTP Server - - -

Welcome to the Fun HTTP Server!

-

This page is served from ./examples/data/htdocs/index.html.

- - diff --git a/examples/data/htdocs/info.fun b/examples/data/htdocs/info.fun deleted file mode 100644 index 65e64cb..0000000 --- a/examples/data/htdocs/info.fun +++ /dev/null @@ -1,58 +0,0 @@ -/* - * This file is part of the Fun programming language. - * https://fun-lang.xyz/ - * - * Copyright 2025 Johannes Findeisen - * Licensed under the terms of the Apache-2.0 license. - * https://opensource.org/license/apache-2-0 - * - * Added: 2025-12-28 - */ - -#include - -print("") -print("

Fun Environment Information

") -print("

Current Path: " + env("PATH") + "

") -print("

Current User: " + env("USER") + "

") -print("

Time: " + date_format(time_now_ms(), "%Y-%m-%d %H:%M:%S") + "

") -print("

Version: " + to_string(fun_version()) + "

") -print("

Full Environment:

") -print("
    ") -all_env = env_all() -all_keys = keys(all_env) -i = 0 -while i < len(all_keys) - key = all_keys[i] - print("
  • " + key + "=" + all_env[key] + "
  • ") - i = i + 1 -print("
") -print("

GET Variables:

") -print("
    ") -qs = env("QUERY_STRING") -if (len(qs) > 0) - params = str_split(qs, "&") - i = 0 - while i < len(params) - kv = str_split(params[i], "=") - if (len(kv) == 2) - print("
  • " + kv[0] + " = " + kv[1] + "
  • ") - else - print("
  • " + params[i] + "
  • ") - i = i + 1 -print("
") -print("

POST Variables:

") -print("
    ") -pd = env("POST_DATA") -if (len(pd) > 0) - params = str_split(pd, "&") - i = 0 - while i < len(params) - kv = str_split(params[i], "=") - if (len(kv) == 2) - print("
  • " + kv[0] + " = " + kv[1] + "
  • ") - else - print("
  • " + params[i] + "
  • ") - i = i + 1 -print("
") -print("") diff --git a/examples/env_all.fun b/examples/env_all.fun deleted file mode 100644 index ccbd93b..0000000 --- a/examples/env_all.fun +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env fun - -/* - * This file is part of the Fun programming language. - * https://fun-lang.xyz/ - * - * Copyright 2025 Johannes Findeisen - * Licensed under the terms of the Apache-2.0 license. - * https://opensource.org/license/apache-2-0 - * - * Added: 2025-12-28 - */ - -all_env = env_all() -keys = keys(all_env) - -print("Number of environment variables: " + to_string(len(keys))) -print("--------------------------------------------------") - -i = 0 -while i < len(keys) - key = keys[i] - print(key + "=" + all_env[key]) - i = i + 1 - -/* Possible output: -Depends on your environment. -*/ diff --git a/examples/extra/http_server.fun b/examples/extra/http_server.fun deleted file mode 100755 index 0335919..0000000 --- a/examples/extra/http_server.fun +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env fun - -/* - * This file is part of the Fun programming language. - * https://fun-lang.xyz/ - * - * Copyright 2025 Johannes Findeisen - * Licensed under the terms of the Apache-2.0 license. - * https://opensource.org/license/apache-2-0 - * - * Added: 2025-12-28 - */ - -#include - -port = 8080 -htdocs = "./examples/data/htdocs" - -server = HTTPServer(port) -server.set_htdocs(htdocs) - -server.start() diff --git a/examples/extra/http_server_test.fun b/examples/extra/http_server_test.fun deleted file mode 100755 index ad3ab64..0000000 --- a/examples/extra/http_server_test.fun +++ /dev/null @@ -1,32 +0,0 @@ -#include - -c = TcpClient() -if (c.connect("127.0.0.1", 8080)) - print("Connecting to server...") - // Test GET - print("Testing GET...") - c.send("GET /info.fun?foo=bar&baz=qux HTTP/1.1\r\nHost: localhost\r\n\r\n") - resp = c.recv_all(4096) - print("GET Response contains foo=bar: " + to_string(find(resp, "foo = bar") >= 0)) - print("GET Response contains baz=qux: " + to_string(find(resp, "baz = qux") >= 0)) - - c.close() -else - print("Failed to connect to server") - -if (c.connect("127.0.0.1", 8080)) - // Test POST - print("Testing POST...") - body = "postfoo=postbar&postbaz=postqux" - req = "POST /info.fun HTTP/1.1\r\n" - req = req + "Host: localhost\r\n" - req = req + "Content-Length: " + to_string(len(body)) + "\r\n" - req = req + "\r\n" - req = req + body - c.send(req) - resp = c.recv_all(4096) - print("POST Response contains postfoo=postbar: " + to_string(find(resp, "postfoo = postbar") >= 0)) - print("POST Response contains postbaz=postqux: " + to_string(find(resp, "postbaz = postqux") >= 0)) - c.close() -else - print("Failed to connect to server for POST") diff --git a/examples/ripemd160_debug.fun b/examples/ripemd160_debug.fun old mode 100755 new mode 100644 diff --git a/examples/ripemd160_demo.fun b/examples/ripemd160_demo.fun old mode 100755 new mode 100644 diff --git a/examples/ripemd160_test.fun b/examples/ripemd160_test.fun old mode 100755 new mode 100644 diff --git a/examples/serial_demo.fun b/examples/serial_demo.fun deleted file mode 100755 index 7b2156c..0000000 --- a/examples/serial_demo.fun +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env fun - -/* - * This file is part of the Fun programming language. - * https://fun-lang.xyz/ - * - * Copyright 2025 Johannes Findeisen - * Licensed under the terms of the Apache-2.0 license. - * https://opensource.org/license/apache-2-0 - * - * Added: 2025-12-28 - */ - -#include - -// This is an example of how to use the Serial class from the stdlib. -// Note: This requires a serial device to be present at the specified path. - -path = "/dev/ttyUSB0" -baud = 115200 - -print("Opening serial port " + path + " at " + to_string(baud) + " baud...") -s = Serial(path, baud) - -if (s.open()) - print("Serial port opened successfully.") - - // Configure: 8 data bits, no parity (0), 1 stop bit, no flow control (0) - if (s.config(8, 0, 1, 0)) - print("Configured to 8N1.") - - sent = s.send("AT\r\n") - print("Sent " + to_string(sent) + " bytes.") - - // Wait a bit for response if needed (mocked by sleep if available) - // sleep_ms(100) - - resp = s.recv(64) - if (len(resp) > 0) - print("Received: " + resp) - else - print("No response received.") - else - print("Failed to configure serial port.") - - s.close() - print("Serial port closed.") -else - print("Failed to open serial port. (Do you have permissions?)") - -/* Possible output: -Opening serial port /dev/ttyUSB0 at 115200 baud... -Failed to open serial port. (Do you have permissions?) -*/ diff --git a/examples/test_bits.fun b/examples/test_bits.fun old mode 100755 new mode 100644 diff --git a/examples/test_rol.fun b/examples/test_rol.fun old mode 100755 new mode 100644 diff --git a/examples/test_serial.fun b/examples/test_serial.fun deleted file mode 100755 index d1c6fa0..0000000 --- a/examples/test_serial.fun +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env fun - -/* - * This file is part of the Fun programming language. - * https://fun-lang.xyz/ - * - * Copyright 2025 Johannes Findeisen - * Licensed under the terms of the Apache-2.0 license. - * https://opensource.org/license/apache-2-0 - * - * Added: 2025-12-28 - */ - -// Test script for serial communication -// This script attempts to open a virtual serial port if it exists, -// or just demonstrates the syntax if not. - -fun test_serial() - number fd = 0 - number baud = 9600 - string path = "/dev/ttyUSB0" - - print("Attempting to open serial port: " + path) - fd = serial_open(path, baud) - - if fd > 0 - print("Successfully opened serial port. FD: " + to_string(fd)) - - // Config: fd, data_bits, parity, stop_bits, flow_control - // Parity: 0=None, 1=Odd, 2=Even - // Flow: 0=None, 1=Hardware - number ok = serial_config(fd, 8, 0, 1, 0) - if ok - print("Configured serial port: 8N1, no flow control") - - number sent = serial_send(fd, "HELLO SERIAL\n") - print("Sent " + to_string(sent) + " bytes") - - // recv is blocking in this implementation - // data = serial_recv(fd, 100) - // print "Received: " + data - else - print("Failed to configure serial port") - - serial_close(fd) - print("Closed serial port") - else - print("Could not open serial port (this is expected if /dev/ttyUSB0 doesn't exist or no permission)") - -test_serial() - -/* Possible output: -Attempting to open serial port: /dev/ttyUSB0 -Could not open serial port (this is expected if /dev/ttyUSB0 doesn't exist or no permission) -*/ diff --git a/examples/test_shl.fun b/examples/test_shl.fun old mode 100755 new mode 100644 diff --git a/examples/test_types.fun b/examples/test_types.fun old mode 100755 new mode 100644 diff --git a/examples/test_xor.fun b/examples/test_xor.fun old mode 100755 new mode 100644 diff --git a/examples/version.fun b/examples/version.fun deleted file mode 100755 index 84d0456..0000000 --- a/examples/version.fun +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env fun - -print(to_string(fun_version())) - diff --git a/lib/crypt/ripemd160.fun b/lib/crypt/ripemd160.fun index f866ab1..bb9abd6 100644 --- a/lib/crypt/ripemd160.fun +++ b/lib/crypt/ripemd160.fun @@ -204,7 +204,7 @@ class RIPEMD160() B = T // Right side step - Tr = this.add32(this.rol32(this.add32(this.add32(Ar, this.F(stage_r, Br, Cr, Dr)), this.add32(M[this.RR[j]], this.KR[stage_r])), this.SR[j]), Er) + Tr = this.add32(this.rol32(this.add32(this.add32(Ar, this.F(stage_r, Br, Cr, Dr)), this.add32(M[this.RR[j]], this.KR[stage])), this.SR[j]), Er) Ar = Er Er = Dr Dr = this.rol32(Cr, 10) diff --git a/lib/io/serial.fun b/lib/io/serial.fun deleted file mode 100644 index 756d3ee..0000000 --- a/lib/io/serial.fun +++ /dev/null @@ -1,65 +0,0 @@ -/* - * This file is part of the Fun programming language. - * https://fun-lang.xyz/ - * - * Copyright 2025 Johannes Findeisen - * Licensed under the terms of the Apache-2.0 license. - * https://opensource.org/license/apache-2-0 - * - * Added: 2025-12-28 - */ - -/* - * Serial communication class for Fun stdlib. - * - * Provides: - * - Serial: wrapper over built-ins: serial_open, serial_config, serial_send, serial_recv, serial_close - * - * Usage: - * #include - * s = Serial("/dev/ttyUSB0", 115200) - * if (s.open()) - * s.config(8, 0, 1, 0) // 8N1, no flow control - * s.send("Hello Serial!") - * resp = s.recv(64) - * print("Received: " + resp) - * s.close() - */ - -class Serial(string path, number baud_rate) - - fun _construct(this, path, baud_rate) - this.path = path - this.baud_rate = baud_rate - this.fd = 0 - - fun open(this) - this.fd = serial_open(this.path, this.baud_rate) - return this.fd > 0 - - fun is_open(this) - return this.fd > 0 - - fun config(this, data_bits, parity, stop_bits, flow_control) - if (!this.is_open()) - return 0 - // parity: 0=None, 1=Odd, 2=Even - // flow_control: 0=None, 1=Hardware (RTS/CTS) - return serial_config(this.fd, data_bits, parity, stop_bits, flow_control) - - fun send(this, data) - if (!this.is_open()) - return -1 - return serial_send(this.fd, to_string(data)) - - fun recv(this, maxlen) - if (!this.is_open()) - return "" - return serial_recv(this.fd, to_number(maxlen)) - - fun close(this) - if (this.is_open()) - res = serial_close(this.fd) - this.fd = 0 - return res - return 0 diff --git a/lib/net/http_server.fun b/lib/net/http_server.fun deleted file mode 100644 index dc78dac..0000000 --- a/lib/net/http_server.fun +++ /dev/null @@ -1,108 +0,0 @@ -/* - * This file is part of the Fun programming language. - * https://fun-lang.xyz/ - * - * Copyright 2025 Johannes Findeisen - * Licensed under the terms of the Apache-2.0 license. - * https://opensource.org/license/apache-2-0 - * - * Added: 2025-12-28 - */ - -#include -#include - -class HTTPServer(number port) - fun _construct(this, port) - this.port = port - srv = TcpServer(port, 10) - this.server = srv - this.htdocs = "./" - - fun set_htdocs(this, path) - this.htdocs = to_string(path) - - fun start(this) - if (this.server.listen() <= 0) - print("HTTPServer: failed to listen on port " + to_string(this.port)) - return 0 - print("HTTPServer: serving " + this.htdocs + " on port " + to_string(this.port)) - while true - client_fd = this.server.accept() - if (client_fd > 0) - this.handle_client(client_fd) - return 1 - - fun handle_client(this, fd) - request = sock_recv(fd, 4096) - if (len(request) == 0) - sock_close(fd) - return 0 - - // Basic request parsing - lines = str_split(request, "\n") - if (len(lines) == 0) - sock_close(fd) - return 0 - - first_line = lines[0] - parts = str_split(first_line, " ") - if (len(parts) < 2) - sock_close(fd) - return 0 - - method = str_trim(parts[0]) - full_path = str_trim(parts[1]) - - path = full_path - query_string = "" - q_pos = find(full_path, "?") - if (q_pos >= 0) - path = substr(full_path, 0, q_pos) - query_string = substr(full_path, q_pos + 1, len(full_path) - q_pos - 1) - - if (path == "/") - path = "/index.html" - - file_path = this.htdocs + path - - post_data = "" - if (method == "POST") - // Find the end of headers (marked by \r\n\r\n or \n\n) - header_end = find(request, "\r\n\r\n") - if (header_end >= 0) - post_data = substr(request, header_end + 4, len(request) - header_end - 4) - else - header_end = find(request, "\n\n") - if (header_end >= 0) - post_data = substr(request, header_end + 2, len(request) - header_end - 2) - - content = "" - if (str_ends_with(path, ".fun")) - env_vars = "" - if (len(query_string) > 0) - env_vars = "QUERY_STRING='" + query_string + "' " - if (len(post_data) > 0) - env_vars = env_vars + "POST_DATA='" + post_data + "' " - - res = proc_run(env_vars + " " + "fun" + " " + file_path) - content = res["out"] - else - content = read_file(file_path) - - if (len(content) > 0) - this.send_response(fd, 200, "OK", content) - else - this.send_response(fd, 404, "Not Found", "

404 Not Found

") - - sock_close(fd) - return 1 - - fun send_response(this, fd, status_code, status_text, body) - resp = "HTTP/1.1 " + to_string(status_code) + " " + status_text + "\r\n" - resp = resp + "Content-Type: text/html\r\n" - resp = resp + "Content-Length: " + to_string(len(body)) + "\r\n" - resp = resp + "Connection: close\r\n" - resp = resp + "\r\n" - resp = resp + body - sock_send(fd, resp) diff --git a/lib/strings.fun b/lib/strings.fun index 2ab3e28..47c803a 100644 --- a/lib/strings.fun +++ b/lib/strings.fun @@ -93,7 +93,7 @@ fun str_replace_all(s, from, to) out = [] number i = 0 while i < n - if ((i + lf <= n) && (substr(src, i, lf) == f)) + if (i + lf <= n) && (substr(src, i, lf) == f) push(out, t) i = i + lf else diff --git a/make b/make index 914b699..171c7f6 100755 --- a/make +++ b/make @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/bash # This file is part of the Fun programming language. # https://fun-lang.xyz/ diff --git a/src/bytecode.c b/src/bytecode.c index f1af0e2..6bf4c6e 100644 --- a/src/bytecode.c +++ b/src/bytecode.c @@ -131,8 +131,6 @@ static const char *opcode_name(OpCode op) { case OP_TIME_NOW_MS: return "TIME_NOW_MS"; case OP_CLOCK_MONO_MS: return "CLOCK_MONO_MS"; case OP_DATE_FORMAT: return "DATE_FORMAT"; - case OP_ENV_ALL: return "ENV_ALL"; - case OP_FUN_VERSION: return "FUN_VERSION"; case OP_THREAD_SPAWN: return "THREAD_SPAWN"; case OP_THREAD_JOIN: return "THREAD_JOIN"; case OP_SLEEP_MS: return "SLEEP_MS"; diff --git a/src/bytecode.h b/src/bytecode.h index 0c0e971..79a457d 100644 --- a/src/bytecode.h +++ b/src/bytecode.h @@ -126,8 +126,6 @@ typedef enum { OP_TIME_NOW_MS, // pushes current wall-clock time in milliseconds since Unix epoch OP_CLOCK_MONO_MS, // pushes monotonic clock in milliseconds (not wall time) OP_DATE_FORMAT, // pops fmt string, ms epoch (int); pushes formatted date string using strftime - OP_ENV_ALL, // pushes map of all environment variables - OP_FUN_VERSION, // pushes version string // Threads OP_THREAD_SPAWN, // operand: 0=no args, 1=has args; pops [args?], fn; pushes thread id (int>0) @@ -217,13 +215,6 @@ typedef enum { // Tk additions OP_TK_BIND, // pops command, event, id; binds event to command - // Serial communication (termios) - OP_SERIAL_OPEN, // pops baud_rate (int), path (string); returns fd (int) or 0 - OP_SERIAL_CONFIG, // pops flow_control, stop_bits, parity, data_bits, fd; returns 1/0 - OP_SERIAL_SEND, // pops data (string), fd; returns bytes sent (int) - OP_SERIAL_RECV, // pops maxlen (int), fd; returns data (string) - OP_SERIAL_CLOSE, // pops fd; returns 1/0 - // Tk (Tcl/Tk) optional minimal API OP_TK_EVAL, // pops script string; pushes int rc (0 = OK) OP_TK_RESULT, // pushes string: last Tcl result diff --git a/src/fun.c b/src/fun.c index 041e306..afd7305 100644 --- a/src/fun.c +++ b/src/fun.c @@ -9,7 +9,6 @@ #include "parser.h" #include #include -#include #include #ifdef FUN_WITH_REPL @@ -43,9 +42,6 @@ static void print_usage(const char *prog) { } int main(int argc, char **argv) { - /* Set FUN_EXECUTABLE environment variable to the path of this binary */ - setenv("FUN_EXECUTABLE", argv[0], 1); - VM vm; vm_init(&vm); diff --git a/src/parser.c b/src/parser.c index f5b69d9..6788539 100644 --- a/src/parser.c +++ b/src/parser.c @@ -757,20 +757,6 @@ static int emit_primary(Bytecode *bc, const char *src, size_t len, size_t *pos) free(name); return 1; } - if (strcmp(name, "env_all") == 0) { - (*pos)++; /* '(' */ - if (!consume_char(src, len, pos, ')')) { parser_fail(*pos, "env_all expects ()"); free(name); return 0; } - bytecode_add_instruction(bc, OP_ENV_ALL, 0); - free(name); - return 1; - } - if (strcmp(name, "fun_version") == 0) { - (*pos)++; /* '(' */ - if (!consume_char(src, len, pos, ')')) { parser_fail(*pos, "fun_version expects ()"); free(name); return 0; } - bytecode_add_instruction(bc, OP_FUN_VERSION, 0); - free(name); - return 1; - } if (strcmp(name, "os_list_dir") == 0) { (*pos)++; /* '(' */ if (!emit_expression(bc, src, len, pos)) { parser_fail(*pos, "os_list_dir expects (path)"); free(name); return 0; } @@ -1302,59 +1288,6 @@ static int emit_primary(Bytecode *bc, const char *src, size_t len, size_t *pos) free(name); return 1; } - /* Serial builtins */ - if (strcmp(name, "serial_open") == 0) { - (*pos)++; /* '(' */ - if (!emit_expression(bc, src, len, pos)) { parser_fail(*pos, "serial_open expects (path, baud)"); free(name); return 0; } - if (!consume_char(src, len, pos, ',')) { parser_fail(*pos, "serial_open expects (path, baud)"); free(name); return 0; } - if (!emit_expression(bc, src, len, pos)) { parser_fail(*pos, "serial_open expects (path, baud)"); free(name); return 0; } - if (!consume_char(src, len, pos, ')')) { parser_fail(*pos, "Expected ')' after serial_open args"); free(name); return 0; } - bytecode_add_instruction(bc, OP_SERIAL_OPEN, 0); - free(name); - return 1; - } - if (strcmp(name, "serial_config") == 0) { - (*pos)++; /* '(' */ - // fd, data_bits, parity, stop_bits, flow_control - for (int i = 0; i < 5; ++i) { - if (!emit_expression(bc, src, len, pos)) { parser_fail(*pos, "serial_config expects 5 arguments"); free(name); return 0; } - if (i < 4) { - if (!consume_char(src, len, pos, ',')) { parser_fail(*pos, "serial_config expects 5 arguments"); free(name); return 0; } - } - } - if (!consume_char(src, len, pos, ')')) { parser_fail(*pos, "Expected ')' after serial_config args"); free(name); return 0; } - bytecode_add_instruction(bc, OP_SERIAL_CONFIG, 0); - free(name); - return 1; - } - if (strcmp(name, "serial_send") == 0) { - (*pos)++; /* '(' */ - if (!emit_expression(bc, src, len, pos)) { parser_fail(*pos, "serial_send expects (fd, data)"); free(name); return 0; } - if (!consume_char(src, len, pos, ',')) { parser_fail(*pos, "serial_send expects (fd, data)"); free(name); return 0; } - if (!emit_expression(bc, src, len, pos)) { parser_fail(*pos, "serial_send expects (fd, data)"); free(name); return 0; } - if (!consume_char(src, len, pos, ')')) { parser_fail(*pos, "Expected ')' after serial_send args"); free(name); return 0; } - bytecode_add_instruction(bc, OP_SERIAL_SEND, 0); - free(name); - return 1; - } - if (strcmp(name, "serial_recv") == 0) { - (*pos)++; /* '(' */ - if (!emit_expression(bc, src, len, pos)) { parser_fail(*pos, "serial_recv expects (fd, maxlen)"); free(name); return 0; } - if (!consume_char(src, len, pos, ',')) { parser_fail(*pos, "serial_recv expects (fd, maxlen)"); free(name); return 0; } - if (!emit_expression(bc, src, len, pos)) { parser_fail(*pos, "serial_recv expects (fd, maxlen)"); free(name); return 0; } - if (!consume_char(src, len, pos, ')')) { parser_fail(*pos, "Expected ')' after serial_recv args"); free(name); return 0; } - bytecode_add_instruction(bc, OP_SERIAL_RECV, 0); - free(name); - return 1; - } - if (strcmp(name, "serial_close") == 0) { - (*pos)++; /* '(' */ - if (!emit_expression(bc, src, len, pos)) { parser_fail(*pos, "serial_close expects (fd)"); free(name); return 0; } - if (!consume_char(src, len, pos, ')')) { parser_fail(*pos, "Expected ')' after serial_close arg"); free(name); return 0; } - bytecode_add_instruction(bc, OP_SERIAL_CLOSE, 0); - free(name); - return 1; - } /* string ops */ if (strcmp(name, "split") == 0) { (*pos)++; /* '(' */ diff --git a/src/vm.c b/src/vm.c index f2a4470..3c714c6 100644 --- a/src/vm.c +++ b/src/vm.c @@ -667,8 +667,6 @@ void vm_run(VM *vm, Bytecode *entry) { #include "vm/math/random_seed.c" #include "vm/os/env.c" - #include "vm/os/env_all.c" - #include "vm/os/fun_version.c" #include "vm/os/sleep_ms.c" #include "vm/os/thread_join.c" #include "vm/os/thread_spawn.c" @@ -678,11 +676,6 @@ void vm_run(VM *vm, Bytecode *entry) { #include "vm/os/clock_mono_ms.c" #include "vm/os/date_format.c" #include "vm/os/random_number.c" - #include "vm/os/serial_open.c" - #include "vm/os/serial_config.c" - #include "vm/os/serial_send.c" - #include "vm/os/serial_recv.c" - #include "vm/os/serial_close.c" /* Socket ops */ #include "vm/os/socket_tcp_listen.c" diff --git a/src/vm.h b/src/vm.h index bff9bfb..4fd2281 100644 --- a/src/vm.h +++ b/src/vm.h @@ -51,7 +51,6 @@ static const char *opcode_names[] = { "EXIT", "OS_LIST_DIR", "TK_BIND", - "SERIAL_OPEN","SERIAL_CONFIG","SERIAL_SEND","SERIAL_RECV","SERIAL_CLOSE", "TK_EVAL","TK_RESULT","TK_LOOP","TK_WM_TITLE","TK_LABEL","TK_BUTTON","TK_PACK", "TRY_PUSH","TRY_POP","THROW" }; diff --git a/src/vm/os/env_all.c b/src/vm/os/env_all.c deleted file mode 100644 index 61b76cc..0000000 --- a/src/vm/os/env_all.c +++ /dev/null @@ -1,35 +0,0 @@ -/** - * This file is part of the Fun programming language. - * https://fun-lang.xyz/ - * - * Copyright 2025 Johannes Findeisen - * Licensed under the terms of the Apache-2.0 license. - * https://opensource.org/license/apache-2-0 - * - * Added: 2025-12-28 - */ - -// Get all environment variables of the operation system and push them as a map. - -case OP_ENV_ALL: { - extern char **environ; - Value m = make_map_empty(); - if (environ) { - for (char **env = environ; *env; ++env) { - char *entry = *env; - char *equals = strchr(entry, '='); - if (equals) { - size_t key_len = equals - entry; - char *key = malloc(key_len + 1); - if (key) { - memcpy(key, entry, key_len); - key[key_len] = '\0'; - map_set(&m, key, make_string(equals + 1)); - free(key); - } - } - } - } - push_value(vm, m); - break; -} diff --git a/src/vm/os/fun_version.c b/src/vm/os/fun_version.c deleted file mode 100644 index f2ca4b6..0000000 --- a/src/vm/os/fun_version.c +++ /dev/null @@ -1,20 +0,0 @@ -/** - * This file is part of the Fun programming language. - * https://fun-lang.xyz/ - * - * Copyright 2025 Johannes Findeisen - * Licensed under the terms of the Apache-2.0 license. - * https://opensource.org/license/apache-2-0 - * - * Added: 2025-12-28 - */ - -// Pushes the current Fun version string onto the stack. - -case OP_FUN_VERSION: { -#ifndef FUN_VERSION -#define FUN_VERSION "0.0.0-dev" -#endif - push_value(vm, make_string(FUN_VERSION)); - break; -} diff --git a/src/vm/os/random_number.c b/src/vm/os/random_number.c index adc81f1..36e3dab 100644 --- a/src/vm/os/random_number.c +++ b/src/vm/os/random_number.c @@ -24,11 +24,8 @@ #if defined(_WIN32) || defined(_WIN64) #include #include -#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) +#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) #include - #include - /* On some BSDs, arc4random_buf might be hidden by _POSIX_C_SOURCE. */ - void arc4random_buf(void *, size_t); #elif defined(__unix__) #if __has_include() #include @@ -88,7 +85,7 @@ case OP_RANDOM_NUMBER: { NTSTATUS st = BCryptGenRandom(NULL, raw, (ULONG)len, BCRYPT_USE_SYSTEM_PREFERRED_RNG); ok = (st == 0); } -#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) +#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) { arc4random_buf(raw, (size_t)len); ok = 1; diff --git a/src/vm/os/serial_close.c b/src/vm/os/serial_close.c deleted file mode 100644 index b03290d..0000000 --- a/src/vm/os/serial_close.c +++ /dev/null @@ -1,31 +0,0 @@ -/** - * This file is part of the Fun programming language. - * https://fun-lang.xyz/ - * - * Copyright 2025 Johannes Findeisen - * Licensed under the terms of the Apache-2.0 license. - * https://opensource.org/license/apache-2-0 - * - * Added: 2025-12-28 - */ - -#ifdef __unix__ -#include -#endif - -case OP_SERIAL_CLOSE: { - /* Pops fd (int); returns 1/0 */ - Value fdv = pop_value(vm); - int ok = 0; -#ifdef __unix__ - if (fdv.type != VAL_INT) { - fprintf(stderr, "Runtime type error: serial_close expects (int fd)\n"); - } else { - int fd = (int)fdv.i; - if (close(fd) == 0) ok = 1; - } -#endif - free_value(fdv); - push_value(vm, make_int(ok)); - break; -} diff --git a/src/vm/os/serial_config.c b/src/vm/os/serial_config.c deleted file mode 100644 index 04994b9..0000000 --- a/src/vm/os/serial_config.c +++ /dev/null @@ -1,90 +0,0 @@ -/** - * This file is part of the Fun programming language. - * https://fun-lang.xyz/ - * - * Copyright 2025 Johannes Findeisen - * Licensed under the terms of the Apache-2.0 license. - * https://opensource.org/license/apache-2-0 - * - * Added: 2025-12-28 - */ - -#ifdef __unix__ -#include -#endif - -case OP_SERIAL_CONFIG: { - /* Pops flow_control (int), stop_bits (int), parity (int), data_bits (int), fd (int); returns 1/0 */ - Value flowv = pop_value(vm); - Value stopv = pop_value(vm); - Value parityv = pop_value(vm); - Value datav = pop_value(vm); - Value fdv = pop_value(vm); - int ok = 0; -#ifdef __unix__ - if (flowv.type != VAL_INT || stopv.type != VAL_INT || parityv.type != VAL_INT || - datav.type != VAL_INT || fdv.type != VAL_INT) { - fprintf(stderr, "Runtime type error: serial_config expects (int fd, int data_bits, int parity, int stop_bits, int flow_control)\n"); - } else { - int fd = (int)fdv.i; - int data_bits = (int)datav.i; - int parity = (int)parityv.i; - int stop_bits = (int)stopv.i; - int flow = (int)flowv.i; - - struct termios options; - if (tcgetattr(fd, &options) == 0) { - // Data bits - options.c_cflag &= ~CSIZE; - switch (data_bits) { - case 5: options.c_cflag |= CS5; break; - case 6: options.c_cflag |= CS6; break; - case 7: options.c_cflag |= CS7; break; - case 8: default: options.c_cflag |= CS8; break; - } - - // Parity - switch (parity) { - case 0: // None - options.c_cflag &= ~PARENB; - break; - case 1: // Odd - options.c_cflag |= PARENB; - options.c_cflag |= PARODD; - break; - case 2: // Even - options.c_cflag |= PARENB; - options.c_cflag &= ~PARODD; - break; - } - - // Stop bits - if (stop_bits == 2) { - options.c_cflag |= CSTOPB; - } else { - options.c_cflag &= ~CSTOPB; - } - - // Flow control -#ifdef CRTSCTS - if (flow == 1) { // Hardware (RTS/CTS) - options.c_cflag |= CRTSCTS; - } else { - options.c_cflag &= ~CRTSCTS; - } -#endif - - if (tcsetattr(fd, TCSANOW, &options) == 0) { - ok = 1; - } - } - } -#endif - free_value(flowv); - free_value(stopv); - free_value(parityv); - free_value(datav); - free_value(fdv); - push_value(vm, make_int(ok)); - break; -} diff --git a/src/vm/os/serial_open.c b/src/vm/os/serial_open.c deleted file mode 100644 index 1694df3..0000000 --- a/src/vm/os/serial_open.c +++ /dev/null @@ -1,142 +0,0 @@ -/** - * This file is part of the Fun programming language. - * https://fun-lang.xyz/ - * - * Copyright 2025 Johannes Findeisen - * Licensed under the terms of the Apache-2.0 license. - * https://opensource.org/license/apache-2-0 - * - * Added: 2025-12-28 - */ - -#ifdef __unix__ -#include -#include -#include - -/* Fallbacks for baud rates that might be missing on some systems */ -#ifndef B50 -#define B50 0000001 -#endif -#ifndef B75 -#define B75 0000002 -#endif -#ifndef B110 -#define B110 0000003 -#endif -#ifndef B134 -#define B134 0000004 -#endif -#ifndef B150 -#define B150 0000005 -#endif -#ifndef B200 -#define B200 0000006 -#endif -#ifndef B300 -#define B300 0000007 -#endif -#ifndef B600 -#define B600 0000010 -#endif -#ifndef B1200 -#define B1200 0000011 -#endif -#ifndef B1800 -#define B1800 0000012 -#endif -#ifndef B2400 -#define B2400 0000013 -#endif -#ifndef B4800 -#define B4800 0000014 -#endif -#ifndef B9600 -#define B9600 0000015 -#endif -#ifndef B19200 -#define B19200 0000016 -#endif -#ifndef B38400 -#define B38400 0000017 -#endif -#ifndef B57600 -#define B57600 0010001 -#endif -#ifndef B115200 -#define B115200 0010002 -#endif -#ifndef B230400 -#define B230400 0010003 -#endif - -#ifndef O_NDELAY -#define O_NDELAY O_NONBLOCK -#endif -#endif - -case OP_SERIAL_OPEN: { - /* Pops baud_rate (int), path (string); returns fd (int) or 0 */ - Value baudv = pop_value(vm); - Value pathv = pop_value(vm); - int fd = 0; -#ifdef __unix__ - if (baudv.type != VAL_INT || pathv.type != VAL_STRING) { - fprintf(stderr, "Runtime type error: serial_open expects (string path, int baud_rate)\n"); - free_value(baudv); - free_value(pathv); - push_value(vm, make_int(0)); - break; - } - - const char *path = pathv.s ? pathv.s : ""; - int baud = (int)baudv.i; - speed_t speed; - - switch (baud) { - case 50: speed = B50; break; - case 75: speed = B75; break; - case 110: speed = B110; break; - case 134: speed = B134; break; - case 150: speed = B150; break; - case 200: speed = B200; break; - case 300: speed = B300; break; - case 600: speed = B600; break; - case 1200: speed = B1200; break; - case 1800: speed = B1800; break; - case 2400: speed = B2400; break; - case 4800: speed = B4800; break; - case 9600: speed = B9600; break; - case 19200: speed = B19200; break; - case 38400: speed = B38400; break; - case 57600: speed = B57600; break; - case 115200: speed = B115200; break; - case 230400: speed = B230400; break; - default: speed = B9600; break; - } - - fd = open(path, O_RDWR | O_NOCTTY | O_NDELAY); - if (fd != -1) { - struct termios options; - tcgetattr(fd, &options); - cfsetispeed(&options, speed); - cfsetospeed(&options, speed); - options.c_cflag |= (CLOCAL | CREAD); - options.c_cflag &= ~PARENB; - options.c_cflag &= ~CSTOPB; - options.c_cflag &= ~CSIZE; - options.c_cflag |= CS8; - options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); - options.c_iflag &= ~(IXON | IXOFF | IXANY); - options.c_oflag &= ~OPOST; - tcsetattr(fd, TCSANOW, &options); - fcntl(fd, F_SETFL, 0); // block on read - } else { - fd = 0; - } -#endif - free_value(baudv); - free_value(pathv); - push_value(vm, make_int(fd > 0 ? fd : 0)); - break; -} diff --git a/src/vm/os/serial_recv.c b/src/vm/os/serial_recv.c deleted file mode 100644 index 520bed3..0000000 --- a/src/vm/os/serial_recv.c +++ /dev/null @@ -1,47 +0,0 @@ -/** - * This file is part of the Fun programming language. - * https://fun-lang.xyz/ - * - * Copyright 2025 Johannes Findeisen - * Licensed under the terms of the Apache-2.0 license. - * https://opensource.org/license/apache-2-0 - * - * Added: 2025-12-28 - */ - -#ifdef __unix__ -#include -#endif - -case OP_SERIAL_RECV: { - /* Pops maxlen (int), fd (int); returns data (string) */ - Value maxv = pop_value(vm); - Value fdv = pop_value(vm); - char *out = NULL; -#ifdef __unix__ - if (fdv.type != VAL_INT || maxv.type != VAL_INT) { - fprintf(stderr, "Runtime type error: serial_recv expects (int fd, int maxlen)\n"); - } else { - int fd = (int)fdv.i; - int maxlen = (int)maxv.i; - if (maxlen <= 0) maxlen = 4096; - if (maxlen > 1<<20) maxlen = 1<<20; /* cap at 1MB */ - out = (char*)malloc((size_t)maxlen + 1); - if (out) { - ssize_t n = read(fd, out, (size_t)maxlen); - if (n <= 0) { - free(out); - out = NULL; - } else { - out[n] = '\0'; - } - } - } -#endif - free_value(maxv); - free_value(fdv); - Value s = make_string(out ? out : ""); - if (out) free(out); - push_value(vm, s); - break; -} diff --git a/src/vm/os/serial_send.c b/src/vm/os/serial_send.c deleted file mode 100644 index c679fcc..0000000 --- a/src/vm/os/serial_send.c +++ /dev/null @@ -1,36 +0,0 @@ -/** - * This file is part of the Fun programming language. - * https://fun-lang.xyz/ - * - * Copyright 2025 Johannes Findeisen - * Licensed under the terms of the Apache-2.0 license. - * https://opensource.org/license/apache-2-0 - * - * Added: 2025-12-28 - */ - -#ifdef __unix__ -#include -#endif - -case OP_SERIAL_SEND: { - /* Pops data (string), fd (int); returns bytes sent (int) */ - Value datav = pop_value(vm); - Value fdv = pop_value(vm); - int sent = -1; -#ifdef __unix__ - if (fdv.type != VAL_INT || datav.type != VAL_STRING) { - fprintf(stderr, "Runtime type error: serial_send expects (int fd, string data)\n"); - } else { - int fd = (int)fdv.i; - const char *buf = datav.s ? datav.s : ""; - size_t len = strlen(buf); - ssize_t n = write(fd, buf, len); - if (n >= 0) sent = (int)n; - } -#endif - free_value(datav); - free_value(fdv); - push_value(vm, make_int(sent)); - break; -}