feat: add await syntax for direct async function calls and new generator/phonebook apps
Add compiler support for calling async functions directly with `await fn(args)` syntax, automatically translating to `await fn.call(args)`. Introduce `create_merge` Makefile target for merging Wren source files. Include new `apps/generator.wren` source code generator using OpenRouter API, `apps/phonebook.wren` CLI phonebook with SQLite backend, and `apps/minitut.md` Wren tutorial reference. Update `example/await_demo.wren` with parameterized async functions, nested awaits, and expression usage. Fix JSON parsing in `example/openrouter_demo.wren` to strip markdown code fences. Document new await syntax in `manual/api/scheduler.html`.
This commit is contained in:
Vendored
+231
-12
@@ -3,20 +3,239 @@
|
||||
import "scheduler" for Scheduler, Future
|
||||
import "timer" for Timer
|
||||
|
||||
System.print("=== Await Demo ===\n")
|
||||
System.print("=== Async/Await Demo ===\n")
|
||||
|
||||
System.print("--- Basic Await ---")
|
||||
await Timer.sleep(1)
|
||||
System.print("Timer completed")
|
||||
System.print("Timer completed after 1ms")
|
||||
|
||||
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")
|
||||
var getValue = async { 42 }
|
||||
var result = await getValue()
|
||||
System.print("Async block returned: %(result)")
|
||||
|
||||
System.print("\n--- Async With Result ---")
|
||||
var task = async { "computed value" }
|
||||
var result = await task
|
||||
System.print("Result: %(result)")
|
||||
System.print("\n--- Parameterized Async Functions ---")
|
||||
var double = async { |x| x * 2 }
|
||||
var add = async { |a, b| a + b }
|
||||
var multiply = async { |a, b| a * b }
|
||||
|
||||
System.print("double(21) = %(await double(21))")
|
||||
System.print("add(3, 4) = %(await add(3, 4))")
|
||||
System.print("multiply(6, 7) = %(await multiply(6, 7))")
|
||||
|
||||
System.print("\n--- Nested Awaits ---")
|
||||
var addTen = async { |x| x + 10 }
|
||||
System.print("addTen(double(5)) = %(await addTen(await double(5)))")
|
||||
System.print("double(double(double(2))) = %(await double(await double(await double(2))))")
|
||||
|
||||
System.print("\n--- Await in Expressions ---")
|
||||
System.print("1 + double(5) = %(1 + await double(5))")
|
||||
System.print("double(3) + double(4) = %(await double(3) + await double(4))")
|
||||
|
||||
System.print("\n--- Await in Conditions ---")
|
||||
var isPositive = async { |x| x > 0 }
|
||||
if (await isPositive(5)) System.print("5 is positive: true")
|
||||
var ternaryResult = await isPositive(10) ? "yes" : "no"
|
||||
System.print("10 is positive? %(ternaryResult)")
|
||||
|
||||
System.print("\n--- Await in Loops ---")
|
||||
var squares = []
|
||||
for (i in 1..5) {
|
||||
var sq = async { |x| x * x }
|
||||
squares.add(await sq(i))
|
||||
}
|
||||
System.print("Squares of 1-5: %(squares)")
|
||||
|
||||
System.print("\n=== Class-Based Async Patterns ===\n")
|
||||
|
||||
System.print("--- Static Async Getters ---")
|
||||
|
||||
class Calculator {
|
||||
static add { async { |a, b| a + b } }
|
||||
static multiply { async { |a, b| a * b } }
|
||||
static square { async { |x| x * x } }
|
||||
static pi { async { 3.14159 } }
|
||||
|
||||
static compute(a, b) {
|
||||
var addFn = Calculator.add
|
||||
var multiplyFn = Calculator.multiply
|
||||
var sum = await addFn(a, b)
|
||||
var product = await multiplyFn(a, b)
|
||||
return {"sum": sum, "product": product}
|
||||
}
|
||||
}
|
||||
|
||||
var addFn = Calculator.add
|
||||
var multiplyFn = Calculator.multiply
|
||||
var squareFn = Calculator.square
|
||||
var piFn = Calculator.pi
|
||||
|
||||
System.print("add(3, 4) = %(await addFn(3, 4))")
|
||||
System.print("multiply(5, 6) = %(await multiplyFn(5, 6))")
|
||||
System.print("square(8) = %(await squareFn(8))")
|
||||
System.print("pi() = %(await piFn())")
|
||||
|
||||
var results = Calculator.compute(5, 3)
|
||||
System.print("Calculator.compute(5, 3) = %(results)")
|
||||
|
||||
System.print("\n--- Instance Methods with Async ---")
|
||||
|
||||
class Counter {
|
||||
construct new(start) {
|
||||
_value = start
|
||||
}
|
||||
|
||||
value { _value }
|
||||
|
||||
add(n) {
|
||||
var op = async { |x|
|
||||
_value = _value + x
|
||||
return _value
|
||||
}
|
||||
return await op(n)
|
||||
}
|
||||
|
||||
subtract(n) {
|
||||
var op = async { |x|
|
||||
_value = _value - x
|
||||
return _value
|
||||
}
|
||||
return await op(n)
|
||||
}
|
||||
|
||||
reset() {
|
||||
var op = async {
|
||||
_value = 0
|
||||
return _value
|
||||
}
|
||||
return await op()
|
||||
}
|
||||
}
|
||||
|
||||
var counter = Counter.new(100)
|
||||
System.print("Initial value: %(counter.value)")
|
||||
System.print("After add(25): %(counter.add(25))")
|
||||
System.print("After subtract(10): %(counter.subtract(10))")
|
||||
System.print("After reset(): %(counter.reset())")
|
||||
System.print("Final value: %(counter.value)")
|
||||
|
||||
System.print("\n--- Mock API Service ---")
|
||||
|
||||
class UserApi {
|
||||
static fetchUser { async { |id|
|
||||
Timer.sleep(1)
|
||||
return {"id": id, "name": "User%(id)", "email": "user%(id)@example.com"}
|
||||
}}
|
||||
|
||||
static fetchPosts { async { |userId|
|
||||
Timer.sleep(1)
|
||||
return [
|
||||
{"id": 1, "userId": userId, "title": "First Post"},
|
||||
{"id": 2, "userId": userId, "title": "Second Post"}
|
||||
]
|
||||
}}
|
||||
|
||||
static getUserWithPosts(userId) {
|
||||
var fetchUser = UserApi.fetchUser
|
||||
var fetchPosts = UserApi.fetchPosts
|
||||
var user = await fetchUser(userId)
|
||||
var posts = await fetchPosts(userId)
|
||||
|
||||
user["posts"] = posts
|
||||
return user
|
||||
}
|
||||
}
|
||||
|
||||
var fetchUser = UserApi.fetchUser
|
||||
var user = await fetchUser(42)
|
||||
System.print("User: %(user["name"]) <%(user["email"])>")
|
||||
|
||||
var fetchPosts = UserApi.fetchPosts
|
||||
var posts = await fetchPosts(42)
|
||||
System.print("Posts count: %(posts.count)")
|
||||
|
||||
var fullUser = UserApi.getUserWithPosts(123)
|
||||
System.print("Full user: %(fullUser["name"]) with %(fullUser["posts"].count) posts")
|
||||
|
||||
System.print("\n--- Data Pipeline ---")
|
||||
|
||||
class DataPipeline {
|
||||
static parse { async { |csv| csv.split(",") } }
|
||||
static filter { async { |list, predicate|
|
||||
var result = []
|
||||
for (item in list) {
|
||||
if (predicate.call(item)) result.add(item)
|
||||
}
|
||||
return result
|
||||
}}
|
||||
static transform { async { |list, mapper|
|
||||
var result = []
|
||||
for (item in list) {
|
||||
result.add(mapper.call(item))
|
||||
}
|
||||
return result
|
||||
}}
|
||||
static reduce { async { |list, initial, reducer|
|
||||
var acc = initial
|
||||
for (item in list) {
|
||||
acc = reducer.call(acc, item)
|
||||
}
|
||||
return acc
|
||||
}}
|
||||
|
||||
static process(csv) {
|
||||
var parse = DataPipeline.parse
|
||||
var filter = DataPipeline.filter
|
||||
var transform = DataPipeline.transform
|
||||
var reduce = DataPipeline.reduce
|
||||
var items = await parse(csv)
|
||||
var filtered = await filter(items) { |s| s.count > 3 }
|
||||
var lengths = await transform(filtered) { |s| s.count }
|
||||
var total = await reduce(lengths, 0) { |acc, n| acc + n }
|
||||
return total
|
||||
}
|
||||
}
|
||||
|
||||
var data = "one,two,three,four,five,six,seven"
|
||||
|
||||
var parse = DataPipeline.parse
|
||||
var parsed = await parse(data)
|
||||
System.print("Parsed: %(parsed)")
|
||||
|
||||
var filter = DataPipeline.filter
|
||||
var filtered = await filter(parsed) { |s| s.count > 3 }
|
||||
System.print("Filtered (length > 3): %(filtered)")
|
||||
|
||||
var transform = DataPipeline.transform
|
||||
var lengths = await transform(filtered) { |s| s.count }
|
||||
System.print("Lengths: %(lengths)")
|
||||
|
||||
var reduce = DataPipeline.reduce
|
||||
var sum = await reduce(lengths, 0) { |acc, n| acc + n }
|
||||
System.print("Sum of lengths: %(sum)")
|
||||
|
||||
var total = DataPipeline.process("apple,banana,cherry,date,elderberry")
|
||||
System.print("Pipeline result: %(total)")
|
||||
|
||||
System.print("\n--- Parallel Task Execution ---")
|
||||
|
||||
var fetchA = async { |x|
|
||||
Timer.sleep(10)
|
||||
return "A:%(x)"
|
||||
}
|
||||
var fetchB = async { |x|
|
||||
Timer.sleep(10)
|
||||
return "B:%(x)"
|
||||
}
|
||||
var fetchC = async { |x|
|
||||
Timer.sleep(10)
|
||||
return "C:%(x)"
|
||||
}
|
||||
|
||||
var futureA = fetchA.call(1)
|
||||
var futureB = fetchB.call(2)
|
||||
var futureC = fetchC.call(3)
|
||||
|
||||
System.print("Started 3 parallel tasks")
|
||||
System.print("Results: %(await futureA), %(await futureB), %(await futureC)")
|
||||
|
||||
System.print("\n=== Demo Complete ===")
|
||||
|
||||
Vendored
+9
-1
@@ -39,7 +39,15 @@ System.print("Status: %(response.statusCode)")
|
||||
System.print("")
|
||||
|
||||
if (response.ok) {
|
||||
var data = Json.parse(response.body)
|
||||
let text = response.body
|
||||
if(text.startsWith("```")){
|
||||
text = text.trim("```")
|
||||
text = text.trim("json")
|
||||
text = text.trim("\n")
|
||||
|
||||
}
|
||||
System.print(text)
|
||||
var data = Json.parse(text)
|
||||
if (data != null && data["choices"] != null && data["choices"].count > 0) {
|
||||
var message = data["choices"][0]["message"]
|
||||
if (message != null && message["content"] != null) {
|
||||
|
||||
Reference in New Issue
Block a user