A lightweight, embeddable, data-centric scripting language whose reach extends from JSON/FD data all the way down to runtime-compiled C and raw machine code.
English (this file) · 简体中文
- Version: 9.0
- Website: https://funlang.org
- Author: Zhang Weidong <zwd@funlang.org>
- License: MIT, plus commercial terms (see License)
Version 9.0: this is not a toy or a prototype — a mature language refined and production-validated for over 15 years (2010–present), with a lineage that reaches back through Nuva (2006) and TemplateScript (2005).
- Why Fun
- Core features
- Quick start
- A taste of Fun
- The capability ladder
- The FD data format
- Foreign function interface
- Keyword aliasing
- Embedding with fun.dll
- Repository layout
- Building
- Standard library
- Examples
- License
In one sentence: Fun is a scripting language that goes all the way from JSON to machine code.
- One runtime spans the whole spectrum, from high-level data work (JSON/FD) down to low-level system programming (FFI, C at runtime, JIT, machine code);
- 58 standard-library modules written in Fun itself ship together as one embeddable
fun.dll; - in AI-agent and domestic-IT scenarios, it is the lightweight glue connecting OSes, databases, chips, and business logic.
Fun is designed around a simple premise: data and code should be equally first-class, and a script should be able to reach down to the machine without leaving the language.
Most scripting languages either stay high-level (easy, but you hit a wall at the FFI) or force you to write C for performance-critical parts. Fun collapses that ladder into one runtime:
- Manipulate JSON and FD data with native list / set / tree collections;
- call arbitrary native code through a compact FFI signature;
- compile C at runtime with a bundled Tiny C Compiler;
- drop to inline assembly / JIT for the tightest loops;
all from pure script, in a single embeddable binary.
Fun is written in Pascal (Delphi / Free Pascal). The core is a small tree-walking interpreter with a dynamic value model, an object system, closures, and modules — deliberately compact so it can be embedded as fun.dll or run as a standalone fun.exe.
- Dynamic, data-centric value model — numbers, strings, time, regex, and first-class collections: list (array), set, and tree, built on a variant-based runtime.
- First-class functions — anonymous functions, function references, currying, default and variadic parameters, and
->pipelines. - Object system —
class,this/base, methods, and property get/set dispatch (methods, getters and setters are dispatched uniformly through the.operator). - Modules —
use 'file.fun'(optionallyas alias) pulls in other scripts; the runtime tracks module state and dependencies. - Regex as a value type — bundled PCRE engine with inline regex literals (
/.../) and match operators (=~,!~). - Built-in data formats — JSON and FD, a JSON-compatible, Markdown-like format friendly to humans and to AI (see below).
- Runtime C & machine code — bundled Tiny C Compiler, JIT, and inline assembly (see the capability ladder).
- Compact FFI — call DLL/shared-library functions with a terse signature string (see FFI).
- Keyword aliasing — a canonical English keyword set with pluggable alias packs (Chinese, French, custom) selected at runtime (see below).
- Cross-platform — Windows (32/64-bit), Linux, ARM, and Windows CE.
- Dual distribution — command-line
fun.exeand embeddable runtimefun.dllexporting a simpleRuninterface. - Self-hosted standard library — 58 modules written in Fun itself, from JSON/YAML/XML to ORM, async, UI, and native bindings.
Run a script:
fun.exe <file.fun> # run a script (.fun / .foo / .fxx)
fun.exe -v <file.fun> # show compile & run timing
fun.exe -log[:log.txt] -gui # log output / run in GUI mode
fun.exe -key:key_cn.ini # load a keyword alias pack
Hello world (canonical keywords):
fun foo()
?. 'Hello, fun!';
end fun;
foo();
fun max(a, b)
if a > b then
result = a;
else
result = b;
end if;
end fun;
?. max(1, 9);
?. max(9, 1);Run:
> fun.exe fun/demo/fun.fun
Hello, fun!
9
9
Two quick, self-contained snippets that show both ends of the language (the full files live in fun/demos/benchmarks/).
Custom operators on classes, first-class functions, composition, and pipelines:
# a class with a custom operator
class Number(me)
this['#'] = you -> (me + you) * me * you;
end class;
var $ = Number(2);
?. $ .# 3; # (2 + 3) * 2 * 3 = 30
# first-class functions, composition & pipelines
var f = a -> a * 2;
var g = a -> a + 3;
?. g(f(1 + 2) + 3); # 12
?. 1 + 2 | f + 3 | g; # 12 (same, pipelined)A data pipeline that turns a query string into a map using regex and collection combinators:
use 'lib-regex.fun';
use 'lib-set.fun';
var q = 'a=1&b=2&c=';
var parseQuery = s -> (s | split(/&/) | map(sp_eq) | fromPairs);
?. parseQuery(q).@toJson(1); # {"a":"1","b":"2","c":""}See test-high-level-language.fun for the complete version.
What makes Fun unusual is how far a script can go without a separate toolchain:
| Layer | Facility | Backing |
|---|---|---|
| High-level | JSON / FD data, list / set / tree | native collections and parsers |
| Native calls | dll.getapi(name, 'signature') |
FFI with a compact signature convention |
| C at runtime | ccompile(code, ...) |
bundled Tiny C Compiler (libtcc.dll) |
| JIT | NewJit(...) |
dispatch between C (TCC) and assembly |
| Machine code | Assembly(code, ...).Load() |
inline assembly, executable memory allocation |
For example, lib-tcc loads libtcc.dll and exposes tcc_new, tcc_compile_string, tcc_get_symbol, ... so you can compile C source from a string and call the resulting symbol immediately. lib-asm allocates executable memory, writes machine code, and invokes it; lib-jit picks the right path based on the source (#!c → TCC, otherwise assembly).
A single script can mix both: NewJit compiles C and inline assembly at runtime, and each can call straight back into a Fun function (@toCallback). The snippet below sums 1..n — once via assembly, once via compiled C — and hands the result to a Fun callback both times (full version: test-jit-cb.fun):
use 'lib-jit.fun';
fun cb(a, b) # a Fun callback called from JIT'd code
result = a * 2^32 + b;
end fun;
# assembly path
var asm = `#!asm i:i
mov ecx, dword ptr [esp+04]
@sum1ton
push eax
push edx
mov eax, <test>
call eax
`;
var jit = NewJit(asm, names: [test: cb.@toCallback(nil, 'ii:i', true)]);
?. jit.Run(100000);
# C path (compiled at runtime with bundled TCC)
var c = `#!C ii:i
int sum(int n, int (*test)(int, int)) {
long long s = 0;
for (int i = 1; i <= n; i++) s += i;
test((int)(s >> 32), (int)(s & 0xFFFFFFFF));
return 1;
}
`;
jit = NewJit(c);
?. jit.call(100000, cb.@toCallback(nil, 'ii:C', true));Platform note: the
#!asmblock above is 32-bit x86 (Windows) assembly (esp-relative args,ecx). The#!Cpath is portable, but the assembly snippet is architecture-specific — on Linux/ARM use the C form or rewrite the assembly for the target ABI.
FD is a data format designed to be readable by humans and by AI, and interoperable with JSON:
- JSON-compatible structure (nested keys, arrays);
- indentation-based, Markdown-like syntax;
- optional SSE compression;
- bidirectional conversion with JSON (
@toJson,getJson).
# FD format (Markdown-like: indentation + space-separated keys)
person
name Zhang Weidong
age 46
skills
- pascal
- c
- fun
# equivalent JSON
{"person": {"name": "Zhang Weidong", "age": 46, "skills": ["pascal", "c", "fun"]}}
Its defining trait is that FD is self-describing: the parser in lib-fd.fun is generated from a BNF grammar written in FD itself (fd.bnf.fd). The grammar file src/parse/bnf/fun.ebnf documents the language grammar in the same spirit.
Fun exposes native functions through a compact signature-string convention. Examples drawn from the standard library:
'kernel32'.getapi('VirtualAlloc', 'iiii:i'); // 4 int args -> int
'tcc'.getapi('tcc_new', 'v:i'); // void arg -> intThe signature encodes each argument's type, then :, then the return type (i = int, s = string, v = void, d = double, etc.). The same mechanism drives COM (lib-winole), the Windows API (lib-winapi), and the C runtime.
The interpreter's canonical keywords are English (fun, if, then, loop, class, ...). Because keywords are resolved through an alias layer (ParseAlias), you can supply pluggable alias packs at startup:
fun.exe -key:key_cn.ini # Chinese keywords (函数=fun, 如果=if, ...)
fun.exe -key:key_fr.ini # French keywords
Included packs: key_cn.ini (简体中文), key_fr.ini (français), and key_pua.ini (custom/private-use). The language itself is keyword-neutral — aliases are a localization/accessibility feature, not a different language.
fun.dll is the embeddable runtime for integrating Fun scripts into third-party applications:
Run(PChar('script.fun')); // compile the script
Run(scriptContent); // execute it
Run(-1); // release- Free use (MIT): personal study, internal tools, and products released under an open-source license.
- Commercial use: embedding
fun.dllin a closed-source commercial product (exe/dmg/apk or a SaaS backend) requires a commercial license — seeLICENSE.dll.
fun/
├── src/
│ ├── core/ # Interpreter core (value model, object system, control flow, IO)
│ ├── parse/ # Lexer/parser
│ │ └── bnf/ # Grammar: fun.ebnf, yacc.y, lex.l (generates .inc/.cod)
│ ├── lib/ # Built-in runtime library (winapi, winole, UI, host, etc.)
│ ├── regex/pcre/ # Bundled PCRE regex engine
│ ├── 3rd/ # Third-party components (KOL)
│ ├── utils/ # Utility functions
│ └── prj/fun/ # Projects & build scripts (funcmd.dpr, Delphi/FPC)
├── fun/
│ ├── lib/ # Standard library (pure Fun, 58 modules)
│ ├── demo/ # Language syntax demos
│ ├── demos/ # Full applications & benchmarks
│ └── key_*.ini # Keyword alias packs (CN / FR / PUA)
└── LICENSE* # License files
The Fun core is Pascal; the source entry point is src/prj/fun/funcmd.dpr.
Toolchain locations are centralized in one file: src/prj/fun/setenv.bat. Edit it once to point at your installed Delphi / Free Pascal, or set the FPC, DELPHI2006, DELPHI2009 environment variables beforehand — every make-*.bat script calls it and picks up the paths. Supported toolchains:
| Target | Script | Toolchain |
|---|---|---|
| Windows 32-bit | src/prj/fun/make-2006.bat / -2009.bat |
Delphi 2006 / 2009 |
| Linux (i386) | make-linux.bat |
FPC 2.4.0 |
| Linux / ARM | make-arm-linux.bat |
FPC cross |
| Windows 64-bit | make-win64.bat |
FPC cross |
| Windows CE / ARM | make-wince.bat |
FPC cross |
Building with -DFunDll produces the embeddable runtime fun.dll, which exports the Run interface. Build artifacts are covered by .gitignore and are not versioned.
The full grammar is defined in src/parse/bnf/fun.ebnf.
The standard library in fun/lib is written in pure Fun (58 modules):
In total roughly 6,000 lines of logical code (excluding comments), about 100 lines per module — all 58 modules written in Fun itself.
- Data:
lib-json,lib-yaml,lib-xml,lib-base64,lib-cstruct,lib-md5,lib-crypt - Collections / algorithms:
lib-set,lib-tree,lib-stack,lib-dyns,lib-math - Text:
lib-string,lib-regex,lib-match,lib-unicode - System / IO:
lib-file,lib-os,lib-time,lib-cmdline,lib-proc - Network:
lib-winsock,lib-ajax,lib-jsonrpc - Databases:
lib-orm,lib-orm-pro,lib-orm-gen,lib-orm-rpc,lib-orm-cte,lib-ado,lib-ado-schema - Native / low-level:
lib-winapi,lib-winole,lib-tcc(C compile),lib-jit,lib-asm,lib-asm-pro - UI:
lib-ui,lib-ui-base,lib-dialog,lib-trayicon - Concurrency / async:
lib-async,lib-jsasync,lib-bind,lib-message
fun/demo— syntax demos: functions, closures, currying, classes, objects, sets, regex, and exception handling.fun/demos— full applications and benchmarks: thenotepad--editor,odbc-search, and performance/assembly/JIT benchmarks.
Fun is distributed under a dual-license model:
- Open-source (MIT) — see
LICENSE. You are free to use, modify, and redistribute the source, provided the copyright notice is retained. - Commercial license (additional terms that apply only to these closed-source redistribution cases):
- Substantially modifying the kernel and commercially distributing the result closed-source — see
LICENSE.custom; - Embedding
fun.dllin a closed-source commercial product or SaaS backend — seeLICENSE.dll.
- Substantially modifying the kernel and commercially distributing the result closed-source — see
In short: internal use, study/research, and releasing modified versions under an open-source license (MIT/GPL etc.) are all free. A commercial license is needed only when you sell a modified kernel or fun.dll as a closed-source commercial product. Commercial licenses are one-time, priced per project/company — contact <zwd@funlang.org>.
© 2010-2026 Zhang Weidong <zwd@funlang.org>