mirror of
https://github.com/twiglet/cs2j.git
synced 2025-01-18 13:15:17 +01:00
support for += and -= for delegates
This commit is contained in:
parent
53e2c3b8c7
commit
05c15f501a
@ -2370,7 +2370,7 @@ namespace Twiglet.CS2J.Translator.TypeRep
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
protected string mkFormattedTypeName(bool incNameSpace, string langle, string rangle)
|
public string mkFormattedTypeName(bool incNameSpace, string langle, string rangle)
|
||||||
{
|
{
|
||||||
StringBuilder fmt = new StringBuilder();
|
StringBuilder fmt = new StringBuilder();
|
||||||
if (TypeName == "System.Array")
|
if (TypeName == "System.Array")
|
||||||
|
@ -982,7 +982,7 @@ implicit_anonymous_function_parameter_list:
|
|||||||
implicit_anonymous_function_parameter:
|
implicit_anonymous_function_parameter:
|
||||||
identifier;
|
identifier;
|
||||||
anonymous_function_body:
|
anonymous_function_body:
|
||||||
expression -> OPEN_BRACE[$expression.tree.Token, "{"] ^(RETURN[$expression.tree.Token, "return"] expression) CLOSE_BRACE[$expression.tree.Token, "}"]
|
expression
|
||||||
| block ;
|
| block ;
|
||||||
|
|
||||||
///////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////
|
||||||
|
@ -579,7 +579,7 @@ scope MkNonGeneric {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
delTypeRoot = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(TYPE, tok, "TYPE"), delTypeRoot);
|
delTypeRoot = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(TYPE, tok, "TYPE"), delTypeRoot);
|
||||||
adaptor.AddChild(delTypeRoot, (CommonTree)adaptor.Create(IDENTIFIER, tok, delType.Java));
|
adaptor.AddChild(delTypeRoot, (CommonTree)adaptor.Create(IDENTIFIER, tok, delType.mkFormattedTypeName(false, "<",">")));
|
||||||
AddToImports(delType.Imports);
|
AddToImports(delType.Imports);
|
||||||
}
|
}
|
||||||
adaptor.AddChild(retTypeRoot, delTypeRoot);
|
adaptor.AddChild(retTypeRoot, delTypeRoot);
|
||||||
@ -664,7 +664,7 @@ scope MkNonGeneric {
|
|||||||
else {
|
else {
|
||||||
CommonTree delTyTree = (CommonTree)adaptor.Nil;
|
CommonTree delTyTree = (CommonTree)adaptor.Nil;
|
||||||
delTyTree = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(TYPE, tok, "TYPE"), delTyTree);
|
delTyTree = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(TYPE, tok, "TYPE"), delTyTree);
|
||||||
adaptor.AddChild(delTyTree, (CommonTree)adaptor.Create(IDENTIFIER, tok, delg.Java));
|
adaptor.AddChild(delTyTree, (CommonTree)adaptor.Create(IDENTIFIER, tok, delg.mkFormattedTypeName(false, "<",">")));
|
||||||
AddToImports(delg.Imports);
|
AddToImports(delg.Imports);
|
||||||
adaptor.AddChild(root, delTyTree);
|
adaptor.AddChild(root, delTyTree);
|
||||||
}
|
}
|
||||||
@ -728,7 +728,7 @@ scope MkNonGeneric {
|
|||||||
else {
|
else {
|
||||||
CommonTree delTyTree = (CommonTree)adaptor.Nil;
|
CommonTree delTyTree = (CommonTree)adaptor.Nil;
|
||||||
delTyTree = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(TYPE, tok, "TYPE"), delTyTree);
|
delTyTree = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(TYPE, tok, "TYPE"), delTyTree);
|
||||||
adaptor.AddChild(delTyTree, (CommonTree)adaptor.Create(IDENTIFIER, tok, delg.Java));
|
adaptor.AddChild(delTyTree, (CommonTree)adaptor.Create(IDENTIFIER, tok, delg.mkFormattedTypeName(false, "<",">")));
|
||||||
AddToImports(delg.Imports);
|
AddToImports(delg.Imports);
|
||||||
adaptor.AddChild(root, delTyTree);
|
adaptor.AddChild(root, delTyTree);
|
||||||
}
|
}
|
||||||
@ -1564,14 +1564,16 @@ assignment
|
|||||||
|
|
||||||
ResolveResult fieldResult = null;
|
ResolveResult fieldResult = null;
|
||||||
ResolveResult indexerResult = null;
|
ResolveResult indexerResult = null;
|
||||||
|
|
||||||
|
CommonTree lhsTree = null;
|
||||||
}
|
}
|
||||||
@after {
|
@after {
|
||||||
if (ret != null)
|
if (ret != null)
|
||||||
$assignment.tree = ret;
|
$assignment.tree = ret;
|
||||||
}:
|
}:
|
||||||
((^('.' expression[ObjectType] identifier generic_argument_list?) | identifier) assignment_operator) =>
|
((^('.' expression[ObjectType] identifier generic_argument_list?) | identifier) assignment_operator) =>
|
||||||
(^('.' se=expression[ObjectType] i=identifier generic_argument_list?)
|
(^(d0='.' se=expression[ObjectType] i=identifier generic_argument_list?) {lhsTree = dupTree($d0.tree); }
|
||||||
| i=identifier { isThis = true; })
|
| i=identifier { isThis = true; lhsTree = dupTree($i.tree); })
|
||||||
{
|
{
|
||||||
TypeRepTemplate varType = SymTabLookup($i.thetext);
|
TypeRepTemplate varType = SymTabLookup($i.thetext);
|
||||||
if (isThis && varType != null) {
|
if (isThis && varType != null) {
|
||||||
@ -1594,12 +1596,70 @@ assignment
|
|||||||
}
|
}
|
||||||
a=assignment_operator rhs=expression[lhsType]
|
a=assignment_operator rhs=expression[lhsType]
|
||||||
{
|
{
|
||||||
|
CommonTree assignmentOp = $a.tree;
|
||||||
|
CommonTree rhsTree = $rhs.tree;
|
||||||
|
TypeRepTemplate rhsType = $rhs.dotNetType ?? ObjectType;
|
||||||
|
// Is lhs a delegate and assignment one of += -=?
|
||||||
|
if (lhsType is DelegateRepTemplate && (assignmentOp.Token.Type == PLUS_ASSIGN || assignmentOp.Token.Type == MINUS_ASSIGN)) {
|
||||||
|
// rewrite to lhs = <op>(lhs,rhs)
|
||||||
|
// First calculate new rhs
|
||||||
|
CommonTree lhsGetter = lhsTree;
|
||||||
|
// Do we have a getter for lhs
|
||||||
|
if (isLocalVar && lhsType.IsWrapped) {
|
||||||
|
Dictionary<string,CommonTree> myMap = new Dictionary<string,CommonTree>();
|
||||||
|
myMap["this"] = wrapExpression($i.tree, $i.tree.Token);
|
||||||
|
lhsGetter = mkJavaWrapper("${this}.getValue()", myMap, $i.tree.Token);
|
||||||
|
}
|
||||||
|
else if (expType != null) {
|
||||||
|
// Is lhs a property?
|
||||||
|
ResolveResult readFieldResult = expType.Resolve($i.thetext, false, AppEnv);
|
||||||
|
if (readFieldResult.Result is PropRepTemplate) {
|
||||||
|
if (!String.IsNullOrEmpty(readFieldResult.Result.Warning)) Warning($i.tree.Token.Line, readFieldResult.Result.Warning);
|
||||||
|
PropRepTemplate readPropRep = readFieldResult.Result as PropRepTemplate;
|
||||||
|
|
||||||
|
if (!String.IsNullOrEmpty(readPropRep.JavaGet)) {
|
||||||
|
// need to translate to setProp(getProp <op> rhs)
|
||||||
|
Dictionary<string,CommonTree> rhsMap = new Dictionary<string,CommonTree>();
|
||||||
|
if (!isThis)
|
||||||
|
rhsMap["this"] = wrapExpression($se.tree, $i.tree.Token);
|
||||||
|
lhsGetter = mkJavaWrapper(readPropRep.JavaGet, rhsMap, assignmentOp.Token);
|
||||||
|
lhsType = readFieldResult.ResultType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// OK, lhsGetter is good for use.
|
||||||
|
List<TypeRepTemplate> args = new List<TypeRepTemplate>();
|
||||||
|
args.Add(lhsType);
|
||||||
|
args.Add(rhsType == null ? lhsType : rhsType);
|
||||||
|
ResolveResult calleeResult = lhsType.Resolve(assignmentOp.Token.Type == PLUS_ASSIGN ? "Combine" : "Remove", args, AppEnv);
|
||||||
|
if (calleeResult != null) {
|
||||||
|
if (!String.IsNullOrEmpty(calleeResult.Result.Warning)) Warning(assignmentOp.Token.Line, calleeResult.Result.Warning);
|
||||||
|
|
||||||
|
Dictionary<string,CommonTree> myMap = new Dictionary<string,CommonTree>();
|
||||||
|
MethodRepTemplate calleeMethod = calleeResult.Result as MethodRepTemplate;
|
||||||
|
myMap[calleeMethod.Params[0].Name] = wrapArgument(lhsGetter, assignmentOp.token);
|
||||||
|
myMap[calleeMethod.Params[1].Name] = wrapArgument(rhsTree, assignmentOp.token);
|
||||||
|
rhsTree = mkJavaWrapper(calleeMethod.Java, myMap, assignmentOp.token);
|
||||||
|
AddToImports(calleeMethod.Imports);
|
||||||
|
rhsType = calleeResult.ResultType;
|
||||||
|
assignmentOp = (CommonTree)adaptor.Create(ASSIGN, assignmentOp.Token, "=");
|
||||||
|
|
||||||
|
// set up a default ret
|
||||||
|
ret = (CommonTree)adaptor.Nil;
|
||||||
|
adaptor.AddChild(ret, dupTree(lhsTree));
|
||||||
|
adaptor.AddChild(ret, dupTree(assignmentOp));
|
||||||
|
adaptor.AddChild(ret, dupTree(rhsTree));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
WarningFailedResolve(assignmentOp.Token.Line, "Could not resolve method application of " + (assignmentOp.Token.Type == PLUS_ASSIGN ? "Combine" : "Remove") + " against " + lhsType.TypeName);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (isLocalVar) {
|
if (isLocalVar) {
|
||||||
// Is this a wrapped parameter?
|
// Is this a wrapped parameter?
|
||||||
if (lhsType.IsWrapped) {
|
if (lhsType.IsWrapped) {
|
||||||
Dictionary<string,CommonTree> myMap = new Dictionary<string,CommonTree>();
|
Dictionary<string,CommonTree> myMap = new Dictionary<string,CommonTree>();
|
||||||
myMap["this"] = wrapExpression($i.tree, $i.tree.Token);
|
myMap["this"] = wrapExpression($i.tree, $i.tree.Token);
|
||||||
myMap["value"] = wrapExpression($rhs.tree, $rhs.tree.Token);
|
myMap["value"] = wrapExpression(rhsTree, rhsTree.Token);
|
||||||
ret = mkJavaWrapper("${this}.setValue(${value})", myMap, $i.tree.Token);
|
ret = mkJavaWrapper("${this}.setValue(${value})", myMap, $i.tree.Token);
|
||||||
}
|
}
|
||||||
// a simple variable assignment
|
// a simple variable assignment
|
||||||
@ -1610,10 +1670,10 @@ assignment
|
|||||||
if (fieldResult.Result is PropRepTemplate) {
|
if (fieldResult.Result is PropRepTemplate) {
|
||||||
PropRepTemplate propRep = fieldResult.Result as PropRepTemplate;
|
PropRepTemplate propRep = fieldResult.Result as PropRepTemplate;
|
||||||
if (!String.IsNullOrEmpty(propRep.JavaSet)) {
|
if (!String.IsNullOrEmpty(propRep.JavaSet)) {
|
||||||
CommonTree newRhsExp = $rhs.tree;
|
CommonTree newRhsExp = rhsTree;
|
||||||
// if assignment operator is a short cut operator then only translate if we also have JavaGet
|
// if assignment operator is a short cut operator then only translate if we also have JavaGet
|
||||||
bool goodTx = true;
|
bool goodTx = true;
|
||||||
if ($a.tree.Token.Type != ASSIGN) {
|
if (assignmentOp.Token.Type != ASSIGN) {
|
||||||
// We have to resolve property reads and writes separately, because they may come from
|
// We have to resolve property reads and writes separately, because they may come from
|
||||||
// different parent classes
|
// different parent classes
|
||||||
ResolveResult readFieldResult = expType.Resolve($i.thetext, false, AppEnv);
|
ResolveResult readFieldResult = expType.Resolve($i.thetext, false, AppEnv);
|
||||||
@ -1627,8 +1687,8 @@ assignment
|
|||||||
Dictionary<string,CommonTree> rhsMap = new Dictionary<string,CommonTree>();
|
Dictionary<string,CommonTree> rhsMap = new Dictionary<string,CommonTree>();
|
||||||
if (!isThis)
|
if (!isThis)
|
||||||
rhsMap["this"] = wrapExpression($se.tree, $i.tree.Token);
|
rhsMap["this"] = wrapExpression($se.tree, $i.tree.Token);
|
||||||
CommonTree rhsPropTree = mkJavaWrapper(readPropRep.JavaGet, rhsMap, $a.tree.Token);
|
CommonTree rhsPropTree = mkJavaWrapper(readPropRep.JavaGet, rhsMap, assignmentOp.Token);
|
||||||
newRhsExp = mkOpExp(mkOpExp($a.tree), rhsPropTree, $rhs.tree);
|
newRhsExp = mkOpExp(mkOpExp(assignmentOp), rhsPropTree, rhsTree);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
goodTx = false;
|
goodTx = false;
|
||||||
@ -1640,7 +1700,7 @@ assignment
|
|||||||
valMap["this"] = wrapExpression($se.tree, $i.tree.Token);
|
valMap["this"] = wrapExpression($se.tree, $i.tree.Token);
|
||||||
valMap["value"] = wrapExpression(newRhsExp, $i.tree.Token);
|
valMap["value"] = wrapExpression(newRhsExp, $i.tree.Token);
|
||||||
if (goodTx) {
|
if (goodTx) {
|
||||||
ret = mkJavaWrapper(propRep.JavaSet, valMap, $a.tree.Token);
|
ret = mkJavaWrapper(propRep.JavaSet, valMap, assignmentOp.Token);
|
||||||
AddToImports(propRep.Imports);
|
AddToImports(propRep.Imports);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1997,13 +2057,13 @@ lambda_expression[TypeRepTemplate typeCtxt] returns [TypeRepTemplate dotNetType]
|
|||||||
if (ret != null)
|
if (ret != null)
|
||||||
$lambda_expression.tree = ret;
|
$lambda_expression.tree = ret;
|
||||||
}:
|
}:
|
||||||
anonymous_function_signature[$typeCtxt]? d='=>' block
|
anonymous_function_signature[$typeCtxt]? d='=>' anonymous_function_body
|
||||||
{
|
{
|
||||||
if ($typeCtxt != null && $typeCtxt is DelegateRepTemplate && $anonymous_function_signature.isTypedParams) {
|
if ($typeCtxt != null && $typeCtxt is DelegateRepTemplate && $anonymous_function_signature.isTypedParams) {
|
||||||
// use an anonymous inner class to generate a delegate object (object wih an Invoke with appropriate arguments)
|
// use an anonymous inner class to generate a delegate object (object wih an Invoke with appropriate arguments)
|
||||||
// new <delegate_name>() { public void Invoke(<formal args>) throw exception <block> }
|
// new <delegate_name>() { public void Invoke(<formal args>) throw exception <block> }
|
||||||
DelegateRepTemplate delType = $typeCtxt as DelegateRepTemplate;
|
DelegateRepTemplate delType = $typeCtxt as DelegateRepTemplate;
|
||||||
ret = mkDelegateObject((CommonTree)$typeCtxt.Tree, $anonymous_function_signature.tree, $block.tree, delType, $d.token);
|
ret = mkDelegateObject((CommonTree)$typeCtxt.Tree, $anonymous_function_signature.tree, $anonymous_function_body.tree, delType, $d.token);
|
||||||
$dotNetType = $typeCtxt;
|
$dotNetType = $typeCtxt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2029,6 +2089,11 @@ anonymous_function_signature[TypeRepTemplate typeCtxt] returns [bool isTypedPara
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
anonymous_function_body:
|
||||||
|
expression[ObjectType]
|
||||||
|
-> {$expression.dotNetType != null && $expression.dotNetType.IsA(VoidType, AppEnv)}? OPEN_BRACE[$expression.tree.Token, "{"] expression SEMI[$expression.tree.Token, ";"] CLOSE_BRACE[$expression.tree.Token, "}"]
|
||||||
|
-> OPEN_BRACE[$expression.tree.Token, "{"] ^(RETURN[$expression.tree.Token, "return"] expression) CLOSE_BRACE[$expression.tree.Token, "}"]
|
||||||
|
| block ;
|
||||||
|
|
||||||
///////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////
|
||||||
// LINQ Section
|
// LINQ Section
|
||||||
|
Loading…
x
Reference in New Issue
Block a user