Compare commits
No commits in common. "21f437ebaf70d522b1249a530242a4edaa8053eb" and "92aacff71a0d6a14f3e481d85e6b4d891c350d00" have entirely different histories.
21f437ebaf
...
92aacff71a
32 changed files with 21 additions and 929 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 <you@hanez.org>
|
||||
* 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
|
||||
*/
|
||||
|
|
@ -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 <you@hanez.org>
|
||||
* Licensed under the terms of the Apache-2.0 license.
|
||||
* https://opensource.org/license/apache-2-0
|
||||
*
|
||||
* Added: 2025-12-27
|
||||
*/
|
||||
|
||||
#include <crypt/ripemd160.fun>
|
||||
|
||||
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
|
||||
*/
|
||||
|
|
@ -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 <you@hanez.org>
|
||||
* 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 <crypt/ripemd160.fun>
|
||||
|
||||
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
|
||||
*/
|
||||
|
|
@ -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 <you@hanez.org>
|
||||
* Licensed under the terms of the Apache-2.0 license.
|
||||
* https://opensource.org/license/apache-2-0
|
||||
*
|
||||
* Added: 2025-12-27
|
||||
*/
|
||||
|
||||
#include <crypt/ripemd160.fun>
|
||||
print("Include OK")
|
||||
|
||||
/* Expected output:
|
||||
Include OK
|
||||
*/
|
||||
|
|
@ -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 <you@hanez.org>
|
||||
* 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
|
||||
*/
|
||||
0
examples/test_dec_to_hex.fun
Executable file → Normal file
0
examples/test_dec_to_hex.fun
Executable file → Normal file
1
examples/test_include.fun
Executable file → Normal file
1
examples/test_include.fun
Executable file → Normal file
|
|
@ -12,7 +12,6 @@
|
|||
*/
|
||||
|
||||
#include <hex.fun>
|
||||
|
||||
print(dec_to_hex(255))
|
||||
|
||||
/* Expected output:
|
||||
|
|
|
|||
|
|
@ -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 <you@hanez.org>
|
||||
* 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
|
||||
*/
|
||||
|
|
@ -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 <you@hanez.org>
|
||||
* 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
|
||||
*/
|
||||
|
|
@ -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 <you@hanez.org>
|
||||
* 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
|
||||
*/
|
||||
|
|
@ -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 <you@hanez.org>
|
||||
* 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
|
||||
*/
|
||||
|
|
@ -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 <you@hanez.org>
|
||||
* Licensed under the terms of the Apache-2.0 license.
|
||||
* https://opensource.org/license/apache-2-0
|
||||
*
|
||||
* Added: 2025-12-23
|
||||
*/
|
||||
|
||||
#include <ui/tk.fun>
|
||||
|
||||
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... ;)
|
||||
*/
|
||||
|
|
@ -31,3 +31,4 @@ tk.loop()
|
|||
/* Expected output:
|
||||
A GUI... ;)
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -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 <you@hanez.org>
|
||||
* Licensed under the terms of the Apache-2.0 license.
|
||||
* https://opensource.org/license/apache-2-0
|
||||
*
|
||||
* Added: 2025-12-23
|
||||
*/
|
||||
|
||||
#include <ui/tk.fun>
|
||||
|
||||
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
|
||||
*/
|
||||
|
|
@ -1,272 +0,0 @@
|
|||
/*
|
||||
* This file is part of the Fun programming language.
|
||||
* https://fun-lang.xyz/
|
||||
*
|
||||
* Copyright 2025 Johannes Findeisen <you@hanez.org>
|
||||
* 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 <strings.fun>
|
||||
|
||||
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)
|
||||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
35
src/parser.c
35
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; }
|
||||
|
|
|
|||
20
src/vm.c
20
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)) {
|
||||
|
|
|
|||
3
src/vm.h
3
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"
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,49 +0,0 @@
|
|||
/**
|
||||
* This file is part of the Fun programming language.
|
||||
* https://fun-lang.xyz/
|
||||
*
|
||||
* Copyright 2025 Johannes Findeisen <you@hanez.org>
|
||||
* 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;
|
||||
}
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
/**
|
||||
* This file is part of the Fun programming language.
|
||||
* https://fun-lang.xyz/
|
||||
*
|
||||
* Copyright 2025 Johannes Findeisen <you@hanez.org>
|
||||
* 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 <event> {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;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue