Luce
Luce BaseSourceLuciaOS

6. Expressions

6.1 Evaluation order#

Operands, arguments and elements evaluate left to right, once. and and or short-circuit. A conditional expression evaluates only the arm it picks.

6.2 Arithmetic#

OperatorOn intOn float
+ - *checked: overflow trapsIEEE
/a float quotient, as Python'sIEEE
//floor division; by zero trapsfloor division
%remainder with the divisor's sign, as Python's; by zero trapsIEEE remainder
**checked power with an int exponent that is not negativefloat power
unary -checkedIEEE
& | ^and, or, exclusive or of the two's complement bits, as Python's—
unary ~-x - 1, the bits inverted—
<<checked: a result past the range traps; a negative count traps—
>>arithmetic, flooring as Python's: -7 >> 1 is -4, a negative value ends at -1; a negative count traps—

int and float never mix in one operation: count * 1.5 is an error and is written float(count) * 1.5. The bit operators take ints alone, and each has its compound assignment (&=, |=, ^=, <<=, >>=). There is no wrapping or saturating form; a program that needs one calls a Base package.

6.3 Comparison and logic#

== != < <= > >= produce bool by §4.4 and do not chain. and, or, not take bool only: an int, a str or an optional is never a condition by itself. x in collection is membership: an element of a list or set, a key of a map, a substring of a str.

6.4 Conditional expression#

a if condition else b, with both arms of one type.

6.5 Conversions#

CallMeaning
int(f)truncates a float toward zero; traps on NaN or out of range
int(s), int(s, base)parses a str as Python's int does: white space around, a sign, digits of base (10 when not given, 2 to 36, letters either case) with single _ between them, and for bases 2, 8 and 16 an optional 0b, 0o, 0x prefix; int!, and a base outside 2 to 36 traps
float(i)the nearest float
float(s)parses a str as a decimal number, a sign, digits with an optional fraction and an optional exponent, spaces around them; float!
str(x)the display of any value with one (§10.5)
bool(x)only from str: "true" or "false", else fails

There is no cast. A conversion is a call, and one that can fail says so.

6.6 Members, calls, indexing, slicing#

value.field, value.method(args), Type.function(args), callable(args), list[i], map[key], list[a..<b], text[a..<b]. Indexing a list with an int out of range traps; reading map[key] yields V?; a slice of a list or a str is a copy (§11). Ranges a..<b and a..=b are values of type range that iterate ints. r.step(size) keeps every sizeth element, from the first the range walks, and traps on a size below one; r.reversed() walks the same elements from the last; so (0..<10).step(3) walks 0, 3, 6, 9 and (0..<10).step(3).reversed() 9, 6, 3, 0, Python's range(0, 10, 3) and its reversed. r.length, r.is_empty and r.contains(x), which is x in r, count and test the elements; a length past the largest int traps. A range displays as written, a step or a direction as the calls that made them, (0..<10).step(3), and two ranges are equal when their bounds, inclusion and step are.

6.7 Precedence#

From tightest: member, call, index; unary - and ~; **; * / // %; + -; << >>; &; ^; |; ..< ..=; in, is, is not, comparisons; not; and; or; if-else; =>; assignment. The bit operators sit where Python puts them, so flags & mask == 0 compares the masked bits and 1 << n - 1 shifts by n - 1. not sits below the comparisons so that not a == b negates the comparison, as in Python.

6.8 Standard modules#

import console
import math
from text import code_of

let longest = math.max(first.length, second.length)
let name = console.read_line("name? ") else "nobody"
let letter = code_of("A")

Four modules come with the language: math, text, console and time. They are imported by name like any module (§15.2), in the interpreter and in a built program alike: import math binds math, and math.abs(x) calls one of its functions; from math import abs binds the function by its name. Nothing of them is visible without an import, an import not used is an error, and their functions are called, never read as values. They declare no types: a module's functions are all it has.

ModuleFunctionMeaning
mathabs(x)the magnitude of an int, where the smallest traps, or of a float
mathmin(a, b), max(a, b)the lesser or greater of two values of one ordered type (§4.4); of two equal ones, the first
mathround(x: float, digits: int = 0) -> floatrounded to digits after the point, or before it when negative, half to even on the exact value, as Python's; a result past the largest float traps
textcode_of(s: str) -> intthe value of a text's one scalar; a text of any other length traps
textfrom_code(n: int) -> strthe text of the scalar n; a number that is no scalar (negative, a surrogate, past 0x10FFFF) traps
consoleread_line(prompt: str = "") -> str?writes the prompt, then reads a line of standard input without its \n and a \r before it; none at the end of the input, and always in a sandboxed run (§17.1)
timesleep(seconds)waits at least seconds, an int or a float, as Python's; a negative count or NaN traps
timenow() -> intnanoseconds from an arbitrary origin that never goes backwards, for measuring intervals
timeunix() -> intwhole seconds since the Unix epoch

math.round takes no int, since an int is whole already (§6.2); math.min and math.max take two values, and a list's own are its methods (§11.1). Arguments are positional, or named by the parameters shown, as for any call (§7.2).

The modules hold what a program needs that no type's method holds, and nothing more. Mathematics beyond them (roots, trigonometry, constants) is a library's: luce-std's math module, reached through its package (§15.5). Both live in one module under two names:

import math
from luce_std import math as fmath

let side = fmath.sqrt(math.abs(area))