struct parser { const char* text; enum token token; int start; int end; int string; int prev_indent; int indent; int line_start; }; static void parse_token(struct parser* p) { const char* text; int i; char c; enum token token; retry: p->start = p->end; text = p->text + p->start; if (p->line_start) { p->line_start = 0; for (i = 0; (c = text[i]) && c == ' '; i++) ; assert(i % 4 == 0); p->indent = i / 4; } if (p->prev_indent < p->indent) { p->prev_indent++; p->token = TOKEN_INDENT; return; } if (p->indent < p->prev_indent) { p->prev_indent--; p->token = TOKEN_DEDENT; return; } c = text[0]; token = char_to_token(c); switch (token) { case TOKEN_EOF: case TOKEN_LEFT_PARENS: case TOKEN_RIGHT_PARENS: case TOKEN_LEFT_BRACE: case TOKEN_RIGHT_BRACE: case TOKEN_COLON: case TOKEN_SEMICOLON: case TOKEN_EQUALS: p->token = token; p->end++; break; case TOKEN_ARROW: c = text[1]; if (c != '>') { printf("expected '->', got '-%c'\n", c); exit(1); } p->token = TOKEN_ARROW; p->end += 2; break; case TOKEN_FN: case TOKEN_RETURN: case TOKEN_I32: case TOKEN_MAX_VALUE: case TOKEN_INDENT: case TOKEN_DEDENT: UNREACHABLE(); break; case TOKEN_NAME: parse_name(p); break; case TOKEN_INTEGER: parse_integer(p); break; case TOKEN_NEWLINE: while (p->text[++p->end] == '\n') ; assert(p->prev_indent == p->indent); p->token = TOKEN_NEWLINE; p->line_start = 1; break; case TOKEN_SPACE: p->end++; goto retry; case TOKEN_ERROR: printf("unexpected character '%c'\n", c); exit(1); } } fn main() -> i32: x = 2 return x x x x x x \n 0 1 fn 1 3 main 4 8 ( 8 9 ) 9 10 -> 11 13 i32 14 17 : 17 18 \n 18 19 [indent] 19 19 x 23 24 = 25 26 2 27 28 \n 28 29 return 33 39 x 40 41 \n 41 43 [dedent] 43 43 x 43 44 \n 44 45 [indent] 45 45 x 49 50 \n 50 51 [indent] 51 51 x 59 60 \n 60 61 [dedent] 61 61 x 65 66 \n 66 67 [indent] 67 67 x 75 76 \n 76 77 [dedent] 77 77 [dedent] 77 77