native "<target>" "<path>" in a package's package.ludic; the compiler records the libraries of every package a program imports and writes them into the IR (; ludic-native:), so ludicc -o, ludic build, ludic test and ludic bundle all link one list. macOS: an rpath to the package and to Contents/Frameworks, where ludic bundle copies and signs each library and drops the build machine's rpath. Windows: the import library, the .dll copied beside the exe (--natives-out for the bundle). tools/native/lib.sh builds from a pinned, checksummed source with clang on both machines; ludic.nativeecho is the worked example; the shim rules are in packages/README.md. Linked at build time rather than dlopen (docs/PACKAGES.md says why). Reseeded. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
69 lines
2.2 KiB
Text
69 lines
2.2 KiB
Text
# echo.ludic - the state, its verbs and its facts. The slices crossing to C are made once and
|
|
# reused (L7), and what C recorded is drained into the queue after each call returns.
|
|
export const ECHO_CAP: int = 64
|
|
|
|
export property EchoFact {
|
|
index: int = 0 # which element went over
|
|
value: float = 0.0
|
|
}
|
|
|
|
export state EchoState {
|
|
ec_xs: []float = null
|
|
ec_n: int = 0
|
|
ec_kinds: []int = null
|
|
ec_values: []float = null
|
|
ec_facts: Queue<EchoFact> = null
|
|
}
|
|
|
|
function ec_ready(echo_st: mut EchoState) -> void {
|
|
if echo_st.ec_xs == null { echo_st.ec_xs = floats(ECHO_CAP) }
|
|
if echo_st.ec_kinds == null { echo_st.ec_kinds = words(ECHO_CAP) }
|
|
if echo_st.ec_values == null { echo_st.ec_values = floats(ECHO_CAP) }
|
|
}
|
|
|
|
# what went over, oldest first
|
|
export function echo_facts(echo_st: mut EchoState) -> Queue<EchoFact> {
|
|
if echo_st.ec_facts == null { echo_st.ec_facts = queue_new("nativeecho.facts") }
|
|
return echo_st.ec_facts
|
|
}
|
|
|
|
# put a value in the next slot; false when the slice is full
|
|
export function echo_put(echo_st: mut EchoState, x: float) -> bool {
|
|
ec_ready(echo_st)
|
|
if echo_st.ec_n >= ECHO_CAP { return false }
|
|
echo_st.ec_xs[echo_st.ec_n] = x
|
|
echo_st.ec_n += 1
|
|
return true
|
|
}
|
|
|
|
export function echo_clear(echo_st: mut EchoState) -> void { echo_st.ec_n = 0 }
|
|
|
|
# the sum of what was put, worked out in C
|
|
export function echo_sum(echo_st: mut EchoState) -> float {
|
|
ec_ready(echo_st)
|
|
return ne_sum(echo_st.ec_xs, echo_st.ec_n)
|
|
}
|
|
|
|
# C walks the values and records each one over `over`; the records come back as facts
|
|
export function echo_scan(echo_st: mut EchoState, over: float) -> int {
|
|
ec_ready(echo_st)
|
|
let hits = ne_scan(echo_st.ec_xs, echo_st.ec_n, over)
|
|
ec_drain(echo_st)
|
|
return hits
|
|
}
|
|
|
|
function ec_drain(echo_st: mut EchoState) -> void {
|
|
let n = ne_drain(echo_st.ec_kinds, echo_st.ec_values, ECHO_CAP)
|
|
for i in 0 .. n {
|
|
let f = new EchoFact
|
|
f.index = echo_st.ec_kinds[i]
|
|
f.value = echo_st.ec_values[i]
|
|
q_push(echo_facts(echo_st), f)
|
|
}
|
|
}
|
|
|
|
# how many records C had to drop because nobody drained them
|
|
export function echo_lost() -> int { return ne_lost_count() }
|
|
|
|
# a 64-bit value there and back
|
|
export function echo_twice(x: long) -> long { return ne_twice(x) }
|