mirror of
https://github.com/twiglet/cs2j.git
synced 2025-01-18 13:15:17 +01:00
support ref and out parameters
This commit is contained in:
parent
82e2dcf770
commit
9d6b510a59
@ -25,6 +25,12 @@ public class RefSupport<T> {
|
|||||||
|
|
||||||
private T value;
|
private T value;
|
||||||
|
|
||||||
|
public RefSupport(T inValue) {
|
||||||
|
value = inValue;
|
||||||
|
}
|
||||||
|
public RefSupport() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param value the value to set
|
* @param value the value to set
|
||||||
*/
|
*/
|
||||||
|
@ -1622,6 +1622,21 @@ namespace Twiglet.CS2J.Translator.TypeRep
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set if value is wrapped in a RefSupport object (used for ref and out params)
|
||||||
|
private bool _isWrapped = false;
|
||||||
|
[XmlIgnore]
|
||||||
|
public bool IsWrapped
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _isWrapped;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_isWrapped = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Client can set _isUnboxedType. If so then we know the expression / type is inboxed
|
// Client can set _isUnboxedType. If so then we know the expression / type is inboxed
|
||||||
private bool _isUnboxedType = false;
|
private bool _isUnboxedType = false;
|
||||||
[XmlIgnore]
|
[XmlIgnore]
|
||||||
@ -1680,6 +1695,21 @@ namespace Twiglet.CS2J.Translator.TypeRep
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ugly, keep a copy of the tree. Its convenient if these are passed around with the type
|
||||||
|
private object _tree = null;
|
||||||
|
[XmlIgnore]
|
||||||
|
public object Tree
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _tree;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_tree = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public TypeRepTemplate()
|
public TypeRepTemplate()
|
||||||
: base()
|
: base()
|
||||||
{
|
{
|
||||||
|
@ -334,6 +334,7 @@ scope MkNonGeneric {
|
|||||||
protected int dummyForeachVarCtr = 0;
|
protected int dummyForeachVarCtr = 0;
|
||||||
protected int dummyStaticConstructorCatchVarCtr = 0;
|
protected int dummyStaticConstructorCatchVarCtr = 0;
|
||||||
protected int dummyTyVarCtr = 0;
|
protected int dummyTyVarCtr = 0;
|
||||||
|
protected int dummyRefVarCtr = 0;
|
||||||
|
|
||||||
// It turns out that 'default:' doesn't have to be last in the switch statement, so
|
// It turns out that 'default:' doesn't have to be last in the switch statement, so
|
||||||
// we need some jiggery pokery when converting to if-then-else.
|
// we need some jiggery pokery when converting to if-then-else.
|
||||||
@ -742,6 +743,12 @@ scope {
|
|||||||
bool found = false;
|
bool found = false;
|
||||||
TypeRepTemplate idType = SymTabLookup($identifier.thetext);
|
TypeRepTemplate idType = SymTabLookup($identifier.thetext);
|
||||||
if (idType != null) {
|
if (idType != null) {
|
||||||
|
// Is this a wrapped parameter?
|
||||||
|
if (idType.IsWrapped) {
|
||||||
|
Dictionary<string,CommonTree> myMap = new Dictionary<string,CommonTree>();
|
||||||
|
myMap["this"] = wrapExpression($i.tree, $i.tree.Token);
|
||||||
|
ret = mkJavaWrapper("${this}.getValue()", myMap, $i.tree.Token);
|
||||||
|
}
|
||||||
$dotNetType = idType;
|
$dotNetType = idType;
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
@ -861,15 +868,38 @@ argument returns [TypeRepTemplate dotNetType, TypeRepTemplate typeofType]:
|
|||||||
;
|
;
|
||||||
argument_name:
|
argument_name:
|
||||||
identifier ':';
|
identifier ':';
|
||||||
argument_value returns [TypeRepTemplate dotNetType, TypeRepTemplate typeofType]:
|
argument_value returns [TypeRepTemplate dotNetType, TypeRepTemplate typeofType]
|
||||||
|
@init {
|
||||||
|
string refVar = null;
|
||||||
|
}:
|
||||||
expression { $dotNetType = $expression.dotNetType; $typeofType = $expression.typeofType; }
|
expression { $dotNetType = $expression.dotNetType; $typeofType = $expression.typeofType; }
|
||||||
| ref_variable_reference { $dotNetType = $ref_variable_reference.dotNetType; $typeofType = $ref_variable_reference.typeofType; }
|
| ref_variable_reference { $dotNetType = $ref_variable_reference.dotNetType; $typeofType = $ref_variable_reference.typeofType; }
|
||||||
| 'out' variable_reference { $dotNetType = $variable_reference.dotNetType; $typeofType = $variable_reference.typeofType; } ;
|
| o='out' variable_reference { refVar = "refVar___" + dummyRefVarCtr++; }
|
||||||
ref_variable_reference returns [TypeRepTemplate dotNetType, TypeRepTemplate typeofType]:
|
magicCreateOutVar[$o.token, refVar, ($variable_reference.dotNetType != null ? (CommonTree)$variable_reference.dotNetType.Tree : null)] magicUpdateFromRefVar[$o.token, refVar, $variable_reference.tree]
|
||||||
'ref'
|
{ $dotNetType = $variable_reference.dotNetType;
|
||||||
|
$typeofType = $variable_reference.typeofType;
|
||||||
|
adaptor.AddChild($embedded_statement::preStatements, $magicCreateOutVar.tree);
|
||||||
|
adaptor.AddChild($embedded_statement::postStatements, $magicUpdateFromRefVar.tree);
|
||||||
|
}
|
||||||
|
-> IDENTIFIER[$o.token, refVar]
|
||||||
|
;
|
||||||
|
ref_variable_reference returns [TypeRepTemplate dotNetType, TypeRepTemplate typeofType]
|
||||||
|
@init {
|
||||||
|
string refVar = null;
|
||||||
|
}:
|
||||||
|
r='ref'
|
||||||
(('(' type ')') => '(' type ')' (ref_variable_reference | variable_reference) { $dotNetType = $type.dotNetType; } // SomeFunc(ref (int) ref foo)
|
(('(' type ')') => '(' type ')' (ref_variable_reference | variable_reference) { $dotNetType = $type.dotNetType; } // SomeFunc(ref (int) ref foo)
|
||||||
// SomeFunc(ref (int) foo)
|
// SomeFunc(ref (int) foo)
|
||||||
| v1=variable_reference { $dotNetType = $v1.dotNetType; $typeofType = $v1.typeofType; }); // SomeFunc(ref foo)
|
| v1=variable_reference // SomeFunc(ref foo)
|
||||||
|
{ refVar = "refVar___" + dummyRefVarCtr++; }
|
||||||
|
magicCreateRefVar[$r.token, refVar, ($v1.dotNetType != null ? (CommonTree)$v1.dotNetType.Tree : null), $v1.tree] magicUpdateFromRefVar[$r.token, refVar, $v1.tree]
|
||||||
|
{
|
||||||
|
$dotNetType = $v1.dotNetType; $typeofType = $v1.typeofType;
|
||||||
|
adaptor.AddChild($embedded_statement::preStatements, $magicCreateRefVar.tree);
|
||||||
|
adaptor.AddChild($embedded_statement::postStatements, $magicUpdateFromRefVar.tree);
|
||||||
|
}
|
||||||
|
-> IDENTIFIER[$r.token, refVar])
|
||||||
|
;
|
||||||
// lvalue
|
// lvalue
|
||||||
variable_reference returns [TypeRepTemplate dotNetType, TypeRepTemplate typeofType]:
|
variable_reference returns [TypeRepTemplate dotNetType, TypeRepTemplate typeofType]:
|
||||||
expression { $dotNetType = $expression.dotNetType; $typeofType = $expression.typeofType; };
|
expression { $dotNetType = $expression.dotNetType; $typeofType = $expression.typeofType; };
|
||||||
@ -1115,13 +1145,23 @@ scope PrimitiveRep;
|
|||||||
type returns [TypeRepTemplate dotNetType, List<CommonTree> argTrees]
|
type returns [TypeRepTemplate dotNetType, List<CommonTree> argTrees]
|
||||||
@ init {
|
@ init {
|
||||||
bool hasRank = false;
|
bool hasRank = false;
|
||||||
|
bool isPredefined = false;
|
||||||
|
CommonTree pTree = null;
|
||||||
|
string boxedName = null;
|
||||||
|
}
|
||||||
|
@after {
|
||||||
|
if ($dotNetType.Tree == null) {
|
||||||
|
$dotNetType.Tree = $type.tree;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
:
|
:
|
||||||
^(TYPE (p=predefined_type { $dotNetType = $predefined_type.dotNetType; }
|
^(TYPE (p=predefined_type { isPredefined = true; $dotNetType = $predefined_type.dotNetType; pTree = $p.tree; boxedName = $predefined_type.dotNetType.BoxedName; }
|
||||||
| type_name { $dotNetType = $type_name.dotNetType; $argTrees = $type_name.argTrees; }
|
| type_name { $dotNetType = $type_name.dotNetType; $argTrees = $type_name.argTrees; }
|
||||||
| 'void' { $dotNetType = AppEnv["System.Void"]; } )
|
| 'void' { $dotNetType = AppEnv["System.Void"]; } )
|
||||||
(rank_specifiers[$dotNetType] { $dotNetType = $rank_specifiers.dotNetType; $argTrees = null; hasRank = true; })? '*'* '?'?)
|
(rank_specifiers[$dotNetType] { isPredefined = false; $dotNetType = $rank_specifiers.dotNetType; $argTrees = null; hasRank = true; })? '*'* '?'?)
|
||||||
-> { $PrimitiveRep::primitiveTypeAsObject && $p.tree != null && !hasRank && !String.IsNullOrEmpty($dotNetType.BoxedName) }? ^(TYPE IDENTIFIER[$p.tree.Token,$dotNetType.BoxedName] '*'* '?'?)
|
magicBoxedType[isPredefined && pTree != null && !String.IsNullOrEmpty(boxedName), (pTree != null ? pTree.Token : null), boxedName]
|
||||||
|
{ $dotNetType.Tree = ($magicBoxedType.tree != null ? dupTree($magicBoxedType.tree) : null); }
|
||||||
|
-> { $PrimitiveRep::primitiveTypeAsObject && $p.tree != null && !hasRank && !String.IsNullOrEmpty($dotNetType.BoxedName) }? ^(TYPE[$p.tree.Token, "TYPE"] IDENTIFIER[$p.tree.Token,$dotNetType.BoxedName] '*'* '?'?)
|
||||||
-> ^(TYPE predefined_type? type_name? 'void'? rank_specifiers? '*'* '?'?)
|
-> ^(TYPE predefined_type? type_name? 'void'? rank_specifiers? '*'* '?'?)
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -1183,6 +1223,14 @@ assignment
|
|||||||
(^('.' se=expression i=identifier generic_argument_list?) | i=identifier { isThis = true;}) a=assignment_operator rhs=expression
|
(^('.' se=expression i=identifier generic_argument_list?) | i=identifier { isThis = true;}) a=assignment_operator rhs=expression
|
||||||
{
|
{
|
||||||
if (isThis && SymTabLookup($i.thetext) != null) {
|
if (isThis && SymTabLookup($i.thetext) != null) {
|
||||||
|
// Is this a wrapped parameter?
|
||||||
|
TypeRepTemplate idType = SymTabLookup($i.thetext);
|
||||||
|
if (idType.IsWrapped) {
|
||||||
|
Dictionary<string,CommonTree> myMap = new Dictionary<string,CommonTree>();
|
||||||
|
myMap["this"] = wrapExpression($i.tree, $i.tree.Token);
|
||||||
|
myMap["value"] = wrapExpression($rhs.tree, $rhs.tree.Token);
|
||||||
|
ret = mkJavaWrapper("${this}.setValue(${value})", myMap, $i.tree.Token);
|
||||||
|
}
|
||||||
// a simple variable assignment
|
// a simple variable assignment
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -1932,13 +1980,25 @@ formal_parameter:
|
|||||||
fixed_parameters:
|
fixed_parameters:
|
||||||
fixed_parameter (',' fixed_parameter)* ;
|
fixed_parameter (',' fixed_parameter)* ;
|
||||||
// 4.0
|
// 4.0
|
||||||
fixed_parameter:
|
fixed_parameter
|
||||||
parameter_modifier? type identifier { $SymTab::symtab[$identifier.thetext] = $type.dotNetType; } default_argument? ;
|
scope PrimitiveRep;
|
||||||
|
@init {
|
||||||
|
$PrimitiveRep::primitiveTypeAsObject = 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.Token, $type.tree]
|
||||||
|
-> {isRefOut}? magicRef identifier default_argument?
|
||||||
|
-> parameter_modifier? type identifier default_argument?
|
||||||
|
;
|
||||||
// 4.0
|
// 4.0
|
||||||
default_argument:
|
default_argument:
|
||||||
'=' expression;
|
'=' expression;
|
||||||
parameter_modifier:
|
parameter_modifier returns [bool isRefOut]
|
||||||
'ref' | 'out' | 'this' ;
|
@init {
|
||||||
|
$isRefOut = true;
|
||||||
|
}:
|
||||||
|
'ref' -> | 'out' -> | 'this' { $isRefOut = false;};
|
||||||
parameter_array:
|
parameter_array:
|
||||||
^(p='params' type identifier { $SymTab::symtab[$identifier.thetext] = findType("System.Array", new TypeRepTemplate[] {$type.dotNetType}); }) ;
|
^(p='params' type identifier { $SymTab::symtab[$identifier.thetext] = findType("System.Array", new TypeRepTemplate[] {$type.dotNetType}); }) ;
|
||||||
|
|
||||||
@ -2031,9 +2091,16 @@ statement[bool isStatementListCtxt]:
|
|||||||
| statement_plus[isStatementListCtxt];
|
| statement_plus[isStatementListCtxt];
|
||||||
statement_plus[bool isStatementListCtxt]:
|
statement_plus[bool isStatementListCtxt]:
|
||||||
labeled_statement[isStatementListCtxt]
|
labeled_statement[isStatementListCtxt]
|
||||||
| embedded_statement[isStatementListCtxt]
|
| embedded_statement[isStatementListCtxt]
|
||||||
;
|
;
|
||||||
embedded_statement[bool isStatementListCtxt]:
|
embedded_statement[bool isStatementListCtxt]scope {
|
||||||
|
CommonTree preStatements;
|
||||||
|
CommonTree postStatements;
|
||||||
|
}
|
||||||
|
@init {
|
||||||
|
$embedded_statement::preStatements = (CommonTree)adaptor.Nil;
|
||||||
|
$embedded_statement::postStatements = (CommonTree)adaptor.Nil;
|
||||||
|
}:
|
||||||
block
|
block
|
||||||
| ^(IF boolean_expression SEP embedded_statement[/* isStatementListCtxt */ false] else_statement?)
|
| ^(IF boolean_expression SEP embedded_statement[/* isStatementListCtxt */ false] else_statement?)
|
||||||
| switch_statement[isStatementListCtxt]
|
| switch_statement[isStatementListCtxt]
|
||||||
@ -2046,7 +2113,8 @@ embedded_statement[bool isStatementListCtxt]:
|
|||||||
| yield_statement
|
| yield_statement
|
||||||
| ^('unsafe' block)
|
| ^('unsafe' block)
|
||||||
| fixed_statement
|
| fixed_statement
|
||||||
| expression_statement // expression!
|
| expression_statement -> {isStatementListCtxt}? { $embedded_statement::preStatements } expression_statement { $embedded_statement::postStatements }
|
||||||
|
-> OPEN_BRACE[$expression_statement.tree.Token, "{"] { $embedded_statement::preStatements } expression_statement { $embedded_statement::postStatements } CLOSE_BRACE[$expression_statement.tree.Token, "}"] // expression!
|
||||||
;
|
;
|
||||||
switch_statement[ bool isStatementListCtxt]
|
switch_statement[ bool isStatementListCtxt]
|
||||||
scope {
|
scope {
|
||||||
@ -2629,3 +2697,28 @@ magicApply[bool isOn, IToken tok, CommonTree methodExp, CommonTree args]:
|
|||||||
->
|
->
|
||||||
;
|
;
|
||||||
|
|
||||||
|
magicRef[bool isOn, IToken tok, CommonTree ty]:
|
||||||
|
-> {isOn}? ^(TYPE[tok, "TYPE"] IDENTIFIER[tok, "RefSupport"] LTHAN[tok, "<"] { dupTree(ty) } GT[tok, ">"])
|
||||||
|
->
|
||||||
|
;
|
||||||
|
|
||||||
|
magicCreateRefVar[IToken tok, String id, CommonTree type, CommonTree value]:
|
||||||
|
-> ^(TYPE[tok, "TYPE"] IDENTIFIER[tok, "RefSupport"] LTHAN[tok, "<"] { dupTree(type) } GT[tok, ">"]) IDENTIFIER[tok, id] ASSIGN[tok, "="]
|
||||||
|
^(NEW[tok, "new"] ^(TYPE[tok, "TYPE"] IDENTIFIER[tok, "RefSupport"] LTHAN[tok, "<"] { dupTree(type) } GT[tok, ">"]) ^(ARGS[tok, "ARGS"] { dupTree(value) }))
|
||||||
|
SEMI[tok,";"]
|
||||||
|
;
|
||||||
|
|
||||||
|
magicCreateOutVar[IToken tok, String id, CommonTree type]:
|
||||||
|
-> ^(TYPE[tok, "TYPE"] IDENTIFIER[tok, "RefSupport"] LTHAN[tok, "<"] { dupTree(type) } GT[tok, ">"]) IDENTIFIER[tok, id] ASSIGN[tok, "="]
|
||||||
|
^(NEW[tok, "new"] ^(TYPE[tok, "TYPE"] IDENTIFIER[tok, "RefSupport"] LTHAN[tok, "<"] { dupTree(type) } GT[tok, ">"]))
|
||||||
|
SEMI[tok,";"]
|
||||||
|
;
|
||||||
|
|
||||||
|
magicUpdateFromRefVar[IToken tok, String id, CommonTree variable_ref]:
|
||||||
|
-> { dupTree(variable_ref) } ASSIGN[tok, "="] ^(APPLY[tok, "APPLY"] ^(DOT[tok, "."] IDENTIFIER[tok, id] IDENTIFIER[tok, "getValue"])) SEMI[tok,";"]
|
||||||
|
;
|
||||||
|
|
||||||
|
magicBoxedType[bool isOn, IToken tok, String boxedName]:
|
||||||
|
-> { isOn }? ^(TYPE[tok, "TYPE"] IDENTIFIER[tok, boxedName])
|
||||||
|
->
|
||||||
|
;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user