-
Notifications
You must be signed in to change notification settings - Fork 19
Testing strategy #5
Comments
The most important thing according to @matklad (and I agree) is that tests should be as close to the definitions as possible. Our "unit" tests should be as close to the definition of the production that they're testing as possible. (No comment on larger testing harnesses at this time.) |
Incrementally we can start with just the basics we know,
Using spans is probably not needed here. But we should test beyond mere pass/fail; we need to ensure that the precedence and such things are interpreted right. So to do that we can convert the typed AST we make into syn & libsyntax's ASTs and then compare what syn & libsyntax parse things to. I think using
Eventually, we can at least require patches to the grammar before stabilization of features. We also need to include features and such so that we track rustc.
If by "fuzzing" you mean property based testing, then I think we should consider that eventually :) |
Please don't make this the primary testing strategy. It's better to serialize the concrete/abstract syntax to some textual format (JSON, s-expressions, bespoke). That way, you don't depend on a particular AST library quirks, and make it much easier to use the test suite for other parsers. |
@matklad oh sure; that also seems easier for rapid prototyping purposes? don't need to recompile so frequently? |
Yep, and you can use |
@matklad of the serialization formats aforementioned, JSON seems like the most cost effective implementation-time wise...? |
@Centril JSON definitely would be the least controversial, though I find a simple hand-rolled one to be preferable, due to better human-readability and diff ability: struct S {
foo: u32
}
|
Interesting; I think for JSON we might have: { "Root": {
"StructDef": {
"name": { "Ident": "S" },
"fields": [ {
"name": { "Ident": "foo" },
"type": { "PathType": { } }
} ]
}
} } (preserving whitespace and terminals is not something we want to do -- span info can be useful for debugging purposes) |
Curious, what is the reasoning behind that? Specifying a parse tree seems more natural than specifying the AST: you don't have to decide what shape the AST should have, you just specify what exists in concrete syntax. It would be cool if the spec could distinguish |
At least, the canonical grammar as formalized in the GLL / BNF notation shouldn't reason or be explicit about whitespace and such things to make the grammar formalization simpler and readable. Similarly, we shouldn't care about error recovery and reporting. If on the other hand, given the canonical grammar, you can still extract whitespace and terminal information from a generated parser, then by all means, I have no objections to that. :) But the work product of the WG should be the canonical grammar. |
Agree here, but let's unpack this: whitespace & comments are a concern of the lexical specification. And it's the job of the lexer to remove them from the resulting token sequence. Agree that it doesn't make much sense to specify whitespace & comments in the test files (I do that in rust-analyzer, just because I care about heuristic-based attachment of whitesapce to nodes), as long as offsets can be recovered. However, terminals are very much a parser's concern, and should be reflected in the tests imo. From AST's pov,
Agree |
Oh sure;
Hm... 🤔 -- it's not part of the abstract syntax of the language at least; i.e. when we want to talk about the type system and such things then it doesn't matter. But you should be able to talk about it as "turbo-fish" syntax in the grammar itself (and write comments in various places...) which is then displayed in a reasonable way in the spec |
For the record, we're prototyping a Lua cross-checker (between It takes a parse forest from Note that the GLL (shared packed) parse forest is a DAG with maximal sharing and individual full-input parse trees are never instantiated. Their number is pretty much the possible combinations of ambiguous choices, which can get pretty high without extra disambiguation (and we don't have the infrastructure for that yet). We can probably make this work with a JSON input for the non-GLL side (effectively "deserializing" on the fly), but to turn the GLL state into JSON (for external checking) would be just as hard, and would also require the external checker to understand ambiguity, on top of that. |
From today's meeting: we'll start simple with pass/fail and mainly testing against syn/libsyntax to ensure compliance. |
I've been experimenting with a new strategy for the test suite and I wanted to see what people think. The general idea is to create a "conformance test suite". It would consist of:
A sample of what a test might look like is:
Multiple tests can be placed in a single file, so a lot of the little variants should be easy to scan visually. WDYT? I think it would be useful to ensure all parsers interpret the language the same, and it would replace the current debug-output tests for the gll grammar. A risk is that it may be difficult to translate between different tree structures (though in my cursory scans, should be possible). Another concern is that it will be another mountain of about 200 structs to define the tree, and then mountains of boring translation code for the different parsers, though I'm willing to put it together. |
@ehuss If we transition to the dynamically typed approach, you could probably work with a dynamic representation for the other libraries too, which might reduce effort dramatically. Any differences in names/structure could be normalized away with little code, without having to do anything for the parts that are the same everywhere. |
What will the testing strategy look like?
This is a pretty broad, but important topic. I'll just spew some random questions I had:
A few relevant links that I had lying around:
The text was updated successfully, but these errors were encountered: