diff --git a/md/learn/adts/union-types.md b/md/learn/adts/union-types.md index ae653b0..b66dc7b 100644 --- a/md/learn/adts/union-types.md +++ b/md/learn/adts/union-types.md @@ -11,7 +11,7 @@ enum Suit Spades, } -val suit = Suit::Hearts +let suit = Suit::Hearts ``` @@ -24,7 +24,7 @@ enum IpAddress V6(String), } -val addr_1 = IpAddress::V4("192.168.0.1") +let addr_1 = IpAddress::V4("192.168.0.1") match addr_1 | IpAddress::V4(ip) diff --git a/md/learn/basics/variables.md b/md/learn/basics/variables.md index a9906b6..656b37d 100644 --- a/md/learn/basics/variables.md +++ b/md/learn/basics/variables.md @@ -2,46 +2,25 @@ thp distinguishes between mutable and immutable variables. -## Mutable variables - -Defined with `var`, followed by a variable name and a value. - -```thp -var name = "John" -var age = 32 -``` - -### Datatype annotation - -Written after the `var` keyword but before the variable name. - -```thp -var String name = "John" -var Int age = 32 -``` - -When annotating a mutable variable the keyword `var` is _required_. - - ## Immutable variables -Defined with `val`, followed by a variable name and a value. +Defined with `let`, followed by a variable name and a value. ```thp -val surname = "Doe" -val year_of_birth = 1984 +let surname = "Doe" +let year_of_birth = 1984 ``` ### Datatype annotation -Same as mutable variables +Written after the `let` keyword but before the variable name. ```thp -val String surname = "Doe" -val Int year_of_birth = 1984 +let String surname = "Doe" +let Int year_of_birth = 1984 ``` -When annotating an immutable variable the `val` keyword is optional +When annotating an immutable variable the `let` keyword is optional ```thp // Equivalent to the previous code @@ -53,4 +32,32 @@ This means that if a variable has only a datatype, it is immutable. +## Mutable variables + +Defined with `let mut`, followed by a variable name and a value. + +```thp +let mut name = "John" +let mut age = 32 +``` + +### Datatype annotation + +Written after the `let mut` keywords but before the variable name. + +```thp +let mut String name = "John" +let mut Int age = 32 +``` + +When annotating a mutable variable the keyword `let` is optional. `mut` is still **required**. + +```thp +// Equivalent to the previous code +mut String name = "John" +mut Int age = 32 +``` + + + diff --git a/md/learn/classes/definition.md b/md/learn/classes/definition.md index 215dbb3..24ea16b 100644 --- a/md/learn/classes/definition.md +++ b/md/learn/classes/definition.md @@ -8,7 +8,7 @@ Basically kotlin syntax. `new` not required, in fact, forbidden. ```thp -val dog = Dog() +let dog = Dog() ``` ## Simple class @@ -18,7 +18,7 @@ Why'd you do this tho? ```thp class SimpleClass -val instance = SimpleClass() +let instance = SimpleClass() ``` ## Properties & methods @@ -27,15 +27,15 @@ val instance = SimpleClass() class SimpleClass { // Properties are private by default - var String? name = ... + mut String? name = ... // Made public with `pub` - pub var String? surname = ... + pub mut String? surname = ... // Methods are private by default fun display_name() { - // `$` is used instead of $this + // `$` is used instead of $this. Mandatory print($name) } @@ -57,12 +57,30 @@ Kotlin style ```thp -class Cat(val String name) +class Cat( + // If a parameter has pub, protected or private they are promoted to properties + private String name, + pub mut Int lives = 9, + protected String surname = "Doe", +) { pub fun get_name() -> String { $name } + + pub fun die() + { + $lives -= 1 + if $lives <= 0 + { + print("Cat {$name} is death") + } + else + { + print("Cat {$name} is life still") + } + } } val michifu = Cat("Michifu") @@ -72,9 +90,9 @@ print(michifu.get_name()) With kotlin's `init` block. ```thp -class Dog(val String name) +class Dog(pub String name) { - val Int name_length + Int name_length init { @@ -89,7 +107,7 @@ class Dog(val String name) Kotlin style ```thp -class Animal(val String name) +class Animal(pub String name) { pub fun say_name() { diff --git a/md/learn/classes/magic.md b/md/learn/classes/magic.md index cea5970..cc0b331 100644 --- a/md/learn/classes/magic.md +++ b/md/learn/classes/magic.md @@ -16,10 +16,10 @@ class Cat ```thp -val option = Some("GAAA") -val Some(value) = option +let option = Some("GAAA") +let Some(value) = option -val colors = Array("red", "green", "blue") -val Array() +let colors = Array("red", "green", "blue") +let Array() ``` diff --git a/md/learn/collections/arrays.md b/md/learn/collections/arrays.md index ccfeb6a..a91c975 100644 --- a/md/learn/collections/arrays.md +++ b/md/learn/collections/arrays.md @@ -6,13 +6,13 @@ for constructing arrays ## Usage ```thp -val fruits = Array("apple", "banana", "cherry") -val apple = fruits.[0] +let fruits = Array("apple", "banana", "cherry") +let apple = fruits.[0] print(apple) -var numbers = Array(0, 1, 2, 3) +let mut numbers = Array(0, 1, 2, 3) // Note the dot numbers.[3] = 5 diff --git a/md/learn/collections/maps.md b/md/learn/collections/maps.md index b6d5e3a..fd3f81f 100644 --- a/md/learn/collections/maps.md +++ b/md/learn/collections/maps.md @@ -6,7 +6,7 @@ Also known as Associative Arrays ## Usage without a declaration ```thp -var person = Obj { +let mut person = Obj { name: "John", surname: "Doe", age: 33, @@ -31,7 +31,7 @@ obj Person = { } -val john_doe = Person { +let john_doe = Person { name: "John", surname: "Doe", age: 33, diff --git a/md/learn/collections/sets.md b/md/learn/collections/sets.md index 357823a..75932f1 100644 --- a/md/learn/collections/sets.md +++ b/md/learn/collections/sets.md @@ -3,7 +3,7 @@ ```thp // Set[Int] -val ages = Set(30, 31, 33, 35) +let ages = Set(30, 31, 33, 35) for age in ages { print("{age}") diff --git a/md/learn/collections/tuples.md b/md/learn/collections/tuples.md index 3db7b71..cd53916 100644 --- a/md/learn/collections/tuples.md +++ b/md/learn/collections/tuples.md @@ -6,9 +6,9 @@ calls (`()`). ## Definition ```thp -val person = #("John", "Doe", 32) +let person = #("John", "Doe", 32) -val #(name, surname, age) = person +let #(name, surname, age) = person ``` diff --git a/md/learn/flow-control/conditionals.md b/md/learn/flow-control/conditionals.md index 0846b95..9a69c41 100644 --- a/md/learn/flow-control/conditionals.md +++ b/md/learn/flow-control/conditionals.md @@ -22,7 +22,7 @@ else } -val result = if condition { value1 } else { value2 } +let result = if condition { value1 } else { value2 } ``` @@ -40,7 +40,7 @@ if variable is Datatype ## If variable is of enum ```thp -val user_id = POST::get("user_id") +let user_id = POST::get("user_id") if Some(user_id) = user_id { diff --git a/md/learn/flow-control/loops.md b/md/learn/flow-control/loops.md index 65ce386..96c7c64 100644 --- a/md/learn/flow-control/loops.md +++ b/md/learn/flow-control/loops.md @@ -5,7 +5,7 @@ Braces are required. ```thp -val numbers = Array(0, 1, 2, 3) +let numbers = Array(0, 1, 2, 3) for number in numbers { @@ -19,7 +19,7 @@ for #(index, number) in numbers.entries() ``` ```thp -val dict = Obj { +let dict = Obj { "apple": 10, "banana": 7, "cherries": 3, @@ -45,8 +45,8 @@ for value in collection ## While loop ```thp -val colors = Array("red", "green", "blue") -var index = 0 +let colors = Array("red", "green", "blue") +let mut index = 0 while index < colors.size() { diff --git a/md/learn/flow-control/match.md b/md/learn/flow-control/match.md index ed2dc14..a5858b3 100644 --- a/md/learn/flow-control/match.md +++ b/md/learn/flow-control/match.md @@ -1,13 +1,15 @@ # Match -## Most likely syntax +## Syntax + +Braces are **required**. ```thp -val user_id = POST::get("user_id") +let user_id = POST::get("user_id") match user_id -| Some(id){ print("user_id exists: {id}") } +| Some(id) { print("user_id exists: {id}") } | None { print("user_id doesn't exist") } match user_id @@ -34,23 +36,4 @@ match user_id ``` -## Alternative syntax? - -```thp -// Alternative syntax? - -match user_id { - Some(id) { print("user_id exists: {id}") } - None { print("user_id doesn't exist") } -} - -match user_id { - Some(id) { - print("user_id exists: {id}") - } - None { - print("user_id doesn't exist") - } -} -``` diff --git a/md/learn/functions/declaration.md b/md/learn/functions/declaration.md index b14935a..43c0a06 100644 --- a/md/learn/functions/declaration.md +++ b/md/learn/functions/declaration.md @@ -21,7 +21,7 @@ fun get_random_number() -> Int Random::get(0, 35_222) } -val number = get_random_number() +let number = get_random_number() ``` ## With parameters and return type @@ -32,7 +32,7 @@ fun get_secure_random_number(Int min, Int max) -> Int Random::get_secure(min, max) } -val number = get_secure_random_number(0, 65535) +let number = get_secure_random_number(0, 65535) ``` @@ -44,10 +44,10 @@ fun get_first_item[T](Array[T] array) -> T array.[0] } -val first = get_first_item[Int](numbers) +let first = get_first_item[Int](numbers) // The type annotation is optional if the compiler can infer the type -val first = get_first_item(numbers) +let first = get_first_item(numbers) ``` diff --git a/md/learn/functions/higher-order.md b/md/learn/functions/higher-order.md index 4ae4bd4..2bc3040 100644 --- a/md/learn/functions/higher-order.md +++ b/md/learn/functions/higher-order.md @@ -23,8 +23,8 @@ fun generate_generator() -> () -> Int } -val generator = generate_generator() // A function -val value = generate_generator()() // An Int +let generator = generate_generator() // A function +let value = generate_generator()() // An Int ``` diff --git a/md/learn/functions/lambdas.md b/md/learn/functions/lambdas.md index 02e1bb8..36c22de 100644 --- a/md/learn/functions/lambdas.md +++ b/md/learn/functions/lambdas.md @@ -22,7 +22,7 @@ By default closures **always** capture variables as **references**. ```thp -var x = 20 +let mut x = 20 val f = fun() { print(x) @@ -44,7 +44,7 @@ fun(parameters) clone(variables) { ``` ```thp -var x = 20 +let mut x = 20 val f = fun() clone(x) { print(x) diff --git a/md/learn/functions/parameters.md b/md/learn/functions/parameters.md index 62e0e31..9e77b76 100644 --- a/md/learn/functions/parameters.md +++ b/md/learn/functions/parameters.md @@ -14,7 +14,7 @@ properties can be used inside the function ```thp fun count(Array[Int] numbers) -> Int { - val items_count = numbers.size() // Ok, `size` is pure + let items_count = numbers.size() // Ok, `size` is pure items_count } @@ -36,7 +36,7 @@ data **can** be mutated. The caller *must* also use `&`. ```thp -val numbers = Array(0, 1, 2, 3) +let numbers = Array(0, 1, 2, 3) push_25(&numbers) // Pass `numbers` as reference. @@ -58,7 +58,7 @@ of the parameter (CoW). The original data will **not** be mutated. ```thp -val numbers = Array(1, 2, 3, 4) +let numbers = Array(1, 2, 3, 4) add_25(numbers) // Pass `numbers` as clone. diff --git a/md/learn/ideas/idea_1.md b/md/learn/ideas/idea_1.md index 7d8d54d..dab5b65 100644 --- a/md/learn/ideas/idea_1.md +++ b/md/learn/ideas/idea_1.md @@ -1,8 +1,8 @@ # Idea 1 -var x = 20 -val y = 30 +let mut x = 20 +let y = 30 type Something = ... @@ -21,8 +21,8 @@ fun do_something(&Something some) -> Bool {} do_something(&s1) -var arr1 = Array(10, 20, 30) -var arr2 = &arr1 +let mut arr1 = Array(10, 20, 30) +let mut arr2 = &arr1 Owned/Reference Mutable @@ -51,9 +51,9 @@ returns those new values in a new array. ### Example ```thp -val numbers = Array(1, 2, 3, 4, 5) +let numbers = Array(1, 2, 3, 4, 5) -val numbers_squared = numbers.map {it ** 2} +let numbers_squared = numbers.map {it ** 2} print(numbers_squared) // Array(1, 4, 9, 16, 25) @@ -80,22 +80,22 @@ Iteratively reduce the array to a single value using `callback`. ### Example ```thp -val numbers = Array(1, 2, 3, 4, 5) +let numbers = Array(1, 2, 3, 4, 5) -val sum = numbers.reduce(0, \+) -val sum = numbers.reduce(0) {$1 + $2} -val sum = numbers.reduce(0, fun(prev, curr) {prev + curr}) +let sum = numbers.reduce(0, \+) +let sum = numbers.reduce(0) {$1 + $2} +let sum = numbers.reduce(0, fun(prev, curr) {prev + curr}) print(sum) // 15 ``` ```thp -val numbers = Array(1, 2, 3, 4, 5) +let numbers = Array(1, 2, 3, 4, 5) -val sum = numbers.reduce("", fun(prev, curr) {prev + curr}) +let sum = numbers.reduce("", fun(prev, curr) {prev + curr}) -val sum = numbers.reduce("") {prev, curr -> prev + curr} +let sum = numbers.reduce("") {prev, curr -> prev + curr} print(sum) // "12345" ``` @@ -145,7 +145,7 @@ fun (>>=)[m, A, B]( (Array[Int], Int -> Array[String]) -> Array[String] -val result = Array(1, 2, 3, 4, 5) >>= {Array($.into[String]())} +let result = Array(1, 2, 3, 4, 5) >>= {Array($.into[String]())} print(result) // Array("1", "2", "3", "4", "5") ``` @@ -194,7 +194,7 @@ fun (>>)[A, B, C]( (B) -> C, ) -> (A) -> C -val f1 = add1 >> times2 +let f1 = add1 >> times2 f1(5) // 12 ``` diff --git a/md/learn/index.md b/md/learn/index.md index e9cbb5c..5ce436a 100644 --- a/md/learn/index.md +++ b/md/learn/index.md @@ -25,7 +25,7 @@ If you want to learn the language, go to the learn section. - Create a **consistent** language. - Create typings for popular libraries (like TS's `.d.ts`). - Have a simple instalation and configuration (requiring just Composer). -- Ship a fast, native binary (not written in PHP). +- Ship a fast, native binary (written in Rust) (why use PHP when we can go native?). - Sub 10ms watch mode. - Support in-place compilation. - Emit readable PHP code. @@ -47,16 +47,154 @@ These are **not** aspects that THP looks to solve or implement. - Change over conventions - Explicit over implicit -That is, while there is value in the items on -the right, we value the items on the left more. -## Compared to PHP +## Some differences with PHP -### Differences +```thp +// PHP +$has_key = str_contains($haystack, 'needle'); -### Runtime similarities +// THP +val has_key = haystack.contains("needle") +``` -## Improvements +- Explicit variable declaration +- No `$` for variable names (and thus no `$$variable`) +- No semicolons +- Use methods on common datatypes +- Strings use only double quotes + +--- + +```thp +// PHP +[ + 'names' => ['Toni', 'Stark'], + 'age' => 33, + 'numbers' => [32, 64, 128] +] + +// THP +Obj { + names: #("Toni", "Stark"), // Tuple + age: 33, + numbers: [32, 64, 128] +} +``` + +- Tuples, Arrays, Sets, Maps are clearly different +- JS-like object syntax + +--- + +```thp +// PHP +$cat = new Cat("Michifu", 7); +$cat->meow(); + +// THP +val cat = Cat("Michifu", 7) +cat.meow(); +``` + +- No `new` for classes +- Use dot `.` instead of arrow `->` syntax + +--- + + +```thp +// PHP +use \Some\Deeply\Nested\Class +use \Some\Deeply\Nested\Interface + +// THP +use Some::Deeply::Nested::{Class, Interface} +``` + +- Different module syntax +- PSR-4 required +- No `include` or `require` + +--- + +Other things: + +- Pattern matching +- ADTs + + +### Runtime changes + +THP should add as little runtime as possible. + +```thp +// ===== current ======= +val name = "John" +var name = "John" + +String name = "John" +var String name = "John" + + + +// ===== new? ======= +let name = "John" +let mut name = "John" + +String name = "John" +mut String name = "John" + + +// For primitive datatypes (Int, Float, Bool, String?) + +// Cloned +fun add(Int x) +// Still cloned, but the x **binding** can be mutated, not the original variable +fun add(mut Int x) +// Same as 1st +fun add(clone Int x) + + +// For other datatypes + +// Pass an immutable reference +fun add(Obj o) +// Pass a mutable reference +fun add(mut Obj o) +// Clone the argument +fun add(clone Obj o) + + +// Only references are passed, not "variables" (as PHP calls them) +let john = Obj {name: "John"} +/* + john --------> {name: "John"} +*/ + +fun set_empty(mut Obj person) { + /* + john ------┬--> {name: "John"} + person ----┘ + */ + + // This creates a **new** Obj, and the variable `person` now points to it. + person = Obj {name: "Alex"} + /* + john ---------> {name: "John"} + person -------> {name: "Alex"} + */ +} + +set_empty(mut obj) + +print(obj) // Obj {name: "John"} + +``` + + + +## Example ```thp use PDO diff --git a/static/js/prism.thp.js b/static/js/prism.thp.js index 2805980..bbf6baa 100644 --- a/static/js/prism.thp.js +++ b/static/js/prism.thp.js @@ -15,7 +15,7 @@ Prism.languages.thp = { pattern: /(["])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/, greedy: true, }, - "keyword": /\b(?:static|const|enum|loop|use|break|catch|continue|do|else|finally|for|fun|if|in|fn|nil|return|throw|try|while|val|var|type|match|with|of|abstract|class|interface|private|pub|obj|override|open|init)\b/, + "keyword": /\b(?:static|const|enum|loop|use|break|catch|continue|do|else|finally|for|fun|if|in|fn|nil|return|throw|try|while|type|match|with|of|abstract|class|interface|private|pub|obj|override|open|init|let|mut)\b/, "number": /\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i, "operator": /[<>]=?|[!=]=?=?|--?|\$|\+\+?|&&?|\|\|?|[?*/~^%]/, "punctuation": /[{}[\];(),.]/,