www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - UDA + Pegged AST Hack

reply "Daniel N" <ufo orbiting.us> writes:
Thanks to the wonderful UDA implementation in 2.061, I thought of 
a little hack, which may interest at least someone.

I'm using it for prototyping ctfe ast transformations together 
with: https://github.com/PhilippeSigaud/Pegged

Yes, it was possible to do similar stuff before and 
"examples/dgrammar.d" from Pegged is quite impressive, but not 
bug free.

This UDA-line-hack-way is actually significantly cleaner, because 
when using __LINE__ you are certain that there will be at least 
one [__LINE__] which is not inside a string or comment on the 
attributed line... this allows one to make a very limited 
grammar/parser which doesn't have to know/parse/understand the 
entire file.

I know my proof-of-concept doesn't handle multi-line, but it can 
be added, and doesn't matter for the sake of prototyping AST 
manipulations.

If anyone else have fun UDA hacks, considering that it's a new 
feature, please share.

import std.string;
import std.range;

struct magic
{
   [__LINE__] int var1;
   [__LINE__] int var2;
   [__LINE__] int var3;
}

enum dsrc = import(__FILE__).splitLines(KeepTerminator.yes);

string parse()
{
   string result = "";

   foreach(m; __traits(allMembers, magic))
     result ~= dsrc.drop(__traits(getAttributes, mixin("magic." ~ 
m))[0]-1).takeOne().front;

   // insert pegged parsing / transformations here.

   return result;
}

mixin("struct magic2\n{\n" ~ parse() ~"}");
Nov 28 2012
next sibling parent reply "Robik" <szadows gmail.com> writes:
On Wednesday, 28 November 2012 at 21:40:35 UTC, Daniel N wrote:
 Thanks to the wonderful UDA implementation in 2.061, I thought 
 of a little hack, which may interest at least someone.

 I'm using it for prototyping ctfe ast transformations together 
 with: https://github.com/PhilippeSigaud/Pegged

 Yes, it was possible to do similar stuff before and 
 "examples/dgrammar.d" from Pegged is quite impressive, but not 
 bug free.

 This UDA-line-hack-way is actually significantly cleaner, 
 because when using __LINE__ you are certain that there will be 
 at least one [__LINE__] which is not inside a string or comment 
 on the attributed line... this allows one to make a very 
 limited grammar/parser which doesn't have to 
 know/parse/understand the entire file.

 I know my proof-of-concept doesn't handle multi-line, but it 
 can be added, and doesn't matter for the sake of prototyping 
 AST manipulations.

 If anyone else have fun UDA hacks, considering that it's a new 
 feature, please share.

 import std.string;
 import std.range;

 struct magic
 {
   [__LINE__] int var1;
   [__LINE__] int var2;
   [__LINE__] int var3;
 }

 enum dsrc = import(__FILE__).splitLines(KeepTerminator.yes);

 string parse()
 {
   string result = "";

   foreach(m; __traits(allMembers, magic))
     result ~= dsrc.drop(__traits(getAttributes, mixin("magic." 
 ~ m))[0]-1).takeOne().front;

   // insert pegged parsing / transformations here.

   return result;
 }

 mixin("struct magic2\n{\n" ~ parse() ~"}");
I made two, but not as cool as yours: http://dpaste.dzfl.pl/32536704 http://dpaste.dzfl.pl/15e4591b
Nov 28 2012
next sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
 I made two, but not as cool as yours: http://dpaste.dzfl.pl/32536704
I like this one :) I think this part: static T readArgs(T)(string[] args) { T ret; pragma(msg, "getopt(args"~buildGetOptArguments!(T, "ret")~");"); mixin("getopt(args"~buildGetOptArguments!(T, "ret")~");"); return ret; } Could be slightly simplified somewhat. Try passing 'ret' as an alias. That way, buildGetOptArguments should be able to create the "ret" string by itself, like this: private static string buildGetOptArguments(T, alias instance)() { enum string instanceName = instance.stringof; // for example ... And I'd have buildGetOptArguments return the "getopt(args" ... ")" part also. Which gives: T readArgs(T)(string[] args) { T ret; pragma(msg, buildGetOptArguments!(T, ret)); mixin(buildGetOptArguments!(T, ret)~";"); return ret; }
Nov 28 2012
prev sibling parent "Daniel N" <ufo orbiting.us> writes:
On Wednesday, 28 November 2012 at 21:43:40 UTC, Robik wrote:
 I made two, but not as cool as yours: 
 http://dpaste.dzfl.pl/32536704 http://dpaste.dzfl.pl/15e4591b
awesome, this is really nice inspiration too, thanks! :)
Nov 29 2012
prev sibling next sibling parent reply Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Wed, Nov 28, 2012 at 10:40 PM, Daniel N <ufo orbiting.us> wrote:

 Thanks to the wonderful UDA implementation in 2.061, I thought of a little
 hack, which may interest at least someone.

 I'm using it for prototyping ctfe ast transformations together with:
 https://github.com/**PhilippeSigaud/Pegged<https://github.com/PhilippeSigaud/Pegged>
Aha!
 Yes, it was possible to do similar stuff before and "examples/dgrammar.d"
 from Pegged is quite impressive, but not bug free.
No kidding :) I've a few contributors who're helping me stabilize / make the engine better. We will tackle the D grammar afterwards. It does make a good testing ground for when I want to push the CTFE throttle.
 This UDA-line-hack-way is actually significantly cleaner, because when
 using __LINE__ you are certain that there will be at least one [__LINE__]
 which is not inside a string or comment on the attributed line... this
 allows one to make a very limited grammar/parser which doesn't have to
 know/parse/understand the entire file.
I don't understand what you're trying to do. Could you please explain it a bit more? UDA's a quite new and I'd be very interested in their interaction with compile-time code manipulation.
 If anyone else have fun UDA hacks, considering that it's a new feature,
 please share.

 import std.string;
 import std.range;

 struct magic
 {
   [__LINE__] int var1;
   [__LINE__] int var2;
   [__LINE__] int var3;
 }

 enum dsrc = import(__FILE__).splitLines(**KeepTerminator.yes);

 string parse()
 {
   string result = "";

   foreach(m; __traits(allMembers, magic))
     result ~= dsrc.drop(__traits(**getAttributes, mixin("magic." ~
 m))[0]-1).takeOne().front;
What I don't get is how the [__LINE__] part in magic contains significant info.
Nov 28 2012
parent reply "Daniel N" <ufo orbiting.us> writes:
On Wednesday, 28 November 2012 at 22:04:14 UTC, Philippe Sigaud 
wrote:
 I don't understand what you're trying to do. Could you please 
 explain it a
 bit more? UDA's a quite new and I'd be very interested in their 
 interaction
 with compile-time code manipulation.
I'm trying to find a safe spot in the middle of a file, where I can start parsing, normally you have to parse the entire file to understand it, ex with your grammar files, there are many keywords inside huge strings, so basically I let the compiler handle comments and white-space parsing, which allows to me to make a stable localized parser for a subset of the language.
 What I don't get is how the [__LINE__] part in magic contains 
 significant
 info.
It allows me to retrieve the entire original source for a declaration... it kinda emulates a ".sourceof" trait / property. :)
Nov 29 2012
parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
 I'm trying to find a safe spot in the middle of a file, where I can start
 parsing, normally you have to parse the entire file to understand it, ex
 with your grammar files, there are many keywords inside huge strings, so
 basically I let the compiler handle comments and white-space parsing, which
 allows to me to make a stable localized parser for a subset of the language.
OK, this I get.
  What I don't get is how the [__LINE__] part in magic contains significant
 info.
It allows me to retrieve the entire original source for a declaration... it kinda emulates a ".sourceof" trait / property. :)
Yeah but... What does this have to do with __LINE__? I'm sorry if I'm dumb here, I still haven't used UDAs.
Nov 29 2012
prev sibling parent reply "deadalnix" <deadalnix gmail.com> writes:
On Wednesday, 28 November 2012 at 21:40:35 UTC, Daniel N wrote:
 Thanks to the wonderful UDA implementation in 2.061, I thought 
 of a little hack, which may interest at least someone.

 I'm using it for prototyping ctfe ast transformations together 
 with: https://github.com/PhilippeSigaud/Pegged

 Yes, it was possible to do similar stuff before and 
 "examples/dgrammar.d" from Pegged is quite impressive, but not 
 bug free.

 This UDA-line-hack-way is actually significantly cleaner, 
 because when using __LINE__ you are certain that there will be 
 at least one [__LINE__] which is not inside a string or comment 
 on the attributed line... this allows one to make a very 
 limited grammar/parser which doesn't have to 
 know/parse/understand the entire file.

 I know my proof-of-concept doesn't handle multi-line, but it 
 can be added, and doesn't matter for the sake of prototyping 
 AST manipulations.

 If anyone else have fun UDA hacks, considering that it's a new 
 feature, please share.

 import std.string;
 import std.range;

 struct magic
 {
   [__LINE__] int var1;
   [__LINE__] int var2;
   [__LINE__] int var3;
 }

 enum dsrc = import(__FILE__).splitLines(KeepTerminator.yes);

 string parse()
 {
   string result = "";

   foreach(m; __traits(allMembers, magic))
     result ~= dsrc.drop(__traits(getAttributes, mixin("magic." 
 ~ m))[0]-1).takeOne().front;

   // insert pegged parsing / transformations here.

   return result;
 }

 mixin("struct magic2\n{\n" ~ parse() ~"}");
Here we go, annotation with strings. The feature is not even out that its quirks already shows up. You take the least resistance path, and this is comprehensible, but anotationg with a string is known to be a bad idea. It have been mentionned in UDA and what you did here is the perfect example : when the least resistance path is something plain wrong, people will do it anyway. Can someone remember me why this ended up in master ? This feature is clearly not ready.
Nov 28 2012
next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2012-11-29 01:16, deadalnix wrote:

 Can someone remember me why this ended up in master ? This feature is
 clearly not ready.
Because that's what Walter do, committing new features to the master branch willy nilly. -- /Jacob Carlborg
Nov 28 2012
parent reply "Max Samukha" <maxsamukha gmail.com> writes:
On Thursday, 29 November 2012 at 07:37:31 UTC, Jacob Carlborg 
wrote:
 On 2012-11-29 01:16, deadalnix wrote:

 Can someone remember me why this ended up in master ? This 
 feature is
 clearly not ready.
Because that's what Walter do, committing new features to the master branch willy nilly.
I want to remind you that there is still no consensus about whether unconstrained attributes are good or bad.
Nov 29 2012
next sibling parent "Daniel N" <ufo orbiting.us> writes:
On Thursday, 29 November 2012 at 09:56:29 UTC, Max Samukha wrote:
 On Thursday, 29 November 2012 at 07:37:31 UTC, Jacob Carlborg 
 wrote:
 On 2012-11-29 01:16, deadalnix wrote:

 Can someone remember me why this ended up in master ? This 
 feature is
 clearly not ready.
Because that's what Walter do, committing new features to the master branch willy nilly.
I want to remind you that there is still no consensus about whether unconstrained attributes are good or bad.
Furthermore I intentionally used __LINE__ (int), as an optimization, among other things; it results in reduced memory consumption during CTFE. In my case I only intend to use the magic type inside the same source file to generate another type(magic2) which I then will expose externally, thus it's perfectly safe. Magic will be discarded and never escape, nor be used for anything.
Nov 29 2012
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2012-11-29 10:56, Max Samukha wrote:

 I want to remind you that there is still no consensus about whether
 unconstrained attributes are good or bad.
That's why it's not good to have it in master, the whole feature. -- /Jacob Carlborg
Nov 29 2012
prev sibling parent "Rob T" <rob ucora.com> writes:
On Thursday, 29 November 2012 at 00:16:28 UTC, deadalnix wrote:
 Can someone remember me why this ended up in master ? This 
 feature is clearly not ready.
Please, read this thread, esp towards the end. "Breaking D2 language/spec changes with D1 being discontinued in a month" The current lack of a sane development and release process is messing up a lot of people like myself. I cannot take D seriously for commercial usage if I cannot rely on at least 3 versions of the compiler. We need one for stable, another for testing/release candidate (these two I would rely on), and a 3rd for adding in new stuff for the compiler + lib devs. However there probably should be a forth "experimental" branch for people like Walter who perform experimental work, such as the spontaneous introduction of UDA's. Debian follows a similar system, and is a clear real-world example of a very good development and release process. Currently, I'm concluding that I simply cannot rely on D for anything but experimental tinkering, which means back to C++ for the commercial work that I do for a living, and that's a real shame! D has a lot of potential, but it's being undermined by a willy-nilly process, which honestly speaking boils down to decisions being made by the current management at the helm. --rt
Nov 29 2012