updated readme

This commit is contained in:
Andrew Segavac
2019-12-30 20:58:27 -07:00
parent 2122bd8f31
commit 43266d898b

View File

@@ -5,11 +5,11 @@
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 (wish list):
* is compiled with a run-time (llvm for convenience + c compatibility) * is compiled with a run-time (llvm for convenience + c/rust compatibility)
* is garbage collected * is garbage collected
* 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
* 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 * supports parametric polymorphism (generics)
* uses struct+traits, rather than classes or stuct+interfaces * uses struct+traits, rather than classes or stuct+interfaces
* has a rich standard library (http server, actor model) * has a rich standard library (http server, actor model)
* is immutable by default * is immutable by default
@@ -46,22 +46,20 @@ async func main(args: Array<Str>) Int32 {
## Mutability ## Mutability
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 `copy` 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.
``` ```
let mut foo := Dict<String, Int32>{ let mut foo = Dict<String, Int32>() // constructors always return a mutable reference
'eggs': 12, foo.insert("eggs", 12)
'bananas': 2, foo.insert("bananas", 2)
} foo.insert("grapes", 2)
// fine
foo.insert('grapes', 2)
let bar = foo // bar is not mutable let bar = foo // bar is not mutable
bar.insert('apples', 4) // fails with compiler error bar.insert("apples", 4) // fails with compiler error
let mut baz = bar.copy() let mut baz = bar.clone()
baz.insert('apples', 4) // fine 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.
@@ -72,7 +70,7 @@ impl Dict<Key: Hashable, Value> {
// mutate self here // mutate self here
} }
func get(self: Dict, key: Key) { func get(self: Dict, key: Key) Optional<Value> {
// no need for `mut` // no need for `mut`
} }
} }
@@ -90,31 +88,31 @@ The boring standard library solves this by using parametric polymorphism. Contex
``` ```
type HTTPRequest<Ctx: Context> = async func(Ctx, http.Request, mut http.Response) type HTTPRequest<Ctx: Context> = async func(Ctx, http.Request, mut http.Response)
pub func tracing_middleware<Ctx: Tracing>(handler: HTTPRequest<Ctx>){ pub func tracing_middleware<Ctx: Tracing>(handler: HTTPRequest<Ctx>) HTTPRequest {
return async func(ctx: Ctx, req: http.Request, resp: mut http.Response) { return async func(ctx: Ctx, req: http.Request, resp: mut http.Response) {
with tracing.NewSpan(ctx, 'request_duration') { with tracing.Span(ctx, "request_duration") {
await handler(ctx, req, resp) await handler(ctx, req, resp)
} }
} }
} }
pub func auth_middleware<Ctx: Auth>(handler: HTTPRequest<Ctx>, scope: Str){ pub func auth_middleware<Ctx: Auth>(handler: HTTPRequest<Ctx>, scope: Str) HTTPRequest {
return async func(ctx: Ctx, req: http.Request, resp: mut http.Response) { return async func(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)
} }
await resp.set_status(403) await resp.set_status(403)
await resp.write('missing scope') await resp.write("missing scope")
} }
} }
pub func cancel_middleware<Ctx: Cancel>(handler: HTTPRequest<Ctx>){ pub func cancel_middleware<Ctx: Cancel>(handler: HTTPRequest<Ctx>) HTTPRequest {
return async func(ctx: Ctx, req: http.Request, resp: mut http.Response) { return async func(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)
} }
await resp.set_status(400) await resp.set_status(400)
await resp.write('cancelled') await resp.write("cancelled")
} }
} }
``` ```
@@ -123,18 +121,22 @@ for the above examples, you would pass a context type that implements all three
## Monadic function modifiers ## Monadic function modifiers
Boring uses function modifiers to implement functionality like `async/await` and `coroutines`. These function by rewriting the AST prior to compilation. The table below describes the modifiers currently available. Boring uses function modifiers to implement functionality like `async/await` and `coroutines`. These function by [rewriting the code into a state machine](https://tmandry.gitlab.io/blog/posts/optimizing-await-1/) prior to compilation. The table below describes the modifiers currently available.
|Type|Change To Return Type|Introduces to Scope| |Type|Change To Return Type|Introduces to Scope|
|---|---|---| |---|---|---|
|async|`Promise<ReturnType>`|await| |`async`|`Promise<ReturnType>`|`await`|
|coroutine|`FirstReturnType,func(Next,Params)...`|yield| |`coroutine`|`FirstReturnType,func(Next,Params)...`|`yield`|
|errors<ErrorType>|`Result<ReturnType,ErrorType>`|?| |`error<ErrorType>`|`Result<ReturnType,ErrorType>`|`?`|
## Import System ## Import System
Similar to python, folders/files represent the `.` seperated import path though 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:
``` ```
import package.path as local_name import package.path as local_name
pub struct MyStruct {
id: Int
}
``` ```