Skip to content

Commit 612f68b

Browse files
1001meibryanlohxzmartin-henz
authored
Integrate Java type checker and compiler into frontend (#2925)
* Integrate Java compiler into frontend * Add typechecker from java-slang * Add program terminated succesfully output to Java * Bump java-slang to 1.0.7 * Remove program terminated output from java in frontend * Change ProgramTerminatedSuccessfully to anonymous class in java * Bump java-slang to 1.0.8 * Bump java-slang to 1.0.9 * Add process/browser to craco polyfill * Add java-parser to jest transform ignore patterns * Bump java-slang to 1.0.13 * Add mocks for java-slang functions * Fix wrong error label in java helper * Increase max file size to cache to 20 --------- Co-authored-by: Bryan Loh <bryanlohxz@gmail.com> Co-authored-by: Martin Henz <henz@comp.nus.edu.sg>
1 parent d1c0a45 commit 612f68b

File tree

5 files changed

+57
-36
lines changed

5 files changed

+57
-36
lines changed

craco.config.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const cracoConfig = {
1818
plugin => plugin.constructor.name === 'InjectManifest'
1919
);
2020
if (injectManifestPlugin) {
21-
injectManifestPlugin.config.maximumFileSizeToCacheInBytes = 17 * 1024 * 1024;
21+
injectManifestPlugin.config.maximumFileSizeToCacheInBytes = 20 * 1024 * 1024;
2222
}
2323

2424
// add rules to pack WASM (for Sourceror)
@@ -47,9 +47,10 @@ const cracoConfig = {
4747
'https': require.resolve('https-browserify'),
4848
'os': require.resolve('os-browserify/browser'),
4949
'path/posix': require.resolve('path-browserify'),
50+
'process/browser': require.resolve('process/browser'),
5051
'stream': require.resolve('stream-browserify'),
5152
'timers': require.resolve('timers-browserify'),
52-
'url': require.resolve('url/')
53+
'url': require.resolve('url/'),
5354
};
5455

5556
// workaround .mjs files by Acorn
@@ -138,6 +139,7 @@ const cracoConfig = {
138139
'split-on-first',
139140
'filter-obj',
140141
'@sourceacademy/c-slang',
142+
'java-parser'
141143
),
142144
'^.+\\.module\\.(css|sass|scss)$'
143145
];

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@
5151
"flexboxgrid": "^6.3.1",
5252
"flexboxgrid-helpers": "^1.1.3",
5353
"hastscript": "^9.0.0",
54-
"java-slang": "^1.0.6",
5554
"js-slang": "^1.0.66",
55+
"java-slang": "^1.0.13",
5656
"js-yaml": "^4.1.0",
5757
"konva": "^9.2.0",
5858
"lodash": "^4.17.21",

src/commons/utils/JavaHelper.ts

Lines changed: 41 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { compileFromSource, typeCheck } from 'java-slang';
2+
import { BinaryWriter } from 'java-slang/dist/compiler/binary-writer';
13
import setupJVM, { parseBin } from 'java-slang/dist/jvm';
24
import { createModuleProxy, loadCachedFiles } from 'java-slang/dist/jvm/utils/integration';
35
import { Context } from 'js-slang';
@@ -9,6 +11,33 @@ import DisplayBufferService from './DisplayBufferService';
911
export async function javaRun(javaCode: string, context: Context) {
1012
let compiled = {};
1113

14+
const stderr = (type: 'TypeCheck' | 'Compile' | 'Runtime', msg: string) => {
15+
context.errors.push({
16+
type: type as any,
17+
severity: 'Error' as any,
18+
location: { start: { line: -1, column: -1 }, end: { line: -1, column: -1 } },
19+
explain: () => msg,
20+
elaborate: () => msg
21+
});
22+
};
23+
24+
const typeCheckResult = typeCheck(javaCode);
25+
if (typeCheckResult.hasTypeErrors) {
26+
const typeErrMsg = typeCheckResult.errorMsgs.join('\n');
27+
stderr('TypeCheck', typeErrMsg);
28+
return Promise.resolve({ status: 'error' });
29+
}
30+
31+
try {
32+
const classFile = compileFromSource(javaCode);
33+
compiled = {
34+
'Main.class': Buffer.from(new BinaryWriter().generateBinary(classFile)).toString('base64')
35+
};
36+
} catch (e) {
37+
stderr('Compile', e);
38+
return Promise.resolve({ status: 'error' });
39+
}
40+
1241
let files = {};
1342
let buffer: string[] = [];
1443

@@ -46,6 +75,7 @@ export async function javaRun(javaCode: string, context: Context) {
4675
}
4776
return parseBin(new DataView(bytes.buffer));
4877
};
78+
4979
const loadNatives = async (path: string) => {
5080
// dynamic load modules
5181
if (path.startsWith('modules')) {
@@ -56,6 +86,7 @@ export async function javaRun(javaCode: string, context: Context) {
5686
}
5787
return await import(`java-slang/dist/jvm/stdlib/${path}.js`);
5888
};
89+
5990
const stdout = (str: string) => {
6091
if (str.endsWith('\n')) {
6192
buffer.push(str);
@@ -67,33 +98,6 @@ export async function javaRun(javaCode: string, context: Context) {
6798
buffer.push(str);
6899
}
69100
};
70-
const stderr = (msg: string) => {
71-
context.errors.push({
72-
type: 'Runtime' as any,
73-
severity: 'Error' as any,
74-
location: {
75-
start: {
76-
line: -1,
77-
column: -1
78-
},
79-
end: {
80-
line: -1,
81-
column: -1
82-
}
83-
},
84-
explain: () => msg,
85-
elaborate: () => msg
86-
});
87-
};
88-
89-
// FIXME: Remove when the compiler is working
90-
try {
91-
const json = JSON.parse(javaCode);
92-
compiled = json;
93-
} catch (e) {
94-
stderr(e);
95-
return Promise.resolve({ status: 'error' });
96-
}
97101

98102
// load cached classfiles from IndexedDB
99103
return loadCachedFiles(() =>
@@ -119,12 +123,20 @@ export async function javaRun(javaCode: string, context: Context) {
119123
readFileSync: readClassFiles,
120124
readFile: loadNatives,
121125
stdout,
122-
stderr,
126+
stderr: (msg: string) => stderr('Runtime', msg),
123127
onFinish: () => {
124128
resolve(
125129
context.errors.length
126130
? { status: 'error' }
127-
: { status: 'finished', context, value: '' }
131+
: {
132+
status: 'finished',
133+
context,
134+
value: new (class {
135+
toString() {
136+
return ' ';
137+
}
138+
})()
139+
}
128140
);
129141
}
130142
},

src/setupTests.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,10 @@ jest.mock('./commons/utils/notifications/createNotification', () => ({
88
show: jest.fn()
99
}
1010
}));
11+
12+
jest.mock('java-slang', () => {
13+
return {
14+
compileFromSource: () => '',
15+
typeCheck: () => ({ hasTypeErrors: false, errorMsgs: [] })
16+
};
17+
});

yarn.lock

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8024,10 +8024,10 @@ java-parser@^2.0.5:
80248024
chevrotain-allstar "0.3.1"
80258025
lodash "4.17.21"
80268026

8027-
java-slang@^1.0.6:
8028-
version "1.0.6"
8029-
resolved "https://registry.yarnpkg.com/java-slang/-/java-slang-1.0.6.tgz#34a68954a8dfb5bde8572d49a6bea170d7026749"
8030-
integrity sha512-CHq2s9xuzuuPfygRp9pQncfPfIuzpHivXn3wfy4QBiQ801IvdVFL3w/nV6qQn6GUG+kvOU+qCuxUFsFH8X5Dhg==
8027+
java-slang@^1.0.13:
8028+
version "1.0.13"
8029+
resolved "https://registry.yarnpkg.com/java-slang/-/java-slang-1.0.13.tgz#601454c9dd28a41ea6918dab51a7e65401d2c2d9"
8030+
integrity sha512-xBh84Gcp7iyc3o9bWDbaIa7GXf75tpUVmDrd/gXIAU/gxNARitJdl5xCjQW5y4iesqwucV7cY+Ewx6MIt4xKeQ==
80318031
dependencies:
80328032
"@types/lodash" "^4.14.198"
80338033
java-parser "^2.0.5"

0 commit comments

Comments
 (0)