Skip to content

Convert the JSON code to use D slices instead of pointers#8555

Merged
JinShil merged 7 commits intodlang:masterfrom
Geod24:json
Aug 18, 2018
Merged

Convert the JSON code to use D slices instead of pointers#8555
JinShil merged 7 commits intodlang:masterfrom
Geod24:json

Conversation

@Geod24
Copy link
Member

@Geod24 Geod24 commented Aug 10, 2018

Since we want to get rid of strlen, I tried to convert a simple global to a D slice and was blocked by the JSON module. So here is the module conversion to D.
Some simple things were added (e.g. RootObject.toString which just strlen on toChars), but I avoided changing the AST as much as possible, so things like kind() and Loc.filename can be done in another PR.

@dlang-bot
Copy link
Contributor

Thanks for your pull request and interest in making D better, @Geod24! We are looking forward to reviewing it, and you should be hearing from a maintainer soon.
Please verify that your PR follows this checklist:

  • My PR is fully covered with tests (you can see the annotated coverage diff directly on GitHub with CodeCov's browser extension
  • My PR is as minimal as possible (smaller, focused PRs are easier to review than big ones)
  • I have provided a detailed rationale explaining my changes
  • New or modified functions have Ddoc comments (with Params: and Returns:)

Please see CONTRIBUTING.md for more information.


If you have addressed all reviews or aren't sure how to proceed, don't hesitate to ping us with a simple comment.

Bugzilla references

Your PR doesn't reference any Bugzilla issue.

If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog.

Testing this PR locally

If you don't have a local development environment setup, you can use Digger to test this PR:

dub fetch digger
dub run digger -- build "master + dmd#8555"

src/dmd/json.d Outdated
if (type)
{
property(name, type.toChars());
property(name, RootObject.toString(type));
Copy link
Member

Choose a reason for hiding this comment

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

Not too thrilled about this. It should be type.toString(). Yes, the C++ code cannot call it, but all you need to do is put a dummy function declaration there on the C++ side so the vtbl[] entries line up.

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed

return buf.extractString();
}

extern (D) const(char)[] toString() const
Copy link
Contributor

Choose a reason for hiding this comment

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

DDoc?

Copy link
Member

Choose a reason for hiding this comment

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

As I mentioned before, toString() is used pervasively in dmd, and as long as it does what the other toString()'s do, adding a Ddoc for it is redundant.

Copy link
Member

Choose a reason for hiding this comment

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

While I agree that a comment is not really necessary here, you have to add some ddoc comment to make the function appear in the documentation at all. Not sure if that is a good thing as you have to litter the code with empty comments this way. Is there an option to put all (public) symbols into the documentation?

Copy link
Member Author

Choose a reason for hiding this comment

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

For the record I added a (trivial) DDOC comment just for this reason (documentation)

return null;
}

extern (D) const(char)[] stcToString(ref StorageClass stc)
Copy link
Contributor

Choose a reason for hiding this comment

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

DDoc?

return trustToString(trust).ptr;
}

extern (D) string trustToString(TRUST trust)
Copy link
Contributor

Choose a reason for hiding this comment

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

DDoc?

return protectionToString(kind).ptr;
}

extern (D) string protectionToString(Prot.Kind kind)
Copy link
Contributor

Choose a reason for hiding this comment

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

DDoc?

src/dmd/json.d Outdated
if (auto filename = toDString(loc.filename))
{
if (!this.filename || strcmp(filename, this.filename))
if (!this.filename.length || filename != this.filename)
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm guessing you're trying keep the new to code be as close as possible to the old code but this first expression (!this.filename.length) isn't needed anymore?

@Geod24
Copy link
Member Author

Geod24 commented Aug 13, 2018

Updated according to feedback

return buf.extractString();
}

/// Provide an human readable representation
Copy link
Member

Choose a reason for hiding this comment

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

Provide a human

src/dmd/hdrgen.d Outdated

/**
* Returns:
* an human readable representation of `stc`
Copy link
Member

Choose a reason for hiding this comment

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

A human

src/dmd/hdrgen.d Outdated

/**
* Returns:
* an human readable representation of `trust`,
Copy link
Member

Choose a reason for hiding this comment

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

A human

src/dmd/hdrgen.d Outdated

/**
* Returns:
* an human readable representation of `kind`
Copy link
Member

Choose a reason for hiding this comment

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

A human

}

void stringPart(const(char)* s)
extern(D) void stringPart(const(char)[] s)
Copy link
Member

Choose a reason for hiding this comment

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

Wouldn't all non-visit members of this visitor be private? Ergo you can just add extern(D): at the top of this body rather than adding it for each individual function.

Think about it for future refactor.

Copy link
Member Author

Choose a reason for hiding this comment

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

True that. At the moment I'm putting extern(D) right and left (got more slice-ification coming), but I also had weird bugs (compiler SEGV) being triggered in the past some I decided to go for verbose and simple. But when enough is converted, we surely can do that.

} while (value);
return buf[i .. $];
}

Copy link
Member

Choose a reason for hiding this comment

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

Seems like a leftover from a previous attempt here.

Copy link
Member Author

Choose a reason for hiding this comment

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

It is, but also its own commit

@Geod24
Copy link
Member Author

Geod24 commented Aug 13, 2018

Fixed typos poor English

src/dmd/json.d Outdated
static extern(D) const(char)[] toDString (const(char)* s)
{
return s ? s[0 .. strlen(s)] : null;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not put this as a global function into utils or similar? It's used at other places too and doesn't really fit in ToJsonVisitor

Copy link
Member Author

Choose a reason for hiding this comment

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

Didn't expect it to be so widely used :(
Also I'm wary that dmd.utils will be imported everywhere soon.
But let's give it a shot...

src/dmd/hdrgen.d Outdated
extern (D) const(char)[] stcToString(ref StorageClass stc)
{
auto p = stcToChars(stc);
return p[0 .. strlen(p)];
Copy link
Contributor

Choose a reason for hiding this comment

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

Could use toDString from below.

extern (D) const(char)[] toString() const
{
auto p = this.toChars();
return p[0 .. strlen(p)];
Copy link
Contributor

Choose a reason for hiding this comment

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

Could use toDString from below.

src/dmd/json.d Outdated
property("kind", s.kind());
property("comment", s.comment);
property("kind", toDString(s.kind()));
property("comment", toDString(s.comment));
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: another advantage of making toDString a global function is that you can do the more natural: s.comment.toDString()

{
import core.stdc.string : strlen;
auto p = this.toChars();
return p[0 .. strlen(p)];
Copy link
Contributor

Choose a reason for hiding this comment

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

Could use toDString from above.

Copy link
Member Author

Choose a reason for hiding this comment

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

Here I choose not to, as we want rootobject to depends on as little as possible.

@Geod24
Copy link
Member Author

Geod24 commented Aug 13, 2018

Addressed @wilzbach 's comments

Copy link
Contributor

@JinShil JinShil left a comment

Choose a reason for hiding this comment

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

Still looking good.

@Geod24
Copy link
Member Author

Geod24 commented Aug 14, 2018

Since this has gotten a bit more reviews, and one might be wondering where I am going, I added a bit more diff than originally intended:

  • Commit 0c91769 moves DArray from globals.h to a standalone header, because we don't want object.h importing globals.h
  • I reworked RootObject.toString to be callable from C++ and added a test.
    Only works on POSIX x64 :'(

As for the end goal is, it's to be able to do this gradually.

semantic3(m, NULL);

// Basic test for D slice passing
DArray<const char> sl = m->toString();
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this work on Windows? I’ve been told D arrays are returned in registers while structs of this size are not on Windows.

Copy link
Member Author

Choose a reason for hiding this comment

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

I should've known it was too good to be true.
I'll wait for the auto-tester to tell me what's the situation with Windows, but it fails on 32 bits.
So I guess I will take that test out for now :'(

Copy link
Member Author

Choose a reason for hiding this comment

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

Hum, the C++ frontend tests only run on POSIX anyway...

Copy link
Contributor

Choose a reason for hiding this comment

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

For reference: #8120 (comment).

}

/// Slices a `\0`-terminated C-string, excluding the terminator
const(char)[] toDString (const(char)* s) pure nothrow @nogc
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not toString?

Copy link
Member Author

Choose a reason for hiding this comment

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

toString is to provide a string representation, this is to convert a const(char)* to a const(char)[].

@Geod24 Geod24 force-pushed the json branch 2 times, most recently from 7cc187a to b5641b3 Compare August 14, 2018 07:03
@Geod24
Copy link
Member Author

Geod24 commented Aug 14, 2018

@wilzbach :

dmd/root/rootobject.d(66:29)[warn]: Methods 'opCmp', 'toHash', 'opEquals', 'opCast', and/or 'toString' are non-const.

What's the deal with that warning ?? extern(C++) classes don't inherit from Object so it doesn't make sense to require them to be const. And I currently cannot make it const.

@wilzbach
Copy link
Contributor

What's the deal with that warning ?? extern(C++) classes don't inherit from Object so it doesn't make sense to require them to be const.

Yeah that's the newly added Dscanner static code analysis check and the idea is that the checks slowly allow to modernize DMD / enforce some automatic code checking.
I guess the assumption behind this check was that "opEquals, opCmp, toHash, and toString are either const, immutable or inout" because they shouldn't be changing any data.

And I currently cannot make it const.

tl;dr: in this case, add your module to this list:

object_const_check="-dmd.dtemplate,-dmd.backend.outbuf"

@Geod24
Copy link
Member Author

Geod24 commented Aug 14, 2018

@wilzbach : Thanks, glad to see there's a way out of it!

virtual const char *toChars();
/// This function is `extern(D)` and should not be called from C++,
/// as the ABI does not match on some platforms
virtual DArray<const char> toString();
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it possible to implement this on the C++ and have the implementation assert?

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't think so.

@Geod24 Geod24 closed this Aug 14, 2018
@Geod24 Geod24 reopened this Aug 14, 2018
@wilzbach wilzbach closed this Aug 14, 2018
@wilzbach wilzbach reopened this Aug 14, 2018
@wilzbach
Copy link
Contributor

@Geod24 I don't know exactly what's up with SemaphoreCI, but #8560 (once merged back to master) will hopefully help a bit.

Geod24 added 7 commits August 14, 2018 18:00
If we want to use DArray from dmd.root it cannot reside in globals.h,
so it is moved to a standalone header.
At the moment it is simply doing an `strlen` on the result of `toChars`,
but as more code uses it, we can start to move away from that.
Another reason to do it this way is because code can rely on the string
being null terminated, so this way `x.toString().ptr` is still a drop-in
replacement of `x.toChars()`.
The conversion is pretty straightforward, but required in order to convert globals.
Since globals are still C-style string, a local toDString is used.
It can later be removed as globals are converted to D slices.
@Geod24
Copy link
Member Author

Geod24 commented Aug 14, 2018

Rebased on master, let's see.

Copy link
Contributor

@JinShil JinShil left a comment

Choose a reason for hiding this comment

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

Yup, I still like it.

Copy link
Contributor

@wilzbach wilzbach left a comment

Choose a reason for hiding this comment

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

Yeah same here. One small step forward (:

@Geod24
Copy link
Member Author

Geod24 commented Aug 16, 2018

Anything else ? Got a few changes depending on this PR (to be precise, on toDString).

@wilzbach
Copy link
Contributor

I think this is just pending/blocked on Ian's change request. @ibuclaw are you okay with moving forward here?

@JinShil JinShil merged commit 0f735fe into dlang:master Aug 18, 2018
@Geod24 Geod24 deleted the json branch August 18, 2018 03:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants