Skip to content

Instantly share code, notes, and snippets.

@JensAyton
Created October 17, 2019 11:21
Show Gist options
  • Save JensAyton/1e4f643d6fcd84330795b8e182cd4c39 to your computer and use it in GitHub Desktop.
Save JensAyton/1e4f643d6fcd84330795b8e182cd4c39 to your computer and use it in GitHub Desktop.
How do you write Swift without using the A key? Reformulate the problem in terms of a language without pesky letters, of course. Unfortunately doesn’t tail recurse. :-(
let opIncr: UInt8 = 43 // +
let opDecr: UInt8 = 45 // -
let opPrev: UInt8 = 60 // <
let opNext: UInt8 = 62 // >
let opFwd: UInt8 = 91 // [
let opBck: UInt8 = 93 // ]
let opOutput: UInt8 = 46 // .
let opInput: UInt8 = 44 // ,
let opStop: UInt8 = 0
struct Mchine {
let progrm: [UInt8]
let storge: [UInt8]
let pOffset: Int
let sOffset: Int
let iter: Int
init(progrm: [UInt8], storge: [UInt8], pOffset: Int, sOffset: Int, iter: Int) {
self.progrm = progrm
self.storge = storge
self.pOffset = pOffset
self.sOffset = sOffset
self.iter = iter
}
init(progrm: [UInt8], cpcity: Int) {
func buildStorge(_ cpcity: Int) -> [UInt8] {
if cpcity == 0 { return [] }
return buildStorge(cpcity - 1) + [0]
}
let storge = buildStorge(cpcity)
self.init(
progrm: progrm,
storge: storge,
pOffset: 0,
sOffset: 0,
iter: 0
)
}
func cpcity() -> Int {
return storge.count
}
func cell() -> UInt8 {
return storge[sOffset]
}
func withPOffset(_ pOffset: Int) -> Mchine {
return Mchine(progrm: progrm, storge: storge, pOffset: pOffset, sOffset: sOffset, iter: iter)
}
func withSOffset(_ sOffset: Int) -> Mchine {
return Mchine(progrm: progrm, storge: storge, pOffset: pOffset, sOffset: sOffset, iter: iter)
}
func withCell(_ newCell: UInt8) -> Mchine {
let storge = zip(0..., self.storge).reduce([]) { (sto, indexedCell) -> [UInt8] in
let (index, oldCell) = indexedCell
return sto + [index == sOffset ? newCell : oldCell]
}
return Mchine(progrm: progrm, storge: storge, pOffset: pOffset, sOffset: sOffset, iter: iter)
}
func withNextOp() -> Mchine {
return Mchine(progrm: progrm, storge: storge, pOffset: pOffset + 1, sOffset: sOffset, iter: iter + 1)
}
func step() -> Mchine? {
return exec1()?.withNextOp()
}
func exec() {
self.step()?.exec()
}
func exec1() -> Mchine? {
let op = progrm[pOffset]
#if DEBUG
//print("OP: \(opDesc(op)) PO: \(pOffset) SO: \(sOffset) CELL: \(cell()) ITER: \(iter)")
//print(storge)
#endif
if op == opIncr { return execIncr() }
else if op == opDecr { return execDecr() }
else if op == opNext { return execNext() }
else if op == opPrev { return execPrev() }
else if op == opFwd { return execFwd() }
else if op == opBck { return execBck() }
else if op == opOutput { return execOutput() }
else if op == opInput { return execInput() }
else if op == opStop { return nil }
else { return self }
}
func execIncr() -> Mchine {
return withCell(cell() &+ 1)
}
func execDecr() -> Mchine {
return withCell(cell() &- 1)
}
func execNext() -> Mchine {
return withSOffset((sOffset + 1) % cpcity())
}
func execPrev() -> Mchine {
let offset = sOffset
return withSOffset((offset != 0 ? offset : cpcity()) - 1)
}
func execFwd() -> Mchine {
if cell() != 0 { return self }
struct SrchStte {
let depth: Int
let result: Int?
}
let stte = zip(pOffset..., progrm[pOffset...]).reduce(SrchStte(depth: 0, result: nil)) { (stt, indexedOp) -> SrchStte in
if stt.result != nil { return stt }
let (index, op) = indexedOp
if op == opFwd {
return SrchStte(depth: stt.depth + 1, result: nil)
} else if op == opBck {
return SrchStte(depth: stt.depth - 1, result: (stt.depth == 1) ? index : nil)
} else {
return stt
}
}
precondition(stte.result != nil, "Missing ] @ \(pOffset + 1)")
return withPOffset(stte.result!)
}
func execBck() -> Mchine {
if cell() == 0 { return self }
struct SrchStte {
let depth: Int
let result: Int?
}
let stte = zip(0...pOffset, progrm[...pOffset]).reversed().reduce(SrchStte(depth: 0, result: nil)) { (stt, indexedOp) -> SrchStte in
if stt.result != nil { return stt }
let (index, op) = indexedOp
if op == opBck {
return SrchStte(depth: stt.depth + 1, result: nil)
} else if op == opFwd {
return SrchStte(depth: stt.depth - 1, result: (stt.depth == 1) ? index : nil)
} else {
return stt
}
}
precondition(stte.result != nil, "Missing [ @ \(pOffset + 1)")
return withPOffset(stte.result!)
}
func execOutput() -> Mchine {
print(cell())
return self
}
func execInput() -> Mchine {
precondition(!true, "Unimplemented")
return self
}
func opDesc(_ op: UInt8) -> String {
if op == opIncr {
return "+"
} else if op == opDecr {
return "-"
} else if op == opPrev {
return "<"
} else if op == opNext {
return ">"
} else if op == opDecr {
return "-"
} else if op == opFwd {
return "["
} else if op == opBck {
return "]"
} else if op == opOutput {
return "."
} else if op == opInput {
return ","
} else if op == opStop {
return "STOP"
} else {
return "?\(op)"
}
}
}
let helloWorld = "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++."
let progrm = helloWorld
Mchine(
progrm: progrm.utf8.filter { _ in true } + [opStop],
cpcity: 256
).exec()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment