/* * 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 Nemerle.Compiler; using PT = Nemerle.Compiler.Parsetree; namespace Nemerle.InternalMacros { macro initializer (params body : list [PExpr]) { <[ {.. $(body.Reverse ()) } ]> } // this macro is a hack for lack of type inference at class level [Nemerle.MacroUsage (Nemerle.MacroPhase.BeforeTypedMembers, Nemerle.MacroTargets.Field)] macro StaticInitializer (t : TypeBuilder, f : ParsedField, val) { match (f.ty) { | <[ _ ]> => match (ConstantFolder.FoldConstants (f.ParsedName.GetEnv (t.GlobalEnv), val)) { | PT.PExpr.Literal (lit) => def mtype = lit.GetInternalType (t.Manager.InternalType); f.ty = PrettyPrint.MTypeToParseTree (mtype); | <[ $_ : $ty ]> | <[ $_ :> $ty ]> => f.ty = ty | _ => try { def expr = Nemerle.Macros.ImplicitCTX ().TypeExpr (val); f.ty = PrettyPrint.MTypeToParseTree (expr.MType()); } catch { | _ => () } } | _ => () } when (Nemerle.Macros.Manager ().IsIntelliSenseMode) { // Add fake method whith body of field initialiser. def n = "_N_field_initialiser__" + f.Name; def attrs = Modifiers (NemerleAttributes.Private | NemerleAttributes.SpecialName, []); Util.locate(val.Location, t.Define (<[ decl: ..$attrs $(n : usesite) () : void { _ = $val; } ]>)); } } [Nemerle.MacroUsage (Nemerle.MacroPhase.WithTypedMembers, Nemerle.MacroTargets.Field)] macro StaticInitializer (t : TypeBuilder, f : FieldBuilder, val) { def is_static = f.Attributes %&& NemerleAttributes.Static; f.HasBeenAssigned = false; // marks as assigned without triggering obsolete warning // for constant fields we fold the expression and try to create // value for literal fields when (is_static && !f.IsMutable) match (ConstantFolder.FoldConstants (t.GlobalEnv, val)) { | PT.PExpr.Literal (Literal.Decimal) => () | PT.PExpr.Literal (Literal.Enum (lit : Literal, _, _)) | PT.PExpr.Literal (lit) => // watch out, we need to get the underlying enum type, // so our literal to type checking works properly mutable enum_ti = null; def target = match (f.GetMemType ()) { | MType.Class (ti, []) when ti.IsEnum => enum_ti = ti; ti.UnderlyingType.GetMemType () | t => t } match (lit.WithType (target)) { | Some (l) => // but we also need to make sure enum fields have proper // literal as initializer f.ConstValue = if (enum_ti == null) l else Literal.Enum (l :> Literal.Integer, enum_ti, f); | None => () } | _ => () } if (Nemerle.Macros.Manager ().IsIntelliSenseMode) {} // Do nothing if is in completion mode. // if we didn't end up with literal value, create assignment in constructor else when (f.ConstValue == null) { def static_attr = if (is_static) BindingFlags.Static else BindingFlags.Instance; def mems = t.GetConstructors (static_attr %| BindingFlags.Public %| BindingFlags.NonPublic %| BindingFlags.DeclaredOnly); def typeName = t.ParsedName; def init = if (is_static) <[ $(typeName : name).$(f.Name : dyn) = $val ]> else <[ this.$(f.Name : dyn) = $val ]>; when (!is_static) t.init_list ::= init; // given existing constructor, insert call to base constructor // at its beginning def inject (ctor) { def ctor = ctor :> MethodBuilder; def bd = ctor.Body; def nbody = Util.locate(ctor.Body.Location, match (bd) { | <[ {.. $(elems) } ]> => // initializer macro is a syntactic placeholder for our initialization // assignments - it will later reverse their order def fetch_inits (seq) { | <[ Nemerle.InternalMacros.initializer (..$inits) ]> :: rest => (init :: inits, rest) | _ => ([init], seq) } match (elems) { | (<[ base (..$_) ]> as b ) :: rest => def (inits, body) = fetch_inits (rest); def i = <[ Nemerle.InternalMacros.initializer (..$inits) ]>; <[ {.. $(b :: i :: body) } ]> // if other ctor was called, then we do not emit initializers | <[ this (..$_) ]> :: _ => bd | _ => def (inits, body) = fetch_inits (elems); def i = <[ Nemerle.InternalMacros.initializer (..$inits) ]>; <[ {.. $(i :: body) } ]> } // this is our first initializer | _ => <[ Nemerle.InternalMacros.initializer ($init); $bd ]> }); ctor.Body = nbody }; when (!is_static && t.IsValueType) Message.Error (val.Location, "instance field initalizers are not allowed in structs" " (they wouldn't work for null initialized instances)"); match (mems) { | [] => def loc = t.Location; def loc1 = Location(loc.FileIndex, loc.Line, loc.Column); Util.locate(loc1, when (is_static) t.Define (<[ decl: static public this () { Nemerle.InternalMacros.initializer ($init); } ]>) ); // inject intializers into static ctor | _ => when (is_static) mems.Iter (inject) } } } [Nemerle.MacroUsage (Nemerle.MacroPhase.BeforeInheritance, Nemerle.MacroTargets.Property, Inherited = false, AllowMultiple = true)] macro PropertyEmbeddedField (t : TypeBuilder, p : ParsedProperty, field_box) { match (field_box) { | PT.PExpr.Quoted (PT.SyntaxElement.ClassMember (PT.ClassMember.Field as val)) => def fld_name = val.name.GetName (); def unique = t.ParsedName.NewName (Util.tmpname (fld_name.Id)); def redirect (f) { | Some(PT.ClassMember.Function(_, _, FunBody.Parsed(bodyExpr)) as func) => def newBody = Util.locate(bodyExpr.Location, <[ InternalMacros.RedirectName ($(fld_name : name), $(unique : name), $bodyExpr) ]>); func.body = FunBody.Parsed(newBody); | _ => () } redirect(p.set); redirect(p.get); when (p.modifiers.mods %&& NemerleAttributes.Static) val.Attributes |= NemerleAttributes.Static; def newdecl = <[ decl: ..$(val.modifiers) $(unique : name) : $(val.ty); ]>; newdecl.Location = val.Location; t.Define (newdecl) | _ => Message.FatalError (field_box.Location, "malformed PropertyEmbeddedField (ICE?)") } } [Nemerle.MacroUsage (Nemerle.MacroPhase.WithTypedMembers, Nemerle.MacroTargets.Event, Inherited = false, AllowMultiple = true)] macro EventEmbeddedField (t : TypeBuilder, p : EventBuilder, field_box) { match (field_box) { | PT.PExpr.Quoted (PT.SyntaxElement.ClassMember (PT.ClassMember.Field as val)) => def fld_name = val.name.GetName (); def unique = t.ParsedName.NewName (Util.tmpname (fld_name.Id)); def set = p.GetRemover (); when (set != null) { def newBody = Util.locate(set.Body.Location, <[ InternalMacros.RedirectName ($(fld_name : name), $(unique : name), $(set.Body)) ]>); set.Body = newBody; } def get = p.GetAdder (); when (get != null) { def newBody = Util.locate(get.Body.Location, <[ InternalMacros.RedirectName ($(fld_name : name), $(unique : name), $(get.Body)) ]>); get.Body = newBody; } when (p.Attributes %&& NemerleAttributes.Static) val.Attributes |= NemerleAttributes.Static; def newdecl = <[ decl: ..$(val.modifiers) $(unique : name) : $(val.ty); ]>; newdecl.Location = val.Location; t.Define (newdecl) | _ => Message.FatalError (field_box.Location, "malformed EventEmbeddedField (ICE?)") } } macro RedirectName (name, newname, oldbody) { match (name) { | <[ $(n : name) ]> => Nemerle.Macros.ImplicitCTX().AddRedirection (n, newname); oldbody | _ => Message.FatalError ("invalid name supplied to RedirectName") } } }