diff options
Diffstat (limited to 'src/parser.c')
-rw-r--r-- | src/parser.c | 204 |
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); } |