spec(gazprea): consolidated spec-review stack — nested types + audit fixes - #139
spec(gazprea): consolidated spec-review stack — nested types + audit fixes#139Sir-NoChill wants to merge 61 commits into
Conversation
Manifest-driven apt/check/healthcheck scripts plus the session's
ephemeral agent signing identity, per the agent-bootstrap protocol.
Volatile paths (key material, baselines, agent-env.sh) are gitignored.
The scaffold is vendor-neutral: the directory is `.agents/`, the default
identity is generic ("Agent"), and the skills-directory path is a
manifest variable rather than hardcoded to any one agent tool's
convention.
Assisted-by: Agent <ai@blobfish.icu>
Applies review feedback from PR #110. Removes the committed rendered scripts (bootstrap.sh, check.sh, healthcheck.sh) and the committed public key (agent-pubkey.asc); each session regenerates the scripts from the .tmpl files via render.py before running bootstrap. Identity is now opt-in: the manifest's `agent:` block is blank by default, and bootstrap only mints a GPG signing key (and writes agent-env.sh) when a user fills it in locally. Users choose their own signing identity; the repo prescribes none. Python dependencies move to pyproject.toml under uv: bootstrap installs uv from astral.sh if missing, then runs `uv sync` to provision a venv pinning sphinx==6.2.1 alongside jinja2 and PyYAML (both needed by render.py, which now uses stock Jinja2 with a `{## ##}` comment tag to avoid colliding with bash's `${#arr[@]}` array-length syntax). Adds an empty `.agents/skills/` directory as the location for bundled review skills; `manifest.yaml`'s `skills:` list names entries under it, and healthcheck asserts each listed skill has a non-empty SKILL.md. BREAKING CHANGE: `.agents/bootstrap.sh`, `.agents/check.sh`, and `.agents/healthcheck.sh` are no longer tracked. Existing checkouts must render them once (`for t in .agents/*.tmpl; do uv run .agents/render.py .agents/manifest.yaml "$t" > "${t%.tmpl}"; done`) before running bootstrap. Users who had a signing identity configured must re-populate the `agent:` block in their local copy of manifest.yaml. Assisted-by: Agent (claude) <ai@blobfish.icu>
Populates .agents/skills/ with the two skills the repo will actually use during specification review, and lists them in manifest.yaml so the healthcheck notices if either goes missing. spec-review is the editorial/structural checklist a human maintainer runs before a spec chapter merges: build integrity (`sphinx-build -W -n`), heading hierarchy, `:term:`/`:ref:`/`:doc:` cross-reference integrity, admonition placement, gazc-backed sanity check on `.. code-block:: gazprea` examples, TODO/FIXME residue, and targeted sibling-file consistency spot-checks. grammar-consistency catches the cross-file syntactic-surface divergences that PRs like #116 (vector-vs-array) and #118 (precedence single-home) exist to fix. It compares the same grammar element (keyword, operator, named rule, type-form) as it appears in different chapters and reports disagreements without picking a winner -- consistency is orthogonal to correctness. Assisted-by: Agent (claude) <ai@blobfish.icu>
Adds .agents/skills/spec-review/check-ci.sh, which runs the same two
checks CI does before a spec change hits the remote:
* Sphinx build across every doc subdir in the top-level Makefile
(setup, generator, lolcode, vcalc, gazprea, info), with -W -n so
warnings and unresolved cross-references become errors -- stricter
than the CI deploy step's own `make html`.
* lychee over the exact file globs and args CI's linkcheck.yml uses,
self-installing the binary from lycheeverse's installer or cargo
when it is missing rather than silently skipping the check.
Sub-modes `sphinx` and `links` scope the run to one workflow's worth
of checks. The SKILL.md checklist's "build integrity" step now points
at the script instead of open-coding the sphinx-build invocation.
Assisted-by: Agent (claude) <ai@blobfish.icu>
Address the review on #110: - manifest.yaml now names ghcr.io/cmput415/docs-dev as the preferred environment; native apt/uv path stays as a fallback. - README.md documents the docker-first flow, keeps the "regenerate on session start" note, and explicitly frames signing as opt-in and non-prescriptive. - bootstrap.sh.tmpl trims the block-level commentary the reviewer called out; identity handling stays gated on a populated agent block. - skills/grammar-consistency/SKILL.md is rewritten to audit English prose (spelling, passive voice, subject/tense, terminology, technical-writing anti-patterns). Deriving the Gazprea grammar from the informal spec is a student exercise and is now out of scope. - skills/spec-review/SKILL.md swaps the hand-rolled check-ci.sh for act-based workflow replay (act ships in the DocsDev image) and points at grammar-consistency for prose review. - Removes .agents/skills/spec-review/check-ci.sh (subsumed by act). Assisted-by: Agent (claude) <ai@blobfish.icu>
The /tree/main/DocsDev path does not exist on cmput415/ci-utils and tripped linkcheck. The repo root already documents the image.
pyproject.toml was committed without its lockfile, so `uv sync` resolved freely on every checkout and the session environment was not actually reproducible. Pin it. Assisted-by: Agent (claude) <ai@blobfish.icu>
String and free len() do not exist (string, length(), or the .len() method do), char is not a type (character is), and comma indexing M[1, 2] is defined nowhere (composite M[1][2] is). Each example now uses the spelling the spec defines. Assisted-by: Agent <ai@blobfish.icu>
Follow-up polish on top of "replace undefined syntax in examples" so the
patch's own examples read cleanly:
* ``procedures.rst`` byvalue/byreference now call ``x.len()`` on the
``string`` argument instead of the free ``length(x)``. ``string`` is
a sub-type of ``vector<character>`` (types/string.rst:76) and
``vector`` defines ``.len()`` (types/vector.rst:65); using the method
keeps the string-vs-vector surface consistent, which is the shape
the rest of the spec assumes.
* ``types/struct.rst`` renames the ``character char`` and ``real float``
fields on the ``Another`` example to ``character c`` and ``real r``.
Naming a field after a type from another language reads like a
keyword clash even though Gazprea's grammar allows it; the new
names follow the ``s1`` example's ``i``/``r``/``iv`` convention.
Also fixes the paragraph that referred to the struct by the wrong
name (``Struct type "s"`` -> ``s1``) and updates the field-name
list to match.
Assisted-by: Agent (claude) <ai@blobfish.icu>
Human-review follow-up. The previous rename (fcf3ad8) landed on `character c, real r, string[256] str, s1 struct_field`, which put Another's `r` right next to the sibling `s1` example's `r` field two lines above. Scoping is fine (each struct owns its field namespace), but the collision reads as an accidental repeat in a two-line example whose whole point is to show that field identifiers are chosen freely. Rename to `character ch, real f, string[256] str, s1 struct_field`, and update the prose that enumerates them. Distinct short names, no shadow of the neighbouring example, and still tracks the `s1` `i`/`r`/`iv` pattern of using initials-of-the-type. Assisted-by: Agent (claude) <ai@blobfish.icu>
vector<T> never said which T are legal, leaving vector<vector<T>>, vector<tuple(...)>, and vector<string> undecidable. Now: base types and 1-D arrays of base types, matching every existing example. Assisted-by: Agent <ai@blobfish.icu>
Human-review follow-up. The new `vector<T>` element-type rule enumerated the base types as `(boolean, character, integer, real)`, which is inconsistent with the two other places the same set is enumerated: `types/array.rst:6` and `constexpr.rst:22` both use `(boolean, integer, real, character)`. Any drift between these three enumerations makes a reader wonder if the set itself changed at one of the sites. Reorder the vector rule to match. Same set, no rot; if the set ever does grow (e.g. `string` promoted to a base type), all three files will need to change in lockstep and having them start identical makes that easier. Assisted-by: Agent (claude) <ai@blobfish.icu>
'Vectors behave exactly like arrays' papered over normative differences the same file relies on: methods, array-valued binary results, and a pad-to-first ragged policy that contradicts matrix pad-to-longest for the same literal. The claim is now an interop list plus an explicit enumeration of the differences, with a cross-reference at the padding rule. Also replaces the undefined term 'subroutines'. Assisted-by: Agent <ai@blobfish.icu>
Follow-up polish on top of "scope the vector-array equivalence claim" (ab6eeed). Two lingering over-broad claims in ``types/vector.rst``: * The intro's differences list said "binary operations *involving a vector* produce array results", but the body (the "Operations" subsection just below) only supports that for *mixed* vector+array operations. The vector+vector case is not stated anywhere. Narrow the intro to match the body: "a mixed binary operation between a vector and an array". * The Operations subsection opened with "Operations on vectors are identical syntactically **and semantically** to operations on arrays" -- the exact over-broad equivalence the patch is scoping out of the intro. Left in place, it re-introduces the paperover a few lines down. Reword to "use the same syntax as ... and, except for the differences enumerated above, share their semantics" so the enumeration in the intro remains authoritative. Assisted-by: Agent (claude) <ai@blobfish.icu>
Human-review follow-up. Two related over-commits in the intro
paragraph now that the six spec-review PRs are viewed as a group:
* "interoperate freely with arrays" — overstates the case once the
vector element-type restriction (companion PR #113) lands. A
`vector<S>` where `S` is a struct never exists, so interop is
"free" only over the element types both sides support. Add the
qualifier: "interoperate with arrays for the element types they
both support".
* "the differences are normative: [three-item list]" — presented as
exhaustive. Once PR #113 merges, a fourth normative difference
(element-type set is narrower on vectors) is documented directly
below, and a reader who trusts this enumeration as complete will
miss it. Soften to "differences include (non-exhaustively)" so
the paragraph remains true after the neighbouring PR merges and
tolerates future additions without re-editing.
Assisted-by: Agent (claude) <ai@blobfish.icu>
'Arrays cannot be indexed with array expressions' collided with ranges being arrays and with slicing being defined as indexing by a range. The rule now names the distinction: array values (including ranges bound to variables) are illegal indices; literal range syntax in an index position is the slice form. Assisted-by: Agent <ai@blobfish.icu>
Follow-up polish on top of "distinguish range slices from array-valued indices" (ebe5f8d). The patch scoped the general rule in statements.rst but left `types/array.rst`'s indexing subsection saying only "An array may be indexed using integers", which continued to contradict the very next subsection defining slices as indexing by a range. Extend the rule here to match: an integer index yields an element, a range at the index position yields a slice (with a cross-reference to the slices subsection), and an array *value* (including a range bound to a variable) is not a legal index. Same distinction the statements.rst hunk introduced, phrased for the type chapter's local vocabulary. Assisted-by: Agent (claude) <ai@blobfish.icu>
…pression Human-review follow-up. The original rule at statements.rst:46 said ``v[w]`` is illegal "when ``w`` is an array variable", but the companion rule at types/array.rst:260 (added on the same branch) correctly says "an array *value* … is not a legal index". Different scopes for the same rule: an expression, a parenthesized value, or a function call that returns an integer array is caught by the array.rst wording and slips past the statements.rst one. Widen statements.rst to "whenever ``w`` evaluates to an array value", and spell out the class of expressions this covers. Same rule stated consistently in both chapters, no more gap on function-returned ranges. Assisted-by: Agent (claude) <ai@blobfish.icu>
The universal claim was false for string/character[*] (no as<> form exists) and glossed the size requirement on scalar-to-array casts. The vague 'higher dimension' exception is replaced with the concrete rule (no 1-D to 2-D promotion; scalars broadcast), the square-matrix note is scoped to ** operands, and the string promotion section now names the array/vector distinction precisely. Assisted-by: Agent <ai@blobfish.icu>
Follow-up polish on top of "scope the promotion-implies-cast claim" (c087971). * The scalar-to-matrix promotion note used "a matrix of any shape". ``shape`` is a stdlib extension in this project, not part of the formal spec (a companion patch consciously scopes it out), and reusing the word here as a common noun invites conflation. Swap to "of any dimensions". * The Character-Array/String section's added tail clause ("a ``string`` used where a character array is expected, or vice-versa, converts silently") duplicated "implicitly converted" from the sentence just above it. Drop the redundant clause; the "of note is between ``string`` and character *arrays*" pointer still carries the intended emphasis. Assisted-by: Agent (claude) <ai@blobfish.icu>
Human-review follow-up. The first commit introduced a positional
forward reference ("see the final section of this chapter") from the
intro's second caveat down to the Character-Array/String section.
Positional references silently break when a later section is added
to the chapter — the "final section" is no longer the intended
target.
Add an `ssec:typePromotion_string` label on the section heading and
swap the intro's forward reference to `:ref:` against that label.
Same target today, robust against reordering, and readable inline
(Sphinx renders the section title).
Assisted-by: Agent (claude) <ai@blobfish.icu>
The precedence relation existed in three copies (expressions.rst, integer.rst, boolean.rst); the per-type copies are the divergence trap since any operator change must land in all three. The per-type pages now reference the normative table in expressions.rst. Assisted-by: Agent <ai@blobfish.icu>
… parens note
Two human-review follow-ups on the operator-precedence single-home
refactor:
* `types/real.rst:55` still routed readers to the integer chapter's
Operations subsection for "operation and precedence". Now that
integer.rst delegates upward instead of hosting the table, this
is a two-hop indirection where the first hop no longer contains
what the sentence promises. Split the sentence: operations
(semantics — IEEE-754-style behavior, unary rules, C99 remainder)
still point at `sssec:integer_ops`; precedence and associativity
point directly at the normative table.
* The integer chapter's removed precedence paragraph carried a
useful note that parentheses are absent from the list because
they override precedence rather than participate in it. The note
is normative guidance about the table, not integer-specific, so
lift it into `expressions.rst` alongside the table itself.
Assisted-by: Agent (claude) <ai@blobfish.icu>
The procedure was fully specified twice: only built_in_functions.rst had the initial state, only streams.rst had the null-value/position rule, and the two used different wording. streams.rst error handling is now normative (codes, initial state, per-type table); built-ins keeps the signature, marked as notional since input_stream is not a language type. Also fixes the F 1.0 output that violated the %g rule, the 'characters have no error state' claim contradicted by the state table, and the undefined 'null value' term. Assisted-by: Agent <ai@blobfish.icu>
The rule was restated in three files; type_qualifiers.rst is now the normative home and the misleading 'essentially a no-op' wording is replaced. The other two sites cross-reference it. Assisted-by: Agent <ai@blobfish.icu>
…e the last duplicate
Two human-review follow-ups on the const-by-default single-home
refactor:
* The normative paragraph in `type_qualifiers.rst` now names the
default-is-const rule explicitly, but the "both spellings are
legal" corollary was only implicit ("writing ``const`` is
therefore redundant"). A reader is left to infer that
``T x`` and ``const T x`` are exchangeable. Add a one-sentence
explicit statement of that equivalence so the normative section
doesn't rely on the reader's inference.
* `procedures.rst:9` is the last remaining restatement: "By default
arguments are ``const`` just like functions." Its scope
(parameter-passing) is narrower than the variable-declaration
rule and it is worth keeping in place for readers landing on the
procedures chapter, but it should point at the normative home so
it does not become a fourth divergent copy. Add a
`see :ref:sec:typeQualifiers` cross-reference.
Assisted-by: Agent (claude) <ai@blobfish.icu>
The impl chapter (sec:errors) defines the full error taxonomy, but a dozen spec rules said only 'an error', leaving class and phase to guess. Each site now names the class from the taxonomy and the first mention in each file cross-references sec:errors. Also normalizes 'should raise' to 'must raise' at these sites. Assisted-by: Agent <ai@blobfish.icu>
Two error-class mentions predate the errors-chapter patch but never had
the (see :ref:`sec:errors`) cross-reference the patch introduced at the
first mention in each file. Add the reference and normalize the site's
wording to the "must raise" phrasing used by the patch:
* typedef.rst: SymbolError for duplicate alias names. Also fixes a
literal-role typo (single-backticks would render as an unresolved
default role) and the missing trailing period.
* types/array.rst: SizeError for RHS-too-large in an array
initializer. This is the first error-class mention in the file
(line 53); the patch's cross-ref at line 280 was on the second
mention.
Assisted-by: Agent <ai@blobfish.icu>
Follow-up to the errors-chapter patch. Three coordinated cleanups, kept
in one commit so the wording change stays local to the sites it touches:
* Fill omitted error classifications the initial patch missed. Adds a
ReturnError classification to the "return reachable by all control
flows" rule (functions.rst), a GlobalError classification covering
the non-constexpr / vector-global / non-global-statement bullets
(globals.rst), a StatementError for a declaration outside the
leading declaration block of a block statement (declarations.rst),
a SyntaxError for iterator loops with more than one domain
(statements.rst iterator loop), and a StatementError for a
``continue`` outside a loop (statements.rst continue, mirroring the
``break`` rule).
* Normalize two "should raise" sites in files the patch already
touched but did not reword: SizeError for matmul dimension mismatch
(types/matrix.rst) and SizeError for elementwise binop size
mismatch (types/array.rst). Also normalizes typedef.rst's inline
"Should raise a ``SizeError``" callout on the size-mismatch example.
* Converge every patch insertion (and the two residuals above) on
"must emit a ``X``" (or the passive "must be emitted") for the
error-raising rule. The initial patch used six different verbs
(issue / raise / yield / cause / is / is to be produced) at
otherwise identical sites; one verb reads more consistently and
matches how the errors chapter itself describes the requirement.
Also drops the redundant ``(see :ref:`sec:errors`)`` on
types/array.rst:279 (out-of-bounds indexing) since types/array.rst:53
now carries the first-mention cross-reference for that file.
Assisted-by: Agent (claude) <ai@blobfish.icu>
Four follow-ups on the errors-chapter branch flagged by a human-review
pass across the six spec-review PRs open on this stack:
* `procedures.rst`: the two "*Gazprea* must emit a ``CallError``"
sites drifted from the "the compiler must emit …" subject used
everywhere else the pass touched. Normalize both to
"the compiler must emit".
* `globals.rst`: the summary paragraph re-enumerated the three
restrictions from the bullet list right above it, and the
re-enumeration silently rots when the bullets are edited.
Collapse to one sentence: "Violations of any of the above must
be reported as a ``GlobalError``." — no drifting second copy.
* `functions.rst`: the ReturnError classification I added on the
return-reachable-by-all-paths rule ended with a sentence
("Control-flow constructs are assumed to be undecidable, so
both branches of every conditional are considered reachable.")
that `impl/errors.rst:104-106` already states as part of the
normative ``ReturnError`` definition. Drop it here; the cross-ref
carries the rule.
* `declarations.rst`: the StatementError classification used the
undefined term "leading declaration block". Nothing else in the
spec introduces it, and the paragraph immediately above uses "at
the start of the block". Reword to "the declaration prefix at
the start of its enclosing block statement", and lead with the
compiler as the subject to match the surrounding rules.
Assisted-by: Agent (claude) <ai@blobfish.icu>
|
WRT Open Questions from the agent:
|
Begin folding PR #106 into the consolidated spec, with review decisions. - glossary: define `initialization` (renames #106's contested "elaboration") and `zero value` (RAII-const default; array padding). - types/array.rst: new Sizing section and an Array-vs-Vector table, both stated for arrays of any rank per #138 -- not 2-D / base-type-only. - Remove the `by` (stride) operator and `StrideError` entirely (it implies array views, which have no efficient implementation): the Stride operation, the precedence-table row, and the stride examples are gone. - Concatenating two scalars is now a `TypeError`; at least one operand of `||` must be a composite value. Refs #106. Assisted-by: Agent (claude) <ai@blobfish.icu>
Renames the implicit-conversion vocabulary from 'promotion' to 'implicit cast' (heading of sec:typePromotion becomes 'Implicit Casts', label kept), and adds two-way array/vector casting sections. Part of folding #106. Assisted-by: Agent (claude) <ai@blobfish.icu>
string is now a language-supplied typealias for vector<character> (not a sub-type). Methods are defined as procedures with a self parameter; only vector/string have them. Adds ragged rules: vector<vector<T>> may be ragged, vector<T[*]> may not; no broadcasting or shape(). Folds #106. Assisted-by: Agent (claude) <ai@blobfish.icu>
Assignment sizing (array pads/SizeError vs vector replaces), generators always yield arrays, vectors print as arrays, length() on a vector is current-length. Replaces the shape() built-in with rows/columns. Folds #106. Assisted-by: Agent (claude) <ai@blobfish.icu>
Explicit-size array params are part of the signature; inferred [*] is initialized at the call; var array can't resize but var vector can. Single source-of-truth list of legal procedure-call positions; call results are castable. Folds #106. Assisted-by: Agent (claude) <ai@blobfish.icu>
Combined struct form takes const/var and structs may be defined in any scope; drop the duplicated Associativity column and StrideError; matrix sizing note. Corrects the character zero value to a space (not the null char) in the glossary and declarations. Assisted-by: Agent (claude) <ai@blobfish.icu>
Fixes the unambiguous findings from the adversarial ratification review: - Complete the promotion -> implicit-cast rename: per-type "Type Casting and Implicit Casts" headings, a glossary "implicit cast" term, and dropping the false "every promotion has an as<> form" claim. - Reconcile contradictions: a generator's rank is set by iterator-variable count, not domain shape; rows/columns are matrix-only; push/append on an array is a TypeError (arrays have no methods), not a SizeError. - Remove `by` from the keyword list; fix the IndexError example (integer[4] -> x[4]) and the mislabeled i[1] SymbolError -> TypeError. - Renumber the array Operations list (a..f), link lvalue/rvalue, use "primitive type", state a global string is illegal, plus many typo, curly-quote, agreement, and US-locale fixes. Design questions the review surfaced are deliberately left untouched (runtime array size vs constexpr, integer ^ and division semantics, the boolean/character cast mapping, namespace count) pending a language-owner decision. Assisted-by: Agent (claude) <ai@blobfish.icu>
Applies the language-owner rulings on the questions the review surfaced, plus the pass-2 review findings. - Runtime array sizing is legal. Sharpen `initialization` (the run-time instant immediately before a declaration's first execution; a size is evaluated exactly once and the array can never be resized), drop the Ada "elaboration" quote, and reconcile constexpr.rst and array.rst so a runtime array size is a legal non-constexpr array -- a vector is only for a length that must change. - string / character[*] has both implicit and explicit as<> forms (a string is a vector), so drop the "no as<> form" caveat in type_promotion.rst and the glossary. - Built-in names (length, rows, columns, reverse, format, stream_state) are semantically reserved, not syntactic keywords: remove them from the keyword list; shadowing any of them, by any identifier, is a SymbolError. - Fixes: scalar-broadcast element-type wording; the misleading method-call "no-op"; loops and domains accept vector and string; an array-valued index is a TypeError; matrix/array pad with the element type's zero value; missing semicolons. Context (already stated in the spec): everything is 32-bit (i32/f32), so integer ^ (reals-then-truncate) is well-defined; boolean -> character is explicit-only, and as<character>(false) is the null character, distinct from the space zero value. Assisted-by: Agent (claude) <ai@blobfish.icu>
Last advisory/nit findings from the convergence pass (the cross-cutting review came back clean): scope the built-ins-on-vectors claim to array-shaped built-ins (length/reverse); rename the mislabeled ssec:procedure_alias -> ssec:procedure_implicit_casts; behaviour -> behavior. Assisted-by: Agent (claude) <ai@blobfish.icu>
| Sizing | ||
| ~~~~~~ | ||
|
|
||
| Arrays are **initialization-time sized**. The length of an array variable -- |
There was a problem hiding this comment.
we should put this definition in the glossary and write in terms of points and paths
| also stand alone as a statement, terminated by a semicolon; this is the | ||
| only expression form that may be used as a statement. An explicit | ||
| ``call`` statement may also be applied to a method call; the method still | ||
| runs and still acts on its receiver exactly as in the bare statement form. | ||
| The ``call`` keyword adds nothing here -- any result is discarded either | ||
| way -- so it is never required for a method call. |
There was a problem hiding this comment.
no, method calls that stand alone must be part of a call statement, else we have a call error
| v2.len() -> std_output; // 3 | ||
|
|
||
| v2.len(); // Does nothing | ||
| v2.len(); // Legal statement; result discarded |
There was a problem hiding this comment.
must be call v2.len()
| This is the single authoritative list of those positions: wherever else this | ||
| specification refers to where a procedure call may appear, it points back to | ||
| this list rather than restating it. In particular, a procedure call may not be | ||
| used as the control expression of a control-flow statement. |
There was a problem hiding this comment.
| This is the single authoritative list of those positions: wherever else this | |
| specification refers to where a procedure call may appear, it points back to | |
| this list rather than restating it. In particular, a procedure call may not be | |
| used as the control expression of a control-flow statement. | |
| This is the single authoritative list of those positions. A procedure call | |
| may not be used as the control expression of a control-flow statement. |
| An argument may be :ref:`implicitly cast <sec:typePromotion>` to the parameter | ||
| type at call time, but only if the argument is passed by value (that is, the | ||
| parameter is ``const``). A mutable (``var``) parameter is effectively call by | ||
| reference, so the parameter and the argument denote the same *l-value* (a | ||
| pointer); there is no separate value to convert, and so no implicit cast can be | ||
| inserted. |
There was a problem hiding this comment.
I just want to fact check this wrt const values being pass by value and var values being passed by reference. I think this is the most sensible way to implement the language for sure, but I'm not sure it is the only way.
Rename type_promotion.rst -> implicit_casts.rst (sec:implicitCasts) and typedef.rst -> typealias.rst (sec:typealias), updating the toctree and impl/part_1 cross-references so 'cast' is the umbrella term over implicit/explicit casts. implicit_casts: add an Array-to-Array section, broaden array<->vector casts to composite element types, scope scalar broadcast to 'array of any rank (matrix = rank-2)', and rename the table placeholder var->value. typealias: a local typealias is a StatementError, and aliasable types use the canonical aggregate-type wording. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Array slices are half-open (lower-inclusive, upper-exclusive) and are always a VIEW into the backing array, never a copy (a splat copy operator is future work); out-of-range slice bounds raise an IndexError. '**' is the dot product for rank-1 operands and matrix multiplication for rank-2, casting mixed element types to a common type. Add missing SizeError/IndexError citations and normalize 'array of any rank (matrix = rank-2)'. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Vector methods split into stateless functions (len, expression-only) and stateful procedures (push/append, call-statement only; bare form is a CallError). Strengthen the string = vector<character> alias. Struct: literal fields may be implicitly cast, dot-access on a non-variable is a TypeError, and field identifiers form a per-struct namespace. Tuple: out-of-range field index is an IndexError, type-inferred init accepts any statically-typed tuple, and a type-signature mismatch on comparison is a TypeError. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Integer overflow raises a MathError, except under -ffast-math where it is the language's sole undefined behavior; %-by-zero is a MathError. Real overflow and division by 0.0 raise a MathError under normal evaluation and produce the IEEE-754 result under -ffast-math. integer<->character casts use the ASCII/byte value; a scalar may be cast to a single-element vector with an explicit element type; add the closed-world 'any undescribed cast is a TypeError' rule. Drop duplicate per-type associativity columns. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Single-source the procedure call positions and the operators allowed on a call result (violations are a CallError); a procedure call cannot appear as a control expression or stream operand. Rescope aliasing to var-involved arguments, add the disjoint-field example, and make two var slices of one backing array always alias. Name MainError for main(), StatementError for I/O in a function, TypeError for a return-type mismatch, and normalize assignment/slice/generator error emissions to the canonical form. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
State that a non-declaration statement at global scope is a GlobalError and that assigning to an undeclared identifier is a SymbolError. Extend the constexpr operator set (comparison/boolean/%/^), split its unary/binary rule, and make aggregate operators and slices over constexpr arrays constexpr. Declare three identifier namespaces (type, variable/function, struct-field). Define 'value type' and fix the storable-types nesting wording; drop maintainer-only signposts and misc prose. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bar tuples and structs from stream output (TypeError) and a procedure call from a stream operand (CallError). format() reuses the output-format representation; length is defined for rank-1/vector/string and a domain-restricted built-in is a TypeError. Carve out -ffast-math integer overflow as the sole undefined behavior in the implementation-defined-behavior entry, add 'explicit cast' and 'value type' glossary entries, and align the referential-transparency entry with the push/append exception. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Rewrap prose paragraphs -- including list items, preserving each marker and its hanging indent -- so no prose line exceeds 80 columns, for a consistent line width across the specification. Formatting only: no content, code-block, or table changes, and the Sphinx build is unaffected. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
| The left hand bound is *inclusive* and the right hand bound is *exclusive*: | ||
| ``a[i..j]`` selects the elements from ``i`` up to but not including ``j``. | ||
| (This differs from a range *value*, whose bounds are both inclusive: | ||
| ``0..10`` written as an expression produces the integers 0 through 10, while |
There was a problem hiding this comment.
Makes me think that we should make ranges upper-bound exclusive to keep everything consistent.
| them, so a later write through either name is visible through the other. (A | ||
| dedicated copy operator is a planned future addition.) |
There was a problem hiding this comment.
We might have to add this in this version of the spec if we want to have meaningful slice semantics. I think that if students don't have a copy operator (a splat) then they will become confused
| 6. Functions cannot call any procedures, with one exception: a mutating | ||
| vector/string method (``push``, ``append``) may be called on a variable | ||
| local to the function (see :ref:`sssec:vec_methods`); any other procedure | ||
| call inside a function must emit a ``CallError`` (see :ref:`sec:errors`). |
There was a problem hiding this comment.
Should we maybe be allowed to call a procedure on any local var to a function? Is this even possible to analyze efficiently?
Consolidated spec-review stack — 20 PRs in one
This collapses the stacked-PR chain (
gh stack #121, formerly[stack 1/20]–[stack 20/20], PRs #110–#138) into a single PR againstmaster. The 20 individual PRs are closed; their branches and comment threads stay readable at the links in the manifest below. All 40 commits are preserved (nothing squashed) — use the Files changed tab for the cumulative diff, or the commit list for the logical steps.Footprint: 35 files, +1576 / −229. Spec: 24 files under
gazprea/spec/. Infra: the.agents/reproducibility scaffold +pyproject.toml/uv.lock(from #110).Provenance: grew out of the vector-semantics discussion (#106) and the Aug-17 rubric-meeting action item (#132). The final nested-types change closes #106, #82, #71, #101, #86.
The stack intentionally states a rule and later revises it. Review the final tree, not the intermediate commits:
vector<T>is a base type or 1-D array only; no vectors/tuples/structs/strings." [stack 20/20] spec(gazprea): permit nested aggregates and n-d arrays #138 reverses this to "any storable type, nested to any depth." Net: permissive.s1 struct_fieldexample to comply with the old "no struct-in-struct" rule; [stack 20/20] spec(gazprea): permit nested aggregates and n-d arrays #138 lifts that rule (struct.rst:10,tuple.rst:6). Net: nesting legal; the example simply no longer demonstrates it.T[n1]...[nk], any element type.Open questions flagged for reviewer attention (per former PR)
These are the ambiguities each PR flagged as needing a language-owner decision (verify against
gazc/ the reference compiler where noted).#122 — combined struct decl form: does
struct S (...) x;accept a qualifier (var struct S (...) x;)? The "combined form is alwaysconst" claim is inferred from examples; ifgazcacceptsvar, it's wrong.#123 — mixed concatenation result: is
char || chareven legal? (patch's "(or characters)" assertschar||char = char[].) Is the rule "at least one operand isstring" or "either operand"?char[] || char[] = char[]is unexemplified.#124 — tuple member conversions: members "convert by their kind" lists only scalar + array. Nested
tuple,string,matrixmembers are unaddressed — now relevant post-#138. Confirm array-in-tuple casts pad/truncate like standalone array casts.#125 — uninit const & stride:
byis restricted to>= 1(rules outby -1reverse iteration — intended?). Uninitconstis defined as "holds the zero value permanently" — confirm that vs. treating uninit-const as a type error.#126 — slice bounds: confirm
..-iselects1..n-i; confirm the 1-indexed assertion doesn't contradict another chapter; confirm grammar acceptsa[i..j] by 2(vsa[i..j by 2]).#127 — struct fixed-length field: patch chose
character[256]overstring[256]. If sized/bounded strings are intended, the fix differs. (See cross-PR note — the nesting ban it obeyed is now reversed.)#128 — procedure call sites: are casts legal on a procedure-call result? (patch adds "and casts" to the operator whitelist.) Confirm the restatement's disallowed-site list is the exact inverse of the chapter-top allowed list.
#129 — method-call surface (largest
feat:): (a) receivers are variables only — doesgazcacceptx.len()on a literal/expression result? (b) mutation limited to function-local vars vs. "no global/captured mutation" — which framing? (c)appendtie-break = single-element wins — matches reference? (d) "method call is the only expression usable as a statement" — reconcile withcallstatements. (e)concat→appendrename is breaking — does the reference still exposeconcatas an alias?#114 — range vs array-index: is matrix slicing intended? (
matrix.rst:103still "indices must be integers"). No formal def of "range syntax" vs "range expression";by-on-slice rule lives in a different chapter and may drift.#115 — promotion vs cast:
type_casting.rst:48still says "promoted" for an explicitas<>cast;type_casting.rst:95allows array→array casts across dimensions — confirm 1-D↔2-D explicit cast is intended.#138 — nested aggregates & n-d arrays (deferred, not in scope): a rank-agnostic
shapeinterface (vsrows/columns, per #82), n-d matrix-multiply, and broadcasting are left to a follow-up. The ragged (vector<vector<T>>) vs rectangular (vector<T[*]>,T[*][*]) split from #101 is implied but not yet spelled out operationally.Lower-priority / follow-ups noted in-PR: #116 (
string.rst:8loose equivalence); #118 (integer.rstAssociativity column duplication); #111 (expressions.rst:54generator-error class; repo-wide "must emit" sweep); #112 (proseString/Vectorcapitalization left per maintainer decision). #119, #120, #130 flagged no open questions.Infra (
.agents/scaffold, from #110) — open feedback digestPR #110 drew 25 inline comments (@Sir-NoChill). Themes (several already addressed by later commits on the same branch —
223c45ddrop identity prescription & generated artifacts,6e2bbbapoint .agents/ at the DocsDoc image + rewrite skills,66ae45fuv lockfile):agent-pubkey.asc. (→ addressed by223c45d.)bootstrap.sh/check.sh/healthcheck.share rendered from templates; gitignore them and regenerate on setup. (→ addressed by223c45d.)cmput415/ci-utils(optionally a nix flake); point the manifest/README at the container instead of a bash env harness. (→ partly addressed by6e2bbba.)uv—pyproject.toml+uv syncon a uv-managed venv. (→ addressed by66ae45f+ pyproject.)jinja2— use the jinja2 package rather than a custom renderer (render.pywas later approved: "This is perfect").grammar-consistencyskill — focus on English prose quality (spelling, passive voice, subject consistency, technical writing), not the Gazprea EBNF (that's the students' exercise); thespec-reviewskill should consume it after the rewrite. (→ addressed by6e2bbba.)actrather than a hand-rolledcheck-ci.shbash harness; add a.agents/scratchgitignore entry.Full thread: #110.
Manifest — the 20 collapsed PRs
chore/agents-scaffoldfix/undefined-syntax-examplesfix/vector-element-typesfix/vector-array-divergencefix/range-index-semanticsfix/promotion-cast-claimrefactor/precedence-single-homerefactor/stream-state-homerefactor/const-default-homefeat/errors-chapterfix/struct-decl-formfix/string-concat-resultfix/tuple-conversion-membersfix/uninit-const-and-stridefix/slice-boundsfix/struct-nestingfix/procedure-call-sitesfeat/method-callsfix/example-correctionsfeat/nested-composite-typesConsolidated from
gh stack #121. Individual PRs closed in favour of this one; commit history preserved.