feat: add async/await keywords, Num/String extensions, and Jinja markdown example

Add `async` and `await` token support to the Wren compiler with scheduler resolution logic, extend `Num` with `e` constant, hyperbolic trig, base conversion, and new methods (`isZero`, `gcd`, `lcm`, `digits`, etc.), extend `String` with `lower`, `upper`, `capitalize`, `title`, and regenerate `wren_core.wren.inc`. Include `Makefile` for multi-platform builds, rewrite `README.md` with updated build instructions, and add `example/await_demo.wren` and `example/jinja_markdown.wren` demonstrating new features.
This commit is contained in:
2026-01-25 03:58:39 +00:00
parent 74ef5cbc11
commit 46fc2e2470
139 changed files with 5078 additions and 73 deletions
+22
View File
@@ -0,0 +1,22 @@
// retoor <retoor@molodetz.nl>
import "scheduler" for Scheduler, Future
import "timer" for Timer
System.print("=== Await Demo ===\n")
System.print("--- Basic Await ---")
await Timer.sleep(1)
System.print("Timer completed")
System.print("\n--- Concurrent Async ---")
var task1 = async { Timer.sleep(1) }
var task2 = async { Timer.sleep(1) }
await task1
await task2
System.print("Both tasks completed concurrently")
System.print("\n--- Async With Result ---")
var task = async { "computed value" }
var result = await task
System.print("Result: %(result)")
+67
View File
@@ -0,0 +1,67 @@
// retoor <retoor@molodetz.nl>
import "jinja" for Environment, DictLoader
System.print("=" * 60)
System.print("JINJA MARKDOWN - Markdown/HTML Conversion in Templates")
System.print("=" * 60)
var templates = {
"md_to_html": "{\% markdowntohtml \%}# {{ title }}
{{ description }}
- Item **one**
- Item **two**
- Item **three**
{\% endmarkdowntohtml \%}",
"html_to_md": "{\% markdownfromhtml \%}<h1>{{ title }}</h1>
<p>This is a <strong>paragraph</strong> with <em>formatting</em>.</p>
<ul>
<li>First</li>
<li>Second</li>
</ul>{\% endmarkdownfromhtml \%}",
"filter_md": "{{ content|markdown }}",
"filter_fromhtml": "{{ content|markdownfromhtml }}",
"mixed": "<div class=\"article\">
{\% markdowntohtml \%}## {{ article.title }}
{{ article.body }}
{\% endmarkdowntohtml \%}
</div>"
}
var env = Environment.new(DictLoader.new(templates))
System.print("\n--- Markdown to HTML (block tag) ---")
System.print(env.getTemplate("md_to_html").render({
"title": "Welcome",
"description": "This is a *template* with markdown support."
}))
System.print("\n--- HTML to Markdown (block tag) ---")
System.print(env.getTemplate("html_to_md").render({
"title": "Documentation"
}))
System.print("\n--- Markdown filter ---")
System.print(env.getTemplate("filter_md").render({
"content": "**Bold** and *italic* text."
}))
System.print("\n--- Markdown from HTML filter ---")
System.print(env.getTemplate("filter_fromhtml").render({
"content": "<h2>Section</h2><p>A paragraph.</p>"
}))
System.print("\n--- Mixed HTML and Markdown ---")
System.print(env.getTemplate("mixed").render({
"article": {
"title": "Getting Started",
"body": "Read the **documentation** for details."
}
}))
+51
View File
@@ -0,0 +1,51 @@
// retoor <retoor@molodetz.nl>
System.print("=== Num Extensions Demo ===\n")
System.print("--- Constants ---")
System.print("Num.pi: %(Num.pi)")
System.print("Num.tau: %(Num.tau)")
System.print("Num.e: %(Num.e)")
System.print("\n--- Query Methods ---")
System.print("0.isZero: %(0.isZero)")
System.print("5.isPositive: %(5.isPositive)")
System.print("(-3).isNegative: %((-3).isNegative)")
System.print("42.isFinite: %(42.isFinite)")
System.print("(1/0).isFinite: %((1/0).isFinite)")
System.print("4.isEven: %(4.isEven)")
System.print("3.isOdd: %(3.isOdd)")
System.print("5.isBetween(1, 10): %(5.isBetween(1, 10))")
System.print("\n--- Math Functions ---")
System.print("100.log10: %(100.log10)")
System.print("0.sinh: %(0.sinh)")
System.print("0.cosh: %(0.cosh)")
System.print("0.tanh: %(0.tanh)")
System.print("\n--- Angle Conversion ---")
var pi = Num.pi
System.print("pi.toDegrees: %(pi.toDegrees)")
System.print("180.toRadians: %(180.toRadians)")
System.print("\n--- Base Conversion ---")
System.print("255.toHex: %(255.toHex)")
System.print("10.toBinary: %(10.toBinary)")
System.print("8.toOctal: %(8.toOctal)")
System.print("255.toBase(16): %(255.toBase(16))")
System.print("100.toBase(36): %(100.toBase(36))")
System.print("\n--- Character Conversion ---")
System.print("65.toChar: %(65.toChar)")
System.print("97.toChar: %(97.toChar)")
System.print("\n--- Formatting ---")
System.print("3.14159.format(2): %(3.14159.format(2))")
System.print("42.format(3): %(42.format(3))")
System.print("(-1.5).format(1): %((-1.5).format(1))")
System.print("\n--- Integer Operations ---")
System.print("12.gcd(8): %(12.gcd(8))")
System.print("4.lcm(6): %(4.lcm(6))")
System.print("123.digits: %(123.digits)")
System.print("0.digits: %(0.digits)")
+167
View File
@@ -0,0 +1,167 @@
// retoor <retoor@molodetz.nl>
import "pathlib" for Path
System.print("=== Pathlib Module Demo ===\n")
System.print("--- Path Construction ---")
var p = Path.new("/home/user/documents/report.tar.gz")
System.print("Path: %(p)")
System.print("Name: %(p.name)")
System.print("Stem: %(p.stem)")
System.print("Suffix: %(p.suffix)")
System.print("Suffixes: %(p.suffixes)")
System.print("Parts: %(p.parts)")
System.print("\n--- Parent Navigation ---")
System.print("Parent: %(p.parent)")
System.print("Parents:")
for (ancestor in p.parents) {
System.print(" %(ancestor)")
}
System.print("\n--- Path Properties ---")
System.print("Root: %(p.root)")
System.print("Anchor: %(p.anchor)")
System.print("Is absolute: %(p.isAbsolute)")
var rel = Path.new("relative/path.txt")
System.print("%(rel) is absolute: %(rel.isAbsolute)")
System.print("\n--- Join Operator (/) ---")
var base = Path.new("/home/user")
var config = base / ".config" / "myapp" / "settings.json"
System.print("%(base) / .config / myapp / settings.json = %(config)")
System.print("\n--- joinpath ---")
var multi = Path.new("/opt").joinpath(["local", "bin", "wren_cli"])
System.print("Joined: %(multi)")
System.print("\n--- withName / withStem / withSuffix ---")
var orig = Path.new("/data/archive.tar.gz")
System.print("Original: %(orig)")
System.print("withName(\"backup.zip\"): %(orig.withName("backup.zip"))")
System.print("withStem(\"snapshot\"): %(orig.withStem("snapshot"))")
System.print("withSuffix(\".bak\"): %(orig.withSuffix(".bak"))")
System.print("\n--- relativeTo ---")
var full = Path.new("/home/user/projects/wren/src/main.c")
var project = Path.new("/home/user/projects/wren")
System.print("%(full) relative to %(project) = %(full.relativeTo(project))")
System.print("\n--- Glob Matching ---")
var file = Path.new("/tmp/notes.txt")
System.print("%(file.name) matches *.txt: %(file.match("*.txt"))")
System.print("%(file.name) matches *.md: %(file.match("*.md"))")
System.print("%(file.name) matches note?: %(file.match("note?"))")
System.print("%(file.name) matches n*s.txt: %(file.match("n*s.txt"))")
System.print("\n--- Home and CWD ---")
System.print("Home: %(Path.home)")
System.print("CWD: %(Path.cwd)")
System.print("\n--- Expand User ---")
var tilde = Path.new("~/.bashrc")
System.print("%(tilde) -> %(tilde.expanduser())")
System.print("\n--- Equality ---")
var a = Path.new("/tmp/test")
var b = Path.new("/tmp/test")
var c = Path.new("/tmp/other")
System.print("%(a) == %(b): %(a == b)")
System.print("%(a) == %(c): %(a == c)")
System.print("%(a) != %(c): %(a != c)")
System.print("\n--- Filesystem Operations ---")
var testDir = Path.new("/tmp/wren_pathlib_demo")
if (testDir.exists()) testDir.rmtree()
testDir.mkdir(true)
System.print("Created: %(testDir)")
System.print("Exists: %(testDir.exists())")
System.print("Is dir: %(testDir.isDir())")
var testFile = testDir / "hello.txt"
testFile.writeText("Hello from pathlib!")
System.print("Wrote: %(testFile)")
System.print("Content: %(testFile.readText())")
System.print("Is file: %(testFile.isFile())")
System.print("\n--- Stat ---")
var s = testFile.stat()
System.print("Size: %(s.size) bytes")
System.print("\n--- Touch ---")
var marker = testDir / "marker"
marker.touch()
System.print("Touched: %(marker) (exists: %(marker.exists()))")
System.print("\n--- Copy ---")
var copy = testDir / "hello_copy.txt"
testFile.copyfile(copy)
System.print("Copied to: %(copy)")
System.print("Copy content: %(copy.readText())")
System.print("\n--- Rename ---")
var renamed = testFile.rename(testDir / "greeting.txt")
System.print("Renamed to: %(renamed)")
System.print("Old exists: %(testFile.exists())")
System.print("New content: %(renamed.readText())")
System.print("\n--- Resolve ---")
var resolved = Path.new(".").resolve()
System.print("Resolved '.': %(resolved)")
System.print("\n--- Same File ---")
System.print("Same file: %(renamed.samefile(renamed))")
System.print("\n--- Owner and Group ---")
System.print("Owner: %(renamed.owner())")
System.print("Group: %(renamed.group())")
System.print("\n--- Mkdir with Parents ---")
var deep = testDir / "a" / "b" / "c"
deep.mkdir(true)
System.print("Created: %(deep)")
System.print("Exists: %(deep.exists())")
System.print("\n--- Iterdir ---")
(testDir / "file1.txt").writeText("one")
(testDir / "file2.txt").writeText("two")
var entries = testDir.iterdir()
System.print("Entries in %(testDir.name):")
for (entry in entries) {
var kind = entry.isDir() ? "dir" : "file"
System.print(" %(entry.name) (%(kind))")
}
System.print("\n--- Glob ---")
var txtFiles = testDir.glob("*.txt")
System.print("Text files in %(testDir.name):")
for (f in txtFiles) {
System.print(" %(f.name)")
}
System.print("\n--- Recursive Glob ---")
(testDir / "a" / "nested.txt").writeText("nested")
(testDir / "a" / "b" / "deep.txt").writeText("deep")
var allTxt = testDir.rglob("*.txt")
System.print("All text files (recursive):")
for (f in allTxt) {
System.print(" %(f.relativeTo(testDir))")
}
System.print("\n--- Walk ---")
System.print("Directory tree:")
for (entry in testDir.walk()) {
var dir = entry[0]
var dirs = entry[1]
var files = entry[2]
var indent = dir == testDir ? "" : " "
System.print("%(indent)%(dir.relativeTo(testDir))/ (%(dirs.count) dirs, %(files.count) files)")
}
System.print("\n--- Cleanup ---")
testDir.rmtree()
System.print("Cleaned up: %(testDir) (exists: %(testDir.exists()))")
System.print("\n=== Demo Complete ===")
+63
View File
@@ -0,0 +1,63 @@
// retoor <retoor@molodetz.nl>
System.print("=== String Methods Demo ===\n")
System.print("--- Case Conversion ---")
var text = "Hello World"
System.print("Original: %(text)")
System.print("lower: %(text.lower)")
System.print("upper: %(text.upper)")
System.print("capitalize: %("hello world".capitalize)")
System.print("title: %("hello world".title)")
System.print("swapCase: %(text.swapCase)")
System.print("\n--- Character Testing ---")
System.print("\"hello\".isLower: %("hello".isLower)")
System.print("\"HELLO\".isUpper: %("HELLO".isUpper)")
System.print("\"12345\".isDigit: %("12345".isDigit)")
System.print("\"hello\".isAlpha: %("hello".isAlpha)")
System.print("\"hello1\".isAlphaNumeric: %("hello1".isAlphaNumeric)")
System.print("\" \".isSpace: %(" ".isSpace)")
System.print("\"hello\".isAscii: %("hello".isAscii)")
System.print("\n--- Search ---")
var sentence = "hello world hello"
System.print("Text: %(sentence)")
System.print("lastIndexOf(\"hello\"): %(sentence.lastIndexOf("hello"))")
System.print("lastIndexOf(\"hello\", 11): %(sentence.lastIndexOf("hello", 11))")
System.print("\n--- Transformation ---")
System.print("\"hello\".reverse: %("hello".reverse)")
System.print("\"hi\".center(10, \"-\"): %("hi".center(10, "-"))")
System.print("\"42\".lpad(5, \"0\"): %("42".lpad(5, "0"))")
System.print("\"hi\".rpad(5, \".\"): %("hi".rpad(5, "."))")
System.print("\"42\".zfill(5): %("42".zfill(5))")
System.print("\"-42\".zfill(6): %("-42".zfill(6))")
System.print("\n--- Prefix/Suffix ---")
System.print("removePrefix(\"Hello\"): %("HelloWorld".removePrefix("Hello"))")
System.print("removeSuffix(\"World\"): %("HelloWorld".removeSuffix("World"))")
System.print("\n--- Comparison ---")
System.print("\"apple\" < \"banana\": %("apple" < "banana")")
System.print("\"banana\" > \"apple\": %("banana" > "apple")")
System.print("\"abc\" <= \"abc\": %("abc" <= "abc")")
System.print("\"abc\" >= \"abc\": %("abc" >= "abc")")
System.print("\"abc\" < \"abcd\": %("abc" < "abcd")")
System.print("\"abcd\" > \"abc\": %("abcd" > "abc")")
System.print("\"Z\" < \"a\": %("Z" < "a")")
var fruits = ["cherry", "apple", "banana"]
System.print("Sorted: %(fruits.sort {|a, b| a < b})")
System.print("\n--- Splitting ---")
var lines = "line1\nline2\nline3".splitLines
System.print("splitLines: %(lines)")
var chars = "abc".chars
System.print("chars: %(chars)")
System.print("\n--- Conversion ---")
System.print("\"42\".toNum: %("42".toNum)")
System.print("\"3.14\".toNum: %("3.14".toNum)")
System.print("\"abc\".toNum: %("abc".toNum)")
+60
View File
@@ -0,0 +1,60 @@
// retoor <retoor@molodetz.nl>
import "tempfile" for TempFile, NamedTemporaryFile, TemporaryDirectory
import "pathlib" for Path
System.print("=== TempFile Module Demo ===\n")
System.print("--- Utility Functions ---")
System.print("Temp directory: %(TempFile.gettempdir())")
System.print("Temp prefix: %(TempFile.gettempprefix())")
System.print("\n--- mktemp (name only, no file created) ---")
var name = TempFile.mktemp(".txt", "demo_")
System.print("Generated name: %(name)")
System.print("File exists: %(Path.new(name).exists())")
System.print("\n--- mkstemp (creates file atomically) ---")
var path = TempFile.mkstemp(".dat", "demo_")
System.print("Created file: %(path)")
System.print("File exists: %(Path.new(path).exists())")
Path.new(path).unlink()
System.print("\n--- mkdtemp (creates directory) ---")
var dir = TempFile.mkdtemp("_work", "demo_")
System.print("Created directory: %(dir)")
System.print("Is directory: %(Path.new(dir).isDir())")
Path.new(dir).rmdir()
System.print("\n--- NamedTemporaryFile ---")
var tmp = NamedTemporaryFile.new(".txt", "demo_")
System.print("Temp file: %(tmp.name)")
tmp.write("Hello from tempfile module!")
System.print("Content: %(tmp.read())")
System.print("Auto-delete: %(tmp.delete)")
tmp.close()
System.print("Deleted after close: %(!(Path.new(tmp.name).exists()))")
System.print("\n--- NamedTemporaryFile.use (context manager) ---")
NamedTemporaryFile.new(".log").use {|f|
f.write("Log entry: operation completed")
System.print("Inside use block: %(f.read())")
}
System.print("Automatically cleaned up after use block")
System.print("\n--- TemporaryDirectory ---")
var tmpDir = TemporaryDirectory.new("_session", "demo_")
System.print("Temp dir: %(tmpDir.name)")
System.print("Is directory: %(tmpDir.path.isDir())")
tmpDir.cleanup()
System.print("Deleted after cleanup: %(!(Path.new(tmpDir.name).exists()))")
System.print("\n--- TemporaryDirectory.use (context manager) ---")
TemporaryDirectory.new().use {|d|
System.print("Working in: %(d.name)")
Path.new(d.name + "/data.txt").writeText("temporary data")
System.print("Created file inside temp dir")
}
System.print("Automatically cleaned up with all contents")
System.print("\n=== Done ===")