Ported the computational interpreter from lambda-py/base/python-interp.rkt.
-
Result type: Control flow handling matching Racket's Result datatype
value- Normal completion (v*s in Racket)return_- Early return from functionbreak_/continue_- Loop control flowexception- Raised exceptionstuck- Debugging aid for stuck states
-
Big-step interpreter (
interp): Handles all λπ expression types- Memory operations: fetch, set!, alloc
- Objects and collections: object, list, tuple, set
- Control flow: seq, if, while, loop, break, continue
- Bindings: let (global/local), id, assign
- Functions: fun_, app, appVararg, frame, return
- Exception handling: raise, tryExcept, tryFinally
- Modules: module, constructModule, inModule
-
Primitive operations (
interpPrim):- Arithmetic:
$add,$sub,$mult,$div - Comparison:
$num=,$str=,$num<,$num>,$num<=,$num>= - I/O:
$print(returns None)
- Arithmetic:
-
Small-step evaluator (
tryStepBase):- Computational version of propositional
StepBaserules - Context-aware stepping through expressions
- Fuel-bounded evaluation via
evalSmallStep
- Computational version of propositional
-
Entry points:
run- Big-step interpreter from empty staterunSmallStep- Small-step with fuel limit
showResult- Format big-stepResultfor displayshowSmallStepResult- Format small-stepSmallStepResultfor displayrunShow/runSmallStepShow- Convenience wrappers
Added interpreter test cases:
- Number allocation
- Sequence evaluation
- Let bindings
- Function application (identity function)
- Arithmetic primitives (3 + 4 = 7)
- While loops
- Comparison operators
- Exception handling (try/except)
.ref rhandling: Now returns the pointer directly instead of allocating an unnecessary copy.letInbindings: Now copies the actual object pointed to, not wrapping the pointer in a new object with.noMeta- Function application (
interpApp,interpAppVararg): AddedvalToObjhelper to properly copy argument objects - Exception handling (
.tryExcept): Fixed exception binding to copy the actual exception object
- Symbol truthiness (
isTruthy): Only the symbol"true"is truthy, not all symbols. Matches Racket's(equal? t 'true)check. - Function return semantics (
interpApp,interpAppVararg): Functions now correctly returnNoneon normal completion (no explicit return). Only explicitreturnstatements return the actual value. This matches Python semantics and Racket's[v*s (vb sb) (alloc-result vnone sb)]. - Frame usage in big-step: Removed
.framewrapper ininterpApp/interpAppVarargsince the big-step interpreter handles return/break/continue directly. Frame is used in small-step semantics only.
- Added
Inhabited Stateinstance to support partial functions in the interpreter
- Updated
PythonOfLean.leanto importInterp.lean - Simplified test code in
Basic.leanusing the new utilities
-
S-expression Parser (
SExpr.lean): Parses Racket's S-expression output format- Handles atoms, numbers, quoted strings, and nested lists
- Tokenizer with proper whitespace and escape sequence handling
-
S-expr to Expr Converter (
SExprToExpr.lean): Converts S-expressions to LeanExprtype- Maps all λπ constructs:
sym,id,seq,let,fun,app,if,while, etc. - Handles
true/false/none→ object construction - MetaVal parsing for
meta-num,meta-str,meta-list, etc.
- Maps all λπ constructs:
-
Racket Integration (
Racket.lean): Spawns Racket process to parse PythonparsePythonString- Parse Python code from stringparsePythonFile- Parse Python file- Uses
scripts/python-to-sexp.rktas the frontend
- Parses Python source using lambda-py's
get-core-syntax - Outputs desugared core syntax as S-expressions via
core->sexp
--run <file.py>- Parse and execute Python file--parse <file.py>- Parse and print Expr representation--parse-sexp <file>- Parse S-expression file directly--eval <code>- Parse and execute Python code string
Complete rewrite to support Python's object model with method dispatch:
-
Type Objects with Magic Methods:
%int,%float: Arithmetic methods (__add__,__sub__,__mul__,__div__,__floordiv__,__mod__)- Comparison methods (
__eq__,__lt__,__gt__,__le__,__ge__) %str: String operations (__add__,__eq__)%bool,%object: Base__getattribute__num: Parent type for numeric operations
-
Method Binding:
mkGetAttributeMethodcreates bound methods with__func__and__self__attributes -
Initial State Setup:
setupBuiltinTypescreates all type objects with their methods as fields -
Constants:
True,False,Nonesingletons -
Exception Types:
BaseException,Exception,TypeError,ValueError,NameError,AttributeError,KeyError,IndexError,StopIteration,ZeroDivisionError,AssertionError -
Runtime Support:
%special_getattr,%locals
Extended interpPrim with full Python runtime primitives:
-
Object Attribute Operations:
obj-getattr,obj-hasattr,obj-setattr,obj-delattr- Internal dict access$getattribute- Method binding (creates bound method objects)
-
Numeric Operations (Racket-compatible names):
num+,num-,num*,num/,num//,num%num=,num<,num>,num<=,num>=,numcmp
-
String Operations:
str+,str= -
Type Introspection:
$class- Get object's classisinstance- Type checkingis-func?,is-bound-method?,is-none?
-
Collections:
len- Length of list/tuple/set/stringlist-getitem,tuple-getitem- Index access
-
Conversion:
num-str- Number to string
- Assignment preserves class: Fixed
assignto copy the actual object instead of wrapping the pointer, which was losing class information and breaking method dispatch on variables
The interpreter now correctly executes:
- Arithmetic expressions:
1 + 2 * 3 - Comparisons:
5 > 3,i < 10 - Control flow:
if/else,whileloops withbreak/continue - Functions:
def, recursion,return - Variables: Global assignment and lookup
- Complex programs: Factorial, Fibonacci, prime counting