Notice: Stat is currently in private beta. This documentation is incomplete and subject to change.
Stat Docs
Introduction
File Types & Sections
Variables
Strings
Numbers
Binary Values
Constant Values
Ranges
Regular Expressions
Introducing the Stat Programming Language
Like most other programming language tutorials, the first program you usually learn is the Hello World program.
It's a simple program that simply outputs
"Hello World"
on the screen. Seems like a good way to get started. So here it is: MAIN let out = open console "Hello World" -> out // Prints "Hello World" on the screen
This is different from the typical "Hello World" program that you're used to so let's break down what's happening.
- The first line
MAIN
is a section header. All Stat files are made up of 1 or more sections. TheMAIN
section is where the program starts executing. If a Stat file doesn't have aMAIN
section, it won't run. - The 2nd line
let out = open console
is a statement that opens up a stream and assigned it to theout
variable. The stream we are opening is theconsole
stream. There are several built-in streams we could open, but in this case, theconsole
stream is what we want so we can output text to the screen. - The 3rd line
"Hello World" -> out
simply sends a string value to the stream that is stored in theout
variable.
A bit about Stat
Stat is a general purpose programming language that offers a syntax
that is both simple and easy to learn. It is a type safe language
that provides many built in data types as well as the flexibility
to create custom or complex data types so that they can be easily reused.
All values are stored in variables. You can define variables in your code and
pass those variables into functions in order to accomplish a task. All variables
have a data type and that data type can't be changed. Once a variable is defined
it must always have a value of a compatible type stored in it. You can change
the value that is stored in a variable, but it must be the correct type.
Since Stat is a type-safe language, this means that it won't run unless your code
conforms to strict type safety rules. If a function requires you to pass in an integer
value, it won't let you pass in a string or some other data type. Furthermore, the
type system is robust and can handle many complex scenarios.
Indentation and White Space
In Stat, it is crucial to indent your code properly. Unlike most other programming languages, indentation
is used to define blocks of code instead of using curly braces. If you've ever programmed in Python, then
you'll be familiar with this concept. There is one major difference though. In Stat, you can only use the
TAB
character to indent your code. Indenting with spaces will result in a syntax error. You MUST use the tab character to indent your code
Using spaces to indent your code will result in a syntax error. Also, unlike other languages, white-space is significant. In most languages, white-space is simply ignored, but
Stat takes a different approach. Instead of allowing white-space wherever and as much or as little as the coder wants,
Stat focuses on the readability of code. In most cases you can only use a single space between words or operators and in many
cases, no white-space is allowed at all. Also, code lines may not have any trailing white space. There are some exceptions like inside multi-line strings,
but for the most part, just use a single space between words and you should be fine. If you've made a mistake with regards to
white-space, it'll be reported to your IDE or you'll get an error when attempting to run the file.
Sections
In Stat, everything is grouped into 1 or more sections. Each section has a different purpose... or reason for existing.
Section names are specified in all capital letters, you can't use lower case letters to specify a section name.
There aren't very many section possibilities so here is the full list.
MAIN
This section is where execution always starts. Put your main code here.META
This section defines the file type as well as some other properties.IMPORTS
This section is exactly what you'd expect. It contains a list of imported files.FUNCTION
This section defines the body of a function. (More on functions later)PERSIST
This section contains variables that persist beyond the execution of a function. (More on this later)OPTIONS
This section contains enum options. (More on enums later)
Sections are defined in all capital letters
You can't use lower case letters to specify a section name.Defining Variables
In Stat, you use the
let
keyword to define a variable. The syntax is the let
keyword, followed by the variable name,
followed by an optional type hint which will be covered later, followed by the equal sign, followed by the initial value. Once a variable is defined, it can
be reassigned as many times as needed, but the data type cannot change. You can't define a string, then assign an integer to that variable. Here is an example: MAIN let name = "John Doe" name = "Jane Doe" let age = 22 // Using a type hint let nickName: string = "Janet"
Some things to note:
- You can only declare a single variable with the
let
keyword. - To define multiple variables, use the
let
keyword multiple times. - All variables must have an initial value when defined
- Variable names must start with a lower case letter and can only contain letters and numbers
- Using a type hint is optional in most cases, but if provided, the initial value must be compatible with the type hint (more on this later)
- All though all values are immutable (more on this later), there is no such thing as a constant variable in Stat. All variables can be reassigned
Naming variables
Variable names have strict rules. They must start with a lower case letter
a-z
and they can only contain letters and numbers.
You cannot use the underscore, the dash character, or any other character like unicode characters to name your variables. MAIN // These are both invalid variable names let my_varInvalid variable name = 10 let MyVarInvalid variable name = 20
However, unlike other programming languages, there are no restrictions on what your variable names can be.
Although it's not recommended because it may confuse developers, you could name your variable say...
if
or function
or even let
MAIN // These are all valid variable names let if = 10 let function = 20 let let = 30
Value Literals
Stat comes with a bunch of built-in value literal types. Here is a quick breakdown of them all. This will help you understand the syntax later in the documentation.
Also, rather than give you a list, we'll just give some code examples to make things simple.
MAIN // A string literal is enclosed in double quotes "Hello World" // A binary literal is enclosed in back ticks `Binary Value` // An integer literal is just the number 100 // A fraction literal can either be a floating point number or a literal fraction 1.5 1 1/3 // A boolean literal is either true or false true // A regular expression literal is enclosed in forward slashes, followed by 0 or more modifiers /[a-z]+/i // A range literal is two numbers with 2 or 3 dots between them or a single number followed by 2 or 3 dots 10..20 52.. // A empty literal is just the empty keyword. This is like null in other languages empty // A list literal is a list of values enclosed in brackets ["Hello", "Hello"] // A struct literal is a list of key/value pairs enclosed in curly braces {name = "John", age = 25}
Comments
Comments are notes that are embedded in the source code that are there for informational purposes only and don't execute at runtime.
You can put comments into your code just like a lot of other popular languages.
- Single line comments start with
//
- Multi-line comments start with
/*
and end with*/
- A special type of multi-line comment is a documentation comment. Those begin with
/**
and end with*/
// This is a single line comment
/* This is a multi-line comment
It can be spread over multiple lines */
/**
* This is special type of multi-line comment
* called a documentation comment. The language
* server will report these where appropriate
* to your IDE when documentation for something is requested.
*/
IMPORTANT:
Comments MUST follow indentation just like everything else. You cannot have a comment in a section without it being indented. Also, comments MUST be on their own line. You cannot have a statement and a comment on the same line.// This comment requires no indentation, because it isn't in a section MAIN // This comment is ok, because it's indented // But this comment is bad because it isn't indentedInvalid indentation let age = 22 /* Even multi-line comments must be properly indented Line 2 */Invalid indentation let name = "John" // This comment is also ok, It's not in a section either // It comes after the end of the MAIN section
Semicolons
Stat doesn't do semicolons... period. The main reason other languages use semicolons is to terminate a statement. The problem
with other languages using a semicolon to terminate a statement is that it allows developers to immediately start another
statement on the same line. This opens the door for all kinds of ways that developers can complicate their code. It also opens
the door for malicious coders to obfuscate their code to the point where nobody knows what it's doing. Stat is different... first, it
knows where 1 statement ends and where the next one begins. Also, it enforces better readability and maintainability by requiring
that each statement starts on its own line.
Type Hints
You can optionally provide a type hint when you define a variable. In some cases you must provide a type hint, but in most cases it's optional. A type hint determines the type of value that a variable
can store. If you don't provide a type hint, then the data type is inferred from the initial value.
To create a type hint, use the colon
:
character followed by the type hint like this: MAIN let myVar: int = 10
When using type hints, the type hint must be compatible with the initial value. Now that we've set the type hint to
int
in the example above, this means that we can re-assign the variable to a different int
value at any time. However, if
we try to assign a different value type, say a string
, we will get an error when trying to run the file. MAIN let myVar: int = 10 myVar = "Hello"Incompatible data types
You can make any type optional which means that it can contain a value or it can be empty.
To make any type optional, simply add a question mark character
?
at the end like so: MAIN // myVar can be an integer or it can be empty let myVar: int? = 10 myVar = empty
Likewise, you can force any type to not be optional by adding the exclamation character
!
.
You'd only need this if you'd like to reference an optional type hint by name, but make it not optional. Here's an example: MAIN // myVar is an optional integer let myVar: int? = 10 // forced is simply an integer... not optional let forced: myVar! = 10
Data Types
string
A string value
binary
A binary data value
int
An integer value
fraction
A floating point or fraction value
bool
A boolean value (true or false)
regExp
A regular expression
range
A range of integers
empty
An empty value (like
null
in other languages)any
Any value no matter the type (except empty)
Here are some examples of using some basic type hints
MAIN let stringVar: string = "Hello" let binaryVar: binary = `Binary Value` let intVar: int = 10 let fractionVar: fraction = 1.6 let boolVar: bool = true let regExpVar: regExp = /[a-z]+/i let rangeVar: range = 10..20 let emptyVar: empty = empty // This variable can contain any value except empty let anyVar: any = "Hello World"
Additionally, there are some special data types available:
list
A list of values. The syntax for a list type hint is:
[subType]
. So if you want a list of strings, use: [string]
struct
A struct of key value pairs. The syntax for a struct type hint is:
{subType}
which means that all values in the struct are that sub type. For a struct of all strings, use: {string}
A struct type hint can also have key/value pairs like so:
{key1: key1Type, key2: key2Type}
. For a struct with a string for key1 and an integer for key2 use: {key1: string, key2: int}
A struct type hint can also be extended by including the name of the struct you want to extend as one of the key / value pairs like so:
{baseStructName, key3: bool, key4: any}
stream
A stream has 2 sub types: input type and output type and is written like this:
<outputType,inputType>
. For a stream that outputs strings and takes integers as input, use <string,int>
If a stream has the same input and output type, you can omit the inputType like so:
<string>
. This is a stream that reads and writes stringsFor an output only stream, use this syntax:
<string,>
. This means that the stream only outputs strings, but you can't send anything to it.For an input only stream, use this syntax:
<,string>
. This means that the stream only accepts strings as input, and won't output anything.enum
To use an enum type hint, simply use the name of the enum as the type hint. Available enums are specified in the
IMPORTS
section. For an enum named "states", use: states
alias
An alias type hint is simply the name of any variable or imported type hint. If there is a variable named "myVar" that is a string, then using
myVar
as a type hint means string
. Any variable name including imports can be used as a type hintfunction
To use a function type hint, simply use the name of the function. Like enums, functions are specified in the
IMPORTS
section.function return type
This is the data type that a function returns. The syntax looks like this:
functionName()
- this means the data type that the function named "functionName" returns.function arg type
This is the data type of a function argument. The syntax looks like this:
functionName.argName
- this means the data type of the argument named "argName" inside the function named "functionName"union
A union type hint allows you to combine 2 or more types so that the variable can contain any of those types. The syntax looks like this:
(int | string)
- this means that the value can be either an integer or a string. You can combine as many types as necessary in a unionoptional types
An optional type means that the value can contain the specified type or it can be empty. Append the question mark character to any type to make it optional like so:
string?
- this means either a string or emptyforced types
A forced type means that the value cannot contain the empty value. Append the exclamation character to any type to force it to not be optional like so:
someVar!
- this means whatever type is stored in someVar
but exclude empty if the type is optionalcomplex types
You can use the types above to create complex and even nested types. Here is an example:
[string?]?
- this means a list or optional strings, and the list itself is also optionalAnother example:
[{string}]
- this is a list of structs which contain stringsA really complex example:
([{(int|string)?}?]|{[any?]})?
- this is either a list of optional structs that contain optional integers or strings or a struct that contain lists of any value or empty, or the whole thing can be empty. As you can see that type hints can be extremely flexiblechained types
Chained types use the dot operator to dive into function data types. Take this example:
myFunc().arg.subArg()
- this refers to the return type of myFunc
which is a function then the arg
argument of that function which is also a function, then the subArg
argument of that function which is... you guessed it, a function, then the return type of that function. Here are some examples of using these type hints:
IMPORTS myFunction myEnum MAIN let stringList: [string] = ["Hello", "World"] let intStruct: {int} = {key1 =10 ,key2 =20 } let keyStruct: {key1: int, key2: string} = {key1 =30 ,key2 ="Value" } let extendedStruct: {keyStruct, key3: bool} = {key1 =25 ,key2 ="Hi" ,key3 =true } let streamVar: <string> = open console let enumOption: myEnum = myEnum.choice let aliasVar: stringList = ["Hi", "There"] let funcAlias: myFunction = myFunction // Assuming that myFunction returns a string let funcReturn: myFunction() = "String Value" // Assuming that myFunction takes an argument named age that's an integer let funcArg: myFunction.age = 15 // unionVar can be a string or an integer let unionVar: (string|int) = 15 // optUnionVar can be a string or an integer or the empty value let unionVar: (string|int)? = empty // optVar can be a string or the empty value let optVar: string? = empty // forcedVar can only be a string let forcedVar: optVar! = "Value" // forcedUnionVar can be a string or an integer let forcedUnionVar: optUnionVar! = 100 // This is a list of nested string lists let nestedStringList: [[string]] = [["Hello", "World"], ["Hi", "There"]] // Each element in this list can either be a string or empty let optStringList: [string?] = ["Hello", empty, "World"] // Same as the last variable, but the whole thing can also be empty let optStringList: [string?]? = empty
Type Inference
Stat is a type safe language which means that you must be clear about the data types that a variable can store and the data types that you can pass to functions.
If a variable is defined as a
string
, you won't be able to assign a binary
to it. Type safety checks are part of the built-in linting system
and are reported directly to your code editor or IDE in real-time as you code. If you don't use a code editor that supports diagnostic errors or you're using a plain
text editor like notepad, then you won't see these errors in real time, but they're still there. When you attempt to run a Stat file, type checking errors will be reported
and the program won't run at all. This allows developers to catch and fix code errors as early as possible in the development cycle. Stat performs type safety checks on every file, but this doesn't mean that you need to provide type hints everywhere. If you don't provide a type hint when
defining a variable, then Stat will infer the type based on the initial value. In practice, it's rare that you need to specify a data type as Stat can almost always figure
out what the data type is based on the initial value assigned to a variable.
The only time that you need to specify a type when defining a variable is when the initial type can't be inferred or when you want the variable to hold more than one type like so:
MAIN // You have to specify a type hint here because // there is no way for Stat to know what types of // values the list is able to hold. let names: [string] = [] // If you want a variable to hold more than 1 type // you'll need to specify a type hint to let Stat know let nameOrAge: (string|int) = 15
Previous
Next