diff options
| -rw-r--r-- | README.md | 10 | ||||
| -rw-r--r-- | src/ast/ast.c | 38 | ||||
| -rw-r--r-- | src/parser/parser_type.c | 21 | ||||
| -rw-r--r-- | tests/basic/test_basics.zc | 14 |
4 files changed, 79 insertions, 4 deletions
@@ -48,6 +48,7 @@ Join the discussion, share demos, ask questions, or report bugs in the official - [Type Aliases](#type-aliases) - [4. Functions & Lambdas](#4-functions--lambdas) - [Functions](#functions) + - [Const Arguments](#const-arguments) - [Default Arguments](#default-arguments) - [Lambdas (Closures)](#lambdas-closures) - [Variadic Functions](#variadic-functions) @@ -256,8 +257,17 @@ fn add(a: int, b: int) -> int { // Named arguments supported in calls add(a: 10, b: 20); +``` > **Note**: Named arguments must strictly follow the defined parameter order. `add(b: 20, a: 10)` is invalid. + +#### Const Arguments +Function arguments can be marked as `const` to enforce read-only semantics. +```zc +fn print_val(v: const int) { + // v = 10; // Error: Cannot assign to const variable + println "{v}"; +} ``` #### Default Arguments diff --git a/src/ast/ast.c b/src/ast/ast.c index 712f6e3..78d7efb 100644 --- a/src/ast/ast.c +++ b/src/ast/ast.c @@ -169,12 +169,31 @@ int type_eq(Type *a, Type *b) return 1; } +static char *type_to_string_impl(Type *t); + char *type_to_string(Type *t) { if (!t) { return xstrdup("void"); } + char *res = type_to_string_impl(t); + if (t->is_const) + { + char *final = xmalloc(strlen(res) + 7); + sprintf(final, "const %s", res); + free(res); + return final; + } + return res; +} + +static char *type_to_string_impl(Type *t) +{ + if (!t) + { + return xstrdup("void"); + } switch (t->kind) { @@ -293,12 +312,31 @@ char *type_to_string(Type *t) // C-compatible type stringifier. // Strictly uses 'struct T' for explicit structs to support external types. // Does NOT mangle pointers to 'Ptr'. +static char *type_to_c_string_impl(Type *t); + char *type_to_c_string(Type *t) { if (!t) { return xstrdup("void"); } + char *res = type_to_c_string_impl(t); + if (t->is_const) + { + char *final = xmalloc(strlen(res) + 7); + sprintf(final, "const %s", res); + free(res); + return final; + } + return res; +} + +static char *type_to_c_string_impl(Type *t) +{ + if (!t) + { + return xstrdup("void"); + } switch (t->kind) { diff --git a/src/parser/parser_type.c b/src/parser/parser_type.c index b11bedb..24e9f69 100644 --- a/src/parser/parser_type.c +++ b/src/parser/parser_type.c @@ -713,11 +713,20 @@ Type *parse_type_base(ParserContext *ctx, Lexer *l) Type *parse_type_formal(ParserContext *ctx, Lexer *l) { int is_restrict = 0; - if (lexer_peek(l).type == TOK_IDENT && lexer_peek(l).len == 8 && - strncmp(lexer_peek(l).start, "restrict", 8) == 0) + int is_const = 0; + + if (lexer_peek(l).type == TOK_IDENT) { - lexer_next(l); // eat restrict - is_restrict = 1; + if (lexer_peek(l).len == 8 && strncmp(lexer_peek(l).start, "restrict", 8) == 0) + { + lexer_next(l); // eat restrict + is_restrict = 1; + } + else if (lexer_peek(l).len == 5 && strncmp(lexer_peek(l).start, "const", 5) == 0) + { + lexer_next(l); // eat const + is_const = 1; + } } // Example: fn(int, int) -> int @@ -829,6 +838,10 @@ Type *parse_type_formal(ParserContext *ctx, Lexer *l) { t->is_restrict = 1; } + if (is_const) + { + t->is_const = 1; + } return t; } diff --git a/tests/basic/test_basics.zc b/tests/basic/test_basics.zc index d54389b..57dbb4e 100644 --- a/tests/basic/test_basics.zc +++ b/tests/basic/test_basics.zc @@ -8,3 +8,17 @@ test "test_vars" { var y: int = 20; println "Sum: {x + y}"; } + +fn take_const_arg(x: const int) -> int { + return x; +} + +test "test_const_args" { + var x = take_const_arg(10); + assert(x == 10, "Failed const arg"); + + var y: const int = 20; + assert(y == 20, "Failed const var"); + + println "Const args work!"; +} |
