DSL in Swift: How to Create Your Own Programming Language in an Evening

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Introduction: When Versatility is the Enemy

\n\n

Imagine you are writing code for network configuration, log parsing, or describing business rules. Every time — repetitive constructs, tons of brackets, nested conditional statements, and painful reading of someone else's code. Sound familiar?

\n\n

In such situations, domain-specific languages (DSL) come to the rescue. This is not magic or reinventing the wheel — it's a way to make code so readable that it documents itself. In this article, we'll break down how to create your own DSL in Swift — powerful, elegant, and yet not requiring a compiler.

\n\n

A DSL in Swift is not just a trendy iOS development fad. It's a tool used in SwiftUI, Combine, and even in backend libraries. You will learn to design languages that solve specific tasks: from data parsing to UI description. Let's go!

\n\n

What is a DSL and Why Does a Developer Need It?

\n\n

A Domain-Specific Language is a language tailored to one narrow area. Unlike a general-purpose language (like Swift or Python), a DSL speaks the language of your subject domain. For example, instead of:

\n\n
let config = NetworkConfig()\nconfig.host = "api.example.com"\nconfig.port = 443\nconfig.timeout = 30
\n\n

You write:

\n\n
let config = networkConfig {\n    host("api.example.com")\n    port(443)\n    timeout(30)\n}
\n\n

The second option reads like instructions in a human language. This is the goal of a DSL — to reduce cognitive load and make code self-documenting.

\n\n

In Swift, creating a DSL most often uses:

\n
    \n
  • Result Builders — a new feature in Swift 5.4+ that allows building nested structures using declarative syntax.
  • \n
  • Functional chains — the classic builder pattern.
  • \n
  • Operators — operator overloading to create fluent interfaces.
  • \n
\n\n

But let's get straight to the point. We will create a DSL for parsing CSV files — a task that torments every developer at least once in their life.

\n\n

Example 1: A Simple DSL for Network Configuration

\n\n

Let's start with a basic example that demonstrates the mechanics. Suppose we need to describe HTTP requests. Instead of a bunch of parameters — a concise DSL.

\n\n
// Define the request structure\nstruct HTTPRequest {\n    var method: String = "GET"\n    var path: String = "/"\n    var headers: [String: String] = [:]\n    var body: Data? = nil\n}\n\n// Create a DSL using Result Builder\n@resultBuilder\nstruct RequestBuilder {\n    static func buildBlock(_ components: HTTPRequestModifier...) -> HTTPRequest {\n        var request = HTTPRequest()\n        for mod in components {\n            mod.apply(&request)\n        }\n        return request\n    }\n}\n\n// Request modifiers\nprotocol HTTPRequestModifier {\n    func apply(_ request: inout HTTPRequest)\n}\n\nstruct MethodModifier: HTTPRequestModifier {\n    let method: String\n    func apply(_ request: inout HTTPRequest) {\n        request.method = method\n    }\n}\n\nstruct PathModifier: HTTPRequestModifier {\n    let path: String\n    func apply(_ request: inout HTTPRequest) {\n        request.path = path\n    }\n}\n\n// Helper functions\nfunc method(_ m: String) -> HTTPRequestModifier { MethodModifier(method: m) }\nfunc path(_ p: String) -> HTTPRequestModifier { PathModifier(path: p) }\n\n// Usage\n@RequestBuilder\nfunc buildGetRequest() -> HTTPRequest {\n    method("GET")\n    path("/users")\n}\n\nlet request = buildGetRequest()\nprint(request.method, request.path) // GET /users
\n\n

This code is the foundation of any DSL in Swift. @resultBuilder collects all expressions inside the block and transforms them into a single structure. Important: each element is a modifier that changes the state.

\n\n

Now let's complicate the task: add nesting and conditions.

Blogs

Book Recommendations