Some more housekeeping. Destroys nothing, but makes some things easier. (0.37.3)
This commit is contained in:
parent
ebae80cf44
commit
2927f88340
8 changed files with 165 additions and 196 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
cmake_minimum_required(VERSION 3.10)
|
cmake_minimum_required(VERSION 3.10)
|
||||||
project(fun VERSION 0.37.2 LANGUAGES C)
|
project(fun VERSION 0.37.3 LANGUAGES C)
|
||||||
|
|
||||||
set(CMAKE_C_STANDARD 99)
|
set(CMAKE_C_STANDARD 99)
|
||||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||||
|
|
|
||||||
325
demo.fun
325
demo.fun
|
|
@ -1,200 +1,153 @@
|
||||||
#!/usr/bin/env fun
|
#!/usr/bin/env fun
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file is part of the Fun programming language.
|
* Interactive demo runner for all examples in ./examples
|
||||||
* https://fun-lang.xyz/
|
* - Asks y/n before running each feature demo
|
||||||
*
|
* - Executes each example as a subprocess
|
||||||
* 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-09-30
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Fun Interactive Demo
|
#include <io/console.fun>
|
||||||
// Run: FUN_LIB_DIR="$(pwd)/lib" ./build/fun demo.fun (Linux/macOS/FreeBSD)
|
|
||||||
// set FUN_LIB_DIR=%CD%\lib && build-debug\fun.exe demo.fun (Windows CMD)
|
|
||||||
// $env:FUN_LIB_DIR="$PWD\lib"; .\build\fun.exe demo.fun (Windows PowerShell)
|
|
||||||
|
|
||||||
// Use a stdlib helper from the repository (fallback to ./lib via preprocessor)
|
fun pick_fun_bin()
|
||||||
#include <utils/math.fun>
|
// Prefer an explicit FUN_BIN override; otherwise rely on PATH
|
||||||
|
b = env("FUN_BIN")
|
||||||
|
if b != ""
|
||||||
|
return b
|
||||||
|
return "fun"
|
||||||
|
|
||||||
print("")
|
fun run_example(bin, path)
|
||||||
print("=== Fun Interactive Demo ===")
|
// Ensure examples can locate stdlib when run from repo root.
|
||||||
|
// We execute via the shell so env assignment + redirection works.
|
||||||
|
cmd = join(["sh -c '\nFUN_LIB_DIR=./lib ", bin, " ", path, " 2>&1\n'"], "")
|
||||||
|
print("-- output begin --")
|
||||||
|
code = system(cmd)
|
||||||
|
print("-- output end --")
|
||||||
|
print(join(["exit code: ", to_string(code)], ""))
|
||||||
|
return code
|
||||||
|
|
||||||
print("")
|
fun main()
|
||||||
print("== Basics: dynamic vs typed variables and typeof ==")
|
c = Console()
|
||||||
x = 123
|
bin = pick_fun_bin()
|
||||||
print("x=" + to_string(x) + " typeof=" + typeof(x))
|
|
||||||
x = "hello"
|
|
||||||
print("x=" + to_string(x) + " typeof=" + typeof(x))
|
|
||||||
|
|
||||||
number n = 42
|
print("=== Fun language feature showcase (interactive) ===")
|
||||||
print("n=" + to_string(n) + " typeof=" + typeof(n))
|
print(join(["Using interpreter: ", bin], ""))
|
||||||
n = n + 8
|
print("Tip: set FUN_BIN=/path/to/fun to override. Stdlib is passed via FUN_LIB_DIR=./lib\n")
|
||||||
print("n=" + to_string(n) + " typeof=" + typeof(n))
|
|
||||||
// Uncomment to see a runtime type error and halt the program:
|
|
||||||
// n = "oops"
|
|
||||||
|
|
||||||
boolean flag = 0
|
// List of example scripts. Keep paths relative to repo root where this demo resides.
|
||||||
print("flag=" + to_string(flag) + " typeof=" + typeof(flag))
|
// If you add/remove examples, update this list.
|
||||||
flag = 2 // gets clamped to 1
|
files = [
|
||||||
print("flag(after clamp 2)=" + to_string(flag))
|
"examples/arrays.fun",
|
||||||
|
"examples/arrays_advanced.fun",
|
||||||
|
"examples/arrays_iter.fun",
|
||||||
|
"examples/boolean_decl.fun",
|
||||||
|
"examples/booleans.fun",
|
||||||
|
"examples/builtins_conversions.fun",
|
||||||
|
"examples/builtins_extended.fun",
|
||||||
|
"examples/builtins_maps_and_more.fun",
|
||||||
|
"examples/byte_for_demo.fun",
|
||||||
|
"examples/byte_overflow_try_catch.fun",
|
||||||
|
"examples/cast_demo.fun",
|
||||||
|
"examples/class_constructor.fun",
|
||||||
|
"examples/classes_demo.fun",
|
||||||
|
"examples/crc32_example.fun",
|
||||||
|
"examples/crc32c_example.fun",
|
||||||
|
"examples/curl_download.fun",
|
||||||
|
"examples/curl_get_json.fun",
|
||||||
|
"examples/curl_post.fun",
|
||||||
|
"examples/datetime_basic.fun",
|
||||||
|
"examples/datetime_extended.fun",
|
||||||
|
"examples/datetime_timer.fun",
|
||||||
|
"examples/debug_reporting.fun",
|
||||||
|
"examples/echo_example.fun",
|
||||||
|
"examples/exit_example.fun",
|
||||||
|
"examples/expressions_test.fun",
|
||||||
|
"examples/fail.fun",
|
||||||
|
"examples/file_io.fun",
|
||||||
|
"examples/file_print_for_file_line_by_line.fun",
|
||||||
|
"examples/floats.fun",
|
||||||
|
"examples/for_range_test.fun",
|
||||||
|
"examples/functions_test.fun",
|
||||||
|
"examples/have_fun.fun",
|
||||||
|
"examples/have_fun_function.fun",
|
||||||
|
"examples/if_else_test.fun",
|
||||||
|
"examples/include_lib.fun",
|
||||||
|
"examples/include_local.fun",
|
||||||
|
"examples/include_local_util.fun",
|
||||||
|
"examples/include_namespace.fun",
|
||||||
|
"examples/inheritance_demo.fun",
|
||||||
|
"examples/ini_class_demo.fun",
|
||||||
|
"examples/ini_complex.fun",
|
||||||
|
"examples/ini_demo.fun",
|
||||||
|
"examples/ini_subsections.fun",
|
||||||
|
"examples/input_example.fun",
|
||||||
|
"examples/json_showcase.fun",
|
||||||
|
"examples/libsql_example.fun",
|
||||||
|
"examples/loops_break_continue.fun",
|
||||||
|
"examples/md5_demo.fun",
|
||||||
|
"examples/namespaced_mod.fun",
|
||||||
|
"examples/nested_loops.fun",
|
||||||
|
"examples/objects_basic.fun",
|
||||||
|
"examples/objects_more.fun",
|
||||||
|
"examples/os_env.fun",
|
||||||
|
"examples/pcre2_opcodes.fun",
|
||||||
|
"examples/pcre2_showcase.fun",
|
||||||
|
"examples/pcsc_example.fun",
|
||||||
|
"examples/process_example.fun",
|
||||||
|
"examples/regex_demo.fun",
|
||||||
|
"examples/regex_procedural.fun",
|
||||||
|
"examples/repl_on_error.fun",
|
||||||
|
"examples/sha1_demo.fun",
|
||||||
|
"examples/sha256_demo.fun",
|
||||||
|
"examples/sha256_str_demo.fun",
|
||||||
|
"examples/sha384_example.fun",
|
||||||
|
"examples/sha512_demo.fun",
|
||||||
|
"examples/sha512_str_demo.fun",
|
||||||
|
"examples/short_circuit_test.fun",
|
||||||
|
"examples/signed_ints.fun",
|
||||||
|
"examples/sqlite_example.fun",
|
||||||
|
"examples/stdlib_showcase.fun",
|
||||||
|
"examples/strings_test.fun",
|
||||||
|
"examples/tcp_http_get.fun",
|
||||||
|
"examples/tcp_http_get_class.fun",
|
||||||
|
"examples/thread_class_example.fun",
|
||||||
|
"examples/threads_demo.fun",
|
||||||
|
"examples/tk_hello.fun",
|
||||||
|
"examples/try_catch_finally.fun",
|
||||||
|
"examples/try_catch_with_error.fun",
|
||||||
|
"examples/typeof.fun",
|
||||||
|
"examples/typeof_features.fun",
|
||||||
|
"examples/type_safety.fun",
|
||||||
|
"examples/type_safety_fails.fun",
|
||||||
|
"examples/types_integers.fun",
|
||||||
|
"examples/types_overview.fun",
|
||||||
|
"examples/uint_types.fun",
|
||||||
|
"examples/unix_socket_echo.fun",
|
||||||
|
"examples/while_test.fun",
|
||||||
|
"examples/xml_access_catalog.fun",
|
||||||
|
"examples/xml_access_employees.fun",
|
||||||
|
"examples/xml_access_ns.fun",
|
||||||
|
"examples/xml_class_example.fun",
|
||||||
|
"examples/xml_minimal.fun"
|
||||||
|
]
|
||||||
|
|
||||||
int8 si = 130 // clamps to 127
|
failures = []
|
||||||
uint8 u8 = 300 // clamps to 255
|
|
||||||
print("int8 si=" + to_string(si) + ", uint8 u8=" + to_string(u8))
|
|
||||||
|
|
||||||
nil nothing = nil
|
for f in files
|
||||||
print("nothing typeof=" + typeof(nothing))
|
q = join(["Run ", f, "?"], "")
|
||||||
|
if c.ask_yes_no(q)
|
||||||
|
print(join(["=== Running: ", f, " ==="], ""))
|
||||||
|
code = run_example(bin, f)
|
||||||
|
if code != 0
|
||||||
|
failures.push(f)
|
||||||
|
print("")
|
||||||
|
else
|
||||||
|
print(join(["Skipped: ", f], ""))
|
||||||
|
|
||||||
print("")
|
if len(failures) == 0
|
||||||
print("== Arithmetic, comparisons, and logic ==")
|
print("All selected examples completed successfully.")
|
||||||
print("3+4=" + to_string(3 + 4))
|
else
|
||||||
print("10-3=" + to_string(10 - 3))
|
print("Some selected examples failed:")
|
||||||
print("6*7=" + to_string(6 * 7))
|
for ff in failures
|
||||||
print("20/3=" + to_string(20 / 3))
|
print(join([" - ", ff], ""))
|
||||||
print("20%3=" + to_string(20 % 3))
|
|
||||||
print("2<3=" + to_string(2 < 3) + ", 3<=3=" + to_string(3 <= 3))
|
|
||||||
print("5>2=" + to_string(5 > 2) + ", 2>=2=" + to_string(2 >= 2))
|
|
||||||
print("2==2=" + to_string(2 == 2) + ", 2!=3=" + to_string(2 != 3))
|
|
||||||
print("(1 && 0)=" + to_string(1 && 0) + ", (0 || 1)=" + to_string(0 || 1) + ", !0=" + to_string(!0))
|
|
||||||
|
|
||||||
print("")
|
main()
|
||||||
print("== Strings and arrays ==")
|
|
||||||
s = "alpha,beta,gamma"
|
|
||||||
parts = split(s, ",")
|
|
||||||
print("split -> len=" + to_string(len(parts)))
|
|
||||||
print("join(parts,'|')=" + join(parts, "|"))
|
|
||||||
print("substr('abcdef', 2, 3)=" + substr("abcdef", 2, 3))
|
|
||||||
print("find('hello world','world')=" + to_string(find("hello world", "world")))
|
|
||||||
|
|
||||||
arr = [1, 2, 3]
|
|
||||||
print("arr len=" + to_string(len(arr)))
|
|
||||||
push(arr, 4)
|
|
||||||
print("after push 4 -> len=" + to_string(len(arr)))
|
|
||||||
v = pop(arr)
|
|
||||||
print("popped=" + to_string(v) + " len=" + to_string(len(arr)))
|
|
||||||
insert(arr, 1, 99) // [1,99,2,3]
|
|
||||||
print("after insert(1,99) arr[1]=" + to_string(arr[1]))
|
|
||||||
set(arr, 2, 55) // [1,99,55,3]
|
|
||||||
print("after set(2,55) arr[2]=" + to_string(arr[2]))
|
|
||||||
print("contains(arr, 55)=" + to_string(contains(arr, 55)) + ", indexOf(arr, 99)=" + to_string(indexOf(arr, 99)))
|
|
||||||
print("slice arr[1:3] len=" + to_string(len(arr[1:3])))
|
|
||||||
print("join(arr, ',')=" + join(arr, ","))
|
|
||||||
|
|
||||||
print("")
|
|
||||||
print("== Enumerate and zip ==")
|
|
||||||
for p in enumerate(["a", "b", "c"])
|
|
||||||
print("idx=" + to_string(p[0]) + " val=" + to_string(p[1]))
|
|
||||||
z = zip([1, 2], ["x", "y"])
|
|
||||||
for pair in z
|
|
||||||
print("(" + to_string(pair[0]) + "," + to_string(pair[1]) + ")")
|
|
||||||
|
|
||||||
print("")
|
|
||||||
print("== Maps (dictionaries) ==")
|
|
||||||
m = {"name": "Alice", "age": 30}
|
|
||||||
print("has(m,'age')=" + to_string(has(m, "age")))
|
|
||||||
print("m['name']=" + to_string(m["name"]))
|
|
||||||
m.age = 31
|
|
||||||
print("m.age after = " + to_string(m.age))
|
|
||||||
print("keys: " + join(keys(m), ","))
|
|
||||||
print("values count=" + to_string(len(values(m))))
|
|
||||||
|
|
||||||
print("")
|
|
||||||
print("== Functions and higher-order ops (map/filter/reduce) ==")
|
|
||||||
fun greet(name)
|
|
||||||
print("Hello, " + to_string(name) + "!")
|
|
||||||
greet("Fun")
|
|
||||||
|
|
||||||
fun double(x)
|
|
||||||
return x * 2
|
|
||||||
|
|
||||||
nums = [1, 2, 3, 4, 5]
|
|
||||||
twice = map(nums, double)
|
|
||||||
print("len(map)=" + to_string(len(twice)) + " first=" + to_string(twice[0]))
|
|
||||||
|
|
||||||
fun isEven(x)
|
|
||||||
return (x % 2) == 0
|
|
||||||
evens = filter(nums, isEven)
|
|
||||||
print("filter evens len=" + to_string(len(evens)))
|
|
||||||
|
|
||||||
fun sum(acc, x)
|
|
||||||
return acc + x
|
|
||||||
total = reduce(nums, 0, sum)
|
|
||||||
print("reduce sum=" + to_string(total))
|
|
||||||
|
|
||||||
print("")
|
|
||||||
print("== If / else-if / else and loops ==")
|
|
||||||
val = 7
|
|
||||||
if (val < 0)
|
|
||||||
print("neg")
|
|
||||||
else if (val == 0)
|
|
||||||
print("zero")
|
|
||||||
else
|
|
||||||
print("pos")
|
|
||||||
|
|
||||||
print("for range(0, 5):")
|
|
||||||
for i in range(0, 5)
|
|
||||||
print(i)
|
|
||||||
|
|
||||||
print("for in array:")
|
|
||||||
for x in ["h", "i", "!"]
|
|
||||||
print(x)
|
|
||||||
|
|
||||||
print("while loop (count to 3):")
|
|
||||||
c = 0
|
|
||||||
while (c < 3)
|
|
||||||
print(c)
|
|
||||||
c = c + 1
|
|
||||||
|
|
||||||
print("")
|
|
||||||
print("== Classes (with 'this' and methods) ==")
|
|
||||||
class Person(string name, number age)
|
|
||||||
// default field values (can be overridden by constructor params)
|
|
||||||
full = name + " (" + to_string(age) + ")"
|
|
||||||
|
|
||||||
// required: first param is 'this'
|
|
||||||
fun say(this)
|
|
||||||
print("I am " + to_string(this.full))
|
|
||||||
|
|
||||||
// typeof(instance) will return this string for Maps tagged with __class
|
|
||||||
fun toString(this)
|
|
||||||
return "Person"
|
|
||||||
|
|
||||||
p = Person("Alice", 30)
|
|
||||||
p.say()
|
|
||||||
print("typeof p: " + typeof(p))
|
|
||||||
|
|
||||||
print("")
|
|
||||||
print("== Math and bitwise helpers ==")
|
|
||||||
print("min(3,9)=" + to_string(min(3, 9)) + ", max(3,9)=" + to_string(max(3, 9)))
|
|
||||||
print("clamp(15,0,10)=" + to_string(clamp(15, 0, 10)) + ", abs(-5)=" + to_string(abs(-5)))
|
|
||||||
print("pow(2,10)=" + to_string(pow(2, 10)))
|
|
||||||
print("band(0xF0,0x3C)=" + to_string(band(0xF0, 0x3C)))
|
|
||||||
print("bor(0x0F,0x30)=" + to_string(bor(0x0F, 0x30)))
|
|
||||||
print("bxor(0xFF,0x0F)=" + to_string(bxor(0xFF, 0x0F)))
|
|
||||||
print("bnot(0x0F)=" + to_string(bnot(0x0F)))
|
|
||||||
print("shl(1,4)=" + to_string(shl(1, 4)) + ", shr(128,3)=" + to_string(shr(128, 3)))
|
|
||||||
print("rol(0x12,1)=" + to_string(rol(0x12, 1)) + ", ror(0x12,1)=" + to_string(ror(0x12, 1)))
|
|
||||||
|
|
||||||
print("")
|
|
||||||
print("== Random numbers ==")
|
|
||||||
random(12345) // seed
|
|
||||||
print("randomInt(1,10) -> " + to_string(randomInt(1, 10)))
|
|
||||||
|
|
||||||
print("")
|
|
||||||
print("== File IO and environment ==")
|
|
||||||
write_ok = write_file("demo_tmp.txt", "Hello from Fun!\n")
|
|
||||||
print("write_file ok=" + to_string(write_ok))
|
|
||||||
content = read_file("demo_tmp.txt")
|
|
||||||
print("read_file len=" + to_string(len(content)))
|
|
||||||
print("PATH starts with: " + substr(env("PATH"), 0, 24))
|
|
||||||
|
|
||||||
print("")
|
|
||||||
print("== Library include demo ==")
|
|
||||||
print("add(2,3) from utils/math.fun -> " + to_string(add(2, 3)))
|
|
||||||
print("times(4,5) from utils/math.fun -> " + to_string(times(4, 5)))
|
|
||||||
|
|
||||||
print("")
|
|
||||||
print("=== Demo complete. Have Fun! ===")
|
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,14 @@ if [[ ! -x "$BIN" ]]; then
|
||||||
exit 2
|
exit 2
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Ensure stdlib is discoverable for examples unless user already set it
|
||||||
|
if [[ -z "${FUN_LIB_DIR:-}" ]]; then
|
||||||
|
export FUN_LIB_DIR="$ROOT/lib"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ensure error bucket exists
|
||||||
|
mkdir -p "$EX_DIR/error"
|
||||||
|
|
||||||
shopt -s nullglob
|
shopt -s nullglob
|
||||||
files=("$EX_DIR"/*.fun)
|
files=("$EX_DIR"/*.fun)
|
||||||
shopt -u nullglob
|
shopt -u nullglob
|
||||||
|
|
@ -64,6 +72,14 @@ for f in "${files[@]}"; do
|
||||||
echo "=== Running: ${f#$ROOT/} ==="
|
echo "=== Running: ${f#$ROOT/} ==="
|
||||||
if ! "$BIN" "$f"; then
|
if ! "$BIN" "$f"; then
|
||||||
echo "FAILED: ${f#$ROOT/}"
|
echo "FAILED: ${f#$ROOT/}"
|
||||||
|
base="$(basename "$f")"
|
||||||
|
dest="$EX_DIR/error/$base"
|
||||||
|
# Move the failing example to the error folder
|
||||||
|
if mv -f "$f" "$dest"; then
|
||||||
|
echo "Moved to: examples/error/$base"
|
||||||
|
else
|
||||||
|
echo "warning: failed to move $base to examples/error/" >&2
|
||||||
|
fi
|
||||||
rc=1
|
rc=1
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue