zexus 1.8.1 → 1.8.2

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/bin/zexus CHANGED
@@ -1,2 +1,12 @@
1
- #!/usr/bin/env bash
2
- python3 -m zexus "$@"
1
+ #!/usr/bin/env node
2
+ const { spawn } = require('child_process');
3
+ const proc = spawn('python3', ['-m', 'zexus', ...process.argv.slice(2)], { stdio: 'inherit' });
4
+ proc.on('error', (err) => {
5
+ if (err.code === 'ENOENT') {
6
+ console.error('Error: python3 not found. Please install Python 3.8+ to use Zexus.');
7
+ process.exit(1);
8
+ }
9
+ console.error('Error:', err.message);
10
+ process.exit(1);
11
+ });
12
+ proc.on('close', (code) => process.exit(code ?? 1));
package/bin/zpics CHANGED
@@ -1,2 +1,12 @@
1
- #!/usr/bin/env bash
2
- python3 -m zexus.pics "$@"
1
+ #!/usr/bin/env node
2
+ const { spawn } = require('child_process');
3
+ const proc = spawn('python3', ['-m', 'zexus.pics', ...process.argv.slice(2)], { stdio: 'inherit' });
4
+ proc.on('error', (err) => {
5
+ if (err.code === 'ENOENT') {
6
+ console.error('Error: python3 not found. Please install Python 3.8+ to use Zexus.');
7
+ process.exit(1);
8
+ }
9
+ console.error('Error:', err.message);
10
+ process.exit(1);
11
+ });
12
+ proc.on('close', (code) => process.exit(code ?? 1));
package/bin/zpm CHANGED
@@ -1,2 +1,12 @@
1
- #!/usr/bin/env bash
2
- python3 -m zexus.zpm "$@"
1
+ #!/usr/bin/env node
2
+ const { spawn } = require('child_process');
3
+ const proc = spawn('python3', ['-m', 'zexus.zpm', ...process.argv.slice(2)], { stdio: 'inherit' });
4
+ proc.on('error', (err) => {
5
+ if (err.code === 'ENOENT') {
6
+ console.error('Error: python3 not found. Please install Python 3.8+ to use Zexus.');
7
+ process.exit(1);
8
+ }
9
+ console.error('Error:', err.message);
10
+ process.exit(1);
11
+ });
12
+ proc.on('close', (code) => process.exit(code ?? 1));
package/bin/zx CHANGED
@@ -1,2 +1,12 @@
1
- #!/usr/bin/env bash
2
- python3 -m zexus "$@"
1
+ #!/usr/bin/env node
2
+ const { spawn } = require('child_process');
3
+ const proc = spawn('python3', ['-m', 'zexus', ...process.argv.slice(2)], { stdio: 'inherit' });
4
+ proc.on('error', (err) => {
5
+ if (err.code === 'ENOENT') {
6
+ console.error('Error: python3 not found. Please install Python 3.8+ to use Zexus.');
7
+ process.exit(1);
8
+ }
9
+ console.error('Error:', err.message);
10
+ process.exit(1);
11
+ });
12
+ proc.on('close', (code) => process.exit(code ?? 1));
package/bin/zx-deploy CHANGED
@@ -1,2 +1,12 @@
1
- #!/usr/bin/env bash
2
- python3 -m zexus.deploy "$@"
1
+ #!/usr/bin/env node
2
+ const { spawn } = require('child_process');
3
+ const proc = spawn('python3', ['-m', 'zexus.deploy', ...process.argv.slice(2)], { stdio: 'inherit' });
4
+ proc.on('error', (err) => {
5
+ if (err.code === 'ENOENT') {
6
+ console.error('Error: python3 not found. Please install Python 3.8+ to use Zexus.');
7
+ process.exit(1);
8
+ }
9
+ console.error('Error:', err.message);
10
+ process.exit(1);
11
+ });
12
+ proc.on('close', (code) => process.exit(code ?? 1));
package/bin/zx-dev CHANGED
@@ -1,2 +1,12 @@
1
- #!/usr/bin/env bash
2
- python3 -m zexus.dev "$@"
1
+ #!/usr/bin/env node
2
+ const { spawn } = require('child_process');
3
+ const proc = spawn('python3', ['-m', 'zexus.dev', ...process.argv.slice(2)], { stdio: 'inherit' });
4
+ proc.on('error', (err) => {
5
+ if (err.code === 'ENOENT') {
6
+ console.error('Error: python3 not found. Please install Python 3.8+ to use Zexus.');
7
+ process.exit(1);
8
+ }
9
+ console.error('Error:', err.message);
10
+ process.exit(1);
11
+ });
12
+ proc.on('close', (code) => process.exit(code ?? 1));
package/bin/zx-run CHANGED
@@ -1,2 +1,12 @@
1
- #!/usr/bin/env bash
2
- python3 -m zexus.runner "$@"
1
+ #!/usr/bin/env node
2
+ const { spawn } = require('child_process');
3
+ const proc = spawn('python3', ['-m', 'zexus.runner', ...process.argv.slice(2)], { stdio: 'inherit' });
4
+ proc.on('error', (err) => {
5
+ if (err.code === 'ENOENT') {
6
+ console.error('Error: python3 not found. Please install Python 3.8+ to use Zexus.');
7
+ process.exit(1);
8
+ }
9
+ console.error('Error:', err.message);
10
+ process.exit(1);
11
+ });
12
+ proc.on('close', (code) => process.exit(code ?? 1));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zexus",
3
- "version": "1.8.1",
3
+ "version": "1.8.2",
4
4
  "description": "A modern, security-first programming language with blockchain support",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -3,74 +3,225 @@
3
3
  const { execSync } = require('child_process');
4
4
  const fs = require('fs');
5
5
  const path = require('path');
6
+ const os = require('os');
6
7
 
7
8
  console.log('\n🚀 Installing Zexus Programming Language...\n');
8
9
 
9
- // Check if Python is available
10
- try {
11
- const pythonVersion = execSync('python3 --version', { encoding: 'utf-8' });
12
- console.log(`✓ Found ${pythonVersion.trim()}`);
13
- } catch (error) {
14
- console.error('❌ Python 3.8+ is required but not found.');
15
- console.error('Please install Python 3.8 or higher: https://www.python.org/downloads/');
16
- process.exit(1);
10
+ // ---------------------------------------------------------------------------
11
+ // Helpers
12
+ // ---------------------------------------------------------------------------
13
+
14
+ function hasCommand(cmd) {
15
+ try {
16
+ execSync(`${cmd} --version`, { stdio: 'ignore' });
17
+ return true;
18
+ } catch {
19
+ return false;
20
+ }
17
21
  }
18
22
 
19
- // Check Python version
20
- try {
21
- const versionCheck = execSync('python3 -c "import sys; sys.exit(0 if sys.version_info >= (3, 8) else 1)"');
22
- console.log('✓ Python version is 3.8 or higher');
23
- } catch (error) {
24
- console.error('❌ Python 3.8 or higher is required.');
23
+ function run(cmd, opts = {}) {
24
+ return execSync(cmd, { encoding: 'utf-8', stdio: 'inherit', ...opts });
25
+ }
26
+
27
+ function runQuiet(cmd) {
28
+ return execSync(cmd, { encoding: 'utf-8', stdio: 'pipe' });
29
+ }
30
+
31
+ const isWin = os.platform() === 'win32';
32
+ const pip = isWin ? 'pip' : 'pip3';
33
+ const python = isWin ? 'python' : 'python3';
34
+
35
+ // ---------------------------------------------------------------------------
36
+ // 1. Python — check or install
37
+ // ---------------------------------------------------------------------------
38
+
39
+ let pythonAvailable = false;
40
+
41
+ if (hasCommand(python)) {
42
+ try {
43
+ const ver = runQuiet(`${python} --version`).trim();
44
+ console.log(`✓ Found ${ver}`);
45
+ // Verify >= 3.8
46
+ runQuiet(`${python} -c "import sys; sys.exit(0 if sys.version_info >= (3, 8) else 1)"`);
47
+ console.log('✓ Python version is 3.8 or higher');
48
+ pythonAvailable = true;
49
+ } catch {
50
+ console.error('❌ Python was found but version is below 3.8.');
51
+ console.error(' Please upgrade to Python 3.8+: https://www.python.org/downloads/');
52
+ }
53
+ } else {
54
+ console.warn('⚠️ python3 not found on PATH.');
55
+ // Attempt auto-install on common platforms
56
+ if (os.platform() === 'linux') {
57
+ console.log(' Attempting to install python3 via apt...');
58
+ try {
59
+ run('sudo apt-get update -qq && sudo apt-get install -y -qq python3 python3-pip python3-venv');
60
+ pythonAvailable = true;
61
+ console.log('✓ Python 3 installed via apt');
62
+ } catch {
63
+ console.warn(' Could not auto-install Python. Please install manually:');
64
+ console.warn(' https://www.python.org/downloads/');
65
+ }
66
+ } else if (os.platform() === 'darwin') {
67
+ if (hasCommand('brew')) {
68
+ console.log(' Attempting to install python3 via Homebrew...');
69
+ try {
70
+ run('brew install python@3');
71
+ pythonAvailable = true;
72
+ console.log('✓ Python 3 installed via Homebrew');
73
+ } catch {
74
+ console.warn(' Could not auto-install Python. Please install manually:');
75
+ console.warn(' https://www.python.org/downloads/');
76
+ }
77
+ } else {
78
+ console.warn(' Please install Python 3.8+: https://www.python.org/downloads/');
79
+ }
80
+ } else {
81
+ console.warn(' Please install Python 3.8+: https://www.python.org/downloads/');
82
+ }
83
+ }
84
+
85
+ if (!pythonAvailable) {
86
+ console.error('\n❌ Python 3.8+ is required but could not be found or installed.');
87
+ console.error(' Install it from: https://www.python.org/downloads/');
88
+ console.error(' Then re-run: npm rebuild zexus');
25
89
  process.exit(1);
26
90
  }
27
91
 
28
- // Install Zexus Python package
92
+ // ---------------------------------------------------------------------------
93
+ // 2. pip — ensure available
94
+ // ---------------------------------------------------------------------------
95
+
96
+ if (!hasCommand(pip) && !hasCommand('pip')) {
97
+ console.log(' pip not found — bootstrapping...');
98
+ try {
99
+ run(`${python} -m ensurepip --upgrade`);
100
+ } catch {
101
+ try {
102
+ run(`${python} -m pip install --upgrade pip`);
103
+ } catch {
104
+ console.warn('⚠️ Could not bootstrap pip. Python package install may fail.');
105
+ }
106
+ }
107
+ }
108
+
109
+ // ---------------------------------------------------------------------------
110
+ // 3. Install Zexus Python package
111
+ // ---------------------------------------------------------------------------
112
+
29
113
  console.log('\n📦 Installing Zexus Python package...');
114
+
115
+ // Check if zexus is already installed and up-to-date
116
+ let zexusInstalled = false;
30
117
  try {
31
- // Install with "full" extras so blockchain/network/security features work out of the box.
32
- // Use --user to avoid permission issues on global Python installs.
33
- execSync('pip3 install --user "zexus[full]"', { stdio: 'inherit' });
34
- console.log('\n✓ Zexus Python package installed successfully');
35
- } catch (error) {
36
- console.error('\n❌ Failed to install Zexus Python package.');
37
- console.error('Please run manually: pip3 install --user "zexus[full]"');
38
- process.exit(1);
118
+ runQuiet(`${python} -c "import zexus"`);
119
+ zexusInstalled = true;
120
+ console.log(' Zexus Python package already installed');
121
+ } catch {
122
+ // Not installed yet
39
123
  }
40
124
 
41
- // Best-effort: build/install Rust VM extension from bundled sources when available.
42
- // This requires a Rust toolchain and may fail on systems without build tooling.
43
- function hasCommand(cmd) {
125
+ if (!zexusInstalled) {
44
126
  try {
45
- execSync(`${cmd} --version`, { stdio: 'ignore' });
46
- return true;
127
+ run(`${python} -m pip install --user "zexus[full]"`);
128
+ console.log('✓ Zexus Python package installed successfully');
47
129
  } catch {
48
- return false;
130
+ // Retry without --user (some environments like venvs don't need it)
131
+ try {
132
+ run(`${python} -m pip install "zexus[full]"`);
133
+ console.log('✓ Zexus Python package installed successfully');
134
+ } catch {
135
+ console.error('❌ Failed to install Zexus Python package.');
136
+ console.error(` Please run manually: ${python} -m pip install "zexus[full]"`);
137
+ // Don't exit — commands that don't need Python may still work
138
+ }
49
139
  }
50
140
  }
51
141
 
142
+ // ---------------------------------------------------------------------------
143
+ // 4. Rust toolchain — check or install, then build rust_core
144
+ // ---------------------------------------------------------------------------
145
+
52
146
  const pkgRoot = path.resolve(__dirname, '..');
53
147
  const cargoToml = path.join(pkgRoot, 'rust_core', 'Cargo.toml');
54
148
 
55
- if (fs.existsSync(cargoToml) && hasCommand('cargo')) {
56
- console.log('\n🦀 Rust toolchain detected — attempting to build zexus_core...');
57
- try {
58
- execSync('python3 -m pip install --user --upgrade maturin', { stdio: 'inherit' });
59
- execSync(`python3 -m maturin develop -m "${cargoToml}" --release`, { stdio: 'inherit' });
60
- execSync('python3 -c "import zexus_core; print(\"zexus_core OK\", zexus_core.version())"', { stdio: 'inherit' });
61
- console.log('✓ Rust VM extension built and installed');
62
- } catch (error) {
63
- console.warn('\n⚠️ Rust VM build failed; continuing with pure-Python VM.');
64
- console.warn(' To retry manually (from source repo):');
65
- console.warn(' pip install maturin && maturin develop -m rust_core/Cargo.toml --release');
149
+ if (fs.existsSync(cargoToml)) {
150
+ let cargoReady = hasCommand('cargo');
151
+
152
+ if (!cargoReady) {
153
+ console.log('\n🦀 Rust toolchain (cargo) not found.');
154
+ console.log(' Attempting to install Rust via rustup...');
155
+ try {
156
+ if (isWin) {
157
+ // On Windows, download and run rustup-init
158
+ console.log(' Please install Rust manually: https://rustup.rs');
159
+ } else {
160
+ // Unix: install rustup non-interactively
161
+ run('curl --proto "=https" --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y');
162
+ // Source the cargo env so it's available in this session
163
+ const cargoEnv = path.join(os.homedir(), '.cargo', 'env');
164
+ if (fs.existsSync(cargoEnv)) {
165
+ // Read the cargo bin path and add to PATH for child processes
166
+ const cargoBin = path.join(os.homedir(), '.cargo', 'bin');
167
+ process.env.PATH = `${cargoBin}${path.delimiter}${process.env.PATH}`;
168
+ }
169
+ cargoReady = hasCommand('cargo');
170
+ if (cargoReady) {
171
+ console.log('✓ Rust toolchain installed via rustup');
172
+ }
173
+ }
174
+ } catch (err) {
175
+ console.warn('⚠️ Could not auto-install Rust. Continuing with pure-Python VM.');
176
+ console.warn(' To install manually: https://rustup.rs');
177
+ }
178
+ } else {
179
+ console.log('\n✓ Rust toolchain detected');
180
+ }
181
+
182
+ if (cargoReady) {
183
+ // Check if zexus_core is already importable
184
+ let rustVmInstalled = false;
185
+ try {
186
+ runQuiet(`${python} -c "import zexus_core"`);
187
+ rustVmInstalled = true;
188
+ console.log('✓ Rust VM extension (zexus_core) already installed');
189
+ } catch {
190
+ // Need to build
191
+ }
192
+
193
+ if (!rustVmInstalled) {
194
+ console.log('🔨 Building Rust VM extension (zexus_core)...');
195
+ try {
196
+ // Ensure maturin is available
197
+ try {
198
+ runQuiet(`${python} -m maturin --version`);
199
+ } catch {
200
+ console.log(' Installing maturin build tool...');
201
+ run(`${python} -m pip install --user --upgrade maturin`);
202
+ }
203
+ run(`${python} -m maturin develop -m "${cargoToml}" --release`);
204
+ runQuiet(`${python} -c "import zexus_core"`);
205
+ console.log('✓ Rust VM extension built and installed');
206
+ } catch (error) {
207
+ console.warn('\n⚠️ Rust VM build failed; continuing with pure-Python VM.');
208
+ console.warn(' To retry manually:');
209
+ console.warn(` ${python} -m pip install maturin && ${python} -m maturin develop -m rust_core/Cargo.toml --release`);
210
+ }
211
+ }
66
212
  }
67
213
  } else {
68
- console.log('\nℹ️ Skipping Rust VM build (cargo not found or rust_core not bundled).');
214
+ console.log('\nℹ️ rust_core/Cargo.toml not bundled; skipping Rust VM build.');
69
215
  }
70
216
 
217
+ // ---------------------------------------------------------------------------
218
+ // Done
219
+ // ---------------------------------------------------------------------------
220
+
71
221
  console.log('\n✅ Zexus installed successfully!\n');
72
222
  console.log('Get started:');
73
223
  console.log(' zexus --help # Show help');
74
224
  console.log(' zx --version # Check version');
225
+ console.log(' zx run file.zx # Run a Zexus file');
75
226
  console.log(' zexus examples/ # Explore examples\n');
76
227
  console.log('Documentation: https://github.com/Zaidux/zexus-interpreter\n');
@@ -4,7 +4,7 @@ Zexus Programming Language
4
4
  A declarative, intent-based programming language for modern applications.
5
5
  """
6
6
 
7
- __version__ = "1.8.1"
7
+ __version__ = "1.8.2"
8
8
  __author__ = "Ziver Labs"
9
9
  __email__ = "ziverofficial567@gmail.com"
10
10
 
@@ -156,7 +156,7 @@ def show_all_commands():
156
156
  console.print("\n[bold green]💡 Tip:[/bold green] Use 'zx <command> --help' for detailed command options\n")
157
157
 
158
158
  @click.group(invoke_without_command=True)
159
- @click.version_option(version="1.8.1", prog_name="Zexus")
159
+ @click.version_option(version="1.8.2", prog_name="Zexus")
160
160
  @click.option('--syntax-style', type=click.Choice(['universal', 'tolerable', 'auto']),
161
161
  default='auto', help='Syntax style to use (universal=strict, tolerable=flexible)')
162
162
  @click.option('--advanced-parsing', is_flag=True, default=True,
@@ -18,7 +18,7 @@ console = Console()
18
18
 
19
19
 
20
20
  @click.group()
21
- @click.version_option(version="1.8.1", prog_name="ZPM")
21
+ @click.version_option(version="1.8.2", prog_name="ZPM")
22
22
  def cli():
23
23
  """ZPM - Zexus Package Manager
24
24
 
@@ -362,6 +362,15 @@ class UltimateParser:
362
362
  if match_brace_depth == 0:
363
363
  in_match_brace = False
364
364
  elif t.type == LAMBDA and getattr(t, 'literal', None) == '=>':
365
+ # Exclude watch => patterns — those are reactive watchers, not lambdas
366
+ if idx > 0 and all_tokens[idx - 1].type == IDENT:
367
+ # Check if this is a watch statement: watch <expr> =>
368
+ # Walk back past identifiers and dots (e.g. watch order.status =>)
369
+ watch_idx = idx - 2
370
+ while watch_idx >= 0 and all_tokens[watch_idx].type in (IDENT, DOT):
371
+ watch_idx -= 1
372
+ if watch_idx >= 0 and getattr(all_tokens[watch_idx], 'type', None) == WATCH:
373
+ continue # Skip watch arrows
365
374
  has_non_match_arrow = True
366
375
  break
367
376
  if has_non_match_arrow:
@@ -4606,8 +4615,16 @@ class UltimateParser:
4606
4615
 
4607
4616
  return UsingStatement(resource_name=resource_name, resource_expr=resource_expr, body=body)
4608
4617
 
4618
+ def parse_type_expression(self):
4619
+ """Parse a simple type expression (identifier)."""
4620
+ if self.cur_token_is(IDENT):
4621
+ type_node = Identifier(self.cur_token.literal)
4622
+ self.next_token()
4623
+ return type_node
4624
+ return None
4625
+
4609
4626
  def parse_channel_statement(self):
4610
- """Parse channel declaration: channel<type> name; or channel<type> name = expr;"""
4627
+ """Parse channel declaration: channel<type>[capacity] name"""
4611
4628
  token = self.cur_token
4612
4629
  self.next_token() # consume CHANNEL
4613
4630
 
@@ -4625,25 +4642,33 @@ class UltimateParser:
4625
4642
 
4626
4643
  self.next_token()
4627
4644
 
4645
+ # Optional capacity in brackets: [10]
4646
+ capacity = None
4647
+ if self.cur_token_is(LBRACKET):
4648
+ self.next_token()
4649
+ capacity = self.parse_expression(LOWEST)
4650
+ if not self.cur_token_is(RBRACKET):
4651
+ self.errors.append(f"Line {token.line}:{token.column} - Expected ']' after channel capacity")
4652
+ return None
4653
+ self.next_token()
4654
+
4628
4655
  # Parse channel name
4629
4656
  if not self.cur_token_is(IDENT):
4630
4657
  self.errors.append(f"Line {token.line}:{token.column} - Expected channel name")
4631
4658
  return None
4632
4659
 
4633
- name = self.cur_token.literal
4660
+ name = Identifier(self.cur_token.literal)
4634
4661
  self.next_token()
4635
4662
 
4636
- # Optional capacity specification
4637
- capacity = None
4638
- if self.cur_token_is(ASSIGN):
4663
+ # Optional capacity via assignment: = expr
4664
+ if capacity is None and self.cur_token_is(ASSIGN):
4639
4665
  self.next_token()
4640
4666
  capacity = self.parse_expression(LOWEST)
4641
4667
 
4642
- if not self.cur_token_is(SEMICOLON):
4643
- self.errors.append(f"Line {token.line}:{token.column} - Expected ';' after channel declaration")
4644
- return None
4668
+ # Semicolons are optional in modern Zexus
4669
+ if self.cur_token_is(SEMICOLON):
4670
+ self.next_token()
4645
4671
 
4646
- self.next_token()
4647
4672
  return ChannelStatement(name=name, element_type=element_type, capacity=capacity)
4648
4673
 
4649
4674
  def parse_send_statement(self):
@@ -16,7 +16,8 @@ STATEMENT_STARTERS = {
16
16
  SIMD, DEFER, PATTERN, ENUM, STREAM, WATCH, LOG, CAPABILITY, GRANT,
17
17
  REVOKE, VALIDATE, SANITIZE, IMMUTABLE, INTERFACE, TYPE_ALIAS, MODULE,
18
18
  PACKAGE, USING, MIDDLEWARE, AUTH, THROTTLE, CACHE, REQUIRE,
19
- EMIT, PROTOCOL, SEAL
19
+ EMIT, PROTOCOL, SEAL,
20
+ CHANNEL, SEND, RECEIVE, ATOMIC, ASYNC,
20
21
  }
21
22
 
22
23
  _MEANINGFUL_TOKEN_TYPES = {
@@ -1267,7 +1268,8 @@ class ContextStackParser:
1267
1268
  EXPORT, USE, DEBUG, ENTITY, CONTRACT, AUDIT, RESTRICT, SANDBOX, TRAIL, NATIVE, GC, INLINE,
1268
1269
  BUFFER, SIMD, DEFER, PATTERN, ENUM, STREAM, WATCH, CAPABILITY, GRANT,
1269
1270
  REVOKE, VALIDATE, SANITIZE, IMMUTABLE, INTERFACE, TYPE_ALIAS, MODULE,
1270
- PACKAGE, USING
1271
+ PACKAGE, USING,
1272
+ CHANNEL, SEND, RECEIVE, ATOMIC, ASYNC,
1271
1273
  }
1272
1274
  j = assign_idx + 1
1273
1275
  nesting_depth = 0
@@ -3983,6 +3985,35 @@ class ContextStackParser:
3983
3985
  i = j
3984
3986
  continue
3985
3987
 
3988
+ elif token.type == CHANNEL:
3989
+ # Parse CHANNEL declaration: channel<type>[capacity] name
3990
+ j = i + 1
3991
+ channel_tokens = [token]
3992
+ # Collect until we hit a statement starter or semicolon at nesting 0
3993
+ nesting = 0
3994
+ while j < len(tokens):
3995
+ tj = tokens[j]
3996
+ if tj.type in (LBRACKET, LT):
3997
+ nesting += 1
3998
+ elif tj.type in (RBRACKET, GT):
3999
+ nesting -= 1
4000
+ elif nesting == 0 and tj.type == SEMICOLON:
4001
+ j += 1 # skip semicolon
4002
+ break
4003
+ elif nesting == 0 and tj.type in statement_starters and len(channel_tokens) > 1:
4004
+ break
4005
+ channel_tokens.append(tj)
4006
+ j += 1
4007
+
4008
+ # Use the context handler to parse the channel tokens
4009
+ block_info = {'tokens': channel_tokens}
4010
+ stmt = self._parse_channel_statement(block_info, tokens)
4011
+ if stmt:
4012
+ statements.append(stmt)
4013
+
4014
+ i = j
4015
+ continue
4016
+
3986
4017
  elif token.type == ATOMIC:
3987
4018
  # Parse ATOMIC statement: atomic { statements }
3988
4019
  j = i + 1
@@ -4015,6 +4046,48 @@ class ContextStackParser:
4015
4046
  continue
4016
4047
 
4017
4048
  elif token.type == ASYNC:
4049
+ # Check if this is "async action" — treat as action with async modifier
4050
+ if i + 1 < len(tokens) and tokens[i + 1].type == ACTION:
4051
+ # Collect entire async action declaration including brace body
4052
+ j = i + 1 # skip to ACTION token
4053
+ stmt_tokens = [tokens[j]] # Start with ACTION token
4054
+ j += 1
4055
+ brace_nest = 0
4056
+ paren_nest = 0
4057
+ while j < len(tokens):
4058
+ tj = tokens[j]
4059
+ stmt_tokens.append(tj)
4060
+ if tj.type == LPAREN:
4061
+ paren_nest += 1
4062
+ elif tj.type == RPAREN:
4063
+ if paren_nest > 0:
4064
+ paren_nest -= 1
4065
+ elif tj.type == LBRACE:
4066
+ brace_nest += 1
4067
+ elif tj.type == RBRACE:
4068
+ brace_nest -= 1
4069
+ if brace_nest == 0:
4070
+ j += 1
4071
+ break
4072
+ j += 1
4073
+
4074
+ # Parse as action statement and set is_async flag
4075
+ block_info = {'tokens': stmt_tokens}
4076
+ stmt = self._parse_action_statement(block_info, tokens)
4077
+ if stmt:
4078
+ stmt.is_async = True
4079
+ try:
4080
+ existing_modifiers = list(getattr(stmt, 'modifiers', []) or [])
4081
+ if 'async' not in existing_modifiers:
4082
+ existing_modifiers.append('async')
4083
+ stmt.modifiers = existing_modifiers
4084
+ except Exception:
4085
+ stmt.modifiers = ['async']
4086
+ statements.append(stmt)
4087
+
4088
+ i = j
4089
+ continue
4090
+
4018
4091
  # Parse ASYNC expression: async <expression>
4019
4092
  j = i + 1
4020
4093
 
@@ -6157,6 +6230,22 @@ class ContextStackParser:
6157
6230
  # If this is "async function", let _parse_function_statement_context handle it
6158
6231
  if len(tokens) > 1 and tokens[1].type == FUNCTION:
6159
6232
  return self._parse_function_statement_context(block_info, all_tokens)
6233
+
6234
+ # If this is "async action", let _parse_action_statement handle it with async flag
6235
+ if len(tokens) > 1 and tokens[1].type == ACTION:
6236
+ action_tokens = tokens[1:] # Strip ASYNC
6237
+ action_block = {'tokens': action_tokens}
6238
+ stmt = self._parse_action_statement(action_block, all_tokens)
6239
+ if stmt:
6240
+ stmt.is_async = True
6241
+ try:
6242
+ existing_modifiers = list(getattr(stmt, 'modifiers', []) or [])
6243
+ if 'async' not in existing_modifiers:
6244
+ existing_modifiers.append('async')
6245
+ stmt.modifiers = existing_modifiers
6246
+ except Exception:
6247
+ stmt.modifiers = ['async']
6248
+ return stmt
6160
6249
 
6161
6250
  # The tokens are [ASYNC, ...expression tokens...]
6162
6251
  # We can just call parse_async_expression from the main parser!