digitalmars.D - Will macros just be syntactic sugar?
- Don Clugston (41/41) Apr 25 2007 A couple of weeks ago, I posted an implementation of BLAS1-style vector
- Davidl (19/60) Apr 25 2007 numerle's macro is somewhat worth consideration
- Davidl (40/100) Apr 25 2007 macro (Token... tokens)
- Davidl (31/60) Apr 25 2007 macro macroname(Token... tokens)
- Don Clugston (7/21) Apr 25 2007 I don't think that's much nicer than
- Davidl (6/25) Apr 25 2007 how to emit a error message by CTFE if arg0 is not an
- Don Clugston (8/13) Apr 25 2007 assert(isIdentifier(arg[0]), "Identifier expected");
- Davidl (3/16) Apr 25 2007 heh, mixin an assert is bad, compile time is even longer :p
- Don Clugston (92/95) Apr 25 2007 No. It's nowhere near clean enough yet. The code below, works right now.
- Davidl (7/7) Apr 25 2007 Nice work!
- Don Clugston (26/34) Apr 25 2007 Yes. I think that's the key improvement to make.
- =?UTF-8?B?SmFyaS1NYXR0aSBNw6RrZWzDpA==?= (7/16) Apr 25 2007 D being a multiparadigm language, it's a bit funny how many 'native'
- Manfred Nowak (4/5) Apr 25 2007 Yeah. Are you able to eliminate switch-statements out of some code and
- Charlie (12/125) Apr 25 2007 I agree, the CTFE & mixins have really put D over the top, and this is
- Davidl (20/112) Apr 25 2007 sorry for typos in the error message :o
- =?UTF-8?B?SmFyaS1NYXR0aSBNw6RrZWzDpA==?= (3/33) Apr 25 2007 Huh, that looks awful. This kind of code surely needs some pattern
- Davidl (14/74) Apr 25 2007 oh noes, why posted so many times.... coz they are too important? :p
A couple of weeks ago, I posted an implementation of BLAS1-style vector expressions, that used tuples and expression templates to generate near-optimal asm code in many circumstances. Unfortunately, when I've looked at the code that is generated, there's a *hideous* amount of stack shuffling -- it is too difficult for the compiler to optimise all the tuple operations away. So I came up with this alternative, which gives _many_ more optimisation opportunities, and doesn't require you to wrap arrays of built-in types. float [] vec1 = [43, 5445, 547, 465]; auto vec2 = [1.24, 765, 6756, 23.143]; mixin(vectorize("vec2+=vec1*3.3254")); This actually works. There are some awesome side effects -- eg, any error messages in the library code appear on the line of user code. You can determine which of the variables are compile-time constants (and optimise the generated code based on the value of those constants). You can get the compiler to do _most_ of the heavy lifting (eg, convert floating point strings <--> const real). As far as I can tell, *all* of the proposed 'macro' functionality can be done already using mixins and CTFE. It looks as though the power of macros will be a subset of the power of mixins. This means that macros can be explored quite thoroughly *before* deciding on the cleanest syntax for them. Today: --------- char [] magic(char [] args) { return "stuff-to-mix-in"; } : mixin(magic("a+=b*c")); : ----------- With macros: macro magic(args) { stuff-to-mix-in } : magic(a+=b*c); : ------------
Apr 25 2007
numerle's macro is somewhat worth consideration an improved syntax should be something like: macro macroname(arg0,arg1,arg2,arg3) syntax realname(arg0)[arg1] :=3D arg2 +arg3 { arg0[arg1] =3D arg2+arg3; } and calling style would be realname(a)[i] :=3D j + k; // which would cal= l = macro macroname(a,i,j,k)A couple of weeks ago, I posted an implementation of BLAS1-style vecto=r =expressions, that used tuples and expression templates to generate =near-optimal asm code in many circumstances. Unfortunately, when I've ==looked at the code that is generated, there's a *hideous* amount of =stack shuffling -- it is too difficult for the compiler to optimise al=l =the tuple operations away. So I came up with this alternative, which gives _many_ more optimisati=on =opportunities, and doesn't require you to wrap arrays of built-in type=s.float [] vec1 =3D [43, 5445, 547, 465]; auto vec2 =3D [1.24, 765, 6756, 23.143]; mixin(vectorize("vec2+=3Dvec1*3.3254")); This actually works. There are some awesome side effects -- eg, any =error messages in the library code appear on the line of user code. Yo=u =can determine which of the variables are compile-time constants (and =optimise the generated code based on the value of those constants). Yo=u =can get the compiler to do _most_ of the heavy lifting (eg, convert =floating point strings <--> const real). As far as I can tell, *all* of the proposed 'macro' functionality can =be =done already using mixins and CTFE. It looks as though the power of =macros will be a subset of the power of mixins. This means that macros==can be explored quite thoroughly *before* deciding on the cleanest =syntax for them. Today: --------- char [] magic(char [] args) { return "stuff-to-mix-in"; } : mixin(magic("a+=3Db*c")); : ----------- With macros: macro magic(args) { stuff-to-mix-in } : magic(a+=3Db*c); : ------------
Apr 25 2007
macro (Token... tokens) { static if (tokens[0].ID !=3D Token.LParen) pragma(error, `( expected`); else static if (tokens[1].ID !=3D Token.Identifier) pragma(error, `identifer expected`); else static if (tokens[2].ID !=3D Token.RParen) pragma(error, ) expected`); else static if (tokens[3].toChars !=3D `:=3D`) pragma(error, `:=3D expected`); static if (tokens[4].ID !=3D Token.LBracket) pragma(error, `( expected`); else static if (tokens[5].ID !=3D Token.Identifier) pragma(error, `identifer expected`); else static if (tokens[6].ID !=3D Token.RBracket) pragma(error, ) expected`); else static if (tokens[7].ID !=3D Token.Identifier) pragma(error, `identifer expected`); else static if (tokens[8].ID !=3D Token.plus) pragma(error, `+ operator expected`); else static if (tokens[9].ID !=3D Token.Identifier) pragma(error, `identifer expected`); alias token[1] arg0; alias token[5] arg1; alias token[7] arg2; alias token[9] arg3; arg0[arg1] =3D arg2 + arg3; } seems the above is more valuable.numerle's macro is somewhat worth consideration an improved syntax should be something like: macro macroname(arg0,arg1,arg2,arg3) syntax realname(arg0)[arg1] :=3D arg2 +arg3 { arg0[arg1] =3D arg2+arg3; } and calling style would be realname(a)[i] :=3D j + k; // which would c=all =macro macroname(a,i,j,k)or =A couple of weeks ago, I posted an implementation of BLAS1-style vect=expressions, that used tuples and expression templates to generate ==near-optimal asm code in many circumstances. Unfortunately, when I've=looked at the code that is generated, there's a *hideous* amount of =ll =stack shuffling -- it is too difficult for the compiler to optimise a=the tuple operations away. So I came up with this alternative, which gives _many_ more ==optimisation opportunities, and doesn't require you to wrap arrays of=built-in types. float [] vec1 =3D [43, 5445, 547, 465]; auto vec2 =3D [1.24, 765, 6756, 23.143]; mixin(vectorize("vec2+=3Dvec1*3.3254")); This actually works. There are some awesome side effects -- eg, any =ou =error messages in the library code appear on the line of user code. Y==can determine which of the variables are compile-time constants (and =ou =optimise the generated code based on the value of those constants). Y=can get the compiler to do _most_ of the heavy lifting (eg, convert ==floating point strings <--> const real). As far as I can tell, *all* of the proposed 'macro' functionality can=f =be done already using mixins and CTFE. It looks as though the power o=s =macros will be a subset of the power of mixins. This means that macro=can be explored quite thoroughly *before* deciding on the cleanest =syntax for them. Today: --------- char [] magic(char [] args) { return "stuff-to-mix-in"; } : mixin(magic("a+=3Db*c")); : ----------- With macros: macro magic(args) { stuff-to-mix-in } : magic(a+=3Db*c); : ------------
Apr 25 2007
macro macroname(Token... tokens) { static if (tokens[0].ID !=3D Token.LParen) pragma(error, `( expected`); else static if (tokens[1].ID !=3D Token.Identifier) pragma(error, `identifer expected`); else static if (tokens[2].ID !=3D Token.RParen) pragma(error, ) expected`); else static if (tokens[3].toChars !=3D `:=3D`) pragma(error, `:=3D expected`); static if (tokens[4].ID !=3D Token.LBracket) pragma(error, `( expected`); else static if (tokens[5].ID !=3D Token.Identifier) pragma(error, `identifer expected`); else static if (tokens[6].ID !=3D Token.RBracket) pragma(error, ) expected`); else static if (tokens[7].ID !=3D Token.Identifier) pragma(error, `identifer expected`); else static if (tokens[8].ID !=3D Token.plus) pragma(error, `+ operator expected`); else static if (tokens[9].ID !=3D Token.Identifier) pragma(error, `identifer expected`); alias token[1] arg0; alias token[5] arg1; alias token[7] arg2; alias token[9] arg3; arg0[arg1] =3D arg2 + arg3; } caller could call the macro with : macroname(arg0)[arg1] :=3D arg2 + arg3; macroname here is used for simplify the parsing.macro (Token... tokens) { static if (tokens[0].ID !=3D Token.LParen) pragma(error, `( expected`); else static if (tokens[1].ID !=3D Token.Identifier) pragma(error, `identifer expected`); else static if (tokens[2].ID !=3D Token.RParen) pragma(error, ) expected`); else static if (tokens[3].toChars !=3D `:=3D`) pragma(error, `:=3D expected`); static if (tokens[4].ID !=3D Token.LBracket) pragma(error, `( expected`); else static if (tokens[5].ID !=3D Token.Identifier) pragma(error, `identifer expected`); else static if (tokens[6].ID !=3D Token.RBracket) pragma(error, ) expected`); else static if (tokens[7].ID !=3D Token.Identifier) pragma(error, `identifer expected`); else static if (tokens[8].ID !=3D Token.plus) pragma(error, `+ operator expected`); else static if (tokens[9].ID !=3D Token.Identifier) pragma(error, `identifer expected`); alias token[1] arg0; alias token[5] arg1; alias token[7] arg2; alias token[9] arg3; arg0[arg1] =3D arg2 + arg3; } seems the above is more valuable.
Apr 25 2007
Davidl wrote:macro macroname(Token... tokens) { static if (tokens[0].ID != Token.LParen) pragma(error, `( expected`);:alias token[1] arg0; alias token[5] arg1; alias token[7] arg2; alias token[9] arg3; arg0[arg1] = arg2 + arg3; } caller could call the macro with : macroname(arg0)[arg1] := arg2 + arg3;I don't think that's much nicer than mixin(macroname("arg0[arg1]:= arg2+ arg3")); which works in DMD 1.012. The static if/Token properties can be done via a CTFE library. If structs were allowed in CTFE functions, the code wouldn't even be too ugly.
Apr 25 2007
how to emit a error message by CTFE if arg0 is not an identifier? and compiling that CTFE library would be pretty much slower compared to my version. And the advantage of macro is the frontend parser can help IDE for auto-completion.Davidl wrote:ia =macro macroname(Token... tokens) { static if (tokens[0].ID !=3D Token.LParen) pragma(error, `( expected`);:alias token[1] arg0; alias token[5] arg1; alias token[7] arg2; alias token[9] arg3; arg0[arg1] =3D arg2 + arg3; } caller could call the macro with : macroname(arg0)[arg1] :=3D arg2 + arg3;I don't think that's much nicer than mixin(macroname("arg0[arg1]:=3D arg2+ arg3")); which works in DMD 1.012. The static if/Token properties can be done v=a CTFE library. If structs were allowed in CTFE functions, the code =wouldn't even be too ugly.
Apr 25 2007
Davidl wrote:how to emit a error message by CTFE if arg0 is not an identifier?assert(isIdentifier(arg[0]), "Identifier expected"); The error message even indicates the line of user's code where the error occurs (doesn't refer to the line in the macro). and compiling that CTFE library would be prettymuch slower compared to my version.Yes, but the speed comes from Token; otherwise, they're pretty much the same.And the advantage of macro is the frontend parser can help IDE for auto-completion.Naturally.
Apr 25 2007
heh, mixin an assert is bad, compile time is even longer :p Though you are kinda sticking with CTFE & mixin , I'm pretty sure you would vote my syntax of macro for macro, right? :)Davidl wrote:how to emit a error message by CTFE if arg0 is not an identifier?assert(isIdentifier(arg[0]), "Identifier expected"); The error message even indicates the line of user's code where the error occurs (doesn't refer to the line in the macro). and compiling that CTFE library would be prettymuch slower compared to my version.Yes, but the speed comes from Token; otherwise, they're pretty much the same.And the advantage of macro is the frontend parser can help IDE for auto-completion.Naturally.
Apr 25 2007
Davidl wrote:heh, mixin an assert is bad, compile time is even longer :p?? It's no different to a static assert.Though you are kinda sticking with CTFE & mixin , I'm pretty sure you would vote my syntax of macro for macro, right? :)No. It's nowhere near clean enough yet. The code below, works right now. The challenge is to make it nicer. //-------------------------- // This is a macro library, defining a 'vectorize' macro. //-------------------------- module Blade; import ExpressionParser; //common code for any macros which use D syntax public import std.stdio; // CTFE macro: returns the code to be mixed in. // prints all symbols used in the expression char [] describe(char [] expr, char [][3][] symbols) { char [] result = "Expression:" ~ expr ~ "\nSYMBOL \tTYPE\t\tVALUE\n"; for (int i=0; i<symbols.length; ++i) { result ~= symbols[i][0] ~ " \t" ~ symbols[i][1] ~ " \t" ~ symbols[i][2] ~ \n; } return `printf("` ~ result ~ `");`; } // TO BE MIXED IN -- inserts the boilerplate code for parsing & type extraction, // then gets the macro text from the named function. char [] vectorize(char [] expr) { return expressionMacro("describe", expr); } //-------------------------- // And this is how the user sees it. //-------------------------- import Blade; void main() { auto a = [1.24, 5.35, 324, 2454]; double [] big = [3.44, 5565, 1.45, 67.1]; const yx=-2.354e-68Li; alias big c; mixin(vectorize("a +=yx *big -c")); } =============================== OUTPUT =============================== Expression:a +=yx *big -c SYMBOL TYPE VALUE a double[4] a yx ireal -2.354e-68i big double[] big c double[] big Note that the constant has been evaluated, and the aliases resolved. And if you change the last line to: mixin(vectorize("a +=yx *big -d")); you get: test.d(10): Error: undefined identifier d That happens automatically. Note that the line number is correct. That expressionMacro must be really horrible, right? Actually, no. It just makes use of some trivial identifier and operator parsing routines, and applies the .stringof property. ----------- // Given an expression string 'expr', make a string to mixin in, // which will have an array of 3 strings for each symbol in the // expression. [0]=symbol name, [1]=type, [2]=value char[] getAllIdentifiers(char [] expr) { char [] result; char [] rest; char [] a; char [] b; a = parseQualifiedName(expr, rest); result = "[[`" ~ a ~"`,typeof(" ~ a ~ ").stringof, " ~a ~ ".stringof]"; while (rest!="") { b = parseOperator(rest, rest); char [] r; a = parseQualifiedName(rest, r); rest=r; result ~= "," ~"[`" ~ a ~"`,typeof(" ~ a ~ ").stringof, " ~a ~ ".stringof]"; } return result ~ "]"; } // Actually it should process the arguments into a standard, convenient form. For now, just pass them on, together with the type information. char [] expressionMacro(char [] macroname, char [] args) { return "mixin ("~macroname ~"(`" ~ args ~"`," ~ getAllIdentifiers(args)~ "));"; } ----------- IMHO, this is already pretty good, despite the fact that there's a couple of workarounds for compiler bugs in there. I just can't believe how powerful this language is now.
Apr 25 2007
Nice work! The compiler now is damned powerful :) Though I still prefer less string operation in compile time, any idea of improving the macro syntax I posted? You see, D is going to bring AST macro in future releases. Let's discuss the syntax it will use?
Apr 25 2007
Davidl wrote:Nice work! The compiler now is damned powerful :) Though I still prefer less string operation in compile time,Yes. I think that's the key improvement to make. any idea ofimproving the macro syntax I posted? You see, D is going to bring AST macro in future releases. Let's discuss the syntax it will use?To the user, we should eliminate the quotes, and the mixin(). My example was a bit specific. Let's consider lazy evaluation. void logging(bool bLog, lazy char [] msg); which shouldn't evaluate msg unless bLog is true. With my method, it would be: bool bActive=true; mixin(logging(`bActive, getFromDatabase("db", "downtime", event)`)); Obviously, we want to get rid of the mixin() and the ``. But that's probably the only thing we need to do, outside of library code. Once we get rid of the ``, we have the requirement that all macro arguments must be syntactically valid D code. This makes things like your := impossible. Then we have: macro logging(char [][] args) { return `if (` ~ args[0].stringof ~ `) printf("%s", ` ~ args[1].stringof ~ `);`; } (macros always return a char [], which is mixed in). But that will look pretty awful if you want to do more than a single function call. OTOH, if we just get rid of the ``, we lose the ability to make decisions at compile time. What then??
Apr 25 2007
Don Clugston wrote:Obviously, we want to get rid of the mixin() and the ``. But that's probably the only thing we need to do, outside of library code. Once we get rid of the ``, we have the requirement that all macro arguments must be syntactically valid D code. This makes things like your := impossible.But that will look pretty awful if you want to do more than a single function call. OTOH, if we just get rid of the ``, we lose the ability to make decisions at compile time. What then??D being a multiparadigm language, it's a bit funny how many 'native' possibilities there are to implement metaprogramming. All of them have some good and some bad sides. So should these new constructs also cover some meta object protocol or s-expressions or just this shorter syntax for string mixins? Or should meta objects and s-expressions be implemented on the library level?
Apr 25 2007
Don Clugston wroteLet's consider lazy evaluation.Yeah. Are you able to eliminate switch-statements out of some code and generate an equivalent series of if-statements---and vice versa? -manfred
Apr 25 2007
Don Clugston wrote:Davidl wrote:heh, mixin an assert is bad, compile time is even longer :p?? It's no different to a static assert.Though you are kinda sticking with CTFE & mixin , I'm pretty sure you would vote my syntax of macro for macro, right? :)No. It's nowhere near clean enough yet. The code below, works right now. The challenge is to make it nicer. //-------------------------- // This is a macro library, defining a 'vectorize' macro. //-------------------------- module Blade; import ExpressionParser; //common code for any macros which use D syntax public import std.stdio; // CTFE macro: returns the code to be mixed in. // prints all symbols used in the expression char [] describe(char [] expr, char [][3][] symbols) { char [] result = "Expression:" ~ expr ~ "\nSYMBOL \tTYPE\t\tVALUE\n"; for (int i=0; i<symbols.length; ++i) { result ~= symbols[i][0] ~ " \t" ~ symbols[i][1] ~ " \t" ~ symbols[i][2] ~ \n; } return `printf("` ~ result ~ `");`; } // TO BE MIXED IN -- inserts the boilerplate code for parsing & type extraction, // then gets the macro text from the named function. char [] vectorize(char [] expr) { return expressionMacro("describe", expr); } //-------------------------- // And this is how the user sees it. //-------------------------- import Blade; void main() { auto a = [1.24, 5.35, 324, 2454]; double [] big = [3.44, 5565, 1.45, 67.1]; const yx=-2.354e-68Li; alias big c; mixin(vectorize("a +=yx *big -c")); } =============================== OUTPUT =============================== Expression:a +=yx *big -c SYMBOL TYPE VALUE a double[4] a yx ireal -2.354e-68i big double[] big c double[] big Note that the constant has been evaluated, and the aliases resolved. And if you change the last line to: mixin(vectorize("a +=yx *big -d")); you get: test.d(10): Error: undefined identifier d That happens automatically. Note that the line number is correct. That expressionMacro must be really horrible, right? Actually, no. It just makes use of some trivial identifier and operator parsing routines, and applies the .stringof property. ----------- // Given an expression string 'expr', make a string to mixin in, // which will have an array of 3 strings for each symbol in the // expression. [0]=symbol name, [1]=type, [2]=value char[] getAllIdentifiers(char [] expr) { char [] result; char [] rest; char [] a; char [] b; a = parseQualifiedName(expr, rest); result = "[[`" ~ a ~"`,typeof(" ~ a ~ ").stringof, " ~a ~ ".stringof]"; while (rest!="") { b = parseOperator(rest, rest); char [] r; a = parseQualifiedName(rest, r); rest=r; result ~= "," ~"[`" ~ a ~"`,typeof(" ~ a ~ ").stringof, " ~a ~ ".stringof]"; } return result ~ "]"; } // Actually it should process the arguments into a standard, convenient form. For now, just pass them on, together with the type information. char [] expressionMacro(char [] macroname, char [] args) { return "mixin ("~macroname ~"(`" ~ args ~"`," ~ getAllIdentifiers(args)~ "));"; } ----------- IMHO, this is already pretty good, despite the fact that there's a couple of workarounds for compiler bugs in there.I just can't believe how powerful this language is now.I agree, the CTFE & mixins have really put D over the top, and this is just the beginning. If we are talking about improving the current syntax I'd really like to see a symbol for explicitly calling a function at call time, having to guess what the code is doing is a PITA , especially if you aren't the original developer. I also think compile time string manipulation could be improved, or at least documented. Do you have this new code up somewhere ? Thanks, Charlie
Apr 25 2007
sorry for typos in the error message :o should be static if (tokens[4].ID !=3D Token.LBracket) pragma(error, `[ expected`); else static if (tokens[5].ID !=3D Token.Identifier) pragma(error, `identifer expected`); else static if (tokens[6].ID !=3D Token.RBracket) pragma(error, `] expected`);macro (Token... tokens) { static if (tokens[0].ID !=3D Token.LParen) pragma(error, `( expected`); else static if (tokens[1].ID !=3D Token.Identifier) pragma(error, `identifer expected`); else static if (tokens[2].ID !=3D Token.RParen) pragma(error, ) expected`); else static if (tokens[3].toChars !=3D `:=3D`) pragma(error, `:=3D expected`); static if (tokens[4].ID !=3D Token.LBracket) pragma(error, `( expected`); else static if (tokens[5].ID !=3D Token.Identifier) pragma(error, `identifer expected`); else static if (tokens[6].ID !=3D Token.RBracket) pragma(error, ) expected`); else static if (tokens[7].ID !=3D Token.Identifier) pragma(error, `identifer expected`); else static if (tokens[8].ID !=3D Token.plus) pragma(error, `+ operator expected`); else static if (tokens[9].ID !=3D Token.Identifier) pragma(error, `identifer expected`); alias token[1] arg0; alias token[5] arg1; alias token[7] arg2; alias token[9] arg3; arg0[arg1] =3D arg2 + arg3; } seems the above is more valuable.call =numerle's macro is somewhat worth consideration an improved syntax should be something like: macro macroname(arg0,arg1,arg2,arg3) syntax realname(arg0)[arg1] :=3D arg2 +arg3 { arg0[arg1] =3D arg2+arg3; } and calling style would be realname(a)[i] :=3D j + k; // which would =macro macroname(a,i,j,k)A couple of weeks ago, I posted an implementation of BLAS1-style =vector expressions, that used tuples and expression templates to ==generate near-optimal asm code in many circumstances. Unfortunately,==when I've looked at the code that is generated, there's a *hideous* ==amount of stack shuffling -- it is too difficult for the compiler to=optimise all the tuple operations away. So I came up with this alternative, which gives _many_ more =f =optimisation opportunities, and doesn't require you to wrap arrays o==built-in types. float [] vec1 =3D [43, 5445, 547, 465]; auto vec2 =3D [1.24, 765, 6756, 23.143]; mixin(vectorize("vec2+=3Dvec1*3.3254")); This actually works. There are some awesome side effects -- eg, any ==error messages in the library code appear on the line of user code. ==You can determine which of the variables are compile-time constants =(and optimise the generated code based on the value of those =ng =constants). You can get the compiler to do _most_ of the heavy lifti=n =(eg, convert floating point strings <--> const real). As far as I can tell, *all* of the proposed 'macro' functionality ca=of =be done already using mixins and CTFE. It looks as though the power =os =macros will be a subset of the power of mixins. This means that macr=can be explored quite thoroughly *before* deciding on the cleanest =syntax for them. Today: --------- char [] magic(char [] args) { return "stuff-to-mix-in"; } : mixin(magic("a+=3Db*c")); : ----------- With macros: macro magic(args) { stuff-to-mix-in } : magic(a+=3Db*c); : ------------
Apr 25 2007
Davidl wrote:macro (Token... tokens) { static if (tokens[0].ID != Token.LParen) pragma(error, `( expected`); else static if (tokens[1].ID != Token.Identifier) pragma(error, `identifer expected`); else static if (tokens[2].ID != Token.RParen) pragma(error, ) expected`); else static if (tokens[3].toChars != `:=`) pragma(error, `:= expected`); static if (tokens[4].ID != Token.LBracket) pragma(error, `( expected`); else static if (tokens[5].ID != Token.Identifier) pragma(error, `identifer expected`); else static if (tokens[6].ID != Token.RBracket) pragma(error, ) expected`); else static if (tokens[7].ID != Token.Identifier) pragma(error, `identifer expected`); else static if (tokens[8].ID != Token.plus) pragma(error, `+ operator expected`); else static if (tokens[9].ID != Token.Identifier) pragma(error, `identifer expected`); alias token[1] arg0; alias token[5] arg1; alias token[7] arg2; alias token[9] arg3; arg0[arg1] = arg2 + arg3; } seems the above is more valuable.Huh, that looks awful. This kind of code surely needs some pattern matching magic. Should we add it to D 2.0 wishlist too.
Apr 25 2007
oh noes, why posted so many times.... coz they are too important? :p forgive my bad network & slow machine , i think the extra posts are caused by themnumerle's macro is somewhat worth consideration an improved syntax should be something like: macro macroname(arg0,arg1,arg2,arg3) syntax realname(arg0)[arg1] :=3D arg2 +arg3 { arg0[arg1] =3D arg2+arg3; } and calling style would be realname(a)[i] :=3D j + k; // which would c=all =macro macroname(a,i,j,k)or =A couple of weeks ago, I posted an implementation of BLAS1-style vect=expressions, that used tuples and expression templates to generate ==near-optimal asm code in many circumstances. Unfortunately, when I've=looked at the code that is generated, there's a *hideous* amount of =ll =stack shuffling -- it is too difficult for the compiler to optimise a=the tuple operations away. So I came up with this alternative, which gives _many_ more ==optimisation opportunities, and doesn't require you to wrap arrays of=built-in types. float [] vec1 =3D [43, 5445, 547, 465]; auto vec2 =3D [1.24, 765, 6756, 23.143]; mixin(vectorize("vec2+=3Dvec1*3.3254")); This actually works. There are some awesome side effects -- eg, any =ou =error messages in the library code appear on the line of user code. Y==can determine which of the variables are compile-time constants (and =ou =optimise the generated code based on the value of those constants). Y=can get the compiler to do _most_ of the heavy lifting (eg, convert ==floating point strings <--> const real). As far as I can tell, *all* of the proposed 'macro' functionality can=f =be done already using mixins and CTFE. It looks as though the power o=s =macros will be a subset of the power of mixins. This means that macro=can be explored quite thoroughly *before* deciding on the cleanest =syntax for them. Today: --------- char [] magic(char [] args) { return "stuff-to-mix-in"; } : mixin(magic("a+=3Db*c")); : ----------- With macros: macro magic(args) { stuff-to-mix-in } : magic(a+=3Db*c); : ------------
Apr 25 2007