]> gitweb.ps.run Git - iftint/blob - main3.c
19110167805a4240e102af4a2152661687e4ae0b
[iftint] / main3.c
1 #include <stdint.h>
2 #include <stdbool.h>
3 #include <stdio.h>
4 #include <stdarg.h>
5
6
7 // Global defines
8
9 #define STR_SIZE 128
10 #define BUF_SIZE 1024*1024
11
12 // Memory
13
14 static char g_memory[1024*1024];
15 static int g_memory_index = 0;
16
17 void * alloc(int num, int size) {
18     void * result = g_memory + g_memory_index;
19     for (int i = 0; i < num*size; i++)
20         g_memory[g_memory_index+i] = 0;
21     g_memory_index += num*size;
22     return result;
23 }
24
25 #define NEW(TYPE) ((TYPE *)alloc(1, sizeof(TYPE)))
26 #define NEWARR(TYPE, NUM) ((TYPE *)alloc(NUM, sizeof(TYPE)))
27 #define NEWSTR NEWARR(char, STR_SIZE)
28
29 // getch
30
31 #ifdef _WIN32
32 #include <windows.h>
33 #include <conio.h>
34 #else
35 #include <sys/ioctl.h>
36 #include <termios.h>
37 #include <unistd.h>
38 #include <stdio.h>
39
40 /* reads from keypress, doesn't echo */
41 int getch(void)
42 {
43     struct termios oldattr, newattr;
44     int ch;
45     tcgetattr( STDIN_FILENO, &oldattr );
46     newattr = oldattr;
47     newattr.c_lflag &= ~( ICANON | ECHO ); // no ECHO for echo(?)
48     tcsetattr( STDIN_FILENO, TCSANOW, &newattr );
49     ch = getchar();
50     tcsetattr( STDIN_FILENO, TCSANOW, &oldattr );
51     return ch;
52 }
53
54 /* ungets keypress */
55 void ungetch(int ch)
56 {
57     struct termios oldattr, newattr;
58     tcgetattr( STDIN_FILENO, &oldattr );
59     newattr = oldattr;
60     newattr.c_lflag &= ~( ICANON | ECHO );
61     tcsetattr( STDIN_FILENO, TCSANOW, &newattr );
62     ungetc(ch, stdin);
63     tcsetattr( STDIN_FILENO, TCSANOW, &oldattr );
64 }
65 #endif
66
67 int
68 peekch() {
69     int c = getch();
70     ungetch(c);
71     return c;
72 }
73
74 // VT100
75
76 #define ASCII_ESC 27
77
78 void vt100Escape(const char * str, ...) {
79     va_list args;
80     va_start(args, str);
81
82     printf("%c", ASCII_ESC);
83     vprintf(str, args);
84 }
85
86 void vt100ClearScreen() { vt100Escape("[2J"); }
87 void vt100CursorHome() { vt100Escape("[H"); }
88 void vt100CursorPos(int v, int h) { vt100Escape("[%d;%dH", v, h); }
89 void vt100SaveCursor() { vt100Escape("7"); }
90 void vt100RestoreCursor() { vt100Escape("8"); }
91 void vt100EnableAlternateBuffer() { vt100Escape("[?1049h"); }
92 void vt100DisableAlternateBuffer() { vt100Escape("[?1049l"); }
93 void vt100EnableNegative() { vt100Escape("[7m"); }
94 void vt100DisableNegative() { vt100Escape("[27m"); }
95 void vt100ShowCursor() { vt100Escape("[?25h"); }
96 void vt100HideCursor() { vt100Escape("[?25l"); }
97 void vt100GetScreenSize(int * v, int * h) {
98 #ifdef _WIN32
99     CONSOLE_SCREEN_BUFFER_INFO csbi;
100     GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
101     *h = csbi.srWindow.Right - csbi.srWindow.Left + 1;
102     *v = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
103 #else
104     struct winsize w;
105     ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
106     *h = w.ws_row;
107     *v = w.ws_col;
108 #endif
109 }
110
111 // Node
112
113 typedef enum NodeKind {
114     NK_Namespace,
115     NK_Struct,
116     NK_Func,
117     NK_VarList,
118     NK_ExprList,
119     NK_Var,
120     NK_VarDecl,
121     NK_VarType,
122     NK_Type,
123     NK_Body,
124     NK_If,
125     NK_While,
126     NK_Num,
127     NK_Str,
128     NK_Call,
129     NK_Op,
130
131     NK_COUNT
132 } NodeKind;
133
134 const char *NK_STRINGS[NK_COUNT] = {
135     "NK_Namespace",
136     "NK_Struct",
137     "NK_Func",
138     "NK_VarList",
139     "NK_ExprList",
140     "NK_Var",
141     "NK_VarDecl",
142     "NK_VarType",
143     "NK_Type",
144     "NK_Body",
145     "NK_If",
146     "NK_While",
147     "NK_Num",
148     "NK_Str",
149     "NK_Call",
150     "NK_Op",
151 };
152
153 typedef struct Node Node;
154 struct Node {
155     NodeKind kind;
156     void * data;
157
158     int childCount;
159     Node *next, *prev, *parent, *child;
160 };
161
162 Node *NodeGetChild(Node *n, unsigned int index) {
163     if (index >= n->childCount)
164         return NULL;
165     
166     Node *result = n->child;
167     for (int i = 0; i < index; i++)
168         result = result->next;
169     return result;
170 }
171
172 void NodeAppend(Node *n1, Node *n2) {
173     if (n1->childCount == 0) {
174         n1->child = n2;
175     }
176     else {
177         Node *lastChild = NodeGetChild(n1, n1->childCount-1);
178
179         lastChild->next = n2;
180         n2->prev = lastChild;
181         n2->next = NULL;
182     }
183     n2->parent = n1;
184     n1->childCount += 1;
185 }
186
187 void NodeInsert(Node *n1, Node *n2, unsigned int index) {
188     if (index >= n1->childCount-1) {
189         NodeAppend(n1, n2);
190         return;
191     }
192
193     Node *insertAfter = NodeGetChild(n1, index);
194     Node *insertBefore = NodeGetChild(n1, index+1);
195
196     insertAfter->next = n2;
197     insertBefore->prev = n2;
198     n2->prev = insertAfter;
199     n2->next = insertBefore;
200
201     n1->childCount += 1;
202 }
203
204 Node *NodeRemove(Node *n1, Node *n2) {
205     if (n1 == NULL)
206         return n2;
207     
208     Node *prev = n2->prev;
209     Node *next = n2->next;
210
211     if (prev != NULL)
212         prev->next = next;
213     if (next != NULL)
214         next->prev = prev;
215     
216     n2->prev = n2->next = n2->parent = NULL;
217
218     if (n2 == n1->child)
219         n1->child = next;
220
221     n1->childCount -= 1;
222     
223     if (prev == NULL)
224         return n1;
225     else
226         return prev;
227 }
228
229 Node *g_NodeDrawSelected;
230
231 void NodeDraw(Node *n) {
232     static int indent = 0;
233     #define INDENT printf("\n"); for (int i = 0; i < indent; i++) printf("  ");
234     
235     #define PRINTF(...) do { if (n == g_NodeDrawSelected) vt100EnableNegative(); printf(__VA_ARGS__); vt100DisableNegative(); } while(0);
236
237     switch (n->kind) {
238     case NK_Namespace: { PRINTF("namespace"); printf(" %s {", n->data); indent++; for (int i = 0; i < n->childCount; i++) { INDENT NodeDraw(NodeGetChild(n, i)); } indent--; INDENT printf("}\n"); break; }
239     case NK_Struct:    { PRINTF("struct"); printf(" %s {", n->data); indent++; for (int i = 0; i < n->childCount; i++) { INDENT NodeDraw(NodeGetChild(n, i)); } indent--; INDENT printf("}\n"); break; }
240     case NK_Func:      { PRINTF("fn"); printf(" %s ", n->data); NodeDraw(NodeGetChild(n, 0)); NodeDraw(NodeGetChild(n, 1)); break; }
241     case NK_VarList:
242     case NK_ExprList:  { PRINTF("("); for (int i = 0; i < n->childCount; i++) { if (i != 0) printf(", "); NodeDraw(NodeGetChild(n, i)); } PRINTF(")"); break; }
243     case NK_Var:       { PRINTF("[%s]", n->data); break; }
244     case NK_VarDecl:   { PRINTF("[%s : ", n->data); NodeDraw(NodeGetChild(n, 0)); printf("]"); break; }
245     case NK_VarType:
246     case NK_Type:      { PRINTF("%s", n->data); for (int i = 0; i < n->childCount; i++) { printf("%s", i == 0 ? "<" : ", "); NodeDraw(NodeGetChild(n, i)); if (i == n->childCount-1) printf(">"); } break; }
247     case NK_Body:      { PRINTF("{"); indent++; for (int i = 0; i < n->childCount; i++) { INDENT NodeDraw(NodeGetChild(n, i)); } indent--; INDENT PRINTF("}\n"); break; }
248     case NK_If:        { PRINTF("if"); printf(" "); NodeDraw(NodeGetChild(n, 0)); INDENT NodeDraw(NodeGetChild(n, 1)); break; }
249     case NK_While:     { PRINTF("while"); printf(" "); NodeDraw(NodeGetChild(n, 0)); INDENT NodeDraw(NodeGetChild(n, 1)); break; }
250     case NK_Num:       { PRINTF("%s", n->data); break; }
251     case NK_Str:       { PRINTF("'%s'", n->data); break; }
252     case NK_Call:      { PRINTF("!%s ", n->data); NodeDraw(NodeGetChild(n, 0)); break; }
253     case NK_Op:        { if (n->childCount <= 1) { PRINTF("%s", n->data); printf(" "); } for (int i = 0; i < n->childCount; i++) { if (i != 0) { printf(" "); PRINTF("%s", n->data); printf(" "); } NodeDraw(NodeGetChild(n, i)); } break; }
254     }
255 }
256
257 // Input
258
259 #define KEY_CTRL_C 3
260 #define KEY_BACKSPACE1 8
261 #define KEY_BACKSPACE2 127
262
263 typedef enum Input {
264     IN_None,
265
266     IN_H,
267     IN_J,
268     IN_K,
269     IN_L,
270
271     IN_SPACE,
272     IN_D,
273     IN_A,
274
275     IN_F,
276     IN_V,
277     IN_T,
278     IN_I,
279     IN_W,
280     IN_N,
281     IN_S,
282     IN_C,
283     IN_O,
284
285     IN_Quit,
286
287     IN_COUNT
288 } Input;
289
290 const char *IN_STRINGS[IN_COUNT] = {
291     "IN_None",
292
293     "IN_H",
294     "IN_J",
295     "IN_K",
296     "IN_L",
297
298     "IN_SPACE",
299     "IN_D",
300     "IN_A",
301
302     "IN_F",
303     "IN_V",
304     "IN_T",
305     "IN_I",
306     "IN_W",
307     "IN_N",
308     "IN_S",
309     "IN_C",
310     "IN_O",
311
312     "IN_Quit",
313 };
314
315 Input InputGet() {
316     int c;
317
318     while (true) {
319         c = getch();
320         switch (c) {
321             case 'h': return IN_H;
322             case 'j': return IN_J;
323             case 'k': return IN_K;
324             case 'l': return IN_L;
325
326             case ' ': return IN_SPACE;
327             case 'd': return IN_D;
328             
329             case 'f': return IN_F;
330             case 'v': return IN_V;
331             case 't': return IN_T;
332             case 'i': return IN_I;
333             case 'w': return IN_W;
334             case 'n': return IN_N;
335             case 's': return IN_S;
336             case 'c': return IN_C;
337             case 'o': return IN_O;
338
339             case 'q': return IN_Quit;
340         }
341     }
342 }
343
344 typedef enum InputAction {
345     IA_None,
346
347     IA_MoveLeft,
348     IA_MoveUp,
349     IA_MoveDown,
350     IA_MoveRight,
351
352     IA_StartEditing,
353     IA_Delete,
354
355     IA_AddNamespace,
356     IA_AddStruct,
357     IA_AddFunc,
358     IA_AddVar,
359     IA_AddVarDecl,
360     IA_AddType,
361     IA_AddIf,
362     IA_AddWhile,
363     IA_AddNum,
364     IA_AddStr,
365     IA_AddCall,
366     IA_AddOp,
367
368     IA_COUNT
369 } InputAction;
370
371 const char *IA_STRINGS[IA_COUNT] = {
372     "IA_None",
373
374     "IA_MoveLeft",
375     "IA_MoveUp",
376     "IA_MoveDown",
377     "IA_MoveRight",
378
379     "IA_StartEditing",
380     "IA_Delete",
381
382     "IA_AddNamespace",
383     "IA_AddStruct",
384     "IA_AddFunc",
385     "IA_AddVar",
386     "IA_AddVarDecl",
387     "IA_AddType",
388     "IA_AddIf",
389     "IA_AddWhile",
390     "IA_AddNum",
391     "IA_AddStr",
392     "IA_AddCall",
393     "IA_AddOp",
394 };
395
396 typedef enum InputMode {
397     IM_Normal,
398     IM_Editing,
399 } InputMode;
400
401 void DrawInfo(InputAction actions[NK_COUNT][IN_COUNT], NodeKind nk, InputMode mode) {
402     int v, h;
403     vt100GetScreenSize(&v, &h);
404
405     int line = 2;
406
407     vt100CursorPos(line++, h-30);
408     printf("%s:%s", NK_STRINGS[nk], (mode == IM_Normal ? "" : " (editing)"));
409
410     for (int i = IN_L+1; i < IN_COUNT; i++) {
411         InputAction action = actions[nk][i];
412         if (action != IA_None) {
413             vt100CursorPos(line++, h-30);
414             printf("%s %s", IN_STRINGS[i], IA_STRINGS[action]);
415         }
416     }
417 }
418
419 Node *GetNode(InputAction actions[NK_COUNT][IN_COUNT]) {
420     Node *result = NEW(Node); result->data = NEWSTR; result->kind = NK_Namespace;
421
422     Node * n = result;
423
424     Input in;
425     InputAction action;
426
427     InputMode mode = IM_Normal;
428
429     while (true) {
430         vt100ClearScreen();
431         vt100CursorHome();
432         g_NodeDrawSelected = n;
433         NodeDraw(result);
434         g_NodeDrawSelected = NULL;
435         DrawInfo(actions, n->kind, mode);
436
437         if (mode == IM_Editing) {
438             int c = getch();
439             char *s = (char*)n->data;
440             int slen = strlen(s);
441             
442             if (c == KEY_BACKSPACE1 || c == KEY_BACKSPACE2) {
443                 s[slen-1] = '\0';
444             }
445             else if (c == '\n' || c == '\r') {
446                 mode = IM_Normal;
447             }
448             else if (slen < STR_SIZE) {
449                 s[slen++] = (char)c;
450             }
451         }
452         else if (mode == IM_Normal) {
453             in = InputGet();
454
455             if (in == IN_Quit)
456                 break;
457
458             action = actions[n->kind][in];
459
460             #define N(NAME, PARENT, KIND) Node *NAME = NEW(Node); NAME->kind = KIND; NodeAppend(PARENT, NAME);
461             #define S(NAME, PARENT, KIND) Node *NAME = NEW(Node); NAME->kind = KIND; NAME->data = NEWSTR; NodeAppend(PARENT, NAME);
462
463             switch (action) {
464             case IA_MoveLeft: { if (n->prev != NULL) n = n->prev; break; }
465             case IA_MoveDown: { if (n->child != NULL) n = n->child; break; }
466             case IA_MoveUp: { if (n->parent != NULL) n = n->parent; break; }
467             case IA_MoveRight: { if (n->next != NULL) n = n->next; break; }
468             
469             case IA_StartEditing: { mode = IM_Editing; break; }
470             case IA_Delete: { n = NodeRemove(n->parent, n); break; }
471
472             case IA_AddNamespace: { S(n1, n, NK_Namespace)                                            n = n1; mode = IM_Editing; break; }
473             case IA_AddStruct:    { S(n1, n, NK_Struct)                                               n = n1; mode = IM_Editing; break; }
474             case IA_AddFunc:      { S(n1, n, NK_Func)       N(n2, n1, NK_VarList)  N(n3, n1, NK_Body) n = n1; mode = IM_Editing; break; }
475             case IA_AddVar:       { S(n1, n, NK_Var)                                                  n = n1; mode = IM_Editing; break; }
476             case IA_AddVarDecl:   { S(n1, n, NK_VarDecl)    S(n2, n1, NK_VarType)                     n = n1; mode = IM_Editing; break; }
477             case IA_AddType:      { S(n1, n, NK_Type)                                                 n = n1; mode = IM_Editing; break; }
478             case IA_AddIf:        { N(n1, n, NK_If)         N(n2, n1, NK_ExprList) N(n3, n1, NK_Body) n = n2;                    break; }
479             case IA_AddWhile:     { N(n1, n, NK_While)      N(n2, n1, NK_ExprList) N(n3, n1, NK_Body) n = n2;                    break; }
480             case IA_AddNum:       { S(n1, n, NK_Num)                                                  n = n1; mode = IM_Editing; break; }
481             case IA_AddStr:       { S(n1, n, NK_Str)                                                  n = n1; mode = IM_Editing; break; }
482             case IA_AddCall:      { S(n1, n, NK_Call)       N(n2, n1, NK_ExprList)                    n = n1; mode = IM_Editing; break; }
483             case IA_AddOp:        { S(n1, n, NK_Op)                                                   n = n1; mode = IM_Editing; break; }
484             }
485
486             #undef NA
487             #undef NS
488         }
489     }
490
491     return result;
492 }
493
494
495 void SetupInputActions(InputAction actions[NK_COUNT][IN_COUNT]) {
496     for (int i = 0; i < NK_COUNT; i++) {
497         actions[i][IN_H] = IA_MoveLeft;
498         actions[i][IN_J] = IA_MoveUp;
499         actions[i][IN_K] = IA_MoveDown;
500         actions[i][IN_L] = IA_MoveRight;
501     }
502
503     actions[NK_Namespace][IN_D] = IA_Delete;
504     actions[NK_Namespace][IN_SPACE] = IA_StartEditing;
505     actions[NK_Namespace][IN_N] = IA_AddNamespace;
506     actions[NK_Namespace][IN_S] = IA_AddStruct;
507     actions[NK_Namespace][IN_F] = IA_AddFunc;
508     
509     actions[NK_Struct][IN_D] = IA_Delete;
510     actions[NK_Struct][IN_SPACE] = IA_StartEditing;
511     actions[NK_Struct][IN_V] = IA_AddVarDecl;
512     actions[NK_Struct][IN_F] = IA_AddFunc;
513
514     actions[NK_Func][IN_D] = IA_Delete;
515     actions[NK_Func][IN_SPACE] = IA_StartEditing;
516
517     actions[NK_VarList][IN_V] = IA_AddVarDecl;
518     
519     actions[NK_ExprList][IN_V] = IA_AddVar;
520     actions[NK_ExprList][IN_I] = IA_AddIf;
521     actions[NK_ExprList][IN_W] = IA_AddWhile;
522     actions[NK_ExprList][IN_N] = IA_AddNum;
523     actions[NK_ExprList][IN_S] = IA_AddStr;
524     actions[NK_ExprList][IN_C] = IA_AddCall;
525     actions[NK_ExprList][IN_O] = IA_AddOp;
526
527     actions[NK_Var][IN_D] = IA_Delete;
528     actions[NK_Var][IN_SPACE] = IA_StartEditing;
529
530     actions[NK_VarDecl][IN_D] = IA_Delete;
531     actions[NK_VarDecl][IN_SPACE] = IA_StartEditing;
532
533     actions[NK_VarType][IN_SPACE] = IA_StartEditing;
534     actions[NK_VarType][IN_T] = IA_AddType;
535
536     actions[NK_Type][IN_D] = IA_Delete;
537     actions[NK_Type][IN_SPACE] = IA_StartEditing;
538     actions[NK_Type][IN_T] = IA_AddType;
539
540     actions[NK_Body][IN_F] = IA_AddFunc;
541     actions[NK_Body][IN_V] = IA_AddVarDecl;
542     actions[NK_Body][IN_I] = IA_AddIf;
543     actions[NK_Body][IN_W] = IA_AddWhile;
544     actions[NK_Body][IN_N] = IA_AddNum;
545     actions[NK_Body][IN_S] = IA_AddStr;
546     actions[NK_Body][IN_C] = IA_AddCall;
547     actions[NK_Body][IN_O] = IA_AddOp;
548
549     actions[NK_If][IN_D] = IA_Delete;
550
551     actions[NK_While][IN_D] = IA_Delete;
552
553     actions[NK_Num][IN_D] = IA_Delete;
554     actions[NK_Num][IN_SPACE] = IA_StartEditing;
555
556     actions[NK_Str][IN_D] = IA_Delete;
557     actions[NK_Str][IN_SPACE] = IA_StartEditing;
558
559     actions[NK_Call][IN_D] = IA_Delete;
560     actions[NK_Call][IN_SPACE] = IA_StartEditing;
561
562     actions[NK_Op][IN_D] = IA_Delete;
563     actions[NK_Op][IN_SPACE] = IA_StartEditing;
564     actions[NK_Op][IN_V] = IA_AddVar;
565     actions[NK_Op][IN_I] = IA_AddIf;
566     actions[NK_Op][IN_W] = IA_AddWhile;
567     actions[NK_Op][IN_N] = IA_AddNum;
568     actions[NK_Op][IN_S] = IA_AddStr;
569     actions[NK_Op][IN_C] = IA_AddCall;
570     actions[NK_Op][IN_O] = IA_AddOp;
571 }
572
573 int main() {
574     // Setup
575     static InputAction actions[NK_COUNT][IN_COUNT];
576     SetupInputActions(actions);
577
578     // Main
579     vt100EnableAlternateBuffer();
580     vt100HideCursor();
581
582     Node *n = GetNode(actions);
583
584     vt100DisableAlternateBuffer();
585     vt100ShowCursor();
586
587     NodeDraw(n);
588
589     return 0;
590 }