Skip to content

Commit fca680f

Browse files
committed
Mark continuation closures and fix continuation?.
1 parent 94de9aa commit fca680f

File tree

7 files changed

+89
-49
lines changed

7 files changed

+89
-49
lines changed

Sources/LispKit/Compiler/Compiler.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -919,7 +919,11 @@ public final class Compiler {
919919
/// Compiles a closure consisting of a list of formal arguments `arglist`, a list of
920920
/// expressions `body`, and a local environment `env`. It puts the closure on top of the
921921
/// stack.
922-
public func compileLambda(_ nameIdx: Int?, _ arglist: Expr, _ body: Expr, _ env: Env) throws {
922+
public func compileLambda(_ nameIdx: Int?,
923+
_ arglist: Expr,
924+
_ body: Expr,
925+
_ env: Env,
926+
continuation: Bool = false) throws {
923927
// Create closure compiler as child of the current compiler
924928
let closureCompiler = Compiler(in: env,
925929
and: env,
@@ -957,7 +961,7 @@ public final class Compiler {
957961
}
958962
}
959963
// Return captured binding count and index of compiled closure
960-
self.emit(.makeClosure(nameIdx ?? -1,
964+
self.emit(.makeClosure(nameIdx ?? (continuation ? -2 : -1),
961965
closureCompiler.captures.count,
962966
codeIndex))
963967
}

Sources/LispKit/Data/Expr.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -882,7 +882,9 @@ extension Expr: CustomStringConvertible {
882882
enclObjs.remove(proc)
883883
return fixString(proc, res)
884884
}
885-
case .continuation(_):
885+
case .rawContinuation(_):
886+
return "#<raw-continuation \(proc.name)>"
887+
case .closure(.continuation, _, _):
886888
return "#<continuation \(proc.name)>"
887889
default:
888890
return "#<procedure \(proc.name)>"

Sources/LispKit/Data/Procedure.swift

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,27 +23,42 @@
2323
/// identity, a name, and a definition in the form of property `kind`. There are four kinds
2424
/// of procedure definitions:
2525
/// 1. Primitives: Built-in procedures
26-
/// 2. Closures: User-defined procedures, e.g. via `lambda`
27-
/// 3. Continuations: Continuations generated by `call-with-current-continuation`
28-
/// 4. Parameters: Parameter objects, which can be mutated for the duration of a
26+
/// 2. Closures: User-defined procedures, e.g. via `lambda`. Closure are either anonymous,
27+
/// they are named, or they are continuations
28+
/// 3. Parameters: Parameter objects, which can be mutated for the duration of a
2929
/// dynamic extent
30-
/// 5. Transformers: User-defined macro transformers defined via `syntax-rules`
30+
/// 4. Transformers: User-defined macro transformers defined via `syntax-rules`
31+
/// 5. Raw continuations: Continuations generated by `call-with-current-continuation`
32+
/// are modeled as closures of closure type `continuation`. Internally, they use
33+
/// raw continuations for encapsulating the state of a virtual machine.
3134
///
3235
public final class Procedure: Reference, CustomStringConvertible {
3336

3437
/// There are four kinds of procedures:
3538
/// 1. Primitives: Built-in procedures
3639
/// 2. Closures: User-defined procedures, e.g. via `lambda`
37-
/// 3. Continuations: Continuations generated by `call-with-current-continuation`
38-
/// 4. Parameters: Parameter objects, which can be mutated for the duration of a
40+
/// 3. Parameters: Parameter objects, which can be mutated for the duration of a
3941
/// dynamic extent
40-
/// 5. Transformers: User-defined macro transformers defined via `syntax-rules`
42+
/// 4. Transformers: User-defined macro transformers defined via `syntax-rules`
43+
/// 5. Raw continuations: Continuations generated by `call-with-current-continuation`
44+
/// are modeled as closures of closure type `continuation`. Internally, they use
45+
/// raw continuations for encapsulating the state of a virtual machine.
4146
public enum Kind {
4247
case primitive(String, Implementation, FormCompiler?)
43-
case closure(String?, Exprs, Code)
44-
case continuation(VirtualMachineState)
48+
case closure(ClosureType, Exprs, Code)
4549
case parameter(Tuple)
4650
case transformer(SyntaxRules)
51+
case rawContinuation(VirtualMachineState)
52+
}
53+
54+
/// There are three types of closures:
55+
/// 1. Anonymous closures: closures that are not named
56+
/// 2. Named closures: Closures that are given a name
57+
/// 3. Continuations: These are unnamed closures generated by `call-with-current-continuation`
58+
public enum ClosureType {
59+
case anonymous
60+
case named(String)
61+
case continuation
4762
}
4863

4964
/// There are three different types of primitive implementations:
@@ -219,13 +234,13 @@ public final class Procedure: Reference, CustomStringConvertible {
219234
}
220235

221236
/// Initializer for closures
222-
public init(_ name: String?, _ captured: Exprs, _ code: Code) {
223-
self.kind = .closure(name, captured, code)
237+
public init(_ type: ClosureType, _ captured: Exprs, _ code: Code) {
238+
self.kind = .closure(type, captured, code)
224239
}
225240

226241
/// Initializer for closures
227242
public init(_ code: Code) {
228-
self.kind = .closure(nil, [], code)
243+
self.kind = .closure(.anonymous, [], code)
229244
}
230245

231246
/// Initializer for parameters
@@ -240,7 +255,7 @@ public final class Procedure: Reference, CustomStringConvertible {
240255

241256
/// Initializer for continuations
242257
public init(_ vmState: VirtualMachineState) {
243-
self.kind = .continuation(vmState)
258+
self.kind = .rawContinuation(vmState)
244259
}
245260

246261
/// Initializer for transformers
@@ -254,7 +269,7 @@ public final class Procedure: Reference, CustomStringConvertible {
254269
switch self.kind {
255270
case .primitive(let str, _, _):
256271
return str
257-
case .closure(.some(let str), _, _):
272+
case .closure(.named(let str), _, _):
258273
return "\(str)@\(self.identityString)"
259274
default:
260275
return self.identityString
@@ -266,7 +281,7 @@ public final class Procedure: Reference, CustomStringConvertible {
266281
switch self.kind {
267282
case .primitive(let str, _, _):
268283
return str
269-
case .closure(.some(let str), _, _):
284+
case .closure(.named(let str), _, _):
270285
return str
271286
default:
272287
return nil
@@ -282,7 +297,7 @@ public final class Procedure: Reference, CustomStringConvertible {
282297
code.mark(tag)
283298
case .parameter(let tuple):
284299
tuple.mark(tag)
285-
case .continuation(let state):
300+
case .rawContinuation(let state):
286301
state.mark(tag)
287302
default:
288303
break

Sources/LispKit/Primitives/DynamicControlLibrary.swift

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ public final class DynamicControlLibrary: NativeLibrary {
5454

5555
// Continuations
5656
self.define(Procedure("continuation?", isContinuation))
57+
self.define(SpecialForm("_continuation", compileContinuation))
5758
self.define(Procedure("_call-with-unprotected-continuation", callWithUnprotectedContinuation))
5859
self.define(Procedure("_wind-down", windDown))
5960
self.define(Procedure("_wind-up", windUp))
@@ -65,7 +66,7 @@ public final class DynamicControlLibrary: NativeLibrary {
6566
"(define (call-with-current-continuation f)",
6667
" (_call-with-unprotected-continuation",
6768
" (lambda (cont)",
68-
" (f (lambda args",
69+
" (f (_continuation args",
6970
" (do ((base (_dynamic-wind-base cont)))",
7071
" ((eqv? (_dynamic-wind-current) base))",
7172
" ((cdr (_wind-down))))",
@@ -197,10 +198,24 @@ public final class DynamicControlLibrary: NativeLibrary {
197198
guard case .procedure(let proc) = expr else {
198199
return .false
199200
}
200-
guard case .continuation(_) = proc.kind else {
201-
return .false
201+
switch proc.kind {
202+
case .rawContinuation(_),
203+
.closure(.continuation, _, _):
204+
return .true
205+
default:
206+
return .false
207+
}
208+
}
209+
210+
private func compileContinuation(compiler: Compiler,
211+
expr: Expr,
212+
env: Env,
213+
tail: Bool) throws -> Bool {
214+
guard case .pair(_, .pair(let arglist, let body)) = expr else {
215+
throw RuntimeError.argumentCount(num: 1, expr: expr)
202216
}
203-
return .true
217+
try compiler.compileLambda(nil, arglist, body, env, continuation: true)
218+
return false
204219
}
205220

206221
func callWithUnprotectedContinuation(_ args: Arguments) throws -> (Procedure, Exprs) {
@@ -249,7 +264,7 @@ public final class DynamicControlLibrary: NativeLibrary {
249264
}
250265

251266
func dynamicWindBase(_ cont: Expr) throws -> Expr {
252-
guard case .continuation(let vmState) = try cont.asProcedure().kind else {
267+
guard case .rawContinuation(let vmState) = try cont.asProcedure().kind else {
253268
preconditionFailure("_dynamic-wind-base(\(cont))")
254269
}
255270
let base = self.context.machine.winders?.commonPrefix(vmState.winders)
@@ -261,7 +276,7 @@ public final class DynamicControlLibrary: NativeLibrary {
261276
}
262277

263278
func dynamicWinders(_ cont: Expr) throws -> Expr {
264-
guard case .continuation(let vmState) = try cont.asProcedure().kind else {
279+
guard case .rawContinuation(let vmState) = try cont.asProcedure().kind else {
265280
preconditionFailure("_dynamic-winders(\(cont))")
266281
}
267282
let base = self.context.machine.winders

Sources/LispKit/Primitives/SystemLibrary.swift

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -417,25 +417,25 @@ public final class SystemLibrary: NativeLibrary {
417417
throw RuntimeError.type(expr, expected: [.procedureType])
418418
}
419419
switch proc.kind {
420-
case .closure(_, let captured, let code):
421-
context.console.print(code.description)
422-
if captured.count > 0 {
423-
context.console.print("CAPTURED:\n")
424-
for i in captured.indices {
425-
context.console.print(" \(i): \(captured[i])\n")
420+
case .closure(_, let captured, let code):
421+
context.console.print(code.description)
422+
if captured.count > 0 {
423+
context.console.print("CAPTURED:\n")
424+
for i in captured.indices {
425+
context.console.print(" \(i): \(captured[i])\n")
426+
}
426427
}
427-
}
428-
case .continuation(let vmState):
429-
context.console.print(vmState.description + "\n")
430-
context.console.print(vmState.registers.code.description)
431-
if vmState.registers.captured.count > 0 {
432-
context.console.print("CAPTURED:\n")
433-
for i in vmState.registers.captured.indices {
434-
context.console.print(" \(i): \(vmState.registers.captured[i])\n")
428+
case .rawContinuation(let vmState):
429+
context.console.print(vmState.description + "\n")
430+
context.console.print(vmState.registers.code.description)
431+
if vmState.registers.captured.count > 0 {
432+
context.console.print("CAPTURED:\n")
433+
for i in vmState.registers.captured.indices {
434+
context.console.print(" \(i): \(vmState.registers.captured[i])\n")
435+
}
435436
}
436-
}
437-
default:
438-
context.console.print("cannot disassemble \(expr)\n")
437+
default:
438+
context.console.print("cannot disassemble \(expr)\n")
439439
}
440440
return .void
441441
}

Sources/LispKit/Runtime/Instruction.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ public enum Instruction: CustomStringConvertible {
110110
/// fragment. The capture list is created from the top _n_ elements on the stack. _f_ is
111111
/// an index into the list of code fragments of the currently executed code. _i_ is a
112112
/// reference into the constant pool referring to the name of the closure (-1 indicates that
113-
/// the closure is anonymous)
113+
/// the closure is anonymous, -2 indicates that the closure is a continuation).
114114
case makeClosure(Int, Int, Int)
115115

116116
/// **`make_frame`**: Pushes a new stack frame onto the stack.
@@ -468,7 +468,7 @@ public enum Instruction: CustomStringConvertible {
468468
case .pushConstant(let index):
469469
return code.constants[index].description
470470
case .makeClosure(let i, _, _):
471-
return i >= 0 ? code.constants[i].description : nil
471+
return i >= 0 ? code.constants[i].description : (i == -2 ? "continuation" : nil)
472472
case .makeVariableArgument(_):
473473
return nil
474474
case .pushChar(let char):

Sources/LispKit/Runtime/VirtualMachine.swift

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,7 @@ public final class VirtualMachine: TrackedObject {
402402
switch proc.kind {
403403
case .closure(_, let captured, let code):
404404
return try self.execute(code, args: n, captured: captured)
405-
case .continuation(_):
405+
case .rawContinuation(_):
406406
return try self.execute()
407407
case .transformer(let rules):
408408
if n != 1 {
@@ -924,7 +924,7 @@ public final class VirtualMachine: TrackedObject {
924924
}
925925
}
926926
// Handle continuations
927-
if case .continuation(let vmState) = proc.kind {
927+
if case .rawContinuation(let vmState) = proc.kind {
928928
// Check that we apply the continuation in the right context
929929
guard vmState.registers.rid == self.registers.rid else {
930930
throw RuntimeError.eval(.illegalContinuationApplication,
@@ -1176,11 +1176,15 @@ public final class VirtualMachine: TrackedObject {
11761176
preconditionFailure(
11771177
"makeClosure has broken closure name \(self.registers.code.constants[i])")
11781178
}
1179-
self.push(.procedure(Procedure(sym.description,
1179+
self.push(.procedure(Procedure(.named(sym.description),
1180+
self.captureExprs(n),
1181+
self.registers.code.fragments[index])))
1182+
} else if i == -2 {
1183+
self.push(.procedure(Procedure(.continuation,
11801184
self.captureExprs(n),
11811185
self.registers.code.fragments[index])))
11821186
} else {
1183-
self.push(.procedure(Procedure(nil,
1187+
self.push(.procedure(Procedure(.anonymous,
11841188
self.captureExprs(n),
11851189
self.registers.code.fragments[index])))
11861190
}
@@ -1272,7 +1276,7 @@ public final class VirtualMachine: TrackedObject {
12721276
}
12731277
// Adjust the stack pointer
12741278
self.sp = self.registers.fp &+ n
1275-
} else if case .continuation(_) = proc.kind {
1279+
} else if case .rawContinuation(_) = proc.kind {
12761280
break
12771281
} else if self.registers.topLevel {
12781282
// Return to interactive environment

0 commit comments

Comments
 (0)