1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355
|
import WasmParser
internal struct Parser {
var lexer: Lexer
init(_ input: String) {
self.lexer = Lexer(input: input)
}
init(_ lexer: Lexer) {
self.lexer = lexer
}
func peek(_ kind: TokenKind? = nil) throws -> Token? {
var lexer = lexer
guard let token = try lexer.lex() else { return nil }
if let kind {
guard token.kind == kind else { return nil }
}
return token
}
func peekKeyword() throws -> String? {
guard let token = try peek(.keyword) else {
return nil
}
return token.text(from: lexer)
}
mutating func take(_ kind: TokenKind) throws -> Bool {
guard try peek(kind) != nil else { return false }
try consume()
return true
}
mutating func takeKeyword(_ keyword: String) throws -> Bool {
guard let token = try peek(.keyword), token.text(from: lexer) == keyword else {
return false
}
try consume()
return true
}
/// Consume a `(keyword` sequence, returning whether the tokens were consumed.
mutating func takeParenBlockStart(_ keyword: String) throws -> Bool {
let original = lexer
guard try take(.leftParen), try takeKeyword(keyword) else {
lexer = original
return false
}
return true
}
mutating func takeUnsignedInt<IntegerType: UnsignedInteger & FixedWidthInteger>(_: IntegerType.Type = IntegerType.self) throws -> IntegerType? {
guard let token = try peek() else { return nil }
guard case let .integer(nil, pattern) = token.kind else {
return nil
}
try consume()
switch pattern {
case .hexPattern(let pattern):
guard let index = IntegerType(pattern, radix: 16) else {
throw WatParserError("invalid index \(pattern)", location: token.location(in: lexer))
}
return index
case .decimalPattern(let pattern):
guard let index = IntegerType(pattern) else {
throw WatParserError("invalid index \(pattern)", location: token.location(in: lexer))
}
return index
}
}
mutating func takeSignedInt<IntegerType: FixedWidthInteger, UnsignedType: FixedWidthInteger & UnsignedInteger>(
fromBitPattern: (UnsignedType) -> IntegerType
) throws -> IntegerType? {
guard let token = try peek() else { return nil }
guard case let .integer(sign, pattern) = token.kind else {
return nil
}
try consume()
let value: UnsignedType
let makeError = { [lexer] in
WatParserError("invalid literal \(token.text(from: lexer))", location: token.location(in: lexer))
}
switch pattern {
case .hexPattern(let pattern):
guard let index = UnsignedType(pattern, radix: 16) else { throw makeError() }
value = index
case .decimalPattern(let pattern):
guard let index = UnsignedType(pattern) else { throw makeError() }
value = index
}
switch sign {
case .plus, nil: return fromBitPattern(value)
case .minus:
let casted = fromBitPattern(~value &+ 1)
guard casted <= 0 else { throw makeError() }
return casted
}
}
mutating func takeStringBytes() throws -> [UInt8]? {
guard let token = try peek(), case .string(let bytes) = token.kind else { return nil }
try consume()
return bytes
}
mutating func takeString() throws -> String? {
guard let bytes = try takeStringBytes() else { return nil }
return String(decoding: bytes, as: UTF8.self)
}
mutating func takeIndexOrId() throws -> IndexOrId? {
let location = lexer.location()
if let index: UInt32 = try takeUnsignedInt() {
return .index(index, location)
} else if let id = try takeId() {
return .id(id, location)
}
return nil
}
@discardableResult
mutating func expect(_ kind: TokenKind) throws -> Token {
guard let token = try lexer.lex() else {
throw WatParserError("expected \(kind)", location: lexer.location())
}
guard token.kind == kind else {
throw WatParserError("expected \(kind)", location: token.location(in: lexer))
}
return token
}
@discardableResult
mutating func expectKeyword(_ keyword: String? = nil) throws -> String {
let token = try expect(.keyword)
let text = token.text(from: lexer)
if let keyword {
guard text == keyword else {
throw WatParserError("expected \(keyword)", location: token.location(in: lexer))
}
}
return text
}
mutating func expectStringBytes() throws -> [UInt8] {
guard let token = try lexer.lex() else {
throw WatParserError("expected string", location: lexer.location())
}
guard case .string(let text) = token.kind else {
throw WatParserError("expected string but got \(token.kind)", location: token.location(in: lexer))
}
return text
}
mutating func expectString() throws -> String {
// TODO: Use SE-0405 once we can upgrade minimum-supported Swift version to 6.0
let bytes = try expectStringBytes()
return try bytes.withUnsafeBufferPointer {
guard let value = String._tryFromUTF8($0) else {
throw WatParserError("invalid UTF-8 string", location: lexer.location())
}
return value
}
}
mutating func expectStringList() throws -> [UInt8] {
var data: [UInt8] = []
while try !take(.rightParen) {
data += try expectStringBytes()
}
return data
}
mutating func expectUnsignedInt<IntegerType: UnsignedInteger & FixedWidthInteger>(_: IntegerType.Type = IntegerType.self) throws -> IntegerType {
guard let value: IntegerType = try takeUnsignedInt() else {
throw WatParserError("expected decimal index without sign", location: lexer.location())
}
return value
}
mutating func expectSignedInt<IntegerType: FixedWidthInteger, UnsignedType: FixedWidthInteger & UnsignedInteger>(
fromBitPattern: (UnsignedType) -> IntegerType
) throws -> IntegerType {
guard let value: IntegerType = try takeSignedInt(fromBitPattern: fromBitPattern) else {
throw WatParserError("expected decimal index with sign", location: lexer.location())
}
return value
}
mutating func expectFloatingPoint<F: BinaryFloatingPoint & LosslessStringConvertible, BitPattern: FixedWidthInteger>(
_: F.Type, toBitPattern: (F) -> BitPattern, isNaN: (BitPattern) -> Bool,
buildBitPattern: (
_ sign: FloatingPointSign,
_ exponentBitPattern: UInt,
_ significandBitPattern: UInt
) -> BitPattern
) throws -> BitPattern {
let token = try consume()
var infinityExponent: UInt {
return 1 &<< UInt(F.exponentBitCount) - 1
}
let makeError = { [lexer] in
WatParserError("invalid float literal \(token.text(from: lexer))", location: token.location(in: lexer))
}
let parse = { (pattern: String) throws -> F in
// Swift's Float{32,64} initializer returns +/- infinity for too large/too small values.
// We know that the given pattern will not be expected to be parsed as infinity,
// so we can check if the parsing succeeded by checking if the returned value is infinite.
guard let value = F(pattern), !value.isInfinite else { throw makeError() }
return value
}
switch token.kind {
case let .float(sign, pattern):
let float: F
switch pattern {
case .decimalPattern(let pattern):
float = try parse(pattern)
case .hexPattern(let pattern):
float = try parse("0x" + pattern)
case .inf:
float = .infinity
case .nan(hexPattern: nil):
float = .nan
case .nan(let hexPattern?):
guard let significandBitPattern = BitPattern(hexPattern, radix: 16) else { throw makeError() }
let bitPattern = buildBitPattern(sign ?? .plus, infinityExponent, UInt(significandBitPattern))
// Ensure that the given bit pattern is a NaN.
guard isNaN(bitPattern) else { throw makeError() }
return bitPattern
}
return toBitPattern(sign == .minus ? -float : float)
case let .integer(sign, pattern):
let float: F
switch pattern {
case .hexPattern(let pattern):
float = try parse("0x" + pattern)
case .decimalPattern(let pattern):
float = try parse(pattern)
}
return toBitPattern(sign == .minus ? -float : float)
default:
throw WatParserError("expected float but got \(token.kind)", location: token.location(in: lexer))
}
}
mutating func expectFloat32() throws -> IEEE754.Float32 {
let bitPattern = try expectFloatingPoint(
Float32.self, toBitPattern: \.bitPattern,
isNaN: { Float32(bitPattern: $0).isNaN },
buildBitPattern: {
UInt32(
($0 == .minus ? 1 : 0) << (Float32.exponentBitCount + Float32.significandBitCount)
+ ($1 << Float32.significandBitCount) + $2
)
}
)
return IEEE754.Float32(bitPattern: bitPattern)
}
mutating func expectFloat64() throws -> IEEE754.Float64 {
let bitPattern = try expectFloatingPoint(
Float64.self, toBitPattern: \.bitPattern,
isNaN: { Float64(bitPattern: $0).isNaN },
buildBitPattern: {
UInt64(
($0 == .minus ? 1 : 0) << (Float64.exponentBitCount + Float64.significandBitCount)
+ ($1 << Float64.significandBitCount) + $2
)
}
)
return IEEE754.Float64(bitPattern: bitPattern)
}
mutating func expectIndex() throws -> UInt32 { try expectUnsignedInt(UInt32.self) }
mutating func expectParenBlockStart(_ keyword: String) throws {
guard try takeParenBlockStart(keyword) else {
throw WatParserError("expected \(keyword)", location: lexer.location())
}
}
enum IndexOrId {
case index(UInt32, Location)
case id(Name, Location)
var location: Location {
switch self {
case .index(_, let location), .id(_, let location):
return location
}
}
}
mutating func expectIndexOrId() throws -> IndexOrId {
guard let indexOrId = try takeIndexOrId() else {
throw WatParserError("expected index or id", location: lexer.location())
}
return indexOrId
}
func isEndOfParen() throws -> Bool {
guard let token = try peek() else { return true }
return token.kind == .rightParen
}
@discardableResult
mutating func consume() throws -> Token {
guard let token = try lexer.lex() else {
throw WatParserError("unexpected EOF", location: lexer.location())
}
return token
}
mutating func takeId() throws -> Name? {
guard let token = try peek(.id) else { return nil }
try consume()
return Name(value: token.text(from: lexer), location: token.location(in: lexer))
}
mutating func skipParenBlock() throws {
var depth = 1
while depth > 0 {
let token = try consume()
switch token.kind {
case .leftParen:
depth += 1
case .rightParen:
depth -= 1
default:
break
}
}
}
}
public struct WatParserError: Error, CustomStringConvertible {
public let message: String
public let location: Location?
public var description: String {
if let location {
let (line, column) = location.computeLineAndColumn()
return "\(line):\(column): \(message)"
} else {
return message
}
}
init(_ message: String, location: Location?) {
self.message = message
self.location = location
}
}
|