///|
/// moonpython interpreter specification
///
/// This file defines the public API contract for a MoonBit-based
/// Python interpreter. Implementations should live in separate files
/// and satisfy the behavior expressed in the spec-driven tests.
///|
/// Source span for errors and diagnostics
pub(all) struct Span {
start : Int32
end : Int32
line : Int32
column : Int32
} derive(ToJson)
///|
pub extend Span with ToJson::{to_json}
///|
/// Literal values that appear in source code
pub enum Literal {
None
Bool(Bool)
Int(@bigint.BigInt)
Float(Double)
Complex(Double, Double)
Str(String)
Bytes(Array[Int32])
} derive(ToJson)
///|
pub extend Literal with ToJson::{to_json}
///|
/// Unary operators
pub enum UnaryOp {
Pos
Neg
Not
Invert
} derive(ToJson)
///|
pub extend UnaryOp with ToJson::{to_json}
///|
/// Binary operators
pub enum BinaryOp {
Add
Sub
Mul
MatMul
Div
FloorDiv
Mod
Pow
ShiftLeft
ShiftRight
BitAnd
BitXor
BitOr
} derive(ToJson)
///|
pub extend BinaryOp with ToJson::{to_json}
///|
/// Boolean operators
pub enum BoolOp {
And
Or
} derive(ToJson)
///|
pub extend BoolOp with ToJson::{to_json}
///|
/// Comparison operators
pub enum CompareOp {
Eq
NotEq
Lt
Lte
Gt
Gte
In
NotIn
Is
IsNot
} derive(ToJson)
///|
pub extend CompareOp with ToJson::{to_json}
///|
/// A comprehension clause: `for in ` (optionally `async for`).
pub struct CompClause {
is_async : Bool
targets : Array[String]
target : Target
iter : Expr
filters : Array[Expr]
} derive(ToJson)
///|
pub extend CompClause with ToJson::{to_json}
///|
/// Expression nodes
pub enum Expr {
Literal(Literal)
Name(String)
Tuple(Array[Expr])
List(Array[Expr])
ListComp(elt~ : Expr, clauses~ : Array[CompClause], filters~ : Array[Expr])
GenExp(elt~ : Expr, clauses~ : Array[CompClause], filters~ : Array[Expr])
Dict(Array[(Expr, Expr)])
DictComp(
key~ : Expr,
value~ : Expr,
clauses~ : Array[CompClause],
filters~ : Array[Expr]
)
Set(Array[Expr])
SetComp(elt~ : Expr, clauses~ : Array[CompClause], filters~ : Array[Expr])
Lambda(params~ : Array[String], defaults~ : Array[Expr], body~ : Expr)
IfExpr(condition~ : Expr, then_expr~ : Expr, else_expr~ : Expr)
FString(String)
NamedExpr(name~ : String, value~ : Expr)
Yield(Expr?)
YieldFrom(Expr)
Await(Expr)
Slice(start~ : Expr?, end~ : Expr?, step~ : Expr?)
Attribute(value~ : Expr, attr~ : String)
Subscript(value~ : Expr, index~ : Expr)
Call(callee~ : Expr, args~ : Array[Expr])
Keyword(name~ : String, value~ : Expr)
Starred(value~ : Expr)
DoubleStarred(value~ : Expr)
Unary(op~ : UnaryOp, expr~ : Expr)
Binary(op~ : BinaryOp, left~ : Expr, right~ : Expr)
BoolOp(op~ : BoolOp, values~ : Array[Expr])
Compare(left~ : Expr, ops~ : Array[CompareOp], comparators~ : Array[Expr])
WithSpan(span~ : Span, expr~ : Expr)
} derive(ToJson)
///|
pub extend Expr with ToJson::{to_json}
///|
/// Assignment targets
pub enum Target {
Name(String)
Tuple(Array[Target])
List(Array[Target])
Starred(Target)
Attribute(value~ : Expr, attr~ : String)
Subscript(value~ : Expr, index~ : Expr)
} derive(ToJson)
///|
pub extend Target with ToJson::{to_json}
///|
/// Match statement patterns (minimal)
pub enum Pattern {
Wildcard
Literal(Literal)
Name(String)
TypeCapture(type_name~ : String, name~ : String)
Tuple(Array[Pattern])
} derive(ToJson)
///|
pub extend Pattern with ToJson::{to_json}
///|
/// Try/except handler (supports except*)
pub struct ExceptHandler {
span : Span
is_star : Bool
exc : Expr?
name : String?
body : Array[Stmt]
} derive(ToJson)
///|
pub extend ExceptHandler with ToJson::{to_json}
///|
/// Statement nodes
pub enum Stmt {
ExprStmt(Expr)
Assign(target~ : Target, value~ : Expr)
AnnAssign(target~ : Target, annotation~ : Expr, value~ : Expr?)
AugAssign(target~ : Target, op~ : BinaryOp, value~ : Expr)
TypeAlias(name~ : String, type_params~ : Array[String], value~ : Expr)
Return(Expr?)
Yield(Expr?)
YieldFrom(Expr)
If(condition~ : Expr, body~ : Array[Stmt], else_body~ : Array[Stmt])
Match(subject~ : Expr, cases~ : Array[(Pattern, Expr?, Array[Stmt])])
While(condition~ : Expr, body~ : Array[Stmt], else_body~ : Array[Stmt])
For(
target~ : Target,
iter~ : Expr,
body~ : Array[Stmt],
else_body~ : Array[Stmt]
)
AsyncFor(
target~ : Target,
iter~ : Expr,
body~ : Array[Stmt],
else_body~ : Array[Stmt]
)
Break
Continue
Function(
name~ : String,
decorators~ : Array[Expr],
type_params~ : Array[String],
params~ : Array[String],
defaults~ : Array[Expr],
annotations~ : Array[(String, Expr)],
return_annotation~ : Expr?,
body~ : Array[Stmt],
is_generator~ : Bool,
is_async~ : Bool
)
Pass
Global(Array[String])
Nonlocal(Array[String])
Assert(condition~ : Expr, message~ : Expr?)
Raise(exc~ : Expr?, cause~ : Expr?)
Del(Array[Target])
Import(module_name~ : String, alias_name~ : String?)
FromImport(module_name~ : String, names~ : Array[(String, String?)])
With(context~ : Expr, target~ : String?, body~ : Array[Stmt])
AsyncWith(context~ : Expr, target~ : String?, body~ : Array[Stmt])
Try(
body~ : Array[Stmt],
handlers~ : Array[ExceptHandler],
else_body~ : Array[Stmt],
finally_body~ : Array[Stmt]
)
Class(
name~ : String,
decorators~ : Array[Expr],
type_params~ : Array[String],
bases~ : Array[Expr],
keywords~ : Array[(String, Expr)],
body~ : Array[Stmt]
)
WithSpan(span~ : Span, stmt~ : Stmt)
} derive(ToJson)
///|
pub extend Stmt with ToJson::{to_json}
///|
/// Parsed module
pub struct Module {
body : Array[Stmt]
} derive(ToJson)
///|
pub extend Module with ToJson::{to_json}
///|
/// Parse error categories
pub(all) enum ParseErrorKind {
Syntax
Indentation
UnexpectedToken
UnexpectedEof
} derive(ToJson)
///|
pub extend ParseErrorKind with ToJson::{to_json}
///|
/// Parse error details
pub(all) struct ParseError {
kind : ParseErrorKind
message : String
span : Span
} derive(ToJson)
///|
pub extend ParseError with ToJson::{to_json}
///|
/// Runtime error categories
pub(all) enum RuntimeErrorKind {
Name
Type
Attribute
Index
Key
ZeroDivision
NotImplemented
Runtime
} derive(ToJson)
///|
pub extend RuntimeErrorKind with ToJson::{to_json}
///|
/// Runtime error details
pub(all) struct RuntimeError {
kind : RuntimeErrorKind
message : String
span : Span?
traceback : Array[TracebackFrame]
traceback_envs : Array[TracebackEnv]
exc_type : String
exc_args : Array[String]
exc_value : Value?
exc_cause : Value?
exc_context : Value?
exc_suppress_context : Bool
} derive(ToJson)
///|
pub extend RuntimeError with ToJson::{to_json}
///|
/// Traceback frame data captured at runtime
pub(all) struct TracebackFrame {
name : String
filename : String
line : Int32
column : Int32
end_column : Int32
} derive(ToJson)
///|
pub extend TracebackFrame with ToJson::{to_json}
///|
/// Best-effort environment snapshot for a traceback frame.
///
/// This is captured at raise-time so traceback formatting (e.g. suggestions in
/// Lib/traceback.py) can access locals/globals even after stack unwinding.
pub(all) struct TracebackEnv {
locals : Array[(String, Value)]
globals : Array[(String, Value)]
} derive(ToJson)
///|
pub extend TracebackEnv with ToJson::{to_json}
///|
/// Wrap RuntimeError as an error type for use with `raise`
pub suberror MpythonError {
MpythonError(RuntimeError)
}
///|
/// Test result from running a test directory
pub struct TestResult {
passed : Int32
failed : Int32
errors : Array[String]
} derive(ToJson)
///|
pub extend TestResult with ToJson::{to_json}
///|
/// Interpreter configuration
pub struct Config {
max_recursion : Int32
traceback_limit : Int32
track_spans : Bool
/// When `true`, bytecode compilation failures (NotImplemented) are surfaced
/// as errors instead of falling back to the legacy AST evaluator.
///
/// This is useful for validating bytecode coverage during refactors.
bytecode_strict : Bool
/// When `false`, only built-in shim modules (e.g. `math`) are allowed.
///
/// This is used by `Interpreter::new_spec()` to keep the environment deterministic.
allow_filesystem_imports : Bool
/// Additional roots for resolving `import ` from files.
///
/// The interpreter always searches the main script directory (when `main_path` is set)
/// and the current working directory (".") first.
import_paths : Array[String]
/// CLI argv to expose as `sys.argv` (including argv[0]).
argv : Array[String]
/// Path of the "main" script being executed (CLI-only).
main_path : String?
} derive(ToJson)
///|
pub extend Config with ToJson::{to_json}
///|
/// Runtime values
pub struct FunctionValue {
name : String
params : Array[String]
defaults : Array[Value]
body : Array[Stmt]
is_generator : Bool
is_async : Bool
closure : Array[(String, Value)]
} derive(ToJson)
///|
pub extend FunctionValue with ToJson::{to_json}
///|
/// A Python class object (minimal)
///
/// `dict` is the class namespace holding methods and attributes.
pub struct ClassValue {
name : String
bases : Array[Value]
dict : Array[(String, Value)]
} derive(ToJson)
///|
pub extend ClassValue with ToJson::{to_json}
///|
/// A Python instance object (minimal)
pub struct InstanceValue {
class : ClassValue
dict : Array[(String, Value)]
} derive(ToJson)
///|
pub extend InstanceValue with ToJson::{to_json}
///|
/// A bound method (minimal descriptor result)
pub struct BoundMethodValue {
function : FunctionValue
self : Value
} derive(ToJson)
///|
pub extend BoundMethodValue with ToJson::{to_json}
///|
/// Runtime values available to user code
pub enum Value {
None
Bool(Bool)
Int(@bigint.BigInt)
Float(Double)
Complex(Double, Double)
Str(String)
Bytes(Array[Int32])
ByteArray(Array[Int32])
MemoryView(Array[Int32])
List(Array[Value])
Tuple(Array[Value])
Dict(Array[(Value, Value)])
Set(Array[Value])
Function(FunctionValue)
Class(ClassValue)
Instance(InstanceValue)
BoundMethod(BoundMethodValue)
} derive(ToJson)
///|
pub extend Value with ToJson::{to_json}
///|
/// Results produced after executing code
pub struct RunResult {
value : Value
stdout : String
stderr : String
globals : Array[(String, Value)]
} derive(ToJson)
///|
pub extend RunResult with ToJson::{to_json}
///|
/// In-memory IO buffers for testing
pub struct MockIO {
stdin : Array[String]
stdin_pos : Ref[Int32]
stdout : StringBuilder
stderr : StringBuilder
}
///|
/// Stateful interpreter
pub struct Interpreter {
config : Config
globals : Array[(String, Value)]
builtins : Array[(String, Value)]
io : MockIO
}
///|
/// Build a default configuration
#declaration_only
pub fn Config::default() -> Config {
...
}
///|
/// Create a new interpreter with default configuration
#declaration_only
pub fn Interpreter::new() -> Interpreter {
...
}
///|
/// Create a new interpreter with custom configuration
#declaration_only
pub fn Interpreter::with_config(config : Config) -> Interpreter {
...
}
///|
/// Create a new interpreter with builtins
#declaration_only
pub fn Interpreter::with_builtins(
builtins : Array[(String, Value)],
config : Config,
) -> Interpreter {
...
}
///|
/// Create a new interpreter with explicit IO
#declaration_only
pub fn Interpreter::with_io(config : Config, io : MockIO) -> Interpreter {
...
}
///|
/// Create mock IO buffers
#declaration_only
pub fn MockIO::new(stdin : Array[String]) -> MockIO {
...
}
///|
/// Read a line from stdin (without newline)
#declaration_only
pub fn MockIO::read_line(self : MockIO) -> String? {
...
}
///|
/// Write to stdout
#declaration_only
pub fn MockIO::write_stdout(self : MockIO, text : String) -> Unit {
...
}
///|
/// Write to stderr
#declaration_only
pub fn MockIO::write_stderr(self : MockIO, text : String) -> Unit {
...
}
///|
/// Retrieve stdout contents
#declaration_only
pub fn MockIO::take_stdout(self : MockIO) -> String {
...
}
///|
/// Retrieve stderr contents
#declaration_only
pub fn MockIO::take_stderr(self : MockIO) -> String {
...
}
///|
/// Parse a full module from source
#declaration_only
pub fn parse(source : String) -> Result[Module, ParseError] {
...
}
///|
/// Parse a single expression from source
#declaration_only
pub fn parse_expr(source : String) -> Result[Expr, ParseError] {
...
}
///|
/// Execute a parsed module
#declaration_only
pub fn Interpreter::exec(
self : Interpreter,
program : Module,
) -> Result[RunResult, RuntimeError] {
...
}
///|
/// Execute source text directly
#declaration_only
pub fn Interpreter::exec_source(
self : Interpreter,
source : String,
) -> Result[RunResult, RuntimeError] {
...
}
///|
/// Evaluate a single expression source
#declaration_only
pub fn Interpreter::eval_source(
self : Interpreter,
source : String,
) -> Result[RunResult, RuntimeError] {
...
}
///|
/// Evaluate a single expression
#declaration_only
pub fn Interpreter::eval(
self : Interpreter,
expr : Expr,
) -> Result[Value, RuntimeError] {
...
}
///|
/// Retrieve a global variable
#declaration_only
pub fn Interpreter::get_global(self : Interpreter, name : String) -> Value? {
...
}
///|
/// Set a global variable
#declaration_only
pub fn Interpreter::set_global(
self : Interpreter,
name : String,
value : Value,
) -> Unit {
...
}
///|
/// Render a parse error for diagnostics
#declaration_only
pub fn format_parse_error(error : ParseError) -> String {
...
}
///|
/// Render a runtime error for diagnostics
#declaration_only
pub fn format_runtime_error(error : RuntimeError) -> String {
...
}
///|
/// Render a runtime error with traceback frames
#declaration_only
pub fn format_runtime_error_with_traceback(
error : RuntimeError,
limit : Int32,
) -> String {
...
}
///|
/// Execute all tests in a directory (like python -m test)
#declaration_only
pub fn Interpreter::execute_test_dir(
self : Interpreter,
path : String,
) -> TestResult raise MpythonError {
...
}