Trash Day 2
Trash
On the second day, you should specify test cases for the MiniJava syntax.
Anatomy of a Test Suite
The initial project contains an example test suite
tests/example.spt
:
module example
language MiniJava
start symbol Start
test constant [[42]] parse succeeds
test incomplete constant [[4]] parse fails
The first three lines specify the name of the test suite, the language under test, and the start symbol used for a test.
The next two lines specify a positive and a negative test case (for now, you can ignore the third test case).
Each test case consists of a name, a code fragment in double square brackets, and a condition which determines what kind of test should be performed (parsing) and what the expected outcome is (success or failure).
You can run the test suite from the
Transform menu.
This will open the
Spoofax Test Runner View which provides you information about failing and succeeding test cases in a test suite.
You can also get instant feedback while editing a test suite.
MiniJava Syntax Definition
In order to write your own test cases, you need to understand MiniJava's syntax.
Here is the ultimate MiniJava syntax definition from the book "Modern Compiler Implementation in Java", 2nd edition.
The MiniJava syntax definition from the book says nothing about reserved words.
But it states that the meaning of a MiniJava program is given by the meaning as a Java program.
Therefore, you should treat all
reserved words in Java as reserved in MiniJava as well and provide test cases which address this issue.
Test Cases
You can now start writing your own test cases.
Lexical and Context-free Syntax
Start with the lexical syntax and think about valid and invalid identifiers.
Try to focus on corner cases like
- identifiers made of a single character,
- mixings of letters and digits (Which kinds of mixing are allowed? Which are not?),
- underscores in identifiers.
Next, you should walk through the whole syntax definition.
Keep thinking of valid and invalid code fragments.
Identify interesting corner cases and turn them into positive and negative test cases.
Try to keep your test cases small.
Each test case should focus on a single aspect.
For example, a negative test case should only contain one error.
The name of a test case should reflect the aspect it addresses.
You can organise test cases which focus on similar aspects in test suites.
Again, the name of a test suite should reflect these aspects.
Finally, you can organise test suites in subfolders of the
tests/
directory.
Tip: You need to define test cases for the following sorts: Program , MainClass , ClassDecl , VarDecl , MethodDecl , Type , Statement , Exp , ID and INT . For grading, it is required to comply with these sort names literally.
|
Abstract Syntax
Next, you should focus on abstract syntax trees.
Come up with positive test cases which specify the expected ASTs.
test integer constant [[42]] parse to SomeFancyConstructor("42")
Think about good constructor names.
Your ASTs should meet the following requirements:
- Similar things are represented in a similar way, e.g.
- classes without a parent are represented similarly to classes with a parent,
- variable references on the left-hand side and on the right-hand side of assignments should be represented the same way,
- different things are represented differently, e.g.
- field declarations are distinguishable from variable declarations,
- identifiers in declarations are distinguishable from identifiers in references,
- constructor names focus on the semantic of a construct, not on the syntax, e.g.
- binary expressions are named after the operation, not after the operator symbol.
Take care, constructors in other SDF grammars do not always meet these requirements.
Tip: Good ASTs for method definitions and calls represent subtrees for FormalList and ExpList as flat lists.
|
Disambiguation
Next, you need to focus on disambiguation.
Come up with positive test cases which specify the correct ASTs for nested expressions.
As an alternative, you can also specify two fragments in concrete syntax, which should result in the same AST:
test left associative addition [[21 + 14 + 14]] parse to [[(21 + 14) + 14]]
Here you can find a table listing the associativity and priorities of operators in Java.
Tip: Do not focus only on binary expressions.
|
Layout
Finally, you can focus on layout.
Think about places where whitespace is not optional but mandatory and define corresponding positive and negative test cases.
Finish with test cases for single-line comments, standard block comments, and nested block comments.
%GS% Challenge:
Single-line comments cannot only end with a newline character, but also at the end of file.
|