codebased/scirpt/parser.c
2023-04-19 00:03:40 +02:00

1334 lines
34 KiB
C

#include "scirpt/parser.h"
#include "common/result.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 <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#define TT(type) ScirptTokenType##type
#define AET(type) ScirptExprType##type
void scirpt_parser_error_destroy(ScirptParserError* error)
{
heapstring_destroy(&error->message);
}
static inline ScirptExpr* alloc_expr(ScirptExpr data)
{
ScirptExpr* expr = malloc(sizeof(ScirptExpr));
*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 ScirptExpr* step_alloc_expr(ScirptParser* parser, ScirptExpr 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)
{
scirpt_parser_destroy(parser);
free(parser);
}
ScirptExpr* scirpt_parser_next(ScirptParser* parser)
{
if (done(parser)) {
return alloc_expr((ScirptExpr) {
.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)
{
for (size_t i = 0; i < parser->errors.length; ++i)
scirpt_parser_error_destroy(&parser->errors.data[i]);
scirpt_parser_error_array_construct(&parser->errors);
}
ScirptExpr* 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 ScirptExpr* assign(
ScirptExprAssignType type,
ScirptExpr* subject,
ScirptExpr* value,
ScirptPosition pos
)
{
return alloc_expr((ScirptExpr) {
.type = AET(Assign),
.pos = pos,
.assign = (ScirptExprAssign) {
.type = type,
.subject = subject,
.value = value,
},
});
}
ScirptExpr* scirpt_parser_parse_assign(ScirptParser* parser)
{
ScirptPosition pos = parser->current.pos;
ScirptExpr* subject = scirpt_parser_parse_expr(parser);
if (current_is(parser, TT(Equal))) {
step(parser);
ScirptExpr* value = scirpt_parser_parse_expr(parser);
return assign(ScirptExprAssignTypeEqual, subject, value, pos);
} else if (current_is(parser, TT(PlusEqual))) {
step(parser);
ScirptExpr* value = scirpt_parser_parse_expr(parser);
return assign(ScirptExprAssignTypeAdd, subject, value, pos);
} else if (current_is(parser, TT(MinusEqual))) {
step(parser);
ScirptExpr* value = scirpt_parser_parse_expr(parser);
return assign(ScirptExprAssignTypeSubtract, subject, value, pos);
} else if (current_is(parser, TT(AsteriskEqual))) {
step(parser);
ScirptExpr* value = scirpt_parser_parse_expr(parser);
return assign(ScirptExprAssignTypeMultiply, subject, value, pos);
} else if (current_is(parser, TT(SlashEqual))) {
step(parser);
ScirptExpr* value = scirpt_parser_parse_expr(parser);
return assign(ScirptExprAssignTypeDivide, subject, value, pos);
} else if (current_is(parser, TT(PercentEqual))) {
step(parser);
ScirptExpr* value = scirpt_parser_parse_expr(parser);
return assign(ScirptExprAssignTypeModulo, subject, value, pos);
} else if (current_is(parser, TT(AsteriskAsteriskEqual))) {
step(parser);
ScirptExpr* value = scirpt_parser_parse_expr(parser);
return assign(ScirptExprAssignTypeExponent, subject, value, pos);
} else {
return subject;
}
}
ScirptExpr* scirpt_parser_parse_expr(ScirptParser* parser)
{
return scirpt_parser_parse_or(parser);
}
static inline ScirptExpr* binary(
ScirptExprBinaryType type,
ScirptExpr* left,
ScirptExpr* right,
ScirptPosition pos
)
{
return alloc_expr((ScirptExpr) {
.type = AET(Binary),
.pos = pos,
.binary = (ScirptExprBinary) {
.type = type,
.left = left,
.right = right,
},
});
}
ScirptExpr* scirpt_parser_parse_or(ScirptParser* parser)
{
ScirptPosition pos = parser->current.pos;
ScirptExpr* left = scirpt_parser_parse_and(parser);
while (!done(parser)) {
if (current_is(parser, TT(Or))) {
step(parser);
ScirptExpr* right = scirpt_parser_parse_and(parser);
left = binary(ScirptExprBinaryTypeOr, left, right, pos);
} else {
break;
}
}
return left;
}
ScirptExpr* scirpt_parser_parse_and(ScirptParser* parser)
{
ScirptPosition pos = parser->current.pos;
ScirptExpr* left = scirpt_parser_parse_equality(parser);
while (!done(parser)) {
if (current_is(parser, TT(And))) {
step(parser);
ScirptExpr* right = scirpt_parser_parse_equality(parser);
left = binary(ScirptExprBinaryTypeAnd, left, right, pos);
} else {
break;
}
}
return left;
}
ScirptExpr* scirpt_parser_parse_equality(ScirptParser* parser)
{
ScirptPosition pos = parser->current.pos;
ScirptExpr* left = scirpt_parser_parse_comparison(parser);
while (!done(parser)) {
if (current_is(parser, TT(EqualEqual))) {
step(parser);
ScirptExpr* right = scirpt_parser_parse_comparison(parser);
left = binary(ScirptExprBinaryTypeEqual, left, right, pos);
} else if (current_is(parser, TT(ExclamationEqual))) {
step(parser);
ScirptExpr* right = scirpt_parser_parse_comparison(parser);
left = binary(ScirptExprBinaryTypeInequal, left, right, pos);
} else {
break;
}
}
return left;
}
ScirptExpr* scirpt_parser_parse_comparison(ScirptParser* parser)
{
ScirptPosition pos = parser->current.pos;
ScirptExpr* left = scirpt_parser_parse_add_subtract(parser);
if (current_is(parser, TT(Lt))) {
step(parser);
ScirptExpr* right = scirpt_parser_parse_add_subtract(parser);
return binary(ScirptExprBinaryTypeLt, left, right, pos);
} else if (current_is(parser, TT(Gt))) {
step(parser);
ScirptExpr* right = scirpt_parser_parse_add_subtract(parser);
return binary(ScirptExprBinaryTypeGt, left, right, pos);
} else if (current_is(parser, TT(LtEqual))) {
step(parser);
ScirptExpr* right = scirpt_parser_parse_add_subtract(parser);
return binary(ScirptExprBinaryTypeLtEqual, left, right, pos);
} else if (current_is(parser, TT(GtEqual))) {
step(parser);
ScirptExpr* right = scirpt_parser_parse_add_subtract(parser);
return binary(ScirptExprBinaryTypeGtEqual, left, right, pos);
} else if (current_is(parser, TT(In))) {
step(parser);
ScirptExpr* right = scirpt_parser_parse_add_subtract(parser);
return binary(ScirptExprBinaryTypeIn, left, right, pos);
} else {
return left;
}
}
ScirptExpr* scirpt_parser_parse_add_subtract(ScirptParser* parser)
{
ScirptPosition pos = parser->current.pos;
ScirptExpr* left = scirpt_parser_parse_multiply_divide_modulo(parser);
while (!done(parser)) {
if (current_is(parser, TT(Plus))) {
step(parser);
ScirptExpr* right
= scirpt_parser_parse_multiply_divide_modulo(parser);
left = binary(ScirptExprBinaryTypeAdd, left, right, pos);
} else if (current_is(parser, TT(Minus))) {
step(parser);
ScirptExpr* right
= scirpt_parser_parse_multiply_divide_modulo(parser);
left = binary(ScirptExprBinaryTypeSubtract, left, right, pos);
} else {
break;
}
}
return left;
}
ScirptExpr* scirpt_parser_parse_multiply_divide_modulo(ScirptParser* parser)
{
ScirptPosition pos = parser->current.pos;
ScirptExpr* left = scirpt_parser_parse_negate(parser);
while (!done(parser)) {
if (current_is(parser, TT(Asterisk))) {
step(parser);
ScirptExpr* right = scirpt_parser_parse_negate(parser);
left = binary(ScirptExprBinaryTypeMultiply, left, right, pos);
} else if (current_is(parser, TT(Slash))) {
step(parser);
ScirptExpr* right = scirpt_parser_parse_negate(parser);
left = binary(ScirptExprBinaryTypeDivide, left, right, pos);
} else if (current_is(parser, TT(Percent))) {
step(parser);
ScirptExpr* right = scirpt_parser_parse_negate(parser);
left = binary(ScirptExprBinaryTypeModulo, left, right, pos);
} else {
break;
}
}
return left;
}
static inline ScirptExpr*
unary(ScirptExprUnaryType type, ScirptExpr* subject, ScirptPosition pos)
{
return alloc_expr((ScirptExpr) {
.type = AET(Unary),
.pos = pos,
.unary = (ScirptExprUnary) {
.type = type,
.subject = subject,
},
});
}
ScirptExpr* scirpt_parser_parse_negate(ScirptParser* parser)
{
if (current_is(parser, TT(Minus))) {
ScirptPosition pos = parser->current.pos;
step(parser);
ScirptExpr* subject = scirpt_parser_parse_negate(parser);
return unary(ScirptExprUnaryTypeNegate, subject, pos);
} else {
return scirpt_parser_parse_exponent(parser);
}
}
ScirptExpr* scirpt_parser_parse_exponent(ScirptParser* parser)
{
ScirptPosition pos = parser->current.pos;
ScirptExpr* left = scirpt_parser_parse_unary(parser);
while (!done(parser)) {
if (current_is(parser, TT(AsteriskAsterisk))) {
step(parser);
ScirptExpr* right = scirpt_parser_parse_unary(parser);
left = binary(ScirptExprBinaryTypeExponent, left, right, pos);
} else {
break;
}
}
return left;
}
ScirptExpr* scirpt_parser_parse_unary(ScirptParser* parser)
{
ScirptPosition pos = parser->current.pos;
if (current_is(parser, TT(Not))) {
step(parser);
ScirptExpr* subject = scirpt_parser_parse_unary(parser);
return unary(ScirptExprUnaryTypeNot, subject, pos);
} else {
return scirpt_parser_parse_member_call_index_expr(parser);
}
}
ScirptExpr* scirpt_parser_parse_member_call_index_expr(ScirptParser* parser)
{
ScirptPosition pos = parser->current.pos;
ScirptExpr* 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_expr_delete(subject);
return alloc_expr((ScirptExpr) {
.type = AET(Error),
.pos = pos,
});
}
HeapString value = heapstring_from(
&parser->text[parser->current.pos.index], parser->current.length
);
subject = alloc_expr((ScirptExpr) {
.type = AET(Member),
.pos = pos,
.member = (ScirptExprMember) {
.subject = subject,
.value = value,
},
});
} else if (current_is(parser, TT(LParen))) {
step(parser);
ScirptExprArray args;
scirpt_expr_array_construct(&args);
if (!done(parser) && parser->current.type != TT(RParen)) {
ScirptExpr* value = scirpt_parser_parse_operand(parser);
scirpt_expr_array_append(&args, value);
while (current_is(parser, TT(Comma))) {
step(parser);
if (done(parser) || parser->current.type == TT(RParen))
break;
ScirptExpr* value = scirpt_parser_parse_operand(parser);
scirpt_expr_array_append(&args, value);
}
}
if (!current_is(parser, TT(RParen))) {
error(
parser,
heapstring_from_cstring("expected ')'"),
parser->current.pos
);
scirpt_expr_delete(subject);
return alloc_expr((ScirptExpr) {
.type = AET(Error),
.pos = pos,
});
}
step(parser);
subject = alloc_expr((ScirptExpr) {
.type = AET(Call),
.pos = pos,
.call = (ScirptExprCall) {
.subject = subject,
.args = args,
},
});
} else if (current_is(parser, TT(LBracket))) {
step(parser);
ScirptExpr* value = scirpt_parser_parse_operand(parser);
if (!current_is(parser, TT(RBracket))) {
error(
parser,
heapstring_from_cstring("expected ']'"),
parser->current.pos
);
scirpt_expr_delete(subject);
return alloc_expr((ScirptExpr) {
.type = AET(Error),
.pos = pos,
});
}
step(parser);
subject = alloc_expr((ScirptExpr) {
.type = AET(Index),
.pos = pos,
.index = (ScirptExprIndex) {
.subject = subject,
.value = value,
},
});
} else {
break;
}
}
return subject;
}
ScirptExpr* 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((ScirptExpr) {
.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,
(ScirptExpr) {
.type = AET(Null),
.pos = pos,
}
);
case TT(False):
return step_alloc_expr(
parser,
(ScirptExpr) {
.type = AET(Bool),
.pos = pos,
.bool_value = false,
}
);
case TT(True):
return step_alloc_expr(
parser,
(ScirptExpr) {
.type = AET(Bool),
.pos = pos,
.bool_value = true,
}
);
case TT(LParen):
return scirpt_parser_parse_group(parser);
case TT(Exclamation):
return scirpt_parser_parse_object(parser);
case TT(LBracket):
return scirpt_parser_parse_array(parser);
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((ScirptExpr) {
.type = AET(Error),
.pos = pos,
});
}
case TT(InvalidChar): {
error(
parser,
heapstring_from_cstring("invalid char"),
parser->current.pos
);
step(parser);
return alloc_expr((ScirptExpr) {
.type = AET(Error),
.pos = pos,
});
}
case TT(MalformedComment): {
error(
parser,
heapstring_from_cstring("malformed comment"),
parser->current.pos
);
return alloc_expr((ScirptExpr) {
.type = AET(Error),
.pos = pos,
});
}
case TT(MalformedString): {
error(
parser,
heapstring_from_cstring("malformed string"),
parser->current.pos
);
step(parser);
return alloc_expr((ScirptExpr) {
.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((ScirptExpr) {
.type = AET(Error),
.pos = pos,
});
}
}
}
ScirptExpr* 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((ScirptExpr) {
.type = AET(Float),
.pos = pos,
.float_value = value,
});
} else {
int64_t value = atoll(int_string.data);
heapstring_destroy(&int_string);
return alloc_expr((ScirptExpr) {
.type = AET(Int),
.pos = pos,
.int_value = value,
});
}
}
ScirptExpr* 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((ScirptExpr) {
.type = AET(Error),
});
}
HeapString value = result.value;
step(parser);
return alloc_expr((ScirptExpr) {
.type = AET(String),
.pos = pos,
.string_value = value,
});
}
ScirptExpr* scirpt_parser_parse_group(ScirptParser* parser)
{
step(parser);
ScirptExpr* expr = scirpt_parser_parse_expr(parser);
if (!current_is(parser, TT(RParen))) {
error(
parser, heapstring_from_cstring("expected ')'"), parser->current.pos
);
scirpt_expr_delete(expr);
return alloc_expr((ScirptExpr) { .type = AET(Error) });
}
step(parser);
return expr;
}
ScirptExpr* scirpt_parser_parse_array(ScirptParser* parser)
{
ScirptPosition pos = parser->current.pos;
step(parser);
ScirptExprArray values;
scirpt_expr_array_construct(&values);
if (!done(parser) && parser->current.type != TT(RBracket)) {
ScirptExpr* value = scirpt_parser_parse_expr(parser);
scirpt_expr_array_append(&values, value);
while (current_is(parser, TT(Comma))) {
step(parser);
if (done(parser) || parser->current.type == TT(RBracket))
break;
ScirptExpr* value = scirpt_parser_parse_expr(parser);
scirpt_expr_array_append(&values, value);
}
}
if (!current_is(parser, TT(RBracket))) {
error(
parser, heapstring_from_cstring("expected ']'"), parser->current.pos
);
scirpt_expr_array_clean_and_destroy(&values);
return alloc_expr((ScirptExpr) { .type = AET(Error) });
}
step(parser);
return alloc_expr((ScirptExpr) {
.type = AET(Array),
.pos = pos,
.array_value = values,
});
}
RESULT_WITH_CTORS(
HeapString, HeapString, IdOrStringValueResult, id_or_string_value_result
)
static inline IdOrStringValueResult
id_or_string_value(const ScirptParser* parser)
{
if (parser->current.type == TT(Id)) {
return id_or_string_value_result_ok(heapstring_from(
&parser->text[parser->current.pos.index], parser->current.length
));
} else if (parser->current.type == TT(String)) {
UnescapeStringResult result = common_unescape_string((StringView) {
.data = &parser->text[parser->current.pos.index],
.length = parser->current.length - 2,
});
if (result.ok) {
return id_or_string_value_result_ok(result.value);
} else {
return id_or_string_value_result_error(result.error);
}
} else {
return id_or_string_value_result_error(
heapstring_from_cstring("expected Id or String")
);
}
}
RESULT_WITH_CTORS(
ScirptExprObjectEntry,
HeapString,
ParseObjectEntryResult,
parse_object_entry_result
)
static inline ParseObjectEntryResult parse_object_entry(ScirptParser* parser)
{
IdOrStringValueResult key_result = id_or_string_value(parser);
if (!key_result.ok) {
error(parser, heapstring_clone(&key_result.error), parser->current.pos);
return parse_object_entry_result_error(key_result.error);
}
step(parser);
if (!current_is(parser, TT(Colon))) {
return parse_object_entry_result_error(
heapstring_from_cstring("expected ':'")
);
}
step(parser);
ScirptExpr* value = scirpt_parser_parse_expr(parser);
return parse_object_entry_result_ok((ScirptExprObjectEntry) {
.key = key_result.value,
.value = value,
});
}
ScirptExpr* scirpt_parser_parse_object(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((ScirptExpr) { .type = AET(Error) });
}
step(parser);
ScirptExprObjectEntryArray entries;
scirpt_expr_object_entry_array_construct(&entries);
if (!done(parser) && parser->current.type != TT(RBrace)) {
ParseObjectEntryResult entry_result = parse_object_entry(parser);
if (!entry_result.ok) {
error(parser, entry_result.error, parser->current.pos);
scirpt_expr_object_entry_array_destroy(&entries);
return alloc_expr((ScirptExpr) { .type = AET(Error) });
}
scirpt_expr_object_entry_array_append(&entries, entry_result.value);
while (current_is(parser, TT(Comma))) {
step(parser);
if (done(parser) || parser->current.type == TT(RBrace))
break;
ParseObjectEntryResult entry_result = parse_object_entry(parser);
if (!entry_result.ok) {
error(parser, entry_result.error, parser->current.pos);
for (size_t i = 0; i < entries.length; ++i) {
heapstring_destroy(&entries.data[i].key);
scirpt_expr_delete(entries.data[i].value);
}
scirpt_expr_object_entry_array_destroy(&entries);
return alloc_expr((ScirptExpr) { .type = AET(Error) });
}
scirpt_expr_object_entry_array_append(&entries, entry_result.value);
}
}
if (!current_is(parser, TT(RBrace))) {
error(
parser, heapstring_from_cstring("expected '}'"), parser->current.pos
);
return alloc_expr((ScirptExpr) { .type = AET(Error) });
}
step(parser);
return alloc_expr((ScirptExpr) {
.type = AET(Object),
.pos = pos,
.object = (ScirptExprObject) {
.entries = entries,
},
});
}
static inline bool requires_semicolon(ScirptExprType type)
{
switch (type) {
case AET(Let):
return true;
default:
return false;
}
}
ScirptExpr* scirpt_parser_parse_block(ScirptParser* parser)
{
ScirptPosition pos = parser->current.pos;
step(parser);
ScirptExprArray statements;
scirpt_expr_array_construct(&statements);
while (!done(parser) && parser->current.type != TT(RBrace)) {
ScirptExpr* statement = scirpt_parser_parse_statement(parser);
scirpt_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_expr_delete(statements.data[i]);
scirpt_expr_array_destroy(&statements);
return alloc_expr((ScirptExpr) {
.type = AET(Error),
.pos = pos,
});
}
step(parser);
return alloc_expr((ScirptExpr){
.type = AET(Block),
.pos = pos,
.block = (ScirptExprBlock) {
.statements = statements,
},
});
}
ScirptExpr* scirpt_parser_parse_if(ScirptParser* parser)
{
ScirptPosition pos = parser->current.pos;
step(parser);
ScirptExpr* condition = scirpt_parser_parse_expr(parser);
if (!current_is(parser, TT(LBrace))) {
error(
parser, heapstring_from_cstring("expected '{'"), parser->current.pos
);
scirpt_expr_delete(condition);
return alloc_expr((ScirptExpr) {
.type = AET(Error),
});
}
ScirptExpr* truthy = scirpt_parser_parse_expr(parser);
ScirptExpr* 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_expr_delete(condition);
scirpt_expr_delete(truthy);
}
falsy = scirpt_parser_parse_expr(parser);
}
return alloc_expr((ScirptExpr) {
.type = AET(If),
.pos = pos,
.if_expr = (ScirptExprIf) {
.condition = condition,
.truthy = truthy,
.falsy = falsy,
},
});
}
ScirptExpr* 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((ScirptExpr) {
.type = AET(Error),
});
}
ScirptExpr* body = scirpt_parser_parse_expr(parser);
return alloc_expr((ScirptExpr) {
.type = AET(Loop),
.pos = pos,
.loop = (ScirptExprLoop) {
.body = body,
},
});
}
ScirptExpr* scirpt_parser_parse_while(ScirptParser* parser)
{
ScirptPosition pos = parser->current.pos;
step(parser);
ScirptExpr* condition = scirpt_parser_parse_expr(parser);
if (!current_is(parser, TT(LBrace))) {
error(
parser, heapstring_from_cstring("expected '{'"), parser->current.pos
);
scirpt_expr_delete(condition);
return alloc_expr((ScirptExpr) {
.type = AET(Error),
});
}
ScirptExpr* body = scirpt_parser_parse_expr(parser);
return alloc_expr((ScirptExpr) {
.type = AET(While),
.pos = pos,
.while_expr = (ScirptExprWhile) {
.condition = condition,
.body = body,
},
});
}
ScirptExpr* 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((ScirptExpr) {
.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((ScirptExpr) {
.type = AET(Error),
});
}
step(parser);
ScirptExpr* 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_expr_delete(value);
return alloc_expr((ScirptExpr) {
.type = AET(Error),
});
}
ScirptExpr* body = scirpt_parser_parse_expr(parser);
return alloc_expr((ScirptExpr) {
.type = AET(While),
.pos = pos,
.while_expr = (ScirptExprWhile) {
.condition = value,
.body = body,
},
});
}
ScirptExpr* 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((ScirptExpr) {
.type = AET(Error),
});
}
step(parser);
HeapStringArray params;
heapstring_array_construct(&params);
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(&params);
return alloc_expr((ScirptExpr) {
.type = AET(Error),
});
}
HeapString param = heapstring_from(
&parser->text[parser->current.pos.index], parser->current.length
);
heapstring_array_append(&params, 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(&params.data[i]);
heapstring_array_destroy(&params);
return alloc_expr((ScirptExpr) {
.type = AET(Error),
});
}
HeapString param = heapstring_from(
&parser->text[parser->current.pos.index], parser->current.length
);
heapstring_array_append(&params, 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(&params.data[i]);
heapstring_array_destroy(&params);
return alloc_expr((ScirptExpr) {
.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(&params.data[i]);
heapstring_array_destroy(&params);
return alloc_expr((ScirptExpr) {
.type = AET(Error),
});
}
ScirptExpr* body = scirpt_parser_parse_expr(parser);
return alloc_expr((ScirptExpr) {
.type = AET(Lambda),
.pos = pos,
.lambda = (ScirptExprLambda) {
.params = params,
.body = body,
},
});
}
ScirptExpr* 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((ScirptExpr) {
.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((ScirptExpr) {
.type = AET(Error),
});
}
step(parser);
HeapStringArray params;
heapstring_array_construct(&params);
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(&params);
return alloc_expr((ScirptExpr) {
.type = AET(Error),
});
}
HeapString param = heapstring_from(
&parser->text[parser->current.pos.index], parser->current.length
);
heapstring_array_append(&params, 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(&params.data[i]);
heapstring_array_destroy(&params);
return alloc_expr((ScirptExpr) {
.type = AET(Error),
});
}
HeapString param = heapstring_from(
&parser->text[parser->current.pos.index], parser->current.length
);
heapstring_array_append(&params, 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(&params.data[i]);
heapstring_array_destroy(&params);
return alloc_expr((ScirptExpr) {
.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(&params.data[i]);
heapstring_array_destroy(&params);
return alloc_expr((ScirptExpr) {
.type = AET(Error),
});
}
ScirptExpr* body = scirpt_parser_parse_expr(parser);
return alloc_expr((ScirptExpr) {
.type = AET(Function),
.pos = pos,
.function = (ScirptExprFunction) {
.subject = subject,
.params = params,
.body = body,
},
});
}
ScirptExpr* 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((ScirptExpr) {
.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((ScirptExpr) {
.type = AET(Error),
});
}
step(parser);
ScirptExpr* value = scirpt_parser_parse_expr(parser);
return alloc_expr((ScirptExpr) {
.type = AET(Let),
.pos = pos,
.let = (ScirptExprLet) {
.subject = subject,
.value = value,
},
});
}
ScirptExpr* scirpt_parser_parse_return(ScirptParser* parser)
{
ScirptPosition pos = parser->current.pos;
step(parser);
ScirptExpr* value = NULL;
if (!done(parser) && parser->current.type != TT(Semicolon)) {
value = scirpt_parser_parse_expr(parser);
}
return alloc_expr((ScirptExpr) {
.type = AET(Return),
.pos = pos,
.return_statement = (ScirptExprReturn) {
.value = value,
},
});
}
ScirptExpr* scirpt_parser_parse_break(ScirptParser* parser)
{
ScirptPosition pos = parser->current.pos;
step(parser);
ScirptExpr* value = NULL;
if (!done(parser) && parser->current.type != TT(Semicolon)) {
value = scirpt_parser_parse_expr(parser);
}
return alloc_expr((ScirptExpr) {
.type = AET(Break),
.pos = pos,
.break_statement = (ScirptExprBreak) {
.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);
}