commit 9dc03661ab1baccce726bd37b704d7ae34a4caa5
parent 9dbfc0ddfc5fa3f502132b72ae52a48d4af8ee97
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date: Tue, 27 Feb 2024 20:58:40 +0000
Working generator and full configuration
* Detect duplicate names and forward declare general template
* Make explicit specialization for general templates
* Detect string literal and call appropriate escape function
* Functions without parameters return templated value
* Full working configuration with comments
* | can be used to detonate a empty line for better readability
when there are no parameters or constraints
* Memory leak free
* Minor consistency fixups
Diffstat:
5 files changed, 279 insertions(+), 64 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
@@ -3,7 +3,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
project(
Alec
- VERSION 0.0.9
+ VERSION 0.0.10
DESCRIPTION "Abstraction Layer for Escape Codes"
HOMEPAGE_URL https://git.dimitrijedobrota.com/alec.git
LANGUAGES C CXX
diff --git a/src/generator.h b/src/generator.h
@@ -20,13 +20,23 @@ struct record {
struct list *recipe;
};
+typedef void(*free_f)(void *);
+typedef int(*cmp_f)(const void *, const void *);
+
+int scmp(const void *a, const void *b);
+
struct list *list_new(char *data, struct list *list);
-void list_free(struct list *l, void (*free_data)(void *));
+void list_free(struct list *l, free_f free_data);
+
+int list_find(struct list *l, void *data, cmp_f cmp);
struct record *record_new(char *name, struct list *args, struct list *rules, struct list *recipe);
void record_free(void *rp);
+struct list *record_dupes(struct list *l);
+
+void record_print_template(const struct record *r, int dup);
void record_print_function(const struct record *r);
-void record_print_template(const struct record *r);
+void record_print_dupes(const struct list *l);
#endif
diff --git a/src/lexer.l b/src/lexer.l
@@ -10,13 +10,14 @@ LINE_END (\n|\r|\r\n)
%%
-{LINE_END} { return EOL; }
-^[\t ]*{LINE_END} { return EOL; }
-^[\t ]*
+{LINE_END} { return EOL; }
+^[\t ]*{LINE_END} { return EOL; }
+^[\t ]*\|*[\t ]*{LINE_END} { return EOL; }
^[\t ]*"//".* { yylval.n = strdup(yytext); return COMMENT; }
-, { return COMMA; }
+, { return COMMA; }
+
[^,\n]* {
char *p = yytext + strlen(yytext) - 1;
while(isspace(*p)) *p-- = '\0';
diff --git a/src/parser.y b/src/parser.y
@@ -73,15 +73,24 @@ int main(const int argc, char *argv[]) {
fclose(f);
}
+ struct list *dupes = record_dupes(records);
+ record_print_dupes(dupes);
+
+ printf("\n/* Template compile-time variables */\n");
for(struct list *p = records; p; p = p->next) {
- record_print_function((const struct record *)p->data);
+ const struct record * r = (const struct record *)p->data;
+ record_print_template(r, list_find(dupes, r->name, scmp));
}
+ printf("\n/* Run-time functions */\n");
for(struct list *p = records; p; p = p->next) {
- record_print_template((const struct record *)p->data);
+ const struct record * r = (const struct record *)p->data;
+ record_print_function(r);
}
list_free(records, record_free);
+ list_free(dupes, 0);
+
yylex_destroy();
}
@@ -138,13 +147,29 @@ void record_free(void *rp) {
free(r);
}
+int list_find(struct list *l, void *data, cmp_f cmp) {
+ while(l) {
+ if(!cmp(l->data, data)) return 1;
+ l = l->next;
+ }
+ return 0;
+}
+
+void record_print_dupes(const struct list *l) {
+ while(l) {
+ printf("template <auto... val> static const char *%s_v;\n", l->data);
+ l = l->next;
+ }
+}
+
void record_print_function(const struct record *r) {
+ struct list dummy = { 0 }, *c = &dummy;
+
if(!r->recipe) { // comment
- printf("%s\n", r->name);
+ printf("%s\n\n", r->name);
return;
}
- struct list dummy, *c = &dummy;
printf("static constexpr auto %s(", r->name);
for(struct list *p = r->args; p; p = p->next) {
c = c->next = list_new(strchr(p->data, ' ') + 1, NULL);
@@ -155,7 +180,7 @@ void record_print_function(const struct record *r) {
if(r->rules) {
for(struct list *p = dummy.next; p; p = p->next) {
- printf("\t assert(");
+ printf("\tassert(");
for(struct list *q = r->rules; q; q = q->next) {
printf("%s(%s)", q->data, p->data);
if(q->next) printf(" && ");
@@ -164,37 +189,44 @@ void record_print_function(const struct record *r) {
}
}
- printf("\treturn details::helper::make(");
- for(struct list *p = r->recipe; p; p = p->next) {
- printf("%s", p->data);
- if(p->next) printf(", ");
- }
- printf(");\n}\n\n");
+ if(r->args) {
+ printf("\treturn details::helper::make(");
+ for(struct list *p = r->recipe; p; p = p->next) {
+ printf("%s", p->data);
+ if(p->next) printf(", ");
+ }
+ printf(")");
+ } else {
+ printf("\treturn %s_v", r->name);
+ }
+ printf(";\n}\n\n");
list_free(dummy.next, NULL);
}
-void record_print_template(const struct record *r) {
+void record_print_template(const struct record *r, int dup) {
+ struct list dummy = { 0 }, *c = &dummy;
+
if(!r->recipe) { // comment
- printf("%s\n", r->name);
+ printf("%s\n\n", r->name);
return;
}
- struct list dummy, *c = &dummy;
-
- printf("template <");
- for(struct list *p = r->args; p; p = p->next) {
- c = c->next = list_new(strchr(p->data, ' ') + 1, NULL);
- printf("%s", p->data);
- if(p->next) printf(", ");
- }
- printf(">\n");
+ if(r->args) {
+ printf("template <");
+ for(struct list *p = r->args; p; p = p->next) {
+ c = c->next = list_new(strchr(p->data, ' ') + 1, NULL);
+ printf("%s", p->data);
+ if(p->next) printf(", ");
+ }
+ printf(">\n");
+ }
if(r->rules) {
printf("\trequires ");
for(struct list *p = dummy.next; p; p = p->next) {
for(struct list *q = r->rules; q; q = q->next) {
- printf("%s_v(%s)", q->data, p->data);
+ printf("%s_v<%s>", q->data, p->data);
if(q->next) printf(" && ");
}
if(p->next) printf(" && ");
@@ -202,16 +234,49 @@ void record_print_template(const struct record *r) {
printf("\n");
}
- printf("static constexpr auto %s_v\n\t = details::escape<", r->name);
- for(struct list *p = r->recipe; p; p = p->next) {
- printf("%s", p->data);
- if(p->next) printf(", ");
- }
- printf(">;\n\n");
+ printf("static constexpr auto %s_v", r->name);
+ if(dup) {
+ printf("<");
+ for(struct list *p = dummy.next; p; p = p->next) {
+ printf("%s", p->data);
+ if(p->next) printf(", ");
+ }
+ printf(">");
+ }
+
+ if(!r->recipe->next && r->recipe->data[0] == '"') {
+ // string literal
+ printf("\n\t = details::escape_literal<%s>;", r->recipe->data);
+ } else {
+ printf("\n\t = details::escape<");
+ for(struct list *p = r->recipe; p; p = p->next) {
+ printf("%s", p->data);
+ if(p->next) printf(", ");
+ }
+ printf(">;");
+ }
+ printf("\n\n");
list_free(dummy.next, NULL);
}
+int scmp(const void *a, const void *b) {
+ return strcmp((const char *)a, (const char *)b);
+}
+
+struct list *record_dupes(struct list *l) {
+ struct list *s = NULL, *d = NULL;
+
+ for(struct list *p = records; p; p = p->next) {
+ const struct record * r = (const struct record *)p->data;
+ if(!list_find(s, r->name, scmp)) s = list_new(r->name, s);
+ else if(!list_find(d, r->name, scmp)) d = list_new(r->name, d);
+ }
+
+ list_free(s, NULL);
+ return d;
+}
+
void yyerror(char *s, ...) {
va_list ap;
va_start(ap, s);
diff --git a/src/rules b/src/rules
@@ -1,44 +1,183 @@
-
-// hello
+// Move cursor up/down/frwd/back
-foreground
-int idx
-limit_256
-32, ';', 5, ';', idx, 'm'
-
+ cursor_up
+ int n
+ limit_pos
+ n, 'A'
+
+ cursor_down
+ int n
+ limit_pos
+ n, 'B'
+
+ cursor_frwd
+ int n
+ limit_pos
+ n, 'C'
+
+ cursor_back
+ int n
+ limit_pos
+ n, 'D'
+
+// Move cursor to the next/prev line
+
+ cursor_line_next
+ int n
+ limit_pos
+ n, 'E'
+
+ cursor_line_prev
+ int n
+ limit_pos
+ n, 'F'
+
+// Set cursor to specific column
+
+ cursor_column
+ int n
+ limit_pos
+ n, 'G'
+
+// Erase functions
+
+ erase_display
+ MOTION m
+ |
+ (int)m, 'J'
+
+ erase_line
+ MOTION m
+ |
+ (int)m, 'K'
+
+// Scroll up/down
+
+ scroll_up
+ int n
+ limit_pos
+ n, 'S'
+
+ scroll_down
+ int n
+ limit_pos
+ n, 'T'
+
+// Set cursor to a specific position
+
+ cursor_position
+ int n, int m
+ limit_pos
+ n, ';', m, 'H'
+
+// color
+
+// palet colors
+
+ foreground
+ COLOR color
+ |
+ (int)color + 30, 'm'
background
+ COLOR color
+ |
+ (int)color + 40, 'm'
+
+// 256-color palette
+
+ foreground
int idx
limit_256
- 42, ';', 5, ';', idx, 'm'
-
+ 38, ';', 5, ';', idx, 'm'
+
+ background
+ int idx
+ limit_256
+ 48, ';', 5, ';', idx, 'm'
+
+// RGB colors
+
foreground
int R, int G, int B
limit_256
38, ';', 5, ';', R, ';', G, ';', B, 'm'
-
- // world
- // world
+ background
+ int R, int G, int B
+ limit_256
+ 48, ';', 5, ';', R, ';', G, ';', B, 'm'
+
+// Set/reset text decorators
+
+ decor_set
+ DECOR decor
+ |
+ (int)decor, 'm'
+
+ decor_reset
+ DECOR decor
+ |
+ (int)decor + 20, 'm'
+
+// Save/load cursor position;
+
+ cursor_save
+ |
+ |
+ 's'
+
+ cursor_load
+ |
+ |
+ 'u'
+
+// Set screen modes
+
+ screen_mode_set
+ int n
+ limit_pos
+ '=', n, 'h'
+
+ screen_mode_reset
+ int n
+ limit_pos
+ '=', n, 'l'
+
+// Private screen modes supported by most terminals
+
+// Save/load screen
+
+ screen_show
+ |
+ |
+ "?47h"
+
+ screen_hide
+ |
+ |
+ "?47l"
-background
-int R, int G, int B
-limit_256
-38 , ';', 5, ';', R, ';', G, ';', B, 'm'
-// comment
-foreground
-COLOR color
-
-(int)color + 30, 'm'
+// Show/hide cursor
+ cursor_show
+ |
+ |
+ "?25h"
-// hello there
-background
-COLOR color
+ cursor_hide
+ |
+ |
+ "?25l"
-(int)color + 40, 'm'
+// Show/hide alternate buffer
+ abuf_show
+ |
+ |
+ "?1049h"
-
-
-
+ abuf_hide
+ |
+ |
+ "?1049l"