A pip-installable version of Apple's gyb python-based templating tool
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.gitignore Initial commit Dec 29, 2018
LICENSE.txt init import from apple Dec 29, 2018
README.md Update README.md Jan 5, 2019
gyb.py init import from apple Dec 29, 2018
linedirective.py add line-directive Jan 4, 2019
setup.py add line-directive Jan 4, 2019

README.md

gyb

A pip-installable version of Apple's gyb python-based templating tool, along with Apple's line-directive utility to map output lines to template lines. To install:

pip install gyb

For help (assuming that the pip installed binaries path is in your PATH):

gyb -h

To use:

gyb file.ext.gyb -o file.ext

For details, see this great blog post.

Summary (from gyb -h)

A GYB template consists of the following elements:

  • Literal text which is inserted directly into the output
  • %% or $$ in literal text, which insert literal '%' and '$' symbols respectively.
  • Substitutions of the form ${<python-expression>}. The Python expression is converted to a string and the result is inserted into the output.
  • Python code delimited by %{...}%. Typically used to inject definitions (functions, classes, variable bindings) into the evaluation context of the template. Common indentation is stripped, so you can add as much indentation to the beginning of this code as you like
  • Lines beginning with optional whitespace followed by a single '%' and Python code. %-lines allow you to nest other constructs inside them. To close a level of nesting, use the %end construct.
  • Lines beginning with optional whitespace and followed by a single '%' and the token "end", which close open constructs in %-lines.

Some examples

Create implementations of all the math operators:

% for op,f in zip('+-*/', 'add sub mul div'.split()):
  public static func ${op}  (lhs:Self, rhs:Self  ) -> Self { return lhs.${f}( rhs) }
% end

Define a variable:

%{ types = ('Float', 'Double') }%

Mapping output lines to template lines

(Thanks to Dave Abrahams for the following explanation and examples.)

#sourceLocation is a directive used by tools like the Swift compiler and debugger to adjust the lines reported in diagnostics and to determine what source you see when you're stepping. #sourceLocation corresponds to #line in C/C++ which is inserted by code generators like Lex/Flex/Yacc/Bison so that you deal with the actual code you wrote and not the generated result. For dealing with errors in the Swift generated by your gyb source it's important that your tools can take you to the right line in your .gyb file rather than in generated .swift file. If you don't have such a tool, manually indirecting through the generated code is tedious, but at least it's possible since gyb leaves #sourceLocation information behind.

But Swift's #sourceLocation directive is suboptimal for the purposes of the freeform code generation done with gyb because it can only appear between grammatically-complete declarations and statements (or something like that). So instead of inserting #sourceLocation directives, gyb inserts // ###sourceLocation comments (by default---it's tunable). This line-directive tool remaps file and line information in the output of your swift compiler (or whatever tool you are using to process generated source---gyb is not swift-specific) so that the error points to the right place in the .gyb source. You invoke it as follows:

line-directive <generated-sources> -- <compilation command>

e.g., if you have foo.swift.gyb, bar.swift.gyb, and baz.swift, instead of

gyb foo.swift.gyb -o foo.swift
gyb bar.swift.gyb -o bar.swift
swiftc foo.swift bar.swift baz.swift

You do this:

gyb foo.swift.gyb -o foo.swift
gyb bar.swift.gyb -o bar.swift
line-directive foo.swift bar.swift -- swiftc foo.swift bar.swift baz.swift