use alloc::string::String;
use brink_format::{DecodeError, DefinitionId};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, thiserror::Error)]
pub enum RanOutOfContentCause {
#[error("unexpectedly reached end of content. Do you need a '->->' to return from a tunnel?")]
Tunnel,
#[error("unexpectedly reached end of content. Do you need a '~ return'?")]
Function,
#[default]
#[error("ran out of content. Do you need a '-> DONE' or '-> END'?")]
Plain,
#[error("unexpectedly reached end of content for unknown reason. Please debug compiler!")]
Unknown,
}
#[derive(Debug, Clone, PartialEq, thiserror::Error)]
pub enum RuntimeError {
#[error("bytecode decode error: {0}")]
Decode(#[from] DecodeError),
#[error("unresolved definition: {0}")]
UnresolvedDefinition(DefinitionId),
#[error("no root container found")]
NoRootContainer,
#[error("value stack underflow")]
StackUnderflow,
#[error("call stack underflow")]
CallStackUnderflow,
#[error("container stack underflow")]
ContainerStackUnderflow,
#[error("invalid choice index: {index} (available: {available})")]
InvalidChoiceIndex { index: usize, available: usize },
#[error("not waiting for choice")]
NotWaitingForChoice,
#[error("story has ended")]
StoryEnded,
#[error("unresolved global: {0}")]
UnresolvedGlobal(DefinitionId),
#[error("type error: {0}")]
TypeError(String),
#[error("division by zero")]
DivisionByZero,
#[error("unimplemented opcode: {0}")]
Unimplemented(String),
#[error("unresolved external function call: {0}")]
UnresolvedExternalCall(DefinitionId),
#[error("output capture underflow (no checkpoint)")]
CaptureUnderflow,
#[error("unknown flow: {0}")]
UnknownFlow(String),
#[error("flow already exists: {0}")]
FlowAlreadyExists(String),
#[error("{0}")]
RanOutOfContent(RanOutOfContentCause),
#[error("step limit exceeded ({0} steps)")]
StepLimitExceeded(u64),
#[error("line limit exceeded ({0} lines in a single turn)")]
LineLimitExceeded(usize),
#[error("locale checksum mismatch: expected {expected:#010x}, got {actual:#010x}")]
LocaleChecksumMismatch { expected: u32, actual: u32 },
#[error("locale scope not in base program: {0}")]
LocaleScopeNotInBase(DefinitionId),
#[error("locale missing scope required by strict mode: {0}")]
LocaleScopeMissing(DefinitionId),
#[error(
"function evaluation yielded (a function called from the engine cannot present choices or end the story)"
)]
FunctionYielded,
#[error("no function evaluation in progress")]
NotEvaluatingFunction,
#[error("a function evaluation is already in progress on this flow")]
AlreadyEvaluatingFunction,
#[error("function not found: {0}")]
FunctionNotFound(String),
#[error("external '{0}' is async; cannot resolve during a synchronous call_function")]
AsyncExternalInCall(String),
#[error("no knot or stitch found at path '{0}'")]
UnknownPath(String),
#[error(
"cannot jump to '{path}': the flow is parked on unresolved external '{external}' — \
resolve it before jumping"
)]
JumpWhileAwaitingExternal { path: String, external: String },
#[error("'{target}' expects {expected} argument(s), got {got}")]
ArgCountMismatch {
target: String,
expected: u8,
got: usize,
},
#[error(
"'{name}' is #@private and cannot be accessed by the host \
(dev tooling may override visibility enforcement)"
)]
PrivateAccess {
name: String,
},
#[error("array index {index} out of bounds (len {len})")]
IndexOutOfBounds { index: i32, len: usize },
#[error("map has no key {key}")]
MapKeyNotFound { key: String },
#[error("cannot index into a {0} value")]
NotIndexable(&'static str),
#[error("array index must be an int, got {0}")]
InvalidArrayIndex(&'static str),
#[error("map key must be int, string, or bool, got {0}")]
InvalidMapKeyType(&'static str),
#[error("literal pool index {0} out of range")]
InvalidLiteralIndex(u32),
#[error("name id {0} out of range")]
InvalidNameId(u16),
#[error("struct shape id {0} out of range")]
InvalidShapeId(u32),
#[error("cannot access a field on a {0} value")]
NotARecord(&'static str),
#[error("struct has no field {0:?}")]
RecordFieldNotFound(String),
#[error("struct field offset {offset} out of range (record has {len} fields)")]
RecordFieldOffsetOutOfRange { offset: u16, len: usize },
#[error("cannot parse {input:?} as {target}")]
ConversionParseFailure { target: &'static str, input: String },
#[error("cannot convert a {got} value to {target}")]
InvalidConversionDomain {
target: &'static str,
got: &'static str,
},
#[error("cannot call a {0} value as a function")]
NotCallable(&'static str),
#[error(
"function value expects {expected} argument(s), got {got} (bound {bound} + supplied {supplied})"
)]
FunctionValueArity {
expected: usize,
got: usize,
bound: usize,
supplied: usize,
},
#[error("function value no longer matches its target's signature: {0}")]
FunctionValueRehydrationMismatch(String),
#[error(
"function value ref-binds flow-private cell `{0}`; cross-flow invocation is a fault in T1c (see #597)"
)]
FunctionValueCrossFlowLocal(String),
#[error("projection invalidated: {0}")]
ProjectionInvalidated(String),
#[error("char_at index must be an int, got {0}")]
CharAtIndexNotInt(&'static str),
#[error("char_at index {index} out of bounds ({len} chars)")]
CharAtOutOfBounds { index: i32, len: usize },
#[error("`{verb}` expects {expected}, got {found}")]
StdlibWrongType {
verb: &'static str,
expected: &'static str,
found: &'static str,
},
#[error("`{verb}` cannot order element of type {found}")]
NotOrderable {
verb: &'static str,
found: &'static str,
},
#[error(
"`{verb}` reached a NaN comparand — NaN cannot be ordered (dev-mode fault; prod mode \
places NaN by the pinned total order)"
)]
UnorderedComparand { verb: &'static str },
#[error("`{verb}` comparator must be a function value `fn(T, T): int`, got {found}")]
ComparatorNotAFunction {
verb: &'static str,
found: &'static str,
},
#[error(
"`{verb}` comparator must return an int (negative = less, zero = tie, positive = \
greater), got {found}"
)]
ComparatorReturnType {
verb: &'static str,
found: &'static str,
},
#[error("`{verb}` callback must be a function value {expected}, got {found}")]
CallbackNotAFunction {
verb: &'static str,
expected: &'static str,
found: &'static str,
},
#[error("`{verb}` callback must return {expected}, got {found}")]
CallbackReturnType {
verb: &'static str,
expected: &'static str,
found: &'static str,
},
#[error("`{verb}` {role} {what} — {role}s must be pure, silent functions")]
ComparatorEscaped {
verb: &'static str,
role: &'static str,
what: &'static str,
},
#[error(
"`{verb}` {role} {what} — {role}s must be pure, silent functions (dev-mode fault; prod \
mode executes the write)"
)]
ComparatorWroteState {
verb: &'static str,
role: &'static str,
what: &'static str,
},
#[error("an Option has no truthiness — test `== none` / `== some(x)` explicitly")]
OptionTruthiness,
#[error("the `as` binding requires an Option, got {found}")]
AsBindingNotOption {
found: &'static str,
},
#[error("`int` cannot draw from the empty range {range} — validate with `non_empty(r)` first")]
EmptyRangeDraw {
range: String,
},
#[error(
"`weighted` requires positive int weights, got {found} — construction refuses empty/zero/negative-weight tables"
)]
WeightedBadWeight {
found: String,
},
#[error("`weighted` construction received {detail}")]
WeightedMalformedTable { detail: &'static str },
#[cfg(feature = "debug-hooks")]
#[error("debug step budget exceeded ({ceiling} steps) while evaluating '{breakpoint}'")]
DebugBudgetExceeded {
breakpoint: String,
ceiling: u64,
},
}
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
#[non_exhaustive]
pub enum RuntimeWarning {
#[error(
"Variable not found: {name}. Using default value of 0 (false). This can happen \
with temporary variables if the declaration hasn't yet been hit."
)]
UninitializedTemp {
slot: u16,
name: String,
},
}
pub const RUNTIME_WARNING_CAP: usize = 64;