summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian>2026-01-28 01:19:20 +0000
committerZuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian>2026-01-28 01:19:20 +0000
commitda12345b6e3c297e530764c4424b7d9e6a1cb65e (patch)
treeb2cf2dda80c80c10425fee60fc31e17bc1de48b3
parent6a28507b59c4a5b89562962817b45e517f442cd4 (diff)
Fix for #141
-rw-r--r--src/codegen/codegen_stmt.c11
-rw-r--r--src/lexer/token.c8
-rw-r--r--src/parser/parser_core.c2
-rw-r--r--src/parser/parser_expr.c37
-rw-r--r--src/parser/parser_stmt.c6
-rw-r--r--tests/features/test_implicit_fstring.zc19
-rw-r--r--tests/features/test_traits_suite.zc2
7 files changed, 72 insertions, 13 deletions
diff --git a/src/codegen/codegen_stmt.c b/src/codegen/codegen_stmt.c
index 70fb297..2f9a2ba 100644
--- a/src/codegen/codegen_stmt.c
+++ b/src/codegen/codegen_stmt.c
@@ -884,8 +884,7 @@ void codegen_node_single(ParserContext *ctx, ASTNode *node, FILE *out)
}
else
{
- fprintf(out, " ZC_AUTO %s = _tmp_%d.%s;\n", node->destruct.names[0], id,
- check);
+ fprintf(out, " ZC_AUTO %s = _tmp_%d.%s;\n", node->destruct.names[0], id, check);
}
}
else
@@ -903,8 +902,8 @@ void codegen_node_single(ParserContext *ctx, ASTNode *node, FILE *out)
}
else
{
- fprintf(out, " ZC_AUTO %s = _tmp_%d.%s;\n", node->destruct.names[i],
- id, field);
+ fprintf(out, " ZC_AUTO %s = _tmp_%d.%s;\n", node->destruct.names[i], id,
+ field);
}
}
else
@@ -916,8 +915,8 @@ void codegen_node_single(ParserContext *ctx, ASTNode *node, FILE *out)
}
else
{
- fprintf(out, " ZC_AUTO %s = _tmp_%d.v%d;\n", node->destruct.names[i],
- id, i);
+ fprintf(out, " ZC_AUTO %s = _tmp_%d.v%d;\n", node->destruct.names[i], id,
+ i);
}
}
}
diff --git a/src/lexer/token.c b/src/lexer/token.c
index decabbe..6696a5c 100644
--- a/src/lexer/token.c
+++ b/src/lexer/token.c
@@ -149,6 +149,14 @@ Token lexer_next(Lexer *l)
{
return (Token){TOK_DEF, s, 3, start_line, start_col};
}
+ if (len == 5 && strncmp(s, "trait", 5) == 0)
+ {
+ return (Token){TOK_TRAIT, s, 5, start_line, start_col};
+ }
+ if (len == 4 && strncmp(s, "impl", 4) == 0)
+ {
+ return (Token){TOK_IMPL, s, 4, start_line, start_col};
+ }
if (len == 8 && strncmp(s, "autofree", 8) == 0)
{
return (Token){TOK_AUTOFREE, s, 8, start_line, start_col};
diff --git a/src/parser/parser_core.c b/src/parser/parser_core.c
index e9a418e..ba6f2fe 100644
--- a/src/parser/parser_core.c
+++ b/src/parser/parser_core.c
@@ -700,7 +700,7 @@ static ASTNode *generate_derive_impls(ParserContext *ctx, ASTNode *strct, char *
{
// Simplistic Debug for now, I know.
code = xmalloc(1024);
- sprintf(code, "impl %s { fn to_string(self) -> char* { return \"%s { ... }\"; } }",
+ sprintf(code, "impl %s { fn to_string(self) -> char* { return \"%s {{ ... }}\"; } }",
name, name);
}
else if (0 == strcmp(trait, "Copy"))
diff --git a/src/parser/parser_expr.c b/src/parser/parser_expr.c
index df2dcf6..332d9c3 100644
--- a/src/parser/parser_expr.c
+++ b/src/parser/parser_expr.c
@@ -935,6 +935,17 @@ static ASTNode *create_fstring_block(ParserContext *ctx, const char *content)
free(txt);
}
+ // Handle escape {{
+ if (brace[1] == '{')
+ {
+ ASTNode *cat = ast_create(NODE_RAW_STMT);
+ cat->raw_stmt.content = xstrdup("strcat(_b, \"{\");");
+ tail->next = cat;
+ tail = cat;
+ cur = brace + 2;
+ continue;
+ }
+
char *end_brace = strchr(brace, '}');
if (!end_brace)
{
@@ -1100,8 +1111,30 @@ static ASTNode *parse_float_literal(Token t)
}
// Parse string literal
-static ASTNode *parse_string_literal(Token t)
+static ASTNode *parse_string_literal(ParserContext *ctx, Token t)
{
+ // Check for implicit interpolation
+ int has_interpolation = 0;
+ for (int i = 1; i < t.len - 1; i++)
+ {
+ if (t.start[i] == '{')
+ {
+ has_interpolation = 1;
+ break;
+ }
+ }
+
+ if (has_interpolation)
+ {
+
+ char *inner = xmalloc(t.len);
+ strncpy(inner, t.start + 1, t.len - 2);
+ inner[t.len - 2] = 0;
+ ASTNode *node = create_fstring_block(ctx, inner);
+ free(inner);
+ return node;
+ }
+
ASTNode *node = ast_create(NODE_EXPR_LITERAL);
node->literal.type_kind = LITERAL_STRING;
node->literal.string_val = xmalloc(t.len);
@@ -1276,7 +1309,7 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l)
}
else if (t.type == TOK_STRING)
{
- node = parse_string_literal(t);
+ node = parse_string_literal(ctx, t);
}
else if (t.type == TOK_FSTRING)
{
diff --git a/src/parser/parser_stmt.c b/src/parser/parser_stmt.c
index ab5b89c..85e9825 100644
--- a/src/parser/parser_stmt.c
+++ b/src/parser/parser_stmt.c
@@ -1877,7 +1877,7 @@ ASTNode *parse_statement(ParserContext *ctx, Lexer *l)
lexer_next(&lookahead);
TokenType next_type = lexer_peek(&lookahead).type;
- if (next_type == TOK_SEMICOLON || next_type == TOK_DOTDOT)
+ if (next_type == TOK_SEMICOLON || next_type == TOK_DOTDOT || next_type == TOK_RBRACE)
{
Token t = lexer_next(l); // consume string
@@ -1894,8 +1894,7 @@ ASTNode *parse_statement(ParserContext *ctx, Lexer *l)
inner[t.len - 2] = 0;
}
- // ; means println (end of line), .. means print (continuation)
- int is_ln = (next_type == TOK_SEMICOLON);
+ int is_ln = (next_type == TOK_SEMICOLON || next_type == TOK_RBRACE);
char **used_syms = NULL;
int used_count = 0;
char *code =
@@ -1913,6 +1912,7 @@ ASTNode *parse_statement(ParserContext *ctx, Lexer *l)
lexer_next(l); // consume optional ;
}
}
+ // If TOK_RBRACE, do not consume it, so parse_block can see it and terminate loop.
ASTNode *n = ast_create(NODE_RAW_STMT);
// Append semicolon to Statement Expression to make it a valid statement
diff --git a/tests/features/test_implicit_fstring.zc b/tests/features/test_implicit_fstring.zc
new file mode 100644
index 0000000..85a6c86
--- /dev/null
+++ b/tests/features/test_implicit_fstring.zc
@@ -0,0 +1,19 @@
+
+test "implicit_fstring_interpolation" {
+ let result = 123;
+ let s = "{result}";
+ // Should be "123"
+ assert(strcmp(s, "123") == 0, "Implicit f-string failed");
+}
+
+test "implicit_fstring_complex" {
+ let a = 10;
+ let b = 20;
+ let s = "Sum: {a + b}";
+ assert(strcmp(s, "Sum: 30") == 0, "Complex implicit f-string failed");
+}
+
+test "no_interpolation" {
+ let s = "Hello World";
+ assert(strcmp(s, "Hello World") == 0, "Plain string failed");
+}
diff --git a/tests/features/test_traits_suite.zc b/tests/features/test_traits_suite.zc
index 205bdf6..2ff8378 100644
--- a/tests/features/test_traits_suite.zc
+++ b/tests/features/test_traits_suite.zc
@@ -90,7 +90,7 @@ test "test_derive" {
// Debug
let s = p1.to_string();
- assert(strcmp(s, "Point { ... }") == 0, "Debug string matches");
+ assert(strcmp(s, "Point {{ ... }}") == 0, "Debug string matches");
// Clone
let p2 = p1.clone();