Jo Shields a575963da9 Imported Upstream version 3.6.0
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
2014-08-13 10:39:27 +01:00

956 lines
30 KiB
C#

//
// Authors:
// Marek Habersack (mhabersack@novell.com)
//
// (C) 2007 Novell, Inc
//
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections;
using System.IO;
using System.Reflection;
using System.Text;
using System.Xml;
using Microsoft.CSharp;
namespace Mono.Tools
{
class Position
{
int start = -1;
int end = -1;
public int Start {
get { return start; }
}
public int End {
get { return end; }
}
public int RequiredUALength {
get {
if (end == -1)
return start;
return end;
}
}
public override string ToString ()
{
StringBuilder sb = new StringBuilder ("Position {");
sb.AppendFormat ("{0}", start);
if (end != -1)
sb.AppendFormat (",{0}}}", end);
else
sb.Append ("}");
return sb.ToString ();
}
public Position (string positions)
{
if (positions == null || positions.Length == 0)
throw new ArgumentException ("'positions' must not be null or empty");
string[] pa = positions.Split ('-');
if (pa.Length > 2)
throw new ApplicationException ("Syntax error in the positions attribute - only one dash can be present");
try {
start = Int32.Parse (pa [0]);
} catch (Exception) {
throw new ApplicationException ("The 'positions' attribute has invalid syntax");
}
if (start < 0)
throw new ApplicationException ("Start must be 0 or more.");
if (pa.Length == 2) {
try {
end = Int32.Parse (pa [1]);
} catch (Exception) {
throw new ApplicationException ("The 'positions' attribute has invalid syntax");
}
if (end < start)
throw new ApplicationException ("End of range must not be smaller than its start");
if (end == start)
end = -1;
}
}
public CodeBinaryOperatorExpression GetExpression (string match)
{
int poslen;
if (end == -1)
poslen = 0;
else
poslen = end - start;
poslen++;
if (match.Length != poslen)
throw new ApplicationException (
String.Format ("Match string '{0}' has incorrect length (expected {1})", match, poslen));
CodeBinaryOperatorExpression expr = new CodeBinaryOperatorExpression ();
if (poslen == 1) {
expr.Left = new CodeArrayIndexerExpression (new CodeVariableReferenceExpression ("ua"),
new CodePrimitiveExpression (Start));
expr.Operator = CodeBinaryOperatorType.ValueEquality;
expr.Right = new CodePrimitiveExpression (match [0]);
} else {
CodeBinaryOperatorExpression cur = expr, prev = expr, tmp;
int i, pos;
for (i = 0, pos = Start; i < poslen; i++, pos++) {
tmp = new CodeBinaryOperatorExpression ();
tmp.Left = new CodeArrayIndexerExpression (new CodeVariableReferenceExpression ("ua"),
new CodePrimitiveExpression (pos));
tmp.Operator = CodeBinaryOperatorType.ValueEquality;
tmp.Right = new CodePrimitiveExpression (match [i]);
if (i + 1 < poslen) {
cur.Left = tmp;
cur.Operator = CodeBinaryOperatorType.BooleanAnd;
prev.Right = cur;
prev = cur;
cur = new CodeBinaryOperatorExpression ();
} else
prev.Right = tmp;
}
}
return expr;
}
}
class GroupDefinition
{
readonly CodeMethodReturnStatement returnTrue = new CodeMethodReturnStatement (new CodePrimitiveExpression (true));
readonly CodeMethodReturnStatement returnFalse = new CodeMethodReturnStatement (new CodePrimitiveExpression (false));
ArrayList positions = null;
ArrayList matches = null;
ArrayList childGroups;
ArrayList exceptions;
bool defaultJS = true;
int scanfrom = -1;
int skip = -1;
int level = 0;
int groupId = 0;
public Position[] Positions {
get {
if (positions == null)
return null;
return (Position[]) positions.ToArray (typeof (Position));
}
}
public string[] Matches {
get {
if (matches == null)
return null;
return (string[]) matches.ToArray (typeof (string));
}
}
public ArrayList ChildGroups {
get { return childGroups; }
}
public bool DefaultJS {
get { return defaultJS; }
}
public int ScanFrom {
get { return scanfrom; }
}
public int Skip {
get { return skip; }
}
public bool Positional {
get { return positions != null; }
}
public bool GroupZero {
get { return positions == null && matches == null && scanfrom == -1 && skip == -1; }
}
public int Level {
get { return level; }
set { level = value; }
}
public int GroupId {
get { return groupId; }
set { groupId = value; }
}
public override string ToString ()
{
if (GroupZero)
return "GroupZero";
StringBuilder sb = new StringBuilder ("Group: ");
if (Positional) {
sb.Append ("positions =");
foreach (Position p in positions)
sb.AppendFormat (" [{0}]", p.ToString ());
} else {
sb.AppendFormat ("scanfrom {0}, skip {1}", scanfrom, skip);
}
sb.Append ("; matches =");
foreach (string m in matches)
sb.AppendFormat (" [{0}]", m);
return sb.ToString ();
}
public GroupDefinition ()
{
childGroups = new ArrayList ();
}
public GroupDefinition (XmlReader reader)
{
childGroups = new ArrayList ();
string positions = reader.GetAttribute ("positions");
string scanfrom = reader.GetAttribute ("scanfrom");
if (positions != null && scanfrom != null)
throw new ApplicationException ("The 'positions' and 'scanfrom' attributes are mutually exclusive");
if ((positions == null || positions.Length == 0) && (scanfrom == null || scanfrom.Length == 0))
throw new ApplicationException ("Exactly one of the 'positions' or 'scanfrom' attributes must be present and have a value");
if (positions != null)
InitPositions (reader, positions);
else
InitScanfrom (reader, scanfrom);
string javascript = reader.GetAttribute ("javascript");
if (javascript != null && javascript.Length > 0) {
try {
defaultJS = Boolean.Parse (javascript);
} catch (Exception) {
throw new ApplicationException ("Invalid value of the 'javascript' attribute. Must be a valid boolean value (true or false)");
}
}
string match = reader.GetAttribute ("match");
if (match == null || match.Length == 0)
throw new ApplicationException ("Missing the 'match' attribute");
InitMatches (match);
}
public void AddExcept (XmlReader reader)
{
if (exceptions == null)
exceptions = new ArrayList ();
exceptions.Add (new GroupDefinition (reader));
}
void InitMatches (string match)
{
if (positions != null) {
string[] ma = match.Split (',');
if (ma.Length != positions.Count)
throw new ApplicationException ("Number of matches provided in the 'match' attribute is different that the number of positions.");
matches = new ArrayList (ma.Length);
foreach (string m in ma)
matches.Add (m);
} else {
matches = new ArrayList (1);
matches.Add (match);
}
}
void InitPositions (XmlReader reader, string positions)
{
string[] pa = positions.Split (',');
this.positions = new ArrayList (pa.Length);
foreach (string p in pa)
this.positions.Add (new Position (p.Trim ()));
}
void InitScanfrom (XmlReader reader, string scanfrom)
{
string skip = reader.GetAttribute ("skip");
if (skip == null || skip.Length == 0)
this.skip = 0;
else {
try {
this.skip = Int32.Parse (skip);
} catch (Exception) {
throw new ApplicationException ("Invalid value of the 'skip' attribute. Must be an integer.");
}
}
try {
this.scanfrom = Int32.Parse (scanfrom);
} catch (Exception) {
throw new ApplicationException ("Invalid value of the 'scanfrom' attribute. Must be an integer.");
}
}
public CodeCompileUnit GenerateCode ()
{
if (!GroupZero)
throw new ApplicationException ("Code can be generated only by GroupZero");
CodeCompileUnit unit = new CodeCompileUnit ();
CodeNamespace ns = new CodeNamespace ("System.Web");
unit.Namespaces.Add (ns);
ns.Imports.Add (new CodeNamespaceImport ("System"));
CodeTypeDeclaration mainClass = new CodeTypeDeclaration ("UplevelHelper");
mainClass.TypeAttributes = TypeAttributes.Class |
TypeAttributes.Sealed |
TypeAttributes.NotPublic |
TypeAttributes.NestedAssembly;
ns.Types.Add (mainClass);
GenerateMethod (mainClass);
return unit;
}
CodeMemberMethod GetMainMethod ()
{
CodeMemberMethod mainMethod = new CodeMemberMethod ();
mainMethod.Name = "IsUplevel";
mainMethod.ReturnType = new CodeTypeReference (typeof (bool));
mainMethod.Parameters.Add (new CodeParameterDeclarationExpression (typeof (string), "ua"));
mainMethod.Attributes = MemberAttributes.Public | MemberAttributes.Static | MemberAttributes.Final;
// if (ua == null)
// return false;
CodeBinaryOperatorExpression uaNull = new CodeBinaryOperatorExpression ();
uaNull.Left = new CodeArgumentReferenceExpression ("ua");
uaNull.Operator = CodeBinaryOperatorType.ValueEquality;
uaNull.Right = new CodePrimitiveExpression (null);
mainMethod.Statements.Add (new CodeConditionStatement (uaNull, returnFalse));
// int ualength = ua.Length;
mainMethod.Statements.Add (
new CodeVariableDeclarationStatement (
typeof (int),
"ualength",
new CodePropertyReferenceExpression (new CodeArgumentReferenceExpression ("ua"), "Length"))
);
// if (ualength == 0)
// return false;
CodeBinaryOperatorExpression uaEmpty = new CodeBinaryOperatorExpression ();
uaEmpty.Left = new CodeVariableReferenceExpression ("ualength");
uaEmpty.Operator = CodeBinaryOperatorType.ValueEquality;
uaEmpty.Right = new CodePrimitiveExpression (0);
mainMethod.Statements.Add (new CodeConditionStatement (uaEmpty, returnFalse));
// bool hasJavaScript = false;
mainMethod.Statements.Add (
new CodeVariableDeclarationStatement (typeof (bool), "hasJavaScript",
new CodePrimitiveExpression (false)));
return mainMethod;
}
CodeMemberMethod GetGroupMethod ()
{
CodeMemberMethod groupMethod = new CodeMemberMethod ();
groupMethod.Name = String.Format ("DetermineUplevel_{0}_{1}", level, groupId);
groupMethod.ReturnType = new CodeTypeReference (typeof (bool));
groupMethod.Parameters.Add (new CodeParameterDeclarationExpression (typeof (string), "ua"));
CodeParameterDeclarationExpression hasJavaScript =
new CodeParameterDeclarationExpression (typeof (bool), "hasJavaScript");
hasJavaScript.Direction = FieldDirection.Out;
groupMethod.Parameters.Add (hasJavaScript);
groupMethod.Parameters.Add (new CodeParameterDeclarationExpression (typeof (int), "ualength"));
groupMethod.Attributes = MemberAttributes.Private | MemberAttributes.Static | MemberAttributes.Final;
// hasJavaScript = <valueOf_DefaultJS>;
CodeAssignStatement assign = new CodeAssignStatement (new CodeVariableReferenceExpression ("hasJavaScript"),
new CodePrimitiveExpression (DefaultJS));
groupMethod.Statements.Add (assign);
return groupMethod;
}
ArrayList GenerateExceptions (CodeTypeDeclaration mainClass, bool assignHasJavaScript)
{
if (exceptions == null || exceptions.Count == 0)
return null;
ArrayList matches = new ArrayList (exceptions.Count);
CodeConditionStatement match;
foreach (GroupDefinition gd in exceptions) {
match = gd.GenerateConditionStatement (mainClass);
matches.Add (match);
if (assignHasJavaScript && gd.Positional)
match.TrueStatements.Add (new CodeAssignStatement (
new CodeVariableReferenceExpression ("hasJavaScript"),
new CodePrimitiveExpression (false)));
if (!assignHasJavaScript || GroupZero)
match.TrueStatements.Add (returnFalse);
else
match.TrueStatements.Add (returnTrue);
}
return matches;
}
CodeMemberMethod GenerateMethod (CodeTypeDeclaration mainClass)
{
CodeMemberMethod method;
if (GroupZero)
method = GetMainMethod ();
else
method = GetGroupMethod ();
mainClass.Members.Add (method);
CodeConditionStatement matches, subMatches;
ArrayList reverseMatches;
CodeMemberMethod childMethod;
CodeExpression hasJSRef = GroupZero ?
(CodeExpression) new CodeVariableReferenceExpression ("hasJavaScript") :
(CodeExpression) new CodeArgumentReferenceExpression ("hasJavaScript");
reverseMatches = GenerateExceptions (mainClass, !GroupZero);
if (reverseMatches != null && reverseMatches.Count > 0)
foreach (CodeConditionStatement ccs in reverseMatches)
method.Statements.Add (ccs);
if (childGroups.Count > 0) {
CodeDirectionExpression hasJavaScript = new CodeDirectionExpression (FieldDirection.Out, hasJSRef);
CodeExpression ualengthRef = GroupZero ?
(CodeExpression) new CodeVariableReferenceExpression ("ualength") :
(CodeExpression) new CodeArgumentReferenceExpression ("ualength");
int groupId = 0;
CodeMethodReturnStatement returnHasJS = new CodeMethodReturnStatement (
new CodeVariableReferenceExpression ("hasJavaScript"));
foreach (GroupDefinition gd in childGroups) {
matches = gd.GenerateConditionStatement (mainClass);
if (gd.ChildGroups.Count > 0) {
childMethod = gd.GenerateMethod (mainClass);
subMatches = new CodeConditionStatement ();
subMatches.Condition = new CodeMethodInvokeExpression (
new CodeMethodReferenceExpression (
new CodeTypeReferenceExpression ("UplevelHelper"), childMethod.Name),
new CodeExpression[] {new CodeArgumentReferenceExpression ("ua"),
hasJavaScript, ualengthRef}
);
subMatches.TrueStatements.Add (returnHasJS);
subMatches.FalseStatements.Add (new CodeMethodReturnStatement (
new CodePrimitiveExpression (false))
);
matches.TrueStatements.Add (subMatches);
} else {
reverseMatches = gd.GenerateExceptions (mainClass, !GroupZero);
if (reverseMatches != null && reverseMatches.Count > 0)
foreach (CodeConditionStatement ccs in reverseMatches)
matches.TrueStatements.Add (ccs);
if (!GroupZero && gd.Positional)
matches.TrueStatements.Add (
new CodeAssignStatement (
new CodeVariableReferenceExpression ("hasJavaScript"),
new CodePrimitiveExpression (true))
);
matches.TrueStatements.Add (returnTrue);
}
method.Statements.Add (matches);
groupId++;
}
// return false;
method.Statements.Add (new CodeMethodReturnStatement (new CodePrimitiveExpression (false)));
} else
// return <valueOf_DefaultJS>
method.Statements.Add (new CodeMethodReturnStatement (new CodePrimitiveExpression (DefaultJS)));
return method;
}
CodeConditionStatement GenerateConditionStatement (CodeTypeDeclaration mainClass)
{
CodeConditionStatement ret = new CodeConditionStatement ();
if (Positional)
ret.Condition = GeneratePositionalExpression ();
else
ret.Condition = GenerateScanfromExpression (mainClass);
return ret;
}
CodeExpression GeneratePositionalExpression ()
{
Position[] positions = Positions;
string[] matches = Matches;
ArrayList components = new ArrayList ();
int i, reqLength = 0;
Position p;
for (i = 0; i < positions.Length; i++) {
p = positions [i];
components.Add (p.GetExpression (matches [i]));
if (p.RequiredUALength > reqLength)
reqLength = p.RequiredUALength;
}
CodeBinaryOperatorExpression expr = null;
int complen = components.Count;
i = 0;
if (complen == 1)
expr = components [0] as CodeBinaryOperatorExpression;
else {
expr = new CodeBinaryOperatorExpression ();
CodeBinaryOperatorExpression cur = expr, prev = expr;
foreach (CodeBinaryOperatorExpression op in components) {
if (i + 1 < complen) {
cur.Left = op;
cur.Operator = CodeBinaryOperatorType.BooleanAnd;
prev.Right = cur;
prev = cur;
cur = new CodeBinaryOperatorExpression ();
} else {
prev.Right = op;
}
i++;
}
}
CodeBinaryOperatorExpression sizeCheck = new CodeBinaryOperatorExpression ();
sizeCheck.Left = GroupZero ?
(CodeExpression) new CodeVariableReferenceExpression ("ualength") :
(CodeExpression) new CodeArgumentReferenceExpression ("ualength");
sizeCheck.Operator = CodeBinaryOperatorType.GreaterThan;
sizeCheck.Right = new CodePrimitiveExpression (reqLength);
CodeBinaryOperatorExpression ret = new CodeBinaryOperatorExpression ();
ret.Left = sizeCheck;
ret.Operator = CodeBinaryOperatorType.BooleanAnd;
ret.Right = expr;
return ret;
}
CodeMemberMethod GenerateScanMethod ()
{
CodeMemberMethod method = new CodeMemberMethod ();
method.Name = String.Format ("ScanForMatch_{0}_{1}", level, groupId);
method.ReturnType = new CodeTypeReference (typeof (bool));
method.Parameters.Add (new CodeParameterDeclarationExpression (typeof (string), "ua"));
CodeParameterDeclarationExpression hasJavaScript =
new CodeParameterDeclarationExpression (typeof (bool), "hasJavaScript");
hasJavaScript.Direction = FieldDirection.Out;
method.Parameters.Add (hasJavaScript);
method.Parameters.Add (new CodeParameterDeclarationExpression (typeof (int), "ualength"));
method.Attributes = MemberAttributes.Private | MemberAttributes.Static | MemberAttributes.Final;
// hasJavaScript = <valueOf_DefaultJS>;
CodeAssignStatement assign = new CodeAssignStatement (new CodeVariableReferenceExpression ("hasJavaScript"),
new CodePrimitiveExpression (DefaultJS));
method.Statements.Add (assign);
return method;
}
CodeBinaryOperatorExpression GenerateScanCondition (string match, int matchLength, int startPosition)
{
CodeBinaryOperatorExpression ret = new CodeBinaryOperatorExpression ();
int endPosition = startPosition + matchLength - 1;
int matchStartPosition = 0;
int matchEndPosition = matchLength - 1;
CodeArgumentReferenceExpression uaRef = new CodeArgumentReferenceExpression ("ua");
if (matchLength == 1) {
ret.Left = new CodeArrayIndexerExpression (uaRef, new CodePrimitiveExpression (startPosition));
ret.Operator = CodeBinaryOperatorType.ValueEquality;
ret.Right = new CodePrimitiveExpression (match [matchStartPosition]);
return ret;
}
CodeBinaryOperatorExpression cur = ret, prev = null, lhs, rhs, tmp;
if (matchLength == 2) {
lhs = new CodeBinaryOperatorExpression ();
lhs.Left = new CodeArrayIndexerExpression (uaRef, new CodePrimitiveExpression (startPosition++));
lhs.Operator = CodeBinaryOperatorType.ValueEquality;
lhs.Right = new CodePrimitiveExpression (match [matchStartPosition]);
rhs = new CodeBinaryOperatorExpression ();
rhs.Left = new CodeArrayIndexerExpression (uaRef, new CodePrimitiveExpression (endPosition--));
rhs.Operator = CodeBinaryOperatorType.ValueEquality;
rhs.Right = new CodePrimitiveExpression (match [matchEndPosition]);
ret.Left = lhs;
ret.Operator = CodeBinaryOperatorType.BooleanAnd;
ret.Right = rhs;
return ret;
}
bool matchOdd = matchLength % 2 != 0;
while (matchLength >= 0) {
matchLength--;
if (!matchOdd || (matchOdd && (matchLength - 1) > 0)) {
lhs = new CodeBinaryOperatorExpression ();
lhs.Left = new CodeArrayIndexerExpression (
uaRef,
new CodeBinaryOperatorExpression (
new CodeVariableReferenceExpression ("startPosition"),
CodeBinaryOperatorType.Add,
new CodePrimitiveExpression (matchStartPosition))
);
lhs.Operator = CodeBinaryOperatorType.ValueEquality;
lhs.Right = new CodePrimitiveExpression (match [matchStartPosition]);
rhs = new CodeBinaryOperatorExpression ();
rhs.Left = new CodeArrayIndexerExpression (
uaRef,
new CodeBinaryOperatorExpression (
new CodeVariableReferenceExpression ("endPosition"),
CodeBinaryOperatorType.Subtract,
new CodePrimitiveExpression (matchEndPosition - matchLength))
);
rhs.Operator = CodeBinaryOperatorType.ValueEquality;
rhs.Right = new CodePrimitiveExpression (match [matchEndPosition]);
tmp = new CodeBinaryOperatorExpression (lhs, CodeBinaryOperatorType.BooleanAnd, rhs);
matchLength--;
} else {
tmp = new CodeBinaryOperatorExpression ();
tmp.Left = new CodeArrayIndexerExpression (
uaRef,
new CodeBinaryOperatorExpression (
new CodeVariableReferenceExpression ("startPosition"),
CodeBinaryOperatorType.Add,
new CodePrimitiveExpression (matchStartPosition - 1))
);
tmp.Operator = CodeBinaryOperatorType.ValueEquality;
tmp.Right = new CodePrimitiveExpression (match [matchStartPosition - 1]);
}
if (matchLength - 1 >= 0) {
cur.Left = tmp;
cur.Operator = CodeBinaryOperatorType.BooleanAnd;
if (prev != null)
prev.Right = cur;
prev = cur;
cur = new CodeBinaryOperatorExpression ();
} else
prev.Right = tmp;
matchStartPosition++;
matchEndPosition--;
}
return ret;
}
CodeExpression GenerateScanfromExpression (CodeTypeDeclaration mainClass)
{
CodeMemberMethod method = GenerateScanMethod ();
int startPosition = scanfrom + skip;
string match = matches [0] as string;
int matchLength = match.Length;
int minsize = startPosition + matchLength + 1;
// if (ualength < minsize)
// return false;
CodeBinaryOperatorExpression uaSizeCheck = new CodeBinaryOperatorExpression ();
uaSizeCheck.Left = new CodeArgumentReferenceExpression ("ualength");
uaSizeCheck.Operator = CodeBinaryOperatorType.LessThan;
uaSizeCheck.Right = new CodePrimitiveExpression (minsize);
method.Statements.Add (
new CodeConditionStatement (uaSizeCheck,
new CodeMethodReturnStatement (new CodePrimitiveExpression (false))));
// int startPosition = 0;
method.Statements.Add (
new CodeVariableDeclarationStatement (typeof (int), "startPosition",
new CodePrimitiveExpression (0)));
// int endPosition = startPosition + matchLength;
method.Statements.Add (
new CodeVariableDeclarationStatement (
typeof (int), "endPosition",
new CodeBinaryOperatorExpression (
new CodeVariableReferenceExpression ("startPosition"),
CodeBinaryOperatorType.Add,
new CodePrimitiveExpression (matchLength - 1))
)
);
// for (int ualeft = ualength; ualeft >= matchlen; ualeft--) {
// if (<condition>) {
// hasJavaScript = true;
// return true;
// }
// startPosition++;
// endPosition++;
// }
CodeIterationStatement iter = new CodeIterationStatement ();
iter.InitStatement = new CodeVariableDeclarationStatement (
typeof (int), "ualeft", new CodeArgumentReferenceExpression ("ualength"));
iter.IncrementStatement = new CodeAssignStatement (
new CodeVariableReferenceExpression ("ualeft"),
new CodeBinaryOperatorExpression (new CodeVariableReferenceExpression ("ualeft"),
CodeBinaryOperatorType.Subtract,
new CodePrimitiveExpression (1))
);
iter.TestExpression = new CodeBinaryOperatorExpression (
new CodeVariableReferenceExpression ("ualeft"),
CodeBinaryOperatorType.GreaterThanOrEqual,
new CodePrimitiveExpression (matchLength)
);
CodeConditionStatement cond = new CodeConditionStatement (
GenerateScanCondition (match, matchLength, startPosition));
cond.TrueStatements.Add (
new CodeAssignStatement (new CodeArgumentReferenceExpression ("hasJavaScript"),
new CodePrimitiveExpression (true)));
cond.TrueStatements.Add (new CodeMethodReturnStatement (new CodePrimitiveExpression (true)));
iter.Statements.Add (cond);
iter.Statements.Add (
new CodeAssignStatement (new CodeVariableReferenceExpression ("startPosition"),
new CodeBinaryOperatorExpression (
new CodeVariableReferenceExpression ("startPosition"),
CodeBinaryOperatorType.Add,
new CodePrimitiveExpression (1)))
);
iter.Statements.Add (
new CodeAssignStatement (new CodeVariableReferenceExpression ("endPosition"),
new CodeBinaryOperatorExpression (
new CodeVariableReferenceExpression ("endPosition"),
CodeBinaryOperatorType.Add,
new CodePrimitiveExpression (1)))
);
method.Statements.Add (iter);
method.Statements.Add (new CodeMethodReturnStatement (new CodePrimitiveExpression (false)));
mainClass.Members.Add (method);
return new CodeMethodInvokeExpression (
new CodeMethodReferenceExpression (new CodeTypeReferenceExpression ("UplevelHelper"), method.Name),
new CodeExpression[] {new CodeArgumentReferenceExpression ("ua"),
new CodeDirectionExpression (
FieldDirection.Out,
new CodeArgumentReferenceExpression ("hasJavaScript")),
new CodeArgumentReferenceExpression ("ualength")}
);
}
}
public class CompileUplevel
{
public static void Main (string[] args)
{
try {
CompileUplevel cu = new CompileUplevel ();
cu.Run (args);
} catch (Exception ex) {
Console.Error.WriteLine ("Exception caught while generating UplevelHelper code:");
Console.Error.Write (ex);
Console.Error.WriteLine ();
}
}
void Usage (string format, params object[] parms)
{
if (format != null && format.Length > 0) {
Console.Error.WriteLine (format, parms);
Environment.Exit (1);
}
Console.Error.WriteLine (@"Usage: culevel [OPTIONS] INPUT_FILE
Options:
-o|--o|-output|--output file to write the generated code to.
If not specified, output goes to the console
-h|--h|-help|--help show this usage information.
");
Environment.Exit (0);
}
void DumpGroup (GroupDefinition gd, int indent)
{
Console.WriteLine ("{0}{1}", new String (' ', indent), gd.ToString ());
foreach (GroupDefinition gd2 in gd.ChildGroups)
DumpGroup (gd2, indent + 1);
}
void Run (string[] args)
{
if (args.Length < 1)
Usage ("Invalid number of parameters");
Stack context = new Stack ();
GroupDefinition groupZero = new GroupDefinition ();
GroupDefinition group, current;
XmlReader reader = null;
string outfile = null, infile = null;
string a;
for (int i = 0; i < args.Length; i++) {
a = args [i];
if (a [0] == '-' && a.Length > 1) {
a = a.Substring (1).Trim ();
switch (a.ToLower ()) {
case "o":
case "output":
case "-output":
i++;
if (i > args.Length)
Usage ("Missing output file name");
outfile = args [i];
break;
case "h":
case "help":
case "-help":
Usage (null);
break;
default:
Usage ("Unknown command line option: '{0}'", a);
break;
}
} else if (infile == null)
infile = args [i];
}
if (infile == null)
Usage ("Missing input file on the command line.");
try {
XmlNodeType nodeType;
int level = 1;
bool ingroup = false;
reader = new XmlTextReader (infile);
while (reader.Read ()) {
nodeType = reader.NodeType;
if (nodeType != XmlNodeType.Element && nodeType != XmlNodeType.EndElement)
continue;
current = context.Count > 0 ? context.Peek () as GroupDefinition : null;
if (ingroup && reader.LocalName == "except") {
if (current == null)
throw new ApplicationException ("Inside a group but there is no group on the stack");
current.AddExcept (reader);
continue;
}
if (reader.LocalName != "group")
continue;
if (reader.NodeType == XmlNodeType.EndElement) {
if (current == null)
throw new ApplicationException ("Found group end, but no current group on stack");
context.Pop ();
if (context.Count == 0) {
groupZero.ChildGroups.Add (current);
current.GroupId = groupZero.ChildGroups.Count;
}
level--;
ingroup = false;
continue;
}
group = new GroupDefinition (reader);
group.Level = level++;
if (current != null) {
current.ChildGroups.Add (group);
group.GroupId = current.ChildGroups.Count;
}
context.Push (group);
ingroup = true;
}
} catch (Exception) {
throw;
} finally {
if (reader != null)
reader.Close();
}
CodeCompileUnit unit = groupZero.GenerateCode ();
if (unit == null)
Environment.Exit (1);
CodeDomProvider provider = new CSharpCodeProvider ();
ICodeGenerator gen = provider.CreateGenerator ();
TextWriter tw;
if (outfile == null)
tw = Console.Out;
else
tw = new IndentedTextWriter (new StreamWriter (outfile, false), "\t");
gen.GenerateCodeFromCompileUnit (unit, tw, new CodeGeneratorOptions ());
if (outfile != null)
tw.Close ();
}
}
}