size_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print, const char **compl_str) { // scan backwards to find start of "a.b.c" chain const char *org_str = str; const char *top = str + len; for (const char *s = top; --s >= str;) { if (!(unichar_isalpha(*s) || unichar_isdigit(*s) || *s == '_' || *s == '.')) { ++s; str = s; break; } } size_t nqstr = QSTR_TOTAL(); // begin search in outer global dict which is accessed from __main__ mp_obj_t obj = MP_OBJ_FROM_PTR(&mp_module___main__); mp_obj_t dest[2]; for (;;) { // get next word in string to complete const char *s_start = str; while (str < top && *str != '.') { ++str; } size_t s_len = str - s_start; if (str < top) { // a complete word, lookup in current object qstr q = qstr_find_strn(s_start, s_len); if (q == MP_QSTR_NULL) { // lookup will fail return 0; } mp_load_method_maybe(obj, q, dest); obj = dest[0]; // attribute, method, or MP_OBJ_NULL if nothing found if (obj == MP_OBJ_NULL) { // lookup failed return 0; } // skip '.' to move to next word ++str; } else { // end of string, do completion on this partial name // look for matches const char *match_str = NULL; size_t match_len = 0; qstr q_first = 0, q_last; for (qstr q = 1; q < nqstr; ++q) { size_t d_len; const char *d_str = (const char*)qstr_data(q, &d_len); if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) { mp_load_method_maybe(obj, q, dest); if (dest[0] != MP_OBJ_NULL) { if (match_str == NULL) { match_str = d_str; match_len = d_len; } else { // search for longest common prefix of match_str and d_str // (assumes these strings are null-terminated) for (size_t j = s_len; j <= match_len && j <= d_len; ++j) { if (match_str[j] != d_str[j]) { match_len = j; break; } } } if (q_first == 0) { q_first = q; } q_last = q; } } } // nothing found if (q_first == 0) { // If there're no better alternatives, and if it's first word // in the line, try to complete "import". if (s_start == org_str) { static const char import_str[] = "import "; if (memcmp(s_start, import_str, s_len) == 0) { *compl_str = import_str + s_len; return sizeof(import_str) - 1 - s_len; } } return 0; } // 1 match found, or multiple matches with a common prefix if (q_first == q_last || match_len > s_len) { *compl_str = match_str + s_len; return match_len - s_len; } // multiple matches found, print them out #define WORD_SLOT_LEN (16) #define MAX_LINE_LEN (4 * WORD_SLOT_LEN) int line_len = MAX_LINE_LEN; // force a newline for first word for (qstr q = q_first; q <= q_last; ++q) { size_t d_len; const char *d_str = (const char*)qstr_data(q, &d_len); if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) { mp_load_method_maybe(obj, q, dest); if (dest[0] != MP_OBJ_NULL) { int gap = (line_len + WORD_SLOT_LEN - 1) / WORD_SLOT_LEN * WORD_SLOT_LEN - line_len; if (gap < 2) { gap += WORD_SLOT_LEN; } if (line_len + gap + d_len <= MAX_LINE_LEN) { // TODO optimise printing of gap? for (int j = 0; j < gap; ++j) { mp_print_str(print, " "); } mp_print_str(print, d_str); line_len += gap + d_len; } else { mp_printf(print, "\n%s", d_str); line_len = d_len; } } } } mp_print_str(print, "\n"); return (size_t)(-1); // indicate many matches } } }
STATIC void emit_inline_xtensa_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_args, mp_parse_node_t *pn_args) { size_t op_len; const char *op_str = (const char*)qstr_data(op, &op_len); if (n_args == 0) { if (op == MP_QSTR_ret_n) { asm_xtensa_op_ret_n(&emit->as); } else { goto unknown_op; } } else if (n_args == 1) { if (op == MP_QSTR_callx0) { uint r0 = get_arg_reg(emit, op_str, pn_args[0]); asm_xtensa_op_callx0(&emit->as, r0); } else if (op == MP_QSTR_j) { int label = get_arg_label(emit, op_str, pn_args[0]); asm_xtensa_j_label(&emit->as, label); } else if (op == MP_QSTR_jx) { uint r0 = get_arg_reg(emit, op_str, pn_args[0]); asm_xtensa_op_jx(&emit->as, r0); } else { goto unknown_op; } } else if (n_args == 2) { uint r0 = get_arg_reg(emit, op_str, pn_args[0]); if (op == MP_QSTR_beqz) { int label = get_arg_label(emit, op_str, pn_args[1]); asm_xtensa_bccz_reg_label(&emit->as, ASM_XTENSA_CCZ_EQ, r0, label); } else if (op == MP_QSTR_bnez) { int label = get_arg_label(emit, op_str, pn_args[1]); asm_xtensa_bccz_reg_label(&emit->as, ASM_XTENSA_CCZ_NE, r0, label); } else if (op == MP_QSTR_mov || op == MP_QSTR_mov_n) { // we emit mov.n for both "mov" and "mov_n" opcodes uint r1 = get_arg_reg(emit, op_str, pn_args[1]); asm_xtensa_op_mov_n(&emit->as, r0, r1); } else if (op == MP_QSTR_movi) { // for convenience we emit l32r if the integer doesn't fit in movi uint32_t imm = get_arg_i(emit, op_str, pn_args[1], 0, 0); asm_xtensa_mov_reg_i32(&emit->as, r0, imm); } else { goto unknown_op; } } else if (n_args == 3) { // search table for 3 arg instructions for (uint i = 0; i < MP_ARRAY_SIZE(opcode_table_3arg); i++) { const opcode_table_3arg_t *o = &opcode_table_3arg[i]; if (op == o->name) { uint r0 = get_arg_reg(emit, op_str, pn_args[0]); uint r1 = get_arg_reg(emit, op_str, pn_args[1]); if (o->type == RRR) { uint r2 = get_arg_reg(emit, op_str, pn_args[2]); asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, o->a0, o->a1, r0, r1, r2)); } else if (o->type == RRI8_B) { int label = get_arg_label(emit, op_str, pn_args[2]); asm_xtensa_bcc_reg_reg_label(&emit->as, o->a0, r0, r1, label); } else { int shift, min, max; if ((o->type & 0xf0) == 0) { shift = 0; min = -128; max = 127; } else { shift = (o->type & 0xf0) >> 5; min = 0; max = 0xff << shift; } uint32_t imm = get_arg_i(emit, op_str, pn_args[2], min, max); asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRI8(o->a0, o->a1, r1, r0, (imm >> shift) & 0xff)); } return; } } goto unknown_op; } else {