├── .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