Rulz and Rulz Language is Copyright © G.A.Jennings, 2015-2023.
This is language specification 2-1/2; last updated 6 October 2022.
Rulz, pronounced "rules", is a general purpose computer language. The language is minimalist with no use of traditional braces, parentheses or commas. It includes all basic types, flow control, blocks, loops and subroutines.
Though yet to be specified formally, Rulz has an assembly language-like structure and uses PHP-like variables and types, and borrows features from Bash and Perl.
But instead of "statements" and "expressions", there are "rules". A group of "rules" in a subroutine is called a "Rule" (uppercase "r"). Together, rules and Rules make up a Rulz Program.
Update 20 Nov 2022: I have started to publish the code, but need to explain much about it...
Here's a "normal" code thing:
if (EXPR) do();
Rulz just asks, what if if
was ?
:
? (EXPR) do();
Rulz also asks what if EXPR
was first (storing the result in a special variable, and the ?
is a test of that special variable):
(EXPR) ? do();
Which in "normalclature" could be:
$t = (EXPR); if ($t) do();
But where $t
is "internal":
(EXPR) if do();
That is similar to Perl. Also in Perl and PHP are things like:
(EXPR) && do();
Rulz is just "reductive", finally eliminating the no longer necessary characters, (
, )
and ;
, though adding a newline:
EXPR ? do
So there is nothing really new here.
References: • Operators • Variables • Data Types • Subroutines
Details: • Lexer • Regex Example
There is a "Tutorial" modeled after other, more typical programming documentation, Rulz Tutorial.
This document uses some identifiers here in particular ways.
rule Rulz language statement Rule two or more rules together or a subroutine var variable name (to be set) val literal value (number, string, etc.) $var variable argument literal or variable (arg)
The basic format of a rule is:
<operator|builtin|subroutine|label>[arguments]
Where:
operator arithmetic, conditional, or other operator builtin builtin command or standard function subroutine name of set of one or more rules; called a Rule label a placeholder for the "jump" operator arguments zero or more arguments (literals, variables)
Though usually, Rulz uses a format like:
OP [ARGS]
Further describing that basic construct as a "RULE", as there are compound operators, those that can have another rule as an argument, are like:
OP OP [ARGS]
And that can be described like:
OP RULE
Rulz' most unique syntax is that operators are always "first on the line" and there is only one per rule.
For example, assignment is =var argument
and not var = argument
. As in Bash, variable assignment does not include the $
.
This is known as "prefix notation" for operations (expressions), but Rulz syntax is more "prefix statement notation".
Here is the ubiquitous "Hello World" program in Rulz.
^Hello World
The ^
is the "print operator" which is like echo
in Bash, outputting all arguments, separated by spaces, terminated with a newline. It also shows that, like Bash and Perl, barewords—identifiers of letters only—are treated as strings. To use any other characters quotes need to be used.
^"Hello, World!"
Otherwise the punctuation characters will be treated as separate arguments:
^Hello, World! prints as 'Hello , World !'
Spaces are needed only in the case of ambiguity. (Though this is not a "free-form" language.) This uses a variable to print "Hello World".
= name'Hello World' ^ $name
For clarity, most examples here use spaces (though it's kind of a convention to not use a space after the operator).
Rulz supports the three basic types of comments: single character beginning a comment line, single character introducing a trailing comment and a block comment defined by begin/end character pairs.
In Rulz, comments are operators (and are "removed" at run-time).
"While we usually think of quotes as literal values, in Perl they function as operators, providing various kinds of interpolating and pattern matching capabilities." – PerlOp
Oh... If at this point you're like, still here, peruse STEM. (I just saw it yesterday, January 26th, 2024).
Rulz has the basics; boolean
, string
, list
(array) and handle
(stream). But, though maybe at times internally integers are used, at the high level the numerical type is number
and will work like integers or floats depending on context.
There are constants for TRUE
, FALSE
and the PHP-like NULL
(undef).
Rulz has several pseudo-types such as file, option and argument—which are similar to barewords but are more specialized in certain contexts.
Variables do not need to be declared. Accessing a non-assigned variable will result in a type's "false", "zero", "empty" or "null" value.
Basic variables are like
where "var" is one or more lowercase letters, and, PHP-like, can be assigned any type. Variable assignment is Bash-like with the $var
$
not used.
Like Bash and Perl all variables are global and there are "my" and "local" attributes for subroutines.
There are Perl-like "special variables" of the format:
. The special variables $[
0-9[:punct:]]
and $0
, differ from their Perl counterparts and are used as defaults for most Operators and Builtins.$_
The variable
is called the "return value", or "r-value",and contains the result of function calls and is the default for most operators and commands.$0
The variable
is called the "function value", or "f-value", and is the default argument for some operators and functions.$_
# a single character comment line; can also # trail a rule ## start of a block comment that will end at the next ##
The block comment usually is for multiple lines.
There are two conditional operators. In their simplest for they test the
special variable.$0
? rule run rule if previous rule was true ! rule run rule if previous rule was false
The logical operations are actually "true if true" and "true if false".
The conditional operators can test a specific variable:
? $var rule run rule if $var true ! $var rule run rule if $var false
Those two rules are the reduction of the syntax of these two PHP statements.
if ($var) statement; if (!$var) statement;
The conditional operators have "compound forms".
<?!> [operator [$var]] rule
And there are ternary versions based on a variable.
? $var rule rule ! $var rule rule
And for result of a rule.
? rule rule rule ! rule rule rule
(Though those are not a "ternary assignment operator" as in other languages.)
Rulz' boolean type is PHP/Perl-like. The conditional operators are "kinda-loose", with
0
,""
(empty string) and()
(empty list) evaluating false, and all other values evaluating true.There is another case that defaults to true,
"0"
(ASCII 48), but as will be seen, there are ways to change run-time operations in ways similar to Bash and Perl – there is a "special variable" to change that to be false.
The assignment operator has the format:
= [var] [argument] assignment
An assignment operator all by itself is valid: it "resets" the special variable
to a "false" value. Otherwise it will set a variable to a value.$0
= var 1729
Note that
= var
does not effectbut assigns the string
$var
var
to.
$0
There are "compound" versions for multiple variables.
= a,b,c 1,2,foo
Without values, compound variables are set to it's "zero" value.
= i,j
With just one value the variables are all set to it. This is same as above.
= i,j 0
To set some and default some, use a comma.
= i,j 1,
!= var [vars] unset $var and all following variables
The arithmetic operators – which are similar to assignment and so are "prefix modified" assignment operators – have three forms:
OP argument OP var argument OP var argument argument
With just one argument:
+= argument add to $0 -= argument subtract from $0 *= argument multiply $0 by /= argument divide $0 by %= argument modulo $0 of .= argument concatenate $0 with
The concatenation operator appends a string to string (PHP-like); and there will be some "type juggling" here with mixed types. See [rulztypes].
And to apply to a variable:
+= var argument add to $var -= var argument subtract from $var *= var argument multiply $var by /= var argument divide $var by %= var argument modulo $var of .= var argument concatenate $var with
When used with a variable name and two arguments the result is like other language arithmetic.
+= var arg arg $var = arg + arg -= var arg arg $var = arg - arg *= var arg arg $var = arg * arg /= var arg arg $var = arg / arg %= var arg arg $var = arg % arg .= var arg arg $var = arg . arg
See also #List Assignment Operations.
The exponentiation operator in Rulz is actually a mathematical operator. See #Mathematical Operators.
As increment and decrement operators in most languages are just a syntactical shortcut, Rulz simply has one more version of add and subtract.
+= increment $0 -= decrement $0 += var increment $var -= var decrement $var
(So, there actually are no increment and decrement operators. Only addition and subtraction, for that's all increment and decrement are.)
There are two ways to create constants—one for enumerations and one for values.
,= A B C A = 1; B = 2; C = 3 := A 1 B 2 C 3 same
The latter can also have extra spaces.
:= A 1 B 2 C 3 same
Or it can have none.
:=A1B2C3 same
Admitedly those are kind of kludgey (looking) so there are ways of defining constants that are more better. See [rulzdata.html].
These operators are listed by number of arguments.
The unary not of bits takes zero or one arguments. If none, $0
is a not of itself, else it is not of the variable.
~= [var] result is Not of bits
The xor and shift operators take one or two arguments, with the result in $0
or a variable respectively.
^= argument [argument] result is Xor of bits <= argument [argument] result is bit shift left >= argument [argument] result is bit shift right
The and and or operators can take from one to many arguments.
&= argument [arguments] result is And of bits |= argument [arguments] result is Or of bits
With one or two values, the result is in $0
(with one value the result is the binary operation with $0
(itself) as the first operand).
&= 1 $0 is $0 And 1 &= $a $b $0 is $a And $b
With a variable name the operations are the same:
&= a 1 $a is $0 And 1 &= c $a $b $c is $a And $b
With three or more arguments, the result is the operator applied to all values.
|= 1 2 4 8 $0 is 15 |= var 1 2 4 8 $var is 15
The logical operators set $0
with the result of the operation.
!! [argument] true if argument or $_ not true || [arguments] true if any argument or $_ true && [arguments] true if all arguments or $_ true ^^ argument [argument] true if either argument or argument and $_ true but not both
In addition, there are two named operators that operate a little different.
or arguments result is the first argument that is found true and arguments result is the first argument if all are true
And two that are unique to Rulz.
is argument [argument] true if argument or argument and $_ are of the same type not argument [argument] true if argument or argument and $_ are not of the same type
Comparison operators are "modified" conditional operators, the result in $0
, and take one or two arguments. If one, the comparison is against $_
; if two, the comparison is between the first and second arguments.
=? argument [argument] true if equal =! argument [argument] true if not equal <? argument [argument] true if less than <! argument [argument] true if not less than >? argument [argument] true if greater than >! argument [argument] true if not greater than
See also #Compound Conditionals.
=? list [list] true if have same key/value pairs =! list [list] true if not the same
The #Assignment Operators can be used with lists.
+= list value add value to each list element += list list add each element of second to each element of first
All basic arithmetic operations are similarly supported.
Concatenation is either push (append) or merge.
.= list value push value onto list .= list list merge second list into first list
There are also several operators dedicated to lists.
Bitwise operations also can be applied to lists in a unique way—with just one argument $_
will be used as if it were the second.
&= [list] list union |= [list] list replace ^= [list] list unique ~= [list] list intersect <= [var] list shift >= [var|val] list unshift
See also #List Operators.
The defined operators mimic the PHP isset and the Perl defined functions.
?? var isset (defined) ?! var not isset (not defined) &? var defined [subroutine] &! var not defined [subroutine]
Where var
is a variable name or interpolates to a variable name.
The evaluation operator mimics the PHP and Perl eval functions.
`= var eval string or list of strings
The list version is similar to calling a subroutine though no arguments are involved.
The percent operators are function-like.
=% argument [argument] percentage of /% argument [argument] percentage against +% argument [argument] percentage add -% argument [argument] percentage from *% argument [argument] percentage between
The Mathematical operators are function-like.
v/ argument square root 2/ argument square 1/ argument reciprocal a/ argument absolute ^/ argument exponent
They work like #String Operators defined below. (There are many more.)
The file I/O operators mimic basic file functions. The $0
variable is TRUE on success or FALSE on error.
& [fh] file open file for reading, handle in $_ or $fh -& [fh] file open file for writing, handle in $_ or $fh +& [fh] file open file for appending, handle in $_ or $fh
The file read operators returns the number of bytes read or FALSE on error.
<& [$fh] var read line from $fh or $_ to $var <& [$fh] var number read number bytes from $fh or $_ to $var [& [$fh] var read line from $fh or $_ to $var without EOL {& [$fh] var read character from $fh or $_ to $var (& [$fh] var format parse line from $fh or $_ to $var according to format /& [$fh] var pattern parse line from $fh or $_ to $var according to regular expression
The file write operators returns the number of bytes written or FALSE on error.
>& [$fh] $var write $var to $fh or $_ with EOL ]& [$fh] $var write $var to $fh or $_ without EOL }& [$fh] $var write character $var to $fh or $_ )& [$fh] var format write $var to $fh or $_ according to format
Other file operators.
@& [$fh] eof test .& [$fh] close %& [$fh] stat =& [$fh] number seek ,& [$fh] rewind ?& [$fh] tell :+ [$fh] truncate
With some file name versions.
%& file stat ^& file touch !& file delete |& file file rename/move
The use of $_
as a default for the file handle is odd as many other operators can subsequently and inadvertently overwrite $_
. Using $_
is recommended only for short sequences of code.
See also #Test Operators.
There are several function-like operators that read or write files directly.
<< [var] file get file as string into $_ or $var [< [var] file get file as list into $_ or $var with EOL (< [var] file get file as list into $_ or $var without EOL
>> [$var] file put $var or $_ as string to file ]> [$var] file put $var or $_ as list to file with EOL )> [$var] file put $var or $_ as list to file without EOL
+> [$var] file append $var or $_ as string to file -> [$var] file prepend $var or $_ as string to file
Special variable $0
is set to FALSE for error, TRUE for success; except that read operators return the number of bytes read, and write operators return the numbers of bytes written on success.
The put, append and prepend file operators have a dual role with two arguments in that if the first argument is the name of a file that exists the file's contents will be used in place of the variable contents.
>> filea fileb copy file +> filea fileb append file -> filea fileb prepend file
Finally, a file can be read and output directly to "standard out".
~< file output file (readfile)
A Rule file can be included.
.< file load source file
The file being included will not be run and any rules outside of subroutines will be ignored. What this means is that only subroutines will be loaded. See [rulzsub.html].
Rulz subroutines can be redefined—any existing subroutine of the same name will be replaced.
There are Rulz builtins for running Rulz programs. See [builtins].
The execution operator, returning the program's output, comes in two forms. The first sets
and exec's all arguments as a single string.$0
`` whoami --version
And the other is as a "backtick argument" that is operator like for assigning to a variable.
= var `whoami --version`
See [rulzargs].
The regular expression operator is like a "search or search and replace" operator, and it too has two forms. The "search" (match):
// /pattern/ search $_ for pattern // $var /pattern/ search $var for pattern
And the "search replace":
// /pattern/text/ search $_ and replace with text // var /pattern/text/ search $var and replace with text
As with variable assignment, the variable name for replace is without the $
.
After a successful match, the following special variables are set:
$# number of matches $& the string that matched $1 the first subexpression match; $2 the 2nd, etc.
For search,
is set to the number of matches; for replace, the number of replacements.$0
These are full PCRE strings except that there is no multi-line version and their arguments can only use
/
as delimiters.
The translate operator is like PHP's strtr
and Perl's tr///
.
\\ /searchlist/replacelist/ \\ var /searchlist/replacelist/
The jump operator is .
. It can have a number of rules to jump over or a string for a "label" to jump to.
. 3 jump 3 rules . label jump to label
A label is operator-like.
:label define label
Multiple labels of the same name is not an error; the jump to label will just go to the first label it finds. Labels by themselves are a "No Op".
Variables can be used for jump conditions:
= n 3 assign $n . $n jump $n lines
= b label assign $b . $b jump to label $b
A jump operator can be preceded by a conditional operator:
? . label conditional jump to label
Though such compound operators are unique to conditional/comparison operators not the jump operator.
@do while 1 <rules> @end
@each [$var] foreach on $0 or $var (as keys and values) <rules> @end
@for [$var] foreach on $0 or $var (as values) <rules> @end
@until [$var|rule] while $0 or [$var|rule] is false <rules> @end
@while [$var|rule] while $0 or [$var|rule] is true <rules> @end
With
the special variable @for
is set to the array value. With $_
the special variable @each
is set to the key, and $(
the value.$)
These operators cannot be nested.
The following operators can control the loop:
.. [rule] break >. [rule] next (continue) <. [rule] redo
The
and @until
operators have one line versions.@while
@while <$var|rule> <rule>
With the caveat that for a conditional <rule>
the loop condition is
, which means that the loop will continue or not based on either $0
<rule>
setting
at some point.$0
When the loop conditional is a variable, the <rule>
argument has to set the variable to continue or stop the loop, either through a subroutine or a builtin.
These are not blocks in the sense of PHP or Perl; but are similar.
@if [$var|rule] if $0 or $var or rule is true <rules> [@else] [rules] @end
These operators cannot nest.
Not being able to nest loops/blocks is a minor thing as there are subroutines.
There are, of course, "short form" loop operators. (Though, actually, the "long form" are the aliases.)
c@ @case d@ @do e@ @each f@ @for i@ @if s@ @switch u@ @until w@ @while @ @end
A modifed jump is an exit depending on context:
.. break, return, exit
In a loop it does a "break", in a subroutine a "return" and in Top Rules "exit".
Related operators are:
>. continue (next) <. redo
And kinda related, and Perl-like:
^. die
Test Operators, based on Bash conditional operators, set $0
with the result of a test on a file—TRUE or FALSE. If the test argument is missing $_
will be used.
f- [file] file exists d- [file] file exists and is a directory r- [file] file is readable w- [file] file is writable
The following "tests" will return a value other than TRUE for success.
s- [file] file size p- [file] file permissions t- [file] file type g- [file] file group a- [file] file access time c- [file] file change time m- [file] file modification time
The type test operators test the type of it's argument or $_
.
S- [argument] is string I- [argument] is integer D- [argument] is double A- [argument] is list or hash N- [argument] is numeric B- [argument] is boolean U- [argument] is null T- [argument] is true (PHP like) Z- [argument] is empty (PHP like)
These return a value other than TRUE.
L- [argument] integer length if string or count if list Y- [argument] string indicating type (PHP like)
Type operators are extensions to test operators on types, and are similar to POSIX character classes and PHP ctype functions.
Again, $_
is used if no argument and the boolean result is in $0
.
u? [argument] is uppercase l? [argument] is lowercase d? [argument] is decimal s? [argument] is whitespace w? [argument] is word character n? [argument] is alpha numeric a? [argument] is alpha c? [argument] is control g? [argument] is graph p? [argument] is printable v? [argument] is punctuation x? [argument] is hexadecimal
All have an !
version to negate the test.
The string operators perform function-like operations on strings.
u~ [count] [arg] to upper case l~ [count] [arg] ro lower case n~ [arg] length q~ [arg] quote meta i~ offset [len] [arg] index (substr) s~ string [off] [arg] string occurrence S~ string [off] [arg] string occurrence (case insensitive) p~ string [off] [arg] string position P~ string [off] [arg] string position (case insensitive) c~ [arg] chop (PHP like) C~ [arg] chomp (Perl like) t~ [string] [arg] trim T~ [string] [arg] trim right L~ [string] [arg] trim left f~ format arg [args] sprintf F~ format arg [args] sscanf h~ [arg] htmlentities H~ [arg] htmlspecialchars x~ [string] [arg] explode w~ [len] [string] [arg] wordwrap r~ string string [arg] string replace R~ string string [arg] string replace (case insensitive) e~ [arg] urlencode E~ [arg] urldecode y~ [string] [arg] crypt g~ string [arg] preg split b~ [string] [arg] basename d~ [arg] dirname
List operators perform Perl/PHP functions. Most create (or modify) lists.
/[ [var] string [string] split :[ [var] list [string] join ~[ [var] list values %[ [var] list keys @[ [var] list sort \[ [var] list reverse <[ [var] list shift >[ [var] list unshift -[ [var] list pop +[ [var] list push ,[ [var] list off [len] slice ([ [var] list string extract ^[ [var] list list difference
Without var
the results are in $_
. For @[
and [
list can be a reference to a list.
+[ list list sum -[ list list subtract *[ list list product /[ list list division
Operators that act upon a list or a hash.
#[ [var] <list|hash> count =[ [var] <list|hash> index/key exists (boolean) ?[ [var] <list|hash> value exists (boolean) [[ [var] <list|hash> value exists (search) returns key *[ [var] <list|hash> random value
See also #List Assignment Operations, #List Bitwise Operations and #List Interpolation.
j[ join v[ values k[ keys s[ sort r[ reverse p[ pop P[ push l[ split L[ slice d[ difference i[ index/key exists e[ value exists (boolean) E[ value exists (search) ; ]
An &
character preceding an argument is another "operator argument" for using a builtin or subroutine return value as an argument.
This Rule calls time with the return in $0
which is passed to date.
time date "M d, Y" $0
The &
argument turns functions into arguments.
date "M d, Y" &time
Otherwise, time would be seen as a bareword.
See [rulzargs].
"Here documents" are supported, with slightly unique syntax, which is that they are "begin/end operators"—a heredoc begins with a (( and ends on another (( on a line by itself (leading and trailing whitespace ignored).
<( Here, here documents are multi-line print statements. They include interpolation and escapes (\$foo = $foo). These end on the next "<(" seen that starts at the first character. Leading whitespaces of "<(" are part of the string: <( Lines are concatenated with spaces; blank lines are replaced by a newline. * Leading whitespace is preserved... ...the trailing newline is not. For that, end with one: <(
<( var This heredoc is assigned to a variable. <(
A "nowdoc" is by the operator ((
.
(( A "nowdoc" does not interpolate $vars and does not convert escapes like \\ or even \'. (Which is kind of Perl-like. I think.) ((
These operators introduce a kind of "operator attribute", in that appending a \n (the string literal, not a real newline) will modify it to append a newline to each line.
(( \n 1) Line 1. 2) Line 2. 3) Line 3. ((
If a heredoc (or theredoc described next) is last in a program or subroutine the ending operator is not required.
An extension to heredoc is to output text to a file—a "there document". This uses the operator >)
and a file name.
=title "Rulz Programming Language" >) head.htm <!DOCTYPE html> <html> <head> <title>$title</title> </head> >)
All the aspects of heredoc applies. The "now theredoc" is ))
.
The #Conditional Operators can test some operators—basically combining two rules in one.
? <rule> <rule>
! f- .. ^$_ not found ! f- $f .. ^$f not found ! &error.log .. ^could not open log file
Similar to basing the conditional test on a variable, here, the conditional test is a rule and only those with operators that set $0
will work as expected.
! += v ^foo
That rule will always increment $v
but will only print foo if $0
"is false".
! += ^foo
That rule will always increment $0
but will only print foo if $0
"was false".
Even though a builtin might set $0
, they will not work this way:
? builtin $v ^foo
The ^foo
will get passed to the builtin (as two arguments), which will be called is $0
true. This is where the comma pseudo-operator comes in.
? builtin $v , ^foo
So, ^foo
will run based on the return of builtin
.$v
Leading and trailing spaces and tabs are ignored. Operators and arguments can be separated by spaces or tabs.
? func = foo 10 ! += $foo >? 10 = f ~/*
The latter rule's argument is a file glob; see [rulzargs].
If there is no ambiguity between operator and argument(s) spaces are not required at all.
?func =foo10 !+=$foo >?10 =f<~/*>