diff --git a/CMakeLists.txt b/CMakeLists.txt index 473099d..328dea4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.10) -project(fun VERSION 0.37.22 LANGUAGES C) +project(fun VERSION 0.37.17 LANGUAGES C) set(CMAKE_C_STANDARD 99) set(CMAKE_C_STANDARD_REQUIRED ON) diff --git a/examples/error/test_indent.fun b/examples/error/test_indent.fun deleted file mode 100755 index a052832..0000000 --- a/examples/error/test_indent.fun +++ /dev/null @@ -1,21 +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-24 - */ - -if (true) - print("This should fail if 4 spaces are not allowed") -else - print("This is 2 spaces") - -/* Expected output: -This should fail if 4 spaces are not allowed -*/ diff --git a/examples/ripemd160_debug.fun b/examples/ripemd160_debug.fun deleted file mode 100644 index 0c40593..0000000 --- a/examples/ripemd160_debug.fun +++ /dev/null @@ -1,154 +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-27 - */ - -#include - -fun to_hex_32(v) - d = ["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"] - out = [] - i = 0 - while i < 4 - b = band(shr(v, (3 - i) * 8), 0xFF) - push(out, d[shr(b, 4)]) - push(out, d[band(b, 0xF)]) - i = i + 1 - return join(out, "") - -rmd = RIPEMD160() -state = [1732584193, 4023233417, 2562383102, 271733878, 3285377520] -block = [] -push(block, 128) // 0x80 -i = 1 -while i < 64 - push(block, 0) - i = i + 1 - -print("Initial state:") -for v in state - print(" " + to_hex_32(v)) - -// Manual process_block logic with prints -M = [] -i = 0 -while i < 16 - j = i * 4 - push(M, rmd.word32_le(block[j], block[j+1], block[j+2], block[j+3])) - i = i + 1 - -al = state[0] -bl = state[1] -cl = state[2] -dl = state[3] -el = state[4] -ar = state[0] -br = state[1] -cr = state[2] -dr = state[3] -er = state[4] - -j = 0 -while j < 80 - if j < 16 - stage = 0 - stage_r = 4 - else if j < 32 - stage = 1 - stage_r = 3 - else if j < 48 - stage = 2 - stage_r = 2 - else if j < 64 - stage = 3 - stage_r = 1 - else - stage = 4 - stage_r = 0 - - f = rmd.F(stage, bl, cl, dl) - TL1 = rmd.add32(al, f) - TL2 = rmd.add32(M[rmd.RL[j]], rmd.KL[stage]) - TL3 = rmd.add32(TL1, TL2) - TL4 = rmd.rol32(TL3, rmd.SL[j]) - TL = rmd.add32(TL4, el) - if j < 2 - print("j=" + to_string(j) + " L: al=" + to_hex_32(al) + " f=" + to_hex_32(f) + " TL3=" + to_hex_32(TL3) + " TL4=" + to_hex_32(TL4) + " TL=" + to_hex_32(TL)) - al = el - el = dl - dl = rmd.rol32(cl, 10) - cl = bl - bl = TL - - fr = rmd.F(stage_r, br, cr, dr) - TR1 = rmd.add32(ar, fr) - TR2 = rmd.add32(M[rmd.RR[j]], rmd.KR[stage]) - TR3 = rmd.add32(TR1, TR2) - TR4 = rmd.rol32(TR3, rmd.SR[j]) - TR = rmd.add32(TR4, er) - if j < 2 - print("j=" + to_string(j) + " R: ar=" + to_hex_32(ar) + " fr=" + to_hex_32(fr) + " TR3=" + to_hex_32(TR3) + " TR4=" + to_hex_32(TR4) + " TR=" + to_hex_32(TR)) - ar = er - er = dr - dr = rmd.rol32(cr, 10) - cr = br - br = TR - - if j == 0 - print("After j=0:") - print(" L: al=" + to_hex_32(al) + " bl=" + to_hex_32(bl) + " cl=" + to_hex_32(cl) + " dl=" + to_hex_32(dl) + " el=" + to_hex_32(el)) - print(" R: ar=" + to_hex_32(ar) + " br=" + to_hex_32(br) + " cr=" + to_hex_32(cr) + " dr=" + to_hex_32(dr) + " er=" + to_hex_32(er)) - - j = j + 1 - -print("Registers after 80 steps:") -print(" L: A=" + to_hex_32(al) + " B=" + to_hex_32(bl) + " C=" + to_hex_32(cl) + " D=" + to_hex_32(dl) + " E=" + to_hex_32(el)) -print(" R: Ar=" + to_hex_32(ar) + " Br=" + to_hex_32(br) + " Cr=" + to_hex_32(cr) + " Dr=" + to_hex_32(dr) + " Er=" + to_hex_32(er)) - -h0 = rmd.add32(state[1], rmd.add32(cl, dr)) -h1 = rmd.add32(state[2], rmd.add32(dl, er)) -h2 = rmd.add32(state[3], rmd.add32(el, ar)) -h3 = rmd.add32(state[4], rmd.add32(al, br)) -h4 = rmd.add32(state[0], rmd.add32(bl, cr)) -state[0] = h0 -state[1] = h1 -state[2] = h2 -state[3] = h3 -state[4] = h4 - -print("Final state:") -for v in state - print(" " + to_hex_32(v)) - -/* Possible output: -Initial state: - 67452301 - efcdab89 - 98badcfe - 10325476 - c3d2e1f0 -j=0 L: al=67452301 f=67452301 TL3=ce8a4682 TL4=52341674 TL=1606f864 -j=0 R: ar=67452301 fr=10325476 TR3=c81a035d TR4=1a035dc8 TR=ddd63fb8 -After j=0: - L: al=c3d2e1f0 bl=1606f864 cl=efcdab89 dl=eb73fa62 el=10325476 - R: ar=c3d2e1f0 br=ddd63fb8 cr=efcdab89 dr=eb73fa62 er=10325476 -j=1 L: al=c3d2e1f0 f=12b8a98f TL3=d68b8b7f TL4=e2dff5a2 TL=f3124a18 -j=1 R: ar=c3d2e1f0 fr=221b9025 TR3=3690fdfb TR4=21fbf66d TR=322e4ae3 -Registers after 80 steps: - L: A=594637a7 B=215d97b3 C=eba027eb D=b99cdc7a E=ec4dcdff - R: Ar=e7eb2e49 Br=85bff1f4 Cr=1d9bc99d Dr=a7ffa90b Er=ffcec761 -Final state: - 836d7c7f - 522680d9 - e46b50be - a2d90b8b - a63e8451 -*/ diff --git a/examples/ripemd160_demo.fun b/examples/ripemd160_demo.fun deleted file mode 100644 index 9f7d06c..0000000 --- a/examples/ripemd160_demo.fun +++ /dev/null @@ -1,58 +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-27 - */ - -// THIS IS BROKEN ACTUALLY! IT DOES NOT CALCULATE THE EXPECTED HASHES! - -// Example usage of the RIPEMD-160 hash algorithm. - -#include - -rmd = RIPEMD160() - -// Test case 1: Empty string -s1 = "" -h1 = rmd.ripemd160_str(s1) -print("RIPEMD-160(\"" + s1 + "\") = " + h1) -// Expected: 9c1185a5c5e9fc54612808977ee8f548b2258d31 - -// Test case 2: "abc" -s2 = "abc" -h2 = rmd.ripemd160_str(s2) -print("RIPEMD-160(\"" + s2 + "\") = " + h2) -// Expected: 8eb208f7e05d987a9b044a8e98c6b087f15a0bfc - -// Test case 3: "message digest" -s3 = "message digest" -h3 = rmd.ripemd160_str(s3) -print("RIPEMD-160(\"" + s3 + "\") = " + h3) -// Expected: 5d0689ef49d2fae572b881b123a85ffa21595f36 - -// Example of hashing from hex string -hex_input = "616263" // "abc" in hex -h4 = rmd.ripemd160_hex(hex_input) -print("RIPEMD-160(hex: " + hex_input + ") = " + h4) -// Expected: 8eb208f7e05d987a9b044a8e98c6b087f15a0bfc - -/* Expected output: -RIPEMD-160("") = 9c1185a5c5e9fc54612808977ee8f548b2258d31 -RIPEMD-160("abc") = 8eb208f7e05d987a9b044a8e98c6b087f15a0bfc -RIPEMD-160("message digest") = 5d0689ef49d2fae572b881b123a85ffa21595f36 -RIPEMD-160(hex: 616263) = 8eb208f7e05d987a9b044a8e98c6b087f15a0bfc -*/ - -/* Actual output: -RIPEMD-160("") = d90cc72ef4ad5a2c51f89dc938de0b989c4c4b46 -RIPEMD-160("abc") = 7f339b642aaa074a849c6c1cd860cb049cc792b3 -RIPEMD-160("message digest") = a4f9cd0270a341d05a713df4bf49a3ce8aabde64 -RIPEMD-160(hex: 616263) = 7f339b642aaa074a849c6c1cd860cb049cc792b3 -*/ diff --git a/examples/ripemd160_test.fun b/examples/ripemd160_test.fun deleted file mode 100644 index 8c2dc27..0000000 --- a/examples/ripemd160_test.fun +++ /dev/null @@ -1,19 +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-27 - */ - -#include -print("Include OK") - -/* Expected output: -Include OK -*/ diff --git a/examples/test_bits.fun b/examples/test_bits.fun deleted file mode 100644 index ab810b2..0000000 --- a/examples/test_bits.fun +++ /dev/null @@ -1,26 +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-27 - */ - -print(bxor(0x80000000, 0x00000001)) -print(bor(0x80000000, 0x00000001)) -print(band(0x80000000, 0x80000000)) -print(bnot(0x80000000)) -print(bnot(0x7FFFFFFF)) - -/* Expected output: -2147483649 -2147483649 -2147483648 -2147483647 -2147483648 -*/ diff --git a/examples/test_dec_to_hex.fun b/examples/test_dec_to_hex.fun old mode 100755 new mode 100644 diff --git a/examples/test_include.fun b/examples/test_include.fun old mode 100755 new mode 100644 index a5acd8b..bf218b7 --- a/examples/test_include.fun +++ b/examples/test_include.fun @@ -12,7 +12,6 @@ */ #include - print(dec_to_hex(255)) /* Expected output: diff --git a/examples/test_rol.fun b/examples/test_rol.fun deleted file mode 100644 index 46c87f1..0000000 --- a/examples/test_rol.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-27 - */ - -print(rol(0x12345678, 4)) // Should be 0x23456781 -print(rol(0x80000000, 1)) // Should be 0x00000001 -print(rol(0x00000001, 31)) // Should be 0x80000000 - -/* Expected output: -591751041 -1 -2147483648 -*/ diff --git a/examples/test_shl.fun b/examples/test_shl.fun deleted file mode 100644 index 1024225..0000000 --- a/examples/test_shl.fun +++ /dev/null @@ -1,20 +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-27 - */ - -print(shl(0x80, 24)) -print(128 * 16777216) - -/* Expected output: -2147483648 -2147483648 -*/ diff --git a/examples/test_types.fun b/examples/test_types.fun deleted file mode 100644 index 120774d..0000000 --- a/examples/test_types.fun +++ /dev/null @@ -1,24 +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-27 - */ - -print(typeof(128 * 16777216)) -print(128 * 16777216) -print(typeof(0x80000000)) -print(0x80000000) - -/* Expected output: -Number -2147483648 -Number -2147483648 -*/ diff --git a/examples/test_xor.fun b/examples/test_xor.fun deleted file mode 100644 index d1caccf..0000000 --- a/examples/test_xor.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-27 - */ - -print(bxor(0xefcdab89, 0x98badcfe)) -print(bxor(0x77767677, 0x10325476)) -print(bxor(bxor(0xefcdab89, 0x98badcfe), 0x10325476)) - -/* Expected output: -2004318071 -1732518401 -1732584193 -*/ diff --git a/examples/tk_file_manager.fun b/examples/tk_file_manager.fun deleted file mode 100755 index 1614c45..0000000 --- a/examples/tk_file_manager.fun +++ /dev/null @@ -1,59 +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-23 - */ - -#include - -print("Initializing Fun File Manager...") -tk = TK() -tk.title("Fun File Manager") - -// Current directory -dir = env("PWD") -if (dir == "") - dir = "." -print("Current directory: " + dir) - -tk.label("path", "Current Dir: " + dir) -tk.pack("path") - -// Files listbox -tk.listbox("files") -tk.pack("files") - -// Populate listbox -fun refresh(tk, dir) - print("Refreshing file list for: " + dir) - tk.clear("files") - files = os_list_dir(dir) - print("Found " + to_string(len(files)) + " entries.") - for f in files - tk.insert("files", "end", f) - -refresh(tk, dir) - -// Refresh button -// Using tk.eval for button because tk.button currently exits the app. -tk.eval("button .refresh -text {Refresh} -command {puts {Refresh requested}}") -tk.pack("refresh") - -// Exit button -tk.button("exit", "Exit") -tk.pack("exit") - -print("Entering Tk loop...") -tk.loop() -print("Tk loop exited.") - -/* Expected output: -A GUI... ;) -*/ diff --git a/examples/tk_hello.fun b/examples/tk_hello.fun index 88d2129..e4a3fe2 100755 --- a/examples/tk_hello.fun +++ b/examples/tk_hello.fun @@ -31,3 +31,4 @@ tk.loop() /* Expected output: A GUI... ;) */ + diff --git a/examples/tk_testing.fun b/examples/tk_testing.fun deleted file mode 100755 index 9bff362..0000000 --- a/examples/tk_testing.fun +++ /dev/null @@ -1,38 +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-23 - */ - -#include - -print("Testing os_list_dir...") -files = os_list_dir(".") -print("Found " + to_string(len(files)) + " files.") -if len(files) > 0 - print("First file: " + files[0]) - -print("Testing tk_bind parsing...") -// We can't easily test Tk without an X server, but we can see if it crashes. -// If built with FUN_WITH_TCLTK, it should at least initialize. -// We use tk_eval to avoid full loop. -rc = tk_eval("set x 1") -print("tk_eval rc: " + to_string(rc)) -if rc == 0 - print("Tcl Result: " + tk_result()) - -/* Expected output: -Testing os_list_dir... -Found 23 files. -First file: build -Testing tk_bind parsing... -tk_eval rc: 0 -Tcl Result: 1 -*/ diff --git a/lib/crypt/ripemd160.fun b/lib/crypt/ripemd160.fun deleted file mode 100644 index bb9abd6..0000000 --- a/lib/crypt/ripemd160.fun +++ /dev/null @@ -1,272 +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-27 - */ - -// THIS IS BROKEN ACTUALLY! IT DOES NOT CALCULATE THE EXPECTED HASHES! - -#include - -class RIPEMD160() - KL = [0, 1518500249, 1859775393, 2400959708, 2840853838] - KR = [1352829926, 1548603684, 1836062451, 2054012649, 0] - - RL = [ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8, - 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12, - 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2, - 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13 - ] - - RR = [ - 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, - 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2, - 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13, - 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14, - 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11 - ] - - SL = [ - 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8, - 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12, - 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5, - 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12, - 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6 - ] - - SR = [ - 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6, - 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11, - 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5, - 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8, - 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11 - ] - - fun u32(this, x) - m = 4294967296 - while x < 0 - x = x + m - while x >= m - x = x - m - return x - - fun rol32(this, x, s) - return rol(this.u32(x), s) - - fun add32(this, a, b) - return this.u32(a + b) - - fun F(this, stage, x, y, z) - if stage == 0 - return bxor(bxor(x, y), z) - else if stage == 1 - return bor(band(x, y), band(bnot(x), z)) - else if stage == 2 - return bxor(bor(x, bnot(y)), z) - else if stage == 3 - return bor(band(x, z), band(y, bnot(z))) - else - return bxor(x, bor(y, bnot(z))) - - fun hex_val(this, ch) - if ch == "0" - return 0 - else if ch == "1" - return 1 - else if ch == "2" - return 2 - else if ch == "3" - return 3 - else if ch == "4" - return 4 - else if ch == "5" - return 5 - else if ch == "6" - return 6 - else if ch == "7" - return 7 - else if ch == "8" - return 8 - else if ch == "9" - return 9 - else if ch == "a" || ch == "A" - return 10 - else if ch == "b" || ch == "B" - return 11 - else if ch == "c" || ch == "C" - return 12 - else if ch == "d" || ch == "D" - return 13 - else if ch == "e" || ch == "E" - return 14 - else if ch == "f" || ch == "F" - return 15 - else - return 0 - - fun byte_from_hex_pair(this, hh) - hi = this.hex_val(substr(hh, 0, 1)) - lo = this.hex_val(substr(hh, 1, 1)) - return hi * 16 + lo - - fun from_hex(this, hex) - arr = [] - i = 0 - n = len(hex) - while i + 1 < n - push(arr, this.byte_from_hex_pair(substr(hex, i, 2))) - i = i + 2 - return arr - - fun two_hex(this, n) - n = band(n, 0xFF) - d = ["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"] - return join([d[shr(n, 4)], d[band(n, 0xF)]], "") - - fun bytes_to_hex(this, arr) - i = 0 - out = [] - while i < len(arr) - push(out, this.two_hex(arr[i])) - i = i + 1 - return join(out, "") - - fun pad_bytes(this, bytes) - L = len(bytes) - out = [] - i = 0 - while i < L - push(out, bytes[i]) - i = i + 1 - push(out, 128) - while (len(out) % 64) != 56 - push(out, 0) - len_bits = L * 8 - j = 0 - while j < 8 - push(out, band(shr(len_bits, 8 * j), 0xFF)) - j = j + 1 - return out - - fun word32_le(this, b0, b1, b2, b3) - return bor(bor(bor(b0, shl(b1, 8)), shl(b2, 16)), shl(b3, 24)) - - fun process_block(this, state, block) - M = [] - i = 0 - while i < 16 - j = i * 4 - push(M, this.word32_le(block[j], block[j+1], block[j+2], block[j+3])) - i = i + 1 - - A = state[0] - B = state[1] - C = state[2] - D = state[3] - E = state[4] - Ar = state[0] - Br = state[1] - Cr = state[2] - Dr = state[3] - Er = state[4] - - j = 0 - while j < 80 - if j < 16 - stage = 0 - stage_r = 4 - else if j < 32 - stage = 1 - stage_r = 3 - else if j < 48 - stage = 2 - stage_r = 2 - else if j < 64 - stage = 3 - stage_r = 1 - else - stage = 4 - stage_r = 0 - - // Left side step - T = this.add32(this.rol32(this.add32(this.add32(A, this.F(stage, B, C, D)), this.add32(M[this.RL[j]], this.KL[stage])), this.SL[j]), E) - A = E - E = D - D = this.rol32(C, 10) - C = B - 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])), this.SR[j]), Er) - Ar = Er - Er = Dr - Dr = this.rol32(Cr, 10) - Cr = Br - Br = Tr - - j = j + 1 - - al = A - bl = B - cl = C - dl = D - el = E - ar = Ar - br = Br - cr = Cr - dr = Dr - er = Er - - h0 = state[0] - h1 = state[1] - h2 = state[2] - h3 = state[3] - h4 = state[4] - - state[0] = this.add32(h1, this.add32(B, Cr)) - state[1] = this.add32(h2, this.add32(C, Dr)) - state[2] = this.add32(h3, this.add32(D, Er)) - state[3] = this.add32(h4, this.add32(E, Ar)) - state[4] = this.add32(h0, this.add32(A, Br)) - return state - - fun ripemd160_bytes(this, bytes) - state = [1732584193, 4023233417, 2562383102, 271733878, 3285377520] - data = this.pad_bytes(bytes) - N = len(data) - off = 0 - while off < N - block = [] - i = 0 - while i < 64 - push(block, data[off + i]) - i = i + 1 - state = this.process_block(state, block) - off = off + 64 - out = [] - j = 0 - while j < 5 - v = state[j] - push(out, band(v, 0xFF)) - push(out, band(shr(v, 8), 0xFF)) - push(out, band(shr(v, 16), 0xFF)) - push(out, band(shr(v, 24), 0xFF)) - j = j + 1 - return out - - fun ripemd160_hex(this, hexStr) - bytes = this.from_hex(hexStr) - digest = this.ripemd160_bytes(bytes) - return this.bytes_to_hex(digest) - - fun ripemd160_str(this, str) - bytes = string_to_bytes_ascii(str) - digest = this.ripemd160_bytes(bytes) - return this.bytes_to_hex(digest) diff --git a/lib/ui/tk.fun b/lib/ui/tk.fun index ca062b5..e39368d 100644 --- a/lib/ui/tk.fun +++ b/lib/ui/tk.fun @@ -31,30 +31,6 @@ class TK() fun pack(this, id) return tk_pack(to_string(id)) - // Create a listbox widget - fun listbox(this, id) - return tk_eval("listbox ." + to_string(id)) - - // Insert text into a widget (like listbox) at index - fun insert(this, id, index, text) - return tk_eval("." + to_string(id) + " insert " + to_string(index) + " {" + to_string(text) + "}") - - // Clear a widget (like listbox) - fun clear(this, id) - return tk_eval("." + to_string(id) + " delete 0 end") - - // Bind an event to a command - fun bind(this, id, event, cmd) - return tk_bind(to_string(id), to_string(event), to_string(cmd)) - - // Evaluate raw Tcl script - fun eval(this, script) - return tk_eval(to_string(script)) - - // Get last Tcl result - fun result(this) - return tk_result() - // Enter the Tk event loop (blocks until windows are closed) fun loop(this) return tk_loop() diff --git a/src/bytecode.h b/src/bytecode.h index 79a457d..7a14da3 100644 --- a/src/bytecode.h +++ b/src/bytecode.h @@ -35,7 +35,7 @@ typedef enum { OP_EQ, // a == b -> push 1/0 OP_NEQ, // a != b -> push 1/0 - OP_POP, // discard top of stack + OP_POP, // dApache-2.0ard top of stack OP_JUMP, // unconditional jump OP_JUMP_IF_FALSE, // jump if top of stack is false (0) @@ -196,6 +196,15 @@ typedef enum { OP_XML_NAME, // pops node handle; pushes string (node name) OP_XML_TEXT, // pops node handle; pushes string (node text) + // 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 + OP_TK_LOOP, // enters Tk event loop; pushes Nil when done + OP_TK_WM_TITLE, // pops title string; sets window title; pushes rc + OP_TK_LABEL, // pops text, id; creates/updates label .id; pushes rc + OP_TK_BUTTON, // pops text, id; creates/updates button .id; pushes rc + OP_TK_PACK, // pops id; packs .id; pushes rc + // Sockets (UNIX platforms) OP_SOCK_TCP_LISTEN, // pops backlog, port; returns listen fd (>0) or 0 OP_SOCK_TCP_ACCEPT, // pops listen fd; returns client fd (>0) or 0 @@ -209,21 +218,6 @@ typedef enum { // process control OP_EXIT, // pops code (or uses operand) and terminates script with exit code - // OS additions - OP_OS_LIST_DIR, // pops path string; pushes array of strings - - // Tk additions - OP_TK_BIND, // pops command, event, id; binds event to command - - // 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 - OP_TK_LOOP, // enters Tk event loop; pushes Nil when done - OP_TK_WM_TITLE, // pops title string; sets window title; pushes rc - OP_TK_LABEL, // pops text, id; creates/updates label .id; pushes rc - OP_TK_BUTTON, // pops text, id; creates/updates button .id; pushes rc - OP_TK_PACK, // pops id; packs .id; pushes rc - // exceptions (minimal) OP_TRY_PUSH, // operand = handler ip; push handler onto try-stack OP_TRY_POP, // pop current handler diff --git a/src/external/curl.c b/src/ext/curl.c similarity index 100% rename from src/external/curl.c rename to src/ext/curl.c diff --git a/src/external/ini.c b/src/ext/ini.c similarity index 100% rename from src/external/ini.c rename to src/ext/ini.c diff --git a/src/external/json.c b/src/ext/json.c similarity index 100% rename from src/external/json.c rename to src/ext/json.c diff --git a/src/external/libsql.c b/src/ext/libsql.c similarity index 100% rename from src/external/libsql.c rename to src/ext/libsql.c diff --git a/src/external/pcre2.c b/src/ext/pcre2.c similarity index 100% rename from src/external/pcre2.c rename to src/ext/pcre2.c diff --git a/src/external/pcsc.c b/src/ext/pcsc.c similarity index 100% rename from src/external/pcsc.c rename to src/ext/pcsc.c diff --git a/src/external/sqlite.c b/src/ext/sqlite.c similarity index 100% rename from src/external/sqlite.c rename to src/ext/sqlite.c diff --git a/src/external/tcltk.c b/src/ext/tcltk.c similarity index 100% rename from src/external/tcltk.c rename to src/ext/tcltk.c diff --git a/src/external/xml2.c b/src/ext/xml2.c similarity index 100% rename from src/external/xml2.c rename to src/ext/xml2.c diff --git a/src/parser.c b/src/parser.c index 6788539..fea4e2f 100644 --- a/src/parser.c +++ b/src/parser.c @@ -757,14 +757,6 @@ static int emit_primary(Bytecode *bc, const char *src, size_t len, size_t *pos) 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; } - if (!consume_char(src, len, pos, ')')) { parser_fail(*pos, "Expected ')' after os_list_dir arg"); free(name); return 0; } - bytecode_add_instruction(bc, OP_OS_LIST_DIR, 0); - free(name); - return 1; - } /* JSON builtins */ if (strcmp(name, "json_parse") == 0) { (*pos)++; /* '(' */ @@ -861,33 +853,6 @@ static int emit_primary(Bytecode *bc, const char *src, size_t len, size_t *pos) free(name); return 1; } - if (strcmp(name, "tk_bind") == 0) { - (*pos)++; /* '(' */ - if (!emit_expression(bc, src, len, pos)) { parser_fail(*pos, "tk_bind expects (id, event, cmd)"); free(name); return 0; } - if (!consume_char(src, len, pos, ',')) { parser_fail(*pos, "tk_bind expects 3 args"); free(name); return 0; } - if (!emit_expression(bc, src, len, pos)) { parser_fail(*pos, "tk_bind expects 3 args"); free(name); return 0; } - if (!consume_char(src, len, pos, ',')) { parser_fail(*pos, "tk_bind expects 3 args"); free(name); return 0; } - if (!emit_expression(bc, src, len, pos)) { parser_fail(*pos, "tk_bind expects 3 args"); free(name); return 0; } - if (!consume_char(src, len, pos, ')')) { parser_fail(*pos, "Expected ')' after tk_bind args"); free(name); return 0; } - bytecode_add_instruction(bc, OP_TK_BIND, 0); - free(name); - return 1; - } - if (strcmp(name, "tk_eval") == 0) { - (*pos)++; /* '(' */ - if (!emit_expression(bc, src, len, pos)) { parser_fail(*pos, "tk_eval expects (script)"); free(name); return 0; } - if (!consume_char(src, len, pos, ')')) { parser_fail(*pos, "Expected ')' after tk_eval arg"); free(name); return 0; } - bytecode_add_instruction(bc, OP_TK_EVAL, 0); - free(name); - return 1; - } - if (strcmp(name, "tk_result") == 0) { - (*pos)++; /* '(' */ - if (!consume_char(src, len, pos, ')')) { parser_fail(*pos, "tk_result expects ()"); free(name); return 0; } - bytecode_add_instruction(bc, OP_TK_RESULT, 0); - free(name); - return 1; - } if (strcmp(name, "json_from_file") == 0) { (*pos)++; /* '(' */ if (!emit_expression(bc, src, len, pos)) { parser_fail(*pos, "json_from_file expects (path)"); free(name); return 0; } diff --git a/src/vm.c b/src/vm.c index 3c714c6..dd96216 100644 --- a/src/vm.c +++ b/src/vm.c @@ -40,15 +40,15 @@ #include "vm.h" // Optional by extensions commonly used code. #ifdef's are in each single file. -#include "external/curl.c" -#include "external/ini.c" -#include "external/json.c" -#include "external/libsql.c" -#include "external/pcsc.c" -#include "external/pcre2.c" -#include "external/sqlite.c" -#include "external/tcltk.c" -#include "external/xml2.c" +#include "ext/curl.c" +#include "ext/ini.c" +#include "ext/json.c" +#include "ext/libsql.c" +#include "ext/pcsc.c" +#include "ext/pcre2.c" +#include "ext/sqlite.c" +#include "ext/tcltk.c" +#include "ext/xml2.c" /* forward declarations for include mapping used in error reporting */ extern char *preprocess_includes(const char *src); @@ -741,7 +741,6 @@ void vm_run(VM *vm, Bytecode *entry) { #include "vm/tk/label.c" #include "vm/tk/button.c" #include "vm/tk/pack.c" - #include "vm/tk/bind.c" #endif /* SQLite ops */ @@ -784,7 +783,6 @@ void vm_run(VM *vm, Bytecode *entry) { #include "vm/typeof.c" #include "vm/uclamp.c" #include "vm/sclamp.c" - #include "vm/os/list_dir.c" default: if (!opcode_is_valid(inst.op)) { diff --git a/src/vm.h b/src/vm.h index 4fd2281..6ee2f7f 100644 --- a/src/vm.h +++ b/src/vm.h @@ -49,9 +49,6 @@ static const char *opcode_names[] = { "XML_PARSE","XML_ROOT","XML_NAME","XML_TEXT", "SOCK_TCP_LISTEN","SOCK_TCP_ACCEPT","SOCK_TCP_CONNECT","SOCK_SEND","SOCK_RECV","SOCK_CLOSE","SOCK_UNIX_LISTEN","SOCK_UNIX_CONNECT", "EXIT", - "OS_LIST_DIR", - "TK_BIND", - "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/list_dir.c b/src/vm/os/list_dir.c deleted file mode 100644 index 5976c60..0000000 --- a/src/vm/os/list_dir.c +++ /dev/null @@ -1,49 +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-23 - */ - -case OP_OS_LIST_DIR: { - /* pops path string; pushes array of strings */ - Value pathv = pop_value(vm); - char *path = value_to_string_alloc(&pathv); - free_value(pathv); - - Value arr = make_array_from_values(NULL, 0); - if (path) { - /* - * Using 'ls -1' as a fallback to avoid dirent.h conflicts on some systems. - * We escape the path minimally for the shell. - */ - size_t slen = strlen(path) + 16; - char *cmd = (char*)malloc(slen); - if (cmd) { - snprintf(cmd, slen, "ls -1 \"%s\"", path); - FILE *fp = popen(cmd, "r"); - if (fp) { - char line[1024]; - while (fgets(line, sizeof(line), fp)) { - /* Strip trailing newline */ - size_t l = strlen(line); - if (l > 0 && line[l-1] == '\n') line[l-1] = '\0'; - if (l > 1 && line[l-2] == '\r') line[l-2] = '\0'; - - if (line[0] != '\0') { - array_push(&arr, make_string(line)); - } - } - pclose(fp); - } - free(cmd); - } - free(path); - } - push_value(vm, arr); - break; -} diff --git a/src/vm/tk/bind.c b/src/vm/tk/bind.c deleted file mode 100644 index 78fb732..0000000 --- a/src/vm/tk/bind.c +++ /dev/null @@ -1,54 +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-23 - */ - -/* TK_BIND */ -case OP_TK_BIND: { - /* stack: ..., id, event, command -> rc */ - Value cmdv = pop_value(vm); - Value eventv = pop_value(vm); - Value idv = pop_value(vm); - char *cmd = value_to_string_alloc(&cmdv); - char *event = value_to_string_alloc(&eventv); - char *id = value_to_string_alloc(&idv); - free_value(cmdv); - free_value(eventv); - free_value(idv); - - if (!id || !event || !cmd) { - if (id) free(id); - if (event) free(event); - if (cmd) free(cmd); - push_value(vm, make_int(-1)); - break; - } - - /* - * Construct: bind .id {command} - * Note: for now, command is just raw Tcl as well, - * but could be extended to call Fun functions if we had a callback mechanism. - */ - size_t slen = strlen(id) + strlen(event) + strlen(cmd) + 32; - char *script = (char*)malloc(slen); - if (!script) { - free(id); free(event); free(cmd); - push_value(vm, make_int(-1)); - break; - } - - snprintf(script, slen, "bind .%s %s {%s}", id, event, cmd); - int rc = fun_tk_eval_script(script); - free(script); - free(id); - free(event); - free(cmd); - push_value(vm, make_int(rc)); - break; -}