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