2025-12-02 06:54:32 +01:00
|
|
|
#define _POSIX_C_SOURCE 200809L
|
|
|
|
|
#include "parser.h"
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
extern void _rava_parser_advance(RavaParser_t *parser);
|
|
|
|
|
extern bool _rava_parser_check(RavaParser_t *parser, RavaTokenType_e type);
|
|
|
|
|
extern bool _rava_parser_match(RavaParser_t *parser, RavaTokenType_e type);
|
|
|
|
|
extern bool _rava_parser_expect(RavaParser_t *parser, RavaTokenType_e type, const char *message);
|
|
|
|
|
extern RavaASTNode_t* _rava_parser_parse_type(RavaParser_t *parser);
|
|
|
|
|
extern RavaASTNode_t* _rava_parser_parse_expression(RavaParser_t *parser);
|
|
|
|
|
extern RavaASTNode_t* _rava_parser_parse_block(RavaParser_t *parser);
|
|
|
|
|
extern void _rava_parser_parse_modifiers(RavaParser_t *parser, RavaModifier_e **modifiers, size_t *count);
|
|
|
|
|
|
|
|
|
|
static RavaASTNode_t* _rava_parser_parse_method_declaration(RavaParser_t *parser,
|
|
|
|
|
RavaModifier_e *modifiers,
|
|
|
|
|
size_t modifiers_count,
|
|
|
|
|
RavaASTNode_t *return_type) {
|
|
|
|
|
RavaASTNode_t *method = rava_ast_node_create(RAVA_AST_METHOD_DECL,
|
|
|
|
|
parser->current_token->line,
|
|
|
|
|
parser->current_token->column);
|
|
|
|
|
|
|
|
|
|
method->data.method_decl.modifiers = modifiers;
|
|
|
|
|
method->data.method_decl.modifiers_count = modifiers_count;
|
|
|
|
|
method->data.method_decl.return_type = return_type;
|
|
|
|
|
|
|
|
|
|
if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) {
|
|
|
|
|
method->data.method_decl.name = strdup(parser->current_token->lexeme);
|
|
|
|
|
_rava_parser_advance(parser);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_rava_parser_expect(parser, RAVA_TOKEN_LPAREN, "Expected '(' after method name");
|
|
|
|
|
|
|
|
|
|
while (!_rava_parser_check(parser, RAVA_TOKEN_RPAREN) &&
|
|
|
|
|
!_rava_parser_check(parser, RAVA_TOKEN_EOF)) {
|
|
|
|
|
RavaASTNode_t *param_type = _rava_parser_parse_type(parser);
|
|
|
|
|
RavaASTNode_t *param = rava_ast_node_create(RAVA_AST_PARAM_DECL,
|
|
|
|
|
parser->current_token->line,
|
|
|
|
|
parser->current_token->column);
|
|
|
|
|
param->data.var_decl.type = param_type;
|
|
|
|
|
|
|
|
|
|
if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) {
|
|
|
|
|
param->data.var_decl.name = strdup(parser->current_token->lexeme);
|
|
|
|
|
_rava_parser_advance(parser);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rava_ast_node_add_child(method, param);
|
|
|
|
|
|
|
|
|
|
if (!_rava_parser_match(parser, RAVA_TOKEN_COMMA)) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_rava_parser_expect(parser, RAVA_TOKEN_RPAREN, "Expected ')' after parameters");
|
|
|
|
|
|
|
|
|
|
if (_rava_parser_check(parser, RAVA_TOKEN_LBRACE)) {
|
|
|
|
|
RavaASTNode_t *body = _rava_parser_parse_block(parser);
|
|
|
|
|
rava_ast_node_add_child(method, body);
|
|
|
|
|
} else {
|
|
|
|
|
_rava_parser_expect(parser, RAVA_TOKEN_SEMICOLON, "Expected ';' or '{' after method declaration");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return method;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RavaASTNode_t* _rava_parser_parse_class_declaration(RavaParser_t *parser) {
|
|
|
|
|
RavaModifier_e *modifiers = NULL;
|
|
|
|
|
size_t modifiers_count = 0;
|
|
|
|
|
|
|
|
|
|
_rava_parser_parse_modifiers(parser, &modifiers, &modifiers_count);
|
|
|
|
|
|
|
|
|
|
_rava_parser_expect(parser, RAVA_TOKEN_KEYWORD_CLASS, "Expected 'class' keyword");
|
|
|
|
|
|
|
|
|
|
RavaASTNode_t *class_decl = rava_ast_node_create(RAVA_AST_CLASS_DECL,
|
|
|
|
|
parser->current_token->line,
|
|
|
|
|
parser->current_token->column);
|
|
|
|
|
|
|
|
|
|
class_decl->data.class_decl.modifiers = modifiers;
|
|
|
|
|
class_decl->data.class_decl.modifiers_count = modifiers_count;
|
|
|
|
|
class_decl->data.class_decl.superclass = NULL;
|
2025-12-02 21:12:50 +01:00
|
|
|
class_decl->data.class_decl.interfaces = NULL;
|
|
|
|
|
class_decl->data.class_decl.interfaces_count = 0;
|
2025-12-02 06:54:32 +01:00
|
|
|
|
|
|
|
|
if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) {
|
|
|
|
|
class_decl->data.class_decl.name = strdup(parser->current_token->lexeme);
|
|
|
|
|
_rava_parser_advance(parser);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_rava_parser_match(parser, RAVA_TOKEN_KEYWORD_EXTENDS)) {
|
|
|
|
|
if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) {
|
|
|
|
|
class_decl->data.class_decl.superclass = strdup(parser->current_token->lexeme);
|
|
|
|
|
_rava_parser_advance(parser);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-02 21:12:50 +01:00
|
|
|
if (_rava_parser_match(parser, RAVA_TOKEN_KEYWORD_IMPLEMENTS)) {
|
|
|
|
|
size_t capacity = 4;
|
|
|
|
|
class_decl->data.class_decl.interfaces = malloc(capacity * sizeof(char*));
|
|
|
|
|
do {
|
|
|
|
|
if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) {
|
|
|
|
|
if (class_decl->data.class_decl.interfaces_count >= capacity) {
|
|
|
|
|
capacity *= 2;
|
|
|
|
|
class_decl->data.class_decl.interfaces = realloc(
|
|
|
|
|
class_decl->data.class_decl.interfaces,
|
|
|
|
|
capacity * sizeof(char*));
|
|
|
|
|
}
|
|
|
|
|
class_decl->data.class_decl.interfaces[class_decl->data.class_decl.interfaces_count++] =
|
|
|
|
|
strdup(parser->current_token->lexeme);
|
|
|
|
|
_rava_parser_advance(parser);
|
|
|
|
|
}
|
|
|
|
|
} while (_rava_parser_match(parser, RAVA_TOKEN_COMMA));
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-02 06:54:32 +01:00
|
|
|
_rava_parser_expect(parser, RAVA_TOKEN_LBRACE, "Expected '{' after class name");
|
|
|
|
|
|
|
|
|
|
while (!_rava_parser_check(parser, RAVA_TOKEN_RBRACE) &&
|
|
|
|
|
!_rava_parser_check(parser, RAVA_TOKEN_EOF)) {
|
|
|
|
|
|
|
|
|
|
RavaModifier_e *member_modifiers = NULL;
|
|
|
|
|
size_t member_modifiers_count = 0;
|
|
|
|
|
|
|
|
|
|
_rava_parser_parse_modifiers(parser, &member_modifiers, &member_modifiers_count);
|
|
|
|
|
|
|
|
|
|
if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER) &&
|
2025-12-03 14:08:55 +01:00
|
|
|
strcmp(parser->current_token->lexeme, class_decl->data.class_decl.name) == 0 &&
|
|
|
|
|
parser->peek_token && parser->peek_token->type == RAVA_TOKEN_LPAREN) {
|
2025-12-02 06:54:32 +01:00
|
|
|
|
|
|
|
|
RavaASTNode_t *constructor = rava_ast_node_create(RAVA_AST_CONSTRUCTOR_DECL,
|
|
|
|
|
parser->current_token->line,
|
|
|
|
|
parser->current_token->column);
|
|
|
|
|
_rava_parser_advance(parser);
|
|
|
|
|
|
|
|
|
|
_rava_parser_expect(parser, RAVA_TOKEN_LPAREN, "Expected '(' after constructor name");
|
|
|
|
|
|
|
|
|
|
while (!_rava_parser_check(parser, RAVA_TOKEN_RPAREN) &&
|
|
|
|
|
!_rava_parser_check(parser, RAVA_TOKEN_EOF)) {
|
|
|
|
|
RavaASTNode_t *param_type = _rava_parser_parse_type(parser);
|
|
|
|
|
RavaASTNode_t *param = rava_ast_node_create(RAVA_AST_PARAM_DECL,
|
|
|
|
|
parser->current_token->line,
|
|
|
|
|
parser->current_token->column);
|
|
|
|
|
param->data.var_decl.type = param_type;
|
|
|
|
|
|
|
|
|
|
if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) {
|
|
|
|
|
param->data.var_decl.name = strdup(parser->current_token->lexeme);
|
|
|
|
|
_rava_parser_advance(parser);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rava_ast_node_add_child(constructor, param);
|
|
|
|
|
|
|
|
|
|
if (!_rava_parser_match(parser, RAVA_TOKEN_COMMA)) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_rava_parser_expect(parser, RAVA_TOKEN_RPAREN, "Expected ')' after constructor parameters");
|
|
|
|
|
|
|
|
|
|
if (_rava_parser_check(parser, RAVA_TOKEN_LBRACE)) {
|
|
|
|
|
RavaASTNode_t *body = _rava_parser_parse_block(parser);
|
|
|
|
|
rava_ast_node_add_child(constructor, body);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rava_ast_node_add_child(class_decl, constructor);
|
|
|
|
|
free(member_modifiers);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RavaASTNode_t *member_type = _rava_parser_parse_type(parser);
|
|
|
|
|
|
|
|
|
|
if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) {
|
|
|
|
|
char *name = strdup(parser->current_token->lexeme);
|
|
|
|
|
_rava_parser_advance(parser);
|
|
|
|
|
|
|
|
|
|
if (_rava_parser_check(parser, RAVA_TOKEN_LPAREN)) {
|
|
|
|
|
RavaASTNode_t *method = _rava_parser_parse_method_declaration(parser,
|
|
|
|
|
member_modifiers,
|
|
|
|
|
member_modifiers_count,
|
|
|
|
|
member_type);
|
|
|
|
|
method->data.method_decl.name = name;
|
|
|
|
|
rava_ast_node_add_child(class_decl, method);
|
|
|
|
|
} else {
|
|
|
|
|
RavaASTNode_t *field = rava_ast_node_create(RAVA_AST_FIELD_DECL,
|
|
|
|
|
parser->current_token->line,
|
|
|
|
|
parser->current_token->column);
|
2025-12-02 21:12:50 +01:00
|
|
|
field->data.field_decl.type = member_type;
|
|
|
|
|
field->data.field_decl.name = name;
|
|
|
|
|
field->data.field_decl.modifiers = member_modifiers;
|
|
|
|
|
field->data.field_decl.modifiers_count = member_modifiers_count;
|
2025-12-02 06:54:32 +01:00
|
|
|
if (_rava_parser_match(parser, RAVA_TOKEN_ASSIGN)) {
|
2025-12-02 21:12:50 +01:00
|
|
|
field->data.field_decl.initializer = _rava_parser_parse_expression(parser);
|
2025-12-02 06:54:32 +01:00
|
|
|
} else {
|
2025-12-02 21:12:50 +01:00
|
|
|
field->data.field_decl.initializer = NULL;
|
2025-12-02 06:54:32 +01:00
|
|
|
}
|
|
|
|
|
_rava_parser_expect(parser, RAVA_TOKEN_SEMICOLON, "Expected ';' after field declaration");
|
|
|
|
|
rava_ast_node_add_child(class_decl, field);
|
2025-12-02 21:12:50 +01:00
|
|
|
member_modifiers = NULL;
|
2025-12-02 06:54:32 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_rava_parser_expect(parser, RAVA_TOKEN_RBRACE, "Expected '}' after class body");
|
|
|
|
|
|
|
|
|
|
return class_decl;
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-02 21:12:50 +01:00
|
|
|
static RavaASTNode_t* _rava_parser_parse_interface_declaration(RavaParser_t *parser) {
|
|
|
|
|
RavaModifier_e *modifiers = NULL;
|
|
|
|
|
size_t modifiers_count = 0;
|
|
|
|
|
|
|
|
|
|
_rava_parser_parse_modifiers(parser, &modifiers, &modifiers_count);
|
|
|
|
|
|
|
|
|
|
_rava_parser_expect(parser, RAVA_TOKEN_KEYWORD_INTERFACE, "Expected 'interface' keyword");
|
|
|
|
|
|
|
|
|
|
RavaASTNode_t *interface_decl = rava_ast_node_create(RAVA_AST_INTERFACE_DECL,
|
|
|
|
|
parser->current_token->line,
|
|
|
|
|
parser->current_token->column);
|
|
|
|
|
|
|
|
|
|
interface_decl->data.interface_decl.modifiers = modifiers;
|
|
|
|
|
interface_decl->data.interface_decl.modifiers_count = modifiers_count;
|
|
|
|
|
|
|
|
|
|
if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) {
|
|
|
|
|
interface_decl->data.interface_decl.name = strdup(parser->current_token->lexeme);
|
|
|
|
|
_rava_parser_advance(parser);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_rava_parser_expect(parser, RAVA_TOKEN_LBRACE, "Expected '{' after interface name");
|
|
|
|
|
|
|
|
|
|
while (!_rava_parser_check(parser, RAVA_TOKEN_RBRACE) &&
|
|
|
|
|
!_rava_parser_check(parser, RAVA_TOKEN_EOF)) {
|
|
|
|
|
|
|
|
|
|
RavaModifier_e *member_modifiers = NULL;
|
|
|
|
|
size_t member_modifiers_count = 0;
|
|
|
|
|
|
|
|
|
|
_rava_parser_parse_modifiers(parser, &member_modifiers, &member_modifiers_count);
|
|
|
|
|
|
|
|
|
|
RavaASTNode_t *member_type = _rava_parser_parse_type(parser);
|
|
|
|
|
|
|
|
|
|
if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) {
|
|
|
|
|
char *name = strdup(parser->current_token->lexeme);
|
|
|
|
|
_rava_parser_advance(parser);
|
|
|
|
|
|
|
|
|
|
if (_rava_parser_check(parser, RAVA_TOKEN_LPAREN)) {
|
|
|
|
|
RavaASTNode_t *method = _rava_parser_parse_method_declaration(parser,
|
|
|
|
|
member_modifiers,
|
|
|
|
|
member_modifiers_count,
|
|
|
|
|
member_type);
|
|
|
|
|
method->data.method_decl.name = name;
|
|
|
|
|
rava_ast_node_add_child(interface_decl, method);
|
|
|
|
|
} else {
|
|
|
|
|
free(name);
|
|
|
|
|
free(member_modifiers);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
free(member_modifiers);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_rava_parser_expect(parser, RAVA_TOKEN_RBRACE, "Expected '}' after interface body");
|
|
|
|
|
|
|
|
|
|
return interface_decl;
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-02 06:54:32 +01:00
|
|
|
RavaASTNode_t* rava_parser_parse(RavaParser_t *parser) {
|
|
|
|
|
RavaASTNode_t *root = rava_ast_node_create(RAVA_AST_COMPILATION_UNIT, 1, 1);
|
|
|
|
|
|
|
|
|
|
while (!_rava_parser_check(parser, RAVA_TOKEN_EOF)) {
|
|
|
|
|
if (parser->had_error) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-02 21:12:50 +01:00
|
|
|
RavaModifier_e *modifiers = NULL;
|
|
|
|
|
size_t modifiers_count = 0;
|
|
|
|
|
_rava_parser_parse_modifiers(parser, &modifiers, &modifiers_count);
|
|
|
|
|
|
|
|
|
|
RavaASTNode_t *decl = NULL;
|
|
|
|
|
|
|
|
|
|
if (_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_INTERFACE)) {
|
|
|
|
|
RavaToken_t *saved = parser->current_token;
|
|
|
|
|
parser->current_token = saved;
|
|
|
|
|
free(modifiers);
|
|
|
|
|
decl = _rava_parser_parse_interface_declaration(parser);
|
|
|
|
|
} else if (_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_CLASS)) {
|
|
|
|
|
RavaToken_t *saved = parser->current_token;
|
|
|
|
|
parser->current_token = saved;
|
|
|
|
|
free(modifiers);
|
|
|
|
|
decl = _rava_parser_parse_class_declaration(parser);
|
|
|
|
|
} else {
|
|
|
|
|
free(modifiers);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-02 06:54:32 +01:00
|
|
|
if (decl) {
|
|
|
|
|
rava_ast_node_add_child(root, decl);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return root;
|
|
|
|
|
}
|