static int cmd_endremapblock(const char *args) { int ret = ERR_BLOCK_TOO_LARGE; unsigned int i, x; struct block *block; (void)args; block = block_alloc(); if (!block) goto ret; fill_block_header(block); block_append(block, current_layer); block_append(block, (unsigned char)pair_lists[REMAP_LIST].len); for (i = 0; i < pair_lists[REMAP_LIST].len; i++) { x = pair_lists[REMAP_LIST].list[i]; block_append(block, (unsigned char)(x >> 8)); block_append(block, (unsigned char)(x & 0xff)); } block->bytes[0] = block->len; block_list_append(block); free(block); pair_list_clear(REMAP_LIST); block_type = BLOCK_NONE; ret = 0; ret: return ret; }
static void fill_block_header(struct block *block) { /* placeholder for size */ block_append(block, 0); /* flags */ block_append(block, (unsigned char)( block_type | (current_select << 3) | ((current_scanset != 0) << 6) | ((current_keyboard_id != 0) << 7))); if (current_scanset) block_append(block, current_scanset); if (current_keyboard_id) { block_append(block, current_keyboard_id & 0xff); block_append(block, (current_keyboard_id >> 8) & 0xff); } ret: return; }
static int cmd_endmacroblock(const char *args) { int ret = ERR_BLOCK_TOO_LARGE; unsigned int i, j, x; struct block *block; (void)args; block = block_alloc(); if (!block) goto ret; fill_block_header(block); block_append(block, (unsigned char)macro_list_len); for (i = 0; i < macro_list_len; i++) { block_append(block, macro_list[i].hid_code); block_append(block, macro_list[i].desired_meta); block_append(block, macro_list[i].matched_meta); block_append(block, macro_list[i].press_flags); block_append(block, macro_list[i].release_flags); for (j = 0; j < macro_list[i].commands.len; j++) { x = macro_list[i].commands.list[j]; block_append(block, (unsigned char)(x >> 8)); block_append(block, (unsigned char)(x & 0xff)); } } block->bytes[0] = block->len; block_list_append(block); free(block); macro_list_clear(); block_type = BLOCK_NONE; ret = 0; ret: return ret; }
// Expands call instructions into a calling sequence static int expand_call_arglist(struct locfile* locations, block* b) { int errors = 0; block ret = gen_noop(); for (inst* curr; (curr = block_take(b));) { if (opcode_describe(curr->op)->flags & OP_HAS_BINDING) { if (!curr->bound_by) { locfile_locate(locations, curr->source, "error: %s is not defined", curr->symbol); errors++; // don't process this instruction if it's not well-defined ret = BLOCK(ret, inst_block(curr)); continue; } } block prelude = gen_noop(); if (curr->op == CALL_JQ) { int actual_args = 0, desired_args = 0; // We expand the argument list as a series of instructions switch (curr->bound_by->op) { default: assert(0 && "Unknown function type"); break; case CLOSURE_CREATE: case CLOSURE_PARAM: { block callargs = gen_noop(); for (inst* i; (i = block_take(&curr->arglist));) { assert(opcode_describe(i->op)->flags & OP_IS_CALL_PSEUDO); block b = inst_block(i); switch (i->op) { default: assert(0 && "Unknown type of parameter"); break; case CLOSURE_REF: block_append(&callargs, b); break; case CLOSURE_CREATE: block_append(&prelude, b); block_append(&callargs, gen_op_bound(CLOSURE_REF, b)); break; } actual_args++; } curr->imm.intval = actual_args; curr->arglist = callargs; if (curr->bound_by->op == CLOSURE_CREATE) { for (inst* i = curr->bound_by->arglist.first; i; i = i->next) { assert(i->op == CLOSURE_PARAM); desired_args++; } } break; } case CLOSURE_CREATE_C: { for (inst* i; (i = block_take(&curr->arglist)); ) { assert(i->op == CLOSURE_CREATE); // FIXME block body = i->subfn; i->subfn = gen_noop(); inst_free(i); // arguments should be pushed in reverse order, prepend them to prelude errors += expand_call_arglist(locations, &body); prelude = BLOCK(gen_subexp(body), prelude); actual_args++; } assert(curr->op == CALL_JQ); curr->op = CALL_BUILTIN; curr->imm.intval = actual_args + 1 /* include the implicit input in arg count */; assert(curr->bound_by->op == CLOSURE_CREATE_C); desired_args = curr->bound_by->imm.cfunc->nargs - 1; assert(!curr->arglist.first); break; } } if (actual_args != desired_args) { locfile_locate(locations, curr->source, "error: %s arguments to %s (expected %d but got %d)", actual_args > desired_args ? "too many" : "too few", curr->symbol, desired_args, actual_args); errors++; } } ret = BLOCK(ret, prelude, inst_block(curr)); } *b = ret; return errors; }
block block_join(block a, block b) { block c = a; block_append(&c, b); return c; }