@shd101wyy/yo 0.1.21 → 0.1.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@shd101wyy/yo",
3
3
  "displayName": "Yo",
4
- "version": "0.1.21",
4
+ "version": "0.1.23",
5
5
  "main": "./out/cjs/index.cjs",
6
6
  "module": "./out/esm/index.mjs",
7
7
  "types": "./out/types/src/index.d.ts",
@@ -0,0 +1,143 @@
1
+ # Yo language installer for Windows (PowerShell).
2
+ #
3
+ # Installs Yo into $env:LOCALAPPDATA\Yo and links the `yo` command into
4
+ # $env:LOCALAPPDATA\Yo\bin (added to user PATH).
5
+ #
6
+ # Usage:
7
+ # irm https://raw.githubusercontent.com/shd101wyy/yo/main/scripts/install.ps1 | iex
8
+ # # or, after cloning:
9
+ # .\scripts\install.ps1
10
+ #
11
+ # Environment variables / parameters:
12
+ # -InstallDir <path> Target install dir. Default: $env:LOCALAPPDATA\Yo
13
+ # -BinDir <path> Wrapper bin dir. Default: $InstallDir\bin
14
+ # -Repo <url> Git repo URL. Default: https://github.com/shd101wyy/yo.git
15
+ # -Ref <ref> Git ref (branch/tag). Default: main
16
+ # -Force Overwrite existing install dir.
17
+
18
+ [CmdletBinding()]
19
+ param(
20
+ [string]$InstallDir = (Join-Path $env:LOCALAPPDATA 'Yo'),
21
+ [string]$BinDir,
22
+ [string]$Repo = 'https://github.com/shd101wyy/yo.git',
23
+ [string]$Ref = 'main',
24
+ [switch]$Force
25
+ )
26
+
27
+ $ErrorActionPreference = 'Stop'
28
+
29
+ if (-not $BinDir) { $BinDir = Join-Path $InstallDir 'bin' }
30
+
31
+ function Info($msg) { Write-Host ">> $msg" -ForegroundColor Cyan }
32
+ function Warn($msg) { Write-Host "!! $msg" -ForegroundColor Yellow }
33
+ function Fail($msg) { Write-Host "XX $msg" -ForegroundColor Red; exit 1 }
34
+
35
+ Info "Installing Yo on Windows"
36
+ Info "Install dir: $InstallDir"
37
+ Info "Bin dir: $BinDir"
38
+
39
+ # ---------------------------------------------------------------------------
40
+ # Required tools
41
+ # ---------------------------------------------------------------------------
42
+
43
+ function Test-Cmd($name) {
44
+ return [bool](Get-Command $name -ErrorAction SilentlyContinue)
45
+ }
46
+
47
+ if (-not (Test-Cmd 'git')) { Fail "Missing required command: git. Install from https://git-scm.com/" }
48
+
49
+ # C compiler (zig recommended on Windows; clang/gcc also work)
50
+ if (-not (Test-Cmd 'zig') -and -not (Test-Cmd 'clang') -and -not (Test-Cmd 'gcc')) {
51
+ Warn "No C compiler found (zig, clang, or gcc). 'yo compile' will not work."
52
+ Warn " Recommended on Windows: install zig via 'winget install zig.zig'"
53
+ }
54
+
55
+ # bun runtime — required to run the current TypeScript-based compiler.
56
+ if (-not (Test-Cmd 'bun')) {
57
+ Info "bun not found - installing via official PowerShell installer..."
58
+ Invoke-RestMethod -Uri 'https://bun.sh/install.ps1' -UseBasicParsing | Invoke-Expression
59
+ $bunBin = Join-Path $env:USERPROFILE '.bun\bin'
60
+ if (Test-Path (Join-Path $bunBin 'bun.exe')) {
61
+ $env:PATH = "$bunBin;$env:PATH"
62
+ }
63
+ if (-not (Test-Cmd 'bun')) {
64
+ Fail "bun installation failed - install manually from https://bun.sh"
65
+ }
66
+ }
67
+ Info "Using bun: $((Get-Command bun).Source) ($(bun --version))"
68
+
69
+ # ---------------------------------------------------------------------------
70
+ # Download Yo
71
+ # ---------------------------------------------------------------------------
72
+
73
+ if (Test-Path $InstallDir) {
74
+ if ($Force) {
75
+ Info "Removing existing install dir (-Force set)"
76
+ Remove-Item -Recurse -Force $InstallDir
77
+ } else {
78
+ Fail "Install dir already exists: $InstallDir. Use -Force to overwrite."
79
+ }
80
+ }
81
+
82
+ Info "Cloning $Repo ($Ref) into $InstallDir"
83
+ $parent = Split-Path -Parent $InstallDir
84
+ if (-not (Test-Path $parent)) { New-Item -ItemType Directory -Path $parent | Out-Null }
85
+ git clone --depth 1 --branch $Ref $Repo $InstallDir
86
+ if ($LASTEXITCODE -ne 0) { Fail "git clone failed" }
87
+
88
+ # ---------------------------------------------------------------------------
89
+ # Build
90
+ # ---------------------------------------------------------------------------
91
+
92
+ Push-Location $InstallDir
93
+ try {
94
+ Info "Installing dependencies (bun install)"
95
+ bun install --silent
96
+ if ($LASTEXITCODE -ne 0) { Fail "bun install failed" }
97
+
98
+ Info "Building Yo (bun run build)"
99
+ bun run build
100
+ if ($LASTEXITCODE -ne 0) { Fail "bun run build failed" }
101
+ } finally {
102
+ Pop-Location
103
+ }
104
+
105
+ # ---------------------------------------------------------------------------
106
+ # Wrapper script
107
+ # ---------------------------------------------------------------------------
108
+
109
+ if (-not (Test-Path $BinDir)) { New-Item -ItemType Directory -Path $BinDir | Out-Null }
110
+
111
+ # yo.cmd — calls the existing yo-cli.ps1
112
+ $wrapperCmd = Join-Path $BinDir 'yo.cmd'
113
+ $yoCli = Join-Path $InstallDir 'yo-cli.ps1'
114
+ @"
115
+ @echo off
116
+ powershell -NoProfile -ExecutionPolicy Bypass -File `"$yoCli`" %*
117
+ "@ | Set-Content -Path $wrapperCmd -Encoding ASCII
118
+
119
+ # yo.ps1 — for direct PowerShell invocation
120
+ $wrapperPs1 = Join-Path $BinDir 'yo.ps1'
121
+ @"
122
+ #!/usr/bin/env pwsh
123
+ & `"$yoCli`" @args
124
+ "@ | Set-Content -Path $wrapperPs1 -Encoding UTF8
125
+
126
+ Info "Installed wrappers: $wrapperCmd, $wrapperPs1"
127
+
128
+ # ---------------------------------------------------------------------------
129
+ # Add bin to user PATH (persistent)
130
+ # ---------------------------------------------------------------------------
131
+
132
+ $userPath = [Environment]::GetEnvironmentVariable('Path', 'User')
133
+ if ($null -eq $userPath) { $userPath = '' }
134
+ $pathParts = $userPath -split ';' | Where-Object { $_ -ne '' }
135
+ if ($pathParts -notcontains $BinDir) {
136
+ $newUserPath = if ($userPath -eq '') { $BinDir } else { "$userPath;$BinDir" }
137
+ [Environment]::SetEnvironmentVariable('Path', $newUserPath, 'User')
138
+ Info "Added $BinDir to user PATH (restart your shell to pick up the change)"
139
+ } else {
140
+ Info "$BinDir already on user PATH"
141
+ }
142
+
143
+ Info "Done. Open a new shell and try: yo --help"
@@ -0,0 +1,139 @@
1
+ #!/usr/bin/env bash
2
+ # Yo language installer for Linux and macOS.
3
+ #
4
+ # Installs Yo into $HOME/.local/Yo and links the `yo` command into
5
+ # $HOME/.local/bin (or a directory of your choice via $YO_BIN_DIR).
6
+ #
7
+ # Usage:
8
+ # curl -fsSL https://raw.githubusercontent.com/shd101wyy/yo/main/scripts/install.sh | bash
9
+ # # or, after cloning:
10
+ # ./scripts/install.sh
11
+ #
12
+ # Environment variables:
13
+ # YO_INSTALL_DIR Target install dir. Default: $HOME/.local/Yo
14
+ # YO_BIN_DIR Wrapper bin dir. Default: $HOME/.local/bin
15
+ # YO_REPO Git repo URL. Default: https://github.com/shd101wyy/yo.git
16
+ # YO_REF Git ref (branch/tag). Default: main
17
+ # YO_FORCE If set, overwrite existing install dir.
18
+
19
+ set -euo pipefail
20
+
21
+ YO_INSTALL_DIR="${YO_INSTALL_DIR:-$HOME/.local/Yo}"
22
+ YO_BIN_DIR="${YO_BIN_DIR:-$HOME/.local/bin}"
23
+ YO_REPO="${YO_REPO:-https://github.com/shd101wyy/yo.git}"
24
+ YO_REF="${YO_REF:-main}"
25
+
26
+ color() { printf '\033[%sm%s\033[0m' "$1" "$2"; }
27
+ info() { printf '%s %s\n' "$(color '1;34' '>>')" "$1"; }
28
+ warn() { printf '%s %s\n' "$(color '1;33' '!!')" "$1" >&2; }
29
+ err() { printf '%s %s\n' "$(color '1;31' 'XX')" "$1" >&2; exit 1; }
30
+
31
+ # ---------------------------------------------------------------------------
32
+ # Detect platform
33
+ # ---------------------------------------------------------------------------
34
+
35
+ OS="$(uname -s)"
36
+ case "$OS" in
37
+ Linux) PLATFORM="linux" ;;
38
+ Darwin) PLATFORM="macos" ;;
39
+ *) err "Unsupported OS: $OS. This installer supports Linux and macOS only." ;;
40
+ esac
41
+
42
+ info "Installing Yo on $PLATFORM"
43
+ info "Install dir: $YO_INSTALL_DIR"
44
+ info "Bin dir: $YO_BIN_DIR"
45
+
46
+ # ---------------------------------------------------------------------------
47
+ # Required tools
48
+ # ---------------------------------------------------------------------------
49
+
50
+ need() {
51
+ command -v "$1" >/dev/null 2>&1 || err "Missing required command: $1"
52
+ }
53
+
54
+ need git
55
+ need curl
56
+
57
+ # C compiler (clang or gcc) — needed for `yo compile`.
58
+ if ! command -v clang >/dev/null 2>&1 && ! command -v gcc >/dev/null 2>&1; then
59
+ warn "No C compiler found (clang or gcc). 'yo compile' will not work until you install one."
60
+ if [ "$PLATFORM" = "macos" ]; then
61
+ warn " Install with: xcode-select --install"
62
+ else
63
+ warn " Install with your distro's package manager (e.g. apt install clang)"
64
+ fi
65
+ fi
66
+
67
+ # bun runtime — required to run the current TypeScript-based compiler.
68
+ if ! command -v bun >/dev/null 2>&1; then
69
+ info "bun not found — installing via official installer..."
70
+ curl -fsSL https://bun.sh/install | bash
71
+ # Try common bun install locations
72
+ for candidate in "$HOME/.bun/bin" "$HOME/.local/share/bun/bin"; do
73
+ if [ -x "$candidate/bun" ]; then
74
+ export PATH="$candidate:$PATH"
75
+ break
76
+ fi
77
+ done
78
+ command -v bun >/dev/null 2>&1 || err "bun installation failed — install manually from https://bun.sh"
79
+ fi
80
+ info "Using bun: $(command -v bun) ($(bun --version))"
81
+
82
+ # ---------------------------------------------------------------------------
83
+ # Download Yo
84
+ # ---------------------------------------------------------------------------
85
+
86
+ if [ -e "$YO_INSTALL_DIR" ]; then
87
+ if [ -n "${YO_FORCE:-}" ]; then
88
+ info "Removing existing install dir (YO_FORCE set)"
89
+ rm -rf "$YO_INSTALL_DIR"
90
+ else
91
+ err "Install dir already exists: $YO_INSTALL_DIR. Set YO_FORCE=1 to overwrite."
92
+ fi
93
+ fi
94
+
95
+ info "Cloning $YO_REPO ($YO_REF) into $YO_INSTALL_DIR"
96
+ mkdir -p "$(dirname "$YO_INSTALL_DIR")"
97
+ git clone --depth 1 --branch "$YO_REF" "$YO_REPO" "$YO_INSTALL_DIR"
98
+
99
+ # ---------------------------------------------------------------------------
100
+ # Build
101
+ # ---------------------------------------------------------------------------
102
+
103
+ info "Installing dependencies (bun install)"
104
+ ( cd "$YO_INSTALL_DIR" && bun install --silent )
105
+
106
+ info "Building Yo (bun run build)"
107
+ ( cd "$YO_INSTALL_DIR" && bun run build )
108
+
109
+ # ---------------------------------------------------------------------------
110
+ # Wrapper script
111
+ # ---------------------------------------------------------------------------
112
+
113
+ mkdir -p "$YO_BIN_DIR"
114
+ WRAPPER="$YO_BIN_DIR/yo"
115
+
116
+ cat > "$WRAPPER" <<EOF
117
+ #!/usr/bin/env bash
118
+ # Yo language CLI — auto-generated by install.sh
119
+ set -euo pipefail
120
+ exec "$YO_INSTALL_DIR/yo-cli" "\$@"
121
+ EOF
122
+ chmod +x "$WRAPPER"
123
+
124
+ info "Installed wrapper: $WRAPPER"
125
+
126
+ # ---------------------------------------------------------------------------
127
+ # PATH check
128
+ # ---------------------------------------------------------------------------
129
+
130
+ case ":$PATH:" in
131
+ *":$YO_BIN_DIR:"*) ;;
132
+ *)
133
+ warn "$YO_BIN_DIR is not on your PATH."
134
+ warn "Add this to your shell rc file (.bashrc / .zshrc / etc):"
135
+ warn " export PATH=\"\$HOME/.local/bin:\$PATH\""
136
+ ;;
137
+ esac
138
+
139
+ info "Done. Try: yo --help"
@@ -49,7 +49,11 @@ ParsedArgs :: object(
49
49
  _option_names : ArrayList(String),
50
50
  _option_values : ArrayList(String),
51
51
  _positionals : ArrayList(String),
52
- _positional_names : ArrayList(String)
52
+ _positional_names : ArrayList(String),
53
+ /// Name of the chosen subcommand (`.None` if none was used).
54
+ _subcommand : Option(String),
55
+ /// Parsed arguments for the chosen subcommand (`.None` if no subcommand).
56
+ _subcommand_args : Option(Self)
53
57
  );
54
58
 
55
59
  /// Command-line argument parser.
@@ -59,7 +63,13 @@ ArgParser :: object(
59
63
  /// Application description shown in help text.
60
64
  _description : String,
61
65
  /// Registered argument definitions.
62
- _args : ArrayList(ArgDef)
66
+ _args : ArrayList(ArgDef),
67
+ /// Subcommand names (parallel to `_subcommand_parsers`).
68
+ _subcommand_names : ArrayList(String),
69
+ /// Subcommand descriptions (parallel to `_subcommand_parsers`).
70
+ _subcommand_descriptions : ArrayList(String),
71
+ /// Subcommand parsers (parallel to `_subcommand_names`).
72
+ _subcommand_parsers : ArrayList(Self)
63
73
  );
64
74
 
65
75
  impl(ParsedArgs,
@@ -69,10 +79,18 @@ impl(ParsedArgs,
69
79
  _option_names: ArrayList(String).new(),
70
80
  _option_values: ArrayList(String).new(),
71
81
  _positionals: ArrayList(String).new(),
72
- _positional_names: ArrayList(String).new()
82
+ _positional_names: ArrayList(String).new(),
83
+ _subcommand: .None,
84
+ _subcommand_args: .None
73
85
  )
74
86
  ),
75
87
 
88
+ /// Returns the name of the chosen subcommand, if any.
89
+ get_subcommand : (fn(self: Self) -> Option(String))(self._subcommand),
90
+
91
+ /// Returns the parsed arguments of the chosen subcommand, if any.
92
+ get_subcommand_args : (fn(self: Self) -> Option(Self))(self._subcommand_args),
93
+
76
94
  get_flag : (fn(self: Self, name: String) -> bool)(
77
95
  self._set_flags.contains(name)
78
96
  ),
@@ -116,10 +134,43 @@ impl(ArgParser,
116
134
  Self(
117
135
  _name: name,
118
136
  _description: description,
119
- _args: ArrayList(ArgDef).new()
137
+ _args: ArrayList(ArgDef).new(),
138
+ _subcommand_names: ArrayList(String).new(),
139
+ _subcommand_descriptions: ArrayList(String).new(),
140
+ _subcommand_parsers: ArrayList(Self).new()
120
141
  )
121
142
  ),
122
143
 
144
+ /// Registers a subcommand with the given name and description.
145
+ /// Returns the new sub-parser, which can be configured with its own
146
+ /// flags, options, positionals, and nested subcommands.
147
+ add_subcommand : (fn(self: Self, name: String, description: String) -> Self)({
148
+ sub := Self.new(name, description);
149
+ self._subcommand_names.push(name);
150
+ self._subcommand_descriptions.push(description);
151
+ self._subcommand_parsers.push(sub);
152
+ return sub;
153
+ }),
154
+
155
+ /// Looks up a subcommand parser by name.
156
+ _find_subcommand : (fn(self: Self, name: String) -> Option(usize))({
157
+ i := usize(0);
158
+ len := self._subcommand_names.len();
159
+ (result : Option(usize)) = .None;
160
+ while ((i < len) && result.is_none()), (i = (i + usize(1))), {
161
+ match(self._subcommand_names.get(i),
162
+ .Some(n) => {
163
+ cond(
164
+ (n == name) => { result = .Some(i); },
165
+ true => ()
166
+ );
167
+ },
168
+ .None => ()
169
+ );
170
+ };
171
+ return result;
172
+ }),
173
+
123
174
  add_flag : (fn(self: Self, long_name: String, short_name: String, description: String) -> unit)({
124
175
  self._args.push(ArgDef(
125
176
  _long_name: long_name,
@@ -265,6 +316,31 @@ impl(ArgParser,
265
316
  );
266
317
 
267
318
  text = text.concat(` --help, -h\tShow this help message\n`);
319
+
320
+ sub_count := self._subcommand_names.len();
321
+ cond(
322
+ (sub_count > usize(0)) => {
323
+ text = text.concat(`\nSubcommands:\n`);
324
+ s := usize(0);
325
+ while (s < sub_count), (s = (s + usize(1))), {
326
+ match(self._subcommand_names.get(s),
327
+ .Some(sn) => {
328
+ match(self._subcommand_descriptions.get(s),
329
+ .Some(sd) => {
330
+ text = text.concat(` ${sn}\t${sd}\n`);
331
+ },
332
+ .None => {
333
+ text = text.concat(` ${sn}\n`);
334
+ }
335
+ );
336
+ },
337
+ .None => ()
338
+ );
339
+ };
340
+ },
341
+ true => ()
342
+ );
343
+
268
344
  return text;
269
345
  })
270
346
  );
@@ -326,30 +402,78 @@ impl(ArgParser,
326
402
  );
327
403
  },
328
404
  true => {
329
- parsed._positionals.push(current_arg);
330
- p_idx := usize(0);
331
- p_count := usize(0);
332
- while (p_idx < arg_defs_len), (p_idx = (p_idx + usize(1))), {
333
- match(self._args.get(p_idx),
334
- .Some(p_def) => {
335
- match(p_def._kind,
336
- .Positional => {
337
- cond(
338
- (p_count == positional_idx) => {
339
- parsed._positional_names.push(p_def._long_name);
405
+ // Check if this is a subcommand (first non-flag positional only).
406
+ is_subcmd := false;
407
+ cond(
408
+ (self._subcommand_names.len() > usize(0)) => {
409
+ match(self._find_subcommand(current_arg),
410
+ .Some(sub_idx) => {
411
+ match(self._subcommand_parsers.get(sub_idx),
412
+ .Some(sub_parser) => {
413
+ // Build new args list: [program_name, ...remaining args after subcommand name].
414
+ sub_args := ArrayList(String).new();
415
+ match(args.get(usize(0)),
416
+ .Some(prog) => { sub_args.push(prog); },
417
+ .None => { sub_args.push(self._name); }
418
+ );
419
+ j := (idx + usize(1));
420
+ while (j < args_len), (j = (j + usize(1))), {
421
+ match(args.get(j),
422
+ .Some(a) => { sub_args.push(a); },
423
+ .None => ()
424
+ );
425
+ };
426
+ // Recursively parse the subcommand.
427
+ match(recur(sub_parser, sub_args),
428
+ .Ok(sub_parsed) => {
429
+ parsed._subcommand = .Some(current_arg);
430
+ parsed._subcommand_args = .Some(sub_parsed);
431
+ idx = args_len;
432
+ is_subcmd = true;
433
+ },
434
+ .Err(sub_err) => {
435
+ err_msg = .Some(sub_err);
436
+ is_subcmd = true;
437
+ }
438
+ );
439
+ },
440
+ .None => ()
441
+ );
442
+ },
443
+ .None => ()
444
+ );
445
+ },
446
+ true => ()
447
+ );
448
+ cond(
449
+ (!is_subcmd) => {
450
+ parsed._positionals.push(current_arg);
451
+ p_idx := usize(0);
452
+ p_count := usize(0);
453
+ while (p_idx < arg_defs_len), (p_idx = (p_idx + usize(1))), {
454
+ match(self._args.get(p_idx),
455
+ .Some(p_def) => {
456
+ match(p_def._kind,
457
+ .Positional => {
458
+ cond(
459
+ (p_count == positional_idx) => {
460
+ parsed._positional_names.push(p_def._long_name);
461
+ },
462
+ true => ()
463
+ );
464
+ p_count = (p_count + usize(1));
340
465
  },
341
- true => ()
466
+ .Flag => (),
467
+ .Opt => ()
342
468
  );
343
- p_count = (p_count + usize(1));
344
469
  },
345
- .Flag => (),
346
- .Opt => ()
470
+ .None => ()
347
471
  );
348
- },
349
- .None => ()
350
- );
351
- };
352
- positional_idx = (positional_idx + usize(1));
472
+ };
473
+ positional_idx = (positional_idx + usize(1));
474
+ },
475
+ true => ()
476
+ );
353
477
  }
354
478
  );
355
479
  },
@@ -696,9 +696,86 @@ impl(forall(T : Type), where(T <: Ord(T)), ArrayList(T),
696
696
  })
697
697
  );
698
698
 
699
+ /// Clone implementation for ArrayList — deep-clones each element.
700
+ impl(forall(T : Type), where(T <: Clone), ArrayList(T), Clone(
701
+ clone : (fn(self: *(Self)) -> Self)(
702
+ {
703
+ n := self.*.len();
704
+ result := Self.with_capacity(n);
705
+ i := usize(0);
706
+ while (i < n), {
707
+ item_opt := self.*.get(i);
708
+ match(item_opt,
709
+ .Some(item) => { result.push((&item).clone()); },
710
+ .None => ()
711
+ );
712
+ i = (i + usize(1));
713
+ };
714
+ result
715
+ }
716
+ )
717
+ ));
718
+
699
719
  export
700
720
  ArrayList,
701
721
  ArrayListError,
702
722
  ArrayListIter,
703
723
  ArrayListIterPtr
704
724
  ;
725
+
726
+ // =============================================================================
727
+ // array_list! literal macro
728
+ // =============================================================================
729
+
730
+ /// Internal helper: build a list of `tmp.push(elem)` statements from `elems`.
731
+ __array_list_build_pushes :: (fn(comptime(tmp) : Expr, comptime(elems) : ExprList) -> comptime(ExprList))(
732
+ cond(
733
+ (elems.len() == usize(0)) => ExprList(),
734
+ true => {
735
+ first :: elems.car();
736
+ rest :: elems.cdr();
737
+ stmt :: quote((unquote(tmp).push(unquote(first))));
738
+ stmt.cons(recur(tmp, rest))
739
+ }
740
+ )
741
+ );
742
+
743
+ /// `array_list` macro — construct an `ArrayList(T)` literal.
744
+ ///
745
+ /// The element type `T` is inferred from the first element via `typeof`, so
746
+ /// at least one element is required.
747
+ ///
748
+ /// # Example
749
+ /// ```rust
750
+ /// xs := array_list(i32(1), i32(2), i32(3));
751
+ /// names := array_list(`alice`, `bob`);
752
+ /// ```
753
+ ///
754
+ /// Expands to:
755
+ /// ```rust
756
+ /// {
757
+ /// __first := <first elem>;
758
+ /// __tmp := ArrayList(typeof(__first)).new();
759
+ /// __tmp.push(__first);
760
+ /// __tmp.push(<elem 2>);
761
+ /// ...
762
+ /// __tmp
763
+ /// }
764
+ /// ```
765
+ array_list :: (fn(...(quote(elems))) -> unquote(Expr)) {
766
+ __ :: comptime_assert((elems.len() > usize(0)),
767
+ "array_list requires at least one element to infer the element type");
768
+ first :: elems.car();
769
+ rest :: elems.cdr();
770
+ tmp :: gensym("array_list");
771
+ first_tmp :: gensym("array_list_first");
772
+ rest_pushes :: __array_list_build_pushes(tmp, rest);
773
+ quote {
774
+ unquote(first_tmp) := unquote(first);
775
+ unquote(tmp) := ArrayList(typeof(unquote(first_tmp))).new();
776
+ unquote(tmp).push(unquote(first_tmp));
777
+ unquote_splicing(rest_pushes);
778
+ unquote(tmp)
779
+ }
780
+ };
781
+ export array_list;