diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2025-08-25 00:49:29 -0400 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2025-08-25 00:49:29 -0400 |
| commit | 1f93e82303f19029394c3e1d2c375c23d56a6498 (patch) | |
| tree | 3d7fa048d36cb903f2f9af5827c720a586125f26 /src | |
| parent | c6014873d83889e4bf598f6073c771480da20b7b (diff) | |
Split out function parsing.
Diffstat (limited to 'src')
| -rw-r--r-- | src/parse/functions.c | 162 | ||||
| -rw-r--r-- | src/parse/functions.h | 10 | ||||
| -rw-r--r-- | src/parse/numbers.h | 2 | ||||
| -rw-r--r-- | src/parse/parse.c | 143 | ||||
| -rw-r--r-- | src/parse/parse.h | 4 |
5 files changed, 173 insertions, 148 deletions
diff --git a/src/parse/functions.c b/src/parse/functions.c new file mode 100644 index 00000000..69c695fd --- /dev/null +++ b/src/parse/functions.c @@ -0,0 +1,162 @@ +// Logic for parsing functions + +#include <gc.h> +#include <stdarg.h> +#include <stdbool.h> +#include <string.h> + +#include <unictype.h> +#include <uniname.h> + +#include "../ast.h" +#include "../stdlib/util.h" +#include "context.h" +#include "errors.h" +#include "functions.h" +#include "parse.h" +#include "utils.h" + +public +arg_ast_t *parse_args(parse_ctx_t *ctx, const char **pos) { + arg_ast_t *args = NULL; + for (;;) { + const char *batch_start = *pos; + ast_t *default_val = NULL; + type_ast_t *type = NULL; + + typedef struct name_list_s { + const char *name; + struct name_list_s *next; + } name_list_t; + + name_list_t *names = NULL; + for (;;) { + whitespace(pos); + const char *name = get_id(pos); + if (!name) break; + whitespace(pos); + + if (match(pos, ":")) { + type = expect(ctx, *pos - 1, pos, parse_type, "I expected a type here"); + names = new (name_list_t, .name = name, .next = names); + whitespace(pos); + if (match(pos, "=")) + default_val = expect(ctx, *pos - 1, pos, parse_term, "I expected a value after this '='"); + break; + } else if (strncmp(*pos, "==", 2) != 0 && match(pos, "=")) { + default_val = expect(ctx, *pos - 1, pos, parse_term, "I expected a value after this '='"); + names = new (name_list_t, .name = name, .next = names); + break; + } else if (name) { + names = new (name_list_t, .name = name, .next = names); + spaces(pos); + if (!match(pos, ",")) break; + } else { + break; + } + } + if (!names) break; + if (!default_val && !type) + parser_err(ctx, batch_start, *pos, + "I expected a ':' and type, or '=' and a default value after this parameter (", names->name, + ")"); + + REVERSE_LIST(names); + for (; names; names = names->next) + args = new (arg_ast_t, .name = names->name, .type = type, .value = default_val, .next = args); + + if (!match_separator(pos)) break; + } + + REVERSE_LIST(args); + return args; +} + +public +ast_t *parse_func_def(parse_ctx_t *ctx, const char *pos) { + const char *start = pos; + if (!match_word(&pos, "func")) return NULL; + + ast_t *name = optional(ctx, &pos, parse_var); + if (!name) return NULL; + + spaces(&pos); + + expect_str(ctx, start, &pos, "(", "I expected a parenthesis for this function's arguments"); + + arg_ast_t *args = parse_args(ctx, &pos); + spaces(&pos); + type_ast_t *ret_type = match(&pos, "->") ? optional(ctx, &pos, parse_type) : NULL; + whitespace(&pos); + bool is_inline = false; + ast_t *cache_ast = NULL; + for (bool specials = match(&pos, ";"); specials; specials = match_separator(&pos)) { + const char *flag_start = pos; + if (match_word(&pos, "inline")) { + is_inline = true; + } else if (match_word(&pos, "cached")) { + if (!cache_ast) cache_ast = NewAST(ctx->file, pos, pos, Int, .str = "-1"); + } else if (match_word(&pos, "cache_size")) { + whitespace(&pos); + if (!match(&pos, "=")) parser_err(ctx, flag_start, pos, "I expected a value for 'cache_size'"); + whitespace(&pos); + cache_ast = expect(ctx, start, &pos, parse_expr, "I expected a maximum size for the cache"); + } + } + expect_closing(ctx, &pos, ")", "I wasn't able to parse the rest of this function definition"); + + ast_t *body = expect(ctx, start, &pos, parse_block, "This function needs a body block"); + return NewAST(ctx->file, start, pos, FunctionDef, .name = name, .args = args, .ret_type = ret_type, .body = body, + .cache = cache_ast, .is_inline = is_inline); +} + +ast_t *parse_convert_def(parse_ctx_t *ctx, const char *pos) { + const char *start = pos; + if (!match_word(&pos, "convert")) return NULL; + + spaces(&pos); + + if (!match(&pos, "(")) return NULL; + + arg_ast_t *args = parse_args(ctx, &pos); + spaces(&pos); + type_ast_t *ret_type = match(&pos, "->") ? optional(ctx, &pos, parse_type) : NULL; + whitespace(&pos); + bool is_inline = false; + ast_t *cache_ast = NULL; + for (bool specials = match(&pos, ";"); specials; specials = match_separator(&pos)) { + const char *flag_start = pos; + if (match_word(&pos, "inline")) { + is_inline = true; + } else if (match_word(&pos, "cached")) { + if (!cache_ast) cache_ast = NewAST(ctx->file, pos, pos, Int, .str = "-1"); + } else if (match_word(&pos, "cache_size")) { + whitespace(&pos); + if (!match(&pos, "=")) parser_err(ctx, flag_start, pos, "I expected a value for 'cache_size'"); + whitespace(&pos); + cache_ast = expect(ctx, start, &pos, parse_expr, "I expected a maximum size for the cache"); + } + } + expect_closing(ctx, &pos, ")", "I wasn't able to parse the rest of this function definition"); + + ast_t *body = expect(ctx, start, &pos, parse_block, "This function needs a body block"); + return NewAST(ctx->file, start, pos, ConvertDef, .args = args, .ret_type = ret_type, .body = body, + .cache = cache_ast, .is_inline = is_inline); +} + +public +ast_t *parse_lambda(parse_ctx_t *ctx, const char *pos) { + const char *start = pos; + if (!match_word(&pos, "func")) return NULL; + spaces(&pos); + if (!match(&pos, "(")) return NULL; + arg_ast_t *args = parse_args(ctx, &pos); + spaces(&pos); + type_ast_t *ret = match(&pos, "->") ? optional(ctx, &pos, parse_type) : NULL; + spaces(&pos); + expect_closing(ctx, &pos, ")", "I was expecting a ')' to finish this anonymous function's arguments"); + ast_t *body = optional(ctx, &pos, parse_block); + if (!body) body = NewAST(ctx->file, pos, pos, Block, .statements = NULL); + return NewAST(ctx->file, start, pos, Lambda, .id = ctx->next_lambda_id++, .args = args, .ret_type = ret, + .body = body); +} diff --git a/src/parse/functions.h b/src/parse/functions.h new file mode 100644 index 00000000..24dbe952 --- /dev/null +++ b/src/parse/functions.h @@ -0,0 +1,10 @@ +// Logic for parsing functions +#pragma once + +#include "../ast.h" +#include "context.h" + +arg_ast_t *parse_args(parse_ctx_t *ctx, const char **pos); +ast_t *parse_lambda(parse_ctx_t *ctx, const char *pos); +ast_t *parse_func_def(parse_ctx_t *ctx, const char *pos); +ast_t *parse_convert_def(parse_ctx_t *ctx, const char *pos); diff --git a/src/parse/numbers.h b/src/parse/numbers.h index 89f5e28b..7ef2c4f6 100644 --- a/src/parse/numbers.h +++ b/src/parse/numbers.h @@ -1,8 +1,6 @@ // Logic for parsing numbers #pragma once -// Parsing logic - #include "../ast.h" #include "context.h" diff --git a/src/parse/parse.c b/src/parse/parse.c index 53365ee7..a3f30c64 100644 --- a/src/parse/parse.c +++ b/src/parse/parse.c @@ -16,6 +16,7 @@ #include "context.h" #include "errors.h" #include "files.h" +#include "functions.h" #include "numbers.h" #include "parse.h" #include "utils.h" @@ -880,22 +881,6 @@ ast_t *parse_return(parse_ctx_t *ctx, const char *pos) { return ret; } -ast_t *parse_lambda(parse_ctx_t *ctx, const char *pos) { - const char *start = pos; - if (!match_word(&pos, "func")) return NULL; - spaces(&pos); - if (!match(&pos, "(")) return NULL; - arg_ast_t *args = parse_args(ctx, &pos); - spaces(&pos); - type_ast_t *ret = match(&pos, "->") ? optional(ctx, &pos, parse_type) : NULL; - spaces(&pos); - expect_closing(ctx, &pos, ")", "I was expecting a ')' to finish this anonymous function's arguments"); - ast_t *body = optional(ctx, &pos, parse_block); - if (!body) body = NewAST(ctx->file, pos, pos, Block, .statements = NULL); - return NewAST(ctx->file, start, pos, Lambda, .id = ctx->next_lambda_id++, .args = args, .ret_type = ret, - .body = body); -} - ast_t *parse_none(parse_ctx_t *ctx, const char *pos) { const char *start = pos; if (!match_word(&pos, "none")) return NULL; @@ -1499,132 +1484,6 @@ ast_t *parse_extend(parse_ctx_t *ctx, const char *pos) { return NewAST(ctx->file, start, pos, Extend, .name = name, .body = body); } -arg_ast_t *parse_args(parse_ctx_t *ctx, const char **pos) { - arg_ast_t *args = NULL; - for (;;) { - const char *batch_start = *pos; - ast_t *default_val = NULL; - type_ast_t *type = NULL; - - typedef struct name_list_s { - const char *name; - struct name_list_s *next; - } name_list_t; - - name_list_t *names = NULL; - for (;;) { - whitespace(pos); - const char *name = get_id(pos); - if (!name) break; - whitespace(pos); - - if (match(pos, ":")) { - type = expect(ctx, *pos - 1, pos, parse_type, "I expected a type here"); - names = new (name_list_t, .name = name, .next = names); - whitespace(pos); - if (match(pos, "=")) - default_val = expect(ctx, *pos - 1, pos, parse_term, "I expected a value after this '='"); - break; - } else if (strncmp(*pos, "==", 2) != 0 && match(pos, "=")) { - default_val = expect(ctx, *pos - 1, pos, parse_term, "I expected a value after this '='"); - names = new (name_list_t, .name = name, .next = names); - break; - } else if (name) { - names = new (name_list_t, .name = name, .next = names); - spaces(pos); - if (!match(pos, ",")) break; - } else { - break; - } - } - if (!names) break; - if (!default_val && !type) - parser_err(ctx, batch_start, *pos, - "I expected a ':' and type, or '=' and a default value after this parameter (", names->name, - ")"); - - REVERSE_LIST(names); - for (; names; names = names->next) - args = new (arg_ast_t, .name = names->name, .type = type, .value = default_val, .next = args); - - if (!match_separator(pos)) break; - } - - REVERSE_LIST(args); - return args; -} - -ast_t *parse_func_def(parse_ctx_t *ctx, const char *pos) { - const char *start = pos; - if (!match_word(&pos, "func")) return NULL; - - ast_t *name = optional(ctx, &pos, parse_var); - if (!name) return NULL; - - spaces(&pos); - - expect_str(ctx, start, &pos, "(", "I expected a parenthesis for this function's arguments"); - - arg_ast_t *args = parse_args(ctx, &pos); - spaces(&pos); - type_ast_t *ret_type = match(&pos, "->") ? optional(ctx, &pos, parse_type) : NULL; - whitespace(&pos); - bool is_inline = false; - ast_t *cache_ast = NULL; - for (bool specials = match(&pos, ";"); specials; specials = match_separator(&pos)) { - const char *flag_start = pos; - if (match_word(&pos, "inline")) { - is_inline = true; - } else if (match_word(&pos, "cached")) { - if (!cache_ast) cache_ast = NewAST(ctx->file, pos, pos, Int, .str = "-1"); - } else if (match_word(&pos, "cache_size")) { - whitespace(&pos); - if (!match(&pos, "=")) parser_err(ctx, flag_start, pos, "I expected a value for 'cache_size'"); - whitespace(&pos); - cache_ast = expect(ctx, start, &pos, parse_expr, "I expected a maximum size for the cache"); - } - } - expect_closing(ctx, &pos, ")", "I wasn't able to parse the rest of this function definition"); - - ast_t *body = expect(ctx, start, &pos, parse_block, "This function needs a body block"); - return NewAST(ctx->file, start, pos, FunctionDef, .name = name, .args = args, .ret_type = ret_type, .body = body, - .cache = cache_ast, .is_inline = is_inline); -} - -ast_t *parse_convert_def(parse_ctx_t *ctx, const char *pos) { - const char *start = pos; - if (!match_word(&pos, "convert")) return NULL; - - spaces(&pos); - - if (!match(&pos, "(")) return NULL; - - arg_ast_t *args = parse_args(ctx, &pos); - spaces(&pos); - type_ast_t *ret_type = match(&pos, "->") ? optional(ctx, &pos, parse_type) : NULL; - whitespace(&pos); - bool is_inline = false; - ast_t *cache_ast = NULL; - for (bool specials = match(&pos, ";"); specials; specials = match_separator(&pos)) { - const char *flag_start = pos; - if (match_word(&pos, "inline")) { - is_inline = true; - } else if (match_word(&pos, "cached")) { - if (!cache_ast) cache_ast = NewAST(ctx->file, pos, pos, Int, .str = "-1"); - } else if (match_word(&pos, "cache_size")) { - whitespace(&pos); - if (!match(&pos, "=")) parser_err(ctx, flag_start, pos, "I expected a value for 'cache_size'"); - whitespace(&pos); - cache_ast = expect(ctx, start, &pos, parse_expr, "I expected a maximum size for the cache"); - } - } - expect_closing(ctx, &pos, ")", "I wasn't able to parse the rest of this function definition"); - - ast_t *body = expect(ctx, start, &pos, parse_block, "This function needs a body block"); - return NewAST(ctx->file, start, pos, ConvertDef, .args = args, .ret_type = ret_type, .body = body, - .cache = cache_ast, .is_inline = is_inline); -} - ast_t *parse_extern(parse_ctx_t *ctx, const char *pos) { const char *start = pos; if (!match_word(&pos, "extern")) return NULL; diff --git a/src/parse/parse.h b/src/parse/parse.h index fed78032..ece99ea9 100644 --- a/src/parse/parse.h +++ b/src/parse/parse.h @@ -17,7 +17,6 @@ ast_t *parse_method_call_suffix(parse_ctx_t *ctx, ast_t *self); ast_t *parse_non_optional_suffix(parse_ctx_t *ctx, ast_t *lhs); ast_t *parse_optional_conditional_suffix(parse_ctx_t *ctx, ast_t *stmt); ast_t *parse_optional_suffix(parse_ctx_t *ctx, ast_t *lhs); -arg_ast_t *parse_args(parse_ctx_t *ctx, const char **pos); type_ast_t *parse_list_type(parse_ctx_t *ctx, const char *pos); type_ast_t *parse_func_type(parse_ctx_t *ctx, const char *pos); type_ast_t *parse_non_optional_type(parse_ctx_t *ctx, const char *pos); @@ -30,7 +29,6 @@ ast_t *parse_list(parse_ctx_t *ctx, const char *pos); ast_t *parse_assignment(parse_ctx_t *ctx, const char *pos); ast_t *parse_block(parse_ctx_t *ctx, const char *pos); ast_t *parse_bool(parse_ctx_t *ctx, const char *pos); -ast_t *parse_convert_def(parse_ctx_t *ctx, const char *pos); ast_t *parse_declaration(parse_ctx_t *ctx, const char *pos); ast_t *parse_defer(parse_ctx_t *ctx, const char *pos); ast_t *parse_do(parse_ctx_t *ctx, const char *pos); @@ -41,11 +39,9 @@ ast_t *parse_expr(parse_ctx_t *ctx, const char *pos); ast_t *parse_extended_expr(parse_ctx_t *ctx, const char *pos); ast_t *parse_extern(parse_ctx_t *ctx, const char *pos); ast_t *parse_for(parse_ctx_t *ctx, const char *pos); -ast_t *parse_func_def(parse_ctx_t *ctx, const char *pos); ast_t *parse_heap_alloc(parse_ctx_t *ctx, const char *pos); ast_t *parse_if(parse_ctx_t *ctx, const char *pos); ast_t *parse_inline_c(parse_ctx_t *ctx, const char *pos); -ast_t *parse_lambda(parse_ctx_t *ctx, const char *pos); ast_t *parse_lang_def(parse_ctx_t *ctx, const char *pos); ast_t *parse_extend(parse_ctx_t *ctx, const char *pos); ast_t *parse_namespace(parse_ctx_t *ctx, const char *pos); |
