1
0
mirror of https://github.com/twiglet/cs2j.git synced 2025-01-18 13:15:17 +01:00

- Generalize the interfaces that we can support by adding in additional code

- If we are overriding, or implementing, a method with type vars as result or param then we need to make sure that primitive types get their unboxed version
This commit is contained in:
Kevin Glynn 2011-10-09 19:34:09 +02:00
parent c43d5ec4a4
commit 87f38f84e9

View File

@ -27,10 +27,11 @@ scope NSContext {
// all typevariables in all scopes
List<string> globalTypeVariables;
// Does this type implement ICollection?
bool IsGenericICollection;
string GenericICollectionTyVar;
bool IsICollection;
// Base Class
ClassRepTemplate baseClass;
// Supported interfaces
IList<InterfaceRepTemplate> interfaceList;
}
// A scope to keep track of the mapping from variables to types
@ -111,10 +112,10 @@ scope MkNonGeneric {
}
protected TypeRepTemplate findType(string name) {
if ($NSContext::globalTypeVariables.Contains(name)) {
if ($NSContext.Count > 0 && $NSContext::globalTypeVariables != null && $NSContext::globalTypeVariables.Contains(name)) {
return new TypeVarRepTemplate(name);
}
return AppEnv.Search($NSContext::globalNamespaces, name, new UnknownRepTemplate(name));
return AppEnv.Search($NSContext.Count > 0 ? $NSContext::globalNamespaces : null, name, new UnknownRepTemplate(name));
}
protected TypeRepTemplate findType(string name, ICollection<TypeRepTemplate> args) {
@ -193,6 +194,46 @@ scope MkNonGeneric {
}
}
// For classes that implement some specific interface types (such as IEnumerable) we add
// additional methods so that they can support an equivalent Java Interface (e.g. Iterable).
// The keys of this map are the supported interface. We map them to a set of imports that are
// needed for the additional methods
// TODO: Move this to Fragments where the code is maintained.
private Dictionary<InterfaceRepTemplate, IList<string>> supportedInterfaces = null;
protected Dictionary<InterfaceRepTemplate, IList<string>> SupportedInterfaces {
get {
if (supportedInterfaces == null) {
supportedInterfaces = new Dictionary<InterfaceRepTemplate, IList<string>>();
supportedInterfaces[IEnumerableType] = new List<String>();
supportedInterfaces[GenericIEnumerableType] = new List<String>();
supportedInterfaces[ICollectionType] = new List<String>();
supportedInterfaces[GenericICollectionType] = new List<String>();
}
return supportedInterfaces;
}
}
private InterfaceRepTemplate iEnumerableType = null;
protected InterfaceRepTemplate IEnumerableType {
get {
if (iEnumerableType == null) {
iEnumerableType = (InterfaceRepTemplate)findType("System.Collections.IEnumerable");
}
return iEnumerableType;
}
}
private InterfaceRepTemplate genericIEnumerableType = null;
protected InterfaceRepTemplate GenericIEnumerableType {
get {
if (genericIEnumerableType == null) {
genericIEnumerableType = (InterfaceRepTemplate)findType("System.Collections.Generic.IEnumerable", new TypeRepTemplate[] {ObjectType});
}
return genericIEnumerableType;
}
}
private InterfaceRepTemplate iCollectionType = null;
protected InterfaceRepTemplate ICollectionType {
get {
@ -615,6 +656,31 @@ scope MkNonGeneric {
return ret;
}
protected CommonTree boxTypesAsRequired(CommonTree fpTree, IList<ParamRepTemplate> fpTemps, IList<CommonTree> boxedTypeTrees, IToken tok) {
if (fpTree == null) {
return fpTree;
}
CommonTree ret = (CommonTree)adaptor.Nil;
ret = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(PARAMS, tok, "PARAMS"), ret);
int typeIdx = 0;
for (int i = 0; i < adaptor.GetChildCount(fpTree); i++) {
// on one level is all the attributes, types, names, etc. of the parameters. Scan down taking each TYPE node and
// modifying it if necessary
CommonTree child = (CommonTree)adaptor.GetChild(fpTree,i);
if (adaptor.GetType(child) == TYPE) {
if (fpTemps[typeIdx].Type.ForceBoxed && boxedTypeTrees[typeIdx] != null) {
child = boxedTypeTrees[typeIdx];
}
typeIdx++;
}
adaptor.AddChild(ret, (CommonTree)adaptor.DupTree(child));
}
return ret;
}
private Dictionary<int,int> _assOpMap = null;
protected Dictionary<int,int> AssOpMap {
get {
@ -951,9 +1017,8 @@ scope NSContext, PrimitiveRep, MkNonGeneric;
$NSContext::typeVariables = new List<string>();
$NSContext::globalTypeVariables = new List<string>();
$NSContext::IsGenericICollection = false;
$NSContext::GenericICollectionTyVar = "";
$NSContext::IsICollection = false;
$NSContext::baseClass = ObjectType;
$NSContext::interfaceList = new List<InterfaceRepTemplate>();
}:
^(pkg=PACKAGE ns=PAYLOAD { $NSContext::currentNS = $ns.text; } dec=type_declaration )
@ -977,10 +1042,84 @@ modifier:
'new' | 'public' | 'protected' | 'private' | 'abstract' | 'sealed' | 'static'
| 'readonly' | 'volatile' | 'extern' | 'virtual' | 'override' | FINAL ;
class_member_declaration:
class_member_declaration
@init {
ResolveResult methodResult = null;
MethodRepTemplate methodTemplate = null;
}:
^(CONST attributes? modifiers? type constant_declarators[$type.dotNetType])
| ^(EVENT attributes? modifiers? event_declaration)
| ^(METHOD attributes? modifiers? type member_name type_parameter_constraints_clauses? type_parameter_list? formal_parameter_list[null,null]? method_body exception*)
| ^(METHOD attributes? modifiers? type identifier type_parameter_constraints_clauses? type_parameter_list? formal_parameter_list[null,null]? method_body exception*)
{
// Look to see if this method is implementing an interface or overriding a base method
foreach (InterfaceRepTemplate ifaceTy in $NSContext::interfaceList) {
methodResult = ifaceTy.Resolve($identifier.thetext, $formal_parameter_list.paramTypes ?? new List<TypeRepTemplate>(), AppEnv);
if (methodResult != null)
break;
}
if (methodResult == null)
methodResult = $NSContext::baseClass.Resolve($identifier.thetext, $formal_parameter_list.paramTypes ?? new List<TypeRepTemplate>(), AppEnv);
if (methodResult != null) {
// Scan return and parameter types to see if they need to be boxed
// this occurs for primitive types that are substituing for a type parameter in the
// parent / interface definition.
methodTemplate = methodResult.Result as MethodRepTemplate;
}
else {
// Check for property read
if ($identifier.thetext.StartsWith("get") && ($formal_parameter_list.paramTypes == null || $formal_parameter_list.paramTypes.Count == 0)){
string propName = $identifier.thetext.Substring(3);
foreach (InterfaceRepTemplate ifaceTy in $NSContext::interfaceList) {
methodResult = ifaceTy.Resolve(propName, false, AppEnv);
if (methodResult != null)
break;
}
if (methodResult == null)
methodResult = $NSContext::baseClass.Resolve(propName, false, AppEnv);
if (methodResult != null) {
// create a methodRepTemplate with appropriate Return and args
PropRepTemplate prop = methodResult.Result as PropRepTemplate;
methodTemplate = new MethodRepTemplate();
methodTemplate.Return = prop.Type;
}
}
else if ($identifier.thetext.StartsWith("set") && $formal_parameter_list.paramTypes != null && $formal_parameter_list.paramTypes.Count == 1) {
string propName = $identifier.thetext.Substring(3);
foreach (InterfaceRepTemplate ifaceTy in $NSContext::interfaceList) {
methodResult = ifaceTy.Resolve(propName, true, AppEnv);
if (methodResult != null)
break;
}
if (methodResult == null)
methodResult = $NSContext::baseClass.Resolve(propName, true, AppEnv);
if (methodResult != null) {
// create a methodRepTemplate with appropriate Return and args
PropRepTemplate prop = methodResult.Result as PropRepTemplate;
methodTemplate = new MethodRepTemplate();
methodTemplate.Return = new TypeRepRef("System.Void");
ParamRepTemplate pram = new ParamRepTemplate();
pram.Type = prop.Type;
pram.Name = "value";
methodTemplate.Params.Add(pram);
}
}
}
// (Optionally) rewrite the method name
if ($identifier.thetext != "Main" && Cfg.TranslatorMakeJavaNamingConventions) {
// Leave Main() as it is because we wrap it with a special main method
$identifier.tree.Token.Text = toJavaConvention(CSharpEntity.METHOD, $identifier.thetext);
}
}
-> ^(METHOD attributes? modifiers? { dupTree(methodTemplate != null && methodTemplate.Return.ForceBoxed && $type.boxedTree != null ? $type.boxedTree : $type.tree) }
identifier type_parameter_constraints_clauses? type_parameter_list?
{ methodTemplate != null ? boxTypesAsRequired($formal_parameter_list.tree, methodTemplate.Params, $formal_parameter_list.boxedTypeTrees, $identifier.tree.Token) : dupTree($formal_parameter_list.tree) }
method_body exception*)
| interface_declaration
| class_declaration
| ^(FIELD attributes? modifiers? type field_declaration[$type.tree, $type.dotNetType])
@ -1567,7 +1706,7 @@ type_name returns [TypeRepTemplate dotNetType, List<CommonTree> argTrees, bool h
-> ^($d $dt $dtg)
;
type_or_generic[String prefix] returns [TypeRepTemplate dotNetType, List<CommonTree> argTrees, bool hasTyArgs]
type_or_generic[String prefix] returns [TypeRepTemplate dotNetType, List<CommonTree> argTrees, bool hasTyArgs, string thetext]
@init {
$hasTyArgs = false;
$argTrees = new List<CommonTree>();
@ -1591,6 +1730,9 @@ type_or_generic[String prefix] returns [TypeRepTemplate dotNetType, List<CommonT
$argTrees = $ga.argTrees;
}
}
// TODO: we ignore generic arguments. At the moment this is used to create a member_name so that
// we can search for methods in their parents.
$thetext = $t.thetext;
}
-> {!this.in_member_name && !$dotNetType.IsUnknownType}? { mkJavaWrapper($dotNetType.Java, tyMap, $t.tree.Token) }
-> $t $ga?
@ -1643,7 +1785,7 @@ scope PrimitiveRep;
t1=type { $tyTypes.Add($t1.dotNetType); $argTrees.Add(dupTree($t1.tree)); } (',' tn=type { $tyTypes.Add($tn.dotNetType); $argTrees.Add(dupTree($tn.tree)); })* ;
// keving: TODO: Look for type vars
type returns [TypeRepTemplate dotNetType, List<CommonTree> argTrees]
type returns [TypeRepTemplate dotNetType, List<CommonTree> argTrees, CommonTree boxedTree]
@ init {
bool hasRank = false;
bool isPredefined = false;
@ -1653,14 +1795,24 @@ type returns [TypeRepTemplate dotNetType, List<CommonTree> argTrees]
if ($dotNetType.Tree == null) {
$dotNetType.Tree = $type.tree;
}
if ($boxedTree == null) {
$boxedTree = $type.tree;
}
}
:
^(t=TYPE (p=predefined_type { isPredefined = true; $dotNetType = $predefined_type.dotNetType; pTree = $p.tree; }
| type_name { $dotNetType = $type_name.dotNetType; $argTrees = $type_name.argTrees; }
| 'void' { $dotNetType = VoidType; } )
(rank_specifiers[$dotNetType] { isPredefined = false; $dotNetType = $rank_specifiers.dotNetType; $argTrees = null; hasRank = true; })? '*'* '?'?)
magicBoxedType[isPredefined && $dotNetType != null && !String.IsNullOrEmpty($dotNetType.BoxedJava), $t.token, $dotNetType == null ? "" : $dotNetType.BoxedJava]
{ if (isPredefined) $dotNetType.Tree = ($magicBoxedType.tree != null ? dupTree($magicBoxedType.tree) : null); }
magicBoxedType[$dotNetType != null && $dotNetType.HasBoxedRep, $t.token, $dotNetType == null ? "" : $dotNetType.BoxedJava]
{
if (isPredefined) {
$dotNetType.Tree = ($magicBoxedType.tree != null ? dupTree($magicBoxedType.tree) : null);
}
if ($magicBoxedType.tree != null) {
$boxedTree = $magicBoxedType.tree;
}
}
-> { $PrimitiveRep::primitiveTypeAsObject && !hasRank && !String.IsNullOrEmpty($dotNetType.BoxedJava) }? ^(TYPE[$t.token, "TYPE"] IDENTIFIER[$t.token,$dotNetType.BoxedJava] '*'* '?'?)
-> ^(TYPE[$t.token, "TYPE"] predefined_type? type_name? 'void'? rank_specifiers? '*'* '?'?)
;
@ -2349,9 +2501,8 @@ scope NSContext,SymTab;
$NSContext::typeVariables = new List<string>();
$NSContext::globalTypeVariables = new List<string>(((NSContext_scope)$NSContext.ToArray()[1]).globalTypeVariables);
$NSContext::IsGenericICollection = false;
$NSContext::GenericICollectionTyVar = "";
$NSContext::IsICollection = false;
$NSContext::baseClass = ObjectType;
$NSContext::interfaceList = new List<InterfaceRepTemplate>();
$SymTab::symtab = new Dictionary<string, TypeRepTemplate>();
}
@ -2375,7 +2526,7 @@ scope NSContext,SymTab;
$SymTab::symtab["this"] = classTypeRep;
ClassRepTemplate baseType = ObjectType;
if (classTypeRep.Inherits != null && classTypeRep.Inherits.Length > 0) {
// if Inherits[0] Take first class as super
// Find a class that we extend
foreach (String super in classTypeRep.Inherits) {
ClassRepTemplate parent = AppEnv.Search(classTypeRep.Uses, super, null) as ClassRepTemplate;
if (parent != null) {
@ -2386,12 +2537,6 @@ scope NSContext,SymTab;
}
$SymTab::symtab["super"] = baseType;
}
if ($NSContext::IsICollection) {
Debug(10, $NSContext::currentNS + " is a Collection");
}
if ($NSContext::IsGenericICollection) {
Debug(10, $NSContext::currentNS + " is a Generic Collection");
}
}
class_body magicAnnotation[$modifiers.tree, $identifier.tree, null, $c.token])
-> {$class_implements.hasExtends && $class_implements.extendDotNetType.IsA(AppEnv.Search("System.Attribute", new UnknownRepTemplate("System.Attribute")), AppEnv)}? magicAnnotation
@ -2416,42 +2561,62 @@ class_implements returns [bool hasExtends, TypeRepTemplate extendDotNetType]
@init {
CommonTree extends = null;
}:
(class_implement_or_extend[extends == null] { if ($class_implement_or_extend.extends != null) {
extends = $class_implement_or_extend.extends;
$hasExtends = true;
$extendDotNetType = $class_implement_or_extend.extendDotNetType;
}})+
(class_implement_or_extend[extends == null]
{ if ($class_implement_or_extend.extends != null) {
extends = $class_implement_or_extend.extends;
$hasExtends = true;
$extendDotNetType = $class_implement_or_extend.dotNetType;
$NSContext::baseClass = ((ClassRepTemplate)$class_implement_or_extend.dotNetType);
}
else {
// An interface
$NSContext::interfaceList.Add((InterfaceRepTemplate)$class_implement_or_extend.dotNetType);
}
})+
-> { extends } class_implement_or_extend*;
class_implement_or_extend[bool lookingForBase] returns [CommonTree extends, TypeRepTemplate extendDotNetType]
class_implement_or_extend[bool lookingForBase] returns [CommonTree extends, TypeRepTemplate dotNetType]
@init {
$extends = null;
}:
^(i=IMPLEMENTS t=type magicExtends[$lookingForBase && $t.dotNetType is ClassRepTemplate, $i.token, $t.tree]
{ if ($lookingForBase && $t.dotNetType is ClassRepTemplate) {
$extends = $magicExtends.tree;
$extendDotNetType = $t.dotNetType;
}
if($t.dotNetType.IsA(ICollectionType,AppEnv)) $NSContext::IsICollection = true;
if($t.dotNetType.IsA(GenericICollectionType,AppEnv) && $t.dotNetType.TypeParams.Length > 0) {
$NSContext::IsGenericICollection = true;
$NSContext::GenericICollectionTyVar = $t.dotNetType.TypeParams[0];
}
$dotNetType = $t.dotNetType;
} )
-> { $lookingForBase && $t.dotNetType is ClassRepTemplate }?
-> ^($i $t);
class_body
@init {
CommonTree collectorNodes = null;
if ($NSContext::IsGenericICollection) {
collectorNodes = this.parseString("class_member_declarations", Fragments.GenericCollectorMethods($NSContext::GenericICollectionTyVar, $NSContext::GenericICollectionTyVar + "__" + dummyTyVarCtr++));
AddToImports("java.util.Iterator");
AddToImports("java.util.Collection");
AddToImports("java.util.ArrayList");
CommonTree collectNodes = null;
string newMethods = "";
foreach (KeyValuePair<InterfaceRepTemplate,IList<string>> member in SupportedInterfaces) {
InterfaceRepTemplate supportedIface = member.Key;
IList<string> supportedIfaceImports = member.Value;
bool sup = false;
List<String> targs = new List<String>();
foreach (InterfaceRepTemplate implementedIface in $NSContext::interfaceList) {
if (implementedIface.IsA(supportedIface, AppEnv)) {
sup = true;
foreach (TypeRepTemplate t in implementedIface.InstantiatedTypes) {
targs.Add(t.mkFormattedTypeName());
}
break;
}
}
if (sup) {
newMethods = newMethods + this.getMethods(supportedIface.TypeName, targs);
// AddToImports(supportedIface.Imports);
AddToImports(supportedIfaceImports);
}
}
if (!String.IsNullOrEmpty(newMethods)) {
collectNodes = this.parseString("class_member_declarations", newMethods);
}
}:
'{' class_member_declarations? '}' -> '{' class_member_declarations? { dupTree(collectorNodes) } '}' ;
'{' class_member_declarations? '}' -> '{' class_member_declarations? { dupTree(collectNodes) } '}' ;
class_member_declarations:
class_member_declaration+ ;
@ -2503,7 +2668,7 @@ method_header:
^(METHOD_HEADER attributes? modifiers? type member_name type_parameter_constraints_clauses? type_parameter_list? formal_parameter_list[null,null]?);
method_body:
block ;
member_name
member_name returns [string thetext]
@init {
// in_member_name is used by type_or-generic so that we don't treat the member name as a type.
string preTy = null;
@ -2513,7 +2678,7 @@ member_name
@after{
this.in_member_name = save_in_member_name;
}:
t1=type_or_generic[""] { preTy = ($t1.dotNetType == null ? "" : $t1.dotNetType.TypeName); }('.' tn=type_or_generic[preTy+"."] { preTy = ($tn.dotNetType == null ? "" : $tn.dotNetType.TypeName); })*
t1=type_or_generic[""] { $thetext = $t1.thetext; preTy = ($t1.dotNetType == null ? "" : $t1.dotNetType.TypeName); }('.' tn=type_or_generic[preTy+"."] { $thetext += "." + $tn.thetext; preTy = ($tn.dotNetType == null ? "" : $tn.dotNetType.TypeName); })*
//(type '.') => type '.' identifier
//| identifier
;
@ -2578,27 +2743,49 @@ constructor_constraint:
'new' '(' ')' ;
return_type:
type ;
formal_parameter_list[IList<ParamRepTemplate> pInfos, ParamArrayRepTemplate paInfo]
formal_parameter_list[IList<ParamRepTemplate> pInfos, ParamArrayRepTemplate paInfo] returns [IList<TypeRepTemplate> paramTypes, IList<CommonTree> boxedTypeTrees]
@init {
int idx = 0;
$paramTypes = new List<TypeRepTemplate>();
$boxedTypeTrees = new List<CommonTree>();
}:
^(PARAMS formal_parameter[$pInfos != null && idx < $pInfos.Count ? $pInfos[idx++\] : null, $paInfo]+) ;
^(PARAMS (formal_parameter[$pInfos != null && idx < $pInfos.Count ? $pInfos[idx++\] : null, $paInfo]
{ $paramTypes.Add($formal_parameter.paramType); $boxedTypeTrees.Add($formal_parameter.boxedTypeTree); }
)+
) ;
formal_parameter[ParamRepTemplate pInfo, ParamArrayRepTemplate paInfo]
formal_parameter[ParamRepTemplate pInfo, ParamArrayRepTemplate paInfo] returns [TypeRepTemplate paramType, CommonTree boxedTypeTree]
@init {
$boxedTypeTree = null;
$paramType = null;
}
:
attributes? (fixed_parameter[$pInfo] | parameter_array[$paInfo])
attributes? (fixed_parameter[$pInfo] {$paramType = $fixed_parameter.paramType; $boxedTypeTree = $fixed_parameter.boxedTypeTree; }
| parameter_array[$paInfo] { $boxedTypeTree = $parameter_array.boxedTypeTree; } )
| '__arglist'; // __arglist is undocumented, see google
//fixed_parameters:
// fixed_parameter (',' fixed_parameter)* ;
// 4.0
fixed_parameter[ParamRepTemplate pInfo]
fixed_parameter[ParamRepTemplate pInfo] returns [TypeRepTemplate paramType, CommonTree boxedTypeTree]
scope PrimitiveRep;
@init {
$PrimitiveRep::primitiveTypeAsObject = $pInfo != null ? $pInfo.Type.ForceBoxed : false;
bool isRefOut = false;
}:
(parameter_modifier { isRefOut = $parameter_modifier.isRefOut; if (isRefOut) { $PrimitiveRep::primitiveTypeAsObject = true; AddToImports("CS2JNet.JavaSupport.language.RefSupport");} })?
type identifier { $type.dotNetType.IsWrapped = isRefOut; $SymTab::symtab[$identifier.thetext] = $type.dotNetType; } default_argument? magicRef[isRefOut, $type.tree != null ? $type.tree.Token : null, $type.tree]
(parameter_modifier
{ isRefOut = $parameter_modifier.isRefOut;
if (isRefOut) {
$PrimitiveRep::primitiveTypeAsObject = true;
AddToImports("CS2JNet.JavaSupport.language.RefSupport");
}
})?
type { $boxedTypeTree = $type.boxedTree; }
identifier { $paramType = $type.dotNetType; $type.dotNetType.IsWrapped = isRefOut; $SymTab::symtab[$identifier.thetext] = $type.dotNetType; }
default_argument?
magicRef[isRefOut, $type.tree != null ? $type.tree.Token : null, $type.tree]
-> {isRefOut}? magicRef identifier default_argument?
-> parameter_modifier? type identifier default_argument?
;
@ -2610,12 +2797,13 @@ parameter_modifier returns [bool isRefOut]
$isRefOut = true;
}:
'ref' -> | 'out' -> | 'this' { $isRefOut = false;};
parameter_array[ParamArrayRepTemplate paInfo]
parameter_array[ParamArrayRepTemplate paInfo] returns [TypeRepTemplate paramType, CommonTree boxedTypeTree]
scope PrimitiveRep;
@init {
$PrimitiveRep::primitiveTypeAsObject = $paInfo != null ? $paInfo.Type.ForceBoxed : false;
}:
^(p='params' type identifier { $SymTab::symtab[$identifier.thetext] = findType("System.Array", new TypeRepTemplate[] {$type.dotNetType}); }) ;
^(p='params' type { $boxedTypeTree = $type.boxedTree; } identifier { $SymTab::symtab[$identifier.thetext] = findType("System.Array", new TypeRepTemplate[] {$type.dotNetType}); $paramType = $SymTab::symtab[$identifier.thetext]; }) ;
///////////////////////////////////////////////////////
@ -2637,6 +2825,12 @@ scope SymTab;
{ AddToImports("CS2JNet.JavaSupport.language.IEventCollection"); }
-> ^(METHOD[$e.token, "METHOD"] attributes? modifiers? magicEventCollectionType identifier EXCEPTION[$i.tree.Token, "Exception"])
| ^(METHOD attributes? modifiers? type identifier type_parameter_constraints_clauses? type_parameter_list? formal_parameter_list[null,null]? exception*)
{
if ($identifier.thetext != "Main" && Cfg.TranslatorMakeJavaNamingConventions) {
// Leave Main() as it is because we are going to wrap it with a special main method
$identifier.tree.Token.Text = toJavaConvention(CSharpEntity.METHOD, $identifier.thetext);
}
}
;
///////////////////////////////////////////////////////