diff options
-rw-r--r-- | ChangeLog | 25 | ||||
-rw-r--r-- | lib.c | 26 | ||||
-rw-r--r-- | lib.h | 4 | ||||
-rw-r--r-- | match.c | 189 |
4 files changed, 166 insertions, 78 deletions
@@ -1,3 +1,28 @@ +2011-10-17 Kaz Kylheku <kaz@kylheku.com> + + Task #11425. + + Vertical skip directive moved into function dispatched + via hash table. Test suite passes. + + * lib.c (cptr_s): New symbol variable. + (cptr_equal_op): New static function. + (cptr_equal_op, cptr, cptr_get): New functions. + (cptr_ops): New static structure. + (obj_init): New variable initialized. + + * lib.h (cptr_s, cptr, cptr_get): Declared. + + * match.c (decline_k, same_data_k): New symbol variables. + (v_match_func): New typedef. + (v_skip): New function. + (match_files): Check symbol in v_directive_table and dispatch + the associated function if an entry exists. + Skip directive handling moved to v_skip function. + (syms_init): Initialize new symbol variables. + (dir_tables_init): Enter v_skip into v_directive_table under + skip_s symbol. + 2011-10-16 Kaz Kylheku <kaz@kylheku.com> Quick and dirty port to MinGW. @@ -51,7 +51,7 @@ val packages; val system_package, keyword_package, user_package; val null, t, cons_s, str_s, chr_s, num_s, sym_s, pkg_s, fun_s, vec_s; -val stream_s, hash_s, hash_iter_s, lcons_s, lstr_s, cobj_s; +val stream_s, hash_s, hash_iter_s, lcons_s, lstr_s, cobj_s, cptr_s; val var_s, expr_s, regex_s, chset_s, set_s, cset_s, wild_s, oneplus_s; val nongreedy_s, compiled_regex_s; val zeroplus_s, optional_s, compl_s, compound_s, or_s, and_s, quasi_s; @@ -1872,6 +1872,29 @@ void cobj_print_op(val obj, val out) format(out, lit(": ~p>"), obj->co.handle, nao); } +static val cptr_equal_op(val left, val right) +{ + return (left->co.handle == right->co.handle) ? t : nil; +} + +static struct cobj_ops cptr_ops = { + cptr_equal_op, + cobj_print_op, + cobj_destroy_stub_op, + cobj_mark_op, + cobj_hash_op +}; + +val cptr(mem_t *ptr) +{ + return cobj(ptr, cptr_s, &cptr_ops); +} + +mem_t *cptr_get(val cptr) +{ + return cobj_handle(cptr, cptr_s); +} + val assoc(val list, val key) { while (list) { @@ -2160,6 +2183,7 @@ static void obj_init(void) lcons_s = intern(lit("lcons"), user_package); lstr_s = intern(lit("lstr"), user_package); cobj_s = intern(lit("cobj"), user_package); + cptr_s = intern(lit("cptr"), user_package); var_s = intern(lit("var"), system_package); expr_s = intern(lit("expr"), system_package); regex_s = intern(lit("regex"), system_package); @@ -240,7 +240,7 @@ INLINE val chr(wchar_t ch) extern val keyword_package, system_package, user_package; extern val null, t, cons_s, str_s, chr_s, num_s, sym_s, pkg_s, fun_s, vec_s; -extern val stream_s, hash_s, hash_iter_s, lcons_s, lstr_s, cobj_s; +extern val stream_s, hash_s, hash_iter_s, lcons_s, lstr_s, cobj_s, cptr_s; extern val var_s, expr_s, regex_s, chset_s, set_s, cset_s, wild_s, oneplus_s; extern val nongreedy_s, compiled_regex_s; extern val zeroplus_s, optional_s, compl_s, compound_s, or_s, and_s, quasi_s; @@ -403,6 +403,8 @@ val length_str_le(val str, val len); val cobj(mem_t *handle, val cls_sym, struct cobj_ops *ops); val cobjp(val obj); mem_t *cobj_handle(val cobj, val cls_sym); +val cptr(mem_t *ptr); +mem_t *cptr_get(val cptr); val assoc(val list, val key); val acons(val list, val car, val cdr); val acons_new(val list, val key, val value); @@ -48,6 +48,7 @@ int output_produced; +val decline_k, same_data_k; val mingap_k, maxgap_k, gap_k, mintimes_k, maxtimes_k, times_k; val lines_k, chars_k; val choose_s, longest_k, shortest_k, greedy_k; @@ -1309,9 +1310,100 @@ static match_files_ctx mf_spec_bindings(match_files_ctx c, val spec, } - static val match_files(match_files_ctx a); +typedef val (*v_match_func)(match_files_ctx c, match_files_ctx *cout); + +static val v_skip(match_files_ctx c, match_files_ctx *cout) +{ + val specline = rest(first(c.spec)); + val other_specs = rest(c.spec); + + if (other_specs == nil) { + *cout = c; + return same_data_k; + } + + if (rest(specline) == nil) { + val spec_linenum = first(first(c.spec)); + val first_spec = first(specline); + val args = rest(first_spec); + val max = first(args); + val min = second(args); + cnum cmax = nump(max) ? c_num(max) : 0; + cnum cmin = nump(min) ? c_num(min) : 0; + val greedy = eq(max, greedy_k); + val last_good_result = nil; + val last_good_line = num(0); + + { + cnum reps_max = 0, reps_min = 0; + uw_block_begin(nil, result); + + while (c.data && min && reps_min < cmin) { + c.data = rest(c.data); + c.data_lineno = plus(c.data_lineno, num(1)); + reps_min++; + } + + if (min) { + if (reps_min != cmin) { + debuglf(spec_linenum, lit("skipped only ~a/~a lines to ~a:~a"), + num(reps_min), num(cmin), + first(c.files), c.data_lineno, nao); + uw_block_return(nil, nil); + } + + debuglf(spec_linenum, lit("skipped ~a lines to ~a:~a"), + num(reps_min), first(c.files), + c.data_lineno, nao); + } + + while (greedy || !max || reps_max++ < cmax) { + result = match_files(mf_spec(c, other_specs)); + + if (result) { + if (greedy) { + last_good_result = result; + last_good_line = c.data_lineno; + } else { + debuglf(spec_linenum, lit("skip matched ~a:~a"), first(c.files), + c.data_lineno, nao); + break; + } + } else { + debuglf(spec_linenum, lit("skip didn't match ~a:~a"), + first(c.files), c.data_lineno, nao); + } + + if (!c.data) + break; + + debuglf(spec_linenum, lit("skip didn't match ~a:~a"), first(c.files), + c.data_lineno, nao); + + c.data = rest(c.data); + c.data_lineno = plus(c.data_lineno, num(1)); + } + + uw_block_end; + + if (result) + return result; + if (last_good_result) { + debuglf(spec_linenum, lit("greedy skip matched ~a:~a"), + first(c.files), last_good_line, nao); + return last_good_result; + } + } + + debuglf(spec_linenum, lit("skip failed"), nao); + return nil; + } + + return decline_k; +} + static val match_files(match_files_ctx c) { gc_hint(c.data); @@ -1363,85 +1455,26 @@ repeat_spec_same_data: if (consp(first_spec)) { val sym = first(first_spec); + val entry = gethash(v_directive_table, sym); + if (entry) { + v_match_func vmf = (v_match_func) cptr_get(entry); + match_files_ctx nc; + val result = vmf(c, &nc); - if (sym == skip_s && rest(specline) == nil) { - val args = rest(first_spec); - val max = first(args); - val min = second(args); - cnum cmax = nump(max) ? c_num(max) : 0; - cnum cmin = nump(min) ? c_num(min) : 0; - val greedy = eq(max, greedy_k); - val last_good_result = nil; - val last_good_line = num(0); - - if ((c.spec = rest(c.spec)) == nil) - break; - - { - cnum reps_max = 0, reps_min = 0; - uw_block_begin(nil, result); - - while (c.data && min && reps_min < cmin) { - c.data = rest(c.data); - c.data_lineno = plus(c.data_lineno, num(1)); - reps_min++; - } - - if (min) { - if (reps_min != cmin) { - debuglf(spec_linenum, lit("skipped only ~a/~a lines to ~a:~a"), - num(reps_min), num(cmin), - first(c.files), c.data_lineno, nao); - uw_block_return(nil, nil); - } - - debuglf(spec_linenum, lit("skipped ~a lines to ~a:~a"), - num(reps_min), first(c.files), - c.data_lineno, nao); - } - - while (greedy || !max || reps_max++ < cmax) { - result = match_files(c); - - if (result) { - if (greedy) { - last_good_result = result; - last_good_line = c.data_lineno; - } else { - debuglf(spec_linenum, lit("skip matched ~a:~a"), first(c.files), - c.data_lineno, nao); - break; - } - } else { - debuglf(spec_linenum, lit("skip didn't match ~a:~a"), - first(c.files), c.data_lineno, nao); - } - - if (!c.data) - break; - - debuglf(spec_linenum, lit("skip didn't match ~a:~a"), first(c.files), - c.data_lineno, nao); - - c.data = rest(c.data); - c.data_lineno = plus(c.data_lineno, num(1)); - } - - uw_block_end; - - if (result) - return result; - if (last_good_result) { - debuglf(spec_linenum, lit("greedy skip matched ~a:~a"), - first(c.files), last_good_line, nao); - return last_good_result; - } + if (result == same_data_k) { + c = nc; + if ((c.spec = rest(c.spec)) == nil) + break; + goto repeat_spec_same_data; + } else if (result == decline_k) { + /* go on to other processing below */ + } else { + return result; } + } - debuglf(spec_linenum, lit("skip failed"), nao); - return nil; - } else if (sym == trailer_s && !rest(specline)) { + if (sym == trailer_s && !rest(specline)) { if ((c.spec = rest(c.spec)) == nil) break; @@ -2400,6 +2433,8 @@ int extract(val spec, val files, val predefined_bindings) static void syms_init(void) { + decline_k = intern(lit("decline"), keyword_package); + same_data_k = intern(lit("same_data"), keyword_package); mingap_k = intern(lit("mingap"), keyword_package); maxgap_k = intern(lit("maxgap"), keyword_package); gap_k = intern(lit("gap"), keyword_package); @@ -2419,6 +2454,8 @@ static void dir_tables_init(void) { h_directive_table = make_hash(nil, nil); v_directive_table = make_hash(nil, nil); + + sethash(v_directive_table, skip_s, cptr((mem_t *) v_skip)); } void match_init(void) |