Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

REPL command language: denotational semantics

In plain terms

The REPL is the interactive surface for inspecting theories and terms: load a theory document, switch the active theory, ask for the type of a term, normalize a term under the directed equations, enumerate the free model. Every interactive command is a small operation on a stateful environment that holds the loaded theories, the loaded morphisms, and a pointer to the currently active theory.

This page pins down what each command does, what state it touches, and what the bare-term-typecheck path means.

Surface syntax

line     ::= command | term
command  ::= ":" cmd args
cmd      ::= "load" | "theories" | "use" | "sorts" | "ops"
           | "type" | "normalize" | "model" | "instance"
           | "quit" | "q"
args     ::= /* command-specific, see table below */

A line that does not begin with : is treated as a term and routed through the typecheck path under the active theory. Comments and blank lines are ignored. The grammar lives in crates/panproto-repl/src/lib.rs.

Abstract syntax

pub enum ReplCommand {
    Load(PathBuf),
    Theories,
    Use(String),
    Sorts,
    Ops,
    TypeOf(String),
    Normalize(String),
    Model(Option<u32>),
    Instance { class: String, target: String, bindings: Vec<(String, String)> },
    Quit,
}

pub enum ReplLine {
    Command(ReplCommand),
    Term(String),
}

(The actual implementation does not export this enum; commands are dispatched directly from string parsing in Repl::handle_command. The shape above is the denotational model.)

Semantic domain

The REPL state is

The semantic codomain is the set of user-visible effects (printed string, typed-term result, error, quit signal). The denotational semantics is the pair of functions

where is state-preserving: .

Semantic equations

Write for a state and for the obvious update. The equations:

The bare-term path:

When (no active theory), all -dependent equations short-circuit to . When any auxiliary (compile, typecheck_term, normalize, free_model, compile_instance) returns an error, the outcome is and the state is unchanged.

Repl::handle_command and Repl::handle_term_typecheck in crates/panproto-repl/src/lib.rs implement these equations pointwise.

Soundness

The REPL is a thin orchestration layer over the GAT engine and the theory DSL compiler. It introduces no new failure modes; every error it reports comes from one of:

  • panproto_theory_dsl::LoadError (during :load or :instance)
  • panproto_gat::GatError (during :type, :normalize, :model)
  • A REPL-level UnknownCommand / UnknownTheory for command-shape errors

State updates are atomic per line: a failed compile in :load rolls back the partial insertions before returning the error, so the post-state is either fully updated or unchanged.

The bare-term path is total in the technical sense: every input string either parses and produces a TypeOf or Error outcome; the REPL does not deadlock or spin.

What is intentionally not modelled

  • Multi-line input. Commands and terms are single-line. Continuations are the user’s responsibility (concatenate into a single line before submission).
  • Macro expansion. There is no :define or :macro; the REPL is a pure inspection interface, not a programming environment.
  • Concurrent state. A Repl instance is single-threaded. The shape above does not model concurrent line submission.
  • Persistent history. The REPL relies on rustyline for history; the persistence model is rustyline’s, not panproto’s.

See also