mirror of
https://github.com/Noratrieb/dilaria.git
synced 2026-01-14 17:35:03 +01:00
oh no
This commit is contained in:
parent
930955590d
commit
1bb09e48ec
13 changed files with 23 additions and 445 deletions
|
|
@ -1,26 +0,0 @@
|
|||
# The interpreter consists of several stages
|
||||
* Lexing
|
||||
* Parsing
|
||||
* Compiling
|
||||
* Interpreting (+GC)
|
||||
|
||||
# Lexer
|
||||
The lexer is handwritten and implemented as an Iterator. Lexing errors are passed on using
|
||||
`Error` tokens. The lexer already allocates identifiers and string literals into the GC.
|
||||
|
||||
# Parser
|
||||
The parser is handwritten using recursive descent. It calls the `next` method on the lexer to get the next token,
|
||||
but the iterator could be any Iterator and doesn't have to be a lexer.
|
||||
|
||||
The AST is allocated using a bump-allocator with the lifetime `'ast`.
|
||||
|
||||
# Compiler
|
||||
The compiler takes the AST and compiles it down to bytecode. The full instruction set my change and can be found in the code.
|
||||
|
||||
The bytecode is allocated using a bump-allocator with the lifetime `'bc`
|
||||
|
||||
# Interpreter (VM)
|
||||
The VM executes the bytecode. It uses the GC for its allocations.
|
||||
|
||||
# GC
|
||||
The garbage-collector is work-in-progress.
|
||||
177
README.md
177
README.md
|
|
@ -1,177 +0,0 @@
|
|||
`dilaria` is a small embeddable scripting language
|
||||
|
||||
It's inspired by Javascript, Lox, Lua, Python, Rust and more
|
||||
|
||||
# Reference
|
||||
|
||||
## Overview
|
||||
|
||||
Declaring variables using `let`
|
||||
|
||||
```rust
|
||||
let hello = 4;
|
||||
```
|
||||
|
||||
Semicolons are needed :)
|
||||
|
||||
```rust
|
||||
let test = 5;
|
||||
let another = 4;
|
||||
```
|
||||
|
||||
The language has strings, numbers, arrays, objects and null and booleans
|
||||
|
||||
```rust
|
||||
let string = "hallo";
|
||||
let number = 4;
|
||||
let array = [];
|
||||
let object = {};
|
||||
let _null = null;
|
||||
let bool = true;
|
||||
```
|
||||
|
||||
You access properties on objects using `.`
|
||||
|
||||
```rust
|
||||
let obj = {};
|
||||
obj.hi = "hi!";
|
||||
```
|
||||
|
||||
There is the `print` statement to print a value, but this will be removed
|
||||
```rust
|
||||
let name = "nils";
|
||||
print name;
|
||||
```
|
||||
|
||||
Functions are first class
|
||||
|
||||
```rust
|
||||
let obj = {};
|
||||
obj.hello = helloFn;
|
||||
obj.hello();
|
||||
```
|
||||
|
||||
Functions are declared using `fn`
|
||||
|
||||
```rust
|
||||
fn greet(name) {
|
||||
return "hello, " + name;
|
||||
}
|
||||
```
|
||||
|
||||
Functions are closures
|
||||
|
||||
Comments using `#`
|
||||
```py
|
||||
# hi!
|
||||
```
|
||||
|
||||
Multiline comments using `##` until `##`
|
||||
```
|
||||
##
|
||||
hi
|
||||
comment
|
||||
##
|
||||
```
|
||||
|
||||
There are many native functions, that can easily be customized and added/removed by the host
|
||||
|
||||
```rust
|
||||
# rocket game
|
||||
turnRocketLeft(29);
|
||||
turnRocketRight(32);
|
||||
|
||||
# chat bot
|
||||
message.respond("hi");
|
||||
|
||||
# dangerous http requests
|
||||
fn callback(html) {
|
||||
print(html);
|
||||
}
|
||||
fetch("https://github.com/Nilstrieb", callback);
|
||||
```
|
||||
|
||||
Basic arithmetic and boolean logic is available
|
||||
|
||||
```rust
|
||||
let a = 5;
|
||||
let b = 5;
|
||||
print(a + b / b * b - a % b);
|
||||
print(true and false or false or true and false);
|
||||
```
|
||||
|
||||
Loops and conditionals
|
||||
|
||||
```rust
|
||||
let x = true;
|
||||
if x {
|
||||
print("true!");
|
||||
} else {
|
||||
print("false :(");
|
||||
}
|
||||
|
||||
loop {
|
||||
while 1 > 5 {
|
||||
print("yeet");
|
||||
break;
|
||||
}
|
||||
# no for loops for now, but will be added (probably like python)
|
||||
}
|
||||
```
|
||||
|
||||
Pattern matching!
|
||||
|
||||
```rust
|
||||
# design is still wip
|
||||
|
||||
let obj = {};
|
||||
obj.x = 5;
|
||||
obj.y = "hey";
|
||||
|
||||
match obj {
|
||||
{ no } => print "our thing didn't match here",
|
||||
{ x, y } => print "we got it! " + x,
|
||||
"test" => print "string 'test'",
|
||||
other => print "something else: " + other,
|
||||
}
|
||||
```
|
||||
|
||||
`dilaria` is dynamically and *strongly* typed
|
||||
|
||||
## Detail
|
||||
|
||||
### Reserved Keywords
|
||||
|
||||
#### Statements
|
||||
`fn`
|
||||
`let`
|
||||
`if`
|
||||
`else`
|
||||
`loop`
|
||||
`while`
|
||||
`for`
|
||||
`break`
|
||||
(`print` temporary)
|
||||
|
||||
#### Values
|
||||
`true`
|
||||
`false`
|
||||
`null`
|
||||
|
||||
#### Operators
|
||||
`not`
|
||||
`and`
|
||||
`or`
|
||||
|
||||
### Operators
|
||||
`==`
|
||||
`>=`
|
||||
`>`
|
||||
`<=`
|
||||
`<`
|
||||
`!=`
|
||||
`+`
|
||||
`-`
|
||||
`*`
|
||||
`/`
|
||||
`%`
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
disallowed-types = [
|
||||
"std::collections::HashMap",
|
||||
"std::collections::HashSet",
|
||||
]
|
||||
3
fuzz/.gitignore
vendored
3
fuzz/.gitignore
vendored
|
|
@ -1,3 +0,0 @@
|
|||
target
|
||||
corpus
|
||||
artifacts
|
||||
53
fuzz/Cargo.lock
generated
53
fuzz/Cargo.lock
generated
|
|
@ -1,53 +0,0 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "arbitrary"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "577b08a4acd7b99869f863c50011b01eb73424ccc798ecd996f2e24817adfca7"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79c2681d6594606957bbb8631c4b90a7fcaaa72cdb714743a437b156d6a7eedd"
|
||||
|
||||
[[package]]
|
||||
name = "dilaria"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dilaria-fuzz"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"dilaria",
|
||||
"libfuzzer-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libfuzzer-sys"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36a9a84a6e8b55dfefb04235e55edb2b9a2a18488fcae777a6bdaa6f06f1deb3"
|
||||
dependencies = [
|
||||
"arbitrary",
|
||||
"cc",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
[package]
|
||||
name = "dilaria-fuzz"
|
||||
version = "0.0.0"
|
||||
authors = ["Automatically generated"]
|
||||
publish = false
|
||||
edition = "2018"
|
||||
|
||||
[package.metadata]
|
||||
cargo-fuzz = true
|
||||
|
||||
[dependencies]
|
||||
libfuzzer-sys = "0.4"
|
||||
|
||||
[dependencies.dilaria]
|
||||
path = ".."
|
||||
|
||||
# Prevent this from interfering with workspaces
|
||||
[workspace]
|
||||
members = ["."]
|
||||
|
||||
[[bin]]
|
||||
name = "lexer"
|
||||
path = "fuzz_targets/lexer.rs"
|
||||
test = false
|
||||
doc = false
|
||||
|
||||
[[bin]]
|
||||
name = "parser"
|
||||
path = "fuzz_targets/parser.rs"
|
||||
test = false
|
||||
doc = false
|
||||
|
||||
[[bin]]
|
||||
name = "compiler"
|
||||
path = "fuzz_targets/compiler.rs"
|
||||
test = false
|
||||
doc = false
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
#![no_main]
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
fuzz_target!(|data: String| {
|
||||
dilaria::_fuzz_compile(&data);
|
||||
});
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
#![no_main]
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
fuzz_target!(|data: String| {
|
||||
dilaria::_fuzz_lex(&data);
|
||||
});
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
#![no_main]
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
fuzz_target!(|data: String| {
|
||||
dilaria::_fuzz_parse(&data);
|
||||
});
|
||||
85
grammar.txt
85
grammar.txt
|
|
@ -1,85 +0,0 @@
|
|||
<program> ::= <statement-list>
|
||||
|
||||
<statement-list> ::= { <statement> }
|
||||
|
||||
<block> ::= "{" <statement-list> "}"
|
||||
|
||||
<statement> ::= <declaration>
|
||||
| <assignment>
|
||||
| <fn-decl>
|
||||
| <if-stmt>
|
||||
| <loop-stmt>
|
||||
| <while-stmt>
|
||||
| <break-stmt>
|
||||
| <return-stmt>
|
||||
| <block>
|
||||
|
||||
|
||||
<declaration> ::= "let" <IDENT> "=" <expression> ";"
|
||||
|
||||
|
||||
<assignment> ::= { call "." } <IDENT> "=" <expression> ";"
|
||||
| <expression> ";"
|
||||
|
||||
|
||||
<fn-decl> ::= "fn" <IDENT> <fn-args> <block>
|
||||
|
||||
<fn-args> ::= "(" <ident-list> ")"
|
||||
|
||||
|
||||
<if-stmt> ::= "if" <expression> <block> { <else-part> }
|
||||
|
||||
<else-part> ::= "else" ( <if-stmt> | <block> )
|
||||
|
||||
|
||||
<loop-stmt> ::= "loop" <block>
|
||||
|
||||
|
||||
<while-stmt> ::= "while" <expression> <block>
|
||||
|
||||
|
||||
<break-stmt> ::= "break" ";"
|
||||
|
||||
|
||||
<return-stmt> ::= "return" { <expression> } ";"
|
||||
|
||||
|
||||
<expression-statement> ::= <expression> ";"
|
||||
|
||||
|
||||
<expression> ::= <logical-or>
|
||||
|
||||
<logical-or> ::= <logical-and> { "or" <logical-or> }
|
||||
|
||||
<logical-and> ::= <equality> { "and" <logical-and> }
|
||||
|
||||
<equality> ::= <comparison> { ("!=" | "==") <comparison> }
|
||||
|
||||
<comparison> ::= <term> { (">" | "<" | ">=" | "<=") <term> }
|
||||
|
||||
<term> ::= <factor> { ("-" | "+") <term> }
|
||||
|
||||
<factor> ::= <unary> { ( "*" | "/" | "%" ) <factor> }
|
||||
|
||||
<unary> ::= { ( "not" | "-" ) } <call>
|
||||
|
||||
<call> ::= <primary> { ( "(" <expr-list> ")" | "." <IDENT> ) }
|
||||
|
||||
<primary> ::= <IDENT>
|
||||
| <NUMBER>
|
||||
| <STRING>
|
||||
| <object-literal>
|
||||
| <array-literal>
|
||||
| "false"
|
||||
| "true"
|
||||
| "null"
|
||||
| "(" <expression> ")"
|
||||
|
||||
<object-literal> ::= "{}"
|
||||
|
||||
<array-literal> ::= "[" <expr-list> "]"
|
||||
|
||||
|
||||
<expr-list> ::= { <expression> { "," <expression> } { "," } }
|
||||
|
||||
<ident-list> ::= { <IDENT> { "," <IDENT> } { "," } }
|
||||
41
src/ast.rs
41
src/ast.rs
|
|
@ -3,11 +3,16 @@
|
|||
//!
|
||||
//! All AST nodes are bump allocated into the lifetime `'ast`
|
||||
|
||||
use crate::errors::Span;
|
||||
#[derive(dbg_pls::DebugPls)]
|
||||
pub struct Span {
|
||||
pub start: usize,
|
||||
pub end: usize,
|
||||
}
|
||||
|
||||
|
||||
type Symbol = usize;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, dbg_pls::DebugPls)]
|
||||
#[derive(dbg_pls::DebugPls)]
|
||||
pub struct Ident {
|
||||
pub sym: Symbol,
|
||||
pub span: Span,
|
||||
|
|
@ -15,13 +20,13 @@ pub struct Ident {
|
|||
|
||||
pub type Program<'ast> = Block<'ast>;
|
||||
|
||||
#[derive(Debug, PartialEq, dbg_pls::DebugPls)]
|
||||
#[derive(dbg_pls::DebugPls)]
|
||||
pub struct Block<'ast> {
|
||||
pub stmts: &'ast [Stmt<'ast>],
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, dbg_pls::DebugPls)]
|
||||
#[derive(dbg_pls::DebugPls)]
|
||||
pub enum Stmt<'ast> {
|
||||
Declaration(Declaration<'ast>),
|
||||
Assignment(Assignment<'ast>),
|
||||
|
|
@ -36,21 +41,21 @@ pub enum Stmt<'ast> {
|
|||
Print(Expr<'ast>, Span),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, dbg_pls::DebugPls)]
|
||||
#[derive(dbg_pls::DebugPls)]
|
||||
pub struct Declaration<'ast> {
|
||||
pub span: Span,
|
||||
pub name: Ident,
|
||||
pub init: Expr<'ast>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, dbg_pls::DebugPls)]
|
||||
#[derive(dbg_pls::DebugPls)]
|
||||
pub struct Assignment<'ast> {
|
||||
pub span: Span,
|
||||
pub lhs: Expr<'ast>,
|
||||
pub rhs: Expr<'ast>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, dbg_pls::DebugPls)]
|
||||
#[derive(dbg_pls::DebugPls)]
|
||||
pub struct FnDecl<'ast> {
|
||||
pub span: Span,
|
||||
pub name: Ident,
|
||||
|
|
@ -58,7 +63,7 @@ pub struct FnDecl<'ast> {
|
|||
pub body: Block<'ast>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, dbg_pls::DebugPls)]
|
||||
#[derive(dbg_pls::DebugPls)]
|
||||
pub struct IfStmt<'ast> {
|
||||
pub span: Span,
|
||||
pub cond: Expr<'ast>,
|
||||
|
|
@ -66,7 +71,7 @@ pub struct IfStmt<'ast> {
|
|||
pub else_part: Option<&'ast ElsePart<'ast>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, dbg_pls::DebugPls)]
|
||||
#[derive(dbg_pls::DebugPls)]
|
||||
pub enum ElsePart<'ast> {
|
||||
Else(Block<'ast>, Span),
|
||||
ElseIf(IfStmt<'ast>, Span),
|
||||
|
|
@ -80,14 +85,14 @@ impl ElsePart<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, dbg_pls::DebugPls)]
|
||||
#[derive(dbg_pls::DebugPls)]
|
||||
pub struct WhileStmt<'ast> {
|
||||
pub span: Span,
|
||||
pub cond: Expr<'ast>,
|
||||
pub body: Block<'ast>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, dbg_pls::DebugPls)]
|
||||
#[derive(dbg_pls::DebugPls)]
|
||||
pub enum Expr<'ast> {
|
||||
Ident(Ident),
|
||||
Literal(Literal<'ast>),
|
||||
|
|
@ -108,7 +113,7 @@ impl Expr<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, dbg_pls::DebugPls)]
|
||||
#[derive(dbg_pls::DebugPls)]
|
||||
pub enum Literal<'ast> {
|
||||
String(Symbol, Span),
|
||||
Number(f64, Span),
|
||||
|
|
@ -131,20 +136,20 @@ impl Literal<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, dbg_pls::DebugPls)]
|
||||
#[derive(dbg_pls::DebugPls)]
|
||||
pub struct UnaryOp<'ast> {
|
||||
pub span: Span,
|
||||
pub expr: Expr<'ast>,
|
||||
pub kind: UnaryOpKind,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, dbg_pls::DebugPls)]
|
||||
#[derive(dbg_pls::DebugPls)]
|
||||
pub enum UnaryOpKind {
|
||||
Not,
|
||||
Neg,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, dbg_pls::DebugPls)]
|
||||
#[derive(dbg_pls::DebugPls)]
|
||||
pub struct BinaryOp<'ast> {
|
||||
pub span: Span,
|
||||
pub lhs: Expr<'ast>,
|
||||
|
|
@ -152,7 +157,7 @@ pub struct BinaryOp<'ast> {
|
|||
pub kind: BinaryOpKind,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, dbg_pls::DebugPls)]
|
||||
#[derive(dbg_pls::DebugPls)]
|
||||
pub enum BinaryOpKind {
|
||||
And,
|
||||
Or,
|
||||
|
|
@ -169,14 +174,14 @@ pub enum BinaryOpKind {
|
|||
Mod,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, dbg_pls::DebugPls)]
|
||||
#[derive(dbg_pls::DebugPls)]
|
||||
pub struct Call<'ast> {
|
||||
pub callee: Expr<'ast>,
|
||||
pub span: Span,
|
||||
pub kind: CallKind<'ast>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, dbg_pls::DebugPls)]
|
||||
#[derive(dbg_pls::DebugPls)]
|
||||
pub enum CallKind<'ast> {
|
||||
Field(Ident),
|
||||
Fn(&'ast [Expr<'ast>]),
|
||||
|
|
|
|||
18
std.md
18
std.md
|
|
@ -1,18 +0,0 @@
|
|||
# Std functions
|
||||
|
||||
`x`, `y`, .. : arguments
|
||||
`x?` : optional
|
||||
`x(): int` : return type
|
||||
|
||||
Available on the global scope for now:
|
||||
|
||||
# IO
|
||||
|
||||
`print(x)`
|
||||
|
||||
`println(x)`
|
||||
|
||||
`input(x?): string`
|
||||
|
||||
`time(): number`
|
||||
|
||||
6
test.dil
6
test.dil
|
|
@ -1,6 +0,0 @@
|
|||
fn test() {
|
||||
print "yo wtf";
|
||||
}
|
||||
|
||||
test();
|
||||
test();
|
||||
Loading…
Add table
Add a link
Reference in a new issue