dankogai/swift-bf
swift-bf
SYNOPSIS
Interpreter
import BF
var bf = try BF("+[,<>.]-") // echo
print(bf.run(input: "Hello, Swift!")) // Hello, Swift!BF.init throws a BF.ParseError if the brackets do not balance:
do {
_ = try BF("+[")
} catch {
print(error) // unmatched [ at offset 1
}You can also drive the machine one command at a time. step() returns false once the program halts, and pc, sp, data and obuf are all readable as it goes:
var bf = try BF("++")
while bf.step() {}
print(bf.data[0]) // 2The ! extension
A ! ends the program, and everything after it is the program's input, so a source can carry its own data:
var bf = try BF("+[,<>.]-!Hello, Swift!")
print(bf.run()) // Hello, Swift!The text after ! is available as embeddedInput, and is what run() feeds , by default. Passing input: explicitly overrides it for that run without discarding it:
var bf = try BF("+[,.]!embedded")
print(bf.run(input: "explicit")) // explicit
print(bf.run()) // embeddedOnly the first ! splits the source, so the input may contain more of them -- which is why "+[,<>.]-!Hello, Swift!" echoes the trailing ! too.
Compiler
import BF
print(BF.compile("+[,<>.]-"))prints
#if canImport(Darwin)
import Darwin
#else
import Glibc
#endif
var data = [UInt8](repeating: 0, count: 65536)
var sp = 0
data[sp] &+= 1
while data[sp] != 0 {
data[sp] = UInt8(truncatingIfNeeded: max(0, getchar()))
sp = (sp + data.count - 1) % data.count
sp = (sp + 1) % data.count
putchar(Int32(data[sp]))
}
data[sp] &-= 1which compiles and runs standalone:
swift run bf | tail -n +2 > echo.swift
swiftc -o echo echo.swift
echo 'Hello, Swift!' | ./echoA source using ! compiles to a self-contained program that needs no stdin -- the input is baked in and , reads from it:
print(BF.compile("+[,<>.]-!Hello, Swift!"))emits the same program as above, but with
var input = Array("Hello, Swift!".utf8)[...]after the preamble, and , compiled to
data[sp] = input.popFirst() ?? 0Semantics
- The tape is 65536 cells of
UInt8. Cells wrap around:-on a zero cell
yields 255.
- The tape is circular.
<on cell 0 moves to cell 65535, and>on the
last cell moves back to cell 0.
!ends the program; everything after the first one is input, not code.
Brackets in the input section are data and need not balance.
- Any other character outside the input section is a comment.
- On end of input,
,halts the interpreter, whereas compiled code follows
the other common convention and stores 0.
Usage
Swift Package Manager
Add it to the dependencies of your Package.swift:
let package = Package(
// ...
dependencies: [
.package(url: "https://github.com/dankogai/swift-bf.git", from: "0.0.2")
],
targets: [
.target(name: "YourTarget", dependencies: [
.product(name: "BF", package: "swift-bf")
])
]
)Build and test locally
swift build
swift test
swift run bfRequirements
Swift 6.0 or later.
Package Metadata
Repository: dankogai/swift-bf
Default branch: main
README: README.md