From bf0d65f1763abb4adc9be993f3a12afecefc8f8a Mon Sep 17 00:00:00 2001 From: Logan Date: Mon, 23 Sep 2024 01:10:17 -0500 Subject: [PATCH] language ideas started --- src/css/style.css | 17 +- src/res/Outfit.woff | Bin 0 -> 16168 bytes src/writings/2-language-ideas.md | 374 +++++++++++++++++++++++++++++++ src/writings/index.md | 1 + 4 files changed, 387 insertions(+), 5 deletions(-) create mode 100644 src/res/Outfit.woff create mode 100644 src/writings/2-language-ideas.md diff --git a/src/css/style.css b/src/css/style.css index 2c4a3b9..d334bd4 100644 --- a/src/css/style.css +++ b/src/css/style.css @@ -1,3 +1,8 @@ +@font-face { + font-family: 'outfit'; + src: url(/res/Outfit.woff); +} + @font-face { font-family: 'atkinson'; src: url(/res/atkinson-regular.woff2); @@ -14,7 +19,7 @@ } body { - font-family: 'merriweather'; + font-family: 'outfit'; background-image: url("/res/grey.png"); background-repeat: repeat; height: 100%; @@ -28,8 +33,8 @@ main { background-color: #ffeedd; margin: auto; max-width: 40em; - line-height: 1.8em; - font-size: 1.2em; + line-height: 1.4em; + font-size: 1.4em; } p { @@ -45,7 +50,9 @@ code { background: #1e1e22; color: #dddde1; padding: 0.1em; - margin: 0.1em 0em 0.1em; + padding-left: 0.3em; + padding-right: 0.3em; + border-radius: 0.4em; } table { @@ -104,7 +111,7 @@ figcaption { line-height: 110%; } -img,iframe,code { +img,iframe { border-radius: 0.4em; } diff --git a/src/res/Outfit.woff b/src/res/Outfit.woff new file mode 100644 index 0000000000000000000000000000000000000000..3d4f5b55f15e6e4980ddf8775b4ba98095223439 GIT binary patch literal 16168 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 z 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 literal 0 HcmV?d00001 diff --git a/src/writings/2-language-ideas.md b/src/writings/2-language-ideas.md new file mode 100644 index 0000000..acea28f --- /dev/null +++ b/src/writings/2-language-ideas.md @@ -0,0 +1,374 @@ +# language ideas +Programming languages are something I think about a lot. This +is a list of design choices I think are interesting, and would +like to implement some day. Treat this page as documentation for +a hypothetical language. Ideas are stolen liberally from +[zig](https://ziglang.org/), [odin](https://odin-lang.org/), jai, +[go](https://go.dev/), and [rust](https://www.rust-lang.org/) + +## guiding principles +A good language is comprehensive but not complex. It should provide a +reasonable implementation for every common algorithm and data type, as well +as many uncommon ones. Its use of concepts and keywords should be economical; +each should perform a unique function not possible in their absence. Language +features should closely map on to the real world mathematical and theoretical +ideas they exist downstream from. It should be fast, simple, and succinct +without compromise + +## primitives +Algebraic primitives are written as a single character followed by a data +size. They include wholes (unsigned), integers (signed), real (floating point), +complex, and quaternion types. The components of complex and quaternion numbers +are reals. Primitive data sizes may be 8, 16, 32, 64, 128, or platform defined. +Reals must have a data size greater than 8. Algebraic primitives may optionally +specify they are big or little endian by appending `be` or `le` respectively. + +The lexical primitives are glyphs, strings, and substrings. A glyph represents a +single Unicode code-point, and is 32 bits wide. A string is an owned buffer +of UTF-8 encoded text. Substrings are "fat pointers" to string buffers, with +a specified +length. + +The logical primitives are booleans and bitflags. A boolean is 8 bits wide, and +can be true or false. Bitflags are a compressed array of booleans, and may be +8, 16, 32, 64, or 128 bits wide. + +The two special types are pointers and the empty type. The pointer type is wide enough to +fit a native pointer, and is intentionally distinct from `wsize` in order to support +the [CHERI](https://www.cl.cam.ac.uk/research/security/ctsrd/cheri/) architecture +(see [this article](https://tratt.net/laurie/blog/2022/making_rust_a_better_fit_for_cheri_and_other_platforms.html)). +The empty type exists only implicitly, and has a size of zero. It is primarily used in +combination with fallible types to represent the absence of a value. No variable or immutable +can be of the empty type. It is represented as an empty block `{}` + +```yaml +primitive: + algebraic: + whole: w8 w16 w32 w64 w128 wsize + integer: i8 i16 i32 i64 i128 isize + real: r16 r32 r64 r128 + complex: c32 c64 c128 c256 + quaternion: q64 q128 q256 q512 + lexical: glyph string substr + logical: bool b8 b16 b32 b64 b128 + special: ptr {} +``` + +## operators +```yaml +math: + - / * % +logical: not and or xor +bitwise: ~ & | ^ << >> +comparative: < <= > >= == != +``` + +## variables +Variables and constants are strongly typed, but the type may be inferred or +explicit. Re-declared variables shadow the previous declaration for the current +scope. Declaration is done using `:=` and `::`. Uninitialized variables are zeroed +by default. Multiple declaration and assignment is allowed +```rust +// Implicit type +v1 := 10; +c1 :: true; +// Explicit type +v2 : i64 = 20; +c2 : bool : false; + +v1 = 15; // Assignment +v3, v4 := 'π', 3.14159; // Multiple declaration +v3, v4 = 'τ', 6.28318; // Multiple assignment +{ + v2 := "Hello World"; // Name shadowing + v4, v5 := 4.0, q128(1.0, 0.0, 0.0, 0.0); +} +// v2 == 20, v4 == 6.28318 +``` + +## conditionals +There are two kinds of conditionals, if-else statements and when statements. The +when statement is similar to the switch statement in other languages. They must +exhaustively cover every case, or include a default case. Both can be used +as the right-hand side of an assignment +```rust +n := 15; +sign := if n < 0 { + print("n is negative"); + -1 +} else { + print("n is positive"); + 1 +} + +s := ":)" +match s { + ":(" -> { + println("Sad face"); + }, + ":)" -> { + println("Happy face"); + }, + ":|" -> { + println("Neutral face"); + }, + default(val) -> { + println("I dont recognize this face:"); + println(val); + } +} +``` + +## blocks +Blocks are surrounded by `{}` and optionally evaluate to some type. A block +may be given a name using the `@` operator. By default, blocks will capture all +variables within the scope they are declared. A block can optionally capture +only specific named variables from the scope in which it is evaluated using the +capture syntax `[]`. + +The `break` keyword is used to escape a block early. A block name can be +provided to break out of multiple nested blocks at once. If the escaped block +evaluates to a type, a value must be provided to break. If the final expression +within a block does not end in a semicolon, the block will evaluate to that +expression. +```rust +sum := 0; +for x : 0..100 @x_block { + for y : 0..100 @y_block { + for z : 0..100 @z_block { + if x == 16 { + break @x_block; + } + else if y == 64 and z == 32 { + break @y_block; + } + sum += x + y + z; + } + } +} + +outside := "foo"; +sum2 := [^sum] { // Captures mutable reference to `sum` + /* outside = "bar"; */ // ERROR: only `sum` is captured + sum *= 2 +} // == sum * 2 +``` + +## functions +Functions and lambdas are not distinct types, and do not have distinct syntax. +A function may be declared anywhere a variable may, including inside other +functions or as a parameter. A function may have any number of ordered +parameters, and may be variadic. Functions may have default parameters, +and default parameters may refer to parameters which come before them. +Multiple values may be returned from a function + +A function may accept any number of receiver types. A receiver types +implements the function as a "method". Multiple receiver parameters refer to +a parenthetical list of objects of the given types, which are order dependent. +Types can use methods defined from any receiver function within the current +scope. Receiver types can be any type, including primitives. + +Function overloading is valid so long as no two functions share both a name +and call signature. Function names can also be shadowed just like variables. + +A function body is a block. This means it can optionally capture local variables +from where it is called. Unlike regular blocks, function blocks do not capture +locals automatically. Functions implicitly return the last expression of their +body if it does not end in a semicolon, and can be returned early by using +`break` without a block name. Note that block captures and names are not part of +a functions signature +```rust +// Receiver types come before parameters, and may be elided +fizzbuzz :: (number: wsize) -> wsize { + sum := 0; + if number == 0 { + println("Input cannot be zero"); + break sum; // Early return + } + for i : 0..number { + if (i % 3 == 0) and (i % 5 == 0) { + println("fizzbuzz"); + sum += 1; + } + else if i % 3 == 0 { + println("fizz"); + } + else if i % 5 == 0 { + println("buzz"); + } + } + sum // return the number of fizzbuzz's +} +f1 := fizzbuzz(15); +f2 := fizzbuzz(number: 30); // Parameters may be explicitly named + +// With a single receiver +fizzbuzz :: (number: wsize)() -> wsize { fizzbuzz(number) } +f3 := 15.fizzbuzz() + +// With multiple receivers +fizzbuzz :: (number1: wsize, number2: wsize)() -> wsize, wsize { + number1.fizzbuzz(), number2.fizzbuzz() +} +f4, f5 := (15, 30).fizzbuzz(); + +// With capture +sum_locals :: () [f1: wsize, f2: wsize, f3: wsize, f4: wsize] { + f1 + f2 + f3 + f4 +} + +f6 := sum_locals(); // Captures local variables implicitly +``` + +## fallibility +A type which is followed by a question mark `?` is marked as fallible. A fallible +type may or may not contain a value, and must be checked before they are accessed. +All types implicitly convert to their fallible counterpart +```rust +something : w64? = 5; +nothing : w64? = {}; + +// Conditional assignment +if num := something { + print("Found a value"); +} else { + print("No value exists"); +} + +// Most boolean operations work on fallible types +maybe = something or nothing; +``` + +Functions may return a fallible type. Placing a question mark after +a fallible value will immediately return from the current +function if that value is empty +```rust +divide :: (numerator: r64, divisor: r64) -> r64? { + if numerator == 0.0 { + break; // Failure case, returns the empty type + } + numerator / divisor +} + +inverse_squared :: (val: r64) -> r64? { + inv : r64 = divide(1.0, val)?; + inv * inv +} +``` + +## generators +Capturing variables within a function allows for generator functions. +A generator function can produce different values each time it is called. +They are often used to lazily evaluate an open-ended sequence, or to iterate +over a collection. The `:` operator inside a for loop expression will call +a function repeatedly until the function fails to return a value +```rust +range (minimum: i64, maximum: i64) -> (() -> i64?) { + current := minimum; + () [minimum, maximum, current] { + last := current; + current += 1; + if current <= maximum { + break last; + } else { + break; + } + } +} + +iterable := range(0, 10); +for i : iterable { + print(i); +} // Prints 0-9 + +iterable := 0..10; // Equivalant to range(0, 10) +``` + +## move, clone, refer +Be default, parameters and receivers are "moved" into the function body. This +means that they can no longer be accessed by the surrounding scope. A variable +may be cloned instead to replicate the classic C "pass by value" behavior. The +`clone` method is implemented on all primitives and may be implemented on any +user defined type. + +Referenced types are prefixed by `&` or `^`, for immutable and mutable +references respectively. Cloning a reference results in a clone of the +underlying value. Receiver arguments can be either type of reference. Values +will implicitly cast to their referenced equivalent for the purpose of method +calls, but not vice-versa +```rust +value : wsize = 10; +reference : &wsize = &2; + +divide :: (numerator: wsize)(divisor: &wsize) { + numerator / divisor +} + +num1 := value.divide(reference); // `value` moves out of scope +num2 := num1.clone().divide(reference); // `num1` stays in scope +num3 := reference.clone().divide(&num1); +``` +## aliased types +A type can be aliased, giving it a new name. The alias is treated as a +completely different type, and will not implicitly cast to the original type +```rust +my_string_alias :: string; +normal_string : string = "Hello World"; +aliased_string : my_string_alias = "Goodbye World"; +/* normal_string = aliased_string; */ // ERROR: incompatible types +``` + +## structures +A structure is defined by aliasing the `struct` type. They may contain named or +unnamed fields, but not a mix of both. Like local variables, uninitialized struct +fields are zeroed by default +```rust +// Struct with named fields +Position :: struct { + x: r64, y: r64 +}; + +origin : Position = {x: 0.0, y: 0.0}; +// With unnamed fields +Color :: struct { + r64, r64, r64 +}; +red : Color = {0.0, 0.0, 0.0}; +// Accessing unnamed fields +red.0 = 1.0; +red.1 = 0.2; +red.2 = 0.2; +// red == {1.0, 0.2, 0.2}; +``` + +## defer +Execution of a block can be deferred until the end of the current scope. Deferred +blocks execute in the reverse order they were declared +```rust +{ + println("First"); + defer { println("Fourth"); } + defer { println("Third"); } + println("Second") +} +``` + +## namespaces +All source files implicitly exist within their own namespace, which must be +named at the top of the file. An inner namespace can also be declared. Members +of a namespace are accessed using the dot `.` operator +```rust +ns1 :: { + foo :: () { + println("foo"); + } + + ns2 :: { + bar :: () { + println("bar"); + } + } +} + +ns1.foo(); +ns1.ns2.bar(); +``` diff --git a/src/writings/index.md b/src/writings/index.md index 024e476..c681ead 100644 --- a/src/writings/index.md +++ b/src/writings/index.md @@ -1,2 +1,3 @@ # writings +* [language ideas](./2-language-ideas.html) * [on build systems](./1-build-systems.html)