a575963da9
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
956 lines
30 KiB
C#
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 ();
|
|
}
|
|
}
|
|
}
|