fixed tests and memory management; added multi selector rule support
This commit is contained in:
parent
8d9b6c5256
commit
e716ece6a9
3
Makefile
3
Makefile
@ -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.*
|
||||||
|
@ -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
28
source/rule.h
Normal 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
|
@ -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); }
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
36
test/double_selector.tbsp
Normal 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
15
test/file2str.h
Normal 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
|
@ -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);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user