feat: add initial plot.py module with beast visualization logic
This commit introduces the core plotting module for the beast project, including the initial implementation of data visualization functions and chart generation utilities. The module provides the foundational structure for rendering beast-related metrics and graphical outputs.
This commit is contained in:
+236
@@ -0,0 +1,236 @@
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#include "parser.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
RavaASTNode_t* rava_ast_node_create(RavaASTNodeType_e type, int line, int column) {
|
||||
RavaASTNode_t *node = calloc(1, sizeof(RavaASTNode_t));
|
||||
node->type = type;
|
||||
node->line = line;
|
||||
node->column = column;
|
||||
node->parent = NULL;
|
||||
node->children = NULL;
|
||||
node->children_count = 0;
|
||||
node->children_capacity = 0;
|
||||
return node;
|
||||
}
|
||||
|
||||
void rava_ast_node_destroy(RavaASTNode_t *node) {
|
||||
if (!node) return;
|
||||
|
||||
for (size_t i = 0; i < node->children_count; i++) {
|
||||
rava_ast_node_destroy(node->children[i]);
|
||||
}
|
||||
free(node->children);
|
||||
|
||||
switch (node->type) {
|
||||
case RAVA_AST_IDENTIFIER_EXPR:
|
||||
free(node->data.identifier.name);
|
||||
break;
|
||||
case RAVA_AST_CLASS_DECL:
|
||||
free(node->data.class_decl.name);
|
||||
free(node->data.class_decl.modifiers);
|
||||
rava_ast_node_destroy(node->data.class_decl.type);
|
||||
break;
|
||||
case RAVA_AST_METHOD_DECL:
|
||||
free(node->data.method_decl.name);
|
||||
free(node->data.method_decl.modifiers);
|
||||
rava_ast_node_destroy(node->data.method_decl.return_type);
|
||||
break;
|
||||
case RAVA_AST_VAR_DECL:
|
||||
free(node->data.var_decl.name);
|
||||
rava_ast_node_destroy(node->data.var_decl.type);
|
||||
rava_ast_node_destroy(node->data.var_decl.initializer);
|
||||
break;
|
||||
case RAVA_AST_TYPE:
|
||||
free(node->data.type.type_name);
|
||||
break;
|
||||
case RAVA_AST_MEMBER_ACCESS_EXPR:
|
||||
free(node->data.member_access.member);
|
||||
rava_ast_node_destroy(node->data.member_access.object);
|
||||
break;
|
||||
case RAVA_AST_CALL_EXPR:
|
||||
rava_ast_node_destroy(node->data.call.callee);
|
||||
for (size_t i = 0; i < node->data.call.arguments_count; i++) {
|
||||
rava_ast_node_destroy(node->data.call.arguments[i]);
|
||||
}
|
||||
free(node->data.call.arguments);
|
||||
break;
|
||||
case RAVA_AST_NEW_EXPR:
|
||||
rava_ast_node_destroy(node->data.new_expr.type);
|
||||
for (size_t i = 0; i < node->data.new_expr.arguments_count; i++) {
|
||||
rava_ast_node_destroy(node->data.new_expr.arguments[i]);
|
||||
}
|
||||
free(node->data.new_expr.arguments);
|
||||
break;
|
||||
case RAVA_AST_LITERAL_EXPR:
|
||||
if (node->data.literal.literal_type == RAVA_TOKEN_LITERAL_STRING) {
|
||||
free(node->data.literal.value.string_value);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
free(node);
|
||||
}
|
||||
|
||||
void rava_ast_node_add_child(RavaASTNode_t *parent, RavaASTNode_t *child) {
|
||||
if (!parent || !child) return;
|
||||
|
||||
if (parent->children_count >= parent->children_capacity) {
|
||||
size_t new_capacity = parent->children_capacity == 0 ? 4 : parent->children_capacity * 2;
|
||||
parent->children = realloc(parent->children, sizeof(RavaASTNode_t*) * new_capacity);
|
||||
parent->children_capacity = new_capacity;
|
||||
}
|
||||
|
||||
parent->children[parent->children_count++] = child;
|
||||
child->parent = parent;
|
||||
}
|
||||
|
||||
RavaParser_t* rava_parser_create(RavaLexer_t *lexer) {
|
||||
RavaParser_t *parser = malloc(sizeof(RavaParser_t));
|
||||
parser->lexer = lexer;
|
||||
parser->current_token = rava_lexer_next_token(lexer);
|
||||
parser->peek_token = rava_lexer_next_token(lexer);
|
||||
parser->error_message = NULL;
|
||||
parser->had_error = false;
|
||||
return parser;
|
||||
}
|
||||
|
||||
void rava_parser_destroy(RavaParser_t *parser) {
|
||||
if (!parser) return;
|
||||
|
||||
rava_token_destroy(parser->current_token);
|
||||
rava_token_destroy(parser->peek_token);
|
||||
free(parser->error_message);
|
||||
free(parser);
|
||||
}
|
||||
|
||||
void _rava_parser_advance(RavaParser_t *parser) {
|
||||
rava_token_destroy(parser->current_token);
|
||||
parser->current_token = parser->peek_token;
|
||||
parser->peek_token = rava_lexer_next_token(parser->lexer);
|
||||
}
|
||||
|
||||
bool _rava_parser_check(RavaParser_t *parser, RavaTokenType_e type) {
|
||||
return parser->current_token->type == type;
|
||||
}
|
||||
|
||||
bool _rava_parser_match(RavaParser_t *parser, RavaTokenType_e type) {
|
||||
if (_rava_parser_check(parser, type)) {
|
||||
_rava_parser_advance(parser);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool _rava_parser_expect(RavaParser_t *parser, RavaTokenType_e type, const char *message) {
|
||||
if (_rava_parser_check(parser, type)) {
|
||||
_rava_parser_advance(parser);
|
||||
return true;
|
||||
}
|
||||
|
||||
parser->had_error = true;
|
||||
if (parser->error_message) free(parser->error_message);
|
||||
parser->error_message = malloc(256);
|
||||
snprintf(parser->error_message, 256, "%s at line %d, column %d",
|
||||
message, parser->current_token->line, parser->current_token->column);
|
||||
return false;
|
||||
}
|
||||
|
||||
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_statement(RavaParser_t *parser);
|
||||
extern RavaASTNode_t* _rava_parser_parse_block(RavaParser_t *parser);
|
||||
|
||||
static RavaModifier_e _rava_token_to_modifier(RavaTokenType_e type) {
|
||||
switch (type) {
|
||||
case RAVA_TOKEN_KEYWORD_PUBLIC: return RAVA_MODIFIER_PUBLIC;
|
||||
case RAVA_TOKEN_KEYWORD_PRIVATE: return RAVA_MODIFIER_PRIVATE;
|
||||
case RAVA_TOKEN_KEYWORD_PROTECTED: return RAVA_MODIFIER_PROTECTED;
|
||||
case RAVA_TOKEN_KEYWORD_STATIC: return RAVA_MODIFIER_STATIC;
|
||||
case RAVA_TOKEN_KEYWORD_FINAL: return RAVA_MODIFIER_FINAL;
|
||||
case RAVA_TOKEN_KEYWORD_ABSTRACT: return RAVA_MODIFIER_ABSTRACT;
|
||||
case RAVA_TOKEN_KEYWORD_NATIVE: return RAVA_MODIFIER_NATIVE;
|
||||
case RAVA_TOKEN_KEYWORD_SYNCHRONIZED: return RAVA_MODIFIER_SYNCHRONIZED;
|
||||
case RAVA_TOKEN_KEYWORD_TRANSIENT: return RAVA_MODIFIER_TRANSIENT;
|
||||
case RAVA_TOKEN_KEYWORD_VOLATILE: return RAVA_MODIFIER_VOLATILE;
|
||||
case RAVA_TOKEN_KEYWORD_STRICTFP: return RAVA_MODIFIER_STRICTFP;
|
||||
default: return RAVA_MODIFIER_PUBLIC;
|
||||
}
|
||||
}
|
||||
|
||||
static bool _rava_is_modifier(RavaTokenType_e type) {
|
||||
return type == RAVA_TOKEN_KEYWORD_PUBLIC ||
|
||||
type == RAVA_TOKEN_KEYWORD_PRIVATE ||
|
||||
type == RAVA_TOKEN_KEYWORD_PROTECTED ||
|
||||
type == RAVA_TOKEN_KEYWORD_STATIC ||
|
||||
type == RAVA_TOKEN_KEYWORD_FINAL ||
|
||||
type == RAVA_TOKEN_KEYWORD_ABSTRACT ||
|
||||
type == RAVA_TOKEN_KEYWORD_NATIVE ||
|
||||
type == RAVA_TOKEN_KEYWORD_SYNCHRONIZED ||
|
||||
type == RAVA_TOKEN_KEYWORD_TRANSIENT ||
|
||||
type == RAVA_TOKEN_KEYWORD_VOLATILE ||
|
||||
type == RAVA_TOKEN_KEYWORD_STRICTFP;
|
||||
}
|
||||
|
||||
void _rava_parser_parse_modifiers(RavaParser_t *parser, RavaModifier_e **modifiers, size_t *count) {
|
||||
size_t capacity = 4;
|
||||
*modifiers = malloc(sizeof(RavaModifier_e) * capacity);
|
||||
*count = 0;
|
||||
|
||||
while (_rava_is_modifier(parser->current_token->type)) {
|
||||
if (*count >= capacity) {
|
||||
capacity *= 2;
|
||||
*modifiers = realloc(*modifiers, sizeof(RavaModifier_e) * capacity);
|
||||
}
|
||||
(*modifiers)[(*count)++] = _rava_token_to_modifier(parser->current_token->type);
|
||||
_rava_parser_advance(parser);
|
||||
}
|
||||
}
|
||||
|
||||
RavaASTNode_t* _rava_parser_parse_type(RavaParser_t *parser) {
|
||||
RavaASTNode_t *type_node = rava_ast_node_create(RAVA_AST_TYPE,
|
||||
parser->current_token->line,
|
||||
parser->current_token->column);
|
||||
|
||||
if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER) ||
|
||||
_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_INT) ||
|
||||
_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_BOOLEAN) ||
|
||||
_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_CHAR) ||
|
||||
_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_BYTE) ||
|
||||
_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_SHORT) ||
|
||||
_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_LONG) ||
|
||||
_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_FLOAT) ||
|
||||
_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_DOUBLE) ||
|
||||
_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_VOID)) {
|
||||
|
||||
type_node->data.type.type_name = strdup(parser->current_token->lexeme);
|
||||
type_node->data.type.is_array = false;
|
||||
type_node->data.type.array_dimensions = 0;
|
||||
_rava_parser_advance(parser);
|
||||
|
||||
while (_rava_parser_check(parser, RAVA_TOKEN_LBRACKET)) {
|
||||
if (parser->peek_token && parser->peek_token->type == RAVA_TOKEN_RBRACKET) {
|
||||
_rava_parser_advance(parser);
|
||||
_rava_parser_advance(parser);
|
||||
type_node->data.type.is_array = true;
|
||||
type_node->data.type.array_dimensions++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
parser->had_error = true;
|
||||
if (parser->error_message) free(parser->error_message);
|
||||
parser->error_message = strdup("Expected type name");
|
||||
rava_ast_node_destroy(type_node);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return type_node;
|
||||
}
|
||||
|
||||
RavaASTNode_t* rava_parser_parse(RavaParser_t *parser);
|
||||
+251
@@ -0,0 +1,251 @@
|
||||
#ifndef RAVA_PARSER_H
|
||||
#define RAVA_PARSER_H
|
||||
|
||||
#include "../lexer/lexer.h"
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef enum {
|
||||
RAVA_AST_COMPILATION_UNIT,
|
||||
|
||||
RAVA_AST_PACKAGE_DECL,
|
||||
RAVA_AST_IMPORT_DECL,
|
||||
|
||||
RAVA_AST_CLASS_DECL,
|
||||
RAVA_AST_INTERFACE_DECL,
|
||||
RAVA_AST_ENUM_DECL,
|
||||
|
||||
RAVA_AST_FIELD_DECL,
|
||||
RAVA_AST_METHOD_DECL,
|
||||
RAVA_AST_CONSTRUCTOR_DECL,
|
||||
RAVA_AST_INITIALIZER_BLOCK,
|
||||
|
||||
RAVA_AST_PARAM_DECL,
|
||||
RAVA_AST_VAR_DECL,
|
||||
|
||||
RAVA_AST_BLOCK_STMT,
|
||||
RAVA_AST_IF_STMT,
|
||||
RAVA_AST_WHILE_STMT,
|
||||
RAVA_AST_DO_WHILE_STMT,
|
||||
RAVA_AST_FOR_STMT,
|
||||
RAVA_AST_ENHANCED_FOR_STMT,
|
||||
RAVA_AST_SWITCH_STMT,
|
||||
RAVA_AST_CASE_STMT,
|
||||
RAVA_AST_TRY_STMT,
|
||||
RAVA_AST_CATCH_CLAUSE,
|
||||
RAVA_AST_THROW_STMT,
|
||||
RAVA_AST_RETURN_STMT,
|
||||
RAVA_AST_BREAK_STMT,
|
||||
RAVA_AST_CONTINUE_STMT,
|
||||
RAVA_AST_EXPR_STMT,
|
||||
RAVA_AST_EMPTY_STMT,
|
||||
RAVA_AST_SYNCHRONIZED_STMT,
|
||||
RAVA_AST_ASSERT_STMT,
|
||||
|
||||
RAVA_AST_LITERAL_EXPR,
|
||||
RAVA_AST_IDENTIFIER_EXPR,
|
||||
RAVA_AST_BINARY_EXPR,
|
||||
RAVA_AST_UNARY_EXPR,
|
||||
RAVA_AST_TERNARY_EXPR,
|
||||
RAVA_AST_ASSIGN_EXPR,
|
||||
RAVA_AST_CALL_EXPR,
|
||||
RAVA_AST_MEMBER_ACCESS_EXPR,
|
||||
RAVA_AST_ARRAY_ACCESS_EXPR,
|
||||
RAVA_AST_NEW_EXPR,
|
||||
RAVA_AST_CAST_EXPR,
|
||||
RAVA_AST_INSTANCEOF_EXPR,
|
||||
RAVA_AST_THIS_EXPR,
|
||||
RAVA_AST_SUPER_EXPR,
|
||||
RAVA_AST_CLASS_LITERAL_EXPR,
|
||||
RAVA_AST_ARRAY_INIT_EXPR,
|
||||
|
||||
RAVA_AST_TYPE,
|
||||
RAVA_AST_TYPE_PARAM,
|
||||
RAVA_AST_MODIFIER
|
||||
} RavaASTNodeType_e;
|
||||
|
||||
typedef enum {
|
||||
RAVA_MODIFIER_PUBLIC,
|
||||
RAVA_MODIFIER_PRIVATE,
|
||||
RAVA_MODIFIER_PROTECTED,
|
||||
RAVA_MODIFIER_STATIC,
|
||||
RAVA_MODIFIER_FINAL,
|
||||
RAVA_MODIFIER_ABSTRACT,
|
||||
RAVA_MODIFIER_NATIVE,
|
||||
RAVA_MODIFIER_SYNCHRONIZED,
|
||||
RAVA_MODIFIER_TRANSIENT,
|
||||
RAVA_MODIFIER_VOLATILE,
|
||||
RAVA_MODIFIER_STRICTFP
|
||||
} RavaModifier_e;
|
||||
|
||||
typedef enum {
|
||||
RAVA_BINOP_ADD,
|
||||
RAVA_BINOP_SUB,
|
||||
RAVA_BINOP_MUL,
|
||||
RAVA_BINOP_DIV,
|
||||
RAVA_BINOP_MOD,
|
||||
RAVA_BINOP_EQ,
|
||||
RAVA_BINOP_NE,
|
||||
RAVA_BINOP_LT,
|
||||
RAVA_BINOP_LE,
|
||||
RAVA_BINOP_GT,
|
||||
RAVA_BINOP_GE,
|
||||
RAVA_BINOP_AND,
|
||||
RAVA_BINOP_OR,
|
||||
RAVA_BINOP_BITAND,
|
||||
RAVA_BINOP_BITOR,
|
||||
RAVA_BINOP_BITXOR,
|
||||
RAVA_BINOP_LSHIFT,
|
||||
RAVA_BINOP_RSHIFT,
|
||||
RAVA_BINOP_URSHIFT
|
||||
} RavaBinaryOp_e;
|
||||
|
||||
typedef enum {
|
||||
RAVA_UNOP_PLUS,
|
||||
RAVA_UNOP_MINUS,
|
||||
RAVA_UNOP_NOT,
|
||||
RAVA_UNOP_BITNOT,
|
||||
RAVA_UNOP_PREINC,
|
||||
RAVA_UNOP_PREDEC,
|
||||
RAVA_UNOP_POSTINC,
|
||||
RAVA_UNOP_POSTDEC
|
||||
} RavaUnaryOp_e;
|
||||
|
||||
typedef struct RavaASTNode_t RavaASTNode_t;
|
||||
|
||||
struct RavaASTNode_t {
|
||||
RavaASTNodeType_e type;
|
||||
int line;
|
||||
int column;
|
||||
RavaASTNode_t *parent;
|
||||
RavaASTNode_t **children;
|
||||
size_t children_count;
|
||||
size_t children_capacity;
|
||||
|
||||
union {
|
||||
struct {
|
||||
char *name;
|
||||
} identifier;
|
||||
|
||||
struct {
|
||||
RavaTokenType_e literal_type;
|
||||
RavaLiteralValue_u value;
|
||||
} literal;
|
||||
|
||||
struct {
|
||||
RavaBinaryOp_e op;
|
||||
RavaASTNode_t *left;
|
||||
RavaASTNode_t *right;
|
||||
} binary;
|
||||
|
||||
struct {
|
||||
RavaUnaryOp_e op;
|
||||
RavaASTNode_t *operand;
|
||||
} unary;
|
||||
|
||||
struct {
|
||||
RavaASTNode_t *condition;
|
||||
RavaASTNode_t *true_expr;
|
||||
RavaASTNode_t *false_expr;
|
||||
} ternary;
|
||||
|
||||
struct {
|
||||
RavaASTNode_t *target;
|
||||
RavaASTNode_t *value;
|
||||
} assign;
|
||||
|
||||
struct {
|
||||
char *name;
|
||||
char *superclass;
|
||||
RavaASTNode_t *type;
|
||||
RavaModifier_e *modifiers;
|
||||
size_t modifiers_count;
|
||||
} class_decl;
|
||||
|
||||
struct {
|
||||
char *name;
|
||||
RavaASTNode_t *return_type;
|
||||
RavaModifier_e *modifiers;
|
||||
size_t modifiers_count;
|
||||
} method_decl;
|
||||
|
||||
struct {
|
||||
char *name;
|
||||
RavaASTNode_t *type;
|
||||
RavaASTNode_t *initializer;
|
||||
} var_decl;
|
||||
|
||||
struct {
|
||||
RavaASTNode_t *condition;
|
||||
RavaASTNode_t *then_stmt;
|
||||
RavaASTNode_t *else_stmt;
|
||||
} if_stmt;
|
||||
|
||||
struct {
|
||||
RavaASTNode_t *condition;
|
||||
RavaASTNode_t *body;
|
||||
} while_stmt;
|
||||
|
||||
struct {
|
||||
RavaASTNode_t *init;
|
||||
RavaASTNode_t *condition;
|
||||
RavaASTNode_t *update;
|
||||
RavaASTNode_t *body;
|
||||
} for_stmt;
|
||||
|
||||
struct {
|
||||
RavaASTNode_t *value;
|
||||
} return_stmt;
|
||||
|
||||
struct {
|
||||
char *type_name;
|
||||
bool is_array;
|
||||
int array_dimensions;
|
||||
} type;
|
||||
|
||||
struct {
|
||||
RavaASTNode_t *callee;
|
||||
RavaASTNode_t **arguments;
|
||||
size_t arguments_count;
|
||||
} call;
|
||||
|
||||
struct {
|
||||
RavaASTNode_t *object;
|
||||
char *member;
|
||||
} member_access;
|
||||
|
||||
struct {
|
||||
RavaASTNode_t *array;
|
||||
RavaASTNode_t *index;
|
||||
} array_access;
|
||||
|
||||
struct {
|
||||
RavaASTNode_t *type;
|
||||
RavaASTNode_t **arguments;
|
||||
size_t arguments_count;
|
||||
} new_expr;
|
||||
|
||||
struct {
|
||||
RavaASTNode_t *type;
|
||||
RavaASTNode_t *expression;
|
||||
} cast;
|
||||
} data;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
RavaLexer_t *lexer;
|
||||
RavaToken_t *current_token;
|
||||
RavaToken_t *peek_token;
|
||||
char *error_message;
|
||||
bool had_error;
|
||||
} RavaParser_t;
|
||||
|
||||
RavaParser_t* rava_parser_create(RavaLexer_t *lexer);
|
||||
void rava_parser_destroy(RavaParser_t *parser);
|
||||
RavaASTNode_t* rava_parser_parse(RavaParser_t *parser);
|
||||
|
||||
RavaASTNode_t* rava_ast_node_create(RavaASTNodeType_e type, int line, int column);
|
||||
void rava_ast_node_destroy(RavaASTNode_t *node);
|
||||
void rava_ast_node_add_child(RavaASTNode_t *parent, RavaASTNode_t *child);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,196 @@
|
||||
#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;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
_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) &&
|
||||
strcmp(parser->current_token->lexeme, class_decl->data.class_decl.name) == 0) {
|
||||
|
||||
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);
|
||||
field->data.var_decl.type = member_type;
|
||||
field->data.var_decl.name = name;
|
||||
if (_rava_parser_match(parser, RAVA_TOKEN_ASSIGN)) {
|
||||
field->data.var_decl.initializer = _rava_parser_parse_expression(parser);
|
||||
} else {
|
||||
field->data.var_decl.initializer = NULL;
|
||||
}
|
||||
_rava_parser_expect(parser, RAVA_TOKEN_SEMICOLON, "Expected ';' after field declaration");
|
||||
rava_ast_node_add_child(class_decl, field);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_rava_parser_expect(parser, RAVA_TOKEN_RBRACE, "Expected '}' after class body");
|
||||
|
||||
return class_decl;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
RavaASTNode_t *decl = _rava_parser_parse_class_declaration(parser);
|
||||
if (decl) {
|
||||
rava_ast_node_add_child(root, decl);
|
||||
}
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
@@ -0,0 +1,433 @@
|
||||
#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);
|
||||
|
||||
RavaASTNode_t* _rava_parser_parse_expression(RavaParser_t *parser);
|
||||
|
||||
static RavaASTNode_t* _rava_parser_parse_primary(RavaParser_t *parser) {
|
||||
RavaASTNode_t *node = NULL;
|
||||
|
||||
if (_rava_parser_check(parser, RAVA_TOKEN_LITERAL_INTEGER) ||
|
||||
_rava_parser_check(parser, RAVA_TOKEN_LITERAL_LONG) ||
|
||||
_rava_parser_check(parser, RAVA_TOKEN_LITERAL_FLOAT) ||
|
||||
_rava_parser_check(parser, RAVA_TOKEN_LITERAL_DOUBLE) ||
|
||||
_rava_parser_check(parser, RAVA_TOKEN_LITERAL_STRING) ||
|
||||
_rava_parser_check(parser, RAVA_TOKEN_LITERAL_CHARACTER) ||
|
||||
_rava_parser_check(parser, RAVA_TOKEN_LITERAL_TRUE) ||
|
||||
_rava_parser_check(parser, RAVA_TOKEN_LITERAL_FALSE) ||
|
||||
_rava_parser_check(parser, RAVA_TOKEN_LITERAL_NULL)) {
|
||||
|
||||
node = rava_ast_node_create(RAVA_AST_LITERAL_EXPR,
|
||||
parser->current_token->line,
|
||||
parser->current_token->column);
|
||||
node->data.literal.literal_type = parser->current_token->type;
|
||||
node->data.literal.value = parser->current_token->value;
|
||||
|
||||
if (parser->current_token->type == RAVA_TOKEN_LITERAL_STRING) {
|
||||
node->data.literal.value.string_value = strdup(parser->current_token->value.string_value);
|
||||
}
|
||||
|
||||
_rava_parser_advance(parser);
|
||||
return node;
|
||||
}
|
||||
|
||||
if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) {
|
||||
node = rava_ast_node_create(RAVA_AST_IDENTIFIER_EXPR,
|
||||
parser->current_token->line,
|
||||
parser->current_token->column);
|
||||
node->data.identifier.name = strdup(parser->current_token->lexeme);
|
||||
_rava_parser_advance(parser);
|
||||
return node;
|
||||
}
|
||||
|
||||
if (_rava_parser_match(parser, RAVA_TOKEN_KEYWORD_THIS)) {
|
||||
return rava_ast_node_create(RAVA_AST_THIS_EXPR,
|
||||
parser->current_token->line,
|
||||
parser->current_token->column);
|
||||
}
|
||||
|
||||
if (_rava_parser_match(parser, RAVA_TOKEN_KEYWORD_SUPER)) {
|
||||
return rava_ast_node_create(RAVA_AST_SUPER_EXPR,
|
||||
parser->current_token->line,
|
||||
parser->current_token->column);
|
||||
}
|
||||
|
||||
if (_rava_parser_match(parser, RAVA_TOKEN_LPAREN)) {
|
||||
RavaASTNode_t *expr = _rava_parser_parse_expression(parser);
|
||||
_rava_parser_expect(parser, RAVA_TOKEN_RPAREN, "Expected ')' after expression");
|
||||
return expr;
|
||||
}
|
||||
|
||||
if (_rava_parser_match(parser, RAVA_TOKEN_KEYWORD_NEW)) {
|
||||
node = rava_ast_node_create(RAVA_AST_NEW_EXPR,
|
||||
parser->current_token->line,
|
||||
parser->current_token->column);
|
||||
node->data.new_expr.type = _rava_parser_parse_type(parser);
|
||||
|
||||
if (_rava_parser_match(parser, RAVA_TOKEN_LBRACKET)) {
|
||||
size_t args_capacity = 4;
|
||||
node->data.new_expr.arguments = malloc(sizeof(RavaASTNode_t*) * args_capacity);
|
||||
node->data.new_expr.arguments_count = 0;
|
||||
|
||||
node->data.new_expr.arguments[node->data.new_expr.arguments_count++] =
|
||||
_rava_parser_parse_expression(parser);
|
||||
|
||||
_rava_parser_expect(parser, RAVA_TOKEN_RBRACKET, "Expected ']' after array size");
|
||||
|
||||
while (_rava_parser_match(parser, RAVA_TOKEN_LBRACKET)) {
|
||||
if (node->data.new_expr.arguments_count >= args_capacity) {
|
||||
args_capacity *= 2;
|
||||
node->data.new_expr.arguments = realloc(node->data.new_expr.arguments,
|
||||
sizeof(RavaASTNode_t*) * args_capacity);
|
||||
}
|
||||
if (!_rava_parser_check(parser, RAVA_TOKEN_RBRACKET)) {
|
||||
node->data.new_expr.arguments[node->data.new_expr.arguments_count++] =
|
||||
_rava_parser_parse_expression(parser);
|
||||
}
|
||||
_rava_parser_expect(parser, RAVA_TOKEN_RBRACKET, "Expected ']'");
|
||||
}
|
||||
|
||||
if (node->data.new_expr.type) {
|
||||
node->data.new_expr.type->data.type.is_array = true;
|
||||
node->data.new_expr.type->data.type.array_dimensions = (int)node->data.new_expr.arguments_count;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
_rava_parser_expect(parser, RAVA_TOKEN_LPAREN, "Expected '(' or '[' after type in new expression");
|
||||
|
||||
size_t args_capacity = 4;
|
||||
node->data.new_expr.arguments = malloc(sizeof(RavaASTNode_t*) * args_capacity);
|
||||
node->data.new_expr.arguments_count = 0;
|
||||
|
||||
if (!_rava_parser_check(parser, RAVA_TOKEN_RPAREN)) {
|
||||
do {
|
||||
if (node->data.new_expr.arguments_count >= args_capacity) {
|
||||
args_capacity *= 2;
|
||||
node->data.new_expr.arguments = realloc(node->data.new_expr.arguments,
|
||||
sizeof(RavaASTNode_t*) * args_capacity);
|
||||
}
|
||||
node->data.new_expr.arguments[node->data.new_expr.arguments_count++] =
|
||||
_rava_parser_parse_expression(parser);
|
||||
} while (_rava_parser_match(parser, RAVA_TOKEN_COMMA));
|
||||
}
|
||||
|
||||
_rava_parser_expect(parser, RAVA_TOKEN_RPAREN, "Expected ')' after arguments");
|
||||
return node;
|
||||
}
|
||||
|
||||
parser->had_error = true;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static RavaASTNode_t* _rava_parser_parse_postfix(RavaParser_t *parser) {
|
||||
RavaASTNode_t *expr = _rava_parser_parse_primary(parser);
|
||||
|
||||
while (true) {
|
||||
if (_rava_parser_match(parser, RAVA_TOKEN_DOT)) {
|
||||
if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) {
|
||||
RavaASTNode_t *member_access = rava_ast_node_create(RAVA_AST_MEMBER_ACCESS_EXPR,
|
||||
parser->current_token->line,
|
||||
parser->current_token->column);
|
||||
member_access->data.member_access.object = expr;
|
||||
member_access->data.member_access.member = strdup(parser->current_token->lexeme);
|
||||
_rava_parser_advance(parser);
|
||||
expr = member_access;
|
||||
}
|
||||
} else if (_rava_parser_match(parser, RAVA_TOKEN_LPAREN)) {
|
||||
RavaASTNode_t *call = rava_ast_node_create(RAVA_AST_CALL_EXPR,
|
||||
parser->current_token->line,
|
||||
parser->current_token->column);
|
||||
call->data.call.callee = expr;
|
||||
|
||||
size_t args_capacity = 4;
|
||||
call->data.call.arguments = malloc(sizeof(RavaASTNode_t*) * args_capacity);
|
||||
call->data.call.arguments_count = 0;
|
||||
|
||||
if (!_rava_parser_check(parser, RAVA_TOKEN_RPAREN)) {
|
||||
do {
|
||||
if (call->data.call.arguments_count >= args_capacity) {
|
||||
args_capacity *= 2;
|
||||
call->data.call.arguments = realloc(call->data.call.arguments,
|
||||
sizeof(RavaASTNode_t*) * args_capacity);
|
||||
}
|
||||
call->data.call.arguments[call->data.call.arguments_count++] =
|
||||
_rava_parser_parse_expression(parser);
|
||||
} while (_rava_parser_match(parser, RAVA_TOKEN_COMMA));
|
||||
}
|
||||
|
||||
_rava_parser_expect(parser, RAVA_TOKEN_RPAREN, "Expected ')' after arguments");
|
||||
expr = call;
|
||||
} else if (_rava_parser_match(parser, RAVA_TOKEN_LBRACKET)) {
|
||||
RavaASTNode_t *array_access = rava_ast_node_create(RAVA_AST_ARRAY_ACCESS_EXPR,
|
||||
parser->current_token->line,
|
||||
parser->current_token->column);
|
||||
array_access->data.array_access.array = expr;
|
||||
array_access->data.array_access.index = _rava_parser_parse_expression(parser);
|
||||
_rava_parser_expect(parser, RAVA_TOKEN_RBRACKET, "Expected ']' after array index");
|
||||
expr = array_access;
|
||||
} else if (_rava_parser_match(parser, RAVA_TOKEN_INC)) {
|
||||
RavaASTNode_t *unary = rava_ast_node_create(RAVA_AST_UNARY_EXPR,
|
||||
parser->current_token->line,
|
||||
parser->current_token->column);
|
||||
unary->data.unary.op = RAVA_UNOP_POSTINC;
|
||||
unary->data.unary.operand = expr;
|
||||
expr = unary;
|
||||
} else if (_rava_parser_match(parser, RAVA_TOKEN_DEC)) {
|
||||
RavaASTNode_t *unary = rava_ast_node_create(RAVA_AST_UNARY_EXPR,
|
||||
parser->current_token->line,
|
||||
parser->current_token->column);
|
||||
unary->data.unary.op = RAVA_UNOP_POSTDEC;
|
||||
unary->data.unary.operand = expr;
|
||||
expr = unary;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
static RavaASTNode_t* _rava_parser_parse_unary(RavaParser_t *parser) {
|
||||
if (_rava_parser_match(parser, RAVA_TOKEN_PLUS)) {
|
||||
RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_UNARY_EXPR,
|
||||
parser->current_token->line,
|
||||
parser->current_token->column);
|
||||
node->data.unary.op = RAVA_UNOP_PLUS;
|
||||
node->data.unary.operand = _rava_parser_parse_unary(parser);
|
||||
return node;
|
||||
}
|
||||
|
||||
if (_rava_parser_match(parser, RAVA_TOKEN_MINUS)) {
|
||||
RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_UNARY_EXPR,
|
||||
parser->current_token->line,
|
||||
parser->current_token->column);
|
||||
node->data.unary.op = RAVA_UNOP_MINUS;
|
||||
node->data.unary.operand = _rava_parser_parse_unary(parser);
|
||||
return node;
|
||||
}
|
||||
|
||||
if (_rava_parser_match(parser, RAVA_TOKEN_BANG)) {
|
||||
RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_UNARY_EXPR,
|
||||
parser->current_token->line,
|
||||
parser->current_token->column);
|
||||
node->data.unary.op = RAVA_UNOP_NOT;
|
||||
node->data.unary.operand = _rava_parser_parse_unary(parser);
|
||||
return node;
|
||||
}
|
||||
|
||||
if (_rava_parser_match(parser, RAVA_TOKEN_TILDE)) {
|
||||
RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_UNARY_EXPR,
|
||||
parser->current_token->line,
|
||||
parser->current_token->column);
|
||||
node->data.unary.op = RAVA_UNOP_BITNOT;
|
||||
node->data.unary.operand = _rava_parser_parse_unary(parser);
|
||||
return node;
|
||||
}
|
||||
|
||||
if (_rava_parser_match(parser, RAVA_TOKEN_INC)) {
|
||||
RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_UNARY_EXPR,
|
||||
parser->current_token->line,
|
||||
parser->current_token->column);
|
||||
node->data.unary.op = RAVA_UNOP_PREINC;
|
||||
node->data.unary.operand = _rava_parser_parse_unary(parser);
|
||||
return node;
|
||||
}
|
||||
|
||||
if (_rava_parser_match(parser, RAVA_TOKEN_DEC)) {
|
||||
RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_UNARY_EXPR,
|
||||
parser->current_token->line,
|
||||
parser->current_token->column);
|
||||
node->data.unary.op = RAVA_UNOP_PREDEC;
|
||||
node->data.unary.operand = _rava_parser_parse_unary(parser);
|
||||
return node;
|
||||
}
|
||||
|
||||
return _rava_parser_parse_postfix(parser);
|
||||
}
|
||||
|
||||
static RavaASTNode_t* _rava_parser_parse_multiplicative(RavaParser_t *parser) {
|
||||
RavaASTNode_t *left = _rava_parser_parse_unary(parser);
|
||||
|
||||
while (_rava_parser_check(parser, RAVA_TOKEN_STAR) ||
|
||||
_rava_parser_check(parser, RAVA_TOKEN_SLASH) ||
|
||||
_rava_parser_check(parser, RAVA_TOKEN_PERCENT)) {
|
||||
|
||||
RavaBinaryOp_e op;
|
||||
if (_rava_parser_match(parser, RAVA_TOKEN_STAR)) {
|
||||
op = RAVA_BINOP_MUL;
|
||||
} else if (_rava_parser_match(parser, RAVA_TOKEN_SLASH)) {
|
||||
op = RAVA_BINOP_DIV;
|
||||
} else {
|
||||
_rava_parser_advance(parser);
|
||||
op = RAVA_BINOP_MOD;
|
||||
}
|
||||
|
||||
RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_BINARY_EXPR,
|
||||
parser->current_token->line,
|
||||
parser->current_token->column);
|
||||
node->data.binary.op = op;
|
||||
node->data.binary.left = left;
|
||||
node->data.binary.right = _rava_parser_parse_unary(parser);
|
||||
left = node;
|
||||
}
|
||||
|
||||
return left;
|
||||
}
|
||||
|
||||
static RavaASTNode_t* _rava_parser_parse_additive(RavaParser_t *parser) {
|
||||
RavaASTNode_t *left = _rava_parser_parse_multiplicative(parser);
|
||||
|
||||
while (_rava_parser_check(parser, RAVA_TOKEN_PLUS) ||
|
||||
_rava_parser_check(parser, RAVA_TOKEN_MINUS)) {
|
||||
|
||||
RavaBinaryOp_e op = _rava_parser_match(parser, RAVA_TOKEN_PLUS) ?
|
||||
RAVA_BINOP_ADD : RAVA_BINOP_SUB;
|
||||
if (op == RAVA_BINOP_SUB) _rava_parser_advance(parser);
|
||||
|
||||
RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_BINARY_EXPR,
|
||||
parser->current_token->line,
|
||||
parser->current_token->column);
|
||||
node->data.binary.op = op;
|
||||
node->data.binary.left = left;
|
||||
node->data.binary.right = _rava_parser_parse_multiplicative(parser);
|
||||
left = node;
|
||||
}
|
||||
|
||||
return left;
|
||||
}
|
||||
|
||||
static RavaASTNode_t* _rava_parser_parse_relational(RavaParser_t *parser) {
|
||||
RavaASTNode_t *left = _rava_parser_parse_additive(parser);
|
||||
|
||||
while (_rava_parser_check(parser, RAVA_TOKEN_LT) ||
|
||||
_rava_parser_check(parser, RAVA_TOKEN_GT) ||
|
||||
_rava_parser_check(parser, RAVA_TOKEN_LE) ||
|
||||
_rava_parser_check(parser, RAVA_TOKEN_GE)) {
|
||||
|
||||
RavaBinaryOp_e op;
|
||||
if (_rava_parser_match(parser, RAVA_TOKEN_LT)) op = RAVA_BINOP_LT;
|
||||
else if (_rava_parser_match(parser, RAVA_TOKEN_GT)) op = RAVA_BINOP_GT;
|
||||
else if (_rava_parser_match(parser, RAVA_TOKEN_LE)) op = RAVA_BINOP_LE;
|
||||
else { _rava_parser_advance(parser); op = RAVA_BINOP_GE; }
|
||||
|
||||
RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_BINARY_EXPR,
|
||||
parser->current_token->line,
|
||||
parser->current_token->column);
|
||||
node->data.binary.op = op;
|
||||
node->data.binary.left = left;
|
||||
node->data.binary.right = _rava_parser_parse_additive(parser);
|
||||
left = node;
|
||||
}
|
||||
|
||||
return left;
|
||||
}
|
||||
|
||||
static RavaASTNode_t* _rava_parser_parse_equality(RavaParser_t *parser) {
|
||||
RavaASTNode_t *left = _rava_parser_parse_relational(parser);
|
||||
|
||||
while (_rava_parser_check(parser, RAVA_TOKEN_EQUAL) ||
|
||||
_rava_parser_check(parser, RAVA_TOKEN_NE)) {
|
||||
|
||||
RavaBinaryOp_e op = _rava_parser_match(parser, RAVA_TOKEN_EQUAL) ?
|
||||
RAVA_BINOP_EQ : RAVA_BINOP_NE;
|
||||
if (op == RAVA_BINOP_NE) _rava_parser_advance(parser);
|
||||
|
||||
RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_BINARY_EXPR,
|
||||
parser->current_token->line,
|
||||
parser->current_token->column);
|
||||
node->data.binary.op = op;
|
||||
node->data.binary.left = left;
|
||||
node->data.binary.right = _rava_parser_parse_relational(parser);
|
||||
left = node;
|
||||
}
|
||||
|
||||
return left;
|
||||
}
|
||||
|
||||
static RavaASTNode_t* _rava_parser_parse_logical_and(RavaParser_t *parser) {
|
||||
RavaASTNode_t *left = _rava_parser_parse_equality(parser);
|
||||
|
||||
while (_rava_parser_match(parser, RAVA_TOKEN_AND)) {
|
||||
RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_BINARY_EXPR,
|
||||
parser->current_token->line,
|
||||
parser->current_token->column);
|
||||
node->data.binary.op = RAVA_BINOP_AND;
|
||||
node->data.binary.left = left;
|
||||
node->data.binary.right = _rava_parser_parse_equality(parser);
|
||||
left = node;
|
||||
}
|
||||
|
||||
return left;
|
||||
}
|
||||
|
||||
static RavaASTNode_t* _rava_parser_parse_logical_or(RavaParser_t *parser) {
|
||||
RavaASTNode_t *left = _rava_parser_parse_logical_and(parser);
|
||||
|
||||
while (_rava_parser_match(parser, RAVA_TOKEN_OR)) {
|
||||
RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_BINARY_EXPR,
|
||||
parser->current_token->line,
|
||||
parser->current_token->column);
|
||||
node->data.binary.op = RAVA_BINOP_OR;
|
||||
node->data.binary.left = left;
|
||||
node->data.binary.right = _rava_parser_parse_logical_and(parser);
|
||||
left = node;
|
||||
}
|
||||
|
||||
return left;
|
||||
}
|
||||
|
||||
static RavaASTNode_t* _rava_parser_parse_assignment(RavaParser_t *parser) {
|
||||
RavaASTNode_t *left = _rava_parser_parse_logical_or(parser);
|
||||
|
||||
if (_rava_parser_match(parser, RAVA_TOKEN_ASSIGN)) {
|
||||
RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_ASSIGN_EXPR,
|
||||
parser->current_token->line,
|
||||
parser->current_token->column);
|
||||
node->data.assign.target = left;
|
||||
node->data.assign.value = _rava_parser_parse_assignment(parser);
|
||||
return node;
|
||||
}
|
||||
|
||||
RavaBinaryOp_e compound_op = -1;
|
||||
if (_rava_parser_match(parser, RAVA_TOKEN_PLUSASSIGN)) {
|
||||
compound_op = RAVA_BINOP_ADD;
|
||||
} else if (_rava_parser_match(parser, RAVA_TOKEN_MINUSASSIGN)) {
|
||||
compound_op = RAVA_BINOP_SUB;
|
||||
} else if (_rava_parser_match(parser, RAVA_TOKEN_STARASSIGN)) {
|
||||
compound_op = RAVA_BINOP_MUL;
|
||||
} else if (_rava_parser_match(parser, RAVA_TOKEN_SLASHASSIGN)) {
|
||||
compound_op = RAVA_BINOP_DIV;
|
||||
} else if (_rava_parser_match(parser, RAVA_TOKEN_PERCENTASSIGN)) {
|
||||
compound_op = RAVA_BINOP_MOD;
|
||||
}
|
||||
|
||||
if (compound_op != (RavaBinaryOp_e)-1) {
|
||||
RavaASTNode_t *binary = rava_ast_node_create(RAVA_AST_BINARY_EXPR,
|
||||
parser->current_token->line,
|
||||
parser->current_token->column);
|
||||
binary->data.binary.op = compound_op;
|
||||
binary->data.binary.left = left;
|
||||
binary->data.binary.right = _rava_parser_parse_assignment(parser);
|
||||
|
||||
RavaASTNode_t *assign = rava_ast_node_create(RAVA_AST_ASSIGN_EXPR,
|
||||
parser->current_token->line,
|
||||
parser->current_token->column);
|
||||
assign->data.assign.target = left;
|
||||
assign->data.assign.value = binary;
|
||||
return assign;
|
||||
}
|
||||
|
||||
return left;
|
||||
}
|
||||
|
||||
RavaASTNode_t* _rava_parser_parse_expression(RavaParser_t *parser) {
|
||||
return _rava_parser_parse_assignment(parser);
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
#include "parser.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static void _rava_print_indent(int depth) {
|
||||
for (int i = 0; i < depth; i++) {
|
||||
printf(" ");
|
||||
}
|
||||
}
|
||||
|
||||
static const char* _rava_ast_node_type_name(RavaASTNodeType_e type) {
|
||||
switch (type) {
|
||||
case RAVA_AST_COMPILATION_UNIT: return "CompilationUnit";
|
||||
case RAVA_AST_CLASS_DECL: return "ClassDecl";
|
||||
case RAVA_AST_METHOD_DECL: return "MethodDecl";
|
||||
case RAVA_AST_FIELD_DECL: return "FieldDecl";
|
||||
case RAVA_AST_CONSTRUCTOR_DECL: return "ConstructorDecl";
|
||||
case RAVA_AST_VAR_DECL: return "VarDecl";
|
||||
case RAVA_AST_PARAM_DECL: return "ParamDecl";
|
||||
case RAVA_AST_BLOCK_STMT: return "BlockStmt";
|
||||
case RAVA_AST_IF_STMT: return "IfStmt";
|
||||
case RAVA_AST_WHILE_STMT: return "WhileStmt";
|
||||
case RAVA_AST_FOR_STMT: return "ForStmt";
|
||||
case RAVA_AST_RETURN_STMT: return "ReturnStmt";
|
||||
case RAVA_AST_BREAK_STMT: return "BreakStmt";
|
||||
case RAVA_AST_CONTINUE_STMT: return "ContinueStmt";
|
||||
case RAVA_AST_EXPR_STMT: return "ExprStmt";
|
||||
case RAVA_AST_LITERAL_EXPR: return "LiteralExpr";
|
||||
case RAVA_AST_IDENTIFIER_EXPR: return "IdentifierExpr";
|
||||
case RAVA_AST_BINARY_EXPR: return "BinaryExpr";
|
||||
case RAVA_AST_UNARY_EXPR: return "UnaryExpr";
|
||||
case RAVA_AST_ASSIGN_EXPR: return "AssignExpr";
|
||||
case RAVA_AST_CALL_EXPR: return "CallExpr";
|
||||
case RAVA_AST_MEMBER_ACCESS_EXPR: return "MemberAccessExpr";
|
||||
case RAVA_AST_ARRAY_ACCESS_EXPR: return "ArrayAccessExpr";
|
||||
case RAVA_AST_NEW_EXPR: return "NewExpr";
|
||||
case RAVA_AST_TYPE: return "Type";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
void rava_ast_print(RavaASTNode_t *node, int depth) {
|
||||
if (!node) {
|
||||
_rava_print_indent(depth);
|
||||
printf("<null>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
_rava_print_indent(depth);
|
||||
printf("%s", _rava_ast_node_type_name(node->type));
|
||||
|
||||
switch (node->type) {
|
||||
case RAVA_AST_CLASS_DECL:
|
||||
printf(": %s\n", node->data.class_decl.name);
|
||||
break;
|
||||
case RAVA_AST_METHOD_DECL:
|
||||
printf(": %s\n", node->data.method_decl.name);
|
||||
break;
|
||||
case RAVA_AST_FIELD_DECL:
|
||||
case RAVA_AST_VAR_DECL:
|
||||
case RAVA_AST_PARAM_DECL:
|
||||
printf(": %s\n", node->data.var_decl.name ? node->data.var_decl.name : "<unnamed>");
|
||||
break;
|
||||
case RAVA_AST_IDENTIFIER_EXPR:
|
||||
printf(": %s\n", node->data.identifier.name);
|
||||
break;
|
||||
case RAVA_AST_LITERAL_EXPR:
|
||||
printf(": ");
|
||||
if (node->data.literal.literal_type == RAVA_TOKEN_LITERAL_INTEGER ||
|
||||
node->data.literal.literal_type == RAVA_TOKEN_LITERAL_LONG) {
|
||||
printf("%lld\n", (long long)node->data.literal.value.int_value);
|
||||
} else if (node->data.literal.literal_type == RAVA_TOKEN_LITERAL_FLOAT ||
|
||||
node->data.literal.literal_type == RAVA_TOKEN_LITERAL_DOUBLE) {
|
||||
printf("%f\n", node->data.literal.value.float_value);
|
||||
} else if (node->data.literal.literal_type == RAVA_TOKEN_LITERAL_STRING) {
|
||||
printf("\"%s\"\n", node->data.literal.value.string_value);
|
||||
} else if (node->data.literal.literal_type == RAVA_TOKEN_LITERAL_TRUE) {
|
||||
printf("true\n");
|
||||
} else if (node->data.literal.literal_type == RAVA_TOKEN_LITERAL_FALSE) {
|
||||
printf("false\n");
|
||||
} else if (node->data.literal.literal_type == RAVA_TOKEN_LITERAL_NULL) {
|
||||
printf("null\n");
|
||||
} else {
|
||||
printf("?\n");
|
||||
}
|
||||
break;
|
||||
case RAVA_AST_TYPE:
|
||||
printf(": %s%s\n", node->data.type.type_name,
|
||||
node->data.type.is_array ? "[]" : "");
|
||||
break;
|
||||
case RAVA_AST_MEMBER_ACCESS_EXPR:
|
||||
printf(": .%s\n", node->data.member_access.member);
|
||||
break;
|
||||
default:
|
||||
printf("\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (node->type == RAVA_AST_BINARY_EXPR) {
|
||||
_rava_print_indent(depth + 1);
|
||||
printf("Left:\n");
|
||||
rava_ast_print(node->data.binary.left, depth + 2);
|
||||
_rava_print_indent(depth + 1);
|
||||
printf("Right:\n");
|
||||
rava_ast_print(node->data.binary.right, depth + 2);
|
||||
} else if (node->type == RAVA_AST_UNARY_EXPR) {
|
||||
_rava_print_indent(depth + 1);
|
||||
printf("Operand:\n");
|
||||
rava_ast_print(node->data.unary.operand, depth + 2);
|
||||
} else if (node->type == RAVA_AST_ASSIGN_EXPR) {
|
||||
_rava_print_indent(depth + 1);
|
||||
printf("Target:\n");
|
||||
rava_ast_print(node->data.assign.target, depth + 2);
|
||||
_rava_print_indent(depth + 1);
|
||||
printf("Value:\n");
|
||||
rava_ast_print(node->data.assign.value, depth + 2);
|
||||
} else if (node->type == RAVA_AST_IF_STMT) {
|
||||
_rava_print_indent(depth + 1);
|
||||
printf("Condition:\n");
|
||||
rava_ast_print(node->data.if_stmt.condition, depth + 2);
|
||||
_rava_print_indent(depth + 1);
|
||||
printf("Then:\n");
|
||||
rava_ast_print(node->data.if_stmt.then_stmt, depth + 2);
|
||||
if (node->data.if_stmt.else_stmt) {
|
||||
_rava_print_indent(depth + 1);
|
||||
printf("Else:\n");
|
||||
rava_ast_print(node->data.if_stmt.else_stmt, depth + 2);
|
||||
}
|
||||
} else if (node->type == RAVA_AST_WHILE_STMT) {
|
||||
_rava_print_indent(depth + 1);
|
||||
printf("Condition:\n");
|
||||
rava_ast_print(node->data.while_stmt.condition, depth + 2);
|
||||
_rava_print_indent(depth + 1);
|
||||
printf("Body:\n");
|
||||
rava_ast_print(node->data.while_stmt.body, depth + 2);
|
||||
} else if (node->type == RAVA_AST_FOR_STMT) {
|
||||
if (node->data.for_stmt.init) {
|
||||
_rava_print_indent(depth + 1);
|
||||
printf("Init:\n");
|
||||
rava_ast_print(node->data.for_stmt.init, depth + 2);
|
||||
}
|
||||
if (node->data.for_stmt.condition) {
|
||||
_rava_print_indent(depth + 1);
|
||||
printf("Condition:\n");
|
||||
rava_ast_print(node->data.for_stmt.condition, depth + 2);
|
||||
}
|
||||
if (node->data.for_stmt.update) {
|
||||
_rava_print_indent(depth + 1);
|
||||
printf("Update:\n");
|
||||
rava_ast_print(node->data.for_stmt.update, depth + 2);
|
||||
}
|
||||
_rava_print_indent(depth + 1);
|
||||
printf("Body:\n");
|
||||
rava_ast_print(node->data.for_stmt.body, depth + 2);
|
||||
} else if (node->type == RAVA_AST_RETURN_STMT) {
|
||||
if (node->data.return_stmt.value) {
|
||||
_rava_print_indent(depth + 1);
|
||||
printf("Value:\n");
|
||||
rava_ast_print(node->data.return_stmt.value, depth + 2);
|
||||
}
|
||||
} else if (node->type == RAVA_AST_VAR_DECL || node->type == RAVA_AST_FIELD_DECL || node->type == RAVA_AST_PARAM_DECL) {
|
||||
if (node->data.var_decl.type) {
|
||||
_rava_print_indent(depth + 1);
|
||||
printf("Type:\n");
|
||||
rava_ast_print(node->data.var_decl.type, depth + 2);
|
||||
}
|
||||
if (node->data.var_decl.initializer) {
|
||||
_rava_print_indent(depth + 1);
|
||||
printf("Initializer:\n");
|
||||
rava_ast_print(node->data.var_decl.initializer, depth + 2);
|
||||
}
|
||||
} else if (node->type == RAVA_AST_METHOD_DECL) {
|
||||
if (node->data.method_decl.return_type) {
|
||||
_rava_print_indent(depth + 1);
|
||||
printf("Return Type:\n");
|
||||
rava_ast_print(node->data.method_decl.return_type, depth + 2);
|
||||
}
|
||||
} else if (node->type == RAVA_AST_CALL_EXPR) {
|
||||
_rava_print_indent(depth + 1);
|
||||
printf("Callee:\n");
|
||||
rava_ast_print(node->data.call.callee, depth + 2);
|
||||
if (node->data.call.arguments_count > 0) {
|
||||
_rava_print_indent(depth + 1);
|
||||
printf("Arguments:\n");
|
||||
for (size_t i = 0; i < node->data.call.arguments_count; i++) {
|
||||
rava_ast_print(node->data.call.arguments[i], depth + 2);
|
||||
}
|
||||
}
|
||||
} else if (node->type == RAVA_AST_MEMBER_ACCESS_EXPR) {
|
||||
_rava_print_indent(depth + 1);
|
||||
printf("Object:\n");
|
||||
rava_ast_print(node->data.member_access.object, depth + 2);
|
||||
} else if (node->type == RAVA_AST_ARRAY_ACCESS_EXPR) {
|
||||
_rava_print_indent(depth + 1);
|
||||
printf("Array:\n");
|
||||
rava_ast_print(node->data.array_access.array, depth + 2);
|
||||
_rava_print_indent(depth + 1);
|
||||
printf("Index:\n");
|
||||
rava_ast_print(node->data.array_access.index, depth + 2);
|
||||
} else if (node->type == RAVA_AST_NEW_EXPR) {
|
||||
_rava_print_indent(depth + 1);
|
||||
printf("Type:\n");
|
||||
rava_ast_print(node->data.new_expr.type, depth + 2);
|
||||
if (node->data.new_expr.arguments_count > 0) {
|
||||
_rava_print_indent(depth + 1);
|
||||
printf("Arguments:\n");
|
||||
for (size_t i = 0; i < node->data.new_expr.arguments_count; i++) {
|
||||
rava_ast_print(node->data.new_expr.arguments[i], depth + 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < node->children_count; i++) {
|
||||
rava_ast_print(node->children[i], depth + 1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
#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_expression(RavaParser_t *parser);
|
||||
extern RavaASTNode_t* _rava_parser_parse_type(RavaParser_t *parser);
|
||||
|
||||
RavaASTNode_t* _rava_parser_parse_statement(RavaParser_t *parser);
|
||||
RavaASTNode_t* _rava_parser_parse_block(RavaParser_t *parser);
|
||||
|
||||
RavaASTNode_t* _rava_parser_parse_block(RavaParser_t *parser) {
|
||||
RavaASTNode_t *block = rava_ast_node_create(RAVA_AST_BLOCK_STMT,
|
||||
parser->current_token->line,
|
||||
parser->current_token->column);
|
||||
|
||||
_rava_parser_expect(parser, RAVA_TOKEN_LBRACE, "Expected '{' at start of block");
|
||||
|
||||
while (!_rava_parser_check(parser, RAVA_TOKEN_RBRACE) &&
|
||||
!_rava_parser_check(parser, RAVA_TOKEN_EOF)) {
|
||||
RavaASTNode_t *stmt = _rava_parser_parse_statement(parser);
|
||||
if (stmt) {
|
||||
rava_ast_node_add_child(block, stmt);
|
||||
}
|
||||
}
|
||||
|
||||
_rava_parser_expect(parser, RAVA_TOKEN_RBRACE, "Expected '}' at end of block");
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
RavaASTNode_t* _rava_parser_parse_statement(RavaParser_t *parser) {
|
||||
if (_rava_parser_check(parser, RAVA_TOKEN_LBRACE)) {
|
||||
return _rava_parser_parse_block(parser);
|
||||
}
|
||||
|
||||
if (_rava_parser_match(parser, RAVA_TOKEN_KEYWORD_IF)) {
|
||||
RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_IF_STMT,
|
||||
parser->current_token->line,
|
||||
parser->current_token->column);
|
||||
|
||||
_rava_parser_expect(parser, RAVA_TOKEN_LPAREN, "Expected '(' after 'if'");
|
||||
node->data.if_stmt.condition = _rava_parser_parse_expression(parser);
|
||||
_rava_parser_expect(parser, RAVA_TOKEN_RPAREN, "Expected ')' after if condition");
|
||||
|
||||
node->data.if_stmt.then_stmt = _rava_parser_parse_statement(parser);
|
||||
|
||||
if (_rava_parser_match(parser, RAVA_TOKEN_KEYWORD_ELSE)) {
|
||||
node->data.if_stmt.else_stmt = _rava_parser_parse_statement(parser);
|
||||
} else {
|
||||
node->data.if_stmt.else_stmt = NULL;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
if (_rava_parser_match(parser, RAVA_TOKEN_KEYWORD_WHILE)) {
|
||||
RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_WHILE_STMT,
|
||||
parser->current_token->line,
|
||||
parser->current_token->column);
|
||||
|
||||
_rava_parser_expect(parser, RAVA_TOKEN_LPAREN, "Expected '(' after 'while'");
|
||||
node->data.while_stmt.condition = _rava_parser_parse_expression(parser);
|
||||
_rava_parser_expect(parser, RAVA_TOKEN_RPAREN, "Expected ')' after while condition");
|
||||
|
||||
node->data.while_stmt.body = _rava_parser_parse_statement(parser);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
if (_rava_parser_match(parser, RAVA_TOKEN_KEYWORD_FOR)) {
|
||||
RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_FOR_STMT,
|
||||
parser->current_token->line,
|
||||
parser->current_token->column);
|
||||
|
||||
_rava_parser_expect(parser, RAVA_TOKEN_LPAREN, "Expected '(' after 'for'");
|
||||
|
||||
if (!_rava_parser_check(parser, RAVA_TOKEN_SEMICOLON)) {
|
||||
bool is_type_decl = false;
|
||||
if (_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_INT) ||
|
||||
_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_LONG) ||
|
||||
_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_DOUBLE) ||
|
||||
_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_BOOLEAN) ||
|
||||
_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_CHAR)) {
|
||||
is_type_decl = true;
|
||||
} else if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) {
|
||||
if (parser->peek_token && parser->peek_token->type == RAVA_TOKEN_IDENTIFIER) {
|
||||
is_type_decl = true;
|
||||
}
|
||||
}
|
||||
if (is_type_decl) {
|
||||
RavaASTNode_t *type = _rava_parser_parse_type(parser);
|
||||
RavaASTNode_t *var_decl = rava_ast_node_create(RAVA_AST_VAR_DECL,
|
||||
parser->current_token->line,
|
||||
parser->current_token->column);
|
||||
var_decl->data.var_decl.type = type;
|
||||
if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) {
|
||||
var_decl->data.var_decl.name = strdup(parser->current_token->lexeme);
|
||||
_rava_parser_advance(parser);
|
||||
}
|
||||
if (_rava_parser_match(parser, RAVA_TOKEN_ASSIGN)) {
|
||||
var_decl->data.var_decl.initializer = _rava_parser_parse_expression(parser);
|
||||
}
|
||||
node->data.for_stmt.init = var_decl;
|
||||
} else {
|
||||
node->data.for_stmt.init = _rava_parser_parse_expression(parser);
|
||||
}
|
||||
} else {
|
||||
node->data.for_stmt.init = NULL;
|
||||
}
|
||||
_rava_parser_expect(parser, RAVA_TOKEN_SEMICOLON, "Expected ';' after for init");
|
||||
|
||||
if (!_rava_parser_check(parser, RAVA_TOKEN_SEMICOLON)) {
|
||||
node->data.for_stmt.condition = _rava_parser_parse_expression(parser);
|
||||
} else {
|
||||
node->data.for_stmt.condition = NULL;
|
||||
}
|
||||
_rava_parser_expect(parser, RAVA_TOKEN_SEMICOLON, "Expected ';' after for condition");
|
||||
|
||||
if (!_rava_parser_check(parser, RAVA_TOKEN_RPAREN)) {
|
||||
node->data.for_stmt.update = _rava_parser_parse_expression(parser);
|
||||
} else {
|
||||
node->data.for_stmt.update = NULL;
|
||||
}
|
||||
_rava_parser_expect(parser, RAVA_TOKEN_RPAREN, "Expected ')' after for update");
|
||||
|
||||
node->data.for_stmt.body = _rava_parser_parse_statement(parser);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
if (_rava_parser_match(parser, RAVA_TOKEN_KEYWORD_RETURN)) {
|
||||
RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_RETURN_STMT,
|
||||
parser->current_token->line,
|
||||
parser->current_token->column);
|
||||
|
||||
if (!_rava_parser_check(parser, RAVA_TOKEN_SEMICOLON)) {
|
||||
node->data.return_stmt.value = _rava_parser_parse_expression(parser);
|
||||
} else {
|
||||
node->data.return_stmt.value = NULL;
|
||||
}
|
||||
|
||||
_rava_parser_expect(parser, RAVA_TOKEN_SEMICOLON, "Expected ';' after return statement");
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
if (_rava_parser_match(parser, RAVA_TOKEN_KEYWORD_BREAK)) {
|
||||
RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_BREAK_STMT,
|
||||
parser->current_token->line,
|
||||
parser->current_token->column);
|
||||
_rava_parser_expect(parser, RAVA_TOKEN_SEMICOLON, "Expected ';' after break");
|
||||
return node;
|
||||
}
|
||||
|
||||
if (_rava_parser_match(parser, RAVA_TOKEN_KEYWORD_CONTINUE)) {
|
||||
RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_CONTINUE_STMT,
|
||||
parser->current_token->line,
|
||||
parser->current_token->column);
|
||||
_rava_parser_expect(parser, RAVA_TOKEN_SEMICOLON, "Expected ';' after continue");
|
||||
return node;
|
||||
}
|
||||
|
||||
bool is_type_decl = false;
|
||||
if (_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_INT) ||
|
||||
_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_BOOLEAN) ||
|
||||
_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_CHAR) ||
|
||||
_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_BYTE) ||
|
||||
_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_SHORT) ||
|
||||
_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_LONG) ||
|
||||
_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_FLOAT) ||
|
||||
_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_DOUBLE)) {
|
||||
is_type_decl = true;
|
||||
} else if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) {
|
||||
if (parser->peek_token && parser->peek_token->type == RAVA_TOKEN_IDENTIFIER) {
|
||||
is_type_decl = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_type_decl) {
|
||||
RavaASTNode_t *type = _rava_parser_parse_type(parser);
|
||||
RavaASTNode_t *var_decl = rava_ast_node_create(RAVA_AST_VAR_DECL,
|
||||
parser->current_token->line,
|
||||
parser->current_token->column);
|
||||
var_decl->data.var_decl.type = type;
|
||||
|
||||
if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) {
|
||||
var_decl->data.var_decl.name = strdup(parser->current_token->lexeme);
|
||||
_rava_parser_advance(parser);
|
||||
}
|
||||
|
||||
if (_rava_parser_match(parser, RAVA_TOKEN_ASSIGN)) {
|
||||
var_decl->data.var_decl.initializer = _rava_parser_parse_expression(parser);
|
||||
} else {
|
||||
var_decl->data.var_decl.initializer = NULL;
|
||||
}
|
||||
|
||||
_rava_parser_expect(parser, RAVA_TOKEN_SEMICOLON, "Expected ';' after variable declaration");
|
||||
|
||||
return var_decl;
|
||||
}
|
||||
|
||||
RavaASTNode_t *expr = _rava_parser_parse_expression(parser);
|
||||
_rava_parser_expect(parser, RAVA_TOKEN_SEMICOLON, "Expected ';' after expression");
|
||||
|
||||
RavaASTNode_t *stmt = rava_ast_node_create(RAVA_AST_EXPR_STMT,
|
||||
parser->current_token->line,
|
||||
parser->current_token->column);
|
||||
rava_ast_node_add_child(stmt, expr);
|
||||
|
||||
return stmt;
|
||||
}
|
||||
Reference in New Issue
Block a user