Giter Site home page Giter Site logo

swift-macro-examples's Introduction

Swift Macro Examples

There is an active effort to introduce macros into the Swift programming language. This repository includes some example macros that can be used to explore the macro proposals and experiment with the current implementation of the feature.

Getting started

Macros are an experimental feature, so you will need a custom Swift toolchain and some extra compiler flags. The Xcode project in this repository is a good starting point. To use it:

  1. Download a development snapshot of the compiler from Swift.org from May 10, 2023 or later. At present, we only have these working on macOS, but are working to get other platforms working with other build systems.
  2. To use SwiftPM to build the example project, use swift build from the toolchain, e.g.:
    /Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2023-03-08-a.xctoolchain/usr/bin/swift build
    
  3. To use Xcode to build the example project: a. Open MacroExamples.xcodeproj in Xcode b. Go to the Xcode -> Toolchains menu and select the development toolchain you downloaded. c. Make sure the MacroExamples scheme is selected, then build and run! If the first build fails, build again--there's something funky going on with the dependencies. Then build again!

The output of the MacroExamples program is pretty simple: it shows the result of running the example macro(s). The main.swift file is annotated to describe what the macros are actually doing.

Example macros

A number of macros in this package are designed to illustrate different capabilities of the macro system:

  • @AddCompletionHandler: Adds a completion-handler form of an async function that creates a new task, calls the async function, and delivers the result to a completion handler. There's also the opposite form, @AddAsync, to add an async version for a synchronous function with a completion handler, automating the use of withCheckedContinuation.
  • @CaseDetectionMacro: Augments an enum with isXXX properties corresponding to each enum case, so one can easily test for a specific case, e.g., filePath.isAbsolute.
  • @Observable: Observation facilities for a property, using a combination of macro kinds.
  • #addBlocker: Demonstrates how a freestanding macro can emit compiler diagnostics based on the source code for the macro argument, by producing a warning for each use of the binary + operator with range highlighting and a Fix-It to replace the + with -.

Adding your own macro

This examples package is meant to grow to include additional macros that have interesting behavior. To add a macro requires both declaring the macro and also implementing the macro, which happen in separate targets:

  • Implementation: a macro is defined in the MacroExamplesPlugin target, by creating a new public struct type that implements one of the macro protocols. The stringify macro implements the ExpressionMacro protocol, e.g.,

    public struct StringifyMacro: ExpressionMacro { ... }

    To test a macro implementation, introduce new tests into the MacroExamplesPluginTest target. These tests start with source code (like #stringify(x + y)) and will run the macro implementation to produce new source code. The translation can make use of the swift-syntax package, a copy of which is included in the toolchain. We recommend implementing and testing your macro this way first so you know it does the source translation you want.

  • Declaration: a macro is declared in the MacroExamplesLib target, using the macro introducer. For example, the simple stringify macro is declared like this:

    @freestanding(expression)
    public macro stringify<T>(_ value: T) -> (T, String) = #externalMacro(module: "MacroExamplesPlugin", type: "StringifyMacro")

    The name after macro is the name to be used in source code, whereas the name after the = is the module and type name for your macro implementation. If you haven't implemented that type, or get the name wrong, you will get a compiler warning.

Once you have both a declaration and an implementation, it's time to use your macro! Go back to MacroExamples and write some code there to exercise your macro however you want.

Macros proposals

The introduction of macros into Swift will involve a number of different proposals. The Swift macros dashboard keeps track of all of them.

swift-macro-examples's People

Contributors

douggregor avatar brunomazzo avatar hborla avatar beccadax avatar dduan avatar nikolairuhe avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.