Squire Documentation




Basic Syntax

To print something to the console, use proclaim():

proclaim("Hello World!")


Numerals use the Roman way of counting: I, II, III, IV, etc.
To convert a Roman numeral to a more modern way of counting (often referred to as Arabic Numerals), use the arabic() function:

arabic(I)


Conversely, one can convert a "modern" numeral to a Roman numeral by simply using the roman() function:

roman(1)

Minus numbers are also supported, represented as follows: -II (-2).


In Squire, the term "Boolean" does not exist. Instead, "veracity" is part of the language.
"true" is "yea" and "false" is "nay".


Interpolation is done using curly brackets (only within strings) as follows:

proclaim("yea == nay? {yea == nay}")


There are two sets of comment types: single-line and multi-line


Multi-line commenting is done using C-style comments as follows:

/* This is the start of the comment
This is the end of the comment */


Single-line commenting has two ways of being implemented:

# This is a single-line comment
N.B. But so is this!



Null is represented with "ni", as homage to the Knights Who Say "Ni".
Squire is dynamically-typed, meaning that no type has to specified when variables are created.
This means that a variable could be initiated as a string then transformed into an integer like so:

variable = "string"
variable = I



Like JavaScript, semicolons can be used to end lines, but is not required.
"\t", "\\", "\'", and "\"" are supported in regards to strings.


@__END__ can be used to halt parsing of a file from that line forwards, and variables can be whatever you want:

foo_bar = I
proclaim(arabic(foo_bar + fooBar + foo bar)) # Prints 3



To differentiate between strings and variables within certain elements of Squire, Fraktur Unicode is used, which looks like this:
𝔰𝔮𝔲𝔦𝔯𝔢 𝔦𝔰 𝔠𝔬𝔬𝔩

The Squire compiler provides a shell script to convert from normal text to Fraktur Unicode.



Books & Codices

Books, Squire's version of arrays, use the familiar bracket syntax as follows:

languages = [𝔖𝔮𝔲𝔦𝔯𝔢, ℜ𝔲𝔰𝔱, ℭ]


Please note that Squire is an I (or 1) indexed language, unlike most languages. Fraktur Unicode is also used to represent strings in books, as discussed in the previous section.

To get the length of a book, the function .length is used like so:

proclaim(languages.length) # Prints III


Naturally, fetching of an element also uses brackets like so:

C = languages[III] # The variable C now equals "C"


It is also possible to use negative numbers to find the last element like so:

C = languages[-I] # C still equals "C"
C = languages[-II] # C now equals "Rust"



If an element is inserted into an index above the next sequential index, then the empty fields are filled with "ni":

languages[V] = 𝔎𝔫𝔦𝔤𝔥𝔱
proclaim(languages) # Index IV is nil



insert() and delete() can be used to add and delete indexes from books as follows:

insert(languages, I, "Quest") # The first index of the "languages" book now equals "Quest"
delete(languages, II) # "Rust" is now no longer in our book




Codices are Squire's dictionaries, maps, etc.
They store two values in one index, whatever you want to call them. They use curly bracket syntax:


numbers = {𝔬𝔫𝔢: I, two: II, 𝔱𝔥𝔯𝔢𝔢: III}

Values can be updated like so:

numbers[𝔱𝔥𝔯𝔢𝔢] = IV


Much like books, the length of a codice can be retrieved by using the .length function.


delete() can also be used with codices.



Control Flow

Squire has basic if statements, however "else" is switched out for "alas":

fav_colour = "black"
if fav_colour == "black" {
 proclaim("Me too :)")
} alas {
 proclaim("Why do you like {fav_colour}?'")
}



During full moons, if statements have a 1% chance to only execute their body if the condition passed is false.
This can be opted out of during compilation using the -DSQ_NMOON_JOKE flag.


Switch statements exist too, represented with forks.

The syntax is as follows:

fork fav_colour {
 path "black":
  proclaim("Me too :D")
 alas:
  proclaim("Why do you like {fav_colour}?")
}



alas is used as the default case. It is optional.


paths can be expressions to shorten if statements like so:

fork yea {
 path fav_colour == "black":
  proclaim("The colour of darkness...nice")
}



Squire does not have for loops, instead the have while (whilst) loops:

i = I
whilst i != V {
 i = i + I
}



Please note that Squire is still in development. Though for loops do not yet exist, that does not mean that they will never be added.


Thankfully, Squire supports basic error handling in it's current state, represented by attempt and catapult:


attempt {
 if i > V {
  catapult("i is above 5")
 }
} alas err {
 proclaim(err)
}



Squire also supports something called whence commonly referred to as COMEFROM in other languages.
whence can be used to escape from nested loops like so:

i = I
whilst i < V {
 j = I
 whilst j < V {
  if j == IV {
   out:
  }
 }
}
whence out # If j equals IV, then the program will be moved to this line





Journeys

In place of functions, Squire has journeys:

journey hello(name) {
 proclaim("{name} says: \"Hello World!\"")
}



It is also possible to return values from functions using reward:


journey goodbye() {
 reward "Goodbye World!"
}
proclaim(goodbye()) # Goodbye World!



Implicit returns:

journey implicit() {
 II + I
}
proclaim(implicit()) # III




Squire also supports lambdas since it is a high level language:

numbers = [I, II, III]
journey func(book, lambda) {
 i = I
 whilst i <= book.length {
  book[i] = lambda(book[i])
  i = i + I
 }
 reward book
}
output = func(numbers, journey(x) { x + I }) # [II, III, IV]



All variables are locally scoped to the journey they're in.
However, if a global variable exists with the same name as that local variable then that global variable will be used.
Locality for variables can be forced using the nigh keyword. Likewise, globality can be forced using renowned:

renowned variable = I
journey function() {
 nigh variable = II
 reward variable + I
}
proclaim("global variable == {variable + I}") # Prints II
proclaim(local variable (going by the same name) == {function()}) # Prints III



All journeys are defined as global, however if you want to predefine a function you must mark it as renowned as follows:

renowned predefined
proclaim(predefine()) # Prints "This function was predefined!"
journey predefined() {
 reward "This function was predefined!"
}





Forms & Imitations

Classes in Squire are reffered to as forms and constructors for those classes are called imitations:

form Person {
 matter name, hungry # Form-specific variables to define what fields imitations can have

 # "change" is the keyword used to define a class method/function
 change set_name(name) {
  this.name = name # soul is Squire's version of 'this', used to reference the current object
 }

 imitate(name) { # Constructor
  set_name(name)
 }
}

sam = Person(𝔖𝔞𝔪)



NOTE: Due to my lack of understanding of the concept essence in Squire, essence and recalls are not covered on this site.
However, I recommend that you read the official documentation page for this section to hopefully get a grasp of the concepts.
It would be greatly appreciated if you would add essences and recalls to the documentation if you understand the two concepts.




Macros

All macro invocations start with @ and end with a semicolon.

@transcribe; is used to import other files into the current one like so:

@transcribe test.sq;


@henceforth; is used for text replacement at compile-time (similar to #define in C).
To escape semicolons in @henceforth you can use the << ... >> construct which interprets its contents literally:

@henceforth $three =
 <<
    proclaim(I);
    proclaim(II);
    proclaim(III);
 >>;

$three # I, II, III


Any variables associated with macros must be prefixed with $.

@henceforth $increment($number) = proclaim($number + I);
$increment(I) # II


There is a special macro variable worth mentioning called $__COUNTER__ which increments every time it is used.

proclaim("$__COUNTER__ = {$__COUNTER__}"); # $__COUNTER__ = N
proclaim("$__COUNTER__ = {$__COUNTER__}"); # $__COUNTER__ = I
proclaim("$__COUNTER__ = {$__COUNTER__}"); # $__COUNTER__ = II


<< ... >> can also be used to escape ','s:

@henceforth $execute($function, $argument) =
 proclaim($journey($arguments));

journey add(x, y) { reward x + y }
$execute(add, << I, II >>) # III



@nevermore simply undeclares a variable defined by @henceforth:

@henceforth $lol = I;
@nevermore $lol;

proclaim($lol) # Program will spit out an error - $lol is undefined


Conditional compilation! It exists in Squire!
It's nothing amazing though, just checking if a variable exists:

@henceforth $foo = I;

@whereupon $foo
 proclaim("Foo exists!")
@alas
 proclaim("Foo doesn't exist!")
@nowhere;
# Outputs "Foo exists!"





Miscellaneous

This section is simply a list of built in functions found in builtins.sq that haven't already been covered.




One function, genus() is not covered here as I cannot find anywhere to explain it's function to me.
If you understand what it does please help out on the repository.