Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
103 changes: 103 additions & 0 deletions languages/elysium-lang - alex/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# Elysium Language

Welcome to **Elysium Language**, a programming language inspired by the elegance and simplicity of Python, the structure of JavaScript, and the functional aspects of Lisp. Elysium is designed for those who appreciate readability, maintainability, and the joy of writing clean code.

## Inspiration

The idea for Elysium Language came to me while working on various projects that required different programming paradigms. I found myself often wishing for a language that combined the best features of my favorite languages:

- **Python's readability and simplicity**: Python's clean syntax and readability have always made coding a pleasant experience for me. I wanted Elysium to reflect that simplicity.
- **JavaScript's versatility**: JavaScript's ability to handle both object-oriented and functional programming inspired the versatile nature of Elysium.
- **Lisp's powerful macro system**: The functional programming capabilities and the macro system of Lisp provided a powerful paradigm that I wanted to incorporate into Elysium.

## Features

- **Clean and Readable Syntax**: Elysium emphasizes code readability and simplicity, making it easy to learn and use.
- **First-Class Functions**: Functions in Elysium are first-class citizens, allowing you to pass them around and use them as arguments.
- **Versatile Paradigms**: Whether you prefer object-oriented programming, functional programming, or a mix of both, Elysium has you covered.
- **Dynamic Typing**: Similar to Python and JavaScript, Elysium uses dynamic typing, allowing you to write flexible and adaptable code.
- **Comprehensive Standard Library**: Elysium comes with a rich standard library that provides essential tools and utilities for everyday programming tasks.

## Installation

To get started with Elysium, you'll need to clone the repository and install the necessary dependencies. Make sure you have Node.js installed on your machine.

1. **Clone the repository**:
```sh
git clone https://github.com/yourusername/elysium-lang.git
cd elysium-lang
```

2. **Install dependencies**:
```sh
npm install
```

3. **Run your first Elysium program**:
```sh
node src/index.js
```

## Example Code

Here's a simple Elysium program to give you a taste of what the language looks like:

```
let x = 10
let y = 20

if x < y {
print x;
} else {
print y;
}

while x > 0 {
print x;
x = x - 1;
}
```

## Language Syntax
# Variables
Variables are declared using the let keyword:

```
let x = 10
let y = x + 1
```

# Functions
# Note: this is a work in progress feature and is super buggy at the moment!!!!
Functions are defined using the function keyword:

```
function add(a, b) {
return a + b;
}
```

# Control Structures
Elysium supports standard control structures such as if, else, and while:

```
if condition {
// code block
} else {
// code block
}

while x > 5 {
// code block
}
```

# Contributing
I welcome contributions from anyone who is passionate about making Elysium better. Whether it's bug fixes, new features, or documentation improvements, your help is appreciated. Please fork the repository, make your changes, and submit a pull request.

# Contact
If you have any questions, suggestions, or feedback, feel free to reach out to me at alexanderli@hotmail.ca. You can also contact me on slack @alexanderli for updates on Elysium and other projects.

Thank you for your interest in Elysium Language. Happy coding!

Elysium Language is a personal project made with ❤️ by Alex.
13 changes: 13 additions & 0 deletions languages/elysium-lang - alex/package-lock.json

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

15 changes: 15 additions & 0 deletions languages/elysium-lang - alex/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "elysium-lang",
"version": "1.0.0",
"description": "A simple programming language",
"main": "src/index.js",
"scripts": {
"start": "node src/index.js"
},
"author": "Alex",
"license": "ISC",
"directories": {
"test": "test"
},
"keywords": []
}
26 changes: 26 additions & 0 deletions languages/elysium-lang - alex/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
const fs = require('fs');
const Lexer = require('./lexer');
const Parser = require('./parser');
const Interpreter = require('./interpreter');

// Read the input file
const input = fs.readFileSync('./test/test.ely', 'utf8');

// Tokenize the input
try {
const lexer = new Lexer(input);
const tokens = lexer.tokenize();
console.log("Tokens:", tokens);

// Parse the tokens
const parser = new Parser(tokens);
const ast = parser.parse();
console.log("AST:", JSON.stringify(ast, null, 2));

// Interpret the AST
const interpreter = new Interpreter();
interpreter.execute(ast);
} catch (error) {
console.error("Error:", error.message);
console.error(error.stack);
}
104 changes: 104 additions & 0 deletions languages/elysium-lang - alex/src/interpreter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
class Interpreter {
constructor() {
this.environment = {};
this.functions = {};
}

evaluate(node) {
switch (node.type) {
case 'Declaration':
this.environment[node.identifier] = this.evaluate(node.value);
break;
case 'Assignment':
if (!(node.identifier in this.environment)) {
throw new Error(`Undefined variable ${node.identifier}`);
}
this.environment[node.identifier] = this.evaluate(node.value);
break;
case 'BinaryExpression':
return this.evaluateBinaryExpression(node);
case 'Identifier':
if (!(node.name in this.environment)) {
throw new Error(`Undefined variable ${node.name}`);
}
return this.environment[node.name];
case 'Literal':
return node.value;
case 'PrintStatement':
const value = this.evaluate(node.value);
console.log(value);
return value;
case 'WhileStatement':
return this.evaluateWhileStatement(node);
case 'IfStatement':
return this.evaluateIfStatement(node);
case 'FunctionDeclaration':
this.functions[node.name] = node;
break;
case 'ReturnStatement':
return this.evaluate(node.value);
default:
throw new Error(`Unknown node type: ${node.type}`);
}
}

evaluateBinaryExpression(node) {
const left = this.evaluate(node.left);
const right = this.evaluate(node.right);
switch (node.operator) {
case '+':
return left + right;
case '-':
return left - right;
case '*':
return left * right;
case '/':
return left / right;
case '<':
return left < right;
case '>':
return left > right;
case '==':
return left == right;
case '<=':
return left <= right;
case '>=':
return left >= right;
case '!=':
return left != right;
default:
throw new Error(`Unknown operator: ${node.operator}`);
}
}

evaluateWhileStatement(node) {
while (this.evaluate(node.condition)) {
for (const statement of node.body) {
this.evaluate(statement);
}
}
}

evaluateIfStatement(node) {
if (this.evaluate(node.condition)) {
for (const statement of node.consequent) {
this.evaluate(statement);
}
} else if (node.alternate) {
for (const statement of node.alternate) {
this.evaluate(statement);
}
}
}

execute(ast) {
ast.forEach(node => {
console.log("Executing node:", node);
this.evaluate(node);
});
console.log("Final environment:", this.environment);
console.log("Values of variables:", this.environment);
}
}

module.exports = Interpreter;
114 changes: 114 additions & 0 deletions languages/elysium-lang - alex/src/lexer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
class Lexer {
constructor(input) {
this.input = input;
this.position = 0;
this.currentChar = this.input[this.position];
}

advance() {
this.position++;
if (this.position < this.input.length) {
this.currentChar = this.input[this.position];
} else {
this.currentChar = null;
}
}

tokenize() {
const tokens = [];
while (this.currentChar !== null) {
if (this.isWhitespace(this.currentChar)) {
this.advance();
} else if (this.isLetter(this.currentChar)) {
tokens.push(this.identifier());
} else if (this.isDigit(this.currentChar)) {
tokens.push(this.number());
} else if (this.currentChar === '=' && this.peek() === '=') {
tokens.push(this.equalityOperator());
} else if (this.currentChar === '!' && this.peek() === '=') {
tokens.push(this.equalityOperator());
} else if (this.currentChar === '=' || this.currentChar === '<' || this.currentChar === '>' || this.currentChar === '!') {
tokens.push(this.relationalOperator());
} else if (this.currentChar === '+') {
tokens.push({ type: 'OPERATOR', value: '+' });
this.advance();
} else if (this.currentChar === '-') {
tokens.push({ type: 'OPERATOR', value: '-' });
this.advance();
} else if (this.currentChar === '*') {
tokens.push({ type: 'OPERATOR', value: '*' });
this.advance();
} else if (this.currentChar === '/') {
tokens.push({ type: 'OPERATOR', value: '/' });
this.advance();
} else if (this.currentChar === '{' || this.currentChar === '}' || this.currentChar === '(' || this.currentChar === ')' || this.currentChar === ',') {
tokens.push({ type: 'PUNCTUATION', value: this.currentChar });
this.advance();
} else {
throw new Error(`Unexpected character: ${this.currentChar}`);
}
}
return tokens;
}

peek() {
return this.position + 1 < this.input.length ? this.input[this.position + 1] : null;
}

isWhitespace(char) {
return /\s/.test(char);
}

isLetter(char) {
return /[a-zA-Z]/.test(char);
}

isDigit(char) {
return /[0-9]/.test(char);
}

identifier() {
let result = '';
while (this.currentChar !== null && this.isLetter(this.currentChar)) {
result += this.currentChar;
this.advance();
}
const type = this.isKeyword(result) ? 'KEYWORD' : 'IDENTIFIER';
return { type, value: result };
}

isKeyword(word) {
return ['let', 'print', 'while', 'if', 'else', 'function', 'return'].includes(word);
}

number() {
let result = '';
while (this.currentChar !== null && this.isDigit(this.currentChar)) {
result += this.currentChar;
this.advance();
}
return { type: 'NUMBER', value: Number(result) };
}

relationalOperator() {
let result = this.currentChar;
this.advance();
if (this.currentChar === '=') {
result += this.currentChar;
this.advance();
}
return { type: 'OPERATOR', value: result };
}

equalityOperator() {
let result = this.currentChar;
this.advance();
if (this.currentChar === '=') {
result += this.currentChar;
this.advance();
}
return { type: 'OPERATOR', value: result };
}
}

module.exports = Lexer;
Loading