/*
* Copyright (c) 2003-2008 The University of Wroclaw.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the University may not be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE UNIVERSITY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using SCG = System.Collections.Generic;
namespace Nemerle.Compiler
{
/* ---------------------------------------------------------------------- */
/* -- GLOBAL PROCESSING OF ALL TYPEBUILDERS------------------------------ */
/* ---------------------------------------------------------------------- */
public partial class TypesManager
{
public mutable infos : list [TypeBuilder] = [];
mutable assembly_attributes : SCG.List [GlobalEnv * Parsetree.PExpr] = SCG.List();
internal mutable run_phase : int;
// used to create fake source code for macro generated expressions
mutable generatedSourceCode : LocatingTextWriter;
mutable generatedSourceLocation : Location;
attribute_macros_queue : Nemerle.Collections.Heap [AttributeMacroExpansion] = Nemerle.Collections.Heap (100);
[Record (Exclude = [AddedNr])]
internal protected class AttributeMacroExpansion : System.IComparable [AttributeMacroExpansion]
{
public Target : MacroTargets;
public Phase : MacroPhase;
public Expression : Parsetree.PExpr;
InitialParms : list [Parsetree.SyntaxElement];
TBuilder : TypeBuilder;
CurrentMethod : MethodBuilder;
internal mutable AddedNr : int;
/// we need the earlier expanded macros to get the highest values, as heap is returning max values first
public CompareTo (other : AttributeMacroExpansion) : int
{
// larger phase values should be expanded later
if (Phase != other.Phase) (other.Phase :> int) - (Phase :> int)
else if (Target != other.Target) (other.Target :> int) - (Target :> int)
else other.AddedNr - AddedNr;
}
protected virtual GEnv : GlobalEnv {
get { TBuilder.GlobalEnv }
}
protected virtual TEnv : TyVarEnv {
get { TBuilder.Tenv; }
}
public override ToString () : string
{
def tb = if (TBuilder != null) TBuilder.ToString () else "";
$"$tb: $Expression - ($AddedNr) - $Target $Phase";
}
public Expand () : bool
{
match (MacroRegistry.lookup_macro (GEnv, Expression, Suffix (Target, Phase))) {
| None => false
| Some ((name, imacro, exprs)) =>
def parms = InitialParms + exprs;
def tenv = if (CurrentMethod == null) TEnv else CurrentMethod.Header.tenv;
def env = name.GetEnv (GEnv);
try {
GEnv.Manager.MacroColors.PushNewColor (name.color, env);
def res = Util.locate (Expression.Location,
imacro.Run (GEnv.Manager.ComponentsFactory.CreateTyper (TBuilder, tenv, CurrentMethod, env), parms));
assert (res == null);
} finally {
GEnv.Manager.MacroColors.PopColor ();
}
true
}
}
public static Suffix (target : MacroTargets, stage : MacroPhase) : string
{
def targetStr = match (target) {
| Assembly => ":assembly"
| Class => ":type"
| Event => ":event"
| Field => ":field"
| Method => ":method"
| Parameter => ":param"
| Property => ":property"
| _ => throw System.ArgumentException ($"macro target $target is not allowed");
}
def stageStr = match (stage) {
| BeforeInheritance => ":postscan"
| BeforeTypedMembers => ":preadd"
| WithTypedMembers => ":postadd"
| _ => throw System.ArgumentException ($"not allowed $stage stage of macro")
}
targetStr + stageStr
}
}
[Record]
internal protected class AssemblyAttributeMacroExpansion : AttributeMacroExpansion
{
genv : GlobalEnv;
protected override GEnv : GlobalEnv { get { genv } }
protected override TEnv : TyVarEnv { get { null } }
}
internal AddMacroExpansion (exp : AttributeMacroExpansion) : void
{
// set ordering
exp.AddedNr = Manager.AttributeMacroExpansion_global_nr;
unchecked (Manager.AttributeMacroExpansion_global_nr++);
//Message.Debug ($"adding $exp");
attribute_macros_queue.Add (exp);
}
private mutable is_expanding : bool = false;
internal ExpandMacros () : void {
when (is_expanding) Nemerle.Imperative.Return ();
def stage = current_macro_phase;
is_expanding = true;
while (!attribute_macros_queue.IsEmpty) {
def first = attribute_macros_queue.Top();
when (first.Phase :> int > stage :> int)
Nemerle.Imperative.Break();
//Message.Debug ($"expanding $first");
_ = attribute_macros_queue.ExtractFirst().Expand();
}
is_expanding = false;
}
current_macro_phase : MacroPhase
{
get {
match (run_phase) {
| 0 | 1 | 2 | 3 | 4 => MacroPhase.BeforeInheritance
| 5 | 6 => MacroPhase.BeforeTypedMembers
| 7 | _ => MacroPhase.WithTypedMembers
}
}
}
public CreateTypeBuilder (par : TypeBuilder, td : Parsetree.TopDeclaration,
ns_node : NamespaceTree.Node) : TypeBuilder
{
def tb = TypeBuilder (this, par, td, ns_node);
infos ::= tb;
tb
}
/**
* Clears the type tree from classes defined in currently analyzed program
*/
public RemoveProgramTypes () : void
{
foreach (tb in infos)
tb.NamespaceNode.CleanUp ();
}
/**
* Construct datastructures we use to check subtyping relations.
*
*
* This probably the hardest part of processing type declarations.
*
* Each type directly subtypes types it extends or implements. This
* pass computes transitive closure of direct subtyping relation
* and stores it [TypeBuilder.supertypes] map. .NET generics doesn't allow
* same type to be subtyped under different instantiations, so we
* use map from (id of) subtyped TypeBuilder object to actual parameters
* of subtyped type.
*
*/
determine_subtyping () : void
{
Iter (fun (ti : TypeBuilder) {
ti.construct_subtyping_map ()
});
}
Iter (builders : list [TypeBuilder], f : TypeBuilder -> void) : void
{
def working_on = Util.next_id (Manager);
def done = Util.next_id (Manager);
def maybe_f (ti : TypeBuilder)
{
def ti = ti;
if (ti.phase == done) ()
else if (ti.phase == working_on) {
ti.parent_type = null; // prevent crash the IntelliSense Engine
// TODO: Create and report cycle path.
Message.Error(ti.Location, "type definition for `" + ti.FullName + "' is cyclic")
}
else {
ti.phase = working_on;
Util.locate (ti.Location, {
ti.iterate_first.Iter (maybe_f);
f (ti)
});
ti.phase = done
}
}
builders.Iter (maybe_f)
}
/**
* Iterate over all types defined in source code.
*
* Supertypes are always processed before subtypes otherwise
* source code order is retained.
*/
public Iter (f : TypeBuilder -> void) : void
{
Iter (infos.Reverse (), f);
}
public IterConditionally (f : TypeBuilder -> void, cond : TypeBuilder -> bool) : void
{
Iter (infos.Reverse (), fun (b) {
when (cond (b))
f (b)
});
}
/**
* Iterate over top level types in source code order.
*/
public SourceTopIter (f : TypeBuilder -> void) : void
{
foreach (x : TypeBuilder in infos.Reverse ())
when (x.DeclaringType == null)
Util.locate (x.Location, f (x))
}
/**
* Iterate over top level types in inheritance order.
*/
public TopIter (f : TypeBuilder -> void) : void
{
def wrap (x : TypeBuilder) : void {
when (x.DeclaringType == null)
Util.locate (x.Location, f (x))
};
Iter (wrap);
}
/**
* Main function of type declaration handling pass.
*
*
* - constructing typing environments [TypeBuilder.make_tyenvs]
* - binding types [TypeBuilder.bind_types]
* - determining subtyping relations [TypeBuilder.determine_subtyping]
* - checking subtyping constraints on types that are already bound
* [TypeBuilder.check_bound_types]
* - adding members [TypeBuilder.add_members]
* - adding the variant/variant option special matching methods
*
*/
public Run () : void
{
ExpandMacros ();
foreach (x : TypeBuilder in infos.Reverse ())
Util.locate (x.Location, x.process_macro_attributes (MacroPhase.BeforeInheritance));
run_phase = 1;
SourceTopIter (fun (x : TypeBuilder) { x.make_tyenvs () });
run_phase = 2;
SourceTopIter (fun (x : TypeBuilder) { x.bind_types () });
// add the _N_GetVariantCode methods to variants and variant options
Iter (fun (x : TypeBuilder) { x.add_special_variant_methods () });
run_phase = 3;
determine_subtyping ();
run_phase = 4;
Iter (fun (x : TypeBuilder) { x.check_bound_types () });
run_phase = 5;
ExpandMacros ();
Iter (fun (x : TypeBuilder) { x.process_macro_attributes (MacroPhase.BeforeTypedMembers) });
run_phase = 6;
Iter (fun (x : TypeBuilder) { x.add_members () });
run_phase = 7;
ExpandMacros ();
Iter (fun (x : TypeBuilder) { x.process_macro_attributes (MacroPhase.WithTypedMembers) });
// add constant object constructors for constant variant options
Iter (fun (x : TypeBuilder) { x.add_constant_variant_ctors () });
// propagate the SpecialName attribute if needed
Iter (fun (x : TypeBuilder) {
when (x.Attributes %&& NemerleAttributes.SpecialName)
x.mark_members_with_special_name ()
});
def check_method_implements (ti : TypeBuilder) {
unless (ti.IsInterface) ti.resolve_method_implements ();
};
Iter (check_method_implements);
Iter (fun (x : TypeBuilder) { x.check_ctor_constraints () });
when (generatedSourceCode != null)
try {
using (genSrcFile = System.IO.StreamWriter (nameOfGeneratedSourceFile ()))
genSrcFile.Write (generatedSourceCode.ToString ());
}
catch {
| e => Message.Warning ("could not save generated source code file: " + e.Message)
}
}
private nameOfGeneratedSourceFile () : string {
System.IO.Path.Combine (System.IO.Path.GetDirectoryName(System.IO.Path.GetFullPath (Manager.Options.OutputFileName)),
"_N_GeneratedSource_" + System.IO.Path.GetFileNameWithoutExtension (Manager.Options.OutputFileName) + ".n")
}
/** Called at the end of the finialization. */
internal CheckFinalization () : void
{
Iter (fun (x : TypeBuilder) {
when (x.type_builder != null)
if (x.CannotFinalize)
Message.FatalError ($ "the type $(x) was not finalized, forgot the "
"TypeBuilder.Compile () on it?")
else
x.FinalizeType ();
});
}
/**
* This method iterates through all the known type builders,
* looking for unused global symbols.
*/
internal CheckForUnusedGlobalSymbols () : void
{
when (Manager.Options.Warnings.IsEnabled (10003) || Manager.Options.Warnings.IsEnabled (649))
Iter (_.check_for_unused_global_symbols ())
}
public GenerateFakeSourceCode (mem : Parsetree.ClassMember) : void
{
when (generatedSourceCode == null)
generatedSourceCode = LocatingTextWriter (System.Text.StringBuilder (),
Location (nameOfGeneratedSourceFile (), 1, 1, 1, 1).AsGenerated());
def begin_loc = generatedSourceCode.Loc;
generatedSourceCode.Write (mem.ToString ());
generatedSourceCode.FetchUpdatedLocation (mem, begin_loc);
generatedSourceCode.Write ("\n");
mem.PrintBody (generatedSourceCode);
generatedSourceCode.Write ("\n\n");
}
}
}