codebased/scirpt/parser.c
2023-04-14 02:17:45 +02:00

275 lines
6.3 KiB
C

#include "scirpt/parser.h"
#include "common/string.h"
#include "parser.h"
#include "scirpt/ast.h"
#include "scirpt/lexer.h"
#include "scirpt/position.h"
#include "scirpt/token.h"
#include <stdint.h>
#include <stdlib.h>
#define TT(type) ScirptTokenType##type
static inline ScirptAstExpr* alloc_expr(ScirptAstExpr data)
{
ScirptAstExpr* expr = malloc(sizeof(ScirptAstExpr));
*expr = data;
return expr;
}
static inline void
error(ScirptParser* parser, HeapString message, ScirptPosition pos)
{
scirpt_parser_error(parser, message, pos);
}
static inline ScirptPosition position(ScirptParser* parser)
{
return parser->current.pos;
}
static inline void step(ScirptParser* parser) { scirpt_parser_step(parser); }
static inline ScirptAstExpr*
step_alloc_expr(ScirptParser* parser, ScirptAstExpr data)
{
step(parser);
return alloc_expr(data);
}
static inline bool current_is(const ScirptParser* parser, ScirptTokenType type)
{
return scirpt_parser_current_is(parser, type);
}
static inline bool done(const ScirptParser* parser)
{
return scirpt_parser_done(parser);
}
ScirptParser*
scirpt_parser_new(const char* text, size_t text_length, ScirptLexer* lexer)
{
ScirptParser* parser = malloc(sizeof(ScirptParser));
scirpt_parser_construct(parser, text, text_length, lexer);
return parser;
}
void scirpt_parser_delete(ScirptParser* parser) { free(parser); }
ScirptAstExpr* scirpt_parser_next(ScirptParser* parser)
{
if (done(parser)) {
return alloc_expr((ScirptAstExpr) {
.type = ScirptAstExprTypeEof,
});
} else {
return scirpt_parser_parse_statement(parser);
}
}
bool scirpt_parser_ok(const ScirptParser* parser) { return parser->ok; }
const ScirptParserErrorArray* scirpt_parser_errors(const ScirptParser* parser)
{
return &parser->errors;
}
void scirpt_parser_construct(
ScirptParser* parser,
const char* text,
size_t text_length,
ScirptLexer* lexer
)
{
ScirptParserErrorArray errors;
scirpt_parser_error_array_construct(&errors);
*parser = (ScirptParser) {
.text = text,
.text_length = text_length,
.lexer = lexer,
.current = scirpt_lexer_next(lexer),
.errors = errors,
.ok = true,
};
}
void scirpt_parser_destroy(ScirptParser* parser)
{
scirpt_parser_error_array_construct(&parser->errors);
}
ScirptAstExpr* scirpt_parser_parse_statement(ScirptParser* parser)
{
return scirpt_parser_parse_expr(parser);
}
ScirptAstExpr* scirpt_parser_parse_expr(ScirptParser* parser)
{
return scirpt_parser_parse_operand(parser);
}
ScirptAstExpr* scirpt_parser_parse_operand(ScirptParser* parser)
{
ScirptPosition pos = position(parser);
switch (parser->current.type) {
case ScirptTokenTypeInt:
return scirpt_parser_parse_int(parser);
case ScirptTokenTypeString:
return scirpt_parser_parse_string(parser);
case ScirptTokenTypeNull:
return step_alloc_expr(
parser,
(ScirptAstExpr) {
.type = ScirptAstExprTypeNull,
.pos = pos,
}
);
case ScirptTokenTypeFalse:
return step_alloc_expr(
parser,
(ScirptAstExpr) {
.type = ScirptAstExprTypeBool,
.pos = pos,
.bool_value = false,
}
);
case ScirptTokenTypeTrue:
return step_alloc_expr(
parser,
(ScirptAstExpr) {
.type = ScirptAstExprTypeBool,
.pos = pos,
.bool_value = true,
}
);
case ScirptTokenTypeIf:
return scirpt_parser_parse_if(parser);
case ScirptTokenTypeEof: {
error(
parser,
heapstring_from_cstring("expected value, got Eof"),
position(parser)
);
return alloc_expr((ScirptAstExpr) {
.type = ScirptAstExprTypeError,
.pos = pos,
});
}
default: {
error(
parser,
heapstring_from_cstring("expected value"),
position(parser)
);
step(parser);
return alloc_expr((ScirptAstExpr) {
.type = ScirptAstExprTypeError,
.pos = pos,
});
}
}
}
ScirptAstExpr* scirpt_parser_parse_int(ScirptParser* parser)
{
ScirptPosition pos = position(parser);
HeapString value_string = heapstring_from(
&parser->text[position(parser).index], parser->current.length
);
int64_t value = atoll(value_string.data);
step(parser);
return alloc_expr((ScirptAstExpr) {
.type = ScirptAstExprTypeInt,
.pos = pos,
.int_value = value,
});
}
ScirptAstExpr* scirpt_parser_parse_string(ScirptParser* parser)
{
ScirptPosition pos = position(parser);
UnescapeStringResult result = common_unescape_string((StringView
) { .data = &parser->text[position(parser).index],
.length = parser->current.length - 2 });
if (!result.ok) {
error(parser, result.error, position(parser));
step(parser);
return alloc_expr((ScirptAstExpr) {
.type = ScirptAstExprTypeError,
});
}
HeapString value = result.value;
step(parser);
return alloc_expr((ScirptAstExpr) {
.type = ScirptAstExprTypeString,
.pos = pos,
.string_value = value,
});
}
ScirptAstExpr* scirpt_parser_parse_if(ScirptParser* parser)
{
ScirptPosition pos = position(parser);
step(parser);
ScirptAstExpr* condition = scirpt_parser_parse_expr(parser);
if (!current_is(parser, ScirptTokenTypeLBrace)) {
error(
parser, heapstring_from_cstring("expected '{'"), position(parser)
);
scirpt_ast_expr_delete(condition);
return alloc_expr((ScirptAstExpr) {
.type = ScirptAstExprTypeError,
});
}
ScirptAstExpr* truthy = scirpt_parser_parse_expr(parser);
ScirptAstExpr* falsy = NULL;
if (current_is(parser, ScirptTokenTypeElse)) {
step(parser);
if (!current_is(parser, ScirptTokenTypeLBrace)) {
error(
parser,
heapstring_from_cstring("expected '{'"),
position(parser)
);
scirpt_ast_expr_delete(condition);
scirpt_ast_expr_delete(truthy);
}
falsy = scirpt_parser_parse_expr(parser);
}
return alloc_expr((ScirptAstExpr) {
.type = ScirptAstExprTypeIf,
.pos = pos,
.if_expr = (ScirptAstExprIf) {
.condition = condition,
.truthy = truthy,
.falsy = falsy,
},
});
}
void scirpt_parser_error(
ScirptParser* parser, HeapString message, ScirptPosition pos
)
{
if (parser->ok)
parser->ok = false;
scirpt_parser_error_array_append(
&parser->errors,
(ScirptParserError) {
.message = message,
.pos = pos,
}
);
}
void scirpt_parser_step(ScirptParser* parser)
{
parser->current = scirpt_lexer_next(parser->lexer);
}
bool scirpt_parser_current_is(const ScirptParser* parser, ScirptTokenType type)
{
return parser->current.type == type;
}
bool scirpt_parser_done(const ScirptParser* parser)
{
return parser->current.type == ScirptTokenTypeEof;
}