Skip to content

Atomic expressions#

Code Example

Runnable Example in Jac and JacLib

"""Atomic expressions: Atomic expressions and literals (strings, numbers, bools, None, types)."""

enum NumEnum { aa = 67, y = 68 }

with entry {
    # Literals
    s = "string";
    b1 = True;
    b2 = False;
    n = None;

    # Integer formats
    dec = 42;
    binary = 0b1100;
    octal = 0o755;
    hexa = 0xFF;

    # Float formats
    flt = 3.14;
    sci = 1.5e10;

    # Ellipsis
    ellip = ...;

    # Parenthesized expressions
    result = (5 + 3) * 2;

    # Named references
    var = 100;

    # Builtin types as values
    type1 = str;
    type2 = int;

    # Collections
    tpl = (1, 2, 3);
    lst = [1, 2, 3];
    dct = {"k": "v"};
    st = {1, 2, 3};

    # Multistring
    multi = "Hello " "World";

    # F-string
    name = "Alice";
    fstr = f"Hello {name}";

    print(dec, binary, octal, hexa, flt, sci, multi, fstr, NumEnum.aa.value);
}
"""Atomic expressions: Atomic expressions and literals (strings, numbers, bools, None, types)."""

enum NumEnum { aa = 67, y = 68 }

with entry {
    # Literals
    s = "string";
    b1 = True;
    b2 = False;
    n = None;

    # Integer formats
    dec = 42;
    binary = 0b1100;
    octal = 0o755;
    hexa = 0xFF;

    # Float formats
    flt = 3.14;
    sci = 1.5e10;

    # Ellipsis
    ellip = ...;

    # Parenthesized expressions
    result = (5 + 3) * 2;

    # Named references
    var = 100;

    # Builtin types as values
    type1 = str;
    type2 = int;

    # Collections
    tpl = (1, 2, 3);
    lst = [1, 2, 3];
    dct = {"k": "v"};
    st = {1, 2, 3};

    # Multistring
    multi = "Hello " "World";

    # F-string
    name = "Alice";
    fstr = f"Hello {name}";

    print(dec, binary, octal, hexa, flt, sci, multi, fstr, NumEnum.aa.value);
}
"""Atom: Atomic expressions and literals (strings, numbers, bools, None, types)."""
from __future__ import annotations
from jaclang.runtimelib.builtin import *
from enum import Enum, auto
from jaclang import JacMachineInterface as _jl

@_jl.sem('', {'aa': '', 'y': ''})
class NumEnum(Enum):
    aa = 67
    y = 68
s = 'string'
b1 = True
b2 = False
n = None
dec = 42
binary = 12
octal = 493
hexa = 255
flt = 3.14
sci = 15000000000.0
ellip = ...
result = (5 + 3) * 2
var = 100
type1 = str
type2 = int
tpl = (1, 2, 3)
lst = [1, 2, 3]
dct = {'k': 'v'}
st = {1, 2, 3}
multi = 'Hello World'
name = 'Alice'
fstr = f'Hello {name}'
print(dec, binary, octal, hexa, flt, sci, multi, fstr, NumEnum.aa.value)
Jac Grammar Snippet
atom: named_ref
    | LPAREN (expression | yield_expr) RPAREN
    | atom_collection
    | atom_literal
    | type_ref

atom_literal: builtin_type
            | NULL
            | BOOL
            | multistring
            | ELLIPSIS
            | FLOAT
            | OCT
            | BIN
            | HEX
            | INT

type_ref: TYPE_OP (named_ref | builtin_type)

multistring: (fstring | STRING)+

fstring: FSTR_START fstr_parts FSTR_END
       | FSTR_SQ_START fstr_sq_parts FSTR_SQ_END
       | FSTR_TRIPLE_START fstr_triple_parts FSTR_TRIPLE_END
       | FSTR_SQ_TRIPLE_START fstr_sq_triple_parts FSTR_SQ_TRIPLE_END

fstr_parts: (FSTR_PIECE | FSTR_BESC | LBRACE expression RBRACE )*
fstr_sq_parts: (FSTR_SQ_PIECE | FSTR_BESC | LBRACE expression RBRACE )*
fstr_triple_parts: (FSTR_TRIPLE_PIECE | FSTR_BESC | LBRACE expression RBRACE )*
fstr_sq_triple_parts: (FSTR_SQ_TRIPLE_PIECE | FSTR_BESC | LBRACE expression RBRACE )*

Description

Atoms are the fundamental building blocks of expressions - the smallest, indivisible pieces of code that represent values directly.

String Literals

Line 7 shows a basic string literal: s = "string";. Strings are sequences of characters enclosed in double quotes.

Lines 42-43 demonstrate multistring concatenation. When you place string literals next to each other, Jac automatically concatenates them into a single string "Hello World". This is useful for splitting long strings across multiple lines in your code.

F-Strings (Formatted Strings)

Lines 45-46 introduce f-strings for embedding expressions within strings. The f prefix before the string makes it a formatted string literal. Expressions inside curly braces {} are evaluated and their values are inserted into the string. This creates "Hello Alice".

Boolean Literals

Lines 8-9 show the two boolean values. These represent truth values. Note they're capitalized - True and False are keywords.

None Literal

Line 10 introduces the None literal. None represents the absence of a value, similar to null in other languages. It's commonly used as a default value or to indicate "no result".

Integer Formats

Jac supports multiple ways to write integer literals:

Format Prefix Example Line Value Decimal Equivalent
Decimal none 13 42 42
Binary 0b 14 0b1100 12
Octal 0o 15 0o755 493
Hexadecimal 0x 16 0xFF 255

Line 13 shows standard decimal notation: dec = 42.

Line 14 uses binary prefix 0b: binary = 0b1100 equals 12 in decimal.

Line 15 uses octal prefix 0o: octal = 0o755 equals 493 in decimal (commonly used for Unix file permissions).

Line 16 uses hexadecimal prefix 0x: hexa = 0xFF equals 255 in decimal.

Float Formats

Lines 19-20 demonstrate floating-point number formats:

graph LR
    A[Float Literals] --> B[Standard: 3.14]
    A --> C[Scientific: 1.5e10]
    C --> D[Means 1.5 × 10^10]
  • Line 19: Standard decimal notation flt = 3.14
  • Line 20: Scientific notation sci = 1.5e10 represents 1.5 × 10^10 (15,000,000,000)

Ellipsis Literal

Line 23 shows the ellipsis literal. The ... (three dots) is a special literal used as a placeholder in various contexts, such as slice notation or to indicate "to be implemented".

Parenthesized Expressions

Line 26 demonstrates using parentheses to group expressions. Parentheses control evaluation order. Without them, this would be 5 + (3 * 2) = 11. With parentheses, it becomes (5 + 3) * 2 = 16.

Named References

Line 29 shows a simple variable reference. Once a variable has a value, you can use its name to reference that value in expressions.

Type Objects as Values

Lines 32-33 demonstrate that types themselves can be values. This assigns the type objects for strings and integers to variables. You can use these to create instances or check types at runtime.

Collection Literals

Lines 36-39 show the four main collection types:

Collection Syntax Line Characteristics
Tuple (1, 2, 3) 36 Immutable, ordered sequence
List [1, 2, 3] 37 Mutable, ordered sequence
Dictionary {"k": "v"} 38 Mutable key-value mapping
Set {1, 2, 3} 39 Mutable, unordered unique values

Tuples use parentheses and can't be changed after creation. Lists use square brackets and can be modified. Dictionaries use curly braces with key: value pairs. Sets use curly braces with just values (no duplicates allowed).

Enum Member Access

Line 48 demonstrates accessing an enum's value. The enum NumEnum defined at line 3 has members. You access a member with dot notation (NumEnum.aa), then get its numeric value with .value. According to line 3, aa = 67, so this prints 67.

Summary of Atomic Values

graph TD
    A[Atoms] --> B[Literals]
    A --> C[References]
    B --> D[Numbers: 42, 3.14, 0xFF]
    B --> E[Strings: 'text', f'Hello']
    B --> F[Booleans: True, False]
    B --> G[None]
    B --> H[Collections: lists, tuples, etc]
    C --> I[Variables: var]
    C --> J[Types: str, int]
    C --> K[Enum members: NumEnum.aa]

Atoms are the foundation of all expressions. You combine them with operators and function calls to build more complex computations, but every expression ultimately breaks down into these atomic pieces.