refactor: Avoid inheritance and ban instanceof #37
1 changed files with 27 additions and 19 deletions
|
|
@ -5,7 +5,7 @@ const tpBrand = Symbol()
|
||||||
|
|
||||||
export class TypePattern {
|
export class TypePattern {
|
||||||
constructor() {
|
constructor() {
|
||||||
this[tpBrand] = true
|
throw new Error('Cannot construct an abstract TypePattern')
|
||||||
}
|
}
|
||||||
match(_typeSequence, _options={}) {
|
match(_typeSequence, _options={}) {
|
||||||
throw new Error('Specific TypePatterns must implement match')
|
throw new Error('Specific TypePatterns must implement match')
|
||||||
|
|
@ -13,16 +13,15 @@ export class TypePattern {
|
||||||
sampleTypes() {
|
sampleTypes() {
|
||||||
throw new Error('Specific TypePatterns must implement sampleTypes')
|
throw new Error('Specific TypePatterns must implement sampleTypes')
|
||||||
}
|
}
|
||||||
equal(other) {return other.constructor === this.constructor}
|
|
||||||
toString() {return 'Abstract Pattern (?!)'}
|
toString() {return 'Abstract Pattern (?!)'}
|
||||||
|
|
||||||
// Returns true if entity is a TypePattern
|
// Returns true if entity is a TypePattern
|
||||||
static holds(entity) {return entity[tpBrand]}
|
static holds(entity) {return entity[tpBrand]}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MatchTypePattern extends TypePattern {
|
class MatchTypePattern {
|
||||||
constructor(typeToMatch) {
|
constructor(typeToMatch) {
|
||||||
super()
|
this[tpBrand] = true
|
||||||
this.type = typeToMatch
|
this.type = typeToMatch
|
||||||
}
|
}
|
||||||
match(typeSequence, options={}) {
|
match(typeSequence, options={}) {
|
||||||
|
|
@ -42,13 +41,15 @@ class MatchTypePattern extends TypePattern {
|
||||||
return [-1, Undefined]
|
return [-1, Undefined]
|
||||||
}
|
}
|
||||||
sampleTypes() {return [this.type]}
|
sampleTypes() {return [this.type]}
|
||||||
equal(other) {return super.equal(other) && this.type === other.type}
|
equal(other) {
|
||||||
|
return this.constructor === other.constructor && this.type === other.type
|
||||||
|
}
|
||||||
toString() {return `Match(${this.type})`}
|
toString() {return `Match(${this.type})`}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SequencePattern extends TypePattern {
|
class SequencePattern {
|
||||||
constructor(itemsToMatch) {
|
constructor(itemsToMatch) {
|
||||||
super()
|
this[tpBrand] = true
|
||||||
this.patterns = itemsToMatch.map(pattern)
|
this.patterns = itemsToMatch.map(pattern)
|
||||||
}
|
}
|
||||||
match(typeSequence, options={_internal: true}) {
|
match(typeSequence, options={_internal: true}) {
|
||||||
|
|
@ -70,16 +71,16 @@ class SequencePattern extends TypePattern {
|
||||||
return this.patterns.map(pat => pat.sampleTypes()).flat()
|
return this.patterns.map(pat => pat.sampleTypes()).flat()
|
||||||
}
|
}
|
||||||
equal(other) {
|
equal(other) {
|
||||||
return super.equal(other)
|
return this.constructor === other.constructor
|
||||||
&& this.patterns.length === other.patterns.length
|
&& this.patterns.length === other.patterns.length
|
||||||
&& this.patterns.every((elt, ix) => elt.equal(other.patterns[ix]))
|
&& this.patterns.every((elt, ix) => elt.equal(other.patterns[ix]))
|
||||||
}
|
}
|
||||||
toString() {return `[${this.patterns}]`}
|
toString() {return `[${this.patterns}]`}
|
||||||
}
|
}
|
||||||
|
|
||||||
class PredicatePattern extends TypePattern {
|
class PredicatePattern {
|
||||||
constructor(predicate) {
|
constructor(predicate) {
|
||||||
super()
|
this[tpBrand] = true
|
||||||
this.predicate = predicate
|
this.predicate = predicate
|
||||||
}
|
}
|
||||||
match(typeSequence, options={}) {
|
match(typeSequence, options={}) {
|
||||||
|
|
@ -93,7 +94,8 @@ class PredicatePattern extends TypePattern {
|
||||||
throw new Error('sampleTypes() not yet implemented for PredicatePattern')
|
throw new Error('sampleTypes() not yet implemented for PredicatePattern')
|
||||||
}
|
}
|
||||||
equal(other) {
|
equal(other) {
|
||||||
return super.equal(other) && this.predicate === other.predicate
|
return this.constructor === other.constructor
|
||||||
|
&& this.predicate === other.predicate
|
||||||
}
|
}
|
||||||
toString() {return `Test(${this.predicate})`}
|
toString() {return `Test(${this.predicate})`}
|
||||||
}
|
}
|
||||||
|
|
@ -110,7 +112,8 @@ export const pattern = patternOrSpec => {
|
||||||
throw new TypeError(`Can't interpret '${patternOrSpec}' as a type pattern`)
|
throw new TypeError(`Can't interpret '${patternOrSpec}' as a type pattern`)
|
||||||
}
|
}
|
||||||
|
|
||||||
class AnyPattern extends TypePattern {
|
class AnyPattern {
|
||||||
|
constructor () {this[tpBrand] = true}
|
||||||
match(typeSequence, options={}) {
|
match(typeSequence, options={}) {
|
||||||
const position = options.position ?? 0
|
const position = options.position ?? 0
|
||||||
return position < typeSequence.length
|
return position < typeSequence.length
|
||||||
|
|
@ -118,14 +121,15 @@ class AnyPattern extends TypePattern {
|
||||||
: [-1, Undefined]
|
: [-1, Undefined]
|
||||||
}
|
}
|
||||||
sampleTypes() {return [Undefined]}
|
sampleTypes() {return [Undefined]}
|
||||||
|
equal(other) {return this.constructor === other.constructor}
|
||||||
toString() {return 'Any'}
|
toString() {return 'Any'}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Any = new AnyPattern()
|
export const Any = new AnyPattern()
|
||||||
|
|
||||||
class OptionalPattern extends TypePattern {
|
class OptionalPattern {
|
||||||
constructor(item) {
|
constructor(item) {
|
||||||
super()
|
this[tpBrand] = true
|
||||||
this.pattern = pattern(item)
|
this.pattern = pattern(item)
|
||||||
}
|
}
|
||||||
match(typeSequence, options={_internal: true}) {
|
match(typeSequence, options={_internal: true}) {
|
||||||
|
|
@ -143,16 +147,17 @@ class OptionalPattern extends TypePattern {
|
||||||
}
|
}
|
||||||
sampleTypes() {return []}
|
sampleTypes() {return []}
|
||||||
equal(other) {
|
equal(other) {
|
||||||
return super.equal(other) && this.pattern.equal(other.pattern)
|
return this.constructor === other.constructor
|
||||||
|
&& this.pattern.equal(other.pattern)
|
||||||
}
|
}
|
||||||
toString() {return `?${this.pattern}`}
|
toString() {return `?${this.pattern}`}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Optional = item => new OptionalPattern(item)
|
export const Optional = item => new OptionalPattern(item)
|
||||||
|
|
||||||
class MultiPattern extends TypePattern {
|
class MultiPattern {
|
||||||
constructor(item) {
|
constructor(item) {
|
||||||
super()
|
this[tpBrand] = true
|
||||||
this.pattern = pattern(item)
|
this.pattern = pattern(item)
|
||||||
}
|
}
|
||||||
match(typeSequence, options={_internal: true}) {
|
match(typeSequence, options={_internal: true}) {
|
||||||
|
|
@ -170,7 +175,8 @@ class MultiPattern extends TypePattern {
|
||||||
}
|
}
|
||||||
sampleTypes() {return []}
|
sampleTypes() {return []}
|
||||||
equal(other) {
|
equal(other) {
|
||||||
return super.equal(other) && this.pattern.equal(other.pattern)
|
return this.constructor === other.constructor
|
||||||
|
&& this.pattern.equal(other.pattern)
|
||||||
}
|
}
|
||||||
toString() {return `${this.pattern}*`}
|
toString() {return `${this.pattern}*`}
|
||||||
}
|
}
|
||||||
|
|
@ -179,13 +185,15 @@ export const Multiple = item => new MultiPattern(item)
|
||||||
|
|
||||||
// Like Multiple(Any) except leaves the argument list alone; it doesn't
|
// Like Multiple(Any) except leaves the argument list alone; it doesn't
|
||||||
// chunk it into a single Array of all arguments
|
// chunk it into a single Array of all arguments
|
||||||
class PassthruPattern extends TypePattern {
|
class PassthruPattern {
|
||||||
|
constructor () {this[tpBrand] = true}
|
||||||
match(typeSequence, options={}) {
|
match(typeSequence, options={}) {
|
||||||
const position = options.position ?? 0
|
const position = options.position ?? 0
|
||||||
return [typeSequence.length, typeSequence.slice(position)]
|
return [typeSequence.length, typeSequence.slice(position)]
|
||||||
}
|
}
|
||||||
sampleTypes() {return []}
|
sampleTypes() {return []}
|
||||||
toString() {return 'Passthru'}
|
toString() {return 'Passthru'}
|
||||||
|
equal(other) {return this.constructor === other.constructor}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Passthru = new PassthruPattern()
|
export const Passthru = new PassthruPattern()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue