Nasal Operators

From FlightGear wiki
Jump to navigation Jump to search

Nasal has support for various operators, both mathematical (add, subtract, multiply, and divide) and programming-specific (assignment, concatenation, control-flow, etc.).

Operators

Nasal has operators similar to most C-family languages. Note that + is for arithmetic addition, and ~ is for string concatenation.

"88" + "88" == 176; # number
88 + "88" == "88" + 88; # same
"88" ~ "88" == "8888"; # string
88 ~ 88 == "8888"; # string as well
"88" ~ 88 == 88 ~ "88"; # same

Nasal also supports null-safe chaining and null-access operators: [1]

print("obj" ?? "default"); # prints "obj"
print(nil ?? "default"); # prints "default"
var hash = {key: 1};
print(hash?.key); # prints 1
# print(hash?.key2) # throws error if variable hash is not null
hash = nil;
# now hash?.key is nil
# print(([1, 2])?.[0]) # "?." does not support vectors

Conditionals

Nasal uses the ! and ?: operators, but uses and and or instead of && and ||. The ?:, and, and or operators are short-circuit evaluated. Example:

var result = !cond1 and cond2 or cond3?"true":"false";
print(result); # prints true

Slicing and indexing

In Nasal, vectors can be sliced (i.e. a new vector is constructed from indexes of an existing vector) and strings, hashes, and vectors can be indexed/subscripted. For an overview of slicing see vector slicing.

Indexing works in different ways for the different types. For strings indexing returns a value equal to the value of the character at the position. For hashes it looks up the key in the hash directly, ignoring the parents vector, and returns nil if it is not found; this treats numbers and strings as different types of keys. For vectors, the value at the index of the array is retrieved, if it is valid. Some examples:

var vec = [0, 1, 2, 3];
vec[0] == 0; 
vec[1] == 1;
vec[-1] == 3; # last element
vec[-2] == 2; # next-from-last element

var hash = {
    -1: 0,
    "-1": 1,
    hello: "hi",
    parents: [{ find_me_here: 42 }]
};
hash[-1] == 0; # look up the number -1 in the hash
hash["-1"] == 1; # look up the string (!) "-1" in the hash
hash[-1~""] == 1; # same thing -- makes a string
hash.hello == "hi"; # find the member hello in the hash
hash["hello"] == "hi"; # approximately the same, but using an index expression
hash.find_me_here == 42; # find the member find_me_here in the hash, or actually its parent
hash["find_me_here"] == nil; # but it cannot be found with an index expression, because its parent isn't searched
hash.parents[0]["find_me_here"] == 42; # but we can always look for the specific parent's member

Semantics

Some insights on the workings of various common operations.

Equality

Here are the rules for checking equality:

  • If both are scalars:
    • If both are numeric: check if they are numerically equal (converting to numbers first).
    • Else: check if they are equal as strings.
  • Else compare id's (items only equal themselves, e.g. nil == nil while [] != [] because they are different vectors with different id's).

Boolean evaluation

Rules for checking if a value is "true" or "false":

  • If nil: return false
  • If numeric:
    • If 0: return false
    • Else: return true
  • Else: error "non-scalar in boolean context" (applies to hashes, functions, vectors, and ghosts)
References