Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
c8a71a1
chore: remove vector type specification
Sir-NoChill Feb 25, 2026
d80f747
chore: remove struct type specification
Sir-NoChill Feb 25, 2026
2b25062
chore: remove matrix type specification
Sir-NoChill Feb 25, 2026
a20d9d2
clean: remove deprecated keywords for removed features
Sir-NoChill Feb 25, 2026
c3f9751
clean: remove length built-in; update shape and reverse for N-D arrays
Sir-NoChill Feb 25, 2026
b4c8c28
impl: add constexpr specification
Sir-NoChill Feb 25, 2026
4f5a077
impl: add value-categories hint document
Sir-NoChill Feb 25, 2026
3cb11d3
clean: update globals initialization rule to reference constexpr
Sir-NoChill Feb 25, 2026
2119881
clean: add range and stride operator definitions to expressions
Sir-NoChill Feb 25, 2026
e8e553e
clean: update generator examples for N-dimensional array syntax
Sir-NoChill Feb 25, 2026
abaa136
clean: replace array spec with unified N-dimensional model
Sir-NoChill Feb 25, 2026
23b19e7
fix: uniform N-D array syntax throughout spec
Sir-NoChill Feb 25, 2026
cca38a1
impl: rewrite string type specification
Sir-NoChill Feb 25, 2026
8b5f0aa
impl: add type lattice diagram and revise type_promotion.rst
Sir-NoChill Feb 25, 2026
435f396
fix: update functions and procedures to reflect revised spec
Sir-NoChill Feb 25, 2026
454dfe9
enh: add integer overflow specification
Sir-NoChill Feb 25, 2026
06067d6
impl: rewrite tuple type specification with named-field support
Sir-NoChill Feb 25, 2026
ea0ac49
clar: clarify that * is not what makes an array dynamic
Sir-NoChill Feb 25, 2026
d8352c0
clar: add implementation hint for slice passing without eager deep copy
Sir-NoChill Feb 25, 2026
8f44885
fix: move value_categories from standalone Hints section into Impleme…
Sir-NoChill Feb 25, 2026
924cd1d
clar: Constexprs and scope constraints
Sir-NoChill Feb 25, 2026
8e08976
fix: clarify the inner scope constexprs
Sir-NoChill Feb 25, 2026
6495ac8
fix: kill the em-dash and fix hallucinations
Sir-NoChill Feb 25, 2026
abe0e48
clar: Remove jagged arrays
Sir-NoChill Feb 25, 2026
3733d27
fix: r-dean comments
Sir-NoChill Feb 27, 2026
a26aee2
fix: grammar
Sir-NoChill Mar 1, 2026
d5fbc16
fix: function calls contradiction
Sir-NoChill Mar 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions gazprea/impl/slice_passing.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
.. _sec:impl_slice_passing:

Slice Passing — Eager Copy vs. Copy-On-Write
============================================

The *Gazprea* specification defines slice expressions as rvalues that produce a
**deep copy** of the selected elements (see :ref:`sssec:array_ops`). This is a
*semantic* guarantee: from the programmer's perspective, a slice always behaves
as an independent value with no aliasing relationship to the source array.

However, the specification does **not** require an *eager* copy to be made at
the point of the slice expression. An implementation is free to use a lazy
strategy such as **Copy-On-Write (COW)**.

Copy-On-Write Strategy
----------------------

Under COW, passing a slice to a function or procedure does not immediately
duplicate the underlying storage. Instead, the implementation shares the same
backing memory and only performs the physical copy when — and if — either the
source array or the slice view is mutated. If no mutation occurs, the copy is
avoided entirely.

This is safe because:

1. Slices can only be passed as ``const`` (by-value) parameters. A callee that
receives a slice argument cannot mutate it through that parameter.
2. The source array variable is not accessible from inside the called
function/procedure (functions are pure; procedures have no aliasing with
``const`` parameters).

Therefore, a COW implementation is observationally equivalent to an eager deep
copy for all legal *Gazprea* programs.

Example
-------

::

function sum(integer[*] v) returns integer { ... }

procedure main() returns integer {
var integer[10] a = 1..10;

// The slice a[2..6] is an rvalue. An eager-copy implementation
// allocates a new 4-element array here. A COW implementation may
// instead pass a lightweight view into a's storage, deferring the
// copy until (if ever) a mutation would make it necessary.
integer total = sum(a[2..6]);
return total;
}

Implementation Note
-------------------

Choosing an eager-copy or COW strategy is an internal quality-of-implementation
decision and does not affect language semantics. Implementations that wish to
avoid the overhead of copying large slices are encouraged to consider COW or
similar lazy strategies.
135 changes: 135 additions & 0 deletions gazprea/impl/value_categories.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
.. _sec:value_categories:

Value Categories
================

Every expression in *Gazprea* belongs to exactly one **value category**,
which determines how the expression may be used. In essence, value categories
describe whether an expression
can appear on the left-hand side of an assignment and whether it can be passed
as a mutable (``var``) argument to a procedure.

*Gazprea* recognises two value categories: **lvalue** and **rvalue**. This is
a deliberate simplification of the richer taxonomy found in modern C++ (which
adds *xvalue*, *prvalue*, and *glvalue*); those additional categories exist to
support move semantics and resource transfer, neither of which *Gazprea*
exposes. The two-category model is sufficient for *Gazprea*'s ownership rules,
which are entirely copy-based.

The full C++ taxonomy is described at
`cppreference: Value categories <https://en.cppreference.com/w/cpp/language/value_category.html>`_
and is worth understanding as background, even if *Gazprea* does not expose all
of it.

.. _ssec:vc_background:

Background: The Full C++ Taxonomy
----------------------------------

C++ characterises expressions along two orthogonal axes:

- **Identity**: does the expression refer to a persistent object that has an
address and can be named again later?
- **Moveability**: can the object's resources be transferred (moved) rather
than copied?

This gives rise to five named categories, arranged in the following hierarchy:

.. code-block:: text

Expression
├── glvalue (has identity)
│ ├── lvalue (identity, not moveable)
│ └── xvalue (identity, moveable — "expiring value")
└── rvalue (may be moved from)
├── xvalue (shared with glvalue above)
└── prvalue (no identity — "pure rvalue")

**glvalue** ("generalised lvalue")
Any expression that determines the identity of an object or function.
Includes both lvalues and xvalues. A glvalue *may* be implicitly converted
to a prvalue.

**lvalue**
A glvalue that is not an xvalue. Refers to a persistent object with a
stable address — something you can take the address of and use again next
time the same expression is evaluated. Variable names, array element
accesses, and dereferenced pointers are classic lvalues.

**xvalue** ("expiring value")
A glvalue whose resources can be reused because the object is near the end
of its lifetime. Introduced in C++11 to support ``std::move`` and rvalue
references. *Gazprea* has no equivalent.*

**prvalue** ("pure rvalue")
An rvalue that is not an xvalue. Computes a value or initialises an object
but has no persistent identity of its own. Literals, arithmetic
sub-expressions, and function return values (when returned by value) are
prvalues.

**rvalue**
The union of xvalues and prvalues, anything that is not a glvalue.
rvalues can generally be moved from (in C++) and cannot be the target of an
ordinary assignment.

.. _ssec:vc_gazprea:

Value Categories in Gazprea
-----------------------------

Because *Gazprea* has no move semantics or reference types, xvalues never
arise. The two remaining categories collapse cleanly:

**lvalue**
An expression that refers to a named, addressable storage location that
persists beyond the expression and can appear on the left-hand side of an
assignment. In *Gazprea*:

- Named variables (``x``, ``arr``, ``my_tuple``)
- Individual element accesses on mutable arrays (``arr[i]``, ``mat[i, j]``,
``tup.1``, ``tup.name``)

**rvalue**
An expression that produces a value but has no persistent, named storage
location. In *Gazprea*, rvalues correspond to what C++ would call
*prvalues*:

- Literals (``42``, ``true``, ``'a'``, ``"hello"``)
- Arithmetic and logical sub-expressions (``x + 1``, ``a and b``)
- Array and tuple literals (``[1, 2, 3]``, ``(x: 1, y: 2)``)
- Range expressions (``1..10``)
- **Slice expressions** (``arr[2..5]``) — even though slices are derived
from a named array, the result is a fresh deep copy with no stable
address of its own
- Function call results

.. _ssec:vc_consequences:

Practical Consequences
-----------------------

The value category of an expression determines what you can do with it:

+---------------------------------------------+----------+---------+
| Operation | lvalue | rvalue |
+=============================================+==========+=========+
| Appear on left-hand side of ``=`` | ✓ | ✗ |
+---------------------------------------------+----------+---------+
| Pass as ``var`` (mutable) procedure argument| ✓ | ✗ |
+---------------------------------------------+----------+---------+
| Pass as ``const`` procedure argument | ✓ | ✓ |
+---------------------------------------------+----------+---------+
| Use in an expression | ✓ | ✓ |
+---------------------------------------------+----------+---------+

In particular, because a slice is an rvalue, the following are both
compile-time errors:

::

var integer[5] a = [10, 20, 30, 40, 50];

a[1..3] = [99, 99]; // ERROR: slice is an r-value, not an l-value

procedure mutate(var integer[*] v) { ... }
call mutate(a[1..3]); // ERROR: cannot pass r-value as var argument
3 changes: 3 additions & 0 deletions gazprea/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Hardware Acceleration Laboratory in Markham, ON.
spec/identifiers
spec/comments
spec/declarations
spec/constexpr
spec/type_qualifiers
spec/types
spec/type_inference
Expand All @@ -42,5 +43,7 @@ Hardware Acceleration Laboratory in Markham, ON.
impl/part_1
impl/part_2
impl/errors
impl/value_categories
impl/slice_passing

.. |gazprea_logo| image:: assets/images/GazpreaLogo.png
38 changes: 14 additions & 24 deletions gazprea/spec/built_in_functions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,52 +14,42 @@ If a declaration or a definition with the same name as a built-in function is
encountered in a *Gazprea* program, then the compiler should issue an error.

Note that although the examples below all use arrays, all the built-ins work
on Vectors and Strings, since they are always compatible with arrays.

.. _ssec:builtIn_length:

Length
------

``length`` takes an array of any element type, and returns an integer
representing the number of elements in the array.

::

integer[*] v = 1..5;

length(v) -> std_output; /* Prints 5 */

on strings as well, since a ``string`` is structurally compatible with
``character[*]``.

.. _ssec:builtIn_rows_cols:

Shape
-----

The built-in ``shape`` operates on arrays of any dimension, and returns an
array listing the size of each dimension.
``integer[*]`` listing the size of each dimension. For a 1-dimensional array,
``shape`` returns a single-element array, so ``shape(v)[1]`` gives the number
of elements in ``v``.

::

integer[*][*] M = [[1, 2, 3], [4, 5, 6]];
integer[4] v = 1..5;
shape(v)[1] -> std_output; /* Prints 4 */

integer[*, *] M = [[1, 2, 3], [4, 5, 6]];
shape(M) -> std_output; /* Prints [2, 3] */

.. _ssec:builtIn_reverse:

Reverse
-------

The reverse built-in takes any single dimensional array, Vector, or String, and returns a
reversed version of it.
The ``reverse`` built-in takes any array or ``string``, and returns a
reversed copy of it.

::

integer[*] v = 1..5;
integer[*] w = reverse(v);
integer[4] v = 1..5;
integer[4] w = reverse(v);

v -> std_output; /* Prints 12345 */
w -> std_output; /* Prints 54321 */
v -> std_output; /* Prints 1234 */
w -> std_output; /* Prints 4321 */

.. _ssec:builtIn_format:

Expand Down
Loading