Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main'
Browse files Browse the repository at this point in the history
  • Loading branch information
JothamWong committed Apr 20, 2024
2 parents a7903ef + 7b60ec4 commit d30edb5
Show file tree
Hide file tree
Showing 3 changed files with 219 additions and 129 deletions.
342 changes: 215 additions & 127 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,155 +1,243 @@
# Ooga

Ooga is a VM-based sub-language of Go developed using TypeScript.
It includes the Ooga toolchain and a web-based playground website using Microsoft's Monaco
editor for execution of code.

## Quick Start

Set up instructions here.

## Features

### Pass by reference

All objects in Ooga are copied by reference. Ooga programmers don't like reasoning in a functional paradigm, so
everything is MUTABLE!

### Sequential Programming Constructs

- Expressions
- Conditionals
- For loops
- Block Scoping
- Function Declarations
- Variable Declarations
- Constant Declarations
- Structs

### Concurrent Programming Constructs

- Goroutines
- WaitGroups
- Channels

Behind the scenes, Ooga uses a Round Robin scheduler to provide "concurrency" and allows for users
to construct race conditions.

#### Channels

Ooga supports buffered and unbuffered channels.

Writing to unbuffered channels block until a corresponding read from the same unbuffered channel.
Writing to a buffered channel blocks if the buffered channel is full while reading from a buffered channel blocks
if the buffered channel is empty.

### Garbage Collection

Ooga uses the LISP 2 Garbage Collection algorithm and supports an unlimited number of declarations (up
to available memory), with no arbitrary node size restriction. Programs such as

```go
func OOGA() int {
var a int = 1;
var b int = 2;
var c int = 3;
var d int = 4;
var e int = 5;
var f int = 6;
var g int = 7;
var h int = 8;
var i int = 9;
var j int = 10;
var k int = 11;
var l int = 12;
var m int = 13;
var n int = 14;
var o int = 15;
var p int = 16;
var q int = 17;
var r int = 18;
var s int = 19;
var t int = 20;
var u int = 21;
var v int = 22;
var w int = 23;
var x int = 24;
var y int = 25;
var z int = 26;
return a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p + q + r + s + t + u + v + w +x + y + z;
}
# Ooga Lang

Ooga is a concurrent virtual machine and interpreter for a subset of the Go programming language. It is implemented in TypeScript and includes a parser, compiler, typechecker, and virtual machine.

## Table of Contents
- [Features](#features)
- [Language Features](#language-features)
- [Virtual Machine Features](#virtual-machine-features)
- [Standard Library](#standard-library)
- [Architecture](#architecture)
- [Getting Started](#getting-started)
- [Prerequisites](#prerequisites)
- [Installation](#installation)
- [Running the Toolchain](#running-the-toolchain)
- [Running Tests](#running-tests)
- [Dev Workflow](#dev-workflow)
- [Usage](#usage)
- [Project Structure](#project-structure)

## Features

### Language Features
- Sequential programming constructs:
- Variable and constant declarations (with type inference)
- Function declarations (including higher order functions)
- Block scoping
- Conditionals (if/else statements)
- Expressions
- For loops
- Switch statements
- Concurrent programming constructs:
- Goroutines
- WaitGroups
- Channels (buffered and unbuffered)
- Select statements
- User-defined types:
- Structs
- Methods
- Compound types:
- Arrays (fixed size)
- Slices (dynamically resizable arrays)
- Strongly statically typed with a typechecker for compile-time type safety
- Designed to be familiar to Go programmers while being a simplified subset

### Virtual Machine Features
- Stack-based bytecode virtual machine
- Lisp 2 mark-compact garbage collection with variable sized nodes (no arbitrary limit on number of declarations)
- Round Robin thread scheduler for concurrency (allows simulation of race conditions)
- Low-level memory model fully accessible from the language
- Visualization of runtime state:
- Operand stack and stack frames for each goroutine
- Heap state at each breakpoint
- Debugger with breakpoints

### Standard Library
- Concurrency utilities:
- Mutexes
- Semaphores
- WaitGroups
- fmt package for string formatting and printing
- time package with sleep function

## Architecture

The Ooga toolchain consists of the following components:

1. **Parser**: A Peggy-based parser that parses Ooga source code and generates an abstract syntax tree (AST).

2. **Typechecker**: Performs static type checking on the AST, ensuring the program is well-typed before compilation. Also annotates the AST with type information.

3. **Compiler**: Compiles the type-annotated AST into instructions for the Ooga virtual machine.

4. **Virtual Machine**: A stack-based VM that executes the compiled bytecode. Includes a garbage collector and a scheduler for concurrency.

The toolchain is designed to be modular, with a clean separation between each phase of program processing.

## Getting Started

### Prerequisites
- Node.js (v14 or newer)
- Yarn package manager

### Installation

1. Clone the repository:
```bash
git clone https://github.com/CS4215-OOGA/ooga-lang.git
```

### Type Checker
2. Install dependencies:
```bash
cd ooga-lang
yarn install
```

Ooga is a strongly statically typed language that comes with a type checker for ensuring the type safety
of programs.
### Running the Toolchain

### Types
1. Generate the parser from the Peggy grammar file:
```bash
yarn peggy
```

Ooga supports integers, floats, booleans, strings and custom Struct expressions.
This command generates `src/parser/ooga.js` from `src/parser/ooga.pegjs`.

Ooga also supports buffered, unbuffered channels as well as arrays and slices which are dynamically resizable arrays.
2. Compile the TypeScript source code:
```bash
yarn build
```

Ooga slices follow Golang's slices behaviour in which a re-allocation of memory creates a new slice.
This command compiles all TypeScript files in the `src` directory into JavaScript in the `dist` directory.

Consider the following ooga snippet code.
```go
var x []int = make([]int, 5, 5); // allocates a slice of len 5 and capacity 5
var y []int = append(x, 5); // this causes a reallocation of a new slice of capacity 10
// x and y now point to slices of capacity 5 and 10 respectively
// y has len = 6
3. Start the server:
```bash
yarn server
```

This is a test case in our suite.
This command starts the server at http://localhost:3001.

The Ooga playground frontend (in the [ooga-frontend](https://github.com/CS4215-OOGA/ooga-frontend) repo) communicates with this server to execute Ooga code and retrieve debugging information.

### Running Tests


The Ooga test suite is located in `src/tests/test.ts`. It contains a series of integration tests that cover all language features and edge cases.

To run the test suite:
```bash
yarn tooga
```

The test suite will compile and run each test case, checking the output against the expected result. The stdout of each test case is also captured and compared to the expected output. Any discrepancies will cause the test to fail.

Actions are set up to run the test suite on every commit pushed to this repository to ensure that the codebase remains correct.

### Test Suite
## Dev Workflow

Ooga comes with a comprehensive test suite that tests all included features. Run `yarn tooga` to see the tests.
When working on the Ooga language, follow these steps:

### Memory Visualization
1. If you make changes to the grammar (`src/parser/ooga.pegjs`), regenerate the parser:
```bash
yarn peggy
```

Ooga uses a low-level memory model and comes with three built-in functions that lets you visualize
the contents of the heap-based memory model.
2. If you make changes to any TypeScript files, recompile the project:
```bash
yarn build
```

The Operating Stack, Runtime Stack and the Environment can be visualized using their corresponding
helper functions.
3. Write your Ooga code in a file named `booga.ooga`.

4. To compile `booga.ooga` to bytecode:
```bash
yarn compile
```
This command outputs the compiled bytecode to `booga.bm`.

## Plan
5. To run `booga.bm` in the virtual machine:
```bash
yarn run
```

Implementing Type checking
Need to read lecture slides
Grammar already supports it, just need to add type information
For convenience, you can use `yarn booga` to compile and run `booga.ooga` in one step.

Memory management, follow idealized VM
Refer to the `package.json` file for more details on the available scripts.

To handle concurrency, there should be a notion of a 'thread' and its registers, aka the
OS, PC, E separately.
## Usage

We would use the oogavm-scheduler to do a round robin scheduling of the threads as per js-slang
Once the server is running, you can use the Ooga language playground by running the [ooga-frontend](https://github.com/CS4215-OOGA/ooga-frontend) on http://localhost:3000.

Write your Ooga code in the editor. Use the "Run" button to execute the code, and the "Debug" button to view the stacks and heap at each breakpoint.

The playground will display the output and any error messages.

Use `breakpoint;` statements in your code to set breakpoints.

In debug mode, you can inspect the state of each goroutine's operand stack and stack frames, as well as the heap state at each breakpoint.


## Project Structure

The Ooga project is structured as follows:

```
ooga-lang/
├── src/
│ ├── vm/
│ │ ├── oogavm-compiler.ts
│ │ ├── oogavm-errors.ts
│ │ ├── oogavm-heap.ts
│ │ ├── oogavm-machine.ts
│ │ ├── oogavm-scheduler.ts
│ │ ├── oogavm-typechecker.ts
│ │ ├── oogavm-types.ts
│ │ └── opcodes.ts
│ │
│ ├── parser/
│ │ ├── ooga.pegjs
│ │ └── ooga.js
│ │
│ ├── tests/
│ │ └── test.ts
│ │
│ ├── server/
│ │ ├── server.ts
│ │ ├── runOogaLang.ts
│ │ └── debug.ts
│ │
│ └── utils/
│ └── utils.ts
├── package.json
└── README.md
```

To do the visualization, we'd need the ability to set breakpoints (how?) and for the heap to be
accessible (interpretably) to the frontend monaco.
The key directories and files are:

- `src/vm/`: Contains the implementation of the Ooga virtual machine and runtime.
- `oogavm-compiler.ts`: Compiles the AST into bytecode.
- `oogavm-errors.ts`: Defines custom error types used throughout the project.
- `oogavm-heap.ts`: Implements the low-level heap and memory management.
- `oogavm-machine.ts`: Defines the bytecode virtual machine and its operation.
- `oogavm-scheduler.ts`: Implements the thread scheduler for concurrency.
- `oogavm-typechecker.ts`: Performs static type checking on the AST.
- `oogavm-types.ts`: Defines the types used in the Ooga language and type-related utility functions.
- `opcodes.ts`: Enumerates the bytecode instruction opcodes.

## Dev instructions
- `src/parser/`: Contains the Ooga parser.
- `ooga.pegjs`: Defines the Peggy grammar for the Ooga language.
- `ooga.js`: The generated parser module (do not edit directly).

Everytime you change the grammar, run `yarn peggy`. This will update the `ooga.js` parser.
Everytime you make changes, run `yarn build`. This compiles typescript to js in `dist` folder.
When you want to compile the test file, run `yarn compile`. It will be outputted to `booga.bm`.
When you want to run the file on the VM, run `yarn run`.
More info can be found on the `package.json` file but this should be sufficient for now.
- `src/tests/`: Contains the test suite for the Ooga toolchain.
- `test.ts`: Defines the integration tests for the entire toolchain.

A convenient function that does compile and run is `yarn booga`.
- `src/server/`: Contains the server code for the Ooga playground frontend.
- `server.ts`: Implements the Express server.
- `runOogaLang.ts`: Runs user-provided Ooga code and collects debug information.
- `debug.ts`: Defines the endpoints for retrieving debug information.

## Structure
- `src/utils/`: Contains utility functions used throughout the project.
- `utils.ts`: Defines various utility functions.

`oogavm-assembler`: tbh idk why i put this file, got inspired by martin
`oogavm-compiler`: in charge of compiling `*.ooga` files to `*.bm` files.
`oogavm-errors`: ooga errors to distinguish user error from typescript errors.
`oogavm-heap`: low level memory implementation.
`oogavm-machine`: run the `*.bm` file.
`oogavm-scheduler`: process scheduler.
`oogavm-typechecker`: ooga's typechecker.
`opcodes`: enumeration of machine opcodes.
- `package.json`: Defines the project's dependencies and scripts.
2 changes: 1 addition & 1 deletion src/vm/oogavm-compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,7 @@ const compileComp = {
// jump to the next select case if possible
jof.addr = wc;
} else if (compCase.tag === 'SelectDefaultCase') {
console.log('Default case');
// log('Default case');
hasDefault = true;
compile(compCase.body, ce);
instrs[wc++] = { tag: Opcodes.END_ATOMIC };
Expand Down
4 changes: 3 additions & 1 deletion src/vm/oogavm-machine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1079,7 +1079,9 @@ const microcode = {
}

let threadsInfo: ThreadInfo[] = [];
for (let [threadId, thread] of threads.entries()) {
// sort the threads by threadId in ascending order
let sortedThreads = new Map([...threads.entries()].sort());
for (let [threadId, thread] of sortedThreads) {
// Ignore the currentThread because it is old
if (currentThreadId === threadId) {
continue;
Expand Down

0 comments on commit d30edb5

Please sign in to comment.