Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Sources/WasmParser/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
add_wasmkit_library(WasmParser
Stream/ByteStream.swift
Stream/FileHandleStream.swift
Stream/Stream.swift
BinaryInstructionDecoder.swift
InstructionVisitor.swift
LEB.swift
Expand Down
39 changes: 31 additions & 8 deletions Sources/WasmParser/Stream/ByteStream.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
public protocol ByteStream: Stream where Element == UInt8 {}
public protocol ByteStream: ~Copyable {
var currentIndex: Int { get }

func consumeAny() throws(WasmParserError) -> UInt8
func consume(_ expected: Set<UInt8>) throws(WasmParserError) -> UInt8
func consume(count: Int) throws(WasmParserError) -> ArraySlice<UInt8>

func peek() throws(WasmParserError) -> UInt8?
}

extension ByteStream {
func consume(_ expected: UInt8) throws(WasmParserError) -> UInt8 {
try consume(Set([expected]))
}

@usableFromInline
func hasReachedEnd() throws(WasmParserError) -> Bool {
try peek() == nil
}
}
public final class StaticByteStream: ByteStream {
public let bytes: ArraySlice<UInt8>
public var currentIndex: Int
Expand All @@ -15,9 +33,9 @@ public final class StaticByteStream: ByteStream {
}

@discardableResult
public func consumeAny() throws -> UInt8 {
public func consumeAny() throws(WasmParserError) -> UInt8 {
guard bytes.indices.contains(currentIndex) else {
throw StreamError<Element>.unexpectedEnd(expected: nil)
throw WasmParserError(kind: .unexpectedEnd(expected: nil), offset: self.currentIndex)
}

let consumed = bytes[currentIndex]
Expand All @@ -26,26 +44,31 @@ public final class StaticByteStream: ByteStream {
}

@discardableResult
public func consume(_ expected: Set<UInt8>) throws -> UInt8 {
public func consume(_ expected: Set<UInt8>) throws(WasmParserError) -> UInt8 {
guard bytes.indices.contains(currentIndex) else {
throw StreamError<Element>.unexpectedEnd(expected: Set(expected))
throw WasmParserError(kind: .unexpectedEnd(expected: Set(expected)), offset: currentIndex)
}

let consumed = bytes[currentIndex]
guard expected.contains(consumed) else {
throw StreamError<Element>.unexpected(consumed, index: currentIndex, expected: Set(expected))
throw WasmParserError(
kind: .unexpectedByte(
consumed,
index: currentIndex,
expected: Set(expected)
), offset: currentIndex)
}

currentIndex = bytes.index(after: currentIndex)
return consumed
}

public func consume(count: Int) throws -> ArraySlice<UInt8> {
public func consume(count: Int) throws(WasmParserError) -> ArraySlice<UInt8> {
guard count > 0 else { return [] }
let updatedIndex = currentIndex + count

guard bytes.indices.contains(updatedIndex - 1) else {
throw StreamError<Element>.unexpectedEnd(expected: nil)
throw WasmParserError(kind: .unexpectedEnd(expected: nil), offset: currentIndex)
}

defer { currentIndex = updatedIndex }
Expand Down
36 changes: 25 additions & 11 deletions Sources/WasmParser/Stream/FileHandleStream.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,22 @@ public final class FileHandleStream: ByteStream {
try readMoreIfNeeded()
}

private func readMoreIfNeeded() throws {
private func readMoreIfNeeded() throws(WasmParserError) {
guard Int(endOffset) == currentIndex else { return }
startOffset = currentIndex

let data = try fileHandle.read(upToCount: bufferLength)
do {
let data = try fileHandle.read(upToCount: bufferLength)

bytes = [UInt8](data)
bytes = [UInt8](data)
} catch {
throw WasmParserError(kind: .unclassified(error), offset: currentIndex)
}
endOffset = startOffset + bytes.count
}

@discardableResult
public func consumeAny() throws -> UInt8 {
public func consumeAny() throws(WasmParserError) -> UInt8 {
guard let consumed = try peek() else {
throw WasmParserError(.unexpectedEnd, offset: currentIndex)
}
Expand All @@ -37,18 +41,23 @@ public final class FileHandleStream: ByteStream {
}

@discardableResult
public func consume(_ expected: Set<UInt8>) throws -> UInt8 {
public func consume(_ expected: Set<UInt8>) throws(WasmParserError) -> UInt8 {
guard let consumed = try peek() else {
throw StreamError<UInt8>.unexpectedEnd(expected: Set(expected))
throw WasmParserError(kind: .unexpectedEnd(expected: Set(expected)), offset: currentIndex)
}
guard expected.contains(consumed) else {
throw StreamError<Element>.unexpected(consumed, index: currentIndex, expected: Set(expected))
throw WasmParserError(
kind: .unexpectedByte(
consumed,
index: currentIndex,
expected: Set(expected)
), offset: currentIndex)
}
currentIndex = bytes.index(after: currentIndex)
return consumed
}

public func consume(count: Int) throws -> ArraySlice<UInt8> {
public func consume(count: Int) throws(WasmParserError) -> ArraySlice<UInt8> {
let bytesToRead = currentIndex + count - endOffset

guard bytesToRead > 0 else {
Expand All @@ -58,9 +67,14 @@ public final class FileHandleStream: ByteStream {
return result
}

let data = try fileHandle.read(upToCount: bytesToRead)
let data: [UInt8]
do {
data = try fileHandle.read(upToCount: bytesToRead)
} catch {
throw WasmParserError(kind: .unclassified(error), offset: currentIndex)
}
guard data.count == bytesToRead else {
throw StreamError<UInt8>.unexpectedEnd(expected: nil)
throw WasmParserError(kind: .unexpectedEnd(expected: nil), offset: currentIndex)
}

bytes.append(contentsOf: [UInt8](data))
Expand All @@ -74,7 +88,7 @@ public final class FileHandleStream: ByteStream {
return result
}

public func peek() throws -> UInt8? {
public func peek() throws(WasmParserError) -> UInt8? {
try readMoreIfNeeded()

let index = currentIndex - startOffset
Expand Down
28 changes: 0 additions & 28 deletions Sources/WasmParser/Stream/Stream.swift

This file was deleted.

58 changes: 53 additions & 5 deletions Sources/WasmParser/WasmParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -217,19 +217,64 @@ public struct WasmParserError: Swift.Error {
}
}

let message: Message
let offset: Int
@usableFromInline
enum Kind: Sendable {
case message(Message)
case unexpectedEnd(expected: Set<UInt8>?)
case unexpectedByte(UInt8, index: Int, expected: Set<UInt8>?)
case unclassified(any Error)
}

let kind: Kind
let offset: Int?

@usableFromInline
init(kind: Kind, offset: Int) {
self.kind = kind
self.offset = offset
}
}

extension WasmParserError {
@usableFromInline
init(_ message: Message, offset: Int) {
self.message = message
self.kind = .message(message)
self.offset = offset
}
}

extension BinaryInteger {
var hexString: String {
"0x\(String(self, radix: 16))"
}
}

extension WasmParserError: CustomStringConvertible {
public var description: String {
return "\"\(message)\" at offset 0x\(String(offset, radix: 16))"
var result: String
switch self.kind {
case .message(let message):
result = message.text
case .unexpectedEnd(let expected):
var result = "Unexpected end of byte sequence."
if let expected, expected.count > 0 {
result.append(contentsOf: " Expected one of \(expected.map {$0.hexString}).")
}
return result
case .unexpectedByte(let byte, let index, let expected):
result = "Unexpected byte \(byte.hexString) at index \(index.hexString)."
if let expected, expected.count > 0 {
result.append(contentsOf: " Expected one of \(expected.map {$0.hexString}).")
}
case .unclassified(let error):
result = "\(error)"
}

if let offset {
return "\"\(result)\" raised at offset 0x\(String(offset, radix: 16))"
} else {
return result
}
}
}

Expand Down Expand Up @@ -595,7 +640,10 @@ extension Parser {
case 0x6F:
elementType = .externRef
default:
throw StreamError.unexpected(b, index: offset, expected: [0x6F, 0x70])
throw WasmParserError(
kind: .unexpectedByte(b, index: offset, expected: [0x6F, 0x70]),
offset: stream.currentIndex
)
}

let limits = try parseLimits()
Expand Down
Loading