Use square brackets for arrays
This commit is contained in:
parent
e2119b135b
commit
2cab819c40
@ -1,23 +1,21 @@
|
|||||||
# Arrays
|
# Arrays
|
||||||
|
|
||||||
No destructuring (for now?). There's no `[]` syntax
|
Use square brackets as usual.
|
||||||
for constructing arrays
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```thp
|
```thp
|
||||||
let fruits = Array("apple", "banana", "cherry")
|
let fruits = ["apple", "banana", "cherry"]
|
||||||
let apple = fruits.[0]
|
let apple = fruits[0]
|
||||||
|
|
||||||
print(apple)
|
print(apple)
|
||||||
|
|
||||||
|
|
||||||
let mut numbers = Array(0, 1, 2, 3)
|
let mut numbers = [0, 1, 2, 3]
|
||||||
|
|
||||||
// Note the dot
|
numbers[3] = 5
|
||||||
numbers.[3] = 5
|
|
||||||
|
|
||||||
print(numbers.[3]) // 5
|
print(numbers[3]) // 5
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
@ -29,6 +27,9 @@ Array[String]
|
|||||||
Array[Int]
|
Array[Int]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The Array signature __requires__ the word `Array`.
|
||||||
|
There is no `Int[]` or `[Int]` signature, since that would cause
|
||||||
|
problems with the language's grammar.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
Braces are required.
|
Braces are required.
|
||||||
|
|
||||||
```thp
|
```thp
|
||||||
let numbers = Array(0, 1, 2, 3)
|
let numbers = [0, 1, 2, 3]
|
||||||
|
|
||||||
for number in numbers
|
for number in numbers
|
||||||
{
|
{
|
||||||
@ -20,9 +20,9 @@ for #(index, number) in numbers.entries()
|
|||||||
|
|
||||||
```thp
|
```thp
|
||||||
let dict = Obj {
|
let dict = Obj {
|
||||||
"apple": 10,
|
apple: 10,
|
||||||
"banana": 7,
|
banana: 7,
|
||||||
"cherries": 3,
|
cherries: 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
for #(key, value) in dict
|
for #(key, value) in dict
|
||||||
@ -45,12 +45,12 @@ for value in collection
|
|||||||
## While loop
|
## While loop
|
||||||
|
|
||||||
```thp
|
```thp
|
||||||
let colors = Array("red", "green", "blue")
|
let colors = ["red", "green", "blue"]
|
||||||
let mut index = 0
|
let mut index = 0
|
||||||
|
|
||||||
while index < colors.size()
|
while index < colors.size()
|
||||||
{
|
{
|
||||||
print("{colors.[index]}")
|
print("{colors[index]}")
|
||||||
index += 1
|
index += 1
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -41,7 +41,7 @@ let number = get_secure_random_number(0, 65535)
|
|||||||
```thp
|
```thp
|
||||||
fun get_first_item[T](Array[T] array) -> T
|
fun get_first_item[T](Array[T] array) -> T
|
||||||
{
|
{
|
||||||
array.[0]
|
array[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
let first = get_first_item[Int](numbers)
|
let first = get_first_item[Int](numbers)
|
||||||
@ -75,22 +75,23 @@ fun html_special_chars(
|
|||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
|
|
||||||
html_special_chars(input, double_encode: false)
|
html_special_chars(input, double_encoding: false)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
TBD: If & how named arguments affect the order of the parameters
|
||||||
|
|
||||||
## Named arguments with different names
|
## Named arguments with different names
|
||||||
|
|
||||||
```thp
|
```thp
|
||||||
fun replace(
|
fun greet(
|
||||||
String in: input,
|
String name,
|
||||||
String each: pattern,
|
String from: city,
|
||||||
String with: replacement,
|
)
|
||||||
) -> String
|
|
||||||
{
|
{
|
||||||
// Use input, pattern and replacement
|
print("Hello {name} from {city}!")
|
||||||
}
|
}
|
||||||
|
|
||||||
replace(each: " ", in: "my name", with: "-")
|
greet(name: "John", from: "LA")
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ By default closures **always** capture variables as **references**.
|
|||||||
```thp
|
```thp
|
||||||
let mut x = 20
|
let mut x = 20
|
||||||
|
|
||||||
val f = fun() {
|
let f = fun() {
|
||||||
print(x)
|
print(x)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ fun(parameters) clone(variables) {
|
|||||||
```thp
|
```thp
|
||||||
let mut x = 20
|
let mut x = 20
|
||||||
|
|
||||||
val f = fun() clone(x) {
|
let f = fun() clone(x) {
|
||||||
print(x)
|
print(x)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,7 +62,7 @@ f() // 20
|
|||||||
|
|
||||||
```thp
|
```thp
|
||||||
numbers.map {
|
numbers.map {
|
||||||
it * 2
|
$0 * 2
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -24,21 +24,21 @@ fun count(Array[Int] numbers) -> Int {
|
|||||||
## Mutable reference
|
## Mutable reference
|
||||||
|
|
||||||
```thp
|
```thp
|
||||||
fun push_25(&Array[Int] numbers) {
|
fun push_25(mut Array[Int] numbers) {
|
||||||
numbers.push(25) // Ok, will also mutate the original array
|
numbers.push(25) // Ok, will also mutate the original array
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Placing a `&` before the type makes the parameter a mutable
|
Placing a `mut` before the type makes the parameter a mutable
|
||||||
reference. Mutable methods can be used, and the original
|
reference. Mutable methods can be used, and the original
|
||||||
data **can** be mutated.
|
data **can** be mutated.
|
||||||
|
|
||||||
The caller *must* also use `&`.
|
The caller *must* also use `mut`.
|
||||||
|
|
||||||
```thp
|
```thp
|
||||||
let numbers = Array(0, 1, 2, 3)
|
let numbers = Array(0, 1, 2, 3)
|
||||||
|
|
||||||
push_25(&numbers) // Pass `numbers` as reference.
|
push_25(mut numbers) // Pass `numbers` as reference.
|
||||||
|
|
||||||
print(numbers(4)) // `Some(25)`
|
print(numbers(4)) // `Some(25)`
|
||||||
```
|
```
|
||||||
@ -60,7 +60,7 @@ of the parameter (CoW). The original data will **not** be mutated.
|
|||||||
```thp
|
```thp
|
||||||
let numbers = Array(1, 2, 3, 4)
|
let numbers = Array(1, 2, 3, 4)
|
||||||
|
|
||||||
add_25(numbers) // Pass `numbers` as clone.
|
add_25(clone numbers) // Pass `numbers` as clone.
|
||||||
|
|
||||||
print(numbers(4)) // None
|
print(numbers(4)) // None
|
||||||
```
|
```
|
||||||
|
@ -199,3 +199,53 @@ let f1 = add1 >> times2
|
|||||||
f1(5) // 12
|
f1(5) // 12
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```thp
|
||||||
|
function_call[Datatype](param1, param2) {
|
||||||
|
// lambda
|
||||||
|
}
|
||||||
|
|
||||||
|
function_call([arr1, arr2])
|
||||||
|
function_call[Datatype]([arr1, arr2])
|
||||||
|
|
||||||
|
|
||||||
|
fun test[A, B](A a, B b) -> B {}
|
||||||
|
|
||||||
|
|
||||||
|
Array[String] v = 20
|
||||||
|
|
||||||
|
val x = Obj {
|
||||||
|
Array[Int] x: [1, 2, 3]
|
||||||
|
}
|
||||||
|
|
||||||
|
value + [1, 2, 3]
|
||||||
|
|
||||||
|
value + [Int]
|
||||||
|
|
||||||
|
|
||||||
|
value[0]
|
||||||
|
|
||||||
|
|
||||||
|
let functions = [
|
||||||
|
{0},
|
||||||
|
{1},
|
||||||
|
{2},
|
||||||
|
]
|
||||||
|
|
||||||
|
let index = 0
|
||||||
|
|
||||||
|
functions[index]()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
```thp
|
||||||
|
fun main()
|
||||||
|
{
|
||||||
|
// Using the turbofish operator
|
||||||
|
let result = "42".parse[Int]()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ These are **not** aspects that THP looks to solve or implement.
|
|||||||
$has_key = str_contains($haystack, 'needle');
|
$has_key = str_contains($haystack, 'needle');
|
||||||
|
|
||||||
// THP
|
// THP
|
||||||
val has_key = haystack.contains("needle")
|
let has_key = haystack.contains("needle")
|
||||||
```
|
```
|
||||||
|
|
||||||
- Explicit variable declaration
|
- Explicit variable declaration
|
||||||
@ -93,7 +93,7 @@ $cat = new Cat("Michifu", 7);
|
|||||||
$cat->meow();
|
$cat->meow();
|
||||||
|
|
||||||
// THP
|
// THP
|
||||||
val cat = Cat("Michifu", 7)
|
let cat = Cat("Michifu", 7)
|
||||||
cat.meow();
|
cat.meow();
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -113,8 +113,9 @@ use Some::Deeply::Nested::{Class, Interface}
|
|||||||
```
|
```
|
||||||
|
|
||||||
- Different module syntax
|
- Different module syntax
|
||||||
|
- Explicit module declaration
|
||||||
- PSR-4 required
|
- PSR-4 required
|
||||||
- No `include` or `require`
|
- No `include`, `include_once`, `require` or `require_once`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -124,93 +125,69 @@ Other things:
|
|||||||
- ADTs
|
- ADTs
|
||||||
|
|
||||||
|
|
||||||
### Runtime changes
|
## Runtime changes
|
||||||
|
|
||||||
THP should add as little runtime as possible.
|
Where possible THP will compile to available PHP functions/classes/methods/etc.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
```thp
|
```thp
|
||||||
// ===== current =======
|
// This expression
|
||||||
val name = "John"
|
let greeting =
|
||||||
var name = "John"
|
match get_person()
|
||||||
|
| Some(person) if person.age > 18
|
||||||
String name = "John"
|
{
|
||||||
var String name = "John"
|
"Welcome, {person.name}"
|
||||||
|
}
|
||||||
|
| Some(person)
|
||||||
|
{
|
||||||
|
"I'm sorry {person.name}, you need to be 18 or older"
|
||||||
|
}
|
||||||
|
| None
|
||||||
|
{
|
||||||
|
"Nobody is here"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Would compile to:
|
||||||
// ===== new? =======
|
$greeting = null;
|
||||||
let name = "John"
|
$_person = get_person();
|
||||||
let mut name = "John"
|
if ($_person !== null) {
|
||||||
|
if ($_person["age"] > 18) {
|
||||||
String name = "John"
|
$greeting = "Welcome, " . $_person["name"];
|
||||||
mut String name = "John"
|
}
|
||||||
|
else {
|
||||||
|
$greeting = "I'm sorry " . $_person["name"] . ", you need to be 18 or older";
|
||||||
// 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
|
|
||||||
use Globals::Env
|
|
||||||
|
|
||||||
val (Some(dbUri) Some(dbUser) Some(dbPassword)) = (
|
|
||||||
Env::get("DB_URI")
|
|
||||||
Env::get("DB_USERNAME")
|
|
||||||
Env::get("DB_PASSWORD")
|
|
||||||
)
|
|
||||||
else {
|
else {
|
||||||
die("All 3 db environment variables must be set.")
|
$greeting = "Nobody is here";
|
||||||
}
|
}
|
||||||
|
|
||||||
match PDO(dbUri dbUser dbPassword)
|
|
||||||
| Ok(connection) { /* db operations */ }
|
|
||||||
| Err(pdoException) { /* handle exception */ }
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
However, more advanced datatypes & helper functions will require a sort of
|
||||||
|
runtime (new classes/functions/etc) or abuse the language's syntax/semantics.
|
||||||
|
|
||||||
|
|
||||||
|
```thp
|
||||||
|
// TBD: Enum compilation
|
||||||
|
enum IpAddress {
|
||||||
|
V4(String),
|
||||||
|
V6(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
let ip_1 = IpAddress::V4("255.255.0.0")
|
||||||
|
|
||||||
|
|
||||||
|
// Would possibly compile to:
|
||||||
|
enum IpAddress {
|
||||||
|
V4,
|
||||||
|
V6,
|
||||||
|
}
|
||||||
|
|
||||||
|
$ip_1 = [IpAddress::V4, "255.255.0.0"]
|
||||||
|
```
|
||||||
|
|
||||||
|
Such changes will be documented
|
||||||
|
|
||||||
|
|
||||||
|
@ -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|type|match|with|of|abstract|class|interface|private|pub|obj|override|open|init|let|mut)\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|clone)\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": /[{}[\];(),.]/,
|
||||||
|
Loading…
Reference in New Issue
Block a user