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

Add parseString and IsJavaish so that we can parse arbitrary snippets of Java(ish) code and weave them into the output

This commit is contained in:
Kevin Glynn 2011-04-13 11:44:29 +02:00
parent 71beb7eef6
commit 18fb3d4063
6 changed files with 166 additions and 15 deletions

View File

@ -129,6 +129,7 @@ namespace Twiglet.CS2J.Translator
.Add ("translator-timestamp-files=", v => cfg.TranslatorAddTimeStamp = Boolean.Parse(v))
.Add ("translator-exception-is-throwable=", v => cfg.TranslatorExceptionIsThrowable = Boolean.Parse(v))
.Add ("experimental-transforms=", v => cfg.ExperimentalTransforms = Boolean.Parse(v))
.Add ("internal-isjavaish", v => cfg.InternalIsJavaish = true)
;
//TODO: fix enum dump
@ -191,6 +192,7 @@ namespace Twiglet.CS2J.Translator
w.Close();
}
}
// load in T.stg template group, put in templates variable
string templateLocation = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, Path.Combine("templates", "java.stg"));
if (File.Exists(templateLocation)) {
@ -279,6 +281,7 @@ namespace Twiglet.CS2J.Translator
// }
csParser p = new csParser(tokens);
p.TraceDestination = Console.Error;
p.IsJavaish = cfg.InternalIsJavaish;
csParser.compilation_unit_return parser_rt = p.compilation_unit();
@ -439,6 +442,7 @@ namespace Twiglet.CS2J.Translator
javaMaker.Cfg = cfg;
javaMaker.CUMap = new Dictionary<string, CUnit>();
javaMaker.CUKeys = new List<string>();
javaMaker.IsJavaish = cfg.InternalIsJavaish;
if (cfg.DebugLevel >= 1) Console.Out.WriteLine("Translating {0} to Java", fullName);
@ -514,6 +518,8 @@ namespace Twiglet.CS2J.Translator
netMaker.AliasKeys = javaMaker.CUMap[typeName].NameSpaceAliasKeys;
netMaker.AliasNamespaces = javaMaker.CUMap[typeName].NameSpaceAliasValues;
netMaker.IsJavaish = cfg.InternalIsJavaish;
if (cfg.DebugLevel > 5) Console.Out.WriteLine("Translating {0} Net Calls to Java", javaFName);
NetMaker.compilation_unit_return javaCompilationUnit = netMaker.compilation_unit();

View File

@ -61,6 +61,11 @@ namespace Twiglet.CS2J.Translator
get; set;
}
public bool InternalIsJavaish
{
get; set;
}
public CS2JSettings ()
{
@ -95,6 +100,8 @@ namespace Twiglet.CS2J.Translator
TranslatorExceptionIsThrowable = false;
ExperimentalTransforms = false;
InternalIsJavaish = false;
}
}
}

View File

@ -2,9 +2,13 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using Antlr.Runtime.Tree;
using Antlr.Runtime;
using AntlrCSharp;
using Twiglet.CS2J.Translator.Utils;
using Twiglet.CS2J.Translator.TypeRep;
using Twiglet.CS2J.Translator;
@ -119,6 +123,84 @@ namespace Twiglet.CS2J.Translator.Transform
return (String.IsNullOrEmpty(ns) ? "" : ns + ".");
}
// Routines to parse strings to ANTLR Trees on the fly, used to generate fragments needed by the transformation
public CommonTree parseString(string startRule, string inStr)
{
if (Cfg.Verbosity > 5) Console.WriteLine("Parsing fragment ");
ICharStream input = new ANTLRStringStream(inStr);
PreProcessor lex = new PreProcessor();
lex.AddDefine(Cfg.MacroDefines);
lex.CharStream = input;
lex.TraceDestination = Console.Error;
CommonTokenStream tokens = new CommonTokenStream(lex);
csParser p = new csParser(tokens);
p.TraceDestination = Console.Error;
p.IsJavaish = true;
// Try and call a rule like CSParser.namespace_body()
// Use reflection to find the rule to use.
MethodInfo mi = p.GetType().GetMethod(startRule);
if (mi == null)
{
throw new Exception("Could not find start rule " + startRule + " in csParser");
}
ParserRuleReturnScope csRet = (ParserRuleReturnScope) mi.Invoke(p, new object[0]);
CommonTreeNodeStream csTreeStream = new CommonTreeNodeStream(csRet.Tree);
csTreeStream.TokenStream = tokens;
JavaMaker javaMaker = new JavaMaker(csTreeStream);
javaMaker.TraceDestination = Console.Error;
javaMaker.Cfg = Cfg;
javaMaker.IsJavaish = true;
// Try and call a rule like CSParser.namespace_body()
// Use reflection to find the rule to use.
mi = javaMaker.GetType().GetMethod(startRule);
if (mi == null)
{
throw new Exception("Could not find start rule " + startRule + " in javaMaker");
}
TreeRuleReturnScope javaSyntaxRet = (TreeRuleReturnScope) mi.Invoke(javaMaker, new object[0]);
CommonTree javaSyntaxAST = (CommonTree)javaSyntaxRet.Tree;
// CommonTreeNodeStream javaSyntaxNodes = new CommonTreeNodeStream(javaSyntaxAST);
//
// javaSyntaxNodes.TokenStream = csTree.TokenStream;
//
// NetMaker netMaker = new NetMaker(javaSyntaxNodes);
// netMaker.TraceDestination = Console.Error;
//
// netMaker.Cfg = Cfg;
// netMaker.AppEnv = AppEnv;
//
// CommonTree javaAST = (CommonTree)netMaker.class_member_declarations().Tree;
//
return javaSyntaxAST;
}
// If true, then we are parsing some JavaIsh fragment
private bool isJavaish = false;
public bool IsJavaish
{
get {
return isJavaish;
}
set {
isJavaish = value;
}
}
}
// Wraps a compilation unit with its imports search path

View File

@ -40,6 +40,7 @@ scope TypeContext {
@header
{
using System;
using System.Text;
using System.Globalization;
}
@ -707,7 +708,17 @@ type_arguments returns [List<string> tyargs]
$tyargs = new List<string>();
}
:
t1=type { $tyargs.Add($t1.thetext); } (',' tn=type { $tyargs.Add($tn.thetext); })* ;
t1=type_argument { $tyargs.Add($t1.thetext); } (',' tn=type_argument { $tyargs.Add($tn.thetext); })* ;
public type_argument returns [string thetext]:
{this.IsJavaish}?=> javaish_type_argument {$thetext = $javaish_type_argument.thetext; }
| type {$thetext = $type.thetext; }
;
public javaish_type_argument returns [string thetext]:
('?' 'extends')=> '?' 'extends' type {$thetext = "? extends " + $type.thetext; }
| '?' {$thetext = "?"; }
| type {$thetext = $type.thetext; }
;
type returns [string thetext]:
((predefined_type | type_name) rank_specifiers) => (p1=predefined_type { $thetext = $p1.thetext; } | tn1=type_name { $thetext = $tn1.thetext; }) rs=rank_specifiers { $thetext += $rs.text; } ('*' { $thetext += "*"; })* -> ^(TYPE $p1? $tn1? $rs '*'*)
@ -1029,11 +1040,14 @@ method_declaration [CommonTree atts, CommonTree mods, List<string> modList, Comm
)?
')'
( type_parameter_constraints_clauses { isToString = false; isMain = false; })?
// Only have throw Exceptions if IsJavaish
throw_exceptions?
b=method_body[isToString]
// build main method if required
argParam=magicMainArgs[isMain && isMainHasArg, $member_name.tree.Token]
mainApply=magicMainApply[isMain, $member_name.tree.Token, $TypeContext::typeName, $argParam.tree]
mainApply=magicMainApply[isMain, $member_name.tree.Token, (isMain ? $TypeContext::typeName : null), $argParam.tree]
mainCall=magicMainExit[isMain, isInt, $member_name.tree.Token, $mainApply.tree]
mainMethod=magicMainWrapper[isMain, $member_name.tree.Token, $mainCall.tree]
@ -1041,7 +1055,7 @@ method_declaration [CommonTree atts, CommonTree mods, List<string> modList, Comm
{ if (isToString) {
$member_name.tree.Token.Text = "toString";
}
exceptions = $b.exceptionList;
exceptions = IsJavaish ? $throw_exceptions.tree : $b.exceptionList;
}
-> $mainMethod?
^(METHOD { dupTree($atts) } { dupTree($mods) } { dupTree($type) }
@ -1053,8 +1067,16 @@ method_body [bool smotherExceptions] returns [CommonTree exceptionList]:
| b=block el=magicThrowsException[true,$b.tree.Token] { $exceptionList=$el.tree; }
-> $b
;
member_name returns [string rawId]:
(type_or_generic '.')* i=identifier { $rawId = $i.text; }
throw_exceptions:
{IsJavaish}?=> 'throws'! t1=identifier { $t1.tree.Type = EXCEPTION; } (','! tn=identifier { $tn.tree.Type = EXCEPTION; } )*
;
member_name returns [string rawId, string full_name]
@init {
$full_name = "";
}:
(type_or_generic '.' {$full_name += mkTypeOrGenericString($type_or_generic.type, $type_or_generic.generic_arguments) + ".";})*
i=identifier { $rawId = $i.text; $full_name += $i.text; }
// keving [interface_type.identifier] | type_name '.' identifier
;

View File

@ -670,8 +670,13 @@ qid_part:
generic_argument_list:
'<' type_arguments '>' -> generic_args(args={ $type_arguments.st });
type_arguments:
ts+=type (',' ts+=type)* -> commalist(items = { $ts });
ts+=type_argument (',' ts+=type_argument)* -> commalist(items = { $ts });
public type_argument:
('?' 'extends')=> '?' 'extends' type -> op(pre={"?"},op={" extends "},post={$type.st})
| '?' -> string(payload={"?"})
| type -> { $type.st }
;
type
@init {
StringTemplate nm = null;
@ -1349,16 +1354,19 @@ predefined_type:
| t='short' | t='string' | t='uint' | t='ulong' | t='ushort') { collectComments($t.TokenStartIndex); } -> string(payload={$t.text});
identifier:
i=IDENTIFIER { collectComments($i.TokenStartIndex); } -> string(payload= { $IDENTIFIER.text }) | also_keyword -> string(payload= { $also_keyword.text });
i=IDENTIFIER { collectComments($i.TokenStartIndex); } -> string(payload= { $IDENTIFIER.text }) | also_keyword -> { $also_keyword.st };
keyword:
'abstract' | 'as' | 'base' | 'bool' | 'break' | 'byte' | 'case' | 'catch' | 'char' | 'checked' | 'class' | 'const' | 'continue' | 'decimal' | 'default' | 'delegate' | 'do' | 'double' | 'else' | 'enum' | 'event' | 'explicit' | 'extern' | 'false' | 'finally' | 'fixed' | 'float' | 'for' | 'foreach' | 'goto' | 'if' | 'implicit' | 'in' | 'int' | 'interface' | 'internal' | 'is' | 'lock' | 'long' | 'namespace' | 'new' | 'null' | 'object' | 'operator' | 'out' | 'override' | 'params' | 'private' | 'protected' | 'public' | 'readonly' | 'ref' | 'return' | 'sbyte' | 'sealed' | 'short' | 'sizeof' | 'stackalloc' | 'static' | 'string' | 'struct' | 'switch' | 'this' | 'throw' | 'true' | 'try' | 'typeof' | 'uint' | 'ulong' | 'unchecked' | 'unsafe' | 'ushort' | 'using' | 'virtual' | 'void' | 'volatile' ;
also_keyword:
'add' | 'alias' | 'assembly' | 'module' | 'field' | 'method' | 'param' | 'property' | 'type' | 'yield'
| 'from' | 'into' | 'join' | 'on' | 'where' | 'orderby' | 'group' | 'by' | 'ascending' | 'descending'
| 'equals' | 'select' | 'pragma' | 'let' | 'remove' | 'get' | 'set' | 'var' | '__arglist' | 'dynamic' | 'elif'
| 'endif' | 'define' | 'undef';
(
t='add' | t='alias' | t='assembly' | t='module' | t='field' | t='method' | t='param' | t='property' | t='type' | t='yield'
| t='from' | t='into' | t='join' | t='on' | t='where' | t='orderby' | t='group' | t='by' | t='ascending' | t='descending'
| t='equals' | t='select' | t='pragma' | t='let' | t='remove' | t='get' | t='set' | t='var' | t='__arglist' | t='dynamic' | t='elif'
| t='endif' | t='define' | t='undef'
) -> string(payload={$t.text})
;
literal:
Real_literal -> string(payload={$Real_literal.text})

View File

@ -15,7 +15,6 @@ tokens {
INTERFACE;
FINAL; /* final modifier */
ANNOTATION;
IN;
OUT;
CONST;
EVENT;
@ -66,6 +65,9 @@ tokens {
ELSE = 'else';
BREAK = 'break';
OBJECT = 'object';
THIS = 'this';
FOREACH = 'foreach';
IN = 'in';
OPEN_BRACKET='[';
CLOSE_BRACKET=']';
@ -176,6 +178,19 @@ tokens {
{
return false;
}
// We have a fragments library for strings that we want to splice in to the generated code.
// This is Java, so to parse it we need to set IsJavaish so that we are a bit more lenient ...
private bool isJavaish = false;
public bool IsJavaish
{
get {
return isJavaish;
}
set {
isJavaish = value;
}
}
}
public compilation_unit:
@ -485,8 +500,16 @@ public qid_part:
public generic_argument_list:
'<' type_arguments '>' ;
public type_arguments:
type (',' type)* ;
type_argument (',' type_argument)* ;
public type_argument:
{this.IsJavaish}?=> javaish_type_argument
| type
;
public javaish_type_argument:
('?' 'extends')=> '?' 'extends' type
| '?'
| type
;
public type:
((predefined_type | type_name) rank_specifiers) => (predefined_type | type_name) rank_specifiers '*'*
| ((predefined_type | type_name) ('*'+ | '?')) => (predefined_type | type_name) ('*'+ | '?')
@ -1127,7 +1150,10 @@ public for_iterator:
public statement_expression_list:
statement_expression (',' statement_expression)* ;
public foreach_statement:
'foreach' '(' local_variable_type identifier 'in' expression ')' embedded_statement ;
'foreach' '(' local_variable_type identifier 'in' expression ')' embedded_statement
| {this.IsJavaish}? f='for' '(' local_variable_type identifier i=':' expression ')' embedded_statement
-> FOREACH[$f,"foreach"] '(' local_variable_type identifier IN[$i,"in"] expression ')' embedded_statement
;
public jump_statement:
break_statement
| continue_statement