* docs/monodoc.xml: Rename the "File Formats" node to "Commands and
[mono.git] / mcs / docs / compiler.txt
index 8b340d2834df15016abf315b7ad647ad4384e13e..275ff0d9566b0dc5f24843b643d27103f40ec7af 100755 (executable)
@@ -2,7 +2,7 @@
        
                                Miguel de Icaza
                              (miguel@ximian.com)
-                                     2002
+                                  2002, 2007
 
 * Abstract
 
        represents the "expression classification" (from the C#
        specs) and the type of the expression.
 
-       Expressions have to be resolved before they are can be used.
+       During parsing, the compiler will create the various trees of
+       expressions.  These expressions have to be resolved before they
+       are can be used.    The semantic analysis is implemented by
+       resolving each of the expressions created during parsing and
+       creating fully resolved expressions.
+
+       A common pattern that you will notice in the compiler is this:
+
+                 Expression expr;
+                 ...
+       
+                 expr = expr.Resolve (ec);
+                 if (expr == null)
+                       // There was an error, stop processing by returning
+
        The resolution process is implemented by overriding the
-       `DoResolve' method.  The DoResolve method has to set the
-       `eclass' field and the `type', perform all error checking and
-       computations that will be required for code generation at this
-       stage. 
+       `DoResolve' method.  The DoResolve method has to set the `eclass'
+       field and the `type', perform all error checking and computations
+       that will be required for code generation at this stage.
 
        The return value from DoResolve is an expression.  Most of the
        time an Expression derived class will return itself (return
        All errors must be reported during the resolution phase
        (DoResolve) and if an error is detected the DoResolve method
        will return null which is used to flag that an error condition
-       has ocurred, this will be used to stop compilation later on.
+       has occurred, this will be used to stop compilation later on.
        This means that anyone that calls Expression.Resolve must
        check the return value for null which would indicate an error
        condition.
        the Expression class.  No error checking must be performed
        during this stage.
 
+       We take advantage of the distinction between the expressions that
+       are generated by the parser and the expressions that are the
+       result of the semantic analysis phase for lambda expressions (more
+       information in the "Lambda Expressions" section).
+
+       But what is important is that expressions and statements that are
+       generated by the parser should implement the cloning
+       functionality.  This is used lambda expressions require the
+       compiler to attempt to resolve a given block of code with
+       different possible types for parameters that have their types
+       implicitly inferred. 
+
 ** Simple Names, MemberAccess
 
        One of the most important classes in the compiler is
        things like SimpleNames and does a different kind of error
        checking than the one used by regular expressions. 
 
-
 ** Constants
 
        Constants in the Mono C# compiler are represented by the
 
 ** Statements
 
+*** Invariant meaning in a block
+
+       The seemingly small section in the standard entitled
+       "invariant meaning in a block" has several subtleties
+       involved, especially when we try to implement the semantics
+       efficiently.
+
+       Most of the semantics are trivial, and basically prevent local
+       variables from shadowing parameters and other local variables.
+       However, this notion is not limited to that, but affects all
+       simple name accesses within a block.  And therein lies the rub
+       -- instead of just worrying about the issue when we arrive at
+       variable declarations, we need to verify this property at
+       every use of a simple name within a block.
+
+       The key notion that helps us is to note the bi-directional
+       action of a variable declaration.  The declaration together
+       with anti-shadowing rules can maintain the IMiaB property for
+       the block containing the declaration and all nested sub
+       blocks.  But, the IMiaB property also forces all surrounding
+       blocks to avoid using the name.  We thus need to maintain a
+       blacklist of taboo names in all surrounding blocks -- and we
+       take the expedient of doing so simply: actually maintaining a
+       (superset of the) blacklist in each block data structure, which
+       we call the 'known_variable' list.
+
+       Because we create the 'known_variable' list during the parse
+       process, by the time we do simple name resolution, all the
+       blacklists are fully populated.  So, we can just enforce the
+       rest of the IMiaB property by looking up a couple of lists.
+
+       This turns out to be quite efficient: when we used a block
+       tree walk, a test case took 5-10mins, while with this simple
+       mildly-redundant data structure, the time taken for the same
+       test case came down to a couple of seconds.
+
+       The IKnownVariable interface is a small wrinkle.  Firstly, the
+       IMiaB also applies to parameter names, especially those of
+       anonymous methods.  Secondly, we need more information than
+       just the name in the blacklist -- we need the location of the
+       name and where it's declared.  We use the IKnownVariable
+       interface to abstract out the parser information stored for
+       local variables and parameters.
+
 * The semantic analysis 
 
        Hence, the compiler driver has to parse all the input files.
        Which drives the process, it first resolves the topblock, then
        emits the required metadata (local variable definitions) and
        finally emits the code.
-               
+
+       A detailed description of anonymous methods and iterators is
+       on the new-anonymous-design.txt file in this directory.
+
+* Lambda Expressions
+
+       Lambda expressions can come in two forms: those that have implicit
+       parameter types and those that have explicit parameter types, for
+       example:
+
+               Explicit:       
+
+                       Foo ((int x) => x + 1);
+
+               Implicit:
+
+                       Foo (x => x + 1)
+
+
+       One of the problems that we faced with lambda expressions is
+       that lambda expressions need to be "probed" with different
+       types until a working combination is found.
+
+       For example:
+
+           x => x.i
+
+       The above expression could mean vastly different things depending
+       on the type of "x".  The compiler determines the type of "x" (left
+       hand side "x") at the moment the above expression is "bound",
+       which means that during the compilation process it will try to
+       match the above lambda with all the possible types available, for
+       example:
+
+        delegate int di (int x);
+        delegate string ds (string s);
+        ..
+        Foo (di x) {}
+        Foo (ds x) {}
+        ...
+        Foo (x => "string")
+
+       In the above example, overload resolution will try "x" as an "int"
+       and will try "x" as a string.  And if one of them "compiles" thats
+       the one it picks (and it also copes with ambiguities if there was
+       more than one matching method).
+
+       To compile this, we need to hook into the resolution process,
+       but since the resolution process has side effects (calling
+       Resolve can either return instances of the resolved expression
+       type, or can alter field internals) it was necessary to
+       incorporate a framework to "clone" expressions before we
+       probe.
+
+       The support for cloning was added into Statements and
+       Expressions and is only necessary for objects of those types
+       that are created during parsing.   It is not necessary to
+       support these in the classes that are the result of calling
+       Resolve.   This means that SimpleName needs support for
+       Cloning, but FieldExpr does not need it (SimpleName is created
+       by the parser, FieldExpr is created during semantic analysis
+       resolution).   
+
+       The work happens through the public method called "Clone" that
+       clones the given Statement or Expression.  The base method in
+       Statement and Expression merely does a MemberwiseCopy of the
+       elements and then calls the virtual CloneTo method to complete
+       the copy.    By default this method throws an exception, this
+       is useful to catch cases where we forgot to override CloneTo
+       for a given Statement/Expression. 
+
+       With the cloning capability it became possible to call resolve
+       multiple times (once for each Cloned copy) and based on this
+       picking the one implementation that would compile and that
+       would not be ambiguous.
+
+       The cloning process is basically a deep copy that happens in the
+       LambdaExpression class and it clones the top-level block for the
+       lambda expression.    The cloning has the side effect of cloning
+       the entire containing block as well. 
+
+       This happens inside this method:
+
+        public override bool ImplicitStandardConversionExists (Type delegate_type)
+
+       This is used to determine if the current Lambda expression can be
+       implicitly converted to the given delegate type.
+
+       And also happens as a result of the generic method parameter
+       type inferencing. 
+
+** Lambda Expressions and Cloning
+
+       All statements that are created during the parsing method should
+       implement the CloneTo method:
+
+                protected virtual void CloneTo (CloneContext clonectx, Statement target)
+
+       This method is called by the Statement.Clone method after it has
+       done a shallow-copy of all the fields in the statement, and they
+       should typically Clone any child statements.
+
+       Expressions should implement the CloneTo method as well:
+
+                protected virtual void CloneTo (CloneContext clonectx, Expression target)
+
+** Lambda Expressions and Contextual Return
+
+       When an expression is parsed as a lambda expression, the parser
+       inserts a call to a special statement, the contextual return.
+
+       The expression:
+
+           a => a+1
+
+       Is actually compiled as:
+
+           a => contextual_return (a+1)
+
+       The contextual_return statement will behave differently depending
+       on the return type of the delegate that the expression will be
+       converted to.
+
+       If the delegate return type is void, the above will basically turn
+       into an empty operation.   Otherwise the above will become
+       a return statement that can infer return types.
+
 * Miscellaneous
 
 ** Error Processing.
        You can use this with -warnaserror to obtain the same effect
        with warnings. 
 
+* Debugging the Parser.
+
+       A useful trick while debugging the parser is to pass the -v
+       command line option to the compiler.
+
+       The -v command line option will dump the various Yacc states
+       as well as the tokens that are being returned from the
+       tokenizer to the compiler.
+
+       This is useful when tracking down problems when the compiler
+       is not able to parse an expression correctly.
+
+       You can match the states reported with the contents of the
+       y.output file, a file that contains the parsing tables and
+       human-readable information about the generated parser.
+
 * Editing the compiler sources
 
        The compiler sources are intended to be edited with 134 columns of width
-       
\ No newline at end of file
+
+* Quick Hacks
+
+       Once you have a full build of mcs, you can improve your
+       development time by just issuing make in the `mcs' directory or
+       using `make qh' in the gmcs directory.