README.md

May 16, 2026 · View on GitHub

Object Parsing

Transform natural language strings into model objects

This package introduces a declarative approach to parsing natural language strings into Swift objects.

To use it, tag a model object with @ParsableObject and attempt to initialize an instance from a natural language string that contains its data:

import ObjectParsing

@ParsableObject
struct SalesRecord {
    let quantity: Int
    let date: Date
}

let record: SalesRecord = try "We sold 130 copies yesterday".parseObject()

Design

  • ObjectParsing's API was inspired by the design of FoundationModels @Generable
    • Although it uses a similar pattern, it is an order of magnitude faster, and is deterministic
  • Typically tens to low-hundreds of microseconds per parse — fast enough to call on every keystroke
  • Extensibility: declare your own string-based data types using string enums

Dependencies

This package depends on SoulverCore for parsing

  • You can also use SoulverCore directly for parsing strings into model objects: just conform your model objects to the ParsableObject protocol (a single initializer)
  • This package makes this a little easier, by adding the @ParsableObject macro that generates ParsableObject conformance for model objects automatically
  • It also includes handy higher-order primitive types (like places, flights, tags, etc.).

Limitations

  • ObjectParsing is designed for structured parsing with known data types (dates, measurements, currencies, places, flight numbers, etc.) – anything that can be pre-declared at compile time or parsed deterministically by SoulverCore.
  • If you need to extract data from strings based on their format, use regular expressions instead.

Requirements

  • Xcode 16+
  • Swift 6.2+

Installation

Add ObjectParsing to your project via the Swift Package Manager:

https://github.com/soulverteam/ObjectParsing

SoulverCore is included automatically as a dependency.

Usage

Tag a struct with @ParsableObject and then attempt to parse a new instance from a string using parseObject:

import ObjectParsing

@ParsableObject
struct Meeting {
    let date: Date
    let participantCount: Int?
}

let meeting: Meeting = try "tomorrow at 4pm, table for 5".parseObject()
// meeting.date → tomorrow at 4pm
// meeting.participantCount → 5
  • Data is scanned in the order your properties are defined.
  • Non-optional properties are required, and an error will be thrown if missing.
  • Optional properties are set to nil if not found in the input.

Unordered Parsing

Specify unordered in the macro to parse properties in any order:

import ObjectParsing

@ParsableObject(ordering: .unordered)
struct Meeting {
    let date: Date
    let participantCount: Int?
}

let meeting: Meeting = try "Table for 3, Thursday at 12:30".parseObject()
// meeting.date → Thursday at 12:30
// meeting.participantCount → 3

Nested Objects

The API is composable and supports nesting structures inside each other:

import ObjectParsing

@ParsableObject
struct Person {
    let age: Int
    let height: Double
    let bankBalance: Decimal
    let pace: Pace
}

@ParsableObject
struct Pace {
    let distanceTravelled: Distance
    let timeTaken: Time
}

let person: Person = try "I am 37 years old, 176 cm tall and have \$1000.00 in my bank account. I ran 650 metres, which took me 3 minutes 30 seconds".parseObject()
// Person(age: 37, height: 176.0, bankBalance: 1000, pace: Pace(distanceTravelled: 650.0 m, timeTaken: 3.5 min))

Custom Keywords

Define a String enum conforming to Keyword to create your own parsable types. Use aliases to declare synonyms (useful for singular/plural forms):

import ObjectParsing

enum BreakfastItem: String, Keyword {
    case waffles
    case eggs

    var aliases: [String] {
        switch self {
        case .waffles: return ["waffle"]
        case .eggs: return ["egg"]
        }
    }
}

@ParsableObject(keywordTypes: [BreakfastItem.self])
struct BreakfastOrder {
    let quantity: Int?
    let item: BreakfastItem
}

let order: BreakfastOrder = try "2 waffles".parseObject()
// order.quantity → 2
// order.item → .waffles

Keywords support multi-word phrases and are matched case-insensitively.

Array Parsing

Array properties will collect all matching values from the input:

import ObjectParsing

@ParsableObject
struct AverageList {
    let numbers: [Int]
    let average: Float
}

let list: AverageList = try "The average of 1, 2, and 4 is 2.3333333333".parseObject()
// list.numbers → [1, 2, 4]
// list.average → 2.3333333333

Parsable Data Types

ObjectParsing can parse a wide range of data types out-of-the-box.

Foundation Types

Int, Double, Decimal, Float, Bool, Date, DateInterval, URL

Measurement Types

Foundation's Measurement types (with convenient type aliases):

Distance, Length, Mass, Speed, Temperature, Area, Volume, Pressure, Energy, Power, Frequency, Angle, FileSize, Time

import ObjectParsing

@ParsableObject
struct RunLog {
    var distance: Distance
    var time: Time
}

let runLog: RunLog = try "I ran 5 km in 25 minutes".parseObject()

Higher-Order Primitives

TypeExamplesNotes
Money"100 USD", "€200"Amount, currency code & name
Flight"QF2", "qf 33"Requires keywordTypes: [Airline.self]
Airline"Qantas", "QF"79 airlines with code & name aliases
FlightDestination"SYD", "London"Resolves to airports with coordinates
GeoSpot"Paris", "Tokyo"Name, coordinates & timezone
IPAddress"192.168.1.1", "8.8.8.8:53"IPv4 with optional port
DigitalContact"john@example.com", "@handle"Email or social handle
TagSet"#swift #ios"Set of hashtag strings
Timecode"1:23:45", "45:30"HH:MM:SS or MM:SS
UnixTimestamp"1633024800"Auto-detects seconds vs milliseconds
Percentage"75%"Decimal percentage value
WeatherParameter"temperature", "feels like"22 weather metrics

Parsing Objects using only SoulverCore

You may prefer to skip this package and use SoulverCore directly to parse objects with ObjectParser. You won't get the convenience macro (@ParsableObject), but this avoids importing Swift Syntax — which is required by any package that uses macros.

Conform your types to ParsableObject and use ObjectParser directly:

import SoulverCore

struct SalesRecord: ParsableObject {
    let quantity: Int
    let date: Date

    init(from parser: ObjectParser) throws {
        self.quantity = try parser.scan(.number)
        self.date = try parser.scan(.date)
    }
}

let record: SalesRecord = try "We sold 130 copies yesterday".parseObject()
// record.quantity → 130
// record.date → yesterday's date

See the ObjectParser documentation for more details.

Sample App

A sample Mac app demonstrating how to parse natural language flight queries, weather queries, currency conversions, and time zones is included in the Demo App folder.

  • DateParsing — natural language date parsing with SoulverCore
  • StringParsing — declarative data point extraction from strings with SoulverCore

Licence

SoulverCore is a commercially licensable, closed-source Swift framework. The standard licensing terms of SoulverCore do apply for its use in object parsing (see SoulverCore Licence). For personal (non-commercial) projects, you do not need a licence. So go ahead and use this great library in your personal projects!