Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/compiler #483

Open
wants to merge 89 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
89 commits
Select commit Hold shift + click to select a range
95131df
Init
happytomatoe Sep 24, 2024
53b5a0b
WIP
happytomatoe Sep 24, 2024
1f3b3f4
WIP
happytomatoe Sep 24, 2024
240aedc
WIP
happytomatoe Sep 25, 2024
3d6f8be
WIP
happytomatoe Sep 25, 2024
49075d7
WIP
happytomatoe Sep 25, 2024
f9dab02
Add symbol table. Add validator skeleton
happytomatoe Sep 25, 2024
029f124
Add more validations
happytomatoe Sep 26, 2024
d07a587
Add more validations
happytomatoe Sep 26, 2024
3a69078
Add unknown subroutine return type error
happytomatoe Sep 27, 2024
b541d22
Add unknown type error
happytomatoe Sep 27, 2024
ab1e0c9
Add CFG for simple cases
happytomatoe Sep 27, 2024
59f7507
Add not all pahts retun validation
happytomatoe Sep 27, 2024
730f72e
Add print binary tree function
happytomatoe Sep 28, 2024
d61c6ca
Add validations for subroutine call
happytomatoe Sep 28, 2024
2fb01eb
Add builtin functions
happytomatoe Sep 28, 2024
81193e2
Add function/method called as function/method
happytomatoe Sep 28, 2024
04d720f
Add more validations
happytomatoe Sep 28, 2024
1511c94
Add int out of range validation
happytomatoe Sep 28, 2024
c40bfdd
Add field cant be referenced in a function validation
happytomatoe Sep 28, 2024
32b91f7
this can't be referenced in a function validation
happytomatoe Sep 28, 2024
d612816
Fix bug in validation
happytomatoe Sep 29, 2024
5716258
WIP
happytomatoe Sep 29, 2024
aee5ec7
WIP
happytomatoe Sep 29, 2024
fec5790
WIP
happytomatoe Oct 3, 2024
3c1185a
WIP
happytomatoe Oct 3, 2024
af250f2
WIP
happytomatoe Oct 3, 2024
cf2c04c
WIP
happytomatoe Oct 3, 2024
ecadfb2
WIP
happytomatoe Oct 3, 2024
be5142a
WIP
happytomatoe Oct 3, 2024
1b9a348
WIP
happytomatoe Oct 3, 2024
afbf33b
WIP
happytomatoe Oct 3, 2024
faef67d
Fix lexer error handling
happytomatoe Oct 3, 2024
dd918cb
WIP
happytomatoe Oct 3, 2024
ae65cc5
WIP
happytomatoe Oct 3, 2024
694dbcd
Add compiler validate methods
happytomatoe Oct 3, 2024
6bd99b8
WIP
happytomatoe Oct 3, 2024
d67729e
WIP
happytomatoe Oct 4, 2024
375001d
WIP
happytomatoe Oct 4, 2024
a170adf
Fix bug - when creating new file there is an error
happytomatoe Oct 4, 2024
aa8a8ca
Fix incorrect error message
happytomatoe Oct 4, 2024
e8e9dd8
Merge branch 'main' of https://github.com/nand2tetris/web-ide into fe…
happytomatoe Oct 4, 2024
4a51caf
WIP
happytomatoe Oct 4, 2024
ae414f2
WIP
happytomatoe Oct 4, 2024
771c2cd
Bug fixes
happytomatoe Oct 4, 2024
d92b385
WIP
happytomatoe Oct 4, 2024
4ae5997
WIP
happytomatoe Oct 4, 2024
d5c7f27
WIP
happytomatoe Oct 4, 2024
f1c9ea3
WIP
happytomatoe Oct 4, 2024
560f043
WIP
happytomatoe Oct 8, 2024
1c0c9ab
WIP
happytomatoe Oct 8, 2024
2aba5fb
WIP
happytomatoe Oct 8, 2024
d27f391
WIP
happytomatoe Oct 8, 2024
ae9be57
WIP
happytomatoe Oct 8, 2024
1317635
WIP
happytomatoe Oct 8, 2024
06432ba
WIP
happytomatoe Oct 8, 2024
46998c6
WIP
happytomatoe Oct 8, 2024
4970648
WIP
happytomatoe Oct 8, 2024
8030509
WIP
happytomatoe Oct 8, 2024
c05caa9
WIP
happytomatoe Oct 8, 2024
074b74a
WIP
happytomatoe Oct 8, 2024
f4d54d8
WIP
happytomatoe Oct 8, 2024
c5d8243
Used string enum for tagged error types
Oct 9, 2024
dbf7d80
Fix minor bug
happytomatoe Oct 11, 2024
8681e06
WIP
happytomatoe Oct 11, 2024
6c5ec41
Change tests to use FileSystem
happytomatoe Oct 11, 2024
98f696e
WIP
happytomatoe Oct 11, 2024
12edbb1
WIP
happytomatoe Oct 11, 2024
1dfc0ce
Remove ! signs
happytomatoe Oct 11, 2024
70cbcec
WIP
happytomatoe Oct 11, 2024
30f1b9c
Format error.ts file
Oct 11, 2024
ce31d3a
WIP
happytomatoe Oct 11, 2024
bf7acd0
Fix bug in jack lexer. Fix cli for compiler
happytomatoe Oct 17, 2024
179a39c
Merge remote-tracking branch 'fork/feat/compilererrors' into feat/com…
happytomatoe Oct 17, 2024
3e35604
Fix bugs
happytomatoe Oct 17, 2024
7604ef5
Generate antlr files
happytomatoe Oct 17, 2024
773cf3d
Migrate to antlr4ng
happytomatoe Oct 20, 2024
7c154b9
WIP
happytomatoe Oct 20, 2024
4bcce0a
WIP
happytomatoe Oct 20, 2024
8b71fdb
WIP
happytomatoe Oct 20, 2024
b573d00
WIP
happytomatoe Oct 20, 2024
7924123
WIP
happytomatoe Oct 20, 2024
8afba76
WIP
happytomatoe Oct 20, 2024
2dbf34d
Fix formatting and lint errors
happytomatoe Oct 20, 2024
a68a248
WIP
happytomatoe Oct 21, 2024
a2620ec
WIP
happytomatoe Oct 22, 2024
d41d95e
WIP
happytomatoe Oct 22, 2024
078f95b
Fix bug with never ending stack increase
happytomatoe Oct 22, 2024
520ce31
Formatting
happytomatoe Oct 22, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,6 @@ out
npm-debug.log*
yarn-debug.log*
yarn-error.log*
**/.vscode/numbered-bookmars.json
**/.antlr
.idea/
7 changes: 7 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@
],
"outFiles": ["${workspaceFolder}/extension/build/test/**/*.js"],
"preLaunchTask": "${defaultBuildTask}"
},
happytomatoe marked this conversation as resolved.
Show resolved Hide resolved
{
"type": "chrome",
"request": "launch",
"name": "Test web ide",
"url": "http://localhost:3000/web-ide",
"webRoot": "${workspaceFolder}"
}
]
}
2 changes: 1 addition & 1 deletion cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { testRunner } from "./testrunner.js";
import { NodeFileSystemAdapter } from "@davidsouther/jiffies/lib/esm/fs_node.js";
import { FileSystem } from "@davidsouther/jiffies/lib/esm/fs.js";
import * as fsCore from "fs";
import { compile } from "@nand2tetris/simulator/jack/compiler.js";
import { compile } from "@nand2tetris/simulator/jack/anltr.compiler.js";

yargs(hideBin(process.argv))
.usage("$0 <cmd>")
Expand Down
53 changes: 43 additions & 10 deletions components/src/stores/compiler.store.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { FileSystem } from "@davidsouther/jiffies/lib/esm/fs.js";
import { compile } from "@nand2tetris/simulator/jack/compiler.js";
import {
compile,
validate,
} from "@nand2tetris/simulator/jack/anltr.compiler.js";
import { CompilationError } from "@nand2tetris/simulator/languages/base.js";
import { Dispatch, MutableRefObject, useContext, useMemo, useRef } from "react";
import { useImmerReducer } from "../react.js";
Expand Down Expand Up @@ -30,7 +33,10 @@ export type CompilerStoreDispatch = Dispatch<{
function classTemplate(name: string) {
return `class ${name} {\n\n}\n`;
}

interface FileEntry {
name: string;
content: string;
}
export function makeCompilerStore(
setStatus: Action<string>,
dispatch: MutableRefObject<CompilerStoreDispatch>,
Expand All @@ -46,13 +52,14 @@ export function makeCompilerStore(
state.title = undefined;
},

setFile(
state: CompilerPageState,
{ name, content }: { name: string; content: string },
) {
setFile(state: CompilerPageState, { name, content }: FileEntry) {
state.files[name] = content;
state.isCompiled = false;
this.compile(state);
},
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Nit) empty blank line, and a couple others around the project.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the rule here? Can we add this to prettier?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please ignore the piece about prettier

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, unfortunately I don't think prettier supports it at this time. I believe Rome might? But I haven't looked into it closely.

Broadly, separate top-level and class-level function declarations by one blank line. Top level and class level properties and variables can be grouped without blank lines between them "so that it looks good" - I know that's not a great rule, but there's room for a bit of aesthetics. "Keep similar things together" is the principle there, but not super strict.

But for the rule - every function should have a blank line before it (or before its docblock, if it has a comment)

Copy link
Contributor Author

@happytomatoe happytomatoe Oct 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, it's a part of eslint, not prettier, that's probably why I couldn't find it.

Copy link
Contributor Author

@happytomatoe happytomatoe Oct 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's agree that we can create another PR and standardize this across the whole codebase

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. Please do your best in the meantime to keep this as tidy as you can.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me know if you want me to change something. Otherwise I will leave it as it is


setFileAndValidate(state: CompilerPageState, entry: FileEntry) {
this.setFile(state, entry);
this.validate(state);
},

// the keys of 'files' have to be the full file path, not basename
Expand All @@ -62,10 +69,12 @@ export function makeCompilerStore(
this.compile(state);
},

compile(state: CompilerPageState) {
const compiledFiles = compile(state.files);
_processCompilationResults(
state: CompilerPageState,
files: Record<string, string | CompilationError>,
) {
state.compiled = {};
for (const [name, compiled] of Object.entries(compiledFiles)) {
for (const [name, compiled] of Object.entries(files)) {
if (typeof compiled === "string") {
state.compiled[name] = {
valid: true,
Expand All @@ -83,6 +92,16 @@ export function makeCompilerStore(
);
},

validate(state: CompilerPageState) {
state.isCompiled = false;
this._processCompilationResults(state, validate(state.files));
},

compile(state: CompilerPageState) {
state.isCompiled = false;
this._processCompilationResults(state, compile(state.files));
},

writeCompiled(state: CompilerPageState) {
if (Object.values(state.compiled).every((compiled) => compiled.valid)) {
for (const [name, compiled] of Object.entries(state.compiled)) {
Expand Down Expand Up @@ -136,15 +155,29 @@ export function makeCompilerStore(
await fs.writeFile(`${name}.jack`, content);
}
},
async writeNewFile(name: string, content?: string) {
happytomatoe marked this conversation as resolved.
Show resolved Hide resolved
content ??= classTemplate(name);
dispatch.current({
action: "setFileAndValidate",
payload: { name, content },
});
if (fs) {
await fs.writeFile(`${name}.jack`, content);
}
},

async reset() {
fs = undefined;
dispatch.current({ action: "reset" });
},

async compile() {
dispatch.current({ action: "compile" });
dispatch.current({ action: "writeCompiled" });
},
async validate() {
dispatch.current({ action: "validate" });
},
};

const initialState: CompilerPageState = {
Expand Down
103 changes: 103 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion simulator/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,24 @@
"@nand2tetris/projects": "^1.0.0",
"@nand2tetris/runner": "^1.0.0",
"@types/node": "^20.14.2",
"antlr4ng": "^3.0.7",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this change need a change in the README?

Copy link
Contributor Author

@happytomatoe happytomatoe Oct 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've already changed the README. Both of these libraries implement the same api/interfaces

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This library already has a ton of comments in typescript sources so I don't know if makes sense to add anything else in terms of documentation

"ohm-js": "^17.1.0",
"rxjs": "^7.8.1"
},
"devDependencies": {
"@babel/preset-typescript": "^7.24.7",
"@types/jest": "^29.5.12",
"antlr4ng-cli": "^2.0.0",
"babel-jest": "^29.7.0",
"jest": "^29.7.0",
"jest-ts-webcompat-resolver": "^1.0.0",
"typescript": "^5.4.5"
},
"scripts": {
"build": "tsc",
"test": "jest --verbose"
"test": "jest --verbose",
"test-jack": "npm run test -- -t \"Jack\"",
DavidSouther marked this conversation as resolved.
Show resolved Hide resolved
"test-jack-w": "npm run test-w -- -t \"Jack\"",
"gen": "cd src/languages/grammars && antlr4ng -Dlanguage=TypeScript JackLexer.g4 JackParser.g4 -o ../../jack/generated"
}
}
25 changes: 25 additions & 0 deletions simulator/src/jack/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# ANTLR Jack compiler

ANTLR gives us ability to generate lexer and parser in the target programming language(typescript in this case) using grammar files for [lexer](src/languages/grammars/JackLexer.g4) and [parser](src/languages/grammars/JackParser.g4).

After parsing is done we get a tree data structure as an output. To do anything useful with this this tree we can use the next 2 design patterns:

1. Listener
2. Visitor

You can read more about this design patterns and the difference between them in this [blog post](https://tomassetti.me/listeners-and-visitors/). You can also check out [antlr mega tutorial from the same company](https://tomassetti.me/antlr-mega-tutorial/).

For jack we use next listeners:

- Error listener - listens to lexer and parser errors
- Global symbol table listener - creates global symbol table (classes and subroutines symbols)
- Validator listener - validates jack program
- VM Writer listener - generates VM code

# Regenerate Jack Lexer and Parser files

Next command gives us ability to regenerate parser and lexer after we've changed the grammar (.g4 files) for [lexer](src/languages/grammars/JackLexer.g4) or [parser](src/languages/grammars/JackParser.g4)

```
npm run gen
```
Loading
Loading