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. The MAIN section is where the program starts executing. If a Stat file doesn't have a MAIN section, it won't run.
  • The 2nd line let out = open console is a statement that opens up a stream and assigned it to the out variable. The stream we are opening is the console stream. There are several built-in streams we could open, but in this case, the console 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 the out 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

Stat offers the following basic data types. To use these as a type hint, simply type them out as shown here.
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 strings
 
For 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 hint
function
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 union
optional 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 empty
forced 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 optional
complex 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 optional
 
Another example: [{string}] - this is a list of structs which contain strings
 
A 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 flexible
chained 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