StarPL
StarPL is a programming language designed by PSTF. It is the variant of Zig in the timeline 284436 by Storm von Kaarzwarde(from Benelux).
Overview
StarPL is a programming language that is very strong and easy to learn. It was inspired by Zig and Python.
Our First Program
use STDIO.SLB let namespace <- std; proc main start print("Hello, world!"); main end
This program should having this output on console:
Hello, world!
Basic Syntax
Data types
We use "var" for variable, and "const" for constant. This is what we often see in the programming languages.
But, instead of equal sign, we use something like ← or <- to assign a value to a variable and "=" is for equality.
We use "let" when we're defining the variable.
let var a: int <- 3; # Define an integer variable with value 3. let const π: float <- 3.1415926535897932384626433832795; # Define a float constant with value of pi. /** * Variable name can be everything except: * 1. Keyword * 2. Start by a digit * 3. Including special symbols except underline or script of other language **/ let var x: string <- "Hello, world!"; let var logical_value: bool <- true; let var p: *void <- address(a); # Get address of a.
Every variable should have its type - either you define its type in advance when defining it, or you must provide a value for the program to infer the type of this variable. Unopened variables cannot be operated on. To open a variable, you need to specify the variable name with "openv". To close a variable, you need to write an assignment statement that lacks a variable value. "Openv" supports to open multiple variables at once.
use EVERYTHING.SLB let namespace <- std; proc main start let var a: int; let var b: int; openv a, b; a <- toInt(input()); b <- toInt(input()); print(a + b); main end
Each variable is only valid within its defined scope. For example, a variable defined in the main subroutine is only valid in main. If it is defined outside of all functions, subroutines, structures, or classes, it is valid throughout the entire program. If it is not defined as a private variable or a protected variable, this variable remains valid when the entire or part of the program (or library) is brought into another program (unless that variable is not imported).
Loop
StarPL supports these looping structure:
While-loop
while (condition) (increment) { code }
In a conditional loop, as long as the condition holds, the code is executed, followed by the increment. If no increment is specified, then after executing the code, no further action is taken, and the condition is evaluated again.
Iterative loop
for (container -> item) { code }
For every item in an iterative container(such as items in list, or numbers in interval), do the code. We use → to represent contents in the iterative container.
Horribler loops
Dead loop
You can put 'true' in the condition position of the conditional loop statement, and this expression will always evaluate to true. Unless an exit method is defined within the code, this loop will continue to execute forever.
Range loop
You can use a range as an iteration container. For example,
use EVERYTHING.SLB let namespace <- std; proc main start let var a: int <- 99; for ((99..1..-1) -> i) { print(f"{i} {"bottle" if i = 1 else "bottles"} of beer on the wall, \n{i} {"bottle" if i = 1 else "bottles"} of beer. \nTake one down, pass it around, \n{i-1} {"bottle" if (i - 1) = 1 else "bottles"} of beer on the wall. \n\n"); } print("No more bottles of beer on the wall, \nno more bottles of beer. \nGo to the store and buy some more, \n99 bottles of beer on the wall."); main end
Label loop
You should know that break
breaks out the loop and continue
skips the current round of loop. You can define a loop with label, and "break" will directly do things after the label.
Conditions
The conditional structure is totally same as what in Zig.
Operator precedence
- There are 3 operations that will be operated first.
- Subscript operator: used to return the element at the specified index in an iterable container.
- Member operators: used to reference the properties or methods of a certain structure or class.
- Member operator (arrow): used to assign an identifier to each element within an iteration container.
- Logical NOT: If the expression is true, then return false.
- Definition of error types and optional value unpacking.
- Get address.
- Positive and negative signs.
- Exponentiation.
- Multiplication, division, integer division, and modulus.
- Addition and subtraction.
- Bitwise NOT.
- Left shift and right shift: Multiply or divide the specified number by 2 a certain number of times. This can result in the loss of some information because it is a bitwise operation.
- Bitwise AND.
- Bitwise XOR.
- Bitwise OR.
- Relational operator.
- Logical AND.
- Logical XOR
- Logical OR.
- Assignment.
Functions
You use "func" for function and "proc" for subroutine.
A function must specify a return value type, but it can have no parameters. If the return value type is blank, it means it is equivalent to a subroutine.
func function_name(argument_list) return_type { code return return_value }
This is a very simple example for the function with parameter:
use EVERYTHING.SLB let namespace <- std; proc main start let var k: str; openv k; print("May I have your name? \n") k <- input(); greet(k); main end func greet(name: str) void { print(f"Nice to meet you, {name}!"); }
The program will ask for your name or at least nickname. For example, if you input "Andy", then the output:
Nice to meet you, Andy!
Functions can of course call themselves within their body, like the thing below that calculates the greatest common divisor:
func gcd(x: int, y: int) int { if (y = 0) {return x;} return gcd(y, x % y); }
Functions can also be overloaded. For example,
func half(x: float) float { return x / 2; } func half(s: str) str { let h: int <- s.length(), res: str <- ""; for ((0..h // 2..1) -> i) {res += s[i];} return res; }
For the half function in this example, if it receives a number, it divides it by 2 and then outputs it. If it receives a string, it outputs the first half of the string.
List and Slice
We can define a list by placing a series of data (not necessarily of the same type) inside square brackets. If the index of the list is in the format start:stop:step
, it returns all elements of the corresponding list in that range, commonly referred to as "slicing". In this index, start is the starting value (including that position, counting from 0), stop is the ending value (excluding that position), and step is the step size — all three can be omitted to create a copy of the list.
Struct and Enum
Structs and enums are the two main ways to define and use custom data types.
Structs and enums provide a higher level of data organization and type safety, making them suitable for different programming scenarios.
Definition of Struct
We use "struct" keyword to create a struct:
struct Something { # Attributes # Methods }
For example, we will generate a virtual kid in the data flow:
use EVERYTHING.SLB let namespace <- std; struct person { let age: int; let name: str; func introduction() void { print(f"Hi! I'm {name}, and I'm {age} years old."); } } proc main start let example: person <- [age <- 15, name <- "Jack"]; example.introduction(); main end
This should output this:
Hi! I'm Jack, and I'm 15 years old.
Enumeration
An enum is a data type that consists of a set of fixed constant values. This is how enum be defined:
enum EnumerateName { # Options }
OOP
As an OOP language, the structs are a bit like class. I don't want to talk about class.
Error Handling
Handling errors in StarPL is a common task, especially when performing system-level programming.
StarPL provides a flexible and explicit error handling mechanism that allows developers to clearly manage and handle errors.
StarPL uses an explicit error handling mechanism by using the ! symbol and try statements to manage errors.
Error handling in StarPL is not as implicit as exceptions; instead, it is explicitly represented in the code, making error handling more transparent and controllable.
Here are some basic error handling strategies and techniques:
- Error Types: Errors in StarPL are usually defined as error types. You can define your own error types to handle specific error cases.
- Return Error: Functions can return a value of error type to indicate an error. Callers need to check the returned value and handle the error accordingly.
- Error Checking: Callers need to check the errors returned by functions and take appropriate action when an error is detected. This often involves using if statements or switch statements.
- nError Propagation: If a function receives an error, it can decide to handle the error or propagate it to the caller. This can be achieved by returning an error or throwing an exception.
- Error Handling Functions: StarPL allows you to define error handling functions that can be called in the program to handle errors.
- Using try Keyword: In StarPL, the try keyword is used to attempt to execute an operation that may fail and capture any errors that occur.
- Error Codes: StarPL allows you to define error codes to represent different error cases. This can be achieved through enum or error types.
- Error Logging: When handling errors, logging errors is a common practice. This can help developers understand the reasons and context of the errors that occur.
- Resource Cleanup: When handling errors, it is important to ensure that all allocated resources are released or cleaned up. This can be done using the finally statement.
- Error Recovery: In some cases, you may want to recover the execution of the program after an error occurs. This can be achieved by retrying the operation or rolling back to a safe state.
For example, this is the "interpreter" for the joke programming language Permission denied by None-One:
use EVERYTHING.SLB let namespace <- std; func permission_denied() !void { return error.PermissionDenied; } proc main start let h: str; openv h; h <- input(); try { permission_denied(); } catch (error.PermissionDenied) { print("Permission denied"); } else { print("Permission denied"); } finally { h <-; } main end
Memory Processing
Same as in Zig, I don't want to talk about it.