@@ -652,22 +652,15 @@ const evaluate_map: EvaluateMap = {
652652 MemberExpression ( path ) {
653653 const { node, scope, ctx} = path ;
654654 const { object, property, computed} = node ;
655- if ( types . isSuper ( node . object ) ) {
656- const $var = scope . $find ( "this" ) ;
657- if ( $var ) {
658- const __this = $var . $get ( ) ;
659- if ( ctx . SuperClass ) {
660- return ctx . SuperClass . prototype [ ( < any > property ) . name ] . bind ( __this ) ;
661- } else {
662- throw node ;
663- }
664- }
665- }
666- if ( computed ) {
667- return evaluate ( path . $child ( object ) ) [ evaluate ( path . $child ( property ) ) ] ;
668- } else {
669- return evaluate ( path . $child ( object ) ) [ ( < types . Identifier > property ) . name ] ;
670- }
655+
656+ const propertyName : string = computed
657+ ? evaluate ( path . $child ( property ) )
658+ : ( < types . Identifier > property ) . name ;
659+
660+ const obj = evaluate ( path . $child ( object ) ) ;
661+ const target = obj [ propertyName ] ;
662+
663+ return typeof target === "function" ? target . bind ( obj ) : target ;
671664 } ,
672665 AssignmentExpression ( path ) {
673666 const { node, scope} = path ;
@@ -781,10 +774,10 @@ const evaluate_map: EvaluateMap = {
781774 }
782775 } ;
783776
784- Object . defineProperties ( func , {
785- length :{ value :node . params . length } ,
786- name : { value :node . id ? node . id . name : "" }
787- } )
777+ Object . defineProperties ( func , {
778+ length : { value : node . params . length } ,
779+ name : { value : node . id ? node . id . name : "" }
780+ } ) ;
788781
789782 return func ;
790783 } ,
@@ -800,96 +793,75 @@ const evaluate_map: EvaluateMap = {
800793 return path . node . value . raw ;
801794 } ,
802795 ClassDeclaration ( path ) {
796+ const ClassConstructor = evaluate (
797+ path . $child ( path . node . body , path . scope . $child ( "block" ) )
798+ ) ;
799+ path . scope . $const ( path . node . id . name , ClassConstructor ) ;
800+ } ,
801+ ClassBody ( path ) {
803802 const { node, scope} = path ;
804- const constructor : types . ClassMethod | void = < types . ClassMethod | void > node . body . body . find (
803+ const constructor : types . ClassMethod | void = < types . ClassMethod | void > node . body . find (
805804 n => types . isClassMethod ( n ) && n . kind === "constructor"
806805 ) ;
807- const methods : types . ClassMethod [ ] = < types . ClassMethod [ ] > node . body . body . filter (
806+ const methods : types . ClassMethod [ ] = < types . ClassMethod [ ] > node . body . filter (
808807 n => types . isClassMethod ( n ) && n . kind !== "constructor"
809808 ) ;
810- const properties : types . ClassProperty [ ] = < types . ClassProperty [ ] > node . body . body . filter (
809+ const properties : types . ClassProperty [ ] = < types . ClassProperty [ ] > node . body . filter (
811810 n => types . isClassProperty ( n )
812811 ) ;
813812
814- let SuperClass ;
815-
816- if ( node . superClass ) {
817- const superClassName : string = ( < any > node . superClass ) . name ;
818- const $var = scope . $find ( superClassName ) ;
819-
820- if ( $var ) {
821- SuperClass = $var . $get ( ) ;
822- } else {
823- throw new ErrNotDefined ( superClassName ) ;
824- }
825- }
813+ const parentNode = ( < Path < types . ClassDeclaration > > path . parent ) . node ;
826814
827815 const Class = ( function ( SuperClass ) {
828816 if ( SuperClass ) {
829817 _inherits ( Class , SuperClass ) ;
830818 }
819+
831820 function Class ( ...args ) {
832821 _classCallCheck ( this , Class ) ;
833-
834- const newScope = scope . $child ( "function" ) ;
835-
836- // babel way to call super();
837- const __this = _possibleConstructorReturn (
838- this ,
839- ( ( < any > Class ) . __proto__ || Object . getPrototypeOf ( Class ) ) . apply (
840- this ,
841- args
842- )
843- ) ;
844-
845- newScope . $const ( "super" , this . __proto__ ) ;
846-
847- // typescript way to call super()
848- // const __this = superClass ? superClass.apply(this, args) || this : this;
849-
850- newScope . $const ( "this" , __this ) ;
822+ const classScope = scope . $child ( "function" ) ;
823+ classScope . $var ( "this" , this ) ;
851824
852825 // define class property
853826 properties . forEach ( p => {
854- __this [ p . key . name ] = evaluate ( path . $child ( p . value , newScope ) ) ;
827+ this [ p . key . name ] = evaluate ( path . $child ( p . value , classScope ) ) ;
855828 } ) ;
856829
857830 if ( constructor ) {
858831 // defined the params
859832 constructor . params . forEach ( ( p : types . LVal , i ) => {
860833 if ( types . isIdentifier ( p ) ) {
861- newScope . $const ( p . name , args [ i ] ) ;
834+ classScope . $const ( p . name , args [ i ] ) ;
862835 } else {
863836 throw new Error ( "Invalid params" ) ;
864837 }
865838 } ) ;
839+ constructor . body . body . forEach ( n =>
840+ evaluate (
841+ path . $child ( n , classScope , {
842+ SuperClass,
843+ ClassConstructor : Class ,
844+ ClassConstructorArguments : args ,
845+ ClassEntity : this
846+ } )
847+ )
848+ ) ;
866849
867- if ( node . superClass ) {
868- // make sure super exist in first line
869- const superCallExpression : types . ExpressionStatement = < types . ExpressionStatement > ( < any > constructor ) . body . body . shift ( ) ;
870-
871- if (
872- ! types . isExpressionStatement ( superCallExpression ) ||
873- ! types . isCallExpression ( superCallExpression . expression ) ||
874- ! types . isSuper ( superCallExpression . expression . callee )
875- ) {
850+ if ( parentNode . superClass ) {
851+ // if not apply super in construtor
852+ // FIXME: should define the var in private scope
853+ if ( ! scope . $find ( "@super" ) ) {
876854 throw ErrNoSuper ;
877- } else {
878- // TODO: run super
879855 }
880856 }
881-
882- constructor . body . body . forEach ( n =>
883- evaluate ( path . $child ( n , newScope , { SuperClass} ) )
884- ) ;
885857 }
886858
887- return __this ;
859+ return this ;
888860 }
889861
890862 // define class name
891863 Object . defineProperties ( Class , {
892- name : { value : node . id . name } ,
864+ name : { value : parentNode . id . name } ,
893865 length : { value : constructor ? constructor . params . length : 0 }
894866 } ) ;
895867
@@ -907,7 +879,12 @@ const evaluate_map: EvaluateMap = {
907879 } ) ;
908880
909881 const result = evaluate (
910- path . $child ( method . body , newScope , { SuperClass} )
882+ path . $child ( method . body , newScope , {
883+ SuperClass,
884+ ClassConstructor : Class ,
885+ ClassMethodArguments : args ,
886+ ClassEntity : this
887+ } )
911888 ) ;
912889 if ( result === RETURN_SINGAL ) {
913890 return result . result ? result . result : result ;
@@ -934,17 +911,54 @@ const evaluate_map: EvaluateMap = {
934911 _createClass ( Class , _methods ) ;
935912
936913 return Class ;
937- } ) ( SuperClass ) ;
914+ } ) (
915+ parentNode . superClass
916+ ? ( ( ) => {
917+ const $var = scope . $find ( ( < any > parentNode . superClass ) . name ) ;
918+ return $var ? $var . $get ( ) : null ;
919+ } ) ( )
920+ : null
921+ ) ;
938922
939- scope . $const ( node . id . name , Class ) ;
923+ return Class ;
940924 } ,
941925 ClassMethod ( path ) {
942926 return evaluate ( path . $child ( path . node . body ) ) ;
943927 } ,
944928 ClassExpression ( path ) { } ,
945929 Super ( path ) {
946- // FIXME: check it include in Class expression
947- return function ( ) { } ;
930+ const { scope, ctx} = path ;
931+ const {
932+ SuperClass,
933+ ClassConstructor,
934+ ClassConstructorArguments,
935+ ClassEntity
936+ } = ctx ;
937+ const ClassBodyPath = path . $findParent ( "ClassBody" ) ;
938+ // make sure it include in ClassDeclaration
939+ if ( ! ClassBodyPath ) {
940+ throw new Error ( "super() only can use in ClassDeclaration" ) ;
941+ }
942+ const parentPath = path . parent ;
943+ if ( parentPath ) {
944+ // super()
945+ if ( types . isCallExpression ( parentPath . node ) ) {
946+ return function inherits ( ...args ) {
947+ _possibleConstructorReturn (
948+ ClassEntity ,
949+ (
950+ ( < any > ClassConstructor ) . __proto__ ||
951+ Object . getPrototypeOf ( ClassConstructor )
952+ ) . apply ( ClassEntity , args )
953+ ) ;
954+ ClassBodyPath . scope . $const ( "@super" , true ) ;
955+ } . bind ( ClassEntity ) ;
956+ } else if ( types . isMemberExpression ( parentPath . node ) ) {
957+ // super.eat()
958+ // then return the superclass prototype
959+ return SuperClass . prototype ;
960+ }
961+ }
948962 } ,
949963 SpreadElement ( path ) {
950964 return evaluate ( path . $child ( path . node . argument ) ) ;
0 commit comments