updated readme
This commit is contained in:
75
README.md
75
README.md
@@ -1,25 +1,56 @@
|
|||||||
# Boring Lang Proposal
|
# Boring Lang
|
||||||
|
|
||||||
**NOTE: This repo is a work in progress as I learn compiler writing, I may abandon this.**
|
|
||||||
**NOTE: The rust code in the repo is temporary abandoned while I finish the python POC, this will eventually be moved to rust**
|
|
||||||
|
|
||||||
The Boring Programming Language (Boring-Lang) is an attempt to create an easy, productive, general purpose programming language that makes as few interesting choices as possible while still being in line with modern concepts in programming languages.
|
The Boring Programming Language (Boring-Lang) is an attempt to create an easy, productive, general purpose programming language that makes as few interesting choices as possible while still being in line with modern concepts in programming languages.
|
||||||
|
|
||||||
The language (wish list):
|
The language:
|
||||||
* is compiled with a run-time (llvm for convenience + c/rust compatibility)
|
* is compiled with a run-time (llvm for convenience + c/rust compatibility)
|
||||||
* has managed memory (via weak pointers and automatic reference counting)
|
* has managed memory (via strong/weak pointers and automatic reference counting)
|
||||||
* uses async-await for all IO, with a built-in multi-core scheduler
|
* uses async-await for all IO, with a built-in multi-core scheduler (tokio)
|
||||||
* supports algebraic data types (Result type for errors, Maybe/Optional type for nullables)
|
* supports algebraic data types (Result type for errors, Maybe/Optional type for nullables)
|
||||||
* supports parametric polymorphism (generics) with higher kinded types
|
* supports parametric polymorphism (generics) with higher kinded types
|
||||||
* uses struct+traits, rather than classes or stuct+interfaces
|
* uses struct+traits, rather than classes or stuct+interfaces
|
||||||
* has a rich standard library (similar scale to python or go)
|
* has a rich standard library (similar scale to python or go)
|
||||||
* is immutable by default
|
* is immutable by default
|
||||||
|
* is sandboxed by default
|
||||||
|
|
||||||
|
It's a middle-ground of Rust, Golang, Swift, Typescript, and Python. The goal is not to break any new ground in PL theory, or even create a language anyone likes, but rather to create a language with as few deal-breakers as possible for maximum day-to-day industrial programming ergonomics.
|
||||||
|
|
||||||
|
This language is under active development, progress will be marked here as the language is developed.
|
||||||
|
|
||||||
|
- [x] Functions
|
||||||
|
- [x] Int Literals
|
||||||
|
- [x] Float Literals
|
||||||
|
- [x] Block expression
|
||||||
|
- [x] Return keyword
|
||||||
|
- [x] Normal assignment
|
||||||
|
- [x] Structs
|
||||||
|
- [x] Define
|
||||||
|
- [x] Literal
|
||||||
|
- [x] Getter
|
||||||
|
- [x] Setter
|
||||||
|
- [x] Type Aliases
|
||||||
|
- [ ] Methods
|
||||||
|
- [x] Declaration
|
||||||
|
- [ ] Use
|
||||||
|
- [ ] Traits
|
||||||
|
- [ ] Generics
|
||||||
|
- [ ] Basic
|
||||||
|
- [ ] Higher kinded types
|
||||||
|
- [ ] Control Flow
|
||||||
|
- [ ] If
|
||||||
|
- [ ] While
|
||||||
|
- [ ] For
|
||||||
|
- [ ] Enums
|
||||||
|
- [ ] Lambdas
|
||||||
|
- [ ] Async-Await
|
||||||
|
- [ ] Imports
|
||||||
|
- [ ] Visibility
|
||||||
|
- [ ] Const / Mut
|
||||||
|
|
||||||
It's basically a middle-ground of Rust, Golang, Swift, Typescript, and Python. The goal is not to break any new ground in PL theory, or even create a language anyone likes, but rather to create a language with as few deal-breakers as possible for day-to-day industrial programming.
|
|
||||||
|
|
||||||
## Http Server Example
|
## Http Server Example
|
||||||
|
|
||||||
```
|
```rust
|
||||||
import net.http as http
|
import net.http as http
|
||||||
import logging as logging
|
import logging as logging
|
||||||
import json as json
|
import json as json
|
||||||
@@ -54,7 +85,7 @@ async fn main(args: Vec[Str], os: OS): I32 {
|
|||||||
|
|
||||||
All variables are immutable by default, to make them mutable use the `mut` keyword. Once a variable becomes immutable it cannot become mutable again. If you need it to become mutable, either implement the `clone` trait, or simply create a new one with the same data.
|
All variables are immutable by default, to make them mutable use the `mut` keyword. Once a variable becomes immutable it cannot become mutable again. If you need it to become mutable, either implement the `clone` trait, or simply create a new one with the same data.
|
||||||
|
|
||||||
```
|
```rust
|
||||||
let mut foo = Dict[String, Int32].new(); // constructor returns a mutable reference
|
let mut foo = Dict[String, Int32].new(); // constructor returns a mutable reference
|
||||||
foo.insert("eggs", 12);
|
foo.insert("eggs", 12);
|
||||||
foo.insert("bananas", 2);
|
foo.insert("bananas", 2);
|
||||||
@@ -70,7 +101,7 @@ baz.insert("apples", 4); // fine
|
|||||||
|
|
||||||
Methods on a struct must specify if they mutate the struct.
|
Methods on a struct must specify if they mutate the struct.
|
||||||
|
|
||||||
```
|
```rust
|
||||||
impl Dict[Key: Hashable, Value] {
|
impl Dict[Key: Hashable, Value] {
|
||||||
fn insert(self: mut Self, key: Key, value: Value) {
|
fn insert(self: mut Self, key: Key, value: Value) {
|
||||||
// mutate self here
|
// mutate self here
|
||||||
@@ -91,10 +122,10 @@ Context is an exceptionally useful feature in golang, but a common complaint is
|
|||||||
|
|
||||||
The boring standard library solves this by using parametric polymorphism. Context is by default an empty object passed through the chain, and each function/set of context parameters is an additional trait condition applied at compile time.
|
The boring standard library solves this by using parametric polymorphism. Context is by default an empty object passed through the chain, and each function/set of context parameters is an additional trait condition applied at compile time.
|
||||||
|
|
||||||
```
|
```rust
|
||||||
type HTTPRequest[Ctx: Context] = async fn(Ctx, http.Request, mut http.Response)
|
type HTTPRequest[Ctx: Context] = async fn(Ctx, http.Request, mut http.Response);
|
||||||
|
|
||||||
pub fn tracing_middleware[Ctx: Tracing](handler: HTTPRequest[Ctx]) HTTPRequest {
|
pub fn tracing_middleware[Ctx: Tracing](handler: HTTPRequest[Ctx]): HTTPRequest {
|
||||||
return async fn(ctx: Ctx, req: http.Request, resp: mut http.Response) {
|
return async fn(ctx: Ctx, req: http.Request, resp: mut http.Response) {
|
||||||
with tracing.Span(ctx, "request_duration") {
|
with tracing.Span(ctx, "request_duration") {
|
||||||
await handler(ctx, req, resp);
|
await handler(ctx, req, resp);
|
||||||
@@ -102,7 +133,7 @@ pub fn tracing_middleware[Ctx: Tracing](handler: HTTPRequest[Ctx]) HTTPRequest {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn auth_middleware[Ctx: Auth](handler: HTTPRequest[Ctx], scope: Str) HTTPRequest {
|
pub fn auth_middleware[Ctx: Auth](handler: HTTPRequest[Ctx], scope: Str): HTTPRequest {
|
||||||
return async fn(ctx: Ctx, req: http.Request, resp: mut http.Response) {
|
return async fn(ctx: Ctx, req: http.Request, resp: mut http.Response) {
|
||||||
if ctx.has_scope(scope) {
|
if ctx.has_scope(scope) {
|
||||||
await handler(ctx, req, resp);
|
await handler(ctx, req, resp);
|
||||||
@@ -112,7 +143,7 @@ pub fn auth_middleware[Ctx: Auth](handler: HTTPRequest[Ctx], scope: Str) HTTPReq
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cancel_middleware[Ctx: Cancel](handler: HTTPRequest[Ctx]) HTTPRequest {
|
pub fn cancel_middleware[Ctx: Cancel](handler: HTTPRequest[Ctx]): HTTPRequest {
|
||||||
return async fn(ctx: Ctx, req: http.Request, resp: mut http.Response) {
|
return async fn(ctx: Ctx, req: http.Request, resp: mut http.Response) {
|
||||||
if !(await ctx.is_cancelled()) { // check cancel token
|
if !(await ctx.is_cancelled()) { // check cancel token
|
||||||
await handler(ctx, req, resp);
|
await handler(ctx, req, resp);
|
||||||
@@ -129,7 +160,7 @@ for the above examples, you would pass a context type that implements all three
|
|||||||
|
|
||||||
Similar to python, folders/files represent the `.` seperated import path, but relative imports are *not* supported. Exported values must be marked with `pub`. All imports take the form:
|
Similar to python, folders/files represent the `.` seperated import path, but relative imports are *not* supported. Exported values must be marked with `pub`. All imports take the form:
|
||||||
|
|
||||||
```
|
```rust
|
||||||
import package.path as local_name
|
import package.path as local_name
|
||||||
|
|
||||||
pub type MyStruct struct {
|
pub type MyStruct struct {
|
||||||
@@ -143,7 +174,7 @@ pub type MyStruct struct {
|
|||||||
|
|
||||||
`if` is an expression in boring-lang, with the last expression in a block being the return value.
|
`if` is an expression in boring-lang, with the last expression in a block being the return value.
|
||||||
|
|
||||||
```
|
```rust
|
||||||
let a = if true {
|
let a = if true {
|
||||||
4
|
4
|
||||||
} else {
|
} else {
|
||||||
@@ -160,7 +191,7 @@ Conditions do not require parenthesis and *must* evaluate to the Boolean type.
|
|||||||
|
|
||||||
Boring-lang supports `for` and `while` loops, with `for` having an `async` variant. `while` loops require an expression of Boolean type, while `for` loops require an expression that implements the `Iter` or `AIter` traits.
|
Boring-lang supports `for` and `while` loops, with `for` having an `async` variant. `while` loops require an expression of Boolean type, while `for` loops require an expression that implements the `Iter` or `AIter` traits.
|
||||||
|
|
||||||
```
|
```rust
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
while i < 100 {
|
while i < 100 {
|
||||||
i = i + 1;
|
i = i + 1;
|
||||||
@@ -179,7 +210,7 @@ async for result in paginated_list {
|
|||||||
|
|
||||||
`continue` and `break` work similar to other languages.
|
`continue` and `break` work similar to other languages.
|
||||||
|
|
||||||
```
|
```rust
|
||||||
while true {
|
while true {
|
||||||
break; // do nothing
|
break; // do nothing
|
||||||
}
|
}
|
||||||
@@ -201,7 +232,7 @@ for i in range(100) {
|
|||||||
|
|
||||||
return async with db.transation(ctx) as t {
|
return async with db.transation(ctx) as t {
|
||||||
await t.insert(ctx, record); // returns result type
|
await t.insert(ctx, record); // returns result type
|
||||||
}
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
### `return`
|
### `return`
|
||||||
@@ -218,7 +249,7 @@ let result = match number {
|
|||||||
1 => 'foo',
|
1 => 'foo',
|
||||||
3 => 'bar',
|
3 => 'bar',
|
||||||
_ => 'baz',
|
_ => 'baz',
|
||||||
}
|
};
|
||||||
|
|
||||||
// result = 'bar'
|
// result = 'bar'
|
||||||
```
|
```
|
||||||
|
|||||||
26
notes.txt
26
notes.txt
@@ -30,29 +30,3 @@ class TypeUsage:
|
|||||||
|
|
||||||
if / match return never if all blocks return never;
|
if / match return never if all blocks return never;
|
||||||
blocks propagate never except at the function level;
|
blocks propagate never except at the function level;
|
||||||
|
|
||||||
|
|
||||||
TODO:
|
|
||||||
* ~Float Literals~
|
|
||||||
* ~Block expression~
|
|
||||||
* ~Return keyword~
|
|
||||||
* ~Normal assignment~
|
|
||||||
* ~Structs~
|
|
||||||
* ~Define~
|
|
||||||
* ~Literal~
|
|
||||||
* ~Getter~
|
|
||||||
* ~Setter~
|
|
||||||
* ~Type Aliases~
|
|
||||||
* Methods
|
|
||||||
* ~Declaration~
|
|
||||||
* Use
|
|
||||||
* Traits
|
|
||||||
* Generics
|
|
||||||
* Enums
|
|
||||||
* Arrays
|
|
||||||
* Strings
|
|
||||||
* Lambdas
|
|
||||||
* Async
|
|
||||||
* Imports
|
|
||||||
* Visibility
|
|
||||||
* Const / Mut
|
|
||||||
|
|||||||
Reference in New Issue
Block a user