Implement static view extensions
An attempt at implementing static extensions with import/export as per #33. This is my first time contributing code to Vapor so please review.
This PR adds two new TemplateSyntax types: TemplateExtend and TemplateImport. TemplateExtend contains a path to a target template and a dictionary of exports (with type [String:[TemplateSyntax]]), while TemplateImport contains a string identifier referencing the name of an export. These types are included in the AST created by the TemplateParser, but they are replaced with their values by a new TemplateRenderer helper method called resolveExtensions (so they should never make it to TemplateSerializer).
resolveExtensions recursively traverses the AST. If it finds a TemplateExtend, it loads the referenced file, runs it through the TemplateParser, and substitutes it in place of the extend statement. It traverses the newly-loaded AST as well, keeping track of the extension's exports to substitute them in place of TemplateImports.
I also included a few test cases. I mocked the input ASTs in a slightly hacky way: I created template files on disk to avoid a file-not-found error, but used a parser that ignored the file contents and returned one of several hard-coded ASTs (using the filename as a selector).
I have not (yet) implemented following features alluded to in #33 or the Swift Forums pitch:
- Merging adjacent
TemplateRaws - Warnings for extraneous exports (errors for unresolved imports are implemented)
- Leaf parser support (this is a purely additive "backend" change. No existing features should break, but the Leaf parser needs to be modified to take advantage of the new feature.)