[Monodevelop-devel] Rethinking the IDocumentMetaInformation

Mike Krüger mkrueger at novell.com
Thu Sep 11 04:45:18 EDT 2008


> > My long term vision for that was that a delta parser should take care of
> > teh document meta information. The meta information should consists only
> > on stuff that are regular expressions.
> Couldn't an incremental/delta parser be used to /update/ the
> CompilationUnit? At this point we don't even know if/how an
> incremental parser could be implemented, so it seems premature to
> design around it. This also seems rather mcs-specific.

An delta parser for a regular grammar is much more easy to do than for
an context sensitive grammar (programming languages are that type). But
I think a delta parser isn't worth it, because we may have to re-parse
the whole file. But we could optimize it a bit more, it's not
neccessarry for every case to re-parse all and then the delta parser for
the other information'll make sense too.
(In fact every time where a body is changed a re-parse is unneccessary,
just the region information of the member should be updated)

> >> I have some suggestions for a solution.
> >>
> >> I suggest we have the IParser instead return an IParsedDocument,
> which
> >> would be very generic, with the basic info used by the text editor:
> >>
> > 
> >> IParsedDocument
> >> {
> >> string FileName;
> >> DateTime ParseTime { get; }
> >> IEnumerable<Fold> GetFoldLocations (); //expected to iterate
> >> over types, comments etc and generate folds
> >> ICollection<Error> Errors { get; } //also warnings
> >> bool HasErrors { get; }
> >> }
> >>
> >> There would then be an ICompilationUnit derived interface, with
> >> generic info for things like the quick finder and document outline.
> >>
> > 
> >> ICompilationUnit : IParsedDocument
> >> {
> >> ICollection<IBaseType> Types { get; }
> >> ICollection<IBaseMember> GlobalMembers { get; }
> >> 
> >> IEnumerable<Comment> Comments { get; }
> >> }
> >>
> >> The .NET info would be in the derived ICompilationUnit, and would
> be
> >> returned by .NET parsers:
> >>
> > 
> >> IDotNetCompilationUnit : ICompilationUnit
> >> {
> >> ICollection<IUsing> Usings { get; }
> >> ICollection<IAttribute> Attributes { get; }
> >> ICollection<IType> Classes { get; } // foreach (IBaseType t in
> >> Types) yield return (IType) t;
> >> ICollection<Coderegion> CodeRegions { get; } //#regions
> >> }
> >>
> >> Even better, this moves some generic logic out of the
> SourceEditor2,
> >> so that the compilationunit / parseddocument could control the fold
> >> locations, i.e. GetFoldLocations () would generate regions by
> >> iterating over the members, classes, comments, C #regions, etc.
> This is one of the important points in my proposal, since IMO we have
> been hardcoding too much .NET-specific functionality into
> SourceEditor2 is a way that is not extensible/overridable.

Can you give some examples ? Take the quick class combo - it only makes
sense when you've classes/members and regions. It's not really designed
for non object oriented functional languages - I admit. But that's not
really troublesome I think. For these languages we should not display
the quick class combo.
I think that's the case for other .NET specific features the same case.
Your language don't have '.NET' attributes or Properties ? No problem,
leave these collections empty in the compilation unit.
MonoDevelop provides the superset (which is in fact very .NET specific,
because it's designed around .NET features). But .NET is a good
superset, because .NET was designed to match many languages.

> >> I could implement an AspNetDocument : IParsedDocument. The C/C++
> >> parser could return a CCompilationUnit : ICompilationUnit
> >>
> >> Does this sound like a good plan? Should I implement it?
> >>
> >
> > Hm, I think that'll produce too many upcasts only for different levels
> > of information.
> Why are the upcasts a problem? They are all designed/intended to be
> used in different ways.

Not different ways, different levels of information. 
* It makes no sense to use object orientation this way, you're just
creating a complicated class hierarchy and in the end it's casted to
(IDotNetCompilationUnit) where all informations can be accessed. Even
the source editor will do it this way. Your three interfaces could be
separated, they shouldn't need to inherit from each other.

* Having a 3-tier hierarchy like this one duplicates the entries
(ICollection<IBaseType> Types { get; } and ICollection<IType> Classes
{ get; }).

* You're still mixing .NET and non .NET stuff
in IDotNetCompilationUnit. And this is your main concern (Usings may be
in .NET languages like c++, but not attributes).

> I've looked at your changes in SVN, and I'm not totally happy; it
> would have been nice to finish the discussion first. At least it's a
> step in the right direction.

It's a proposal. I prefer to communicate over source code :).

> My concerns are:
> * Still not generic enough -- .NET-centric: ConditionalRegion,
> PreProcessorDefine, ICompilationUnit will not be needed for many
> languages, and are not things that the text editor will use.

Yes that's true, for many 'languages' the CompilationUnit will be null.
PreProcessorDefine will only be used for defines ... that's true that
most langugages don't have something like this, but c, c++ share this
with c# as well as the conditional regions (that are the #if DEFINED ...
#else ... #endif) stuff. 

Think of the user side:
Somewhere deep in future highlighting code:

IParsedDocument doc = GetDoc ();

// highlight errors red

INetCentricParsedDocument netDoc = doc as INetCentricParsedDocument;
if (netDoc != null) {
  foreach(ConditionalRegion r in netDoc.ConditionalRegion) {
    if (!netDoc.IsDefined (r.Condition)) {
       // make gray

You would have just:

IParsedDocument doc = GetDoc ();

// highlight errors red

foreach(ConditionalRegion r in doc.ConditionalRegion) {
  if (!doc.IsDefined (r.Condition)) {
    // make gray

Your code is still .NET centric because it does the same thing but you just cast more.

> * Not designed around use cases -- for example, things like the quick
> finder and document outline will still be tied to .NET. IMO the
> ParseDocument should be "decomposable" into different interfaces for
> different purposes, i.e. text editor's errors&folding, quick
> finder/outline showing structure, .NET completion DB information, etc.
> Only a single upcast would be required for any one purpose.

See the example above, the code will still be .NET centric, but does the
upcast. If we've very domain specific information it'll make sense to
hide them, but pre processor stuff, regions, usings are shared accross
some languages. And I don't see that it hurts other languages, because
you just re-use the ParsedDocument that's available and fill in the
stuff that your language provides. From the user point of view I think
that's easier than to get comfortable with a class hierarchy. (But I may
be wrong - comments ?)

> * Still leaves ICompilationUnit->folds mapping code in the
> SourceEditor2. I'd like the ParseDocument to be able to perform this
> mapping so that it can be overridden.

That can be done, is a different aspect than the inheritance stuff.


More information about the Monodevelop-devel-list mailing list