Change syntax from val/var to let (mut)

This commit is contained in:
Araozu 2023-12-16 20:33:55 -05:00
parent 94c0831533
commit e2119b135b
18 changed files with 259 additions and 113 deletions

View File

@ -11,7 +11,7 @@ enum Suit
Spades, Spades,
} }
val suit = Suit::Hearts let suit = Suit::Hearts
``` ```
@ -24,7 +24,7 @@ enum IpAddress
V6(String), V6(String),
} }
val addr_1 = IpAddress::V4("192.168.0.1") let addr_1 = IpAddress::V4("192.168.0.1")
match addr_1 match addr_1
| IpAddress::V4(ip) | IpAddress::V4(ip)

View File

@ -2,46 +2,25 @@
thp distinguishes between mutable and immutable variables. 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 ## 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 ```thp
val surname = "Doe" let surname = "Doe"
val year_of_birth = 1984 let year_of_birth = 1984
``` ```
### Datatype annotation ### Datatype annotation
Same as mutable variables Written after the `let` keyword but before the variable name.
```thp ```thp
val String surname = "Doe" let String surname = "Doe"
val Int year_of_birth = 1984 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 ```thp
// Equivalent to the previous code // 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
```

View File

@ -8,7 +8,7 @@ Basically kotlin syntax.
`new` not required, in fact, forbidden. `new` not required, in fact, forbidden.
```thp ```thp
val dog = Dog() let dog = Dog()
``` ```
## Simple class ## Simple class
@ -18,7 +18,7 @@ Why'd you do this tho?
```thp ```thp
class SimpleClass class SimpleClass
val instance = SimpleClass() let instance = SimpleClass()
``` ```
## Properties & methods ## Properties & methods
@ -27,15 +27,15 @@ val instance = SimpleClass()
class SimpleClass class SimpleClass
{ {
// Properties are private by default // Properties are private by default
var String? name = ... mut String? name = ...
// Made public with `pub` // Made public with `pub`
pub var String? surname = ... pub mut String? surname = ...
// Methods are private by default // Methods are private by default
fun display_name() fun display_name()
{ {
// `$` is used instead of $this // `$` is used instead of $this. Mandatory
print($name) print($name)
} }
@ -57,12 +57,30 @@ Kotlin style
```thp ```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 pub fun get_name() -> String
{ {
$name $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") val michifu = Cat("Michifu")
@ -72,9 +90,9 @@ print(michifu.get_name())
With kotlin's `init` block. With kotlin's `init` block.
```thp ```thp
class Dog(val String name) class Dog(pub String name)
{ {
val Int name_length Int name_length
init init
{ {
@ -89,7 +107,7 @@ class Dog(val String name)
Kotlin style Kotlin style
```thp ```thp
class Animal(val String name) class Animal(pub String name)
{ {
pub fun say_name() pub fun say_name()
{ {

View File

@ -16,10 +16,10 @@ class Cat
```thp ```thp
val option = Some("GAAA") let option = Some("GAAA")
val Some(value) = option let Some(value) = option
val colors = Array("red", "green", "blue") let colors = Array("red", "green", "blue")
val Array() let Array()
``` ```

View File

@ -6,13 +6,13 @@ for constructing arrays
## Usage ## Usage
```thp ```thp
val fruits = Array("apple", "banana", "cherry") let fruits = Array("apple", "banana", "cherry")
val apple = fruits.[0] let apple = fruits.[0]
print(apple) print(apple)
var numbers = Array(0, 1, 2, 3) let mut numbers = Array(0, 1, 2, 3)
// Note the dot // Note the dot
numbers.[3] = 5 numbers.[3] = 5

View File

@ -6,7 +6,7 @@ Also known as Associative Arrays
## Usage without a declaration ## Usage without a declaration
```thp ```thp
var person = Obj { let mut person = Obj {
name: "John", name: "John",
surname: "Doe", surname: "Doe",
age: 33, age: 33,
@ -31,7 +31,7 @@ obj Person = {
} }
val john_doe = Person { let john_doe = Person {
name: "John", name: "John",
surname: "Doe", surname: "Doe",
age: 33, age: 33,

View File

@ -3,7 +3,7 @@
```thp ```thp
// Set[Int] // Set[Int]
val ages = Set(30, 31, 33, 35) let ages = Set(30, 31, 33, 35)
for age in ages { for age in ages {
print("{age}") print("{age}")

View File

@ -6,9 +6,9 @@ calls (`()`).
## Definition ## Definition
```thp ```thp
val person = #("John", "Doe", 32) let person = #("John", "Doe", 32)
val #(name, surname, age) = person let #(name, surname, age) = person
``` ```

View File

@ -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 ## If variable is of enum
```thp ```thp
val user_id = POST::get("user_id") let user_id = POST::get("user_id")
if Some(user_id) = user_id if Some(user_id) = user_id
{ {

View File

@ -5,7 +5,7 @@
Braces are required. Braces are required.
```thp ```thp
val numbers = Array(0, 1, 2, 3) let numbers = Array(0, 1, 2, 3)
for number in numbers for number in numbers
{ {
@ -19,7 +19,7 @@ for #(index, number) in numbers.entries()
``` ```
```thp ```thp
val dict = Obj { let dict = Obj {
"apple": 10, "apple": 10,
"banana": 7, "banana": 7,
"cherries": 3, "cherries": 3,
@ -45,8 +45,8 @@ for value in collection
## While loop ## While loop
```thp ```thp
val colors = Array("red", "green", "blue") let colors = Array("red", "green", "blue")
var index = 0 let mut index = 0
while index < colors.size() while index < colors.size()
{ {

View File

@ -1,9 +1,11 @@
# Match # Match
## Most likely syntax ## Syntax
Braces are **required**.
```thp ```thp
val user_id = POST::get("user_id") let user_id = POST::get("user_id")
match user_id 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")
}
}
```

View File

@ -21,7 +21,7 @@ fun get_random_number() -> Int
Random::get(0, 35_222) Random::get(0, 35_222)
} }
val number = get_random_number() let number = get_random_number()
``` ```
## With parameters and return type ## With parameters and return type
@ -32,7 +32,7 @@ fun get_secure_random_number(Int min, Int max) -> Int
Random::get_secure(min, max) 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] 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 // The type annotation is optional if the compiler can infer the type
val first = get_first_item(numbers) let first = get_first_item(numbers)
``` ```

View File

@ -23,8 +23,8 @@ fun generate_generator() -> () -> Int
} }
val generator = generate_generator() // A function let generator = generate_generator() // A function
val value = generate_generator()() // An Int let value = generate_generator()() // An Int
``` ```

View File

@ -22,7 +22,7 @@ By default closures **always** capture variables as **references**.
```thp ```thp
var x = 20 let mut x = 20
val f = fun() { val f = fun() {
print(x) print(x)
@ -44,7 +44,7 @@ fun(parameters) clone(variables) {
``` ```
```thp ```thp
var x = 20 let mut x = 20
val f = fun() clone(x) { val f = fun() clone(x) {
print(x) print(x)

View File

@ -14,7 +14,7 @@ properties can be used inside the function
```thp ```thp
fun count(Array[Int] numbers) -> Int { 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 items_count
} }
@ -36,7 +36,7 @@ data **can** be mutated.
The caller *must* also use `&`. The caller *must* also use `&`.
```thp ```thp
val numbers = Array(0, 1, 2, 3) let numbers = Array(0, 1, 2, 3)
push_25(&numbers) // Pass `numbers` as reference. push_25(&numbers) // Pass `numbers` as reference.
@ -58,7 +58,7 @@ of the parameter (CoW). The original data will **not** be mutated.
```thp ```thp
val numbers = Array(1, 2, 3, 4) let numbers = Array(1, 2, 3, 4)
add_25(numbers) // Pass `numbers` as clone. add_25(numbers) // Pass `numbers` as clone.

View File

@ -1,8 +1,8 @@
# Idea 1 # Idea 1
var x = 20 let mut x = 20
val y = 30 let y = 30
type Something = ... type Something = ...
@ -21,8 +21,8 @@ fun do_something(&Something some) -> Bool {}
do_something(&s1) do_something(&s1)
var arr1 = Array(10, 20, 30) let mut arr1 = Array(10, 20, 30)
var arr2 = &arr1 let mut arr2 = &arr1
Owned/Reference Mutable Owned/Reference Mutable
@ -51,9 +51,9 @@ returns those new values in a new array.
### Example ### Example
```thp ```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) print(numbers_squared) // Array(1, 4, 9, 16, 25)
@ -80,22 +80,22 @@ Iteratively reduce the array to a single value using `callback`.
### Example ### Example
```thp ```thp
val numbers = Array(1, 2, 3, 4, 5) let numbers = Array(1, 2, 3, 4, 5)
val sum = numbers.reduce(0, \+) let sum = numbers.reduce(0, \+)
val sum = numbers.reduce(0) {$1 + $2} let sum = numbers.reduce(0) {$1 + $2}
val sum = numbers.reduce(0, fun(prev, curr) {prev + curr}) let sum = numbers.reduce(0, fun(prev, curr) {prev + curr})
print(sum) // 15 print(sum) // 15
``` ```
```thp ```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" print(sum) // "12345"
``` ```
@ -145,7 +145,7 @@ fun (>>=)[m, A, B](
(Array[Int], Int -> Array[String]) -> Array[String] (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") print(result) // Array("1", "2", "3", "4", "5")
``` ```
@ -194,7 +194,7 @@ fun (>>)[A, B, C](
(B) -> C, (B) -> C,
) -> (A) -> C ) -> (A) -> C
val f1 = add1 >> times2 let f1 = add1 >> times2
f1(5) // 12 f1(5) // 12
``` ```

View File

@ -25,7 +25,7 @@ If you want to learn the language, go to the learn section.
- Create a **consistent** language. - Create a **consistent** language.
- Create typings for popular libraries (like TS's `.d.ts`). - Create typings for popular libraries (like TS's `.d.ts`).
- Have a simple instalation and configuration (requiring just Composer). - 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. - Sub 10ms watch mode.
- Support in-place compilation. - Support in-place compilation.
- Emit readable PHP code. - Emit readable PHP code.
@ -47,16 +47,154 @@ These are **not** aspects that THP looks to solve or implement.
- Change over conventions - Change over conventions
- Explicit over implicit - 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 ```thp
use PDO use PDO

View File

@ -15,7 +15,7 @@ Prism.languages.thp = {
pattern: /(["])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/, pattern: /(["])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,
greedy: true, 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, "number": /\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,
"operator": /[<>]=?|[!=]=?=?|--?|\$|\+\+?|&&?|\|\|?|[?*/~^%]/, "operator": /[<>]=?|[!=]=?=?|--?|\$|\+\+?|&&?|\|\|?|[?*/~^%]/,
"punctuation": /[{}[\];(),.]/, "punctuation": /[{}[\];(),.]/,