Error Catalog
=============

Diagnostics
-----------

Every diagnostic has the form::

  [Error type], pos [line/col]: [message]

for example::

  Compile error, pos 5/1: resource capacity must be a non-negative integer; got -1

Positions are 1-indexed for both line and column. Runtime errors carry no
position, because the failing instruction's source location is not
retained by the VM::

  Runtime error: integer division by zero

Phases
------

An error belongs to exactly one phase, and the compiler stops at the end
of the phase that produced it. A phase reports every independent fault it
finds before stopping, so a file with two bad declarations yields two
diagnostics rather than one; faults that are consequences of an earlier
one in the same construct are suppressed:

============  ==================================================
``SCANNER``   Lexical: illegal characters, malformed literals,
              unterminated strings.
``PARSER``    Syntactic: a token stream that no production
              accepts, including reserved words used as
              identifiers.
``SEMANTIC``  Everything the grammar cannot express: types,
              scoping, effect discipline, declaration order,
              and the constraints in ``eb-constraints.rst``.
``RUNTIME``   Detected during execution: division by zero,
              out-of-range group index, a negative value where
              only a constant could have been checked earlier.
============  ==================================================

Scanner and parser errors are reported one at a time. A semantic error
does not stop analysis of unrelated declarations, so a single ``eb
check`` may report several.

Exit codes
----------

=====  ===========================================
``0``  success
``1``  runtime error
``2``  compile error (scanner, parser, or semantic)
=====  ===========================================

Constant versus runtime detection
---------------------------------

Several rules are checked at compile time when the offending expression
is a constant and at runtime otherwise — a negative ``timeout`` (AG-80),
a negative ``sched`` delta (SCHED-15), a negative resource capacity
(RC-30). The same violation therefore appears in this catalog under two
different phases depending on how it was written. This is deliberate:
constant-folding the check is an optimization, not a change in what is
legal.

The catalog
-----------

What follows is generated from ``tests/suite`` by ``./mk errors`` and
verified by ``./mk spec``. It is not maintained by hand: the test suite
is what pins the behavior, so a hand-copied catalog could only drift from
it. To add an entry, add a test case.

Each entry gives the feature under test, the file it lives in, and the
exact message the compiler is asserted to produce.

.. BEGIN GENERATED CATALOG -- edit tests/suite, then run ./mk errors

Scanner Errors
--------------

10 cases, from ``tests/suite/invalid_scanner/``. Every message below is the exact ``EXPECT-MSG`` the compiler is asserted to produce.

**Illegal character** — ``at_sign.eb``

::

   Scanner error, pos 5/6: illegal character '@'

**Illegal character backtick** — ``backtick.eb``

::

   Scanner error, pos 5/6: illegal character '`'

**Invalid escape sequence** — ``bad_escape.eb``

::

   Scanner error, pos 5/8: invalid escape sequence '\q'

**Number literal — decimal point requires leading digit** — ``dbl_no_leading_digit.eb``

::

   Scanner error, pos 5/6: number literal must have digit before decimal point

**Number literal — digits required after decimal point** — ``dbl_no_trailing_digit.eb``

::

   Scanner error, pos 5/6: number literal must have digit after decimal point

**Illegal character $** — ``dollar_sign.eb``

::

   Scanner error, pos 5/6: illegal character '$'

**Multiple decimal points** — ``multiple_dots.eb``

::

   Scanner error, pos 5/6: unexpected character in number literal

**Digit run immediately followed by identifier character** — ``number_then_letter.eb``

::

   Scanner error, pos 5/6: unexpected character in number literal

**Trailing underscore in a number literal** — ``trailing_underscore.eb``

::

   Scanner error, pos 5/6: unexpected character in number literal

**Unterminated string literal** — ``unterminated_string.eb``

::

   Scanner error, pos 5/6: unterminated string literal

Parser Errors
-------------

14 cases, from ``tests/suite/invalid_parser/``. Every message below is the exact ``EXPECT-MSG`` the compiler is asserted to produce.

**fn return type is mandatory** — ``fn_missing_ret.eb``

::

   Compile error, pos 6/3: function return type is mandatory: expected ':' after ')'

**Guard arm missing expression after ->** — ``guard_missing_expr.eb``

::

   Compile error, pos 7/1: expected expression after '->'

**init block requires end** — ``init_missing_end.eb``

::

   Compile error, pos 8/1: expected 'end' to close 'init' block

**Declaration missing right-hand side** — ``missing_rhs.eb``

::

   Compile error, pos 6/1: expected expression, found EOF

**obs_r with no variable** — ``obs_missing_var.eb``

::

   Compile error, pos 6/1: expected variable name after 'obs_r'

**obs_r requires a variable name, not a reserved word** — ``reserved_word_obs_r.eb``

::

   Compile error, pos 5/7: expected variable name after 'obs_r'

**Reserved word used as identifier** — ``reserved_word_run.eb``

::

   Compile error, pos 5/1: 'run' is a reserved word and cannot be used as an identifier

**resource capacity type must be int** — ``resource_non_int_type.eb``

::

   Compile error, pos 5/1: resource capacity type must be 'int'

**rsc is only a parameter type** — ``rsc_as_var_type.eb``

::

   Compile error, pos 5/5: type 'rsc' is only valid as a parameter type

**run() requires braces around duration and nruns** — ``run_missing_braces.eb``

::

   Compile error, pos 6/7: expected '{' after run() arguments

**run() duration and nruns are comma separated** — ``run_missing_comma.eb``

::

   Compile error, pos 6/10: expected ',' between duration and nruns

**timeout is not a valid pi body item** — ``timeout_in_pi.eb``

::

   Compile error, pos 6/3: expected expression, found 'timeout'

**timeout requires parentheses** — ``timeout_missing_parens.eb``

::

   Compile error, pos 7/1: expected '(' after 'timeout'

**Type keywords are lowercase only** — ``type_wrong_case.eb``

::

   Compile error, pos 5/4: unknown type 'INT'; expected int, dbl, str, or bool

Semantic Errors
---------------

30 cases, from ``tests/suite/invalid_semantic/``. Every message below is the exact ``EXPECT-MSG`` the compiler is asserted to produce.

**Agent invocation is a statement, not an expression** — ``agent_in_expression.eb``

::

   Compile error, pos 9/6: 'worker' is an agent and cannot be used in an expression

**agent declared but no run()** — ``agent_no_run.eb``

::

   Compile error: model has agent declarations but no run() statement

**dbl value cannot be assigned to an int variable** — ``assign_dbl_to_int.eb``

::

   Compile error, pos 5/10: cannot assign dbl to int variable 'x'

**Assignment to an undeclared variable** — ``assign_without_decl.eb``

::

   Compile error, pos 5/1: assignment to undeclared variable 'x'; use ':=' to declare

**claim is invalid inside an event body** — ``claim_in_event.eb``

::

   Compile error, pos 7/3: 'claim' is only valid inside an agent body or init block

**claim argument must be type rsc** — ``claim_not_rsc.eb``

::

   Compile error, pos 7/9: argument to 'claim' must be type rsc

**fn body may not reference a pi by name** — ``fn_reads_pi.eb``

::

   Compile error, pos 7/10: a function body may not reference pi 'x'; pass its value as a parameter (FN-35)

**for loop variable may not shadow an outer variable** — ``for_shadow_outer.eb``

::

   Compile error, pos 7/5: 'i' is already declared

**Guard arms must produce the same type** — ``guard_arm_types.eb``

::

   Compile error, pos 6/6: guard arms produce different types: int and str (GUARD-40)

**Guard expression requires a terminating default arm** — ``guard_no_default.eb``

::

   Compile error, pos 6/6: guard expression requires a terminating '_' (or 'true') arm

**if condition must be bool** — ``if_cond_not_bool.eb``

::

   Compile error, pos 7/4: if condition must be bool, got int

**Series extraction on a non-observed variable** — ``last_not_observed.eb``

::

   Compile error, pos 7/12: ':last' requires observation data; 'y' is not observed

**Simulation model requires observations** — ``model_no_obs.eb``

::

   Compile error: there are no observations in the model

**No-horizon pi model without stop_r or halt** — ``no_horizon_no_stop.eb``

::

   Compile error: a run with no time horizon requires a stop_r or halt

**pi and obs declared but no run()** — ``pi_no_run.eb``

::

   Compile error: model has pi declarations but no run() statement

**More than one :randseed call is invalid** — ``randseed_twice.eb``

::

   Compile error: more than one ':randseed' call is not permitted (EXEC-35)

**Constant resource capacity below zero** — ``rc_capacity_negative.eb``

::

   Compile error, pos 5/1: resource capacity must be a non-negative integer; got -1

**Redeclaration of an already-declared variable** — ``redeclare_var.eb``

::

   Compile error, pos 6/1: 'x' is already declared

**release is invalid inside an event body** — ``release_in_event.eb``

::

   Compile error, pos 9/3: 'release' is only valid inside an agent body or init block

**release argument must be type rsc** — ``release_not_rsc.eb``

::

   Compile error, pos 9/11: argument to 'release' must be type rsc

**run() requires a simulation declaration** — ``run_with_no_sim.eb``

::

   Compile error: run() requires at least one pi, event, or agent declaration

**Only event handlers may be scheduled** — ``sched_a_fn.eb``

::

   Compile error, pos 9/10: 'f' is a fn; only event handlers may be scheduled

**Shadowing a module-level declaration is prohibited** — ``shadow_module_var.eb``

::

   Compile error, pos 7/3: declaration of 'x' shadows a module-level declaration

**stop_r at model level is invalid** — ``stop_r_model_level.eb``

::

   Compile error, pos 7/1: 'stop_r' is only valid inside pi, event, agent, or init bodies

**stop_s inside an event body is invalid** — ``stop_s_in_event.eb``

::

   Compile error, pos 6/3: 'stop_s' is only valid at module level

**timeout is invalid inside an event body** — ``timeout_in_event.eb``

::

   Compile error, pos 6/3: 'timeout' is only valid inside an agent body or init block

**timeout is invalid inside a fn body** — ``timeout_in_fn.eb``

::

   Compile error, pos 6/3: 'timeout' is only valid inside an agent body or init block

**Constant negative timeout delta** — ``timeout_negative_const.eb``

::

   Compile error, pos 6/3: 'timeout' delta must be non-negative; got -1

**Only one init block per program** — ``two_init_blocks.eb``

::

   Compile error: only one 'init' block is permitted per program

**Reference to an undefined variable** — ``undefined_var.eb``

::

   Compile error, pos 5/6: undefined variable 'x'

Runtime Errors
--------------

6 cases, from ``tests/suite/invalid_runtime/``. Every message below is the exact ``EXPECT-MSG`` the compiler is asserted to produce.

**Runtime group index out of declared range** — ``grp_index_out_of_range.eb``

::

   Runtime error: group index 4 is out of range 1..3

**Integer division by zero** — ``int_div_zero.eb``

::

   Runtime error: integer division by zero

**:nth index out of range at runtime** — ``nth_out_of_range.eb``

::

   Runtime error: ':nth' index 6 is out of range 1..5

**double release — the second finds nothing held** — ``release_twice.eb``

::

   Runtime error: release of resource 'r', which this agent does not hold

**releasing a resource the agent does not hold** — ``release_without_claim.eb``

::

   Runtime error: release of resource 'r', which this agent does not hold

**Negative timeout delta at runtime** — ``timeout_negative_runtime.eb``

::

   Runtime error: 'timeout' delta must be non-negative

.. END GENERATED CATALOG
