/* * Copyright (c) 2005-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.Collections; using Nemerle.Compiler; using Nemerle.Compiler.Parsetree; using Nemerle.Logging.Helper; namespace Nemerle.Logging { internal module Helper { public Flags : Hashtable [string, PExpr] = Hashtable (); // empty string holds default print function (also set when no VERB=>expr mapping is specified) public FlagsToFunctions : Hashtable [string, PExpr] = Hashtable (); public mutable SetPrintExpression = false; public mutable PrependFlag = false; public mutable AdditionalLoggingCondition : PExpr = null; public GetName (expr : PExpr) : string { | PExpr.Ref (name) => name.Id | _ => Message.FatalError ($ "expected a plain identifier, got $expr"); } Init () : void { Flags.Clear (); } this () { ManagerClass.OnInit += Init; FlagsToFunctions [""] = <[ System.Console.WriteLine ]>; Init (); } public LogFlag (id : PExpr, is_on : PExpr) : void { def is_on = match (is_on) { | <[ 1 ]> => <[ true ]> | <[ 0 ]> => <[ false ]> | _ => is_on } def name = GetName (id); when (Flags.Contains (name)) Message.Error ($ "redefinition of the flag `$(name)'"); Flags [name] = is_on; } public LogFunction (fn : list [PExpr]) : void { when (SetPrintExpression) Message.Error ("the logging expression already set"); SetPrintExpression = true; match (fn) { | <[ $_ => $_ ]> :: _ => foreach (f in fn) { | <[ $(verb : name) => $fn ]> => FlagsToFunctions [verb.Id] = fn; | _ => Message.Error ($ "expected mapping of VERB to print function, like " "`DEBUG => My.DebugFunction' got $f"); } | [fn] => FlagsToFunctions [""] = fn; | _ => Message.Error ("expected single logging function or set of mappings" " from VERB to print functions"); } } public AddCondition (body : PExpr) : PExpr { if (AdditionalLoggingCondition == null) body else <[ when ($AdditionalLoggingCondition) $body ]> } } [Nemerle.MacroUsage (Nemerle.MacroPhase.BeforeInheritance, Nemerle.MacroTargets.Assembly)] macro LogFlag (id, is_on) { LogFlag (id, is_on); } [Nemerle.MacroUsage (Nemerle.MacroPhase.BeforeInheritance, Nemerle.MacroTargets.Class)] macro LogFlag (_ : TypeBuilder, id, is_on) { LogFlag (id, is_on) } [Nemerle.MacroUsage (Nemerle.MacroPhase.BeforeInheritance, Nemerle.MacroTargets.Assembly)] macro LogFunction (params fn : list [PExpr]) { LogFunction (fn); } [Nemerle.MacroUsage (Nemerle.MacroPhase.BeforeInheritance, Nemerle.MacroTargets.Class)] macro LogFunction (_ : TypeBuilder, params fn : list [PExpr]) { LogFunction (fn); } [Nemerle.MacroUsage (Nemerle.MacroPhase.BeforeInheritance, Nemerle.MacroTargets.Assembly)] macro LogCondition (expr) { when (AdditionalLoggingCondition != null) Message.Error ("LogCondition already set"); AdditionalLoggingCondition = expr; } [Nemerle.MacroUsage (Nemerle.MacroPhase.BeforeInheritance, Nemerle.MacroTargets.Assembly)] macro LogFormat (params flags : list [PExpr]) { foreach (flag in flags) { | <[ PrependFlag ]> => PrependFlag = true | f => Message.Error ($ "invalid LogFormat: $f") } } macro log (flag, params exprs : list [PExpr]) { def name = GetName (flag); def print_expr = match (FlagsToFunctions.Get (name)) { | Some (e) => e | _ => FlagsToFunctions [""] } def exprs = if (PrependFlag) match (exprs) { | x :: xs => <[ $(name + ": " : string) + $x ]> :: xs | [] => [] } else exprs; if (Flags.Contains (name)) match (Flags [name]) { | <[ true ]> => AddCondition (<[ $print_expr (.. $exprs) ]>) | <[ false ]> => <[ {} ]> | _ => AddCondition (<[ when($(Flags [name])) { $print_expr (.. $exprs) } ]>) } else { Message.Error ($ "there is no flag named `$(name)'"); <[ {} ]> } } macro @whenlogging (flag, body) syntax ("whenlogging", "(", flag, ")", body) { def name = GetName (flag); if (Flags.Contains (name)) match (Flags [name]) { | <[ true ]> => body | <[ false ]> => <[ {} ]> | _ => <[ when($(Flags [name])) { $body } ]> } else { Message.Error ($ "there is no flag named `$(name)'"); <[ {} ]> } } }