www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Lazy variadic not working, any alternatives?

reply "Tofu Ninja" <emmons0 purdue.edu> writes:
So I was writing a simple parser and I wanted a functionality 
that was basically "try list of tokens in order and if any of 
them fail, rewind input".

I tried using a lazy variadic function:

bool tok_and(lazy bool[] terms ...)
{
	auto backup = getInputLocation();
	for(int i = 0; i < terms.length; i++)
	{
		if(terms[i] == false)
		{
			rewind(backup);
			return false;
		}
	}
	return true;
}

But this does not work because of BUG9110
https://issues.dlang.org/show_bug.cgi?id=9110

Any one have an idea how to achieve similar functionality without 
a bunch of boilerplate at the call site? The lazy version would 
have been nice because it would have allowed for:

if(tok_and(ident(), equal(), expression())) {...}
else if(tok_and(some(), other(), grammar())) {...}
else ...
May 25 2015
next sibling parent reply "Tofu Ninja" <emmons0 purdue.edu> writes:
On Tuesday, 26 May 2015 at 05:22:26 UTC, Tofu Ninja wrote:
Actually the code seems to compile on 2.067.1 but definitely does 
not work as expected.

Another example of Lazy variadic to show how it works...

void main(string[] args)
{
	test(a(), b(), c());
}

bool a()
{
	writeln("a");
	return true;
}

bool b()
{
	writeln("b");
	return true;
}

bool c()
{
	writeln("c");
	return true;
}

void test(lazy bool[] c...)
{
	for(int i = 0; i < c.length; i++)
	{
		writeln("iteration: ", i);
		if(c[i]) writeln("success");
	}
}

prints...

a
b
c
iteration: 0
a
b
c
success
a
b
c
iteration: 1
a
b
c
success
a
b
c
iteration: 2
a
b
c
success
a
b
c

Though because it still runs in order, maybe I can still make 
this work...
May 25 2015
parent reply "Tofu Ninja" <emmons0 purdue.edu> writes:
On Tuesday, 26 May 2015 at 05:43:59 UTC, Tofu Ninja wrote:
 On Tuesday, 26 May 2015 at 05:22:26 UTC, Tofu Ninja wrote:
 Actually the code seems to compile on 2.067.1 but definitely 
 does not work as expected.
 ...
I guess it stems from the fact that its "lazy (bool[])" Wish I could do "(lazy bool)[]"
May 25 2015
parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 5/25/15 11:53 PM, Tofu Ninja wrote:
 On Tuesday, 26 May 2015 at 05:43:59 UTC, Tofu Ninja wrote:
 On Tuesday, 26 May 2015 at 05:22:26 UTC, Tofu Ninja wrote:
 Actually the code seems to compile on 2.067.1 but definitely does not
 work as expected.
 ...
I guess it stems from the fact that its "lazy (bool[])" Wish I could do "(lazy bool)[]"
Lazy variadic functions are clearly defined here: http://dlang.org/function.html The correct way to do it is: bool tok_and(bool delegate()[] terms ...) -Steve
May 26 2015
prev sibling parent reply "John Colvin" <john.loughran.colvin gmail.com> writes:
On Tuesday, 26 May 2015 at 05:22:26 UTC, Tofu Ninja wrote:
 So I was writing a simple parser and I wanted a functionality 
 that was basically "try list of tokens in order and if any of 
 them fail, rewind input".

 I tried using a lazy variadic function:

 bool tok_and(lazy bool[] terms ...)
 {
 	auto backup = getInputLocation();
 	for(int i = 0; i < terms.length; i++)
 	{
 		if(terms[i] == false)
 		{
 			rewind(backup);
 			return false;
 		}
 	}
 	return true;
 }

 But this does not work because of BUG9110
 https://issues.dlang.org/show_bug.cgi?id=9110

 Any one have an idea how to achieve similar functionality 
 without a bunch of boilerplate at the call site? The lazy 
 version would have been nice because it would have allowed for:

 if(tok_and(ident(), equal(), expression())) {...}
 else if(tok_and(some(), other(), grammar())) {...}
 else ...
Something like this appears to work: import std.typetuple : allSatisfy; enum implicityConvertibleToBool(T) = is(T : bool); bool tok_and(Args...)(lazy Args terms) if(allSatisfy!(implicitlyConvertibleToBool, Args)) { auto backup = getInputLocation(); foreach(term; terms) { if(term == false) { rewind(backup); return false; } } return true; }
May 25 2015
parent reply "Tofu Ninja" <emmons0 purdue.edu> writes:
On Tuesday, 26 May 2015 at 05:54:11 UTC, John Colvin wrote:
 Something like this appears to work:

 import std.typetuple : allSatisfy;

 enum implicityConvertibleToBool(T) = is(T : bool);

 bool tok_and(Args...)(lazy Args terms)
 if(allSatisfy!(implicitlyConvertibleToBool, Args))
 {
 	auto backup = getInputLocation();
 	foreach(term; terms)
 	{
 		if(term == false)
 		{
 			rewind(backup);
 			return false;
 		}
 	}
 	return true;
 }
Hmmm.... this does seem to work. Does this essentially expand out to tok_and(lazy bool arg1, lazy bool arg2, ...)?
May 25 2015
parent "John Colvin" <john.loughran.colvin gmail.com> writes:
On Tuesday, 26 May 2015 at 06:04:59 UTC, Tofu Ninja wrote:
 On Tuesday, 26 May 2015 at 05:54:11 UTC, John Colvin wrote:
 Something like this appears to work:

 import std.typetuple : allSatisfy;

 enum implicityConvertibleToBool(T) = is(T : bool);

 bool tok_and(Args...)(lazy Args terms)
 if(allSatisfy!(implicitlyConvertibleToBool, Args))
 {
 	auto backup = getInputLocation();
 	foreach(term; terms)
 	{
 		if(term == false)
 		{
 			rewind(backup);
 			return false;
 		}
 	}
 	return true;
 }
Hmmm.... this does seem to work. Does this essentially expand out to tok_and(lazy bool arg1, lazy bool arg2, ...)?
Apparently yes, which surprised me. Storage classes and TypeTuples (or Arguments, as they are now) are a bit of a dark corner. E.g. void foo(ref int, ref int); alias A(T...) = T; static assert(is(ParameterTypeTuple!foo == A!(ParameterTypeTuple!foo))); That fails.
May 26 2015