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 +```