Thread overview
A feture adjustment request and a syntax blasphemy
Oct 28, 2006
BCS
Oct 28, 2006
BCS
Oct 29, 2006
David Medlock
Oct 30, 2006
BCS
Oct 31, 2006
BCS
October 28, 2006
This is allowed:

  void foo(int[] ar){}
  ...
  static int[] i = [1,2,3];
  i.foo();

And this is allowed:

  struct I
  {
    int[] v;
    void foo(){}
  }
  ...
  I i;
  auto dg = &i.foo;

So why no this?

  void foo(int[] ar){}
  ...
  static int[] i = [1,2,3];
  auto dg = &i.foo;



And another one:

This is allowed:

  static int[] i = [1,2,3];
  void function(int[]) fp = function void(int[] j){return;};
  i.fp();

So why no this?

  static int[] i = [1,2,3];
  i.function void(int[] j){return;}();




You may be wondering where this is all going (and what that was about a blasphemy). Well her it is:

<code type="WTF!">

	// a base type for derivation
class Type{}
	// a templated derived type to store things in
class TypeT(T) : Type
{
	public T val;
	static TypeT!(T) opCall(T v)
	{
		auto ret = new TypeT!(T);
		ret.val = v;
		return ret;
	}
}

/*
Doc ::=
	  A:a B:b C:c	= new Fig(a,b,c)
	| D:d E:e		= new Fig(d,e)
*/
TypeT!(Fig) delegate() Parse_Doc(inout char[] from)
{
	char[] tmp;

		// copy from
	tmp = from;
	if(auto a = Parse_A(tmp)) // try to parse an "a"
	if(auto b = Parse_B(tmp)) // try to parse an "b"
	if(auto c = Parse_C(tmp)) // try to parse an "c"
	{	// if all's good
			// update what's been parsed
		from = tmp;
		return &(
				// make an array from the args
			[cast(Type delegate())a,b,c]
				// copy it (force off stack)
			.dup
			)
				// form delegate from array
				// and function literal				
			.function TypeT!(Fig)(Type delegate()[] args)
			{
					// literal calls given code
				auto ret =
					new Fig(
						// call args for values
					cast(a.typeof)args[0]().val,
					cast(b.typeof)args[1]().val,
					cast(b.typeof)args[2]().val);

					// place in object and return
				return TypeT!(ret.typeof)(ret);
			};
	}

		// restore tmp
	tmp = from;

		// blah, blah, blah
	if(auto d = Parse_D(tmp))
	if(auto e = Parse_E(tmp))
	{
		from = tmp;
		return &([cast(Type delegate())d,e].dup)
			.function TypeT!(Fig)(Type delegate()[] args)
			{
				auto ret =
					new Fig(
				cast(d.typeof)args[0]().val,
				cast(e.typeof)args[1]().val);
				return TypeT!(ret.typeof)(ret);
			};
	}

	return null;
}
/*
A ::=
	"hello":v	= v
*/
TypeT!(char[]) delegate() Parse_A(inout char[] from)
{
	char[] tmp;

	tmp=from;
		// check for a "hello"
	if(from[0.."hello".length] == "hello")
	{
			// update from
		from = from["hello".length..$];
			// return delegate returning "hello" in obj
		return &("hello".dup).function TypeT!(char[])()
			{
				auto ret =
					from[0.."hello".length];
				return TypeT!(ret.typeof)(ret);
			};
	}

	return null;
}
/// ........

</code>
<script> for(auto i = brain.Remove; true; i.Lather.Rinse){} </script>


WHAT IN ALL THAT IS HOLY WAS THAT!!!!

It is a recursive decent parser that avoids executing actions that are never used. This would allow for actions to have side effects that would otherwise have to be undone after it is discovered that the current parse attempt fails.

Rather than do each action as it is tried, each reduction function returns a delegate that has enough info to do the actions for the components and the code to use the result to execute the action. After calling the topmost Reduction function, the return value then needs to be called.

auto a = Parse_Doc(SomeString);
if(a is null) return;
auto a().val;

The important things are

# making delegates from function used as properties of arrays
# using function literals in the above.

I would like to see both of these things added.

Also, this syntax blasphemy shows that there is a use for som of these things  and was to cool to not post about
October 28, 2006
BCS wrote:
> This is allowed:
> 
>   void foo(int[] ar){}
>   ...
>   static int[] i = [1,2,3];
>   i.foo();
> 
> And this is allowed:
> 
>   struct I
>   {
>     int[] v;
>     void foo(){}
>   }
>   ...
>   I i;
>   auto dg = &i.foo;
> 
> So why no this?
> 
>   void foo(int[] ar){}
>   ...
>   static int[] i = [1,2,3];
>   auto dg = &i.foo;
> 
> 
> 
> And another one:
> 
> This is allowed:
> 
>   static int[] i = [1,2,3];
>   void function(int[]) fp = function void(int[] j){return;};
>   i.fp();
> 
> So why no this?
> 
>   static int[] i = [1,2,3];
>   i.function void(int[] j){return;}();
> 
> 
> 
> 
> You may be wondering where this is all going (and what that was about a blasphemy). Well her it is:
> 
> <code type="WTF!">
> 
>     // a base type for derivation
> class Type{}
>     // a templated derived type to store things in
> class TypeT(T) : Type
> {
>     public T val;
>     static TypeT!(T) opCall(T v)
>     {
>         auto ret = new TypeT!(T);
>         ret.val = v;
>         return ret;
>     }
> }
> 
> /*
> Doc ::=
>       A:a B:b C:c    = new Fig(a,b,c)
>     | D:d E:e        = new Fig(d,e)
> */
> TypeT!(Fig) delegate() Parse_Doc(inout char[] from)
> {
>     char[] tmp;
> 
>         // copy from
>     tmp = from;
>     if(auto a = Parse_A(tmp)) // try to parse an "a"
>     if(auto b = Parse_B(tmp)) // try to parse an "b"
>     if(auto c = Parse_C(tmp)) // try to parse an "c"
>     {    // if all's good
>             // update what's been parsed
>         from = tmp;
>         return &(
>                 // make an array from the args
>             [cast(Type delegate())a,b,c]
>                 // copy it (force off stack)
>             .dup
>             )
>                 // form delegate from array
>                 // and function literal                           .function TypeT!(Fig)(Type delegate()[] args)
>             {
>                     // literal calls given code
>                 auto ret =
>                     new Fig(
>                         // call args for values
>                     cast(a.typeof)args[0]().val,
>                     cast(b.typeof)args[1]().val,
>                     cast(b.typeof)args[2]().val);
> 
>                     // place in object and return
>                 return TypeT!(ret.typeof)(ret);
>             };
>     }
> 
>         // restore tmp
>     tmp = from;
> 
>         // blah, blah, blah
>     if(auto d = Parse_D(tmp))
>     if(auto e = Parse_E(tmp))
>     {
>         from = tmp;
>         return &([cast(Type delegate())d,e].dup)
>             .function TypeT!(Fig)(Type delegate()[] args)
>             {
>                 auto ret =
>                     new Fig(
>                 cast(d.typeof)args[0]().val,
>                 cast(e.typeof)args[1]().val);
>                 return TypeT!(ret.typeof)(ret);
>             };
>     }
> 
>     return null;
> }
> /*
> A ::=
>     "hello":v    = v
> */
> TypeT!(char[]) delegate() Parse_A(inout char[] from)
> {
>     char[] tmp;
> 
>     tmp=from;
>         // check for a "hello"
>     if(from[0.."hello".length] == "hello")
>     {
>             // update from
>         from = from["hello".length..$];
>             // return delegate returning "hello" in obj
>         return &("hello".dup).function TypeT!(char[])()
>             {
>                 auto ret =
>                     from[0.."hello".length];
>                 return TypeT!(ret.typeof)(ret);
>             };
>     }
> 
>     return null;
> }
> /// ........
> 
> </code>
> <script> for(auto i = brain.Remove; true; i.Lather.Rinse){} </script>
> 
> 
> WHAT IN ALL THAT IS HOLY WAS THAT!!!!
> 
> It is a recursive decent parser that avoids executing actions that are never used. This would allow for actions to have side effects that would otherwise have to be undone after it is discovered that the current parse attempt fails.
> 
> Rather than do each action as it is tried, each reduction function returns a delegate that has enough info to do the actions for the components and the code to use the result to execute the action. After calling the topmost Reduction function, the return value then needs to be called.
> 
> auto a = Parse_Doc(SomeString);
> if(a is null) return;
> auto a().val;
> 
> The important things are
> 
> # making delegates from function used as properties of arrays
> # using function literals in the above.
> 
> I would like to see both of these things added.
> 
> Also, this syntax blasphemy shows that there is a use for som of these things  and was to cool to not post about

My brain hurts from reading that.  You are an evil, evil, little man, and I utterly despise you for all that dribble!

And yet... despite myself, I do find it strangely compelling.  :)  Perhaps there ought to be a way found to at least achieve what you're after.  Pretty ingenious -- but still very, very evil.

-- Chris Nicholson-Sauls
October 28, 2006
== Quote from Chris Nicholson-Sauls's article
> My brain hurts from reading that.  You are an evil, evil, little man,
> and I utterly despise you for all that dribble!
> And yet... despite myself, I do find it strangely compelling.  :)
> Perhaps there ought to be a way found to at least achieve what
> you're after.  Pretty ingenious -- but still very, very evil.
> -- Chris Nicholson-Sauls

In case you are interested, if anyone working under me ever attempted to get paid for something like that, I'd give them twenty lashes with a handful of wet noodles.

OTOH doing that with a code generator...
October 29, 2006
BCS wrote:
> This is allowed:
> 
>   void foo(int[] ar){}
>   ...
>   static int[] i = [1,2,3];
>   i.foo();
> 
> And this is allowed:
> 
>   struct I
>   {
>     int[] v;
>     void foo(){}
>   }
>   ...
>   I i;
>   auto dg = &i.foo;
> 
> So why no this?
> 
>   void foo(int[] ar){}
>   ...
>   static int[] i = [1,2,3];
>   auto dg = &i.foo;
> 
> 
If I am not mistaken but this is a closure.
In javascript the above is:

var i = [ 1,2,3,4];
var dg = function() { return foo(i); }

If you have a function
f( a, b )

then you wish to call it with only a single parameter

g = f(x)

this will yield
a function g which has the following behavior:

g( y ) = f( x, y )

This is currying, or partial evaluation.

A good paper on this is:
http://www.dina.kvl.dk/~sestoft/pebook/

Very good paper.

-DavidM





October 29, 2006
"BCS" <BCS@pathlink.com> wrote in message news:ehu935$d2p$4@digitaldaemon.com...

> So why no this?
>
>   void foo(int[] ar){}
>   ...
>   static int[] i = [1,2,3];
>   auto dg = &i.foo;

As David said, this is called partial evaluation, and I believe someone has written a template library for D to do just this.. Ah, here it is, Tom S. wrote it:

http://158.75.59.9/~h3/code/bind.rar

Maybe that will let you do at least somewhat what you'd like to do :)

> So why no this?
>
>   static int[] i = [1,2,3];
>   i.function void(int[] j){return;}();

How about:

 static int[] i = [1,2,3];
 auto f = function void(int[] j){return;};
 i.f();

?


October 30, 2006
Closures and currying provide some of what I was looking for. However, if I understand them correctly*, they don't do exactly what I want.

The closure approach would be fine if it didn't require some language magic or annotations to get the local parameters off the stack. The system I used avoids this by dynamically allocating off the heap for the context. (this is only better than annotation because it doesn’t require language support)

Currying (again, if I understand correctly) will end up using some sort of runtime generated function or a wrapper delegate that manipulates the stack (another form of a closure) again this doesn’t quite have the effect I'm looking for. In this case it is because of the extra call/return overhead.

Really what I want is to be able to form a delegate from any heap item and a literal code block. particularly I want the context of such a thing to be the heap item, not the enclosing scope.

<ptr_type>.delegate <type>(<type_list>){<code>}

FWIW, I got the program I posted working but had to use an anonymous class with the function as a method. Not as clean a solution because of the overhead involving objects, but it works.

{
	auto c = new class{
		T delegate() d;
		T action()
		{
			return d();
		}
	}
	return &a.action;
}

*I haven’t read the article DavidM cited yet (lack of time n'all)


== Quote from Jarrett Billingsley (kb3ctd2@yahoo.com)'s article
> "BCS" <BCS@pathlink.com> wrote in message
> > So why no this?
> >
> >   static int[] i = [1,2,3];
> >   i.function void(int[] j){return;}();
> How about:
>  static int[] i = [1,2,3];
>  auto f = function void(int[] j){return;};
>  i.f();
> ?


I was trying to get away without the temporary. If you will notice, you suggestion is effectively the same as the example of something that works that I gave.
October 31, 2006
BCS wrote:
> This is allowed:
> 
>   void foo(int[] ar){}
>   ...
>   static int[] i = [1,2,3];
>   i.foo();
> 
> And this is allowed:
> 
>   struct I
>   {
>     int[] v;
>     void foo(){}
>   }
>   ...
>   I i;
>   auto dg = &i.foo;
> 
> So why no this?
> 
>   void foo(int[] ar){}
>   ...
>   static int[] i = [1,2,3];
>   auto dg = &i.foo;
> 

FWIW I realized (at midnight this morning) why this doesn't work.

in the struct/class case the context is a pointer (32 bits) in the array case it is a pointer length pair (64 bits). It just doesn't fit in the hole.



and for the strong of will here is the working version using class literals. (The grammar comes from my CS homework, that, BTW is not the impetus for the program)

/*
Code ::=
 BlatA:b "@" Code:c = new Code(b,c)
 BlatA:b = new Code(b)

BlatA ::=
 Thunk:t Blat:b = new BlatA(t,b)

Blat ::=
 "!" Thunk:t Blat:b = new Blat(t,b)
 "*" Chunk:c Blat:b = new Blat(c,b)
 = new Blat()

Thunk ::=
 T:t Thunk:c T:u = new Thunk(t, c, u);
 B:b Thunk:c A:a = new Thunk(b, c, a);
 A:a Thunk:c B:b = new Thunk(a, c, b);
 W:w = new Thunk(w);

Chunk ::=
 T:t Chunk:c T:u = new Chunk(t, c, u);
 B:b Chunk:c B:d = new Chunk(b, c, d);
 A:a Chunk:c A:b = new Chunk(a, c, b);
 W:w = new Chunk(w);

T ::=
 "T":t = new T(t);

B ::=
 "B":b = new B(b);

A ::=
 "A":a = new A(a);

W ::=
 "W" = new W();
*/

import std.stdio;



void main()
{
 char[] str = "W*TWT*W@BAWBA!BBWAA!W@W".dup;
 auto ret = Parse_Code(str);
 if(ret is null)
  writef("false");
 else
  ret().val.dmp();
 writef(\n);
}


/********** some utils ****/

class Type{}
class TypeT(T)
{
 public T val;
 this(T v){val = v;}
}
alias Type delegate() ret_;

bool Peak(T)(inout T[] from, T[] match)
{
 if(from.length >= match.length && from[0..match.length] == match)
 {
  from = from[match.length..$];
  return true;
 }
 return false;
}


/*
Code ::=
 BlatA:b "@" Code:c = new Code(b,c)
 BlatA:b = new Code(b)
*/
alias TypeT!(Code) delegate() ret_Code;
ret_Code Parse_Code(inout char[] from)
{
 char[] data;


 data = from;
 if(auto b = Parse_BlatA(data))
 if(Peak!(char)(data, "@"))
 if(auto c = Parse_Code(data))
 {
  from = data;
  auto ret = new class
  {
   ret_BlatA dg_b;
   ret_Code dg_c;

   TypeT!(Code) action()
   {
    auto b = dg_b().val;
    auto c = dg_c().val;
    return new TypeT!(Code)(new Code(b,c));
   }
  };

  ret.dg_b = b;
  ret.dg_c = c;

  return &ret.action;
 }

 data = from;
 if(auto b = Parse_BlatA(data))
 {
  from = data;
  auto ret = new class
  {
   ret_BlatA dg_b;

   TypeT!(Code) action()
   {
    auto b = dg_b().val;
    return new TypeT!(Code)(new Code(b));
   }
  };

  ret.dg_b = b;

  return &ret.action;
 }


 return null;
}

/*
BlatA ::=
 Thunk:t Blat:b = new BlatA(t,b)
*/
alias TypeT!(BlatA) delegate() ret_BlatA;
ret_BlatA Parse_BlatA(inout char[] from)
{
 char[] data;


 data = from;
 if(auto t = Parse_Thunk(data))
 if(auto b = Parse_Blat(data))
 {
  from = data;
  auto ret = new class
  {
   ret_Thunk dg_t;
   ret_Blat dg_b;

   TypeT!(BlatA) action()
   {
    auto t = dg_t().val;
    auto b = dg_b().val;
    return new TypeT!(BlatA)(new BlatA(t,b));
   }
  };

  ret.dg_t = t;
  ret.dg_b = b;

  return &ret.action;
 }
 return null;
}


/*
Blat ::=
 "!" Thunk:t Blat:b = new Blat(t,b)
 "*" Chunk:c Blat:b = new Blat(c,b)
 = new Blat()
*/
alias TypeT!(Blat) delegate() ret_Blat;
ret_Blat Parse_Blat(inout char[] from)
{
 char[] data;


 data = from;
 if(Peak!(char)(data, "!"))
 if(auto t = Parse_Thunk(data))
 if(auto b = Parse_Blat(data))
 {
  from = data;
  auto ret = new class
  {
   ret_Thunk dg_t;
   ret_Blat dg_b;

   TypeT!(Blat) action()
   {
    auto t = dg_t().val;
    auto b = dg_b().val;
    return new TypeT!(Blat)(new Blat(t, b));
   }
  };

  ret.dg_t = t;
  ret.dg_b = b;

  return &ret.action;
 }

 data = from;
 if(Peak!(char)(data, "*"))
 if(auto c = Parse_Chunk(data))
 if(auto b = Parse_Blat(data))
 {
  from = data;
  auto ret = new class
  {
   ret_Chunk dg_c;
   ret_Blat dg_b;

   TypeT!(Blat) action()
   {
    auto c = dg_c().val;
    auto b = dg_b().val;
    return new TypeT!(Blat)(new Blat(c, b));
   }
  };

  ret.dg_c = c;
  ret.dg_b = b;

  return &ret.action;
 }

 data = from;
 if(true)
 {
  from = data;
  auto ret = new class
  {

   TypeT!(Blat) action()
   {
    return new TypeT!(Blat)(new Blat());
   }
  };


  return &ret.action;
 }


 return null;
}


/*
Thunk ::=
 T:t Thunk:c T:u = new Thunk(t, c, u);
 B:b Thunk:c A:a = new Thunk(b, c, a);
 A:a Thunk:c B:b = new Thunk(a, c, b);
 W:w = new Thunk(w);
*/

alias TypeT!(Thunk) delegate() ret_Thunk;
ret_Thunk Parse_Thunk(inout char[] from)
{
 char[] data;

 data = from;
 if(auto t = Parse_T(data))
 if(auto c = Parse_Thunk(data))
 if(auto u = Parse_T(data))
 {
  from = data;
  auto ret = new class
  {
   ret_T dg_t;
   ret_Thunk dg_c;
   ret_T dg_u;

   TypeT!(Thunk) action()
   {
    auto t = dg_t().val;
    auto c = dg_c().val;
    auto u = dg_u().val;
    return new TypeT!(Thunk)(new Thunk(t, c, u));
   }
  };

  ret.dg_t = t;
  ret.dg_c = c;
  ret.dg_u = u;

  return &ret.action;
 }

 data = from;
 if(auto b = Parse_B(data))
 if(auto c = Parse_Thunk(data))
 if(auto a = Parse_A(data))
 {
  from = data;
  auto ret = new class
  {
   ret_B dg_b;
   ret_Thunk dg_c;
   ret_A dg_a;

   TypeT!(Thunk) action()
   {
    auto b = dg_b().val;
    auto c = dg_c().val;
    auto a = dg_a().val;
    return new TypeT!(Thunk)(new Thunk(b, c, a));
   }
  };

  ret.dg_b = b;
  ret.dg_c = c;
  ret.dg_a = a;

  return &ret.action;
 }

 data = from;
 if(auto a = Parse_A(data))
 if(auto c = Parse_Thunk(data))
 if(auto b = Parse_B(data))
 {
  from = data;
  auto ret = new class
  {
   ret_A dg_a;
   ret_Thunk dg_c;
   ret_B dg_b;

   TypeT!(Thunk) action()
   {
    auto a = dg_a().val;
    auto c = dg_c().val;
    auto b = dg_b().val;
    return new TypeT!(Thunk)(new Thunk(a, c, b));
   }
  };

  ret.dg_a = a;
  ret.dg_c = c;
  ret.dg_b = b;

  return &ret.action;
 }

 data = from;

 if(auto w = Parse_W(data))
 {
  from = data;
  auto ret = new class
  {
   ret_W dg_w;

   TypeT!(Thunk) action()
   {
    auto w = dg_w().val;
    return new TypeT!(Thunk)(new Thunk(w));
   }
  };

  ret.dg_w = w;

  return &ret.action;
 }

 return null;
}

/*
Chunk ::=
 T:t Chunk:c T:u = new Chunk(t, c, u);
 B:b Chunk:c B:d = new Chunk(b, c, d);
 A:a Chunk:c A:b = new Chunk(a, c, b);
 W:w = new Chunk(w);
*/

alias TypeT!(Chunk) delegate() ret_Chunk;
ret_Chunk Parse_Chunk(inout char[] from)
{
 char[] data;


 data = from;
 if(auto t = Parse_T(data))
 if(auto c = Parse_Chunk(data))
 if(auto u = Parse_T(data))
 {
  from = data;
  auto ret = new class
  {
   ret_T dg_t;
   ret_Chunk dg_c;
   ret_T dg_u;

   TypeT!(Chunk) action()
   {
    auto t = dg_t().val;
    auto c = dg_c().val;
    auto u = dg_u().val;
    return new TypeT!(Chunk)(new Chunk(t, c, u));
   }
  };

  ret.dg_t = t;
  ret.dg_c = c;
  ret.dg_u = u;

  return &ret.action;
 }

 data = from;
 if(auto b = Parse_B(data))
 if(auto c = Parse_Chunk(data))
 if(auto d = Parse_B(data))
 {
  from = data;
  auto ret = new class
  {
   ret_B dg_b;
   ret_Chunk dg_c;
   ret_B dg_d;

   TypeT!(Chunk) action()
   {
    auto b = dg_b().val;
    auto c = dg_c().val;
    auto d = dg_d().val;
    return new TypeT!(Chunk)(new Chunk(b, c, d));
   }
  };

  ret.dg_b = b;
  ret.dg_c = c;
  ret.dg_d = d;

  return &ret.action;
 }

 data = from;
 if(auto a = Parse_A(data))
 if(auto c = Parse_Chunk(data))
 if(auto b = Parse_A(data))
 {
  from = data;
  auto ret = new class
  {
   ret_A dg_a;
   ret_Chunk dg_c;
   ret_A dg_b;

   TypeT!(Chunk) action()
   {
    auto a = dg_a().val;
    auto c = dg_c().val;
    auto b = dg_b().val;
    return new TypeT!(Chunk)(new Chunk(a, c, b));
   }
  };

  ret.dg_a = a;
  ret.dg_c = c;
  ret.dg_b = b;

  return &ret.action;
 }

 data = from;
 if(auto w = Parse_W(data))
 {
  from = data;
  auto ret = new class
  {
   ret_W dg_w;

   TypeT!(Chunk) action()
   {
    auto w = dg_w().val;
    return new TypeT!(Chunk)(new Chunk(w));
   }
  };

  ret.dg_w = w;

  return &ret.action;
 }

 return null;
}




/*
T ::= "T":t = new T(t);
*/
alias TypeT!(T) delegate() ret_T;
ret_T Parse_T(inout char[] from)
{
 char[] data = from;
 if(Peak(data, "T"))
 {
  from = data;
  auto ret = new class
  {
   TypeT!(T) action()
   {
    return new TypeT!(T)(new T());
   }
  };
  return &ret.action;
 }
 return null;
}



/*
B ::= "B":b = new B(b);
*/
alias TypeT!(B) delegate() ret_B;
ret_B Parse_B(inout char[] from)
{
 char[] data = from;
 if(Peak(data, "B"))
 {
  from = data;
  auto ret = new class
  {
   TypeT!(B) action()
   {
    return new TypeT!(B)(new B());
   }
  };
  return &ret.action;
 }
 return null;
}

/*
A ::= "A":a = new A(a);
*/
alias TypeT!(A) delegate() ret_A;
ret_A Parse_A(inout char[] from)
{
 char[] data = from;
 if(Peak(data, "A"))
 {
  from = data;
  auto ret = new class
  {
   TypeT!(A) action()
   {
    return new TypeT!(A)(new A());
   }
  };
  return &ret.action;
 }
 return null;
}
/*
W ::= "W" = new W();
*/
alias TypeT!(W) delegate() ret_W;
ret_W Parse_W(inout char[] from)
{
 char[] data = from;
 if(Peak(data, "W"))
 {
  from = data;
  auto ret = new class
  {
   TypeT!(W) action()
   {
    return new TypeT!(W)(new W());
   }
  };
  return &ret.action;
 }
 return null;
}








/*********** stuff for actions   ********/

class Code
{
 BlatA bl;
 Code co;
 this(BlatA b){bl=b; co=null;}
 this(BlatA b, Code c){bl=b; co=c;}

 void dmp()
 {
  writef("Code(");
  bl.dmp();
  if(co !is null)
  {
   writef(" @ ");
   co.dmp;
  }
  writef(")");
 }
}

class BlatA
{
 Thunk th;
 Blat bl;
 this(Thunk t, Blat b){th=t;bl=b;}
 void dmp()
 {
  writef(" BlatA(");
  th.dmp();
  bl.dmp();
  writef(")");
 }
}

class Blat
{
 Thunk th;
 Chunk ch;
 Blat bl;
 this(){th=null;ch=null;bl=null;}
 this(Thunk t, Blat b){th=t;bl=b;ch=null;}
 this(Chunk c, Blat b){ch=c;bl=b;th=null;}

 void dmp()
 {
  if(bl is null) return;
  writef(" Blat(");
  if(th !is null)
  {
   writef("! ");
   th.dmp();
   bl.dmp();
  }
  else
  {
   writef("* ");
   ch.dmp();
   bl.dmp();
  }
  writef(")");

 }
}

class Thunk
{
 char f;
 Thunk th;
 this(T v, Thunk t, T u){th=t;f='T';}
 this(B b, Thunk t, A a){th=t;f='B';}
 this(A a, Thunk t, B b){th=t;f='A';}
 this(W w){th=null;f='W';}
 void dmp()
 {
  writef(" Thunk(");
  switch(f)
  {
   case 'W':
    W.dmp();
    break;
   case 'T':
    T.dmp();
    th.dmp();
    T.dmp();
    break;
   case 'B':
    B.dmp();
    th.dmp();
    A.dmp();
    break;
   case 'A':
    A.dmp();
    th.dmp();
    B.dmp();
    break;
  }
  writef(")");
 }
}

class Chunk
{
 char f;
 Chunk ch;
 this(T t, Chunk c, T u){ch=c;f='T';}
 this(B b, Chunk c, B d){ch=c;f='B';}
 this(A a, Chunk c, A b){ch=c;f='A';}
 this(W w){ch=null;f='W';}
 void dmp()
 {
  writef(" Chunk(");
  switch(f)
  {
   case 'W':
    W.dmp();
    break;
   case 'T':
    T.dmp();
    ch.dmp();
    T.dmp();
    break;
   case 'B':
    B.dmp();
    ch.dmp();
    B.dmp();
    break;
   case 'A':
    A.dmp();
    ch.dmp();
    A.dmp();
    break;
  }
  writef(")");
 }
}

class T
{
 this(){}
 static void dmp(){writef(" T ");}
}
class A
{
 this(){}
 static void dmp(){writef(" A ");}
}
class B
{
 this(){}
 static void dmp(){writef(" B ");}
}
class W
{
 this(){}
 static void dmp(){writef(" W ");}
}