1158 lines
30 KiB
C
1158 lines
30 KiB
C
#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 <stddef.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#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);
|
|
}
|