This commit is contained in:
nora 2022-04-23 17:25:15 +02:00
parent 930955590d
commit 1bb09e48ec
13 changed files with 23 additions and 445 deletions

View file

@ -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
View file

@ -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
`==`
`>=`
`>`
`<=`
`<`
`!=`
`+`
`-`
`*`
`/`
`%`

View file

@ -1,4 +0,0 @@
disallowed-types = [
"std::collections::HashMap",
"std::collections::HashSet",
]

3
fuzz/.gitignore vendored
View file

@ -1,3 +0,0 @@
target
corpus
artifacts

53
fuzz/Cargo.lock generated
View file

@ -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"

View file

@ -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

View file

@ -1,6 +0,0 @@
#![no_main]
use libfuzzer_sys::fuzz_target;
fuzz_target!(|data: String| {
dilaria::_fuzz_compile(&data);
});

View file

@ -1,6 +0,0 @@
#![no_main]
use libfuzzer_sys::fuzz_target;
fuzz_target!(|data: String| {
dilaria::_fuzz_lex(&data);
});

View file

@ -1,6 +0,0 @@
#![no_main]
use libfuzzer_sys::fuzz_target;
fuzz_target!(|data: String| {
dilaria::_fuzz_parse(&data);
});

View file

@ -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> } { "," } }

View file

@ -3,11 +3,16 @@
//! //!
//! All AST nodes are bump allocated into the lifetime `'ast` //! 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; type Symbol = usize;
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, dbg_pls::DebugPls)] #[derive(dbg_pls::DebugPls)]
pub struct Ident { pub struct Ident {
pub sym: Symbol, pub sym: Symbol,
pub span: Span, pub span: Span,
@ -15,13 +20,13 @@ pub struct Ident {
pub type Program<'ast> = Block<'ast>; pub type Program<'ast> = Block<'ast>;
#[derive(Debug, PartialEq, dbg_pls::DebugPls)] #[derive(dbg_pls::DebugPls)]
pub struct Block<'ast> { pub struct Block<'ast> {
pub stmts: &'ast [Stmt<'ast>], pub stmts: &'ast [Stmt<'ast>],
pub span: Span, pub span: Span,
} }
#[derive(Debug, PartialEq, dbg_pls::DebugPls)] #[derive(dbg_pls::DebugPls)]
pub enum Stmt<'ast> { pub enum Stmt<'ast> {
Declaration(Declaration<'ast>), Declaration(Declaration<'ast>),
Assignment(Assignment<'ast>), Assignment(Assignment<'ast>),
@ -36,21 +41,21 @@ pub enum Stmt<'ast> {
Print(Expr<'ast>, Span), Print(Expr<'ast>, Span),
} }
#[derive(Debug, PartialEq, dbg_pls::DebugPls)] #[derive(dbg_pls::DebugPls)]
pub struct Declaration<'ast> { pub struct Declaration<'ast> {
pub span: Span, pub span: Span,
pub name: Ident, pub name: Ident,
pub init: Expr<'ast>, pub init: Expr<'ast>,
} }
#[derive(Debug, PartialEq, dbg_pls::DebugPls)] #[derive(dbg_pls::DebugPls)]
pub struct Assignment<'ast> { pub struct Assignment<'ast> {
pub span: Span, pub span: Span,
pub lhs: Expr<'ast>, pub lhs: Expr<'ast>,
pub rhs: Expr<'ast>, pub rhs: Expr<'ast>,
} }
#[derive(Debug, PartialEq, dbg_pls::DebugPls)] #[derive(dbg_pls::DebugPls)]
pub struct FnDecl<'ast> { pub struct FnDecl<'ast> {
pub span: Span, pub span: Span,
pub name: Ident, pub name: Ident,
@ -58,7 +63,7 @@ pub struct FnDecl<'ast> {
pub body: Block<'ast>, pub body: Block<'ast>,
} }
#[derive(Debug, PartialEq, dbg_pls::DebugPls)] #[derive(dbg_pls::DebugPls)]
pub struct IfStmt<'ast> { pub struct IfStmt<'ast> {
pub span: Span, pub span: Span,
pub cond: Expr<'ast>, pub cond: Expr<'ast>,
@ -66,7 +71,7 @@ pub struct IfStmt<'ast> {
pub else_part: Option<&'ast ElsePart<'ast>>, pub else_part: Option<&'ast ElsePart<'ast>>,
} }
#[derive(Debug, PartialEq, dbg_pls::DebugPls)] #[derive(dbg_pls::DebugPls)]
pub enum ElsePart<'ast> { pub enum ElsePart<'ast> {
Else(Block<'ast>, Span), Else(Block<'ast>, Span),
ElseIf(IfStmt<'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 struct WhileStmt<'ast> {
pub span: Span, pub span: Span,
pub cond: Expr<'ast>, pub cond: Expr<'ast>,
pub body: Block<'ast>, pub body: Block<'ast>,
} }
#[derive(Debug, PartialEq, dbg_pls::DebugPls)] #[derive(dbg_pls::DebugPls)]
pub enum Expr<'ast> { pub enum Expr<'ast> {
Ident(Ident), Ident(Ident),
Literal(Literal<'ast>), Literal(Literal<'ast>),
@ -108,7 +113,7 @@ impl Expr<'_> {
} }
} }
#[derive(Debug, PartialEq, dbg_pls::DebugPls)] #[derive(dbg_pls::DebugPls)]
pub enum Literal<'ast> { pub enum Literal<'ast> {
String(Symbol, Span), String(Symbol, Span),
Number(f64, 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 struct UnaryOp<'ast> {
pub span: Span, pub span: Span,
pub expr: Expr<'ast>, pub expr: Expr<'ast>,
pub kind: UnaryOpKind, pub kind: UnaryOpKind,
} }
#[derive(Debug, PartialEq, dbg_pls::DebugPls)] #[derive(dbg_pls::DebugPls)]
pub enum UnaryOpKind { pub enum UnaryOpKind {
Not, Not,
Neg, Neg,
} }
#[derive(Debug, PartialEq, dbg_pls::DebugPls)] #[derive(dbg_pls::DebugPls)]
pub struct BinaryOp<'ast> { pub struct BinaryOp<'ast> {
pub span: Span, pub span: Span,
pub lhs: Expr<'ast>, pub lhs: Expr<'ast>,
@ -152,7 +157,7 @@ pub struct BinaryOp<'ast> {
pub kind: BinaryOpKind, pub kind: BinaryOpKind,
} }
#[derive(Debug, PartialEq, dbg_pls::DebugPls)] #[derive(dbg_pls::DebugPls)]
pub enum BinaryOpKind { pub enum BinaryOpKind {
And, And,
Or, Or,
@ -169,14 +174,14 @@ pub enum BinaryOpKind {
Mod, Mod,
} }
#[derive(Debug, PartialEq, dbg_pls::DebugPls)] #[derive(dbg_pls::DebugPls)]
pub struct Call<'ast> { pub struct Call<'ast> {
pub callee: Expr<'ast>, pub callee: Expr<'ast>,
pub span: Span, pub span: Span,
pub kind: CallKind<'ast>, pub kind: CallKind<'ast>,
} }
#[derive(Debug, PartialEq, dbg_pls::DebugPls)] #[derive(dbg_pls::DebugPls)]
pub enum CallKind<'ast> { pub enum CallKind<'ast> {
Field(Ident), Field(Ident),
Fn(&'ast [Expr<'ast>]), Fn(&'ast [Expr<'ast>]),

18
std.md
View file

@ -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`

View file

@ -1,6 +0,0 @@
fn test() {
print "yo wtf";
}
test();
test();