-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit bb19d7f
Showing
32 changed files
with
4,752 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
name: Lint and Test | ||
on: [push] | ||
jobs: | ||
test: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Checkout code | ||
uses: actions/checkout@v4 | ||
|
||
- name: Install Node.js | ||
uses: actions/setup-node@v4 | ||
with: | ||
node-version: '22' | ||
|
||
- name: Install dependencies | ||
run: npm ci | ||
|
||
- name: Lint code | ||
run: npm run lint | ||
|
||
- name: Run tests | ||
run: npm test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
node_modules | ||
.vscode |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
# Complect - A Toy Compiler | ||
|
||
<img src="https://i.imgur.com/NLVzU2tm.png" alt="Complect Logo"/> | ||
|
||
Complect is a toy compiler developed in Node.js. It operates as a stream-based compiler, processing code as a continuous stream of data. Currently, Complect functions primarily as a transpiler, converting Complect code into JavaScript using the Babel Abstract Syntax Tree (AST). Future enhancements will include support for additional ASTs, enabling compilation to WebAssembly (WASM) and other targets. | ||
|
||
The initial implementation of this compiler was created to support a talk I presented at **OpenJS World 2022**. You can find the contents of this talk here. [Slides](https://static.sched.com/hosted_files/openjsworld2022/78/OpenJSW%20World%202022.pdf) [Video](https://youtu.be/aPHf_-N2yTU) | ||
|
||
## Stages | ||
- Preprocessor: Transforms an input stream into a stream of preprocessing tokens. | ||
- Tokenizer: Converts the stream of preprocessing tokens into a stream of tokens. | ||
- Abstract Syntax Tree (AST): Generates an AST from the stream of tokens, currently utilizing Babel. | ||
- Output: The Babel AST outputs code in JavaScript. | ||
|
||
## Design | ||
Complect utilizes a handcrafted parser and lexer to give developers fine-grained control over the compilation process. The parser in Complect is a top-down parser of the LL(1) type, chosen for its simplicity and efficiency in parsing. | ||
|
||
### Key Design Elements | ||
- Handcrafted Parser and Lexer: Complect's components are manually written, unlike tools-generated parsers and lexers. This allows for greater customization and optimization specific to the language's needs. | ||
|
||
- Top-Down Parsing (LL(1)): Complect's choice of a top-down parser of the LL(1) type is not arbitrary. This parsing method, which proceeds from left to right and produces a leftmost derivation with a single token lookahead, is known for its efficiency and simplicity. The grammar of the Complect language has been meticulously designed to facilitate this type of parsing, ensuring that parsing decisions can be made with minimal lookahead. | ||
|
||
- Stream-Based Compilation: The compiler processes code as a data stream, enhancing efficiency and memory usage. This will also allow easier insertion of future optimization layers. | ||
|
||
- Babel AST Integration: Complect currently generates an Abstract Syntax Tree (AST) using Babel, which outputs JavaScript code. This integration with Babel allows leveraging its robust ecosystem to further process and transform the generated JavaScript code. | ||
|
||
### Future | ||
- Integration of Binaryen as the AST to generate code in WebAssembly. | ||
- Explore compiler optimization passes. | ||
|
||
## Usage | ||
### CLI | ||
You can use Complect as a command-line tool. The entry point of the application is `cli.js`. It reads from the standard input, compiles the input, and writes the output to the standard output. | ||
|
||
### Testing | ||
Tests are written using Node's built-in test module. | ||
`npm run test` | ||
|
||
### Linting | ||
Linting is done using ESLint. | ||
`npm run lint` | ||
|
||
## Language | ||
### Keywords and Usage | ||
Complect is changing as the parser develops, expect things to change. | ||
|
||
### FizzBuzz in Complect | ||
``` | ||
make i 1 | ||
make f 0 | ||
make b 0 | ||
make output '' | ||
as i <= 16 | ||
f = i % 3 | ||
b = i % 5 | ||
assign output '' | ||
if f == 0 | ||
output = output + 'Fizz' | ||
endif | ||
if b == 0 | ||
output = output + 'Buzz' | ||
endif | ||
if output == '' | ||
output = output + i | ||
endif | ||
print output | ||
i = i + 1 | ||
repeat | ||
``` | ||
## Author | ||
Complect is created by Jarrod Connolly. | ||
|
||
## License | ||
GNU General Public License v3.0 | ||
|
||
See [COPYING](COPYING) to see the full text. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
/* Complect - Compiler for the Complect programming language | ||
* | ||
* Copyright © 2024 Jarrod Connolly | ||
* GNU General Public License v3.0 (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) | ||
*/ | ||
import { parse } from '@babel/parser'; | ||
//import generate from '@babel/generator'; | ||
|
||
const code = 'console.log(foo);'; | ||
const ast = parse(code); | ||
console.log(JSON.stringify(ast, null, 2)); | ||
// const output = generate( | ||
// ast, | ||
// { | ||
// /* options */ | ||
// }, | ||
// code | ||
// ); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
/* Complect - Compiler for the Complect programming language | ||
* | ||
* Copyright © 2024 Jarrod Connolly | ||
* GNU General Public License v3.0 (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) | ||
*/ | ||
// { parse } from '@babel/parser'; | ||
import {CodeGenerator} from '@babel/generator'; | ||
import * as t from '@babel/types'; | ||
|
||
//const code = "let foo = 'bar'"; | ||
//const ast = parse(code); | ||
|
||
const identifierFoo = t.identifier('foo'); | ||
const stringLiteralBar = t.stringLiteral('bar'); | ||
const variableDeclarator = t.variableDeclarator(identifierFoo, stringLiteralBar); | ||
|
||
const variableDeclaration = t.variableDeclaration('let', [variableDeclarator]); | ||
|
||
const program = t.program([variableDeclaration], [], 'script'); | ||
const file = t.file(program); | ||
const output = new CodeGenerator(file).generate(); | ||
|
||
console.log(output.code); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
#!/usr/bin/env node | ||
/* Complect - Compiler for the Complect programming language | ||
* | ||
* Copyright © 2024 Jarrod Connolly | ||
* GNU General Public License v3.0 (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) | ||
*/ | ||
import { compile } from '../lib/compiler.js'; | ||
import { pretty } from '../lib/util/pretty-hrtime.js'; | ||
|
||
const inputStream = process.stdin; | ||
|
||
const start = process.hrtime.bigint(); | ||
compile(inputStream) | ||
.then((results) => { | ||
const end = process.hrtime.bigint(); | ||
const totalTime = pretty(end - start); | ||
const message = `Total Time: ${totalTime} PreTokens: ${results.preprocessorTokenCount} Tokens: ${results.tokenCount} AST Nodes: ${results.astNodeCount} `; | ||
console.log(`// ${message}`); | ||
console.log(`\n${results.code}`); | ||
}) | ||
.catch((err) => { | ||
console.error(err); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
/* Complect - Compiler for the Complect programming language | ||
* | ||
* Copyright © 2024 Jarrod Connolly | ||
* GNU General Public License v3.0 (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) | ||
*/ | ||
import globals from "globals"; | ||
import pluginJs from "@eslint/js"; | ||
|
||
export default [ | ||
{languageOptions: { globals: globals.node }}, | ||
pluginJs.configs.recommended, | ||
]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
make a 0 | ||
make b 1 | ||
make t 0 | ||
make n 12 | ||
as n > 0 | ||
n = n - 1 | ||
assign t a | ||
assign a b | ||
b = b + t | ||
print a | ||
repeat |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
make i 1 | ||
make f 0 | ||
make b 0 | ||
make output '' | ||
|
||
as i <= 16 | ||
f = i % 3 | ||
b = i % 5 | ||
assign output '' | ||
if f == 0 | ||
output = output + 'Fizz' | ||
endif | ||
if b == 0 | ||
output = output + 'Buzz' | ||
endif | ||
if output == '' | ||
output = output + i | ||
endif | ||
print output | ||
i = i + 1 | ||
repeat |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
make foo 'bar' | ||
print foo | ||
|
||
make a 37 | ||
print a | ||
assign a 42 | ||
print a | ||
a = a + 8 | ||
print a | ||
|
||
make b 10 | ||
make c 20 | ||
make d 0 | ||
d = b + c | ||
print d | ||
|
||
if d < 30 | ||
print 'less than 30' | ||
endif | ||
|
||
if d >= 30 | ||
print 'greater or equal to 30' | ||
endif | ||
|
||
d = d % 2 | ||
|
||
make i 0 | ||
as i <= 10 | ||
i = i + 1 | ||
print i | ||
repeat |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
identifier one | ||
whitespace | ||
identifier two | ||
linefeed | ||
identifier three | ||
linefeed | ||
identifier four | ||
whitespace | ||
identifier five | ||
whitespace | ||
identifier six | ||
linefeed | ||
identifier something | ||
linefeed | ||
number 123 | ||
whitespace | ||
number 456 | ||
linefeed | ||
number 789 | ||
linefeed | ||
identifier x | ||
whitespace | ||
operator = | ||
whitespace | ||
number 42 | ||
whitespace | ||
operator + | ||
whitespace | ||
number 45 | ||
operator ; | ||
linefeed | ||
number 4.5 | ||
linefeed | ||
number 25.123 | ||
linefeed | ||
identifier foo | ||
whitespace | ||
operator = | ||
whitespace | ||
string 'test' | ||
eof |
Oops, something went wrong.