// REFERENCE: Nemerle.Compiler using Nemerle.Compiler; using Nemerle.Collections; namespace DesignPatterns { [Nemerle.MacroUsage (Nemerle.MacroPhase.BeforeInheritance, Nemerle.MacroTargets.Class)] macro Singleton (t : TypeBuilder, getter) { def mems = t.GetParsedMembers (); // find constructor, which we will need to call // to create instance def ctor = List.Filter (mems, fun (x) { | <[ decl: ..$_ this (..$_) $_ ]> => true | _ => false }); match (ctor) { | [ <[ decl: ..$_ this (..$parms) $_ ]> as constructor ] => match (getter) { | <[ $(getter_name : name) ]> => // we must prepare expressions for invoking constructor def invoke_parms = List.Map (parms, fun (x) { <[ $(x.ParsedName : name) ]> }); // first define the field, where a single instance will be stored t.Define (<[ decl: private static mutable instance : $(t.ParsedName : name); ]>); // finally, define getter t.Define (<[ decl: public static $(getter_name : name) : $(t.ParsedName : name) { get { // lazy initialization in generated code when (instance == null) instance = $(t.ParsedName : name) (..$invoke_parms); instance; } } ]>); // make sure constructor is protected constructor.Attributes |= NemerleAttributes.Protected; | _ => Message.FatalError ($"Singleton must be supplied with a simple name for getter, got $getter") } | _ => Message.Error ("Singleton design pattern requires exactly one constructor defined") } } }