fixed tests and memory management; added multi selector rule support

This commit is contained in:
anon 2024-09-16 16:53:48 +02:00
parent 8d9b6c5256
commit e716ece6a9
10 changed files with 206 additions and 98 deletions

View File

@ -29,7 +29,7 @@ else
endif endif
CFLAGS += -std=c2x -Wall -Wpedantic CFLAGS += -std=c2x -Wall -Wpedantic
CPPFLAGS += -Iobject -Ilibrary CPPFLAGS += -Isource -Iobject -Ilibrary
# --- Rule Section --- # --- Rule Section ---
${OUT}: ${GENSOURCE} ${GENOBJECT} ${OBJECT} ${LIBS} ${OUT}: ${GENSOURCE} ${GENOBJECT} ${OBJECT} ${LIBS}
@ -60,3 +60,4 @@ clean:
-rm ${GENSOURCE} -rm ${GENSOURCE}
-rm ${OBJECT} -rm ${OBJECT}
-rm ${OUT} -rm ${OUT}
-rm test/*.tb.*

View File

@ -23,10 +23,6 @@ extern int tbsp_yy_deinit(void);
extern int tbsp_c_yy_init(void); extern int tbsp_c_yy_init(void);
extern int tbsp_c_yy_deinit(void); extern int tbsp_c_yy_deinit(void);
char * language = NULL;
char * verbatim = NULL;
char * top = NULL;
void yyerror(const char * const fmt, ...) { void yyerror(const char * const fmt, ...) {
extern int yylineno; extern int yylineno;
va_list args; va_list args;
@ -52,7 +48,7 @@ void dump_rule_table(const char * const name, rule_type_t type_mask) {
sprint_r = asprintf(&sprint_buffer, sprint_r = asprintf(&sprint_buffer,
TBSP_case, TBSP_case,
kv_A(rules, i).string, kv_A(rules, i).string,
kv_A(rules, i).target kv_A(codes, kv_A(rules, i).code_index).number
); );
fputs(sprint_buffer, yyout); fputs(sprint_buffer, yyout);
free(sprint_buffer); free(sprint_buffer);
@ -82,7 +78,7 @@ void dump_output(void) {
dump_rule_table("leave_cases", LEAVE_RULE); dump_rule_table("leave_cases", LEAVE_RULE);
fputs(TBSP_traverse_top, yyout); fputs(TBSP_traverse_top, yyout);
for (int i = 0; i < kv_size(rules); i++) { for (int i = 0; i < kv_size(codes); i++) {
const char * const case_string = "\ const char * const case_string = "\
case %d: {\n\ case %d: {\n\
%s\n\ %s\n\
@ -90,8 +86,8 @@ void dump_output(void) {
"; ";
sprint_r = asprintf(&sprint_buffer, sprint_r = asprintf(&sprint_buffer,
case_string, case_string,
kv_A(rules, i).target, kv_A(codes, i).number,
kv_A(rules, i).code kv_A(codes, i).code
); );
fputs(sprint_buffer, yyout); fputs(sprint_buffer, yyout);
free(sprint_buffer); free(sprint_buffer);
@ -111,17 +107,13 @@ void init(void) {
static inline static inline
void deinit(void) { void deinit(void) {
for (int i = 0; i < kv_size(rules); i++) { fclose(yyin);
free(kv_A(rules, i).string); fclose(yyout);
free(kv_A(rules, i).code); tbsp_tab_deinit();
}
tbsp_yy_deinit(); tbsp_yy_deinit();
tbsp_c_yy_deinit(); tbsp_c_yy_deinit();
free(output_file_name); free(output_file_name);
free(input_file_name); free(input_file_name);
free(verbatim);
free(language);
free(top);
} }
signed main(const int argc, const char * const * const argv) { signed main(const int argc, const char * const * const argv) {

28
source/rule.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef RULE_H
#define RULE_H
#include <kvec.h>
typedef enum {
ENTER_RULE = 0b0001,
LEAVE_RULE = 0b0010,
} rule_type_t;
typedef struct {
int number;
char * code;
} code_t;
typedef struct {
rule_type_t type;
char * string;
int code_index;
} rule_t;
typedef kvec_t(rule_t) rule_vector_t;
extern rule_vector_t rules;
typedef kvec_t(code_t) code_vector_t;
extern code_vector_t codes;
#endif

View File

@ -40,7 +40,7 @@ identifier [a-zA-z][-a-zA-z0-9_]*
return SEPARATOR; return SEPARATOR;
} }
. { . {
yyerror("unknown shit"); yyerror("unknown expression in rule section");
} }
} }
@ -86,7 +86,6 @@ leave[[:space:]] { return LEAVE; }
} }
--code_nesting; --code_nesting;
;
} }
.|\n { buffer = sdscat(buffer, yytext); } .|\n { buffer = sdscat(buffer, yytext); }
} }

View File

@ -1,36 +1,30 @@
%{ %{
#include "tbsp.yy.h" #include "tbsp.yy.h"
#include <kvec.h>
extern char * language;
extern char * top;
extern char * verbatim;
int target_counter = 1; int target_counter = 1;
kvec_t(char *) rule_selectors;
char * language = NULL;
char * verbatim = NULL;
char * top = NULL;
#define COMA , #define COMA ,
%} %}
%code requires { %code requires {
typedef enum { #include "rule.h"
ENTER_RULE = 0b0001,
LEAVE_RULE = 0b0010,
} rule_type_t;
typedef struct {
rule_type_t type;
int target;
char * string;
char * code;
} rule_t;
#include <kvec.h>
typedef kvec_t(rule_t) rule_vector_t;
extern rule_vector_t rules;
extern void yyerror(const char * const s, ...); extern void yyerror(const char * const s, ...);
} }
%code provides { %code provides {
void tbsp_tab_init(void); void tbsp_tab_init(void);
void tbsp_tab_deinit(void); void tbsp_tab_deinit(void);
extern rule_vector_t rules;
extern char * language;
extern char * top;
extern char * verbatim;
} }
%union{ %union{
char * strval; char * strval;
@ -41,7 +35,6 @@
%token ENTER LEAVE %token ENTER LEAVE
%token<strval> IDENTIFIER CODE_BLOB %token<strval> IDENTIFIER CODE_BLOB
%type<ruleval> rule_type %type<ruleval> rule_type
%type<strval> rule_selector
%% %%
document document
: %empty : %empty
@ -91,16 +84,22 @@ rule
char * code_blob_expanded = strdup(tbsp_c_expland_code($3)); char * code_blob_expanded = strdup(tbsp_c_expland_code($3));
kv_push(rule_t, rules, (rule_t) { kv_push(code_t, codes, (code_t) {
.type = $1 COMA .number = target_counter++ COMA
.target = target_counter COMA .code = code_blob_expanded COMA
.string = $2 COMA
.code = code_blob_expanded COMA
}); });
++target_counter; for (int i = 0; i < kv_size(rule_selectors); i++) {
kv_push(rule_t, rules, (rule_t) {
.type = $1 COMA
.string = kv_A(rule_selectors, i) COMA
.code_index = codes.n-1 COMA
});
}
rule_selectors.n = 0;
tbsp_c_yy_reset(); tbsp_c_yy_reset();
free($3);
} }
; ;
@ -111,7 +110,12 @@ rule_type
; ;
rule_selector rule_selector
: IDENTIFIER { $$ = $1; } : IDENTIFIER {
kv_push(char *, rule_selectors, $1);
}
| IDENTIFIER rule_selector {
kv_push(char *, rule_selectors, $1);
}
; ;
@ -123,16 +127,32 @@ code_section
%% %%
rule_vector_t rules; rule_vector_t rules;
code_vector_t codes;
void tbsp_tab_init(void) { void tbsp_tab_init(void) {
kv_init(rules); kv_init(rules);
kv_init(codes);
kv_init(rule_selectors);
} }
void tbsp_tab_deinit(void) { void tbsp_tab_deinit(void) {
for (int i = 0; i < kv_size(rule_selectors); i++) {
free(kv_A(rule_selectors, i));
}
for (int i = 0; i < kv_size(codes); i++) {
free(kv_A(codes, i).code);
}
for (int i = 0; i < kv_size(rules); i++) { for (int i = 0; i < kv_size(rules); i++) {
free(kv_A(rules, i).string); free(kv_A(rules, i).string);
free(kv_A(rules, i).code);
} }
kv_destroy(rules); kv_destroy(rules);
kv_destroy(codes);
kv_destroy(rule_selectors);
free(verbatim);
free(language);
free(top);
} }

View File

@ -1,25 +1,53 @@
class CMDTEST_master_batch < Cmdtest::Testcase class CMDTEST_master_batch < Cmdtest::Testcase
def setup
import_file "test/file2str.h", "./"
end
def test_converter def test_converter
import_file "test/convert.tbsp", "./" source = "convert"
import_file "test/#{source}.tbsp", "./"
import_file "test/input.md", "./" import_file "test/input.md", "./"
cmd "tbsp -o convert.tb.c convert.tbsp" do cmd "tbsp -o #{source}.tb.c #{source}.tbsp" do
created_files ["convert.tb.c"] created_files ["#{source}.tb.c"]
end end
shell "bake convert.tb.c" cmd "gcc -w -o #{source}.out #{source}.tb.c $(pkg-config --cflags --libs tree-sitter) -ltree-sitter-markdown" do
cmd "./convert.tb.out input.md" do created_files ["#{source}.out"]
end
cmd "./#{source}.out input.md" do
stdout_equal /.+/ stdout_equal /.+/
end end
end end
def test_function_collector def test_function_collector
import_file "test/function_collector.tbsp", "./" source = "function_collector"
cmd "tbsp -o function_collector.tb.cpp function_collector.tbsp" do import_file "test/#{source}.tbsp", "./"
created_files ["function_collector.tb.cpp"]
cmd "tbsp -o #{source}.tb.cpp #{source}.tbsp" do
created_files ["#{source}.tb.cpp"]
end end
shell "bake function_collector.tb.cpp" cmd "g++ -w -o #{source}.out #{source}.tb.cpp $(pkg-config --cflags --libs tree-sitter tree-sitter-cpp)" do
cmd "./function_collector.tb.out function_collector.tb.cpp" do created_files ["#{source}.out"]
end
cmd "./#{source}.out #{source}.tb.cpp" do
stdout_equal /.+/
end
end
def test_double_selector
source = "double_selector"
import_file "test/#{source}.tbsp", "./"
cmd "tbsp #{source}.tbsp" do
created_files ["#{source}.tb.c"]
end
cmd "g++ -w -o #{source}.out #{source}.tb.c $(pkg-config --cflags --libs tree-sitter tree-sitter-c)" do
created_files ["#{source}.out"]
end
cmd "./#{source}.out #{source}.tb.c" do
stdout_equal /.+/ stdout_equal /.+/
end end
end end

View File

@ -14,6 +14,7 @@ leave section {
} }
enter atx_heading { enter atx_heading {
puts("AAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
printf("<h%d>\n", depth); printf("<h%d>\n", depth);
} }
leave atx_heading { leave atx_heading {
@ -21,66 +22,57 @@ leave atx_heading {
} }
enter paragraph { enter paragraph {
printf("<p>"); puts("<p>");
} }
leave paragraph { leave paragraph {
printf("</p>\n"); puts("</p>");
} }
enter list { enter list {
printf("<ol>"); puts("<ol>");
} }
leave list { leave list {
printf("</ol>\n"); puts("</ol>");
} }
enter list_item { enter list_item {
printf("<li>"); puts("<li>");
} }
leave list_item { leave list_item {
printf("</li>\n"); puts("</li>");
} }
enter fenced_code_block { enter fenced_code_block {
printf("<pre>"); puts("<pre>");
} }
leave fenced_code_block { leave fenced_code_block {
printf("</pre>\n"); puts("</pre>");
} }
enter inline { enter inline {
char * text = tbget_text; char * text = tbget_text;
printf(text); puts(text);
free(text); free(text);
} }
enter code_fence_content { enter code_fence_content {
char * text = tbget_text; char * text = tbget_text;
printf(text); puts(text);
free(text); free(text);
} }
%% %%
// @BAKE g++ -o $*.out $@ $(pkg-config --cflags --libs tree-sitter) -ltree-sitter-markdown -ggdb /* @BAKE
tbsp $@
gcc -o $*.out $*.tb.c $(pkg-config --cflags --libs tree-sitter) -ltree-sitter-markdown -ggdb
./$*.out input.md
@STOP
*/
#include "file2str.h"
signed main(int argc, char * * argv) { signed main(int argc, char * * argv) {
if (argc < 2) { if (argc < 2) { return 1; }
return 1; FILE2STR(fstr, argv[1]);
}
FILE* f = fopen(argv[1], "r");
if (!f) {
return 2;
}
fseek(f, 0, SEEK_END);
int flen = ftell(f);
rewind(f);
char fstr[flen+1];
fstr[flen] = '\00';
fread(fstr, flen, sizeof(char), f);
fclose(f);
printf("-- meta: %d chars\n", flen); printf("-- meta: %d chars\n", flen);

36
test/double_selector.tbsp Normal file
View File

@ -0,0 +1,36 @@
%language c
%%
enter function_definition declaration {
TSNode declarator = $$->"declarator";
TSNode next_declarator = declarator;
while (next_declarator = tbnode_child_by_field_name(next_declarator, "declarator"),
!ts_node_is_null(next_declarator)) {
declarator = next_declarator;
}
char * s = tbget_node_text(declarator);
puts(s);
free(s);
}
%%
/* @BAKE
tbsp $@
gcc -o $*.out $*.tb.c $(pkg-config --cflags --libs tree-sitter tree-sitter-c) -ggdb
./$*.out $.tb.c
@STOP
*/
#include "file2str.h"
signed main(int argc, char * * argv) {
if (argc < 2) { return 1; }
FILE2STR(fstr, argv[1]);
puts(fstr);
tbtraverse(fstr);
return 0;
}

15
test/file2str.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef FILE2STR_H
#define FILE2STR_H
#define FILE2STR(dest, filename) \
FILE* f = fopen(filename, "r"); \
if (!f) { return 1; } \
fseek(f, 0, SEEK_END); \
int flen = ftell(f); \
rewind(f); \
char fstr[flen+1]; \
dest[flen] = '\00'; \
fread(dest, flen, sizeof(char), f); \
fclose(f);
#endif

View File

@ -19,22 +19,19 @@ enter function_definition {
} }
%% %%
/* @BAKE
tbsp -o $*.tb.cpp $@
g++ -o $*.out $*.tb.cpp $(pkg-config --cflags --libs tree-sitter tree-sitter-cpp) -ggdb
./$*.out $@
@STOP
*/
// @BAKE g++ $@ -o $*.out $(pkg-config --cflags --libs tree-sitter tree-sitter-cpp) #include "file2str.h"
signed main(int argc, char * * argv) { signed main(int argc, char * * argv) {
if (argc < 2) { if (argc < 2) { return 1; }
return 1;
}
FILE* f = fopen(argv[1], "r"); FILE2STR(fstr, argv[1]);
fseek(f, 0, SEEK_END);
int flen = ftell(f);
rewind(f);
char fstr[flen+1];
fstr[flen] = '\00';
fread(fstr, flen, sizeof(char), f);
fclose(f);
tbtraverse(fstr); tbtraverse(fstr);