Skip to content

Commit

Permalink
Integrate Java type checker and compiler into frontend (#2925)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
Co-authored-by: Martin Henz <[email protected]>
  • Loading branch information
3 people authored Apr 13, 2024
1 parent d1c0a45 commit 612f68b
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 36 deletions.
6 changes: 4 additions & 2 deletions craco.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const cracoConfig = {
plugin => plugin.constructor.name === 'InjectManifest'
);
if (injectManifestPlugin) {
injectManifestPlugin.config.maximumFileSizeToCacheInBytes = 17 * 1024 * 1024;
injectManifestPlugin.config.maximumFileSizeToCacheInBytes = 20 * 1024 * 1024;
}

// add rules to pack WASM (for Sourceror)
Expand Down Expand Up @@ -47,9 +47,10 @@ const cracoConfig = {
'https': require.resolve('https-browserify'),
'os': require.resolve('os-browserify/browser'),
'path/posix': require.resolve('path-browserify'),
'process/browser': require.resolve('process/browser'),
'stream': require.resolve('stream-browserify'),
'timers': require.resolve('timers-browserify'),
'url': require.resolve('url/')
'url': require.resolve('url/'),
};

// workaround .mjs files by Acorn
Expand Down Expand Up @@ -138,6 +139,7 @@ const cracoConfig = {
'split-on-first',
'filter-obj',
'@sourceacademy/c-slang',
'java-parser'
),
'^.+\\.module\\.(css|sass|scss)$'
];
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@
"flexboxgrid": "^6.3.1",
"flexboxgrid-helpers": "^1.1.3",
"hastscript": "^9.0.0",
"java-slang": "^1.0.6",
"js-slang": "^1.0.66",
"java-slang": "^1.0.13",
"js-yaml": "^4.1.0",
"konva": "^9.2.0",
"lodash": "^4.17.21",
Expand Down
70 changes: 41 additions & 29 deletions src/commons/utils/JavaHelper.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { compileFromSource, typeCheck } from 'java-slang';
import { BinaryWriter } from 'java-slang/dist/compiler/binary-writer';
import setupJVM, { parseBin } from 'java-slang/dist/jvm';
import { createModuleProxy, loadCachedFiles } from 'java-slang/dist/jvm/utils/integration';
import { Context } from 'js-slang';
Expand All @@ -9,6 +11,33 @@ import DisplayBufferService from './DisplayBufferService';
export async function javaRun(javaCode: string, context: Context) {
let compiled = {};

const stderr = (type: 'TypeCheck' | 'Compile' | 'Runtime', msg: string) => {
context.errors.push({
type: type as any,
severity: 'Error' as any,
location: { start: { line: -1, column: -1 }, end: { line: -1, column: -1 } },
explain: () => msg,
elaborate: () => msg
});
};

const typeCheckResult = typeCheck(javaCode);
if (typeCheckResult.hasTypeErrors) {
const typeErrMsg = typeCheckResult.errorMsgs.join('\n');
stderr('TypeCheck', typeErrMsg);
return Promise.resolve({ status: 'error' });
}

try {
const classFile = compileFromSource(javaCode);
compiled = {
'Main.class': Buffer.from(new BinaryWriter().generateBinary(classFile)).toString('base64')
};
} catch (e) {
stderr('Compile', e);
return Promise.resolve({ status: 'error' });
}

let files = {};
let buffer: string[] = [];

Expand Down Expand Up @@ -46,6 +75,7 @@ export async function javaRun(javaCode: string, context: Context) {
}
return parseBin(new DataView(bytes.buffer));
};

const loadNatives = async (path: string) => {
// dynamic load modules
if (path.startsWith('modules')) {
Expand All @@ -56,6 +86,7 @@ export async function javaRun(javaCode: string, context: Context) {
}
return await import(`java-slang/dist/jvm/stdlib/${path}.js`);
};

const stdout = (str: string) => {
if (str.endsWith('\n')) {
buffer.push(str);
Expand All @@ -67,33 +98,6 @@ export async function javaRun(javaCode: string, context: Context) {
buffer.push(str);
}
};
const stderr = (msg: string) => {
context.errors.push({
type: 'Runtime' as any,
severity: 'Error' as any,
location: {
start: {
line: -1,
column: -1
},
end: {
line: -1,
column: -1
}
},
explain: () => msg,
elaborate: () => msg
});
};

// FIXME: Remove when the compiler is working
try {
const json = JSON.parse(javaCode);
compiled = json;
} catch (e) {
stderr(e);
return Promise.resolve({ status: 'error' });
}

// load cached classfiles from IndexedDB
return loadCachedFiles(() =>
Expand All @@ -119,12 +123,20 @@ export async function javaRun(javaCode: string, context: Context) {
readFileSync: readClassFiles,
readFile: loadNatives,
stdout,
stderr,
stderr: (msg: string) => stderr('Runtime', msg),
onFinish: () => {
resolve(
context.errors.length
? { status: 'error' }
: { status: 'finished', context, value: '' }
: {
status: 'finished',
context,
value: new (class {
toString() {
return ' ';
}
})()
}
);
}
},
Expand Down
7 changes: 7 additions & 0 deletions src/setupTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,10 @@ jest.mock('./commons/utils/notifications/createNotification', () => ({
show: jest.fn()
}
}));

jest.mock('java-slang', () => {
return {
compileFromSource: () => '',
typeCheck: () => ({ hasTypeErrors: false, errorMsgs: [] })
};
});
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -8024,10 +8024,10 @@ java-parser@^2.0.5:
chevrotain-allstar "0.3.1"
lodash "4.17.21"

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

0 comments on commit 612f68b

Please sign in to comment.