1- import { buildMatch } from " ./match" ;
2- import * as Types from " ./types" ;
1+ import { buildMatch } from ' ./match' ;
2+ import * as Types from ' ./types' ;
33
44const FUNC = Symbol ( ) ;
55
66export class MatchError extends Error {
77 constructor ( arg ) {
88 super ( ) ;
99
10- if ( typeof arg === " symbol" ) {
11- this . message = " No match for: " + arg . toString ( ) ;
10+ if ( typeof arg === ' symbol' ) {
11+ this . message = ' No match for: ' + arg . toString ( ) ;
1212 } else if ( Array . isArray ( arg ) ) {
1313 let mappedValues = arg . map ( x => x . toString ( ) ) ;
14- this . message = " No match for: " + mappedValues ;
14+ this . message = ' No match for: ' + mappedValues ;
1515 } else {
16- this . message = " No match for: " + arg ;
16+ this . message = ' No match for: ' + arg ;
1717 }
1818
1919 this . stack = new Error ( ) . stack ;
@@ -46,15 +46,48 @@ export function trampoline(fn) {
4646}
4747
4848export function defmatch ( ...clauses ) {
49+ const arities = getArityMap ( clauses ) ;
50+
4951 return function ( ...args ) {
52+ let [ funcToCall , params ] = findMatchingFunction ( args , arities ) ;
53+ return funcToCall . apply ( this , params ) ;
54+ } ;
55+ }
56+
57+ export function defmatchgen ( ...clauses ) {
58+ const arities = getArityMap ( clauses ) ;
59+
60+ return function * ( ...args ) {
61+ let [ funcToCall , params ] = findMatchingFunction ( args , arities ) ;
62+ return yield * funcToCall . apply ( this , params ) ;
63+ } ;
64+ }
65+
66+ export function defmatchGen ( ...args ) {
67+ return defmatchgen ( ...args ) ;
68+ }
69+
70+ export function defmatchAsync ( ...clauses ) {
71+ const arities = getArityMap ( clauses ) ;
72+
73+ return async function ( ...args ) {
74+ let [ funcToCall , params ] = findMatchingFunction ( args , arities ) ;
75+ return funcToCall . apply ( this , params ) ;
76+ } ;
77+ }
78+
79+ function findMatchingFunction ( args , arities ) {
80+ if ( arities . has ( args . length ) ) {
81+ const arityClauses = arities . get ( args . length ) ;
82+
5083 let funcToCall = null ;
5184 let params = null ;
52- for ( let processedClause of clauses ) {
85+ for ( let processedClause of arityClauses ) {
5386 let result = [ ] ;
5487 args = fillInOptionalValues (
5588 args ,
5689 processedClause . arity ,
57- processedClause . optionals
90+ processedClause . optionals ,
5891 ) ;
5992
6093 if (
@@ -68,35 +101,49 @@ export function defmatch(...clauses) {
68101 }
69102
70103 if ( ! funcToCall ) {
71- console . error ( " No match for:" , args ) ;
104+ console . error ( ' No match for:' , args ) ;
72105 throw new MatchError ( args ) ;
73106 }
74107
75- return funcToCall . apply ( this , params ) ;
76- } ;
108+ return [ funcToCall , params ] ;
109+ } else {
110+ console . error ( 'Arity of' , args . length , 'not found. No match for:' , args ) ;
111+ throw new MatchError ( args ) ;
112+ }
77113}
78114
79- export function defmatchgen ( ...clauses ) {
80- return function * ( ...args ) {
81- for ( let processedClause of clauses ) {
82- let result = [ ] ;
83- args = fillInOptionalValues (
84- args ,
85- processedClause . arity ,
86- processedClause . optionals
87- ) ;
115+ function getArityMap ( clauses ) {
116+ let map = new Map ( ) ;
88117
89- if (
90- processedClause . pattern ( args , result ) &&
91- processedClause . guard . apply ( this , result )
92- ) {
93- return yield * processedClause . fn . apply ( this , result ) ;
118+ for ( const clause of clauses ) {
119+ const range = getArityRange ( clause ) ;
120+
121+ for ( const arity of range ) {
122+ let arityClauses = [ ] ;
123+
124+ if ( map . has ( arity ) ) {
125+ arityClauses = map . get ( arity ) ;
94126 }
127+
128+ arityClauses . push ( clause ) ;
129+ map . set ( arity , arityClauses ) ;
95130 }
131+ }
96132
97- console . error ( "No match for:" , args ) ;
98- throw new MatchError ( args ) ;
99- } ;
133+ return map ;
134+ }
135+
136+ function getArityRange ( clause ) {
137+ const min = clause . arity - clause . optionals . length ;
138+ const max = clause . arity ;
139+
140+ let range = [ min ] ;
141+
142+ while ( range [ range . length - 1 ] != max ) {
143+ range . push ( range [ range . length - 1 ] + 1 ) ;
144+ }
145+
146+ return range ;
100147}
101148
102149function getOptionalValues ( pattern ) {
@@ -105,7 +152,7 @@ function getOptionalValues(pattern) {
105152 for ( let i = 0 ; i < pattern . length ; i ++ ) {
106153 if (
107154 pattern [ i ] instanceof Types . Variable &&
108- pattern [ i ] . default_value != Symbol . for ( " tailored.no_value" )
155+ pattern [ i ] . default_value != Symbol . for ( ' tailored.no_value' )
109156 ) {
110157 optionals . push ( [ i , pattern [ i ] . default_value ] ) ;
111158 }
@@ -144,7 +191,7 @@ export function match(pattern, expr, guard = () => true) {
144191 if ( processedPattern ( expr , result ) && guard . apply ( this , result ) ) {
145192 return result ;
146193 } else {
147- console . error ( " No match for:" , expr ) ;
194+ console . error ( ' No match for:' , expr ) ;
148195 throw new MatchError ( expr ) ;
149196 }
150197}
@@ -153,7 +200,7 @@ export function match_or_default(
153200 pattern ,
154201 expr ,
155202 guard = ( ) => true ,
156- default_value = null
203+ default_value = null ,
157204) {
158205 let result = [ ] ;
159206 let processedPattern = buildMatch ( pattern ) ;
0 commit comments