:(scenarios run_mu_scenario)
:(scenario keyboard_in_scenario)
scenario keyboard-in-scenario [
assume-console [
type [abc]
]
run [
1:character, console:address, 2:boolean <- read-key console:address
3:character, console:address, 4:boolean <- read-key console:address
5:character, console:address, 6:boolean <- read-key console:address
7:character, console:address, 8:boolean, 9:boolean <- read-key console:address
]
memory-should-contain [
1 <- 97
2 <- 1
3 <- 98
4 <- 1
5 <- 99
6 <- 1
7 <- 0
8 <- 1
9 <- 1
]
]
:(before "End Scenario Globals")
const long long int CONSOLE = Next_predefined_global_for_scenarios++;
:(before "End Special Scenario Variable Names(r)")
Name[r]["console"] = CONSOLE;
:(before "End is_special_name Cases")
if (s == "console") return true;
:(before "End Primitive Recipe Declarations")
ASSUME_CONSOLE,
:(before "End Primitive Recipe Numbers")
Recipe_ordinal["assume-console"] = ASSUME_CONSOLE;
:(before "End Primitive Recipe Implementations")
case ASSUME_CONSOLE: {
istringstream in("[" + current_instruction().ingredients.at(0).name + "]");
recipe r = slurp_recipe(in);
long long int num_events = count_events(r);
long long int size = num_events*size_of_event() + 1;
ensure_space(size);
long long int event_data_address = Current_routine->alloc;
Memory[event_data_address] = num_events;
++Current_routine->alloc;
for (long long int i = 0; i < SIZE(r.steps); ++i) {
const instruction& curr = r.steps.at(i);
if (curr.name == "left-click") {
Memory[Current_routine->alloc] = 2;
Memory[Current_routine->alloc+1+0] = TB_KEY_MOUSE_LEFT;
Memory[Current_routine->alloc+1+1] = to_integer(curr.ingredients.at(0).name);
Memory[Current_routine->alloc+1+2] = to_integer(curr.ingredients.at(1).name);
Current_routine->alloc += size_of_event();
}
else if (curr.name == "press") {
Memory[Current_routine->alloc] = 1;
Memory[Current_routine->alloc+1] = to_integer(curr.ingredients.at(0).name);
Current_routine->alloc += size_of_event();
}
else {
assert(curr.name == "type");
const string& contents = curr.ingredients.at(0).name;
const char* raw_contents = contents.c_str();
long long int num_keyboard_events = unicode_length(contents);
long long int curr = 0;
for (long long int i = 0; i < num_keyboard_events; ++i) {
Memory[Current_routine->alloc] = 0;
uint32_t curr_character;
assert(curr < SIZE(contents));
tb_utf8_char_to_unicode(&curr_character, &raw_contents[curr]);
Memory[Current_routine->alloc+1] = curr_character;
curr += tb_utf8_char_length(raw_contents[curr]);
Current_routine->alloc += size_of_event();
}
}
}
assert(Current_routine->alloc == event_data_address+size);
ensure_space(size_of_events());
Memory[CONSOLE] = Current_routine->alloc;
Current_routine->alloc += size_of_events();
Memory[Memory[CONSOLE]+1] = event_data_address;
break;
}
:(scenario events_in_scenario)
scenario events-in-scenario [
assume-console [
type [abc]
left-click 0, 1
press 65515
type [d]
]
run [
1:event <- read-event console:address
5:event <- read-event console:address
9:event <- read-event console:address
13:event <- read-event console:address
17:event <- read-event console:address
21:event <- read-event console:address
]
memory-should-contain [
1 <- 0
2 <- 97
3 <- 0
4 <- 0
5 <- 0
6 <- 98
7 <- 0
8 <- 0
9 <- 0
10 <- 99
11 <- 0
12 <- 0
13 <- 2
14 <- 65513
15 <- 0
16 <- 1
17 <- 1
18 <- 65515
19 <- 0
20 <- 0
21 <- 0
22 <- 100
23 <- 0
24 <- 0
25 <- 0
]
]
:(before "End Primitive Recipe Declarations")
REPLACE_IN_CONSOLE,
:(before "End Primitive Recipe Numbers")
Recipe_ordinal["replace-in-console"] = REPLACE_IN_CONSOLE;
:(before "End Primitive Recipe Implementations")
case REPLACE_IN_CONSOLE: {
assert(scalar(ingredients.at(0)));
if (!Memory[CONSOLE]) {
raise << "console not initialized\n" << end();
break;
}
long long int console_data = Memory[Memory[CONSOLE]+1];
long long int size = Memory[console_data];
for (long long int i = 0, curr = console_data+1; i < size; ++i, curr+=size_of_event()) {
if (Memory[curr] != 0) continue;
if (Memory[curr+1] != ingredients.at(0).at(0)) continue;
for (long long int n = 0; n < size_of_event(); ++n)
Memory[curr+n] = ingredients.at(1).at(n);
}
break;
}
:(code)
long long int count_events(const recipe& r) {
long long int result = 0;
for (long long int i = 0; i < SIZE(r.steps); ++i) {
const instruction& curr = r.steps.at(i);
if (curr.name == "type")
result += unicode_length(curr.ingredients.at(0).name);
else
result++;
}
return result;
}
long long int size_of_event() {
static long long int result = 0;
if (result) return result;
vector<type_ordinal> type;
type.push_back(Type_ordinal["event"]);
result = size_of(type);
return result;
}
long long int size_of_events() {
static long long int result = 0;
if (result) return result;
vector<type_ordinal> type;
assert(Type_ordinal["console"]);
type.push_back(Type_ordinal["console"]);
result = size_of(type);
return result;
}