#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 #include #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; }