Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[mycpp] translate % to StrFormat() #1430

Merged
merged 4 commits into from Dec 20, 2022
Merged

[mycpp] translate % to StrFormat() #1430

merged 4 commits into from Dec 20, 2022

Conversation

melvinw
Copy link
Collaborator

@melvinw melvinw commented Dec 18, 2022

No description provided.

@melvinw melvinw requested a review from andychu December 18, 2022 19:00
@melvinw melvinw marked this pull request as ready for review December 18, 2022 19:00
@melvinw
Copy link
Collaborator Author

melvinw commented Dec 18, 2022

I don't understand the logic in cppgen_pass.py super well yet, but this seems to work. @andychu is this missing anything?

if isinstance(args[0], StrExpr):
fmt = 'StrFormat(%s' % escape_format_str(args[0].value)
else:
fmt = 'dynamic_fmt_dummy('
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this still necessary? I thought this is what we want to get rid of

fmt_types = [self.types[arg] for arg in rest]
temp_name = self._WriteFmtFunc(fmt, fmt_types)
self.fmt_ids[o] = temp_name
fmt = escape_format_str(args[0].value)
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe pedantic, but how about naming this:

quoted_fmt = PythonStringLiteral(args[0].value) 

? Logically that is the operation we want -- create a python string literal from a string


Digression (probably thinking about my latest Zulip posts :) --

For some reason I think of "escaping" as using an "escape character", although I realize using such prefixes is a common method of "quoting" (turning special chars / operator chars into literals)

e.g.

  • \n in C/JSON is an escape sequence, but I wouldn't call it quoting
  • \\ in C/JSON is technically quoting, equivalent to '\' in shell

I also think of & in HTML also as escaping

Or maybe this is a bogus distinction and they are synonyms :)

@@ -47,6 +47,9 @@ def run_tests():
x = 'x'
print("%s\tb\n%s\td\n" % (x, x))

fmt = "%d"
print(fmt % 10)
Copy link
Contributor

Choose a reason for hiding this comment

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

StrFormat() already has good coverage, but I would add a few more cases here because it's very easy and the assertions get checked "for free"

The test harness compares stdout of C++ and Python and then diffs them

that's ninja mycpp-logs-equal, which is part of mycpp/TEST.sh test-translator

@melvinw
Copy link
Collaborator Author

melvinw commented Dec 20, 2022

Pushed a few changes. Have a look?

Turns out adding support for arbitrary expressions as format strings was pretty easy. Just had to call accept()

Copy link
Contributor

@andychu andychu left a comment

Choose a reason for hiding this comment

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

Looks great, thank you!

fputs("\n", stdout);
}

// Like print(..., file=sys.stderr), but Python code explicitly calls it.
void println_stderr(Str* s) {
fputs(s->data(), stderr);
for (int i = 0; i < len(s); ++i) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Ah I see, I guess this was necessary to make tests pass with NUL bytes!

When we do the C I/O -> POSIX I/O changes, I think this will end up using man 2 write

write(0, s->data(), len(s))
write(0, "\n", 1)

@andychu andychu merged commit bf828c9 into soil-staging Dec 20, 2022
@andychu
Copy link
Contributor

andychu commented Dec 20, 2022

Also one interesting thing is that it appears it's MyPy that's giving the compile error on %z ? I thought that we did it in mycpp, but no

Also it appears we let through %x and it becomes a C++ compile error, not a translation error

i.e. there is a gap between what we support and what Python supports (and MyPy checks). I would like to tighten those things up to help contributors avoid errors in the future

I started mycpp/examples/invalid* to check those

@melvinw
Copy link
Collaborator Author

melvinw commented Dec 20, 2022

Ah right! You mentioned this on the other PR and I forgot. I'll send a PR to do some validation on the fmt strings

@melvinw melvinw deleted the dynfmt branch December 20, 2022 16:37
@andychu
Copy link
Contributor

andychu commented Dec 20, 2022

I added mycpp/examples/invalid_format_strings.py in this commit (currently in soil-staging, will be on master)

a4607aa

Which can be run with mycpp/TEST.sh test-invalid-examples

A flaw with this testing method and mycpp is that it only allows ONE error per file

It would be better if you could assert that the file has 5 errors, but unfortunately no

@andychu
Copy link
Contributor

andychu commented Dec 20, 2022

Basically I want to eventually rewrite mycpp to get rid of MyPy, and hopefully the tests will guide us! :)

@andychu
Copy link
Contributor

andychu commented Dec 20, 2022

Yeah I should have put in some validation in mycpp/format_strings.py, but that still exists and can be reused

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.

None yet

2 participants