2 // System.Web.Compilation.AspGenerator
5 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 // (C) 2002,2003 Ximian, Inc (http://www.ximian.com)
10 using System.Collections;
15 namespace System.Web.Compilation
19 public ControlBuilder Builder;
20 public ILocation Location;
22 public BuilderLocation (ControlBuilder builder, ILocation location)
24 this.Builder = builder;
25 this.Location = location;
29 class BuilderLocationStack : Stack
31 public override void Push (object o)
33 if (!(o is BuilderLocation))
34 throw new InvalidOperationException ();
39 public virtual void Push (ControlBuilder builder, ILocation location)
41 BuilderLocation bl = new BuilderLocation (builder, location);
45 public new BuilderLocation Peek ()
47 return (BuilderLocation) base.Peek ();
50 public new BuilderLocation Pop ()
52 return (BuilderLocation) base.Pop ();
55 public ControlBuilder Builder {
56 get { return Peek ().Builder; }
64 BuilderLocationStack stack;
65 TemplateParser tparser;
67 RootBuilder rootBuilder;
70 static Hashtable emptyHash = new Hashtable ();
72 public AspGenerator (TemplateParser tparser)
74 this.tparser = tparser;
75 this.filename = Path.GetFullPath (tparser.InputFile);
76 tparser.AddDependency (tparser.InputFile);
77 text = new StringBuilder ();
78 stack = new BuilderLocationStack ();
79 rootBuilder = new RootBuilder (tparser);
80 stack.Push (rootBuilder, null);
81 tparser.RootBuilder = rootBuilder;
84 BaseCompiler GetCompilerFromType ()
86 Type type = tparser.GetType ();
87 if (type == typeof (PageParser))
88 return new PageCompiler ((PageParser) tparser);
90 if (type == typeof (ApplicationFileParser))
91 return new GlobalAsaxCompiler ((ApplicationFileParser) tparser);
93 if (type == typeof (UserControlParser))
94 return new UserControlCompiler ((UserControlParser) tparser);
96 throw new Exception ("Got type: " + type);
99 public Type GetCompiledType ()
101 //FIXME: use the encoding of the file or the one specified in the machine.config/web.config file.
102 StreamReader reader = new StreamReader (filename, Encoding.Default);
103 parser = new AspParser (filename, reader);
104 parser.Error += new ParseErrorHandler (ParseError);
105 parser.TagParsed += new TagParsedHandler (TagParsed);
106 parser.TextParsed += new TextParsedHandler (TextParsed);
113 PrintTree (rootBuilder, 0);
117 throw new ParseException (stack.Builder.location,
118 "Expecting </" + stack.Builder.TagName + ">" + stack.Builder);
120 BaseCompiler compiler = GetCompilerFromType ();
122 return compiler.GetCompiledType ();
126 static void PrintTree (ControlBuilder builder, int indent)
131 string i = new string ('\t', indent);
133 Console.WriteLine ("b: {0} id: {1} type: {2} parent: {3}",
134 builder, builder.ID, builder.ControlType, builder.parentBuilder);
136 if (builder.Children != null)
137 foreach (object o in builder.Children) {
138 if (o is ControlBuilder)
139 PrintTree ((ControlBuilder) o, indent++);
144 static void PrintLocation (ILocation loc)
146 Console.WriteLine ("\tFile name: " + loc.Filename);
147 Console.WriteLine ("\tBegin line: " + loc.BeginLine);
148 Console.WriteLine ("\tEnd line: " + loc.EndLine);
149 Console.WriteLine ("\tBegin column: " + loc.BeginColumn);
150 Console.WriteLine ("\tEnd column: " + loc.EndColumn);
151 Console.WriteLine ("\tPlainText: " + loc.PlainText);
152 Console.WriteLine ();
155 void ParseError (ILocation location, string message)
157 throw new ParseException (location, message);
160 void TagParsed (ILocation location, TagType tagtype, string tagid, TagAttributes attributes)
162 this.location = new Location (location);
164 tparser.Location = location;
166 if (text.Length != 0)
169 if (0 == String.Compare (tagid, "script", true)) {
170 if (ProcessScript (tagtype, attributes))
175 case TagType.Directive:
177 tagid = tparser.DefaultDirectiveName;
179 tparser.AddDirective (tagid, attributes.GetDictionary (null));
182 if (!ProcessTag (tagid, attributes))
183 TextParsed (location, location.PlainText);
186 if (!CloseControl (tagid))
187 TextParsed (location, location.PlainText);
189 case TagType.SelfClosing:
190 int count = stack.Count;
191 if (!ProcessTag (tagid, attributes)) {
192 TextParsed (location, location.PlainText);
193 } else if (stack.Count != count) {
194 CloseControl (tagid);
197 case TagType.DataBinding:
198 goto case TagType.CodeRender;
199 case TagType.CodeRenderExpression:
200 goto case TagType.CodeRender;
201 case TagType.CodeRender:
202 ProcessCode (tagtype, tagid, location);
204 case TagType.Include:
205 string file = attributes ["virtual"] as string;
206 bool isvirtual = (file != null);
208 file = attributes ["file"] as string;
210 TextParsed (location, tparser.ProcessInclude (isvirtual, file));
215 //PrintLocation (location);
218 void TextParsed (ILocation location, string text)
220 if (text.IndexOf ("<%") != -1) {
221 if (this.text.Length > 0)
223 CodeRenderParser r = new CodeRenderParser (text, stack.Builder);
228 this.text.Append (text);
229 //PrintLocation (location);
234 string t = text.ToString ();
237 // TODO: store location
238 tparser.Scripts.Add (t);
242 if (tparser.DefaultDirectiveName == "application" && t.Trim () != "")
243 throw new ParseException (location, "Content not valid for application file.");
245 stack.Builder.AppendLiteralString (t);
248 bool ProcessTag (string tagid, TagAttributes atts)
250 ControlBuilder parent = stack.Builder;
251 ControlBuilder builder = null;
252 BuilderLocation bl = null;
253 Hashtable htable = (atts != null) ? atts.GetDictionary (null) : emptyHash;
255 builder = parent.CreateSubBuilder (tagid, htable, null, tparser, location);
257 if (builder == null && atts != null && atts.IsRunAtServer ())
258 builder = rootBuilder.CreateSubBuilder (tagid, htable, null, tparser, location);
263 builder.location = location;
264 builder.ID = htable ["id"] as string;
265 if (builder.HasBody ()) {
266 if (builder is TemplateBuilder) {
269 stack.Push (builder, location);
271 // FIXME:ObjectTags...
272 parent.AppendSubBuilder (builder);
273 builder.CloseControl ();
279 bool ProcessScript (TagType tagtype, TagAttributes attributes)
281 if (tagtype != TagType.Close && attributes != null && attributes.IsRunAtServer ()) {
282 if (tagtype == TagType.Tag) {
283 parser.VerbatimID = "script";
285 } //else if (tagtype == TagType.SelfClosing)
286 // load script file here
291 bool result = inScript;
297 bool CloseControl (string tagid)
299 ControlBuilder current = stack.Builder;
300 string btag = current.TagName;
301 if (0 != String.Compare (tagid, btag, true))
304 // if (current is TemplateBuilder)
305 // pop from the id list
306 current.CloseControl ();
308 stack.Builder.AppendSubBuilder (current);
312 bool ProcessCode (TagType tagtype, string code, ILocation location)
314 ControlBuilder b = null;
315 if (tagtype == TagType.CodeRender)
316 b = new CodeRenderBuilder (code, false, location);
317 else if (tagtype == TagType.CodeRenderExpression)
318 b = new CodeRenderBuilder (code, true, location);
319 else if (tagtype == TagType.DataBinding)
320 b = new DataBindingBuilder (code, location);
322 throw new HttpException ("Should never happen");
324 stack.Builder.AppendSubBuilder (b);
328 public ILocation Location {
329 get { return location; }
332 // Used to get CodeRender tags in attribute values
333 class CodeRenderParser
336 ControlBuilder builder;
338 public CodeRenderParser (string str, ControlBuilder builder)
341 this.builder = builder;
344 public void AddChildren ()
346 int index = str.IndexOf ("<%");
348 TextParsed (null, str.Substring (0, index));
349 str = str.Substring (index);
352 AspParser parser = new AspParser ("@@inner_string@@", new StringReader (str));
353 parser.Error += new ParseErrorHandler (ParseError);
354 parser.TagParsed += new TagParsedHandler (TagParsed);
355 parser.TextParsed += new TextParsedHandler (TextParsed);
359 void TagParsed (ILocation location, TagType tagtype, string tagid, TagAttributes attributes)
361 if (tagtype == TagType.CodeRender)
362 builder.AppendSubBuilder (new CodeRenderBuilder (tagid, false, location));
363 else if (tagtype == TagType.CodeRenderExpression)
364 builder.AppendSubBuilder (new CodeRenderBuilder (tagid, true, location));
365 else if (tagtype == TagType.DataBinding)
366 builder.AppendSubBuilder (new DataBindingBuilder (tagid, location));
368 builder.AppendLiteralString (location.PlainText);
371 void TextParsed (ILocation location, string text)
373 builder.AppendLiteralString (text);
376 void ParseError (ILocation location, string message)
378 throw new ParseException (location, message);