The Haxial Programming Language
General Syntax

KL has a very simple and consistent structure. Except for comments, EVERY line in the source code is a command invocation (an invocation of a command). There are commands for doing all sorts of things and performing all sorts of actions.

The name of the command being invoked is always at the beginning of the line. The command name cannot contain any spaces. Then following the command name, there is always a list of parameters separated by commas (except if the command has no parameters). Then the line always finishes with a semicolon (";").

It is very consistent. Compare with the C++ language. In C++, some lines must end with a semicolon, while other lines cannot. There is not really much sense to the rules regarding which lines require a semicolon and which lines require absence of a semicolon. Whereas in KL, EVERY line ends with a semicolon, making it easy to remember the rule.

So keep in mind that KL source code consists of a list of COMMANDS (invocations of commands, to be precise). Excluding comments, every line is a command invocation. Command name, then parameters separated by commas, then semicolon. The command name is separated from the first parameter by a space character.

NameOfCommand;
NameOfCommand Param;
NameOfCommand Param1, Param2;
NameOfCommand Param1, Param2, Param3;
NameOfCommand Param1, Param2, Param3, Param4;

Parameters are information to pass to the command. The command uses the information from the parameters to do whatever it does (in other words, the parameters affect the operation of the command).

Look at this line of KL source code:

module MyProgram;

That line is an invocation of a command. What is the name of the command? Remember the command name is always at the beginning. Thus the command name is "module". What does this "module" command do? It defines (makes) a new module (modules are a convenient way of grouping things together). This command invocation has 1 parameter and in the above example, "MyProgram" has been passed for that parameter. The "module" command interprets it as the name of the new module to define.

Now look at this line of KL source code:

var x, uint, 123;

That line is an invocation of a command. What is the name of the command? Remember the command name is always at the beginning. Thus the command name is "var". What does this "var" command do? It defines a new variable (where a variable is a place to store a number or other value). There are 3 parameters, separated by commas. Thus the first parameter is "x", the second parameter is "uint", and the third parameter is "123". How parameters are interpreted depends on which command is being invoked (meaning what command name was specified).

Now look at this line of KL source code:

MText.AppendChar msg, x;

That line is an invocation of a command. What is the name of the command? Remember the command name is always at the beginning. However this command name has a dot (".") in it. "MText" is the name of a module (a kind of grouping), and "AppendChar" is the name of a command inside that module. The full name of the command is thus "MText.AppendChar".

This is similar to how people have a first name and a family name (surname). In KL, we say the surname (module name) first, unlike English-speaking countries where the surname is usually said second. Also, in English we usually separate the first name and surname with a space, whereas in KL we separate it with dot (".").

Your Own Commands

Now for something slightly confusing. Look at this line of KL source code:

cmd Test;

That line is an invocation of a command. What is the name of the command? Remember the command name is always at the beginning. Thus the command name is "cmd". What does this "cmd" command do? It makes a new command!

Yes, you can use the command named "cmd" to make/write/define your own commands. A command that you made consists of invocations of other commands (to be precise, the implementation of your command consists of invocations of other commands).

Being able to make your own commands is essential. Without this important capability, you would only be able to write rather small programs. Large programs would quickly become unmanageable. For example, if you make a command that consists of 20 invocations of other commands, you can invoke your command in multiple places instead of repeating those 20 invocations in each one of those places. How to write your own commands is explained in more detail elsewhere.

Be careful to avoid confusing Command Invocations with Command Implementations. They are 2 different but related things. It can be very confusing if you are reading something that talks about command invocations but in your mind you think it is talking about command implementations, or vice-versa.

A command invocation is an invocation of a command, meaning a line of source code where you specify that you want a certain command to be invoked/executed/run/performed/done at that point in your program.

Whereas a command implementation is the implementation of a command, meaning the list of other commands to be invoked when this command is invoked. Thus a command implementation consists of a list of command invocations.

If you are reading something and it just says "command" without saying whether it means a command invocation or a command implementation, then you must determine which it means by looking at the context (how the word "command" is used).

Parameters

Parameters are used to transfer information into, and out of, a command. Most parameters are input, some are output, and some are both input and output ("in/out").

When invoking a command, one of the following can be supplied for each parameter. These things are explained in more detail elsewhere (this is an overview).

Some types of parameters cannot accept some of the above. For example, an output parameter cannot accept an expression resulting in a number. Instead it requires that a destination storage location (for receiving the outgoing value) be specified.

Note that an invocation of a command (including parameter values) cannot contain an invocation of another command. Instead the other command must be invoked as the next or previous command invocation. Command invocations are organized as a list (with sections), not a hierarchy. (When reading this paragraph, remember to not confuse command invocations with implementations!)

Comments

A "comment" in the source code is some text that explains part of the program, or provides some extra explanatory, useful, or relevant information, etc. The compiler ignores/skips all text that is marked as being within a comment.

To write a comment, enclose it in curly brackets. For example:

{This is a test comment.}
var x, uint, 123;

Comments can be placed on lines by themselves, and also at the end of lines:

var x, uint, 123;  {This is a test comment.}

A comment can span multiple lines of text (it can have line breaks inside it).

Comments can be nested, meaning a comment can contain another comment. For example this is valid:

{A test comment {with nested comment}}
var x, uint, 123;

You can temporarily disable some commands in your source code by placing them inside a comment:

{var x, uint, 123;
var y, uint, 123;}

Because comments can be nested, it is easy to use a comment to disable multiple lines of code containing some small comments (without having to remove those inner comments).

Comments separate words as do spaces. In the following spaceless example, "foo" and "bar" are interpreted as 2 separate words. The comment is not blindly removed.

foo{comment}bar

An alternate style of single-line comment is also supported. These comments begin with 2 forward-slash characters ("//") and continue until the end of the line (the line break character marks the end of the comment). A space is usually written after the "//" but this is not mandatory. For example:

// This is a test comment.
var x, uint, 123;  // Another comment here.
//A third comment.

If "//" appears within a curly bracket comment, it is ignored the same as if it were 2 letter or space characters (the curly bracket comment disables checking for "//"). Thus a curly bracket comment can be used to disable multiple lines of source code that include some "//" comments.

Symbol Operators

Symbols such as "+", "*", "/", etc are used as operators. For example, "/" is used as the division operator.

A symbol operator can consist of multiple symbol characters. For example, "<=" is interpreted as a single operator known as the "less-than-or-equal-to" operator. Note that while "+" is interpreted as the addition operator, "++" would mean a different operator, but if you put a space between them (as in "+ +") then you have 2 addition operators.

Note that whitespace, alphabetic, numeric characters, and underscore separate symbol operators, but symbol characters appearing together without space between them are interpreted as single operators. For example "x,+y" (without space) is interpreted as "x  ,+  y" not as "x,  +y" and that results in an error message saying that ",+" is not a valid/recognized operator. So separate your symbol operators with spaces.

Names

A name (for example the name of a command or a variable) can contain only the following characters:

A name cannot contain:

A name can optionally contain the underscore ("_") character. For example you can write a name as "pizzaIsGreat" or you might prefer to write it as "pizza_is_great". You cannot write it with spaces as "pizza is great".

The name cannot begin with a "0" to "9" digit but can contain "0" to "9" elsewhere within the name or at the end. This rule makes it easy and quick for the compiler to distinguish between names and numbers.

Names are case-sensitive. For example, "tortilla" and "Tortilla" are interpreted as different names.

Whitespace

The main whitespace characters are:

  1. The normal space character. Produced when you press the big spacebar key on your keyboard to put a space between words.
  2. The tab character. Produced by the "Tab" key. Usually advances the position of the next character to the next tab-stop position.
  3. The line break character. Produced by the "Enter" key ("Return" on some keyboards). Advances the position of the next character down and left, to the beginning of the next line/row. 2 makes a blank line. Also known as "newline" or "linefeed" character.
  4. The carriage return character. An unnecessary and obsolete character used in conjunction with (or instead of) the line break character.
  5. The non-breaking space character. Same as the normal space except the words either side are supposed to be kept on the same line/row at all times. Not permitted in KL source code text.

Whitespace characters are NOT ignored by the compiler. If all whitespace characters are removed from the source code, or whitespace is randomly inserted, it will most likely become invalid. Whitespace is optional in some places, and required in other places, and prohibited in some other places.

That sounds complicated, but in practise the whitespace rules are intuitive and easy to remember, and the compiler is not an anal-retentive space nazi. Usually it is obvious when you have broken a whitespace rule because it looks wrong. For example "t esting" looks wrong. Obviously you cannot insert whitespace in the middle of a word, number, or multi-character symbol operator. If you do, the compiler will interpret it as 2 separate words/numbers/operators, changing the meaning.

Where you have 1 whitespace character that is allowed to be where it is, you have the option of replacing it with 1 or more whitespace characters (of same or different or mixed types) without changing the meaning of your program. Multiple whitespace characters are treated the same as 1 whitespace character.

If you have 2 adjacent words with no whitespace or symbol characters between them, they will be interpreted as 1 word because obviously there is nothing to separate them. Multi-character symbol operators are much the same -- they need to be separated with something or they will be interpreted as 1 operator (and that may result in an error message saying it is an invalid operator).

Separating everything with spaces is not required. For example, as we progress from left to right in "foo+bar", the change from alphabetic characters to a symbolic character is sufficient to end the word "foo" (because words are prohibited from containing symbolic characters). On the other hand, in "foo3bar" the "3" does not cause separation because words are permitted to contain numeric digit characters, and thus if you did want it separated you would have to insert spaces.

The compiler does not interpret whitespace in any way that is considered to be unrobust, such as counting the number of whitespace characters to determine the meaning of the program, or changing the meaning of the program merely by using 2 whitespace characters in place of 1.

Commands are normally written 1 per line, however this is not a requirement. Multiple commands can be on the same line, and a command can be split across multiple lines, without changing the meaning of the program (provided you do not put a line break in the middle of a word/name/etc, ofcourse). You can freely insert blank lines between commands.

Commands can be indented using 1 or more tab characters (or normal spaces but tabs are preferred for identing). Indenting has no effect on the meaning of your program, however sensible indenting does make it much easier for you to read.

Command invocations are terminated with a semicolon character, not with a line break character. This makes it more robust. For example, if some source code or snippet of source code is printed to paper or in a book or displayed on a website, there may be a command invocation that is longer than the width of the page or available space, requiring that a line break (or virtual line break) be inserted so it can be continued on the next line. If line breaks were used to terminate command invocations instead of semicolons, the font size would have to be reduced until the entire command invocation can be displayed on 1 line, otherwise the meaning of the program would be changed or the syntax would be incorrect.

Where there is a special whitespace rule applying to a particular situation, it is noted in the section of the documentation applying to that situation.