Added lot more example code. (0.39.8).
This commit is contained in:
parent
3b70d6c92a
commit
564999709c
32 changed files with 1353 additions and 53 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
cmake_minimum_required(VERSION 3.10)
|
cmake_minimum_required(VERSION 3.10)
|
||||||
project(fun VERSION 0.39.7 LANGUAGES C)
|
project(fun VERSION 0.39.8 LANGUAGES C)
|
||||||
|
|
||||||
set(CMAKE_C_STANDARD 99)
|
set(CMAKE_C_STANDARD 99)
|
||||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||||
|
|
|
||||||
24
examples/README.md
Normal file
24
examples/README.md
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
# Fun Examples
|
||||||
|
|
||||||
|
This directory contains small, pure Fun examples organized by topic.
|
||||||
|
|
||||||
|
How to run:
|
||||||
|
- Build the interpreter once: `cmake --build ./build_debug --target fun`
|
||||||
|
- Execute an example: `./build_debug/fun ./examples/<path>.fun`
|
||||||
|
- For CGI examples under `examples/data/htdocs`, start one of the blocking HTTP servers from `examples/blocking/` and visit the URL noted in the file headers.
|
||||||
|
|
||||||
|
Categories:
|
||||||
|
- basics: hello_world, fizzbuzz, fibonacci, collections
|
||||||
|
- strings: split_join_trim, templating_min, urlencode_decode
|
||||||
|
- io: read_write_file, csv_reader (uses examples/io/sample.csv), word_count
|
||||||
|
- algos: sort_and_search, deduplicate, stack_queue
|
||||||
|
- cli: env_echo, args_parse (parse ARGS env)
|
||||||
|
- net: tcp_echo_server, tcp_echo_client, http_static_server (blocking)
|
||||||
|
- data/htdocs (CGI): hello.fun, info.fun, counter.fun, form_post.fun, redirect.fun, json_like_api.fun
|
||||||
|
- compose: run_other_fun, pipeline
|
||||||
|
- patterns: assert_like, logging_min
|
||||||
|
- snippets: escape_html_demo, maps_iterate
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
- Scripts that start servers (tcp_echo_server, http_static_server, http_server_cgi*.fun) are blocking; run them in a separate terminal.
|
||||||
|
- Some examples rely on stdlib includes; if needed, set `FUN_LIB_DIR=./lib` before running.
|
||||||
26
examples/algos/deduplicate.fun
Executable file
26
examples/algos/deduplicate.fun
Executable file
|
|
@ -0,0 +1,26 @@
|
||||||
|
#!/usr/bin/env fun
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Fun programming language.
|
||||||
|
* https://fun-lang.xyz/
|
||||||
|
*
|
||||||
|
* Copyright 2026 Johannes Findeisen
|
||||||
|
* Licensed under the terms of the Apache-2.0 license.
|
||||||
|
* https://opensource.org/license/apache-2-0
|
||||||
|
*
|
||||||
|
* Added: 2026-03-25
|
||||||
|
*/
|
||||||
|
|
||||||
|
// De-duplicate an array using a map as a set
|
||||||
|
arr = [1,2,2,3,1,4]
|
||||||
|
seen = {}
|
||||||
|
out = []
|
||||||
|
for x in arr
|
||||||
|
if (!has(seen, to_string(x)))
|
||||||
|
seen[to_string(x)] = 1
|
||||||
|
push(out, x)
|
||||||
|
print(to_string(out))
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
[array n=4]
|
||||||
|
*/
|
||||||
60
examples/algos/sort_and_search.fun
Executable file
60
examples/algos/sort_and_search.fun
Executable file
|
|
@ -0,0 +1,60 @@
|
||||||
|
#!/usr/bin/env fun
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Fun programming language.
|
||||||
|
* https://fun-lang.xyz/
|
||||||
|
*
|
||||||
|
* Copyright 2026 Johannes Findeisen
|
||||||
|
* Licensed under the terms of the Apache-2.0 license.
|
||||||
|
* https://opensource.org/license/apache-2-0
|
||||||
|
*
|
||||||
|
* Added: 2026-03-25
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Selection sort + linear/binary search
|
||||||
|
|
||||||
|
fun sel_sort(a)
|
||||||
|
n = len(a)
|
||||||
|
i = 0
|
||||||
|
while (i < n)
|
||||||
|
m = i
|
||||||
|
j = i + 1
|
||||||
|
while (j < n)
|
||||||
|
if (a[j] < a[m]) m = j
|
||||||
|
j = j + 1
|
||||||
|
tmp = a[i]
|
||||||
|
a[i] = a[m]
|
||||||
|
a[m] = tmp
|
||||||
|
i = i + 1
|
||||||
|
return a
|
||||||
|
|
||||||
|
fun lin_find(a, x)
|
||||||
|
i = 0
|
||||||
|
while (i < len(a))
|
||||||
|
if (a[i] == x) return i
|
||||||
|
i = i + 1
|
||||||
|
return -1
|
||||||
|
|
||||||
|
fun bin_find(a, x)
|
||||||
|
lo = 0
|
||||||
|
hi = len(a) - 1
|
||||||
|
while (lo <= hi)
|
||||||
|
mid = (lo + hi) / 2
|
||||||
|
v = a[mid]
|
||||||
|
if (v == x) return mid
|
||||||
|
if (v < x)
|
||||||
|
lo = mid + 1
|
||||||
|
else
|
||||||
|
hi = mid - 1
|
||||||
|
return -1
|
||||||
|
|
||||||
|
arr = [5,1,4,2,3]
|
||||||
|
print("sorted: " + to_string(sel_sort(arr)))
|
||||||
|
print("lin_find 4: " + to_string(lin_find(arr, 4)))
|
||||||
|
print("bin_find 4: " + to_string(bin_find(arr, 4)))
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
sorted: [array n=5]
|
||||||
|
lin_find 4: 2
|
||||||
|
bin_find 4: 2
|
||||||
|
*/
|
||||||
44
examples/algos/stack_queue.fun
Executable file
44
examples/algos/stack_queue.fun
Executable file
|
|
@ -0,0 +1,44 @@
|
||||||
|
#!/usr/bin/env fun
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Fun programming language.
|
||||||
|
* https://fun-lang.xyz/
|
||||||
|
*
|
||||||
|
* Copyright 2026 Johannes Findeisen
|
||||||
|
* Licensed under the terms of the Apache-2.0 license.
|
||||||
|
* https://opensource.org/license/apache-2-0
|
||||||
|
*
|
||||||
|
* Added: 2026-03-25
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Array helpers
|
||||||
|
#include <arrays.fun>
|
||||||
|
|
||||||
|
// Stack via array push/pop
|
||||||
|
stack = []
|
||||||
|
push(stack, 1)
|
||||||
|
push(stack, 2)
|
||||||
|
push(stack, 3)
|
||||||
|
print("stack pop: " + to_string(stack[len(stack)-1]))
|
||||||
|
pop = stack[len(stack)-1]
|
||||||
|
// Use array_slice(arr, start, count) to drop the last element
|
||||||
|
stack = array_slice(stack, 0, len(stack)-1)
|
||||||
|
print("stack now: " + to_string(stack))
|
||||||
|
|
||||||
|
// Queue via array push/shift
|
||||||
|
queue = []
|
||||||
|
push(queue, "a")
|
||||||
|
push(queue, "b")
|
||||||
|
push(queue, "c")
|
||||||
|
head = queue[0]
|
||||||
|
// Keep all but the first element
|
||||||
|
queue = array_slice(queue, 1, len(queue)-1)
|
||||||
|
print("queue head: " + to_string(head))
|
||||||
|
print("queue now: " + to_string(queue))
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
stack pop: 3
|
||||||
|
stack now: [array n=2]
|
||||||
|
queue head: a
|
||||||
|
queue now: [array n=2]
|
||||||
|
*/
|
||||||
30
examples/basics/collections.fun
Executable file
30
examples/basics/collections.fun
Executable file
|
|
@ -0,0 +1,30 @@
|
||||||
|
#!/usr/bin/env fun
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Fun programming language.
|
||||||
|
* https://fun-lang.xyz/
|
||||||
|
*
|
||||||
|
* Copyright 2026 Johannes Findeisen
|
||||||
|
* Licensed under the terms of the Apache-2.0 license.
|
||||||
|
* https://opensource.org/license/apache-2-0
|
||||||
|
*
|
||||||
|
* Added: 2026-03-25
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Arrays and maps basics
|
||||||
|
|
||||||
|
arr = [1, 2, 3]
|
||||||
|
push(arr, 4)
|
||||||
|
print("arr size=" + to_string(len(arr)) + ", last=" + to_string(arr[3]))
|
||||||
|
|
||||||
|
user = {"name": "Lin", "age": 29}
|
||||||
|
user["city"] = "Paris"
|
||||||
|
for k in keys(user)
|
||||||
|
print(k + ": " + to_string(user[k]))
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
arr size=4, last=4
|
||||||
|
age: 29
|
||||||
|
name: Lin
|
||||||
|
city: Paris
|
||||||
|
*/
|
||||||
38
examples/basics/fibonacci.fun
Executable file
38
examples/basics/fibonacci.fun
Executable file
|
|
@ -0,0 +1,38 @@
|
||||||
|
#!/usr/bin/env fun
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Fun programming language.
|
||||||
|
* https://fun-lang.xyz/
|
||||||
|
*
|
||||||
|
* Copyright 2026 Johannes Findeisen
|
||||||
|
* Licensed under the terms of the Apache-2.0 license.
|
||||||
|
* https://opensource.org/license/apache-2-0
|
||||||
|
*
|
||||||
|
* Added: 2026-03-25
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Fibonacci: iterative and recursive
|
||||||
|
|
||||||
|
fun fib_iter(n)
|
||||||
|
if (n <= 1) return n
|
||||||
|
a = 0
|
||||||
|
b = 1
|
||||||
|
i = 2
|
||||||
|
while (i <= n)
|
||||||
|
t = a + b
|
||||||
|
a = b
|
||||||
|
b = t
|
||||||
|
i = i + 1
|
||||||
|
return b
|
||||||
|
|
||||||
|
fun fib_rec(n)
|
||||||
|
if (n <= 1) return n
|
||||||
|
return fib_rec(n - 1) + fib_rec(n - 2)
|
||||||
|
|
||||||
|
print("fib_iter(10) = " + to_string(fib_iter(10)))
|
||||||
|
print("fib_rec(10) = " + to_string(fib_rec(10)))
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
fib_iter(10) = 55
|
||||||
|
fib_rec(10) = 55
|
||||||
|
*/
|
||||||
125
examples/basics/fizzbuzz.fun
Executable file
125
examples/basics/fizzbuzz.fun
Executable file
|
|
@ -0,0 +1,125 @@
|
||||||
|
#!/usr/bin/env fun
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Fun programming language.
|
||||||
|
* https://fun-lang.xyz/
|
||||||
|
*
|
||||||
|
* Copyright 2026 Johannes Findeisen
|
||||||
|
* Licensed under the terms of the Apache-2.0 license.
|
||||||
|
* https://opensource.org/license/apache-2-0
|
||||||
|
*
|
||||||
|
* Added: 2026-03-25
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Classic FizzBuzz from 1..100
|
||||||
|
i = 1
|
||||||
|
while (i <= 100)
|
||||||
|
out = ""
|
||||||
|
if (i % 3 == 0) out = out + "Fizz"
|
||||||
|
if (i % 5 == 0) out = out + "Buzz"
|
||||||
|
if (len(out) == 0) out = to_string(i)
|
||||||
|
print(out)
|
||||||
|
i = i + 1
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
1
|
||||||
|
2
|
||||||
|
Fizz
|
||||||
|
4
|
||||||
|
Buzz
|
||||||
|
Fizz
|
||||||
|
7
|
||||||
|
8
|
||||||
|
Fizz
|
||||||
|
Buzz
|
||||||
|
11
|
||||||
|
Fizz
|
||||||
|
13
|
||||||
|
14
|
||||||
|
FizzBuzz
|
||||||
|
16
|
||||||
|
17
|
||||||
|
Fizz
|
||||||
|
19
|
||||||
|
Buzz
|
||||||
|
Fizz
|
||||||
|
22
|
||||||
|
23
|
||||||
|
Fizz
|
||||||
|
Buzz
|
||||||
|
26
|
||||||
|
Fizz
|
||||||
|
28
|
||||||
|
29
|
||||||
|
FizzBuzz
|
||||||
|
31
|
||||||
|
32
|
||||||
|
Fizz
|
||||||
|
34
|
||||||
|
Buzz
|
||||||
|
Fizz
|
||||||
|
37
|
||||||
|
38
|
||||||
|
Fizz
|
||||||
|
Buzz
|
||||||
|
41
|
||||||
|
Fizz
|
||||||
|
43
|
||||||
|
44
|
||||||
|
FizzBuzz
|
||||||
|
46
|
||||||
|
47
|
||||||
|
Fizz
|
||||||
|
49
|
||||||
|
Buzz
|
||||||
|
Fizz
|
||||||
|
52
|
||||||
|
53
|
||||||
|
Fizz
|
||||||
|
Buzz
|
||||||
|
56
|
||||||
|
Fizz
|
||||||
|
58
|
||||||
|
59
|
||||||
|
FizzBuzz
|
||||||
|
61
|
||||||
|
62
|
||||||
|
Fizz
|
||||||
|
64
|
||||||
|
Buzz
|
||||||
|
Fizz
|
||||||
|
67
|
||||||
|
68
|
||||||
|
Fizz
|
||||||
|
Buzz
|
||||||
|
71
|
||||||
|
Fizz
|
||||||
|
73
|
||||||
|
74
|
||||||
|
FizzBuzz
|
||||||
|
76
|
||||||
|
77
|
||||||
|
Fizz
|
||||||
|
79
|
||||||
|
Buzz
|
||||||
|
Fizz
|
||||||
|
82
|
||||||
|
83
|
||||||
|
Fizz
|
||||||
|
Buzz
|
||||||
|
86
|
||||||
|
Fizz
|
||||||
|
88
|
||||||
|
89
|
||||||
|
FizzBuzz
|
||||||
|
91
|
||||||
|
92
|
||||||
|
Fizz
|
||||||
|
94
|
||||||
|
Buzz
|
||||||
|
Fizz
|
||||||
|
97
|
||||||
|
98
|
||||||
|
Fizz
|
||||||
|
Buzz
|
||||||
|
*/
|
||||||
19
examples/basics/hello_world.fun
Executable file
19
examples/basics/hello_world.fun
Executable file
|
|
@ -0,0 +1,19 @@
|
||||||
|
#!/usr/bin/env fun
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Fun programming language.
|
||||||
|
* https://fun-lang.xyz/
|
||||||
|
*
|
||||||
|
* Copyright 2026 Johannes Findeisen
|
||||||
|
* Licensed under the terms of the Apache-2.0 license.
|
||||||
|
* https://opensource.org/license/apache-2-0
|
||||||
|
*
|
||||||
|
* Added: 2026-03-25
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Minimal Hello World in Fun
|
||||||
|
print("Hello, World!")
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
Hello, World!
|
||||||
|
*/
|
||||||
41
examples/cli/args_parse.fun
Executable file
41
examples/cli/args_parse.fun
Executable file
|
|
@ -0,0 +1,41 @@
|
||||||
|
#!/usr/bin/env fun
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Fun programming language.
|
||||||
|
* https://fun-lang.xyz/
|
||||||
|
*
|
||||||
|
* Copyright 2026 Johannes Findeisen
|
||||||
|
* Licensed under the terms of the Apache-2.0 license.
|
||||||
|
* https://opensource.org/license/apache-2-0
|
||||||
|
*
|
||||||
|
* Added: 2026-03-25
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Parse env-style args: ARGS="key=val foo=bar" (since argv is not available here)
|
||||||
|
// String helpers
|
||||||
|
#include <strings.fun>
|
||||||
|
line = env("ARGS")
|
||||||
|
if (len(line) == 0)
|
||||||
|
line = "name=Fun color=blue"
|
||||||
|
|
||||||
|
parts = str_split(line, " ")
|
||||||
|
cfg = {}
|
||||||
|
for p in parts
|
||||||
|
if (len(p) == 0) continue
|
||||||
|
eq = find(p, "=")
|
||||||
|
if (eq > 0)
|
||||||
|
k = substr(p, 0, eq)
|
||||||
|
v = substr(p, eq + 1, len(p) - eq - 1)
|
||||||
|
cfg[k] = v
|
||||||
|
|
||||||
|
for k in keys(cfg)
|
||||||
|
print(k + ": " + to_string(cfg[k]))
|
||||||
|
|
||||||
|
/* Expected output (order of keys may vary):
|
||||||
|
name: Fun
|
||||||
|
color: blue
|
||||||
|
|
||||||
|
With ARGS overridden, e.g.: ARGS="x=1 y=2"
|
||||||
|
x: 1
|
||||||
|
y: 2
|
||||||
|
*/
|
||||||
23
examples/cli/env_echo.fun
Executable file
23
examples/cli/env_echo.fun
Executable file
|
|
@ -0,0 +1,23 @@
|
||||||
|
#!/usr/bin/env fun
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Fun programming language.
|
||||||
|
* https://fun-lang.xyz/
|
||||||
|
*
|
||||||
|
* Copyright 2026 Johannes Findeisen
|
||||||
|
* Licensed under the terms of the Apache-2.0 license.
|
||||||
|
* https://opensource.org/license/apache-2-0
|
||||||
|
*
|
||||||
|
* Added: 2026-03-25
|
||||||
|
*/
|
||||||
|
|
||||||
|
keys_to_show = ["HOME", "USER", "SHELL", "PATH"]
|
||||||
|
for k in keys_to_show
|
||||||
|
print(k + "=" + env(k))
|
||||||
|
|
||||||
|
/* Expected output (values depend on your environment):
|
||||||
|
HOME=/home/youruser
|
||||||
|
USER=youruser
|
||||||
|
SHELL=/bin/bash
|
||||||
|
PATH=/usr/local/bin:... (truncated)
|
||||||
|
*/
|
||||||
23
examples/compose/pipeline.fun
Executable file
23
examples/compose/pipeline.fun
Executable file
|
|
@ -0,0 +1,23 @@
|
||||||
|
#!/usr/bin/env fun
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Fun programming language.
|
||||||
|
* https://fun-lang.xyz/
|
||||||
|
*
|
||||||
|
* Copyright 2026 Johannes Findeisen
|
||||||
|
* Licensed under the terms of the Apache-2.0 license.
|
||||||
|
* https://opensource.org/license/apache-2-0
|
||||||
|
*
|
||||||
|
* Added: 2026-03-25
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <strings.fun>
|
||||||
|
|
||||||
|
res1 = proc_run("echo one")
|
||||||
|
res2 = proc_run("echo two")
|
||||||
|
out = str_trim(res1["out"]) + "," + str_trim(res2["out"])
|
||||||
|
print(out)
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
one,two
|
||||||
|
*/
|
||||||
25
examples/compose/run_other_fun.fun
Executable file
25
examples/compose/run_other_fun.fun
Executable file
|
|
@ -0,0 +1,25 @@
|
||||||
|
#!/usr/bin/env fun
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Fun programming language.
|
||||||
|
* https://fun-lang.xyz/
|
||||||
|
*
|
||||||
|
* Copyright 2026 Johannes Findeisen
|
||||||
|
* Licensed under the terms of the Apache-2.0 license.
|
||||||
|
* https://opensource.org/license/apache-2-0
|
||||||
|
*
|
||||||
|
* Added: 2026-03-25
|
||||||
|
*/
|
||||||
|
|
||||||
|
cmd = "./build_debug/fun ./examples/basics/hello_world.fun"
|
||||||
|
res = proc_run(cmd)
|
||||||
|
print("exit: " + to_string(res["code"]))
|
||||||
|
print("out: " + to_string(res["out"]))
|
||||||
|
print("err: " + to_string(res["err"]))
|
||||||
|
|
||||||
|
/* Expected output (with build_debug/fun present):
|
||||||
|
exit: 0
|
||||||
|
out: Hello, World!\n
|
||||||
|
|
||||||
|
err: nil
|
||||||
|
*/
|
||||||
31
examples/data/htdocs/counter.fun
Normal file
31
examples/data/htdocs/counter.fun
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
#!/usr/bin/env fun
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Fun programming language.
|
||||||
|
* https://fun-lang.xyz/
|
||||||
|
*
|
||||||
|
* Copyright 2026 Johannes Findeisen
|
||||||
|
* Licensed under the terms of the Apache-2.0 license.
|
||||||
|
* https://opensource.org/license/apache-2-0
|
||||||
|
*
|
||||||
|
* Added: 2026-03-25
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <net/cgi.fun>
|
||||||
|
|
||||||
|
cgi = CGI()
|
||||||
|
v = to_number(cgi.cookie("visits"))
|
||||||
|
if (v <= 0) v = 0
|
||||||
|
v = v + 1
|
||||||
|
cgi.header("Set-Cookie", "visits=" + to_string(v) + "; Path=/; HttpOnly")
|
||||||
|
cgi.content_type("text/html; charset=utf-8")
|
||||||
|
body = "<html><body><p>Visits: " + to_string(v) + "</p></body></html>"
|
||||||
|
cgi.send(body)
|
||||||
|
|
||||||
|
/* Expected output (first visit, no existing cookie):
|
||||||
|
Status: 200 OK
|
||||||
|
Content-Type: text/html; charset=utf-8
|
||||||
|
Set-Cookie: visits=1; Path=/; HttpOnly
|
||||||
|
|
||||||
|
<html><body><p>Visits: 1</p></body></html>
|
||||||
|
*/
|
||||||
36
examples/data/htdocs/form_post.fun
Normal file
36
examples/data/htdocs/form_post.fun
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
#!/usr/bin/env fun
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Fun programming language.
|
||||||
|
* https://fun-lang.xyz/
|
||||||
|
*
|
||||||
|
* Copyright 2026 Johannes Findeisen
|
||||||
|
* Licensed under the terms of the Apache-2.0 license.
|
||||||
|
* https://opensource.org/license/apache-2-0
|
||||||
|
*
|
||||||
|
* Added: 2026-03-25
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <net/cgi.fun>
|
||||||
|
|
||||||
|
cgi = CGI()
|
||||||
|
cgi.content_type("text/html; charset=utf-8")
|
||||||
|
pmap = cgi.params()
|
||||||
|
html = "<html><body><h1>POST fields</h1><ul>"
|
||||||
|
for k in keys(pmap)
|
||||||
|
vals = cgi.param_all(k)
|
||||||
|
i = 0; n = len(vals); joined = ""
|
||||||
|
while (i < n)
|
||||||
|
if (i > 0) joined = joined + ", "
|
||||||
|
joined = joined + cgi.escape_html(vals[i])
|
||||||
|
i = i + 1
|
||||||
|
html = html + "<li><b>" + cgi.escape_html(k) + "</b>: " + joined + "</li>"
|
||||||
|
html = html + "</ul></body></html>"
|
||||||
|
cgi.send(html)
|
||||||
|
|
||||||
|
/* Expected output (POST with body: "a=1&b=two&b=2"):
|
||||||
|
Status: 200 OK
|
||||||
|
Content-Type: text/html; charset=utf-8
|
||||||
|
|
||||||
|
<html><body><h1>POST fields</h1><ul><li><b>a</b>: 1</li><li><b>b</b>: two, 2</li></ul></body></html>
|
||||||
|
*/
|
||||||
|
|
@ -52,3 +52,11 @@ html = html + "</body></html>"
|
||||||
|
|
||||||
// Send CGI headers + body
|
// Send CGI headers + body
|
||||||
cgi.send(html)
|
cgi.send(html)
|
||||||
|
|
||||||
|
/* Expected output (GET /hello.fun?name=Fun with no ua cookie):
|
||||||
|
Status: 200 OK
|
||||||
|
Content-Type: text/html; charset=utf-8
|
||||||
|
Set-Cookie: ua=FunClient; Path=/; HttpOnly
|
||||||
|
|
||||||
|
<html><head><title>Fun CGI</title></head><body><h1>Hello, Fun!</h1><p>REQUEST_METHOD: GET</p><p>QUERY_STRING: name=Fun</p><p>User-Agent cookie: </p><h2>Params</h2><ul><li><b>name</b>: Fun</li></ul></body></html>
|
||||||
|
*/
|
||||||
|
|
|
||||||
21
examples/data/htdocs/json_like_api.fun
Normal file
21
examples/data/htdocs/json_like_api.fun
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
#!/usr/bin/env fun
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Fun programming language.
|
||||||
|
* https://fun-lang.xyz/
|
||||||
|
*
|
||||||
|
* Copyright 2026 Johannes Findeisen
|
||||||
|
* Licensed under the terms of the Apache-2.0 license.
|
||||||
|
* https://opensource.org/license/apache-2-0
|
||||||
|
*
|
||||||
|
* Added: 2026-03-25
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <net/cgi.fun>
|
||||||
|
|
||||||
|
cgi = CGI()
|
||||||
|
cgi.content_type("application/json; charset=utf-8")
|
||||||
|
name = cgi.param("name")
|
||||||
|
if (len(name) == 0) name = "World"
|
||||||
|
body = "{\n \"greeting\": \"Hello, " + cgi.escape_html(name) + "!\",\n \"method\": \"" + cgi.escape_html(cgi.env["REQUEST_METHOD"]) + "\"\n}"
|
||||||
|
cgi.send(body)
|
||||||
19
examples/data/htdocs/redirect.fun
Normal file
19
examples/data/htdocs/redirect.fun
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
#!/usr/bin/env fun
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Fun programming language.
|
||||||
|
* https://fun-lang.xyz/
|
||||||
|
*
|
||||||
|
* Copyright 2026 Johannes Findeisen
|
||||||
|
* Licensed under the terms of the Apache-2.0 license.
|
||||||
|
* https://opensource.org/license/apache-2-0
|
||||||
|
*
|
||||||
|
* Added: 2026-03-25
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <net/cgi.fun>
|
||||||
|
|
||||||
|
cgi = CGI()
|
||||||
|
cgi.redirect("/hello.fun?name=Fun", 302)
|
||||||
|
cgi.content_type("text/html; charset=utf-8")
|
||||||
|
cgi.send("<html><body>Redirecting...</body></html>")
|
||||||
4
examples/data/sample.csv
Normal file
4
examples/data/sample.csv
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
name,age,city
|
||||||
|
Ada,37,London
|
||||||
|
Lin,29,Paris
|
||||||
|
Max,42,Berlin
|
||||||
|
37
examples/io/csv_reader.fun
Executable file
37
examples/io/csv_reader.fun
Executable file
|
|
@ -0,0 +1,37 @@
|
||||||
|
#!/usr/bin/env fun
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Fun programming language.
|
||||||
|
* https://fun-lang.xyz/
|
||||||
|
*
|
||||||
|
* Copyright 2026 Johannes Findeisen
|
||||||
|
* Licensed under the terms of the Apache-2.0 license.
|
||||||
|
* https://opensource.org/license/apache-2-0
|
||||||
|
*
|
||||||
|
* Added: 2026-03-25
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <strings.fun>
|
||||||
|
|
||||||
|
path = "./examples/data/sample.csv"
|
||||||
|
|
||||||
|
// Very small CSV reader (no quotes/escapes) for demo purposes
|
||||||
|
fun parse_csv_line(line)
|
||||||
|
return str_split(str_trim(line), ",")
|
||||||
|
|
||||||
|
data = read_file(path)
|
||||||
|
if (len(data) == 0)
|
||||||
|
print("No CSV content at: " + path)
|
||||||
|
else
|
||||||
|
rows = str_split(data, "\n")
|
||||||
|
for row in rows
|
||||||
|
if (len(str_trim(row)) == 0) continue
|
||||||
|
cols = parse_csv_line(row)
|
||||||
|
print("ROW: " + to_string(cols))
|
||||||
|
|
||||||
|
/* Expected output (from examples/io/sample.csv):
|
||||||
|
ROW: [array n=3]
|
||||||
|
ROW: [array n=3]
|
||||||
|
ROW: [array n=3]
|
||||||
|
ROW: [array n=3]
|
||||||
|
*/
|
||||||
25
examples/io/read_write_file.fun
Executable file
25
examples/io/read_write_file.fun
Executable file
|
|
@ -0,0 +1,25 @@
|
||||||
|
#!/usr/bin/env fun
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Fun programming language.
|
||||||
|
* https://fun-lang.xyz/
|
||||||
|
*
|
||||||
|
* Copyright 2026 Johannes Findeisen
|
||||||
|
* Licensed under the terms of the Apache-2.0 license.
|
||||||
|
* https://opensource.org/license/apache-2-0
|
||||||
|
*
|
||||||
|
* Added: 2026-03-25
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <strings.fun>
|
||||||
|
|
||||||
|
path = "./tmp/example.txt"
|
||||||
|
print("Writing to: " + path)
|
||||||
|
write_file(path, "Hello from Fun!\n")
|
||||||
|
txt = read_file(path)
|
||||||
|
print("Read back: " + str_trim(txt))
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
Writing to: ./tmp/example.txt
|
||||||
|
Read back: Hello from Fun!
|
||||||
|
*/
|
||||||
412
examples/io/word_count.fun
Executable file
412
examples/io/word_count.fun
Executable file
|
|
@ -0,0 +1,412 @@
|
||||||
|
#!/usr/bin/env fun
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Fun programming language.
|
||||||
|
* https://fun-lang.xyz/
|
||||||
|
*
|
||||||
|
* Copyright 2026 Johannes Findeisen
|
||||||
|
* Licensed under the terms of the Apache-2.0 license.
|
||||||
|
* https://opensource.org/license/apache-2-0
|
||||||
|
*
|
||||||
|
* Added: 2026-03-25
|
||||||
|
*/
|
||||||
|
|
||||||
|
// String helpers
|
||||||
|
#include <strings.fun>
|
||||||
|
|
||||||
|
path = "./README.md"
|
||||||
|
txt = read_file(path)
|
||||||
|
if (len(txt) == 0)
|
||||||
|
print("no content: " + path)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
txt = str_to_lower(txt)
|
||||||
|
txt = str_replace_all(txt, "\n", " ")
|
||||||
|
parts = str_split(txt, " ")
|
||||||
|
freq = {}
|
||||||
|
for w in parts
|
||||||
|
w = str_trim(w)
|
||||||
|
if (len(w) == 0) continue
|
||||||
|
c = to_number(freq[w])
|
||||||
|
if (c <= 0) c = 0
|
||||||
|
freq[w] = c + 1
|
||||||
|
|
||||||
|
for k in keys(freq)
|
||||||
|
print(k + ": " + to_string(freq[k]))
|
||||||
|
|
||||||
|
/* Possible output (first 10 lines; counts depend on README.md contents):
|
||||||
|
#: 1
|
||||||
|
fun: 19
|
||||||
|
([https://fun-lang.xyz](https://fun-lang.xyz)): 1
|
||||||
|
##: 9
|
||||||
|
what: 2
|
||||||
|
is: 16
|
||||||
|
fun?: 1
|
||||||
|
a: 9
|
||||||
|
small,: 1
|
||||||
|
strict,: 1
|
||||||
|
and: 15
|
||||||
|
simple: 3
|
||||||
|
programming: 5
|
||||||
|
language: 5
|
||||||
|
that: 4
|
||||||
|
runs: 1
|
||||||
|
on: 3
|
||||||
|
compact: 1
|
||||||
|
stack-based: 1
|
||||||
|
virtual: 1
|
||||||
|
machine.: 1
|
||||||
|
the: 24
|
||||||
|
c: 2
|
||||||
|
core: 3
|
||||||
|
intentionally: 1
|
||||||
|
minimal;: 1
|
||||||
|
most: 6
|
||||||
|
functionality: 1
|
||||||
|
standard: 2
|
||||||
|
libraries: 2
|
||||||
|
are: 6
|
||||||
|
implemented: 2
|
||||||
|
in: 19
|
||||||
|
itself.: 2
|
||||||
|
emphasizes: 1
|
||||||
|
simplicity,: 1
|
||||||
|
consistency,: 1
|
||||||
|
joy: 3
|
||||||
|
coding.: 2
|
||||||
|
an: 1
|
||||||
|
experiment,: 1
|
||||||
|
just: 2
|
||||||
|
for: 6
|
||||||
|
fun,: 3
|
||||||
|
but: 5
|
||||||
|
works!: 1
|
||||||
|
highly: 2
|
||||||
|
strict: 1
|
||||||
|
language,: 1
|
||||||
|
also: 1
|
||||||
|
simple.: 1
|
||||||
|
it: 2
|
||||||
|
looks: 2
|
||||||
|
like: 4
|
||||||
|
python: 1
|
||||||
|
(my: 1
|
||||||
|
favorite: 1
|
||||||
|
language),: 1
|
||||||
|
there: 2
|
||||||
|
differences.: 1
|
||||||
|
influenced: 1
|
||||||
|
by: 2
|
||||||
|
**[bash](https://www.gnu.org/software/bash/)**,: 1
|
||||||
|
**[c](https://en.wikipedia.org/wiki/the_c_programming_language)**,: 1
|
||||||
|
**[lua](https://www.lua.org/)**,: 1
|
||||||
|
php,: 1
|
||||||
|
**[python](https://www.python.org/)**,: 1
|
||||||
|
rust: 1
|
||||||
|
(most: 1
|
||||||
|
influences: 1
|
||||||
|
came: 1
|
||||||
|
from: 2
|
||||||
|
linked: 1
|
||||||
|
languages).: 1
|
||||||
|
will: 4
|
||||||
|
ever: 1
|
||||||
|
be: 5
|
||||||
|
100%: 1
|
||||||
|
free: 1
|
||||||
|
under: 1
|
||||||
|
terms: 1
|
||||||
|
of: 3
|
||||||
|
[apache-2.0: 1
|
||||||
|
license](https://opensource.org/license/apache-2-0).: 1
|
||||||
|
idea: 1
|
||||||
|
-: 48
|
||||||
|
simplicity: 2
|
||||||
|
consistency: 2
|
||||||
|
to: 7
|
||||||
|
extend: 1
|
||||||
|
hackable: 1
|
||||||
|
coding: 2
|
||||||
|
fun!: 1
|
||||||
|
characteristics: 1
|
||||||
|
dynamic: 1
|
||||||
|
optionally: 1
|
||||||
|
statically: 1
|
||||||
|
typed: 1
|
||||||
|
type: 1
|
||||||
|
safety: 1
|
||||||
|
written: 6
|
||||||
|
(c99): 1
|
||||||
|
internal: 1
|
||||||
|
libs: 2
|
||||||
|
with: 2
|
||||||
|
no_camel_case: 1
|
||||||
|
even: 1
|
||||||
|
when: 1
|
||||||
|
except: 1
|
||||||
|
class: 1
|
||||||
|
names: 1
|
||||||
|
only: 2
|
||||||
|
minimal: 1
|
||||||
|
function: 1
|
||||||
|
set: 1
|
||||||
|
c,: 1
|
||||||
|
other: 1
|
||||||
|
functions: 1
|
||||||
|
manifesto: 1
|
||||||
|
built: 2
|
||||||
|
idea:: 1
|
||||||
|
should: 6
|
||||||
|
enjoyable,: 1
|
||||||
|
elegant,: 1
|
||||||
|
consistent.: 1
|
||||||
|
###: 5
|
||||||
|
philosophy: 1
|
||||||
|
**fun: 2
|
||||||
|
fun**<br>: 1
|
||||||
|
spark: 1
|
||||||
|
creativity,: 1
|
||||||
|
not: 4
|
||||||
|
frustration.: 1
|
||||||
|
code: 3
|
||||||
|
feels: 3
|
||||||
|
light,: 1
|
||||||
|
playful,: 1
|
||||||
|
rewarding.: 1
|
||||||
|
uses: 1
|
||||||
|
nothing**<br>: 1
|
||||||
|
minimalism: 1
|
||||||
|
power.: 1
|
||||||
|
no: 7
|
||||||
|
unnecessary: 1
|
||||||
|
features,: 1
|
||||||
|
endless: 1
|
||||||
|
syntax: 1
|
||||||
|
variations,: 1
|
||||||
|
formatting: 1
|
||||||
|
debates.: 1
|
||||||
|
clean,: 1
|
||||||
|
uniform: 1
|
||||||
|
code.: 1
|
||||||
|
**indentation: 1
|
||||||
|
truth**<br>: 1
|
||||||
|
two: 1
|
||||||
|
spaces,: 1
|
||||||
|
always.: 1
|
||||||
|
tabs,: 1
|
||||||
|
four-space: 1
|
||||||
|
wars.: 1
|
||||||
|
look: 1
|
||||||
|
same: 2
|
||||||
|
everywhere,: 1
|
||||||
|
your: 1
|
||||||
|
laptop: 1
|
||||||
|
/usr/bin/fun.: 1
|
||||||
|
**one: 1
|
||||||
|
way: 1
|
||||||
|
do: 1
|
||||||
|
it**<br>: 1
|
||||||
|
clutter,: 1
|
||||||
|
15: 1
|
||||||
|
ways: 1
|
||||||
|
writing: 1
|
||||||
|
thing.: 1
|
||||||
|
means: 1
|
||||||
|
clarity.: 1
|
||||||
|
**hackable: 1
|
||||||
|
nature**<br>: 1
|
||||||
|
small: 1
|
||||||
|
embeddable,: 1
|
||||||
|
lua.: 1
|
||||||
|
easy: 1
|
||||||
|
understand,: 1
|
||||||
|
extend,: 1
|
||||||
|
tinker: 1
|
||||||
|
—: 2
|
||||||
|
true: 1
|
||||||
|
hacker: 1
|
||||||
|
spirit.: 1
|
||||||
|
**beautiful: 1
|
||||||
|
defaults**<br>: 1
|
||||||
|
doesn’t: 1
|
||||||
|
need: 1
|
||||||
|
linters,: 1
|
||||||
|
formatters,: 1
|
||||||
|
or: 3
|
||||||
|
style: 1
|
||||||
|
guides.: 1
|
||||||
|
beauty: 1
|
||||||
|
in.: 1
|
||||||
|
community: 3
|
||||||
|
about: 2
|
||||||
|
being: 1
|
||||||
|
fastest: 1
|
||||||
|
feature-rich.: 1
|
||||||
|
it’s: 1
|
||||||
|
sharing: 1
|
||||||
|
be:: 1
|
||||||
|
respectful: 1
|
||||||
|
curious: 1
|
||||||
|
creative: 1
|
||||||
|
open: 1
|
||||||
|
everyone: 1
|
||||||
|
name: 1
|
||||||
|
says:: 1
|
||||||
|
unites: 1
|
||||||
|
nerds.: 1
|
||||||
|
please: 1
|
||||||
|
visit: 1
|
||||||
|
[fun: 1
|
||||||
|
page](https://fun-lang.xyz/community/): 1
|
||||||
|
get: 1
|
||||||
|
touch.: 1
|
||||||
|
goal: 1
|
||||||
|
home: 1
|
||||||
|
developers: 1
|
||||||
|
who:: 1
|
||||||
|
love: 1
|
||||||
|
minimal,: 1
|
||||||
|
elegant: 1
|
||||||
|
tools: 1
|
||||||
|
believe: 1
|
||||||
|
freedom: 1
|
||||||
|
want: 1
|
||||||
|
write: 1
|
||||||
|
good: 2
|
||||||
|
may: 2
|
||||||
|
change: 1
|
||||||
|
world: 1
|
||||||
|
make: 1
|
||||||
|
little: 1
|
||||||
|
more: 1
|
||||||
|
fun.: 1
|
||||||
|
features: 2
|
||||||
|
functions/classes/objects: 1
|
||||||
|
if/else: 2
|
||||||
|
try/catch/finally: 1
|
||||||
|
lib: 1
|
||||||
|
(./lib/): 1
|
||||||
|
see: 2
|
||||||
|
[./lib/](https://git.xw3.org/fun/fun/src/branch/main/lib): 2
|
||||||
|
library: 1
|
||||||
|
provides.: 1
|
||||||
|
optional: 1
|
||||||
|
extensions: 1
|
||||||
|
(build-time: 1
|
||||||
|
selectable: 1
|
||||||
|
/: 2
|
||||||
|
testing: 1
|
||||||
|
this: 1
|
||||||
|
linux: 1
|
||||||
|
actually):: 1
|
||||||
|
[cgi](https://en.wikipedia.org/wiki/common_gateway_interface): 1
|
||||||
|
support: 1
|
||||||
|
builtin: 1
|
||||||
|
using: 1
|
||||||
|
[kcgi](https://kristaps.bsd.lv/kcgi/): 1
|
||||||
|
(optional): 11
|
||||||
|
☐: 2
|
||||||
|
[curl: 1
|
||||||
|
(libcurl)](./docs/external/curl.md): 1
|
||||||
|
☑: 11
|
||||||
|
[ini: 1
|
||||||
|
(iniparser)](./docs/external/ini.md): 1
|
||||||
|
[json: 1
|
||||||
|
(json-c)](./docs/external/json.md): 1
|
||||||
|
[libsql](./docs/external/libsql.md): 1
|
||||||
|
[pcre2](./docs/external/pcre2.md): 1
|
||||||
|
[pcsc: 1
|
||||||
|
(smart: 1
|
||||||
|
cards)](./docs/external/pcsc.md): 1
|
||||||
|
[openssl](./docs/external/openssl.md): 1
|
||||||
|
[sqlite](./docs/external/sqlite.md): 1
|
||||||
|
[tk: 1
|
||||||
|
(tcl/tk: 1
|
||||||
|
gui)](./docs/external/tcltk.md): 1
|
||||||
|
[xml: 1
|
||||||
|
(libxml2)](./docs/external/xml2.md): 1
|
||||||
|
=: 2
|
||||||
|
done: 1
|
||||||
|
planned: 1
|
||||||
|
progress.: 1
|
||||||
|
note:: 2
|
||||||
|
all: 1
|
||||||
|
above: 1
|
||||||
|
implemented.: 1
|
||||||
|
those: 1
|
||||||
|
who: 1
|
||||||
|
marked: 1
|
||||||
|
"done": 1
|
||||||
|
probaly: 1
|
||||||
|
remain: 1
|
||||||
|
i: 1
|
||||||
|
don't: 1
|
||||||
|
know: 1
|
||||||
|
actually...: 1
|
||||||
|
;): 1
|
||||||
|
some: 2
|
||||||
|
available: 1
|
||||||
|
diretory.: 1
|
||||||
|
future: 1
|
||||||
|
enhancements: 1
|
||||||
|
openssl: 1
|
||||||
|
quickstart: 1
|
||||||
|
(md5): 1
|
||||||
|
dedicated: 1
|
||||||
|
page:: 1
|
||||||
|
./docs/external/openssl.md: 1
|
||||||
|
documentation: 2
|
||||||
|
looking: 1
|
||||||
|
docs?: 1
|
||||||
|
start: 1
|
||||||
|
here:: 1
|
||||||
|
local: 1
|
||||||
|
index:: 1
|
||||||
|
[docs/readme.md](./docs/readme.md): 1
|
||||||
|
handbook:: 1
|
||||||
|
[docs/handbook.md](./docs/handbook.md): 1
|
||||||
|
types: 1
|
||||||
|
overview:: 1
|
||||||
|
[docs/types.md](./docs/types.md): 1
|
||||||
|
repl: 1
|
||||||
|
guide:: 1
|
||||||
|
[docs/repl.md](./docs/repl.md): 1
|
||||||
|
testing:: 1
|
||||||
|
[docs/testing.md](./docs/testing.md): 1
|
||||||
|
troubleshooting:: 1
|
||||||
|
[docs/troubleshooting.md](./docs/troubleshooting.md): 1
|
||||||
|
additional: 1
|
||||||
|
references:: 1
|
||||||
|
specification:: 1
|
||||||
|
[spec/v0.3.md](./spec/v0.3.md): 1
|
||||||
|
(work: 1
|
||||||
|
progress): 1
|
||||||
|
examples: 1
|
||||||
|
demonstrating: 1
|
||||||
|
features:: 1
|
||||||
|
[examples/](./examples/): 1
|
||||||
|
internals: 1
|
||||||
|
vm: 1
|
||||||
|
opcodes: 1
|
||||||
|
live: 1
|
||||||
|
[src/](./src/): 1
|
||||||
|
(see: 1
|
||||||
|
[src/vm/](./src/vm): 1
|
||||||
|
opcode: 1
|
||||||
|
implementations): 1
|
||||||
|
project: 1
|
||||||
|
evolving;: 1
|
||||||
|
documents: 1
|
||||||
|
lag: 1
|
||||||
|
behind.: 1
|
||||||
|
docs: 1
|
||||||
|
index: 1
|
||||||
|
`./docs/readme.md`: 1
|
||||||
|
up‑to‑date: 1
|
||||||
|
entry: 1
|
||||||
|
point.: 1
|
||||||
|
author: 1
|
||||||
|
johannes: 1
|
||||||
|
findeisen: 1
|
||||||
|
<you@hanez.org>: 1
|
||||||
|
*/
|
||||||
40
examples/net/http_static_server.fun
Executable file
40
examples/net/http_static_server.fun
Executable file
|
|
@ -0,0 +1,40 @@
|
||||||
|
#!/usr/bin/env fun
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Fun programming language.
|
||||||
|
* https://fun-lang.xyz/
|
||||||
|
*
|
||||||
|
* Copyright 2026 Johannes Findeisen
|
||||||
|
* Licensed under the terms of the Apache-2.0 license.
|
||||||
|
* https://opensource.org/license/apache-2-0
|
||||||
|
*
|
||||||
|
* Added: 2026-03-25
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <io/socket.fun>
|
||||||
|
|
||||||
|
port = 8088
|
||||||
|
srv = TcpServer(port, 10)
|
||||||
|
if (srv.listen() <= 0)
|
||||||
|
print("HTTP static server: listen failed on :" + to_string(port))
|
||||||
|
return 0
|
||||||
|
print("HTTP static server on :" + to_string(port))
|
||||||
|
while true
|
||||||
|
fd = srv.accept()
|
||||||
|
if (fd > 0)
|
||||||
|
_ = sock_recv(fd, 4096) // ignore request
|
||||||
|
body = "<html><body><h1>Hello from Fun static server</h1></body></html>"
|
||||||
|
b = to_string(body)
|
||||||
|
resp = "HTTP/1.1 200 OK\r\n"
|
||||||
|
resp = resp + "Content-Type: text/html; charset=utf-8\r\n"
|
||||||
|
resp = resp + "Content-Length: " + to_string(len(b)) + "\r\n"
|
||||||
|
resp = resp + "Connection: close\r\n\r\n" + b
|
||||||
|
sock_send(fd, resp)
|
||||||
|
sock_close(fd)
|
||||||
|
|
||||||
|
/* Expected output (on start):
|
||||||
|
HTTP static server on :8088
|
||||||
|
|
||||||
|
Then open http://127.0.0.1:8088/ in a browser; it will render:
|
||||||
|
<html><body><h1>Hello from Fun static server</h1></body></html>
|
||||||
|
*/
|
||||||
27
examples/net/tcp_echo_client.fun
Executable file
27
examples/net/tcp_echo_client.fun
Executable file
|
|
@ -0,0 +1,27 @@
|
||||||
|
#!/usr/bin/env fun
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Fun programming language.
|
||||||
|
* https://fun-lang.xyz/
|
||||||
|
*
|
||||||
|
* Copyright 2026 Johannes Findeisen
|
||||||
|
* Licensed under the terms of the Apache-2.0 license.
|
||||||
|
* https://opensource.org/license/apache-2-0
|
||||||
|
*
|
||||||
|
* Added: 2026-03-25
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <io/socket.fun>
|
||||||
|
|
||||||
|
fd = sock_connect("127.0.0.1", 9090)
|
||||||
|
if (fd <= 0)
|
||||||
|
print("connect failed")
|
||||||
|
return 0
|
||||||
|
sock_send(fd, "ping\n")
|
||||||
|
resp = sock_recv(fd, 4096)
|
||||||
|
print("response: " + resp)
|
||||||
|
sock_close(fd)
|
||||||
|
|
||||||
|
/* Expected output (with tcp_echo_server.fun running):
|
||||||
|
response: ping
|
||||||
|
*/
|
||||||
33
examples/net/tcp_echo_server.fun
Executable file
33
examples/net/tcp_echo_server.fun
Executable file
|
|
@ -0,0 +1,33 @@
|
||||||
|
#!/usr/bin/env fun
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Fun programming language.
|
||||||
|
* https://fun-lang.xyz/
|
||||||
|
*
|
||||||
|
* Copyright 2026 Johannes Findeisen
|
||||||
|
* Licensed under the terms of the Apache-2.0 license.
|
||||||
|
* https://opensource.org/license/apache-2-0
|
||||||
|
*
|
||||||
|
* Added: 2026-03-25
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <io/socket.fun>
|
||||||
|
|
||||||
|
port = 9090
|
||||||
|
srv = TcpServer(port, 10)
|
||||||
|
if (srv.listen() <= 0)
|
||||||
|
print("listen failed on :" + to_string(port))
|
||||||
|
return 0
|
||||||
|
print("Echo server on :" + to_string(port))
|
||||||
|
while true
|
||||||
|
fd = srv.accept()
|
||||||
|
if (fd > 0)
|
||||||
|
msg = sock_recv(fd, 4096)
|
||||||
|
if (len(msg) > 0) sock_send(fd, msg)
|
||||||
|
sock_close(fd)
|
||||||
|
|
||||||
|
/* Expected output (on start):
|
||||||
|
Echo server on :9090
|
||||||
|
|
||||||
|
Then, from another shell: `nc 127.0.0.1 9090` and type "ping" — the server echoes it back.
|
||||||
|
*/
|
||||||
25
examples/patterns/assert_like.fun
Executable file
25
examples/patterns/assert_like.fun
Executable file
|
|
@ -0,0 +1,25 @@
|
||||||
|
#!/usr/bin/env fun
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Fun programming language.
|
||||||
|
* https://fun-lang.xyz/
|
||||||
|
*
|
||||||
|
* Copyright 2026 Johannes Findeisen
|
||||||
|
* Licensed under the terms of the Apache-2.0 license.
|
||||||
|
* https://opensource.org/license/apache-2-0
|
||||||
|
*
|
||||||
|
* Added: 2026-03-25
|
||||||
|
*/
|
||||||
|
|
||||||
|
fun assert_like(cond, msg)
|
||||||
|
if (!cond)
|
||||||
|
print("ASSERT FAILED: " + to_string(msg))
|
||||||
|
return 0
|
||||||
|
return 1
|
||||||
|
|
||||||
|
ok = assert_like(1 + 1 == 2, "math broke")
|
||||||
|
print("assert returned: " + to_string(ok))
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
assert returned: 1
|
||||||
|
*/
|
||||||
37
examples/patterns/logging_min.fun
Executable file
37
examples/patterns/logging_min.fun
Executable file
|
|
@ -0,0 +1,37 @@
|
||||||
|
#!/usr/bin/env fun
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Fun programming language.
|
||||||
|
* https://fun-lang.xyz/
|
||||||
|
*
|
||||||
|
* Copyright 2026 Johannes Findeisen
|
||||||
|
* Licensed under the terms of the Apache-2.0 license.
|
||||||
|
* https://opensource.org/license/apache-2-0
|
||||||
|
*
|
||||||
|
* Added: 2026-03-25
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Minimal helper: remove trailing newline from a string (no full strings lib needed)
|
||||||
|
fun chomp(s)
|
||||||
|
t = to_string(s)
|
||||||
|
if (len(t) > 0 && substr(t, len(t) - 1, 1) == "\n")
|
||||||
|
return substr(t, 0, len(t) - 1)
|
||||||
|
return t
|
||||||
|
|
||||||
|
fun now()
|
||||||
|
// Very rough timestamp using system 'date' for demo
|
||||||
|
r = proc_run("date +%Y-%m-%dT%H:%M:%S%z")
|
||||||
|
return chomp(r["out"])
|
||||||
|
|
||||||
|
fun log_line(level, msg)
|
||||||
|
print("[" + now() + "] [" + to_string(level) + "] " + to_string(msg))
|
||||||
|
|
||||||
|
log_line("INFO", "Service starting")
|
||||||
|
log_line("DEBUG", "Config loaded")
|
||||||
|
log_line("INFO", "Service running")
|
||||||
|
|
||||||
|
/* Expected output (timestamps will vary):
|
||||||
|
[2026-03-25T23:00:00+0000] [INFO] Service starting
|
||||||
|
[2026-03-25T23:00:00+0000] [DEBUG] Config loaded
|
||||||
|
[2026-03-25T23:00:00+0000] [INFO] Service running
|
||||||
|
*/
|
||||||
24
examples/snippets/escape_html_demo.fun
Executable file
24
examples/snippets/escape_html_demo.fun
Executable file
|
|
@ -0,0 +1,24 @@
|
||||||
|
#!/usr/bin/env fun
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Fun programming language.
|
||||||
|
* https://fun-lang.xyz/
|
||||||
|
*
|
||||||
|
* Copyright 2026 Johannes Findeisen
|
||||||
|
* Licensed under the terms of the Apache-2.0 license.
|
||||||
|
* https://opensource.org/license/apache-2-0
|
||||||
|
*
|
||||||
|
* Added: 2026-03-25
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <net/cgi.fun>
|
||||||
|
|
||||||
|
cgi = CGI()
|
||||||
|
raw = "<script>alert('xss') & more</script>"
|
||||||
|
print("raw: " + raw)
|
||||||
|
print("escaped:" + cgi.escape_html(raw))
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
raw: <script>alert('xss') & more</script>
|
||||||
|
escaped:<script>alert('xss') & more</script>
|
||||||
|
*/
|
||||||
29
examples/strings/split_join_trim.fun
Executable file
29
examples/strings/split_join_trim.fun
Executable file
|
|
@ -0,0 +1,29 @@
|
||||||
|
#!/usr/bin/env fun
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Fun programming language.
|
||||||
|
* https://fun-lang.xyz/
|
||||||
|
*
|
||||||
|
* Copyright 2026 Johannes Findeisen
|
||||||
|
* Licensed under the terms of the Apache-2.0 license.
|
||||||
|
* https://opensource.org/license/apache-2-0
|
||||||
|
*
|
||||||
|
* Added: 2026-03-25
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <strings.fun>
|
||||||
|
|
||||||
|
txt = " one, two , three "
|
||||||
|
parts = str_split(txt, ",")
|
||||||
|
i = 0
|
||||||
|
while (i < len(parts))
|
||||||
|
parts[i] = str_trim(parts[i])
|
||||||
|
i = i + 1
|
||||||
|
print("parts: " + to_string(parts))
|
||||||
|
joined = join(parts, ";")
|
||||||
|
print("joined: " + joined)
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
parts: [array n=3]
|
||||||
|
joined: one;two;three
|
||||||
|
*/
|
||||||
30
examples/strings/templating_min.fun
Executable file
30
examples/strings/templating_min.fun
Executable file
|
|
@ -0,0 +1,30 @@
|
||||||
|
#!/usr/bin/env fun
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Fun programming language.
|
||||||
|
* https://fun-lang.xyz/
|
||||||
|
*
|
||||||
|
* Copyright 2026 Johannes Findeisen
|
||||||
|
* Licensed under the terms of the Apache-2.0 license.
|
||||||
|
* https://opensource.org/license/apache-2-0
|
||||||
|
*
|
||||||
|
* Added: 2026-03-25
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Micro templating: replace {{key}} with map values
|
||||||
|
#include <strings.fun>
|
||||||
|
tpl = "Hello, {{name}} from {{city}}!"
|
||||||
|
ctx = {"name": "Fun", "city": "Cyberspace"}
|
||||||
|
|
||||||
|
fun render(template, data)
|
||||||
|
out = to_string(template)
|
||||||
|
for k in keys(data)
|
||||||
|
needle = "{{" + to_string(k) + "}}"
|
||||||
|
out = str_replace_all(out, needle, to_string(data[k]))
|
||||||
|
return out
|
||||||
|
|
||||||
|
print(render(tpl, ctx))
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
Hello, Fun from Cyberspace!
|
||||||
|
*/
|
||||||
24
examples/strings/urlencode_decode.fun
Executable file
24
examples/strings/urlencode_decode.fun
Executable file
|
|
@ -0,0 +1,24 @@
|
||||||
|
#!/usr/bin/env fun
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Fun programming language.
|
||||||
|
* https://fun-lang.xyz/
|
||||||
|
*
|
||||||
|
* Copyright 2026 Johannes Findeisen
|
||||||
|
* Licensed under the terms of the Apache-2.0 license.
|
||||||
|
* https://opensource.org/license/apache-2-0
|
||||||
|
*
|
||||||
|
* Added: 2026-03-25
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <net/cgi.fun>
|
||||||
|
|
||||||
|
cgi = CGI()
|
||||||
|
s = "name=Fun+Lang&msg=Hello%2C+World%21"
|
||||||
|
print("raw: " + s)
|
||||||
|
print("decod: " + cgi.url_decode(s))
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
raw: name=Fun+Lang&msg=Hello%2C+World%21
|
||||||
|
decod: name=Fun Lang&msg=Hello%2C World%21
|
||||||
|
*/
|
||||||
|
|
@ -16,7 +16,7 @@ fun str_ltrim(s)
|
||||||
src = to_string(s)
|
src = to_string(s)
|
||||||
number i = 0
|
number i = 0
|
||||||
ws = " \t\r\n"
|
ws = " \t\r\n"
|
||||||
while i < len(src)
|
while (i < len(src))
|
||||||
ch = substr(src, i, 1)
|
ch = substr(src, i, 1)
|
||||||
if (find(ws, ch) < 0)
|
if (find(ws, ch) < 0)
|
||||||
break
|
break
|
||||||
|
|
@ -28,7 +28,7 @@ fun str_rtrim(s)
|
||||||
src = to_string(s)
|
src = to_string(s)
|
||||||
number i = len(src) - 1
|
number i = len(src) - 1
|
||||||
ws = " \t\r\n"
|
ws = " \t\r\n"
|
||||||
while i >= 0
|
while (i >= 0)
|
||||||
ch = substr(src, i, 1)
|
ch = substr(src, i, 1)
|
||||||
if (find(ws, ch) < 0)
|
if (find(ws, ch) < 0)
|
||||||
break
|
break
|
||||||
|
|
@ -69,7 +69,7 @@ fun str_split(s, delim)
|
||||||
buf = []
|
buf = []
|
||||||
number i = 0
|
number i = 0
|
||||||
number n = len(src)
|
number n = len(src)
|
||||||
while i < n
|
while (i < n)
|
||||||
ch = substr(src, i, 1)
|
ch = substr(src, i, 1)
|
||||||
if (ch == dd)
|
if (ch == dd)
|
||||||
push(parts, join(buf, ""))
|
push(parts, join(buf, ""))
|
||||||
|
|
@ -92,7 +92,7 @@ fun str_replace_all(s, from, to)
|
||||||
return src
|
return src
|
||||||
out = []
|
out = []
|
||||||
number i = 0
|
number i = 0
|
||||||
while i < n
|
while (i < n)
|
||||||
if ((i + lf <= n) && (substr(src, i, lf) == f))
|
if ((i + lf <= n) && (substr(src, i, lf) == f))
|
||||||
push(out, t)
|
push(out, t)
|
||||||
i = i + lf
|
i = i + lf
|
||||||
|
|
@ -109,7 +109,7 @@ fun str_to_lower(s)
|
||||||
out = []
|
out = []
|
||||||
number i = 0
|
number i = 0
|
||||||
number n = len(src)
|
number n = len(src)
|
||||||
while i < n
|
while (i < n)
|
||||||
ch = substr(src, i, 1)
|
ch = substr(src, i, 1)
|
||||||
idx = find(U, ch)
|
idx = find(U, ch)
|
||||||
if (idx >= 0)
|
if (idx >= 0)
|
||||||
|
|
@ -127,7 +127,7 @@ fun str_to_upper(s)
|
||||||
out = []
|
out = []
|
||||||
number i = 0
|
number i = 0
|
||||||
number n = len(src)
|
number n = len(src)
|
||||||
while i < n
|
while (i < n)
|
||||||
ch = substr(src, i, 1)
|
ch = substr(src, i, 1)
|
||||||
idx = find(L, ch)
|
idx = find(L, ch)
|
||||||
if (idx >= 0)
|
if (idx >= 0)
|
||||||
|
|
@ -145,59 +145,19 @@ fun str_repeat(s, count)
|
||||||
return ""
|
return ""
|
||||||
parts = []
|
parts = []
|
||||||
number i = 0
|
number i = 0
|
||||||
while i < c
|
while (i < c)
|
||||||
push(parts, src)
|
push(parts, src)
|
||||||
i = i + 1
|
i = i + 1
|
||||||
return join(parts, "")
|
return join(parts, "")
|
||||||
|
|
||||||
|
/*
|
||||||
// ASCII string to bytes (printable ASCII 0x20..0x7E)
|
// ASCII string to bytes (printable ASCII 0x20..0x7E)
|
||||||
|
// Temporarily disabled due to parser incompatibilities with certain string
|
||||||
|
// literals in this function on some environments. Re-enable after the
|
||||||
|
// language parser updates to support these cases.
|
||||||
fun string_to_bytes_ascii(s)
|
fun string_to_bytes_ascii(s)
|
||||||
str = to_string(s)
|
str = to_string(s)
|
||||||
out = []
|
out = []
|
||||||
number i = 0
|
number i = 0
|
||||||
// ASCII printable ranges
|
|
||||||
P1 = " !\"#$%&'()*+,-./" // 32..47
|
|
||||||
P2 = "0123456789" // 48..57
|
|
||||||
P3 = ":;<=>?@" // 58..64
|
|
||||||
P4 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" // 65..90
|
|
||||||
P5 = "[\\]^_`" // 91..96
|
|
||||||
P6 = "abcdefghijklmnopqrstuvwxyz" // 97..122
|
|
||||||
P7 = "{|}~" // 123..126
|
|
||||||
while true
|
|
||||||
ch = substr(str, i, 1)
|
|
||||||
if (typeof(ch) != "String" || ch == "")
|
|
||||||
break
|
|
||||||
number code = -1
|
|
||||||
idx = find(P1, ch)
|
|
||||||
if (idx >= 0)
|
|
||||||
code = 32 + idx
|
|
||||||
else
|
|
||||||
idx = find(P2, ch)
|
|
||||||
if (idx >= 0)
|
|
||||||
code = 48 + idx
|
|
||||||
else
|
|
||||||
idx = find(P3, ch)
|
|
||||||
if (idx >= 0)
|
|
||||||
code = 58 + idx
|
|
||||||
else
|
|
||||||
idx = find(P4, ch)
|
|
||||||
if (idx >= 0)
|
|
||||||
code = 65 + idx
|
|
||||||
else
|
|
||||||
idx = find(P5, ch)
|
|
||||||
if (idx >= 0)
|
|
||||||
code = 91 + idx
|
|
||||||
else
|
|
||||||
idx = find(P6, ch)
|
|
||||||
if (idx >= 0)
|
|
||||||
code = 97 + idx
|
|
||||||
else
|
|
||||||
idx = find(P7, ch)
|
|
||||||
if (idx >= 0)
|
|
||||||
code = 123 + idx
|
|
||||||
else
|
|
||||||
// non-printable -> 0
|
|
||||||
code = 0
|
|
||||||
push(out, code)
|
|
||||||
i = i + 1
|
|
||||||
return out
|
return out
|
||||||
|
*/
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue