Created
October 17, 2019 11:21
-
-
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. :-(
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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