ludic/selfhost/frontend/aliases.ludic

87 lines
2.8 KiB
Text

# aliases.ludic — L6: a namespace method that is a name for a function. Inside a namespace block,
# alias fill_rectangle(x, y, width, height, color) = fill_rect
# makes `Screen.fill_rectangle(...)` a call to `fill_rect`, taking named arguments by those labels
# in the target's parameter order. With no label list the target's own parameter names are the
# labels; an empty one, `alias show() = present`, takes no named arguments. The engine declares
# its namespaces this way in runtime/native/namespaces.ludic, and a package owns an API the same
# way, in its own files - neither needs a line in the compiler.
var g_al_ns: []pointer = new []pointer
var g_al_meth: []pointer = new []pointer
var g_al_target: []pointer = new []pointer
var g_al_labels: []pointer = new []pointer # "a|b|c"; "" for none; null for the target's own
var g_al_file: []pointer = new []pointer # where the alias is declared (the engine's: runtime/native)
function ns_parse_alias(nsname: pointer, is_exp: int) -> void {
pi += 1
let meth = eat_id()
var labels: pointer = null
if is_op("(") {
pi += 1
labels = ""
while not is_op(")") {
if len(labels) > 0 { labels = labels + "|" }
labels = labels + eat_id()
if is_op(",") { pi += 1 }
}
eat_op(")")
}
eat_op("=")
let target = eat_id()
register_namespace(nsname)
if is_exp == 0 { return }
if ns_alias_find(nsname, meth) >= 0 { perr(`{nsname}.{meth} is declared twice`) }
push(g_al_ns, nsname)
push(g_al_meth, meth)
push(g_al_target, target)
push(g_al_labels, labels)
push(g_al_file, g_parse_file)
}
function ns_alias_find(ns: pointer, meth: pointer) -> int {
var i = 0
while i < len(g_al_ns) {
if (g_al_meth[i] == meth) and (g_al_ns[i] == ns) { return i }
i += 1
}
return -1
}
function ns_alias_labels(i: int) -> []pointer {
let out = new []pointer
let ls = g_al_labels[i]
if ls == null {
var d = find_fn(g_al_target[i])
if d == null { d = find_extern(g_al_target[i]) }
if d != null { return param_labels(d) }
return out
}
# 0.S: a target's leading states come first, by their own names (they are supplied, not written)
let t = find_fn(g_al_target[i])
if t != null {
var k = 0
while k < len(t.kids) and t.kids[k].kind == N_PARAM and is_state_ty(t.kids[k].ty) {
push(out, t.kids[k].s)
k += 1
}
}
var a = 0
var j = 0
let n = len(ls)
while j <= n {
if j == n or ls[j] == '|' {
if j > a { push(out, ls[a .. j]) }
a = j + 1
}
j += 1
}
return out
}
function emit_alias_call(i: int, e: Node) -> Val {
state_inject(e, find_fn(g_al_target[i])) # 0.S: the target's states, supplied
call_mixed_to_named(e, ns_alias_labels(i))
reorder_named(e, ns_alias_labels(i))
let id = node(E_ID)
id.s = g_al_target[i]
id.file = e.file
id.line = e.line
e.a = id
return emit_call(e)
}