-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 16dc9e1
Showing
10 changed files
with
707 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
.DS_Store | ||
/.build | ||
/Packages | ||
/*.xcodeproj | ||
xcuserdata/ | ||
DerivedData/ | ||
.swiftpm | ||
.netrc |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
{ | ||
"pins" : [ | ||
{ | ||
"identity" : "bigint", | ||
"kind" : "remoteSourceControl", | ||
"location" : "https://github.com/attaswift/BigInt", | ||
"state" : { | ||
"revision" : "0ed110f7555c34ff468e72e1686e59721f2b0da6", | ||
"version" : "5.3.0" | ||
} | ||
}, | ||
{ | ||
"identity" : "binarycodable", | ||
"kind" : "remoteSourceControl", | ||
"location" : "https://github.com/jverkoey/BinaryCodable", | ||
"state" : { | ||
"revision" : "aebaa30f1b73c5c45c374d251029b8bd68bde755", | ||
"version" : "0.3.1" | ||
} | ||
}, | ||
{ | ||
"identity" : "swift-bignum", | ||
"kind" : "remoteSourceControl", | ||
"location" : "https://github.com/dankogai/swift-bignum", | ||
"state" : { | ||
"revision" : "c7e3e4374d9b956e5e9e9014952a981fcf2aca2b", | ||
"version" : "5.2.5" | ||
} | ||
}, | ||
{ | ||
"identity" : "swift-bls-signatures", | ||
"kind" : "remoteSourceControl", | ||
"location" : "git@github.com:keyspacewallet/swift-bls-signatures.git", | ||
"state" : { | ||
"revision" : "e107b5caca1ee4c06591b9db512bd2c5357b94b6", | ||
"version" : "0.0.3" | ||
} | ||
}, | ||
{ | ||
"identity" : "swift-clvm", | ||
"kind" : "remoteSourceControl", | ||
"location" : "git@github.com:keyspaceapp/swift-clvm.git", | ||
"state" : { | ||
"revision" : "c1d09e8d986e253bc477b8a810ad6e9adcffcb4a", | ||
"version" : "0.0.5" | ||
} | ||
}, | ||
{ | ||
"identity" : "swift-numerics", | ||
"kind" : "remoteSourceControl", | ||
"location" : "https://github.com/apple/swift-numerics", | ||
"state" : { | ||
"revision" : "0a5bc04095a675662cf24757cc0640aa2204253b", | ||
"version" : "1.0.2" | ||
} | ||
} | ||
], | ||
"version" : 2 | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// swift-tools-version: 5.7 | ||
|
||
import PackageDescription | ||
|
||
let package = Package( | ||
name: "swift-clvm-tools", | ||
platforms: [ | ||
.iOS(.v15), | ||
.macOS(.v10_15) | ||
], | ||
products: [ | ||
.library( | ||
name: "CLVMTools", | ||
targets: ["CLVMTools"]) | ||
], | ||
dependencies: [ | ||
.package(url: "git@github.com:keyspaceapp/swift-clvm.git", from: "0.0.5") | ||
], | ||
targets: [ | ||
.target( | ||
name: "CLVMTools", | ||
dependencies: [ | ||
.product(name: "CLVM", package: "swift-clvm", condition: nil), | ||
]), | ||
.testTarget( | ||
name: "CLVMToolsTests", | ||
dependencies: ["CLVMTools"]), | ||
] | ||
) |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# swift-clvm-tools | ||
|
||
Chialisp compiler and other CLVM related tools. |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,268 @@ | ||
import Foundation | ||
import BigInt | ||
import CLVM | ||
|
||
typealias Token = (String, Int) | ||
typealias Stream = IndexingIterator<[Token]> | ||
|
||
enum SyntaxError: Error { | ||
case unexpectedEndOfStream | ||
case missingClosingParenthesis | ||
case unterminatedString(Int, String) | ||
case illegalDotExpression(Int) | ||
case invalidHex(Int, String) | ||
case badIRFormat(SExp) | ||
} | ||
|
||
/// This also deals with comments. | ||
func consume_whitespace(s: String, offset: Int) -> Int { | ||
var offset = offset | ||
while true { | ||
while offset < s.count && s[s.index(s.startIndex, offsetBy: offset)].isWhitespace { | ||
offset += 1 | ||
} | ||
if offset >= s.count || s[s.index(s.startIndex, offsetBy: offset)] != ";" { | ||
break | ||
} | ||
while offset < s.count && !Set(["\n", "\r"]).contains(s[s.index(s.startIndex, offsetBy: offset)]) { | ||
offset += 1 | ||
} | ||
} | ||
return offset | ||
} | ||
|
||
func consume_until_whitespace(s: String, offset: Int) -> Token { | ||
let start = offset | ||
var offset = offset | ||
while offset < s.count && !s[s.index(s.startIndex, offsetBy: offset)].isWhitespace && s[s.index(s.startIndex, offsetBy: offset)] != ")" { | ||
offset += 1 | ||
} | ||
return (String(s[s.index(s.startIndex, offsetBy: start)..<s.index(s.startIndex, offsetBy: offset)]), offset) | ||
} | ||
|
||
func next_cons_token(stream: inout Stream) throws -> Token { | ||
if let token = stream.next() { | ||
return token | ||
} | ||
throw SyntaxError.missingClosingParenthesis | ||
} | ||
|
||
func tokenize_cons(token: String, offset: Int, stream: inout Stream) throws -> CLVMObject { | ||
if token == ")" { | ||
return CLVMObject(v: .sexp(try ir_new(type: .NULL, val: .int(0), offset: offset))) | ||
} | ||
|
||
let initial_offset = offset | ||
|
||
let first_sexp = try tokenize_sexp(token: token, offset: offset, stream: &stream) | ||
|
||
var (token, offset) = try next_cons_token(stream: &stream) | ||
let rest_sexp: CLVMObject | ||
if token == "." { | ||
let dot_offset = offset | ||
// grab the last item | ||
(token, offset) = try next_cons_token(stream: &stream) | ||
rest_sexp = try tokenize_sexp(token: token, offset: offset, stream: &stream) | ||
(token, offset) = try next_cons_token(stream: &stream) | ||
if token != ")" { | ||
throw SyntaxError.illegalDotExpression(dot_offset) | ||
} | ||
} | ||
else { | ||
rest_sexp = try tokenize_cons(token: token, offset: offset, stream: &stream) | ||
} | ||
return CLVMObject(v: .sexp( | ||
try ir_cons( | ||
first: SExp(obj: first_sexp), | ||
rest: SExp(obj: rest_sexp), | ||
offset: initial_offset | ||
) | ||
)) | ||
} | ||
|
||
func tokenize_int(token: String, offset: Int) throws -> CLVMObject? { | ||
do { | ||
// hack to avoid assert in bigint | ||
if token == "-" { | ||
return nil | ||
} | ||
guard let int = BigInt(token) else { | ||
throw ValueError("Invalid Int") | ||
} | ||
return CLVMObject(v: .sexp(try ir_new(type: .INT, val: .int(int), offset: offset))) | ||
} | ||
catch is ValueError { | ||
//pass | ||
} | ||
return nil | ||
} | ||
|
||
func tokenize_hex(token: String, offset: Int) throws -> CLVMObject? { | ||
if token.prefix(2).uppercased() == "0X" { | ||
do { | ||
var token = String(token.suffix(token.count - 2)) | ||
if token.count % 2 == 1 { | ||
token = "0" + token | ||
} | ||
return CLVMObject(v: .sexp(try ir_new(type: .HEX, val: .bytes(Data(hex: token)), offset: offset))) | ||
} | ||
catch { | ||
throw SyntaxError.invalidHex(offset, token) | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func tokenize_quotes(token: String, offset: Int) throws -> CLVMObject? { | ||
if token.count < 2 { | ||
return nil | ||
} | ||
let c = token.first | ||
if !Set(["\'", "\\", "\""]).contains(c) { | ||
return nil | ||
} | ||
|
||
if token.last != c { | ||
throw SyntaxError.unterminatedString(offset, token) | ||
} | ||
|
||
let q_type: IRType = c == "'" ? .SINGLE_QUOTE : .DOUBLE_QUOTE | ||
|
||
return CLVMObject(v: .tuple((.tuple((.int(BigInt(q_type.rawValue)), .int(BigInt(offset)))), .bytes(token.suffix(token.count-1).data(using: .utf8)!)))) | ||
} | ||
|
||
func tokenize_symbol(token: String, offset: Int) -> CLVMObject? { | ||
return CLVMObject(v: .tuple(( | ||
.tuple(( | ||
.int(BigInt(IRType.SYMBOL.rawValue)), | ||
.int(BigInt(offset)) | ||
)), | ||
.bytes(token.data(using: .utf8)!) | ||
))) | ||
} | ||
|
||
func tokenize_sexp(token: String, offset: Int, stream: inout Stream) throws -> CLVMObject { | ||
if token == "(" { | ||
let (token, offset) = try next_cons_token(stream: &stream) | ||
return try tokenize_cons(token: token, offset: offset, stream: &stream) | ||
} | ||
|
||
for f in [ | ||
tokenize_int, | ||
tokenize_hex, | ||
tokenize_quotes, | ||
tokenize_symbol, | ||
] { | ||
if let r = try f(token, offset) { | ||
return r | ||
} | ||
} | ||
|
||
throw ValueError("Invalid sexp") | ||
} | ||
|
||
func token_stream(s: String) throws -> Stream { | ||
// Python implements this with yield.. we can do something similar with AsyncThrowingStream | ||
// but then everything becomes async. | ||
var tokens: [Token] = [] | ||
var offset = 0 | ||
while offset < s.count { | ||
offset = consume_whitespace(s: s, offset: offset) | ||
if offset >= s.count { | ||
break | ||
} | ||
let c = s[s.index(s.startIndex, offsetBy: offset)] | ||
if ["(", ".", ")"].contains(c) { | ||
tokens.append((String(c), offset)) | ||
offset += 1 | ||
continue | ||
} | ||
if ["\\", "\"", "'"].contains(c) { | ||
let start = offset | ||
let initial_c = s[s.index(s.startIndex, offsetBy: start)] | ||
offset += 1 | ||
while offset < s.count && s[s.index(s.startIndex, offsetBy: offset)] != initial_c { | ||
offset += 1 | ||
} | ||
if offset < s.count { | ||
tokens.append((String(s[s.index(s.startIndex, offsetBy: start)..<s.index(s.startIndex, offsetBy: offset + 1)]), start)) | ||
offset += 1 | ||
continue | ||
} | ||
else { | ||
throw SyntaxError.unterminatedString(start, String(s.suffix(s.count - start))) | ||
} | ||
} | ||
let (token, end_offset) = consume_until_whitespace(s: s, offset: offset) | ||
tokens.append((token, offset)) | ||
offset = end_offset | ||
} | ||
return tokens.makeIterator() | ||
} | ||
|
||
func read_ir( | ||
s: String, | ||
to_sexp: @escaping (CastableType) throws -> SExp = SExp.to | ||
) throws -> SExp { | ||
var stream = try token_stream(s: s) | ||
guard let (token, offset) = stream.next() else { | ||
throw SyntaxError.unexpectedEndOfStream | ||
} | ||
return try to_sexp(.object(try tokenize_sexp( | ||
token: token, | ||
offset: offset, | ||
stream: &stream | ||
))) | ||
} | ||
|
||
|
||
#warning("hack") | ||
|
||
extension Data { | ||
public init(hex: String) { | ||
self.init(Array<UInt8>(hex: hex)) | ||
} | ||
} | ||
|
||
// Data(hex:) | ||
// From https://github.com/krzyzanowskim/CryptoSwift/ (MIT) | ||
extension Array where Element == UInt8 { | ||
public init(hex: String) { | ||
self.init() | ||
reserveCapacity(hex.unicodeScalars.lazy.underestimatedCount) | ||
var buffer: UInt8? | ||
var skip = hex.hasPrefix("0x") ? 2 : 0 | ||
for char in hex.unicodeScalars.lazy { | ||
guard skip == 0 else { | ||
skip -= 1 | ||
continue | ||
} | ||
guard char.value >= 48 && char.value <= 102 else { | ||
removeAll() | ||
return | ||
} | ||
let v: UInt8 | ||
let c: UInt8 = UInt8(char.value) | ||
switch c { | ||
case let c where c <= 57: | ||
v = c - 48 | ||
case let c where c >= 65 && c <= 70: | ||
v = c - 55 | ||
case let c where c >= 97: | ||
v = c - 87 | ||
default: | ||
removeAll() | ||
return | ||
} | ||
if let b = buffer { | ||
append(b << 4 | v) | ||
buffer = nil | ||
} else { | ||
buffer = v | ||
} | ||
} | ||
if let b = buffer { | ||
append(b) | ||
} | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import Foundation | ||
|
||
/// Associated values are `Int.from_bytes(b, .big)` where b is the utf8 encoding of the type's symbol. | ||
public enum IRType: Int { | ||
case CONS = 1129270867 | ||
case NULL = 1314212940 | ||
case INT = 4804180 | ||
case HEX = 4736344 | ||
case QUOTES = 20820 | ||
case DOUBLE_QUOTE = 4477268 | ||
case SINGLE_QUOTE = 5460308 | ||
case SYMBOL = 5462349 | ||
case OPERATOR = 20304 | ||
case CODE = 1129268293 | ||
case NODE = 1313817669 | ||
} | ||
|
||
let CONS_TYPES: Set<IRType> = Set([.CONS]) |
Oops, something went wrong.