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

before invoking delegates in a Multi instance make a copy of the invocation list and invoke from that in case they manipulate the original delegate

This commit is contained in:
Kevin Glynn 2011-07-18 20:34:45 +02:00
parent 1b2222254a
commit d928e3c7bf
6 changed files with 51 additions and 4 deletions

View File

@ -21,6 +21,7 @@
package CS2JNet.System;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import CS2JNet.JavaSupport.util.ListSupport;
@ -32,7 +33,12 @@ import CS2JNet.JavaSupport.util.ListSupport;
public class __MultiEventHandler<TEventArgs> implements EventHandler<TEventArgs> {
public void Invoke(Object other, TEventArgs e) throws Exception {
for (EventHandler<TEventArgs> d : this.GetInvocationList())
List<EventHandler<TEventArgs>> copy, members = this.GetInvocationList();
synchronized (members)
{
copy = new LinkedList<EventHandler<TEventArgs>>(members);
}
for (EventHandler<TEventArgs> d : copy)
{
d.Invoke(other, e);
}

View File

@ -250,6 +250,14 @@ lock(<exp>)
<block(statements = block, indent = indent)>
>>
synchstat(comments,exp,stats) ::= <<
<comments; separator=""\n"">
synchronized (<exp>)
{
<stats>
}
>>
yield(comments,exp) ::= <<
<comments; separator=""\n"">
yield <if(exp)>return <exp><else>break<endif>;

View File

@ -1556,8 +1556,10 @@ scope TypeContext;
multiDelName = "__Multi" + delName;
delClassMemberNodes = this.parseString("class_member_declarations", Fragments.MultiDelegateMethods(mkTypeString(delName, $variant_generic_parameter_list.tyargs), mkTypeString(multiDelName, $variant_generic_parameter_list.tyargs),mkTypeArgString($variant_generic_parameter_list.tyargs)));
AddToImports("java.util.List");
AddToImports("java.util.LinkedList");
AddToImports("java.util.ArrayList");
AddToImports("CS2JNet.JavaSupport.util.ListSupport");
$NSContext::namespaces.Add("System.Collection"); // System.Collection.Ilist used in multi invoke method
}
magicMultiDelClass[$d.token, $atts, toplevel ? dupTree($mods) : addModifier($mods, (CommonTree)adaptor.Create(STATIC, $d.token, "static")), multiDelName, ifTree, $type_parameter_constraints_clauses.tree, $variant_generic_parameter_list.tree, $magicMultiInvokerMethod.tree, delClassMemberNodes]
{
@ -2259,14 +2261,28 @@ magicDelegateInterface[IToken tok, CommonTree return_type, CommonTree identifier
;
// First execute all but the last one, then execute the last one and (if non-void) return its result.
// List<CompleteCallback> copy, members = this.GetInvocationList();
// synchronized (members) {
// copy = new LinkedList<CompleteCallback>(members);
// }
// for (CompleteCallback d : copy)
// {
// d.Invoke(name, result);
// }
//
magicMultiInvokerMethod[IToken tok, CommonTree return_type, bool retIsVoid, CommonTree type, CommonTree formal_parameter_list, CommonTree argument_list, List<String> tyArgs]
:
e1=magicThrowsException[Cfg.TranslatorBlanketThrow, tok]
-> {retIsVoid}?
^(METHOD[tok, "METHOD"] PUBLIC[tok, "public"] { dupTree($return_type) } IDENTIFIER[tok,"Invoke"] { dupTree($formal_parameter_list) }
OPEN_BRACE[tok, "{"]
^(TYPE[tok, "TYPE"] IDENTIFIER[tok, "IList"] LTHAN[tok, "<"] { dupTree($type) } GT[tok, ">"]) IDENTIFIER[tok, "copy"] COMMA[tok, ","] IDENTIFIER[tok, "members"] ASSIGN[tok, "="] ^(APPLY[tok, "APPLY"] ^(DOT[tok,"."] THIS[tok,"this"] IDENTIFIER[tok,"GetInvocationList"])) SEMI[tok, ";"]
^(SYNCHRONIZED[tok, "synchronized"] IDENTIFIER[tok, "members"] OPEN_BRACE[tok, "{"]
IDENTIFIER[tok, "copy"] ASSIGN[tok, "="] ^(NEW[tok, "new"] ^(TYPE[tok, "TYPE"] IDENTIFIER[tok, "LinkedList"] LTHAN[tok, "<"] { dupTree($type) } GT[tok, ">"]) ^(ARGS[tok, "ARGS"] IDENTIFIER[tok, "members"])) SEMI[tok, ";"]
CLOSE_BRACE[tok, "}"]
)
^(FOREACH[tok, "foreach"]
{ $type } IDENTIFIER[tok, "d"] ^(APPLY[tok, "APPLY"] ^(DOT[tok,"."] THIS[tok,"this"] IDENTIFIER[tok,"GetInvocationList"]))
{ $type } IDENTIFIER[tok, "d"] IDENTIFIER[tok, "copy"]
SEP[tok, "SEP"]
OPEN_BRACE[tok, "{"]
^(APPLY[tok, "APPLY"] ^(DOT[tok,"."] IDENTIFIER[tok,"d"] IDENTIFIER[tok,"Invoke"]) { $argument_list }) SEMI[tok, ";"]
@ -2277,9 +2293,14 @@ magicMultiInvokerMethod[IToken tok, CommonTree return_type, bool retIsVoid, Comm
)
-> ^(METHOD[tok, "METHOD"] PUBLIC[tok, "public"] { dupTree($return_type) } IDENTIFIER[tok,"Invoke"] { dupTree($formal_parameter_list) }
OPEN_BRACE[tok, "{"]
^(TYPE[tok, "TYPE"] IDENTIFIER[tok, "IList"] LTHAN[tok, "<"] { dupTree($type) } GT[tok, ">"]) IDENTIFIER[tok, "copy"] COMMA[tok, ","] IDENTIFIER[tok, "members"] ASSIGN[tok, "="] ^(APPLY[tok, "APPLY"] ^(DOT[tok,"."] THIS[tok,"this"] IDENTIFIER[tok,"GetInvocationList"])) SEMI[tok, ";"]
^(SYNCHRONIZED[tok, "synchronized"] IDENTIFIER[tok, "members"] OPEN_BRACE[tok, "{"]
IDENTIFIER[tok, "copy"] ASSIGN[tok, "="] ^(NEW[tok, "new"] ^(TYPE[tok, "TYPE"] IDENTIFIER[tok, "LinkedList"] LTHAN[tok, "<"] { dupTree($type) } GT[tok, ">"]) ^(ARGS[tok, "ARGS"] IDENTIFIER[tok, "members"])) SEMI[tok, ";"]
CLOSE_BRACE[tok, "}"]
)
{ $type } IDENTIFIER[tok, "prev"] ASSIGN[tok, "="] NULL[tok, "null"] SEMI[tok,";"]
^(FOREACH[tok, "foreach"]
{ $type } IDENTIFIER[tok, "d"] ^(APPLY[tok, "APPLY"] ^(DOT[tok,"."] THIS[tok,"this"] IDENTIFIER[tok,"GetInvocationList"]))
{ $type } IDENTIFIER[tok, "d"] IDENTIFIER[tok, "copy"]
SEP[tok, "SEP"]
OPEN_BRACE[tok, "{"]
^(IF[tok, "if"] ^(NOT_EQUAL[tok, "!="] IDENTIFIER[tok,"prev"] NULL[tok, "null"]) SEP ^(APPLY[tok, "APPLY"] ^(DOT[tok,"."] IDENTIFIER[tok,"prev"] IDENTIFIER[tok,"Invoke"]) { $argument_list }) SEMI[tok, ";"])

View File

@ -1465,6 +1465,7 @@ embedded_statement returns [bool isSemi, bool isIf, bool indent]
catches = { $catch_clauses.st }, fin = { $finally_clause.st } )
| checked_statement -> { $checked_statement.st }
| unchecked_statement -> { $unchecked_statement.st }
| synchronized_statement -> { $synchronized_statement.st }
| lock_statement -> { $lock_statement.st }
| yield_statement -> { $yield_statement.st }
| ^('unsafe' { preComments = CollectedComments; } block { someText = %op(); %{someText}.op="unsafe"; %{someText}.post = $block.st; })
@ -1564,6 +1565,10 @@ catch_clause:
^('catch' type identifier block) -> catch_template(type = { $type.st }, id = { $identifier.st }, block = {$block.st}, blockindent = { $block.isSemi } );
finally_clause:
^('finally' block) -> fin(block = {$block.st}, blockindent = { $block.isSemi });
synchronized_statement:
^(SYNCHRONIZED expression '{' s+=statement* '}') -> synchstat(exp={ $expression.st }, stats = { $s });
checked_statement
@init {
StringTemplate someText = null;

View File

@ -519,7 +519,7 @@ scope MkNonGeneric {
}
protected CommonTree mkJavaRep(IToken tok, TypeRepTemplate ty) {
if (ty.InstantiatedTypes.Length == 0) {
if (ty.InstantiatedTypes == null || ty.InstantiatedTypes.Length == 0) {
return (CommonTree)adaptor.Create(IDENTIFIER, tok, ty.Java);
}
else {
@ -2634,6 +2634,7 @@ embedded_statement[bool isStatementListCtxt]
| ^('try' block catch_clauses? finally_clause?)
| checked_statement
| unchecked_statement
| synchronized_statement // Java: synchronized(obj) {}
| lock_statement
| yield_statement
| ^('unsafe' block)
@ -2932,6 +2933,10 @@ checked_statement:
'checked' block ;
unchecked_statement:
^(UNCHECKED block) ;
synchronized_statement:
^(SYNCHRONIZED expression[ObjectType] '{' statement_list '}') ;
lock_statement:
'lock' '(' expression[ObjectType] ')' embedded_statement[/* isStatementListCtxt */ false] ;

View File

@ -148,6 +148,8 @@ tokens {
EXCEPTION;
SYNCHRONIZED;
PAYLOAD; // carries arbitrary text for the output file
PAYLOAD_LIST;
JAVAWRAPPER;