#include "../include/parser.h" #include "../include/bytecode.h" #include typedef struct { TslTokenizer tokenizer; TslBytecodeWriter bytecode_writer; } 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); tsl_bytecode_writer_init(&self->bytecode_writer); } 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; \ } for(;;) { TslToken token = tsl_tokenizer_next(&self->tokenizer); if(token == TSL_TOKEN_NUM) { printf("rhs num: %ld\n", self->tokenizer.number_value); parse_map_element_separator } else if(token == TSL_TOKEN_BOOL) { printf("rhs bool: %s\n", self->tokenizer.bool_value ? "true" : "false"); parse_map_element_separator } else if(token == TSL_TOKEN_NULL) { printf("rhs null\n"); parse_map_element_separator } else if(token == TSL_TOKEN_STRING) { printf("rhs string: |%.*s|\n", self->tokenizer.string.size, self->tokenizer.string.data); parse_map_element_separator } else if(token == TSL_TOKEN_RBRACE) { /* '}' after trailing ',' or an empty map */ return 0; } else { fprintf(stderr, "Error: Expected '}', got TODO\n"); return -1; } token = tsl_tokenizer_next(&self->tokenizer); } } 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; \ } 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); parse_list_element_separator } else if(token == TSL_TOKEN_BOOL) { printf("rhs bool: %s\n", self->tokenizer.bool_value ? "true" : "false"); parse_list_element_separator } else if(token == TSL_TOKEN_NULL) { printf("rhs null\n"); parse_list_element_separator } else if(token == TSL_TOKEN_STRING) { printf("rhs string: |%.*s|\n", self->tokenizer.string.size, self->tokenizer.string.data); parse_list_element_separator } else if(token == TSL_TOKEN_RBRACKET) { /* ']' after trailing ',' or an empty list */ return 0; } else { fprintf(stderr, "Error: Expected '}', got TODO\n"); return -1; } } } /* 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_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"); } else if(token == TSL_TOKEN_NULL) { printf("rhs null\n"); } 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) { return tsl_parser_parse_map(self); } else if(token == TSL_TOKEN_LBRACKET) { 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 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; } /* 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_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 == end_token) { break; } else { fprintf(stderr, "Error: Expected identifier, got TODO\n"); return -1; } } return 0; } int tsl_parse(const char *code, size_t code_size) { TslParser parser; tsl_parser_init(&parser, code, code_size); return tsl_parser_parse_expressions(&parser, TSL_TOKEN_END_OF_FILE); }