aboutsummaryrefslogtreecommitdiff
path: root/src/parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/parser.c')
-rw-r--r--src/parser.c204
1 files changed, 168 insertions, 36 deletions
diff --git a/src/parser.c b/src/parser.c
index 3f9c030..1324305 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -6,26 +6,27 @@ typedef struct {
} TslParser;
static int tsl_parser_parse_rhs(TslParser *self);
+static int tsl_parser_parse_expressions(TslParser *self, TslToken end_token);
static void tsl_parser_init(TslParser *self, const char *code, size_t code_size) {
tsl_tokenizer_init(&self->tokenizer, code, code_size);
}
static int tsl_parser_parse_map(TslParser *self) {
-#define parse_map_element_separator \
- if(!tsl_tokenizer_accept(&self->tokenizer, TSL_TOKEN_COLON)) \
- return -1; \
- if(tsl_parser_parse_rhs(self) != 0) \
- return -1; \
- token = tsl_tokenizer_next(&self->tokenizer); \
- if(token == TSL_TOKEN_COMMA) { \
- continue; \
- } else if(token == TSL_TOKEN_RBRACE) { \
- return 0; \
- } else { \
- fprintf(stderr, "Error: Expected ',' or '}', got TODO\n"); \
- return -1; \
- }
+ #define parse_map_element_separator \
+ if(!tsl_tokenizer_accept(&self->tokenizer, TSL_TOKEN_COLON)) \
+ return -1; \
+ if(tsl_parser_parse_rhs(self) != 0) \
+ return -1; \
+ token = tsl_tokenizer_next(&self->tokenizer); \
+ if(token == TSL_TOKEN_COMMA) { \
+ continue; \
+ } else if(token == TSL_TOKEN_RBRACE) { \
+ return 0; \
+ } else { \
+ fprintf(stderr, "Error: Expected ',' or '}', got TODO\n"); \
+ return -1; \
+ }
for(;;) {
TslToken token = tsl_tokenizer_next(&self->tokenizer);
@@ -54,18 +55,19 @@ static int tsl_parser_parse_map(TslParser *self) {
}
static int tsl_parser_parse_list(TslParser *self) {
-#define parse_list_element_separator \
- token = tsl_tokenizer_next(&self->tokenizer); \
- if(token == TSL_TOKEN_COMMA) { \
- continue; \
- } else if(token == TSL_TOKEN_RBRACKET) { \
- return 0; \
- } else { \
- fprintf(stderr, "Error: Expected ',' or ']', got TODO\n"); \
- return -1; \
- }
+ #define parse_list_element_separator \
+ token = tsl_tokenizer_next(&self->tokenizer); \
+ if(token == TSL_TOKEN_COMMA) { \
+ continue; \
+ } else if(token == TSL_TOKEN_RBRACKET) { \
+ return 0; \
+ } else { \
+ fprintf(stderr, "Error: Expected ',' or ']', got TODO\n"); \
+ return -1; \
+ }
for(;;) {
+ /* TODO: Use tsl_parser_parse_rhs instead */
TslToken token = tsl_tokenizer_next(&self->tokenizer);
if(token == TSL_TOKEN_NUM) {
printf("rhs num: %ld\n", self->tokenizer.number_value);
@@ -89,9 +91,128 @@ static int tsl_parser_parse_list(TslParser *self) {
}
}
+/* FN_BODY = '{' EXPRS '}' */
+static int tsl_parser_parse_fn_body(TslParser *self) {
+ if(!tsl_tokenizer_accept(&self->tokenizer, TSL_TOKEN_LBRACE))
+ return -1;
+ return tsl_parser_parse_expressions(self, TSL_TOKEN_RBRACE);
+}
+
+/* FN = '(' (IDENTIFIER ',')* ')' FN_BODY */
+static int tsl_parser_parse_fn(TslParser *self) {
+ if(!tsl_tokenizer_accept(&self->tokenizer, TSL_TOKEN_LPAREN))
+ return -1;
+
+ for(;;) {
+ TslToken token = tsl_tokenizer_next(&self->tokenizer);
+ if(token == TSL_TOKEN_RPAREN) {
+ return tsl_parser_parse_fn_body(self);
+ } else if(token == TSL_TOKEN_IDENTIFIER) {
+ TslStringView param_name = self->tokenizer.identifier;
+ token = tsl_tokenizer_next(&self->tokenizer);
+ if(token == TSL_TOKEN_COMMA) {
+ continue;
+ } else if(token == TSL_TOKEN_RPAREN) {
+ return tsl_parser_parse_fn_body(self);
+ } else {
+ fprintf(stderr, "Error: Expected ',' or ')', got TODO\n");
+ return -1;
+ }
+ } else {
+ fprintf(stderr, "Error: Expected parameter name or ')', got TODO\n");
+ return -1;
+ }
+ }
+}
+
+/* VAR_INDEX = '[' RHS ']' */
+static int tsl_parser_parse_var_indexing(TslParser *self) {
+ if(!tsl_tokenizer_accept(&self->tokenizer, TSL_TOKEN_LBRACKET))
+ return -1;
+
+ if(tsl_parser_parse_rhs(self) != 0)
+ return -1;
+
+ if(tsl_tokenizer_accept(&self->tokenizer, TSL_TOKEN_RBRACKET))
+ return 0;
+ else
+ return -1;
+}
+
+/* FUNC_CALL = '(' (RHS ',')* ')' */
+static int tsl_parser_parse_func_call(TslParser *self) {
+ if(!tsl_tokenizer_accept(&self->tokenizer, TSL_TOKEN_LPAREN))
+ return -1;
+
+ for(;;) {
+ TslToken token = tsl_tokenizer_peek(&self->tokenizer);
+ if(token == TSL_TOKEN_RPAREN) {
+ tsl_tokenizer_next(&self->tokenizer); /* consume previous TSL_TOKEN_RPAREN */
+ return 0;
+ } else {
+ if(tsl_parser_parse_rhs(self) != 0)
+ return -1;
+ token = tsl_tokenizer_next(&self->tokenizer);
+ if(token == TSL_TOKEN_COMMA) {
+ continue;
+ } else if(token == TSL_TOKEN_RPAREN) {
+ return 0;
+ } else {
+ fprintf(stderr, "Error: Expected ',' or ')', got TODO\n");
+ return -1;
+ }
+ }
+ }
+}
+
+/* TODO: Do not allow empty command */
+/* TODO: Allow command inside another command */
+/* COMMAND = TODO */
+static int tsl_parser_parse_command(TslParser *self) {
+ if(!tsl_tokenizer_accept(&self->tokenizer, TSL_TOKEN_LPAREN))
+ return -1;
+
+ for(;;) {
+ TslStringView command_arg;
+ TslCommandToken command_token = tsl_tokenizer_next_command_arg(&self->tokenizer, &command_arg);
+ if(command_token == TSL_COMMAND_TOKEN_ARG) {
+ printf("command arg: |%.*s|\n", (int)command_arg.size, command_arg.data);
+ } else if(command_token == TSL_COMMAND_TOKEN_END) {
+ return 0;
+ } else {
+ fprintf(stderr, "Error: Expected command argument or ')', got TODO\n");
+ return -1;
+ }
+ }
+}
+
+/* RHS_SUB = VAR_INDEX|FUNC_CALL RHS_SUB? */
+static int tsl_parser_parse_rhs_sub(TslParser *self) {
+ TslToken token = tsl_tokenizer_peek(&self->tokenizer);
+ if(token == TSL_TOKEN_LBRACKET) {
+ if(tsl_parser_parse_var_indexing(self) != 0)
+ return -1;
+ return tsl_parser_parse_rhs_sub(self);
+ } else if(token == TSL_TOKEN_LPAREN) {
+ if(tsl_parser_parse_func_call(self) != 0)
+ return -1;
+ return tsl_parser_parse_rhs_sub(self);
+ }
+ /*
+ No sub expression found, possibly a new expression after this (a new expression on a new line), let that
+ part of the code handle error if there is any instead.
+ */
+ return 0;
+}
+
+/* RHS = (IDENTIFIER|NUM|BOOL|NULL|STRING|MAP|LIST|('fn' FN)|('$' COMMAND)) RHS_SUB? */
int tsl_parser_parse_rhs(TslParser *self) {
TslToken token = tsl_tokenizer_next(&self->tokenizer);
- if(token == TSL_TOKEN_NUM) {
+ if(token == TSL_TOKEN_IDENTIFIER) {
+ TslStringView var_name = self->tokenizer.identifier;
+ printf("var: %.*s\n", (int)var_name.size, var_name.data);
+ return tsl_parser_parse_rhs_sub(self);
+ } else if(token == TSL_TOKEN_NUM) {
printf("rhs num: %ld\n", self->tokenizer.number_value);
} else if(token == TSL_TOKEN_BOOL) {
printf("rhs bool: %s\n", self->tokenizer.bool_value ? "true" : "false");
@@ -100,29 +221,39 @@ int tsl_parser_parse_rhs(TslParser *self) {
} else if(token == TSL_TOKEN_STRING) {
printf("rhs string: |%.*s|\n", self->tokenizer.string.size, self->tokenizer.string.data);
} else if(token == TSL_TOKEN_LBRACE) {
- tsl_parser_parse_map(self);
+ return tsl_parser_parse_map(self);
} else if(token == TSL_TOKEN_LBRACKET) {
- tsl_parser_parse_list(self);
+ return tsl_parser_parse_list(self);
+ } else if(token == TSL_TOKEN_FN) {
+ return tsl_parser_parse_fn(self);
+ } else if(token == TSL_TOKEN_DOLLAR_SIGN) {
+ return tsl_parser_parse_command(self);
} else {
- fprintf(stderr, "Error: Expected number, bool or null, got TODO\n");
+ fprintf(stderr, "Error: Expected variable, number, bool, null, map, list, function or command, got TODO (%d) (line: %d)\n", token, tsl_tokenizer_get_line_by_index(&self->tokenizer, self->tokenizer.prev_code_index));
return -1;
}
return 0;
}
-static int tsl_parser_parse(TslParser *self) {
+/*
+ EXPR = IDENTIFIER ('=' RHS)|RHS_SUB
+ EXPRS = EXPR*
+*/
+int tsl_parser_parse_expressions(TslParser *self, TslToken end_token) {
for(;;) {
TslToken token = tsl_tokenizer_next(&self->tokenizer);
if(token == TSL_TOKEN_IDENTIFIER) {
TslStringView identifier = self->tokenizer.identifier;
printf("identifier: %.*s\n", identifier.size, identifier.data);
- if(!tsl_tokenizer_accept(&self->tokenizer, TSL_TOKEN_EQUAL)) {
- return -1;
- }
- if(tsl_parser_parse_rhs(self) != 0) {
- return -1;
+ if(tsl_tokenizer_peek(&self->tokenizer) == TSL_TOKEN_EQUAL) {
+ tsl_tokenizer_next(&self->tokenizer); /* consume previous TSL_TOKEN_EQUAL */
+ if(tsl_parser_parse_rhs(self) != 0)
+ return -1;
+ } else {
+ if(tsl_parser_parse_rhs_sub(self) != 0)
+ return -1;
}
- } else if(token == TSL_TOKEN_END_OF_FILE) {
+ } else if(token == end_token) {
break;
} else {
fprintf(stderr, "Error: Expected identifier, got TODO\n");
@@ -132,8 +263,9 @@ static int tsl_parser_parse(TslParser *self) {
return 0;
}
+/* EXPRS */
int tsl_parse(const char *code, size_t code_size) {
TslParser parser;
tsl_parser_init(&parser, code, code_size);
- return tsl_parser_parse(&parser);
+ return tsl_parser_parse_expressions(&parser, TSL_TOKEN_END_OF_FILE);
}