127 lines
4.4 KiB
Text
127 lines
4.4 KiB
Text
# view.ludic — L11: a view is the one bridge between a program and its UI templates. The
|
|
# program says what a template may read and what it may do, and nothing else crosses:
|
|
#
|
|
# view Yard {
|
|
# purse = hm_purse # a field: the global's own type
|
|
# spots: int = yard_spots() # any expression, with its type said
|
|
# function placed(hf: int) -> int { return yard_placed(hf) } # a query a template may ask
|
|
# on buy(hf: int) { yard_buy(hf) } # an event a template may send
|
|
# }
|
|
#
|
|
# gives view_yard() -> UiView, whose model() is a Value object of every field (a record is an
|
|
# object of its fields, a list and a registry a list) and whose call(name, args) runs a query or
|
|
# an event by name with its arguments out of a Value list. Everything generated belongs to the
|
|
# view's own file, so it is in the view's module and exported only when the view is.
|
|
var g_vw_name: []pointer = new []pointer
|
|
var g_vw_node: []Node = new []Node # view_<name>(), which carries the file, line and export
|
|
var g_vw_fields: [][]Node = new [][]Node # the getters, one per field
|
|
var g_vw_fnames: [][]pointer = new [][]pointer
|
|
var g_vw_calls: [][]Node = new [][]Node # the queries and the events
|
|
var g_vw_cnames: [][]pointer = new [][]pointer
|
|
var g_vw_helpers: []pointer = new []pointer # conversion helpers already written, program-wide
|
|
var g_vw_hdr: []int = new []int # 0.S: where state parameters go (after the name)
|
|
var g_vw_nps: []int = new []int # how many the view declares
|
|
var g_vw_ps: [][]Node = new [][]Node # and which
|
|
|
|
function vw_prefix(name: pointer) -> pointer { return `view_{reg_lower(name)}_` }
|
|
|
|
# view NAME [(states)] { members } - 0.S: the states the view's getters, queries and events read,
|
|
# supplied by the runtime when a template asks
|
|
function parse_view() -> void {
|
|
pi += 1
|
|
let name = eat_id()
|
|
push(g_vw_hdr, toks[pi - 1].end)
|
|
let vps = parse_entry_params()
|
|
push(g_vw_nps, len(vps))
|
|
push(g_vw_ps, vps)
|
|
let vi = len(g_vw_name)
|
|
let px = vw_prefix(name)
|
|
g_uses_value = true
|
|
let fields = new []Node
|
|
let fnames = new []pointer
|
|
let calls = new []Node
|
|
let cnames = new []pointer
|
|
skipnl()
|
|
eat_op("{")
|
|
while true {
|
|
skipnl()
|
|
if is_op("}") { break }
|
|
if is_id("function") or is_id("on") {
|
|
let ev = is_id("on")
|
|
if ev { toks[pi].text = "function" }
|
|
let f = parse_fn()
|
|
state_params_onto(f, vps)
|
|
f.vw = vi
|
|
push(cnames, f.s)
|
|
if ev { f.s = px + "on_" + f.s } else { f.s = px + f.s }
|
|
push(calls, f)
|
|
push(prog, f)
|
|
continue
|
|
}
|
|
push(fnames, eat_id())
|
|
let getter = vw_field(px, fnames[len(fnames) - 1])
|
|
state_params_onto(getter, vps)
|
|
getter.vw = vi
|
|
push(fields, getter)
|
|
}
|
|
eat_op("}")
|
|
let head = vw_head(name, px)
|
|
push(g_vw_name, name)
|
|
push(g_vw_node, head)
|
|
push(g_vw_fields, fields)
|
|
push(g_vw_fnames, fnames)
|
|
push(g_vw_calls, calls)
|
|
push(g_vw_cnames, cnames)
|
|
}
|
|
# one field: NAME [: TYPE] = EXPR, as a getter function whose type the finish fills in if unsaid
|
|
function vw_field(px: pointer, fname: pointer) -> Node {
|
|
let g = node(N_FN)
|
|
g.s = px + "get_" + fname
|
|
g.ty = null
|
|
if is_op(":") {
|
|
pi += 1
|
|
g.ty = ptype()
|
|
}
|
|
if not is_op("=") { perr(`view field {fname}: say what it is - {fname} = some_global`) }
|
|
pi += 1
|
|
let r = node(S_RETURN)
|
|
r.a = expr()
|
|
let body = node(N_BLOCK)
|
|
push(body.kids, r)
|
|
g.a = body
|
|
push(prog, g)
|
|
return g
|
|
}
|
|
# view_<name>() -> UiView, written now so it takes the export the declaration is under
|
|
function vw_head(name: pointer, px: pointer) -> Node {
|
|
let src = `function view_{reg_lower(name)}() -> UiView {{\n let v = new UiView\n v.name = "{name}"\n v.model = fn {px}model\n v.call = fn {px}call\n return v\n}}\n`
|
|
let at = len(prog)
|
|
vw_parse(src, g_parse_file, toks[pi].line, 0)
|
|
return prog[at]
|
|
}
|
|
# parse generated source into the program, as if it were written in `file` at `line`
|
|
function vw_parse(src: pointer, file: pointer, line: int, vis: int) -> void {
|
|
let saved_toks = toks
|
|
let saved_pi = pi
|
|
let saved_file = g_parse_file
|
|
let saved_parsing = g_parsing
|
|
g_parse_file = file
|
|
g_parsing = true
|
|
lex_at(src, line)
|
|
pi = 0
|
|
let at = len(prog)
|
|
while true {
|
|
skipnl()
|
|
if toks[pi].kind == TK_EOF { break }
|
|
parse_one_decl()
|
|
}
|
|
var k = at
|
|
while k < len(prog) {
|
|
prog[k].vis = vis
|
|
k += 1
|
|
}
|
|
toks = saved_toks
|
|
pi = saved_pi
|
|
g_parse_file = saved_file
|
|
g_parsing = saved_parsing
|
|
}
|