HellLang

From Esolang
Jump to navigation Jump to search
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