:(before "End initialize_transform_rewrite_literal_string_to_text()")
recipes_taking_literal_strings.insert("assume-console");
:(scenarios run_mu_scenario)
:(scenario keyboard_in_scenario)
scenario keyboard-in-scenario [
assume-console [
type [abc]
]
run [
1:char, console, 2:bool <- read-key console
3:char, console, 4:bool <- read-key console
5:char, console, 6:bool <- read-key console
7:char, console, 8:bool, 9:bool <- read-key console
]
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")
extern const 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")
put(Recipe_ordinal, "assume-console", ASSUME_CONSOLE);
:(before "End Primitive Recipe Checks")
case ASSUME_CONSOLE: {
break;
}
:(before "End Primitive Recipe Implementations")
case ASSUME_CONSOLE: {
istringstream in("[" + current_instruction().ingredients.at(0).name + "]");
recipe r;
slurp_body(in, r);
int num_events = count_events(r);
int size = 2 + num_events*size_of_event();
int event_data_address = allocate(size);
put(Memory, event_data_address+1, num_events);
int curr_address = event_data_address + 2;
for (int i = 0; i < SIZE(r.steps); ++i) {
const instruction& inst = r.steps.at(i);
if (inst.name == "left-click") {
trace(9999, "mem") << "storing 'left-click' event starting at " << Current_routine->alloc << end();
put(Memory, curr_address, 2);
put(Memory, curr_address+1+0, TB_KEY_MOUSE_LEFT);
put(Memory, curr_address+1+1, to_integer(inst.ingredients.at(0).name));
put(Memory, curr_address+1+2, to_integer(inst.ingredients.at(1).name));
curr_address += size_of_event();
}
else if (inst.name == "press") {
trace(9999, "mem") << "storing 'press' event starting at " << curr_address << end();
string key = inst.ingredients.at(0).name;
if (is_integer(key))
put(Memory, curr_address+1, to_integer(key));
else if (contains_key(Key, key))
put(Memory, curr_address+1, Key[key]);
else
raise << "assume-console: can't press '" << key << "'\n" << end();
if (get_or_insert(Memory, curr_address+1) < 256)
put(Memory, curr_address, 0);
else {
put(Memory, curr_address, 1);
}
curr_address += size_of_event();
}
else {
assert(inst.name == "type");
trace(9999, "mem") << "storing 'type' event starting at " << curr_address << end();
const string& contents = inst.ingredients.at(0).name;
const char* raw_contents = contents.c_str();
int num_keyboard_events = unicode_length(contents);
int curr = 0;
for (int i = 0; i < num_keyboard_events; ++i) {
trace(9999, "mem") << "storing 'text' tag at " << curr_address << end();
put(Memory, curr_address, 0);
uint32_t curr_character;
assert(curr < SIZE(contents));
tb_utf8_char_to_unicode(&curr_character, &raw_contents[curr]);
trace(9999, "mem") << "storing character " << curr_character << " at " << curr_address+1 << end();
put(Memory, curr_address+1, curr_character);
curr += tb_utf8_char_length(raw_contents[curr]);
curr_address += size_of_event();
}
}
}
assert(curr_address == event_data_address+size);
int console_address = allocate(size_of_console());
trace(9999, "mem") << "storing console in " << console_address << end();
put(Memory, CONSOLE, console_address);
trace(9999, "mem") << "storing console data in " << console_address+1+1 << end();
put(Memory, console_address+1+1, event_data_address);
put(Memory, event_data_address, 1);
put(Memory, console_address, 1);
break;
}
:(before "End Globals")
map<string, int> Key;
:(before "End One-time Setup")
initialize_key_names();
:(code)
void initialize_key_names() {
Key["F1"] = TB_KEY_F1;
Key["F2"] = TB_KEY_F2;
Key["F3"] = TB_KEY_F3;
Key["F4"] = TB_KEY_F4;
Key["F5"] = TB_KEY_F5;
Key["F6"] = TB_KEY_F6;
Key["F7"] = TB_KEY_F7;
Key["F8"] = TB_KEY_F8;
Key["F9"] = TB_KEY_F9;
Key["F10"] = TB_KEY_F10;
Key["F11"] = TB_KEY_F11;
Key["F12"] = TB_KEY_F12;
Key["insert"] = TB_KEY_INSERT;
Key["delete"] = TB_KEY_DELETE;
Key["home"] = TB_KEY_HOME;
Key["end"] = TB_KEY_END;
Key["page-up"] = TB_KEY_PGUP;
Key["page-down"] = TB_KEY_PGDN;
Key["up-arrow"] = TB_KEY_ARROW_UP;
Key["down-arrow"] = TB_KEY_ARROW_DOWN;
Key["left-arrow"] = TB_KEY_ARROW_LEFT;
Key["right-arrow"] = TB_KEY_ARROW_RIGHT;
Key["ctrl-a"] = TB_KEY_CTRL_A;
Key["ctrl-b"] = TB_KEY_CTRL_B;
Key["ctrl-c"] = TB_KEY_CTRL_C;
Key["ctrl-d"] = TB_KEY_CTRL_D;
Key["ctrl-e"] = TB_KEY_CTRL_E;
Key["ctrl-f"] = TB_KEY_CTRL_F;
Key["ctrl-g"] = TB_KEY_CTRL_G;
Key["backspace"] = TB_KEY_BACKSPACE;
Key["ctrl-h"] = TB_KEY_CTRL_H;
Key["tab"] = TB_KEY_TAB;
Key["ctrl-i"] = TB_KEY_CTRL_I;
Key["ctrl-j"] = TB_KEY_CTRL_J;
Key["enter"] = TB_KEY_NEWLINE;
Key["ctrl-k"] = TB_KEY_CTRL_K;
Key["ctrl-l"] = TB_KEY_CTRL_L;
Key["ctrl-m"] = TB_KEY_CTRL_M;
Key["ctrl-n"] = TB_KEY_CTRL_N;
Key["ctrl-o"] = TB_KEY_CTRL_O;
Key["ctrl-p"] = TB_KEY_CTRL_P;
Key["ctrl-q"] = TB_KEY_CTRL_Q;
Key["ctrl-r"] = TB_KEY_CTRL_R;
Key["ctrl-s"] = TB_KEY_CTRL_S;
Key["ctrl-t"] = TB_KEY_CTRL_T;
Key["ctrl-u"] = TB_KEY_CTRL_U;
Key["ctrl-v"] = TB_KEY_CTRL_V;
Key["ctrl-w"] = TB_KEY_CTRL_W;
Key["ctrl-x"] = TB_KEY_CTRL_X;
Key["ctrl-y"] = TB_KEY_CTRL_Y;
Key["ctrl-z"] = TB_KEY_CTRL_Z;
Key["escape"] = TB_KEY_ESC;
}
:(after "Begin check_or_set_invalid_types(r)")
if (is_scenario(caller))
initialize_special_name(r);
:(code)
bool is_scenario(const recipe& caller) {
return starts_with(caller.name, "scenario_");
}
void initialize_special_name(reagent& r) {
if (r.type) return;
if (r.name == "console") r.type = new_type_tree("address:console");
}
:(scenario events_in_scenario)
scenario events-in-scenario [
assume-console [
type [abc]
left-click 0, 1
press up-arrow
type [d]
]
run [
1:event <- read-event console
5:event <- read-event console
9:event <- read-event console
13:event <- read-event console
17:event <- read-event console
21:event <- read-event console
]
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 <- 65517
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")
put(Recipe_ordinal, "replace-in-console", REPLACE_IN_CONSOLE);
:(before "End Primitive Recipe Checks")
case REPLACE_IN_CONSOLE: {
break;
}
:(before "End Primitive Recipe Implementations")
case REPLACE_IN_CONSOLE: {
assert(scalar(ingredients.at(0)));
if (!get_or_insert(Memory, CONSOLE)) {
raise << "console not initialized\n" << end();
break;
}
int console_address = get_or_insert(Memory, CONSOLE);
int console_data = get_or_insert(Memory, console_address+1);
int length = get_or_insert(Memory, console_data);
for (int i = 0, curr = console_data+1; i < length; ++i, curr+=size_of_event()) {
if (get_or_insert(Memory, curr) != 0) continue;
if (get_or_insert(Memory, curr+1) != ingredients.at(0).at(0)) continue;
for (int n = 0; n < size_of_event(); ++n)
put(Memory, curr+n, ingredients.at(1).at(n));
}
break;
}
:(code)
int count_events(const recipe& r) {
int result = 0;
for (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;
}
int size_of_event() {
static int result = 0;
if (result) return result;
type_tree* type = new type_tree("event");
result = size_of(type);
delete type;
return result;
}
int size_of_console() {
static int result = 0;
if (result) return result;
assert(get(Type_ordinal, "console"));
type_tree* type = new type_tree("console");
result = size_of(type)+1;
delete type;
return result;
}