2010-06-03 Jb Evain <jbevain@novell.com>
[mcs.git] / tools / culevel / CompileUplevel.cs
blob6eba5927897093b7c44b8ac1f93ff7a057e197e6
1 //
2 // Authors:
3 // Marek Habersack (mhabersack@novell.com)
4 //
5 // (C) 2007 Novell, Inc
6 //
8 //
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:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
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.
28 using System;
29 using System.CodeDom;
30 using System.CodeDom.Compiler;
31 using System.Collections;
32 using System.IO;
33 using System.Reflection;
34 using System.Text;
35 using System.Xml;
36 using Microsoft.CSharp;
38 namespace Mono.Tools
40 class Position
42 int start = -1;
43 int end = -1;
45 public int Start {
46 get { return start; }
49 public int End {
50 get { return end; }
53 public int RequiredUALength {
54 get {
55 if (end == -1)
56 return start;
57 return end;
61 public override string ToString ()
63 StringBuilder sb = new StringBuilder ("Position {");
64 sb.AppendFormat ("{0}", start);
65 if (end != -1)
66 sb.AppendFormat (",{0}}}", end);
67 else
68 sb.Append ("}");
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 ('-');
80 if (pa.Length > 2)
81 throw new ApplicationException ("Syntax error in the positions attribute - only one dash can be present");
83 try {
84 start = Int32.Parse (pa [0]);
85 } catch (Exception) {
86 throw new ApplicationException ("The 'positions' attribute has invalid syntax");
89 if (start < 0)
90 throw new ApplicationException ("Start must be 0 or more.");
92 if (pa.Length == 2) {
93 try {
94 end = Int32.Parse (pa [1]);
95 } catch (Exception) {
96 throw new ApplicationException ("The 'positions' attribute has invalid syntax");
99 if (end < start)
100 throw new ApplicationException ("End of range must not be smaller than its start");
102 if (end == start)
103 end = -1;
107 public CodeBinaryOperatorExpression GetExpression (string match)
109 int poslen;
111 if (end == -1)
112 poslen = 0;
113 else
114 poslen = end - start;
115 poslen++;
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 ();
123 if (poslen == 1) {
124 expr.Left = new CodeArrayIndexerExpression (new CodeVariableReferenceExpression ("ua"),
125 new CodePrimitiveExpression (Start));
126 expr.Operator = CodeBinaryOperatorType.ValueEquality;
127 expr.Right = new CodePrimitiveExpression (match [0]);
128 } else {
129 CodeBinaryOperatorExpression cur = expr, prev = expr, tmp;
130 int i, pos;
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) {
140 cur.Left = tmp;
141 cur.Operator = CodeBinaryOperatorType.BooleanAnd;
142 prev.Right = cur;
143 prev = cur;
144 cur = new CodeBinaryOperatorExpression ();
145 } else
146 prev.Right = tmp;
150 return expr;
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;
165 int scanfrom = -1;
166 int skip = -1;
167 int level = 0;
168 int groupId = 0;
170 public Position[] Positions {
171 get {
172 if (positions == null)
173 return null;
174 return (Position[]) positions.ToArray (typeof (Position));
178 public string[] Matches {
179 get {
180 if (matches == null)
181 return null;
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; }
198 public int Skip {
199 get { return skip; }
202 public bool Positional {
203 get { return positions != null; }
206 public bool GroupZero {
207 get { return positions == null && matches == null && scanfrom == -1 && skip == -1; }
210 public int Level {
211 get { return level; }
212 set { level = value; }
215 public int GroupId {
216 get { return groupId; }
217 set { groupId = value; }
220 public override string ToString ()
222 if (GroupZero)
223 return "GroupZero";
225 StringBuilder sb = new StringBuilder ("Group: ");
226 if (Positional) {
227 sb.Append ("positions =");
228 foreach (Position p in positions)
229 sb.AppendFormat (" [{0}]", p.ToString ());
230 } else {
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);
260 else
261 InitScanfrom (reader, scanfrom);
263 string javascript = reader.GetAttribute ("javascript");
264 if (javascript != null && javascript.Length > 0) {
265 try {
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");
276 InitMatches (match);
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)
297 matches.Add (m);
298 } else {
299 matches = new ArrayList (1);
300 matches.Add (match);
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)
317 this.skip = 0;
318 else {
319 try {
320 this.skip = Int32.Parse (skip);
321 } catch (Exception) {
322 throw new ApplicationException ("Invalid value of the 'skip' attribute. Must be an integer.");
326 try {
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 ()
335 if (!GroupZero)
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);
352 return unit;
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;
363 // if (ua == null)
364 // return false;
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 (
374 typeof (int),
375 "ualength",
376 new CodePropertyReferenceExpression (new CodeArgumentReferenceExpression ("ua"), "Length"))
379 // if (ualength == 0)
380 // return false;
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)));
392 return mainMethod;
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);
414 return groupMethod;
417 ArrayList GenerateExceptions (CodeTypeDeclaration mainClass, bool assignHasJavaScript)
419 if (exceptions == null || exceptions.Count == 0)
420 return null;
422 ArrayList matches = new ArrayList (exceptions.Count);
423 CodeConditionStatement match;
425 foreach (GroupDefinition gd in exceptions) {
426 match = gd.GenerateConditionStatement (mainClass);
427 matches.Add (match);
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);
435 else
436 match.TrueStatements.Add (returnTrue);
439 return matches;
442 CodeMemberMethod GenerateMethod (CodeTypeDeclaration mainClass)
444 CodeMemberMethod method;
446 if (GroupZero)
447 method = GetMainMethod ();
448 else
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");
470 int groupId = 0;
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);
494 } else {
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);
509 groupId++;
512 // return false;
513 method.Statements.Add (new CodeMethodReturnStatement (new CodePrimitiveExpression (false)));
514 } else
515 // return <valueOf_DefaultJS>
516 method.Statements.Add (new CodeMethodReturnStatement (new CodePrimitiveExpression (DefaultJS)));
518 return method;
521 CodeConditionStatement GenerateConditionStatement (CodeTypeDeclaration mainClass)
523 CodeConditionStatement ret = new CodeConditionStatement ();
525 if (Positional)
526 ret.Condition = GeneratePositionalExpression ();
527 else
528 ret.Condition = GenerateScanfromExpression (mainClass);
530 return ret;
533 CodeExpression GeneratePositionalExpression ()
535 Position[] positions = Positions;
536 string[] matches = Matches;
537 ArrayList components = new ArrayList ();
539 int i, reqLength = 0;
540 Position p;
542 for (i = 0; i < positions.Length; i++) {
543 p = positions [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;
552 i = 0;
554 if (complen == 1)
555 expr = components [0] as CodeBinaryOperatorExpression;
556 else {
557 expr = new CodeBinaryOperatorExpression ();
558 CodeBinaryOperatorExpression cur = expr, prev = expr;
559 foreach (CodeBinaryOperatorExpression op in components) {
560 if (i + 1 < complen) {
561 cur.Left = op;
562 cur.Operator = CodeBinaryOperatorType.BooleanAnd;
563 prev.Right = cur;
564 prev = cur;
565 cur = new CodeBinaryOperatorExpression ();
566 } else {
567 prev.Right = op;
569 i++;
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;
583 ret.Right = expr;
585 return ret;
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);
608 return method;
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]);
624 return ret;
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]);
640 ret.Left = lhs;
641 ret.Operator = CodeBinaryOperatorType.BooleanAnd;
642 ret.Right = rhs;
644 return ret;
647 bool matchOdd = matchLength % 2 != 0;
649 while (matchLength >= 0) {
650 matchLength--;
651 if (!matchOdd || (matchOdd && (matchLength - 1) > 0)) {
652 lhs = new CodeBinaryOperatorExpression ();
653 lhs.Left = new CodeArrayIndexerExpression (
654 uaRef,
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 (
665 uaRef,
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);
676 matchLength--;
677 } else {
678 tmp = new CodeBinaryOperatorExpression ();
679 tmp.Left = new CodeArrayIndexerExpression (
680 uaRef,
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) {
691 cur.Left = tmp;
692 cur.Operator = CodeBinaryOperatorType.BooleanAnd;
693 if (prev != null)
694 prev.Right = cur;
695 prev = cur;
696 cur = new CodeBinaryOperatorExpression ();
697 } else
698 prev.Right = tmp;
700 matchStartPosition++;
701 matchEndPosition--;
704 return ret;
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)
717 // return false;
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;
745 // return true;
746 // }
747 // startPosition++;
748 // endPosition++;
749 // }
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 (
796 FieldDirection.Out,
797 new CodeArgumentReferenceExpression ("hasJavaScript")),
798 new CodeArgumentReferenceExpression ("ualength")}
803 public class CompileUplevel
805 public static void Main (string[] args)
807 try {
808 CompileUplevel cu = new CompileUplevel ();
809 cu.Run (args);
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
825 Options:
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)
842 if (args.Length < 1)
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;
850 string a;
852 for (int i = 0; i < args.Length; i++) {
853 a = args [i];
854 if (a [0] == '-' && a.Length > 1) {
855 a = a.Substring (1).Trim ();
857 switch (a.ToLower ()) {
858 case "o":
859 case "output":
860 case "-output":
861 i++;
862 if (i > args.Length)
863 Usage ("Missing output file name");
864 outfile = args [i];
865 break;
867 case "h":
868 case "help":
869 case "-help":
870 Usage (null);
871 break;
873 default:
874 Usage ("Unknown command line option: '{0}'", a);
875 break;
877 } else if (infile == null)
878 infile = args [i];
881 if (infile == null)
882 Usage ("Missing input file on the command line.");
884 try {
885 XmlNodeType nodeType;
886 int level = 1;
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)
893 continue;
895 current = context.Count > 0 ? context.Peek () as GroupDefinition : null;
896 if (ingroup && reader.LocalName == "except") {
897 if (current == null)
898 throw new ApplicationException ("Inside a group but there is no group on the stack");
900 current.AddExcept (reader);
901 continue;
904 if (reader.LocalName != "group")
905 continue;
907 if (reader.NodeType == XmlNodeType.EndElement) {
908 if (current == null)
909 throw new ApplicationException ("Found group end, but no current group on stack");
910 context.Pop ();
911 if (context.Count == 0) {
912 groupZero.ChildGroups.Add (current);
913 current.GroupId = groupZero.ChildGroups.Count;
915 level--;
916 ingroup = false;
917 continue;
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);
929 ingroup = true;
931 } catch (Exception) {
932 throw;
933 } finally {
934 if (reader != null)
935 reader.Close();
938 CodeCompileUnit unit = groupZero.GenerateCode ();
939 if (unit == null)
940 Environment.Exit (1);
942 CodeDomProvider provider = new CSharpCodeProvider ();
943 ICodeGenerator gen = provider.CreateGenerator ();
945 TextWriter tw;
946 if (outfile == null)
947 tw = Console.Out;
948 else
949 tw = new IndentedTextWriter (new StreamWriter (outfile, false), "\t");
950 gen.GenerateCodeFromCompileUnit (unit, tw, new CodeGeneratorOptions ());
951 if (outfile != null)
952 tw.Close ();