- Introduce $vaarg[...] syntax and deprecate the old $vaarg(...).

- Similar change to `$vasplat`: `$vasplat` and `$vasplat[1..]`.
This commit is contained in:
Christoffer Lerno
2024-08-16 09:28:28 +02:00
parent 9fd9280132
commit edfea639cf
20 changed files with 119 additions and 74 deletions

View File

@@ -135,7 +135,7 @@ fn void panicf(String fmt, String file, String function, uint line, args...)
macro void unreachable(String string = "Unreachable statement reached.", ...) @builtin @noreturn
{
$if env::COMPILER_SAFE_MODE:
panicf(string, $$FILE, $$FUNC, $$LINE, $vasplat());
panicf(string, $$FILE, $$FUNC, $$LINE, $vasplat);
$endif;
$$unreachable();
}
@@ -146,7 +146,7 @@ macro void unreachable(String string = "Unreachable statement reached.", ...) @b
**/
macro void unsupported(String string = "Unsupported function invoked") @builtin @noreturn
{
panicf(string, $$FILE, $$FUNC, $$LINE, $vasplat());
panicf(string, $$FILE, $$FUNC, $$LINE, $vasplat);
$$unreachable();
}
@@ -291,12 +291,12 @@ macro @prefetch(void* ptr, PrefetchLocality $locality = VERY_NEAR, bool $write =
macro swizzle(v, ...) @builtin
{
return $$swizzle(v, $vasplat());
return $$swizzle(v, $vasplat);
}
macro swizzle2(v, v2, ...) @builtin
{
return $$swizzle2(v, v2, $vasplat());
return $$swizzle2(v, v2, $vasplat);
}
macro anyfault @catch(#expr) @builtin

View File

@@ -97,13 +97,13 @@ macro bool equals(a, b) @builtin
macro min(x, ...) @builtin
{
$if $vacount == 1:
return less(x, $vaarg(0)) ? x : $vaarg(0);
return less(x, $vaarg[0]) ? x : $vaarg[0];
$else
var result = x;
$for (var $i = 0; $i < $vacount; $i++)
if (less($vaarg($i), result))
if (less($vaarg[$i], result))
{
result = $vaarg($i);
result = $vaarg[$i];
}
$endfor
return result;
@@ -113,13 +113,13 @@ macro min(x, ...) @builtin
macro max(x, ...) @builtin
{
$if $vacount == 1:
return greater(x, $vaarg(0)) ? x : $vaarg(0);
return greater(x, $vaarg[0]) ? x : $vaarg[0];
$else
var result = x;
$for (var $i = 0; $i < $vacount; $i++)
if (greater($vaarg($i), result))
if (greater($vaarg[$i], result))
{
result = $vaarg($i);
result = $vaarg[$i];
}
$endfor
return result;

View File

@@ -591,7 +591,7 @@ fn void* tmalloc(usz size, usz alignment = 0) @builtin @inline @nodiscard
/**
* @require $vacount < 2 : "Too many arguments."
* @require $vacount == 0 ||| $assignable($vaexpr(0), $Type) : "The second argument must be an initializer for the type"
* @require $vacount == 0 ||| $assignable($vaexpr[0], $Type) : "The second argument must be an initializer for the type"
* @require $Type.alignof <= DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'alloc_aligned' instead"
**/
macro new($Type, ...) @nodiscard
@@ -600,7 +600,7 @@ macro new($Type, ...) @nodiscard
return ($Type*)calloc($Type.sizeof);
$else
$Type* val = malloc($Type.sizeof);
*val = $vaexpr(0);
*val = $vaexpr[0];
return val;
$endif
}
@@ -609,7 +609,7 @@ macro new($Type, ...) @nodiscard
* Allocate using an aligned allocation. This is necessary for types with a default memory alignment
* exceeding DEFAULT_MEM_ALIGNMENT. IMPORTANT! It must be freed using free_aligned.
* @require $vacount < 2 : "Too many arguments."
* @require $vacount == 0 ||| $assignable($vaexpr(0), $Type) : "The second argument must be an initializer for the type"
* @require $vacount == 0 ||| $assignable($vaexpr[0], $Type) : "The second argument must be an initializer for the type"
**/
macro new_aligned($Type, ...) @nodiscard
{
@@ -617,7 +617,7 @@ macro new_aligned($Type, ...) @nodiscard
return ($Type*)calloc_aligned($Type.sizeof, $Type.alignof);
$else
$Type* val = malloc_aligned($Type.sizeof, $Type.alignof);
*val = $vaexpr(0);
*val = $vaexpr[0];
return val;
$endif
}
@@ -641,7 +641,7 @@ macro alloc_aligned($Type) @nodiscard
/**
* @require $vacount < 2 : "Too many arguments."
* @require $vacount == 0 ||| $assignable($vaexpr(0), $Type) : "The second argument must be an initializer for the type"
* @require $vacount == 0 ||| $assignable($vaexpr[0], $Type) : "The second argument must be an initializer for the type"
**/
macro temp_new($Type, ...) @nodiscard
{
@@ -649,7 +649,7 @@ macro temp_new($Type, ...) @nodiscard
return ($Type*)tcalloc($Type.sizeof) @inline;
$else
$Type* val = tmalloc($Type.sizeof) @inline;
*val = $vaexpr(0);
*val = $vaexpr[0];
return val;
$endif
}

View File

@@ -149,7 +149,7 @@ macro void free_aligned(Allocator allocator, void* ptr)
/**
* @require $Type.alignof <= mem::DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'new_aligned' instead"
* @require $vacount < 2 : "Too many arguments."
* @require $vacount == 0 ||| $assignable($vaexpr(0), $Type) : "The second argument must be an initializer for the type"
* @require $vacount == 0 ||| $assignable($vaexpr[0], $Type) : "The second argument must be an initializer for the type"
**/
macro new(Allocator allocator, $Type, ...) @nodiscard
{
@@ -157,7 +157,7 @@ macro new(Allocator allocator, $Type, ...) @nodiscard
return ($Type*)calloc(allocator, $Type.sizeof);
$else
$Type* val = malloc(allocator, $Type.sizeof);
*val = $vaexpr(0);
*val = $vaexpr[0];
return val;
$endif
}
@@ -165,7 +165,7 @@ macro new(Allocator allocator, $Type, ...) @nodiscard
/**
* @require $Type.alignof <= mem::DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'new_aligned' instead"
* @require $vacount < 2 : "Too many arguments."
* @require $vacount == 0 ||| $assignable($vaexpr(0), $Type) : "The second argument must be an initializer for the type"
* @require $vacount == 0 ||| $assignable($vaexpr[0], $Type) : "The second argument must be an initializer for the type"
**/
macro new_try(Allocator allocator, $Type, ...) @nodiscard
{
@@ -173,7 +173,7 @@ macro new_try(Allocator allocator, $Type, ...) @nodiscard
return ($Type*)calloc_try(allocator, $Type.sizeof);
$else
$Type* val = malloc_try(allocator, $Type.sizeof)!;
*val = $vaexpr(0);
*val = $vaexpr[0];
return val;
$endif
}
@@ -182,7 +182,7 @@ macro new_try(Allocator allocator, $Type, ...) @nodiscard
* Allocate using an aligned allocation. This is necessary for types with a default memory alignment
* exceeding DEFAULT_MEM_ALIGNMENT. IMPORTANT! It must be freed using free_aligned.
* @require $vacount < 2 : "Too many arguments."
* @require $vacount == 0 ||| $assignable($vaexpr(0), $Type) : "The second argument must be an initializer for the type"
* @require $vacount == 0 ||| $assignable($vaexpr[0], $Type) : "The second argument must be an initializer for the type"
**/
macro new_aligned($Type, ...) @nodiscard
{
@@ -190,7 +190,7 @@ macro new_aligned($Type, ...) @nodiscard
return ($Type*)calloc_aligned(allocator, $Type.sizeof, $Type.alignof);
$else
$Type* val = malloc_aligned(allocator, $Type.sizeof, $Type.alignof);
*val = $vaexpr(0);
*val = $vaexpr[0];
return val;
$endif
}

View File

@@ -40,7 +40,7 @@ fault NumberConversion
macro String tformat(String fmt, ...)
{
DString str = dstring::temp_with_capacity(fmt.len + $vacount * 8);
str.appendf(fmt, $vasplat());
str.appendf(fmt, $vasplat);
return str.str_view();
}
@@ -52,7 +52,7 @@ macro String tformat(String fmt, ...)
macro ZString tformat_zstr(String fmt, ...)
{
DString str = dstring::temp_with_capacity(fmt.len + $vacount * 8);
str.appendf(fmt, $vasplat());
str.appendf(fmt, $vasplat);
return str.zstr_view();
}
@@ -67,7 +67,7 @@ macro String new_format(String fmt, ..., Allocator allocator = allocator::heap()
@pool(allocator)
{
DString str = dstring::temp_with_capacity(fmt.len + $vacount * 8);
str.appendf(fmt, $vasplat());
str.appendf(fmt, $vasplat);
return str.copy_str(allocator);
};
}
@@ -83,7 +83,7 @@ macro ZString new_format_zstr(String fmt, ..., Allocator allocator = allocator::
@pool(allocator)
{
DString str = dstring::temp_with_capacity(fmt.len + $vacount * 8);
str.appendf(fmt, $vasplat());
str.appendf(fmt, $vasplat);
return str.copy_zstr(allocator);
};
}

View File

@@ -199,7 +199,7 @@ macro bool @has_same(#a, #b, ...) @const
return false;
$endif
$for (var $i = 0; $i < $vacount; $i++)
$if @typeid($vaexpr($i)) != $type_a:
$if @typeid($vaexpr[$i]) != $type_a:
return false;
$endif
$endfor

View File

@@ -365,7 +365,7 @@ macro max(x, y, ...)
$else
var m = $$max(x, y);
$for (var $i = 0; $i < $vacount; $i++)
m = $$max(m, $vaarg($i));
m = $$max(m, $vaarg[$i]);
$endfor
return m;
$endif
@@ -382,7 +382,7 @@ macro min(x, y, ...)
$else
var m = $$min(x, y);
$for (var $i = 0; $i < $vacount; $i++)
m = $$min(m, $vaarg($i));
m = $$min(m, $vaarg[$i]);
$endfor
return m;
$endif

View File

@@ -33,6 +33,8 @@
- Add temp allocator scribble.
- Use PIC by default on Linux.
- `$exec` may now provide a stdin parameter.
- Introduce `$vaarg[...]` syntax and deprecate the old `$vaarg(...)`.
- Similar change to `$vasplat`: `$vasplat` and `$vasplat[1..]`.
### Fixes

View File

@@ -19,7 +19,7 @@ macro @with_mode(String user, #action, ...)
@scope(context_user)
{
context_user = user;
return #action($vasplat());
return #action($vasplat);
};
}

View File

@@ -40,7 +40,6 @@ int comment_level = 0;
"$alignof" { count(); return(CT_ALIGNOF); }
"$and" { count(); return(CT_AND); }
"$assert" { count(); return(CT_ASSERT); }
"$assignable" { count(); return(CT_ASSIGNABLE); }
"$case" { count(); return(CT_CASE); }
@@ -55,6 +54,7 @@ int comment_level = 0;
"$error" { count(); return(CT_ERROR); }
"$eval" { count(); return(CT_EVAL); }
"$evaltype" { count(); return(CT_EVALTYPE); }
"$exec" { count(); return(CT_EXEC); }
"$extnameof" { count(); return(CT_EXTNAMEOF); }
"$feature" { count(); return(CT_FEATURE); }
"$for" { count(); return(CT_FOR); }
@@ -195,6 +195,9 @@ b64\`{B64}\` { count(); return(BYTES); }
"!!" { count(); return(BANGBANG); }
"..." { count(); return(ELLIPSIS); }
".." { count(); return(DOTDOT); }
"&&&" { count(); return(CT_AND_OP); }
"|||" { count(); return(CT_OR_OP); }
"+++" { count(); return(CT_CONCAT_OP); }
">>=" { count(); return(SHR_ASSIGN); }
"<<=" { count(); return(SHL_ASSIGN); }
"+=" { count(); return(ADD_ASSIGN); }

View File

@@ -14,6 +14,7 @@ void yyerror(const char *s);
%token TYPE_IDENT CT_TYPE_IDENT
%token AT_TYPE_IDENT AT_IDENT CT_INCLUDE
%token STRING_LITERAL INTEGER
%token CT_AND_OP CT_OR_OP CT_CONCAT_OP CT_EXEC
%token INC_OP DEC_OP SHL_OP SHR_OP LE_OP GE_OP EQ_OP NE_OP
%token AND_OP OR_OP MUL_ASSIGN DIV_ASSIGN MOD_ASSIGN ADD_ASSIGN
%token LGENPAR RGENPAR
@@ -90,7 +91,7 @@ ct_analyse
| CT_IS_CONST
;
ct_arg
ct_vaarg
: CT_VACONST
| CT_VAARG
| CT_VAREF
@@ -146,11 +147,10 @@ base_expr_assignable
| '(' expr ')'
| expr_block
| ct_call '(' flat_path ')'
| ct_arg '(' expr ')'
| ct_vaarg '[' expr ']'
| ct_analyse '(' expression_list ')'
| CT_VACOUNT
| CT_FEATURE '(' CONST_IDENT ')'
| CT_AND '(' expression_list ')'
| ct_castable '(' expr ',' type ')'
| lambda_decl compound_statement
;
@@ -333,21 +333,25 @@ try_chain_expr
and_expr
: relational_expr
| and_expr AND_OP relational_expr
| and_expr CT_AND_OP relational_expr
;
and_stmt_expr
: relational_stmt_expr
| and_stmt_expr AND_OP relational_expr
| and_stmt_expr CT_AND_OP relational_expr
;
or_expr
: and_expr
| or_expr OR_OP and_expr
| or_expr CT_OR_OP and_expr
;
or_stmt_expr
: and_stmt_expr
| or_stmt_expr OR_OP and_expr
| or_stmt_expr CT_OR_OP and_expr
;
suffix_expr
@@ -445,8 +449,7 @@ arg
| type
| param_path '=' type
| expr
| CT_VASPLAT '(' range_expr ')'
| CT_VASPLAT '(' ')'
| CT_VASPLAT '[' range_expr ']'
| ELLIPSIS expr
;
@@ -532,7 +535,7 @@ base_type
| CT_TYPE_IDENT
| CT_TYPEOF '(' expr ')'
| CT_TYPEFROM '(' constant_expr ')'
| CT_VATYPE '(' constant_expr ')'
| CT_VATYPE '[' constant_expr ']'
| CT_EVALTYPE '(' constant_expr ')'
;
@@ -1233,9 +1236,16 @@ opt_extern
| empty
;
exec_decl
: CT_EXEC '(' expr ')' opt_attributes ';'
| CT_EXEC '(' expr ',' initializer_list ')' opt_attributes ';'
| CT_EXEC '(' expr ',' initializer_list ',' expr ')' opt_attributes ';'
;
top_level
: module
| import_decl
| exec_decl
| opt_extern func_definition
| opt_extern const_declaration
| opt_extern global_declaration

View File

@@ -110,7 +110,7 @@ void print_type(FILE *file, TypeInfo *type)
PRINTF("$typeof(%s)", scratch_buffer_to_string());
break;
case TYPE_INFO_VATYPE:
PRINTF("$vatype(...)");
PRINTF("$vatype[...]");
break;
case TYPE_INFO_EVALTYPE:
PRINTF("$evaltype(...)");

View File

@@ -449,18 +449,34 @@ static Expr *parse_lambda(ParseContext *c, Expr *left)
/**
* vasplat ::= CT_VASPLAT '(' range_expr ')'
* -> TODO, this is the only one in 0.7
* vasplat ::= CT_VASPLAT ('[' range_expr ']')?
*/
Expr *parse_vasplat(ParseContext *c)
{
Expr *expr = EXPR_NEW_TOKEN(EXPR_VASPLAT);
advance_and_verify(c, TOKEN_CT_VASPLAT);
TRY_CONSUME_OR_RET(TOKEN_LPAREN, "'$vasplat' must be followed by '()'.", poisoned_expr);
if (!try_consume(c, TOKEN_RPAREN))
bool lparen = try_consume(c, TOKEN_LPAREN);
if (lparen && try_consume(c, TOKEN_RPAREN)) goto END;
if (lparen || try_consume(c, TOKEN_LBRACKET))
{
if (!parse_range(c, &expr->vasplat_expr)) return poisoned_expr;
CONSUME_OR_RET(TOKEN_RPAREN, poisoned_expr);
CONSUME_OR_RET(lparen ? TOKEN_RPAREN : TOKEN_RBRACKET, poisoned_expr);
}
RANGE_EXTEND_PREV(expr);
END:
// TODO remove in 0.7
if (lparen && !compiler.context.silence_deprecation)
{
if (expr->vasplat_expr.end || expr->vasplat_expr.start)
{
SEMA_NOTE(expr, "'$vasplat(...)' is deprecated, use '$vasplat[...]' instead.");
}
else
{
SEMA_NOTE(expr, "'$vasplat()' is deprecated, use '$vasplat' instead.");
}
}
return expr;
}
/**
@@ -1207,9 +1223,17 @@ static Expr *parse_ct_arg(ParseContext *c, Expr *left)
advance(c);
if (type != TOKEN_CT_VACOUNT)
{
CONSUME_OR_RET(TOKEN_LPAREN, poisoned_expr);
// TODO remove in 0.7
bool is_lparen = try_consume(c, TOKEN_LPAREN);
if (!is_lparen) CONSUME_OR_RET(TOKEN_LBRACKET, poisoned_expr);
ASSIGN_EXPRID_OR_RET(expr->ct_arg_expr.arg, parse_expr(c), poisoned_expr);
CONSUME_OR_RET(TOKEN_RPAREN, poisoned_expr);
CONSUME_OR_RET(is_lparen ? TOKEN_RPAREN : TOKEN_RBRACKET, poisoned_expr);
// TODO remove in 0.7
if (is_lparen && !compiler.context.silence_deprecation)
{
SEMA_NOTE(expr, "'%s(...)' is deprecated, use '%s[...]' instead.",
token_type_to_string(type), token_type_to_string(type));
}
}
RANGE_EXTEND_PREV(expr);
return expr;

View File

@@ -421,10 +421,16 @@ static inline TypeInfo *parse_base_type(ParseContext *c)
if (try_consume(c, TOKEN_CT_VATYPE))
{
TypeInfo *type_info = type_info_new(TYPE_INFO_VATYPE, c->prev_span);
CONSUME_OR_RET(TOKEN_LPAREN, poisoned_type_info);
bool is_lparen = try_consume(c, TOKEN_LPAREN);
if (!is_lparen) CONSUME_OR_RET(TOKEN_LBRACKET, poisoned_type_info);
ASSIGN_EXPR_OR_RET(type_info->unresolved_type_expr, parse_expr(c), poisoned_type_info);
CONSUME_OR_RET(TOKEN_RPAREN, poisoned_type_info);
CONSUME_OR_RET(is_lparen ? TOKEN_RPAREN : TOKEN_RBRACKET, poisoned_type_info);
RANGE_EXTEND_PREV(type_info);
// TODO remove in 0.7
if (is_lparen && !compiler.context.silence_deprecation)
{
SEMA_NOTE(type_info, "'$vatype(...)' is deprecated, use '$vatype[...]' instead.");
}
return type_info;
}
if (try_consume(c, TOKEN_CT_EVALTYPE))

View File

@@ -4774,7 +4774,7 @@ static Expr **sema_vasplat_append(SemaContext *context, Expr **init_expressions,
{
if (!range->is_range)
{
SEMA_ERROR(expr, "$vasplat() expected a range.");
SEMA_ERROR(expr, "$vasplat expected a range.");
return NULL;
}
if (!sema_analyse_expr(context, start)) return NULL;

View File

@@ -6,10 +6,10 @@ import std::io;
macro print_type_info(...)
{
$for (var $i = 0; $i < $vacount; $i++)
io::printfn("type: %s", $vatype($i).nameof);
io::printfn("%s.sizeof = %d", $vatype($i).nameof, $vatype($i).sizeof);
io::printfn("%s.min = %s", $vatype($i).nameof, $vatype($i).min);
io::printfn("%s.max = %s\n", $vatype($i).nameof, $vatype($i).max);
io::printfn("type: %s", $vatype[$i].nameof);
io::printfn("%s.sizeof = %d", $vatype[$i].nameof, $vatype[$i].sizeof);
io::printfn("%s.min = %s", $vatype[$i].nameof, $vatype[$i].min);
io::printfn("%s.max = %s\n", $vatype[$i].nameof, $vatype[$i].max);
$endfor;
}

View File

@@ -1,20 +1,20 @@
macro foo(...)
{
$vaarg("hello"); // #error: Expected the argument index here
$vaarg["hello"]; // #error: Expected the argument index here
int x;
$vaarg(x); // #error: Vararg functions need a constant argument
$vaarg(-1); // #error: negative
$vaarg(100); // #error: varargs exist
$vaarg[x]; // #error: Vararg functions need a constant argument
$vaarg[-1]; // #error: negative
$vaarg[100]; // #error: varargs exist
}
macro foo2(...)
{
$vaconst(0);
$vaconst[0];
}
macro foo3(...)
{
$vatype(0) a;
$vatype[0] a;
}
fn void main()
{

View File

@@ -6,10 +6,10 @@ import std::io;
macro @foo(...)
{
int i = $vaarg(1) + $vaarg(1);
int j = $vaexpr(2) + $vaexpr(2);
int i = $vaarg[1] + $vaarg[1];
int j = $vaexpr[2] + $vaexpr[2];
$for (var $i = 0; $i < $vacount; $i++)
io::printfn("%d", $vaarg($i));
io::printfn("%d", $vaarg[$i]);
$endfor;
}
@@ -17,9 +17,9 @@ macro foo2(...)
{
$for (var $i = 0; $i < $vacount; $i++)
{
$vatype($i) x;
$vatype[$i] x;
}
io::printfn("%s", $vatype($i).nameof);
io::printfn("%s", $vatype[$i].nameof);
$endfor;
}
@@ -34,9 +34,9 @@ macro foo3(...)
macro @foo4(...)
{
$typeof(*$varef(0)) a = *$varef(0);
*$varef(0) = *$varef(1);
*$varef(1) = a;
$typeof(*$varef[0]) a = *$varef[0];
*$varef[0] = *$varef[1];
*$varef[1] = a;
}
fn int ping(int val)
{

View File

@@ -4,47 +4,47 @@ import std::io;
macro @hello(...)
{
int[*] a = { 1, $vasplat(), 3 };
int[*] a = { 1, $vasplat, 3 };
foreach (i, x : a) io::printfn("%d: %d", i, x);
}
macro @hello1(...)
{
int[*] a = { 1, $vasplat() };
int[*] a = { 1, $vasplat };
foreach (i, x : a) io::printfn("x:%d: %d", i, x);
}
macro @hello2(...)
{
int[*] a = { $vasplat(), 888 };
int[*] a = { $vasplat, 888 };
foreach (i, x : a) io::printfn("x:%d: %d", i, x);
}
macro @hello3(...)
{
int[*] a = { $vasplat() };
int[*] a = { $vasplat };
foreach (i, x : a) io::printfn("x:%d: %d", i, x);
}
macro @hello4(...)
{
int[*] a = { 5, $vasplat(2..4), 77 };
int[*] a = { 5, $vasplat[2..4], 77 };
foreach (i, x : a) io::printfn("y:%d: %d", i, x);
}
macro @hello5(...)
{
int[*] a = { 5, $vasplat(2..), 77 };
int[*] a = { 5, $vasplat[2..], 77 };
foreach (i, x : a) io::printfn("y:%d: %d", i, x);
int[*] b = { 55, $vasplat(2..^2), 88 };
int[*] b = { 55, $vasplat[2..^2], 88 };
foreach (i, x : b) io::printfn("z:%d: %d", i, x);
int[*] c = { 55, $vasplat(0:^2), 88 };
int[*] c = { 55, $vasplat[0:^2], 88 };
foreach (i, x : c) io::printfn("zz:%d: %d", i, x);
}
macro @hello6(...)
{
@hello(66, $vasplat());
@hello(66, $vasplat);
}
fn void main()
{

View File

@@ -5,7 +5,7 @@ import std::io;
macro test(start, ...)
{
$for (var $i = 0; $i < $vacount; $i++)
for ($vatype($i) i = ($vatype($i))start; i < 5; i+=2)
for ($vatype[$i] i = ($vatype[$i])start; i < 5; i+=2)
{
assert(math::is_even(i));
assert(i.is_even());