~ubuntu-branches/ubuntu/oneiric/monodevelop/oneiric-updates

« back to all changes in this revision

Viewing changes to src/addins/MonoDevelop.XmlEditor/MonoDevelop.Xml.StateEngine/Parser.cs

  • Committer: Bazaar Package Importer
  • Author(s): Jo Shields
  • Date: 2009-02-18 08:40:51 UTC
  • mfrom: (1.2.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20090218084051-gh8m6ukvokbwj7cf
Tags: 1.9.2+dfsg-1ubuntu1
* Merge from Debian Experimental (LP: #330519), remaining Ubuntu changes:
  + debian/control:
    - Update for Gnome# 2.24
    - Add libmono-cairo1.0-cil to build-deps to fool pkg-config check

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// 
 
2
// Parser.cs
 
3
// 
 
4
// Author:
 
5
//   Michael Hutchinson <mhutchinson@novell.com>
 
6
// 
 
7
// Copyright (C) 2008 Novell, Inc (http://www.novell.com)
 
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.
 
27
//
 
28
 
 
29
using System;
 
30
using System.Collections.Generic;
 
31
using System.Text;
 
32
 
 
33
using MonoDevelop.Projects.Dom;
 
34
using MonoDevelop.Ide.Gui.Content;
 
35
 
 
36
namespace MonoDevelop.Xml.StateEngine
 
37
{
 
38
        public class Parser : IDocumentStateEngine, IParseContext
 
39
        {
 
40
                RootState rootState;
 
41
                State currentState;
 
42
                State previousState;
 
43
                bool buildTree;
 
44
                
 
45
                int position;
 
46
                DomLocation location;
 
47
                int stateTag;
 
48
                StringBuilder keywordBuilder;
 
49
                int currentStateLength;
 
50
                NodeStack nodes;
 
51
                List<Error> errors;
 
52
                
 
53
                public Parser (RootState rootState, bool buildTree)
 
54
                {
 
55
                        this.rootState = rootState;
 
56
                        this.currentState = rootState;
 
57
                        this.previousState = rootState;
 
58
                        this.buildTree = buildTree;
 
59
                        Reset ();
 
60
                }
 
61
                
 
62
                Parser (Parser copyFrom)
 
63
                {
 
64
                        buildTree = false;
 
65
                        
 
66
                        rootState = copyFrom.rootState;
 
67
                        currentState = copyFrom.currentState;
 
68
                        previousState = copyFrom.previousState;
 
69
                        
 
70
                        position = copyFrom.position;
 
71
                        location = copyFrom.location;
 
72
                        stateTag = copyFrom.stateTag;
 
73
                        keywordBuilder = new StringBuilder (copyFrom.keywordBuilder.ToString ());
 
74
                        currentStateLength = copyFrom.currentStateLength;
 
75
                        
 
76
                        //clone the node stack
 
77
                        List<XObject> l = new List<XObject> (CopyXObjects (copyFrom.nodes));
 
78
                        l.Reverse ();
 
79
                        nodes = new NodeStack (l);
 
80
                }
 
81
                
 
82
                IEnumerable<XObject> CopyXObjects (IEnumerable<XObject> src)
 
83
                {
 
84
                        foreach (XObject o in src)
 
85
                                yield return o.ShallowCopy ();
 
86
                }
 
87
                
 
88
                public RootState RootState { get { return rootState; } }
 
89
                
 
90
                #region IDocumentStateEngine
 
91
                
 
92
                public int Position { get { return position; } }
 
93
                public DomLocation Location { get { return location; } }
 
94
                
 
95
                public void Reset ()
 
96
                {
 
97
                        currentState = rootState;
 
98
                        previousState = rootState;
 
99
                        position = 0;
 
100
                        stateTag = 0;
 
101
                        location.Line = 1;
 
102
                        location.Column = 1;
 
103
                        keywordBuilder = new StringBuilder ();
 
104
                        currentStateLength = 0;
 
105
                        nodes = new NodeStack ();
 
106
                        nodes.Push (rootState.CreateDocument ());
 
107
                        
 
108
                        if (buildTree)
 
109
                                errors = new List<Error> ();
 
110
                        else
 
111
                                errors = null;
 
112
                }
 
113
                
 
114
                public void Parse (System.IO.TextReader reader)
 
115
                {
 
116
                        int i = reader.Read ();
 
117
                        while (i >= 0) {
 
118
                                char c = (char) i;
 
119
                                Push (c);
 
120
                                i = reader.Read ();
 
121
                        }
 
122
                }
 
123
 
 
124
                public void Push (char c)
 
125
                {
 
126
                        try {
 
127
                                //track line, column
 
128
                                if (c == '\n') {
 
129
                                        location.Line++;
 
130
                                        location.Column = 1;
 
131
                                } else {
 
132
                                        location.Column++;
 
133
                                }
 
134
                                
 
135
                                position++;
 
136
                                for (int loopLimit = 0; loopLimit < 10; loopLimit++) {
 
137
                                        currentStateLength++;
 
138
                                        string rollback = null;
 
139
                                        State nextState = currentState.PushChar (c, this, ref rollback);
 
140
                                        
 
141
                                        // no state change
 
142
                                        if (nextState == currentState || nextState == null)
 
143
                                                return;
 
144
                                        
 
145
                                        // state changed; reset stuff
 
146
                                        previousState = currentState;
 
147
                                        currentState = nextState;
 
148
                                        stateTag = 0;
 
149
                                        currentStateLength = 0;
 
150
                                        if (keywordBuilder.Length < 50)
 
151
                                                keywordBuilder.Length = 0;
 
152
                                        else
 
153
                                                keywordBuilder = new StringBuilder ();
 
154
                                        
 
155
                                        
 
156
                                        // only loop if the same char should be run through the new state
 
157
                                        if (rollback == null)
 
158
                                                return;
 
159
                                        
 
160
                                        //"complex" rollbacks require actually skipping backwards.
 
161
                                        //Note the previous state is invalid for this operation.
 
162
                                        else if (rollback.Length > 0) {
 
163
                                                position -= (rollback.Length + 1);
 
164
                                                foreach (char rollChar in rollback)
 
165
                                                        Push (rollChar);
 
166
                                                position++;
 
167
                                        }
 
168
                                }
 
169
                                throw new InvalidOperationException ("Too many state changes for char '" + c + "'. Current state is " + currentState.ToString () + ".");
 
170
                        } catch (Exception ex)  {
 
171
                                //attach parser state to exceptions
 
172
                                throw new Exception (ToString (), ex);
 
173
                        }
 
174
                }
 
175
                
 
176
                object ICloneable.Clone ()
 
177
                {
 
178
                        if (buildTree)
 
179
                                throw new InvalidOperationException ("Parser can only be cloned when in stack mode");
 
180
                        return new Parser (this);
 
181
                }
 
182
                
 
183
                #endregion
 
184
                
 
185
                public Parser GetTreeParser ()
 
186
                {
 
187
                        if (buildTree)
 
188
                                throw new InvalidOperationException ("Parser can only be cloned when in stack mode");
 
189
                        Parser p = new Parser (this);
 
190
                        
 
191
                        p.buildTree = true;
 
192
                        
 
193
                        //reconnect the node tree
 
194
                        ((IParseContext)p).ConnectAll ();
 
195
                        
 
196
                        p.errors = new List<Error> ();
 
197
                        
 
198
                        return p;
 
199
                }
 
200
                
 
201
                public override string ToString ()
 
202
                {
 
203
                        StringBuilder builder = new StringBuilder ();
 
204
                        builder.AppendFormat ("[Parser Location={0} CurrentStateLength={1}", position, currentStateLength);
 
205
                        builder.AppendLine ();
 
206
                        
 
207
                        builder.Append (' ', 2);
 
208
                        builder.AppendLine ("Stack=");
 
209
                        
 
210
                        XObject rootOb = null;
 
211
                        foreach (XObject ob in nodes) {
 
212
                                rootOb = ob;
 
213
                                builder.Append (' ', 4);
 
214
                                builder.Append (ob.ToString ());
 
215
                                builder.AppendLine ();
 
216
                        }
 
217
                        
 
218
                        builder.Append (' ', 2);
 
219
                        builder.AppendLine ("States=");
 
220
                        State s = currentState;
 
221
                        while (s != null) {
 
222
                                builder.Append (' ', 4);
 
223
                                builder.Append (s.ToString ());
 
224
                                builder.AppendLine ();
 
225
                                s = s.Parent;
 
226
                        }
 
227
                        
 
228
                        if (buildTree && rootOb != null) {
 
229
                                builder.Append (' ', 2);
 
230
                                builder.AppendLine ("Tree=");
 
231
                                rootOb.BuildTreeString (builder, 3);
 
232
                        }
 
233
                        
 
234
                        if (buildTree && errors.Count > 0) {
 
235
                                builder.Append (' ', 2);
 
236
                                builder.AppendLine ("Errors=");
 
237
                                foreach (Error err in errors) {
 
238
                                        builder.Append (' ', 4);
 
239
                                        builder.AppendFormat ("[{0}@{1}:{2}, {3}]\n", err.ErrorType, err.Region.Start.Line,
 
240
                                                              err.Region.Start.Column, err.Message);
 
241
                                }
 
242
                        }
 
243
                        
 
244
                        builder.AppendLine ("]");
 
245
                        return builder.ToString ();
 
246
                }
 
247
                
 
248
                #region IParseContext
 
249
                                
 
250
                int IParseContext.StateTag {
 
251
                        get { return stateTag; }
 
252
                        set { stateTag = value; }
 
253
                }
 
254
                
 
255
                DomLocation IParseContext.LocationMinus (int colOffset)
 
256
                {
 
257
                        int col = Location.Column - colOffset;
 
258
                        System.Diagnostics.Debug.Assert (col > 0);
 
259
                        return new DomLocation (Location.Line, col);
 
260
                }
 
261
                
 
262
                StringBuilder IParseContext.KeywordBuilder {
 
263
                        get { return keywordBuilder; }
 
264
                }
 
265
                
 
266
                State IParseContext.PreviousState {
 
267
                        get { return previousState; }
 
268
                }
 
269
                
 
270
                public int CurrentStateLength { get { return currentStateLength; } }
 
271
                public NodeStack Nodes { get { return nodes; } }
 
272
                
 
273
                public bool BuildTree { get { return buildTree; } }
 
274
                
 
275
                void IParseContext.LogError (string message)
 
276
                {
 
277
                        if (errors != null || ErrorLogged != null)
 
278
                                InternalLogError (new Error (ErrorType.Error, Location, message));
 
279
                }
 
280
                
 
281
                void IParseContext.LogWarning (string message)
 
282
                {
 
283
                        if (errors != null || ErrorLogged != null)
 
284
                                InternalLogError (new Error (ErrorType.Warning, Location, message));
 
285
                }
 
286
                
 
287
                void IParseContext.LogError (string message, DomLocation location)
 
288
                {
 
289
                        if (errors != null || ErrorLogged != null)
 
290
                                InternalLogError (new Error (ErrorType.Error, location, message));
 
291
                }
 
292
                
 
293
                void IParseContext.LogWarning (string message, DomLocation location)
 
294
                {
 
295
                        if (errors != null || ErrorLogged != null)
 
296
                                InternalLogError (new Error (ErrorType.Warning, location, message));
 
297
                }
 
298
                
 
299
                void IParseContext.LogError (string message, DomRegion region)
 
300
                {
 
301
                        if (errors != null || ErrorLogged != null)
 
302
                                InternalLogError (new Error (ErrorType.Error, region, message));
 
303
                }
 
304
                
 
305
                void IParseContext.LogWarning (string message, DomRegion region)
 
306
                {
 
307
                        if (errors != null || ErrorLogged != null)
 
308
                                InternalLogError (new Error (ErrorType.Warning, region, message));
 
309
                }
 
310
                
 
311
                void InternalLogError (Error err)
 
312
                {
 
313
                        if (errors != null)
 
314
                                errors.Add (err);
 
315
                        if (ErrorLogged != null)
 
316
                                ErrorLogged (err);
 
317
                }
 
318
                
 
319
                void IParseContext.ConnectAll ()
 
320
                {
 
321
                        XNode prev = null;
 
322
                        foreach (XObject o in Nodes) {
 
323
                                XContainer container = o as XContainer;
 
324
                                if (prev != null && container != null && prev.IsComplete)
 
325
                                        container.AddChildNode (prev);
 
326
                                if (o.Parent != null)
 
327
                                        break;
 
328
                                prev = o as XNode;
 
329
                        }
 
330
                }
 
331
                
 
332
                void IParseContext.EndAll (bool pop)
 
333
                {
 
334
                        int popCount = 0;
 
335
                        foreach (XObject ob in Nodes) {
 
336
                                if (!ob.IsEnded && !(ob is XDocument)) {
 
337
                                        ob.End (Location);
 
338
                                        popCount++;
 
339
                                } else {
 
340
                                        break;
 
341
                                }
 
342
                        }
 
343
                        if (pop)
 
344
                                for (; popCount > 0; popCount--)
 
345
                                        Nodes.Pop ();
 
346
                }
 
347
                
 
348
                #endregion
 
349
                
 
350
                public State CurrentState { get { return currentState; } }
 
351
                
 
352
                public IList<Error> Errors { get { return errors; } }
 
353
                
 
354
                public event Action<Error> ErrorLogged;
 
355
        }
 
356
        
 
357
        public interface IParseContext
 
358
        {
 
359
                int StateTag { get; set; }
 
360
                StringBuilder KeywordBuilder { get; }
 
361
                int CurrentStateLength { get; }
 
362
                DomLocation Location { get; }
 
363
                DomLocation LocationMinus (int colOffset);
 
364
                State PreviousState { get; }
 
365
                NodeStack Nodes { get; }
 
366
                bool BuildTree { get; }
 
367
                void LogError (string message);
 
368
                void LogWarning (string message);
 
369
                void LogError (string message, DomLocation location);
 
370
                void LogWarning (string message, DomLocation location);
 
371
                void LogError (string message, DomRegion region);
 
372
                void LogWarning (string message, DomRegion region);
 
373
                void EndAll (bool pop);
 
374
                void ConnectAll ();
 
375
        }
 
376
        
 
377
        public class NodeStack : Stack<XObject>
 
378
        {
 
379
                public NodeStack (IEnumerable<XObject> collection) : base (collection) {}
 
380
                public NodeStack () {}
 
381
                
 
382
                public XObject Peek (int down)
 
383
                {
 
384
                        int i = 0;
 
385
                        foreach (XObject o in this) {
 
386
                                if (i == down)
 
387
                                        return o;
 
388
                                i++;
 
389
                        }
 
390
                        return null;
 
391
                }
 
392
                
 
393
                public XDocument GetRoot ()
 
394
                {
 
395
                        XObject last = null;
 
396
                        foreach (XObject o in this)
 
397
                                last = o;
 
398
                        return last as XDocument;
 
399
                }
 
400
        }
 
401
}