@@ -12,20 +12,27 @@ export interface Options {
1212 foldName : string
1313 /** the name used for the input of pattern matching functions */
1414 matcheeName : string
15+ /**
16+ * the pattern matching handlers can be expressed as positional arguments
17+ * or a single object literal `tag -> handler`
18+ */
19+ handlersStyle : { type : 'positional' } | { type : 'record' ; handlersName : string }
1520}
1621
1722export const defaultOptions : Options = {
1823 tagName : 'type' ,
1924 foldName : 'fold' ,
20- matcheeName : 'fa'
25+ matcheeName : 'fa' ,
26+ handlersStyle : { type : 'positional' }
2127}
2228
2329const getLens = Lens . fromProp < Options > ( )
2430
2531export const lenses : { [ K in keyof Options ] : Lens < Options , Options [ K ] > } = {
2632 tagName : getLens ( 'tagName' ) ,
2733 foldName : getLens ( 'foldName' ) ,
28- matcheeName : getLens ( 'matcheeName' )
34+ matcheeName : getLens ( 'matcheeName' ) ,
35+ handlersStyle : getLens ( 'handlersStyle' )
2936}
3037
3138export interface AST < A > extends Reader < Options , A > { }
@@ -198,9 +205,96 @@ const getHandlerName = (c: M.Constructor): string => {
198205 return `on${ c . name } `
199206}
200207
208+ const getPositionalFoldHandlers = ( d : M . Data , isEager : boolean ) : Array < ts . ParameterDeclaration > => {
209+ const returnTypeParameterName = getFoldReturnTypeParameterName ( d . introduction )
210+ return d . constructors . toArray ( ) . map ( c => {
211+ const type =
212+ isEager && isNullaryConstructor ( c )
213+ ? ts . createTypeReferenceNode ( returnTypeParameterName , [ ] )
214+ : ts . createFunctionTypeNode (
215+ undefined ,
216+ c . members . map ( ( m , position ) => getParameterDeclaration ( getMemberName ( m , position ) , getType ( m . type ) ) ) ,
217+ ts . createTypeReferenceNode ( returnTypeParameterName , [ ] )
218+ )
219+ return getParameterDeclaration ( getHandlerName ( c ) , type )
220+ } )
221+ }
222+
223+ const getRecordFoldHandlers = ( d : M . Data , handlersName : string , isEager : boolean ) : Array < ts . ParameterDeclaration > => {
224+ const returnTypeParameterName = getFoldReturnTypeParameterName ( d . introduction )
225+ const type = ts . createTypeLiteralNode (
226+ d . constructors . toArray ( ) . map ( c => {
227+ const type =
228+ isEager && isNullaryConstructor ( c )
229+ ? ts . createTypeReferenceNode ( returnTypeParameterName , [ ] )
230+ : ts . createFunctionTypeNode (
231+ undefined ,
232+ c . members . map ( ( m , position ) => getParameterDeclaration ( getMemberName ( m , position ) , getType ( m . type ) ) ) ,
233+ ts . createTypeReferenceNode ( returnTypeParameterName , [ ] )
234+ )
235+ return ts . createPropertySignature ( undefined , getHandlerName ( c ) , undefined , type , undefined )
236+ } )
237+ )
238+ return [ getParameterDeclaration ( handlersName , type ) ]
239+ }
240+
241+ const getPositionalFoldBody = ( d : M . Data , matcheeName : string , tagName : string , isEager : boolean ) => {
242+ return ts . createBlock ( [
243+ ts . createSwitch (
244+ ts . createPropertyAccess ( ts . createIdentifier ( matcheeName ) , tagName ) ,
245+ ts . createCaseBlock (
246+ d . constructors . toArray ( ) . map ( c => {
247+ const access = ts . createIdentifier ( getHandlerName ( c ) )
248+ return ts . createCaseClause ( ts . createStringLiteral ( c . name ) , [
249+ ts . createReturn (
250+ isEager && isNullaryConstructor ( c )
251+ ? access
252+ : ts . createCall (
253+ access ,
254+ [ ] ,
255+ c . members . map ( ( m , position ) => {
256+ return ts . createPropertyAccess ( ts . createIdentifier ( matcheeName ) , getMemberName ( m , position ) )
257+ } )
258+ )
259+ )
260+ ] )
261+ } )
262+ )
263+ )
264+ ] )
265+ }
266+
267+ const getRecordFoldBody = ( d : M . Data , matcheeName : string , tagName : string , handlersName : string , isEager : boolean ) => {
268+ return ts . createBlock ( [
269+ ts . createSwitch (
270+ ts . createPropertyAccess ( ts . createIdentifier ( matcheeName ) , tagName ) ,
271+ ts . createCaseBlock (
272+ d . constructors . toArray ( ) . map ( c => {
273+ const access = ts . createPropertyAccess ( ts . createIdentifier ( handlersName ) , getHandlerName ( c ) )
274+ return ts . createCaseClause ( ts . createStringLiteral ( c . name ) , [
275+ ts . createReturn (
276+ isEager && isNullaryConstructor ( c )
277+ ? access
278+ : ts . createCall (
279+ access ,
280+ [ ] ,
281+ c . members . map ( ( m , position ) => {
282+ return ts . createPropertyAccess ( ts . createIdentifier ( matcheeName ) , getMemberName ( m , position ) )
283+ } )
284+ )
285+ )
286+ ] )
287+ } )
288+ )
289+ )
290+ ] )
291+ }
292+
201293const getFold = ( d : M . Data , name : string , isEager : boolean ) : AST < ts . FunctionDeclaration > => {
202294 return new Reader ( e => {
203295 const matcheeName = e . matcheeName
296+ const tagName = e . tagName
297+ const handlersStyle = e . handlersStyle
204298 const returnTypeParameterName = getFoldReturnTypeParameterName ( d . introduction )
205299 const typeParameters = d . introduction . parameters
206300 . concat ( M . parameter ( returnTypeParameterName , none ) )
@@ -212,41 +306,16 @@ const getFold = (d: M.Data, name: string, isEager: boolean): AST<ts.FunctionDecl
212306 d . introduction . parameters . map ( p => ts . createTypeReferenceNode ( p . name , [ ] ) )
213307 )
214308 )
215- const handlers = d . constructors . toArray ( ) . map ( c => {
216- const type =
217- isEager && isNullaryConstructor ( c )
218- ? ts . createTypeReferenceNode ( returnTypeParameterName , [ ] )
219- : ts . createFunctionTypeNode (
220- undefined ,
221- c . members . map ( ( m , position ) => getParameterDeclaration ( getMemberName ( m , position ) , getType ( m . type ) ) ) ,
222- ts . createTypeReferenceNode ( returnTypeParameterName , [ ] )
223- )
224- return getParameterDeclaration ( getHandlerName ( c ) , type )
225- } )
309+ const handlers =
310+ handlersStyle . type === 'positional'
311+ ? getPositionalFoldHandlers ( d , isEager )
312+ : getRecordFoldHandlers ( d , handlersStyle . handlersName , isEager )
226313 const parameters = [ matchee , ...handlers ]
227314 const type = ts . createTypeReferenceNode ( returnTypeParameterName , [ ] )
228- const body = ts . createBlock ( [
229- ts . createSwitch (
230- ts . createPropertyAccess ( ts . createIdentifier ( matcheeName ) , e . tagName ) ,
231- ts . createCaseBlock (
232- d . constructors . toArray ( ) . map ( c => {
233- return ts . createCaseClause ( ts . createStringLiteral ( c . name ) , [
234- ts . createReturn (
235- isEager && isNullaryConstructor ( c )
236- ? ts . createIdentifier ( getHandlerName ( c ) )
237- : ts . createCall (
238- ts . createIdentifier ( getHandlerName ( c ) ) ,
239- [ ] ,
240- c . members . map ( ( m , position ) => {
241- return ts . createPropertyAccess ( ts . createIdentifier ( matcheeName ) , getMemberName ( m , position ) )
242- } )
243- )
244- )
245- ] )
246- } )
247- )
248- )
249- ] )
315+ const body =
316+ handlersStyle . type === 'positional'
317+ ? getPositionalFoldBody ( d , matcheeName , tagName , isEager )
318+ : getRecordFoldBody ( d , matcheeName , tagName , handlersStyle . handlersName , isEager )
250319 return getFunctionDeclaration ( name , typeParameters , parameters , type , body )
251320 } )
252321}
0 commit comments