3 // Marek Habersack (mhabersack@novell.com)
5 // (C) 2007 Novell, Inc
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 using System
.CodeDom
.Compiler
;
31 using System
.Collections
;
33 using System
.Reflection
;
36 using Microsoft
.CSharp
;
53 public int RequiredUALength
{
61 public override string ToString ()
63 StringBuilder sb
= new StringBuilder ("Position {");
64 sb
.AppendFormat ("{0}", start
);
66 sb
.AppendFormat (",{0}}}", end
);
70 return sb
.ToString ();
73 public Position (string positions
)
75 if (positions
== null || positions
.Length
== 0)
76 throw new ArgumentException ("'positions' must not be null or empty");
78 string[] pa
= positions
.Split ('-');
81 throw new ApplicationException ("Syntax error in the positions attribute - only one dash can be present");
84 start
= Int32
.Parse (pa
[0]);
86 throw new ApplicationException ("The 'positions' attribute has invalid syntax");
90 throw new ApplicationException ("Start must be 0 or more.");
94 end
= Int32
.Parse (pa
[1]);
96 throw new ApplicationException ("The 'positions' attribute has invalid syntax");
100 throw new ApplicationException ("End of range must not be smaller than its start");
107 public CodeBinaryOperatorExpression
GetExpression (string match
)
114 poslen
= end
- start
;
117 if (match
.Length
!= poslen
)
118 throw new ApplicationException (
119 String
.Format ("Match string '{0}' has incorrect length (expected {1})", match
, poslen
));
121 CodeBinaryOperatorExpression expr
= new CodeBinaryOperatorExpression ();
124 expr
.Left
= new CodeArrayIndexerExpression (new CodeVariableReferenceExpression ("ua"),
125 new CodePrimitiveExpression (Start
));
126 expr
.Operator
= CodeBinaryOperatorType
.ValueEquality
;
127 expr
.Right
= new CodePrimitiveExpression (match
[0]);
129 CodeBinaryOperatorExpression cur
= expr
, prev
= expr
, tmp
;
132 for (i
= 0, pos
= Start
; i
< poslen
; i
++, pos
++) {
133 tmp
= new CodeBinaryOperatorExpression ();
134 tmp
.Left
= new CodeArrayIndexerExpression (new CodeVariableReferenceExpression ("ua"),
135 new CodePrimitiveExpression (pos
));
136 tmp
.Operator
= CodeBinaryOperatorType
.ValueEquality
;
137 tmp
.Right
= new CodePrimitiveExpression (match
[i
]);
139 if (i
+ 1 < poslen
) {
141 cur
.Operator
= CodeBinaryOperatorType
.BooleanAnd
;
144 cur
= new CodeBinaryOperatorExpression ();
154 class GroupDefinition
156 readonly CodeMethodReturnStatement returnTrue
= new CodeMethodReturnStatement (new CodePrimitiveExpression (true));
157 readonly CodeMethodReturnStatement returnFalse
= new CodeMethodReturnStatement (new CodePrimitiveExpression (false));
159 ArrayList positions
= null;
160 ArrayList matches
= null;
161 ArrayList childGroups
;
162 ArrayList exceptions
;
164 bool defaultJS
= true;
170 public Position
[] Positions
{
172 if (positions
== null)
174 return (Position
[]) positions
.ToArray (typeof (Position
));
178 public string[] Matches
{
182 return (string[]) matches
.ToArray (typeof (string));
186 public ArrayList ChildGroups
{
187 get { return childGroups; }
190 public bool DefaultJS
{
191 get { return defaultJS; }
194 public int ScanFrom
{
195 get { return scanfrom; }
202 public bool Positional
{
203 get { return positions != null; }
206 public bool GroupZero
{
207 get { return positions == null && matches == null && scanfrom == -1 && skip == -1; }
211 get { return level; }
212 set { level = value; }
216 get { return groupId; }
217 set { groupId = value; }
220 public override string ToString ()
225 StringBuilder sb
= new StringBuilder ("Group: ");
227 sb
.Append ("positions =");
228 foreach (Position p
in positions
)
229 sb
.AppendFormat (" [{0}]", p
.ToString ());
231 sb
.AppendFormat ("scanfrom {0}, skip {1}", scanfrom
, skip
);
234 sb
.Append ("; matches =");
235 foreach (string m
in matches
)
236 sb
.AppendFormat (" [{0}]", m
);
238 return sb
.ToString ();
241 public GroupDefinition ()
243 childGroups
= new ArrayList ();
246 public GroupDefinition (XmlReader reader
)
248 childGroups
= new ArrayList ();
250 string positions
= reader
.GetAttribute ("positions");
251 string scanfrom
= reader
.GetAttribute ("scanfrom");
253 if (positions
!= null && scanfrom
!= null)
254 throw new ApplicationException ("The 'positions' and 'scanfrom' attributes are mutually exclusive");
255 if ((positions
== null || positions
.Length
== 0) && (scanfrom
== null || scanfrom
.Length
== 0))
256 throw new ApplicationException ("Exactly one of the 'positions' or 'scanfrom' attributes must be present and have a value");
258 if (positions
!= null)
259 InitPositions (reader
, positions
);
261 InitScanfrom (reader
, scanfrom
);
263 string javascript
= reader
.GetAttribute ("javascript");
264 if (javascript
!= null && javascript
.Length
> 0) {
266 defaultJS
= Boolean
.Parse (javascript
);
267 } catch (Exception
) {
268 throw new ApplicationException ("Invalid value of the 'javascript' attribute. Must be a valid boolean value (true or false)");
272 string match
= reader
.GetAttribute ("match");
273 if (match
== null || match
.Length
== 0)
274 throw new ApplicationException ("Missing the 'match' attribute");
279 public void AddExcept (XmlReader reader
)
281 if (exceptions
== null)
282 exceptions
= new ArrayList ();
284 exceptions
.Add (new GroupDefinition (reader
));
287 void InitMatches (string match
)
289 if (positions
!= null) {
290 string[] ma
= match
.Split (',');
292 if (ma
.Length
!= positions
.Count
)
293 throw new ApplicationException ("Number of matches provided in the 'match' attribute is different that the number of positions.");
295 matches
= new ArrayList (ma
.Length
);
296 foreach (string m
in ma
)
299 matches
= new ArrayList (1);
304 void InitPositions (XmlReader reader
, string positions
)
306 string[] pa
= positions
.Split (',');
307 this.positions
= new ArrayList (pa
.Length
);
308 foreach (string p
in pa
)
309 this.positions
.Add (new Position (p
.Trim ()));
312 void InitScanfrom (XmlReader reader
, string scanfrom
)
314 string skip
= reader
.GetAttribute ("skip");
316 if (skip
== null || skip
.Length
== 0)
320 this.skip
= Int32
.Parse (skip
);
321 } catch (Exception
) {
322 throw new ApplicationException ("Invalid value of the 'skip' attribute. Must be an integer.");
327 this.scanfrom
= Int32
.Parse (scanfrom
);
328 } catch (Exception
) {
329 throw new ApplicationException ("Invalid value of the 'scanfrom' attribute. Must be an integer.");
333 public CodeCompileUnit
GenerateCode ()
336 throw new ApplicationException ("Code can be generated only by GroupZero");
338 CodeCompileUnit unit
= new CodeCompileUnit ();
339 CodeNamespace ns
= new CodeNamespace ("System.Web");
340 unit
.Namespaces
.Add (ns
);
342 ns
.Imports
.Add (new CodeNamespaceImport ("System"));
344 CodeTypeDeclaration mainClass
= new CodeTypeDeclaration ("UplevelHelper");
345 mainClass
.TypeAttributes
= TypeAttributes
.Class
|
346 TypeAttributes
.Sealed
|
347 TypeAttributes
.NotPublic
|
348 TypeAttributes
.NestedAssembly
;
349 ns
.Types
.Add (mainClass
);
351 GenerateMethod (mainClass
);
355 CodeMemberMethod
GetMainMethod ()
357 CodeMemberMethod mainMethod
= new CodeMemberMethod ();
358 mainMethod
.Name
= "IsUplevel";
359 mainMethod
.ReturnType
= new CodeTypeReference (typeof (bool));
360 mainMethod
.Parameters
.Add (new CodeParameterDeclarationExpression (typeof (string), "ua"));
361 mainMethod
.Attributes
= MemberAttributes
.Public
| MemberAttributes
.Static
| MemberAttributes
.Final
;
365 CodeBinaryOperatorExpression uaNull
= new CodeBinaryOperatorExpression ();
366 uaNull
.Left
= new CodeArgumentReferenceExpression ("ua");
367 uaNull
.Operator
= CodeBinaryOperatorType
.ValueEquality
;
368 uaNull
.Right
= new CodePrimitiveExpression (null);
369 mainMethod
.Statements
.Add (new CodeConditionStatement (uaNull
, returnFalse
));
371 // int ualength = ua.Length;
372 mainMethod
.Statements
.Add (
373 new CodeVariableDeclarationStatement (
376 new CodePropertyReferenceExpression (new CodeArgumentReferenceExpression ("ua"), "Length"))
379 // if (ualength == 0)
381 CodeBinaryOperatorExpression uaEmpty
= new CodeBinaryOperatorExpression ();
382 uaEmpty
.Left
= new CodeVariableReferenceExpression ("ualength");
383 uaEmpty
.Operator
= CodeBinaryOperatorType
.ValueEquality
;
384 uaEmpty
.Right
= new CodePrimitiveExpression (0);
385 mainMethod
.Statements
.Add (new CodeConditionStatement (uaEmpty
, returnFalse
));
387 // bool hasJavaScript = false;
388 mainMethod
.Statements
.Add (
389 new CodeVariableDeclarationStatement (typeof (bool), "hasJavaScript",
390 new CodePrimitiveExpression (false)));
395 CodeMemberMethod
GetGroupMethod ()
397 CodeMemberMethod groupMethod
= new CodeMemberMethod ();
398 groupMethod
.Name
= String
.Format ("DetermineUplevel_{0}_{1}", level
, groupId
);
399 groupMethod
.ReturnType
= new CodeTypeReference (typeof (bool));
400 groupMethod
.Parameters
.Add (new CodeParameterDeclarationExpression (typeof (string), "ua"));
401 CodeParameterDeclarationExpression hasJavaScript
=
402 new CodeParameterDeclarationExpression (typeof (bool), "hasJavaScript");
404 hasJavaScript
.Direction
= FieldDirection
.Out
;
405 groupMethod
.Parameters
.Add (hasJavaScript
);
406 groupMethod
.Parameters
.Add (new CodeParameterDeclarationExpression (typeof (int), "ualength"));
407 groupMethod
.Attributes
= MemberAttributes
.Private
| MemberAttributes
.Static
| MemberAttributes
.Final
;
409 // hasJavaScript = <valueOf_DefaultJS>;
410 CodeAssignStatement assign
= new CodeAssignStatement (new CodeVariableReferenceExpression ("hasJavaScript"),
411 new CodePrimitiveExpression (DefaultJS
));
412 groupMethod
.Statements
.Add (assign
);
417 ArrayList
GenerateExceptions (CodeTypeDeclaration mainClass
, bool assignHasJavaScript
)
419 if (exceptions
== null || exceptions
.Count
== 0)
422 ArrayList matches
= new ArrayList (exceptions
.Count
);
423 CodeConditionStatement match
;
425 foreach (GroupDefinition gd
in exceptions
) {
426 match
= gd
.GenerateConditionStatement (mainClass
);
429 if (assignHasJavaScript
&& gd
.Positional
)
430 match
.TrueStatements
.Add (new CodeAssignStatement (
431 new CodeVariableReferenceExpression ("hasJavaScript"),
432 new CodePrimitiveExpression (false)));
433 if (!assignHasJavaScript
|| GroupZero
)
434 match
.TrueStatements
.Add (returnFalse
);
436 match
.TrueStatements
.Add (returnTrue
);
442 CodeMemberMethod
GenerateMethod (CodeTypeDeclaration mainClass
)
444 CodeMemberMethod method
;
447 method
= GetMainMethod ();
449 method
= GetGroupMethod ();
451 mainClass
.Members
.Add (method
);
452 CodeConditionStatement matches
, subMatches
;
453 ArrayList reverseMatches
;
454 CodeMemberMethod childMethod
;
455 CodeExpression hasJSRef
= GroupZero
?
456 (CodeExpression
) new CodeVariableReferenceExpression ("hasJavaScript") :
457 (CodeExpression
) new CodeArgumentReferenceExpression ("hasJavaScript");
459 reverseMatches
= GenerateExceptions (mainClass
, !GroupZero
);
460 if (reverseMatches
!= null && reverseMatches
.Count
> 0)
461 foreach (CodeConditionStatement ccs
in reverseMatches
)
462 method
.Statements
.Add (ccs
);
464 if (childGroups
.Count
> 0) {
465 CodeDirectionExpression hasJavaScript
= new CodeDirectionExpression (FieldDirection
.Out
, hasJSRef
);
466 CodeExpression ualengthRef
= GroupZero
?
467 (CodeExpression
) new CodeVariableReferenceExpression ("ualength") :
468 (CodeExpression
) new CodeArgumentReferenceExpression ("ualength");
472 CodeMethodReturnStatement returnHasJS
= new CodeMethodReturnStatement (
473 new CodeVariableReferenceExpression ("hasJavaScript"));
475 foreach (GroupDefinition gd
in childGroups
) {
476 matches
= gd
.GenerateConditionStatement (mainClass
);
478 if (gd
.ChildGroups
.Count
> 0) {
479 childMethod
= gd
.GenerateMethod (mainClass
);
481 subMatches
= new CodeConditionStatement ();
482 subMatches
.Condition
= new CodeMethodInvokeExpression (
483 new CodeMethodReferenceExpression (
484 new CodeTypeReferenceExpression ("UplevelHelper"), childMethod
.Name
),
485 new CodeExpression
[] {new CodeArgumentReferenceExpression ("ua"),
486 hasJavaScript
, ualengthRef
}
488 subMatches
.TrueStatements
.Add (returnHasJS
);
489 subMatches
.FalseStatements
.Add (new CodeMethodReturnStatement (
490 new CodePrimitiveExpression (false))
493 matches
.TrueStatements
.Add (subMatches
);
495 reverseMatches
= gd
.GenerateExceptions (mainClass
, !GroupZero
);
496 if (reverseMatches
!= null && reverseMatches
.Count
> 0)
497 foreach (CodeConditionStatement ccs
in reverseMatches
)
498 matches
.TrueStatements
.Add (ccs
);
500 if (!GroupZero
&& gd
.Positional
)
501 matches
.TrueStatements
.Add (
502 new CodeAssignStatement (
503 new CodeVariableReferenceExpression ("hasJavaScript"),
504 new CodePrimitiveExpression (true))
506 matches
.TrueStatements
.Add (returnTrue
);
508 method
.Statements
.Add (matches
);
513 method
.Statements
.Add (new CodeMethodReturnStatement (new CodePrimitiveExpression (false)));
515 // return <valueOf_DefaultJS>
516 method
.Statements
.Add (new CodeMethodReturnStatement (new CodePrimitiveExpression (DefaultJS
)));
521 CodeConditionStatement
GenerateConditionStatement (CodeTypeDeclaration mainClass
)
523 CodeConditionStatement ret
= new CodeConditionStatement ();
526 ret
.Condition
= GeneratePositionalExpression ();
528 ret
.Condition
= GenerateScanfromExpression (mainClass
);
533 CodeExpression
GeneratePositionalExpression ()
535 Position
[] positions
= Positions
;
536 string[] matches
= Matches
;
537 ArrayList components
= new ArrayList ();
539 int i
, reqLength
= 0;
542 for (i
= 0; i
< positions
.Length
; i
++) {
544 components
.Add (p
.GetExpression (matches
[i
]));
545 if (p
.RequiredUALength
> reqLength
)
546 reqLength
= p
.RequiredUALength
;
549 CodeBinaryOperatorExpression expr
= null;
551 int complen
= components
.Count
;
555 expr
= components
[0] as CodeBinaryOperatorExpression
;
557 expr
= new CodeBinaryOperatorExpression ();
558 CodeBinaryOperatorExpression cur
= expr
, prev
= expr
;
559 foreach (CodeBinaryOperatorExpression op
in components
) {
560 if (i
+ 1 < complen
) {
562 cur
.Operator
= CodeBinaryOperatorType
.BooleanAnd
;
565 cur
= new CodeBinaryOperatorExpression ();
573 CodeBinaryOperatorExpression sizeCheck
= new CodeBinaryOperatorExpression ();
574 sizeCheck
.Left
= GroupZero
?
575 (CodeExpression
) new CodeVariableReferenceExpression ("ualength") :
576 (CodeExpression
) new CodeArgumentReferenceExpression ("ualength");
577 sizeCheck
.Operator
= CodeBinaryOperatorType
.GreaterThan
;
578 sizeCheck
.Right
= new CodePrimitiveExpression (reqLength
);
580 CodeBinaryOperatorExpression ret
= new CodeBinaryOperatorExpression ();
581 ret
.Left
= sizeCheck
;
582 ret
.Operator
= CodeBinaryOperatorType
.BooleanAnd
;
588 CodeMemberMethod
GenerateScanMethod ()
590 CodeMemberMethod method
= new CodeMemberMethod ();
591 method
.Name
= String
.Format ("ScanForMatch_{0}_{1}", level
, groupId
);
593 method
.ReturnType
= new CodeTypeReference (typeof (bool));
594 method
.Parameters
.Add (new CodeParameterDeclarationExpression (typeof (string), "ua"));
595 CodeParameterDeclarationExpression hasJavaScript
=
596 new CodeParameterDeclarationExpression (typeof (bool), "hasJavaScript");
598 hasJavaScript
.Direction
= FieldDirection
.Out
;
599 method
.Parameters
.Add (hasJavaScript
);
600 method
.Parameters
.Add (new CodeParameterDeclarationExpression (typeof (int), "ualength"));
601 method
.Attributes
= MemberAttributes
.Private
| MemberAttributes
.Static
| MemberAttributes
.Final
;
603 // hasJavaScript = <valueOf_DefaultJS>;
604 CodeAssignStatement assign
= new CodeAssignStatement (new CodeVariableReferenceExpression ("hasJavaScript"),
605 new CodePrimitiveExpression (DefaultJS
));
607 method
.Statements
.Add (assign
);
611 CodeBinaryOperatorExpression
GenerateScanCondition (string match
, int matchLength
, int startPosition
)
613 CodeBinaryOperatorExpression ret
= new CodeBinaryOperatorExpression ();
615 int endPosition
= startPosition
+ matchLength
- 1;
616 int matchStartPosition
= 0;
617 int matchEndPosition
= matchLength
- 1;
618 CodeArgumentReferenceExpression uaRef
= new CodeArgumentReferenceExpression ("ua");
620 if (matchLength
== 1) {
621 ret
.Left
= new CodeArrayIndexerExpression (uaRef
, new CodePrimitiveExpression (startPosition
));
622 ret
.Operator
= CodeBinaryOperatorType
.ValueEquality
;
623 ret
.Right
= new CodePrimitiveExpression (match
[matchStartPosition
]);
627 CodeBinaryOperatorExpression cur
= ret
, prev
= null, lhs
, rhs
, tmp
;
629 if (matchLength
== 2) {
630 lhs
= new CodeBinaryOperatorExpression ();
631 lhs
.Left
= new CodeArrayIndexerExpression (uaRef
, new CodePrimitiveExpression (startPosition
++));
632 lhs
.Operator
= CodeBinaryOperatorType
.ValueEquality
;
633 lhs
.Right
= new CodePrimitiveExpression (match
[matchStartPosition
]);
635 rhs
= new CodeBinaryOperatorExpression ();
636 rhs
.Left
= new CodeArrayIndexerExpression (uaRef
, new CodePrimitiveExpression (endPosition
--));
637 rhs
.Operator
= CodeBinaryOperatorType
.ValueEquality
;
638 rhs
.Right
= new CodePrimitiveExpression (match
[matchEndPosition
]);
641 ret
.Operator
= CodeBinaryOperatorType
.BooleanAnd
;
647 bool matchOdd
= matchLength
% 2 != 0;
649 while (matchLength
>= 0) {
651 if (!matchOdd
|| (matchOdd
&& (matchLength
- 1) > 0)) {
652 lhs
= new CodeBinaryOperatorExpression ();
653 lhs
.Left
= new CodeArrayIndexerExpression (
655 new CodeBinaryOperatorExpression (
656 new CodeVariableReferenceExpression ("startPosition"),
657 CodeBinaryOperatorType
.Add
,
658 new CodePrimitiveExpression (matchStartPosition
))
660 lhs
.Operator
= CodeBinaryOperatorType
.ValueEquality
;
661 lhs
.Right
= new CodePrimitiveExpression (match
[matchStartPosition
]);
663 rhs
= new CodeBinaryOperatorExpression ();
664 rhs
.Left
= new CodeArrayIndexerExpression (
666 new CodeBinaryOperatorExpression (
667 new CodeVariableReferenceExpression ("endPosition"),
668 CodeBinaryOperatorType
.Subtract
,
669 new CodePrimitiveExpression (matchEndPosition
- matchLength
))
672 rhs
.Operator
= CodeBinaryOperatorType
.ValueEquality
;
673 rhs
.Right
= new CodePrimitiveExpression (match
[matchEndPosition
]);
675 tmp
= new CodeBinaryOperatorExpression (lhs
, CodeBinaryOperatorType
.BooleanAnd
, rhs
);
678 tmp
= new CodeBinaryOperatorExpression ();
679 tmp
.Left
= new CodeArrayIndexerExpression (
681 new CodeBinaryOperatorExpression (
682 new CodeVariableReferenceExpression ("startPosition"),
683 CodeBinaryOperatorType
.Add
,
684 new CodePrimitiveExpression (matchStartPosition
- 1))
686 tmp
.Operator
= CodeBinaryOperatorType
.ValueEquality
;
687 tmp
.Right
= new CodePrimitiveExpression (match
[matchStartPosition
- 1]);
690 if (matchLength
- 1 >= 0) {
692 cur
.Operator
= CodeBinaryOperatorType
.BooleanAnd
;
696 cur
= new CodeBinaryOperatorExpression ();
700 matchStartPosition
++;
707 CodeExpression
GenerateScanfromExpression (CodeTypeDeclaration mainClass
)
709 CodeMemberMethod method
= GenerateScanMethod ();
711 int startPosition
= scanfrom
+ skip
;
712 string match
= matches
[0] as string;
713 int matchLength
= match
.Length
;
714 int minsize
= startPosition
+ matchLength
+ 1;
716 // if (ualength < minsize)
718 CodeBinaryOperatorExpression uaSizeCheck
= new CodeBinaryOperatorExpression ();
719 uaSizeCheck
.Left
= new CodeArgumentReferenceExpression ("ualength");
720 uaSizeCheck
.Operator
= CodeBinaryOperatorType
.LessThan
;
721 uaSizeCheck
.Right
= new CodePrimitiveExpression (minsize
);
722 method
.Statements
.Add (
723 new CodeConditionStatement (uaSizeCheck
,
724 new CodeMethodReturnStatement (new CodePrimitiveExpression (false))));
726 // int startPosition = 0;
727 method
.Statements
.Add (
728 new CodeVariableDeclarationStatement (typeof (int), "startPosition",
729 new CodePrimitiveExpression (0)));
731 // int endPosition = startPosition + matchLength;
732 method
.Statements
.Add (
733 new CodeVariableDeclarationStatement (
734 typeof (int), "endPosition",
735 new CodeBinaryOperatorExpression (
736 new CodeVariableReferenceExpression ("startPosition"),
737 CodeBinaryOperatorType
.Add
,
738 new CodePrimitiveExpression (matchLength
- 1))
742 // for (int ualeft = ualength; ualeft >= matchlen; ualeft--) {
743 // if (<condition>) {
744 // hasJavaScript = true;
750 CodeIterationStatement iter
= new CodeIterationStatement ();
751 iter
.InitStatement
= new CodeVariableDeclarationStatement (
752 typeof (int), "ualeft", new CodeArgumentReferenceExpression ("ualength"));
753 iter
.IncrementStatement
= new CodeAssignStatement (
754 new CodeVariableReferenceExpression ("ualeft"),
755 new CodeBinaryOperatorExpression (new CodeVariableReferenceExpression ("ualeft"),
756 CodeBinaryOperatorType
.Subtract
,
757 new CodePrimitiveExpression (1))
759 iter
.TestExpression
= new CodeBinaryOperatorExpression (
760 new CodeVariableReferenceExpression ("ualeft"),
761 CodeBinaryOperatorType
.GreaterThanOrEqual
,
762 new CodePrimitiveExpression (matchLength
)
765 CodeConditionStatement cond
= new CodeConditionStatement (
766 GenerateScanCondition (match
, matchLength
, startPosition
));
768 cond
.TrueStatements
.Add (
769 new CodeAssignStatement (new CodeArgumentReferenceExpression ("hasJavaScript"),
770 new CodePrimitiveExpression (true)));
771 cond
.TrueStatements
.Add (new CodeMethodReturnStatement (new CodePrimitiveExpression (true)));
772 iter
.Statements
.Add (cond
);
773 iter
.Statements
.Add (
774 new CodeAssignStatement (new CodeVariableReferenceExpression ("startPosition"),
775 new CodeBinaryOperatorExpression (
776 new CodeVariableReferenceExpression ("startPosition"),
777 CodeBinaryOperatorType
.Add
,
778 new CodePrimitiveExpression (1)))
780 iter
.Statements
.Add (
781 new CodeAssignStatement (new CodeVariableReferenceExpression ("endPosition"),
782 new CodeBinaryOperatorExpression (
783 new CodeVariableReferenceExpression ("endPosition"),
784 CodeBinaryOperatorType
.Add
,
785 new CodePrimitiveExpression (1)))
787 method
.Statements
.Add (iter
);
788 method
.Statements
.Add (new CodeMethodReturnStatement (new CodePrimitiveExpression (false)));
790 mainClass
.Members
.Add (method
);
792 return new CodeMethodInvokeExpression (
793 new CodeMethodReferenceExpression (new CodeTypeReferenceExpression ("UplevelHelper"), method
.Name
),
794 new CodeExpression
[] {new CodeArgumentReferenceExpression ("ua"),
795 new CodeDirectionExpression (
797 new CodeArgumentReferenceExpression ("hasJavaScript")),
798 new CodeArgumentReferenceExpression ("ualength")}
803 public class CompileUplevel
805 public static void Main (string[] args
)
808 CompileUplevel cu
= new CompileUplevel ();
810 } catch (Exception ex
) {
811 Console
.Error
.WriteLine ("Exception caught while generating UplevelHelper code:");
812 Console
.Error
.Write (ex
);
813 Console
.Error
.WriteLine ();
817 void Usage (string format
, params object[] parms
)
819 if (format
!= null && format
.Length
> 0) {
820 Console
.Error
.WriteLine (format
, parms
);
821 Environment
.Exit (1);
824 Console
.Error
.WriteLine (@"Usage: culevel [OPTIONS] INPUT_FILE
826 -o|--o|-output|--output file to write the generated code to.
827 If not specified, output goes to the console
828 -h|--h|-help|--help show this usage information.
830 Environment
.Exit (0);
833 void DumpGroup (GroupDefinition gd
, int indent
)
835 Console
.WriteLine ("{0}{1}", new String (' ', indent
), gd
.ToString ());
836 foreach (GroupDefinition gd2
in gd
.ChildGroups
)
837 DumpGroup (gd2
, indent
+ 1);
840 void Run (string[] args
)
843 Usage ("Invalid number of parameters");
845 Stack context
= new Stack ();
846 GroupDefinition groupZero
= new GroupDefinition ();
847 GroupDefinition
group, current
;
848 XmlReader reader
= null;
849 string outfile
= null, infile
= null;
852 for (int i
= 0; i
< args
.Length
; i
++) {
854 if (a
[0] == '-' && a
.Length
> 1) {
855 a
= a
.Substring (1).Trim ();
857 switch (a
.ToLower ()) {
863 Usage ("Missing output file name");
874 Usage ("Unknown command line option: '{0}'", a
);
877 } else if (infile
== null)
882 Usage ("Missing input file on the command line.");
885 XmlNodeType nodeType
;
887 bool ingroup
= false;
889 reader
= new XmlTextReader (infile
);
890 while (reader
.Read ()) {
891 nodeType
= reader
.NodeType
;
892 if (nodeType
!= XmlNodeType
.Element
&& nodeType
!= XmlNodeType
.EndElement
)
895 current
= context
.Count
> 0 ? context
.Peek () as GroupDefinition
: null;
896 if (ingroup
&& reader
.LocalName
== "except") {
898 throw new ApplicationException ("Inside a group but there is no group on the stack");
900 current
.AddExcept (reader
);
904 if (reader
.LocalName
!= "group")
907 if (reader
.NodeType
== XmlNodeType
.EndElement
) {
909 throw new ApplicationException ("Found group end, but no current group on stack");
911 if (context
.Count
== 0) {
912 groupZero
.ChildGroups
.Add (current
);
913 current
.GroupId
= groupZero
.ChildGroups
.Count
;
920 group = new GroupDefinition (reader
);
921 group.Level
= level
++;
923 if (current
!= null) {
924 current
.ChildGroups
.Add (group);
925 group.GroupId
= current
.ChildGroups
.Count
;
928 context
.Push (group);
931 } catch (Exception
) {
938 CodeCompileUnit unit
= groupZero
.GenerateCode ();
940 Environment
.Exit (1);
942 CodeDomProvider provider
= new CSharpCodeProvider ();
943 ICodeGenerator gen
= provider
.CreateGenerator ();
949 tw
= new IndentedTextWriter (new StreamWriter (outfile
, false), "\t");
950 gen
.GenerateCodeFromCompileUnit (unit
, tw
, new CodeGeneratorOptions ());