2KWLang

From Esolang
Jump to navigation Jump to search

2KWLang (2-Keyword Language) is an esoteric programming language created by User:PythonshellDebugwindow. It is named after its two keywords, import and print.

Files

2KWLang programs are divided into sections known as files. A file header consists of an equals sign followed by a newline- or EOF-terminated filename. Empty or duplicate filenames are invalid. Exactly one filename in a program must be followed immediately by an exclamation mark, which is not counted as part of the filename. For example, the following program outline contains two files, titled main.2kwl and another file.2kwl.

=main.2kwl!
  Some code here...
=another file.2kwl
  Some more code here...

The end of a file is signified by an equals sign which is not inside a string literal (as described in #Datatypes and literals) and which is preceded by a semicolon (;) and optionally by whitespace; the equals sign begins the header of the next file.

When the program begins, the file whose name is followed by an exclamation mark is run.

Except for whitespace, the first character in a valid 2KWLang program must be an equals sign.

Syntax and semantics

This section deals with the syntax and semantics of code within files.

Within files, all whitespace outside of string literals is ignored.

Datatypes and literals

There are three datatypes in 2KWLang: integers, reals, and strings. Integers and reals are unbounded, and reals have unbounded precision. If a real is evenly divisible by one, it is automatically converted to an integer.

Integer literals consist of sequences of decimal digits, such as 12345. Real literals consist of two integer literals separated by a decimal point, such as 123.45.

String literals consist of arbitrary text enclosed by double quotes, such as "this". Inside of string literals, a double quote can be escaped by a preceding backlash; with the exception of decimal integers (as described in #File importing and user input), backslashes do not escape any other characters. For example, the string literal "\Hello, \\\"test\"!" produces the string \Hello, \\"test"!.

Exceptions

In some situations, a program can cause an exception to be raised. What happens in this situation depends on whether the currently running file was imported from another file. If it was, execution immediately returns to the file which imported the current one; otherwise, the program is immediately terminated.

File importing and user input

A statement of the form import filename; can have one of three effects, based on the type of filename.

If filename is a string, the file whose name is filename is run; if no such file exists, then an exception is instead raised. For example, the following statement would run the file test.2kwl if it exists:

import "test.2kwl";

If filename is an integer, a line is read from user input, and the pair of filename and the read line is added to the input dictionary, which is a mapping from nonnegative integers to strings. If an existing entry in the dictionary had filename as its first item, that entry is removed.

If filename is a real, an exception is raised.

An item from the input dictionary can be referenced within a string using a backslash followed by a nonnegative decimal integer. If the integer is the first item of an entry in the dictionary, the backslash and integer within the string are replaced with the second item of the entry; otherwise, they are replaced with the empty string. For example, the following is an infinite cat program:

=cat.2kwl!
  import 0;
  print "You entered: \0";
  import "cat.2kwl";

Output

To print some value x to standard output with a trailing newline, a statement of the form print x; can be used. Similarly, a statement of the form print x | ""; outputs x without a trailing newline. For example, the following program outputs Hello, world! with a trailing newline:

=hello.2kwl!
  print "Hello, " | "";
  print "world!";

To append to some value x to a file whose filename is y, a statement of the form print x > y; can be used. The file named y is overwritten if x is the empty string; otherwise, x is appended to the contents of the file, followed by a newline. If y is not a string, an exception is instead raised. As with regular output, the trailing newline can be suppressed by writing | "" after x; note that this is not necessary if x is the empty string. For example, the following program segment would write Hello, world! followed by a newline to the file output after overwriting the previous contents of the file.

print "" > "output";
print "Hello, " | "" > "output";
print "world!" > "output";

If a real is printed or written to a file, the maximum number of fractional digits which will be output after the decimal point is implementation-defined; however, implementations are required to support at least five fractional digits. If a real has fewer fractional digits than the implementation's limit, then it should not be padded with trailing zeros when output.

Reading files

A statement of the form print import filename; can be used to output the contents of the file named filename, followed by a newline. Note that this syntax does not support outputting to a file, nor outputting without a final newline.

To read the contents of the file named filename, the expression import print filename can be used.

Attempting to read a nonexistent file causes an exception to be raised.

Operators

2KWLang uses five mathematical operators: + (addition), - (subtraction), * (multiplication), / (division), and % (modulus). Of these operators, the final three have precedence over the first two; operators with the same precedence are evaluated from left to right. If a string is used as an operand of any of these operators, or if zero is used as the right-hand operand of the division or modulus operator, an exception is raised.

There are also six comparison operators: == (equals), != (not-equals), < (less-than), > (greater-than), <= (less-than or equal to), and >= (greater-than or equal to). These have precedence over mathematical operators, and are evaluated from left to right. If a string is used as an operand of any of the latter four comparison operators, an exception is raised.

Parentheses (( and )) are used to group operators.

Examples

Hello, World!

=hello.2kwl!
  print "Hello, World!";

Cat

=cat.2kwl!
  import 0;
  print "\0";
  import "cat.2kwl";

Truth-machine

=main.2kwl!
  import 0;
  import "\0.2kwl";
=1.2kwl
  print "1";
  import "1.2kwl";
=0.2kwl
  print "0";

Quine

=main.2kwl!
  print "=main.2kwl!";
  print import print "main.2kwl" | "";

Infinite looping counter

=main.2kwl!
  print 1 | "" > "n.2kwl";
  import "inc.2kwl";
=inc.2kwl
  print ""                               > "count.2kwl";
  print "print "                    | "" > "count.2kwl";
  print import print "n.2kwl"       | "" > "count.2kwl";
  print "; print "                  | "" > "count.2kwl";
  print import print "n.2kwl"       | "" > "count.2kwl";
  print " + 1 | \"\" > \"n.2kwl\";" | "" > "count.2kwl";
  print "import \"inc.2kwl\";"      | "" > "count.2kwl";
  import "count.2kwl";

Finite looping counter

=main.2kwl!
  import 0;
  print "\0" | "" > "max.2kwl";
  print 1 | "" > "n.2kwl";
  import "inc.2kwl";
=inc.2kwl
  print ""                                > "range.test";
  print "import \"range.test."       | "" > "range.test";
  print ""                                > "makerange.2kwl";
  print "print "                     | "" > "makerange.2kwl";
  print import print "n.2kwl"        | "" > "makerange.2kwl";
  print " <= "                       | "" > "makerange.2kwl";
  print import print "max.2kwl"      | "" > "makerange.2kwl";
  print " | \"\" > \"range.test\";"  | "" > "makerange.2kwl";
  import "makerange.2kwl";
  print "\"; import \"rangesucceeded.2kwl\";" | "" > "range.test";
  import "range.test";
=rangesucceeded.2kwl
  print ""                               > "count.2kwl";
  print "print "                    | "" > "count.2kwl";
  print import print "n.2kwl"       | "" > "count.2kwl";
  print "; print "                  | "" > "count.2kwl";
  print import print "n.2kwl"       | "" > "count.2kwl";
  print " + 1 | \"\" > \"n.2kwl\";"      > "count.2kwl";
  
  print "import \"inc.2kwl\";"      | "" > "count.2kwl";
  import "count.2kwl";
=range.test.1