2 new NonTerminals: TypedNT and CommandNonTerminal

Oct 13, 2012 at 3:21 AM
Edited Oct 13, 2012 at 9:53 PM

The first one is really just a toy: dispense with explicitly naming it if the node-name - "Node" suits:

public class TypedNonTerminal : NonTerminal {
   public TypedNonTerminal(Type type) : base(type.Name.Replace("Node",string.Empty), type) {}
}

The second is more substantial. In the music parser, changes to the default Tempo, Style, Octave
and NoteLength can be made in the music string, and these are tracked by setting values in a class
named Notes. Here is a single NonTerminal which, as its Evaluation, sets the corresponding static
fields for these settings.

/// <summary>
///  A NonTerminal publishing an internal AstNodeCreator using a <i>setter</i> for the given 
///  class (constructed from the supplied <i>getter</i>) as its fieldUpdater.
/// <see cref="CommandAstNode{TValue}"/>
/// </summary>
/// <typeparam name="TClass">The class for which a <i>setter</i> is desired.</typeparam>
/// <typeparam name="TValue">The Type for both the <i>setter</i> and <i>getter</i>.</typeparam>
public class CommandNonTerminal<TClass,TValue> : NonTerminal
where TClass:new() 
where TValue:struct {
   /// <summary>
   ///  Returns a NonTerminal publishing an internal AstNodeCreator using a <i>setter</i> for the given 
   ///  class constructed from  the supplied <i>getter</i> as its fieldUpdater.
   /// </summary>
   /// <typeparam name="TClass">The class for which a <i>setter</i> is desired.</typeparam>
   /// <typeparam name="TValue">The Type for both the <i>setter</i> and <i>getter</i>.</typeparam>
   public CommandNonTerminal(Expression<Func<TClass,TValue>> getter) 
   : base(((MemberExpression)getter.Body).Member.Name) {
      base.AstConfig.NodeCreator = CommandNodeCreator(getter);
   }
   /// <summary>
   ///  Returns an AstNodeCreator using a <i>setter</i> for the given class constructed from 
   ///  the supplied <i>getter</i> as its fieldUpdater.
   /// </summary>
   /// <typeparam name="TClass">The class for which a <i>setter</i> is desired.</typeparam>
   /// <typeparam name="TValue">The Type for both the <i>setter</i> and <i>getter</i>.</typeparam>
   /// <param name="getter">A <i>getter</i> in class <b>TClass</b></param>
   /// <returns>AstNodeCreator for the specified flavour of Command Node, using the constructed 
   /// <i>setter</i> as its <i>fieldUpdater</i>.</returns>
   private AstNodeCreator CommandNodeCreator(Expression<Func<TClass,TValue>> getter) {
      var member	= (MemberExpression)getter.Body;
      var action = Utils.SetterFromGetter<TClass,TValue>(getter);

      Action<TValue> fieldUpdater = (t) => action(new TClass(),t);
      return (c,s) => (new CommandAstNode<TValue>(fieldUpdater, member.Member.Name)).Init(c,s);
   }
}

And the code for SetterToGetter, of course:

public static Action<TClass,TValue> SetterFromGetter<TClass,TValue>(
   Expression<Func<TClass,TValue>> getter) 
{
   var member	= (MemberExpression)getter.Body;
   var param	= Expression.Parameter(typeof(TValue), "value");
   var setter	= Expression.Lambda<Action<TClass,TValue>>(
                  Expression.Assign(member, param), getter.Parameters[0], param);

   return setter.Compile();
}
Oct 13, 2012 at 3:26 AM
Edited Oct 13, 2012 at 3:27 AM

And an example of theri use in the music parser:

var Tempo	= new CommandNonTerminal <Notes,byte>	(Notes => Notes.Tempo);
var Length	= new CommandNonTerminal <Notes,byte>	(Notes => Notes.Length);
var Style	= new CommandNonTerminal <Notes,Style>	(Notes => Notes.Style);
var OctaveNo	= new CommandNonTerminal <Notes,byte>	(Notes => Notes.Octave);
var Shift	= new CommandNonTerminal <Notes,OctaveShift>	(Notes => Notes.Shift);

var Note	= new TypedNonTerminal(typeof(NoteNode));
var Rest	= new TypedNonTerminal(typeof(RestNode));
var Pitch	= new TypedNonTerminal(typeof(PitchNode));
var NoteNumber	= new TypedNonTerminal(typeof(NoteNumberNode));
var NoteElement	= new TypedNonTerminal(typeof(NoteElementNode));