Skip to content

Commit 8186fd1

Browse files
committed
Support native objects. Refactor definition of custom == operators.
1 parent 270e83a commit 8186fd1

13 files changed

+151
-101
lines changed

Sources/LispKit/Base/Reference.swift

+8-5
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,12 @@ open class Reference: Hashable {
3535
public final var hashValue: Int {
3636
return ObjectIdentifier(self).hashValue
3737
}
38-
}
39-
40-
/// Equality based on the identity of references
41-
public func ==(lhs: Reference, rhs: Reference) -> Bool {
42-
return lhs === rhs
38+
39+
open var typeDescription: String {
40+
return "reference"
41+
}
42+
43+
public static func ==(lhs: Reference, rhs: Reference) -> Bool {
44+
return lhs === rhs
45+
}
4346
}

Sources/LispKit/Compiler/Checkpointer.swift

+16-17
Original file line numberDiff line numberDiff line change
@@ -139,22 +139,21 @@ public enum CheckpointData: Hashable, CustomStringConvertible {
139139
return "Expansion(\(expr.description))"
140140
}
141141
}
142-
}
143-
144-
public func ==(left: CheckpointData, right: CheckpointData) -> Bool {
145-
switch (left, right) {
146-
case (.systemDefined, .systemDefined):
147-
return true
148-
case (.imported, .imported):
149-
return true
150-
case (.fromGlobalEnv(let lexpr), .fromGlobalEnv(let rexpr)):
151-
return eqExpr(rexpr, lexpr)
152-
case (.valueBinding(let lsym), .valueBinding(let rsym)):
153-
return lsym == rsym
154-
case (.expansion(let lexpr), .expansion(let rexpr)):
155-
return lexpr == rexpr
156-
default:
157-
return false
142+
143+
public static func ==(left: CheckpointData, right: CheckpointData) -> Bool {
144+
switch (left, right) {
145+
case (.systemDefined, .systemDefined):
146+
return true
147+
case (.imported, .imported):
148+
return true
149+
case (.fromGlobalEnv(let lexpr), .fromGlobalEnv(let rexpr)):
150+
return eqExpr(rexpr, lexpr)
151+
case (.valueBinding(let lsym), .valueBinding(let rsym)):
152+
return lsym == rsym
153+
case (.expansion(let lexpr), .expansion(let rexpr)):
154+
return lexpr == rexpr
155+
default:
156+
return false
157+
}
158158
}
159159
}
160-

Sources/LispKit/Compiler/Compiler.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import NumberKit
2929
public final class Compiler {
3030

3131
/// Context in which this compiler is running
32-
public let context: Context
32+
public unowned let context: Context
3333

3434
/// Environment in which expressions should be compiled
3535
internal var env: Env
@@ -391,7 +391,7 @@ public final class Compiler {
391391
self.emit(.pushChar(char))
392392
case .symbol(_), .string(_), .bytes(_), .pair(_, _), .box(_), .mpair(_),
393393
.vector(_), .record(_), .table(_), .promise(_), .procedure(_), .env(_),
394-
.port(_), .tagged(_, _), .error(_):
394+
.port(_), .object(_), .tagged(_, _), .error(_):
395395
self.pushConstant(expr)
396396
case .special(_):
397397
throw RuntimeError.eval(.illegalKeywordUsage, expr)

Sources/LispKit/Compiler/Env.swift

+30-28
Original file line numberDiff line numberDiff line change
@@ -182,21 +182,22 @@ public enum Env: CustomStringConvertible, Equatable {
182182
return "local " + group.identityString
183183
}
184184
}
185-
}
186-
187-
/// Compares two env objects. Two weak environments are the same if they have the same
188-
/// type (i.e. same enumeration case) and for local environments, the bindings groups are
189-
/// identical (same object).
190-
public func ==(lhs: Env, rhs: Env) -> Bool {
191-
switch (lhs, rhs) {
192-
case (.expired, .expired):
193-
return true
194-
case (.global(let env1), .global(let env2)):
195-
return env1 === env2
196-
case (.local(let group1), .local(let group2)):
197-
return group1 === group2
198-
default:
199-
return false
185+
186+
187+
/// Compares two env objects. Two weak environments are the same if they have the same
188+
/// type (i.e. same enumeration case) and for local environments, the bindings groups are
189+
/// identical (same object).
190+
public static func ==(lhs: Env, rhs: Env) -> Bool {
191+
switch (lhs, rhs) {
192+
case (.expired, .expired):
193+
return true
194+
case (.global(let env1), .global(let env2)):
195+
return env1 === env2
196+
case (.local(let group1), .local(let group2)):
197+
return group1 === group2
198+
default:
199+
return false
200+
}
200201
}
201202
}
202203

@@ -227,18 +228,19 @@ public enum WeakEnv: Hashable {
227228
return ObjectIdentifier(box).hashValue
228229
}
229230
}
230-
}
231-
232-
/// Compares two weak environments. Two weak environments are the same if they have the same
233-
/// type (i.e. same enumeration case) and for local environments, the bindings groups are
234-
/// identical (same object).
235-
public func ==(lhs: WeakEnv, rhs: WeakEnv) -> Bool {
236-
switch (lhs, rhs) {
237-
case (.global(let lbox), .global(let rbox)):
238-
return lbox === rbox
239-
case (.local(let lbox), .local(let rbox)):
240-
return lbox === rbox
241-
default:
242-
return false
231+
232+
233+
/// Compares two weak environments. Two weak environments are the same if they have the same
234+
/// type (i.e. same enumeration case) and for local environments, the bindings groups are
235+
/// identical (same object).
236+
public static func ==(lhs: WeakEnv, rhs: WeakEnv) -> Bool {
237+
switch (lhs, rhs) {
238+
case (.global(let lbox), .global(let rbox)):
239+
return lbox === rbox
240+
case (.local(let lbox), .local(let rbox)):
241+
return lbox === rbox
242+
default:
243+
return false
244+
}
243245
}
244246
}

Sources/LispKit/Data/Equality.swift

+11-5
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,11 @@ struct Equality: Hashable {
3636
var hashValue: Int {
3737
return ref1.hashValue &+ ref2.hashValue
3838
}
39-
}
40-
41-
func ==(lhs: Equality, rhs: Equality) -> Bool {
42-
return lhs.ref1 == rhs.ref1 && lhs.ref2 == rhs.ref2 ||
43-
lhs.ref1 == rhs.ref2 && lhs.ref2 == rhs.ref1
39+
40+
static func ==(lhs: Equality, rhs: Equality) -> Bool {
41+
return lhs.ref1 == rhs.ref1 && lhs.ref2 == rhs.ref2 ||
42+
lhs.ref1 == rhs.ref2 && lhs.ref2 == rhs.ref1
43+
}
4444
}
4545

4646
public func equalExpr(_ this: Expr, _ that: Expr) -> Bool {
@@ -192,6 +192,8 @@ public func equalExpr(_ this: Expr, _ that: Expr) -> Bool {
192192
return e1 == e2
193193
case (.port(let p1), .port(let p2)):
194194
return p1 == p2
195+
case (.object(let o1), .object(let o2)):
196+
return o1 == o2
195197
case (.tagged(let t1, let e1), .tagged(let t2, let e2)):
196198
return eqvExpr(t1, t2) && equals(e1, e2)
197199
case (.error(let e1), .error(let e2)):
@@ -264,6 +266,8 @@ public func eqvExpr(_ lhs: Expr, _ rhs: Expr) -> Bool {
264266
return e1 === e2
265267
case (.port(let p1), .port(let p2)):
266268
return p1 === p2
269+
case (.object(let o1), .object(let o2)):
270+
return o1 === o2
267271
case (.tagged(let t1, let e1), .tagged(let t2, let e2)):
268272
return eqvExpr(t1, t2) && eqvExpr(e1, e2)
269273
case (.error(let e1), .error(let e2)):
@@ -333,6 +337,8 @@ public func eqExpr(_ lhs: Expr, _ rhs: Expr) -> Bool {
333337
return e1 === e2
334338
case (.port(let p1), .port(let p2)):
335339
return p1 === p2
340+
case (.object(let o1), .object(let o2)):
341+
return o1 === o2
336342
case (.tagged(let t1, let e1), .tagged(let t2, let e2)):
337343
return eqvExpr(t1, t2) && eqExpr(e1, e2)
338344
case (.error(let e1), .error(let e2)):

Sources/LispKit/Data/Expr.swift

+18-8
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ public enum Expr: Trackable, Hashable {
5353
case special(SpecialForm)
5454
case env(Environment)
5555
case port(Port)
56+
case object(Reference)
5657
indirect case tagged(Expr, Expr)
5758
case error(RuntimeError)
5859
indirect case syntax(SourcePosition, Expr)
@@ -114,8 +115,10 @@ public enum Expr: Trackable, Hashable {
114115
return .envType
115116
case .port(_):
116117
return .portType
118+
case .object(_):
119+
return .objectType
117120
case .tagged(_, _):
118-
return .taggedType
121+
return .taggedType
119122
case .error(_):
120123
return .errorType
121124
case .syntax(_, _):
@@ -292,7 +295,7 @@ public enum Expr: Trackable, Hashable {
292295
switch self {
293296
case .undef, .void, .eof, .null, .true, .false, .uninit(_), .symbol(_),
294297
.fixnum(_), .bignum(_), .rational(_, _), .flonum(_), .complex(_),
295-
.char(_), .string(_), .bytes(_), .env(_), .port(_):
298+
.char(_), .string(_), .bytes(_), .env(_), .port(_), .object(_):
296299
return true
297300
default:
298301
return false
@@ -633,6 +636,13 @@ extension Expr {
633636
}
634637
return port
635638
}
639+
640+
@inline(__always) public func asObject() throws -> Reference {
641+
guard case .object(let obj) = self else {
642+
throw RuntimeError.type(self, expected: [.objectType])
643+
}
644+
return obj
645+
}
636646
}
637647

638648

@@ -901,6 +911,8 @@ extension Expr: CustomStringConvertible {
901911
return builder.description
902912
case .port(let port):
903913
return "#<\(port.typeDescription) \(port.identDescription)>"
914+
case .object(let obj):
915+
return "#<\(obj.typeDescription) \(obj.identityString)>"
904916
case .tagged(.mpair(let tuple), let expr):
905917
return "#\(stringReprOf(tuple.fst)):\(stringReprOf(expr))"
906918
case .tagged(let tag, let expr):
@@ -934,13 +946,11 @@ extension Expr: CustomStringConvertible {
934946
}
935947
return res
936948
}
937-
}
938-
939-
public func ==(lhs: Expr, rhs: Expr) -> Bool {
940-
return equalExpr(rhs, lhs)
949+
950+
public static func ==(lhs: Expr, rhs: Expr) -> Bool {
951+
return equalExpr(rhs, lhs)
952+
}
941953
}
942954

943955
public typealias ByteVector = MutableBox<[UInt8]>
944-
public typealias FixedRational = ImmutableBox<Rational<Int64>>
945-
public typealias BigRational = ImmutableBox<Rational<BigInt>>
946956
public typealias DoubleComplex = ImmutableBox<Complex<Double>>

Sources/LispKit/Data/Hash.swift

+16-10
Original file line numberDiff line numberDiff line change
@@ -135,12 +135,14 @@ public func equalHash(_ expr: Expr) -> Int {
135135
return environment.hashValue &* 31 &+ 26
136136
case .port(let port):
137137
return port.hashValue &* 31 &+ 27
138+
case .object(let obj):
139+
return obj.hashValue &* 31 &+ 28
138140
case .tagged(let tag, let expr):
139-
return (eqvHash(tag) &* 31 &+ hash(expr)) &* 31 &+ 28
141+
return (eqvHash(tag) &* 31 &+ hash(expr)) &* 31 &+ 29
140142
case .error(let err):
141-
return err.hashValue &* 31 &+ 29
143+
return err.hashValue &* 31 &+ 30
142144
case .syntax(let pos, let expr):
143-
return ((pos.hashValue &* 31) &+ hash(expr)) &* 31 &+ 30
145+
return ((pos.hashValue &* 31) &+ hash(expr)) &* 31 &+ 31
144146
}
145147
}
146148

@@ -204,12 +206,14 @@ public func eqvHash(_ expr: Expr) -> Int {
204206
return environment.hashValue &* 31 &+ 26
205207
case .port(let port):
206208
return port.hashValue &* 31 &+ 27
209+
case .object(let obj):
210+
return obj.hashValue &* 31 &+ 28
207211
case .tagged(let tag, let expr):
208-
return (eqvHash(tag) &* 31 &+ eqvHash(expr)) &* 31 &+ 28
212+
return (eqvHash(tag) &* 31 &+ eqvHash(expr)) &* 31 &+ 29
209213
case .error(let err):
210-
return err.hashValue &* 31 &+ 29
214+
return err.hashValue &* 31 &+ 30
211215
case .syntax(let pos, let expr):
212-
return ((pos.hashValue &* 31) &+ eqvHash(expr)) &* 31 &+ 30
216+
return ((pos.hashValue &* 31) &+ eqvHash(expr)) &* 31 &+ 31
213217
}
214218
}
215219

@@ -235,7 +239,7 @@ public func eqHash(_ expr: Expr) -> Int {
235239
case .bignum(let num):
236240
return num.hashValue &* 31 &+ 8
237241
case .rational(let n, let d):
238-
return ((eqHash(n) &* 31) &+ eqHash(d)) &* 31 + 9
242+
return ((eqHash(n) &* 31) &+ eqHash(d)) &* 31 &+ 9
239243
case .flonum(let num):
240244
return num.hashValue &* 31 &+ 11
241245
case .complex(let num):
@@ -270,11 +274,13 @@ public func eqHash(_ expr: Expr) -> Int {
270274
return environment.hashValue &* 31 &+ 26
271275
case .port(let port):
272276
return port.hashValue &* 31 &+ 27
277+
case .object(let obj):
278+
return obj.hashValue &* 31 &+ 28
273279
case .tagged(let tag, let expr):
274-
return (eqvHash(tag) &* 31 &+ eqHash(expr)) &* 31 &+ 28
280+
return (eqvHash(tag) &* 31 &+ eqHash(expr)) &* 31 &+ 29
275281
case .error(let err):
276-
return err.hashValue &* 31 &+ 29
282+
return err.hashValue &* 31 &+ 30
277283
case .syntax(let pos, let expr):
278-
return ((pos.hashValue &* 31) &+ eqHash(expr)) &* 31 &+ 30
284+
return ((pos.hashValue &* 31) &+ eqHash(expr)) &* 31 &+ 31
279285
}
280286
}

Sources/LispKit/Data/Port.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ open class Port: Reference, CustomStringConvertible {
115115
}
116116
}
117117

118-
open var typeDescription: String {
118+
override open var typeDescription: String {
119119
return (self.isTextualPort ? "text-" : "binary-") +
120120
(self.isInputPort ? "input-port" : "output-port")
121121
}

Sources/LispKit/Data/Type.swift

+3
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ public enum Type: Int, CustomStringConvertible {
5353
case specialType
5454
case envType
5555
case portType
56+
case objectType
5657
case numberType
5758
case exactNumberType
5859
case listType
@@ -125,6 +126,8 @@ public enum Type: Int, CustomStringConvertible {
125126
return "environment"
126127
case .portType:
127128
return "port"
129+
case .objectType:
130+
return "object"
128131
case .numberType:
129132
return "number"
130133
case .exactNumberType:

Sources/LispKit/Runtime/ImportSet.swift

+16-17
Original file line numberDiff line numberDiff line change
@@ -184,22 +184,21 @@ public indirect enum ImportSet: Equatable, CustomStringConvertible {
184184
return "(rename \(map) from \(importSet))"
185185
}
186186
}
187-
}
188-
189-
public func ==(_ left: ImportSet, _ right: ImportSet) -> Bool {
190-
switch (left, right) {
191-
case (.library(let e1), .library(let e2)):
192-
return e1 == e2
193-
case (.only(let s1, let is1), .only(let s2, let is2)):
194-
return s1 == s2 && is1 == is2
195-
case (.except(let s1, let is1), .except(let s2, let is2)):
196-
return s1 == s2 && is1 == is2
197-
case (.prefix(let s1, let is1), .prefix(let s2, let is2)):
198-
return s1 == s2 && is1 == is2
199-
case (.rename(let m1, let is1), .rename(let m2, let is2)):
200-
return m1 == m2 && is1 == is2
201-
default:
202-
return false
187+
188+
public static func ==(_ left: ImportSet, _ right: ImportSet) -> Bool {
189+
switch (left, right) {
190+
case (.library(let e1), .library(let e2)):
191+
return e1 == e2
192+
case (.only(let s1, let is1), .only(let s2, let is2)):
193+
return s1 == s2 && is1 == is2
194+
case (.except(let s1, let is1), .except(let s2, let is2)):
195+
return s1 == s2 && is1 == is2
196+
case (.prefix(let s1, let is1), .prefix(let s2, let is2)):
197+
return s1 == s2 && is1 == is2
198+
case (.rename(let m1, let is1), .rename(let m2, let is2)):
199+
return m1 == m2 && is1 == is2
200+
default:
201+
return false
202+
}
203203
}
204204
}
205-

0 commit comments

Comments
 (0)