digitalmars.D.learn - How to insert code in place with templates/mixins?
- rempas (51/51) Dec 20 2021 Here I am having a problem with templates again. No matter how
- rumbu (25/29) Dec 20 2021 because you cannot have statements directly in a template (the
- rempas (12/37) Dec 20 2021 Thanks a lot for the info. When I try to use this code, I'm
- rumbu (19/31) Dec 20 2021 My fault, I forgot to put some char delimiters. You can find
- Tejas (32/65) Dec 20 2021 Ehh, it still fails; should've explicitly put the length of the
- rempas (3/15) Dec 20 2021 Thanks! A mixin is not necessary, it will do the same thing
- rempas (2/23) Dec 20 2021 Well it seem that it actually needs it...
- rempas (12/27) Dec 20 2021 That's cool! And I was wondering how I can make sting literal
- Stanislav Blinov (2/6) Dec 20 2021 https://dlang.org/spec/traits.html#identifier
Here I am having a problem with templates again. No matter how much I read, I can't seem to understand how templates/mixins work. So I'm having the following code (just a snippet of the real code): ``` if (c != '%') { if (stdout_index < STDOUT_BUF_LEN) { stdout_buffer[stdout_index++] = c; continue; } else { sys_write(1, stdout_buffer.ptr, cast(i32)stdout_index); stdout_index = 0; stdout_buffer[stdout_index++] = c; continue; } } ``` And I want to create a macro (using the C terms) to make the code inside the first if statement (`if (c != '%')`) into a template that will be able to used and added in place (not as a function as I don't want to function call). I tried to make it both a template and a mixin template and It will not compile, rather it will give my the following error: ``` Error: declaration expected, not `if` Error: declaration expected, not `continue` Error: declaration expected, not `else` Error: basic type expected, not `0` Error: found `0` when expecting `;` Error: no identifier for declarator `stdout_buffer[stdout_index++]` Error: declaration expected, not `=` Error: declaration expected, not `continue` Error: unrecognized declaration ``` It should be clear what I tried to still I will post what I tried in case someone is curious to see: ``` mixin template add_char() { if (stdout_index < STDOUT_BUF_LEN) { stdout_buffer[stdout_index++] = c; continue; } else { sys_write(1, stdout_buffer.ptr, cast(i32)stdout_index); stdout_index = 0; stdout_buffer[stdout_index++] = c; continue; } } ``` So any ideas why this doesn't work?
Dec 20 2021
On Monday, 20 December 2021 at 08:45:50 UTC, rempas wrote:Here I am having a problem with templates again. No matter how much I read, I can't seem to understand how templates/mixins work. So any ideas why this doesn't work?because you cannot have statements directly in a template (the fact that is a mixin template is irelevant), only declarations. If you want to just insert some random code, use strings. You can create a templated enum to store your parametrized string. Please note how your parameter (c) becomes part of the resulting string through concatenation (~): ``` enum add_char(char c) = `if (stdout_index < STDOUT_BUF_LEN) { stdout_buffer[stdout_index++] =` ~ c ~ `; continue; } else { sys_write(1, stdout_buffer.ptr, cast(i32)stdout_index); stdout_index = 0; stdout_buffer[stdout_index++] =` ~ c ~ `; continue; }`; ``` and when you want the code inserted: ``` mixin(add_char!'%'); ``` If you want to be sure that your string is syntactically correct, use token strings (https://dlang.org/spec/lex.html#token_strings)
Dec 20 2021
On Monday, 20 December 2021 at 09:30:30 UTC, rumbu wrote:because you cannot have statements directly in a template (the fact that is a mixin template is irelevant), only declarations. If you want to just insert some random code, use strings. You can create a templated enum to store your parametrized string. Please note how your parameter (c) becomes part of the resulting string through concatenation (~): ``` enum add_char(char c) = `if (stdout_index < STDOUT_BUF_LEN) { stdout_buffer[stdout_index++] =` ~ c ~ `; continue; } else { sys_write(1, stdout_buffer.ptr, cast(i32)stdout_index); stdout_index = 0; stdout_buffer[stdout_index++] =` ~ c ~ `; continue; }`; ``` and when you want the code inserted: ``` mixin(add_char!'%'); ``` If you want to be sure that your string is syntactically correct, use token strings (https://dlang.org/spec/lex.html#token_strings)Thanks a lot for the info. When I try to use this code, I'm getting the following error: ``` Error: expression expected, not `%` Error: expression expected, not `%` ``` So I suppose there is a problem with string concatenation. I couldn't use it anyway because it is inefficient and because I'm using betterC. Do you know any other way that I can concatenate strings that does not depend an the Garbage Collector or the standard library?
Dec 20 2021
On Monday, 20 December 2021 at 10:49:20 UTC, rempas wrote:On Monday, 20 December 2021 at 09:30:30 UTC, rumbu wrote: Thanks a lot for the info. When I try to use this code, I'm getting the following error: ``` Error: expression expected, not `%` Error: expression expected, not `%` ```My fault, I forgot to put some char delimiters. You can find tested code here: https://run.dlang.io/is/KfdED0So I suppose there is a problem with string concatenation. I couldn't use it anyway because it is inefficient and because I'm using betterC. Do you know any other way that I can concatenate strings that does not depend an the Garbage Collector or the standard library?Enums (that's why the string is declarated as enum) are evaluated at compile time, the concatenation op will not end in your code as instruction, so you can do anything outside betterC rules as long you do it at compile time. You are just building some code to use later, the compiler does not generate any instruction for it. In the example above you can press the AST button to see exactly how your code is generated. Wnen you have doubts about a generated string you can always test it with ```pragma msg```. In this case, if you write: ``` pragma(msg, add_char!'%'); ``` you will have in the output exactly what the compiler will generate for your mixin.
Dec 20 2021
On Monday, 20 December 2021 at 11:30:09 UTC, rumbu wrote:On Monday, 20 December 2021 at 10:49:20 UTC, rempas wrote:Ehh, it still fails; should've explicitly put the length of the array and the `extern (C)` in `main` ```d module demo; //i am just declaring these to have them. size_t stdout_index; enum STDOUT_BUF_LEN = 42; char[STDOUT_BUF_LEN] stdout_buffer; /+indexing an uninitialized dynamic array resulted in out of bounds error even for index == 0+/ alias i32 = int; void sys_write(int i, void* p, int index) {} // enum add_char(char c) = `if (stdout_index < STDOUT_BUF_LEN) { stdout_buffer[stdout_index++] ='` ~ c ~ `'; continue; } else { sys_write(1, stdout_buffer.ptr, cast(i32)stdout_index); stdout_index = 0; stdout_buffer[stdout_index++] ='` ~ c ~ `'; continue; }`; extern(C) /+added this because you used -betterC+/ void main() { while (true) { mixin(add_char!'%'); mixin(add_char!'$'); } } ```On Monday, 20 December 2021 at 09:30:30 UTC, rumbu wrote: Thanks a lot for the info. When I try to use this code, I'm getting the following error: ``` Error: expression expected, not `%` Error: expression expected, not `%` ```My fault, I forgot to put some char delimiters. You can find tested code here: https://run.dlang.io/is/KfdED0So I suppose there is a problem with string concatenation. I couldn't use it anyway because it is inefficient and because I'm using betterC. Do you know any other way that I can concatenate strings that does not depend an the Garbage Collector or the standard library?Enums (that's why the string is declarated as enum) are evaluated at compile time, the concatenation op will not end in your code as instruction, so you can do anything outside betterC rules as long you do it at compile time. You are just building some code to use later, the compiler does not generate any instruction for it. In the example above you can press the AST button to see exactly how your code is generated. Wnen you have doubts about a generated string you can always test it with ```pragma msg```. In this case, if you write: ``` pragma(msg, add_char!'%'); ``` you will have in the output exactly what the compiler will generate for your mixin.
Dec 20 2021
On Monday, 20 December 2021 at 11:58:58 UTC, Tejas wrote:Ehh, it still fails; should've explicitly put the length of the array and the `extern (C)` in `main` ```d module demo; [ ... ] extern(C) /+added this because you used -betterC+/ void main() { while (true) { mixin(add_char!'%'); mixin(add_char!'$'); } } ```Thanks! A mixin is not necessary, it will do the same thing without it.
Dec 20 2021
On Monday, 20 December 2021 at 18:06:32 UTC, rempas wrote:On Monday, 20 December 2021 at 11:58:58 UTC, Tejas wrote:Well it seem that it actually needs it...Ehh, it still fails; should've explicitly put the length of the array and the `extern (C)` in `main` ```d module demo; [ ... ] extern(C) /+added this because you used -betterC+/ void main() { while (true) { mixin(add_char!'%'); mixin(add_char!'$'); } } ```Thanks! A mixin is not necessary, it will do the same thing without it.
Dec 20 2021
On Monday, 20 December 2021 at 11:30:09 UTC, rumbu wrote:Enums (that's why the string is declarated as enum) are evaluated at compile time, the concatenation op will not end in your code as instruction, so you can do anything outside betterC rules as long you do it at compile time. You are just building some code to use later, the compiler does not generate any instruction for it. In the example above you can press the AST button to see exactly how your code is generated. Wnen you have doubts about a generated string you can always test it with ```pragma msg```. In this case, if you write: ``` pragma(msg, add_char!'%'); ``` you will have in the output exactly what the compiler will generate for your mixin.That's cool! And I was wondering how I can make sting literal concatenation at compile time. Now the problem is that I want it to get the name of so symbol and add it to a string literal. Let's check this example: enum state(alias name) = `name` ~ ` = 10;`; I want this to add the token of that will be used as name in the string. For example, I want `state!val;` to get "expanded" as `val = 10;` rather than `10 = 10;`. So I don't want it to take the value of "val" but the word/token "val" itself. I tried using `alias` instead of `char` for the parameter but it didn't worked. Do you know how I can do that?
Dec 20 2021
On Monday, 20 December 2021 at 18:03:09 UTC, rempas wrote:https://dlang.org/spec/traits.html#identifierNow the problem is that I want it to get the name of so symbol and add it to a string literal.Let's check this example: enum state(alias name) = `name` ~ ` = 10;`;
Dec 20 2021
On Monday, 20 December 2021 at 18:12:35 UTC, Stanislav Blinov wrote:https://dlang.org/spec/traits.html#identifierThanks!!! Finally I was able to do it! The code is the following (well not in my final project but it's a demonstration): ``` enum add_char(string c) = `if (stdout_index < STDOUT_BUF_LEN) { stdout_buffer[stdout_index++] =` ~ c ~ `; continue; } else { sys_write(1, stdout_buffer.ptr, cast(i32)stdout_index); stdout_index = 0; stdout_buffer[stdout_index++] =` ~ c ~ `; continue; }`; void main() { mixin(add_char!(__traits(identifier, c))); } ``` I don't know if there is another way to do it but this works for me. Also another thing that I want to ask is if the "mixin" is generated every time inside a loop and if there is a better way to do that?
Dec 20 2021
On Monday, 20 December 2021 at 18:23:44 UTC, rempas wrote:On Monday, 20 December 2021 at 18:12:35 UTC, Stanislav Blinov wrote:You can see the ["String mixins" section here](http://ddili.org/ders/d.en/mixin.html) for more details. Mixins are generated at compile time, so if you're referring to a string mixin inside a runtime loop, the code will not be generated every time the loop runs.https://dlang.org/spec/traits.html#identifierThanks!!! Finally I was able to do it! The code is the following (well not in my final project but it's a demonstration): ``` enum add_char(string c) = `if (stdout_index < STDOUT_BUF_LEN) { stdout_buffer[stdout_index++] =` ~ c ~ `; continue; } else { sys_write(1, stdout_buffer.ptr, cast(i32)stdout_index); stdout_index = 0; stdout_buffer[stdout_index++] =` ~ c ~ `; continue; }`; void main() { mixin(add_char!(__traits(identifier, c))); } ``` I don't know if there is another way to do it but this works for me. Also another thing that I want to ask is if the "mixin" is generated every time inside a loop and if there is a better way to do that?
Dec 20 2021
On Monday, 20 December 2021 at 18:58:39 UTC, bachmeier wrote:You can see the ["String mixins" section here](http://ddili.org/ders/d.en/mixin.html) for more details. Mixins are generated at compile time, so if you're referring to a string mixin inside a runtime loop, the code will not be generated every time the loop runs.Thanks! Yeah after I commented, I thought a little bit about how they generate code at compile time like you said and understand that what I'm saying doesn't make much sense. Have a nice day my friend!
Dec 20 2021