@@ -67,7 +67,10 @@ import {
67
67
68
68
hasDecorator ,
69
69
hasModifier ,
70
- mangleInternalName
70
+ mangleInternalName ,
71
+ ElementAccessExpression ,
72
+ ThisExpression ,
73
+ SuperExpression
71
74
} from "./ast" ;
72
75
73
76
import {
@@ -896,11 +899,11 @@ export class Program extends DiagnosticEmitter {
896
899
}
897
900
898
901
/** Resolves an identifier to the element it refers to. */
899
- resolveIdentifier ( identifier : IdentifierExpression , contextualFunction : Function ) : Element | null {
902
+ resolveIdentifier ( identifier : IdentifierExpression , contextualFunction : Function ) : ResolvedElement | null {
900
903
var name = identifier . name ;
901
904
var local = contextualFunction . locals . get ( name ) ;
902
905
if ( local )
903
- return local ;
906
+ return resolvedElement . set ( local ) ;
904
907
905
908
var element : Element | null ;
906
909
var namespace : Element | null ;
@@ -909,96 +912,131 @@ export class Program extends DiagnosticEmitter {
909
912
if ( contextualFunction && ( namespace = contextualFunction . prototype . namespace ) ) {
910
913
do {
911
914
if ( element = this . elements . get ( namespace . internalName + STATIC_DELIMITER + name ) )
912
- return element ;
915
+ return resolvedElement . set ( element ) ;
913
916
} while ( namespace = namespace . namespace ) ;
914
917
}
915
918
916
919
// search current file
917
920
if ( element = this . elements . get ( identifier . range . source . internalPath + PATH_DELIMITER + name ) )
918
- return element ;
921
+ return resolvedElement . set ( element ) ;
919
922
920
923
// search global scope
921
924
if ( element = this . elements . get ( name ) )
922
- return element ;
925
+ return resolvedElement . set ( element ) ;
923
926
924
927
this . error ( DiagnosticCode . Cannot_find_name_0 , identifier . range , name ) ;
925
928
return null ;
926
929
}
927
930
928
931
/** Resolves a property access to the element it refers to. */
929
- resolvePropertyAccess ( propertyAccess : PropertyAccessExpression , contextualFunction : Function ) : Element | null {
930
- var expression = propertyAccess . expression ;
931
- var target : Element | null = null ;
932
- switch ( expression . kind ) {
933
-
934
- case NodeKind . IDENTIFIER :
935
- target = this . resolveIdentifier ( < IdentifierExpression > expression , contextualFunction ) ;
936
- break ;
937
-
938
- case NodeKind . PROPERTYACCESS :
939
- target = this . resolvePropertyAccess ( < PropertyAccessExpression > expression , contextualFunction ) ;
940
- break ;
941
-
942
- // case NodeKind.ELEMENTACCESS:
932
+ resolvePropertyAccess ( propertyAccess : PropertyAccessExpression , contextualFunction : Function ) : ResolvedElement | null {
933
+ var resolved : ResolvedElement | null ;
943
934
944
- default :
945
- throw new Error ( "property target expected" ) ;
946
- }
947
- if ( ! target )
935
+ // start by resolving the lhs target (expression before the last dot)
936
+ var targetExpression = propertyAccess . expression ;
937
+ if ( ! ( resolved = this . resolveExpression ( targetExpression , contextualFunction ) ) )
948
938
return null ;
939
+ var target = resolved . element ;
949
940
941
+ // at this point we know exactly what the target is, so look up the element within
950
942
var propertyName = propertyAccess . property . name ;
943
+ var targetType : Type | null ;
951
944
switch ( target . kind ) {
952
945
953
946
case ElementKind . GLOBAL :
954
947
case ElementKind . LOCAL :
955
- var type = ( < VariableLikeElement > target ) . type ;
956
- assert ( type != null ) ; // locals don't have lazy types, unlike globals
957
- if ( ( < Type > type ) . classType ) {
958
- target = < Class > ( < Type > type ) . classType ;
948
+ targetType = ( < VariableLikeElement > target ) . type ;
949
+ if ( ! targetType ) // FIXME: are globals always resolved here?
950
+ throw new Error ( "type expected" ) ;
951
+ if ( targetType . classType )
952
+ target = targetType . classType ;
959
953
// fall-through
960
- } else
954
+ else
961
955
break ;
962
956
963
957
default :
964
958
if ( target . members ) {
965
959
var member = target . members . get ( propertyName ) ;
966
960
if ( member )
967
- return member ;
961
+ return resolvedElement . set ( member ) . withTarget ( target , targetExpression ) ;
968
962
}
969
963
break ;
970
964
}
971
- this . error ( DiagnosticCode . Property_0_does_not_exist_on_type_1 , propertyAccess . property . range , propertyAccess . property . name , target . internalName ) ;
965
+ this . error ( DiagnosticCode . Property_0_does_not_exist_on_type_1 , propertyAccess . property . range , propertyName , target . internalName ) ;
972
966
return null ;
973
967
}
974
968
975
- resolveElement ( expression : Expression , contextualFunction : Function ) : Element | null {
969
+ resolveElementAccess ( elementAccess : ElementAccessExpression , contextualFunction : Function ) : ResolvedElement | null {
970
+ var resolved : ResolvedElement | null ;
976
971
977
- // this -> Class
978
- if ( expression . kind == NodeKind . THIS ) {
979
- if ( contextualFunction . instanceMethodOf )
980
- return contextualFunction . instanceMethodOf ;
981
- this . error ( DiagnosticCode . _this_cannot_be_referenced_in_current_location , expression . range ) ;
972
+ // start by resolving the lhs target (expression before the last dot)
973
+ var targetExpression = elementAccess . expression ;
974
+ if ( ! ( resolved = this . resolveExpression ( targetExpression , contextualFunction ) ) )
982
975
return null ;
983
- }
976
+ var target = resolved . element ;
977
+
978
+ // at this point we know exactly what the target is, so make sure it is an array and look up the element within
979
+ throw new Error ( "not implemented" ) ;
980
+ }
984
981
985
- // local or global name
986
- if ( expression . kind == NodeKind . IDENTIFIER ) {
987
- return this . resolveIdentifier ( < IdentifierExpression > expression , contextualFunction ) ;
982
+ resolveExpression ( expression : Expression , contextualFunction : Function ) : ResolvedElement | null {
983
+ var classType : Class | null ;
984
+ switch ( expression . kind ) {
988
985
989
- // static or instance property (incl. enum values) or method
990
- } else if ( expression . kind == NodeKind . PROPERTYACCESS ) {
991
- return this . resolvePropertyAccess ( < PropertyAccessExpression > expression , contextualFunction ) ;
986
+ case NodeKind . THIS : // -> Class
987
+ if ( classType = contextualFunction . instanceMethodOf )
988
+ return resolvedElement . set ( classType ) ;
989
+ this . error ( DiagnosticCode . _this_cannot_be_referenced_in_current_location , expression . range ) ;
990
+ return null ;
991
+
992
+ case NodeKind . SUPER : // -> Class
993
+ if ( ( classType = contextualFunction . instanceMethodOf ) && ( classType = classType . base ) )
994
+ return resolvedElement . set ( classType ) ;
995
+ this . error ( DiagnosticCode . _super_can_only_be_referenced_in_a_derived_class , expression . range ) ;
996
+ return null ;
992
997
993
- // instantiation
994
- } else if ( expression . kind == NodeKind . NEW ) {
995
- return this . resolveElement ( ( < NewExpression > expression ) . expression , contextualFunction ) ;
998
+ case NodeKind . IDENTIFIER :
999
+ return this . resolveIdentifier ( < IdentifierExpression > expression , contextualFunction ) ;
1000
+
1001
+ case NodeKind . PROPERTYACCESS :
1002
+ return this . resolvePropertyAccess ( < PropertyAccessExpression > expression , contextualFunction ) ;
1003
+
1004
+ case NodeKind . ELEMENTACCESS :
1005
+ return this . resolveElementAccess ( < ElementAccessExpression > expression , contextualFunction ) ;
1006
+
1007
+ default :
1008
+ this . error ( DiagnosticCode . Operation_not_supported , expression . range ) ;
1009
+ return null ;
996
1010
}
1011
+ }
1012
+ }
997
1013
998
- throw new Error ( "not implemented" ) ;
1014
+ /** Common result structure returned when calling any of the resolve functions on a {@link Program}. */
1015
+ export class ResolvedElement {
1016
+
1017
+ /** The target element, if a property or element access */
1018
+ target : Element | null ;
1019
+ /** The target element's sub-expression, if a property or element access. */
1020
+ targetExpression : Expression | null ;
1021
+ /** The element being accessed. */
1022
+ element : Element ;
1023
+
1024
+ set ( element : Element ) : this {
1025
+ this . target = null ;
1026
+ this . targetExpression = null ;
1027
+ this . element = element ;
1028
+ return this ;
1029
+ }
1030
+
1031
+ withTarget ( target : Element , targetExpression : Expression ) : this {
1032
+ this . target = target ;
1033
+ this . targetExpression = targetExpression ;
1034
+ return this ;
999
1035
}
1000
1036
}
1001
1037
1038
+ var resolvedElement = new ResolvedElement ( ) ;
1039
+
1002
1040
/** Indicates the specific kind of an {@link Element}. */
1003
1041
export enum ElementKind {
1004
1042
/** A {@link Global}. */
@@ -1288,6 +1326,7 @@ export class Local extends VariableLikeElement {
1288
1326
1289
1327
kind = ElementKind . LOCAL ;
1290
1328
1329
+ type : Type ; // more specific
1291
1330
/** Local index. */
1292
1331
index : i32 ;
1293
1332
@@ -1685,6 +1724,7 @@ export class Field extends Element {
1685
1724
/** Constructs a new field. */
1686
1725
constructor ( prototype : FieldPrototype , internalName : string , type : Type ) {
1687
1726
super ( prototype . program , prototype . simpleName , internalName ) ;
1727
+ this . prototype = prototype ;
1688
1728
this . flags = prototype . flags ;
1689
1729
this . type = type ;
1690
1730
}
0 commit comments