///|
/// Spec for a small, R6RS-compatible Scheme interpreter.
///
/// Phase 1 scope (implemented by tests in this module):
/// - exact integers, exact rationals, inexact floats, booleans, symbols,
/// characters, strings, pairs/lists
/// - quote, quasiquote, unquote, unquote-splicing, if, begin, lambda, define,
/// set!, let (including named let), let*, letrec, letrec*, let-syntax,
/// letrec-syntax, and, or, cond (including =>), case, do, case-lambda,
/// let-values, let*-values, define-values, parameterize, guard,
/// syntax-case (limited), identifier-syntax
/// - dynamic-wind
/// - define-syntax + syntax-rules (hygienic identifiers), including "..." repetition
/// - application with left-to-right evaluation
/// - proper tail calls for procedure application
/// - call/cc (call-with-current-continuation)
/// - define-record-type (records with inheritance and protocol)
/// - library and import (minimal library support)
/// - builtins: + - * / = < > <= >= cons car cdr list null? pair? symbol?
/// identifier? syntax? free-identifier=? bound-identifier=?
/// symbol? symbol=? symbol->string string->symbol syntax syntax->datum datum->syntax
/// boolean? boolean=? number? integer? exact-integer? rational? real? complex? exact? inexact?
/// zero? positive? negative? odd? even? finite? infinite? nan?
/// exact->inexact inexact->exact number->string string->number
/// make-rectangular make-polar real-part imag-part magnitude angle
/// sqrt exp log expt sin cos tan asin acos atan
/// numerator denominator abs quotient remainder modulo div mod div0 mod0
/// div-and-mod div0-and-mod0 gcd lcm
/// max min floor ceiling truncate round
/// procedure? record? record-rtd record-type-descriptor?
/// record-constructor-descriptor? record-type-name record-type-parent
/// record-type-uid record-type-generative?
/// record-type-sealed? record-type-opaque? record-type-field-names
/// record-type-field-mutable?
/// record-constructor-descriptor record-constructor
/// record-predicate record-accessor record-mutator
/// make-record-type-descriptor make-record-constructor-descriptor
/// not apply call/cc call-with-current-continuation eq? eqv?
/// equal? list? make-list list-ref list-tail length append
/// reverse c[ad]+r member memq memv assoc assq assv map for-each list-copy
/// set-car! set-cdr!
/// char? char=? char char>? char<=? char>=?
/// char-ci=? char-ci char-ci>? char-ci<=? char-ci>=?
/// char->integer integer->char char-alphabetic? char-numeric? char-whitespace?
/// char-upper-case? char-lower-case? char-upcase char-downcase char-foldcase
/// char-general-category
/// string make-string string? string=? string string>? string<=? string>=?
/// string-ci=? string-ci string-ci>? string-ci<=? string-ci>=?
/// string-length string-append string-ref string-set! string-copy string-copy!
/// string-fill! string->list list->string
/// string-map string-for-each
/// string-upcase string-downcase string-foldcase
/// string-normalize-nfc string-normalize-nfd string-normalize-nfkc string-normalize-nfkd
/// string-hash string-ci-hash symbol-hash equal-hash
/// vector make-vector vector? vector-length vector-ref vector-set!
/// vector-copy vector-copy! vector-fill! vector-map vector-for-each
/// vector->list list->vector
/// bytevector make-bytevector bytevector? bytevector-length bytevector=?
/// bytevector-u8-ref bytevector-u8-set! bytevector-s8-ref bytevector-s8-set!
/// bytevector-copy bytevector-copy!
/// bytevector-fill!
/// bytevector->u8-list u8-list->bytevector string->utf8 utf8->string
/// endianness native-endianness bytevector-uint-ref bytevector-sint-ref
/// bytevector-uint-set! bytevector-sint-set!
/// display write newline open-output-string get-output-string current-output-port
/// with-exception-handler raise raise-continuable
/// values call-with-values make-parameter dynamic-wind parameterize
/// guard
/// (equality is structural for datums in this subset)
/// - printing via value_to_string (booleans as #t/#f, empty list as ())
///
/// Out of scope for now: full numeric tower.
///|
pub(all) suberror ParseError {
ParseError(String)
} derive(Debug, Eq)
///|
pub extend ParseError with @debug.Debug::{to_repr}
///|
pub extend ParseError with Eq::{not_equal, equal}
///|
pub(all) suberror EvalError {
EvalError(String)
} derive(Debug, Eq)
///|
pub extend EvalError with @debug.Debug::{to_repr}
///|
pub extend EvalError with Eq::{not_equal, equal}
///|
/// Datum is the reader-level data representation used by quote.
/// It is also used to store list/vector elements, so it includes runtime-only
/// variants for records/conditions even though the reader never produces them.
pub(all) enum Datum {
Nil
Bool(Bool)
Int(Int)
BigInt(@bigint.BigInt)
Rat(Int, Int)
BigRat(@bigint.BigInt, @bigint.BigInt)
Float(Float)
Complex(Ref[Datum], Ref[Datum])
Label(Int, Ref[Datum])
Char(Char)
String(Ref[String])
Symbol(String)
Pair(Ref[Datum], Ref[Datum])
Vector(Array[Datum])
ByteVector(Array[Int])
Record(Record)
Condition(Condition)
Value(Value)
}
///|
/// Primitive procedures provided by the base environment.
///|
pub(all) enum Primitive {
Add
Sub
Mul
Div
NumEq
Less
Greater
LessEq
GreaterEq
Eq
Eqv
Equal
Cons
Car
Cdr
List
NullP
PairP
SymbolP
SymbolEq
IdentifierP
SyntaxP
FreeIdentifierEq
BoundIdentifierEq
SymbolToString
StringToSymbol
StringHash
StringCiHash
SymbolHash
EqualHash
SyntaxToDatum
DatumToSyntax
BooleanP
BooleanEq
NumberP
IntegerP
ExactIntegerP
RationalP
RealP
ComplexP
ExactP
InexactP
ZeroP
PositiveP
NegativeP
OddP
EvenP
FiniteP
InfiniteP
NanP
ProcedureP
RecordP
RecordRtd
RecordTypeDescriptorP
RecordConstructorDescriptorP
RecordTypeName
RecordTypeParent
RecordTypeUid
RecordTypeGenerativeP
RecordTypeSealedP
RecordTypeOpaqueP
RecordTypeFieldNames
RecordTypeFieldMutableP
RecordConstructorDescriptor
RecordConstructor
RecordPredicate
RecordAccessor
RecordMutator
MakeRecordTypeDescriptor
MakeRecordConstructorDescriptor
Condition
ConditionP
SimpleConditions
ConditionPredicate
ConditionAccessor
MakeEqHashtable
MakeEqvHashtable
MakeHashtable
HashtableP
HashtableSize
HashtableRef
HashtableSet
HashtableDelete
HashtableContainsP
HashtableUpdate
HashtableCopy
HashtableClear
HashtableKeys
HashtableEntries
HashtableEquivalenceFunction
HashtableHashFunction
HashtableMutableP
MakeEnumeration
EnumSetUniverse
EnumSetIndexer
EnumSetConstructor
EnumSetP
EnumSetMemberP
EnumSetSubsetP
EnumSetEq
EnumSetUnion
EnumSetIntersection
EnumSetDifference
EnumSetComplement
EnumSetProjection
EnumSetToList
Not
Apply
CallCC
Values
CallWithValues
MakeParameter
DynamicWind
Eval
Environment
PromiseP
MakePromise
Force
ExactToInexact
InexactToExact
ExactIntegerSqrt
Rationalize
NumberToString
StringToNumber
MakeRectangular
MakePolar
RealPart
ImagPart
Magnitude
Angle
Sqrt
Exp
Log
Expt
Sin
Cos
Tan
Asin
Acos
Atan
Numerator
Denominator
Abs
Quotient
Remainder
Modulo
Gcd
Lcm
Max
Min
Floor
Ceiling
Truncate
Round
BitwiseAnd
BitwiseIor
BitwiseXor
BitwiseNot
BitwiseIf
ArithmeticShift
BitwiseBitCount
BitwiseLength
BitwiseFirstBitSet
BitwiseBitSetP
BitwiseCopyBit
BitwiseBitField
BitwiseCopyBitField
BitwiseRotateBitField
BitwiseReverseBitField
FixnumP
FixnumWidth
LeastFixnum
GreatestFixnum
FxEq
FxLess
FxGreater
FxLessEq
FxGreaterEq
FxZeroP
FxPositiveP
FxNegativeP
FxOddP
FxEvenP
FxMin
FxMax
FxAdd
FxSub
FxMul
FxDiv
FxMod
FxDiv0
FxMod0
FxAddCarry
FxSubCarry
FxMulCarry
FxNot
FxAnd
FxIor
FxXor
FxIf
FxBitCount
FxLength
FxFirstBitSet
FxBitSetP
FxCopyBit
FxBitField
FxCopyBitField
FxRotateBitField
FxReverseBitField
FxArithmeticShift
FxArithmeticShiftLeft
FxArithmeticShiftRight
FlonumP
RealToFlonum
FixnumToFlonum
FlEq
FlLess
FlGreater
FlLessEq
FlGreaterEq
FlIntegerP
FlZeroP
FlPositiveP
FlNegativeP
FlOddP
FlEvenP
FlFiniteP
FlInfiniteP
FlNanP
FlMax
FlMin
FlAdd
FlMul
FlSub
FlDiv
FlAbs
FlDivAndMod
FlDivInt
FlMod
FlDiv0AndMod0
FlDiv0
FlMod0
FlNumerator
FlDenominator
FlFloor
FlCeiling
FlTruncate
FlRound
FlExp
FlLog
FlSin
FlCos
FlTan
FlAsin
FlAcos
FlAtan
FlSqrt
FlExpt
MakeVariableTransformer
GenerateTemporaries
ListP
MakeList
Length
Append
Reverse
ListRef
ListTail
Cxr(String)
Member
Memq
Memv
Assoc
Assq
Assv
Map
ForEach
SetCar
SetCdr
ListCopy
CharEq
CharLess
CharGreater
CharLessEq
CharGreaterEq
CharCiEq
CharCiLess
CharCiGreater
CharCiLessEq
CharCiGreaterEq
CharP
CharToInteger
IntegerToChar
CharAlphabeticP
CharNumericP
CharWhitespaceP
CharUpperCaseP
CharLowerCaseP
CharUpcase
CharDowncase
CharFoldcase
CharGeneralCategory
StringEq
StringLess
StringGreater
StringLessEq
StringGreaterEq
StringCiEq
StringCiLess
StringCiGreater
StringCiLessEq
StringCiGreaterEq
String
MakeString
StringP
StringLength
StringAppend
StringRef
StringSet
StringCopy
Substring
StringCopyBang
StringFill
StringToList
ListToString
StringMap
StringForEach
StringUpcase
StringDowncase
StringFoldcase
StringNormalizeNfc
StringNormalizeNfd
StringNormalizeNfkc
StringNormalizeNfkd
Vector
MakeVector
VectorP
VectorLength
VectorRef
VectorSet
VectorFill
VectorToList
ListToVector
VectorCopy
VectorCopyBang
VectorAppend
VectorMap
VectorForEach
ByteVector
MakeByteVector
ByteVectorP
ByteVectorLength
ByteVectorEq
ByteVectorU8Ref
ByteVectorU8Set
ByteVectorCopy
ByteVectorCopyBang
ByteVectorAppend
ByteVectorFill
ByteVectorToU8List
U8ListToByteVector
StringToUtf8
Utf8ToString
NativeEndianness
ByteVectorUintRef
ByteVectorSintRef
ByteVectorUintSet
ByteVectorSintSet
Display
Write
Newline
OpenOutputString
GetOutputString
CurrentOutputPort
WithExceptionHandler
Raise
RaiseContinuable
Error
AssertionViolation
ImplementationRestrictionViolation
UndefinedViolation
SyntaxViolation
} derive(Eq)
///|
pub extend Primitive with Eq::{not_equal, equal}
///|
/// Lexical environment (stack of frames) captured by closures.
/// The implementation treats this as an internal detail.
///|
pub struct Binding {
id : Int
value : Value
}
///|
pub type Env = Array[Map[String, Binding]]
///|
/// A syntax-rules transformer.
///|
pub struct SyntaxRule {
pattern : Datum
template : Datum
fender : Datum?
}
///|
/// A collection of syntax-rules with literal identifiers.
///|
pub(all) enum SyntaxRulesKind {
SyntaxRules
SyntaxCase
}
///|
pub struct SyntaxRules {
literals : Array[String]
rules : Array[SyntaxRule]
ellipsis : String
kind : SyntaxRulesKind
def_env : Env
}
///|
pub(all) enum MacroTransformer {
Rules(SyntaxRules)
Procedure(Value, Env)
}
///|
/// Closure is an opaque procedure value produced by lambda.
/// The interpreter may store extra data internally; tests treat it as opaque.
///|
pub struct Closure {
id : Int
params : Array[String]
rest : String?
body : Array[Datum]
env : Env
}
///|
pub struct CaseClause {
params : Array[String]
rest : String?
body : Array[Datum]
}
///|
pub struct CaseClosure {
id : Int
clauses : Array[CaseClause]
env : Env
}
///|
pub struct GuardHandler {
id : Int
name : String
clauses : Array[Datum]
env : Env
resume_value : Value
handlers : Array[Value]
}
///|
pub struct Parameter {
id : Int
value : Ref[Value]
converter : Value?
}
///|
pub(all) enum PromiseState {
Thunk(Value)
Value(Value)
}
///|
pub struct Promise {
id : Int
state : Ref[PromiseState]
}
///|
pub struct EvalEnv {
id : Int
env : Env
}
///|
pub struct SyntaxObject {
datum : Datum
scopes : Array[Int]
binding_id : Int?
}
///|
/// Runtime values produced by evaluation.
///|
pub(all) enum Value {
Void
Datum(Datum)
Primitive(Primitive)
Closure(Closure)
CaseClosure(CaseClosure)
Values(Array[Value])
GuardHandler(GuardHandler)
Parameter(Parameter)
Promise(Promise)
EvalEnv(EvalEnv)
Continuation(Continuation)
Port(Port)
Record(Record)
RecordProc(RecordProc)
ConditionProc(ConditionProc)
Hashtable(Hashtable)
EnumSet(EnumSet)
EnumSetProc(EnumSetProc)
RecordTypeDescriptor(RecordTypeDescriptor)
RecordConstructorDescriptor(RecordConstructorDescriptor)
SyntaxObject(SyntaxObject)
SyntaxKeyword(String)
Macro(MacroTransformer)
}
///|
pub impl Show for ParseError with fn output(self, logger) {
logger.write_string(@debug.render(self.to_repr(), max_depth=2147483647))
}
///|
pub extend ParseError with Show::{to_string, output}
///|
pub impl Show for EvalError with fn output(self, logger) {
logger.write_string(@debug.render(self.to_repr(), max_depth=2147483647))
}
///|
pub extend EvalError with Show::{to_string, output}