#include "scirpt/parser.h" #include "common/string.h" #include "common/string_array.h" #include "parser.h" #include "scirpt/ast.h" #include "scirpt/lexer.h" #include "scirpt/position.h" #include "scirpt/token.h" #include #include #include #include #define TT(type) ScirptTokenType##type #define AET(type) ScirptAstExprType##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 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 = AET(Eof), }); } else if (parser->current.type == TT(Semicolon)) { step(parser); while (current_is(parser, TT(Semicolon))) step(parser); return scirpt_parser_next(parser); } 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) { switch (parser->current.type) { case TT(If): return scirpt_parser_parse_if(parser); case TT(Loop): return scirpt_parser_parse_loop(parser); case TT(While): return scirpt_parser_parse_while(parser); case TT(For): return scirpt_parser_parse_for(parser); case TT(Let): return scirpt_parser_parse_let(parser); case TT(Fn): return scirpt_parser_parse_function(parser); case TT(Return): return scirpt_parser_parse_return(parser); case TT(Break): return scirpt_parser_parse_break(parser); default: return scirpt_parser_parse_assign(parser); } } static inline ScirptAstExpr* assign( ScirptAstExprAssignType type, ScirptAstExpr* subject, ScirptAstExpr* value, ScirptPosition pos ) { return alloc_expr((ScirptAstExpr) { .type = AET(Assign), .pos = pos, .assign = (ScirptAstExprAssign) { .type = type, .subject = subject, .value = value, }, }); } ScirptAstExpr* scirpt_parser_parse_assign(ScirptParser* parser) { ScirptPosition pos = parser->current.pos; ScirptAstExpr* subject = scirpt_parser_parse_expr(parser); if (current_is(parser, TT(Equal))) { step(parser); ScirptAstExpr* value = scirpt_parser_parse_expr(parser); return assign(ScirptAstExprAssignTypeEqual, subject, value, pos); } else if (current_is(parser, TT(PlusEqual))) { step(parser); ScirptAstExpr* value = scirpt_parser_parse_expr(parser); return assign(ScirptAstExprAssignTypeAdd, subject, value, pos); } else if (current_is(parser, TT(MinusEqual))) { step(parser); ScirptAstExpr* value = scirpt_parser_parse_expr(parser); return assign(ScirptAstExprAssignTypeSubtract, subject, value, pos); } else if (current_is(parser, TT(AsteriskEqual))) { step(parser); ScirptAstExpr* value = scirpt_parser_parse_expr(parser); return assign(ScirptAstExprAssignTypeMultiply, subject, value, pos); } else if (current_is(parser, TT(SlashEqual))) { step(parser); ScirptAstExpr* value = scirpt_parser_parse_expr(parser); return assign(ScirptAstExprAssignTypeDivide, subject, value, pos); } else if (current_is(parser, TT(PercentEqual))) { step(parser); ScirptAstExpr* value = scirpt_parser_parse_expr(parser); return assign(ScirptAstExprAssignTypeModulo, subject, value, pos); } else if (current_is(parser, TT(AsteriskAsteriskEqual))) { step(parser); ScirptAstExpr* value = scirpt_parser_parse_expr(parser); return assign(ScirptAstExprAssignTypeExponent, subject, value, pos); } else { return subject; } } ScirptAstExpr* scirpt_parser_parse_expr(ScirptParser* parser) { return scirpt_parser_parse_or(parser); } static inline ScirptAstExpr* binary( ScirptAstExprBinaryType type, ScirptAstExpr* left, ScirptAstExpr* right, ScirptPosition pos ) { return alloc_expr((ScirptAstExpr) { .type = AET(Binary), .pos = pos, .binary = (ScirptAstExprBinary) { .type = type, .left = left, .right = right, }, }); } ScirptAstExpr* scirpt_parser_parse_or(ScirptParser* parser) { ScirptPosition pos = parser->current.pos; ScirptAstExpr* left = scirpt_parser_parse_and(parser); while (!done(parser)) { if (current_is(parser, TT(Or))) { step(parser); ScirptAstExpr* right = scirpt_parser_parse_and(parser); left = binary(ScirptAstExprBinaryTypeOr, left, right, pos); } else { break; } } return left; } ScirptAstExpr* scirpt_parser_parse_and(ScirptParser* parser) { ScirptPosition pos = parser->current.pos; ScirptAstExpr* left = scirpt_parser_parse_equality(parser); while (!done(parser)) { if (current_is(parser, TT(And))) { step(parser); ScirptAstExpr* right = scirpt_parser_parse_equality(parser); left = binary(ScirptAstExprBinaryTypeAnd, left, right, pos); } else { break; } } return left; } ScirptAstExpr* scirpt_parser_parse_equality(ScirptParser* parser) { ScirptPosition pos = parser->current.pos; ScirptAstExpr* left = scirpt_parser_parse_comparison(parser); while (!done(parser)) { if (current_is(parser, TT(EqualEqual))) { step(parser); ScirptAstExpr* right = scirpt_parser_parse_comparison(parser); left = binary(ScirptAstExprBinaryTypeEqual, left, right, pos); } else if (current_is(parser, TT(ExclamationEqual))) { step(parser); ScirptAstExpr* right = scirpt_parser_parse_comparison(parser); left = binary(ScirptAstExprBinaryTypeInequal, left, right, pos); } else { break; } } return left; } ScirptAstExpr* scirpt_parser_parse_comparison(ScirptParser* parser) { ScirptPosition pos = parser->current.pos; ScirptAstExpr* left = scirpt_parser_parse_add_subtract(parser); if (current_is(parser, TT(Lt))) { step(parser); ScirptAstExpr* right = scirpt_parser_parse_add_subtract(parser); return binary(ScirptAstExprBinaryTypeLt, left, right, pos); } else if (current_is(parser, TT(Gt))) { step(parser); ScirptAstExpr* right = scirpt_parser_parse_add_subtract(parser); return binary(ScirptAstExprBinaryTypeGt, left, right, pos); } else if (current_is(parser, TT(LtEqual))) { step(parser); ScirptAstExpr* right = scirpt_parser_parse_add_subtract(parser); return binary(ScirptAstExprBinaryTypeLtEqual, left, right, pos); } else if (current_is(parser, TT(GtEqual))) { step(parser); ScirptAstExpr* right = scirpt_parser_parse_add_subtract(parser); return binary(ScirptAstExprBinaryTypeGtEqual, left, right, pos); } else if (current_is(parser, TT(In))) { step(parser); ScirptAstExpr* right = scirpt_parser_parse_add_subtract(parser); return binary(ScirptAstExprBinaryTypeIn, left, right, pos); } else { return left; } } ScirptAstExpr* scirpt_parser_parse_add_subtract(ScirptParser* parser) { ScirptPosition pos = parser->current.pos; ScirptAstExpr* left = scirpt_parser_parse_multiply_divide_modulo(parser); while (!done(parser)) { if (current_is(parser, TT(Plus))) { step(parser); ScirptAstExpr* right = scirpt_parser_parse_multiply_divide_modulo(parser); left = binary(ScirptAstExprBinaryTypeAdd, left, right, pos); } else if (current_is(parser, TT(Minus))) { step(parser); ScirptAstExpr* right = scirpt_parser_parse_multiply_divide_modulo(parser); left = binary(ScirptAstExprBinaryTypeSubtract, left, right, pos); } else { break; } } return left; } ScirptAstExpr* scirpt_parser_parse_multiply_divide_modulo(ScirptParser* parser) { ScirptPosition pos = parser->current.pos; ScirptAstExpr* left = scirpt_parser_parse_negate(parser); while (!done(parser)) { if (current_is(parser, TT(Asterisk))) { step(parser); ScirptAstExpr* right = scirpt_parser_parse_negate(parser); left = binary(ScirptAstExprBinaryTypeMultiply, left, right, pos); } else if (current_is(parser, TT(Slash))) { step(parser); ScirptAstExpr* right = scirpt_parser_parse_negate(parser); left = binary(ScirptAstExprBinaryTypeDivide, left, right, pos); } else if (current_is(parser, TT(Percent))) { step(parser); ScirptAstExpr* right = scirpt_parser_parse_negate(parser); left = binary(ScirptAstExprBinaryTypeModulo, left, right, pos); } else { break; } } return left; } static inline ScirptAstExpr* unary(ScirptAstExprUnaryType type, ScirptAstExpr* subject, ScirptPosition pos) { return alloc_expr((ScirptAstExpr) { .type = AET(Unary), .pos = pos, .unary = (ScirptAstExprUnary) { .type = type, .subject = subject, }, }); } ScirptAstExpr* scirpt_parser_parse_negate(ScirptParser* parser) { if (current_is(parser, TT(Minus))) { ScirptPosition pos = parser->current.pos; step(parser); ScirptAstExpr* subject = scirpt_parser_parse_negate(parser); return unary(ScirptAstExprUnaryTypeNegate, subject, pos); } else { return scirpt_parser_parse_exponent(parser); } } ScirptAstExpr* scirpt_parser_parse_exponent(ScirptParser* parser) { ScirptPosition pos = parser->current.pos; ScirptAstExpr* left = scirpt_parser_parse_unary(parser); while (!done(parser)) { if (current_is(parser, TT(AsteriskAsterisk))) { step(parser); ScirptAstExpr* right = scirpt_parser_parse_unary(parser); left = binary(ScirptAstExprBinaryTypeExponent, left, right, pos); } else { break; } } return left; } ScirptAstExpr* scirpt_parser_parse_unary(ScirptParser* parser) { ScirptPosition pos = parser->current.pos; if (current_is(parser, TT(Not))) { step(parser); ScirptAstExpr* subject = scirpt_parser_parse_unary(parser); return unary(ScirptAstExprUnaryTypeNot, subject, pos); } else { return scirpt_parser_parse_member_call_index_expr(parser); } } ScirptAstExpr* scirpt_parser_parse_member_call_index_expr(ScirptParser* parser) { ScirptPosition pos = parser->current.pos; ScirptAstExpr* subject = scirpt_parser_parse_operand(parser); while (!done(parser)) { if (current_is(parser, TT(Dot))) { step(parser); if (!current_is(parser, TT(Id))) { error( parser, heapstring_from_cstring("expected id"), parser->current.pos ); scirpt_ast_expr_delete(subject); return alloc_expr((ScirptAstExpr) { .type = AET(Error), .pos = pos, }); } HeapString value = heapstring_from( &parser->text[parser->current.pos.index], parser->current.length ); subject = alloc_expr((ScirptAstExpr) { .type = AET(Member), .pos = pos, .member = (ScirptAstExprMember) { .subject = subject, .value = value, }, }); } else if (current_is(parser, TT(LParen))) { step(parser); ScirptAstExprArray args; scirpt_ast_expr_array_construct(&args); if (!done(parser) && parser->current.type != TT(RParen)) { ScirptAstExpr* value = scirpt_parser_parse_operand(parser); scirpt_ast_expr_array_append(&args, value); while (current_is(parser, TT(Comma))) { step(parser); if (done(parser) || parser->current.type == TT(RParen)) break; ScirptAstExpr* value = scirpt_parser_parse_operand(parser); scirpt_ast_expr_array_append(&args, value); } } if (!current_is(parser, TT(RParen))) { error( parser, heapstring_from_cstring("expected ')'"), parser->current.pos ); scirpt_ast_expr_delete(subject); return alloc_expr((ScirptAstExpr) { .type = AET(Error), .pos = pos, }); } step(parser); subject = alloc_expr((ScirptAstExpr) { .type = AET(Call), .pos = pos, .call = (ScirptAstExprCall) { .subject = subject, .args = args, }, }); } else if (current_is(parser, TT(LBracket))) { step(parser); ScirptAstExpr* value = scirpt_parser_parse_operand(parser); if (!current_is(parser, TT(RBracket))) { error( parser, heapstring_from_cstring("expected ']'"), parser->current.pos ); scirpt_ast_expr_delete(subject); return alloc_expr((ScirptAstExpr) { .type = AET(Error), .pos = pos, }); } step(parser); subject = alloc_expr((ScirptAstExpr) { .type = AET(Index), .pos = pos, .index = (ScirptAstExprIndex) { .subject = subject, .value = value, }, }); } else { break; } } return subject; } ScirptAstExpr* scirpt_parser_parse_operand(ScirptParser* parser) { ScirptPosition pos = parser->current.pos; switch (parser->current.type) { case TT(Id): { HeapString value = heapstring_from( &parser->text[parser->current.pos.index], parser->current.length ); step(parser); return alloc_expr((ScirptAstExpr) { .type = AET(Id), .pos = pos, .id_value = value, }); } case TT(Int): return scirpt_parser_parse_int_or_float(parser); case TT(String): return scirpt_parser_parse_string(parser); case TT(Null): return step_alloc_expr( parser, (ScirptAstExpr) { .type = AET(Null), .pos = pos, } ); case TT(False): return step_alloc_expr( parser, (ScirptAstExpr) { .type = AET(Bool), .pos = pos, .bool_value = false, } ); case TT(True): return step_alloc_expr( parser, (ScirptAstExpr) { .type = AET(Bool), .pos = pos, .bool_value = true, } ); case TT(LBrace): return scirpt_parser_parse_block(parser); case TT(If): return scirpt_parser_parse_if(parser); case TT(Loop): return scirpt_parser_parse_loop(parser); case TT(While): return scirpt_parser_parse_while(parser); case TT(For): return scirpt_parser_parse_for(parser); case TT(Fn): return scirpt_parser_parse_lambda(parser); case TT(Eof): { error( parser, heapstring_from_cstring("expected value, got Eof"), parser->current.pos ); return alloc_expr((ScirptAstExpr) { .type = AET(Error), .pos = pos, }); } case TT(InvalidChar): { error( parser, heapstring_from_cstring("invalid char"), parser->current.pos ); step(parser); return alloc_expr((ScirptAstExpr) { .type = AET(Error), .pos = pos, }); } case TT(MalformedComment): { error( parser, heapstring_from_cstring("malformed comment"), parser->current.pos ); return alloc_expr((ScirptAstExpr) { .type = AET(Error), .pos = pos, }); } case TT(MalformedString): { error( parser, heapstring_from_cstring("malformed string"), parser->current.pos ); step(parser); return alloc_expr((ScirptAstExpr) { .type = AET(Error), .pos = pos, }); } default: { fprintf(stderr, "unhandled token %d\n", parser->current.type); error( parser, heapstring_from_cstring("expected value"), parser->current.pos ); step(parser); return alloc_expr((ScirptAstExpr) { .type = AET(Error), .pos = pos, }); } } } ScirptAstExpr* scirpt_parser_parse_int_or_float(ScirptParser* parser) { ScirptPosition pos = parser->current.pos; HeapString int_string = heapstring_from( &parser->text[parser->current.pos.index], parser->current.length ); step(parser); if (current_is(parser, TT(Decimals))) { HeapString float_string = heapstring_from( &parser->text[parser->current.pos.index], parser->current.length ); step(parser); StringBuilder builder; stringbuilder_construct(&builder); for (size_t i = 0; i < int_string.length; ++i) stringbuilder_append(&builder, int_string.data[i]); for (size_t i = 0; i < float_string.length; ++i) stringbuilder_append(&builder, float_string.data[i]); heapstring_destroy(&int_string); heapstring_destroy(&float_string); HeapString value_string = stringbuilder_build(&builder); stringbuilder_destroy(&builder); double value = atof(value_string.data); heapstring_destroy(&value_string); return alloc_expr((ScirptAstExpr) { .type = AET(Float), .pos = pos, .float_value = value, }); } else { int64_t value = atoll(int_string.data); heapstring_destroy(&int_string); return alloc_expr((ScirptAstExpr) { .type = AET(Int), .pos = pos, .int_value = value, }); } } ScirptAstExpr* scirpt_parser_parse_string(ScirptParser* parser) { ScirptPosition pos = parser->current.pos; UnescapeStringResult result = common_unescape_string((StringView ) { .data = &parser->text[parser->current.pos.index], .length = parser->current.length - 2 }); if (!result.ok) { error(parser, result.error, parser->current.pos); step(parser); return alloc_expr((ScirptAstExpr) { .type = AET(Error), }); } HeapString value = result.value; step(parser); return alloc_expr((ScirptAstExpr) { .type = AET(String), .pos = pos, .string_value = value, }); } static inline bool requires_semicolon(ScirptAstExprType type) { switch (type) { case AET(Let): return true; default: return false; } } ScirptAstExpr* scirpt_parser_parse_block(ScirptParser* parser) { ScirptPosition pos = parser->current.pos; step(parser); ScirptAstExprArray statements; scirpt_ast_expr_array_construct(&statements); while (!done(parser) && parser->current.type != TT(RBrace)) { ScirptAstExpr* statement = scirpt_parser_parse_statement(parser); scirpt_ast_expr_array_append(&statements, statement); if (current_is(parser, TT(Semicolon))) { step(parser); while (current_is(parser, TT(Semicolon))) step(parser); } else { if (requires_semicolon(statement->type)) { error( parser, heapstring_from_cstring( "expected ';', required for statement" ), parser->current.pos ); } break; } } if (!current_is(parser, TT(RBrace))) { error( parser, heapstring_from_cstring("expected '}'"), parser->current.pos ); for (size_t i = 0; i < statements.length; ++i) scirpt_ast_expr_delete(statements.data[i]); scirpt_ast_expr_array_destroy(&statements); return alloc_expr((ScirptAstExpr) { .type = AET(Error), .pos = pos, }); } step(parser); return alloc_expr((ScirptAstExpr){ .type = AET(Block), .pos = pos, .block = (ScirptAstExprBlock) { .statements = statements, }, }); } ScirptAstExpr* scirpt_parser_parse_if(ScirptParser* parser) { ScirptPosition pos = parser->current.pos; step(parser); ScirptAstExpr* condition = scirpt_parser_parse_expr(parser); if (!current_is(parser, TT(LBrace))) { error( parser, heapstring_from_cstring("expected '{'"), parser->current.pos ); scirpt_ast_expr_delete(condition); return alloc_expr((ScirptAstExpr) { .type = AET(Error), }); } ScirptAstExpr* truthy = scirpt_parser_parse_expr(parser); ScirptAstExpr* falsy = NULL; if (current_is(parser, TT(Else))) { step(parser); if (!current_is(parser, TT(LBrace))) { error( parser, heapstring_from_cstring("expected '{'"), parser->current.pos ); scirpt_ast_expr_delete(condition); scirpt_ast_expr_delete(truthy); } falsy = scirpt_parser_parse_expr(parser); } return alloc_expr((ScirptAstExpr) { .type = AET(If), .pos = pos, .if_expr = (ScirptAstExprIf) { .condition = condition, .truthy = truthy, .falsy = falsy, }, }); } ScirptAstExpr* scirpt_parser_parse_loop(ScirptParser* parser) { ScirptPosition pos = parser->current.pos; step(parser); if (!current_is(parser, TT(LBrace))) { error( parser, heapstring_from_cstring("expected '{'"), parser->current.pos ); return alloc_expr((ScirptAstExpr) { .type = AET(Error), }); } ScirptAstExpr* body = scirpt_parser_parse_expr(parser); return alloc_expr((ScirptAstExpr) { .type = AET(Loop), .pos = pos, .loop = (ScirptAstExprLoop) { .body = body, }, }); } ScirptAstExpr* scirpt_parser_parse_while(ScirptParser* parser) { ScirptPosition pos = parser->current.pos; step(parser); ScirptAstExpr* condition = scirpt_parser_parse_expr(parser); if (!current_is(parser, TT(LBrace))) { error( parser, heapstring_from_cstring("expected '{'"), parser->current.pos ); scirpt_ast_expr_delete(condition); return alloc_expr((ScirptAstExpr) { .type = AET(Error), }); } ScirptAstExpr* body = scirpt_parser_parse_expr(parser); return alloc_expr((ScirptAstExpr) { .type = AET(While), .pos = pos, .while_expr = (ScirptAstExprWhile) { .condition = condition, .body = body, }, }); } ScirptAstExpr* scirpt_parser_parse_for(ScirptParser* parser) { ScirptPosition pos = parser->current.pos; step(parser); if (!current_is(parser, TT(Id))) { error( parser, heapstring_from_cstring("expected Id"), parser->current.pos ); return alloc_expr((ScirptAstExpr) { .type = AET(Error), }); } HeapString subject = heapstring_from( &parser->text[parser->current.pos.index], parser->current.length ); step(parser); if (!current_is(parser, TT(In))) { error( parser, heapstring_from_cstring("expected 'in'"), parser->current.pos ); heapstring_destroy(&subject); return alloc_expr((ScirptAstExpr) { .type = AET(Error), }); } step(parser); ScirptAstExpr* value = scirpt_parser_parse_expr(parser); if (!current_is(parser, TT(LBrace))) { error( parser, heapstring_from_cstring("expected '{'"), parser->current.pos ); heapstring_destroy(&subject); scirpt_ast_expr_delete(value); return alloc_expr((ScirptAstExpr) { .type = AET(Error), }); } ScirptAstExpr* body = scirpt_parser_parse_expr(parser); return alloc_expr((ScirptAstExpr) { .type = AET(While), .pos = pos, .while_expr = (ScirptAstExprWhile) { .condition = value, .body = body, }, }); } ScirptAstExpr* scirpt_parser_parse_lambda(ScirptParser* parser) { ScirptPosition pos = parser->current.pos; step(parser); if (!current_is(parser, TT(LParen))) { error( parser, heapstring_from_cstring("expected '('"), parser->current.pos ); return alloc_expr((ScirptAstExpr) { .type = AET(Error), }); } step(parser); HeapStringArray params; heapstring_array_construct(¶ms); if (!done(parser) && parser->current.type == TT(RParen)) { step(parser); if (!current_is(parser, TT(Id))) { error( parser, heapstring_from_cstring("expected Id"), parser->current.pos ); heapstring_array_destroy(¶ms); return alloc_expr((ScirptAstExpr) { .type = AET(Error), }); } HeapString param = heapstring_from( &parser->text[parser->current.pos.index], parser->current.length ); heapstring_array_append(¶ms, param); step(parser); while (current_is(parser, TT(Comma))) { step(parser); if (done(parser) || parser->current.type == TT(RParen)) break; if (!current_is(parser, TT(Id))) { error( parser, heapstring_from_cstring("expected Id"), parser->current.pos ); for (size_t i = 0; i < params.length; ++i) heapstring_destroy(¶ms.data[i]); heapstring_array_destroy(¶ms); return alloc_expr((ScirptAstExpr) { .type = AET(Error), }); } HeapString param = heapstring_from( &parser->text[parser->current.pos.index], parser->current.length ); heapstring_array_append(¶ms, param); step(parser); } } if (!current_is(parser, TT(RParen))) { error( parser, heapstring_from_cstring("expected ')'"), parser->current.pos ); for (size_t i = 0; i < params.length; ++i) heapstring_destroy(¶ms.data[i]); heapstring_array_destroy(¶ms); return alloc_expr((ScirptAstExpr) { .type = AET(Error), .pos = pos, }); } step(parser); if (!current_is(parser, TT(LBrace))) { error( parser, heapstring_from_cstring("expected '{'"), parser->current.pos ); for (size_t i = 0; i < params.length; ++i) heapstring_destroy(¶ms.data[i]); heapstring_array_destroy(¶ms); return alloc_expr((ScirptAstExpr) { .type = AET(Error), }); } ScirptAstExpr* body = scirpt_parser_parse_expr(parser); return alloc_expr((ScirptAstExpr) { .type = AET(Lambda), .pos = pos, .lambda = (ScirptAstExprLambda) { .params = params, .body = body, }, }); } ScirptAstExpr* scirpt_parser_parse_function(ScirptParser* parser) { ScirptPosition pos = parser->current.pos; step(parser); if (!current_is(parser, TT(Id))) { error( parser, heapstring_from_cstring("expected Id"), parser->current.pos ); return alloc_expr((ScirptAstExpr) { .type = AET(Error), }); } HeapString subject = heapstring_from( &parser->text[parser->current.pos.index], parser->current.length ); step(parser); if (!current_is(parser, TT(LParen))) { error( parser, heapstring_from_cstring("expected '('"), parser->current.pos ); return alloc_expr((ScirptAstExpr) { .type = AET(Error), }); } step(parser); HeapStringArray params; heapstring_array_construct(¶ms); if (!done(parser) && parser->current.type == TT(RParen)) { step(parser); if (!current_is(parser, TT(Id))) { error( parser, heapstring_from_cstring("expected Id"), parser->current.pos ); heapstring_destroy(&subject); heapstring_array_destroy(¶ms); return alloc_expr((ScirptAstExpr) { .type = AET(Error), }); } HeapString param = heapstring_from( &parser->text[parser->current.pos.index], parser->current.length ); heapstring_array_append(¶ms, param); step(parser); while (current_is(parser, TT(Comma))) { step(parser); if (done(parser) || parser->current.type == TT(RParen)) break; if (!current_is(parser, TT(Id))) { error( parser, heapstring_from_cstring("expected Id"), parser->current.pos ); heapstring_destroy(&subject); for (size_t i = 0; i < params.length; ++i) heapstring_destroy(¶ms.data[i]); heapstring_array_destroy(¶ms); return alloc_expr((ScirptAstExpr) { .type = AET(Error), }); } HeapString param = heapstring_from( &parser->text[parser->current.pos.index], parser->current.length ); heapstring_array_append(¶ms, param); step(parser); } } if (!current_is(parser, TT(RParen))) { error( parser, heapstring_from_cstring("expected ')'"), parser->current.pos ); heapstring_destroy(&subject); for (size_t i = 0; i < params.length; ++i) heapstring_destroy(¶ms.data[i]); heapstring_array_destroy(¶ms); return alloc_expr((ScirptAstExpr) { .type = AET(Error), .pos = pos, }); } step(parser); if (!current_is(parser, TT(LBrace))) { error( parser, heapstring_from_cstring("expected '{'"), parser->current.pos ); heapstring_destroy(&subject); for (size_t i = 0; i < params.length; ++i) heapstring_destroy(¶ms.data[i]); heapstring_array_destroy(¶ms); return alloc_expr((ScirptAstExpr) { .type = AET(Error), }); } ScirptAstExpr* body = scirpt_parser_parse_expr(parser); return alloc_expr((ScirptAstExpr) { .type = AET(Function), .pos = pos, .function = (ScirptAstExprFunction) { .subject = subject, .params = params, .body = body, }, }); } ScirptAstExpr* scirpt_parser_parse_let(ScirptParser* parser) { ScirptPosition pos = parser->current.pos; step(parser); if (!current_is(parser, TT(Id))) { error( parser, heapstring_from_cstring("expected Id"), parser->current.pos ); return alloc_expr((ScirptAstExpr) { .type = AET(Error), }); } HeapString subject = heapstring_from( &parser->text[parser->current.pos.index], parser->current.length ); step(parser); if (!current_is(parser, TT(Equal))) { error( parser, heapstring_from_cstring("expected '='"), parser->current.pos ); heapstring_destroy(&subject); return alloc_expr((ScirptAstExpr) { .type = AET(Error), }); } step(parser); ScirptAstExpr* value = scirpt_parser_parse_expr(parser); return alloc_expr((ScirptAstExpr) { .type = AET(Let), .pos = pos, .let = (ScirptAstExprLet) { .subject = subject, .value = value, }, }); } ScirptAstExpr* scirpt_parser_parse_return(ScirptParser* parser) { ScirptPosition pos = parser->current.pos; step(parser); ScirptAstExpr* value = NULL; if (!done(parser) && parser->current.type != TT(Semicolon)) { value = scirpt_parser_parse_expr(parser); } return alloc_expr((ScirptAstExpr) { .type = AET(Return), .pos = pos, .return_statement = (ScirptAstExprReturn) { .value = value, }, }); } ScirptAstExpr* scirpt_parser_parse_break(ScirptParser* parser) { ScirptPosition pos = parser->current.pos; step(parser); ScirptAstExpr* value = NULL; if (!done(parser) && parser->current.type != TT(Semicolon)) { value = scirpt_parser_parse_expr(parser); } return alloc_expr((ScirptAstExpr) { .type = AET(Break), .pos = pos, .break_statement = (ScirptAstExprBreak) { .value = value, }, }); } 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 == TT(Eof); }