diff --git a/src/lexer/identifier_lexer.ts b/src/lexer/identifier_lexer.ts
index 3390f93..773e9d4 100644
--- a/src/lexer/identifier_lexer.ts
+++ b/src/lexer/identifier_lexer.ts
@@ -34,7 +34,7 @@ export function scan_identifier(input: string, starting_position: number, is_dat
}
function check_keyword(value: string): string {
- const keywords = ["throws", "extends", "constructor", "case", "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", "override", "open", "init", "val", "var", "mut", "clone"];
+ const keywords = ["throws", "extends", "constructor", "case", "static", "const", "enum", "union", "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", "override", "open", "init", "val", "var", "mut", "clone"];
if (keywords.includes(value)) {
return "keyword";
diff --git a/src/pages/api/std/Array.mdx b/src/pages/api/std/Array.mdx
index 88e30e9..090079c 100644
--- a/src/pages/api/std/Array.mdx
+++ b/src/pages/api/std/Array.mdx
@@ -141,6 +141,16 @@ abstraction, as if all indexes were valid.
## Usage
+### Empty array
+
+To create an empty array use square brackets.
+If you create an empty array, you need to specify the datatype.
+
+```thp
+Array[Int] empty = []
+```
+
+
### Creation
To create an array use square brackets notation:
@@ -149,6 +159,8 @@ To create an array use square brackets notation:
val numbers = [0, 1, 2, 3, 4, 5]
```
+When the array is not empty, you don't need to specify a datatype.
+
When the Array is declared over many lines, the last
item should have a trailing comma:
diff --git a/src/pages/api/std/Array/filter.md b/src/pages/api/std/Array/filter.md
new file mode 100644
index 0000000..052af3d
--- /dev/null
+++ b/src/pages/api/std/Array/filter.md
@@ -0,0 +1,6 @@
+---
+layout: ../../../../layouts/ApiLayout.astro
+---
+
+# Array.filter
+
diff --git a/src/pages/learn/data-structures/enums.md b/src/pages/learn/data-structures/enums.md
index 935014b..7a26df8 100644
--- a/src/pages/learn/data-structures/enums.md
+++ b/src/pages/learn/data-structures/enums.md
@@ -3,10 +3,18 @@ layout: ../../../layouts/DocsLayout.astro
title: Enums
---
-# Enums (Tagged unions)
+# Enums
+
+From the [PHP documentation](https://www.php.net/manual/en/language.enumerations.overview.php):
+
+Enums allow a developer to define a custom type that is limited to one of a discrete number of possible values.
+
+THP enums are a 1 to 1 map of PHP enums, with a slightly different syntax.
## Basic enums
+Enums don't have a scalar value by default.
+
```thp
enum Suit
{
@@ -19,38 +27,21 @@ enum Suit
val suit = Suit::Hearts
```
+## Backed enums
-## Enums with values
+Backed enums can have a scalar for each case. The scalar values can only be
+`String` or `Int`.
```thp
-enum IpAddress
+enum Suit(String)
{
- V4(String),
- V6(String),
-}
-
-val addr_1 = IpAddress::V4("192.168.0.1")
-
-match addr_1
-case IpAddress::V4(ip)
-{
- // code..
-}
-case IpAddress::V6(ip)
-{
- // more code..
-}
-
-// Without the full qualifier
-match addr_1
-case ::V4(ip)
-{
- // code...
-}
-case ::V6(ip)
-{
- // even more code...
+ Hearts = "H",
+ Diamonds = "D",
+ Clubs = "C",
+ Spades = "S",
}
```
+All cases must explicitly define their value, there is no automatic generation.
+
diff --git a/src/pages/learn/data-structures/unions.md b/src/pages/learn/data-structures/unions.md
new file mode 100644
index 0000000..b6f3b25
--- /dev/null
+++ b/src/pages/learn/data-structures/unions.md
@@ -0,0 +1,58 @@
+---
+layout: ../../../layouts/DocsLayout.astro
+title: Tagged unions
+---
+
+# Tagged unions
+
+Tagged unions can hold a value from a fixed selection of types.
+
+```thp
+union Shape
+{
+ Dot,
+ Square(Int),
+ Rectangle(Int, Int),
+}
+
+val dot = Shape::Dot
+val square1 = Shape::Square(10)
+val rectangle1 = Shape::Rectangle(5, 15)
+```
+
+## Pattern matching
+
+```thp
+match shape_1
+case ::Square(side)
+{
+ print("Area of the square: {side * side}")
+}
+case ::Rectangle(length, height)
+{
+ print("Area of the rectangle: {length * height}")
+}
+```
+
+## Internal representation
+
+When compiled down to PHP, tagged unions are a combination of an enum and an array.
+
+THP creates an enum of the same name and with the same cases, and the values
+are contained as part of an array.
+
+
+```php
+// The first snippet is compiled to:
+enum Shape
+{
+ case Dot;
+ case Square;
+ case Rectangle;
+}
+
+$dot = [Shape::Dot];
+$square1 = [Shape::Square, 10];
+$rectangle1 = [Shape::Rectangle, 5, 15]
+```
+
diff --git a/src/pages/learn/index.mdx b/src/pages/learn/index.mdx
index 35a43d1..2e6eb49 100644
--- a/src/pages/learn/index.mdx
+++ b/src/pages/learn/index.mdx
@@ -26,6 +26,7 @@ pagesLayout:
- path: arrays
- path: maps
- path: enums
+ - path: unions
- path: functions
title: Functions
children:
@@ -59,7 +60,7 @@ THP is a new programming language that compiles to PHP.
![Accurate visual description of THP](/img/desc_thp.jpg)
-This page discusses some of the design decitions of the language,
+This page details the main design desitions of the language,
if you want to install THP go to the [installation guide](install)
@@ -135,32 +136,41 @@ that it is a different language, and has different semantics.
## Some differences with PHP
-```thp
+```php
// PHP
$has_key = str_contains($haystack, 'needle');
+print("has key? " . $has_key);
+```
+```thp
// THP
val has_key = haystack.contains("needle")
+print("has key? " + has_key)
```
- Explicit variable declaration
-- No `$` for variable names (and thus no `$$variable`)
+- No `$` for variable names (and thus no `$$variable`, use a map instead)
- No semicolons
- Use methods on common datatypes
- Strings use only double quotes
+- String concatenation with `+`
----
-```thp
+
+
+
+```php
// PHP
-[
+$obj = [
'names' => ['Toni', 'Stark'],
'age' => 33,
'numbers' => [32, 64, 128]
]
+```
+```thp
// THP
-.{
+val obj = .{
names: #("Toni", "Stark"), // Tuple
age: 33,
numbers: [32, 64, 128]
@@ -170,29 +180,36 @@ val has_key = haystack.contains("needle")
- Tuples, Arrays, Sets, Maps are clearly different
- JSON-like object syntax
----
+
+
-```thp
+```php
// PHP
$cat = new Cat("Michifu", 7);
$cat->meow();
+```
+
+```thp
// THP
val cat = Cat("Michifu", 7)
cat.meow();
```
-- No `new` for classes
+- Instantiate classes without `new`
- Use dot `.` instead of arrow `->` syntax
----
+
+
-
-```thp
+```php
// PHP
use \Some\Deeply\Nested\Class
use \Some\Deeply\Nested\Interface
+```
+
+```thp
// THP
use Some::Deeply::Nested::{Class, Interface}
```
@@ -202,7 +219,9 @@ use Some::Deeply::Nested::{Class, Interface}
- PSR-4 required
- No `include`, `include_once`, `require` or `require_once`
----
+
+
+
Other things:
@@ -232,8 +251,9 @@ val greeting =
{
"Nobody is here"
}
+```
-
+```php
// Would compile to:
$greeting = null;
$_person = get_person();
@@ -262,8 +282,9 @@ enum IpAddress {
}
val ip_1 = IpAddress::V4("255.255.0.0")
+```
-
+```php
// Would possibly compile to:
enum IpAddress {
V4,
diff --git a/src/pages/spec/ast/ast.md b/src/pages/spec/ast/ast.md
index 223eb20..81db789 100644
--- a/src/pages/spec/ast/ast.md
+++ b/src/pages/spec/ast/ast.md
@@ -31,6 +31,33 @@ Statement = VariableBinding
See the Expression section
-
+## VariableBinding
+
+```ebnf
+VariableBinding = ImplicitBinding
+ | ExplicitBinding
+
+ImplicitBinding = Datatype, Identifier, "=", Expression
+ExplicitBinding = ("var" | "val"), Datatype?, Identifier, "=", Expression
+```
+
+## FunctionDeclaration
+
+```ebnf
+FunctionDeclaration = "fun", Identifier, ParameterList, ("->", Datatype)?, Block
+
+ParameterList = "(", (Parameter, ",")*, ")"
+
+Parameter = Datatype, Identifier
+```
+
+## Block
+
+```ebnf
+Block = "{", BlockMember*, "}"
+
+BlockMember = Statement
+ | Expression
+```