Swift AST written in Swift. Part 4 of ∞
In previous part I have discussed let
and var
declrartions grammar. As I discovered, grammar reflects not all syntax restrictions of the language.
In this part I will discover structure of function
declaration. Let’s start from looking at formal grammar definition:
Single root declaration is good. It also contains a lot of subreferenses, let’s look into them more carefully.
First of all, let’s flatten this definition as much sa possible. Function head can be replaced with it’s own content, as no variance presented in its definition.
Second, function signature can be simplified by modeling parameter-clause
as [Parameter]
. throws
and rethrows
can be modeled as single optional enum.
After all simplification, function-declaration
can be expressed like this:
struct FunctionDeclaration {
let attributes: [Attribute]
let modifiers: [DeclarationModifier]
let name: FunctionName
let genericParamters: GenericParameterClause?
let parameters: [Parameter]
let throwBehavior: ThrowsModifier?
let result: FunctionResult?
let `where`: GenericWhereClause?
let body: CodeBlock?
}
A lot of optionals here. FunctionName
is the first extra definition. In Swift, function can represent regular method or operator body. Only change is grammar of FunctionName
. As usual, we will model it as enum
:
enum FunctionName {
case identifier(Identifier)
case `operator`(Operator)
}
Now we will cover Parameter
definition. There is 3 possible options for single paramter.
- With default value
- With variadic length (aka ellipsis)
- Simplest form without modifiers.
In other words we can optionally have one of two modifiers.
struct Parameter {
let externalName: Identifier?
let localName: Identifier
let type: TypeAnnotation
let modifier: ParameterModifier?
}enum ParameterModifier {
case `default`(Expression)
case ellipsis
}
So minimal representation of this would be just local name and type.
Next stop for us is definition of throwing. Function can be declared with throw
or rethrow
or without any. Again it looks like optional choice from 2 options.
enum ThrowsModifier {
case `throws`, `rethrows`
}
Last piece of FunctionDeclaration
is a function result. It is simple Type
in most cases, but we can specify custom attributes for it (do you know some examples?) so I will model it as struct:
struct FunctionResult {
let attributes: [Attribute]
let type: Type
}
Thats it.
Looks like function declaration is not so scary, or I become “bit of an expert in this things” © Daddy Pig.
In next part I will build enum
declaration model. I will try to keep this articles short and focused, and publish them more often.
Thank you for your time and interest in this area.