summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorZuhaitz <zuhaitz.zechhub@gmail.com>2026-01-13 14:50:43 +0000
committerGitHub <noreply@github.com>2026-01-13 14:50:43 +0000
commit7eb91d69beb19da7a7cb7ac84625f701890ce6eb (patch)
tree4b86f4ad20a66b0e984feb4d5a2abaf6eaa1227f /src
parent8fc9c88304fde65d6c3a619c3aee7e6e00540695 (diff)
parent856267f36e60211ba537d63a80c5d36aa4436a4f (diff)
Merge branch 'main' into pr-34-testing
Diffstat (limited to 'src')
-rw-r--r--src/ast/ast.h2
-rw-r--r--src/codegen/codegen.h2
-rw-r--r--src/codegen/codegen_decl.c9
-rw-r--r--src/codegen/codegen_main.c2
-rw-r--r--src/main.c4
-rw-r--r--src/parser/parser.h7
-rw-r--r--src/parser/parser_expr.c4
-rw-r--r--src/parser/parser_stmt.c54
-rw-r--r--src/parser/parser_utils.c32
-rw-r--r--src/utils/utils.c25
10 files changed, 114 insertions, 27 deletions
diff --git a/src/ast/ast.h b/src/ast/ast.h
index 8c5bff4..1e14369 100644
--- a/src/ast/ast.h
+++ b/src/ast/ast.h
@@ -416,6 +416,8 @@ struct ASTNode
struct
{
char *content;
+ char **used_symbols;
+ int used_symbol_count;
} raw_stmt;
struct
diff --git a/src/codegen/codegen.h b/src/codegen/codegen.h
index d489fb3..4b66f99 100644
--- a/src/codegen/codegen.h
+++ b/src/codegen/codegen.h
@@ -24,7 +24,7 @@ const char *parse_original_method_name(const char *mangled);
void emit_auto_type(ParserContext *ctx, ASTNode *init_expr, Token t, FILE *out);
// Declaration emission (codegen_decl.c).
-void emit_preamble(FILE *out);
+void emit_preamble(ParserContext *ctx, FILE *out);
void emit_includes_and_aliases(ASTNode *node, FILE *out);
void emit_struct_defs(ParserContext *ctx, ASTNode *node, FILE *out);
void emit_trait_defs(ASTNode *node, FILE *out);
diff --git a/src/codegen/codegen_decl.c b/src/codegen/codegen_decl.c
index ac4ae14..4979236 100644
--- a/src/codegen/codegen_decl.c
+++ b/src/codegen/codegen_decl.c
@@ -8,7 +8,7 @@
#include <string.h>
// Emit C preamble with standard includes and type definitions.
-void emit_preamble(FILE *out)
+void emit_preamble(ParserContext *ctx, FILE *out)
{
if (g_config.is_freestanding)
{
@@ -54,8 +54,11 @@ void emit_preamble(FILE *out)
fputs("#include <unistd.h>\n#include <fcntl.h>\n", out); // POSIX functions
fputs("#ifdef __TINYC__\n#define __auto_type __typeof__\n#endif\n", out);
fputs("typedef size_t usize;\ntypedef char* string;\n", out);
- fputs("#include <pthread.h>\n", out);
- fputs("typedef struct { pthread_t thread; void *result; } Async;\n", out);
+ if (ctx->has_async)
+ {
+ fputs("#include <pthread.h>\n", out);
+ fputs("typedef struct { pthread_t thread; void *result; } Async;\n", out);
+ }
fputs("typedef struct { void *func; void *ctx; } z_closure_T;\n", out);
fputs("#define U0 void\n#define I8 int8_t\n#define U8 uint8_t\n#define I16 "
"int16_t\n#define U16 uint16_t\n",
diff --git a/src/codegen/codegen_main.c b/src/codegen/codegen_main.c
index c9c69f6..3634af3 100644
--- a/src/codegen/codegen_main.c
+++ b/src/codegen/codegen_main.c
@@ -202,7 +202,7 @@ void codegen_node(ParserContext *ctx, ASTNode *node, FILE *out)
if (!ctx->skip_preamble)
{
- emit_preamble(out);
+ emit_preamble(ctx, out);
}
emit_includes_and_aliases(kids, out);
diff --git a/src/main.c b/src/main.c
index d0e1530..580b555 100644
--- a/src/main.c
+++ b/src/main.c
@@ -306,9 +306,9 @@ int main(int argc, char **argv)
// TCC-specific adjustments?
// Already handled by user passing --cc tcc
- snprintf(cmd, sizeof(cmd), "%s %s %s %s %s -o %s out.c -lm -lpthread -I./src %s", g_config.cc,
+ snprintf(cmd, sizeof(cmd), "%s %s %s %s %s -o %s out.c -lm %s -I./src %s", g_config.cc,
g_config.gcc_flags, g_cflags, g_config.is_freestanding ? "-ffreestanding" : "", "",
- outfile, g_link_flags);
+ outfile, g_parser_ctx->has_async ? "-lpthread" : "", g_link_flags);
if (g_config.verbose)
{
diff --git a/src/parser/parser.h b/src/parser/parser.h
index 4aeb2c8..9cdd0d2 100644
--- a/src/parser/parser.h
+++ b/src/parser/parser.h
@@ -265,6 +265,7 @@ struct ParserContext
FILE *hoist_out; // For plugins to hoist code to file scope
int skip_preamble; // If 1, codegen_node(NODE_ROOT) won't emit preamble
int is_repl; // REPL mode flag
+ int has_async; // Track if async features are used
};
// Token helpers
@@ -376,7 +377,7 @@ void init_builtins();
// Expression rewriting
char *rewrite_expr_methods(ParserContext *ctx, char *raw);
-char *process_fstring(ParserContext *ctx, const char *content);
+char *process_fstring(ParserContext *ctx, const char *content, char ***used_syms, int *count);
char *instantiate_function_template(ParserContext *ctx, const char *name,
const char *concrete_type);
FuncSig *find_func(ParserContext *ctx, const char *name);
@@ -408,8 +409,8 @@ ASTNode *parse_guard(ParserContext *ctx, Lexer *l);
ASTNode *parse_match(ParserContext *ctx, Lexer *l);
ASTNode *parse_return(ParserContext *ctx, Lexer *l);
-char *process_printf_sugar(ParserContext *ctx, const char *content, int newline,
- const char *target);
+char *process_printf_sugar(ParserContext *ctx, const char *content, int newline, const char *target,
+ char ***used_syms, int *count);
ASTNode *parse_assert(ParserContext *ctx, Lexer *l);
ASTNode *parse_defer(ParserContext *ctx, Lexer *l);
ASTNode *parse_asm(ParserContext *ctx, Lexer *l);
diff --git a/src/parser/parser_expr.c b/src/parser/parser_expr.c
index f7af80f..9861de6 100644
--- a/src/parser/parser_expr.c
+++ b/src/parser/parser_expr.c
@@ -2240,7 +2240,7 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec)
}
// Reuse printf sugar to generate the prompt print
- char *print_code = process_printf_sugar(ctx, inner, 0, "stdout");
+ char *print_code = process_printf_sugar(ctx, inner, 0, "stdout", NULL, NULL);
free(inner);
// Checks for (args...) suffix for SCAN mode
@@ -2405,7 +2405,7 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec)
newline = 0;
}
- char *code = process_printf_sugar(ctx, inner, newline, "stderr");
+ char *code = process_printf_sugar(ctx, inner, newline, "stderr", NULL, NULL);
free(inner);
ASTNode *n = ast_create(NODE_RAW_STMT);
diff --git a/src/parser/parser_stmt.c b/src/parser/parser_stmt.c
index 8a89cc7..484d742 100644
--- a/src/parser/parser_stmt.c
+++ b/src/parser/parser_stmt.c
@@ -37,6 +37,11 @@ ASTNode *parse_function(ParserContext *ctx, Lexer *l, int is_async)
Token name_tok = lexer_next(l);
char *name = token_strdup(name_tok);
+ if (is_async)
+ {
+ ctx->has_async = 1;
+ }
+
// Check for C reserved word conflict
if (is_c_reserved_word(name))
{
@@ -1668,7 +1673,8 @@ ASTNode *parse_for(ParserContext *ctx, Lexer *l)
return n;
}
-char *process_printf_sugar(ParserContext *ctx, const char *content, int newline, const char *target)
+char *process_printf_sugar(ParserContext *ctx, const char *content, int newline, const char *target,
+ char ***used_syms, int *count)
{
char *gen = xmalloc(8192);
strcpy(gen, "({ ");
@@ -1760,12 +1766,34 @@ char *process_printf_sugar(ParserContext *ctx, const char *content, int newline,
clean_expr++; // Skip leading spaces
}
- // Mark the variable as used (fixes "Unused variable" warnings for f-string
- // interpolation)
- Symbol *sym = find_symbol_entry(ctx, clean_expr);
- if (sym)
+ // Analyze usage
{
- sym->is_used = 1;
+ Lexer lex;
+ lexer_init(&lex, clean_expr);
+ Token t;
+ while ((t = lexer_next(&lex)).type != TOK_EOF)
+ {
+ if (t.type == TOK_IDENT)
+ {
+ char *name = token_strdup(t);
+ Symbol *sym = find_symbol_entry(ctx, name);
+ if (sym)
+ {
+ sym->is_used = 1;
+ }
+
+ if (used_syms && count)
+ {
+ *used_syms = xrealloc(*used_syms, sizeof(char *) * (*count + 1));
+ (*used_syms)[*count] = name;
+ (*count)++;
+ }
+ else
+ {
+ free(name);
+ }
+ }
+ }
}
char *type = find_symbol_type(ctx, clean_expr);
@@ -2092,7 +2120,9 @@ ASTNode *parse_statement(ParserContext *ctx, Lexer *l)
// ; means println (end of line), .. means print (continuation)
int is_ln = (next_type == TOK_SEMICOLON);
- char *code = process_printf_sugar(ctx, inner, is_ln, "stdout");
+ char **used_syms = NULL;
+ int used_count = 0;
+ char *code = process_printf_sugar(ctx, inner, is_ln, "stdout", &used_syms, &used_count);
if (next_type == TOK_SEMICOLON)
{
@@ -2109,6 +2139,8 @@ ASTNode *parse_statement(ParserContext *ctx, Lexer *l)
ASTNode *n = ast_create(NODE_RAW_STMT);
n->raw_stmt.content = code;
+ n->raw_stmt.used_symbols = used_syms;
+ n->raw_stmt.used_symbol_count = used_count;
free(inner);
return n;
}
@@ -2501,7 +2533,9 @@ ASTNode *parse_statement(ParserContext *ctx, Lexer *l)
inner[t.len - 2] = 0;
}
- char *code = process_printf_sugar(ctx, inner, is_ln, target);
+ char **used_syms = NULL;
+ int used_count = 0;
+ char *code = process_printf_sugar(ctx, inner, is_ln, target, &used_syms, &used_count);
free(inner);
if (lexer_peek(l).type == TOK_SEMICOLON)
@@ -2511,6 +2545,8 @@ ASTNode *parse_statement(ParserContext *ctx, Lexer *l)
ASTNode *n = ast_create(NODE_RAW_STMT);
n->raw_stmt.content = code;
+ n->raw_stmt.used_symbols = used_syms;
+ n->raw_stmt.used_symbol_count = used_count;
return n;
}
}
@@ -3876,7 +3912,7 @@ char *run_comptime_block(ParserContext *ctx, Lexer *l)
zpanic("Could not create temp file %s", filename);
}
- emit_preamble(f);
+ emit_preamble(ctx, f);
fprintf(
f,
"size_t _z_check_bounds(size_t index, size_t size) { if (index >= size) { fprintf(stderr, "
diff --git a/src/parser/parser_utils.c b/src/parser/parser_utils.c
index 7733ef7..ba506a0 100644
--- a/src/parser/parser_utils.c
+++ b/src/parser/parser_utils.c
@@ -1554,7 +1554,7 @@ char *instantiate_function_template(ParserContext *ctx, const char *name, const
return mangled;
}
-char *process_fstring(ParserContext *ctx, const char *content)
+char *process_fstring(ParserContext *ctx, const char *content, char ***used_syms, int *count)
{
(void)ctx; // suppress unused parameter warning
char *gen = xmalloc(4096);
@@ -1621,6 +1621,36 @@ char *process_fstring(ParserContext *ctx, const char *content)
fmt = colon + 1;
}
+ // Analyze usage in expression
+ {
+ Lexer lex;
+ lexer_init(&lex, expr);
+ Token t;
+ while ((t = lexer_next(&lex)).type != TOK_EOF)
+ {
+ if (t.type == TOK_IDENT)
+ {
+ char *name = token_strdup(t);
+ Symbol *sym = find_symbol_entry(ctx, name);
+ if (sym)
+ {
+ sym->is_used = 1;
+ }
+
+ if (used_syms && count)
+ {
+ *used_syms = xrealloc(*used_syms, sizeof(char *) * (*count + 1));
+ (*used_syms)[*count] = name;
+ (*count)++;
+ }
+ else
+ {
+ free(name);
+ }
+ }
+ }
+ }
+
if (fmt)
{
strcat(gen, "sprintf(_t, \"%");
diff --git a/src/utils/utils.c b/src/utils/utils.c
index 2645b49..19a722e 100644
--- a/src/utils/utils.c
+++ b/src/utils/utils.c
@@ -561,7 +561,10 @@ void scan_build_directives(ParserContext *ctx, const char *src)
if (0 == strncmp(line, "link:", 5))
{
char *val = line + 5;
- while (*val == ' ') val++;
+ while (*val == ' ')
+ {
+ val++;
+ }
if (strlen(g_link_flags) > 0)
{
strcat(g_link_flags, " ");
@@ -571,7 +574,10 @@ void scan_build_directives(ParserContext *ctx, const char *src)
else if (0 == strncmp(line, "cflags:", 7))
{
char *val = line + 7;
- while (*val == ' ') val++;
+ while (*val == ' ')
+ {
+ val++;
+ }
if (strlen(g_cflags) > 0)
{
strcat(g_cflags, " ");
@@ -581,7 +587,10 @@ void scan_build_directives(ParserContext *ctx, const char *src)
else if (0 == strncmp(line, "include:", 8))
{
char *val = line + 8;
- while (*val == ' ') val++;
+ while (*val == ' ')
+ {
+ val++;
+ }
char flags[2048];
sprintf(flags, "-I%s", val);
if (strlen(g_cflags) > 0)
@@ -593,7 +602,10 @@ void scan_build_directives(ParserContext *ctx, const char *src)
else if (strncmp(line, "lib:", 4) == 0)
{
char *val = line + 4;
- while (*val == ' ') val++;
+ while (*val == ' ')
+ {
+ val++;
+ }
char flags[2048];
sprintf(flags, "-L%s", val);
if (strlen(g_link_flags) > 0)
@@ -605,7 +617,10 @@ void scan_build_directives(ParserContext *ctx, const char *src)
else if (strncmp(line, "define:", 7) == 0)
{
char *val = line + 7;
- while (*val == ' ') val++;
+ while (*val == ' ')
+ {
+ val++;
+ }
char flags[2048];
sprintf(flags, "-D%s", val);
if (strlen(g_cflags) > 0)