rip-lang 2.8.3 → 2.8.5

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.
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rip-lang",
3
- "version": "2.8.3",
3
+ "version": "2.8.5",
4
4
  "description": "A modern language that compiles to JavaScript",
5
5
  "type": "module",
6
6
  "main": "src/compiler.js",
package/src/compiler.js CHANGED
@@ -2582,8 +2582,20 @@ export class CodeGenerator {
2582
2582
  const stmts = this.withIndent(() => this.formatStatements(statements));
2583
2583
  return `{\n${stmts.join('\n')}\n${this.indent()}}`;
2584
2584
  }
2585
- // In value context, just format statements
2586
- return this.formatStatements(statements, context);
2585
+ // In value context, handle sequences like (a; b; c)
2586
+ if (statements.length === 0) return 'undefined';
2587
+ if (statements.length === 1) return this.generate(statements[0], context);
2588
+ // Check if last statement is control flow (break/continue/return/throw)
2589
+ const last = statements[statements.length - 1];
2590
+ const lastIsControl = Array.isArray(last) && ['break', 'continue', 'return', 'throw'].includes(last[0]);
2591
+ if (lastIsControl) {
2592
+ // Control flow needs block form: { stmt1; stmt2; break; }
2593
+ const bodyParts = statements.map(s => this.addSemicolon(s, this.generate(s, 'statement')));
2594
+ return `{\n${this.withIndent(() => bodyParts.map(p => this.indent() + p).join('\n'))}\n${this.indent()}}`;
2595
+ }
2596
+ // Use comma operator for value sequences: (a, b, c) returns c
2597
+ const parts = statements.map(s => this.generate(s, 'value'));
2598
+ return `(${parts.join(', ')})`;
2587
2599
  }
2588
2600
 
2589
2601
  /**
@@ -2750,16 +2762,8 @@ export class CodeGenerator {
2750
2762
  for (const whenClause of whens) {
2751
2763
  const [, test, body] = whenClause;
2752
2764
 
2753
- // Handle multiple test values (when 1, 2, 3)
2754
- // Need to distinguish:
2755
- // ["-", "1"] → single s-expression (unary minus)
2756
- // ["a", "b"] → multiple string/number values
2757
- // Check if first element is an operator (s-expression) or a value (list)
2758
- const firstTest = normalize(Array.isArray(test) && test.length > 0 ? test[0] : null);
2759
- const isTestList = Array.isArray(test) && test.length > 0 &&
2760
- typeof firstTest === 'string' &&
2761
- !firstTest.match(/^[-+*\/%<>=!&|^~]$|^(typeof|delete|new|not|await|yield)$/);
2762
- const tests = isTestList ? test : [test];
2765
+ // SimpleArgs always produces an array of test values
2766
+ const tests = test;
2763
2767
 
2764
2768
  for (const t of tests) {
2765
2769
  const tValue = normalize(t);
@@ -5099,20 +5103,35 @@ export class CodeGenerator {
5099
5103
  // Don't unwrap if there are operators or multiple parts outside the parens
5100
5104
  while (code.startsWith('(') && code.endsWith(')')) {
5101
5105
  // Check if these parens wrap the entire expression
5102
- let depth = 0;
5106
+ let parenDepth = 0;
5107
+ let bracketDepth = 0; // Track [] and {}
5103
5108
  let canUnwrap = true;
5109
+ let hasCommaAtDepth1 = false;
5104
5110
 
5105
5111
  for (let i = 0; i < code.length; i++) {
5106
- if (code[i] === '(') depth++;
5107
- if (code[i] === ')') depth--;
5112
+ const ch = code[i];
5113
+ if (ch === '(') parenDepth++;
5114
+ if (ch === ')') parenDepth--;
5115
+ if (ch === '[' || ch === '{') bracketDepth++;
5116
+ if (ch === ']' || ch === '}') bracketDepth--;
5117
+
5118
+ // Check for comma operator at depth 1 (inside outer parens, not inside [] or {})
5119
+ if (ch === ',' && parenDepth === 1 && bracketDepth === 0) {
5120
+ hasCommaAtDepth1 = true;
5121
+ }
5108
5122
 
5109
5123
  // If we hit depth 0 before the end, parens don't wrap everything
5110
- if (depth === 0 && i < code.length - 1) {
5124
+ if (parenDepth === 0 && i < code.length - 1) {
5111
5125
  canUnwrap = false;
5112
5126
  break;
5113
5127
  }
5114
5128
  }
5115
5129
 
5130
+ // Don't unwrap comma operator expressions - the parens are required
5131
+ if (hasCommaAtDepth1) {
5132
+ canUnwrap = false;
5133
+ }
5134
+
5116
5135
  if (canUnwrap) {
5117
5136
  code = code.slice(1, -1);
5118
5137
  } else {
@@ -5459,10 +5478,13 @@ export class CodeGenerator {
5459
5478
  const whenClause = whens[i];
5460
5479
  const [, test, body] = whenClause;
5461
5480
 
5481
+ // SimpleArgs now always produces array; for if-chain we use first (typically only) condition
5482
+ const condition = Array.isArray(test) ? test[0] : test;
5483
+
5462
5484
  if (i === 0) {
5463
- code += `if (${this.generate(test, 'value')}) {\n`;
5485
+ code += `if (${this.generate(condition, 'value')}) {\n`;
5464
5486
  } else {
5465
- code += ` else if (${this.generate(test, 'value')}) {\n`;
5487
+ code += ` else if (${this.generate(condition, 'value')}) {\n`;
5466
5488
  }
5467
5489
  this.indentLevel++;
5468
5490
 
@@ -585,10 +585,10 @@ grammar =
585
585
  o 'Elision TERMINATOR'
586
586
  ]
587
587
 
588
- # Simple argument lists for switch statements
588
+ # Simple argument lists for switch statements (always produces array)
589
589
  SimpleArgs: [
590
- o 'Expression'
591
- o 'SimpleArgs , Expression', 'Array.isArray($1) ? [...$1, $3] : [$1, $3]' # Prevent splitting Strings into chars
590
+ o 'Expression' , '[$1]' # Single: wrap in array
591
+ o 'SimpleArgs , Expression', '[...$1, $3]' # Multiple: spread + add
592
592
  ]
593
593
 
594
594
  # Try/catch/finally exception handling
@@ -612,10 +612,10 @@ grammar =
612
612
  o 'THROW INDENT Object OUTDENT', '["throw", 3]'
613
613
  ]
614
614
 
615
- # Parenthesized expressions - unwrap single-element Bodies
615
+ # Parenthesized expressions - unwrap single-element Bodies, wrap multiple in block
616
616
  Parenthetical: [
617
- o '( Body )' , '$2.length === 1 ? $2[0] : $2'
618
- o '( INDENT Body OUTDENT )', '$3.length === 1 ? $3[0] : $3'
617
+ o '( Body )' , '$2.length === 1 ? $2[0] : ["block", ...$2]'
618
+ o '( INDENT Body OUTDENT )', '$3.length === 1 ? $3[0] : ["block", ...$3]'
619
619
  ]
620
620
 
621
621
  # While loop conditions (consolidated)
package/src/lexer.js CHANGED
@@ -2579,7 +2579,7 @@ Rewriter = (function() {
2579
2579
  // Close implicit objects such as:
2580
2580
  // return a: 1, b: 2 unless true
2581
2581
  // But NOT for || or && which should stay inside objects
2582
- } else if (inImplicitObject() && !isLogicalOp && sameLine && tag !== 'TERMINATOR' && prevTag !== ':' && !((tag === 'POST_IF' || tag === 'FOR' || tag === 'WHILE' || tag === 'UNTIL') && startsLine && implicitObjectContinues(i + 1))) {
2582
+ } else if (inImplicitObject() && !isLogicalOp && sameLine && tag !== 'TERMINATOR' && prevTag !== ':' && !((tag === 'POST_IF' || tag === 'POST_UNLESS' || tag === 'FOR' || tag === 'WHILE' || tag === 'UNTIL') && startsLine && implicitObjectContinues(i + 1))) {
2583
2583
  endImplicitObject();
2584
2584
  // Close implicit objects when at end of line, line didn't end with a comma
2585
2585
  // and the implicit object didn't start the line or the next line doesn't look like
@@ -3281,7 +3281,7 @@ IMPLICIT_UNSPACED_CALL = ['+', '-'];
3281
3281
 
3282
3282
  // Tokens that always mark the end of an implicit call for single-liners.
3283
3283
  // Includes || and && so that `read 'body' or ''` parses as `read('body') || ''`
3284
- IMPLICIT_END = ['POST_IF', 'FOR', 'WHILE', 'UNTIL', 'WHEN', 'BY', 'LOOP', 'TERMINATOR', '||', '&&'];
3284
+ IMPLICIT_END = ['POST_IF', 'POST_UNLESS', 'FOR', 'WHILE', 'UNTIL', 'WHEN', 'BY', 'LOOP', 'TERMINATOR', '||', '&&'];
3285
3285
 
3286
3286
  // Literals that trigger comma insertion before arrows: get '/path' -> ... becomes get('/path', -> ...)
3287
3287
  IMPLICIT_COMMA_BEFORE_ARROW = ['STRING', 'STRING_END', 'REGEX', 'REGEX_END', 'NUMBER', 'BOOL', 'NULL', 'UNDEFINED', 'INFINITY', 'NAN', ']', '}'];
package/src/parser.js CHANGED
@@ -11,10 +11,10 @@ const parserInstance = {
11
11
  switch (rule) {
12
12
  case 1: return ["program"];
13
13
  case 2: return ["program", ...$[$0]];
14
- case 3: case 61: case 128: case 193: case 212: case 235: case 267: case 281: case 285: case 344: case 350: return [$[$0]];
15
- case 4: case 129: case 194: case 213: case 236: case 268: return [...$[$0-2], $[$0]];
14
+ case 3: case 61: case 128: case 193: case 212: case 235: case 267: case 281: case 285: case 289: case 344: case 350: return [$[$0]];
15
+ case 4: case 129: case 194: case 213: case 236: case 268: case 290: return [...$[$0-2], $[$0]];
16
16
  case 5: case 63: case 288: return $[$0-1];
17
- case 6: case 7: case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28: case 29: case 47: case 48: case 55: case 56: case 57: case 58: case 59: case 66: case 67: case 71: case 72: case 73: case 76: case 77: case 78: case 83: case 88: case 89: case 90: case 91: case 94: case 97: case 98: case 99: case 100: case 101: case 123: case 124: case 125: case 126: case 132: case 136: case 137: case 138: case 139: case 141: case 142: case 170: case 171: case 172: case 173: case 174: case 175: case 176: case 177: case 178: case 179: case 180: case 181: case 217: case 219: case 221: case 240: case 243: case 272: case 273: case 274: case 276: case 289: case 309: case 342: case 358: case 360: return $[$0];
17
+ case 6: case 7: case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28: case 29: case 47: case 48: case 55: case 56: case 57: case 58: case 59: case 66: case 67: case 71: case 72: case 73: case 76: case 77: case 78: case 83: case 88: case 89: case 90: case 91: case 94: case 97: case 98: case 99: case 100: case 101: case 123: case 124: case 125: case 126: case 132: case 136: case 137: case 138: case 139: case 141: case 142: case 170: case 171: case 172: case 173: case 174: case 175: case 176: case 177: case 178: case 179: case 180: case 181: case 217: case 219: case 221: case 240: case 243: case 272: case 273: case 274: case 276: case 309: case 342: case 358: case 360: return $[$0];
18
18
  case 30: return ["def", $[$0-4], $[$0-2], $[$0]];
19
19
  case 31: return ["def", $[$0-1], [], $[$0]];
20
20
  case 32: return ["state", $[$0-2], $[$0]];
@@ -142,7 +142,6 @@ const parserInstance = {
142
142
  case 279: return [...$[$0-2], ...$[$0-1]];
143
143
  case 280: return [...$[$0-5], ...$[$0-4], ...$[$0-2], ...$[$0-1]];
144
144
  case 284: return [...$[$0]];
145
- case 290: return Array.isArray($[$0-2]) ? [...$[$0-2], $[$0]] : [$[$0-2], $[$0]];
146
145
  case 291: return ["try", $[$0]];
147
146
  case 292: return ["try", $[$0-1], $[$0]];
148
147
  case 293: return ["try", $[$0-2], $[$0]];
@@ -151,8 +150,8 @@ const parserInstance = {
151
150
  case 297: return [null, $[$0]];
152
151
  case 298: return ["throw", $[$0]];
153
152
  case 299: return ["throw", $[$0-1]];
154
- case 300: return $[$0-1].length === 1 ? $[$0-1][0] : $[$0-1];
155
- case 301: return $[$0-2].length === 1 ? $[$0-2][0] : $[$0-2];
153
+ case 300: return $[$0-1].length === 1 ? $[$0-1][0] : ["block", ...$[$0-1]];
154
+ case 301: return $[$0-2].length === 1 ? $[$0-2][0] : ["block", ...$[$0-2]];
156
155
  case 302: return ["while", $[$0]];
157
156
  case 303: return ["while", $[$0-2], $[$0]];
158
157
  case 304: return ["until", $[$0]];