Skip to content

Commit

Permalink
support adding strings and numbers and add doc about OOP
Browse files Browse the repository at this point in the history
  • Loading branch information
TheTrio committed Jul 30, 2024
1 parent 0c793e1 commit df680d0
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 51 deletions.
129 changes: 80 additions & 49 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,50 +17,6 @@ This goes without saying, but this is not a language for serious use.

It's based off of the Monkey language from the book [Writing an Interpreter in Go](https://interpreterbook.com/). I highly recommend it if you're interested in building your own language. I deviated from the book after the first couple of chapters, but the core ideas are the same.

## Installation

You can run the repl by cloning the repository and running

```bash
git clone https://github.com/TheTrio/Espresso
cd Espresso
pnpm install
pnpm repl
```

In the REPL, you can type `.editor` to enter multiline mode. Then you can type your code and press `Ctrl + D` to run it.

Or you can run single line code by typing it directly.

```bash
$ pnpm repl

> @ repl /Users/shashwat/Code/Espresso
> tsc && node dist/src/repl.js
> .editor
// Entering editor mode (Ctrl+D to finish, Ctrl+C to cancel)
if(true){
"true"
}else{
"false"
}
// press Ctrl + D
true
```

```bash
$ pnpm repl

> @ repl /Users/shashwat/Code/Espresso
> tsc && node dist/src/repl.js

> let word = "hello";
undefined
> word + " world"
hello world

```

## Usage

1. [Variables](#variables)
Expand All @@ -72,8 +28,9 @@ hello world
7. [Loops](#loops)
8. [Scoping](#scoping)
9. [Returning values](#returning-values)
10. [Comments](#comments)
11. [Built-in functions](#built-in-functions)
10. [Object Oriented Programming](#object-oriented-programming)
11. [Comments](#comments)
12. [Built-in functions](#built-in-functions)

### Variables

Expand All @@ -85,7 +42,7 @@ let b = 20;
a + b; // 30
```

There are currently 4 types of values: `number`, `boolean`, `string`, `array`, `null`, and `function`.
There are currently 8 types of values: `number`, `boolean`, `string`, `array`, `null`, `undefined`, `dictionaries` , and `function`.

_**Note**_: Arrays and Functions are stored as references, while the rest are primitive values.

Expand Down Expand Up @@ -432,6 +389,36 @@ let func = fn(){
Now the value of `func()` will be `5`, as expected.
### Object Oriented Programming
Espresso doesn't support object oriented programming. However, you can pretty much get all the way there by using dictionaries and functions.
```js
let Person = fn(name, age) {
let person = {
"name": name,
"age": age,
"greet": fn() {
print("Hello, my name is " + person["name"] + " and I am " + person["age"] + " years old.");
},
"birthday": fn() {
person["age"] = person["age"] + 1;
}
};
return person;
};

let john = Person("John", 30);
let jane = Person("Jane", 25);

john["greet"](); // Output: Hello, my name is John and I am 30 years old.
jane["greet"](); // Output: Hello, my name is Jane and I am 25 years old.
john["birthday"]();
john["greet"](); // Output: Hello, my name is John and I am 31 years old.
```
Behold, the power of first class functions and dictionaries. Its [functions all the way down](https://en.wikipedia.org/wiki/Turtles_all_the_way_down).
### Comments
Comments start with `//` and go until the end of the line.
Expand All @@ -445,10 +432,10 @@ let a = 10; // This is also a comment

Espresso comes with a few built-in functions.

- `len`: Returns the length of a string or an array.
- `len`: Returns the length of any iterable.
- `print`: Prints a value to the console.
- `push`: Pushes a value to the end of an array.
- `pop`: Pops a value from the end of an array by default. Takes an optional index to pop from a specific index.
- `pop`: Pops a value from the end of an array by default. Takes an optional index to pop from that instead.

```js
let count = len("hello"); // 5
Expand All @@ -474,3 +461,47 @@ It's also important to note that these aren't reserved keywords. You can overrid
}
print(len("hello")); // 5
```

## Installation

You can run the repl by cloning the repository and running

```bash
git clone https://github.com/TheTrio/Espresso
cd Espresso
pnpm install
pnpm repl
```

In the REPL, you can type `.editor` to enter multiline mode. Then you can type your code and press `Ctrl + D` to run it.

Or you can run single line code by typing it directly.

```bash
$ pnpm repl

> @ repl /Users/shashwat/Code/Espresso
> tsc && node dist/src/repl.js
> .editor
// Entering editor mode (Ctrl+D to finish, Ctrl+C to cancel)
if(true){
"true"
}else{
"false"
}
// press Ctrl + D
true
```

```bash
$ pnpm repl

> @ repl /Users/shashwat/Code/Espresso
> tsc && node dist/src/repl.js

> let word = "hello";
undefined
> word + " world"
hello world

```
9 changes: 9 additions & 0 deletions src/evaluator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,15 @@ const evaluateBinaryExpression = (
if (typeof left === 'string' && typeof right === 'string') {
return left + right
}

if (typeof left === 'string' && typeof right === 'number') {
return left + right
}

if (typeof left === 'number' && typeof right === 'string') {
return left + right
}

throw new TypeMismatchError(TokenType.PLUS, typeof left, typeof right)
case TokenType.MINUS:
if (typeof left === 'number' && typeof right === 'number') {
Expand Down
3 changes: 1 addition & 2 deletions tests/evaluator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ describe('Testing single line expressions', () => {
expect(getOutput('4 - 5')).toBe(-1)
expect(getOutput('2 * 3')).toBe(6)
expect(getOutput('8 / 2')).toBe(4)
expect(getOutput('1 + 2 + "3"')).toBe('33')
})
test('precedence', () => {
expect(getOutput('1 + 2 * 3')).toBe(7)
Expand Down Expand Up @@ -818,9 +819,7 @@ describe('Miscellaneous tests', () => {

describe('Error handling', () => {
test('Data type errors', () => {
expect(() => getOutput('1 + false')).toThrowError(TypeMismatchError)
expect(() => getOutput('true / false')).toThrowError(TypeMismatchError)
expect(() => getOutput('"1" + 1')).toThrowError(TypeMismatchError)
expect(() => getOutput('"1" - "1"')).toThrowError(TypeMismatchError)
})
test('Syntax errors', () => {
Expand Down

0 comments on commit df680d0

Please sign in to comment.