From 1f7e382c927d7b9fec915dea91567bf187ed1a0c Mon Sep 17 00:00:00 2001 From: Devine Lu Linvega Date: Mon, 6 May 2024 19:29:14 -0700 Subject: [PATCH 01/41] Added wryls lisp example --- examples/lisp.modal | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 examples/lisp.modal diff --git a/examples/lisp.modal b/examples/lisp.modal new file mode 100644 index 0000000..3264847 --- /dev/null +++ b/examples/lisp.modal @@ -0,0 +1,22 @@ +<> ((defun ?n ?p ?b)) (defun ?n ?p ?b) +<> (defun ?n ?p ?b) (<> (?n ?p) ?b) +<> (q ?x) (q ?x) +<> ((unwrap ?x)) (unwrap ?x) +<> (unwrap ((?x))) (unwrap (?x)) +<> (unwrap ?x) ?x +<> (if ?c ?t ?f) (if/q ?c q ?t q ?f) +<> (if/q (true) q ?t q ?f) (unwrap ?t) +<> (if/q (false) q ?t q ?f) (unwrap ?f) +<> (== (?x) (?x)) (true) +<> (== (?x) (?y)) (false) +<> (math ?: ?0 ?1) ?: +<> (+ (?x) (?y)) (math + ?x ?y) +<> (- (?x) (?y)) (math - ?x ?y) +<> (* (?x) (?y)) (math * ?x ?y) + +(defun factorial (?n) + (if (== (?n) (1)) + (?n) + (* (?n) (factorial (- (?n) (1)))))) + +(factorial (5)) \ No newline at end of file From 09dd2a979543208ec822c931093280f2d455ad3b Mon Sep 17 00:00:00 2001 From: Devine Lu Linvega Date: Tue, 7 May 2024 07:55:04 -0700 Subject: [PATCH 02/41] Added CapitalExs mandelbrot --- examples/mandelbrot.modal | 33 +++++++++++++++++++++++++++++++++ src/modal.c | 2 +- 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 examples/mandelbrot.modal diff --git a/examples/mandelbrot.modal b/examples/mandelbrot.modal new file mode 100644 index 0000000..e24912c --- /dev/null +++ b/examples/mandelbrot.modal @@ -0,0 +1,33 @@ +<> (iterating ?x ?y (100) ?z ?a ?b) (?((?:) ?:) *\s) +<> (iterating ?x ?y ?n (1) ?a ?b) (?((?:) ?:) \s\s) + +<> (iterating (?x) (?y) (?n) (?c) (?a) (?b)) ( + iterating (?x) (?y) (?n 1 `+) (?a ?a f* ?b ?b f* `+ 4096 `>) + (?a ?a f* ?b ?b f* `- ?x `+) + (?a ?b 2048 f* f* ?y `+) +) + + +<> (?0 ?1 f*) (?0 ?1 `* 1024 `/) +<> (?0 ?1 f/) (?0 1024 `* ?1 `/) +<> (?0 ?1 `?:) ?: + +<> (mandelbrot (?x) (?y)) ( + plot-mandelbrot (0) (0) (2529 ?x `/) (2293 ?y `/) (-2048) (-1146) +) + +<> (plot-mandelbrot (40) (36) (?r) (?d) (?x) (?y)) () + +<> (plot-mandelbrot (40) (?j) (?r) (?d) (?x) (?y)) ( + ?(?: ?:) \n + iterating (?x) (?y) (0) (0) (0) (0) + plot-mandelbrot (0) (?j 1 `+) (?r) (?d) (-2048) (?y ?d `+) +) + +<> (plot-mandelbrot (?i) (?j) (?r) (?d) (?x) (?y)) ( + iterating (?x) (?y) (0) (0) (0) (0) + plot-mandelbrot (?i 1 `+) (?j) (?r) (?d) (?x ?r `+) (?y) +) + + +mandelbrot (40) (36) diff --git a/src/modal.c b/src/modal.c index d2986ae..bf8e2f4 100644 --- a/src/modal.c +++ b/src/modal.c @@ -5,7 +5,7 @@ typedef struct { char *a, *b; } Rule; -static int flip, quiet, debug, cycles = 0x10000; +static int flip, quiet, debug, cycles = 0x200000; static Rule rules[0x1000], *rules_ = rules, lambda; static char dict[0x8000], *dict_ = dict, empty; static char bank_a[0x4000], *src_ = bank_a; From 680a039cf91b01525c5d77f4cf54e1484d47093f Mon Sep 17 00:00:00 2001 From: Devine Lu Linvega Date: Tue, 7 May 2024 08:20:39 -0700 Subject: [PATCH 03/41] Removed lambda rule memory --- src/modal.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/modal.c b/src/modal.c index bf8e2f4..7d69815 100644 --- a/src/modal.c +++ b/src/modal.c @@ -6,7 +6,7 @@ typedef struct { } Rule; static int flip, quiet, debug, cycles = 0x200000; -static Rule rules[0x1000], *rules_ = rules, lambda; +static Rule rules[0x1000], *rules_ = rules; static char dict[0x8000], *dict_ = dict, empty; static char bank_a[0x4000], *src_ = bank_a; static char bank_b[0x4000], *dst_ = bank_b; @@ -252,17 +252,17 @@ rewrite(void) } /* phase: lambda */ if(c == '?' && s[1] == '(') { - char *d_ = dict_; + char *d = dict_; cap = walk(s + 1); - r = &lambda, r->id = -1; + r = rules_, r->id = -1; parse_frag(&r->b, parse_frag(&r->a, s + 2)); s = cap; while(*s == ' ') s++; - if(!apply_rule(&lambda, s)) { + if(!apply_rule(r, s)) { if(!quiet) fprintf(stderr, "%02d %s\n", r->id, src_), ++r->refs; write_tail(s); } - dict_ = d_; + dict_ = d; return 1; } /* phase: match */ @@ -286,7 +286,7 @@ main(int argc, char **argv) return !printf("usage: modal [-vqn] source.modal\n"); for(i = 1; i < argc && *argv[i] == '-'; i++) { switch(argv[i][1]) { - case 'v': /* version */ return !printf("Modal Interpreter, 4 May 2024.\n"); + case 'v': /* version */ return !printf("Modal Interpreter, 7 May 2024.\n"); case 'q': /* quiet */ quiet = 1; break; case 'p': /* debug */ debug = 1; break; case 'n': /* infinite */ cycles = 0xffffffff; break; From 002da4bcc2696d5e6588a8b94337ece1b2c513f1 Mon Sep 17 00:00:00 2001 From: Devine Lu Linvega Date: Thu, 9 May 2024 14:24:21 -0700 Subject: [PATCH 04/41] Abstracted writing --- src/modal.c | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/src/modal.c b/src/modal.c index 7d69815..54f02b7 100644 --- a/src/modal.c +++ b/src/modal.c @@ -14,6 +14,12 @@ static char *regs[0x100], stack[0x10], *stack_ = stack; #define spacer(c) (c <= ' ' || c == '(' || c == ')') +static void +pushchr(char c) +{ + *dst_++ = c; +} + static char * walk(char *s) { @@ -86,9 +92,9 @@ device_read(void) { char c, *origin = dst_; while(fread(&c, 1, 1, stdin) && c >= ' ') - *dst_++ = c; + pushchr(c); if(feof(stdin)) - *dst_++ = 'E', *dst_++ = 'O', *dst_++ = 'F'; + pushchr('E'), pushchr('O'), pushchr('F'); if(dst_ - origin == 0) dst_--; } @@ -103,11 +109,11 @@ write_reg(char r, char *reg) case '^': /* op: join */ if(*reg == '(') reg++, --cap; while(reg < cap && (c = *reg++)) - if(!spacer(c)) *dst_++ = c; + if(!spacer(c)) pushchr(c); return; case '.': /* op: unwrap */ if(*reg == '(') reg++, --cap; - while(reg < cap) *dst_++ = *reg++; + while(reg < cap) pushchr(*reg++); return; case '*': { /* op: explode */ int i, depth = 0; @@ -115,18 +121,17 @@ write_reg(char r, char *reg) reg++; while(reg < cap) { while((c = *reg) && !spacer(c)) - *dst_++ = c, reg++; - *dst_++ = ' '; - *dst_++ = '(', reg++, depth++; + pushchr(c), reg++; + pushchr(' '), pushchr('('), reg++, depth++; } } else /* token */ while((c = *reg++) && !spacer(c)) - *dst_++ = c, *dst_++ = ' ', *dst_++ = '(', depth++; - for(i = 0; i < depth; i++) *dst_++ = ')'; + pushchr(c), pushchr(' '), pushchr('('), depth++; + for(i = 0; i < depth; i++) pushchr(')'); return; } default: - while(reg < cap) *dst_++ = *reg++; + while(reg < cap) pushchr(*reg++); return; } } @@ -136,7 +141,7 @@ write_tail(char *s) { while((*dst_++ = *s++)) ; - *dst_ = 0; + pushchr(0); if((flip = !flip)) src_ = bank_b, dst_ = bank_a; else @@ -175,9 +180,9 @@ apply_rule(Rule *r, char *s) if((reg = regs[rid])) b++, write_reg(rid, reg); else - *dst_++ = c; + pushchr(c); } else - *dst_++ = c; + pushchr(c); } if(dst_ == origin) { while(*s == ' ') s++; @@ -269,10 +274,10 @@ rewrite(void) for(r = rules; r < rules_; r++) if(r->a && apply_rule(r, s)) return 1; } - *dst_++ = last = c; + pushchr(c), last = c; s++; } - *dst_++ = 0; + pushchr(0); return 0; } @@ -286,7 +291,7 @@ main(int argc, char **argv) return !printf("usage: modal [-vqn] source.modal\n"); for(i = 1; i < argc && *argv[i] == '-'; i++) { switch(argv[i][1]) { - case 'v': /* version */ return !printf("Modal Interpreter, 7 May 2024.\n"); + case 'v': /* version */ return !printf("Modal Interpreter, 9 May 2024.\n"); case 'q': /* quiet */ quiet = 1; break; case 'p': /* debug */ debug = 1; break; case 'n': /* infinite */ cycles = 0xffffffff; break; From defe9ed963ea7e4ae282ddc023eda3e6a2af5bad Mon Sep 17 00:00:00 2001 From: Devine Lu Linvega Date: Thu, 9 May 2024 15:15:04 -0700 Subject: [PATCH 05/41] Housekeeping --- src/modal.c | 99 ++++++++++++++++++++++++++--------------------------- 1 file changed, 48 insertions(+), 51 deletions(-) diff --git a/src/modal.c b/src/modal.c index 54f02b7..255a96b 100644 --- a/src/modal.c +++ b/src/modal.c @@ -14,12 +14,6 @@ static char *regs[0x100], stack[0x10], *stack_ = stack; #define spacer(c) (c <= ' ' || c == '(' || c == ')') -static void -pushchr(char c) -{ - *dst_++ = c; -} - static char * walk(char *s) { @@ -49,12 +43,12 @@ sint(char *s) static void device_write(char *s) { - char c = *s, *cap = walk(s), **reg = regs + '0'; + char **reg = regs + '0'; /* phase: ALU */ if(*reg) { int acc = sint(*reg++); /* clang-format off */ - switch(c) { + switch(*s) { case '+': while(*reg) acc += sint(*reg++); break; case '-': while(*reg) acc -= sint(*reg++); break; case '*': while(*reg) acc *= sint(*reg++); break; @@ -71,19 +65,21 @@ device_write(char *s) /* clang-format on */ dst_ += snprintf(dst_, 0x10, "%d", acc); return; - } - /* phase: string */ - if(*s == '(') s++, --cap; - while(s < cap) { - c = *s++; - if(c == '\\') { - switch(*s++) { - case 't': putc(0x09, stdout); break; - case 'n': putc(0x0a, stdout); break; - case 's': putc(0x20, stdout); break; - } - } else - putc(c, stdout); + } else { + /* phase: string */ + char *cap = walk(s); + if(*s == '(') s++, --cap; + while(s < cap) { + char c = *s++; + if(c == '\\') { + switch(*s++) { + case 't': putc(0x09, stdout); break; + case 'n': putc(0x0a, stdout); break; + case 's': putc(0x20, stdout); break; + } + } else + putc(c, stdout); + } } } @@ -92,9 +88,9 @@ device_read(void) { char c, *origin = dst_; while(fread(&c, 1, 1, stdin) && c >= ' ') - pushchr(c); + *dst_++ = c; if(feof(stdin)) - pushchr('E'), pushchr('O'), pushchr('F'); + *dst_++ = 'E', *dst_++ = 'O', *dst_++ = 'F'; if(dst_ - origin == 0) dst_--; } @@ -102,38 +98,45 @@ device_read(void) static void write_reg(char r, char *reg) { - char c, *cap = walk(reg); switch(r) { case ':': device_write(reg); return; case '~': device_read(); return; - case '^': /* op: join */ + case '^': { /* op: join */ + char c, *cap = walk(reg); if(*reg == '(') reg++, --cap; while(reg < cap && (c = *reg++)) - if(!spacer(c)) pushchr(c); + if(!spacer(c)) *dst_++ = c; return; - case '.': /* op: unwrap */ + } + case '.': { /* op: unwrap */ + char *cap = walk(reg); if(*reg == '(') reg++, --cap; - while(reg < cap) pushchr(*reg++); + while(reg < cap) *dst_++ = *reg++; return; + } case '*': { /* op: explode */ int i, depth = 0; + char c, *cap = walk(reg); if(*reg == '(' && reg[1] != ')') { /* tuple */ reg++; while(reg < cap) { while((c = *reg) && !spacer(c)) - pushchr(c), reg++; - pushchr(' '), pushchr('('), reg++, depth++; + *dst_++ = c, reg++; + *dst_++ = ' '; + *dst_++ = '(', reg++, depth++; } } else /* token */ while((c = *reg++) && !spacer(c)) - pushchr(c), pushchr(' '), pushchr('('), depth++; - for(i = 0; i < depth; i++) pushchr(')'); + *dst_++ = c, *dst_++ = ' ', *dst_++ = '(', depth++; + for(i = 0; i < depth; i++) *dst_++ = ')'; return; } - default: - while(reg < cap) pushchr(*reg++); + default: { + char *cap = walk(reg); + while(reg < cap) *dst_++ = *reg++; return; } + } } static int @@ -141,7 +144,7 @@ write_tail(char *s) { while((*dst_++ = *s++)) ; - pushchr(0); + *dst_ = 0; if((flip = !flip)) src_ = bank_b, dst_ = bank_a; else @@ -175,14 +178,10 @@ apply_rule(Rule *r, char *s) if(!spacer(c)) return 0; /* phase: write rule */ while((c = *b++)) { - if(c == '?') { - rid = *b; - if((reg = regs[rid])) - b++, write_reg(rid, reg); - else - pushchr(c); - } else - pushchr(c); + if(c == '?' && (rid = *b) && (reg = regs[rid])) + write_reg(rid, reg), b++; + else + *dst_++ = c; } if(dst_ == origin) { while(*s == ' ') s++; @@ -274,10 +273,9 @@ rewrite(void) for(r = rules; r < rules_; r++) if(r->a && apply_rule(r, s)) return 1; } - pushchr(c), last = c; - s++; + *dst_++ = last = c, s++; } - pushchr(0); + *dst_++ = 0; return 0; } @@ -285,7 +283,7 @@ int main(int argc, char **argv) { FILE *f; - int i, pl = 0, pr = 0, rw = 0; + int i, pr = 0, rw = 0; char c, last = 0, *w = bank_a; if(argc < 2) return !printf("usage: modal [-vqn] source.modal\n"); @@ -304,15 +302,14 @@ main(int argc, char **argv) if(c == ' ' && last == '(') continue; if(c == ')' && last == ' ') w--; if(c == ' ' && last == ' ') w--; - if(c == '(') pl++; - if(c == ')') pr++; + if(c == '(') pr++; + if(c == ')') pr--; if(c == '(' && last != '?' && !spacer(last)) *w++ = ' '; if(last == ')' && !spacer(c)) *w++ = ' '; *w++ = last = c; } - while(*(--w) <= ' ') *w = 0; fclose(f); - if(pr != pl) + if(pr) return !fprintf(stderr, "Modal program imbalanced.\n"); while(rewrite() && ++rw) if(!cycles--) return !fprintf(stderr, "Modal rewrites exceeded.\n"); From 2ce9aadd56651725ec92b80a997e9b1afffed0b7 Mon Sep 17 00:00:00 2001 From: Devine Lu Linvega Date: Thu, 9 May 2024 16:17:12 -0700 Subject: [PATCH 06/41] Added file_import --- examples/file.modal | 3 +++ makefile | 3 ++- src/modal.c | 54 ++++++++++++++++++++++++++++----------------- 3 files changed, 39 insertions(+), 21 deletions(-) create mode 100644 examples/file.modal diff --git a/examples/file.modal b/examples/file.modal new file mode 100644 index 0000000..5d89dd4 --- /dev/null +++ b/examples/file.modal @@ -0,0 +1,3 @@ +<> (?_ import) (?_) + +(examples/postcard.modal import) \ No newline at end of file diff --git a/makefile b/makefile index 563ad91..075d996 100644 --- a/makefile +++ b/makefile @@ -10,12 +10,13 @@ dest: run: all bin/modal @ bin/modal -q examples/hello.modal debug: all bin/modal-debug - @ bin/modal-debug examples/hello.modal + @ bin/modal-debug -a examples/file.modal test: all bin/modal-debug bin/modal @ bin/modal -v @ bin/modal-debug -q examples/fizzbuzz.modal @ bin/modal-debug -q examples/sierpinski.modal @ bin/modal-debug -q examples/tests.modal + @ bin/modal-debug -a examples/file.modal install: bin/modal cp bin/modal ~/bin/ uninstall: diff --git a/src/modal.c b/src/modal.c index 255a96b..315a87d 100644 --- a/src/modal.c +++ b/src/modal.c @@ -5,7 +5,7 @@ typedef struct { char *a, *b; } Rule; -static int flip, quiet, debug, cycles = 0x200000; +static int flip, quiet, debug, access, cycles = 0x200000; static Rule rules[0x1000], *rules_ = rules; static char dict[0x8000], *dict_ = dict, empty; static char bank_a[0x4000], *src_ = bank_a; @@ -95,12 +95,42 @@ device_read(void) dst_--; } +static void +file_import(char *path) +{ + FILE *f; + int pr = 0; + char c, last = 0; + if((f = fopen(path, "r"))) { + while(fread(&c, 1, 1, f)) { + c = c <= 0x20 ? 0x20 : c; + if(c == ' ' && last == '(') continue; + if(c == ')' && last == ' ') dst_--; + if(c == ' ' && last == ' ') dst_--; + if(c == '(') pr++; + if(c == ')') pr--; + if(c == '(' && last != '?' && !spacer(last)) *dst_++ = ' '; + if(last == ')' && !spacer(c)) *dst_++ = ' '; + *dst_++ = last = c; + } + fclose(f); + if(pr) fprintf(stderr, "Modal program imbalanced.\n"); + } else + *dst_++ = 'N', *dst_++ = 'A', *dst_++ = 'F'; +} + static void write_reg(char r, char *reg) { switch(r) { case ':': device_write(reg); return; case '~': device_read(); return; + case '_': { + char filepath[0x80], *path = filepath, *cap = walk(reg); + while(reg < cap) *path++ = *reg++; + file_import(filepath); + return; + } case '^': { /* op: join */ char c, *cap = walk(reg); if(*reg == '(') reg++, --cap; @@ -282,9 +312,7 @@ rewrite(void) int main(int argc, char **argv) { - FILE *f; - int i, pr = 0, rw = 0; - char c, last = 0, *w = bank_a; + int i, rw = 0; if(argc < 2) return !printf("usage: modal [-vqn] source.modal\n"); for(i = 1; i < argc && *argv[i] == '-'; i++) { @@ -292,25 +320,11 @@ main(int argc, char **argv) case 'v': /* version */ return !printf("Modal Interpreter, 9 May 2024.\n"); case 'q': /* quiet */ quiet = 1; break; case 'p': /* debug */ debug = 1; break; + case 'a': /* access */ access = 1; break; case 'n': /* infinite */ cycles = 0xffffffff; break; } } - if(!(f = fopen(argv[i], "r"))) - return !printf("Modal file invalid: %s.\n", argv[i]); - while(fread(&c, 1, 1, f)) { - c = c <= 0x20 ? 0x20 : c; - if(c == ' ' && last == '(') continue; - if(c == ')' && last == ' ') w--; - if(c == ' ' && last == ' ') w--; - if(c == '(') pr++; - if(c == ')') pr--; - if(c == '(' && last != '?' && !spacer(last)) *w++ = ' '; - if(last == ')' && !spacer(c)) *w++ = ' '; - *w++ = last = c; - } - fclose(f); - if(pr) - return !fprintf(stderr, "Modal program imbalanced.\n"); + dst_ = bank_a, file_import(argv[i]), dst_ = bank_b; while(rewrite() && ++rw) if(!cycles--) return !fprintf(stderr, "Modal rewrites exceeded.\n"); if(!quiet) { From 87cc3e816f6a6780500c88e81d1dd10d95136997 Mon Sep 17 00:00:00 2001 From: Devine Lu Linvega Date: Thu, 9 May 2024 16:45:34 -0700 Subject: [PATCH 07/41] Abstracted copy string --- examples/file.modal | 5 ++-- examples/import.modal | 1 + makefile | 4 +-- src/modal.c | 60 +++++++++++++++++++++---------------------- 4 files changed, 35 insertions(+), 35 deletions(-) create mode 100644 examples/import.modal diff --git a/examples/file.modal b/examples/file.modal index 5d89dd4..597f909 100644 --- a/examples/file.modal +++ b/examples/file.modal @@ -1,3 +1,4 @@ -<> (?_ import) (?_) +<> (?_ import) (?(?: ?:) (?_ \n) ) -(examples/postcard.modal import) \ No newline at end of file +(examples/import.modal import) +(examples/missing.modal import) diff --git a/examples/import.modal b/examples/import.modal new file mode 100644 index 0000000..ea0f4c3 --- /dev/null +++ b/examples/import.modal @@ -0,0 +1 @@ +(this (file (gets (imported by file.modal)))) \ No newline at end of file diff --git a/makefile b/makefile index 075d996..c486511 100644 --- a/makefile +++ b/makefile @@ -10,13 +10,13 @@ dest: run: all bin/modal @ bin/modal -q examples/hello.modal debug: all bin/modal-debug - @ bin/modal-debug -a examples/file.modal + @ bin/modal-debug -a examples/hello.modal test: all bin/modal-debug bin/modal @ bin/modal -v @ bin/modal-debug -q examples/fizzbuzz.modal @ bin/modal-debug -q examples/sierpinski.modal @ bin/modal-debug -q examples/tests.modal - @ bin/modal-debug -a examples/file.modal + @ bin/modal-debug -q -a examples/file.modal install: bin/modal cp bin/modal ~/bin/ uninstall: diff --git a/src/modal.c b/src/modal.c index 315a87d..8bc473c 100644 --- a/src/modal.c +++ b/src/modal.c @@ -14,6 +14,23 @@ static char *regs[0x100], stack[0x10], *stack_ = stack; #define spacer(c) (c <= ' ' || c == '(' || c == ')') +static char * +copy(char *src, char *dst, int length) +{ + while(length--) *dst++ = *src++; + return dst; +} + +static int +sint(char *s) +{ + char c; + int r = 0, n = 1; + if(*s == '-') { n = -1, s++; } + while((c = *s++) && !spacer(c)) r = r * 10 + c - '0'; + return r * n; +} + static char * walk(char *s) { @@ -30,16 +47,6 @@ walk(char *s) return s; } -static int -sint(char *s) -{ - char c; - int r = 0, n = 1; - if(*s == '-') { n = -1, s++; } - while((c = *s++) && !spacer(c)) r = r * 10 + c - '0'; - return r * n; -} - static void device_write(char *s) { @@ -87,12 +94,9 @@ static void device_read(void) { char c, *origin = dst_; - while(fread(&c, 1, 1, stdin) && c >= ' ') - *dst_++ = c; - if(feof(stdin)) - *dst_++ = 'E', *dst_++ = 'O', *dst_++ = 'F'; - if(dst_ - origin == 0) - dst_--; + while(fread(&c, 1, 1, stdin) && c >= ' ') *dst_++ = c; + if(feof(stdin)) dst_ = copy("EOF", dst_, 3); + if(dst_ - origin == 0) dst_--; } static void @@ -116,7 +120,7 @@ file_import(char *path) fclose(f); if(pr) fprintf(stderr, "Modal program imbalanced.\n"); } else - *dst_++ = 'N', *dst_++ = 'A', *dst_++ = 'F'; + dst_ = copy("NAF", dst_, 3); } static void @@ -126,8 +130,8 @@ write_reg(char r, char *reg) case ':': device_write(reg); return; case '~': device_read(); return; case '_': { - char filepath[0x80], *path = filepath, *cap = walk(reg); - while(reg < cap) *path++ = *reg++; + char filepath[0x80]; + copy(reg, filepath, walk(reg) - reg); file_import(filepath); return; } @@ -141,7 +145,7 @@ write_reg(char r, char *reg) case '.': { /* op: unwrap */ char *cap = walk(reg); if(*reg == '(') reg++, --cap; - while(reg < cap) *dst_++ = *reg++; + dst_ = copy(reg, dst_, cap - reg); return; } case '*': { /* op: explode */ @@ -162,8 +166,7 @@ write_reg(char r, char *reg) return; } default: { - char *cap = walk(reg); - while(reg < cap) *dst_++ = *reg++; + dst_ = copy(reg, dst_, walk(reg) - reg); return; } } @@ -233,7 +236,7 @@ parse_frag(char **side, char *src) } *side = dict_, cap = walk(src), wrapped = c == '('; if(wrapped) src++, cap--; - while(src < cap) c = *src, *dict_++ = *src++; + while(src < cap) *dict_++ = *src++; src += wrapped, *dict_++ = 0; return src; } @@ -328,14 +331,9 @@ main(int argc, char **argv) while(rewrite() && ++rw) if(!cycles--) return !fprintf(stderr, "Modal rewrites exceeded.\n"); if(!quiet) { - while(rules_-- > rules) { - if(rules_->a) { - if(!rules_->refs) - fprintf(stderr, "-- Unused rule: %d <> (%s) (%s)\n", rules_->id, rules_->a, rules_->b); - if(debug) - fprintf(stderr, " (%s) (%s), %d times.\n", rules_->a, rules_->b, rules_->refs); - } - } + while(rules_-- > rules) + if(rules_->a && !rules_->refs) + fprintf(stderr, "-- Unused rule: %d <> (%s) (%s)\n", rules_->id, rules_->a, rules_->b); if(rw) fprintf(stderr, ".. %s\nCompleted in %d rewrites.\n", src_, rw); } From 4f78e7cb3d0eae2e7da1f2cdac227a65cad90e06 Mon Sep 17 00:00:00 2001 From: Devine Lu Linvega Date: Thu, 9 May 2024 20:44:35 -0700 Subject: [PATCH 08/41] Improved formatter tests --- examples/tests.modal | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/tests.modal b/examples/tests.modal index 2c9d38e..e546086 100644 --- a/examples/tests.modal +++ b/examples/tests.modal @@ -8,12 +8,12 @@ ?(?-) (Formatter) -?((?x ?y) two) aaa(bbb) = two (formatter 1) test -?((?x ?y) two) (bbb)aaa = two (formatter 2) test -(a b c ) = (a b c) (formatter 3) test -( a b c) = (a b c) (formatter 4) test -( a b c ) = (a b c) (formatter 5) test -(a b c ( a b c ) ) = (a b c (a b c)) (formatter 6) test +?((aaa (bbb)) ok) aaa(bbb) = ok (formatter 1) test +?(((bbb) aaa) ok) (bbb)aaa = ok (formatter 2) test +?(((?a ?b ?c)) ((?a ?b ?c))) (a b c ) = (a b c) (formatter 3) test +?(((?a ?b ?c)) ((?a ?b ?c))) ( a b c) = (a b c) (formatter 4) test +?(((?a ?b ?c)) ((?a ?b ?c))) ( a b c ) = (a b c) (formatter 5) test +?(((?a ?b ?c (?d ?e ?f))) ((?a ?b ?c (?d ?e ?f)))) (a b c ( a b c ) ) = (a b c (a b c)) (formatter 6) test ?(?-) (Empty replacements) From fec9cffcd6dbf11567a2dfe258c220af213856d2 Mon Sep 17 00:00:00 2001 From: Devine Lu Linvega Date: Thu, 9 May 2024 21:01:55 -0700 Subject: [PATCH 09/41] Removed formatter for file input --- examples/tictactoe.modal | 2 +- src/modal.c | 9 ++------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/examples/tictactoe.modal b/examples/tictactoe.modal index d69b1c3..4b29a7f 100644 --- a/examples/tictactoe.modal +++ b/examples/tictactoe.modal @@ -41,4 +41,4 @@ -- (Interface) ((Input a move, like "X 0 1":\n) put-str) -((- - -) (- - -) (- - -)) ready +((- - -) (- - -) (- - -)) ready diff --git a/src/modal.c b/src/modal.c index 8bc473c..56c55a2 100644 --- a/src/modal.c +++ b/src/modal.c @@ -104,18 +104,13 @@ file_import(char *path) { FILE *f; int pr = 0; - char c, last = 0; + char c; if((f = fopen(path, "r"))) { while(fread(&c, 1, 1, f)) { c = c <= 0x20 ? 0x20 : c; - if(c == ' ' && last == '(') continue; - if(c == ')' && last == ' ') dst_--; - if(c == ' ' && last == ' ') dst_--; if(c == '(') pr++; if(c == ')') pr--; - if(c == '(' && last != '?' && !spacer(last)) *dst_++ = ' '; - if(last == ')' && !spacer(c)) *dst_++ = ' '; - *dst_++ = last = c; + *dst_++ = c; } fclose(f); if(pr) fprintf(stderr, "Modal program imbalanced.\n"); From 0de5bb473bbdeef17417ae9f32d9f9c4bb09c9e1 Mon Sep 17 00:00:00 2001 From: Devine Lu Linvega Date: Fri, 10 May 2024 08:42:37 -0700 Subject: [PATCH 10/41] Improved implementation of file_import --- src/modal.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/modal.c b/src/modal.c index 56c55a2..4a94246 100644 --- a/src/modal.c +++ b/src/modal.c @@ -99,23 +99,24 @@ device_read(void) if(dst_ - origin == 0) dst_--; } -static void -file_import(char *path) +static char * +file_import(char *path, char *ptr) { FILE *f; int pr = 0; - char c; if((f = fopen(path, "r"))) { + char c; while(fread(&c, 1, 1, f)) { c = c <= 0x20 ? 0x20 : c; if(c == '(') pr++; if(c == ')') pr--; - *dst_++ = c; + *ptr++ = c; } fclose(f); if(pr) fprintf(stderr, "Modal program imbalanced.\n"); - } else - dst_ = copy("NAF", dst_, 3); + return ptr; + } + return copy("NAF", ptr, 3); } static void @@ -127,7 +128,7 @@ write_reg(char r, char *reg) case '_': { char filepath[0x80]; copy(reg, filepath, walk(reg) - reg); - file_import(filepath); + dst_ = file_import(filepath, dst_); return; } case '^': { /* op: join */ @@ -322,7 +323,7 @@ main(int argc, char **argv) case 'n': /* infinite */ cycles = 0xffffffff; break; } } - dst_ = bank_a, file_import(argv[i]), dst_ = bank_b; + file_import(argv[i], src_); while(rewrite() && ++rw) if(!cycles--) return !fprintf(stderr, "Modal rewrites exceeded.\n"); if(!quiet) { From f6d0cc8eceb3a47ae5c7b315abe5f9205a211235 Mon Sep 17 00:00:00 2001 From: Devine Lu Linvega Date: Fri, 10 May 2024 09:31:09 -0700 Subject: [PATCH 11/41] Use copy() in parse_frag --- src/modal.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/modal.c b/src/modal.c index 4a94246..c18da75 100644 --- a/src/modal.c +++ b/src/modal.c @@ -221,20 +221,19 @@ apply_rule(Rule *r, char *s) } static char * -parse_frag(char **side, char *src) +parse_frag(char **side, char *s) { int wrapped; char c, *cap; - while((c = *src) && c == ' ') src++; - if(c == ')' || (c == '<' && src[1] == '>')) { + while((c = *s) && c == ' ') s++; + if(c == ')' || (c == '<' && s[1] == '>')) { *side = ∅ - return src; + return s; } - *side = dict_, cap = walk(src), wrapped = c == '('; - if(wrapped) src++, cap--; - while(src < cap) *dict_++ = *src++; - src += wrapped, *dict_++ = 0; - return src; + *side = dict_, cap = walk(s), wrapped = c == '('; + if(wrapped) s++, cap--; + dict_ = copy(s, dict_, cap - s), s = cap + wrapped, *dict_++ = 0; + return s; } static Rule * @@ -291,7 +290,7 @@ rewrite(void) parse_frag(&r->b, parse_frag(&r->a, s + 2)); s = cap; while(*s == ' ') s++; - if(!apply_rule(r, s)) { + if(r->a && !apply_rule(r, s)) { if(!quiet) fprintf(stderr, "%02d %s\n", r->id, src_), ++r->refs; write_tail(s); } From 318a5fddf5333fd7d0374a898e9697640c8587ab Mon Sep 17 00:00:00 2001 From: Devine Lu Linvega Date: Fri, 10 May 2024 09:36:40 -0700 Subject: [PATCH 12/41] Reformatted parse_frag --- src/modal.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/modal.c b/src/modal.c index c18da75..bdb77be 100644 --- a/src/modal.c +++ b/src/modal.c @@ -223,16 +223,16 @@ apply_rule(Rule *r, char *s) static char * parse_frag(char **side, char *s) { - int wrapped; char c, *cap; while((c = *s) && c == ' ') s++; - if(c == ')' || (c == '<' && s[1] == '>')) { + if(c == ')' || (c == '<' || c == '>')) *side = ∅ - return s; + else { + int wrapped; + *side = dict_, cap = walk(s), wrapped = c == '('; + if(wrapped) s++, cap--; + dict_ = copy(s, dict_, cap - s), s = cap + wrapped, *dict_++ = 0; } - *side = dict_, cap = walk(s), wrapped = c == '('; - if(wrapped) s++, cap--; - dict_ = copy(s, dict_, cap - s), s = cap + wrapped, *dict_++ = 0; return s; } From 3cbd3d196dbcb6045291da9d570a80c319c2511f Mon Sep 17 00:00:00 2001 From: Devine Lu Linvega Date: Fri, 10 May 2024 09:45:58 -0700 Subject: [PATCH 13/41] Faster parse frag --- src/modal.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/modal.c b/src/modal.c index bdb77be..8c21e5c 100644 --- a/src/modal.c +++ b/src/modal.c @@ -228,10 +228,12 @@ parse_frag(char **side, char *s) if(c == ')' || (c == '<' || c == '>')) *side = ∅ else { - int wrapped; - *side = dict_, cap = walk(s), wrapped = c == '('; - if(wrapped) s++, cap--; - dict_ = copy(s, dict_, cap - s), s = cap + wrapped, *dict_++ = 0; + cap = walk(s), *side = dict_; + if(c == '(') + dict_ = copy(s + 1, dict_, cap - s - 2); + else + dict_ = copy(s, dict_, cap - s); + s = cap, *dict_++ = 0; } return s; } From e3316d6cbe89491a38bca3a811b5585acb58e103 Mon Sep 17 00:00:00 2001 From: Devine Lu Linvega Date: Fri, 10 May 2024 09:52:03 -0700 Subject: [PATCH 14/41] Lambda should not print when application fail --- src/modal.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/modal.c b/src/modal.c index 8c21e5c..24c4b08 100644 --- a/src/modal.c +++ b/src/modal.c @@ -292,10 +292,7 @@ rewrite(void) parse_frag(&r->b, parse_frag(&r->a, s + 2)); s = cap; while(*s == ' ') s++; - if(r->a && !apply_rule(r, s)) { - if(!quiet) fprintf(stderr, "%02d %s\n", r->id, src_), ++r->refs; - write_tail(s); - } + if(r->a && !apply_rule(r, s)) write_tail(s); dict_ = d; return 1; } From 79b9831f27e2d817c2c1c604e00656fcf7c0e220 Mon Sep 17 00:00:00 2001 From: Devine Lu Linvega Date: Fri, 10 May 2024 13:39:01 -0700 Subject: [PATCH 15/41] Added numbers to tests --- examples/tests.modal | 109 +++++++++++++++++++++---------------------- makefile | 3 +- 2 files changed, 55 insertions(+), 57 deletions(-) diff --git a/examples/tests.modal b/examples/tests.modal index e546086..e44060b 100644 --- a/examples/tests.modal +++ b/examples/tests.modal @@ -8,30 +8,29 @@ ?(?-) (Formatter) -?((aaa (bbb)) ok) aaa(bbb) = ok (formatter 1) test -?(((bbb) aaa) ok) (bbb)aaa = ok (formatter 2) test -?(((?a ?b ?c)) ((?a ?b ?c))) (a b c ) = (a b c) (formatter 3) test -?(((?a ?b ?c)) ((?a ?b ?c))) ( a b c) = (a b c) (formatter 4) test -?(((?a ?b ?c)) ((?a ?b ?c))) ( a b c ) = (a b c) (formatter 5) test -?(((?a ?b ?c (?d ?e ?f))) ((?a ?b ?c (?d ?e ?f)))) (a b c ( a b c ) ) = (a b c (a b c)) (formatter 6) test +?((aaa (bbb)) ok) aaa(bbb) = ok (formatter 1/6) test +?(((bbb) aaa) ok) (bbb)aaa = ok (formatter 2/6) test +?(((?a ?b ?c)) ((?a ?b ?c))) (a b c ) = (a b c) (formatter 3/6) test +?(((?a ?b ?c)) ((?a ?b ?c))) ( a b c) = (a b c) (formatter 4/6) test +?(((?a ?b ?c)) ((?a ?b ?c))) ( a b c ) = (a b c) (formatter 5/6) test +?(((?a ?b ?c (?d ?e ?f))) ((?a ?b ?c (?d ?e ?f)))) (a b c ( a b c ) ) = (a b c (a b c)) (formatter 6/6) test ?(?-) (Empty replacements) -(ab cd () ghost) = (ab cd ()) (empty 1) test -(ab cd ghost ()) = (ab cd ()) (empty 2) test -(ab ghost cd ()) = (ab cd ()) (empty 3) test -(ghost ab cd ()) = (ab cd ()) (empty 4) test -(ghost) = () (empty 5) test - -(q ?((?x ?y ?z) (?x ?y)) a b c) = (q a b) (empty 6) test -(q ?((?x ?y ?z) (?x ?z)) a b c) = (q a c) (empty 7) test -(q ?((?x ?y ?z) (?y ?z)) a b c) = (q b c) (empty 8) test +(ab cd () ghost) = (ab cd ()) (empty 1/10) test +(ab cd ghost ()) = (ab cd ()) (empty 2/10) test +(ab ghost cd ()) = (ab cd ()) (empty 3/10) test +(ghost ab cd ()) = (ab cd ()) (empty 4/10) test +(ghost) = () (empty 5/10) test +(q ?((?x ?y ?z) (?x ?y)) a b c) = (q a b) (empty 6/10) test +(q ?((?x ?y ?z) (?x ?z)) a b c) = (q a c) (empty 7/10) test +(q ?((?x ?y ?z) (?y ?z)) a b c) = (q b c) (empty 8/10) test <> (prefix/pop ?x) () <> (?x suffix/pop) () -(ab prefix/pop cd ef) = (ab ef) (empty 9) test -(ab cd suffix/pop ef) = (ab ef) (empty 10) test +(ab prefix/pop cd ef) = (ab ef) (empty 9/10) test +(ab cd suffix/pop ef) = (ab ef) (empty 10/10) test ?(?-) (Basic register setups) @@ -41,50 +40,42 @@ <> (rotate (?x (?y (?z)))) (?y (?z (?x))) <> (unused ?x) ?y -(dup (abc)) = (abc abc) (basic 1) test -(swap (abc def)) = (def abc) (basic 2) test -(compare (abc abc abc)) = (#t) (basic 3) test -(rotate (abc (def (ghi)))) = (def (ghi (abc))) (basic 4) test -(unused hey) = (?y) (basic 5) test +(dup (abc)) = (abc abc) (basic 1/5) test +(swap (abc def)) = (def abc) (basic 2/5) test +(compare (abc abc abc)) = (#t) (basic 3/5) test +(rotate (abc (def (ghi)))) = (def (ghi (abc))) (basic 4/5) test +(unused hey) = (?y) (basic 5/5) test ?(?-) (Substring registers) <> (connect ?x ?y ?z) (?x-?y?z) <> (prefix-?x) (?x-suffix) -connect foo bar baz = foo-barbaz (substring 1) test -prefix-anything = anything-suffix (substring 2) test -?(foo QQQ) foobar = foobar (substring 3) test +connect foo bar baz = foo-barbaz (substring 1/3) test +prefix-anything = anything-suffix (substring 2/3) test +?(foo QQQ) foobar = foobar (substring 3/3) test ?(?-) (Lambdas) -(?(?x (?x ?x)) abc) = (abc abc) (lambda 1) test -abc ?(?x) def = abc (lambda 2) test +(?(?x (?x ?x)) abc) = (abc abc) (lambda 1/2) test +abc ?(?x) def = abc (lambda 2/2) test ?(?-) (op: explode) -(?(?* ?*) cow) = (c (o (w ()))) (explode word) test -(?(?* ?*) (12 34 45)) = (12 (34 (45 ()))) (explode tuple) test -(?(?* ?*) ()) = () (explode empty) test +(?(?* ?*) cow) = (c (o (w ()))) (explode word 1/3) test +(?(?* ?*) (12 34 45)) = (12 (34 (45 ()))) (explode tuple 2/3) test +(?(?* ?*) ()) = () (explode empty 3/3) test ?(?-) (op: join) -?(?^ ?^) (b (a (t ()))) = bat (join 1) test -?(?^ ?^) (12 (34 (56 ()))) = 123456 (join 2) test -(?(?^ ?^) ()) = () (join empty) test +?(?^ ?^) (b (a (t ()))) = bat (join 1/3) test +?(?^ ?^) (12 (34 (56 ()))) = 123456 (join 2/3) test +(?(?^ ?^) ()) = () (join 3/3) test ?(?-) (op: unwrap) -?(?. ?.) (abcd) = abcd (unwrap 1) test -(?(?. ?.) ()) = () (unwrap empty) test - -?(?-) (List reversal) - -<> (reverse List () ?^) (?^) -<> (reverse (?*)) (reverse List (?*) ()) -<> (reverse List (?x ?y) ?z) (reverse List ?y (?x ?z)) - -reverse (modal) = ladom (reverse 1) test +?(?. ?.) (abcd) = abcd (unwrap 1/2) test +(?(?. ?.) ()) = () (unwrap 2/2) test ?(?-) (Incomplete definitions) @@ -94,17 +85,17 @@ reverse (modal) = ladom (reverse 1) test <> (incomplete-reg ?x) <> (waste-rule) * -(incomplete-basic) = () (incomplete 1) test -(incomplete-reg abcdef) = () (incomplete 2) test -(?(?x) incomplete-lambda) = () (incomplete 3) test -(?() abc) = (abc) (incomplete 4) test +(incomplete-basic) = () (incomplete 1/4) test +(incomplete-reg abcdef) = () (incomplete 2/4) test +(?(?x) incomplete-lambda) = () (incomplete 3/4) test +(?() abc) = (abc) (incomplete 4/4) test ?(?-) (Inline rules) <> ((?x -> ?y)) (<> ?x ?y) (nap -> (tap =)) -nap tap (inline 1) test +nap tap (inline 1/1) test ?(?-) (Undefinition) @@ -113,27 +104,35 @@ nap tap (inline 1) test <> (undefine-me) (ghi) >< (undefine-me) -(undefine-me) = (def) (undefinition 1) test +(undefine-me) = (def) (undefinition 1/3) test >< (undefine-me) -(undefine-me) = (ghi) (undefinition 2) test +(undefine-me) = (ghi) (undefinition 2/3) test >< (undefine-unknown) ?(* (>< (undefine-me))) * -(undefine-me) = (undefine-me) (undefinition 3) test +(undefine-me) = (undefine-me) (undefinition 3/3) test ?(?-) (Arithmetic) -?((?: ?0 ?1 ?2) ?:) + 1 2 3 = 6 (Arithmetic 1) test -?((?0 ?: ?1) ?:) 16 - 8 = 8 (Arithmetic 2) test -?((?0 ?1 ?:) ?:) 12 10 * = 120 (Arithmetic 3) test +?((?: ?0 ?1 ?2) ?:) + 1 2 3 = 6 (Arithmetic 1/4) test +?((?0 ?: ?1) ?:) 16 - 8 = 8 (Arithmetic 2/4) test +?((?0 ?1 ?:) ?:) 12 10 * = 120 (Arithmetic 3/4) test <> (?0 ?1 `?:) (?:) -(12 45 `+ -2 `+) = (55) (Arithmetic 4) test +(12 45 `+ -2 `+) = (55) (Arithmetic 4/4) test + +?(?-) (List reversal) + +<> (reverse List () ?^) (?^) +<> (reverse (?*)) (reverse List (?*) ()) +<> (reverse List (?x ?y) ?z) (reverse List ?y (?x ?z)) + +reverse (modal) = ladom (reverse 1) test ?(?-) (Late Test Primitives) diff --git a/makefile b/makefile index c486511..906314b 100644 --- a/makefile +++ b/makefile @@ -15,8 +15,7 @@ test: all bin/modal-debug bin/modal @ bin/modal -v @ bin/modal-debug -q examples/fizzbuzz.modal @ bin/modal-debug -q examples/sierpinski.modal - @ bin/modal-debug -q examples/tests.modal - @ bin/modal-debug -q -a examples/file.modal + @ bin/modal-debug -q -a examples/tests.modal install: bin/modal cp bin/modal ~/bin/ uninstall: From e80db68aa6b1ff4950e9b7fe1da8618fdf0e772b Mon Sep 17 00:00:00 2001 From: Devine Lu Linvega Date: Fri, 10 May 2024 14:05:15 -0700 Subject: [PATCH 16/41] Use NULL for empty rules --- examples/tests.modal | 2 -- src/modal.c | 21 +++++++++++---------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/examples/tests.modal b/examples/tests.modal index e44060b..e2c7881 100644 --- a/examples/tests.modal +++ b/examples/tests.modal @@ -79,8 +79,6 @@ abc ?(?x) def = abc (lambda 2/2) test ?(?-) (Incomplete definitions) -<> <> -<> () () <> (incomplete-basic) <> (incomplete-reg ?x) <> (waste-rule) * diff --git a/src/modal.c b/src/modal.c index 24c4b08..35f7992 100644 --- a/src/modal.c +++ b/src/modal.c @@ -7,7 +7,7 @@ typedef struct { static int flip, quiet, debug, access, cycles = 0x200000; static Rule rules[0x1000], *rules_ = rules; -static char dict[0x8000], *dict_ = dict, empty; +static char dict[0x8000], *dict_ = dict; static char bank_a[0x4000], *src_ = bank_a; static char bank_b[0x4000], *dst_ = bank_b; static char *regs[0x100], stack[0x10], *stack_ = stack; @@ -206,11 +206,12 @@ apply_rule(Rule *r, char *s) c = *s; if(!spacer(c)) return 0; /* phase: write rule */ - while((c = *b++)) { - if(c == '?' && (rid = *b) && (reg = regs[rid])) - write_reg(rid, reg), b++; - else - *dst_++ = c; + if(b != NULL) { + while((c = *b++)) + if(c == '?' && (rid = *b) && (reg = regs[rid])) + write_reg(rid, reg), b++; + else + *dst_++ = c; } if(dst_ == origin) { while(*s == ' ') s++; @@ -226,7 +227,7 @@ parse_frag(char **side, char *s) char c, *cap; while((c = *s) && c == ' ') s++; if(c == ')' || (c == '<' || c == '>')) - *side = ∅ + *side = NULL; else { cap = walk(s), *side = dict_; if(c == '(') @@ -277,7 +278,7 @@ rewrite(void) if(c == '<' && s[1] == '>') { r = rules_, r->id = rules_ - rules; s = parse_frag(&r->b, parse_frag(&r->a, s + 2)); - if(*r->a) { + if(r->a != NULL) { if(!quiet) fprintf(stderr, "<> (%s) (%s)\n", r->a, r->b); rules_++; } @@ -292,13 +293,13 @@ rewrite(void) parse_frag(&r->b, parse_frag(&r->a, s + 2)); s = cap; while(*s == ' ') s++; - if(r->a && !apply_rule(r, s)) write_tail(s); + if(r->a == NULL || !apply_rule(r, s)) write_tail(s); dict_ = d; return 1; } /* phase: match */ for(r = rules; r < rules_; r++) - if(r->a && apply_rule(r, s)) return 1; + if(r->a != NULL && apply_rule(r, s)) return 1; } *dst_++ = last = c, s++; } From 4a57c3c56436c483523cc7247d9c207a90c3b8e4 Mon Sep 17 00:00:00 2001 From: Devine Lu Linvega Date: Fri, 10 May 2024 14:25:54 -0700 Subject: [PATCH 17/41] Catch empty rules --- examples/tests.modal | 3 ++- src/modal.c | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/examples/tests.modal b/examples/tests.modal index e2c7881..4f58865 100644 --- a/examples/tests.modal +++ b/examples/tests.modal @@ -81,7 +81,8 @@ abc ?(?x) def = abc (lambda 2/2) test <> (incomplete-basic) <> (incomplete-reg ?x) -<> (waste-rule) * +<> <> +<> () () (incomplete-basic) = () (incomplete 1/4) test (incomplete-reg abcdef) = () (incomplete 2/4) test diff --git a/src/modal.c b/src/modal.c index 35f7992..55ef37f 100644 --- a/src/modal.c +++ b/src/modal.c @@ -226,7 +226,7 @@ parse_frag(char **side, char *s) { char c, *cap; while((c = *s) && c == ' ') s++; - if(c == ')' || (c == '<' || c == '>')) + if(c == ')' || c == '<' || c == '>' || (c == '(' && s[1] == ')')) *side = NULL; else { cap = walk(s), *side = dict_; @@ -315,7 +315,7 @@ main(int argc, char **argv) return !printf("usage: modal [-vqn] source.modal\n"); for(i = 1; i < argc && *argv[i] == '-'; i++) { switch(argv[i][1]) { - case 'v': /* version */ return !printf("Modal Interpreter, 9 May 2024.\n"); + case 'v': /* version */ return !printf("Modal Interpreter, 10 May 2024.\n"); case 'q': /* quiet */ quiet = 1; break; case 'p': /* debug */ debug = 1; break; case 'a': /* access */ access = 1; break; From c89013f263065cbd566bb3d36a1283e749c3fb39 Mon Sep 17 00:00:00 2001 From: Devine Lu Linvega Date: Fri, 10 May 2024 14:36:58 -0700 Subject: [PATCH 18/41] Allow for unicode --- examples/unicode.modal | 4 ++++ makefile | 2 +- src/modal.c | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 examples/unicode.modal diff --git a/examples/unicode.modal b/examples/unicode.modal new file mode 100644 index 0000000..a1fe73f --- /dev/null +++ b/examples/unicode.modal @@ -0,0 +1,4 @@ +<> (🯅 |) () +<> (🯅 ?x) (?x 🯅) + +🯅 _ _ _ | diff --git a/makefile b/makefile index 906314b..afebb2f 100644 --- a/makefile +++ b/makefile @@ -10,7 +10,7 @@ dest: run: all bin/modal @ bin/modal -q examples/hello.modal debug: all bin/modal-debug - @ bin/modal-debug -a examples/hello.modal + @ bin/modal-debug -a examples/unicode.modal test: all bin/modal-debug bin/modal @ bin/modal -v @ bin/modal-debug -q examples/fizzbuzz.modal diff --git a/src/modal.c b/src/modal.c index 55ef37f..dcdbd88 100644 --- a/src/modal.c +++ b/src/modal.c @@ -105,7 +105,7 @@ file_import(char *path, char *ptr) FILE *f; int pr = 0; if((f = fopen(path, "r"))) { - char c; + unsigned char c; while(fread(&c, 1, 1, f)) { c = c <= 0x20 ? 0x20 : c; if(c == '(') pr++; From 4f03a673cccbf25c2b4ae9b16b4cf9decb93fda2 Mon Sep 17 00:00:00 2001 From: Devine Lu Linvega Date: Fri, 10 May 2024 15:53:25 -0700 Subject: [PATCH 19/41] Improved unicode test --- examples/unicode.modal | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/unicode.modal b/examples/unicode.modal index a1fe73f..24ad374 100644 --- a/examples/unicode.modal +++ b/examples/unicode.modal @@ -1,4 +1,6 @@ -<> (🯅 |) () +<> (🯅 (?x)) (🯅) +<> (🯅 🯉) (🯉 🯅 (hey!)) +<> (?x 🯉) (🯉 ?x) <> (🯅 ?x) (?x 🯅) -🯅 _ _ _ | +🯅 _ _ _ 🯉 \ No newline at end of file From 72bb13b59dc544eb444bd1ee99a6b33a1b2c5434 Mon Sep 17 00:00:00 2001 From: Devine Lu Linvega Date: Fri, 10 May 2024 16:26:40 -0700 Subject: [PATCH 20/41] Added access flag in README --- README.md | 1 + examples/tests.modal | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f3ca1ea..6fd2991 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ bin/modal examples/hello.modal -v Print version -q Quiet mode, no step printing -p Print summary with refs count + -a Allow files to be imported -n Infinite mode, no rewrites limit ``` diff --git a/examples/tests.modal b/examples/tests.modal index 4f58865..4438ef0 100644 --- a/examples/tests.modal +++ b/examples/tests.modal @@ -93,8 +93,14 @@ abc ?(?x) def = abc (lambda 2/2) test <> ((?x -> ?y)) (<> ?x ?y) (nap -> (tap =)) +nap tap (inline 1/2) test -nap tap (inline 1/1) test +<> (?x -> ?y) (<> ?x ?y) +fruit_a -> apple +fruit_b -> banana +(apple banana) -> (fruit-salad) + +(fruit_a fruit_b) = (fruit-salad) (inline 2/2) test ?(?-) (Undefinition) From a97e6b1963ab9d1943318f992a0208e4b222323e Mon Sep 17 00:00:00 2001 From: Devine Lu Linvega Date: Fri, 10 May 2024 19:59:59 -0700 Subject: [PATCH 21/41] Removed check for empty input --- src/modal.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/modal.c b/src/modal.c index dcdbd88..226e61b 100644 --- a/src/modal.c +++ b/src/modal.c @@ -96,7 +96,6 @@ device_read(void) char c, *origin = dst_; while(fread(&c, 1, 1, stdin) && c >= ' ') *dst_++ = c; if(feof(stdin)) dst_ = copy("EOF", dst_, 3); - if(dst_ - origin == 0) dst_--; } static char * From 16cb1823c42c36f909e01a821a4c2200f1c722c3 Mon Sep 17 00:00:00 2001 From: Devine Lu Linvega Date: Fri, 10 May 2024 20:17:05 -0700 Subject: [PATCH 22/41] Empty rules are leaving empty lists behind --- src/modal.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/modal.c b/src/modal.c index 226e61b..41bcb1d 100644 --- a/src/modal.c +++ b/src/modal.c @@ -225,9 +225,13 @@ parse_frag(char **side, char *s) { char c, *cap; while((c = *s) && c == ' ') s++; - if(c == ')' || c == '<' || c == '>' || (c == '(' && s[1] == ')')) + if(c == ')') { *side = NULL; - else { + return s; + } else if((c == '<' && s[1] == '>') || (c == '>' && s[1] == '<') || (c == '(' && s[1] == ')')) { + *side = NULL; + return s + 2; + } else { cap = walk(s), *side = dict_; if(c == '(') dict_ = copy(s + 1, dict_, cap - s - 2); @@ -267,7 +271,7 @@ rewrite(void) while(*s == ' ') s++; cap = walk(s), r = find_rule(s, cap); if(r != NULL) { - if(!quiet) fprintf(stderr, ">< (%s) (%s)\n", r->a, r->b); + if(!quiet) fprintf(stderr, ">< (%s) (%s)\n", r->a ? r->a : "", r->b ? r->b : ""); r->a = 0; } while(*cap == ' ') cap++; @@ -278,7 +282,7 @@ rewrite(void) r = rules_, r->id = rules_ - rules; s = parse_frag(&r->b, parse_frag(&r->a, s + 2)); if(r->a != NULL) { - if(!quiet) fprintf(stderr, "<> (%s) (%s)\n", r->a, r->b); + if(!quiet) fprintf(stderr, "<> (%s) (%s)\n", r->a ? r->a : "", r->b ? r->b : ""); rules_++; } while(*s == ' ') s++; From 8d49821fddc1519229c01f4ef5d55b1d307173f8 Mon Sep 17 00:00:00 2001 From: Devine Lu Linvega Date: Fri, 10 May 2024 20:24:47 -0700 Subject: [PATCH 23/41] Allow input of utf8 characters --- src/modal.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/modal.c b/src/modal.c index 41bcb1d..5447fde 100644 --- a/src/modal.c +++ b/src/modal.c @@ -90,14 +90,6 @@ device_write(char *s) } } -static void -device_read(void) -{ - char c, *origin = dst_; - while(fread(&c, 1, 1, stdin) && c >= ' ') *dst_++ = c; - if(feof(stdin)) dst_ = copy("EOF", dst_, 3); -} - static char * file_import(char *path, char *ptr) { @@ -123,7 +115,12 @@ write_reg(char r, char *reg) { switch(r) { case ':': device_write(reg); return; - case '~': device_read(); return; + case '~': { + unsigned char c; + while(fread(&c, 1, 1, stdin) && c >= ' ') *dst_++ = c; + if(feof(stdin)) dst_ = copy("EOF", dst_, 3); + return; + } case '_': { char filepath[0x80]; copy(reg, filepath, walk(reg) - reg); From 549d7d52185166f9e5f0b909b925c72a4cd9f9e2 Mon Sep 17 00:00:00 2001 From: Devine Lu Linvega Date: Fri, 10 May 2024 20:35:49 -0700 Subject: [PATCH 24/41] Explode should not include the closing paren --- src/modal.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/modal.c b/src/modal.c index 5447fde..91f31c3 100644 --- a/src/modal.c +++ b/src/modal.c @@ -145,11 +145,10 @@ write_reg(char r, char *reg) char c, *cap = walk(reg); if(*reg == '(' && reg[1] != ')') { /* tuple */ reg++; - while(reg < cap) { + while(reg < cap - 1) { while((c = *reg) && !spacer(c)) *dst_++ = c, reg++; - *dst_++ = ' '; - *dst_++ = '(', reg++, depth++; + *dst_++ = ' ', *dst_++ = '(', reg++, depth++; } } else /* token */ while((c = *reg++) && !spacer(c)) From f7a2b491208ad805dddc27c54123d40d16ff7eda Mon Sep 17 00:00:00 2001 From: Devine Lu Linvega Date: Mon, 13 May 2024 12:32:44 -0700 Subject: [PATCH 25/41] Added hex output --- examples/binary.modal | 5 +++++ makefile | 2 +- src/modal.c | 33 +++++++++++++++++++++++++-------- 3 files changed, 31 insertions(+), 9 deletions(-) create mode 100644 examples/binary.modal diff --git a/examples/binary.modal b/examples/binary.modal new file mode 100644 index 0000000..9a98afc --- /dev/null +++ b/examples/binary.modal @@ -0,0 +1,5 @@ +?(?: ?:) \#48 +?(?: ?:) \101 +?(?: ?:) \#6c +?(?: ?:) \108 +?(?: ?:) \#6f \ No newline at end of file diff --git a/makefile b/makefile index afebb2f..a7e9458 100644 --- a/makefile +++ b/makefile @@ -10,7 +10,7 @@ dest: run: all bin/modal @ bin/modal -q examples/hello.modal debug: all bin/modal-debug - @ bin/modal-debug -a examples/unicode.modal + @ bin/modal-debug -a examples/binary.modal test: all bin/modal-debug bin/modal @ bin/modal -v @ bin/modal-debug -q examples/fizzbuzz.modal diff --git a/src/modal.c b/src/modal.c index 91f31c3..e74ec10 100644 --- a/src/modal.c +++ b/src/modal.c @@ -21,14 +21,14 @@ copy(char *src, char *dst, int length) return dst; } -static int -sint(char *s) +int +chex(char c) { - char c; - int r = 0, n = 1; - if(*s == '-') { n = -1, s++; } - while((c = *s++) && !spacer(c)) r = r * 10 + c - '0'; - return r * n; + c -= 0x30; + if(c < 10) return c; + c -= 0x31; + if(c < 6) return 10 + c; + return 0; } static char * @@ -47,6 +47,21 @@ walk(char *s) return s; } +static int +sint(char *s) +{ + char c = *s, *cap = walk(s); + int r = 0, n = 1; + if(c == '#') { + s++; + while((c = *s) && s++ < cap) r = (r << 4) | chex(c); + return r; + } + if(c == '-') { n = -1, s++; } + while((c = *s) && s++ < cap) r = r * 10 + c - '0'; + return r * n; +} + static void device_write(char *s) { @@ -83,7 +98,9 @@ device_write(char *s) case 't': putc(0x09, stdout); break; case 'n': putc(0x0a, stdout); break; case 's': putc(0x20, stdout); break; + default: putc(sint(--s), stdout), s = walk(s); } + } else putc(c, stdout); } @@ -314,7 +331,7 @@ main(int argc, char **argv) return !printf("usage: modal [-vqn] source.modal\n"); for(i = 1; i < argc && *argv[i] == '-'; i++) { switch(argv[i][1]) { - case 'v': /* version */ return !printf("Modal Interpreter, 10 May 2024.\n"); + case 'v': /* version */ return !printf("Modal Interpreter, 13 May 2024.\n"); case 'q': /* quiet */ quiet = 1; break; case 'p': /* debug */ debug = 1; break; case 'a': /* access */ access = 1; break; From f88bb1f137a20d5c9138289eb10571ab5c6af1c0 Mon Sep 17 00:00:00 2001 From: Devine Lu Linvega Date: Mon, 13 May 2024 14:37:21 -0700 Subject: [PATCH 26/41] Use macro for chex --- src/modal.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/src/modal.c b/src/modal.c index e74ec10..13a886c 100644 --- a/src/modal.c +++ b/src/modal.c @@ -13,6 +13,7 @@ static char bank_b[0x4000], *dst_ = bank_b; static char *regs[0x100], stack[0x10], *stack_ = stack; #define spacer(c) (c <= ' ' || c == '(' || c == ')') +#define chex(c) (0xf & (c - (c <= '9' ? '0' : 0x57))) static char * copy(char *src, char *dst, int length) @@ -21,16 +22,6 @@ copy(char *src, char *dst, int length) return dst; } -int -chex(char c) -{ - c -= 0x30; - if(c < 10) return c; - c -= 0x31; - if(c < 6) return 10 + c; - return 0; -} - static char * walk(char *s) { @@ -98,9 +89,9 @@ device_write(char *s) case 't': putc(0x09, stdout); break; case 'n': putc(0x0a, stdout); break; case 's': putc(0x20, stdout); break; - default: putc(sint(--s), stdout), s = walk(s); + default: putc(sint(--s), stdout), s = walk(s); } - + } else putc(c, stdout); } From 5419d9579adc072b77adb56bd8ef25e95c83ee8f Mon Sep 17 00:00:00 2001 From: Devine Lu Linvega Date: Mon, 13 May 2024 15:14:37 -0700 Subject: [PATCH 27/41] Keep input format during arithmetic --- examples/binary.modal | 7 ++++++- src/modal.c | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/examples/binary.modal b/examples/binary.modal index 9a98afc..106f046 100644 --- a/examples/binary.modal +++ b/examples/binary.modal @@ -2,4 +2,9 @@ ?(?: ?:) \101 ?(?: ?:) \#6c ?(?: ?:) \108 -?(?: ?:) \#6f \ No newline at end of file +?(?: ?:) \#6f + +?(?: ?:) \#ce +?(?: ?:) \#bb + +?((?: ?0 ?1) ?:) + #34 #67 diff --git a/src/modal.c b/src/modal.c index 13a886c..08d4bc4 100644 --- a/src/modal.c +++ b/src/modal.c @@ -59,7 +59,7 @@ device_write(char *s) char **reg = regs + '0'; /* phase: ALU */ if(*reg) { - int acc = sint(*reg++); + int hex = **reg == '#', acc = sint(*reg++); /* clang-format off */ switch(*s) { case '+': while(*reg) acc += sint(*reg++); break; @@ -76,7 +76,7 @@ device_write(char *s) case '<': while(*reg) acc = acc < sint(*reg++); break; } /* clang-format on */ - dst_ += snprintf(dst_, 0x10, "%d", acc); + dst_ += snprintf(dst_, 0x10, hex ? "#%x" : "%d", acc); return; } else { /* phase: string */ From 97a686913cb3f115ac34988e01e434969fea7143 Mon Sep 17 00:00:00 2001 From: Devine Lu Linvega Date: Mon, 13 May 2024 15:31:14 -0700 Subject: [PATCH 28/41] Raw byte export --- examples/binary.modal | 4 ++-- src/modal.c | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/examples/binary.modal b/examples/binary.modal index 106f046..d43dce0 100644 --- a/examples/binary.modal +++ b/examples/binary.modal @@ -1,7 +1,7 @@ ?(?: ?:) \#48 -?(?: ?:) \101 +?(?: ?:) \#65 +?(?: ?:) \#6c ?(?: ?:) \#6c -?(?: ?:) \108 ?(?: ?:) \#6f ?(?: ?:) \#ce diff --git a/src/modal.c b/src/modal.c index 08d4bc4..1d41808 100644 --- a/src/modal.c +++ b/src/modal.c @@ -83,15 +83,14 @@ device_write(char *s) char *cap = walk(s); if(*s == '(') s++, --cap; while(s < cap) { - char c = *s++; + char c = *s++, hb, lb; if(c == '\\') { switch(*s++) { case 't': putc(0x09, stdout); break; case 'n': putc(0x0a, stdout); break; case 's': putc(0x20, stdout); break; - default: putc(sint(--s), stdout), s = walk(s); + case '#': hb = *s++, lb = *s++, putc((chex(hb) << 4) | chex(lb), stdout); break; } - } else putc(c, stdout); } From fc903be471d0687ce0f8d82e3bd62fedf32241cc Mon Sep 17 00:00:00 2001 From: Devine Lu Linvega Date: Fri, 17 May 2024 09:45:30 -0700 Subject: [PATCH 29/41] Returned the input formatter --- examples/binary.modal | 6 +++--- examples/tests.modal | 15 ++++++++------- makefile | 2 +- src/modal.c | 11 ++++++++--- 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/examples/binary.modal b/examples/binary.modal index d43dce0..c0b924f 100644 --- a/examples/binary.modal +++ b/examples/binary.modal @@ -3,8 +3,8 @@ ?(?: ?:) \#6c ?(?: ?:) \#6c ?(?: ?:) \#6f +?(?: ?:) \#0a -?(?: ?:) \#ce -?(?: ?:) \#bb - +?(?: ?:) \#ce\#bb\#0a +?(?: ?:) \#e9\#ad\#91\#e9\#ad\#85\#e9\#ad\#8d\#e9\#ad\#8e\#0a ?((?: ?0 ?1) ?:) + #34 #67 diff --git a/examples/tests.modal b/examples/tests.modal index 4438ef0..5b80968 100644 --- a/examples/tests.modal +++ b/examples/tests.modal @@ -79,9 +79,8 @@ abc ?(?x) def = abc (lambda 2/2) test ?(?-) (Incomplete definitions) -<> (incomplete-basic) -<> (incomplete-reg ?x) -<> <> +<> (incomplete-basic) () +<> (incomplete-reg ?x) () <> () () (incomplete-basic) = () (incomplete 1/4) test @@ -123,13 +122,15 @@ fruit_b -> banana ?(?-) (Arithmetic) -?((?: ?0 ?1 ?2) ?:) + 1 2 3 = 6 (Arithmetic 1/4) test -?((?0 ?: ?1) ?:) 16 - 8 = 8 (Arithmetic 2/4) test -?((?0 ?1 ?:) ?:) 12 10 * = 120 (Arithmetic 3/4) test +?((?: ?0 ?1 ?2) ?:) + 1 2 3 = 6 (Arithmetic 1/6) test +?((?0 ?: ?1) ?:) 16 - 8 = 8 (Arithmetic 2/6) test +?((?0 ?1 ?:) ?:) 12 10 * = 120 (Arithmetic 3/6) test <> (?0 ?1 `?:) (?:) -(12 45 `+ -2 `+) = (55) (Arithmetic 4/4) test +(12 45 `+ -2 `+) = (55) (Arithmetic 4/6) test +(#12 45 `+ -2 `+) = (#3d) (Arithmetic 5/6) test +(12 #45 `+ -2 `+) = (79) (Arithmetic 6/6) test ?(?-) (List reversal) diff --git a/makefile b/makefile index a7e9458..b785838 100644 --- a/makefile +++ b/makefile @@ -10,7 +10,7 @@ dest: run: all bin/modal @ bin/modal -q examples/hello.modal debug: all bin/modal-debug - @ bin/modal-debug -a examples/binary.modal + @ bin/modal-debug examples/hello.modal test: all bin/modal-debug bin/modal @ bin/modal -v @ bin/modal-debug -q examples/fizzbuzz.modal diff --git a/src/modal.c b/src/modal.c index 1d41808..451279b 100644 --- a/src/modal.c +++ b/src/modal.c @@ -103,12 +103,17 @@ file_import(char *path, char *ptr) FILE *f; int pr = 0; if((f = fopen(path, "r"))) { - unsigned char c; + unsigned char c, last = 0; while(fread(&c, 1, 1, f)) { c = c <= 0x20 ? 0x20 : c; if(c == '(') pr++; if(c == ')') pr--; - *ptr++ = c; + if(c == ' ' && last == '(') continue; + if(c == ')' && last == ' ') ptr--; + if(c == ' ' && last == ' ') ptr--; + if(c == '(' && last != '?' && !spacer(last)) *ptr++ = ' '; + if(last == ')' && !spacer(c)) *ptr++ = ' '; + *ptr++ = last = c; } fclose(f); if(pr) fprintf(stderr, "Modal program imbalanced.\n"); @@ -321,7 +326,7 @@ main(int argc, char **argv) return !printf("usage: modal [-vqn] source.modal\n"); for(i = 1; i < argc && *argv[i] == '-'; i++) { switch(argv[i][1]) { - case 'v': /* version */ return !printf("Modal Interpreter, 13 May 2024.\n"); + case 'v': /* version */ return !printf("Modal Interpreter, 17 May 2024.\n"); case 'q': /* quiet */ quiet = 1; break; case 'p': /* debug */ debug = 1; break; case 'a': /* access */ access = 1; break; From ff0c53cf68358b4b6dc0a6c95f9e7c79ad92fcd4 Mon Sep 17 00:00:00 2001 From: Devine Lu Linvega Date: Tue, 21 May 2024 10:36:14 -0700 Subject: [PATCH 30/41] Join memory during undefinition --- examples/rules.modal | 19 +++++++++++++++++++ makefile | 2 +- src/modal.c | 44 +++++++++++++++++++++++++++++++++++--------- 3 files changed, 55 insertions(+), 10 deletions(-) create mode 100644 examples/rules.modal diff --git a/examples/rules.modal b/examples/rules.modal new file mode 100644 index 0000000..2e01a22 --- /dev/null +++ b/examples/rules.modal @@ -0,0 +1,19 @@ +<> rule0 data +<> rule1 data-1 +<> rule2 +<> rule3 data-10 +<> rule4 data-100 + +?(?-) (Undefine an empty rule) + +>< rule2 + +?(?-) (Undefine the last rule) + +>< rule4 + +?(?-) (Undefine a non-existant rule) + +>< rule5 + +a sample program \ No newline at end of file diff --git a/makefile b/makefile index b785838..ccee82f 100644 --- a/makefile +++ b/makefile @@ -10,7 +10,7 @@ dest: run: all bin/modal @ bin/modal -q examples/hello.modal debug: all bin/modal-debug - @ bin/modal-debug examples/hello.modal + @ bin/modal-debug examples/rules.modal test: all bin/modal-debug bin/modal @ bin/modal -v @ bin/modal-debug -q examples/fizzbuzz.modal diff --git a/src/modal.c b/src/modal.c index 451279b..0a9ab35 100644 --- a/src/modal.c +++ b/src/modal.c @@ -22,6 +22,15 @@ copy(char *src, char *dst, int length) return dst; } +static int +slen(char *s) +{ + char *cap = s; + while(*cap++) + ; + return cap - s; +} + static char * walk(char *s) { @@ -233,10 +242,10 @@ parse_frag(char **side, char *s) { char c, *cap; while((c = *s) && c == ' ') s++; - if(c == ')') { + if(c == ')' || (c == '<' && s[1] == '>') || (c == '>' && s[1] == '<')) { *side = NULL; return s; - } else if((c == '<' && s[1] == '>') || (c == '>' && s[1] == '<') || (c == '(' && s[1] == ')')) { + } else if((c == '(' && s[1] == ')')) { *side = NULL; return s + 2; } else { @@ -257,14 +266,31 @@ find_rule(char *s, char *cap) if(*s == '(') s++, cap--; while(r < rules_) { char *ss = s, *a = r->a; - if(a) - while(*ss++ == *a++) - if(!*a && ss == cap) return r; + while(*ss++ == *a++) + if(!*a && ss == cap) return r; r++; } return NULL; } +static void +remove_rule(Rule *r) +{ + if(r < rules_ - 1) { + int distance = slen(r->a) + (r->b != NULL ? slen(r->b) : 0); + char *memsrc = (r + 1)->a; + copy(memsrc, r->a, dict_ - memsrc); + while(r < rules_ - 1) { + Rule *next = r + 1; + r->id = next->id, r->refs = next->refs; + r->a = next->a - distance; + r->b = next->b == NULL ? NULL : next->b - distance; + r++; + } + } + rules_--; +} + static int rewrite(void) { @@ -272,7 +298,7 @@ rewrite(void) while(*s == ' ') s++; while((c = *s)) { if(c == '(' || spacer(last)) { - Rule *r = NULL; + Rule *r; /* phase: undefine */ if(c == '>' && s[1] == '<') { s += 2; @@ -280,7 +306,7 @@ rewrite(void) cap = walk(s), r = find_rule(s, cap); if(r != NULL) { if(!quiet) fprintf(stderr, ">< (%s) (%s)\n", r->a ? r->a : "", r->b ? r->b : ""); - r->a = 0; + remove_rule(r); } while(*cap == ' ') cap++; return write_tail(cap); @@ -310,7 +336,7 @@ rewrite(void) } /* phase: match */ for(r = rules; r < rules_; r++) - if(r->a != NULL && apply_rule(r, s)) return 1; + if(apply_rule(r, s)) return 1; } *dst_++ = last = c, s++; } @@ -326,7 +352,7 @@ main(int argc, char **argv) return !printf("usage: modal [-vqn] source.modal\n"); for(i = 1; i < argc && *argv[i] == '-'; i++) { switch(argv[i][1]) { - case 'v': /* version */ return !printf("Modal Interpreter, 17 May 2024.\n"); + case 'v': /* version */ return !printf("Modal Interpreter, 21 May 2024.\n"); case 'q': /* quiet */ quiet = 1; break; case 'p': /* debug */ debug = 1; break; case 'a': /* access */ access = 1; break; From 170cfde4373a0fd1d19269deadfec023a085a3fb Mon Sep 17 00:00:00 2001 From: Devine Lu Linvega Date: Tue, 21 May 2024 10:41:27 -0700 Subject: [PATCH 31/41] Empty rules point to a null byte --- src/modal.c | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/src/modal.c b/src/modal.c index 0a9ab35..df6f2f4 100644 --- a/src/modal.c +++ b/src/modal.c @@ -222,13 +222,11 @@ apply_rule(Rule *r, char *s) c = *s; if(!spacer(c)) return 0; /* phase: write rule */ - if(b != NULL) { - while((c = *b++)) - if(c == '?' && (rid = *b) && (reg = regs[rid])) - write_reg(rid, reg), b++; - else - *dst_++ = c; - } + while((c = *b++)) + if(c == '?' && (rid = *b) && (reg = regs[rid])) + write_reg(rid, reg), b++; + else + *dst_++ = c; if(dst_ == origin) { while(*s == ' ') s++; if(*s == ')' && *(dst_ - 1) == ' ') dst_--; @@ -243,11 +241,8 @@ parse_frag(char **side, char *s) char c, *cap; while((c = *s) && c == ' ') s++; if(c == ')' || (c == '<' && s[1] == '>') || (c == '>' && s[1] == '<')) { - *side = NULL; + *side = dict_, *dict_++ = 0; return s; - } else if((c == '(' && s[1] == ')')) { - *side = NULL; - return s + 2; } else { cap = walk(s), *side = dict_; if(c == '(') @@ -277,14 +272,14 @@ static void remove_rule(Rule *r) { if(r < rules_ - 1) { - int distance = slen(r->a) + (r->b != NULL ? slen(r->b) : 0); + int distance = slen(r->a) + slen(r->b); char *memsrc = (r + 1)->a; copy(memsrc, r->a, dict_ - memsrc); while(r < rules_ - 1) { Rule *next = r + 1; r->id = next->id, r->refs = next->refs; r->a = next->a - distance; - r->b = next->b == NULL ? NULL : next->b - distance; + r->b = next->b - distance; r++; } } @@ -315,7 +310,7 @@ rewrite(void) if(c == '<' && s[1] == '>') { r = rules_, r->id = rules_ - rules; s = parse_frag(&r->b, parse_frag(&r->a, s + 2)); - if(r->a != NULL) { + if(*r->a) { if(!quiet) fprintf(stderr, "<> (%s) (%s)\n", r->a ? r->a : "", r->b ? r->b : ""); rules_++; } @@ -330,7 +325,7 @@ rewrite(void) parse_frag(&r->b, parse_frag(&r->a, s + 2)); s = cap; while(*s == ' ') s++; - if(r->a == NULL || !apply_rule(r, s)) write_tail(s); + if(!(*r->a) || !apply_rule(r, s)) write_tail(s); dict_ = d; return 1; } From 44b04fa8933224e208be4e7d169c2edaf5801e32 Mon Sep 17 00:00:00 2001 From: Devine Lu Linvega Date: Tue, 21 May 2024 20:09:15 -0700 Subject: [PATCH 32/41] slen() is not needed to get lenght of rule data --- src/modal.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/modal.c b/src/modal.c index df6f2f4..5dcd970 100644 --- a/src/modal.c +++ b/src/modal.c @@ -22,15 +22,6 @@ copy(char *src, char *dst, int length) return dst; } -static int -slen(char *s) -{ - char *cap = s; - while(*cap++) - ; - return cap - s; -} - static char * walk(char *s) { @@ -272,8 +263,8 @@ static void remove_rule(Rule *r) { if(r < rules_ - 1) { - int distance = slen(r->a) + slen(r->b); char *memsrc = (r + 1)->a; + int distance = (r + 1)->a - r->a; copy(memsrc, r->a, dict_ - memsrc); while(r < rules_ - 1) { Rule *next = r + 1; From 155857c120049821adda2396a5387226155cc7ab Mon Sep 17 00:00:00 2001 From: Devine Lu Linvega Date: Tue, 21 May 2024 20:35:49 -0700 Subject: [PATCH 33/41] Launch repl on run --- examples/repl.modal | 8 -------- makefile | 2 +- src/repl.modal | 17 +++++++++++++++++ 3 files changed, 18 insertions(+), 9 deletions(-) delete mode 100644 examples/repl.modal create mode 100644 src/repl.modal diff --git a/examples/repl.modal b/examples/repl.modal deleted file mode 100644 index 15cbd7f..0000000 --- a/examples/repl.modal +++ /dev/null @@ -1,8 +0,0 @@ -?(?-) (This is a fully functional Modal REPL.) - -<> quit EOF -<> wait?~ (?~ wait!) -<> (?: print) ?: -<> (EOF wait!) (Bye.\n print) - -(Say something, or type "quit":\n) print wait! \ No newline at end of file diff --git a/makefile b/makefile index ccee82f..f36c470 100644 --- a/makefile +++ b/makefile @@ -8,7 +8,7 @@ all: dest dest: @ mkdir -p bin run: all bin/modal - @ bin/modal -q examples/hello.modal + @ bin/modal src/repl.modal debug: all bin/modal-debug @ bin/modal-debug examples/rules.modal test: all bin/modal-debug bin/modal diff --git a/src/repl.modal b/src/repl.modal new file mode 100644 index 0000000..d3875a8 --- /dev/null +++ b/src/repl.modal @@ -0,0 +1,17 @@ +?(?: ?:) ( +\n +\t Hello. Welcome to Modal\n +\t Start rewriting, or type "quit"\n +\n +\t <> Defines a rule\n +\t >< Undefines a rule\n +\t ?x Assigns a register\n +\n +\t Have fun!\n +\n +) + +<> (quit listen!) (?(?: ?:) (\n\tSee you soon.\n\n)) +<> listen?~ (?~ listen!) + +listen! \ No newline at end of file From 9f8d78c9ece450cc6fd1bf0df76dd3543e7428af Mon Sep 17 00:00:00 2001 From: Devine Lu Linvega Date: Tue, 21 May 2024 21:29:41 -0700 Subject: [PATCH 34/41] Print result after the rewrite is entirely done --- src/modal.c | 12 ++++++------ src/repl.modal | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/modal.c b/src/modal.c index 5dcd970..558fb2a 100644 --- a/src/modal.c +++ b/src/modal.c @@ -176,7 +176,7 @@ write_reg(char r, char *reg) } static int -write_tail(char *s) +write_tail(char *s, Rule *r) { while((*dst_++ = *s++)) ; @@ -185,6 +185,7 @@ write_tail(char *s) src_ = bank_b, dst_ = bank_a; else src_ = bank_a, dst_ = bank_b; + if(r && !quiet) fprintf(stderr, "%02d %s\n", r->id, src_), ++r->refs; return 1; } @@ -222,8 +223,7 @@ apply_rule(Rule *r, char *s) while(*s == ' ') s++; if(*s == ')' && *(dst_ - 1) == ' ') dst_--; } - if(!quiet) fprintf(stderr, "%02d %s\n", r->id, src_), ++r->refs; - return write_tail(s); + return write_tail(s, r); } static char * @@ -295,7 +295,7 @@ rewrite(void) remove_rule(r); } while(*cap == ' ') cap++; - return write_tail(cap); + return write_tail(cap, NULL); } /* phase: define */ if(c == '<' && s[1] == '>') { @@ -306,7 +306,7 @@ rewrite(void) rules_++; } while(*s == ' ') s++; - return write_tail(s); + return write_tail(s, NULL); } /* phase: lambda */ if(c == '?' && s[1] == '(') { @@ -316,7 +316,7 @@ rewrite(void) parse_frag(&r->b, parse_frag(&r->a, s + 2)); s = cap; while(*s == ' ') s++; - if(!(*r->a) || !apply_rule(r, s)) write_tail(s); + if(!(*r->a) || !apply_rule(r, s)) write_tail(s, NULL); dict_ = d; return 1; } diff --git a/src/repl.modal b/src/repl.modal index d3875a8..c331b4e 100644 --- a/src/repl.modal +++ b/src/repl.modal @@ -11,7 +11,7 @@ \n ) -<> (quit listen!) (?(?: ?:) (\n\tSee you soon.\n\n)) -<> listen?~ (?~ listen!) +<> (quit ...) (?(?: ?:) (\n\tSee you soon.\n\n)) +<> ..?~ (?~ ...) -listen! \ No newline at end of file +... \ No newline at end of file From 8431ac66f69cabd8e6196564358c4d9d543b1fdd Mon Sep 17 00:00:00 2001 From: Devine Lu Linvega Date: Fri, 24 May 2024 08:15:59 -0700 Subject: [PATCH 35/41] Fixed issue with trailing whitespace --- src/modal.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/modal.c b/src/modal.c index 558fb2a..d718473 100644 --- a/src/modal.c +++ b/src/modal.c @@ -115,6 +115,7 @@ file_import(char *path, char *ptr) if(last == ')' && !spacer(c)) *ptr++ = ' '; *ptr++ = last = c; } + while(*(--ptr) <= ' ') *ptr = 0; fclose(f); if(pr) fprintf(stderr, "Modal program imbalanced.\n"); return ptr; @@ -338,7 +339,7 @@ main(int argc, char **argv) return !printf("usage: modal [-vqn] source.modal\n"); for(i = 1; i < argc && *argv[i] == '-'; i++) { switch(argv[i][1]) { - case 'v': /* version */ return !printf("Modal Interpreter, 21 May 2024.\n"); + case 'v': /* version */ return !printf("Modal Interpreter, 24 May 2024.\n"); case 'q': /* quiet */ quiet = 1; break; case 'p': /* debug */ debug = 1; break; case 'a': /* access */ access = 1; break; From 9780e2aad71ae4dd000a75676355beef622fb20d Mon Sep 17 00:00:00 2001 From: Devine Lu Linvega Date: Fri, 24 May 2024 17:12:16 -0700 Subject: [PATCH 36/41] Fixed issue with writing empty register --- src/modal.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/modal.c b/src/modal.c index d718473..2dcd110 100644 --- a/src/modal.c +++ b/src/modal.c @@ -194,7 +194,7 @@ static int apply_rule(Rule *r, char *s) { unsigned char rid; - char c, *a = r->a, *b = r->b, *origin = dst_, *reg; + char c, *a = r->a, *b = r->b, *origin = dst_, *reg, last = 0; /* phase: clean regs */ while(stack_ != stack) regs[(int)*(--stack_)] = 0; /* phase: match rule */ @@ -216,10 +216,15 @@ apply_rule(Rule *r, char *s) if(!spacer(c)) return 0; /* phase: write rule */ while((c = *b++)) - if(c == '?' && (rid = *b) && (reg = regs[rid])) + if(c == '?' && (rid = *b) && (reg = regs[rid])){ + char *ori = dst_; write_reg(rid, reg), b++; - else - *dst_++ = c; + if(dst_ == ori){ + if(b[0] == ' ') b++; + else if(last == ' ') dst_--; + } + } else + *dst_++ = last = c; if(dst_ == origin) { while(*s == ' ') s++; if(*s == ')' && *(dst_ - 1) == ' ') dst_--; From 6f5b5fc36c4e69c2908118ef301141e1637103c7 Mon Sep 17 00:00:00 2001 From: Devine Lu Linvega Date: Fri, 24 May 2024 18:34:43 -0700 Subject: [PATCH 37/41] Improved catching of empty registers --- src/modal.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/modal.c b/src/modal.c index 2dcd110..661a36b 100644 --- a/src/modal.c +++ b/src/modal.c @@ -123,35 +123,36 @@ file_import(char *path, char *ptr) return copy("NAF", ptr, 3); } -static void +static int write_reg(char r, char *reg) { + char *origin = dst_; switch(r) { - case ':': device_write(reg); return; + case ':': device_write(reg); break; case '~': { unsigned char c; while(fread(&c, 1, 1, stdin) && c >= ' ') *dst_++ = c; if(feof(stdin)) dst_ = copy("EOF", dst_, 3); - return; + break; } case '_': { char filepath[0x80]; copy(reg, filepath, walk(reg) - reg); dst_ = file_import(filepath, dst_); - return; + break; } case '^': { /* op: join */ char c, *cap = walk(reg); if(*reg == '(') reg++, --cap; while(reg < cap && (c = *reg++)) if(!spacer(c)) *dst_++ = c; - return; + break; } case '.': { /* op: unwrap */ char *cap = walk(reg); if(*reg == '(') reg++, --cap; dst_ = copy(reg, dst_, cap - reg); - return; + break; } case '*': { /* op: explode */ int i, depth = 0; @@ -167,13 +168,11 @@ write_reg(char r, char *reg) while((c = *reg++) && !spacer(c)) *dst_++ = c, *dst_++ = ' ', *dst_++ = '(', depth++; for(i = 0; i < depth; i++) *dst_++ = ')'; - return; - } - default: { - dst_ = copy(reg, dst_, walk(reg) - reg); - return; + break; } + default: dst_ = copy(reg, dst_, walk(reg) - reg); } + return dst_ - origin; } static int @@ -216,12 +215,13 @@ apply_rule(Rule *r, char *s) if(!spacer(c)) return 0; /* phase: write rule */ while((c = *b++)) - if(c == '?' && (rid = *b) && (reg = regs[rid])){ - char *ori = dst_; - write_reg(rid, reg), b++; - if(dst_ == ori){ - if(b[0] == ' ') b++; - else if(last == ' ') dst_--; + if(c == '?' && (rid = *b) && (reg = regs[rid])) { + b++; + if(!write_reg(rid, reg)) { + if(*b == ' ') + b++; + else if(last == ' ') + dst_--; } } else *dst_++ = last = c; From 13ec84d7ef3ed871445a23afb0df87c6355a84a1 Mon Sep 17 00:00:00 2001 From: Devine Lu Linvega Date: Fri, 24 May 2024 18:42:00 -0700 Subject: [PATCH 38/41] Unnecessary return --- src/modal.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/modal.c b/src/modal.c index 661a36b..0c1af6e 100644 --- a/src/modal.c +++ b/src/modal.c @@ -237,10 +237,9 @@ parse_frag(char **side, char *s) { char c, *cap; while((c = *s) && c == ' ') s++; - if(c == ')' || (c == '<' && s[1] == '>') || (c == '>' && s[1] == '<')) { + if(c == ')' || (c == '<' && s[1] == '>') || (c == '>' && s[1] == '<')) *side = dict_, *dict_++ = 0; - return s; - } else { + else { cap = walk(s), *side = dict_; if(c == '(') dict_ = copy(s + 1, dict_, cap - s - 2); From 89f393e3492381e2f1115a6c33cf576624305ffa Mon Sep 17 00:00:00 2001 From: Devine Lu Linvega Date: Fri, 24 May 2024 18:56:06 -0700 Subject: [PATCH 39/41] Handle empty register writes at the register level --- src/modal.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/src/modal.c b/src/modal.c index 0c1af6e..32ba312 100644 --- a/src/modal.c +++ b/src/modal.c @@ -123,16 +123,17 @@ file_import(char *path, char *ptr) return copy("NAF", ptr, 3); } -static int +static void write_reg(char r, char *reg) { - char *origin = dst_; switch(r) { case ':': device_write(reg); break; case '~': { unsigned char c; + char *origin = dst_; while(fread(&c, 1, 1, stdin) && c >= ' ') *dst_++ = c; if(feof(stdin)) dst_ = copy("EOF", dst_, 3); + if(origin == dst_) dst_--; break; } case '_': { @@ -172,7 +173,6 @@ write_reg(char r, char *reg) } default: dst_ = copy(reg, dst_, walk(reg) - reg); } - return dst_ - origin; } static int @@ -193,7 +193,7 @@ static int apply_rule(Rule *r, char *s) { unsigned char rid; - char c, *a = r->a, *b = r->b, *origin = dst_, *reg, last = 0; + char c, *a = r->a, *b = r->b, *origin = dst_, *reg; /* phase: clean regs */ while(stack_ != stack) regs[(int)*(--stack_)] = 0; /* phase: match rule */ @@ -215,16 +215,10 @@ apply_rule(Rule *r, char *s) if(!spacer(c)) return 0; /* phase: write rule */ while((c = *b++)) - if(c == '?' && (rid = *b) && (reg = regs[rid])) { - b++; - if(!write_reg(rid, reg)) { - if(*b == ' ') - b++; - else if(last == ' ') - dst_--; - } - } else - *dst_++ = last = c; + if(c == '?' && (rid = *b) && (reg = regs[rid])) + write_reg(rid, reg), b++; + else + *dst_++ = c; if(dst_ == origin) { while(*s == ' ') s++; if(*s == ')' && *(dst_ - 1) == ' ') dst_--; From da91bc0aedcc8f856b8865ca0f38e1accd19a7cb Mon Sep 17 00:00:00 2001 From: Devine Lu Linvega Date: Fri, 24 May 2024 19:10:13 -0700 Subject: [PATCH 40/41] Do not use # for true/false --- examples/tests.modal | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/examples/tests.modal b/examples/tests.modal index 5b80968..2ba30ca 100644 --- a/examples/tests.modal +++ b/examples/tests.modal @@ -2,7 +2,7 @@ ?(?-) (Early Test Primitives) -<> (?x = ?x ?n test) (?(?: ?:) (#pass ?n\n)) +<> (?x = ?x ?n test) (?(?: ?:) (pass ?n\n)) <> (ghost) () @@ -36,15 +36,17 @@ <> (dup (?x)) (?x ?x) <> (swap (?x ?y)) (?y ?x) -<> (compare (?x ?x ?x)) (#t) +<> (compare (?x ?x ?x)) (@t) +<> (compare (?x ?y ?z)) (@f) <> (rotate (?x (?y (?z)))) (?y (?z (?x))) <> (unused ?x) ?y -(dup (abc)) = (abc abc) (basic 1/5) test -(swap (abc def)) = (def abc) (basic 2/5) test -(compare (abc abc abc)) = (#t) (basic 3/5) test -(rotate (abc (def (ghi)))) = (def (ghi (abc))) (basic 4/5) test -(unused hey) = (?y) (basic 5/5) test +(dup (abc)) = (abc abc) (basic 1/6) test +(swap (abc def)) = (def abc) (basic 2/6) test +(compare (abc abc abc)) = (@t) (basic 3/6) test +(compare (abc abc def)) = (@f) (basic 4/6) test +(rotate (abc (def (ghi)))) = (def (ghi (abc))) (basic 5/6) test +(unused hey) = (?y) (basic 6/6) test ?(?-) (Substring registers) @@ -142,5 +144,5 @@ reverse (modal) = ladom (reverse 1) test ?(?-) (Late Test Primitives) -<> (?x = ?y ?n test) (?(?: ?:) (#fail ?n found: ?x expect: ?y\n)) +<> (?x = ?y ?n test) (?(?: ?:) (fail ?n found: ?x, expects: ?y\n)) From d6d004ca87c3bdd6c7ea663a1008b269ab14193e Mon Sep 17 00:00:00 2001 From: Devine Lu Linvega Date: Fri, 24 May 2024 21:03:49 -0700 Subject: [PATCH 41/41] Improved repl --- src/repl.modal | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/repl.modal b/src/repl.modal index c331b4e..7812b69 100644 --- a/src/repl.modal +++ b/src/repl.modal @@ -1,17 +1,17 @@ ?(?: ?:) ( \n -\t Hello. Welcome to Modal\n +\t Hi! Welcome to Modal\n \t Start rewriting, or type "quit"\n \n -\t <> Defines a rule\n -\t >< Undefines a rule\n -\t ?x Assigns a register\n +\t <> Define a rule\n +\t >< Undefine a rule\n +\t ?x Assign a register\n \n -\t Have fun!\n +\t Have fun\n \n ) -<> (quit ...) (?(?: ?:) (\n\tSee you soon.\n\n)) -<> ..?~ (?~ ...) +<> (quit @.) (?(?: ?:) (\n\t See you soon\n)) +<> @?~ (?~ @.) -... \ No newline at end of file +@. \ No newline at end of file