merge lang/foundations into lang/native-jolt (seeds regenerated)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
commit
b44b88e00e
10 changed files with 51152 additions and 50365 deletions
|
|
@ -14,6 +14,7 @@ export property UiBackend {
|
|||
clip: fn(float, float, float, float) -> void = null
|
||||
unclip: fn() -> void = null
|
||||
scale: fn() -> float = null # screen pixels per design pixel
|
||||
pointer_scale: fn() -> float = null # screen pixels per unit of Input.mouse_x/y (2 on Retina)
|
||||
translate: fn(string) -> string = null # the program's language, for every text a template shows
|
||||
sound: fn(string) -> void = null # a control was used: "click", or its sound="..."
|
||||
read: fn(string) -> string = null # a template file's text (else Fs.read_text)
|
||||
|
|
|
|||
|
|
@ -37,8 +37,9 @@ function in_read(ui_st: mut UiState) -> void {
|
|||
ui_st.in_last = ui_st.in_now
|
||||
let i = new UiInput
|
||||
if ui_st.ui_be != null and ui_st.ui_be.input {
|
||||
i.x = float(Input.mouse_x())
|
||||
i.y = float(Input.mouse_y())
|
||||
let ps = in_pointer_scale(ui_st)
|
||||
i.x = float(Input.mouse_x()) * ps
|
||||
i.y = float(Input.mouse_y()) * ps
|
||||
i.down = Input.mouse_down(0)
|
||||
i.down_right = Input.mouse_down(1)
|
||||
i.down_middle = Input.mouse_down(2)
|
||||
|
|
@ -60,6 +61,12 @@ function in_read(ui_st: mut UiState) -> void {
|
|||
in_repeat(ui_st, i)
|
||||
ui_st.in_now = i
|
||||
}
|
||||
# the platform reports the pointer in window points and a renderer draws in pixels: on Retina the
|
||||
# layout is twice the pointer's numbers, and every hit landed up and to the left of the cursor
|
||||
function in_pointer_scale(ui_st: UiState) -> float {
|
||||
if ui_st.ui_be.pointer_scale == null { return 1.0 }
|
||||
return ui_st.ui_be.pointer_scale()
|
||||
}
|
||||
function in_any_key() -> int {
|
||||
for k in 8 .. 167 {
|
||||
if Input.key_pressed(k) { return k }
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ function r3u_make() -> UiBackend {
|
|||
b.clip = fn r3u_clip
|
||||
b.unclip = fn r3u_unclip
|
||||
b.scale = fn r3u_scale
|
||||
b.pointer_scale = fn r3u_pointer_scale
|
||||
b.now = fn r3u_now
|
||||
return b
|
||||
}
|
||||
|
|
@ -40,6 +41,7 @@ export function ui_atlas(ui_st: mut UiState, prefix: string, tex: int, cols: int
|
|||
}
|
||||
function r3u_now() -> float { return float(Time.now_us() / 1000) / 1000.0 }
|
||||
function r3u_scale(ui_st: UiState) -> float { return float(gl_height()) / 1080.0 * ui_st.r3u_user }
|
||||
function r3u_pointer_scale() -> float { return float(gl_pixel_scale()) }
|
||||
function r3u_r(c: int) -> float { return float((c / 65536) % 256) / 255.0 }
|
||||
function r3u_g(c: int) -> float { return float((c / 256) % 256) / 255.0 }
|
||||
function r3u_b(c: int) -> float { return float(c % 256) / 255.0 }
|
||||
|
|
|
|||
|
|
@ -7,15 +7,19 @@
|
|||
var ck_ro: []int = new []int # parallel to ck_names: 1 for a read-only state
|
||||
var ck_alias: []Node = new []Node # parallel to ck_names: the global a local's reference came from
|
||||
var ck_ro_st: []pointer = new []pointer # parallel to ck_names: the state that makes a local read-only
|
||||
var ck_from_st: []pointer = new []pointer # parallel to ck_names: the state a local's reference came out of, mut or not
|
||||
|
||||
function ck_set_ro(ro: bool) -> void {
|
||||
let k = ck_top - 1
|
||||
while len(ck_ro) < len(ck_names) { push(ck_ro, 0) }
|
||||
while len(ck_alias) < len(ck_names) { push(ck_alias, null) }
|
||||
while len(ck_ro_st) < len(ck_names) { push(ck_ro_st, null) }
|
||||
while len(ck_from_st) < len(ck_names) { push(ck_from_st, null) }
|
||||
if ro { ck_ro[k] = 1 } else { ck_ro[k] = 0 }
|
||||
ck_alias[k] = null
|
||||
ck_ro_st[k] = null
|
||||
ck_from_st[k] = null
|
||||
if is_state_ty(ck_tys[k]) { ck_from_st[k] = ck_tys[k] }
|
||||
if ro { ck_ro_st[k] = ck_tys[k] }
|
||||
}
|
||||
# the local just bound is read-only for the same state as local `li`
|
||||
|
|
@ -42,6 +46,7 @@ function ck_let_from(e: Node, ty: pointer) -> void {
|
|||
if li >= 0 and li < k {
|
||||
if ck_is_ro(li) { ck_ro_like(li) }
|
||||
if li < len(ck_alias) { ck_alias[k] = ck_alias[li] }
|
||||
if li < len(ck_from_st) and k < len(ck_from_st) { ck_from_st[k] = ck_from_st[li] }
|
||||
return
|
||||
}
|
||||
if li >= 0 { return }
|
||||
|
|
@ -75,6 +80,7 @@ function ck_write_check(t: Node, what: pointer) -> void {
|
|||
if li >= 0 {
|
||||
mg_local_write(ck_tys[li]) # 0.S2 --migrate-prune: a state changed here
|
||||
if li < len(ck_ro_st) { mg_local_write(ck_ro_st[li]) }
|
||||
if li < len(ck_from_st) and ck_from_st[li] != null { mg_local_write(ck_from_st[li]) } # through a local holding part of it
|
||||
if li < len(ck_alias) and ck_alias[li] != null {
|
||||
let ag = ck_alias[li]
|
||||
mg_write(t, ag)
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
var g_migrate: bool = false
|
||||
var g_mg_runtime: bool = false # --migrate-runtime: the runtime's own vars too
|
||||
var g_mg_prune: bool = false # --migrate-prune: a declared state nothing uses is taken out
|
||||
var g_mg_tighten: bool = false # --migrate-tighten: and a `mut` state nothing down the chain writes is read-only
|
||||
var g_ma_node: []Node = new []Node # each state argument a call passes (an E_ID), its call, its state
|
||||
var g_ma_call: []int = new []int
|
||||
var g_ma_state: []int = new []int
|
||||
|
|
@ -602,7 +603,7 @@ function mg_norm_line(line: pointer) -> pointer {
|
|||
}
|
||||
if len(w) < 2 { return line }
|
||||
let k = w[0]
|
||||
if (k == "VAR") or (k == "REF") or (k == "INS") or (k == "LET") or (k == "CLOSE") or (k == "DELITEM") { w[1] = mg_norm(w[1]) }
|
||||
if (k == "VAR") or (k == "REF") or (k == "INS") or (k == "LET") or (k == "CLOSE") or (k == "DELITEM") or (k == "DELMUT") { w[1] = mg_norm(w[1]) }
|
||||
if (k == "?") { w[1] = mg_norm(w[1]) }
|
||||
if (k == "VAR") and len(w) > 5 { w[5] = mg_norm_key(w[5]) }
|
||||
if (k == "STATE") and len(w) > 6 {
|
||||
|
|
@ -787,6 +788,7 @@ function mg_prune_unit(u: int, n: Node) -> void {
|
|||
let p = n.kids[i]
|
||||
if p.kind == N_PARAM and is_state_ty(p.ty) and p.pos >= 0 and p.file != null {
|
||||
if not has_sub(g_mu_need[u], `,{itoa(mg_state_named(p.ty))},`) { mg_emit(`DELITEM {p.file} {itoa(p.pos)}`, "") }
|
||||
else if g_mg_tighten and p.uns == 1 and p.pos2 >= 0 and not has_sub(g_mu_mut[u], `,{itoa(mg_state_named(p.ty))},`) { mg_emit(`DELMUT {p.file} {itoa(p.pos2)}`, "") }
|
||||
}
|
||||
i += 1
|
||||
}
|
||||
|
|
|
|||
50733
selfhost/ludicc.seed.ll
50733
selfhost/ludicc.seed.ll
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -162,6 +162,10 @@ entry {
|
|||
g_allow_globals = true
|
||||
}
|
||||
else if a == "--migrate-prune" { g_mg_prune = true } # 0.S2: state parameters nothing uses go too
|
||||
else if a == "--migrate-tighten" { # 0.R5: and `mut` goes where nothing down the chain writes
|
||||
g_mg_prune = true
|
||||
g_mg_tighten = true
|
||||
}
|
||||
else if a == "--migrate-runtime" { g_mg_runtime = true } # 0.S: the toolchain's own programs keep module-level vars # parse, type, module and port checks; nothing emitted
|
||||
else if a == "--coverage" { g_coverage = true }
|
||||
else if a == "--target" { ai += 1; if ai < arg_count() { target = arg(ai) } }
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ program Ludic {
|
|||
print(" compile and run the project's tests (-v: every test's line)")
|
||||
print(" deps [file] [--graph|--dot|--writes|--uses MOD|--check F|--baseline F]")
|
||||
print(" the module graph as the compiler sees it, and how tangled it is")
|
||||
print(" migrate state [file] [--prune] [--runtime] module-level vars into states, passed as parameters (0.S); --prune drops states nothing uses")
|
||||
print(" migrate state [file] [--prune] [--runtime] module-level vars into states, passed as parameters (0.S); --prune drops states nothing uses, --tighten also mut nothing writes")
|
||||
print(" clean remove build/")
|
||||
print("")
|
||||
print("packages:")
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@
|
|||
# migrate.ludic, `ludicc --migrate-state <plan>`); this applies them to the source, file by file,
|
||||
# and prints what it could not decide.
|
||||
#
|
||||
# ludic migrate state [file|dir...] [--prune] [--runtime] [--unsafe] [--dry-run]
|
||||
# ludic migrate state [file|dir...] [--prune | --tighten] [--runtime] [--unsafe] [--dry-run]
|
||||
# --tighten prunes, and takes `mut` off every state parameter nothing down the chain writes
|
||||
# --root DIR lets the edits reach DIR too (a package the program imports) without running its programs
|
||||
# --prune also takes out every state parameter (and the argument that fills it) a function no
|
||||
# longer uses, nor anything it calls
|
||||
#
|
||||
|
|
@ -172,7 +174,7 @@ function mgx_mine(path: pointer) -> bool {
|
|||
}
|
||||
function cmd_migrate() -> int {
|
||||
if arg_count() < 3 or not (arg(2) == "state") {
|
||||
err("usage: ludic migrate state [file|dir...] [--prune] [--runtime] [--unsafe] [--dry-run]\n")
|
||||
err("usage: ludic migrate state [file|dir...] [--prune | --tighten] [--runtime] [--unsafe] [--dry-run]\n")
|
||||
return 2
|
||||
}
|
||||
let srcs = new []pointer
|
||||
|
|
@ -190,6 +192,12 @@ function cmd_migrate() -> int {
|
|||
else if a == "--unsafe" { g_unsafe_build = true }
|
||||
else if a == "--dry-run" { dry = true }
|
||||
else if a == "--prune" { prune = " --migrate-prune" }
|
||||
else if a == "--tighten" { prune = " --migrate-tighten" }
|
||||
else if a == "--root" and ai + 1 < arg_count() {
|
||||
# a directory the edits may reach without its programs being run (a package the program imports)
|
||||
ai += 1
|
||||
push(mgx_roots, mgx_dir(arg(ai)))
|
||||
}
|
||||
else if a[0] == '-' { err(`ludic migrate: unknown option {a}\n`); return 2 }
|
||||
else if shq(`test -d {sh_single(a)}`) {
|
||||
let found = test_files_in(a)
|
||||
|
|
@ -282,8 +290,10 @@ function mgx_apply(lines: []pointer, dry: bool) -> int {
|
|||
let w = dp_words(lines[i])
|
||||
if len(w) == 0 { continue }
|
||||
var at = ""
|
||||
if (w[0] == "VAR") or (w[0] == "REF") or (w[0] == "INS") or (w[0] == "CLOSE") or (w[0] == "LET") or (w[0] == "DELITEM") { at = w[1] }
|
||||
if (w[0] == "VAR") or (w[0] == "REF") or (w[0] == "INS") or (w[0] == "CLOSE") or (w[0] == "LET") or (w[0] == "DELITEM") or (w[0] == "DELMUT") { at = w[1] }
|
||||
if (w[0] == "STATE") and len(w) > 2 { at = w[2] }
|
||||
# a package's own `mut` is tightened in its own checkout; a program's run leaves it be
|
||||
if (w[0] == "DELMUT") and len(at) > 0 and mgx_roots != null and not mgx_mine(at) { continue }
|
||||
if len(at) > 0 and mgx_roots != null and not mgx_mine(at) {
|
||||
var seen = false
|
||||
for k in 0 .. len(foreign) { if foreign[k] == at { seen = true } }
|
||||
|
|
@ -323,6 +333,11 @@ function mgx_apply(lines: []pointer, dry: bool) -> int {
|
|||
mgx_edit(w[1], s_to_int(w[2]), s_to_int(w[3]), mgx_unesc(w[4]))
|
||||
} else if (w[0] == "INS") and len(w) == 4 {
|
||||
mgx_edit(w[1], s_to_int(w[2]), 0, mgx_unesc(w[3]))
|
||||
} else if (w[0] == "DELMUT") and len(w) == 3 {
|
||||
# a state parameter nothing down the chain writes: its `mut ` goes (only where the text says so)
|
||||
let t = mgx_text_of(w[1])
|
||||
let p = s_to_int(w[2])
|
||||
if t[p] == 'm' and t[p + 1] == 'u' and t[p + 2] == 't' and t[p + 3] == ' ' { mgx_edit(w[1], p, 4, "") }
|
||||
} else if (w[0] == "DELITEM") and len(w) == 3 {
|
||||
# a parameter or an argument taken out, with the comma that goes with it
|
||||
let t = mgx_text_of(w[1])
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue