Write README.md.
This commit is contained in:
parent
8c1d56dc1a
commit
db675b5601
224
README.md
Normal file
224
README.md
Normal file
@ -0,0 +1,224 @@
|
||||
# Deimos
|
||||
|
||||
### Brief History
|
||||
|
||||
Deimos lang is a project I properly began in November 2024 while a student at the
|
||||
University of Wisconsin-Madison. I was learning Rust at the time and was inspired
|
||||
by its elegance and complexity.
|
||||
|
||||
I had had ideas for creating a language as early as 2020, but did not yet have the computer
|
||||
science skills necessary for designing and implementing it. I was mainly
|
||||
inspired by the linguistic problems at hand in language design, especially
|
||||
grammar design and parsing.
|
||||
|
||||
After completing an introduction-to-compilers course in spring 2025 (as well as my
|
||||
summer internship), I returned to work on the project in the fall of that year.
|
||||
I grew very frustrated with the state of the code base after a few months; my
|
||||
best software engineering instincts and skills were running up against classic
|
||||
problems: inflexibility, unmaintainability, and lack of proper testing.
|
||||
|
||||
As such, I rebooted the project in February 2026 from scratch. The old project
|
||||
code all resides under `/src`, whereas one should look in the following directories
|
||||
for the new, hopefully better, code:
|
||||
|
||||
- `/dm`: the main entry program; takes a script and runs it.
|
||||
- `/dm-std-lib`: the runtime standard library for Deimos (Rust side)
|
||||
- `/dmc-lib`: the compiler proper
|
||||
- `/dvm-lib`: the virtual machine
|
||||
|
||||
Currently, one can run the `hello.dm` example (from the `/examples` directory)
|
||||
by running:
|
||||
|
||||
`cargo run -p dm -- examples/hello.dm`
|
||||
|
||||
You will see `Hello, World!` as well as `None` printed to the console. The `None`
|
||||
is returned by the Deimos Virtual Machine (dvm) upon completion; I'm planning on
|
||||
having the `call()` function (in `dvm-lib/src/vm/mod.rs`) return whatever the `main`
|
||||
(Deimos lang) function returns, possibly limiting it in a manner similar to Rust
|
||||
(like a `Result<(), Error>` kind of thing).
|
||||
|
||||
## Goals
|
||||
|
||||
- Fast and embeddable, like Lua
|
||||
- Scalable, like Java/JVM, but without the complexity
|
||||
- Elegant syntax, like Ruby/Rust
|
||||
- Convenient, like Groovy
|
||||
- Mathematically inspired, like Haskell
|
||||
|
||||
## Grammar
|
||||
|
||||
Not all of this is implemented yet, nor is this complete by itself.
|
||||
|
||||
```
|
||||
compilation_unit := module_level_declaration*
|
||||
module_level_declaration := function | extern_function
|
||||
function := FN identifier L_PARENS parameter_list? R_PARENS statement* END
|
||||
extern_function := EXTERN FN identifier L_PARENS parameter_list? R_PARENS
|
||||
identifier := [a-zA-Z_]+
|
||||
parameter_list := parameter ( COMMA parameter )*
|
||||
parameter := identifier COLON type_use
|
||||
type_use := identifier
|
||||
statement := let_statement | expression_statement
|
||||
let_statement := LET identifier EQUALS expression
|
||||
expression_statement := expression
|
||||
expression := integer_literal | string_literal | call
|
||||
integer_literal := [0-9]+
|
||||
string_literal := DOUBLE_QUOTE .* DOUBLE_QUOTE
|
||||
call := expression L_PARENS expression_list? R_PARENS
|
||||
expression_list := expression ( COMMA expression )*
|
||||
```
|
||||
|
||||
It's been enough to chew on for now.
|
||||
|
||||
## Type System
|
||||
|
||||
Again, not all implemented, but these are my ideas:
|
||||
|
||||
- Primitives
|
||||
- Byte, Short, Int, Long (might have unsigned versions, too)
|
||||
- Char, String (yes, String is primitive; everything UTF-8)
|
||||
- Boolean
|
||||
- Arrays
|
||||
- Interfaces and Classes
|
||||
- Closures/Function pointers
|
||||
- Higher-kinded types/Traits like Haskell/Scala
|
||||
|
||||
## Examples
|
||||
|
||||
The following demonstrate some planned features for the language.
|
||||
|
||||
Basic hello world:
|
||||
```
|
||||
fn main()
|
||||
println("Hello, World")
|
||||
end
|
||||
```
|
||||
|
||||
Map some cli arguments using closures:
|
||||
```
|
||||
fn main(args: Array<String>)
|
||||
args
|
||||
.map { it.toUppercase() }
|
||||
.each { println(it) }
|
||||
end
|
||||
```
|
||||
|
||||
Interface, classes, and some other things:
|
||||
```
|
||||
int Animal
|
||||
fn name() -> String
|
||||
fn speak() -> Void
|
||||
end
|
||||
|
||||
class Dog(name: String) : Animal
|
||||
fn name() -> String = self.name
|
||||
fn speak() -> String = 'Woof'
|
||||
end
|
||||
|
||||
class Cat(name: String) : Animal
|
||||
fn name() -> String = self.name
|
||||
|
||||
fn speak() -> String
|
||||
self.name == 'Good Kitty' ? 'Meow' : 'MEOW'
|
||||
end
|
||||
end
|
||||
|
||||
fn main()
|
||||
let doggo = Dog('Bearo')
|
||||
let kitty = Cat('Willow')
|
||||
let animals = [doggo, kitty] // inferred to be List<Animal>
|
||||
animals.each { println(it.speak) } // Woof | MEOW
|
||||
end
|
||||
```
|
||||
|
||||
Higher-kinded types and enums:
|
||||
```
|
||||
trait Functor[T]
|
||||
fn <U> map(f: fn (t: T) -> U) -> Self<U>
|
||||
end
|
||||
|
||||
enum Option<T>
|
||||
Some(T),
|
||||
None
|
||||
end
|
||||
|
||||
impl<T> Functor[T] for Option<T>
|
||||
fn map(f: fn: (t: T) -> U) -> Self<U>
|
||||
if self is Some(t) then
|
||||
Some(f(t))
|
||||
else
|
||||
None
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
fn main()
|
||||
let x = Some(42)
|
||||
let y = x.map { it / 2 }
|
||||
if y is Some(twentyOne) then
|
||||
println(twentyOne) // 21
|
||||
else
|
||||
throw Exception()
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
Higher-kinded types can ask for static methods (sort of like Rust):
|
||||
|
||||
```
|
||||
trait Default
|
||||
static default() -> Self
|
||||
end
|
||||
|
||||
int Animal
|
||||
fn speak() -> String
|
||||
end
|
||||
|
||||
class Dog(name: String) : Animal, Default
|
||||
static fn default() -> Self = Dog('Skyeo')
|
||||
fn speak() -> String = 'My name is ' + self.name
|
||||
end
|
||||
|
||||
fn main()
|
||||
let sixteenDogs = Array::fill::<Dog>(16) // or something like this
|
||||
sixteenDogs.each { println(it.speak) } // My name is Skeyo (x16)
|
||||
end
|
||||
```
|
||||
|
||||
## Implementation
|
||||
|
||||
### Compiler
|
||||
|
||||
I'm currently using a handwritten lexer and parser. The grammar is embedded
|
||||
throughout the methods of the Parser implementation; once the grammar is more
|
||||
stable, I will use a proper predictive-parsing algorithm using a parse table
|
||||
(built from FIRST and FOLLOW sets), which should be not only faster but much
|
||||
cleaner.
|
||||
|
||||
Each AST node has the following methods:
|
||||
|
||||
- `gather_name_declarations`: The first phase of name analysis. This just gathers
|
||||
all declared names (functions, parameters, variables, etc.), since the plan is
|
||||
to allow entities that are declared later in the file to be in scope (unlike C,
|
||||
where forward declarations are required to do so).
|
||||
- `check_name_usages`: Make sure that usages of names refer to entities that are
|
||||
in scope.
|
||||
- `type_check`: Assert that types of parameters/arguments match, etc.
|
||||
- `assemble`: Convert the AST nodes to Deimos assembly code.
|
||||
|
||||
The first three methods must all be called, in the order listed above, as they
|
||||
constitute distinct, dependent phases of semantic analysis. If there are no
|
||||
`Diagnostic`s at all from those phases, `assemble` can be safely called.
|
||||
|
||||
### Deimos Assembly Code
|
||||
|
||||
The `asm_*` modules contain a low-level set of Rust enums/structs which basically
|
||||
map one-to-one to the actual code used by the virtual machine. I'm trying to
|
||||
design this language with optimizations and register allocation algorithms in mind.
|
||||
|
||||
### Virtual Machine
|
||||
|
||||
The virtual machine is inspired by the Lua and Java virtual machines. It is register-based,
|
||||
and uses a stack for function calls, etc. It supports calling Rust code from Deimos code via
|
||||
a `PlatformFunction` API.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user