Skip to content

Draft language v0.2: arrays, main(args), string conversions, f-strings - #22

Open
yunabe wants to merge 2 commits into
mainfrom
claude/spec-v0.2-draft
Open

Draft language v0.2: arrays, main(args), string conversions, f-strings#22
yunabe wants to merge 2 commits into
mainfrom
claude/spec-v0.2-draft

Conversation

@yunabe

@yunabe yunabe commented Sep 3, 2026

Copy link
Copy Markdown
Owner

Summary

Starts the v0.2 cycle the same way v0.1 started: specification first. LANGUAGE_SPEC.md on main becomes the v0.2 draft — a status note marks it unimplemented and points at the v0.1.0 tag, which preserves the released v0.1 spec+compiler pair. Scope is the candidate list we accumulated during v0.1 development; everything else stays in §13.

Arrays (§3.1, §4.5, §8.4–8.6, §9.3, §10.2, §11)

  • []T over any element type — arrays compose, so [][]i64 is a jagged .NET long[][] with chained indexing grid[i][j] (revised after review: the nesting restriction was a non-orthogonal special case that saved almost nothing). Fixed length, reference semantics, never null, mutable elements; the repeat form's sharing consequence ([[0; 3]; 2] shares one inner array) is specified with the fill-in-a-loop idiom.
  • Creation: [e1, …, en] (with an expected []T, elements force to T; without one, elements resolve independently and must agree — so [] without an expectation is a compile-time error) and the repeat form [value; count] (value then count, each once; negative count is a runtime error).
  • Zero-based i64 indexing (an expected-type position, like range endpoints) with runtime bounds errors on reads and writes; assignment targets extend to name[index] op= value.
  • for x in array shares the range loop's variable rules; elements are read per iteration.
  • len(array) -> i64 as a second compiler builtin — expression-valued, unlike print; len on strings deliberately stays out (§13).
  • Deliberately absent: array ==/!= and print(array) — reference-vs-content ambiguity is postponed rather than answered wrongly.

fn main(args: []string) (§5.1)

Receives all arguments verbatim (no program name, no parsing, no usage exit), alongside — not replacing — the typed-parameter form. []string is the only array type allowed on main and cannot be mixed with typed parameters.

String conversions (§7)

i32/i64/f32/f64/bool(string) parse with exactly the §5.1 argument grammar (invariant, finite-only, case-insensitive bool) and fail with a runtime error — consistent with the section's other checked conversions, and making i64(string(x)) == x hold for integers. The main(args) + i64(arg) combination closes the loop that motivated typed main. A non-fatal try-style form is a §13 candidate.

Interpolated strings (§4.6)

f"x = ${x}", defined entirely by desugaring: text segments concatenated with string(hole) conversions, left to right. Per the earlier discussion: ${expr} only — a bare $ is a compile-time error (reserving $name shorthand, listed in §13), \$ escapes — and plain strings are untouched ($ stays ordinary, \$ invalid there). Holes take any primitive-typed expression, nested f-strings included.

Grammar (§12)

type gains the [] prefix; postfix indexing joins precedence level 1; array-expression; assignment-target; the for range clause becomes optional; interpolated-string joins literal with a lexical note.

Specification only — no compiler changes (dotnet test: 421 passed / 1 skipped, untouched). README's note now distinguishes "implemented v0.1" from "drafted v0.2", and CHANGELOG gains an Unreleased entry.

Points I'd flag for review as the debatable calls: reference semantics (vs. disallowing array assignment), the [value; count] evaluation order and its nested-array sharing, banning bare $, len rejecting strings, and keeping array equality/printing out entirely.

🤖 Generated with Claude Code

yunabe and others added 2 commits September 3, 2026 21:24
Rewrites LANGUAGE_SPEC.md as the version 0.2 draft (the v0.1
specification is preserved at the v0.1.0 tag; a status note marks the
draft as unimplemented). The scope is the candidate list accumulated
during v0.1 development:

- Array types []T over primitive elements: fixed length, reference
  semantics, always non-null; creation via element lists and the
  [value; count] repeat form (empty literals need an expected type);
  zero-based i64 indexing with runtime bounds errors; element
  assignment including compound forms; no array operators, equality,
  or printing in this version.
- for over arrays, sharing the range loop's variable rules.
- fn main(args: []string) receiving all arguments verbatim, alongside
  the typed-parameter form.
- string-to-primitive conversions using exactly the main-argument
  grammar, failing with a runtime error, making string(x)/i64(s)
  inverses for integers.
- Interpolated strings: f-prefixed, ${expression} holes only, defined
  by desugaring to string(...) concatenation; \$ escapes a dollar and
  a bare $ is reserved (a compile-time error).
- len as a second compiler builtin (arrays only, expression-valued).
- Section 13 pruned to what remains outside 0.2, gaining nested
  arrays, string length/indexing, $name shorthand, and non-fatal
  string parsing.

README points at the tagged v0.1 spec and marks the draft; CHANGELOG
gains an Unreleased entry. Specification only - no compiler changes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Review pushback: the nesting restriction saved almost nothing. The
draft grammar already parsed chained indexing and nested literals; the
real implementation delta is an interned recursive array type and a
TypeSpec row for array-of-array tokens, while the element-kind
dispatch in the emitter is needed for []string regardless. Excluding
nesting bought ~35 lines at the cost of a non-orthogonal special case.

Array types now compose ([][]i64 is a jagged .NET long[][]; types are
structural), indexing and assignment targets chain (grid[i][j]), and
the repeat form's reference-sharing consequence is spelled out with
the [[0; 3]; 2] example and the fill-in-a-loop idiom. Rectangular
multi-dimensional arrays move to section 13.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comment thread LANGUAGE_SPEC.md
Element-list form `[e1, e2, …, en]`:

- The elements are evaluated left to right.
- When an expected array type `[]T` is available (Section 7), every element takes `T` as its expected type and must have type `T`.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The expected-type model is incomplete here. This rule makes let names: []string = [] valid, but Section 7 still says that an expected type applies only to a literal of the same numeric category. The repeat form also never says whether an expected []T is propagated to value, so a common case such as let xs: []i32 = [0; n] is currently undefined (or would infer []i64). Please update Section 7 to include array creation expressions and explicitly define contextual typing for the repeat form, including recursive propagation for nested arrays.

Comment thread LANGUAGE_SPEC.md
- A `string` converts to itself.

Converting a `string` to another type is not supported in version 0.1.
A `string` may be converted to any other primitive type. The text is parsed with exactly the grammar of a `main` argument of that type (Section 5.1): culture-invariant, optional sign and exponent for numerics, finite values only, case-insensitive `true`/`false` for `bool`, surrounding white space ignored. A string that fails to parse is a **runtime error** — consistent with the other checked conversions in this section — so `i64("12")` is `12` and `i64(string(x)) == x` holds for every integer `x`, while `i64("12.5")` and `bool("yes")` fail at runtime:

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sentence contains two conflicting claims. First, “optional sign and exponent for numerics” implies that an integer conversion such as i64("1e2") accepts an exponent, whereas Section 5.1 permits exponents only for floating-point arguments; consider saying “an optional sign for numerics and an optional exponent for floating-point values.” Second, i64(string(x)) == x is not well-typed for an i32 value because mixed-width numeric comparisons are prohibited. Either restrict x to i64, or state the round trip using the matching integer type.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant