Compare commits

...

1 Commits

Author SHA1 Message Date
Christoffer Lerno
c7f11a6cf4 Updated named arguments, experimental branch. 2024-08-28 10:42:15 +02:00
40 changed files with 403 additions and 302 deletions

View File

@@ -78,13 +78,13 @@ fn usz! AnyList.to_format(&self, Formatter* formatter) @dynamic
fn String AnyList.to_new_string(&self, Allocator allocator = null) @dynamic
{
return string::format("%s", *self, .allocator = allocator ?: allocator::heap());
return string::format("%s", *self, allocator: allocator ?: allocator::heap());
}
fn String AnyList.to_string(&self, Allocator allocator) @dynamic
{
return string::format("%s", *self, .allocator = allocator);
return string::format("%s", *self, allocator: allocator);
}
fn String AnyList.to_tstring(&self) => string::tformat("%s", *self);

View File

@@ -41,12 +41,12 @@ fn usz! ElasticArray.to_format(&self, Formatter* formatter) @dynamic
fn String ElasticArray.to_string(&self, Allocator allocator) @dynamic
{
return string::format("%s", *self, .allocator = allocator);
return string::format("%s", *self, allocator: allocator);
}
fn String ElasticArray.to_new_string(&self, Allocator allocator = nul) @dynamic
{
return string::format("%s", *self, .allocator = allocator ?: allocator::heap());
return string::format("%s", *self, allocator: allocator ?: allocator::heap());
}
fn String ElasticArray.to_tstring(&self)

View File

@@ -27,12 +27,12 @@ fn usz! EnumMap.to_format(&self, Formatter* formatter) @dynamic
fn String EnumMap.to_string(&self, Allocator allocator) @dynamic
{
return string::format("%s", *self, .allocator = allocator);
return string::format("%s", *self, allocator: allocator);
}
fn String EnumMap.to_new_string(&self, Allocator allocator = null) @dynamic
{
return string::format("%s", *self, .allocator = allocator ?: allocator::heap());
return string::format("%s", *self, allocator: allocator ?: allocator::heap());
}
fn String EnumMap.to_tstring(&self) @dynamic

View File

@@ -143,12 +143,12 @@ fn usz! EnumSet.to_format(&set, Formatter* formatter) @dynamic
fn String EnumSet.to_new_string(&set, Allocator allocator = allocator::heap()) @dynamic
{
return string::format("%s", *set, .allocator = allocator);
return string::format("%s", *set, allocator: allocator);
}
fn String EnumSet.to_string(&set, Allocator allocator) @dynamic
{
return string::format("%s", *set, .allocator = allocator);
return string::format("%s", *set, allocator: allocator);
}
fn String EnumSet.to_tstring(&set) @dynamic

View File

@@ -102,7 +102,7 @@ fn usz! List.to_format(&self, Formatter* formatter) @dynamic
fn String List.to_new_string(&self, Allocator allocator = allocator::heap()) @dynamic
{
return string::format("%s", *self, .allocator = allocator);
return string::format("%s", *self, allocator: allocator);
}
fn String List.to_tstring(&self)
@@ -352,7 +352,7 @@ fn void List.ensure_capacity(&self, usz min_capacity) @local
min_capacity = math::next_power_of_2(min_capacity);
$if type_is_overaligned():
self.entries = allocator::realloc_aligned(self.allocator, self.entries, Type.sizeof * min_capacity, .alignment = Type[1].alignof)!!;
self.entries = allocator::realloc_aligned(self.allocator, self.entries, Type.sizeof * min_capacity, alignment: Type[1].alignof)!!;
$else
self.entries = allocator::realloc(self.allocator, self.entries, Type.sizeof * min_capacity);
$endif;

View File

@@ -53,7 +53,7 @@ fn Map new_from_map(Map other_map, Allocator allocator = null)
MapImpl* other_map_impl = (MapImpl*)other_map;
if (!other_map_impl)
{
if (allocator) return new(.allocator = allocator);
if (allocator) return new(allocator: allocator);
return null;
}
MapImpl* map = (MapImpl*)new(other_map_impl.table.len, other_map_impl.load_factor, allocator ?: allocator::heap());

View File

@@ -156,7 +156,7 @@ fn void Object.init_map_if_needed(&self) @private
if (self.is_empty())
{
self.type = ObjectInternalMap.typeid;
self.map.new_init(.allocator = self.allocator);
self.map.new_init(allocator: self.allocator);
}
}
@@ -168,7 +168,7 @@ fn void Object.init_array_if_needed(&self) @private
if (self.is_empty())
{
self.type = ObjectInternalList.typeid;
self.array.new_init(.allocator = self.allocator);
self.array.new_init(allocator: self.allocator);
}
}

View File

@@ -31,12 +31,12 @@ fn Type Range.get(&self, usz index) @operator([])
fn String Range.to_new_string(&self, Allocator allocator = allocator::heap()) @dynamic @deprecated
{
return string::format("[%s..%s]", self.start, self.end, .allocator = allocator);
return string::format("[%s..%s]", self.start, self.end, allocator: allocator);
}
fn String Range.to_string(&self, Allocator allocator) @dynamic
{
return string::format("[%s..%s]", self.start, self.end, .allocator = allocator);
return string::format("[%s..%s]", self.start, self.end, allocator: allocator);
}
fn String Range.to_tstring(&self)
@@ -78,7 +78,7 @@ fn String ExclusiveRange.to_new_string(&self, Allocator allocator = null) @dynam
fn String ExclusiveRange.to_string(&self, Allocator allocator) @dynamic
{
return string::format("[%s..<%s]", self.start, self.end, .allocator = allocator);
return string::format("[%s..<%s]", self.start, self.end, allocator: allocator);
}
fn String ExclusiveRange.to_tstring(&self)

View File

@@ -34,7 +34,7 @@ struct TrackingAllocator (Allocator)
fn void TrackingAllocator.init(&self, Allocator allocator)
{
*self = { .inner_allocator = allocator };
self.map.new_init(.allocator = allocator);
self.map.new_init(allocator: allocator);
}
/**

View File

@@ -123,7 +123,7 @@ fn void panicf(String fmt, String file, String function, uint line, args...)
@stack_mem(512; Allocator allocator)
{
DString s;
s.new_init(.allocator = allocator);
s.new_init(allocator: allocator);
s.appendf(fmt, ...args);
panic(s.str_view(), file, function, line);
};

View File

@@ -143,7 +143,7 @@ macro void free_aligned(Allocator allocator, void* ptr)
$if env::TESTING:
((char*)ptr)[0] = 0xBA;
$endif
allocator.release(ptr, .aligned = true);
allocator.release(ptr, aligned: true);
}
/**

View File

@@ -66,7 +66,7 @@ macro String format(String fmt, ..., Allocator allocator)
*
* @param [in] fmt `The formatting string`
**/
macro String new_format(String fmt, ..., Allocator allocator = null) => format(fmt, $vasplat, .allocator = allocator ?: allocator::heap());
macro String new_format(String fmt, ..., Allocator allocator = null) => format(fmt, $vasplat, allocator: allocator ?: allocator::heap());
/**
* Return a temporary String created using the formatting function.

View File

@@ -22,7 +22,7 @@ fn String[]! CsvReader.read_new_row_with_allocator(self, Allocator allocator = a
{
@pool(allocator)
{
return io::treadline(self.stream).split(self.separator, .allocator = allocator);
return io::treadline(self.stream).split(self.separator, allocator: allocator);
};
}
@@ -56,7 +56,7 @@ macro CsvReader.@each_row(self, int rows = int.max; @body(String[] row))
if (err == IoError.EOF) return;
return err?;
}
parts = s.split(sep, .allocator = mem);
parts = s.split(sep, allocator: mem);
};
@body(parts);
};

View File

@@ -4,7 +4,7 @@ import std::io, std::os;
fn PathList! native_ls(Path dir, bool no_dirs, bool no_symlinks, String mask, Allocator allocator)
{
PathList list;
list.new_init(.allocator = allocator);
list.new_init(allocator: allocator);
DIRPtr directory = posix::opendir(dir.str_view() ? dir.as_zstr() : (ZString)".");
defer if (directory) posix::closedir(directory);
if (!directory) return (path::is_dir(dir) ? IoError.CANNOT_READ_DIR : IoError.FILE_NOT_DIR)?;
@@ -27,7 +27,7 @@ import std::time, std::os, std::io;
fn PathList! native_ls(Path dir, bool no_dirs, bool no_symlinks, String mask, Allocator allocator)
{
PathList list;
list.new_init(.allocator = allocator);
list.new_init(allocator: allocator);
@pool(allocator)
{

View File

@@ -141,7 +141,7 @@ fn Path! new_win32_wstring(WString path, Allocator allocator = allocator::heap()
{
@pool(allocator)
{
return path::new(string::temp_from_wstring(path)!, .allocator = allocator);
return path::new(string::temp_from_wstring(path)!, allocator: allocator);
};
}
@@ -520,7 +520,7 @@ fn bool! Path.walk(self, PathWalker w, void* data)
@stack_mem(PATH_MAX; Allocator allocator)
{
Path abs = self.new_absolute(allocator)!;
PathList files = new_ls(abs, .allocator = allocator)!;
PathList files = new_ls(abs, allocator: allocator)!;
foreach (f : files)
{
if (f.str_view() == "." || f.str_view() == "..") continue;

View File

@@ -131,7 +131,7 @@ fn usz! ByteBuffer.available(&self) @inline @dynamic
fn void! ByteBuffer.grow(&self, usz n)
{
n = math::next_power_of_2(n);
char* p = allocator::realloc_aligned(self.allocator, self.bytes, n, .alignment = char.alignof)!;
char* p = allocator::realloc_aligned(self.allocator, self.bytes, n, alignment: char.alignof)!;
self.bytes = p[:n];
}

View File

@@ -105,7 +105,7 @@ fn Path! new_get_config_dir(Allocator allocator = allocator::heap())
String s = get_var_temp("XDG_CONFIG_HOME") ?? get_var_temp("HOME")!;
const DIR = ".config";
$endif
return path::temp_new(s).new_append(DIR, .allocator = allocator);
return path::temp_new(s).new_append(DIR, allocator: allocator);
$endif
};
}

View File

@@ -193,10 +193,10 @@ fn Backtrace! resolve_backtrace(void* addr, Win32_HANDLE process, Allocator allo
ZString zname = (ZString)&name;
if (!symGetLineFromAddr64(process, (Win32_ULONG64)addr - 1, &offset, &line))
{
backtrace.init((uptr)addr, zname.str_view(), module_name.str_view(), .allocator = allocator);
backtrace.init((uptr)addr, zname.str_view(), module_name.str_view(), allocator: allocator);
return backtrace;
}
String filename = ((ZString)line.fileName).str_view();
backtrace.init((uptr)addr, zname.str_view(), module_name.str_view(), .file = filename, .line = line.lineNumber, .allocator = allocator);
backtrace.init((uptr)addr, zname.str_view(), module_name.str_view(), file: filename, line: line.lineNumber, allocator: allocator);
return backtrace;
}

View File

@@ -443,11 +443,19 @@ param_path
| param_path param_path_element
;
arg_name
: IDENT
| CT_TYPE_IDENT
| HASH_IDENT
| CT_IDENT
;
arg
: param_path '=' expr
| param_path
| type
| param_path '=' type
| param_path
| arg_name ':' expr
| arg_name ':' type
| type
| expr
| CT_VASPLAT '[' range_expr ']'
| ELLIPSIS expr

View File

@@ -611,9 +611,9 @@ typedef struct Decl_
void *backend_value;
void *tb_symbol;
};
AlignSize alignment;
AlignSize offset;
AlignSize padding;
AlignSize alignment;
struct CompilationUnit_ *unit;
union
{
@@ -807,6 +807,13 @@ typedef struct
Expr *value;
} ExprDesignator;
typedef struct
{
const char *name;
SourceSpan name_span;
Expr *value;
} ExprNamedArgument;
typedef struct
{
Decl *type;
@@ -1093,6 +1100,7 @@ struct Expr_
Decl *decl_expr; // 8
Expr** designated_init_list; // 8
ExprDesignator designator_expr; // 16
ExprNamedArgument named_argument_expr;
ExprEmbedExpr embed_expr; // 16
Expr** exec_expr; // 8
ExprAsmArg expr_asm_arg; // 24
@@ -3147,7 +3155,7 @@ INLINE bool expr_poison(Expr *expr) { expr->expr_kind = EXPR_POISONED; expr->res
static inline void expr_list_set_span(Expr **expr, SourceSpan loc);
static inline void exprid_set_span(ExprId expr_id, SourceSpan loc);
INLINE void expr_set_span(Expr *expr, SourceSpan loc);
static inline void expr_set_span(Expr *expr, SourceSpan loc);
static inline void const_init_set_span(ConstInitializer *init, SourceSpan loc)
{
@@ -3191,11 +3199,15 @@ static inline void const_init_set_span(ConstInitializer *init, SourceSpan loc)
static inline void expr_list_set_span(Expr **expr, SourceSpan loc);
static inline void exprid_set_span(ExprId expr_id, SourceSpan loc);
INLINE void expr_set_span(Expr *expr, SourceSpan loc)
static inline void expr_set_span(Expr *expr, SourceSpan loc)
{
expr->span = loc;
switch (expr->expr_kind)
{
case EXPR_NAMED_ARGUMENT:
expr->named_argument_expr.name_span = loc;
expr_set_span(expr->named_argument_expr.value, loc);
return;
case EXPR_CONST:
switch (expr->const_expr.const_kind)
{

View File

@@ -294,6 +294,9 @@ Expr *copy_expr(CopyStruct *c, Expr *source_expr)
case EXPR_OTHER_CONTEXT:
MACRO_COPY_EXPR(expr->expr_other_context.inner);
return expr;
case EXPR_NAMED_ARGUMENT:
MACRO_COPY_EXPR(expr->named_argument_expr.value);
return expr;
case EXPR_EMBED:
MACRO_COPY_EXPR(expr->embed_expr.len);
MACRO_COPY_EXPR(expr->embed_expr.filename);

View File

@@ -793,6 +793,7 @@ typedef enum
EXPR_MACRO_BODY,
EXPR_MACRO_BODY_EXPANSION,
EXPR_MEMBER_GET,
EXPR_NAMED_ARGUMENT,
EXPR_NOP,
EXPR_OPERATOR_CHARS,
EXPR_OPTIONAL,

View File

@@ -97,16 +97,24 @@ bool expr_may_addr(Expr *expr)
case EXPR_COND:
case EXPR_CONST:
case EXPR_DECL:
case EXPR_DEFAULT_ARG:
case EXPR_DESIGNATED_INITIALIZER_LIST:
case EXPR_DESIGNATOR:
case EXPR_EMBED:
case EXPR_EXPRESSION_LIST:
case EXPR_INITIALIZER_LIST:
case EXPR_EXPR_BLOCK:
case EXPR_OPTIONAL:
case EXPR_FORCE_UNWRAP:
case EXPR_GENERIC_IDENT:
case EXPR_INITIALIZER_LIST:
case EXPR_LAMBDA:
case EXPR_LAST_FAULT:
case EXPR_MACRO_BLOCK:
case EXPR_MACRO_BODY:
case EXPR_MACRO_BODY_EXPANSION:
case EXPR_NAMED_ARGUMENT:
case EXPR_NOP:
case EXPR_OPERATOR_CHARS:
case EXPR_OPTIONAL:
case EXPR_POINTER_OFFSET:
case EXPR_POST_UNARY:
case EXPR_RETHROW:
@@ -115,20 +123,13 @@ bool expr_may_addr(Expr *expr)
case EXPR_SLICE_COPY:
case EXPR_SUBSCRIPT_ADDR:
case EXPR_SUBSCRIPT_ASSIGN:
case EXPR_SWIZZLE:
case EXPR_TERNARY:
case EXPR_TRY_UNWRAP:
case EXPR_TRY_UNWRAP_CHAIN:
case EXPR_TYPEID:
case EXPR_TYPEID_INFO:
case EXPR_VASPLAT:
case EXPR_SWIZZLE:
case EXPR_LAMBDA:
case EXPR_GENERIC_IDENT:
case EXPR_EMBED:
case EXPR_MACRO_BODY:
case EXPR_DEFAULT_ARG:
case EXPR_LAST_FAULT:
case EXPR_DESIGNATOR:
return false;
}
UNREACHABLE
@@ -340,6 +341,7 @@ bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind)
case EXPR_SUBSCRIPT_ASSIGN:
case EXPR_GENERIC_IDENT:
case EXPR_MACRO_BODY:
case EXPR_NAMED_ARGUMENT:
UNREACHABLE
case EXPR_NOP:
return true;
@@ -757,6 +759,7 @@ bool expr_is_pure(Expr *expr)
case EXPR_RETHROW:
case EXPR_HASH_IDENT:
case EXPR_MACRO_BLOCK:
case EXPR_NAMED_ARGUMENT:
case EXPR_INITIALIZER_LIST:
case EXPR_DESIGNATED_INITIALIZER_LIST:
case EXPR_POST_UNARY:

View File

@@ -7066,6 +7066,7 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr)
case EXPR_OTHER_CONTEXT:
case EXPR_DESIGNATOR:
case EXPR_MEMBER_GET:
case EXPR_NAMED_ARGUMENT:
UNREACHABLE
case EXPR_DEFAULT_ARG:
llvm_emit_default_arg(c, value, expr);

View File

@@ -493,6 +493,79 @@ bool parse_arg_list(ParseContext *c, Expr ***result, TokenType param_end, bool *
Expr *expr = NULL;
DesignatorElement **path;
SourceSpan start_span = c->span;
if (peek(c) == TOKEN_COLON && token_is_param_name(c->tok))
{
// Create the parameter expr
expr = expr_new(EXPR_NAMED_ARGUMENT, start_span);
expr->named_argument_expr.name = symstr(c);
expr->named_argument_expr.name_span = c->span;
advance(c);
advance(c);
ASSIGN_EXPR_OR_RET(expr->named_argument_expr.value, parse_expr(c), false);
RANGE_EXTEND_PREV(expr);
goto DONE;
}
if (tok_is(c, TOKEN_DOT) && token_is_param_name(peek(c)))
{
// Create the parameter expr
expr = expr_new(EXPR_NAMED_ARGUMENT, start_span);
advance(c);
expr->named_argument_expr.name = symstr(c);
expr->named_argument_expr.name_span = c->span;
advance(c);
CONSUME_OR_RET(TOKEN_EQ, false);
ASSIGN_EXPR_OR_RET(expr->named_argument_expr.value, parse_expr(c), false);
RANGE_EXTEND_PREV(expr);
if (!compiler.context.silence_deprecation)
{
SEMA_NOTE(expr, "Named arguments using the '.foo = expr' style are deprecated, please use 'foo: expr' instead.");
}
goto DONE;
}
if (vasplat && tok_is(c, TOKEN_CT_VASPLAT))
{
ASSIGN_EXPR_OR_RET(expr, parse_vasplat(c), false);
goto DONE;
}
if (splat)
{
if (*splat)
{
PRINT_ERROR_HERE("'...' is only allowed on the last argument in a call.");
return false;
}
*splat = try_consume(c, TOKEN_ELLIPSIS);
}
ASSIGN_EXPR_OR_RET(expr, parse_expr(c), false);
DONE:
vec_add(*result, expr);
if (!try_consume(c, TOKEN_COMMA))
{
return true;
}
if (tok_is(c, param_end)) return true;
if (splat && *splat)
{
}
}
}
/**
* param_list ::= ('...' arg | arg (',' arg)*)?
*
* parameter ::= ((param_path '=')? expr) | param_path
*/
bool parse_init_list(ParseContext *c, Expr ***result, TokenType param_end, bool *splat, bool vasplat)
{
*result = NULL;
if (splat) *splat = false;
while (1)
{
Expr *expr = NULL;
DesignatorElement **path;
SourceSpan start_span = c->span;
if (!parse_param_path(c, &path)) return false;
if (path != NULL)
{
@@ -500,29 +573,29 @@ bool parse_arg_list(ParseContext *c, Expr ***result, TokenType param_end, bool *
expr = expr_new(EXPR_DESIGNATOR, start_span);
expr->designator_expr.path = path;
if (try_consume(c, TOKEN_EQ)) {
if (try_consume(c, TOKEN_EQ))
{
ASSIGN_EXPR_OR_RET(expr->designator_expr.value, parse_expr(c), false);
}
RANGE_EXTEND_PREV(expr);
goto DONE;
}
else if (vasplat && tok_is(c, TOKEN_CT_VASPLAT))
if (vasplat && tok_is(c, TOKEN_CT_VASPLAT))
{
ASSIGN_EXPR_OR_RET(expr, parse_vasplat(c), false);
goto DONE;
}
else
if (splat)
{
if (splat)
if (*splat)
{
if (*splat)
{
PRINT_ERROR_HERE("'...' is only allowed on the last argument in a call.");
return false;
}
*splat = try_consume(c, TOKEN_ELLIPSIS);
PRINT_ERROR_HERE("'...' is only allowed on the last argument in a call.");
return false;
}
ASSIGN_EXPR_OR_RET(expr, parse_expr(c), false);
*splat = try_consume(c, TOKEN_ELLIPSIS);
}
ASSIGN_EXPR_OR_RET(expr, parse_expr(c), false);
DONE:
vec_add(*result, expr);
if (!try_consume(c, TOKEN_COMMA))
{
@@ -809,7 +882,7 @@ Expr *parse_initializer_list(ParseContext *c, Expr *left)
if (!try_consume(c, TOKEN_RBRACE))
{
Expr **exprs = NULL;
if (!parse_arg_list(c, &exprs, TOKEN_RBRACE, NULL, true)) return poisoned_expr;
if (!parse_init_list(c, &exprs, TOKEN_RBRACE, NULL, true)) return poisoned_expr;
int designated = -1;
FOREACH(Expr *, expr, exprs)
{

View File

@@ -113,6 +113,19 @@ INLINE bool expect(ParseContext *c, TokenType token_type)
return false;
}
INLINE bool token_is_param_name(TokenType token_type)
{
switch (token_type)
{
case TOKEN_CT_IDENT:
case TOKEN_IDENT:
case TOKEN_HASH_IDENT:
case TOKEN_CT_TYPE_IDENT:
return true;
default:
return false;
}
}
INLINE bool token_is_some_ident(TokenType token_type)
{
switch (token_type)

View File

@@ -137,7 +137,6 @@ INLINE bool sema_call_expand_arguments(SemaContext *context, CalledDecl *callee,
Expr **args, unsigned func_param_count,
Variadic variadic, unsigned vararg_index, bool *optional,
Expr ***varargs_ref, Expr **vararg_splat_ref, bool *no_match_ref);
static inline int sema_call_find_index_of_named_parameter(SemaContext *context, Decl **func_params, Expr *expr);
static inline bool sema_call_check_contract_param_match(SemaContext *context, Decl *param, Expr *expr);
static bool sema_call_analyse_body_expansion(SemaContext *macro_context, Expr *call);
static bool sema_slice_len_is_in_range(SemaContext *context, Type *type, Expr *len_expr, bool from_end, bool *remove_from_end);
@@ -594,6 +593,7 @@ static bool sema_binary_is_expr_lvalue(SemaContext *context, Expr *top_expr, Exp
case EXPR_MACRO_BODY:
case EXPR_LAST_FAULT:
case EXPR_MEMBER_GET:
case EXPR_NAMED_ARGUMENT:
goto ERR;
}
UNREACHABLE
@@ -668,8 +668,9 @@ static bool expr_may_ref(Expr *expr)
case EXPR_EXPRESSION_LIST:
if (!vec_size(expr->expression_list)) return false;
return expr_may_ref(VECLAST(expr->expression_list));
case EXPR_POISONED:
case EXPR_ANYSWITCH:
case EXPR_ASM:
case EXPR_BENCHMARK_HOOK:
case EXPR_BINARY:
case EXPR_BITASSIGN:
case EXPR_BUILTIN:
@@ -681,27 +682,32 @@ static bool expr_may_ref(Expr *expr)
case EXPR_COMPOUND_LITERAL:
case EXPR_COND:
case EXPR_CONST:
case EXPR_CT_ARG:
case EXPR_CT_CASTABLE:
case EXPR_CT_AND_OR:
case EXPR_CT_APPEND:
case EXPR_CT_ARG:
case EXPR_CT_CALL:
case EXPR_CT_CASTABLE:
case EXPR_CT_CONCAT:
case EXPR_CT_DEFINED:
case EXPR_CT_IS_CONST:
case EXPR_CT_APPEND:
case EXPR_CT_EVAL:
case EXPR_CT_IS_CONST:
case EXPR_DECL:
case EXPR_DESIGNATED_INITIALIZER_LIST:
case EXPR_DESIGNATOR:
case EXPR_EXPR_BLOCK:
case EXPR_OPTIONAL:
case EXPR_FORCE_UNWRAP:
case EXPR_GENERIC_IDENT:
case EXPR_INITIALIZER_LIST:
case EXPR_LAST_FAULT:
case EXPR_MACRO_BLOCK:
case EXPR_MACRO_BODY:
case EXPR_MACRO_BODY_EXPANSION:
case EXPR_NAMED_ARGUMENT:
case EXPR_NOP:
case EXPR_OPERATOR_CHARS:
case EXPR_OPTIONAL:
case EXPR_POINTER_OFFSET:
case EXPR_POISONED:
case EXPR_POST_UNARY:
case EXPR_RETHROW:
case EXPR_RETVAL:
@@ -709,18 +715,13 @@ static bool expr_may_ref(Expr *expr)
case EXPR_SLICE_COPY:
case EXPR_STRINGIFY:
case EXPR_TERNARY:
case EXPR_TEST_HOOK:
case EXPR_TRY_UNWRAP:
case EXPR_TRY_UNWRAP_CHAIN:
case EXPR_TYPEID:
case EXPR_TYPEID_INFO:
case EXPR_TYPEINFO:
case EXPR_ANYSWITCH:
case EXPR_VASPLAT:
case EXPR_BENCHMARK_HOOK:
case EXPR_TEST_HOOK:
case EXPR_GENERIC_IDENT:
case EXPR_MACRO_BODY:
case EXPR_LAST_FAULT:
return false;
}
UNREACHABLE
@@ -1185,51 +1186,17 @@ static inline bool sema_binary_analyse_arithmetic_subexpr(SemaContext *context,
return sema_binary_arithmetic_promotion(context, left, right, left_type, right_type, expr, error, bool_and_bitstruct_is_allowed);
}
static inline int sema_call_find_index_of_named_parameter(SemaContext *context, Decl **func_params, Expr *expr)
{
if (vec_size(expr->designator_expr.path) != 1)
{
SEMA_ERROR(expr, "Expected the name of a function parameter here, this looks like a member path.");
return -1;
}
DesignatorElement *element = expr->designator_expr.path[0];
if (element->kind != DESIGNATOR_FIELD)
{
SEMA_ERROR(expr, "Expected the name of a function parameter here, this looks like an array path field.");
return -1;
}
Expr *field = sema_expr_resolve_access_child(context, element->field_expr, NULL);
if (!field) return false;
const char *name;
switch (field->expr_kind)
{
case EXPR_IDENTIFIER:
name = field->identifier_expr.ident;
break;
case EXPR_CT_IDENT:
name = field->ct_ident_expr.identifier;
break;
case EXPR_TYPEINFO:
name = field->type_expr->unresolved.name;
break;
default:
SEMA_ERROR(expr, "A name was expected here.");
return -1;
}
const char *name = expr->named_argument_expr.name;
FOREACH_IDX(i, Decl *, func_param, func_params)
{
if (func_param && func_param->name == name) return (int) i;
if (func_param && func_param->name == name) return (int)i;
}
SEMA_ERROR(expr, "There's no parameter with the name '%s'.", name);
return -1;
}
static inline bool sema_call_check_invalid_body_arguments(SemaContext *context, Expr *call, CalledDecl *callee)
{
Expr *macro_body = exprptrzero(call->call_expr.macro_body);
@@ -1301,13 +1268,14 @@ INLINE bool sema_call_expand_arguments(SemaContext *context, CalledDecl *callee,
// 2. Loop through the parameters.
bool has_named = false;
bool found_splat = false;
ArrayIndex last_index = -1;
Expr *last_named_arg;
for (unsigned i = 0; i < num_args; i++)
{
Expr *arg = args[i];
assert(expr_ok(arg));
// 3. Handle named parameters
if (arg->expr_kind == EXPR_DESIGNATOR)
if (arg->expr_kind == EXPR_NAMED_ARGUMENT)
{
// Find the location of the parameter.
int index = sema_call_find_index_of_named_parameter(context, params, arg);
@@ -1323,7 +1291,7 @@ INLINE bool sema_call_expand_arguments(SemaContext *context, CalledDecl *callee,
if (params[index]->var.vararg)
{
RETURN_SEMA_FUNC_ERROR(callee->definition, arg, "Vararg parameters may not be named parameters, "
"use normal parameters instead.", params[index]->name);
"use normal parameters instead.", params[index]->name);
}
// 8e. We might have already set this parameter, that is not allowed.
@@ -1332,12 +1300,16 @@ INLINE bool sema_call_expand_arguments(SemaContext *context, CalledDecl *callee,
RETURN_SEMA_ERROR(arg, "The parameter '%s' was already set.", params[index]->name);
}
// 8g. Set the parameter
if (!arg->designator_expr.value)
if (last_index > index)
{
RETURN_SEMA_ERROR(arg, "Expected a value for this argument.");
SEMA_ERROR(arg, "Named arguments must always be declared in order.");
SEMA_NOTE(last_named_arg, "Place it before this argument.");
return false;
}
actual_args[index] = arg->designator_expr.value;
last_index = index;
last_named_arg = arg;
actual_args[index] = arg->named_argument_expr.value;
continue;
}
if (*vararg_splat_ref)
@@ -1467,7 +1439,7 @@ INLINE bool sema_call_expand_arguments(SemaContext *context, CalledDecl *callee,
print_error_after(args[num_args - 1]->span, "Argument #%d is not set.", i);
RETURN_NOTE_FUNC_DEFINITION;
}
print_error_after(args[num_args - 1]->span, "Expected '.%s = ...' after this argument.", param->name);
print_error_after(args[num_args - 1]->span, "Expected '%s: ...' after this argument.", param->name);
RETURN_NOTE_FUNC_DEFINITION;
}
if (num_args > (callee->struct_var ? 1 : 0))
@@ -8966,6 +8938,7 @@ static inline bool sema_expr_analyse_ct_defined(SemaContext *context, Expr *expr
case EXPR_DECL:
case EXPR_LAST_FAULT:
case EXPR_DEFAULT_ARG:
case EXPR_NAMED_ARGUMENT:
UNREACHABLE
case EXPR_CT_ARG:
FALLTHROUGH;
@@ -9668,6 +9641,7 @@ static inline bool sema_analyse_expr_dispatch(SemaContext *context, Expr *expr)
case EXPR_MACRO_BODY:
case EXPR_DEFAULT_ARG:
case EXPR_MEMBER_GET:
case EXPR_NAMED_ARGUMENT:
UNREACHABLE
case EXPR_TAGOF:
RETURN_SEMA_ERROR(expr, "Expected '()' after this.");

View File

@@ -262,6 +262,7 @@ RETRY:
case EXPR_MACRO_BODY:
case EXPR_OTHER_CONTEXT:
case EXPR_MEMBER_GET:
case EXPR_NAMED_ARGUMENT:
UNREACHABLE
case EXPR_DESIGNATOR:
sema_trace_expr_liveness(expr->designator_expr.value);

View File

@@ -623,6 +623,7 @@ static inline bool sema_expr_valid_try_expression(Expr *expr)
case EXPR_CT_DEFINED:
case EXPR_CT_EVAL:
case EXPR_CT_IDENT:
case EXPR_NAMED_ARGUMENT:
UNREACHABLE
case EXPR_BINARY:
case EXPR_POINTER_OFFSET:

View File

@@ -9,7 +9,7 @@ macro foo($bar, $Type)
fn void bar()
{
int x = foo(.$bar = 167, .$Type = int);
int x = foo($bar: 167, $Type: int);
}
/* #expect: test.ll

View File

@@ -29,8 +29,8 @@ import std::io;
fn void main()
{
test::test(1, 2);
test::test(.a = 3);
test::test(1, .b = 32);
test::test(a: 3);
test::test(1, b: 32);
test::test();
test::test();
}

View File

@@ -15,7 +15,7 @@ fn void main()
{
Func a = &test;
Func b = &test2;
io::printfn("%d", a(.y = 123));
io::printfn("%d", a(y: 123));
io::printfn("%d", (&test2)());
FuncSame z = &test2;
io::printfn("%d", z());

View File

@@ -0,0 +1,11 @@
import std;
macro void test(int a, int $baz)
{
io::printn(a + $baz);
}
fn void main()
{
test(.$baz = 1, .a = 4); // #error: Named arguments must always
test($baz: 1, a: 4); // #error: Named arguments must always
}

View File

@@ -4,5 +4,5 @@ fn void test(int... abc, int a)
fn void main()
{
int[] b = { 1, 2 };
test(...b, .a = 123);
test(...b, a: 123);
}

View File

@@ -13,12 +13,12 @@ fn void test2(int x, int... y, int z)
fn void a()
{
test(.z = 32, 3); // #error: Named arguments must be placed after positional arguments
test(z: 32, 3); // #error: Named arguments must be placed after positional arguments
}
fn void b()
{
test(1, .x = 3); // #error: The parameter 'x' was already set.
test(1, x: 3); // #error: The parameter 'x' was already set.
}
fn void c()
@@ -28,8 +28,8 @@ fn void c()
fn void d()
{
test2(1, .z = 3);
test2(1, 2, 3); // #error: Expected '.z = ...' after this argument
test2(1, z: 3);
test2(1, 2, 3); // #error: Expected 'z: ...' after this argument
}

View File

@@ -14,8 +14,8 @@ fn void test2(int x, y..., int z = 2)
fn void main()
{
test(3, 4, 5, .z = 123);
test2(3, 4, 5, .z = 123);
test(3, 4, 5, z: 123);
test2(3, 4, 5, z: 123);
test(3, 4, 5);
test2(3, 4, 5);
}

View File

@@ -161,7 +161,7 @@ fn void! main()
String foo_tmpl = "<<{{foo}} | {{bar}}>>";
FooTmpl ft;
ft.init(foo_tmpl, .using = allocator::temp())!;
ft.init(foo_tmpl, using: allocator::temp())!;
defer ft.free()!!;

View File

@@ -492,7 +492,7 @@ struct TrieNode
fn void Trie.init(&self, usz initial_capacity = 8, Allocator using = allocator::heap())
{
*self = {};
self.nodes.new_init(initial_capacity, .allocator = using);
self.nodes.new_init(initial_capacity, allocator: using);
self.nodes.push(TrieNode{});
}

View File

@@ -21,197 +21,197 @@ fn void! test_parent()
{
Path p = path::new("")!;
assert(@catch(p.parent()));
p = path::new("/", .path_env = PathEnv.POSIX)!;
p = path::new("/", path_env: PathEnv.POSIX)!;
assert(@catch(p.parent()));
p = path::new("/a/b/c", .path_env = PathEnv.POSIX)!;
p = path::new("/a/b/c", path_env: PathEnv.POSIX)!;
assert(p.parent().str_view()! == "/a/b");
p = path::new("/a/b/c", .path_env = PathEnv.WIN32)!;
p = path::new("/a/b/c", path_env: PathEnv.WIN32)!;
assert(p.parent().str_view()! == `\a\b`);
}
fn void! test_path_normalized()
{
assert(path::new("", .path_env = PathEnv.WIN32).str_view()! == "");
assert(@catch(path::new("1:\\a\\b\\c.txt", .path_env = PathEnv.WIN32)));
assert(@catch(path::new(":", .path_env = PathEnv.WIN32)));
assert(@catch(path::new("1:", .path_env = PathEnv.WIN32)));
assert(@catch(path::new("1:a", .path_env = PathEnv.WIN32)));
// assert(@catch(path::new(`\\\a\b\c.txt`, .path_env = PathEnv.WIN32)));
assert(@catch(path::new(`\\server\a\b\..\..\..\c`, .path_env = PathEnv.WIN32)));
assert(path::new("", path_env: PathEnv.WIN32).str_view()! == "");
assert(@catch(path::new("1:\\a\\b\\c.txt", path_env: PathEnv.WIN32)));
assert(@catch(path::new(":", path_env: PathEnv.WIN32)));
assert(@catch(path::new("1:", path_env: PathEnv.WIN32)));
assert(@catch(path::new("1:a", path_env: PathEnv.WIN32)));
// assert(@catch(path::new(`\\\a\b\c.txt`, path_env: PathEnv.WIN32)));
assert(@catch(path::new(`\\server\a\b\..\..\..\c`, path_env: PathEnv.WIN32)));
assert(@catch(path::new(`\\a`, .path_env = PathEnv.WIN32)));
assert(@catch(path::new(`/a/b/../../../c`, .path_env = PathEnv.WIN32)));
assert(@catch(path::new(`/a/b/../../../c`, .path_env = PathEnv.POSIX)));
assert(@catch(path::new(`/a/b/../../..`, .path_env = PathEnv.WIN32)));
assert(@catch(path::new(`/a/b/../../..`, .path_env = PathEnv.POSIX)));
assert(@catch(path::new(`/../a`, .path_env = PathEnv.WIN32)));
assert(@catch(path::new(`/../a`, .path_env = PathEnv.POSIX)));
assert(@catch(path::new(`/..`, .path_env = PathEnv.WIN32)));
assert(@catch(path::new(`/..`, .path_env = PathEnv.POSIX)));
assert(@catch(path::new(`C:/a/b/../../../c`, .path_env = PathEnv.WIN32)));
assert(@catch(path::new(`C:/../a`, .path_env = PathEnv.WIN32)));
assert(@catch(path::new(`C:/..`, .path_env = PathEnv.WIN32)));
assert(@catch(path::new(`\\a`, path_env: PathEnv.WIN32)));
assert(@catch(path::new(`/a/b/../../../c`, path_env: PathEnv.WIN32)));
assert(@catch(path::new(`/a/b/../../../c`, path_env: PathEnv.POSIX)));
assert(@catch(path::new(`/a/b/../../..`, path_env: PathEnv.WIN32)));
assert(@catch(path::new(`/a/b/../../..`, path_env: PathEnv.POSIX)));
assert(@catch(path::new(`/../a`, path_env: PathEnv.WIN32)));
assert(@catch(path::new(`/../a`, path_env: PathEnv.POSIX)));
assert(@catch(path::new(`/..`, path_env: PathEnv.WIN32)));
assert(@catch(path::new(`/..`, path_env: PathEnv.POSIX)));
assert(@catch(path::new(`C:/a/b/../../../c`, path_env: PathEnv.WIN32)));
assert(@catch(path::new(`C:/../a`, path_env: PathEnv.WIN32)));
assert(@catch(path::new(`C:/..`, path_env: PathEnv.WIN32)));
assert(path::new("/", .path_env = PathEnv.POSIX).str_view()! == "/");
assert(path::new("/./", .path_env = PathEnv.POSIX).str_view()! == "/");
assert(path::new("/foo/../", .path_env = PathEnv.POSIX).str_view()! == "/");
assert(path::new("/foo/bar/../", .path_env = PathEnv.POSIX).str_view()! == "/foo");
assert(path::new("/foo//bar", .path_env = PathEnv.POSIX).str_view()! == "/foo/bar");
assert(path::new("/foo//bar/../", .path_env = PathEnv.POSIX).str_view()! == "/foo");
assert(path::new("/foo/.bar", .path_env = PathEnv.POSIX).str_view()! == "/foo/.bar");
assert(path::new(`\foo\.bar`, .path_env = PathEnv.WIN32).str_view()! == `\foo\.bar`);
assert(path::new("a\\b/c.txt", .path_env = PathEnv.WIN32).str_view()! == `a\b\c.txt`);
assert(path::new("a\\b/c.txt", .path_env = PathEnv.POSIX).str_view()! == "a\\b/c.txt");
assert(path::new("C:\\a\\b/c.txt", .path_env = PathEnv.WIN32).str_view()! == `C:\a\b\c.txt`);
assert(path::new("C:\\a\\b/c.txt", .path_env = PathEnv.POSIX).str_view()! == "C:\\a\\b/c.txt");
assert(path::new(`\\server\a\b/c.txt`, .path_env = PathEnv.WIN32).str_view()! == `\\server\a\b\c.txt`);
assert(path::new(`\\server\a\b/c.txt`, .path_env = PathEnv.POSIX).str_view()! == `\\server\a\b/c.txt`);
assert(path::new(`c:\hello//bar\\\\foo.txt`, .path_env = PathEnv.WIN32).str_view()! == `c:\hello\bar\foo.txt`);
assert(path::new("/", path_env: PathEnv.POSIX).str_view()! == "/");
assert(path::new("/./", path_env: PathEnv.POSIX).str_view()! == "/");
assert(path::new("/foo/../", path_env: PathEnv.POSIX).str_view()! == "/");
assert(path::new("/foo/bar/../", path_env: PathEnv.POSIX).str_view()! == "/foo");
assert(path::new("/foo//bar", path_env: PathEnv.POSIX).str_view()! == "/foo/bar");
assert(path::new("/foo//bar/../", path_env: PathEnv.POSIX).str_view()! == "/foo");
assert(path::new("/foo/.bar", path_env: PathEnv.POSIX).str_view()! == "/foo/.bar");
assert(path::new(`\foo\.bar`, path_env: PathEnv.WIN32).str_view()! == `\foo\.bar`);
assert(path::new("a\\b/c.txt", path_env: PathEnv.WIN32).str_view()! == `a\b\c.txt`);
assert(path::new("a\\b/c.txt", path_env: PathEnv.POSIX).str_view()! == "a\\b/c.txt");
assert(path::new("C:\\a\\b/c.txt", path_env: PathEnv.WIN32).str_view()! == `C:\a\b\c.txt`);
assert(path::new("C:\\a\\b/c.txt", path_env: PathEnv.POSIX).str_view()! == "C:\\a\\b/c.txt");
assert(path::new(`\\server\a\b/c.txt`, path_env: PathEnv.WIN32).str_view()! == `\\server\a\b\c.txt`);
assert(path::new(`\\server\a\b/c.txt`, path_env: PathEnv.POSIX).str_view()! == `\\server\a\b/c.txt`);
assert(path::new(`c:\hello//bar\\\\foo.txt`, path_env: PathEnv.WIN32).str_view()! == `c:\hello\bar\foo.txt`);
assert(path::new(`~\a\b/c.txt`, .path_env = PathEnv.WIN32).str_view()! == `~\a\b\c.txt`);
assert(path::new(`~\a\b/c.txt`, .path_env = PathEnv.POSIX).str_view()! == `~\a\b/c.txt`);
assert(path::new(`~\a\b/c.txt`, path_env: PathEnv.WIN32).str_view()! == `~\a\b\c.txt`);
assert(path::new(`~\a\b/c.txt`, path_env: PathEnv.POSIX).str_view()! == `~\a\b/c.txt`);
assert(path::new(`a/b/../../../c`, .path_env = PathEnv.WIN32).str_view()! == `..\c`);
assert(path::new(`a/b/../../../c`, .path_env = PathEnv.POSIX).str_view()! == `../c`);
assert(path::new(`a/b/../../..`, .path_env = PathEnv.WIN32).str_view()! == `..`);
assert(path::new(`a/b/../../..`, .path_env = PathEnv.POSIX).str_view()! == `..`);
assert(path::new(`../a`, .path_env = PathEnv.WIN32).str_view()! == `..\a`);
assert(path::new(`../a`, .path_env = PathEnv.POSIX).str_view()! == `../a`);
assert(path::new(`..`, .path_env = PathEnv.WIN32).str_view()! == `..`);
assert(path::new(`..`, .path_env = PathEnv.POSIX).str_view()! == `..`);
assert(path::new(`a/b/../c`, .path_env = PathEnv.WIN32).str_view()! == `a\c`);
assert(path::new(`a/b/../c`, .path_env = PathEnv.POSIX).str_view()! == `a/c`);
assert(path::new(`a/b/../../c`, .path_env = PathEnv.WIN32).str_view()! == `c`);
assert(path::new(`a/b/../../c`, .path_env = PathEnv.POSIX).str_view()! == `c`);
assert(path::new(`a/b/..`, .path_env = PathEnv.WIN32).str_view()! == `a`);
assert(path::new(`a/b/..`, .path_env = PathEnv.POSIX).str_view()! == `a`);
assert(path::new(`a/b/../`, .path_env = PathEnv.WIN32).str_view()! == `a`);
assert(path::new(`a/b/../`, .path_env = PathEnv.POSIX).str_view()! == `a`);
assert(path::new(`a/b/../..`, .path_env = PathEnv.WIN32).str_view()! == ".");
assert(path::new(`a/b/../..`, .path_env = PathEnv.POSIX).str_view()! == ".");
assert(path::new(`a/b/../../`, .path_env = PathEnv.WIN32).str_view()! == ".");
assert(path::new(`a/b/../../`, .path_env = PathEnv.POSIX).str_view()! == ".");
assert(path::new(`a/b/../c/../d`, .path_env = PathEnv.WIN32).str_view()! == `a\d`);
assert(path::new(`a/b/../c/../d`, .path_env = PathEnv.POSIX).str_view()! == `a/d`);
assert(path::new(`a/b/../c/../d/`, .path_env = PathEnv.WIN32).str_view()! == `a\d`);
assert(path::new(`a/b/../c/../d/`, .path_env = PathEnv.POSIX).str_view()! == `a/d`);
assert(path::new(`a/b//d`, .path_env = PathEnv.WIN32).str_view()! == `a\b\d`);
assert(path::new(`a/b//d`, .path_env = PathEnv.POSIX).str_view()! == `a/b/d`);
assert(path::new(`a/b/././.`, .path_env = PathEnv.WIN32).str_view()! == `a\b`);
assert(path::new(`a/b/././.`, .path_env = PathEnv.POSIX).str_view()! == `a/b`);
assert(path::new(`a/b/./././`, .path_env = PathEnv.WIN32).str_view()! == `a\b`);
assert(path::new(`a/b/./././`, .path_env = PathEnv.POSIX).str_view()! == `a/b`);
assert(path::new(`./a/`, .path_env = PathEnv.WIN32).str_view()! == `a`);
assert(path::new(`./a/`, .path_env = PathEnv.POSIX).str_view()! == `a`);
assert(path::new(`./`, .path_env = PathEnv.WIN32).str_view()! == `.`);
assert(path::new(`./`, .path_env = PathEnv.POSIX).str_view()! == `.`);
assert(path::new(`.`, .path_env = PathEnv.WIN32).str_view()! == `.`);
assert(path::new(`.`, .path_env = PathEnv.POSIX).str_view()! == `.`);
assert(path::new(``, .path_env = PathEnv.WIN32).str_view()! == ``);
assert(path::new(``, .path_env = PathEnv.POSIX).str_view()! == ``);
assert(path::new(`/a`, .path_env = PathEnv.WIN32).str_view()! == `\a`);
assert(path::new(`/a`, .path_env = PathEnv.POSIX).str_view()! == `/a`);
assert(path::new(`/a/`, .path_env = PathEnv.WIN32).str_view()! == `\a`);
assert(path::new(`/a/`, .path_env = PathEnv.POSIX).str_view()! == `/a`);
assert(path::new(`/a/b/../c`, .path_env = PathEnv.WIN32).str_view()! == `\a\c`);
assert(path::new(`/a/b/../c`, .path_env = PathEnv.POSIX).str_view()! == `/a/c`);
assert(path::new(`/a/b/../../c`, .path_env = PathEnv.WIN32).str_view()! == `\c`);
assert(path::new(`/a/b/../../c`, .path_env = PathEnv.POSIX).str_view()! == `/c`);
assert(path::new(`/a/b/..`, .path_env = PathEnv.WIN32).str_view()! == `\a`);
assert(path::new(`/a/b/..`, .path_env = PathEnv.POSIX).str_view()! == `/a`);
assert(path::new(`/a/b/../..`, .path_env = PathEnv.WIN32).str_view()! == `\`);
assert(path::new(`/a/b/../..`, .path_env = PathEnv.POSIX).str_view()! == `/`);
assert(path::new(`/a/b/../c/../d`, .path_env = PathEnv.WIN32).str_view()! == `\a\d`);
assert(path::new(`/a/b/../c/../d`, .path_env = PathEnv.POSIX).str_view()! == `/a/d`);
assert(path::new(`/a/b//d`, .path_env = PathEnv.WIN32).str_view()! == `\a\b\d`);
assert(path::new(`/a/b//d`, .path_env = PathEnv.POSIX).str_view()! == `/a/b/d`);
assert(path::new(`/./a/`, .path_env = PathEnv.WIN32).str_view()! == `\a`);
assert(path::new(`/./a/`, .path_env = PathEnv.POSIX).str_view()! == `/a`);
assert(path::new(`/./`, .path_env = PathEnv.WIN32).str_view()! == `\`);
assert(path::new(`/./`, .path_env = PathEnv.POSIX).str_view()! == `/`);
assert(path::new(`/.`, .path_env = PathEnv.WIN32).str_view()! == `\`);
assert(path::new(`/.`, .path_env = PathEnv.POSIX).str_view()! == `/`);
assert(path::new(`/`, .path_env = PathEnv.WIN32).str_view()! == `\`);
assert(path::new(`/`, .path_env = PathEnv.POSIX).str_view()! == `/`);
assert(path::new(`C:/a`, .path_env = PathEnv.WIN32).str_view()! == `C:\a`);
assert(path::new(`C:/a`, .path_env = PathEnv.POSIX).str_view()! == `C:/a`);
assert(path::new(`C:/a/b/../c`, .path_env = PathEnv.WIN32).str_view()! == `C:\a\c`);
assert(path::new(`C:/a/b/../c`, .path_env = PathEnv.POSIX).str_view()! == `C:/a/c`);
assert(path::new(`C:/a/b/../../c`, .path_env = PathEnv.WIN32).str_view()! == `C:\c`);
assert(path::new(`C:/a/b/../../c`, .path_env = PathEnv.POSIX).str_view()! == `C:/c`);
assert(path::new(`C:/a/b/../../../c`, .path_env = PathEnv.POSIX).str_view()! == `c`);
assert(path::new(`C:/a/b/..`, .path_env = PathEnv.WIN32).str_view()! == `C:\a`);
assert(path::new(`C:/a/b/..`, .path_env = PathEnv.POSIX).str_view()! == `C:/a`);
assert(path::new(`C:/a/b/../..`, .path_env = PathEnv.WIN32).str_view()! == `C:\`);
assert(path::new(`C:/a/b/../..`, .path_env = PathEnv.POSIX).str_view()! == `C:`);
assert(path::new(`C:/a/b/../c/../d`, .path_env = PathEnv.WIN32).str_view()! == `C:\a\d`);
assert(path::new(`C:/a/b/../c/../d`, .path_env = PathEnv.POSIX).str_view()! == `C:/a/d`);
assert(path::new(`C:/a/b//d`, .path_env = PathEnv.WIN32).str_view()! == `C:\a\b\d`);
assert(path::new(`C:/a/b//d`, .path_env = PathEnv.POSIX).str_view()! == `C:/a/b/d`);
assert(path::new(`C:/a/b/././.`, .path_env = PathEnv.WIN32).str_view()! == `C:\a\b`);
assert(path::new(`C:/a/b/././.`, .path_env = PathEnv.POSIX).str_view()! == `C:/a/b`);
assert(path::new(`C:/./a`, .path_env = PathEnv.WIN32).str_view()! == `C:\a`);
assert(path::new(`C:/./a`, .path_env = PathEnv.POSIX).str_view()! == `C:/a`);
assert(path::new(`C:/./`, .path_env = PathEnv.WIN32).str_view()! == `C:\`);
assert(path::new(`C:/./`, .path_env = PathEnv.POSIX).str_view()! == `C:`);
assert(path::new(`C:/../a`, .path_env = PathEnv.POSIX).str_view()! == `a`);
assert(path::new(`C:/..`, .path_env = PathEnv.POSIX).str_view()! == `.`);
assert(path::new(`C:/`, .path_env = PathEnv.WIN32).str_view()! == `C:\`);
assert(path::new(`C:/`, .path_env = PathEnv.POSIX).str_view()! == `C:`);
assert(path::new(`C:a`, .path_env = PathEnv.WIN32).str_view()! == `C:a`);
assert(path::new(`C:a`, .path_env = PathEnv.POSIX).str_view()! == `C:a`);
assert(path::new(`C:a/`, .path_env = PathEnv.WIN32).str_view()! == `C:a`);
assert(path::new(`C:a/`, .path_env = PathEnv.POSIX).str_view()! == `C:a`);
assert(path::new(`a/b/../../../c`, path_env: PathEnv.WIN32).str_view()! == `..\c`);
assert(path::new(`a/b/../../../c`, path_env: PathEnv.POSIX).str_view()! == `../c`);
assert(path::new(`a/b/../../..`, path_env: PathEnv.WIN32).str_view()! == `..`);
assert(path::new(`a/b/../../..`, path_env: PathEnv.POSIX).str_view()! == `..`);
assert(path::new(`../a`, path_env: PathEnv.WIN32).str_view()! == `..\a`);
assert(path::new(`../a`, path_env: PathEnv.POSIX).str_view()! == `../a`);
assert(path::new(`..`, path_env: PathEnv.WIN32).str_view()! == `..`);
assert(path::new(`..`, path_env: PathEnv.POSIX).str_view()! == `..`);
assert(path::new(`a/b/../c`, path_env: PathEnv.WIN32).str_view()! == `a\c`);
assert(path::new(`a/b/../c`, path_env: PathEnv.POSIX).str_view()! == `a/c`);
assert(path::new(`a/b/../../c`, path_env: PathEnv.WIN32).str_view()! == `c`);
assert(path::new(`a/b/../../c`, path_env: PathEnv.POSIX).str_view()! == `c`);
assert(path::new(`a/b/..`, path_env: PathEnv.WIN32).str_view()! == `a`);
assert(path::new(`a/b/..`, path_env: PathEnv.POSIX).str_view()! == `a`);
assert(path::new(`a/b/../`, path_env: PathEnv.WIN32).str_view()! == `a`);
assert(path::new(`a/b/../`, path_env: PathEnv.POSIX).str_view()! == `a`);
assert(path::new(`a/b/../..`, path_env: PathEnv.WIN32).str_view()! == ".");
assert(path::new(`a/b/../..`, path_env: PathEnv.POSIX).str_view()! == ".");
assert(path::new(`a/b/../../`, path_env: PathEnv.WIN32).str_view()! == ".");
assert(path::new(`a/b/../../`, path_env: PathEnv.POSIX).str_view()! == ".");
assert(path::new(`a/b/../c/../d`, path_env: PathEnv.WIN32).str_view()! == `a\d`);
assert(path::new(`a/b/../c/../d`, path_env: PathEnv.POSIX).str_view()! == `a/d`);
assert(path::new(`a/b/../c/../d/`, path_env: PathEnv.WIN32).str_view()! == `a\d`);
assert(path::new(`a/b/../c/../d/`, path_env: PathEnv.POSIX).str_view()! == `a/d`);
assert(path::new(`a/b//d`, path_env: PathEnv.WIN32).str_view()! == `a\b\d`);
assert(path::new(`a/b//d`, path_env: PathEnv.POSIX).str_view()! == `a/b/d`);
assert(path::new(`a/b/././.`, path_env: PathEnv.WIN32).str_view()! == `a\b`);
assert(path::new(`a/b/././.`, path_env: PathEnv.POSIX).str_view()! == `a/b`);
assert(path::new(`a/b/./././`, path_env: PathEnv.WIN32).str_view()! == `a\b`);
assert(path::new(`a/b/./././`, path_env: PathEnv.POSIX).str_view()! == `a/b`);
assert(path::new(`./a/`, path_env: PathEnv.WIN32).str_view()! == `a`);
assert(path::new(`./a/`, path_env: PathEnv.POSIX).str_view()! == `a`);
assert(path::new(`./`, path_env: PathEnv.WIN32).str_view()! == `.`);
assert(path::new(`./`, path_env: PathEnv.POSIX).str_view()! == `.`);
assert(path::new(`.`, path_env: PathEnv.WIN32).str_view()! == `.`);
assert(path::new(`.`, path_env: PathEnv.POSIX).str_view()! == `.`);
assert(path::new(``, path_env: PathEnv.WIN32).str_view()! == ``);
assert(path::new(``, path_env: PathEnv.POSIX).str_view()! == ``);
assert(path::new(`/a`, path_env: PathEnv.WIN32).str_view()! == `\a`);
assert(path::new(`/a`, path_env: PathEnv.POSIX).str_view()! == `/a`);
assert(path::new(`/a/`, path_env: PathEnv.WIN32).str_view()! == `\a`);
assert(path::new(`/a/`, path_env: PathEnv.POSIX).str_view()! == `/a`);
assert(path::new(`/a/b/../c`, path_env: PathEnv.WIN32).str_view()! == `\a\c`);
assert(path::new(`/a/b/../c`, path_env: PathEnv.POSIX).str_view()! == `/a/c`);
assert(path::new(`/a/b/../../c`, path_env: PathEnv.WIN32).str_view()! == `\c`);
assert(path::new(`/a/b/../../c`, path_env: PathEnv.POSIX).str_view()! == `/c`);
assert(path::new(`/a/b/..`, path_env: PathEnv.WIN32).str_view()! == `\a`);
assert(path::new(`/a/b/..`, path_env: PathEnv.POSIX).str_view()! == `/a`);
assert(path::new(`/a/b/../..`, path_env: PathEnv.WIN32).str_view()! == `\`);
assert(path::new(`/a/b/../..`, path_env: PathEnv.POSIX).str_view()! == `/`);
assert(path::new(`/a/b/../c/../d`, path_env: PathEnv.WIN32).str_view()! == `\a\d`);
assert(path::new(`/a/b/../c/../d`, path_env: PathEnv.POSIX).str_view()! == `/a/d`);
assert(path::new(`/a/b//d`, path_env: PathEnv.WIN32).str_view()! == `\a\b\d`);
assert(path::new(`/a/b//d`, path_env: PathEnv.POSIX).str_view()! == `/a/b/d`);
assert(path::new(`/./a/`, path_env: PathEnv.WIN32).str_view()! == `\a`);
assert(path::new(`/./a/`, path_env: PathEnv.POSIX).str_view()! == `/a`);
assert(path::new(`/./`, path_env: PathEnv.WIN32).str_view()! == `\`);
assert(path::new(`/./`, path_env: PathEnv.POSIX).str_view()! == `/`);
assert(path::new(`/.`, path_env: PathEnv.WIN32).str_view()! == `\`);
assert(path::new(`/.`, path_env: PathEnv.POSIX).str_view()! == `/`);
assert(path::new(`/`, path_env: PathEnv.WIN32).str_view()! == `\`);
assert(path::new(`/`, path_env: PathEnv.POSIX).str_view()! == `/`);
assert(path::new(`C:/a`, path_env: PathEnv.WIN32).str_view()! == `C:\a`);
assert(path::new(`C:/a`, path_env: PathEnv.POSIX).str_view()! == `C:/a`);
assert(path::new(`C:/a/b/../c`, path_env: PathEnv.WIN32).str_view()! == `C:\a\c`);
assert(path::new(`C:/a/b/../c`, path_env: PathEnv.POSIX).str_view()! == `C:/a/c`);
assert(path::new(`C:/a/b/../../c`, path_env: PathEnv.WIN32).str_view()! == `C:\c`);
assert(path::new(`C:/a/b/../../c`, path_env: PathEnv.POSIX).str_view()! == `C:/c`);
assert(path::new(`C:/a/b/../../../c`, path_env: PathEnv.POSIX).str_view()! == `c`);
assert(path::new(`C:/a/b/..`, path_env: PathEnv.WIN32).str_view()! == `C:\a`);
assert(path::new(`C:/a/b/..`, path_env: PathEnv.POSIX).str_view()! == `C:/a`);
assert(path::new(`C:/a/b/../..`, path_env: PathEnv.WIN32).str_view()! == `C:\`);
assert(path::new(`C:/a/b/../..`, path_env: PathEnv.POSIX).str_view()! == `C:`);
assert(path::new(`C:/a/b/../c/../d`, path_env: PathEnv.WIN32).str_view()! == `C:\a\d`);
assert(path::new(`C:/a/b/../c/../d`, path_env: PathEnv.POSIX).str_view()! == `C:/a/d`);
assert(path::new(`C:/a/b//d`, path_env: PathEnv.WIN32).str_view()! == `C:\a\b\d`);
assert(path::new(`C:/a/b//d`, path_env: PathEnv.POSIX).str_view()! == `C:/a/b/d`);
assert(path::new(`C:/a/b/././.`, path_env: PathEnv.WIN32).str_view()! == `C:\a\b`);
assert(path::new(`C:/a/b/././.`, path_env: PathEnv.POSIX).str_view()! == `C:/a/b`);
assert(path::new(`C:/./a`, path_env: PathEnv.WIN32).str_view()! == `C:\a`);
assert(path::new(`C:/./a`, path_env: PathEnv.POSIX).str_view()! == `C:/a`);
assert(path::new(`C:/./`, path_env: PathEnv.WIN32).str_view()! == `C:\`);
assert(path::new(`C:/./`, path_env: PathEnv.POSIX).str_view()! == `C:`);
assert(path::new(`C:/../a`, path_env: PathEnv.POSIX).str_view()! == `a`);
assert(path::new(`C:/..`, path_env: PathEnv.POSIX).str_view()! == `.`);
assert(path::new(`C:/`, path_env: PathEnv.WIN32).str_view()! == `C:\`);
assert(path::new(`C:/`, path_env: PathEnv.POSIX).str_view()! == `C:`);
assert(path::new(`C:a`, path_env: PathEnv.WIN32).str_view()! == `C:a`);
assert(path::new(`C:a`, path_env: PathEnv.POSIX).str_view()! == `C:a`);
assert(path::new(`C:a/`, path_env: PathEnv.WIN32).str_view()! == `C:a`);
assert(path::new(`C:a/`, path_env: PathEnv.POSIX).str_view()! == `C:a`);
assert(path::new(`C:a/b/../c`, .path_env = PathEnv.WIN32).str_view()! == `C:a\c`);
assert(path::new(`C:a/b/../c`, .path_env = PathEnv.POSIX).str_view()! == `C:a/c`);
assert(path::new(`C:a/b/../../c`, .path_env = PathEnv.WIN32).str_view()! == `C:c`);
assert(path::new(`C:a/b/../../c`, .path_env = PathEnv.POSIX).str_view()! == `c`);
assert(path::new(`C:a/b/..`, .path_env = PathEnv.WIN32).str_view()! == `C:a`);
assert(path::new(`C:a/b/..`, .path_env = PathEnv.POSIX).str_view()! == `C:a`);
assert(path::new(`C:a/b/../..`, .path_env = PathEnv.WIN32).str_view()! == `C:`);
assert(path::new(`C:a/b/../..`, .path_env = PathEnv.POSIX).str_view()! == `.`);
assert(path::new(`C:a/b/../c/../d`, .path_env = PathEnv.WIN32).str_view()! == `C:a\d`);
assert(path::new(`C:a/b/../c/../d`, .path_env = PathEnv.POSIX).str_view()! == `C:a/d`);
assert(path::new(`C:a/b//d`, .path_env = PathEnv.WIN32).str_view()! == `C:a\b\d`);
assert(path::new(`C:a/b//d`, .path_env = PathEnv.POSIX).str_view()! == `C:a/b/d`);
assert(path::new(`C:a/b/././.`, .path_env = PathEnv.WIN32).str_view()! == `C:a\b`);
assert(path::new(`C:a/b/././.`, .path_env = PathEnv.POSIX).str_view()! == `C:a/b`);
assert(path::new(`C:a/b/../../../c`, .path_env = PathEnv.WIN32).str_view()! == `C:..\c`);
assert(path::new(`C:./a`, .path_env = PathEnv.WIN32).str_view()! == `C:a`);
assert(path::new(`C:./a`, .path_env = PathEnv.POSIX).str_view()! == `C:./a`);
assert(path::new(`C:./`, .path_env = PathEnv.WIN32).str_view()! == `C:`);
assert(path::new(`C:./`, .path_env = PathEnv.POSIX).str_view()! == `C:.`);
assert(path::new(`C:../a`, .path_env = PathEnv.POSIX).str_view()! == `C:../a`);
assert(path::new(`C:../a`, .path_env = PathEnv.WIN32).str_view()! == `C:..\a`);
assert(path::new(`C:..`, .path_env = PathEnv.POSIX).str_view()! == `C:..`);
assert(path::new(`C:..`, .path_env = PathEnv.WIN32).str_view()! == `C:..`);
assert(path::new(`C:`, .path_env = PathEnv.WIN32).str_view()! == `C:`);
assert(path::new(`C:`, .path_env = PathEnv.POSIX).str_view()! == `C:`);
assert(path::new(`C:a/b/../c`, path_env: PathEnv.WIN32).str_view()! == `C:a\c`);
assert(path::new(`C:a/b/../c`, path_env: PathEnv.POSIX).str_view()! == `C:a/c`);
assert(path::new(`C:a/b/../../c`, path_env: PathEnv.WIN32).str_view()! == `C:c`);
assert(path::new(`C:a/b/../../c`, path_env: PathEnv.POSIX).str_view()! == `c`);
assert(path::new(`C:a/b/..`, path_env: PathEnv.WIN32).str_view()! == `C:a`);
assert(path::new(`C:a/b/..`, path_env: PathEnv.POSIX).str_view()! == `C:a`);
assert(path::new(`C:a/b/../..`, path_env: PathEnv.WIN32).str_view()! == `C:`);
assert(path::new(`C:a/b/../..`, path_env: PathEnv.POSIX).str_view()! == `.`);
assert(path::new(`C:a/b/../c/../d`, path_env: PathEnv.WIN32).str_view()! == `C:a\d`);
assert(path::new(`C:a/b/../c/../d`, path_env: PathEnv.POSIX).str_view()! == `C:a/d`);
assert(path::new(`C:a/b//d`, path_env: PathEnv.WIN32).str_view()! == `C:a\b\d`);
assert(path::new(`C:a/b//d`, path_env: PathEnv.POSIX).str_view()! == `C:a/b/d`);
assert(path::new(`C:a/b/././.`, path_env: PathEnv.WIN32).str_view()! == `C:a\b`);
assert(path::new(`C:a/b/././.`, path_env: PathEnv.POSIX).str_view()! == `C:a/b`);
assert(path::new(`C:a/b/../../../c`, path_env: PathEnv.WIN32).str_view()! == `C:..\c`);
assert(path::new(`C:./a`, path_env: PathEnv.WIN32).str_view()! == `C:a`);
assert(path::new(`C:./a`, path_env: PathEnv.POSIX).str_view()! == `C:./a`);
assert(path::new(`C:./`, path_env: PathEnv.WIN32).str_view()! == `C:`);
assert(path::new(`C:./`, path_env: PathEnv.POSIX).str_view()! == `C:.`);
assert(path::new(`C:../a`, path_env: PathEnv.POSIX).str_view()! == `C:../a`);
assert(path::new(`C:../a`, path_env: PathEnv.WIN32).str_view()! == `C:..\a`);
assert(path::new(`C:..`, path_env: PathEnv.POSIX).str_view()! == `C:..`);
assert(path::new(`C:..`, path_env: PathEnv.WIN32).str_view()! == `C:..`);
assert(path::new(`C:`, path_env: PathEnv.WIN32).str_view()! == `C:`);
assert(path::new(`C:`, path_env: PathEnv.POSIX).str_view()! == `C:`);
assert(path::new(`\\server\foo/a`, .path_env = PathEnv.WIN32).str_view()! == `\\server\foo\a`);
assert(path::new(`\\server\foo/a`, .path_env = PathEnv.POSIX).str_view()! == `\\server\foo/a`);
assert(path::new(`\\server\foo\a\b\..\c`, .path_env = PathEnv.WIN32).str_view()! == `\\server\foo\a\c`);
assert(path::new(`\\server\foo\a\b\..\..\c`, .path_env = PathEnv.WIN32).str_view()! == `\\server\foo\c`);
assert(path::new(`\\server\foo\a\b\..`, .path_env = PathEnv.WIN32).str_view()! == `\\server\foo\a`);
assert(path::new(`\\server\foo\a\..`, .path_env = PathEnv.WIN32).str_view()! == `\\server\foo\`);
assert(path::new(`\\server\foo\a\b\..\c\..\d`, .path_env = PathEnv.WIN32).str_view()! == `\\server\foo\a\d`);
assert(path::new(`\\server\foo\a\b\\d`, .path_env = PathEnv.WIN32).str_view()! == `\\server\foo\a\b\d`);
assert(path::new(`\\server\foo\a\b\.\.\.`, .path_env = PathEnv.WIN32).str_view()! == `\\server\foo\a\b`);
assert(path::new(`\\server\foo\.\a`, .path_env = PathEnv.WIN32).str_view()! == `\\server\foo\a`);
assert(path::new(`\\server\foo\.`, .path_env = PathEnv.WIN32).str_view()! == `\\server\foo\`);
assert(path::new(`\\server\foo\`, .path_env = PathEnv.WIN32).str_view()! == `\\server\foo\`);
assert(path::new(`\\server\foo/a`, path_env: PathEnv.WIN32).str_view()! == `\\server\foo\a`);
assert(path::new(`\\server\foo/a`, path_env: PathEnv.POSIX).str_view()! == `\\server\foo/a`);
assert(path::new(`\\server\foo\a\b\..\c`, path_env: PathEnv.WIN32).str_view()! == `\\server\foo\a\c`);
assert(path::new(`\\server\foo\a\b\..\..\c`, path_env: PathEnv.WIN32).str_view()! == `\\server\foo\c`);
assert(path::new(`\\server\foo\a\b\..`, path_env: PathEnv.WIN32).str_view()! == `\\server\foo\a`);
assert(path::new(`\\server\foo\a\..`, path_env: PathEnv.WIN32).str_view()! == `\\server\foo\`);
assert(path::new(`\\server\foo\a\b\..\c\..\d`, path_env: PathEnv.WIN32).str_view()! == `\\server\foo\a\d`);
assert(path::new(`\\server\foo\a\b\\d`, path_env: PathEnv.WIN32).str_view()! == `\\server\foo\a\b\d`);
assert(path::new(`\\server\foo\a\b\.\.\.`, path_env: PathEnv.WIN32).str_view()! == `\\server\foo\a\b`);
assert(path::new(`\\server\foo\.\a`, path_env: PathEnv.WIN32).str_view()! == `\\server\foo\a`);
assert(path::new(`\\server\foo\.`, path_env: PathEnv.WIN32).str_view()! == `\\server\foo\`);
assert(path::new(`\\server\foo\`, path_env: PathEnv.WIN32).str_view()! == `\\server\foo\`);
}
fn void! test_extension()
{
assert(@catch(path::new(`C:`, .path_env = PathEnv.WIN32).extension()));
assert(@catch(path::new(`C:`, .path_env = PathEnv.POSIX).extension()));
assert(@catch(path::new(`file`, .path_env = PathEnv.WIN32).extension()));
assert(@catch(path::new(`file`, .path_env = PathEnv.POSIX).extension()));
assert(@catch(path::new(`C:\temp\foo.bar\README`, .path_env = PathEnv.WIN32).extension()));
assert(@catch(path::new(`C:`, path_env: PathEnv.WIN32).extension()));
assert(@catch(path::new(`C:`, path_env: PathEnv.POSIX).extension()));
assert(@catch(path::new(`file`, path_env: PathEnv.WIN32).extension()));
assert(@catch(path::new(`file`, path_env: PathEnv.POSIX).extension()));
assert(@catch(path::new(`C:\temp\foo.bar\README`, path_env: PathEnv.WIN32).extension()));
assert(path::new_windows("file.txt").extension()! == "txt");
assert(path::new_posix("file.txt").extension()! == "txt");
@@ -241,7 +241,7 @@ fn void! test_extension()
fn void! test_has_extension()
{
assert(!path::new(`C:\temp\foo.bar\README`, .path_env = PathEnv.WIN32)!.has_extension(`bar\README`));
assert(!path::new(`C:\temp\foo.bar\README`, path_env: PathEnv.WIN32)!.has_extension(`bar\README`));
assert(path::new_windows("file.txt")!.has_extension("txt"));
assert(path::new_posix("file.txt")!.has_extension("txt"));

View File

@@ -11,7 +11,7 @@ fn String add(String s, Allocator a, int x)
};
ulong* y = mem::temp_alloc(ulong);
*y = 0xAAAA_AAAA_AAAA_AAAA;
return tmp.concat("a", .allocator = a);
return tmp.concat("a", allocator: a);
}
fn String breakit(String s, Allocator a)