* ```abnf * FnDef = "@" IDENT [TypeParams] Params [":" Type] Block * ```
(s: ITokenStream)
| 150 | * ``` |
| 151 | */ |
| 152 | function parseFnDef(s: ITokenStream): Ast.Definition { |
| 153 | const startPos = s.getPos(); |
| 154 | |
| 155 | s.expect(TokenKind.At); |
| 156 | s.next(); |
| 157 | |
| 158 | s.expect(TokenKind.Identifier); |
| 159 | const nameStartPos = s.getPos(); |
| 160 | const name = s.getTokenValue(); |
| 161 | s.next(); |
| 162 | const dest = NODE('identifier', { name }, nameStartPos, s.getPos()); |
| 163 | |
| 164 | let typeParams: Ast.TypeParam[]; |
| 165 | if (s.is(TokenKind.Lt)) { |
| 166 | typeParams = parseTypeParams(s); |
| 167 | } else { |
| 168 | typeParams = []; |
| 169 | } |
| 170 | |
| 171 | const params = parseParams(s); |
| 172 | |
| 173 | let type: Ast.TypeSource | undefined; |
| 174 | if (s.is(TokenKind.Colon)) { |
| 175 | s.next(); |
| 176 | type = parseType(s); |
| 177 | } |
| 178 | |
| 179 | const body = parseBlock(s); |
| 180 | |
| 181 | const endPos = s.getPos(); |
| 182 | |
| 183 | return NODE('def', { |
| 184 | dest, |
| 185 | expr: NODE('fn', { |
| 186 | typeParams, |
| 187 | params: params, |
| 188 | retType: type, |
| 189 | children: body, |
| 190 | }, startPos, endPos), |
| 191 | mut: false, |
| 192 | attr: [], |
| 193 | }, startPos, endPos); |
| 194 | } |
| 195 | |
| 196 | /** |
| 197 | * ```abnf |
no test coverage detected