onyx_lex_tokens(&tokenizer);
bh_arr(OnyxToken) token_arr = tokenizer.tokens;
- // bh_printf("There are %d tokens (Allocated space for %d tokens)\n", bh_arr_length(token_arr), bh_arr_capacity(token_arr));
+#if 0
+ bh_printf("There are %d tokens (Allocated space for %d tokens)\n", bh_arr_length(token_arr), bh_arr_capacity(token_arr));
- // for (OnyxToken* it = token_arr; !bh_arr_end(token_arr, it); it++) {
- // onyx_token_null_toggle(*it);
- // bh_printf("%s (%s:%l:%l)\n", onyx_get_token_type_name(it->type), it->pos.filename, it->pos.line, it->pos.column);
- // onyx_token_null_toggle(*it);
- // }
+ for (OnyxToken* it = token_arr; !bh_arr_end(token_arr, it); it++) {
+ onyx_token_null_toggle(*it);
+ bh_printf("%s (%s:%l:%l)\n", onyx_get_token_type_name(it->type), it->pos.filename, it->pos.line, it->pos.column);
+ onyx_token_null_toggle(*it);
+ }
+#endif
bh_arena msg_arena;
bh_arena_init(&msg_arena, alloc, 4096);
OnyxParser parser = onyx_parser_create(ast_alloc, &tokenizer, &msgs);
OnyxAstNode* program = onyx_parse(&parser);
- onyx_message_print(&msgs);
- onyx_ast_print(program);
+ // NOTE: if there are errors, assume the parse tree was generated wrong,
+ // even if it may have still been generated correctly.
+ if (onyx_message_has_errors(&msgs)) {
+ onyx_message_print(&msgs);
+ } else {
+ onyx_ast_print(program);
+ }
bh_file_contents_delete(&fc);
onyx_tokenizer_free(&tokenizer);
"for", //"TOKEN_TYPE_KEYWORD_FOR",
"do", //"TOKEN_TYPE_KEYWORD_DO",
"return", //"TOKEN_TYPE_KEYWORD_RETURN",
+ "const", //"TOKEN_TYPE_KEYWORD_CONST",
"foreign", //"TOKEN_TYPE_KEYWORD_FOREIGN",
"proc", //"TOKEN_TYPE_KEYWORD_PROC",
"global", //"TOKEN_TYPE_KEYWORD_GLOBAL",
LITERAL_TOKEN("foreign", TOKEN_TYPE_KEYWORD_FOREIGN);
LITERAL_TOKEN("for", TOKEN_TYPE_KEYWORD_FOR);
LITERAL_TOKEN("return", TOKEN_TYPE_KEYWORD_RETURN);
+ LITERAL_TOKEN("const", TOKEN_TYPE_KEYWORD_CONST);
LITERAL_TOKEN("do", TOKEN_TYPE_KEYWORD_DO);
LITERAL_TOKEN("proc", TOKEN_TYPE_KEYWORD_PROC);
LITERAL_TOKEN("global", TOKEN_TYPE_KEYWORD_GLOBAL);
static OnyxToken* expect(OnyxParser* parser, OnyxTokenType token_type);
static OnyxAstNodeScope* enter_scope(OnyxParser* parser);
static OnyxAstNodeScope* leave_scope(OnyxParser* parser);
-static void insert_identifier(OnyxParser* parser, OnyxAstNodeLocal* local);
+static void insert_local(OnyxParser* parser, OnyxAstNodeLocal* local);
static OnyxAstNode* parse_factor(OnyxParser* parser);
static OnyxAstNode* parse_bin_op(OnyxParser* parser, OnyxAstNode* left);
static OnyxAstNode* parse_expression(OnyxParser* parser);
static OnyxAstNode* parse_if_stmt(OnyxParser* parser);
-static b32 parse_expression_statement(OnyxParser* parser, OnyxAstNode** ret);
+static b32 parse_symbol_statement(OnyxParser* parser, OnyxAstNode** ret);
static OnyxAstNode* parse_return_statement(OnyxParser* parser);
static OnyxAstNodeBlock* parse_block(OnyxParser* parser, b32 belongs_to_function);
static OnyxAstNode* parse_statement(OnyxParser* parser);
}
}
+static void find_token(OnyxParser* parser, OnyxTokenType token_type) {
+ while (parser->curr_token->type != token_type && !is_terminating_token(parser->curr_token->type)) {
+ parser_next_token(parser);
+ }
+}
+
// Advances to next token no matter what
static OnyxToken* expect(OnyxParser* parser, OnyxTokenType token_type) {
OnyxToken* token = parser->curr_token;
return ident;
}
-static void insert_identifier(OnyxParser* parser, OnyxAstNodeLocal* local) {
+static void insert_local(OnyxParser* parser, OnyxAstNodeLocal* local) {
OnyxAstNodeScope* scope = parser->curr_scope;
local->prev_local = scope->last_local;
scope->last_local = local;
// Returns 1 if the symbol was consumed. Returns 0 otherwise
// ret is set to the statement to insert
-static b32 parse_expression_statement(OnyxParser* parser, OnyxAstNode** ret) {
+static b32 parse_symbol_statement(OnyxParser* parser, OnyxAstNode** ret) {
if (parser->curr_token->type != TOKEN_TYPE_SYMBOL) return 0;
OnyxToken* symbol = expect(parser, TOKEN_TYPE_SYMBOL);
case TOKEN_TYPE_SYM_COLON: {
parser_next_token(parser);
OnyxTypeInfo* type = &builtin_types[ONYX_TYPE_INFO_KIND_UNKNOWN];
+ u32 flags = ONYX_AST_FLAG_LVAL;
+
+ // NOTE: var: const ...
+ if (parser->curr_token->type == TOKEN_TYPE_KEYWORD_CONST) {
+ parser_next_token(parser);
+ flags |= ONYX_AST_FLAG_CONST;
+ }
// NOTE: var: type
if (parser->curr_token->type == TOKEN_TYPE_SYMBOL) {
OnyxAstNodeLocal* local = (OnyxAstNodeLocal*) onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_LOCAL);
local->token = symbol;
local->type = type;
+ local->flags |= flags;
- insert_identifier(parser, local);
+ insert_local(parser, local);
if (parser->curr_token->type == TOKEN_TYPE_SYM_EQUALS) {
parser_next_token(parser);
OnyxAstNode* lval = lookup_identifier(parser, symbol);
+ if (lval != NULL && lval->flags & ONYX_AST_FLAG_LVAL && (lval->flags & ONYX_AST_FLAG_CONST) == 0) {
+ OnyxAstNode* rval = parse_expression(parser);
+ OnyxAstNode* assignment = onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_ASSIGNMENT);
+ assignment->right = rval;
+ assignment->left = lval;
+ *ret = assignment;
+ return 1;
+ }
+
+ onyx_token_null_toggle(*symbol);
if (lval == NULL) {
- // TODO: error handling
+ onyx_message_add(parser->msgs,
+ ONYX_MESSAGE_TYPE_UNKNOWN_SYMBOL,
+ symbol->pos, symbol->token);
+ }
+
+ else if ((lval->flags & ONYX_AST_FLAG_LVAL) == 0) {
+ onyx_message_add(parser->msgs,
+ ONYX_MESSAGE_TYPE_NOT_LVAL,
+ symbol->pos, symbol->token);
}
- OnyxAstNode* rval = parse_expression(parser);
- OnyxAstNode* assignment = onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_ASSIGNMENT);
- assignment->right = rval;
- assignment->left = lval;
- *ret = assignment;
+ else if (lval->flags & ONYX_AST_FLAG_CONST) {
+ onyx_message_add(parser->msgs,
+ ONYX_MESSAGE_TYPE_ASSIGN_CONST,
+ symbol->pos, symbol->token);
+ }
+ onyx_token_null_toggle(*symbol);
+
+ find_token(parser, TOKEN_TYPE_SYM_SEMICOLON);
return 1;
}
case TOKEN_TYPE_SYMBOL: {
OnyxAstNode* ret = NULL;
- if (parse_expression_statement(parser, &ret)) return ret;
+ if (parse_symbol_statement(parser, &ret)) return ret;
// fallthrough
}
parser->curr_token->pos,
onyx_get_token_type_name(TOKEN_TYPE_SYM_SEMICOLON),
onyx_get_token_type_name(parser->curr_token->type));
+
+ find_token(parser, TOKEN_TYPE_SYM_SEMICOLON);
}
parser_next_token(parser);
}
OnyxTypeInfo* return_type = parse_type(parser);
func_def->return_type = return_type;
- // TODO: Add params to parser.identifiers
+ // BUG: if a param has the same name as a global or function, that global/function
+ // will no longer be in scope after the function body ends
for (OnyxAstNodeParam* p = func_def->params; p != NULL; p = p->next) {
onyx_token_null_toggle(*p->token);
bh_hash_put(OnyxAstNode*, parser->identifiers, p->token->token, (OnyxAstNode*) p);
func_def->body = parse_block(parser, 1);
- // TODO: Remove params from parser.identifiers
for (OnyxAstNodeParam* p = func_def->params; p != NULL; p = p->next) {
onyx_token_null_toggle(*p->token);
bh_hash_delete(OnyxAstNode*, parser->identifiers, p->token->token);