www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Create mixins from a list of strings

reply "Casper =?UTF-8?B?RsOmcmdlbWFuZCI=?= <shorttail hotmail.com> writes:
Have:
enum (or is immutable array better?) array = ["derp", "lala"];

Want:
mixin("some syntax" ~ array[0]);
mixin("some syntax" ~ array[1]);

Basically, to specify a number of similar functions based on a 
list of strings.
Why? Pegged's semantic actions allows only calling a function by 
name, not specifying parameters. I could probably ask for an 
extension, but if there's a cool template or whatever way to do 
this, it would be a lot nicer. :3
Jan 10 2014
parent reply "Jakob Ovrum" <jakobovrum gmail.com> writes:
On Saturday, 11 January 2014 at 07:45:31 UTC, Casper Færgemand 
wrote:
 Have:
 enum (or is immutable array better?) array = ["derp", "lala"];

 Want:
 mixin("some syntax" ~ array[0]);
 mixin("some syntax" ~ array[1]);
You can use template argument lists for indexable compile-time lists: --- import std.typetuple : TypeTuple; alias array = TypeTuple!("derp", "lala"); mixin("some syntax" ~ array[0]); mixin("some syntax" ~ array[1]); ---
 Basically, to specify a number of similar functions based on a 
 list of strings.
 Why? Pegged's semantic actions allows only calling a function 
 by name, not specifying parameters. I could probably ask for an 
 extension, but if there's a cool template or whatever way to do 
 this, it would be a lot nicer. :3
Your problem is probably better solved without string mixins, but we'd probably need to see some code or more elaboration to accurately suggest a solution.
Jan 10 2014
parent reply "Casper =?UTF-8?B?RsOmcmdlbWFuZCI=?= <shorttail hotmail.com> writes:
On Saturday, 11 January 2014 at 07:50:51 UTC, Jakob Ovrum wrote:
 Your problem is probably better solved without string mixins, 
 but we'd probably need to see some code or more elaboration to 
 accurately suggest a solution.
enum semanticArray = ["test"]; mixin(`T ` ~ semanticArray[0] ~ `(T)(T t) { t.name ~= "` ~ semanticArray[0] ~ `"; return t; }`); This will mixin a single templated function named "test", which changes an AST node's name to whatever it was concatenated with "test". I want this to happen automatically for any length of semanticArray.
Jan 11 2014
next sibling parent reply Philippe Sigaud <philippe.sigaud gmail.com> writes:
Maybe you could use just one name and put the dispatching code inside it?

T actor(T)(T t)
{
    switch (t.name)
    {
        case "Gramm.Expr":
            return foo(t);
        case "Gramm.FunctionCall":
            return foo(t);
        case "Gramm.Declaration":
            return foo(t);
        default:
            throw new Exception("...");
    }
}

or do it with a template, holding function names as aliases:

alias actor = dispatcher!(foo, bar, baz);
Jan 11 2014
parent reply "Casper =?UTF-8?B?RsOmcmdlbWFuZCI=?= <shorttail hotmail.com> writes:
On Saturday, 11 January 2014 at 09:17:34 UTC, Philippe Sigaud 
wrote:
         case "Gramm.Expr":
             return foo(t);
         case "Gramm.FunctionCall":
             return foo(t);
         case "Gramm.Declaration":
             return foo(t);
         default:
             throw new Exception("...");
I can't do this since there will be multiple rules with the same name that require different treatment. The reason I want to use semantic actions is that I don't want to push an already heavy grammar into double or triple size just to name specific rules in a certain way. Semantic actions take up very little space and fit nicely into the syntax.
 or do it with a template, holding function names as aliases:

 alias actor = dispatcher!(foo, bar, baz);
I have no idea what you mean. :D
Jan 11 2014
next sibling parent reply Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Sat, Jan 11, 2014 at 2:34 PM,  <"Casper Færgemand\"
<shorttail hotmail.com>" puremagic.com> wrote:
 On Saturday, 11 January 2014 at 09:17:34 UTC, Philippe Sigaud wrote:
         case "Gramm.Expr":
             return foo(t);
         case "Gramm.FunctionCall":
             return foo(t);
         case "Gramm.Declaration":
             return foo(t);
         default:
             throw new Exception("...");
I can't do this since there will be multiple rules with the same name that require different treatment. The reason I want to use semantic actions is that I don't want to push an already heavy grammar into double or triple size just to name specific rules in a certain way. Semantic actions take up very little space and fit nicely into the syntax.
OK, fair enough. I'm a bit leery of putting D call syntax into semantic actions, because it'll also explode the Pegged grammar size (I'm fairly sure I'd have to pull in a big part of D if I want to get function calls right). That's one feature I wanted at one time, but I'm not sure it's a good idea. OTOH, you can define a templated semantic action: template foo(string s, int i) { T foo(T)(T t) { writeln("Calling foo"); t.name ~= s ~ to!string(i); return t; } } And then invoke it with a parameter: mixin(grammar(` Test: A <- B { foo!("abc",1) } C { foo!("def",2) } B <- 'b' C <- 'c' `)); I did not test it thoroughly, so I'm not sure every template parameter combination is OK. It's probably better not to have curly braces inside the arg list. Pegged also authorize anonymous functions as semantic actions: https://github.com/PhilippeSigaud/Pegged/wiki/Semantic-Actions#anonymous-functions-as-actions Maybe that could be another solution. Something like B { p => foo(arg1, p) } Note that closures are not (yet) supported in CTFE, because else another solution would be a function-returning function: auto bar(string s, int i) { return (ParseTree p) { p.name ~= s ~ to!string(i); return p; }; }
Jan 11 2014
parent "Casper =?UTF-8?B?RsOmcmdlbWFuZCI=?= <shorttail hotmail.com> writes:
On Saturday, 11 January 2014 at 16:07:30 UTC, Philippe Sigaud 
wrote:
 I'm a bit leery of putting D call syntax into semantic actions,
 because it'll also explode the Pegged grammar size (I'm fairly 
 sure
 I'd have to pull in a big part of D if I want to get function 
 calls
 right). That's one feature I wanted at one time, but I'm not 
 sure it's
 a good idea.
Yes, and I would not be able to argue this is the definite way to handle things anyway. It's a try at type checking with little regard to efficiency. I'm just happy it works with Timon Gehr's extremely simple solution. :3 On Saturday, 11 January 2014 at 20:52:15 UTC, Timon Gehr wrote:
 import std.string, std.algorithm;

 enum semanticArray = ["derp", "lala"];

 mixin(semanticArray.map!(a=>`T `~a~`(T)(T t) {
     t.name ~= "`~a~`";
     return t;
 }`).join());
Here, have a heart. <3
Jan 11 2014
prev sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
 Note that closures are not (yet) supported in CTFE, because else
 another solution would be a function-returning function:

 auto bar(string s, int i)
 {
     return
         (ParseTree p) {
             p.name ~= s ~ to!string(i);
             return p;
         };
 }
Duh, instead of closures, you can use opCall-ed structs: import pegged.grammar; auto foo(string s, int i) { return Foo(s,i); } struct Foo { string s; int i; this(string s, int i) { this.s = s; this.i = i;} ParseTree opCall(ParseTree p) { p.name ~= s ~ to!string(i); return p; } } mixin(grammar(` Test: A <- B { foo("abc",1) } C { foo("def",2) } B <- 'b' C <- 'c' `)); void main() { enum result = Test("bc"); // Compile-time parsing is still possible pragma(msg, result); writeln(result); }
Jan 11 2014
prev sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 01/11/2014 09:35 AM, "Casper Færgemand" <shorttail hotmail.com>" wrote:
 On Saturday, 11 January 2014 at 07:50:51 UTC, Jakob Ovrum wrote:
 Your problem is probably better solved without string mixins, but we'd
 probably need to see some code or more elaboration to accurately
 suggest a solution.
enum semanticArray = ["test"]; mixin(`T ` ~ semanticArray[0] ~ `(T)(T t) { t.name ~= "` ~ semanticArray[0] ~ `"; return t; }`); This will mixin a single templated function named "test", which changes an AST node's name to whatever it was concatenated with "test". I want this to happen automatically for any length of semanticArray.
import std.string, std.algorithm; enum semanticArray = ["derp", "lala"]; mixin(semanticArray.map!(a=>`T `~a~`(T)(T t) { t.name ~= "`~a~`"; return t; }`).join());
Jan 11 2014