arc-lang 0.6.7 → 0.6.8

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/dist/ast.d.ts CHANGED
@@ -2,7 +2,7 @@ export interface Loc {
2
2
  line: number;
3
3
  col: number;
4
4
  }
5
- export type Expr = IntLiteral | FloatLiteral | BoolLiteral | NilLiteral | StringLiteral | StringInterp | Identifier | BinaryExpr | UnaryExpr | CallExpr | MemberExpr | IndexExpr | PipelineExpr | IfExpr | MatchExpr | LambdaExpr | ListLiteral | MapLiteral | ListComprehension | ToolCallExpr | RangeExpr | BlockExpr | AsyncExpr | AwaitExpr | FetchExpr | SpreadExpr | OptionalMemberExpr | TryExpr | TryCatchExpr;
5
+ export type Expr = IntLiteral | FloatLiteral | BoolLiteral | NilLiteral | StringLiteral | StringInterp | Identifier | BinaryExpr | UnaryExpr | CallExpr | MemberExpr | IndexExpr | PipelineExpr | IfExpr | MatchExpr | LambdaExpr | ListLiteral | MapLiteral | ListComprehension | ToolCallExpr | RangeExpr | BlockExpr | AsyncExpr | AwaitExpr | FetchExpr | SpreadExpr | OptionalMemberExpr | TryExpr | TryCatchExpr | GroupExpr;
6
6
  export interface IntLiteral {
7
7
  kind: "IntLiteral";
8
8
  value: number;
@@ -177,6 +177,11 @@ export interface TryCatchExpr {
177
177
  catchBody: Expr;
178
178
  loc: Loc;
179
179
  }
180
+ export interface GroupExpr {
181
+ kind: "GroupExpr";
182
+ expr: Expr;
183
+ loc: Loc;
184
+ }
180
185
  export type Pattern = WildcardPattern | LiteralPattern | BindingPattern | ArrayPattern | OrPattern | ConstructorPattern;
181
186
  export interface WildcardPattern {
182
187
  kind: "WildcardPattern";
package/dist/formatter.js CHANGED
@@ -35,6 +35,16 @@ function extractComments(source) {
35
35
  col++;
36
36
  }
37
37
  }
38
+ else if (source[i] === '/' && i + 1 < source.length && source[i + 1] === '/') {
39
+ const startLine = line, startCol = col;
40
+ let text = '';
41
+ while (i < source.length && source[i] !== '\n') {
42
+ text += source[i];
43
+ i++;
44
+ col++;
45
+ }
46
+ comments.push({ text, line: startLine, col: startCol });
47
+ }
38
48
  else if (source[i] === '#') {
39
49
  const startLine = line, startCol = col;
40
50
  let text = '';
@@ -244,6 +254,7 @@ export function format(source, options) {
244
254
  const targets = expr.targets.map(t => formatExpr(t, depth)).join(", ");
245
255
  return `fetch [${targets}]`;
246
256
  }
257
+ case "GroupExpr": return `(${formatExpr(expr.expr, depth)})`;
247
258
  case "SpreadExpr": return `...${formatExpr(expr.expr, depth)}`;
248
259
  case "OptionalMemberExpr": return `${formatExpr(expr.object, depth)}?.${expr.property}`;
249
260
  case "TryExpr": return `${formatExpr(expr.expr, depth)}?`;
@@ -20,6 +20,13 @@ class Env {
20
20
  if (this.parent)
21
21
  return this.parent.get(name);
22
22
  // Collect all known variable names for "did you mean?" suggestion
23
+ if (name === "mut" || name === "var") {
24
+ throw new ArcRuntimeError(`Undefined variable: ${name}`, {
25
+ code: ErrorCode.UNDEFINED_VARIABLE,
26
+ category: "RuntimeError",
27
+ suggestion: "Did you mean 'let mut' to declare a mutable variable?",
28
+ });
29
+ }
23
30
  const candidates = this.allNames();
24
31
  const closest = findClosestMatch(name, candidates);
25
32
  throw new ArcRuntimeError(`Undefined variable: ${name}`, {
@@ -2681,7 +2688,15 @@ function evalExpr(expr, env) {
2681
2688
  if (obj === null)
2682
2689
  return null;
2683
2690
  if (obj && typeof obj === "object" && "__map" in obj) {
2684
- return obj.entries.get(expr.property) ?? null;
2691
+ const mapObj = obj;
2692
+ const val = mapObj.entries.get(expr.property);
2693
+ if (val === undefined && "__module" in obj) {
2694
+ const modName = obj.__module;
2695
+ const candidates = [...mapObj.entries.keys()];
2696
+ const closest = findClosestMatch(expr.property, candidates);
2697
+ throw new ArcRuntimeError(`Module '${modName}' has no member '${expr.property}'${closest ? `. Did you mean '${closest}'?` : ""}`, { code: ErrorCode.PROPERTY_ACCESS, loc: expr.loc });
2698
+ }
2699
+ return val ?? null;
2685
2700
  }
2686
2701
  // Teaching error messages for common method-style access
2687
2702
  const prop = expr.property;
@@ -2956,6 +2971,8 @@ function evalExpr(expr, env) {
2956
2971
  }
2957
2972
  return result;
2958
2973
  }
2974
+ case "GroupExpr":
2975
+ return evalExpr(expr.expr, env);
2959
2976
  default:
2960
2977
  throw new Error(`Unknown expression kind: ${expr.kind}`);
2961
2978
  }
package/dist/linter.js CHANGED
@@ -2,6 +2,16 @@
2
2
  // Checks for common code quality issues
3
3
  import { lex } from "./lexer.js";
4
4
  import { parse } from "./parser.js";
5
+ /** Walk an expression to find the root variable name (e.g. `a[b].c` → "a") */
6
+ function getRootVariable(expr) {
7
+ if (expr.kind === "Identifier")
8
+ return expr.name;
9
+ if (expr.kind === "MemberExpr" || expr.kind === "OptionalMemberExpr")
10
+ return getRootVariable(expr.object);
11
+ if (expr.kind === "IndexExpr")
12
+ return getRootVariable(expr.object);
13
+ return null;
14
+ }
5
15
  const DEFAULT_OPTIONS = {
6
16
  maxLineLength: 100,
7
17
  file: "<stdin>",
@@ -399,15 +409,27 @@ export function lint(source, options) {
399
409
  scope.markUsed(stmt.target);
400
410
  analyzeExpr(stmt.value, scope);
401
411
  break;
402
- case "MemberAssignStmt":
412
+ case "MemberAssignStmt": {
403
413
  analyzeExpr(stmt.object, scope);
404
414
  analyzeExpr(stmt.value, scope);
415
+ const memberRoot = getRootVariable(stmt.object);
416
+ if (memberRoot) {
417
+ scope.markMutated(memberRoot);
418
+ scope.markUsed(memberRoot);
419
+ }
405
420
  break;
406
- case "IndexAssignStmt":
421
+ }
422
+ case "IndexAssignStmt": {
407
423
  analyzeExpr(stmt.object, scope);
408
424
  analyzeExpr(stmt.index, scope);
409
425
  analyzeExpr(stmt.value, scope);
426
+ const indexRoot = getRootVariable(stmt.object);
427
+ if (indexRoot) {
428
+ scope.markMutated(indexRoot);
429
+ scope.markUsed(indexRoot);
430
+ }
410
431
  break;
432
+ }
411
433
  }
412
434
  }
413
435
  const globalScope = new LintScope();
package/dist/modules.js CHANGED
@@ -124,7 +124,7 @@ export function handleUse(stmt, env, currentFile) {
124
124
  for (const [name, value] of Object.entries(exports)) {
125
125
  entries.set(name, value);
126
126
  }
127
- env.set(nsName, { __map: true, entries });
127
+ env.set(nsName, { __map: true, __module: nsName, entries });
128
128
  }
129
129
  /**
130
130
  * Create a UseHandler bound to a specific file path.
package/dist/parser.d.ts CHANGED
@@ -37,6 +37,7 @@ export declare class Parser {
37
37
  private parsePrefix;
38
38
  private parseStringInterp;
39
39
  private parseListOrComprehension;
40
+ private isIdentOrKeyword;
40
41
  private isMapStart;
41
42
  private parseMapEntry;
42
43
  private parseMapOrBlock;
package/dist/parser.js CHANGED
@@ -68,6 +68,10 @@ export class Parser {
68
68
  case TokenType.Type: return this.parseType();
69
69
  case TokenType.Ret: return this.parseRet();
70
70
  case TokenType.Try: return this.parseTryStmtOrExpr();
71
+ case TokenType.Mut: {
72
+ const loc = this.loc();
73
+ throw new ParseError(`'mut' is not a statement. Did you mean 'let mut' to declare a mutable variable?`, loc);
74
+ }
71
75
  default: {
72
76
  const exprLoc = this.loc();
73
77
  const expr = this.parseExpr();
@@ -696,7 +700,7 @@ export class Parser {
696
700
  this.pos = saved;
697
701
  const expr = this.parseExpr();
698
702
  this.expect(TokenType.RParen);
699
- return expr;
703
+ return { kind: "GroupExpr", expr, loc };
700
704
  }
701
705
  // List literal or comprehension
702
706
  if (t.type === TokenType.LBracket) {
@@ -856,9 +860,13 @@ export class Parser {
856
860
  this.expect(TokenType.RBracket);
857
861
  return { kind: "ListLiteral", elements, loc };
858
862
  }
863
+ isIdentOrKeyword(t) {
864
+ const tt = t ?? this.peek().type;
865
+ return tt === TokenType.Ident || tt === TokenType.Match || tt === TokenType.Fn || tt === TokenType.Let || tt === TokenType.If || tt === TokenType.For || tt === TokenType.In || tt === TokenType.Do || tt === TokenType.While || tt === TokenType.Until || tt === TokenType.Use || tt === TokenType.Pub || tt === TokenType.Type || tt === TokenType.Ret || tt === TokenType.Where || tt === TokenType.Matching || tt === TokenType.Fetch || tt === TokenType.Async || tt === TokenType.Await || tt === TokenType.Try || tt === TokenType.Catch || tt === TokenType.Mut || tt === TokenType.True || tt === TokenType.False || tt === TokenType.NilKw || tt === TokenType.And || tt === TokenType.Or || tt === TokenType.Not || tt === TokenType.Break || tt === TokenType.Continue || tt === TokenType.El;
866
+ }
859
867
  isMapStart() {
860
868
  // Check if current position (after {) looks like a map entry
861
- if (this.at(TokenType.Ident) && this.tokens[this.pos + 1]?.type === TokenType.Colon)
869
+ if (this.isIdentOrKeyword() && this.tokens[this.pos + 1]?.type === TokenType.Colon)
862
870
  return true;
863
871
  if (this.at(TokenType.String) && this.tokens[this.pos + 1]?.type === TokenType.Colon)
864
872
  return true;
@@ -912,7 +920,13 @@ export class Parser {
912
920
  const value = this.parseExpr();
913
921
  return { key, value };
914
922
  }
915
- // Ident key: name: value
923
+ // Ident or keyword key: name: value
924
+ if (this.isIdentOrKeyword()) {
925
+ const key = this.advance().value;
926
+ this.expect(TokenType.Colon);
927
+ const value = this.parseExpr();
928
+ return { key, value };
929
+ }
916
930
  const key = this.expect(TokenType.Ident).value;
917
931
  this.expect(TokenType.Colon);
918
932
  const value = this.parseExpr();
package/dist/version.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export declare const ARC_VERSION = "0.6.7";
1
+ export declare const ARC_VERSION = "0.6.8";
2
2
  export declare const ARC_BUILD_DATE: string;
3
3
  export declare const ARC_PLATFORM: string;
4
4
  /** Print version info */
package/dist/version.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // Arc Version System
2
- export const ARC_VERSION = "0.6.7";
2
+ export const ARC_VERSION = "0.6.8";
3
3
  export const ARC_BUILD_DATE = new Date().toISOString().split("T")[0];
4
4
  export const ARC_PLATFORM = `${process.platform}-${process.arch}`;
5
5
  /** Print version info */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arc-lang",
3
- "version": "0.6.7",
3
+ "version": "0.6.8",
4
4
  "description": "Arc ⚡ — A programming language designed by AI agents, for AI agents. 27-63% fewer tokens than JavaScript.",
5
5
  "type": "module",
6
6
  "bin": {