HellLang
- This is still a work in progress. It may be changed in the future.
HellLang is a programming language meant to allow an optimizing compiler to very easily compile and optimize any given program at the expense of the user and any normal non-optimizing compiler. This is accomplished by forcing the user to add a bunch of keywords that could normally be implied. Note this language is a work in progress and as such the information on this page may not be accurate.
Language overview
HellLang can do many of the things a normal programming language can such as declare variables, interact with memory, and include files. for the time being, if I use something later in this page and it isn't defined anywhere assume its done in the same way c does it i.e. out = a + b
storing the sum of a and b into out. for the sake of simplicity, all statements must end in a semicolon.
Execution
Execution begins in the function with the modifier 'entry', the compiler should throw an error if it cannot find such a function or it finds two or more such functions.
Variables
Variables are declared by typing {modifiers} type label (= value);
where modifiers is a list and '= value' is optional. i.e:
int bar = 10;
Modifier | Description |
---|---|
global
|
Allows this variable to be seen by any file who includes it |
pointer
|
Allows pointer operators to be used on this variable, the * (make pointer) type does not exist |
mutable
|
Allows this variable to be modified |
local
|
Allows this variable can only be used in this file, not to be confused with local variables |
const
|
This variable cannot be modified, if this variable wasn't assigned a value 0 is assigned instead. |
All non scoped variables are by default global const
while scoped variables become local const
. You can overwrite this by specifying a variable be mutable or the inverse visibility.
Variables can be declared global within a scope, doing so effectively places the variable just above the scope it was defined in. As such, these variables can be accessed anywhere in the program.
Note you cannot have two conflicting modifiers in a variable declaration and all non mutable variables must be assigned some default value. i.e:
int foo = 10; // this variable is 'const' and 'global' as it isn't defined in a scope. local int bar = 20; // this variable is both 'local' and 'const' mutable int foobar; // this variable in 'mutable' and acts the way variables in other languages may act. global local int foo = 10; // error mutable const int bar; // error
Scopes
The start of a scope begins either with a function declaration, if statements, loops, or the begin
keyword. All scopes must end with the end
keyword. Any time begin;
would appear on the same line as another scope declaration it is instead ignored such that func foo
and func foo begin;
become identical. Because of this, all scope declarations that do not use the begin
keyword do not need to end in a semicolon ';'.
This system provides no tangible difference between the method c uses ({ and }), it only exists because I don't like to press my shift key to type '{'.
func foo // some code end;
func bar begin; // some code end;
if you use the begin
keyword you may assign a label to it, scopes using this method need to be ended with the same label. you can use this to nest scopes although it would only really be useful to label nested if or loop statements and goto
i.e:
func foo begin function; // some code end function; func bar begin foo; mutable int x; begin bar; mutable int y; x = 20; // valid, x is still within the 'foo' scope end foo; x = 25; // error y = 30; // valid end bar; y = 35; // error end;
Functions
Functions are declared by typing {Modifiers} fuct {input variables} : {output types} (begin label;)
. for example:
inline<1G> global runtime func int a, mutable int b, char c : int out function; // code here end function;
Modifier | Description |
---|---|
global
|
This function can be called from any file who includes it |
inline<const int size>
|
This function is to be in-lined unless in-lining it causes the output executable to be larger than size bytes, if size is not specified it is implied to be 4mib |
static
|
This function should never be in-lined. |
entry
|
This function is the entry into your program, there can only be one entry function. entry function are innately global. |
local
|
This function may only be called or in-lined from within this file, this is an arbitrary limitation to make developers lives easier. |
const
|
This function can be compiled into a single value or set of values, as such constant values can be assigned to a call to this function. works kinda like a macro. |
runtime
|
This function cannot be compiled into a single value or set of values and is instead used during runtime. |
All functions are by default inline global const
, you can overwrite this in the same way you can with variables and the same restrictions apply i.e. a function cannot be both const
and runtime
. function declarations are allowed to take up multiple lines by adding the + sign after the func
keyword, functions declarations declared this way must end with the begin
keyword. for example:
func+ foo int a, int b begin; // some code end;
variables that are declared in the function declaration are counted as being apart of the scope and as such are local const
by default. All input variable modifiers behave in their default way, with const function only allowing const variables. Output variables can be given any modifiers to no effect. Any variables defined as both an input and output variable will instead by passed as reference. Input variables can use the angled brackets (<>) after their name to tell the compiler to compiler a new version of that function for each value in the angled brackets, if that value would be a question mark the compiler is make a new version of that function for each constant value passed to that function. if no variables are defined it is assumed the function takes 'void' as input and returns 'void'. you can also specify default values for variables by using the = operator. for example:
func foo mutable int var int, size : int var // variable a is passed as reference and is mutable, note if a variable is passed as 'var' and it isn't mutable this wont compile func bar char<1 2 3 -1> data: int out // 5 versions of this function are made, the first 4 assume char is 1, 2, 3, and -1. the last version is used if the input doesn't fit within this list func foobar mutable int<1, 2> i // 3 versions of this function are made, the first 2 are called if a const value of 1 or 2 is passed, the last is used in every other case func name mutable int64<?> data // a new version of this function is made for each call to it with a constant value func function mutable int test = 16 // when calling this function, test will be assigned to 16 unless otherwise stated
functions can be called using the call
keyword followed by a function name and its parameters. if a function call were to take up more than one line the call+
keyword should be used instead. you can pass values to function either by name or order, for instance call foo 10, 20
vs call foo a = 10, b = 20
. Note the first method cannot change default values. Output parameters are separated from must be variable names and must be mutable unless the function is a const function. New variables are allowed to be declared as part of the function call. For example:
func foo int a, int b : int out out = a + b; end; call foo 10, 20 : int DATA; // data is a const int with the value 30