aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2025-08-25 00:49:29 -0400
committerBruce Hill <bruce@bruce-hill.com>2025-08-25 00:49:29 -0400
commit1f93e82303f19029394c3e1d2c375c23d56a6498 (patch)
tree3d7fa048d36cb903f2f9af5827c720a586125f26 /src
parentc6014873d83889e4bf598f6073c771480da20b7b (diff)
Split out function parsing.
Diffstat (limited to 'src')
-rw-r--r--src/parse/functions.c162
-rw-r--r--src/parse/functions.h10
-rw-r--r--src/parse/numbers.h2
-rw-r--r--src/parse/parse.c143
-rw-r--r--src/parse/parse.h4
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);