www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - A feture adjustment request and a syntax blasphemy

reply BCS <BCS pathlink.com> writes:
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




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
Oct 27 2006
next sibling parent reply Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
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
 


 
 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
Oct 27 2006
parent BCS <nobody pathlink.com> writes:
== 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...
Oct 28 2006
prev sibling next sibling parent David Medlock <noone nowhere.com> writes:
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
Oct 28 2006
prev sibling next sibling parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"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(); ?
Oct 29 2006
parent BCS <nobody pathlink.com> writes:
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.
Oct 29 2006
prev sibling parent BCS <BCS pathlink.com> writes:
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 ");} }
Oct 30 2006