~ubuntu-branches/ubuntu/feisty/monodevelop/feisty

« back to all changes in this revision

Viewing changes to Extras/AspNetEdit/AspNetEdit.Editor.Persistence/AspParser.cs

  • Committer: Bazaar Package Importer
  • Author(s): Sebastian Dröge
  • Date: 2006-08-18 00:51:23 UTC
  • mfrom: (1.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20060818005123-5iit07y0j7wjg55f
Tags: 0.11+svn20060818-0ubuntu1
* New SVN snapshot
  + Works with Gtk# 2.9.0
* debian/control:
  + Updated Build-Depends
* debian/patches/use_nunit2.2.dpatch,
  debian/patches/use_real_libs.dpatch:
  + Updated
* debian/patches/versioncontrol_buildfix.dpatch:
  + Fix build failure in the version control addin

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//
 
2
// System.Web.Compilation.AspParser
 
3
//
 
4
// Authors:
 
5
//      Gonzalo Paniagua Javier (gonzalo@ximian.com)
 
6
//
 
7
// (C) 2002,2003 Ximian, Inc (http://www.ximian.com)
 
8
//
 
9
 
 
10
//
 
11
// Permission is hereby granted, free of charge, to any person obtaining
 
12
// a copy of this software and associated documentation files (the
 
13
// "Software"), to deal in the Software without restriction, including
 
14
// without limitation the rights to use, copy, modify, merge, publish,
 
15
// distribute, sublicense, and/or sell copies of the Software, and to
 
16
// permit persons to whom the Software is furnished to do so, subject to
 
17
// the following conditions:
 
18
// 
 
19
// The above copyright notice and this permission notice shall be
 
20
// included in all copies or substantial portions of the Software.
 
21
// 
 
22
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 
23
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
24
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 
25
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 
26
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 
27
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 
28
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
29
//
 
30
using System;
 
31
using System.Collections;
 
32
using System.Globalization;
 
33
using System.IO;
 
34
using System.Text;
 
35
using System.Web.Util;
 
36
 
 
37
namespace AspNetEdit.Editor.Persistence
 
38
{
 
39
        delegate void ParseErrorHandler (ILocation location, string message);
 
40
        delegate void TextParsedHandler (ILocation location, string text);
 
41
        delegate void TagParsedHandler (ILocation location, TagType tagtype, string id, TagAttributes attributes);
 
42
 
 
43
        class AspParser : ILocation
 
44
        {
 
45
                AspTokenizer tokenizer;
 
46
                int beginLine, endLine;
 
47
                int beginColumn, endColumn;
 
48
                int beginPosition, endPosition;
 
49
                string filename;
 
50
                string fileText;
 
51
                string verbatimID;
 
52
 
 
53
                public AspParser (string filename, TextReader input)
 
54
                {
 
55
                        this.filename = filename;
 
56
                        fileText = input.ReadToEnd ();
 
57
                        StringReader reader = new StringReader (fileText);
 
58
                        tokenizer = new AspTokenizer (reader);
 
59
                }
 
60
 
 
61
                public int BeginLine {
 
62
                        get { return beginLine; }
 
63
                }
 
64
 
 
65
                public int BeginColumn {
 
66
                        get { return beginColumn; }
 
67
                }
 
68
 
 
69
                public int EndLine {
 
70
                        get { return endLine; }
 
71
                }
 
72
 
 
73
                public int EndColumn {
 
74
                        get { return endColumn; }
 
75
                }
 
76
 
 
77
                public string PlainText {
 
78
                        get {
 
79
                                if (beginPosition >= endPosition)
 
80
                                        return null;
 
81
 
 
82
                                return fileText.Substring (beginPosition, endPosition - beginPosition);
 
83
                        }
 
84
                }
 
85
 
 
86
                public string Filename {
 
87
                        get { return filename; }
 
88
                }
 
89
 
 
90
                public string VerbatimID {
 
91
                        set {
 
92
                                tokenizer.Verbatim = true;
 
93
                                verbatimID = value.ToUpper (CultureInfo.InvariantCulture);
 
94
                        }
 
95
                }
 
96
                
 
97
                bool Eat (int expected_token)
 
98
                {
 
99
                        if (tokenizer.get_token () != expected_token) {
 
100
                                tokenizer.put_back ();
 
101
                                return false;
 
102
                        }
 
103
 
 
104
                        endLine = tokenizer.EndLine;
 
105
                        endColumn = tokenizer.EndColumn;
 
106
                        return true;
 
107
                }
 
108
 
 
109
                void BeginElement ()
 
110
                {
 
111
                        beginLine = tokenizer.BeginLine;
 
112
                        beginColumn = tokenizer.BeginColumn;
 
113
                        beginPosition = tokenizer.Position - 1;
 
114
                }
 
115
 
 
116
                void EndElement ()
 
117
                {
 
118
                        endLine = tokenizer.EndLine;
 
119
                        endColumn = tokenizer.EndColumn;
 
120
                        endPosition = tokenizer.Position;
 
121
                }
 
122
 
 
123
                public void Parse ()
 
124
                {
 
125
                        int token;
 
126
                        string id;
 
127
                        TagAttributes attributes;
 
128
                        TagType tagtype = TagType.Text;
 
129
                        StringBuilder text =  new StringBuilder ();
 
130
 
 
131
                        while ((token = tokenizer.get_token ()) != Token.EOF) {
 
132
                                BeginElement ();
 
133
 
 
134
                                if (tokenizer.Verbatim){
 
135
                                        string end_verbatim = "</" + verbatimID + ">";
 
136
                                        string verbatim_text = GetVerbatim (token, end_verbatim);
 
137
 
 
138
                                        if (verbatim_text == null)
 
139
                                                OnError ("Unexpected EOF processing " + verbatimID);
 
140
 
 
141
                                        tokenizer.Verbatim = false;
 
142
 
 
143
                                        EndElement ();
 
144
                                        endPosition -= end_verbatim.Length;
 
145
                                        OnTextParsed (verbatim_text);
 
146
                                        beginPosition = endPosition;
 
147
                                        endPosition += end_verbatim.Length;
 
148
                                        OnTagParsed (TagType.Close, verbatimID, null);
 
149
                                        continue;
 
150
                                }
 
151
                                
 
152
                                if (token == '<') {
 
153
                                        GetTag (out tagtype, out id, out attributes);
 
154
                                        EndElement ();
 
155
                                        if (tagtype == TagType.ServerComment)
 
156
                                                continue;
 
157
 
 
158
                                        if (tagtype == TagType.Text)
 
159
                                                OnTextParsed (id);
 
160
                                        else
 
161
                                                OnTagParsed (tagtype, id, attributes);
 
162
 
 
163
                                        continue;
 
164
                                }
 
165
 
 
166
                                if (tokenizer.Value.Trim () == "" && tagtype == TagType.Directive) {
 
167
                                        continue;
 
168
                                }
 
169
 
 
170
                                text.Length = 0;
 
171
                                do {
 
172
                                        text.Append (tokenizer.Value);
 
173
                                        token = tokenizer.get_token ();
 
174
                                } while (token != '<' && token != Token.EOF);
 
175
 
 
176
                                tokenizer.put_back ();
 
177
                                EndElement ();
 
178
                                OnTextParsed (text.ToString ());
 
179
                        }
 
180
                }
 
181
 
 
182
                bool GetInclude (string str, out string pathType, out string filename)
 
183
                {
 
184
                        pathType = null;
 
185
                        filename = null;
 
186
                        str = str.Substring (2).Trim ();
 
187
                        int len = str.Length;
 
188
                        int lastQuote = str.LastIndexOf ('"');
 
189
                        if (len < 10 || lastQuote != len - 1)
 
190
                                return false;
 
191
 
 
192
                        if (!StrUtils.StartsWith (str, "#include ", true))
 
193
                                return false;
 
194
 
 
195
                        str = str.Substring (9).Trim ();
 
196
                        bool isfile = (StrUtils.StartsWith (str ,"file", true));
 
197
                        if (!isfile && !StrUtils.StartsWith (str, "virtual", true))
 
198
                                return false;
 
199
 
 
200
                        pathType = (isfile) ? "file" : "virtual";
 
201
                        if (str.Length < pathType.Length + 3)
 
202
                                return false;
 
203
 
 
204
                        str = str.Substring (pathType.Length).Trim ();
 
205
                        if (str.Length < 3 || str [0] != '=')
 
206
                                return false;
 
207
 
 
208
                        int index = 1;
 
209
                        for (; index < str.Length; index++) {
 
210
                                if (Char.IsWhiteSpace (str [index]))
 
211
                                        index++;
 
212
                                else if (str [index] == '"')
 
213
                                        break;
 
214
                        }
 
215
 
 
216
                        if (index == str.Length || index == lastQuote)
 
217
                                return false;
 
218
 
 
219
                        str = str.Substring (index);
 
220
                        if (str.Length == 2) { // only quotes
 
221
                                OnError ("Empty file name.");
 
222
                                return false;
 
223
                        }
 
224
 
 
225
                        filename = str.Trim ().Substring (index, str.Length - 2);
 
226
                        if (filename.LastIndexOf  ('"') != -1)
 
227
                                return false; // file=""" -> no error
 
228
 
 
229
                        return true;
 
230
                }
 
231
 
 
232
                void GetTag (out TagType tagtype, out string id, out TagAttributes attributes)
 
233
                {
 
234
                        int token = tokenizer.get_token ();
 
235
 
 
236
                        tagtype = TagType.ServerComment;
 
237
                        id = null;
 
238
                        attributes = null;
 
239
                        switch (token){
 
240
                        case '%':
 
241
                                GetServerTag (out tagtype, out id, out attributes);
 
242
                                break;
 
243
                        case '/':
 
244
                                if (!Eat (Token.IDENTIFIER))
 
245
                                        OnError ("expecting TAGNAME");
 
246
 
 
247
                                id = tokenizer.Value;
 
248
                                if (!Eat ('>'))
 
249
                                        OnError ("expecting '>'. Got '" + id + "'");
 
250
 
 
251
                                tagtype = TagType.Close;
 
252
                                break;
 
253
                        case '!':
 
254
                                bool double_dash = Eat (Token.DOUBLEDASH);
 
255
                                if (double_dash)
 
256
                                        tokenizer.put_back ();
 
257
 
 
258
                                tokenizer.Verbatim = true;
 
259
                                string end = double_dash ? "-->" : ">";
 
260
                                string comment = GetVerbatim (tokenizer.get_token (), end);
 
261
                                tokenizer.Verbatim = false;
 
262
                                if (comment == null)
 
263
                                        OnError ("Unfinished HTML comment/DTD");
 
264
 
 
265
                                string pathType, filename;
 
266
                                if (double_dash && GetInclude (comment, out pathType, out filename)) {
 
267
                                        tagtype = TagType.Include;
 
268
                                        attributes = new TagAttributes ();
 
269
                                        attributes.Add (pathType, filename);
 
270
                                } else {
 
271
                                        tagtype = TagType.Text;
 
272
                                        id = "<!" + comment + end;
 
273
                                }
 
274
                                break;
 
275
                        case Token.IDENTIFIER:
 
276
                                if (this.filename == "@@inner_string@@") {
 
277
                                        // Actually not tag but "xxx < yyy" stuff in inner_string!
 
278
                                        tagtype = TagType.Text;
 
279
                                        tokenizer.InTag = false;
 
280
                                        id = "<" + tokenizer.Odds + tokenizer.Value;
 
281
                                } else {
 
282
                                        id = tokenizer.Value;
 
283
                                        try {
 
284
                                                attributes = GetAttributes ();
 
285
                                        } catch (Exception e) {
 
286
                                                OnError (e.Message);
 
287
                                                break;
 
288
                                        }
 
289
                                        
 
290
                                        tagtype = TagType.Tag;
 
291
                                        if (Eat ('/') && Eat ('>')) {
 
292
                                                tagtype = TagType.SelfClosing;
 
293
                                        } else if (!Eat ('>')) {
 
294
                                                if (attributes.IsRunAtServer ()) {
 
295
                                                        OnError ("The server tag is not well formed.");
 
296
                                                        break;
 
297
                                                }
 
298
                                                tokenizer.Verbatim = true;
 
299
                                                attributes.Add ("", GetVerbatim (tokenizer.get_token (), ">") + ">");
 
300
                                                tokenizer.Verbatim = false;
 
301
                                        }
 
302
                                }
 
303
 
 
304
                                break;
 
305
                        default:
 
306
                                tagtype = TagType.Text;
 
307
                                tokenizer.InTag = false;
 
308
                                id = "<" + tokenizer.Value;
 
309
                                break;
 
310
                        }
 
311
                }
 
312
 
 
313
                TagAttributes GetAttributes ()
 
314
                {
 
315
                        int token;
 
316
                        TagAttributes attributes;
 
317
                        string id;
 
318
 
 
319
                        attributes = new TagAttributes ();
 
320
                        while ((token = tokenizer.get_token ()) != Token.EOF){
 
321
                                if (token == '<' && Eat ('%')) {
 
322
                                        tokenizer.Verbatim = true;
 
323
                                        attributes.Add ("", "<%" + 
 
324
                                                        GetVerbatim (tokenizer.get_token (), "%>") + "%>");
 
325
                                        tokenizer.Verbatim = false;
 
326
                                        tokenizer.InTag = true;
 
327
                                        continue;
 
328
                                }
 
329
                                        
 
330
                                if (token != Token.IDENTIFIER)
 
331
                                        break;
 
332
 
 
333
                                id = tokenizer.Value;
 
334
                                if (Eat ('=')){
 
335
                                        if (Eat (Token.ATTVALUE)){
 
336
                                                attributes.Add (id, tokenizer.Value);
 
337
                                        } else if (Eat ('<') && Eat ('%')) {
 
338
                                                tokenizer.Verbatim = true;
 
339
                                                attributes.Add (id, "<%" + 
 
340
                                                                GetVerbatim (tokenizer.get_token (), "%>") + "%>");
 
341
                                                tokenizer.Verbatim = false;
 
342
                                                tokenizer.InTag = true;
 
343
                                        } else {
 
344
                                                OnError ("expected ATTVALUE");
 
345
                                                return null;
 
346
                                        }
 
347
                                } else {
 
348
                                        attributes.Add (id, null);
 
349
                                }
 
350
                        }
 
351
 
 
352
                        tokenizer.put_back ();
 
353
                        return attributes;
 
354
                }
 
355
 
 
356
                string GetVerbatim (int token, string end)
 
357
                {
 
358
                        StringBuilder vb_text = new StringBuilder ();
 
359
                        int i = 0;
 
360
 
 
361
                        if (tokenizer.Value.Length > 1){
 
362
                                // May be we have a put_back token that is not a single character
 
363
                                vb_text.Append (tokenizer.Value);
 
364
                                token = tokenizer.get_token ();
 
365
                        }
 
366
 
 
367
                        while (token != Token.EOF){
 
368
                                if (Char.ToUpper ((char) token, CultureInfo.InvariantCulture) == end [i]){
 
369
                                        if (++i >= end.Length)
 
370
                                                break;
 
371
                                        token = tokenizer.get_token ();
 
372
                                        continue;
 
373
                                } else if (i > 0) {
 
374
                                        for (int j = 0; j < i; j++)
 
375
                                                vb_text.Append (end [j]);
 
376
                                        i = 0;
 
377
                                }
 
378
 
 
379
                                vb_text.Append ((char) token);
 
380
                                token = tokenizer.get_token ();
 
381
                        } 
 
382
 
 
383
                        return RemoveComments (vb_text.ToString ());
 
384
                }
 
385
 
 
386
                string RemoveComments (string text)
 
387
                {
 
388
                        int end;
 
389
                        int start = text.IndexOf ("<%--");
 
390
 
 
391
                        while (start != -1) {
 
392
                                end = text.IndexOf ("--%>");
 
393
                                if (end == -1 || end <= start + 1)
 
394
                                        break;
 
395
 
 
396
                                text = text.Remove (start, end - start + 4);
 
397
                                start = text.IndexOf ("<%--");
 
398
                        }
 
399
 
 
400
                        return text;
 
401
                }
 
402
 
 
403
                void GetServerTag (out TagType tagtype, out string id, out TagAttributes attributes)
 
404
                {
 
405
                        string inside_tags;
 
406
                        bool old = tokenizer.ExpectAttrValue;
 
407
 
 
408
                        tokenizer.ExpectAttrValue = false;
 
409
                        if (Eat ('@')){
 
410
                                tokenizer.ExpectAttrValue = old;
 
411
                                tagtype = TagType.Directive;
 
412
                                id = "";
 
413
                                if (Eat (Token.DIRECTIVE))
 
414
                                        id = tokenizer.Value;
 
415
 
 
416
                                attributes = GetAttributes ();
 
417
                                if (!Eat ('%') || !Eat ('>'))
 
418
                                        OnError ("expecting '%>'");
 
419
 
 
420
                                return;
 
421
                        }
 
422
                        
 
423
                        if (Eat (Token.DOUBLEDASH)) {
 
424
                                tokenizer.ExpectAttrValue = old;
 
425
                                tokenizer.Verbatim = true;
 
426
                                inside_tags = GetVerbatim (tokenizer.get_token (), "--%>");
 
427
                                tokenizer.Verbatim = false;
 
428
                                id = null;
 
429
                                attributes = null;
 
430
                                tagtype = TagType.ServerComment;
 
431
                                return;
 
432
                        }
 
433
 
 
434
                        tokenizer.ExpectAttrValue = old;
 
435
                        bool varname;
 
436
                        bool databinding;
 
437
                        varname = Eat ('=');
 
438
                        databinding = !varname && Eat ('#');
 
439
 
 
440
                        tokenizer.Verbatim = true;
 
441
                        inside_tags = GetVerbatim (tokenizer.get_token (), "%>");
 
442
                        tokenizer.Verbatim = false;
 
443
                        id = inside_tags;
 
444
                        attributes = null;
 
445
                        tagtype = (databinding ? TagType.DataBinding :
 
446
                                  (varname ? TagType.CodeRenderExpression : TagType.CodeRender));
 
447
                }
 
448
 
 
449
                public event ParseErrorHandler Error;
 
450
                public event TagParsedHandler TagParsed;
 
451
                public event TextParsedHandler TextParsed;
 
452
 
 
453
                void OnError (string msg)
 
454
                {
 
455
                        if (Error != null)
 
456
                                Error (this, msg);
 
457
                }
 
458
 
 
459
                void OnTagParsed (TagType tagtype, string id, TagAttributes attributes)
 
460
                {
 
461
                        if (TagParsed != null)
 
462
                                TagParsed (this, tagtype, id, attributes);
 
463
                }
 
464
 
 
465
                void OnTextParsed (string text)
 
466
                {
 
467
                        if (TextParsed != null)
 
468
                                TextParsed (this, text);
 
469
                }
 
470
        }
 
471
 
 
472
}
 
473