├── .gitignore ├── .swiftpm └── xcode │ ├── package.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata │ └── xcschemes │ ├── Swifties.xcscheme │ └── swifu.xcscheme ├── Package.swift ├── README.md ├── Sources └── Swifties │ ├── Cont.swift │ ├── Env.swift │ ├── Form.swift │ ├── Frame.swift │ ├── Func.swift │ ├── Iter.swift │ ├── Lib.swift │ ├── Macro.swift │ ├── Multi.swift │ ├── Op.swift │ ├── Parser.swift │ ├── Pos.swift │ ├── Prim.swift │ ├── Scope.swift │ ├── Slot.swift │ ├── Stack.swift │ ├── Type.swift │ ├── errors │ ├── DupBinding.swift │ ├── EmitError.swift │ ├── EvalError.swift │ ├── FuncNotApplicable.swift │ ├── MultiNotApplicable.swift │ ├── ReadError.swift │ └── UnknownId.swift │ ├── forms │ ├── CallForm.swift │ ├── DoForm.swift │ ├── IdForm.swift │ ├── LiteralForm.swift │ ├── PairForm.swift │ ├── QuoteForm.swift │ ├── SpliceForm.swift │ └── StackForm.swift │ ├── libs │ ├── CoreLib.swift │ └── MathLib.swift │ ├── ops │ ├── Bench.swift │ ├── Branch.swift │ ├── Call.swift │ ├── Copy.swift │ ├── Drop.swift │ ├── For.swift │ ├── Goto.swift │ ├── Load.swift │ ├── Push.swift │ ├── PushDown.swift │ ├── Quote.swift │ ├── Recall.swift │ ├── Reset.swift │ ├── Restore.swift │ ├── Return.swift │ ├── Splat.swift │ ├── Stop.swift │ ├── Store.swift │ ├── Suspend.swift │ ├── Swap.swift │ └── Zip.swift │ ├── readers │ ├── CallReader.swift │ ├── CharReader.swift │ ├── IdReader.swift │ ├── IntReader.swift │ ├── PairReader.swift │ ├── QuoteReader.swift │ ├── SpaceReader.swift │ ├── SpliceReader.swift │ ├── StackReader.swift │ └── StringReader.swift │ └── types │ ├── AnyType.swift │ ├── BoolType.swift │ ├── CharType.swift │ ├── ContType.swift │ ├── FormType.swift │ ├── FuncType.swift │ ├── IdType.swift │ ├── IntType.swift │ ├── IterType.swift │ ├── MacroType.swift │ ├── MetaType.swift │ ├── MultiType.swift │ ├── PairType.swift │ ├── PrimType.swift │ ├── RegisterType.swift │ ├── StackType.swift │ └── StringType.swift └── Tests ├── LinuxMain.swift └── SwiftiesTests ├── Tests.swift └── XCTestManifests.swift /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | /*.xcodeproj 5 | xcuserdata/ 6 | -------------------------------------------------------------------------------- /.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.swiftpm/xcode/xcshareddata/xcschemes/Swifties.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 67 | 68 | 74 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /.swiftpm/xcode/xcshareddata/xcschemes/swifu.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 67 | 68 | 74 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.3 2 | 3 | import PackageDescription 4 | 5 | let package = Package( 6 | name: "Swifties", 7 | products: [ 8 | .library( 9 | name: "Swifties", 10 | targets: ["Swifties"]) 11 | ], 12 | dependencies: [ 13 | ], 14 | targets: [ 15 | .target( 16 | name: "Swifties", 17 | dependencies: []), 18 | .testTarget( 19 | name: "SwiftiesTests", 20 | dependencies: ["Swifties"]), 21 | ] 22 | ) 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Swifties 2 | ### a custom language construction kit 3 | 4 | ### intro 5 | [Swifties](https://github.com/codr7/swifties) aims to provide a flexible toolkit for creating custom languages in Swift. 6 | 7 | ### demo 8 | A custom Lisp REPL is [provided](https://github.com/codr7/swifties-repl) for demonstration purposes. 9 | 10 | ### primitives 11 | Primitives are called at compile time and may take any number (min/max are specified in the constructor) of forms as arguments and emit operations. 12 | 13 | ```swift 14 | let pos = Pos(source: "test", line: -1, column: -1) 15 | 16 | let p = Prim(env: env, pos: self.pos, name: "do", (0, -1), { 17 | pos, args in 18 | for a in args { try a.emit() } 19 | }) 20 | 21 | env.openScope().bind(pos: pos, id: "do", env.coreLib!.primType, p) 22 | ``` 23 | 24 | ### functions 25 | Functions may take any number of arguments and return any number of results; `pos` indicates the call site; evaluation resumes from the returned `Pc`. 26 | 27 | ```swift 28 | let pos = Pos(source: "test", line: -1, column: -1) 29 | 30 | let f = Func(env: env, pos: pos, name: "foo", args: [], rets: [env.coreLib!.intType], { 31 | pos, self, ret in 32 | env.push(env.coreLib!.intType, 42) 33 | return ret 34 | }) 35 | 36 | env.openScope().bind(pos: pos, id: "foo", env.coreLib!.funcType, f) 37 | ``` 38 | 39 | Functions may alternatively be instantiated with `Form`-bodies, which emits operations behind the scenes and generates a function containing the code required to evaluate them. 40 | 41 | ```swift 42 | let f = Func(env: env, pos: pos, name: "foo", args: [], rets: [env.coreLib!.intType]) 43 | try f.compileBody(LiteralForm(env: env, pos: pos, env.coreLib!.intType, 42)) 44 | ``` 45 | 46 | ### multimethods 47 | Multimethods are sets of functions sharing the same name sorted from most specific to least that delegate to the most specific applicable function when called. 48 | 49 | ```swift 50 | let m = Multi(env: env, pos: pos, name: "foo") 51 | f.addFunc(f) 52 | ``` 53 | 54 | ### types 55 | Two levels of types are used, `ÀnyType`, and it's direct parameterized subclass `Type` from which all other types inherit. 56 | 57 | - Any - Any kind of value 58 | - Bool - Boolean values 59 | - Char - Character values 60 | - Cont - Continuations as values 61 | - Form - Forms as values 62 | - Func - Functions as values 63 | - Id - Quoted identifiers 64 | - Int - Integer values 65 | - Iter - Iterators 66 | - Macro - Macros as values 67 | - Meta - Types as values 68 | - Multi - Multimethods as values 69 | - Pair - Pairs of values 70 | - Prim - Primitives as values 71 | - Register - Register references as values 72 | - Seq - Iterable values 73 | - Stack - Stack values 74 | - String - String values 75 | - Target - Callable values 76 | 77 | ### parsing 78 | `Parser` may be used to simplify the process of turning code into forms. 79 | 80 | ```swift 81 | let pos = Pos("test", line: -1, column: -1) 82 | let env = Env() 83 | try env.initCoreLib(pos: pos) 84 | 85 | let parser = Parser(env: env, source: "test", 86 | prefix: [spaceReader, intReader], 87 | suffix: []) 88 | 89 | try parser.slurp("1 2 3") 90 | for f in parser.forms { try f.emit() } 91 | env.emit(STOP) 92 | try env.eval(0) 93 | 94 | XCTAssertEqual(Slot(env.coreLib!.intType, 3), env.pop(pos: pos)) 95 | XCTAssertEqual(Slot(env.coreLib!.intType, 2), env.pop(pos: pos)) 96 | XCTAssertEqual(Slot(env.coreLib!.intType, 1), env.pop(pos: pos)) 97 | ``` 98 | 99 | #### readers 100 | Readers specialize in parsing a specific kind of form. 101 | 102 | - Call - Reads call forms 103 | - Char - Reads character literals 104 | - Id - Reads identifiers 105 | - Int - Reads integer literals 106 | - Pair - Reads pair literals 107 | - Quote - Reads quoted forms 108 | - Space - Skips whitespace 109 | - Splice - Reads spliced expressions 110 | - Stack - Reads stack literals 111 | - String - Reads string literals 112 | 113 | It's trivial to extend the framework with custom readers. 114 | Just make sure to return `nil` if you can't find what you're looking for, since each reader is tried in sequence for every new position. 115 | 116 | ```swift 117 | func intReader(_ p: Parser) throws -> Form? { 118 | let fpos = p.pos 119 | var v = 0 120 | 121 | while let c = p.getc() { 122 | if !c.isNumber { 123 | p.ungetc(c) 124 | break 125 | } 126 | 127 | v *= 10 128 | v += c.hexDigitValue! 129 | p.nextColumn() 130 | } 131 | 132 | return (p.pos == fpos) ? nil : LiteralForm(env: p.env, pos: p.pos, p.env.coreLib!.intType, v) 133 | } 134 | ``` 135 | 136 | ### forms 137 | Code is parsed into forms, which is what primitives and macros operate on. 138 | 139 | - Call - Emits code to call specified target with args 140 | - Do - Emits args in sequence 141 | - Id - Emits the value of specified binding and calls it if possible 142 | - Literal - Emits code to push specified value 143 | - Pair - Emits code to push specified pair 144 | - Quote - Emits code to push quoted form 145 | - Splice - Emits result of evaluating form if quoted depth is `1` 146 | - Stack - Emits code to push a stack with specified items 147 | 148 | ### operations 149 | Forms emit operations, which are the basic building blocks that are eventually evaluated in sequence to get the desired result. 150 | 151 | - Bench - Repeats body specified number of times and pushes elapsed time in milliseconds 152 | - Branch - Branches conditionally 153 | - Call - Calls specified value 154 | - Drop - Drops specified number of items from stack 155 | - For - Repeats code for each value in sequence on top of stack 156 | - Goto - Resumes evaluation from specified `Pc` 157 | - Load - Loads value from specified register 158 | - Push - Pushes specified value on stack 159 | - PushDown - Pushes top of stack onto next item 160 | - Quote - Quotes and pushes specified form 161 | - Recall - Restarts current function without pushing frame 162 | - Reset - Clears stack 163 | - Restore - Restores continuation 164 | - Return - Pops frame from call stack and resumes evaluation from it's return pc 165 | - Splat - Replaces top of stack (which has to be iterable) with it's items 166 | - Stop - Stops evaluation without error 167 | - Store - Stores value in specified register 168 | - Suspend - Pushes continuation 169 | - Zip - Replaces top two stack items with pair 170 | 171 | Operations may be manually emitted at any point using `Env.emit(Op)`. 172 | 173 | ```swift 174 | let pos = Pos("test", line: -1, column: -1) 175 | let env = Env() 176 | try env.initCoreLib(pos: pos) 177 | let v = Slot(env.coreLib!.intType, 42) 178 | env.emit(Push(pc: env.pc, v)) 179 | env.emit(STOP) 180 | try env.eval(0) 181 | XCTAssertEqual(v, env.pop(pos: pos)) 182 | ``` 183 | 184 | ### todo 185 | - add filter like map 186 | - add odd?/even? to math 187 | - add lambdas 188 | - extract subclass from Func 189 | - add type 190 | - trap stack target in call form 191 | - push lambda 192 | - ([x y z] [] ...) 193 | - finish macros 194 | - add support for \n & \t to char/stringReader 195 | - add string interpolation 196 | - swift syntax 197 | - add unsafe prim 198 | - add Env.safetyLevel = 0 199 | - add Unsafe op 200 | - copy Bench 201 | - dec/defer inc safetyLevel 202 | - add Env.unsafe { safetyLevel > 0 } 203 | - skip Func.IsApplicable if env.unsafe 204 | - skip result check in Frame.restore if env.unsafe 205 | - add return prim 206 | - emit args & Return 207 | - make suggestions based on edit distance for missing ids 208 | - recursive like find 209 | -------------------------------------------------------------------------------- /Sources/Swifties/Cont.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class Cont { 4 | init(env: Env, restorePc: Pc) { 5 | _env = env 6 | _scope = env._scope 7 | _stack = env._stack 8 | _registers = env._registers 9 | _frames = env._frames 10 | _restorePc = restorePc 11 | } 12 | 13 | func dump() -> String { "Cont(\(_restorePc))" } 14 | 15 | func restore() -> Pc { 16 | _env._scope = _scope 17 | _env._stack = _stack 18 | _env._registers = _registers 19 | _env._frames = _frames 20 | return _restorePc 21 | } 22 | 23 | private let _env: Env 24 | private let _scope: Scope? 25 | private let _stack: Stack 26 | private let _registers: Registers 27 | private let _frames: Frames 28 | private let _restorePc: Pc 29 | } 30 | -------------------------------------------------------------------------------- /Sources/Swifties/Env.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public typealias Frames = [Frame] 4 | public typealias Bin = [Op] 5 | public typealias Pc = Int 6 | public typealias Register = Int 7 | public typealias Registers = [Slot?] 8 | public typealias TypeId = UInt 9 | 10 | public let STOP_PC: Pc = -1 11 | public let SWIFTIES_VERSION = 5 12 | 13 | open class Env { 14 | open var bin: Bin { _bin } 15 | open var coreLib: CoreLib? { _coreLib } 16 | open var pc: Pc { _bin.count } 17 | open var scope: Scope? { _scope } 18 | open var stack: Stack { _stack } 19 | open var registers: Registers { _registers } 20 | 21 | public init() {} 22 | 23 | @discardableResult 24 | open func begin() -> Scope { 25 | _scope = Scope(env: self, outer: _scope) 26 | return _scope! 27 | } 28 | 29 | open func end() { 30 | precondition(_scope != nil, "No open scopes") 31 | 32 | let s = _scope! 33 | _scope = s.outer 34 | } 35 | 36 | @discardableResult 37 | open func pushFrame(pos: Pos, _func: Func, scope: Scope, startPc: Pc, ret: Pc) -> Frame { 38 | let f = Frame(env: self, pos: pos, _func: _func, scope: scope, startPc: startPc, ret: ret) 39 | _frames.append(f) 40 | return f 41 | } 42 | 43 | open func peekFrame() -> Frame? { _frames.last } 44 | 45 | open func popFrame(pos: Pos) throws -> Pc { 46 | if _frames.count == 0 { throw EvalError(pos, "No calls in progress") } 47 | return try _frames.popLast()!.restore() 48 | } 49 | 50 | @discardableResult 51 | open func initCoreLib(pos: Pos) throws -> CoreLib { 52 | if _coreLib == nil { 53 | _coreLib = CoreLib(env: self, pos: pos) 54 | } 55 | 56 | return _coreLib! 57 | } 58 | 59 | open func nextTypeId() -> TypeId { 60 | let id = _nextTypeId 61 | _nextTypeId += 1 62 | return id 63 | } 64 | 65 | @discardableResult 66 | open func emit(_ op: Op, pc: Int? = nil) -> Pc { 67 | if let i = pc { 68 | _bin[i] = op 69 | return i 70 | } 71 | 72 | _bin.append(op) 73 | return _bin.count-1 74 | } 75 | 76 | open func push(_ slots: Slot...) { push(slots) } 77 | 78 | open func push(_ slots: [Slot]) { 79 | for s in slots { _stack.append(s) } 80 | } 81 | 82 | open func push(_ type: Type, _ value: T) { push(Slot(type, value)) } 83 | 84 | open func peek(pos: Pos, offset: Int = 0) throws -> Slot { 85 | let v = tryPeek(offset: offset) 86 | if v == nil { throw EvalError(pos, "Stack is empty") } 87 | return v! 88 | } 89 | 90 | open func tryPeek(offset: Int = 0) -> Slot? { 91 | if offset >= _stack.count { return nil } 92 | return _stack[_stack.count - offset - 1] 93 | } 94 | 95 | open func poke(pos: Pos, _ type: Type, _ value: T, offset: Int = 0) throws { 96 | if offset >= _stack.count { throw EvalError(pos, "Stack is empty") } 97 | _stack[_stack.count - offset - 1] = Slot(type, value) 98 | } 99 | 100 | @discardableResult 101 | open func pop(pos: Pos, offset: Int = 0) throws -> Slot { 102 | if offset >= _stack.count { throw EvalError(pos, "Stack is empty") } 103 | let v = (offset == 0) ? _stack.popLast() : _stack.remove(at: _stack.count-offset-1) 104 | return v! 105 | } 106 | 107 | open func copy(pos: Pos, count: Int = 1) throws { 108 | if _stack.count < count { throw EvalError(pos, "Stack is empty") } 109 | _stack.append(contentsOf: _stack[_stack.count-count..<_stack.count]) 110 | } 111 | 112 | open func drop(pos: Pos, offset: Int = 0, count: Int = 1) throws { 113 | if _stack.count < count { throw EvalError(pos, "Stack is empty") } 114 | if offset == 0 { 115 | _stack = _stack.dropLast(count) 116 | } else { 117 | for _ in 0.. Cont { Cont(env: self, restorePc: restorePc) } 153 | 154 | open func getType(pos: Pos, _ name: String) throws -> AnyType { 155 | let found = _scope!.find(name) 156 | if found == nil { throw EmitError(pos, "Invalid type: \(name)") } 157 | if found!.type != _coreLib!.metaType { throw EmitError(pos, "Invalid type: \(found!)") } 158 | return found!.value as! AnyType 159 | } 160 | 161 | var _bin: Bin = [] 162 | var _scope: Scope? 163 | var _stack: Stack = [] 164 | var _registers: Registers = [] 165 | var _frames: Frames = [] 166 | 167 | private var _nextTypeId: TypeId = 1 168 | private var _coreLib: CoreLib? 169 | } 170 | -------------------------------------------------------------------------------- /Sources/Swifties/Form.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class Form: Equatable { 4 | public static func == (lhs: Form, rhs: Form) -> Bool { lhs === rhs } 5 | 6 | open var env: Env { _env } 7 | open var pos: Pos { _pos } 8 | open var slot: Slot? { nil } 9 | 10 | public init(env: Env, pos: Pos) { 11 | _env = env 12 | _pos = pos 13 | } 14 | 15 | open func dump() -> String { "*?*" } 16 | open func expand() throws -> Form { self } 17 | open func emit() throws {} 18 | open func quote1() throws -> Form { self } 19 | open func quote2(depth: Int) throws -> Form { return self } 20 | open func quote3(depth: Int) throws -> Slot { Slot(env.coreLib!.formType, try quote2(depth: depth)) } 21 | 22 | private let _env: Env 23 | private let _pos: Pos 24 | } 25 | 26 | public typealias Forms = [Form] 27 | 28 | public extension Forms { 29 | func dump() -> String { 30 | var out = "" 31 | 32 | for i in 0.. 0 { out += " " } 34 | out += self[i].dump() 35 | } 36 | 37 | return out 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Sources/Swifties/Frame.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct Frame { 4 | public init(env: Env, pos: Pos, _func: Func, scope: Scope, startPc: Pc, ret: Pc) { 5 | _env = env 6 | _pos = pos 7 | self._func = _func 8 | let s = env._stack 9 | _env._stack = Stack(s.dropFirst(s.count-_func.args.count)) 10 | _stack = s.dropLast(_func.args.count) 11 | _registers = _env._registers 12 | _startPc = startPc 13 | (_scope, _env._scope) = (_env._scope!, scope) 14 | _ret = ret 15 | } 16 | 17 | public func restore() throws -> Pc { 18 | let n = _env._stack.count 19 | if n < _func.rets.count { throw EvalError(_pos, "Missing results: \(_func.name) \(_env._stack)")} 20 | let rstack = _env._stack.dropFirst(n-_func.rets.count) 21 | _env._stack = _stack 22 | 23 | for i in 0..<_func.rets.count { 24 | let v = rstack[i] 25 | if !v.type.isa(_func.rets[i]) { throw EvalError(_pos, "Invalid result: \(_func.name) \(v)") } 26 | } 27 | 28 | _env._stack.append(contentsOf: rstack) 29 | _env._registers = _registers 30 | _env._scope = _scope 31 | return _ret 32 | } 33 | 34 | public func recall(pos: Pos, check: Bool) throws -> Pc { 35 | if check && !_func.isApplicable() { throw FuncNotApplicable(pos: pos, target: _func, stack: _env._stack) } 36 | return _startPc 37 | } 38 | 39 | private let _env: Env 40 | private let _pos: Pos 41 | private let _func: Func 42 | private let _scope: Scope 43 | private let _stack: Stack 44 | private let _registers: Registers 45 | private let _startPc, _ret: Pc 46 | } 47 | -------------------------------------------------------------------------------- /Sources/Swifties/Func.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class Func: Definition { 4 | public typealias Arg = (String?, AnyType) 5 | public typealias Body = (_ pos: Pos, _ self: Func, _ ret: Pc) throws -> Pc 6 | public typealias Ret = AnyType 7 | public typealias Weight = UInt 8 | 9 | public static func getArg(env: Env, pos: Pos, _ f: Form) throws -> Arg { 10 | var l: String? 11 | var r: String 12 | 13 | switch f { 14 | case let f as IdForm: 15 | r = f.name 16 | case let f as PairForm: 17 | l = (f.left as! IdForm).name 18 | r = (f.right as! IdForm).name 19 | default: 20 | throw EmitError(pos, "Invalid func argument: #\(f)") 21 | } 22 | 23 | return (l, try env.getType(pos: pos, r)) 24 | } 25 | 26 | public static func getRet(env: Env, pos: Pos, _ f: Form) throws -> Ret { 27 | if !(f is IdForm) { throw EmitError(pos, "Invalid func result: #\(f)") } 28 | return try env.getType(pos: pos, (f as! IdForm).name) 29 | } 30 | 31 | open var env: Env { _env } 32 | open var pos: Pos { _pos } 33 | open var name: String { _name } 34 | open var args: [Arg] { _args } 35 | open var weight: Weight { _weight } 36 | open var rets: [Ret] { _rets } 37 | open var slot: Slot { Slot(_env.coreLib!.funcType, self) } 38 | 39 | public init(env: Env, pos: Pos, name: String, args: [Arg], rets: [Ret], _ body: Body? = nil) { 40 | _env = env 41 | _pos = pos 42 | _name = name 43 | _args = args 44 | _weight = args.map({a in a.1.id}).reduce(0, +) 45 | _rets = rets 46 | _body = body 47 | } 48 | 49 | open func compileBody(_ form: Form) throws { 50 | let skip = _env.emit(STOP) 51 | let startPc = _env.pc 52 | let scope = _env.begin() 53 | 54 | do { 55 | defer { _env.end() } 56 | var offset = 0 57 | 58 | for (n, _) in _args.reversed() { 59 | if n == nil { 60 | offset += 1 61 | } else if n == "_" { 62 | env.emit(Drop(env: _env, pos: _pos, pc: _env.pc, offset: offset)) 63 | } else { 64 | let i = try scope.nextRegister(pos: pos, id: "$\(n!)") 65 | env.emit(Store(env: _env, pos: _pos, pc: _env.pc, index: i, offset: offset)) 66 | } 67 | } 68 | 69 | try form.emit() 70 | } 71 | 72 | _env.emit(Return(env: _env, pos: form.pos)) 73 | _env.emit(Goto(pc: env.pc), pc: skip) 74 | 75 | _body = {p, f, ret in 76 | self._env.pushFrame(pos: p, _func: f, scope: scope, startPc: startPc, ret: ret) 77 | return startPc 78 | } 79 | } 80 | 81 | open func isApplicable() -> Bool { 82 | for i in 0..<_args.count { 83 | let v = _env.tryPeek(offset: _args.count-i-1) 84 | if v == nil || !v!.type.isa(_args[i].1) { return false } 85 | } 86 | 87 | return true 88 | } 89 | 90 | open func call(pos: Pos, ret: Pc) throws -> Pc { try _body!(pos, self, ret) } 91 | 92 | open func dump() -> String { "Func\(_name)" } 93 | 94 | private let _pos: Pos 95 | private let _env: Env 96 | private let _name: String 97 | private let _args: [Arg] 98 | private let _weight: Weight 99 | private let _rets: [Ret] 100 | private var _body: Body? 101 | } 102 | -------------------------------------------------------------------------------- /Sources/Swifties/Iter.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public typealias Iter = (Pos) throws -> Slot? 4 | -------------------------------------------------------------------------------- /Sources/Swifties/Lib.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public protocol Definition { 4 | var pos: Pos {get} 5 | var name: String {get} 6 | var slot: Slot {get} 7 | } 8 | 9 | open class Lib { 10 | open var env: Env { _env } 11 | open var pos: Pos { _pos } 12 | 13 | public init(env: Env, pos: Pos) { 14 | _env = env 15 | _pos = pos 16 | } 17 | 18 | open func define(_ ds: Definition...) { define(ds) } 19 | 20 | open func define(_ ds: [Definition]) { 21 | for d in ds { 22 | _bindings[d.name] = d.slot 23 | } 24 | } 25 | 26 | open func define(_ id: String, _ type: Type, _ value: T) { 27 | _bindings[id] = Slot(type, value) 28 | } 29 | 30 | open func bind(pos: Pos, _ names: String...) throws { try bind(pos: pos, names) } 31 | 32 | open func bind(pos: Pos, _ names: [String]) throws { 33 | for n in (names.count == 0) ? _bindings.map({n, _ in n}) : names { 34 | if let s = _bindings[n] { 35 | try env.scope!.bind(pos: pos, id: n, s) 36 | } else { 37 | throw UnknownId(pos: pos, id: n) 38 | } 39 | } 40 | } 41 | 42 | private let _env: Env 43 | private let _pos: Pos 44 | private var _bindings: [String: Slot] = [:] 45 | } 46 | -------------------------------------------------------------------------------- /Sources/Swifties/Macro.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class Macro { 4 | public typealias Body = (_ pos: Pos, _ args: [Form]) throws -> Form 5 | 6 | open var name: String { _name } 7 | 8 | public init(env: Env, name: String, _ body: @escaping Body) { 9 | _env = env 10 | _name = name 11 | _body = body 12 | } 13 | 14 | open func expand(pos: Pos, args: [Form]) throws -> Form { 15 | try _body(pos, args) 16 | } 17 | 18 | open func dump() -> String { "Macro\(_name)" } 19 | 20 | private let _env: Env 21 | private let _name: String 22 | private let _body: Body 23 | } 24 | -------------------------------------------------------------------------------- /Sources/Swifties/Multi.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class Multi { 4 | open var name: String { _name } 5 | 6 | public init(env: Env, name: String) { 7 | _env = env 8 | _name = name 9 | } 10 | 11 | open func addFunc(_ f: Func) { 12 | precondition(f.name == _name, "Wrong func name: \(f.name)") 13 | let i = _funcs.firstIndex(where: {g in f.weight < g.weight}) 14 | _funcs.insert(f, at: i ?? 0) 15 | } 16 | 17 | open func dump() -> String { "Multi\(_name)" } 18 | 19 | open func call(pos: Pos, ret: Pc) throws -> Pc { 20 | for f in _funcs { 21 | if f.isApplicable() { return try f.call(pos: pos, ret: ret) } 22 | } 23 | 24 | throw MultiNotApplicable(pos: pos, target: self, stack: _env._stack) 25 | } 26 | 27 | private let _env: Env 28 | private let _name: String 29 | private var _funcs: [Func] = [] 30 | } 31 | -------------------------------------------------------------------------------- /Sources/Swifties/Op.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public protocol Op { 4 | func eval() throws -> Pc 5 | } 6 | -------------------------------------------------------------------------------- /Sources/Swifties/Parser.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public typealias Reader = (_ p: Parser) throws -> Form? 4 | 5 | open class Parser { 6 | open var env: Env { _env } 7 | open var input: String { _input } 8 | open var pos: Pos { _pos } 9 | open var forms: [Form] { _forms } 10 | 11 | public init(env: Env, source: String, prefix: [Reader], suffix: [Reader]) { 12 | _env = env 13 | _pos = Pos(source) 14 | _prefix = prefix 15 | _suffix = suffix 16 | } 17 | 18 | open func getc() -> Character? { _input.popLast() } 19 | open func ungetc(_ c: Character) { _input.append(c) } 20 | 21 | open func readForm() throws -> Bool { 22 | for r in _prefix { 23 | if let f = try r(self) { 24 | _forms.append(f) 25 | try readSuffix() 26 | return true 27 | } 28 | } 29 | 30 | return false 31 | } 32 | 33 | @discardableResult 34 | open func readSuffix() throws -> Bool { 35 | for r in _suffix { 36 | if let f = try r(self) { 37 | _forms.append(f) 38 | try readSuffix() 39 | return true 40 | } 41 | } 42 | 43 | return false 44 | } 45 | 46 | open func popForm() -> Form? { _forms.popLast() } 47 | 48 | open func slurp(_ input: String) throws { 49 | _input = String(input.reversed()) + _input 50 | let (inputCopy, posCopy, formsCopy) = (_input, _pos, _forms) 51 | 52 | do { 53 | while try readForm() {} 54 | } catch let e { 55 | _input = inputCopy 56 | _pos = posCopy 57 | _forms = formsCopy 58 | throw e 59 | } 60 | } 61 | 62 | open func nextColumn() { _pos.nextColumn() } 63 | open func newLine() { _pos.newLine() } 64 | 65 | open func reset() { 66 | _forms = [] 67 | _pos = Pos(pos.source) 68 | } 69 | 70 | private let _env: Env 71 | private var _input: String = "" 72 | private var _pos: Pos 73 | private var _prefix, _suffix: [Reader] 74 | private var _forms: [Form] = [] 75 | } 76 | -------------------------------------------------------------------------------- /Sources/Swifties/Pos.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct Pos: Equatable { 4 | public static func == (lhs: Pos, rhs: Pos) -> Bool { 5 | lhs._source == rhs._source && lhs._line == rhs._line && lhs._column == rhs._column 6 | } 7 | 8 | public var source: String { _source } 9 | 10 | public init(_ source: String, line: Int = 0, column: Int = 0) { 11 | _source = source 12 | self._line = line 13 | self._column = column 14 | } 15 | 16 | public mutating func nextColumn() { 17 | self._column += 1 18 | } 19 | 20 | public mutating func newLine() { 21 | self._line += 1 22 | self._column = 0 23 | } 24 | 25 | private let _source: String 26 | private var _line, _column: Int 27 | } 28 | -------------------------------------------------------------------------------- /Sources/Swifties/Prim.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class Prim: Definition { 4 | public typealias Body = (_ pos: Pos, _ args: [Form]) throws -> Void 5 | 6 | open var env: Env { _env } 7 | open var pos: Pos { _pos } 8 | open var name: String { _name } 9 | open var slot: Slot { Slot(_env.coreLib!.primType, self) } 10 | 11 | public init(env: Env, pos: Pos, name: String, _ args: (Int, Int), _ body: @escaping Body) { 12 | _env = env 13 | _pos = pos 14 | _name = name 15 | _args = args 16 | _body = body 17 | } 18 | 19 | open func emit(pos: Pos, args: [Form]) throws { 20 | if args.count < _args.0 || (_args.1 != -1 && args.count > _args.1) { 21 | throw EmitError(pos, "Wrong number of arguments: \(_name)") 22 | } 23 | 24 | try _body(pos, args) 25 | } 26 | 27 | open func dump() -> String { "Prim\(_name)" } 28 | 29 | private let _env: Env 30 | private let _name: String 31 | private let _args: (Int, Int) 32 | private let _pos: Pos 33 | private let _body: Body 34 | } 35 | -------------------------------------------------------------------------------- /Sources/Swifties/Scope.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class Scope { 4 | open var outer: Scope? { _outer } 5 | open var registerCount: Int { _nextRegister } 6 | 7 | public init(env: Env, outer: Scope?) { 8 | _env = env 9 | _outer = outer 10 | } 11 | 12 | open func bind(pos: Pos, id: String, _ slot: Slot, force: Bool = false) throws { 13 | if !force && _bindings.keys.contains(id) { throw DupBinding(pos: pos, id: id) } 14 | _bindings[id] = slot 15 | } 16 | 17 | open func bind(pos: Pos, id: String, _ type: Type, _ value: T, force: Bool = false) throws { 18 | try bind(pos: pos, id: id, Slot(type, value), force: force) 19 | } 20 | 21 | open func unbind(pos: Pos, _ id: String) throws { 22 | let s = _bindings.removeValue(forKey: id) 23 | if s == nil { throw EmitError(pos, "Failed unbinding: \(id)") } 24 | precondition(s!.type == _env.coreLib!.registerType, "Unbinding non register slot: \(s!.type.name)") 25 | _nextRegister = min(_nextRegister, s!.value as! Register) 26 | } 27 | 28 | open func find(_ id: String) -> Slot? { 29 | var found = _bindings[id] 30 | 31 | if found == nil && _outer != nil { 32 | found = _outer!.find(id) 33 | if found != nil && found!.type == _env.coreLib!.registerType { found = nil } 34 | } 35 | 36 | return found 37 | } 38 | 39 | open func nextRegister(pos: Pos, id: String) throws -> Register { 40 | let i = _nextRegister 41 | try bind(pos: pos, id: id, _env.coreLib!.registerType, i) 42 | _nextRegister += 1 43 | return i 44 | } 45 | 46 | private let _env: Env 47 | private let _outer: Scope? 48 | private var _bindings: [String: Slot] = [:] 49 | private var _nextRegister = 0 50 | } 51 | 52 | -------------------------------------------------------------------------------- /Sources/Swifties/Slot.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct Slot: Equatable { 4 | public static func == (lhs: Slot, rhs: Slot) -> Bool { 5 | if (lhs._type !== rhs._type) { return false } 6 | precondition(lhs._type.equalValues != nil, "Equality not supported for type \(lhs._type.name)") 7 | return lhs._type.equalValues!(lhs.value, rhs.value) 8 | } 9 | 10 | public var type: AnyType { get { _type } } 11 | public var value: Any { get { _value } } 12 | 13 | public init(_ type: Type, _ value: T) { 14 | self._type = type 15 | self._value = value 16 | } 17 | 18 | public func dump() -> String { _type.dumpValue!(_value) } 19 | 20 | private let _type: AnyType 21 | private let _value: Any 22 | } 23 | -------------------------------------------------------------------------------- /Sources/Swifties/Stack.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public typealias Stack = [Slot] 4 | 5 | extension Stack { 6 | public func dump() -> String { 7 | var out = "[" 8 | 9 | for i in 0.. 0 { out += " " } 11 | out += self[i].dump() 12 | } 13 | 14 | out += "]" 15 | return out 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Sources/Swifties/Type.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class Type: AnyType { 4 | public override init(_ env: Env, pos: Pos, name: String, parentTypes: [AnyType]) { 5 | super.init(env, pos: pos, name: name, parentTypes: parentTypes) 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Sources/Swifties/errors/DupBinding.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct DupBinding: Error { 4 | public init(pos: Pos, id: String) { 5 | _pos = pos 6 | _id = id 7 | } 8 | 9 | private let _pos: Pos 10 | private let _id: String 11 | } 12 | -------------------------------------------------------------------------------- /Sources/Swifties/errors/EmitError.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct EmitError: Error { 4 | public init(_ pos: Pos, _ message: String) { 5 | _pos = pos 6 | _message = message 7 | } 8 | 9 | private let _pos: Pos 10 | private let _message: String 11 | } 12 | -------------------------------------------------------------------------------- /Sources/Swifties/errors/EvalError.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct EvalError: Error { 4 | public init(_ pos: Pos, _ message: String) { 5 | _pos = pos 6 | _message = message 7 | } 8 | 9 | private let _pos: Pos 10 | private let _message: String 11 | } 12 | -------------------------------------------------------------------------------- /Sources/Swifties/errors/FuncNotApplicable.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct FuncNotApplicable: Error { 4 | public var localizedDescription: String { "Func not applicable: \(_target.name) \(_stack.dump())" } 5 | 6 | public init(pos: Pos, target: Func, stack: Stack) { 7 | _pos = pos 8 | _target = target 9 | _stack = stack 10 | } 11 | 12 | private let _pos: Pos 13 | private let _target: Func 14 | private let _stack: Stack 15 | } 16 | -------------------------------------------------------------------------------- /Sources/Swifties/errors/MultiNotApplicable.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct MultiNotApplicable: Error { 4 | public init(pos: Pos, target: Multi, stack: Stack) { 5 | _pos = pos 6 | _target = target 7 | _stack = stack 8 | } 9 | 10 | private let _pos: Pos 11 | private let _target: Multi 12 | private let _stack: Stack 13 | } 14 | -------------------------------------------------------------------------------- /Sources/Swifties/errors/ReadError.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct ReadError: Error { 4 | public init(_ pos: Pos, _ message: String) { 5 | _pos = pos 6 | _message = message 7 | } 8 | 9 | private let _pos: Pos 10 | private let _message: String 11 | } 12 | -------------------------------------------------------------------------------- /Sources/Swifties/errors/UnknownId.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct UnknownId: Error { 4 | public init(pos: Pos, id: String) { 5 | _pos = pos 6 | _id = id 7 | } 8 | 9 | private let _pos: Pos 10 | private let _id: String 11 | } 12 | -------------------------------------------------------------------------------- /Sources/Swifties/forms/CallForm.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class CallForm: Form { 4 | public init(env: Env, pos: Pos, target: Form, args: [Form]) { 5 | _target = target 6 | _args = args 7 | super.init(env: env, pos: pos) 8 | } 9 | 10 | open override func dump() -> String { "(\(_target.dump()) \(_args.dump()))" } 11 | 12 | open override func expand() throws -> Form { 13 | let newTarget = try _target.expand() 14 | let newArgs = try _args.map {a in try a.expand()} 15 | 16 | if let found = env.scope!.find((newTarget as! IdForm).name) { 17 | if found.type == env.coreLib!.macroType { 18 | let m = (found.value as! Macro) 19 | return try m.expand(pos: pos, args: newArgs) 20 | } 21 | } 22 | 23 | if newTarget != _target || newArgs != _args { 24 | return try CallForm(env: env, pos: pos, target: _target, args: newArgs).expand() 25 | } 26 | 27 | return self 28 | } 29 | 30 | open override func emit() throws { 31 | var t = env.scope!.find((_target as! IdForm).name) 32 | if t == nil { throw EmitError(pos, "Unknown target: \(_target)") } 33 | 34 | if t!.type == env.coreLib!.primType { 35 | try (t!.value as! Prim).emit(pos: pos, args: _args) 36 | } else { 37 | for a in _args { try a.emit() } 38 | 39 | if t!.type == env.coreLib!.registerType { 40 | env.emit(Load(env: env, pos: pos, pc: env.pc, index: t!.value as! Register)) 41 | t = nil 42 | } 43 | 44 | env.emit(Call(env: env, pos: pos, pc: env.pc, target: t, check: true)) 45 | } 46 | } 47 | 48 | open override func quote1() throws -> Form { 49 | _target = try _target.quote1() 50 | for i in 0..<_args.count { _args[i] = try _args[i].quote1() } 51 | return self 52 | } 53 | 54 | open override func quote2(depth: Int) throws -> Form { 55 | _target = try _target.quote2(depth: depth) 56 | for i in 0..<_args.count { _args[i] = try _args[i].quote2(depth: depth) } 57 | return self 58 | } 59 | 60 | private var _target: Form 61 | private var _args: Forms 62 | } 63 | -------------------------------------------------------------------------------- /Sources/Swifties/forms/DoForm.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class DoForm: Form { 4 | public init(env: Env, pos: Pos, body: Forms) { 5 | _body = body 6 | super.init(env: env, pos: pos) 7 | } 8 | 9 | open override func dump() -> String { "\(_body.dump())" } 10 | 11 | open override func expand() throws -> Form { 12 | let newBody = try _body.map {a in try a.expand()} 13 | if newBody != _body { return try DoForm(env: env, pos: pos, body: newBody).expand() } 14 | return self 15 | } 16 | 17 | open override func emit() throws { 18 | for f in _body{ try f.emit() } 19 | } 20 | 21 | open override func quote1() throws -> Form { 22 | for i in 0..<_body.count { _body[i] = try _body[i].quote1() } 23 | return self 24 | } 25 | 26 | open override func quote2(depth: Int) throws -> Form { 27 | for i in 0..<_body.count { _body[i] = try _body[i].quote2(depth: depth) } 28 | return self 29 | } 30 | 31 | private var _body: Forms 32 | } 33 | -------------------------------------------------------------------------------- /Sources/Swifties/forms/IdForm.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class IdForm: Form { 4 | open var name: String { _name } 5 | open var isCopy: Bool { _name.allSatisfy({c in c == "c"}) } 6 | open var isDrop: Bool { _name.allSatisfy({c in c == "d"}) } 7 | open var isRef: Bool { _name.first == "&" } 8 | open var isSwap: Bool { _name.allSatisfy({c in c == "s"}) } 9 | 10 | open override var slot: Slot? { 11 | get { 12 | if isDrop { return nil } 13 | 14 | if let found = env.scope!.find(self._name) { 15 | if found.type != env.coreLib!.registerType { 16 | return found 17 | } 18 | } 19 | 20 | return nil 21 | } 22 | } 23 | 24 | public init(env: Env, pos: Pos, name: String) { 25 | _name = name 26 | super.init(env: env, pos: pos) 27 | } 28 | 29 | open override func dump() -> String { _name } 30 | 31 | open override func expand() throws -> Form { 32 | if let found = env.scope!.find(self._name) { 33 | if found.type == env.coreLib!.macroType { 34 | return try (found.value as! Macro).expand(pos: pos, args: []) 35 | } 36 | } 37 | 38 | return self 39 | } 40 | 41 | open func emit(name: String) throws { 42 | if let found = env.scope!.find(name) { 43 | if found.type == env.coreLib!.registerType { 44 | env.emit(Load(env: env, pos: pos, pc: env.pc, index: found.value as! Int)) 45 | } else { 46 | env.emit(Push(pc: env.pc, found)) 47 | } 48 | } else { 49 | throw EmitError(pos, "Unknown identifier: \(name)") 50 | } 51 | } 52 | 53 | open override func emit() throws { 54 | if isCopy { 55 | env.emit(Copy(env: env, pos: pos, pc: env.pc, count: _name.count)) 56 | } else if isDrop { 57 | env.emit(Drop(env: env, pos: pos, pc: env.pc, count: _name.count)) 58 | } else if isSwap { 59 | env.emit(Swap(env: env, pos: pos, pc: env.pc, count: _name.count)) 60 | } else if isRef { 61 | try emit(name: String(_name.dropFirst())) 62 | } else if let found = env.scope!.find(_name) { 63 | if found.type == env.coreLib!.primType { 64 | try (found.value as! Prim).emit(pos: pos, args: []) 65 | } else if let _ = found.type.callValue { 66 | env.emit(Call(env: env, pos: pos, pc: env.pc, target: found, check: true)) 67 | } else { 68 | try emit(name: _name) 69 | } 70 | } else { 71 | try emit(name: _name) 72 | } 73 | } 74 | 75 | open override func quote3(depth: Int) -> Slot { Slot(env.coreLib!.idType, _name) } 76 | 77 | private let _name: String 78 | } 79 | -------------------------------------------------------------------------------- /Sources/Swifties/forms/LiteralForm.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class LiteralForm: Form { 4 | open override var slot: Slot? { _slot } 5 | 6 | public convenience init(env: Env, pos: Pos, _ type: Type, _ value: T) { 7 | self.init(env: env, pos: pos, Slot(type, value)) 8 | } 9 | 10 | public init(env: Env, pos: Pos, _ slot: Slot) { 11 | _slot = slot 12 | super.init(env: env, pos: pos) 13 | } 14 | 15 | open override func dump() -> String { _slot.dump() } 16 | 17 | open override func emit() throws { 18 | env.emit(Push(pc: env.pc, _slot)) 19 | } 20 | 21 | open override func quote3(depth: Int) -> Slot { _slot } 22 | 23 | private let _slot: Slot 24 | } 25 | -------------------------------------------------------------------------------- /Sources/Swifties/forms/PairForm.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class PairForm: Form { 4 | open var left: Form { _values.0 } 5 | open var right: Form { _values.1 } 6 | 7 | open override var slot: Slot? { _slot } 8 | 9 | public init(env: Env, pos: Pos, _ values: (Form, Form)) { 10 | _values = values 11 | let (l, r) = (values.0.slot, values.1.slot) 12 | 13 | if l != nil && r != nil { 14 | _slot = Slot(env.coreLib!.pairType, (l!, r!)) 15 | } else { 16 | _slot = nil 17 | } 18 | 19 | super.init(env: env, pos: pos) 20 | } 21 | 22 | open override func dump() -> String { "\(left.dump()):\(right.dump())" } 23 | 24 | open override func emit() throws { 25 | if _slot == nil { 26 | try _values.0.emit() 27 | try _values.1.emit() 28 | env.emit(Zip(env: env, pos: pos, pc: env.pc)) 29 | } else { 30 | env.emit(Push(pc: env.pc, _slot!)) 31 | } 32 | } 33 | 34 | open override func quote1() throws -> Form { 35 | _values = (try left.quote1(), try right.quote1()) 36 | return self 37 | } 38 | 39 | open override func quote2(depth: Int) throws -> Form { 40 | _values = (try left.quote2(depth: depth), try right.quote2(depth: depth)) 41 | return self 42 | } 43 | 44 | private var _values: (Form, Form) 45 | private let _slot: Slot? 46 | } 47 | -------------------------------------------------------------------------------- /Sources/Swifties/forms/QuoteForm.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class QuoteForm: Form { 4 | public init(env: Env, pos: Pos, form: Form) { 5 | _form = form 6 | super.init(env: env, pos: pos) 7 | } 8 | 9 | open override func dump() -> String { "'\(_form.dump())" } 10 | 11 | open override func expand() throws -> Form { 12 | let newForm = try _form.expand() 13 | if newForm != _form { return try QuoteForm(env: env, pos: pos, form: newForm).expand() } 14 | return self 15 | } 16 | 17 | open override func emit() throws { 18 | let f = try _form.quote1() 19 | env.emit(Quote(env: env, pc: env.pc, form: f)) 20 | } 21 | 22 | open override func quote1() throws -> Form { 23 | _form = try _form.quote1() 24 | return self 25 | } 26 | 27 | open override func quote2(depth: Int) throws -> Form { 28 | _form = try _form.quote2(depth: depth+1) 29 | return self 30 | } 31 | 32 | private var _form: Form 33 | } 34 | -------------------------------------------------------------------------------- /Sources/Swifties/forms/SpliceForm.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class SpliceForm: Form { 4 | public init(env: Env, pos: Pos, form: Form) { 5 | _form = form 6 | super.init(env: env, pos: pos) 7 | } 8 | 9 | open override func dump() -> String { ",\(_form.dump())" } 10 | 11 | open override func expand() throws -> Form { 12 | let newForm = try _form.expand() 13 | if newForm != _form { return try SpliceForm(env: env, pos: pos, form: newForm).expand() } 14 | return self 15 | } 16 | 17 | open override func emit() throws { 18 | throw EmitError(pos, "Unquote outside of quoted context") 19 | } 20 | 21 | open override func quote1() throws -> Form { 22 | let skipPc = env.emit(STOP) 23 | _startPc = env.pc 24 | try _form.quote1().emit() 25 | env.emit(STOP) 26 | env.emit(Goto(pc: env.pc), pc: skipPc) 27 | return self 28 | } 29 | 30 | open override func quote2(depth: Int) throws -> Form { 31 | if depth == 1 { 32 | let prevCount = env._stack.count 33 | try env.eval(_startPc!) 34 | var fs: Forms = [] 35 | let n = env._stack.count-prevCount 36 | for _ in 0.. String { "[\(_items.dump())]" } 12 | 13 | open override func expand() throws -> Form { 14 | let newItems = try _items.map {it in try it.expand()} 15 | if newItems != _items { return try StackForm(env: env, pos: pos, items: newItems).expand() } 16 | return self 17 | } 18 | 19 | open override func emit() throws { 20 | env.emit(Push(pc: env.pc, env.coreLib!.stackType, Stack())) 21 | 22 | for it in _items { 23 | try it.emit() 24 | env.emit(PushDown(env: env, pos: pos, pc: env.pc)) 25 | } 26 | } 27 | 28 | open override func quote1() throws -> Form { 29 | for i in 0..<_items.count { _items[i] = try _items[i].quote1() } 30 | return self 31 | } 32 | 33 | open override func quote2(depth: Int) throws -> Form { 34 | for i in 0..<_items.count { _items[i] = try _items[i].quote2(depth: depth) } 35 | return self 36 | } 37 | 38 | private var _items: Forms 39 | } 40 | -------------------------------------------------------------------------------- /Sources/Swifties/libs/CoreLib.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class CoreLib: Lib { 4 | public let anyType, seqType, targetType: AnyType 5 | 6 | public let boolType: BoolType 7 | public let charType: CharType 8 | public let contType: ContType 9 | public let formType: FormType 10 | public let funcType: FuncType 11 | public let idType: IdType 12 | public let intType: IntType 13 | public let iterType: IterType 14 | public let macroType: MacroType 15 | public let metaType: MetaType 16 | public let multiType: MultiType 17 | public let pairType: PairType 18 | public let primType: PrimType 19 | public let registerType: RegisterType 20 | public let stackType: StackType 21 | public let stringType: StringType 22 | 23 | public override init(env: Env, pos: Pos) { 24 | anyType = AnyType(env, pos: pos, name: "Any", parentTypes: []) 25 | 26 | seqType = AnyType(env, pos: pos, name: "Seq", parentTypes: [anyType]) 27 | targetType = AnyType(env, pos: pos, name: "Target", parentTypes: [anyType]) 28 | 29 | boolType = BoolType(env, pos: pos, name: "Bool", parentTypes: [anyType]) 30 | charType = CharType(env, pos: pos, name: "Char", parentTypes: [anyType]) 31 | contType = ContType(env, pos: pos, name: "Cont", parentTypes: [anyType]) 32 | formType = FormType(env, pos: pos, name: "Form", parentTypes: [anyType]) 33 | funcType = FuncType(env, pos: pos, name: "Func", parentTypes: [anyType, targetType]) 34 | 35 | iterType = IterType(env, pos: pos, name: "Iter", parentTypes: [anyType, seqType]) 36 | 37 | intType = IntType(env, pos: pos, name: "Int", parentTypes: [anyType, seqType]) 38 | macroType = MacroType(env, pos: pos, name: "Meta", parentTypes: [anyType]) 39 | metaType = MetaType(env, pos: pos, name: "Meta", parentTypes: [anyType]) 40 | multiType = MultiType(env, pos: pos, name: "Multi", parentTypes: [anyType, targetType]) 41 | pairType = PairType(env, pos: pos, name: "Pair", parentTypes: [anyType]) 42 | primType = PrimType(env, pos: pos, name: "Prim", parentTypes: [anyType, targetType]) 43 | registerType = RegisterType(env, pos: pos, name: "Register", parentTypes: [anyType]) 44 | stackType = StackType(env, pos: pos, name: "Stack", parentTypes: [anyType, seqType]) 45 | 46 | stringType = StringType(env, pos: pos, name: "String", parentTypes: [anyType, seqType]) 47 | idType = IdType(env, pos: pos, name: "Id", parentTypes: [anyType, stringType]) 48 | 49 | super.init(env: env, pos: pos) 50 | } 51 | 52 | open func nop(pos: Pos, args: [Form]) {} 53 | 54 | open func equals(pos: Pos, self: Func, ret: Pc) throws -> Pc { 55 | let y = try env.pop(pos: pos) 56 | let x = try env.peek(pos: pos) 57 | try env.poke(pos: pos, env.coreLib!.boolType, (x.type == y.type) && x.type.equalValues!(x.value, y.value)) 58 | return ret 59 | } 60 | 61 | open func isZero(pos: Pos, self: Func, ret: Pc) throws -> Pc { 62 | try env.poke(pos: pos, env.coreLib!.boolType, env.peek(pos: pos).value as! Int == 0) 63 | return ret 64 | } 65 | 66 | open func isOne(pos: Pos, self: Func, ret: Pc) throws -> Pc { 67 | try env.poke(pos: pos, env.coreLib!.boolType, env.peek(pos: pos).value as! Int == 1) 68 | return ret 69 | } 70 | 71 | open func and(pos: Pos, args: [Form]) throws { 72 | try args[0].emit() 73 | let branchPc = env.emit(STOP) 74 | env.emit(Drop(env: env, pos: pos, pc: env.pc)) 75 | try args[1].emit() 76 | env.emit(Branch(env: env, pos: pos, truePc: branchPc+1, falsePc: env.pc, pop: false), pc: branchPc) 77 | } 78 | 79 | open func bench(pos: Pos, args: [Form]) throws { 80 | let reps = (args[0] as! LiteralForm).slot!.value as! Int 81 | let i = env.emit(STOP) 82 | let startPc = env.pc 83 | for f in args[1...] { try f.emit() } 84 | env.emit(Bench(env: env, reps: reps, startPc: startPc, endPc: env.pc), pc: i) 85 | } 86 | 87 | open func _do(pos: Pos, args: [Form]) throws { 88 | for a in args { try a.emit() } 89 | } 90 | 91 | open func _for(pos: Pos, args: [Form]) throws { 92 | var src = args[0] 93 | var bindId: String? 94 | var bindReg: Register = -1 95 | 96 | if src is PairForm { 97 | let p = src as! PairForm 98 | bindId = (p.left as! IdForm).name 99 | bindReg = try env.scope!.nextRegister(pos: pos, id: bindId!) 100 | src = p.right 101 | } 102 | 103 | try src.emit() 104 | let forPc = env.emit(STOP) 105 | if bindId != nil { env.emit(Store(env: env, pos: pos, pc: env.pc, index: bindReg)) } 106 | for a in args[1...] { try a.emit() } 107 | env.emit(STOP) 108 | env.emit(For(env: env, pos: pos, pc: forPc, nextPc: env.pc), pc: forPc) 109 | if bindId != nil { try env.scope!.unbind(pos: pos, bindId!) } 110 | } 111 | 112 | open func _func(pos: Pos, args: [Form]) throws { 113 | let name = (args[0] as! IdForm).name 114 | let fargs = try (args[1] as! StackForm).items.map({f in try Func.getArg(env: env, pos: pos, f)}) 115 | let frets = try (args[2] as! StackForm).items.map({f in try Func.getRet(env: env, pos: pos, f)}) 116 | let f = Func(env: env, pos: pos, name: name, args: fargs, rets: frets) 117 | 118 | if let exists = env.scope!.find(name) { 119 | switch exists.type { 120 | case env.coreLib!.multiType: 121 | let m = exists.value as! Multi 122 | m.addFunc(f) 123 | case env.coreLib!.funcType: 124 | let m = Multi(env: env, name: name) 125 | m.addFunc(exists.value as! Func) 126 | m.addFunc(f) 127 | try env.scope!.bind(pos: pos, id: name, env.coreLib!.multiType, m, force: true) 128 | default: 129 | throw EmitError(pos, "Invalid func binding: \(exists.type.name)") 130 | } 131 | } else { 132 | try env.scope!.bind(pos: pos, id: name, env.coreLib!.funcType, f) 133 | } 134 | 135 | try f.compileBody(DoForm(env: env, pos: pos, body: Array(args[3...]))) 136 | } 137 | 138 | open func _if(pos: Pos, args: [Form]) throws { 139 | let cond = args[0] 140 | try cond.emit() 141 | let trueBranch = args[1] 142 | let falseBranch = args[2] 143 | let branchPc = env.emit(STOP) 144 | try falseBranch.emit() 145 | let skipTrue = env.emit(STOP) 146 | let truePc = env.pc 147 | try trueBranch.emit() 148 | env.emit(Goto(pc: env.pc), pc: skipTrue) 149 | env.emit(Branch(env: env, pos: pos, truePc: truePc, falsePc: branchPc+1), pc: branchPc) 150 | } 151 | 152 | open func _let(pos: Pos, args: [Form]) throws { 153 | let bindings = Array((args[0] as! StackForm).items.reversed()) 154 | let scope = env.scope! 155 | var ids: [String] = [] 156 | var i = 0 157 | 158 | while i+1 < bindings.count { 159 | let (v, id) = (bindings[i], "$\((bindings[i+1] as! IdForm).name)") 160 | try v.emit() 161 | let register = try scope.nextRegister(pos: pos, id: id) 162 | env.emit(Store(env: env, pos: pos, pc: env.pc, index: register)) 163 | ids.append(id) 164 | i += 2 165 | } 166 | 167 | for a in args[1...] { try a.emit() } 168 | for id in ids { try scope.unbind(pos: pos, id) } 169 | } 170 | 171 | open func map(pos: Pos, self: Func, ret: Pc) throws -> Pc { 172 | let src = try env.pop(pos: pos) 173 | let fn = try env.pop(pos: pos) 174 | let it = src.type.iterValue!(src.value) 175 | 176 | env.push(env.coreLib!.iterType, { pos in 177 | if let v = try it(pos) { 178 | self.env.push(v) 179 | 180 | if try fn.type.callValue!(fn.value, pos, -1, true) != -1 { 181 | throw EvalError(pos, "Jump from iterator") 182 | } 183 | 184 | return try self.env.pop(pos: pos) 185 | } 186 | 187 | return nil 188 | }) 189 | 190 | return ret 191 | } 192 | 193 | open func not(pos: Pos, self: Func, ret: Pc) throws -> Pc { 194 | let s = try env.peek(pos: pos) 195 | try env.poke(pos: pos, env.coreLib!.boolType, !s.type.valueIsTrue(s.value)) 196 | return ret 197 | } 198 | 199 | open func or(pos: Pos, args: [Form]) throws { 200 | try args[0].emit() 201 | let branchPc = env.emit(STOP) 202 | env.emit(Drop(env: env, pos: pos, pc: env.pc)) 203 | try args[1].emit() 204 | env.emit(Branch(env: env, pos: pos, truePc: env.pc, falsePc: branchPc+1, pop: false), pc: branchPc) 205 | } 206 | 207 | open func quote(pos: Pos, args: [Form]) throws { 208 | env.emit(Quote(env: env, pc: env.pc, form: try args.first!.quote1())) 209 | } 210 | 211 | open func recall(pos: Pos, args: [Form]) throws { 212 | for a in args { try a.emit() } 213 | env.emit(Recall(env: env, pos: pos, check: true)) 214 | } 215 | 216 | open func reset(pos: Pos, args: [Form]) { 217 | env.emit(Reset(env: env, pc: env.pc)) 218 | } 219 | 220 | open func restore(pos: Pos, self: Func, ret: Pc) throws -> Pc { 221 | try (env.pop(pos: pos).value as! Cont).restore() 222 | } 223 | 224 | open func stash(pos: Pos, self: Func, ret: Pc) throws -> Pc { 225 | let tmp = env.stack 226 | env.reset() 227 | env.push(env.coreLib!.stackType, tmp) 228 | return ret 229 | } 230 | 231 | open func splat(pos: Pos, args: [Form]) throws { 232 | for a in args { 233 | try a.emit() 234 | env.emit(Splat(env: env, pos: pos, pc: env.pc)) 235 | } 236 | } 237 | 238 | open func suspend(pos: Pos, args: [Form]) throws { 239 | let suspendPc = env.emit(STOP) 240 | for a in args { try a.emit() } 241 | env.emit(STOP) 242 | env.emit(Suspend(env: env, pc: suspendPc, restorePc: env.pc), pc: suspendPc) 243 | } 244 | 245 | open override func bind(pos: Pos, _ names: [String]) throws { 246 | define(anyType, 247 | boolType, 248 | charType, contType, 249 | formType, funcType, 250 | idType, intType, iterType, 251 | macroType, metaType, multiType, 252 | pairType, primType, 253 | registerType, 254 | seqType, stackType, stringType, 255 | targetType) 256 | 257 | define("t", boolType, true) 258 | define("f", boolType, false) 259 | 260 | define(Prim(env: env, pos: self.pos, name: "_", (0, 0), self.nop)) 261 | define(Func(env: env, pos: self.pos, name: "=", args: [("lhs", anyType), ("rhs", anyType)], rets: [boolType], self.equals)) 262 | define(Func(env: env, pos: self.pos, name: "z?", args: [("val", intType)], rets: [boolType], self.isZero)) 263 | define(Func(env: env, pos: self.pos, name: "one?", args: [("val", intType)], rets: [boolType], self.isOne)) 264 | define(Prim(env: env, pos: self.pos, name: "and", (2, 2), self.and)) 265 | define(Prim(env: env, pos: self.pos, name: "bench", (1, -1), self.bench)) 266 | define(Prim(env: env, pos: self.pos, name: "do", (0, -1), self._do)) 267 | define(Prim(env: env, pos: self.pos, name: "for", (1, -1), self._for)) 268 | define(Prim(env: env, pos: self.pos, name: "func", (3, -1), self._func)) 269 | define(Prim(env: env, pos: self.pos, name: "if", (3, 3), self._if)) 270 | define(Prim(env: env, pos: self.pos, name: "let", (1, -1), self._let)) 271 | define(Func(env: env, pos: self.pos, name: "map", args: [("fn", targetType), ("src", seqType)], rets: [iterType], self.map)) 272 | define(Func(env: env, pos: self.pos, name: "not", args: [("val", anyType)], rets: [boolType], self.not)) 273 | define(Prim(env: env, pos: self.pos, name: "or", (2, 2), self.or)) 274 | define(Prim(env: env, pos: self.pos, name: "quote", (1, 1), self.quote)) 275 | define(Prim(env: env, pos: self.pos, name: "recall", (0, -1), self.recall)) 276 | define(Prim(env: env, pos: self.pos, name: "reset", (0, 0), self.reset)) 277 | define(Func(env: env, pos: self.pos, name: "restore", args: [("cont", contType)], rets: [], self.restore)) 278 | define(Prim(env: env, pos: self.pos, name: "splat", (1, -1), self.splat)) 279 | define(Func(env: env, pos: self.pos, name: "stash", args: [], rets: [stackType], self.stash)) 280 | define(Prim(env: env, pos: self.pos, name: "suspend", (-1, -1), self.suspend)) 281 | 282 | try super.bind(pos: pos, names) 283 | } 284 | } 285 | -------------------------------------------------------------------------------- /Sources/Swifties/libs/MathLib.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class MathLib: Lib { 4 | public override init(env: Env, pos: Pos) { super.init(env: env, pos: pos) } 5 | 6 | open func plusOne(pos: Pos, self: Func, ret: Pc) throws -> Pc { 7 | try env.poke(pos: pos, env.coreLib!.intType, (env.peek(pos: pos).value as! Int)+1, offset: 0) 8 | return ret 9 | } 10 | 11 | open func minusOne(pos: Pos, self: Func, ret: Pc) throws -> Pc { 12 | try env.poke(pos: pos, env.coreLib!.intType, (env.peek(pos: pos).value as! Int)-1, offset: 0) 13 | return ret 14 | } 15 | 16 | open func plusInt(pos: Pos, self: Func, ret: Pc) throws -> Pc { 17 | let y = try env.pop(pos: pos) 18 | let x = try env.peek(pos: pos) 19 | try env.poke(pos: pos, env.coreLib!.intType, (x.value as! Int) + (y.value as! Int), offset: 0) 20 | return ret 21 | } 22 | 23 | open func minusInt(pos: Pos, self: Func, ret: Pc) throws -> Pc { 24 | let y = try env.pop(pos: pos) 25 | let x = try env.peek(pos: pos) 26 | try env.poke(pos: pos, env.coreLib!.intType, (x.value as! Int) - (y.value as! Int), offset: 0) 27 | return ret 28 | } 29 | 30 | open func ltInt(pos: Pos, self: Func, ret: Pc) throws -> Pc { 31 | let y = try env.pop(pos: pos) 32 | let x = try env.peek(pos: pos) 33 | try env.poke(pos: pos, env.coreLib!.boolType, (x.value as! Int) < (y.value as! Int), offset: 0) 34 | return ret 35 | } 36 | 37 | open func gtInt(pos: Pos, self: Func, ret: Pc) throws -> Pc { 38 | let y = try env.pop(pos: pos) 39 | let x = try env.peek(pos: pos) 40 | try env.poke(pos: pos, env.coreLib!.boolType, (x.value as! Int) > (y.value as! Int), offset: 0) 41 | return ret 42 | } 43 | 44 | open override func bind(pos: Pos, _ names: [String]) throws { 45 | define(Func(env: env, pos: self.pos, name: "++", args: [("val", env.coreLib!.intType)], rets: [env.coreLib!.intType], self.plusOne)) 46 | define(Func(env: env, pos: self.pos, name: "--", args: [("val", env.coreLib!.intType)], rets: [env.coreLib!.intType], self.minusOne)) 47 | 48 | define(Func(env: env, pos: self.pos, name: "+", 49 | args: [("lhs", env.coreLib!.intType), ("rhs", env.coreLib!.intType)], 50 | rets: [env.coreLib!.intType], 51 | self.plusInt)) 52 | 53 | define(Func(env: env, pos: self.pos, name: "-", 54 | args: [("lhs", env.coreLib!.intType), ("rhs", env.coreLib!.intType)], 55 | rets: [env.coreLib!.intType], 56 | self.minusInt)) 57 | 58 | define(Func(env: env, pos: self.pos, name: "<", 59 | args: [("lhs", env.coreLib!.intType), ("rhs", env.coreLib!.intType)], 60 | rets: [env.coreLib!.boolType], 61 | self.ltInt)) 62 | 63 | define(Func(env: env, pos: self.pos, name: ">", 64 | args: [("lhs", env.coreLib!.intType), ("rhs", env.coreLib!.intType)], 65 | rets: [env.coreLib!.boolType], 66 | self.gtInt)) 67 | 68 | try super.bind(pos: pos, names) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Sources/Swifties/ops/Bench.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class Bench: Op { 4 | public init(env: Env, reps: Int, startPc: Pc, endPc: Pc) { 5 | _env = env 6 | _reps = reps 7 | _startPc = startPc 8 | _endPc = endPc 9 | } 10 | 11 | open func eval() throws -> Pc { 12 | let stack = _env._stack 13 | _env._stack = [] 14 | let t1 = DispatchTime.now() 15 | for _ in 0..<_reps { try _env.eval(_startPc) } 16 | let t2 = DispatchTime.now() 17 | _env._stack = stack 18 | _env.push(_env.coreLib!.intType, Int((t2.uptimeNanoseconds-t1.uptimeNanoseconds) / 1000000)) 19 | return _endPc 20 | } 21 | 22 | private let _env: Env 23 | private let _reps: Int 24 | private let _startPc, _endPc: Pc 25 | } 26 | -------------------------------------------------------------------------------- /Sources/Swifties/ops/Branch.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class Branch: Op { 4 | public init(env: Env, pos: Pos, truePc: Pc, falsePc: Pc, pop: Bool = true) { 5 | _env = env 6 | _pos = pos 7 | _truePc = truePc 8 | _falsePc = falsePc 9 | _pop = pop 10 | } 11 | 12 | open func eval() throws -> Pc { 13 | let v = _pop ? try _env.pop(pos: _pos) : try _env.peek(pos: _pos) 14 | return v.type.valueIsTrue(v.value) ? _truePc : _falsePc 15 | } 16 | 17 | private let _env: Env 18 | private let _pos: Pos 19 | private let _truePc, _falsePc: Pc 20 | private let _pop: Bool 21 | } 22 | -------------------------------------------------------------------------------- /Sources/Swifties/ops/Call.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class Call: Op { 4 | public init(env: Env, pos: Pos, pc: Pc, target: Slot?, check: Bool) { 5 | _env = env 6 | _pos = pos 7 | _pc = pc 8 | _target = target 9 | _check = check 10 | } 11 | 12 | open func eval() throws -> Pc { 13 | var t = _target 14 | if t == nil { t = try _env.pop(pos: _pos)} 15 | if t!.type.callValue == nil { throw EvalError(_pos, "Invalid target: \(t!)") } 16 | return try t!.type.callValue!(t!.value, _pos, _pc+1, _check) 17 | } 18 | 19 | private let _env: Env 20 | private let _pos: Pos 21 | private let _pc: Pc 22 | private let _target: Slot? 23 | private let _check: Bool 24 | } 25 | -------------------------------------------------------------------------------- /Sources/Swifties/ops/Copy.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class Copy: Op { 4 | public init(env: Env, pos: Pos, pc: Pc, count: Int = 1) { 5 | _env = env 6 | _pos = pos 7 | _pc = pc 8 | _count = count 9 | } 10 | 11 | open func eval() throws -> Pc { 12 | try _env.copy(pos: _pos, count: _count) 13 | return _pc+1 14 | } 15 | 16 | private let _env: Env 17 | private let _pos: Pos 18 | private let _pc: Pc 19 | private let _count: Int 20 | } 21 | -------------------------------------------------------------------------------- /Sources/Swifties/ops/Drop.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class Drop: Op { 4 | public init(env: Env, pos: Pos, pc: Pc, offset: Int = 0, count: Int = 1) { 5 | _env = env 6 | _pos = pos 7 | _pc = pc 8 | _offset = offset 9 | _count = count 10 | } 11 | 12 | open func eval() throws -> Pc { 13 | try _env.drop(pos: _pos, offset: _offset, count: _count) 14 | return _pc+1 15 | } 16 | 17 | private let _env: Env 18 | private let _pos: Pos 19 | private let _pc: Pc 20 | private let _offset, _count: Int 21 | } 22 | -------------------------------------------------------------------------------- /Sources/Swifties/ops/For.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class For: Op { 4 | public init(env: Env, pos: Pos, pc: Pc, nextPc: Pc) { 5 | _env = env 6 | _pos = pos 7 | _pc = pc 8 | _nextPc = nextPc 9 | } 10 | 11 | open func eval() throws -> Pc { 12 | let src = try _env.pop(pos: _pos) 13 | if src.type.iterValue == nil { throw EvalError(_pos, "Value is not iterable: \(src.type.name)")} 14 | let iter = src.type.iterValue!(src.value) 15 | 16 | while true { 17 | let v = try iter(_pos) 18 | if v == nil { break } 19 | _env.push(v!) 20 | try _env.eval(_pc+1) 21 | } 22 | 23 | return _nextPc 24 | } 25 | 26 | private let _env: Env 27 | private let _pos: Pos 28 | private let _pc, _nextPc: Pc 29 | } 30 | -------------------------------------------------------------------------------- /Sources/Swifties/ops/Goto.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class Goto: Op { 4 | public init(pc: Pc) { _pc = pc } 5 | 6 | open func eval() throws -> Pc { _pc } 7 | 8 | private let _pc: Pc 9 | } 10 | -------------------------------------------------------------------------------- /Sources/Swifties/ops/Load.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class Load: Op { 4 | public init(env: Env, pos: Pos, pc: Pc, index: Register) { 5 | _env = env 6 | _pos = pos 7 | _pc = pc 8 | _index = index 9 | } 10 | 11 | open func eval() throws -> Pc { 12 | try _env.load(pos: _pos, index: _index) 13 | return _pc+1 14 | } 15 | 16 | private let _env: Env 17 | private let _pos: Pos 18 | private let _pc: Pc 19 | private let _index: Register 20 | } 21 | -------------------------------------------------------------------------------- /Sources/Swifties/ops/Push.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class Push: Op { 4 | open var env: Env { _slot.type.env } 5 | 6 | public init(pc: Pc, _ slot: Slot) { 7 | _pc = pc 8 | _slot = slot 9 | } 10 | 11 | public convenience init(pc: Pc, _ type: Type, _ value: T) { self.init(pc: pc, Slot(type, value)) } 12 | 13 | open func eval() throws -> Pc { 14 | env.push(_slot) 15 | return _pc+1 16 | } 17 | 18 | private let _pc: Pc 19 | private let _slot: Slot 20 | } 21 | -------------------------------------------------------------------------------- /Sources/Swifties/ops/PushDown.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class PushDown: Op { 4 | public init(env: Env, pos: Pos, pc: Pc) { 5 | _env = env 6 | _pos = pos 7 | _pc = pc 8 | } 9 | 10 | open func eval() throws -> Pc { 11 | let v = try _env.pop(pos: _pos) 12 | let s = try _env.peek(pos: _pos) 13 | if s.type != _env.coreLib!.stackType { throw EvalError(_pos, "Invalid stack: \(s.type.name)") } 14 | var dst = s.value as! Stack 15 | dst.append(v) 16 | try _env.poke(pos: _pos, _env.coreLib!.stackType, dst, offset: 0) 17 | return _pc+1 18 | } 19 | 20 | private let _env: Env 21 | private let _pos: Pos 22 | private let _pc: Pc 23 | } 24 | -------------------------------------------------------------------------------- /Sources/Swifties/ops/Quote.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class Quote: Op { 4 | public init(env: Env, pc: Pc, form: Form) { 5 | _env = env 6 | _pc = pc 7 | _form = form 8 | } 9 | 10 | open func eval() throws -> Pc { 11 | _env.push(try _form.quote3(depth: 1)) 12 | return _pc+1 13 | } 14 | 15 | private let _env: Env 16 | private let _pc: Pc 17 | private let _form: Form 18 | } 19 | -------------------------------------------------------------------------------- /Sources/Swifties/ops/Recall.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class Recall: Op { 4 | public init(env: Env, pos: Pos, check: Bool) { 5 | _env = env 6 | _pos = pos 7 | _check = check 8 | } 9 | 10 | open func eval() throws -> Pc { 11 | let f = _env.peekFrame() 12 | if f == nil { throw EvalError(_pos, "No calls in progress") } 13 | return try f!.recall(pos: _pos, check: _check) 14 | } 15 | 16 | private let _env: Env 17 | private let _pos: Pos 18 | private let _check: Bool 19 | } 20 | -------------------------------------------------------------------------------- /Sources/Swifties/ops/Reset.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class Reset: Op { 4 | public init(env: Env, pc: Pc) { 5 | _env = env 6 | _pc = pc 7 | } 8 | 9 | open func eval() throws -> Pc { 10 | _env.reset() 11 | return _pc+1 12 | } 13 | 14 | private let _env: Env 15 | private let _pc: Pc 16 | } 17 | -------------------------------------------------------------------------------- /Sources/Swifties/ops/Restore.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class Restore: Op { 4 | public init(env: Env, pos: Pos) { 5 | _env = env 6 | _pos = pos 7 | } 8 | 9 | open func eval() throws -> Pc { 10 | let s = try _env.pop(pos: _pos) 11 | let c = s.value as! Cont 12 | return c.restore() 13 | } 14 | 15 | private let _env: Env 16 | private let _pos: Pos 17 | } 18 | -------------------------------------------------------------------------------- /Sources/Swifties/ops/Return.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class Return: Op { 4 | public init(env: Env, pos: Pos) { 5 | _env = env 6 | _pos = pos 7 | } 8 | 9 | open func eval() throws -> Pc { try _env.popFrame(pos: _pos) } 10 | 11 | private let _env: Env 12 | private let _pos: Pos 13 | } 14 | -------------------------------------------------------------------------------- /Sources/Swifties/ops/Splat.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class Splat: Op { 4 | public init(env: Env, pos: Pos, pc: Pc) { 5 | _env = env 6 | _pos = pos 7 | _pc = pc 8 | } 9 | 10 | open func eval() throws -> Pc { 11 | let s = try _env.pop(pos: _pos) 12 | if s.type.iterValue == nil { throw EvalError(_pos, "Not iterable: \(s.type.name)") } 13 | let it = s.type.iterValue!(s.value) 14 | while let v = try it(_pos) { _env.push(v) } 15 | return _pc+1 16 | } 17 | 18 | private let _env: Env 19 | private let _pos: Pos 20 | private let _pc: Pc 21 | } 22 | -------------------------------------------------------------------------------- /Sources/Swifties/ops/Stop.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public let STOP = Stop() 4 | 5 | open class Stop: Op { 6 | open func eval() -> Pc { STOP_PC } 7 | } 8 | -------------------------------------------------------------------------------- /Sources/Swifties/ops/Store.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class Store: Op { 4 | public init(env: Env, pos: Pos, pc: Pc, index: Register, offset: Int = 0) { 5 | _env = env 6 | _pos = pos 7 | _pc = pc 8 | _index = index 9 | _offset = offset 10 | } 11 | 12 | open func eval() throws -> Pc { 13 | try _env.store(pos: _pos, index: _index, offset: _offset) 14 | return _pc+1 15 | } 16 | 17 | private let _env: Env 18 | private let _pos: Pos 19 | private let _pc: Pc 20 | private let _index: Register 21 | private let _offset: Int 22 | } 23 | -------------------------------------------------------------------------------- /Sources/Swifties/ops/Suspend.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class Suspend: Op { 4 | public init(env: Env, pc: Pc, restorePc: Pc) { 5 | _env = env 6 | _pc = pc 7 | _restorePc = restorePc 8 | } 9 | 10 | open func prepare() {} 11 | 12 | open func eval() throws -> Pc { 13 | _env.push(_env.coreLib!.contType, _env.suspend(_restorePc)) 14 | return _pc+1 15 | } 16 | 17 | private let _env: Env 18 | private let _pc, _restorePc: Pc 19 | } 20 | -------------------------------------------------------------------------------- /Sources/Swifties/ops/Swap.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class Swap: Op { 4 | public init(env: Env, pos: Pos, pc: Pc, count: Int = 1) { 5 | _env = env 6 | _pos = pos 7 | _pc = pc 8 | _count = count 9 | } 10 | 11 | open func eval() throws -> Pc { 12 | try _env.swap(pos: _pos, count: _count) 13 | return _pc+1 14 | } 15 | 16 | private let _env: Env 17 | private let _pos: Pos 18 | private let _pc: Pc 19 | private let _count: Int 20 | } 21 | -------------------------------------------------------------------------------- /Sources/Swifties/ops/Zip.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class Zip: Op { 4 | public init(env: Env, pos: Pos, pc: Pc) { 5 | _env = env 6 | _pos = pos 7 | _pc = pc 8 | } 9 | 10 | open func eval() throws -> Pc { 11 | let l = try _env.pop(pos: _pos) 12 | let r = try _env.peek(pos: _pos) 13 | try _env.poke(pos: _pos, _env.coreLib!.pairType, (l, r)) 14 | return _pc+1 15 | } 16 | 17 | private let _env: Env 18 | private let _pos: Pos 19 | private let _pc: Pc 20 | } 21 | -------------------------------------------------------------------------------- /Sources/Swifties/readers/CallReader.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func callReader(_ p: Parser) throws -> Form? { 4 | let fpos = p.pos 5 | var c = p.getc() 6 | 7 | if c != "(" { 8 | if c != nil { p.ungetc(c!) } 9 | return nil 10 | } 11 | 12 | p.nextColumn() 13 | if !(try p.readForm()) { throw ReadError(p.pos, "Missing target") } 14 | var target = p.popForm()! 15 | var args: [Form] = [] 16 | 17 | c = p.getc() 18 | 19 | if c == "." { 20 | args.append(target) 21 | if !(try p.readForm()) { throw ReadError(p.pos, "Missing target") } 22 | target = p.popForm()! 23 | } else if c != nil { 24 | p.ungetc(c!) 25 | } 26 | 27 | while true { 28 | try spaceReader(p) 29 | c = p.getc() 30 | if c == nil || c == ")" { break } 31 | p.ungetc(c!) 32 | if !(try p.readForm()) { break } 33 | args.append(p.popForm()!) 34 | } 35 | 36 | if c != ")" { throw ReadError(p.pos, "Open call form: \((c == nil) ? "nil" : String(c!))") } 37 | p.nextColumn() 38 | 39 | return CallForm(env: p.env, pos: fpos, target: target, args: args) 40 | } 41 | -------------------------------------------------------------------------------- /Sources/Swifties/readers/CharReader.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func charReader(p: Parser) throws -> Form? { 4 | let fpos = p.pos 5 | var c = p.getc() 6 | 7 | if c != "\\" { 8 | if c != nil { p.ungetc(c!) } 9 | return nil 10 | } 11 | 12 | p.nextColumn() 13 | c = p.getc() 14 | if c == nil { throw ReadError(p.pos, "Invalid char literal") } 15 | p.nextColumn() 16 | return LiteralForm(env: p.env, pos: fpos, p.env.coreLib!.charType, c!) 17 | } 18 | -------------------------------------------------------------------------------- /Sources/Swifties/readers/IdReader.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | let ID_STOPS: Set = ["(", ")", "[", "]", ":", ".", "'", ","] 4 | 5 | public func idReader(p: Parser) -> Form? { 6 | let fpos = p.pos 7 | var out = "" 8 | 9 | while let c = p.getc() { 10 | if c.isWhitespace || ID_STOPS.contains(c) { 11 | p.ungetc(c) 12 | break 13 | } 14 | 15 | out.append(c) 16 | p.nextColumn() 17 | } 18 | 19 | return (out.count == 0) ? nil : IdForm(env: p.env, pos: fpos, name: out) 20 | } 21 | -------------------------------------------------------------------------------- /Sources/Swifties/readers/IntReader.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func intReader(_ p: Parser) throws -> Form? { 4 | let fpos = p.pos 5 | var v = 0 6 | var neg = false 7 | 8 | let c = p.getc() 9 | if c == nil { return nil } 10 | 11 | if c == "-" { 12 | if let c = p.getc() { 13 | if c.isNumber { 14 | neg = true 15 | } else { 16 | p.ungetc(c) 17 | p.ungetc("-") 18 | } 19 | } 20 | } else { 21 | p.ungetc(c!) 22 | } 23 | 24 | while let c = p.getc() { 25 | if !c.isNumber { 26 | p.ungetc(c) 27 | break 28 | } 29 | 30 | v *= 10 31 | v += c.hexDigitValue! 32 | p.nextColumn() 33 | } 34 | 35 | return (p.pos == fpos) ? nil : LiteralForm(env: p.env, pos: p.pos, p.env.coreLib!.intType, neg ? -v : v) 36 | } 37 | -------------------------------------------------------------------------------- /Sources/Swifties/readers/PairReader.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func pairReader(_ p: Parser) throws -> Form? { 4 | let c = p.getc() 5 | 6 | if c != ":" { 7 | if c != nil { p.ungetc(c!) } 8 | return nil 9 | } 10 | 11 | p.nextColumn() 12 | let left = p.popForm() 13 | if left == nil { throw ReadError(p.pos, "Missing left value"); } 14 | if !(try p.readForm()) { throw ReadError(p.pos, "Missing right value")} 15 | let right = p.popForm() 16 | 17 | return PairForm(env: p.env, pos: left!.pos, (left!, right!)) 18 | } 19 | -------------------------------------------------------------------------------- /Sources/Swifties/readers/QuoteReader.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func quoteReader(_ p: Parser) throws -> Form? { 4 | let fpos = p.pos 5 | 6 | if let c = p.getc() { 7 | if c == "'" { 8 | p.nextColumn() 9 | 10 | if try p.readForm() { 11 | if let f = p.popForm() { 12 | return QuoteForm(env: p.env, pos: fpos, form: f) 13 | } 14 | } 15 | } 16 | 17 | p.ungetc(c) 18 | } 19 | 20 | return nil 21 | } 22 | -------------------------------------------------------------------------------- /Sources/Swifties/readers/SpaceReader.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | @discardableResult 4 | public func spaceReader(_ p: Parser) throws -> Form? { 5 | while let c = p.getc() { 6 | if c.isNewline { 7 | p.newLine() 8 | } else if c.isWhitespace { 9 | p.nextColumn() 10 | } else { 11 | p.ungetc(c) 12 | break 13 | } 14 | } 15 | 16 | return nil 17 | } 18 | -------------------------------------------------------------------------------- /Sources/Swifties/readers/SpliceReader.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func spliceReader(_ p: Parser) throws -> Form? { 4 | let fpos = p.pos 5 | 6 | if let c = p.getc() { 7 | if c == "," { 8 | p.nextColumn() 9 | 10 | if try p.readForm() { 11 | if let f = p.popForm() { 12 | return SpliceForm(env: p.env, pos: fpos, form: f) 13 | } 14 | } 15 | } 16 | 17 | p.ungetc(c) 18 | } 19 | 20 | return nil 21 | } 22 | -------------------------------------------------------------------------------- /Sources/Swifties/readers/StackReader.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func stackReader(p: Parser) throws -> Form? { 4 | let fpos = p.pos 5 | var c = p.getc() 6 | 7 | if c != "[" { 8 | if c != nil { p.ungetc(c!) } 9 | return nil 10 | } 11 | 12 | p.nextColumn() 13 | var items: [Form] = [] 14 | 15 | while true { 16 | try spaceReader(p) 17 | c = p.getc() 18 | if c == nil || c == "]" { break } 19 | p.ungetc(c!) 20 | if !(try p.readForm()) { break } 21 | items.append(p.popForm()!) 22 | } 23 | 24 | if c != "]" { throw ReadError(p.pos, "Open stack form: \((c == nil) ? "nil" : String(c!))") } 25 | p.nextColumn() 26 | 27 | return StackForm(env: p.env, pos: fpos, items: items) 28 | } 29 | -------------------------------------------------------------------------------- /Sources/Swifties/readers/StringReader.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func stringReader(p: Parser) throws -> Form? { 4 | let fpos = p.pos 5 | var c = p.getc() 6 | 7 | if c != "\"" { 8 | if c != nil { p.ungetc(c!) } 9 | return nil 10 | } 11 | 12 | p.nextColumn() 13 | var chars: [Character] = [] 14 | 15 | while true { 16 | try spaceReader(p) 17 | c = p.getc() 18 | if c == nil || c == "\"" { break } 19 | chars.append(c!) 20 | } 21 | 22 | if c != "\"" { throw ReadError(p.pos, "Open string: \((c == nil) ? "nil" : String(c!))") } 23 | p.nextColumn() 24 | return LiteralForm(env: p.env, pos: fpos, p.env.coreLib!.stringType, String(chars)) 25 | } 26 | -------------------------------------------------------------------------------- /Sources/Swifties/types/AnyType.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class AnyType: Definition, Equatable { 4 | public typealias CallValue = (_ target: Any, _ pos: Pos, _ ret: Pc, _ check: Bool) throws -> Pc 5 | public typealias DumpValue = (_ value: Any) -> String 6 | public typealias EqualValues = (_ lhs: Any, _ rhs: Any) -> Bool 7 | public typealias IterValue = (_ value: Any) -> Iter 8 | public typealias ValueIsTrue = (_ value: Any) -> Bool 9 | 10 | public typealias ParentTypes = Set 11 | 12 | public static func == (lhs: AnyType, rhs: AnyType) -> Bool { 13 | return lhs === rhs 14 | } 15 | 16 | open var env: Env { _env } 17 | open var pos: Pos { _pos } 18 | open var id: TypeId { _id } 19 | open var name: String { _name } 20 | open var slot: Slot { Slot(_env.coreLib!.metaType, self) } 21 | 22 | open var callValue: CallValue? 23 | open var dumpValue: DumpValue? 24 | open var equalValues: EqualValues? 25 | open var iterValue: IterValue? 26 | open var valueIsTrue: ValueIsTrue 27 | 28 | public init(_ env: Env, pos: Pos, name: String, parentTypes: [AnyType]) { 29 | _env = env 30 | _pos = pos 31 | _id = env.nextTypeId() 32 | _name = name 33 | valueIsTrue = {_ in true} 34 | for pt in parentTypes { addParent(pt) } 35 | } 36 | 37 | open func addParent(_ parent: AnyType) { 38 | _parentTypes.insert(parent._id) 39 | for pid in parent._parentTypes { _parentTypes.insert(pid) } 40 | } 41 | 42 | open func isa(_ parent: AnyType) -> Bool { 43 | return parent == self || _parentTypes.contains(parent._id) 44 | } 45 | 46 | private let _env: Env 47 | private let _pos: Pos 48 | private let _id: TypeId 49 | private let _name: String 50 | private var _parentTypes: ParentTypes = [] 51 | } 52 | -------------------------------------------------------------------------------- /Sources/Swifties/types/BoolType.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class BoolType: Type { 4 | public override init(_ env: Env, pos: Pos, name: String, parentTypes: [AnyType]) { 5 | super.init(env, pos: pos, name: name, parentTypes: parentTypes) 6 | dumpValue = {v in (v as! Bool) ? "t" : "f"} 7 | equalValues = {lhs, rhs in lhs as! Bool == rhs as! Bool} 8 | valueIsTrue = {v in v as! Bool} 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Sources/Swifties/types/CharType.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class CharType: Type { 4 | public override init(_ env: Env, pos: Pos, name: String, parentTypes: [AnyType]) { 5 | super.init(env, pos: pos, name: name, parentTypes: parentTypes) 6 | 7 | dumpValue = {v in 8 | switch v as! Character { 9 | case " ": 10 | return "#\\s" 11 | case "\n": 12 | return "#\\n" 13 | case "\t": 14 | return "#\\t" 15 | default: 16 | return "#\(v as! Character)" 17 | } 18 | } 19 | 20 | equalValues = {lhs, rhs in lhs as! Character == rhs as! Character} 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Sources/Swifties/types/ContType.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class ContType: Type { 4 | public override init(_ env: Env, pos: Pos, name: String, parentTypes: [AnyType]) { 5 | super.init(env, pos: pos, name: name, parentTypes: parentTypes) 6 | dumpValue = {v in (v as! Cont).dump()} 7 | equalValues = {lhs, rhs in lhs as! Cont === rhs as! Cont} 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Sources/Swifties/types/FormType.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class FormType: Type
{ 4 | public override init(_ env: Env, pos: Pos, name: String, parentTypes: [AnyType]) { 5 | super.init(env, pos: pos, name: name, parentTypes: parentTypes) 6 | dumpValue = {v in "'\((v as! Form).dump())"} 7 | equalValues = {lhs, rhs in lhs as! Form === rhs as! Form} 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Sources/Swifties/types/FuncType.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class FuncType: Type { 4 | public override init(_ env: Env, pos: Pos, name: String, parentTypes: [AnyType]) { 5 | super.init(env, pos: pos, name: name, parentTypes: parentTypes) 6 | 7 | callValue = {target, pos, ret, check throws in 8 | let f = target as! Func 9 | 10 | if check && !f.isApplicable() { 11 | throw FuncNotApplicable(pos: pos, target: f, stack: self.env.stack) 12 | } 13 | 14 | return try f.call(pos: pos, ret: ret) 15 | } 16 | 17 | dumpValue = { v in (v as! Func).dump() } 18 | equalValues = {lhs, rhs in lhs as! Func === rhs as! Func} 19 | } 20 | } 21 | 22 | -------------------------------------------------------------------------------- /Sources/Swifties/types/IdType.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class IdType: StringType { 4 | public override init(_ env: Env, pos: Pos, name: String, parentTypes: [AnyType]) { 5 | super.init(env, pos: pos, name: name, parentTypes: parentTypes) 6 | dumpValue = {v in "'\(v as! String)"} 7 | valueIsTrue = {_ in true} 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Sources/Swifties/types/IntType.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class IntType: Type { 4 | public override init(_ env: Env, pos: Pos, name: String, parentTypes: [AnyType]) { 5 | super.init(env, pos: pos, name: name, parentTypes: parentTypes) 6 | dumpValue = {v in String(v as! Int)} 7 | 8 | equalValues = {lhs, rhs in lhs as! Int == rhs as! Int} 9 | 10 | iterValue = {v in 11 | let max = v as! Int 12 | var i = 0 13 | 14 | return { pos in 15 | if i < max { 16 | let out = Slot(env.coreLib!.intType, i) 17 | i += 1 18 | return out 19 | } 20 | 21 | return nil 22 | } 23 | } 24 | 25 | valueIsTrue = {v in (v as! Int) != 0} 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/Swifties/types/IterType.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class IterType: Type { 4 | public override init(_ env: Env, pos: Pos, name: String, parentTypes: [AnyType]) { 5 | super.init(env, pos: pos, name: name, parentTypes: parentTypes) 6 | dumpValue = {_ in "Iter"} 7 | iterValue = {v in v as! Iter} 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Sources/Swifties/types/MacroType.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class MacroType: Type { 4 | public override init(_ env: Env, pos: Pos, name: String, parentTypes: [AnyType]) { 5 | super.init(env, pos: pos, name: name, parentTypes: parentTypes) 6 | dumpValue = {v in (v as! Macro).dump()} 7 | equalValues = {lhs, rhs in lhs as! Macro === rhs as! Macro} 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Sources/Swifties/types/MetaType.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class MetaType: Type { 4 | public override init(_ env: Env, pos: Pos, name: String, parentTypes: [AnyType]) { 5 | super.init(env, pos: pos, name: name, parentTypes: parentTypes) 6 | dumpValue = {v in (v as! AnyType).name} 7 | equalValues = {lhs, rhs in lhs as! AnyType === rhs as! AnyType} 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Sources/Swifties/types/MultiType.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class MultiType: Type { 4 | public override init(_ env: Env, pos: Pos, name: String, parentTypes: [AnyType]) { 5 | super.init(env, pos: pos, name: name, parentTypes: parentTypes) 6 | callValue = {target, pos, ret, check throws in try (target as! Multi).call(pos: pos, ret: ret) } 7 | dumpValue = { v in (v as! Multi).dump() } 8 | equalValues = {lhs, rhs in lhs as! Multi === rhs as! Multi} 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Sources/Swifties/types/PairType.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public typealias Pair = (Slot, Slot) 4 | 5 | open class PairType: Type { 6 | public override init(_ env: Env, pos: Pos, name: String, parentTypes: [AnyType]) { 7 | super.init(env, pos: pos, name: name, parentTypes: parentTypes) 8 | 9 | dumpValue = {v in 10 | let p = v as! Pair 11 | return p.0.type.dumpValue!(p.0.value) + ":" + p.1.type.dumpValue!(p.1.value) 12 | } 13 | 14 | equalValues = {lhs, rhs in 15 | let (l, r) = (lhs as! Pair, rhs as! Pair) 16 | return l.0.type == r.0.type && 17 | l.1.type == r.1.type && 18 | l.0.type.equalValues!(l.0, r.0) && 19 | l.1.type.equalValues!(l.1, r.1) 20 | } 21 | 22 | valueIsTrue = {v in 23 | let p = v as! Pair 24 | return p.0.type.valueIsTrue(p.0) && p.1.type.valueIsTrue(p.1) 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/Swifties/types/PrimType.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class PrimType: Type { 4 | public override init(_ env: Env, pos: Pos, name: String, parentTypes: [AnyType]) { 5 | super.init(env, pos: pos, name: name, parentTypes: parentTypes) 6 | dumpValue = {v in (v as! Macro).dump()} 7 | equalValues = {lhs, rhs in lhs as! Prim === rhs as! Prim} 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Sources/Swifties/types/RegisterType.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class RegisterType: Type { 4 | public override init(_ env: Env, pos: Pos, name: String, parentTypes: [AnyType]) { 5 | super.init(env, pos: pos, name: name, parentTypes: parentTypes) 6 | dumpValue = {v in "Register\(v as! Register)"} 7 | equalValues = {lhs, rhs in lhs as! Register == rhs as! Register} 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Sources/Swifties/types/StackType.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class StackType: Type { 4 | public override init(_ env: Env, pos: Pos, name: String, parentTypes: [AnyType]) { 5 | super.init(env, pos: pos, name: name, parentTypes: parentTypes) 6 | dumpValue = {v in (v as! Stack).dump()} 7 | equalValues = {lhs, rhs in lhs as! Stack == rhs as! Stack} 8 | 9 | iterValue = {v in 10 | var s = (v as! Stack).makeIterator() 11 | 12 | return { pos in 13 | if let v = s.next() { return v } 14 | return nil 15 | } 16 | } 17 | 18 | valueIsTrue = {v in (v as! Stack).count > 0} 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Sources/Swifties/types/StringType.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class StringType: Type { 4 | public override init(_ env: Env, pos: Pos, name: String, parentTypes: [AnyType]) { 5 | super.init(env, pos: pos, name: name, parentTypes: parentTypes) 6 | dumpValue = {v in "\"\(v as! String)\""} 7 | 8 | equalValues = {lhs, rhs in lhs as! String == rhs as! String} 9 | 10 | iterValue = {v in 11 | var s = (v as! String).makeIterator() 12 | 13 | return { pos in 14 | if let c = s.next() { return Slot(env.coreLib!.charType, c) } 15 | return nil 16 | } 17 | } 18 | 19 | valueIsTrue = {v in (v as! String).count > 0} 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Tests/LinuxMain.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | import swifuTests 4 | 5 | var tests = [XCTestCaseEntry]() 6 | tests += swifuTests.allTests() 7 | XCTMain(tests) 8 | -------------------------------------------------------------------------------- /Tests/SwiftiesTests/Tests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import Swifties 3 | 4 | final class Tests: XCTestCase { 5 | func testPush() throws { 6 | let p = Pos("testPush") 7 | let env = Env() 8 | 9 | try env.initCoreLib(pos: p) 10 | XCTAssertEqual("Int", env.coreLib!.intType.name) 11 | 12 | let v = Slot(env.coreLib!.intType, 42) 13 | env.emit(Push(pc: env.pc, v)) 14 | env.emit(STOP) 15 | try env.eval(0) 16 | XCTAssertEqual(v, try env.pop(pos: p)) 17 | } 18 | 19 | func testStaticBinding() throws { 20 | let p = Pos("testStaticBinding") 21 | let env = Env() 22 | try env.initCoreLib(pos: p) 23 | let v = Slot(env.coreLib!.intType, 42) 24 | try env.begin().bind(pos: p, id: "foo", v) 25 | try IdForm(env: env, pos: p, name: "foo").emit() 26 | env.emit(STOP) 27 | try env.eval(0) 28 | XCTAssertEqual(v, try env.pop(pos: p)) 29 | } 30 | 31 | func testDynamicBinding() throws { 32 | let pos = Pos("testDynamicBinding") 33 | let env = Env() 34 | try env.initCoreLib(pos: pos) 35 | let scope = env.begin() 36 | let v = Slot(env.coreLib!.intType, 42) 37 | let i = try scope.nextRegister(pos: pos, id: "foo") 38 | env.emit(Push(pc: env.pc, v)) 39 | env.emit(Store(env: env, pos: pos, pc: env.pc, index: i)) 40 | env.emit(Load(env: env, pos: pos, pc: env.pc, index: i)) 41 | env.emit(STOP) 42 | env.end() 43 | try env.eval(0) 44 | XCTAssertEqual(v, try env.pop(pos: pos)) 45 | } 46 | 47 | func testFunc() throws { 48 | let p = Pos("testFunc") 49 | let env = Env() 50 | try env.initCoreLib(pos: p) 51 | env.begin() 52 | 53 | let f = Func(env: env, pos: p, name: "foo", args: [(nil, env.coreLib!.intType)], rets: [env.coreLib!.intType], 54 | {(pos, self, ret) in 55 | env.push(env.coreLib!.intType, try env.pop(pos: p).value as! Int + 7) 56 | return ret 57 | }) 58 | 59 | env.emit(Push(pc: env.pc, env.coreLib!.intType, 35)) 60 | env.emit(Call(env: env, pos: p, pc: env.pc, target: Slot(env.coreLib!.funcType, f), check: true)) 61 | env.emit(STOP) 62 | try env.eval(0) 63 | XCTAssertEqual(Slot(env.coreLib!.intType, 42), try env.pop(pos: p)) 64 | } 65 | 66 | func testCompileFunc() throws { 67 | let p = Pos("testCompileFunc") 68 | let env = Env() 69 | try env.initCoreLib(pos: p) 70 | env.begin() 71 | 72 | let f = Func(env: env, pos: p, name: "foo", args: [("bar", env.coreLib!.intType)], rets: [env.coreLib!.intType]) 73 | try f.compileBody(IdForm(env: env, pos: p, name: "$bar")) 74 | 75 | env.push(env.coreLib!.intType, 42) 76 | env.emit(Call(env: env, pos: p, pc: env.pc, target: Slot(env.coreLib!.funcType, f), check: true)) 77 | env.emit(STOP) 78 | try env.eval(0) 79 | 80 | XCTAssertEqual(Slot(env.coreLib!.intType, 42), try env.pop(pos: p)) 81 | XCTAssertEqual(nil, env.tryPeek()) 82 | } 83 | 84 | func testMulti() throws { 85 | let p = Pos("testMulti") 86 | let env = Env() 87 | try env.initCoreLib(pos: p) 88 | env.begin() 89 | 90 | let f1 = Func(env: env, pos: p, name: "foo", args: [(nil, env.coreLib!.anyType)], rets: [], 91 | {(pos, self, ret) in 92 | try env.pop(pos: pos) 93 | return ret 94 | }) 95 | 96 | let f2 = Func(env: env, pos: p, name: "foo", args: [(nil, env.coreLib!.intType)], rets: [], 97 | {(pos, self, ret) in 98 | return ret 99 | }) 100 | 101 | let m = Multi(env: env, name: "foo") 102 | m.addFunc(f1) 103 | m.addFunc(f2) 104 | 105 | env.emit(Push(pc: env.pc, env.coreLib!.intType, 42)) 106 | env.emit(Call(env: env, pos: p, pc: env.pc, target: Slot(env.coreLib!.multiType, m), check: true)) 107 | env.emit(STOP) 108 | try env.eval(0) 109 | XCTAssertEqual(Slot(env.coreLib!.intType, 42), try env.pop(pos: p)) 110 | } 111 | 112 | func testIf() throws { 113 | let pos = Pos("testIf") 114 | let env = Env() 115 | env.begin() 116 | try env.initCoreLib(pos: pos).bind(pos: pos) 117 | 118 | try CallForm(env: env, pos: pos, target: IdForm(env: env, pos: pos, name: "if"), args: [ 119 | IdForm(env: env, pos: pos, name: "t"), 120 | LiteralForm(env: env, pos: pos, env.coreLib!.intType, 1), 121 | LiteralForm(env: env, pos: pos, env.coreLib!.intType, 2) 122 | ]).emit() 123 | 124 | env.emit(STOP) 125 | env.push(env.coreLib!.intType, 42) 126 | try env.eval(0) 127 | XCTAssertEqual(Slot(env.coreLib!.intType, 1), try env.pop(pos: pos)) 128 | XCTAssertEqual(Slot(env.coreLib!.intType, 42), try env.pop(pos: pos)) 129 | XCTAssertEqual(nil, env.tryPeek()) 130 | } 131 | 132 | func testMap() throws { 133 | let pos = Pos("testMap") 134 | let env = Env() 135 | env.begin() 136 | try env.initCoreLib(pos: pos).bind(pos: pos) 137 | let m = MathLib(env: env, pos: pos) 138 | try m.bind(pos: pos) 139 | env.push(env.scope!.find("++")!) 140 | env.push(env.coreLib!.stackType, [Slot(env.coreLib!.intType, 1), Slot(env.coreLib!.intType, 2), Slot(env.coreLib!.intType, 3)]) 141 | let map = env.scope!.find("map") 142 | XCTAssertEqual(-1, try map!.type.callValue!(map!.value, pos, -1, true)) 143 | let out = try env.pop(pos: pos) 144 | let it = out.value as! Iter 145 | XCTAssertEqual(Slot(env.coreLib!.intType, 2), try it(pos)) 146 | XCTAssertEqual(Slot(env.coreLib!.intType, 3), try it(pos)) 147 | XCTAssertEqual(Slot(env.coreLib!.intType, 4), try it(pos)) 148 | } 149 | 150 | func testRef() throws { 151 | let pos = Pos("testRef") 152 | let env = Env() 153 | env.begin() 154 | try env.initCoreLib(pos: pos).bind(pos: pos) 155 | 156 | try IdForm(env: env, pos: pos, name: "&stash").emit() 157 | env.emit(STOP) 158 | try env.eval(0) 159 | 160 | let f = try env.pop(pos: pos).value as! Func 161 | XCTAssertEqual("stash", f.name) 162 | XCTAssertEqual(nil, env.tryPeek()) 163 | } 164 | 165 | func testQuote() throws { 166 | let pos = Pos("testQuote") 167 | let env = Env() 168 | try env.initCoreLib(pos: pos) 169 | env.begin() 170 | try env.scope!.bind(pos: pos, id: "foo", env.coreLib!.intType, 42) 171 | 172 | let f = QuoteForm(env: env, pos: pos, form: StackForm(env: env, pos: pos, items: [SpliceForm(env: env, pos: pos, form: IdForm(env: env, pos: pos, name: "foo"))])) 173 | 174 | try f.emit() 175 | env.emit(STOP) 176 | try env.eval(0) 177 | 178 | let s = try env.pop(pos: pos).value as! StackForm 179 | let v = s.items[0] as! LiteralForm 180 | XCTAssertEqual(Slot(env.coreLib!.intType, 42), v.slot) 181 | XCTAssertEqual(nil, env.tryPeek()) 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /Tests/SwiftiesTests/XCTestManifests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | #if !canImport(ObjectiveC) 4 | open func allTests() -> [XCTestCaseEntry] { 5 | return [ 6 | testCase(swifuTests.allTests), 7 | ] 8 | } 9 | #endif 10 | --------------------------------------------------------------------------------