Program Structure
The shape of a J2 source file: comments, statements, blocks, and the words the language reserves for itself.
A program is a script
A J2 program is a sequence of statements executed top to bottom. There is no
main function and no boilerplate; the file is the program.
greeting = "hello"
print(greeting)
Function and class definitions are statements like any other. Code at the top level can call a function defined earlier in the file, and functions may call functions defined later (mutual recursion works), but a top-level statement only sees bindings that were executed before it.
Comments
A comment starts with # and runs to the end of the line. There is no
block comment form.
# This whole line is a comment.
x = 1 # so is the rest of this one
print(x)
Statements and newlines
Newlines separate statements; there are no semicolons. Inside parentheses, square brackets, or a map literal, lines join implicitly, so long calls and literals can wrap freely:
values = [
10,
20,
30
]
print(sum(values))
Two statements may also share a line, separated by whitespace alone. This is idiomatic only for very small bodies:
x := 0
repeat x < 3 { print(x) x += 1 }
Blocks
Braces group statements into a block wherever a body is expected: after
if, around loop bodies, and as function bodies. A block used as a function
body produces the value of its last expression (see
Functions).
Identifiers
Names consist of letters, digits, and underscores, and cannot start with a digit.
Convention is snake_case for functions and bindings and
CapitalCase for classes. A leading underscore signals something internal by
convention; the language does not enforce visibility. The bare underscore
_ is special: it is the implicit element variable in filter predicates and
a throwaway name in loops, not a general-purpose binding.
Keywords
The following words are reserved and cannot be used as names:
| Keyword | Used for |
|---|---|
func | function definitions and lambdas |
give | returning a value from a function |
for in | iteration |
if else | conditionals, loop filters, and try handlers |
repeat do loop | condition-driven and infinite loops |
stop skip | leaving a loop, or one iteration of it |
until | bounding a for loop with a condition |
try | error handling |
assert | runtime checks |
class extends | class literals |
and or not | logical operators |
global | declaring a name at program scope; rarely needed, since top-level bindings are already visible to functions |
rust | the raw native escape hatch, disabled by default (see How J2 Runs) |
The literals true, false, and null and the
numeric constants PI, E, TAU, INF,
NAN, MAX_VAL, and MIN_VAL are also reserved; they
are covered in Values and Types.
Diagnostics
J2 reports problems in two shapes. Errors caught before the program runs come with the offending line and a caret:
error[SyntaxError]: unexpected token in expression: Colon
--> report.j2:14:9
|
14 | m = {"a": 1}
| ^
Errors raised while the program runs print the error class, a message, and the line,
and end the program with a nonzero exit status unless a try handles them
(see Error Handling):
ZeroDivisionError: division by zero (at line 3)