Skip to content

Implement partial support for #define objects#302

Open
davispuh wants to merge 1 commit into
jacob-carlborg:masterfrom
davispuh:objects
Open

Implement partial support for #define objects#302
davispuh wants to merge 1 commit into
jacob-carlborg:masterfrom
davispuh:objects

Conversation

@davispuh

Copy link
Copy Markdown

Consider common C pattern like:

struct S
{
  int a;
  int b;
};

#define S_INIT { 1, 2 }

int main()
{
   struct S s = S_INIT;
}

Currently dstep will ignore S_INIT which loses this "init" information.
This PR implements partial support so that

enum S_INIT = null; // FIXME: {1,2};

Will be produced, which allows to create simple shell script with simple sed command to afterwards fix up these case with something like this:

$ sed -iE 's|null; // FIXME: {\([^}]*\)}|S(\1)|g' file.d

Which will make final version to be:

enum S_INIT = S(1,2);

And that will work correctly when S_INIT is used.
Unfortunately this 2nd step with sed or another processing tool is needed because implementing usage-aware processing inside dstep is not trivial and would require significant effort to also parse macro usages so that's why I'm settling on this partial support.

Copilot AI review requested due to automatic review settings March 19, 2026 17:03

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds partial handling for object-like #define macros that expand to C braced initializer lists (e.g. {1,2}), so dstep can preserve that initializer information in generated D output (as a placeholder with a FIXME marker).

Changes:

  • Extend the macro expression AST with a new braced-initializer expression node (ObjectExpr).
  • Parse { ... } token sequences as a standalone expression in MacroParser.
  • Translate this expression into a placeholder D value while retaining the original braced text in a FIXME comment.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
dstep/translator/TypeInference.d Treats the new braced-initializer expression as Generic during type inference.
dstep/translator/MacroParser.d Introduces ObjectExpr and parsing logic for { ... } object-style macro bodies.
dstep/translator/MacroDefinition.d Adds translation support for ObjectExpr into a placeholder value with a FIXME marker.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment thread dstep/translator/MacroDefinition.d Outdated
Comment thread dstep/translator/MacroParser.d Outdated
Comment thread dstep/translator/MacroParser.d Outdated
Comment thread dstep/translator/MacroParser.d Outdated
@jacob-carlborg

Copy link
Copy Markdown
Owner

Is it possible to determine that it's an initializer and have DStep do the translation?

```
struct S
{
  int a;
  int b;
};

 #define S_INIT { 1, 2 }

int main()
{
   struct S s = S_INIT;
}
```

Currently dstep will ignore `S_INIT` which loses this "init" information.
This PR implements partial support so that it becomes:
```
enum S_INIT = null /* FIXME: {1,2} */;
```
Which allows to create simple shell script with `sed` command to afterwards fix up these case with something like this:
```
$ sed -iE 's|null; /* FIXME: {\([^}]*\)}|S(\1)|g' file.d
```
Which will make final version to be:
```
enum S_INIT = S(1,2);
```
@davispuh

davispuh commented Jun 27, 2026

Copy link
Copy Markdown
Author

Is it possible to determine that it's an initializer and have DStep do the translation?

Unfortunately not really possible because:

  1. At initializer #define time it's impossible to know what exactly it is and to which type it would map to. That can only be known at usage place.
  2. Currently DStep parses .h one by one but it could be used in some later file or even not included as part of given input files.
  3. Usually initializers are used in .c files so you might not even see any usage case. Usage might be only described in documentation.

Eg. consider .h file:

struct s1 {
	int *p1;
	int *p2;
};

struct s2 {
	struct s1 a;
	int	b;
	int	c;
};

#define INITIALIZER(x, y) { {{NULL}, {NULL}}, x, y }
// Use this like struct s2 d = INITIALIZER(1, 2);

(none of files have actual usage so you can't know what type it maps to)
Only if you know how it's supposed to be used then you know that it maps to

extern (D) auto INITIALIZER(T1, T2)(auto ref T1 x, auto ref T2 y)
{
    return s2(s1.init, x, y);
}

You have to know that it's s2 and s1.
The only way how I think this could be automated is if dstep accepts mapping file like:

INITIALIZER: s2

So you would create this mapping file manually and pass it to dstep so it would know to map it to this type.

Also FYI I improved this PR and added tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants