#include "parse.h" #include "Token.h" #include "Scope.h" #include #include static void *unexpected(const Token *tok, int n); static const Token *expression(const Token *tok); static const Token *keyword_fn(const Token *tok); static const Token *keyword_var(Scope *scope, const Token *tok); static const Token *keyword_const(Scope *scope, const Token *tok); int parse(const Token *tok) { Scope *scope = scope_create(NULL); if (scope == NULL) return 1; while (tok != NULL && tok->type != TOK_NONE) { switch (tok->type) { case TOK_KW_FN: tok = keyword_fn(tok); break; case TOK_KW_VAR: tok = keyword_var(scope, tok); break; case TOK_KW_CONST: tok = keyword_const(scope, tok); break; default: unexpected(tok, -1); return free(scope), 1; } if (tok == NULL) return free(scope), 1; } return free(scope), 0; } /* write unexpected token error to stderr before returning NULL, * `n` is used to mark the error in code */ static void *unexpected(const Token *tok, int n) { fprintf(stderr, "[%d] unexpected %s %s%s%sat %u:%u\n", n, token_type_str(tok->type), (tok->s != NULL) ? "(" : "", (tok->s != NULL) ? tok->s : "", (tok->s != NULL) ? ") " : "", tok->line, tok->column); return NULL; } /* any chain of instructions that results in a value */ static const Token *expression(const Token *tok) { if (tok->type == TOK_INTEGER) return tok + 1; if (tok->type == TOK_STRING) return tok + 1; if (tok->type == TOK_WORD) return tok + 1; return unexpected(tok, 20); } static const Token *keyword_fn(const Token *tok) { tok += 1; if (tok->type != TOK_WORD) return unexpected(tok, 0); const Token *name = tok; tok += 1; (void)name; if (tok->type != TOK_PAREN_OPEN) return unexpected(tok, 1); tok += 1; size_t args = 0; while (tok->type == TOK_WORD) { tok += 1; args += 1; if (tok->type == TOK_COMMA) tok += 1; } if (tok->type != TOK_PAREN_CLOS) return unexpected(tok, 2); printf("%zu args\n", args); return tok + 1; } /* mutable variable declaration */ static const Token *keyword_var(Scope *scope, const Token *tok) { tok += 1; if (tok->type != TOK_WORD) return unexpected(tok, 10); const Token *name = tok; (void)name; tok += 1; /* no initialization */ if (tok->type == TOK_SEMICOLON) { if (scope_insert(scope, name->s, 0)) return NULL; return tok + 1; } if (tok->type != TOK_ASSIGN) return unexpected(tok, 11); tok = expression(tok + 1); if (tok == NULL) return NULL; if (tok->type != TOK_SEMICOLON) return unexpected(tok, 12); if (scope_insert(scope, name->s, 0)) return NULL; return tok + 1; } /* constant variable declaration */ static const Token *keyword_const(Scope *scope, const Token *tok) { tok += 1; if (tok->type != TOK_WORD) return unexpected(tok, 10); const Token *name = tok; (void)name; tok += 1; if (tok->type != TOK_ASSIGN) return unexpected(tok, 11); tok = expression(tok + 1); if (tok == NULL) return NULL; if (tok->type != TOK_SEMICOLON) return unexpected(tok, 12); if (scope_insert(scope, name->s, 0)) return NULL; return tok + 1; }