Skip to content

Commit eeb3c90

Browse files
authored
Merge pull request #32 from source-academy/compiler
Compiler cleanup
2 parents 91aa7e1 + 635ef6a commit eeb3c90

32 files changed

+1601
-1250
lines changed

.eslintignore

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ node_modules
22
dist
33

44
src/ast
5-
src/compiler
65
src/types
76

8-
**/__tests__/*
7+
**/__tests__/*

.prettierignore

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,5 @@ node_modules
22
dist
33

44
src/ast
5-
src/compiler
65
src/ec-evaluator
7-
src/types
6+
src/types

docs/specs/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
PDFLATEX = latexmk -pdf
22

3-
SPECSCOMPONENT = JVM csec
3+
SPECSCOMPONENT = JVM csec compiler
44

55
SPECS = $(SPECSCOMPONENT:%=java_%)
66

docs/specs/java_compiler.tex

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
\input java_header.tex
2+
3+
\begin{document}
4+
5+
\docheader{2024}{Java}{Compiler}{Martin Henz, Lai Mei Tin}
6+
7+
\input java_intro.tex
8+
9+
\input java_bnf.tex
10+
11+
\input java_compiler_bnf.tex
12+
13+
\input java_compiler_bnf_cont.tex
14+
15+
\input java_compiler_constraints.tex
16+
17+
\input java_identifiers.tex
18+
19+
\input java_compiler_operator_precedence.tex
20+
21+
\end{document}

docs/specs/java_compiler_bnf.tex

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
\begin{alignat*}{9}
2+
&& \textit{compilation-unit} && \quad ::= & \quad && \textit{import-declaration} ... \ \textit{class-declaration} && \\[1mm]
3+
&& \textit{import-declaration} && \quad ::= & \quad && \textit{single-type-import-declaration} && \\
4+
&& && | & \quad && \textit{type-import-on-demand-declaration} && \\[1mm]
5+
&& \textit{single-type-import-declaration} && \quad ::= & \quad && \textbf{\texttt{import}} \ \textit{type-name} \ \textbf{\texttt{;}} && \\[1mm]
6+
&& \textit{type-import-on-demand-declaration} && \quad ::= & \quad && \textbf{\texttt{import}} \ \textit{package-name} \ \textbf{\texttt{$.\ *$}} && \\[1mm]
7+
&& \textit{class-declaration} && \quad ::= & \quad && \textbf{\texttt{public class}} \ \textit{identifier} \ \textit{class-body} && \\[1mm]
8+
&& \textit{class-body} && \quad ::= & \quad && \textbf{\texttt{\{}} \textit{class-body-declaration} ... \textbf{\texttt{\}}} && \\[1mm]
9+
&& \textit{class-body-declaration} && \quad ::= & \quad && \textit{field-declaration} && \\
10+
&& && | & \quad && \textit{method-declaration} && \\
11+
&& && | & \quad && \textit{constructor-declaration} && \\[2mm]
12+
&& \textit{field-declaration} && \quad ::= & \quad && \textit{field-modifier} \ \textit{type} \ \textit{identifier} \ \textbf{\texttt{;}} && \\[1mm]
13+
&& \textit{field-modifier} && \quad ::= & \quad && \textbf{\texttt{public}} \ [ \ \textbf{\texttt{static}} \ ] && \\[1mm]
14+
&& \textit{method-declaration} && \quad ::= & \quad && \textit{method-modifier} \ \textit{method-header} \ \textit{block} && \\[1mm]
15+
&& \textit{method-modifier} && \quad ::= & \quad && \textbf{\texttt{public}} \ [ \ \textbf{\texttt{static}} \ ] && \\[1mm]
16+
&& \textit{method-header} && \quad ::= & \quad && \textit{result-type} \ \textit{method-declarator} && \\[1mm]
17+
&& \textit{result-type} && \quad ::= & \quad && \textit{type} \ | \ \textbf{\texttt{void}} && \\[1mm]
18+
&& \textit{method-declarator} && \quad ::= & \quad && \textit{identifier} \ \textbf{\texttt{(}} \textit{formal-parameters} \textbf{\texttt{)}} && \\[1mm]
19+
&& \textit{formal-parameters} && \quad ::= & \quad && \epsilon \ | \ \textit{formal-parameter} \
20+
| \ \textit{formal-parameter} \ (\textbf{\texttt{,}} \textit{formal-parameter}) ... &&\\[2mm]
21+
&& \textit{formal-parameter} && \quad ::= & \quad && \textit{type} \ \textit{identifer} && \\[2mm]
22+
&& \textit{constructor-declaration} && \quad ::= & \quad && \textit{identifier} \ \textbf{\texttt{(}} \textit{formal-parameters} \textbf{\texttt{)}} \ \textit{block} && \\[2mm]
23+
&& \textit{type} && \quad ::= & \quad && \textit{primitive-type} \ | \ \textit{reference-type} && \\[1mm]
24+
&& \textit{primitive-type} && \quad ::= & \quad && \textbf{\texttt{int}} \ | \ \textbf{\texttt{float}} \ | \ \textbf{\texttt{long}} \ | \ \textbf{\texttt{double}} \ | \ \textbf{\texttt{boolean}} \ | \ \textbf{\texttt{char}} && \\[1mm]
25+
&& \textit{reference-type} && \quad ::= & \quad && \textit{identifer} \ (\textbf{\texttt{\string[]}})&& \\[2mm]
26+
&& \textit{block} && \quad ::= & \quad && \textbf{\texttt{\{}} \textit{block-statement} ... \textbf{\texttt{\}}} && \\[1mm]
27+
&& \textit{block-statement} && \quad ::= & \quad && \textit{local-variable-declaration-statement} && \\
28+
&& && | & \quad && \textit{statement} && \\[1mm]
29+
&& \textit{local-variable-declaration-statement} && \quad ::= & \quad && \textit{type} \ \textit{identifier} \ [ \ \textbf{\texttt{=}} \ \textit{variable-initializer} \ ] \ \textbf{\texttt{;}} && \\[2mm]
30+
&& \textit{variable-initializer} && \quad ::= & \quad && \textit{expression} \ | \ \textbf{\texttt{\{}} \textit{expressions} \ \textbf{\texttt{\}}} && \\[2mm]
31+
&& \textit{statement} && \quad ::= & \quad && \textit{block} && \\
32+
&& && | & \quad && \textit{if-statement} && \\
33+
&& && | & \quad && \textit{for-statement} && \\
34+
&& && | & \quad && \textit{while-statement} && \\
35+
&& && | & \quad && \textit{do-statement} && \\
36+
&& && | & \quad && \textbf{\texttt{;}} && \\
37+
&& && | & \quad && \textbf{\texttt{break ;}} && \\
38+
&& && | & \quad && \textbf{\texttt{continue ;}} && \\
39+
&& && | & \quad && \textbf{\texttt{return}} \ [ \ \textit{expression} \ ] \ \textbf{\texttt{;}} && \\
40+
&& && | & \quad && \textit{expression-statement} && \\
41+
&& \textit{if-statement} && \quad ::= & \quad && \textbf{\texttt{if (}} \textit{statement-expression} \textbf{\texttt{)}} \ \textit{statement} \ [ \ \textbf{\texttt{else }} \textit{statement} \ ]&& \\[1mm]
42+
&& \textit{for-statement} && \quad ::= & \quad && \textbf{\texttt{for (}} \ [ \ \textit{for-init} \ ] \ \textbf{\texttt{;}} \ [ \ \textit{expression} \ ] \ \textbf{\texttt{;}} \ [ \ \textit{for-update} \ ] \ \textbf{\texttt{)}} \textit{statement} && \\[1mm]
43+
\end{alignat*}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
\begin{alignat*}{9}
2+
&& \textit{for-init} && \quad ::= & \quad && \textit{local-variable-declaration} \ | \ \textit{statement-expression-list} && \\[1mm]
3+
&& \textit{for-update} && \quad ::= & \quad && \textit{statement-expression-list} && \\[1mm]
4+
&& \textit{while-statement} && \quad ::= & \quad && \textbf{\texttt{while (}} \textit{expression} \textbf{\texttt{)}} \ \textit{statement} && \\[1mm]
5+
&& \textit{do-statement} && \quad ::= & \quad && \textbf{\texttt{do}} \ \textit{statement} \ \textbf{\texttt{while (}} \ \textit{expression} \ \textbf{\texttt{) ;}}&& \\[1mm]
6+
&& \textit{statement-expression-list} && \quad ::= & \quad && \epsilon \ | \ \textit{statement-expression} \ (\textbf{\texttt{,}} \textit{statement-expression}) ... && \\[2mm]
7+
&& \textit{expression-statement} && \quad ::= & \quad && \textit{statement-expression} \ \textbf{\texttt{;}} && \\[1mm]
8+
&& \textit{statement-expression} && \quad ::= & \quad && \textit{assignment} \ | \ \textit{unary-expression} \ | \ \textit{method-invocation} && \\[2mm]
9+
&& \textit{assignment} && \quad ::= & \quad && \textit{left-hand-side} \ \textit{assignment-operator} \ \textit{expression} && \\[1mm]
10+
&& \textit{left-hand-side} && \quad ::= & \quad && \textit{expression-name} \ | \ \textit{field-access} \ | \ \textit{array-access} && \\[2mm]
11+
&& \textit{assignment-operator} && \quad ::= & \quad && \textbf{\texttt{=}} \ | \ \textbf{\texttt{+=}} \ | \ \textbf{\texttt{-=}} \ | \ \textbf{\texttt{*=}} \ | \ \textbf{\texttt{/=}} \ | \ \textbf{\texttt{\%=}} \ | \ \textbf{\texttt{\&=}} \ | \ \textbf{\texttt{\string^=}} \ | \ \textbf{\texttt{|=}} \ | \ \textbf{\texttt{<}}\textbf{\texttt{<=}} \ | \ \textbf{\texttt{>}}\textbf{\texttt{>=}} \ | \ \textbf{\texttt{>}}\textbf{\texttt{>}}\textbf{\texttt{>=}} && \\[1mm]
12+
&& \textit{expressions} && \quad ::= & \quad && \epsilon \ | \ \textit{expression} \ (\textbf{\texttt{,}}\textit{expression}) ...&& \\
13+
&& \textit{expression} && \quad ::= & \quad && \textit{assignment} && \\
14+
&& && | & \quad && \textit{non-assignment-expression} && \\
15+
&& \textit{non-assignment-expression} && \quad ::= & \quad && \textit{unary-expression} && \\
16+
&& && | & \quad && \textit{binary-expression} && \\
17+
&& && | & \quad && \textit{ternary-expression} && \\
18+
&& && | & \quad && \textit{primary} && \\
19+
&& && | & \quad && \textit{expression-name} && \\
20+
&& \textit{primary} && \quad ::= & \quad && \textit{literal} && \\
21+
&& && | & \quad && \textit{field-access} && \\
22+
&& && | & \quad && \textit{array-access} && \\
23+
&& && | & \quad && \textit{method-invocation} && \\
24+
&& && | & \quad && \textit{class-instance-creation-expression} && \\[2mm]
25+
&& \textit{unary-expression} && \quad ::= & \quad && \textit{unary-operator} \ \textit{expression} && \\
26+
&& && | & \quad && \textit{expression} \ \textit{increment-decrement-operator} && \\[1mm]
27+
&& && | & \quad && \textit{increment-decrement-operator} \ \textit{expression} && \\[1mm]
28+
&& \textit{unary-operator} && \quad ::= & \quad && \textbf{\texttt{+}} \ | \ \textbf{\texttt{-}} \ | \ \textbf{\texttt{!}} \ | \ \textbf{\texttt{\textasciitilde}} && \\[1mm]
29+
&& \textit{increment-decrement-operator} && \quad ::= & \quad && \textbf{\texttt{++}} \ | \ \textbf{\texttt{-}}\textbf{\texttt{-}} && \\[1mm]
30+
&& \textit{binary-expression} && \quad ::= & \quad && \textit{expression} \ \textit{binary-operator} \ \textit{expression} && \\[1mm]
31+
&& \textit{binary-operator} && \quad ::= & \quad && \textbf{\texttt{+}} \ | \ \textbf{\texttt{-}} \ | \ \textbf{\texttt{*}} \ | \ \textbf{\texttt{/}} \ | \ \textbf{\texttt{\%}} \ | \ \textbf{\texttt{\&}} \ | \ \textbf{\texttt{\string^}} \ | \ \textbf{\texttt{|}} \ | \ \textbf{\texttt{<}}\textbf{\texttt{<}} \ | \ \textbf{\texttt{>}}\textbf{\texttt{>}} \ | \ \textbf{\texttt{\&\&}} \ | \ \textbf{\texttt{||}} \ | \ \textbf{\texttt{==}} \ | \ \textbf{\texttt{!=}} \ | \ \textbf{\texttt{<=}} \ | \ \textbf{\texttt{>=}} && \\
32+
&& && | & \quad && \textbf{\texttt{<}} \ | \ \textbf{\texttt{>}} \ | \ \textbf{\texttt{>}}\textbf{\texttt{>}}\textbf{\texttt{>}} && \\[1mm]
33+
&& \textit{ternary-expression} && \quad ::= & \quad && \textit{expression} \ \textbf{\texttt{?}} \ \textit{expression} \ \textbf{\texttt{:}} \ \textit{non-assignment-expression} && \\[1mm]
34+
&& \textit{field-access} && \quad ::= & \quad && (\textbf{\texttt{this}} \ | \ \textit{expression-name})
35+
\textbf{\texttt{.}}
36+
\textit{identifier} && \\[2mm]
37+
&& \textit{array-access} && \quad ::= & \quad && \textit{expression} \ [ \ \textit{expression} \ ] && \\[2mm]
38+
&& \textit{method-invocation} && \quad ::= & \quad && \textit{expression-name} \ \textbf{\texttt{(}} \textit{expression} ... \textbf{\texttt{)}} && \\
39+
&& && | & \quad && \textbf{\texttt{this}} \textbf{\texttt{.}} \textit{identifier} \ \textbf{\texttt{(}} \textit{expression} ... \textbf{\texttt{)}} && \\
40+
&& \textit{class-instance-creation-expression} && \quad ::= & \quad && \textbf{\texttt{new}} \ \textit{identifier} \ \textbf{\texttt{(}} \textit{expression} ... \textbf{\texttt{)}} && \\[2mm]
41+
&& \textit{expression-name} && \quad ::= & \quad && \textit{identifier} \ | \ \textit{expression-name} \textbf{\texttt{.}} \textit{identifier} && \\[1mm]
42+
&& \textit{type-name} && \quad ::= & \quad && \textit{identifier} \ | \ \textit{package-name} \textbf{\texttt{.}} \textit{identifier} && \\[1mm]
43+
&& \textit{package-name} && \quad ::= & \quad && \textit{identifier} \ | \ \textit{package-name} \textbf{\texttt{.}} \textit{identifier} && \\[1mm]
44+
&& \textit{literal} && \quad ::= & \quad && number \ | \ string \ | \ \textbf{\texttt{true}} \ | \ \textbf{\texttt{false}} \ | \ \textbf{\texttt{null}}&& \\[2mm]
45+
\end{alignat*}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
\subsection*{Constraints}
2+
Besides adhering to the BNF-form specification, the program also needs to satisfy several additional constraints. These constraints are listed separately below to capture aspects of the sublanguage that would be challenging to express solely through the BNF-form.
3+
\begin{itemize}
4+
\item The program should be free of any type errors.
5+
\item The program should contain only ASCII characters.
6+
\item There should be exactly one method in the class with the method signature \textbf{public static void main(String[])}.
7+
\item Type conversion is not supported at all. For example, conversion from \textbf{int} to \textbf{long} is not supported. Hence, both operands of a binary operator must have exactly same type.
8+
\item For unary expressions and conditional expressions, the operands could only have type \textbf{int/boolean}.
9+
\item The program shall not have any overloaded method.
10+
\end{itemize}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
\subsection*{Operator precedence}
2+
The table below lists all unary operators, binary operators, and assigment operators that are valid according to the BNF-form above, from highest to lowest precedence.
3+
4+
\begin{center}
5+
6+
\begin{tabularx}{1.0\textwidth} {
7+
| >{\centering\arraybackslash}X
8+
| >{\centering\arraybackslash}X
9+
| >{\centering\arraybackslash}X | }
10+
\hline
11+
operator(s) & description & associativity \\
12+
\hline
13+
\textbf{\texttt{++ -}}\textbf{\texttt{-}} & unary post increment/decrement & left to right \\
14+
\hline
15+
\textbf{\texttt{+ - !\ \textasciitilde }} \textbf{\texttt{++ -}}\textbf{\texttt{-}} & unary pre operations & right to left \\
16+
\hline
17+
\textbf{\texttt{* / \%}} & multiplicative & left to right \\
18+
\hline
19+
\textbf{\texttt{+ -}} & additive & left to right \\
20+
\hline
21+
\textbf{\texttt{<}}\textbf{\texttt{<}} \ \textbf{\texttt{>}}\textbf{\texttt{>}} \ \textbf{\texttt{>}}\textbf{\texttt{>}}\textbf{\texttt{>}} & bit shift & left to right \\
22+
\hline
23+
\textbf{\texttt{< <= > >=}} & relational & left to right \\
24+
\hline
25+
\textbf{\texttt{== !=}} & equality & left to right \\
26+
\hline
27+
\textbf{\texttt{\&}} & bitwise AND & left to right \\
28+
\hline
29+
\textbf{\texttt{\string^}} & bitwise XOR & left to right \\
30+
\hline
31+
\textbf{\texttt{|}} & bitwise OR & left to right \\
32+
\hline
33+
\textbf{\texttt{\&\&}} & logical AND & left to right \\
34+
\hline
35+
\textbf{\texttt{||}} & logical OR & left to right \\
36+
\hline
37+
\textbf{\texttt{= += -= *= /= \%= \&= \string^= |= }} \textbf{\texttt{<}}\textbf{\texttt{<=}} \ \textbf{\texttt{>}}\textbf{\texttt{>=}} \ \textbf{\texttt{>}}\textbf{\texttt{>}}\textbf{\texttt{>=}} & assignment & right to left \\
38+
\hline
39+
\end{tabularx}
40+
41+
\end{center}

src/compiler/__tests__/test-utils.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@ export type testCase = {
1515

1616
const debug = false;
1717
const pathToTestDir = "./src/compiler/__tests__/";
18-
const javaPegGrammar = fs.readFileSync('./src/compiler/__tests__/main.pegjs', 'utf-8');
18+
const javaPegGrammar = fs.readFileSync('./src/compiler/main.pegjs', 'utf-8');
1919
const parser = peggy.generate(javaPegGrammar, {
2020
allowedStartRules: ["CompilationUnit"],
2121
});
2222
const compiler = new Compiler();
2323
const binaryWriter = new BinaryWriter();
2424

25-
export function runTest(program: string, expectedResult: string) {
25+
export function runTest(program: string, expectedLines: string[]) {
2626
const ast = parser.parse(program);
2727
expect(ast).not.toBeNull();
2828

@@ -36,10 +36,12 @@ export function runTest(program: string, expectedResult: string) {
3636
const prevDir = process.cwd();
3737
process.chdir(pathToTestDir);
3838
execSync("java -noverify Main > output.log 2> err.log");
39-
const actualResult = fs.readFileSync("./output.log", 'utf-8');
39+
40+
// ignore difference between \r\n and \n
41+
const actualLines = fs.readFileSync("./output.log", 'utf-8').split(/\r?\n/).slice(0, -1);
4042
process.chdir(prevDir);
4143

42-
expect(actualResult).toBe(expectedResult);
44+
expect(actualLines).toStrictEqual(expectedLines);
4345
}
4446

4547
describe("compiler's test utils", () => {

src/compiler/__tests__/tests/arithmeticExpression.test.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@ const testCases: testCase[] = [
8383
export const arithmeticExpressionTest = () => describe("arithmetic expression", () => {
8484
for (let testCase of testCases) {
8585
const { comment: comment, program: program, expectedLines: expectedLines } = testCase;
86-
const expectedResult = expectedLines.join("\n") + "\n";
87-
it(comment, () => runTest(program, expectedResult));
86+
it(comment, () => runTest(program, expectedLines));
8887
}
8988
});

0 commit comments

Comments
 (0)