about summary refs log tree commit diff stats
path: root/084console.mu
blob: 68fd5413436bbb8929565d638a1eba345cee1b5a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# Wrappers around interaction primitives that take a potentially fake object
# and are thus easier to test.

exclusive-container event [
  text:character
  keycode:number  # keys on keyboard without a unicode representation
  touch:touch-event  # mouse, track ball, etc.
  resize:resize-event
  # update the assume-console handler if you add more variants
]

container touch-event [
  type:number
  row:number
  column:number
]

container resize-event [
  width:number
  height:number
]

container console [
  index:number
  data:address:array:event
]

recipe new-fake-console events:address:array:event -> result:address:console [
  local-scope
  load-ingredients
  result:address:console <- new console:type
  buf:address:address:array:event <- get-address *result, data:offset
  *buf <- copy events
  idx:address:number <- get-address *result, index:offset
  *idx <- copy 0
]

recipe read-event console:address:console -> result:event, console:address:console, found?:boolean, quit?:boolean [
  local-scope
  load-ingredients
  {
    break-unless console
    idx:address:number <- get-address *console, index:offset
    buf:address:array:event <- get *console, data:offset
    {
      max:number <- length *buf
      done?:boolean <- greater-or-equal *idx, max
      break-unless done?
      dummy:address:event <- new event:type
      reply *dummy, console/same-as-ingredient:0, 1/found, 1/quit
    }
    result <- index *buf, *idx
    *idx <- add *idx, 1
    reply result, console/same-as-ingredient:0, 1/found, 0/quit
  }
  switch  # real event source is infrequent; avoid polling it too much
  result:event, found?:boolean <- check-for-interaction
  reply result, console/same-as-ingredient:0, found?, 0/quit
]

# variant of read-event for just keyboard events. Discards everything that
# isn't unicode, so no arrow keys, page-up/page-down, etc. But you still get
# newlines, tabs, ctrl-d..
recipe read-key console:address:console -> result:character, console:address:console, found?:boolean, quit?:boolean [
  local-scope
  load-ingredients
  x:event, console, found?:boolean, quit?:boolean <- read-event console
  reply-if quit?, 0, console/same-as-ingredient:0, found?, quit?
  reply-unless found?, 0, console/same-as-ingredient:0, found?, quit?
  c:address:character <- maybe-convert x, text:variant
  reply-unless c, 0, console/same-as-ingredient:0, 0/found, 0/quit
  reply *c, console/same-as-ingredient:0, 1/found, 0/quit
]

recipe send-keys-to-channel console:address:console, chan:address:channel, screen:address:screen -> console:address:console, chan:address:channel, screen:address:screen [
  local-scope
  load-ingredients
  {
    c:character, console, found?:boolean, quit?:boolean <- read-key console
    loop-unless found?
    break-if quit?
    assert c, [invalid event, expected text]
    screen <- print screen, c
    chan <- write chan, c
    loop
  }
]

recipe wait-for-event console:address:console -> console:address:console [
  local-scope
  load-ingredients
  {
    _, console, found?:boolean <- read-event console
    loop-unless found?
  }
]

# use this helper to skip rendering if there's lots of other events queued up
recipe has-more-events? console:address:console -> result:boolean [
  local-scope
  load-ingredients
  {
    break-unless console
    # fake consoles should be plenty fast; never skip
    reply 0/false
  }
  result <- interactions-left?
]
pan class="p">.name]; } string_tree* p = property(x, "space"); if (!p || !p->atom) raise << "/space property should have exactly one (non-negative integer) value\n" << end(); int n = to_integer(p->value); assert(n >= 0); recipe_ordinal surrounding_recipe = lookup_surrounding_recipe(default_recipe, n); if (surrounding_recipe == -1) return -1; set<recipe_ordinal> done; vector<recipe_ordinal> path; return lookup_name(x, surrounding_recipe, done, path); } // If the recipe we need to lookup this name in doesn't have names done yet, // recursively call transform_names on it. int lookup_name(const reagent& x, const recipe_ordinal r, set<recipe_ordinal>& done, vector<recipe_ordinal>& path) { if (!Name[r].empty()) return Name[r][x.name]; if (contains_key(done, r)) { raise << "can't compute address of '" << to_string(x) << "' because\n" << end(); for (int i = 1; i < SIZE(path); ++i) { raise << path.at(i-1) << " requires computing names of " << path.at(i) << '\n' << end(); } raise << path.at(SIZE(path)-1) << " requires computing names of " << r << "..ad infinitum\n" << end(); return -1; } done.insert(r); path.push_back(r); transform_names(r); // Not passing 'done' through. Might this somehow cause an infinite loop? assert(!Name[r].empty()); return Name[r][x.name]; } recipe_ordinal lookup_surrounding_recipe(const recipe_ordinal r, int n) { if (n == 0) return r; if (!contains_key(Surrounding_space, r)) { raise << "don't know surrounding recipe of '" << get(Recipe, r).name << "'\n" << end(); return -1; } assert(contains_key(Surrounding_space, r)); return lookup_surrounding_recipe(get(Surrounding_space, r), n-1); } //: weaken use-before-set detection just a tad :(replace{} "bool already_transformed(const reagent& r, const map<string, int>& names)") bool already_transformed(const reagent& r, const map<string, int>& names) { if (has_property(r, "space")) { string_tree* p = property(r, "space"); if (!p || !p->atom) { raise << "/space property should have exactly one (non-negative integer) value in '" << r.original_string << "'\n" << end(); return false; } if (p->value != "0") return true; } return contains_key(names, r.name); } :(scenario missing_surrounding_space) % Hide_errors = true; def f [ local-scope x:num/space:1 <- copy 34 ] +error: don't know surrounding recipe of 'f' +error: f: can't find a place to store 'x' //: extra test for try_reclaim_locals() from previous layers :(scenario local_scope_ignores_nonlocal_spaces) def new-scope [ local-scope x:&:num <- new number:type *x:&:num <- copy 34 return default-space:space ] def use-scope [ local-scope outer:space/names:new-scope <- next-ingredient 0:space/names:new-scope <- copy outer:space return *x:&:num/space:1 ] def main [ 1:space/raw <- new-scope 2:num/raw <- use-scope 1:space/raw ] +mem: storing 34 in location 2