updated readme

This commit is contained in:
Andrew Segavac
2021-06-16 12:02:02 -06:00
parent b2403176b9
commit 8408983bc2
2 changed files with 53 additions and 48 deletions

View File

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

View File

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