-
-
Save SebastiaanYN/72789494eb5bf1785ec9554d7ac7ed92 to your computer and use it in GitHub Desktop.
Implementation of multi inheritance output for a transpiler in JS
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
interface Parents { | |
[parent: string]: Class; | |
} | |
abstract class Class { | |
$child?: Class; | |
readonly $parents: Parents; | |
constructor($parents: Parents) { | |
this.$parents = $parents; | |
} | |
$instanceof(clazz: any): boolean { | |
if (clazz instanceof this.constructor) { | |
return true; | |
} | |
for (const parent of Object.values(this.$parents)) { | |
if (parent.$instanceof(clazz)) { | |
return true; | |
} | |
} | |
return false; | |
} | |
$callSelf(method: string, params: any[]): any { | |
return (this as any)[method](...params); | |
} | |
$callUp(method: string, params: any[]): any { | |
let highest: Class | undefined; | |
let current: Class = this; | |
// Find highest child with the given method name | |
while (current.$child) { | |
current = current.$child; | |
if (current.$has(method)) { | |
highest = current; | |
} | |
} | |
if (highest) { | |
return highest.$callSelf(method, params); | |
} | |
if (this.$has(method)) { | |
return this.$callSelf(method, params); | |
} | |
return this.$callDown(method, params); | |
} | |
$callDown(method: string, params: any[]): any { | |
if (this.$has(method)) { | |
return this.$callSelf(method, params); | |
} | |
let parents = Object.values(this.$parents); | |
while (parents.length) { | |
for (let i = 0; i < parents.length; i += 1) { | |
if (parents[i].$has(method)) { | |
return parents[i].$callSelf(method, params); | |
} | |
} | |
const newParents: Class[] = []; | |
for (let i = 0; i < parents.length; i += 1) { | |
newParents.push(...Object.values(parents[i].$parents)); | |
} | |
parents = newParents; | |
} | |
return undefined; | |
} | |
$has(prop: string): boolean { | |
return Object.prototype.hasOwnProperty.call(this, prop); | |
} | |
} | |
class A extends Class { | |
constructor() { | |
super({}); | |
} | |
print(): string { | |
return 'Class A'; | |
} | |
} | |
class B extends Class { | |
constructor() { | |
super({}); | |
} | |
print(): string { | |
return 'Class B'; | |
} | |
callOtherMethod(): string { | |
// This call would be equal to: this.print() | |
// It first checks if a child has the method, then checks for itself, then goes down | |
return this.$callUp('print', []); | |
} | |
} | |
class C extends Class { | |
constructor() { | |
// Pass parents of C | |
super({ A: new A(), B: new B() }); | |
} | |
// override because of naming collision | |
print(): string { | |
// This call would be equal to: A.super.print() | |
// It only goes down the chain | |
return this.$parents.A.$callDown('print', []); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment