From ed5d338a39eb0c0d4bb19f80807f9d0bc5dafff5 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Tue, 27 Aug 2024 22:31:22 +0200 Subject: [PATCH] Added new style named arguments. --- lib/std/collections/anylist.c3 | 4 +- lib/std/collections/elastic_array.c3 | 4 +- lib/std/collections/enummap.c3 | 4 +- lib/std/collections/enumset.c3 | 4 +- lib/std/collections/list.c3 | 4 +- lib/std/collections/map.c3 | 2 +- lib/std/collections/object.c3 | 4 +- lib/std/collections/range.c3 | 6 +- lib/std/core/allocators/tracking_allocator.c3 | 2 +- lib/std/core/builtin.c3 | 2 +- lib/std/core/mem_allocator.c3 | 2 +- lib/std/core/string.c3 | 2 +- lib/std/encoding/csv.c3 | 4 +- lib/std/encoding/json.c3 | 2 +- lib/std/io/os/ls.c3 | 4 +- lib/std/io/path.c3 | 4 +- lib/std/io/stream/bytebuffer.c3 | 2 +- lib/std/os/env.c3 | 2 +- lib/std/os/win32/process.c3 | 4 +- releasenotes.md | 2 +- resources/grammar/grammar.y | 12 +- src/compiler/compiler_internal.h | 18 +- src/compiler/copying.c | 3 + src/compiler/enums.h | 1 + src/compiler/expr.c | 23 +- src/compiler/llvm_codegen_expr.c | 1 + src/compiler/parse_expr.c | 99 ++++- src/compiler/parser_internal.h | 13 + src/compiler/sema_expr.c | 88 ++--- src/compiler/sema_liveness.c | 1 + src/compiler/sema_stmts.c | 1 + test/test_suite/functions/ct_named_params.c3t | 2 +- .../functions/defered_default_arguments.c3t | 4 +- .../func_ptr_conversions_and_names.c3t | 2 +- test/test_suite/functions/named_arg_order.c3 | 11 + test/test_suite/functions/unsplat_named.c3 | 2 +- .../functions/vararg_and_named_tests.c3 | 8 +- .../functions/varargs_followed_by_named.c3t | 4 +- .../generic/generic_lambda_complex.c3t | 2 +- .../switch/switch_in_defer_macro.c3t | 2 +- test/unit/stdlib/io/path.c3 | 346 +++++++++--------- test/unit/stdlib/mem/temp_mem.c3 | 2 +- 42 files changed, 405 insertions(+), 304 deletions(-) create mode 100644 test/test_suite/functions/named_arg_order.c3 diff --git a/lib/std/collections/anylist.c3 b/lib/std/collections/anylist.c3 index 18b091ddd..95a6653de 100644 --- a/lib/std/collections/anylist.c3 +++ b/lib/std/collections/anylist.c3 @@ -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); diff --git a/lib/std/collections/elastic_array.c3 b/lib/std/collections/elastic_array.c3 index d03665c2d..7a38da86a 100644 --- a/lib/std/collections/elastic_array.c3 +++ b/lib/std/collections/elastic_array.c3 @@ -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) diff --git a/lib/std/collections/enummap.c3 b/lib/std/collections/enummap.c3 index cf8fda36b..2271f5498 100644 --- a/lib/std/collections/enummap.c3 +++ b/lib/std/collections/enummap.c3 @@ -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 diff --git a/lib/std/collections/enumset.c3 b/lib/std/collections/enumset.c3 index 3181d1ea7..00711b89f 100644 --- a/lib/std/collections/enumset.c3 +++ b/lib/std/collections/enumset.c3 @@ -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 diff --git a/lib/std/collections/list.c3 b/lib/std/collections/list.c3 index e23d48294..8809974a7 100644 --- a/lib/std/collections/list.c3 +++ b/lib/std/collections/list.c3 @@ -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; diff --git a/lib/std/collections/map.c3 b/lib/std/collections/map.c3 index 21c5eba1e..fe9b0fb56 100644 --- a/lib/std/collections/map.c3 +++ b/lib/std/collections/map.c3 @@ -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()); diff --git a/lib/std/collections/object.c3 b/lib/std/collections/object.c3 index 141d610a1..12bfa1bbd 100644 --- a/lib/std/collections/object.c3 +++ b/lib/std/collections/object.c3 @@ -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); } } diff --git a/lib/std/collections/range.c3 b/lib/std/collections/range.c3 index 102828141..7f8c26aba 100644 --- a/lib/std/collections/range.c3 +++ b/lib/std/collections/range.c3 @@ -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) diff --git a/lib/std/core/allocators/tracking_allocator.c3 b/lib/std/core/allocators/tracking_allocator.c3 index ae2ae68da..99ecb5943 100644 --- a/lib/std/core/allocators/tracking_allocator.c3 +++ b/lib/std/core/allocators/tracking_allocator.c3 @@ -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); } /** diff --git a/lib/std/core/builtin.c3 b/lib/std/core/builtin.c3 index c8ad66ad3..dc6370e6d 100644 --- a/lib/std/core/builtin.c3 +++ b/lib/std/core/builtin.c3 @@ -146,7 +146,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); in_panic = false; panic(s.str_view(), file, function, line); diff --git a/lib/std/core/mem_allocator.c3 b/lib/std/core/mem_allocator.c3 index 4e3768786..945af2289 100644 --- a/lib/std/core/mem_allocator.c3 +++ b/lib/std/core/mem_allocator.c3 @@ -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); } /** diff --git a/lib/std/core/string.c3 b/lib/std/core/string.c3 index 917ba8fd5..45faf36c5 100644 --- a/lib/std/core/string.c3 +++ b/lib/std/core/string.c3 @@ -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. diff --git a/lib/std/encoding/csv.c3 b/lib/std/encoding/csv.c3 index 25050c53f..cae32db50 100644 --- a/lib/std/encoding/csv.c3 +++ b/lib/std/encoding/csv.c3 @@ -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); }; diff --git a/lib/std/encoding/json.c3 b/lib/std/encoding/json.c3 index 98448e49a..c463b4d40 100644 --- a/lib/std/encoding/json.c3 +++ b/lib/std/encoding/json.c3 @@ -106,7 +106,7 @@ fn JsonTokenType! lex_number(JsonContext *context, char c) @local { @stack_mem(256; Allocator mem) { - DString t = dstring::new_with_capacity(32, .allocator = mem); + DString t = dstring::new_with_capacity(32, allocator: mem); bool negate = c == '-'; if (negate) { diff --git a/lib/std/io/os/ls.c3 b/lib/std/io/os/ls.c3 index 0a72fb7eb..3dcef7089 100644 --- a/lib/std/io/os/ls.c3 +++ b/lib/std/io/os/ls.c3 @@ -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) { diff --git a/lib/std/io/path.c3 b/lib/std/io/path.c3 index 1776fe4cd..9e9c6e82c 100644 --- a/lib/std/io/path.c3 +++ b/lib/std/io/path.c3 @@ -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; diff --git a/lib/std/io/stream/bytebuffer.c3 b/lib/std/io/stream/bytebuffer.c3 index 8864b3630..764640883 100644 --- a/lib/std/io/stream/bytebuffer.c3 +++ b/lib/std/io/stream/bytebuffer.c3 @@ -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]; } diff --git a/lib/std/os/env.c3 b/lib/std/os/env.c3 index bbe1ebd6f..c0f8ea8ce 100644 --- a/lib/std/os/env.c3 +++ b/lib/std/os/env.c3 @@ -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 }; } diff --git a/lib/std/os/win32/process.c3 b/lib/std/os/win32/process.c3 index c57155baa..7986388b2 100644 --- a/lib/std/os/win32/process.c3 +++ b/lib/std/os/win32/process.c3 @@ -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; } diff --git a/releasenotes.md b/releasenotes.md index 15ccd00fd..9da7c594c 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -3,7 +3,7 @@ ## 0.6.3 Change list ### Changes / improvements -*None yet* +- Introduce `arg: x` named arguments instead of `.arg = x`, deprecate old style. ### Fixes - Issue where a lambda wasn't correctly registered as external. #1408 diff --git a/resources/grammar/grammar.y b/resources/grammar/grammar.y index 34531d042..67d3ad446 100644 --- a/resources/grammar/grammar.y +++ b/resources/grammar/grammar.y @@ -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 diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 284072755..16f9f04ca 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -597,9 +597,9 @@ typedef struct Decl_ void *backend_value; void *tb_symbol; }; - AlignSize alignment; AlignSize offset; AlignSize padding; + AlignSize alignment; struct CompilationUnit_ *unit; union { @@ -793,6 +793,13 @@ typedef struct Expr *value; } ExprDesignator; +typedef struct +{ + const char *name; + SourceSpan name_span; + Expr *value; +} ExprNamedArgument; + typedef struct { Decl *type; @@ -1079,6 +1086,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 @@ -3132,7 +3140,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) { @@ -3176,11 +3184,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) { diff --git a/src/compiler/copying.c b/src/compiler/copying.c index 3c702c84a..db2350c64 100644 --- a/src/compiler/copying.c +++ b/src/compiler/copying.c @@ -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); diff --git a/src/compiler/enums.h b/src/compiler/enums.h index b8392accf..0966e88c4 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -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, diff --git a/src/compiler/expr.c b/src/compiler/expr.c index 14720f229..202c51410 100644 --- a/src/compiler/expr.c +++ b/src/compiler/expr.c @@ -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: diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index b17bdc512..ca5c09c90 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -7095,6 +7095,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); diff --git a/src/compiler/parse_expr.c b/src/compiler/parse_expr.c index 39855c5b3..ead200fbb 100644 --- a/src/compiler/parse_expr.c +++ b/src/compiler/parse_expr.c @@ -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) { diff --git a/src/compiler/parser_internal.h b/src/compiler/parser_internal.h index d03116df0..d3f41061b 100644 --- a/src/compiler/parser_internal.h +++ b/src/compiler/parser_internal.h @@ -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) diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index d0c216eb9..626af63ee 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -141,7 +141,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); @@ -567,6 +566,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 @@ -641,8 +641,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: @@ -654,27 +655,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: @@ -682,18 +688,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 @@ -1161,51 +1162,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); @@ -1277,13 +1244,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); @@ -1299,7 +1267,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. @@ -1308,12 +1276,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) @@ -1443,7 +1415,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)) @@ -8396,6 +8368,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; @@ -8888,6 +8861,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."); diff --git a/src/compiler/sema_liveness.c b/src/compiler/sema_liveness.c index 630840aa5..decd2dc68 100644 --- a/src/compiler/sema_liveness.c +++ b/src/compiler/sema_liveness.c @@ -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); diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index fd69825a3..95f424ff5 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -656,6 +656,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: diff --git a/test/test_suite/functions/ct_named_params.c3t b/test/test_suite/functions/ct_named_params.c3t index 081ee7157..286b8d58f 100644 --- a/test/test_suite/functions/ct_named_params.c3t +++ b/test/test_suite/functions/ct_named_params.c3t @@ -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 diff --git a/test/test_suite/functions/defered_default_arguments.c3t b/test/test_suite/functions/defered_default_arguments.c3t index 86367a541..baabb7beb 100644 --- a/test/test_suite/functions/defered_default_arguments.c3t +++ b/test/test_suite/functions/defered_default_arguments.c3t @@ -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(); } diff --git a/test/test_suite/functions/func_ptr_conversions_and_names.c3t b/test/test_suite/functions/func_ptr_conversions_and_names.c3t index 09bff4ced..57cf0d55e 100644 --- a/test/test_suite/functions/func_ptr_conversions_and_names.c3t +++ b/test/test_suite/functions/func_ptr_conversions_and_names.c3t @@ -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()); diff --git a/test/test_suite/functions/named_arg_order.c3 b/test/test_suite/functions/named_arg_order.c3 new file mode 100644 index 000000000..adf7c7389 --- /dev/null +++ b/test/test_suite/functions/named_arg_order.c3 @@ -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 +} \ No newline at end of file diff --git a/test/test_suite/functions/unsplat_named.c3 b/test/test_suite/functions/unsplat_named.c3 index 760acb708..6e5ed0503 100644 --- a/test/test_suite/functions/unsplat_named.c3 +++ b/test/test_suite/functions/unsplat_named.c3 @@ -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); } \ No newline at end of file diff --git a/test/test_suite/functions/vararg_and_named_tests.c3 b/test/test_suite/functions/vararg_and_named_tests.c3 index 05528e0b6..eb9b038e2 100644 --- a/test/test_suite/functions/vararg_and_named_tests.c3 +++ b/test/test_suite/functions/vararg_and_named_tests.c3 @@ -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 } diff --git a/test/test_suite/functions/varargs_followed_by_named.c3t b/test/test_suite/functions/varargs_followed_by_named.c3t index ba5935c0b..73c89e108 100644 --- a/test/test_suite/functions/varargs_followed_by_named.c3t +++ b/test/test_suite/functions/varargs_followed_by_named.c3t @@ -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); } diff --git a/test/test_suite/generic/generic_lambda_complex.c3t b/test/test_suite/generic/generic_lambda_complex.c3t index 0493b91f6..298bb3687 100644 --- a/test/test_suite/generic/generic_lambda_complex.c3t +++ b/test/test_suite/generic/generic_lambda_complex.c3t @@ -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()!!; diff --git a/test/test_suite/switch/switch_in_defer_macro.c3t b/test/test_suite/switch/switch_in_defer_macro.c3t index 1f122f2f2..12c33d4c9 100644 --- a/test/test_suite/switch/switch_in_defer_macro.c3t +++ b/test/test_suite/switch/switch_in_defer_macro.c3t @@ -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{}); } diff --git a/test/unit/stdlib/io/path.c3 b/test/unit/stdlib/io/path.c3 index f3851d630..890daab6d 100644 --- a/test/unit/stdlib/io/path.c3 +++ b/test/unit/stdlib/io/path.c3 @@ -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")); diff --git a/test/unit/stdlib/mem/temp_mem.c3 b/test/unit/stdlib/mem/temp_mem.c3 index c94434dae..c981b6a34 100644 --- a/test/unit/stdlib/mem/temp_mem.c3 +++ b/test/unit/stdlib/mem/temp_mem.c3 @@ -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)