Skip to content

Jac Language Reference

Introduction

Welcome to the official reference guide for the Jac programming language. This document is designed to serve as a comprehensive reference manual as well as a formal specification of the language. The mission of this guide is to be a resource for developers seeking to answer the question, "How do I code X in Jac?"

This document is organized around the formal grammar for the language code examples and corresponding grammar snippets being directly generated from the actual grammar and test cases maintained in the official repository. We expect the descriptions may occasionally lag behind the rapid evolution of Jac in the early days. If you notice something, make a pull request and join our contributor community.

Base Module structure

Code Example

"""A Docstring can be added the head of any module.

Any element in the module can also have a docstring.
If there is only one docstring before the first element,
it is assumed to be a module docstring.
"""

"""A docstring for add function"""
can add(a: int, b: int) -> int {
    return a + b;
}
# No docstring for subtract function

can subtract(a: int, b: int) -> int {
    return a - b;
}

with entry:__main__ {
    print(add(1, subtract(3, 1)));
}
"""A Docstring can be added the head of any module.

Any element in the module can also have a docstring.
If there is only one docstring before the first element,
it is assumed to be a module docstring.
"""

"""A docstring for add function"""


def add(a: int, b: int) -> int:
    return a + b


def subtract(a: int, b: int) -> int:
    return a - b


if __name__ == "__main__":
    print(add(1, subtract(3, 1)))
Jac Grammar Snippet
start: module

module: (doc_tag? element (element_with_doc | element)*)?
      | doc_tag (element_with_doc (element_with_doc | element)*)?

doc_tag: STRING | DOC_STRING
element_with_doc: doc_tag element

element: import_stmt
       | architype
       | ability
       | global_var
       | free_code
       | py_code_block
       | test

Description

In Jac, a module is analogous to a Python module, serving as a container for various elements such as functions, classes (referred to as "architypes" later in this document), global variables, and other constructs that facilitate code organization and reusability. Each module begins with an optional module-level docstring, which provides a high-level overview of the module's purpose and functionality. This docstring, if present, is positioned at the very start of the module, before any other elements.

Docstrings

Jac adopts a stricter approach to docstring usage compared to Python. It mandates the inclusion of a single docstring at the module level and permits individual docstrings for each element within the module. This ensures that both the module itself and its constituent elements are adequately documented. If only one docstring precedes the first element, it is automatically designated as the module-level docstring.

Also Note, that Jac enforces type annotations in function signatures and class fields to promote type safety and ultimately more readable and scalable codebases.

Elements within a Jac module encompass familiar constructs from Python, including functions and classes, with the addition of some unique elements that will be discussed in further detail. Below is a table of module elements in Jac. These constructs are described in detail later in this document.

Module Item Description
Import Statements Same as python with slightly different syntax, works with both .jac and .py files (in addition to packages)
Architypes Includes traditional python class construct with equiviant semantics, and additionaly introduces a number of new class-like constructs including obj, node, edge, and walker to enable the data spatial programming paradigmn
Function Abilities Equivalent to traditional python function semantics with change of keyword def to can. Type hints are required in parameters and returns
Data Spatial Abilities A function like construct that is triggered by types of nodes or walkers in the data spatial paradigm
Free Floating Code Construct (with entry {...}) to express presence of free floating code within a module that is not part of a function or class-like object. Primarily for code cleanliness, readability, and maintainability.
Global Variables Module level construct to express global module level variables without using with entry syntax. (glob x=5 is equivalent to with entry {x=5;})
Test A language level construct for testing, functionality realized with test and check keywords.
Inline Python Native python code can be inlined alongside jac code at arbitrary locations in a Jac program using ::py:: directive

Moreover, Jac requires that any standalone, module-level code be encapsulated within a with entry {} block. This design choice aims to enhance the clarity and cleanliness of Jac codebase.

Import/Include Statements

Code Example

import:py os;
import:py datetime as dt;
import from math { sqrt as square_root, log }
import:jac from base_module_structure { add }
import from base_module_structure { subtract }
include global_variables;

with entry {
    for i in range(int(square_root(dt.datetime.now().year))) {
        print(
            os.getcwd(),
            add(i, subtract(i, 1)),
            int(log(i + 1))
        );
    }
}
from jaclang import jac_import as __jac_import__
import os
import datetime as dt
from math import sqrt as square_root, log

(add, subtract) = __jac_import__(
    target="base_module_structure",
    base_path=__file__,
    items={"add": None, "subtract": None},
)

for i in range(int(square_root(dt.datetime.now().year))):
    print(os.getcwd(), add(i, subtract(i, 1)), int(log(i + 1)))
Jac Grammar Snippet
import_stmt: KW_IMPORT sub_name? KW_FROM from_path LBRACE import_items RBRACE
           | KW_IMPORT sub_name? KW_FROM from_path COMMA import_items SEMI  //Deprecated
           | KW_IMPORT sub_name? import_path (COMMA import_path)* SEMI
           | include_stmt

from_path: (DOT | ELLIPSIS)* import_path
         | (DOT | ELLIPSIS)+

import_path: named_ref (DOT named_ref)* (KW_AS NAME)?
import_items: (import_item COMMA)* import_item COMMA?
import_item: named_ref (KW_AS NAME)?
sub_name: COLON NAME
include_stmt: KW_INCLUDE sub_name? import_path SEMI

Description

Jac's import and include statements provides a propoer superset of python's import semantics with some improvements for imports of Jac modules. That being said, its important to note an important syntax difference in that from X import Y is reworked into import from X, Y (import X remains in the style of import X in Jac). Also there is a :py or :jac after the import statment to signify which type of import to consider.

  • Python Imports: Utilize import:py to seamlessly import Python libraries, allowing full access to Python's ecosystem within Jac programs, with the same semantics as python.
  • Jac Imports: Use import:jac for importing Jac-specific modules from .jac files with the same symantics as python files with and additional functionality for Jac's impl separation (described later), and static analysis features.

Architypes

Code Example

can print_base_classes(cls: type) -> type {
    print(f"Base classes of {cls.__name__}: {[c.__name__  for c in cls.__bases__]}");
    return cls;
}

class Animal {}

obj Domesticated {}

@print_base_classes
node Pet :Animal, Domesticated: {}

walker Person :Animal: {}

walker Feeder :Person: {}

@print_base_classes
walker Zoologist :Feeder: {}
from jaclang.plugin.feature import JacFeature as jac


def print_base_classes(cls: type) -> type:
    print(f"Base classes of {cls.__name__}: {[c.__name__ for c in cls.__bases__]}")
    return cls


@jac.make_obj(on_entry=[], on_exit=[])
class Animal:
    pass


@jac.make_obj(on_entry=[], on_exit=[])
class Domesticated(jac.Obj):
    pass


@print_base_classes
@jac.make_node(on_entry=[], on_exit=[])
class Pet(Animal, Domesticated, jac.Node):
    pass


@jac.make_walker(on_entry=[], on_exit=[])
class Person(Animal, jac.Walker):
    pass


@jac.make_walker(on_entry=[], on_exit=[])
class Feeder(Person, jac.Walker):
    pass


@print_base_classes
@jac.make_walker(on_entry=[], on_exit=[])
class Zoologist(Feeder, jac.Walker):
    pass
Jac Grammar Snippet
architype: decorators? architype_decl
         | architype_def
         | enum

architype_decl: arch_type access_tag? STRING? NAME inherited_archs? (member_block | SEMI)
architype_def: abil_to_arch_chain member_block
decorators: (DECOR_OP atomic_chain)+
access_tag: COLON ( KW_PROT | KW_PUB | KW_PRIV )

inherited_archs: LT (atomic_chain COMMA)* atomic_chain GT
               | COLON (atomic_chain COMMA)* atomic_chain COLON

arch_type: KW_WALKER
          | KW_OBJECT
          | KW_EDGE
          | KW_NODE
          | KW_CLASS

Description

The provided Jac code snippet demonstrates the use of archetypes (a key concept in Jac programming), which supersets traditional classes in object-oriented programming. In Jac, archetypes can be defined using different keywords to signify their roles and characteristics within the program. These include obj, node, walker, edge, and class, each serving distinct purposes in the design of a Jac application.

Defining Archetypes

  • Object (obj): This keyword is used to define a basic archetype. In the example, Animal and Domesticated are simple archetypes with no inherited or additional members.

  • Node (node): Defines an archetype that can be part of a graph object structure. Pet is declared as a node and inherits features from Animal and Domesticated, demonstrating multiple inheritance.

  • Walker (walker): This keyword is used to define archetypes that perform actions or traverse nodes and edges within a graph. Person, Feeder, and Zoologist are examples of walkers, with Zoologist also including the use of a decorator.

Inheritance

The example illustrates how archetypes can inherit from one or more other archetypes, using the syntax :ParentArchetype:. For instance, Feeder inherits from Person, which in turn inherits from Pet, indicating a chain of inheritance.

Decorators

Decorators in Jac, denoted by @, are used to modify or enhance the behavior of archetypes without altering their code directly. The @print_base_classes decorator is applied to Pet and Zoologist to print their base classes at runtime, demonstrating a practical use of decorators for introspection or debugging purposes.

Architype bodies

Code Example

obj Car {
    has make: str,
        model: str,
        year: int;
    static has wheels: int = 4;

    can display_car_info {
        print(f"Car Info: {self.year} {self.make} {self.model}");
    }

    static can get_wheels {
        return Car.wheels;
    }
}

with entry {
    car = Car("Toyota", "Camry", 2020);
    car.display_car_info();
    print("Number of wheels:", Car.get_wheels());
}
class Car:
    wheels: int = 4

    def __init__(self, make: str, model: str, year: int):
        self.make = make
        self.model = model
        self.year = year

    def display_car_info(self):
        print(f"Car Info: {self.year} {self.make} {self.model}")

    @staticmethod
    def get_wheels():
        return Car.wheels


car1 = Car("Toyota", "Camry", 2020)
car1.display_car_info()
print("Number of wheels:", Car.get_wheels())
Jac Grammar Snippet
member_block: LBRACE member_stmt* RBRACE
member_stmt: doc_tag? (py_code_block | abstract_ability | ability | architype | has_stmt | free_code)
has_stmt: KW_STATIC? (KW_LET | KW_HAS) access_tag? has_assign_list SEMI
has_assign_list: (has_assign_list COMMA)? typed_has_clause
typed_has_clause: named_ref (COLON STRING)? type_tag (EQ expression | KW_BY KW_POST_INIT)?
type_tag: COLON expression

Description

In Jac, an architype functions similarly to classes in traditional object-oriented programming languages. It allows the definition of data structures with both state and behavior encapsulated within. The provided Jac code snippet demonstrates the definition and usage of an architype named Car.

The Car architype includes three instance variables (make, model, and year) and one class variable (wheels). Instance variables are defined using the has keyword and can have specific types (str for strings and int for integers). The static keyword precedes the class variable definition, indicating that wheels is shared across all instances of Car.

Types are annotated directly after the variable name (required for all has variables) and are followed by a colon. For instance, make: str declares a variable make of type string.

The Car architype also defines two methods, display_car_info as an instance method and get_wheels as a static method. Methods are introduced with the can keyword. The instance method display_car_info uses a formatted string to print car information, accessing instance variables with the self reference. The static method get_wheels returns the value of the static variable wheels.

An instance of Car is created using the architype name as a constructor, passing in values for make, model, and year. This instance is assigned to the variable car.

Instance methods are invoked using the dot notation on the instance (car.display_car_info()), and static methods are called directly on the architype (Car.get_wheels()).

The entry block serves as the entry point of the program, where a Car instance is created, and its methods are invoked to display the car's information and the number of wheels.

Enumerations

Code Example

import from enum { unique }

@unique
enum Color;

:enum:Color {
    RED = 1,
    GREEN = 2
}

enum :protect Role {
    ADMIN = 'admin',
    USER = 'user',
    with entry {
        print('Initializing role system..');
    },
    can foo -> str {
        return 'Accessing privileged Data';
    }
}
with entry {
    print(Color.RED.value, Role.foo());
}
from enum import Enum, auto, unique


@unique
class Color(Enum):
    RED = 1
    pencil = auto()


class Role(Enum):
    ADMIN = ("admin",)
    USER = "user"

    print("Initializing role system..")

    def foo():
        return "Accessing privileged Data"


print(Color.RED.value, Role.foo())
Jac Grammar Snippet
enum: decorators? enum_decl
     | enum_def

enum_decl: KW_ENUM access_tag? STRING? NAME inherited_archs? (enum_block | SEMI)
enum_def: arch_to_enum_chain enum_block
enum_block: LBRACE ((enum_stmt COMMA)* enum_stmt COMMA?)? RBRACE

enum_stmt: NAME (COLON STRING)? EQ expression
         | NAME (COLON STRING)?
         | py_code_block
         | free_code
         | abstract_ability
         | ability

Description

Jac has enumerations directly in the language. The enum Color defines an enumeration called Color, which includes two members: RED assigned the value 1 and pencil which implicitly takes the next integer value, 2 (effectively the same as a typical pencil = auto() in Python's enum).

The entry point of the program is defined with with entry, which serves as the main function or starting point for execution. Inside this block, the code prints the value of the RED enumeration member using print(Color.RED.value);. Since RED is assigned the value 1, this statement will output 1 to the console when the program runs.

Abilities

Code Example

obj Divider {
    can divide(x: float, y: float) -> float {
        return (x / y);
    }
}
#this is an abstract class as it has the abstract method

obj Calculator {
    static can : priv multiply(a: float, b: float) -> float {
        return a * b;
    }
    can substract -> float abs;
    can add(number: float, *a: tuple) -> float;
}

obj substractor :Calculator: {
    can substract(x: float, y: float) -> float {
        return (x - y);
    }
}

:obj:Calculator:can:add
(number: float, *a: tuple) -> float {
    return (number * sum(a));
}

with entry {
    div = Divider();
    sub = substractor();
    print(div.divide(55, 11));
    print(Calculator.multiply(9, -2));
    print(sub.add(5, 20, 34, 56));
    print(sub.substract(9, -2));
}
from abc import ABC, abstractmethod


class Calculator(ABC):
    @staticmethod
    def multiply(a: float, b: float) -> float:
        return a * b

    @abstractmethod
    def substract(self, x: float, y: float) -> float:
        pass

    def add(self, number: float, *a: tuple) -> str:
        return str(number * sum(a))


class Substractor(Calculator):
    def substract(self, x: float, y: float) -> float:
        return x - y


class Divider:
    def divide(self, x: float, y: float):
        return x / y


sub = Substractor()
div = Divider()
print(div.divide(55, 11))
print(Calculator.multiply(9, -2))
print(sub.add(5, 20, 34, 56))
print(sub.substract(9, -2))
Jac Grammar Snippet
ability: decorators? KW_ASYNC? ability_decl
        | decorators? genai_ability
        | ability_def

ability_decl: KW_OVERRIDE? KW_STATIC? KW_CAN access_tag? STRING? named_ref (func_decl | event_clause) (code_block | SEMI)
ability_def: arch_to_abil_chain (func_decl | event_clause) code_block
abstract_ability: KW_OVERRIDE? KW_STATIC? KW_CAN access_tag? STRING? named_ref (func_decl | event_clause) KW_ABSTRACT SEMI
genai_ability: KW_OVERRIDE? KW_STATIC? KW_CAN access_tag? STRING? named_ref (func_decl) KW_BY atomic_call SEMI
event_clause: KW_WITH expression? (KW_EXIT | KW_ENTRY) (STRING? RETURN_HINT expression)?
func_decl: (LPAREN func_decl_params? RPAREN)? (RETURN_HINT (STRING COLON)? expression)?
func_decl_params: (param_var COMMA)* param_var COMMA?
param_var: (STAR_POW | STAR_MUL)? NAME (COLON STRING)? type_tag (EQ expression)?

Description

Global variables

Code Example

let:priv a = 5;

glob:pub X = 10;

glob:protect y = 15;

glob z = 20;

obj:priv Myobj{}

with entry:__main__ {
    print(a, X, y, z);
}
1
2
3
4
5
6
7
global a, X, y, z
a = 5
X = 10
y = 15
z = 20

print(a, X, y, z)
Jac Grammar Snippet
global_var: (KW_LET | KW_GLOBAL) access_tag? assignment_list SEMI
assignment_list: (assignment_list COMMA)? assignment

Description

Free code

Code Example

import:py math;

obj circle {
    can init(radius: float) {
        self.radius = radius;
    }

    can area -> float {
        return math.pi * self.radius * self.radius;
    }
}

can foo(n_1: float) {
    return n_1 ** 2;
}

with entry {
    print("Hello World!");
    print(foo(7));
    print(int(circle(10).area()));

    #code block
}
import math


class Circle:
    def __init__(self, radius: float):
        self.radius = radius

    def area(self):
        return math.pi * self.radius * self.radius


def foo(n_1: float):
    return n_1**2


print("Hello World!")
print(foo(7))
print(int(Circle(10).area()))
Jac Grammar Snippet
free_code: KW_WITH KW_ENTRY sub_name? code_block

Description

Inline python

Code Example

with entry {
    print("hello ");
}

::py::
def foo():
    print("world")

foo()
::py::
1
2
3
4
5
6
7
8
print("hello ")


def foo():
    print("world")


foo()
Jac Grammar Snippet
py_code_block: PYNLINE

Description

Tests

Code Example

test test1 {
    check almostEqual(4.99999, 4.99999);
}

test test2 {
    check 5 == 5;
}

test test3 {
    check "e" in "qwerty";
}

with entry:__main__ {
    import:py subprocess;
    result = subprocess.run(
        ["jac", "test", f"{__file__}"],
        stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True
    );
    print(result.stderr);
}
import unittest


class TestCases(unittest.TestCase):
    def test_test1(self):
        self.assertAlmostEqual(4.99999, 4.99999)

    def test_test2(self):
        self.assertEqual(5, 5)

    def test_test3(self):
        self.assertIn("e", "qwerty")


if __name__ == "__main__":
    unittest.main()
Jac Grammar Snippet
test: KW_TEST NAME? code_block

Description

Implementations

Code Example

can foo();

obj vehicle;

enum Size; #implementations

:can:foo() {
    return ("Hello");
}

:obj:vehicle  {
    has name: str = "Car";
}

:enum:Size {
    Small=1,
    Medium=2,
    Large=3
}

with entry {
    car = vehicle();
    print(foo());
    print(car.name);
    print(Size.Medium.value);
}
from enum import Enum


def foo() -> None:
    return "Hello"


class vehicle:
    def __init__(self) -> None:
        self.name = "Car"


class Size(Enum):
    Small = 1
    Medium = 2
    Large = 3


car = vehicle()
print(foo())
print(car.name)
print(Size.Medium.value)
Jac Grammar Snippet
arch_or_ability_chain: arch_or_ability_chain? (ability_ref | arch_ref)
abil_to_arch_chain: arch_or_ability_chain? arch_ref
arch_to_abil_chain: arch_or_ability_chain? ability_ref
arch_to_enum_chain: arch_or_ability_chain? enum_ref

arch_ref: class_ref
        | object_ref
        | walker_ref
        | edge_ref
        | node_ref

node_ref: NODE_OP named_ref
edge_ref: EDGE_OP named_ref
walker_ref: WALKER_OP named_ref
class_ref: CLASS_OP named_ref
object_ref: OBJECT_OP named_ref
enum_ref: ENUM_OP named_ref
ability_ref: ABILITY_OP named_ref

Description

Codeblocks and Statements

Code Example

1
2
3
4
5
6
7
with entry {
    print("Welcome to the world of Jaseci!");
    can add(x: int, y: int) -> int {
        return (x + y);
    }
    print(add(10, 89));
}
1
2
3
4
5
6
7
8
print("Welcome to the world of Jaseci!")


def add(x: int, y: int) -> int:
    return x + y


print(add(10, 89))
Jac Grammar Snippet
code_block: LBRACE statement* RBRACE

statement: import_stmt
       | ability
       | architype
       | if_stmt
       | while_stmt
       | for_stmt
       | try_stmt
       | match_stmt
       | with_stmt
       | global_ref SEMI
       | nonlocal_ref SEMI
       | typed_ctx_block
       | return_stmt SEMI
       | (yield_expr | KW_YIELD) SEMI
       | raise_stmt SEMI
       | assert_stmt SEMI
       | check_stmt SEMI
       | assignment SEMI
       | delete_stmt SEMI
       | report_stmt SEMI
       | expression SEMI
       | ctrl_stmt SEMI
       | py_code_block
       | walker_stmt
       | SEMI

Description

If statements

Code Example

with entry {
    x = 15;
    if 0 <= x<= 5 {
        print("Not Bad");
    } elif 6 <= x<= 10 {
        print("Average");
    } else {
        print("Good Enough");
    }
}
1
2
3
4
5
6
7
x = 15
if 0 <= x <= 5:
    print("Not Bad")
elif 6 <= x <= 10:
    print("Average")
else:
    print("Good Enough")
Jac Grammar Snippet
if_stmt: KW_IF expression code_block (elif_stmt | else_stmt)?
elif_stmt: KW_ELIF expression code_block (elif_stmt | else_stmt)?
else_stmt: KW_ELSE code_block

Description

While statements

Code Example

1
2
3
4
5
6
7
with entry {
    i = 1;
    while i < 6 {
        print(i);
        i+=1;
    }
}
1
2
3
4
i = 1
while i < 6:
    print(i)
    i += 1
Jac Grammar Snippet
while_stmt: KW_WHILE expression code_block

Description

For statements

Code Example

1
2
3
4
5
6
7
8
9
with entry {
    for i in "ban" {
        for j in range(1, 3) {
            for k=1 to k<3 by k+=1  {
                print(i, j, k);
            }
        }
    }
}
1
2
3
4
for i in "ban":
    for j in range(1, 3):
        for k in range(1, 3, 1):
            print(i, j, k)
Jac Grammar Snippet
for_stmt: KW_ASYNC? KW_FOR assignment KW_TO expression KW_BY assignment code_block else_stmt?
       | KW_ASYNC? KW_FOR atomic_chain KW_IN expression code_block else_stmt?

Description

Try statements

Code Example

1
2
3
4
5
6
7
with entry {
    try  {
        print("Result", 5 / 0);
    } except Exception as e  {
        print(e);
    }
}
1
2
3
4
try:
    print("Result", 5 / 0)
except Exception as e:
    print(e)
Jac Grammar Snippet
try_stmt: KW_TRY code_block except_list? else_stmt? finally_stmt?
except_list: except_def+
except_def: KW_EXCEPT expression (KW_AS NAME)? code_block
finally_stmt: KW_FINALLY code_block

Description

Match statements

Code Example

1
2
3
4
5
6
7
8
9
with entry {
    a = 8;
    match a {
        case 7:
            print("doable");
        case _:
            print("Undoable");
    }
}
1
2
3
4
5
6
a = 8
match a:
    case 7:
        print("Doable")
    case _:
        print("Undoable")
Jac Grammar Snippet
match_stmt: KW_MATCH expression LBRACE match_case_block+ RBRACE
match_case_block: KW_CASE pattern_seq (KW_IF expression)? COLON statement+

Description

Match patterns

Code Example

obj Point {
    has x: float,
        y: float;
}

can match_example(data: any) {
    match data {

        # MatchValue
        case 42:
            print("Matched the value 42.");

            # MatchSingleton
        case True:
            print("Matched the singleton True.");
        case None:
            print("Matched the singleton None.");

            # MatchSequence
        case [1, 2, 3]:
            print("Matched a specific sequence [1, 2, 3].");

            # MatchStar
        case [1, *rest, 3]:
            print(f"Matched a sequence starting with 1 and ending with 3. Middle: {rest}");

            # MatchMapping
        case {"key1" : 1, "key2" : 2, **rest}:
            print(f"Matched a mapping with key1 and key2. Rest: {rest}");

            # MatchClass
        case Point(int(a), y = 0):
            print(f"Point with x={a} and y=0");

            # MatchAs
        case [1, 2, rest_val as value]:
            print(f"Matched a sequence and captured the last value: {value}");

            # MatchOr
        case [1, 2] | [3, 4]:
            print("Matched either the sequence [1, 2] or [3, 4].");
        case _:
            print("No match found.");
    }
}

with entry {
    match_example(Point(x=9, y=0));
}
class Point:
    def __init__(self, x: float, y: float):
        self.x = x
        self.y = y


def match_example(data: any):
    match data:
        # MatchValue
        case 42:
            print("Matched the value 42.")

        # MatchSingleton
        case True:
            print("Matched the singleton True.")
        case None:
            print("Matched the singleton None.")

        # MatchSequence
        case [1, 2, 3]:
            print("Matched a specific sequence [1, 2, 3].")

        # MatchStar
        case [1, *rest, 3]:
            print(
                f"Matched a sequence starting with 1 and ending with 3. Middle: {rest}"
            )

        # MatchMapping
        case {"key1": 1, "key2": 2, **rest}:
            print(f"Matched a mapping with key1 and key2. Rest: {rest}")

        # MatchClass
        case Point(x=int(a), y=0):
            print(f"Point with x={a} and y=0")

        # MatchAs
        case [1, 2, rest_val as value]:
            print(f"Matched a sequence and captured the last value: {value}")

        # MatchOr
        case [1, 2] | [3, 4]:
            print("Matched either the sequence [1, 2] or [3, 4].")

        case _:
            print("No match found.")


match_example(Point(x=9, y=0))
Jac Grammar Snippet
pattern_seq: (or_pattern | as_pattern)
or_pattern: (pattern BW_OR)* pattern
as_pattern: or_pattern KW_AS NAME

pattern: literal_pattern
    | singleton_pattern
    | capture_pattern
    | sequence_pattern
    | mapping_pattern
    | class_pattern

Description

Match litteral patterns

Code Example

1
2
3
4
5
6
7
8
9
with entry {
    num = 89;
    match num {
        case 89:
            print("Correct");
        case 8:
            print("Nope");
    }
}
1
2
3
4
5
6
num = 89
match num:
    case 89:
        print("Correct")
    case 8:
        print("Nope")
Jac Grammar Snippet
literal_pattern: (INT | FLOAT | multistring)

Description

Match singleton patterns

Code Example

with entry {
    data = True;
    match True {

        # MatchSingleton
        case True:
            print("Matched the singleton True.");
        case None:
            print("Matched the singleton None.");
    }
}
1
2
3
4
5
6
7
data = True
match True:
    # MatchSingleton
    case True:
        print("Matched the singleton True.")
    case None:
        print("Matched the singleton None.")
Jac Grammar Snippet
singleton_pattern: (NULL | BOOL)

Description

Match capture patterns

Code Example

1
2
3
4
5
6
7
8
9
with entry {
    day = " sunday";
    match day {
        case "monday":
            print("confirmed");
        case _:
            print("other");
    }
}
1
2
3
4
5
6
day = " sunday"
match day:
    case "monday":
        print("confirmed")
    case _:
        print("other")
Jac Grammar Snippet
capture_pattern: NAME

Description

Match sequence patterns

Code Example

1
2
3
4
5
6
7
8
9
with entry {
    data = [1, 2, 3];
    match data {
        case [1, 2, 3]:
            print("Matched");
        case _:
            print("Not Found");
    }
}
1
2
3
4
5
6
data = [1, 2, 3]
match data:
    case [1, 2, 3]:
        print("Matched")
    case _:
        print("Not Found")
Jac Grammar Snippet
sequence_pattern: LSQUARE list_inner_pattern (COMMA list_inner_pattern)* RSQUARE
                | LPAREN list_inner_pattern (COMMA list_inner_pattern)* RPAREN

Description

Match mapping patterns

Code Example

1
2
3
4
5
6
7
with entry {
    data = {"key1":1, "key2":2, "232":3453 };
    match data {
        case {"key1" : 1, "key2" : 2, **rest}:
            print(f"Matched a mapping with key1 and key2. Rest: {rest}");
    }
}
1
2
3
4
5
data = {"key1": 1, "key2": 2, "232": 3453}

match data:
    case {"key1": 1, "key2": 2, **rest}:
        print(f"Matched a mapping with key1 and key2. Rest: {rest}")
Jac Grammar Snippet
mapping_pattern: LBRACE (dict_inner_pattern (COMMA dict_inner_pattern)*)? RBRACE
list_inner_pattern: (pattern_seq | STAR_MUL NAME)
dict_inner_pattern: (literal_pattern COLON pattern_seq | STAR_POW NAME)

Description

Match class patterns

Code Example

obj Point {
    has x: float,
        y: float;
}

with entry {
    data = Point(x=9, y=0);
    match data {
        case Point(int(a), y = 0):
            print(f"Point with x={a} and y=0");
        case _:
            print("Not on the x-axis");
    }
}
from __future__ import annotations
from jaclang.plugin.feature import JacFeature as Jac
from dataclasses import dataclass as dataclass


@Jac.make_obj(on_entry=[], on_exit=[])
@dataclass(eq=False)
class Point:
    x: float
    y: float


data = Point(x=9, y=0)
match data:
    case Point(int(a), y=0):
        print(f"Point with x={a} and y=0")
    case _:
        print("Not on the x-axis")
Jac Grammar Snippet
class_pattern: NAME (DOT NAME)* LPAREN kw_pattern_list? RPAREN
             | NAME (DOT NAME)* LPAREN pattern_list (COMMA kw_pattern_list)? RPAREN

pattern_list: (pattern_list COMMA)? pattern_seq
kw_pattern_list: (kw_pattern_list COMMA)? named_ref EQ pattern_seq

Description

Context managers

Code Example

1
2
3
4
5
with entry {
    with open(__file__, 'r') as file {
        print(file.read());
    }
}
with open(__file__.replace(".py", ".jac"), "r") as file:
    print(file.read())
Jac Grammar Snippet
with_stmt: KW_ASYNC? KW_WITH expr_as_list code_block
expr_as_list: (expr_as COMMA)* expr_as
expr_as: expression (KW_AS expression)?

Description

Global and nonlocal statements

Code Example

glob x = "Jaclang ";

can foo() -> None {
    :g: x ;

    x = 'Jaclang is ';
    y = 'Awesome';
    can foo2() -> tuple[str, str] {
        :nl: y ;

        y = "Fantastic";
        return (x, y);
    }
    print(x, y);
    print(foo2());
}

with entry {
    foo();
}
from __future__ import annotations

x = "Jaclang "


def foo() -> None:
    global x
    x = "Jaclang is "
    y = "Awesome"

    def foo2() -> tuple[str, str]:
        nonlocal y
        y = "Fantastic"
        return (x, y)

    print(x, y)
    print(foo2())


foo()
Jac Grammar Snippet
global_ref: GLOBAL_OP name_list
nonlocal_ref: NONLOCAL_OP name_list
name_list: (named_ref COMMA)* named_ref

Description

Data spatial typed context blocks

Code Example

walker Producer {
    can produce with `root entry;
}

node Product {
    has number: int;

    can make with Producer entry;
}

:walker:Producer:can:produce {
    end = here;
    for i=0 to i<=2 by i+=1  {
        end ++> (end := Product(number=i + 1));
    }
    visit [-->];
}

:node:Product:can:make -> str {
    print(f"Hi, I am {self} returning a String");
    visit [-->];
}

with entry {
    root spawn Producer();
}
from __future__ import annotations
from jaclang.plugin.feature import JacFeature as Jac
from jaclang.plugin.builtin import *
from dataclasses import dataclass


@Jac.make_walker(on_entry=[Jac.DSFunc("produce")], on_exit=[])
@dataclass(eq=False)
class Producer(Jac.Walker):

    def produce(self, _jac_here_: Jac.RootType) -> None:
        end = _jac_here_
        i = 0
        while i <= 2:
            Jac.connect(
                left=end,
                right=(end := Product(number=i + 1)),
                edge_spec=Jac.build_edge(
                    is_undirected=False, conn_type=None, conn_assign=None
                ),
            )
            i += 1
        if Jac.visit_node(
            self,
            Jac.edge_ref(
                _jac_here_,
                target_obj=None,
                dir=Jac.EdgeDir.OUT,
                filter_func=None,
                edges_only=False,
            ),
        ):
            pass


@Jac.make_node(on_entry=[Jac.DSFunc("make")], on_exit=[])
@dataclass(eq=False)
class Product(Jac.Node):
    number: int

    def make(self, _jac_here_: Producer) -> None:
        print(f"Hi, I am {self} returning a String")
        if Jac.visit_node(
            _jac_here_,
            Jac.edge_ref(
                self,
                target_obj=None,
                dir=Jac.EdgeDir.OUT,
                filter_func=None,
                edges_only=False,
            ),
        ):
            pass


Jac.spawn_call(Jac.get_root(), Producer())
Jac Grammar Snippet
typed_ctx_block: RETURN_HINT expression code_block

Description

Return statements

Code Example

1
2
3
4
5
6
7
8
can foo() {
    a = 42;
    return a;
}

with entry {
    print("Returned:", foo());
}
1
2
3
4
5
6
def foo():
    a = 42
    return a


print("Returned:", foo())
Jac Grammar Snippet
return_stmt: KW_RETURN expression?

Description

Yield statements

Code Example

can myFunc() {
    yield "Hello";
    yield 91;
    yield "Good Bye";
    yield ;
}

with entry {
    x = myFunc();
    for z in x {
        print(z);
    }
}
def myFunc() -> None:
    yield "Hello"
    yield 91
    yield "Good Bye"
    yield


x = myFunc()

for z in x:
    print(z)
Jac Grammar Snippet
yield_expr: KW_YIELD KW_FROM? expression

Description

Raise statements

Code Example

can foo(value: int) {
    if value < 0 {
        raise ValueError("Value must be non-negative");
    }
}

with entry {
    try  {
        foo(-1);
    } except ValueError as e  {
        print("Raised:", e);
    }
}
1
2
3
4
5
6
7
8
9
def foo(value: int):
    if value < 0:
        raise ValueError("Value must be non-negative")


try:
    foo(-1)
except ValueError as e:
    print("Raised:", e)
Jac Grammar Snippet
raise_stmt: KW_RAISE (expression (KW_FROM expression)?)?

Description

Assert statements

Code Example

can foo(value: int) {
    assert value > 0 , "Value must be positive";
}

with entry {
    try  {
        foo(-5);
    } except AssertionError as e  {
        print("Asserted:", e);
    }
}
1
2
3
4
5
6
7
8
def foo(value: int):
    assert value > 0, "Value must be positive"


try:
    foo(-5)
except AssertionError as e:
    print("Asserted:", e)
Jac Grammar Snippet
assert_stmt: KW_ASSERT expression (COMMA expression)?

Description

Check statements

Code Example

glob a = 5, b = 2;

test test1 {
    check almostEqual(a, 6);
}

test test2 {
    check a != b;
}

test test3 {
    check "d" in "abc";
}

test test4 {
    check a - b == 3;
}
from __future__ import annotations
from jaclang.plugin.feature import JacFeature as _Jac

a = 5
b = 2


@_Jac.create_test
def test_test1(check) -> None:
    check.assertAlmostEqual(a, 6)


@_Jac.create_test
def test_test2(check) -> None:
    check.assertTrue(a != b)


@_Jac.create_test
def test_test3(check) -> None:
    check.assertIn("d", "abc")


@_Jac.create_test
def test_test4(check) -> None:
    check.assertEqual(a - b, 3)
Jac Grammar Snippet
check_stmt: KW_CHECK expression

Description

Delete statements

Code Example

1
2
3
4
5
6
with entry {
    x = [2, 4, 5, 7, 9];
    print("Before Delete:", x);
    del x[3];
    print("After Delete:", x);
}
1
2
3
4
x = [2, 4, 5, 7, 9]
print("Before Delete:", x)
del x[3]
print("After Delete:", x)
Jac Grammar Snippet
delete_stmt: KW_DELETE expression

Description

Report statements

Code Example

1
2
3
with entry {
    print("Not used.");
}
print("Not used.")
Jac Grammar Snippet
report_stmt: KW_REPORT expression

Description

Control statements

Code Example

with entry {
    for i in range(9) {
        if i > 2 {
            print("loop is stopped!!");
            break;
        }
        print(i);
    }
    for i in "WIN" {
        if i == "W" {
            continue;
        }
        print(i);
    }
    #skip is not working need to look at it
}
1
2
3
4
5
6
7
8
9
for i in range(9):
    if i > 2:
        print("loop is stopped!!")
        break
    print(i)
for i in "WIN":
    if i == "W":
        continue
    print(i)
Jac Grammar Snippet
ctrl_stmt: KW_SKIP | KW_BREAK | KW_CONTINUE

Description

Data spatial Walker statements

Code Example

walker Visitor {
    can self_destruct with entry {
        print("get's here");
        disengage;
        print("but not here");
    }
}

with entry {
    root spawn Visitor();
}
from __future__ import annotations
from jaclang.plugin.feature import JacFeature as _Jac


@_Jac.make_walker(on_entry=[_Jac.DSFunc("self_destruct", None)], on_exit=[])
class Visitor:
    def self_destruct(self, _jac_here_) -> None:
        print("get's here")
        _Jac.disengage(self)
        return
        print("but not here")


_Jac.spawn_call(_Jac.get_root(), Visitor())
Jac Grammar Snippet
walker_stmt: visit_stmt
       | revisit_stmt
       | disengage_stmt
       | ignore_stmt

Description

Visit statements

Code Example

walker Visitor {
    can travel with `root entry {
        visit [-->] else {
            visit root;
            disengage;
        }
    }
}

node item {
    can speak with Visitor entry {
        print("Hey There!!!");
    }
}

with entry {
    for i=0 to i<5 by i+=1  {
        root ++> item();
    }
    root spawn Visitor();
}
from __future__ import annotations
from jaclang.plugin.feature import JacFeature as _Jac


@_Jac.make_walker(on_entry=[_Jac.DSFunc("travel", _Jac.get_root_type())], on_exit=[])
class Visitor:
    def travel(self, _jac_here_: _Jac.get_root_type()) -> None:
        if _Jac.visit_node(
            self, _Jac.edge_ref(_jac_here_, None, _Jac.EdgeDir.OUT, None, None)
        ):
            pass
        elif _Jac.visit_node(self, _Jac.get_root()):
            pass


@_Jac.make_node(on_entry=[_Jac.DSFunc("speak", Visitor)], on_exit=[])
class item:
    def speak(self, _jac_here_: Visitor) -> None:
        print("Hey There!!!")


i = 0
while i < 5:
    _Jac.connect(_Jac.get_root(), item(), _Jac.build_edge(_Jac.EdgeDir.OUT, None, None))
    i += 1
_Jac.spawn_call(_Jac.get_root(), Visitor())
Jac Grammar Snippet
visit_stmt: KW_VISIT (inherited_archs)? expression (else_stmt | SEMI)

Description

Revisit statements

Code Example

1
2
3
with entry {
    print("Not used.");
}
print("Not used.")
Jac Grammar Snippet
revisit_stmt: KW_REVISIT expression? (else_stmt | SEMI)

Description

Disengage statements

Code Example

walker Visitor {
    can travel with `root entry {
        visit [-->] else {
            visitroot;
        }
    }
}

node item {
    can speak with Visitor entry {
        print("Hey There!!!");
        disengage;
    }
}

with entry {
    for i=0 to i<5 by i+=1  {
        root ++> item();
    }
    root spawn Visitor();
}
from __future__ import annotations
from jaclang.plugin.feature import JacFeature as _Jac


@_Jac.make_walker(on_entry=[_Jac.DSFunc("travel", _Jac.get_root_type())], on_exit=[])
class Visitor:
    def travel(self, _jac_here_: _Jac.get_root_type()) -> None:
        if _Jac.visit_node(
            self, _Jac.edge_ref(_jac_here_, None, _Jac.EdgeDir.OUT, None, None)
        ):
            pass
        elif _Jac.visit_node(self, _Jac.get_root()):
            pass


@_Jac.make_node(on_entry=[_Jac.DSFunc("speak", Visitor)], on_exit=[])
class item:
    def speak(self, _jac_here_: Visitor) -> None:
        print("Hey There!!!")
        _Jac.disengage(_jac_here_)
        return


i = 0
while i < 5:
    _Jac.connect(_Jac.get_root(), item(), _Jac.build_edge(_Jac.EdgeDir.OUT, None, None))
    i += 1
_Jac.spawn_call(_Jac.get_root(), Visitor())
Jac Grammar Snippet
disengage_stmt: KW_DISENGAGE SEMI

Description

Ignore statements

Code Example

walker Visitor {
    can travel with `root entry {
        ignore [-->][0];
        visit [-->] else {
            visitroot;
        }
    }
}

node item {
    can speak with Visitor entry {
        print("Hey There!!!");
    }
}

with entry {
    for i=0 to i<5 by i+=1  {
        root ++> item();
    }
    root spawn Visitor();
}
from __future__ import annotations
from jaclang.plugin.feature import JacFeature as Jac
from jaclang.plugin.builtin import *
from dataclasses import dataclass


@Jac.make_walker(on_entry=[Jac.DSFunc("travel")], on_exit=[])
@dataclass(eq=False)
class Visitor(Jac.Walker):

    def travel(self, _jac_here_: Jac.RootType) -> None:
        Jac.ignore(
            self,
            Jac.edge_ref(
                _jac_here_,
                target_obj=None,
                dir=Jac.EdgeDir.OUT,
                filter_func=None,
                edges_only=False,
            )[0],
        )
        if Jac.visit_node(
            self,
            Jac.edge_ref(
                _jac_here_,
                target_obj=None,
                dir=Jac.EdgeDir.OUT,
                filter_func=None,
                edges_only=False,
            ),
        ):
            pass
        elif Jac.visit_node(self, Jac.get_root()):
            pass


@Jac.make_node(on_entry=[Jac.DSFunc("speak")], on_exit=[])
@dataclass(eq=False)
class item(Jac.Node):

    def speak(self, _jac_here_: Visitor) -> None:
        print("Hey There!!!")


i = 0
while i < 5:
    Jac.connect(
        left=Jac.get_root(),
        right=item(),
        edge_spec=Jac.build_edge(is_undirected=False, conn_type=None, conn_assign=None),
    )
    i += 1
Jac.spawn_call(Jac.get_root(), Visitor())
Jac Grammar Snippet
ignore_stmt: KW_IGNORE expression SEMI

Description

Assignments

Code Example

with entry {
    a = b = 16;
    let c = 18;
    print(a, b, c);
    a>>=2;
    print(a);
    a<<=2;
    print(a);
    c//=4;
    print(c);
}
1
2
3
4
5
6
7
8
9
a = b = 16
c = 18
print(a, b, c)
a >>= 2
print(a)
a <<= 2
print(a)
c //= 4
print(c)
Jac Grammar Snippet
assignment: KW_LET? (atomic_chain EQ)+ (yield_expr | expression)
          | atomic_chain (COLON STRING)? type_tag (EQ (yield_expr | expression))?
          | atomic_chain aug_op (yield_expr | expression)

aug_op: RSHIFT_EQ
       | LSHIFT_EQ
       | BW_NOT_EQ
       | BW_XOR_EQ
       | BW_OR_EQ
       | BW_AND_EQ
       | MOD_EQ
       | DIV_EQ
       | FLOOR_DIV_EQ
       | MUL_EQ
       | SUB_EQ
       | ADD_EQ
       | MATMUL_EQ
       | STAR_POW_EQ

Description

Expressions

Code Example

1
2
3
4
with entry {
    x = 1 if 5 / 2 == 1 else 2;
    print(x);
}
1
2
3
4
5
6
if 5 / 2 == 1:
    x = 1
else:
    x = 2

print(x)
Jac Grammar Snippet
expression: walrus_assign (KW_IF expression KW_ELSE expression)?
          | lambda_expr

Description

Walrus assignments

Code Example

1
2
3
4
5
6
with entry {
    a = 5;
    if (b := a + a // 2) > 5 {
        print("b is grater than 5");
    }
}
1
2
3
a = 5
if (b := (a + a // 2)) > 5:
    print("b is grater than 5")
Jac Grammar Snippet
walrus_assign: (named_ref WALRUS_EQ)? pipe

Description

Lambda expressions

Code Example

1
2
3
4
with entry {
    x = with a: int, b: int can b + a;
    print(x(5, 4));
}
x = lambda a, b: a + b
print(x(5, 4))
Jac Grammar Snippet
lambda_expr: KW_WITH func_decl_params? (RETURN_HINT expression)? KW_CAN expression

Description

Pipe expressions

Code Example

1
2
3
4
5
6
7
8
9
can square(x: int) -> int {
    return (x ** 2);
}

with entry {
    number = 5;
    result = number |> square;
    print(result);
}
1
2
3
4
5
6
7
def square(x: int) -> int:
    return x**2


number = 5
result = square(number)
print(result)
Jac Grammar Snippet
pipe: (pipe PIPE_FWD)? pipe_back

Description

Pipe back expressions

Code Example

1
2
3
4
5
6
7
8
9
can double(x: int) -> int {
    return (x * 2);
}

with entry {
    number = 5;
    result = double <| number;
    print(result);
}
1
2
3
4
5
6
7
def double(x: int) -> int:
    return x * 2


number = 5
result = double(number)
print(result)
Jac Grammar Snippet
pipe_back: (pipe_back PIPE_BKWD)? elvis_check

Description

Elvis expressions

Code Example

1
2
3
4
5
with entry {
    user_language = None;
    preferred_language = user_language ?: 'english';
    print(preferred_language);
}
1
2
3
4
5
from jaclang.plugin.feature import JacFeature as jac

user_language = None
preferred_language = jac.elvis(user_language, "english")
print(preferred_language)
Jac Grammar Snippet
elvis_check: (elvis_check ELVIS_OP)? bitwise_or

Description

Bitwise expressions

Code Example

1
2
3
4
5
6
7
8
9
with entry {
    p = print;
    p("&:", 5 & 3);
    p("|:", 5 | 3);
    p("^:", 5 ^ 3);
    p("~:", ~5);
    p("<<:", 5 << 1);
    p(">>:", 5 >> 1);
}
1
2
3
4
5
6
7
p = print
p("&:", 5 & 3)
p("|:", 5 | 3)
p("^:", 5 ^ 3)
p("~:", ~5)
p("<<:", 5 << 1)
p(">>:", 5 >> 1)
Jac Grammar Snippet
bitwise_or: (bitwise_or BW_OR)? bitwise_xor
bitwise_xor: (bitwise_xor BW_XOR)? bitwise_and
bitwise_and: (bitwise_and BW_AND)? shift
shift: (shift (RSHIFT | LSHIFT))? logical_or

Description

Logical and compare expressions

Code Example

with entry {
    if 5 > 4 {
        print("True");
    } elif "a" != "b" {
        print("'a' is 'a' ");
    } else {
        print("No");
    }
    a = [1, 2, 3];
    b = [1, 2, 3];
    print(a is b);
    print(3 in a);
    print(True or False);
    print(False and False);
}
if 5 > 4:
    print("True")
elif "a" != "a":
    print("'a' is 'a' ")
else:
    print("False")
a = [1, 2, 3]
b = [1, 2, 3]
print(a is b)
print(3 in a)

print(True or False)
print(False and False)
Jac Grammar Snippet
logical_or: logical_and (KW_OR logical_and)*
logical_and: logical_not (KW_AND logical_not)*
logical_not: NOT logical_not | compare
compare: (arithmetic cmp_op)* arithmetic

cmp_op: KW_ISN
      | KW_IS
      | KW_NIN
      | KW_IN
      | NE
      | GTE
      | LTE
      | GT
      | LT
      | EE

Description

Arithmetic expressions

Code Example

1
2
3
4
5
6
7
8
9
with entry {
    p = print;
    p("Multiply:", 7 * 2);
    p("Division:", 15 / 3);
    p("Floor:", 15 // 3);
    p("Modulo:", 17 % 5);
    p("Expon:", 2 ** 3);
    p("combo:", (9 + 2) * 9 - 2);
}
1
2
3
4
5
6
7
8
p = print

p("Multiply:", 7 * 2)
p("Division:", 15 / 3)
p("Floor:", 15 // 3)
p("Modulo:", 17 % 5)
p("Expon:", 2**3)
p("combo:", (9 + 2) * 9 - 2)
Jac Grammar Snippet
arithmetic: (arithmetic (MINUS | PLUS))? term
term: (term (MOD | DIV | FLOOR_DIV | STAR_MUL | DECOR_OP))? power
power: (power STAR_POW)? factor
factor: (BW_NOT | MINUS | PLUS) factor | connect

Description

Connect expressions

Code Example

node node_a {
    has value: int;
}

walker Creator {
    can create with `root entry;
    can travel with `root | node_a entry;
}

edge MyEdge {
    has val: int = 5;
}

:walker:Creator:can:create {
    end = here;
    for i=0 to i<7 by i+=1  {
        if i % 2 == 0 {
            end ++> (end := node_a(value=i));
        } else {
            end +:MyEdge:val=i:+> (end := node_a(value=i + 10));
        }
    }
}

:walker:Creator:can:travel {
    for i in [-:MyEdge:val <= 6:->] {
        print(i.value);
    }
    visit [-->];
}

with entry :__main__ {
    root spawn Creator();
}
from __future__ import annotations
from jaclang.plugin.feature import JacFeature as Jac
from jaclang.plugin.builtin import *
from dataclasses import dataclass


@Jac.make_node(on_entry=[], on_exit=[])
@dataclass(eq=False)
class node_a(Jac.Node):
    value: int


@Jac.make_walker(on_entry=[Jac.DSFunc("create"), Jac.DSFunc("travel")], on_exit=[])
@dataclass(eq=False)
class Creator(Jac.Walker):
    def create(self, _jac_here_: Jac.RootType) -> None:
        end = _jac_here_
        i = 0
        while i < 7:
            if i % 2 == 0:
                Jac.connect(
                    left=end,
                    right=(end := node_a(value=i)),
                    edge_spec=Jac.build_edge(
                        is_undirected=False, conn_type=None, conn_assign=None
                    ),
                )
            else:
                Jac.connect(
                    left=end,
                    right=(end := node_a(value=i + 10)),
                    edge_spec=Jac.build_edge(
                        is_undirected=False,
                        conn_type=MyEdge,
                        conn_assign=(("val",), (i,)),
                    ),
                )
            i += 1

    def travel(self, _jac_here_: Jac.RootType | node_a) -> None:
        for i in Jac.edge_ref(
            _jac_here_,
            target_obj=None,
            dir=Jac.EdgeDir.OUT,
            filter_func=lambda x: [i for i in x if isinstance(i, MyEdge) if i.val <= 6],
            edges_only=False,
        ):
            print(i.value)
        if Jac.visit_node(
            self,
            Jac.edge_ref(
                _jac_here_,
                target_obj=None,
                dir=Jac.EdgeDir.OUT,
                filter_func=None,
                edges_only=False,
            ),
        ):
            pass


@Jac.make_edge(on_entry=[], on_exit=[])
@dataclass(eq=False)
class MyEdge(Jac.Edge):
    val: int = Jac.has_instance_default(gen_func=lambda: 5)


if __name__ == "__main__":
    Jac.spawn_call(Jac.get_root(), Creator())
Jac Grammar Snippet
connect: (connect (connect_op | disconnect_op))? atomic_pipe

Description

Atomic expressions

Code Example

1
2
3
4
with entry {
    "Hello world!" :> print;
    "Welcome" :> type :> print;
}
print("Hello world!")
print(type("welcome"))
Jac Grammar Snippet
atomic_pipe: (atomic_pipe A_PIPE_FWD)? atomic_pipe_back

Description

Atomic pipe back expressions

Code Example

1
2
3
4
5
6
7
with entry {
    print <: "Hello world!";
    a = [2, 4, 5, 7, 8];
    b = [4, 8, 9, 13, 20];
    c = len <: a + b :> len;
    print(c);
}
1
2
3
4
5
print("Hello world!")
a = [2, 4, 5, 7, 8]
b = [4, 8, 9, 13, 20]
c = len(a) + len(b)
print(c)
Jac Grammar Snippet
atomic_pipe_back: (atomic_pipe_back A_PIPE_BKWD)? ds_spawn

Description

Data spatial spawn expressions

Code Example

walker Adder {
    can do with `root entry;
}

node node_a {
    has x: int = 0,
        y: int = 0;

    can add with Adder entry;
}

:walker:Adder:can:do {
    here ++> node_a();
    visit [-->];
}

:node:node_a:can:add {
    self.x = 550;
    self.y = 450;
    print(int(self.x) + int(self.y));
}

with entry {
# spawn will iniiate the walker Adder from root node
Adder() spawn root;
}
from __future__ import annotations
from jaclang.plugin.feature import JacFeature as Jac
from jaclang.plugin.builtin import *
from dataclasses import dataclass


@Jac.make_walker(on_entry=[Jac.DSFunc("do")], on_exit=[])
@dataclass(eq=False)
class Adder(Jac.Walker):
    def do(self, _jac_here_: Jac.RootType) -> None:
        Jac.connect(
            left=_jac_here_,
            right=node_a(),
            edge_spec=Jac.build_edge(
                is_undirected=False, conn_type=None, conn_assign=None
            ),
        )
        if Jac.visit_node(
            self,
            Jac.edge_ref(
                _jac_here_,
                target_obj=None,
                dir=Jac.EdgeDir.OUT,
                filter_func=None,
                edges_only=False,
            ),
        ):
            pass


@Jac.make_node(on_entry=[Jac.DSFunc("add")], on_exit=[])
@dataclass(eq=False)
class node_a(Jac.Node):
    x: int = Jac.has_instance_default(gen_func=lambda: 0)
    y: int = Jac.has_instance_default(gen_func=lambda: 0)

    def add(self, _jac_here_: Adder) -> None:
        self.x = 550
        self.y = 450
        print(int(self.x) + int(self.y))


Jac.spawn_call(Adder(), Jac.get_root())
Jac Grammar Snippet
ds_spawn: (ds_spawn KW_SPAWN)? unpack

Description

Unpack expressions

Code Example

can combine_via_func(a: int, b: int, c: int, d: int) -> int {
    return a + b + c + d;
}

with entry {
    first_list = [1, 2, 3, 4, 5];
    second_list = [5, 8, 7, 6, 9];
    combined_list = [*first_list, *second_list];
    print(combined_list);

    # Original dictionary
    first_dict = {'a':1, 'b':2 };

    # Another dictionary
    second_dict = {'c':3, 'd':4 };

    # Combining dictionaries using dictionary unpacking
    combined_dict = {**first_dict, **second_dict };

    # Printing the combined dictionary
    print(combine_via_func(**combined_dict));
    print(combine_via_func(**first_dict, **second_dict));
}
def combine_via_func(a: int, b: int, c: int, d: int) -> int:
    return a + b + c + d


first_list = [1, 2, 3, 4, 5]
second_list = [5, 8, 7, 6, 9]
combined_list = [*first_list, *second_list]
print(combined_list)
first_dict = {"a": 1, "b": 2}
second_dict = {"c": 3, "d": 4}
combined_dict = {**first_dict, **second_dict}
print(combine_via_func(**combined_dict))
print(combine_via_func(**first_dict, **second_dict))
Jac Grammar Snippet
unpack: STAR_MUL? ref

Description

References (unused)

Code Example

1
2
3
with entry {
    print("Not used.");
}
print("Not used.")
Jac Grammar Snippet
ref: BW_AND? pipe_call

Description

Data spatial calls

Code Example

walker Creator {
    can func2 with `root entry;
}

node node_1 {
    has val: int;

    can func_1 with Creator entry;
}

:node:node_1:can:func_1 {
    print("visiting ", self);
    visit [-->];
}

:walker:Creator:can:func2 {
    end = here;
    for i=0 to i<5 by i+=1  {
        end ++> (end := node_1(val=i + 1));
    }
    visit [-->];
}

with entry {
    root spawn :> Creator;
    root spawn |> Creator;
}
from __future__ import annotations
from jaclang.plugin.feature import JacFeature as Jac
from jaclang.plugin.builtin import *
from dataclasses import dataclass


@Jac.make_walker(on_entry=[Jac.DSFunc("func2")], on_exit=[])
@dataclass(eq=False)
class Creator(Jac.Walker):
    def func2(self, _jac_here_: Jac.RootType) -> None:
        end = _jac_here_
        i = 0
        while i < 5:
            Jac.connect(
                left=end,
                right=(end := node_1(val=i + 1)),
                edge_spec=Jac.build_edge(
                    is_undirected=False, conn_type=None, conn_assign=None
                ),
            )
            i += 1
        if Jac.visit_node(
            self,
            Jac.edge_ref(
                _jac_here_,
                target_obj=None,
                dir=Jac.EdgeDir.OUT,
                filter_func=None,
                edges_only=False,
            ),
        ):
            pass


@Jac.make_node(on_entry=[Jac.DSFunc("func_1")], on_exit=[])
@dataclass(eq=False)
class node_1(Jac.Node):
    val: int

    def func_1(self, _jac_here_: Creator) -> None:
        print("visiting ", self)
        if Jac.visit_node(
            _jac_here_,
            Jac.edge_ref(
                self,
                target_obj=None,
                dir=Jac.EdgeDir.OUT,
                filter_func=None,
                edges_only=False,
            ),
        ):
            pass


Jac.spawn_call(Jac.get_root(), Creator())
Jac.spawn_call(Jac.get_root(), Creator())
Jac Grammar Snippet
pipe_call: (PIPE_FWD | A_PIPE_FWD | KW_SPAWN | KW_AWAIT)? atomic_chain

Description

Subscripted and dotted expressions

Code Example

obj Sample {
    has my_list: list = [1, 2, 3],
        my_dict: dict = {"name":"John", "age":30 };
}

glob (first, second) = (Sample().my_list[2], Sample().my_dict["name"]);

with entry {
    print(first, second);
}
class Sample:
    def __init__(self):
        self.my_list = [1, 2, 3]
        self.my_dict = {"name": "John", "age": 30}


def main():
    sample_instance = Sample()
    first, second = sample_instance.my_list[2], sample_instance.my_dict["name"]

    print(first, second)


main()
Jac Grammar Snippet
atomic_chain: atomic_chain NULL_OK? (filter_compr | assign_compr | index_slice)
            | atomic_chain NULL_OK? (DOT_BKWD | DOT_FWD | DOT) named_ref
            | (atomic_call | atom | edge_ref_chain)

index_slice: LSQUARE                                                             \
                     expression? COLON expression? (COLON expression?)?          \
                     (COMMA expression? COLON expression? (COLON expression?)?)* \
              RSQUARE
           | list_val

Description

Function calls

Code Example

1
2
3
4
5
6
7
8
9
can foo(x: int, y: int, z: int) {
    return (x * y, y * z);
}

with entry {
    a = 5;
    output = foo(x=4, y=4 if a % 3 == 2 else 3, z=9);
    print(output);
}
1
2
3
4
5
6
7
def foo(x: int, y: int, z: int) -> None:
    return (x * y, y * z)


a = 5
output = foo(x=4, y=4 if a % 3 == 2 else 3, z=9)
print(output)
Jac Grammar Snippet
atomic_call: atomic_chain LPAREN param_list? (KW_BY atomic_call)? RPAREN

param_list: expr_list COMMA kw_expr_list COMMA?
          | kw_expr_list COMMA?
          | expr_list COMMA?

Description

Atom

Code Example

:enum:x {
    aa=67,
    y="aaa" + f"b{aa}bbcc"
}

glob c = (3, 4, 5), list1 = [2, 3, 4, 5];

with entry {
    a = "abcde....";
    b = True;
    c = bin(12);
    d = hex(78);
    print(list1, a, b, c, d);

    # pp=0x4e;

    # print(0b1100);
    enum x;
    print(x.y.value);
}
class X:
    a_b = 67
    y = "aaa" + f"b{a_b}bbcc"


c = (3, 4, 5)
l_1 = [2, 3, 4, 5]


def entry():
    x = X

    a = "abcde...."
    b = True
    c = bin(12)
    d = hex(78)
    # e = 0x4E
    print(l_1, a, b, c, d)
    print(x.y)


# Run the entry block
entry()
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 | DOC_STRING)+

fstring: FSTR_START fstr_parts FSTR_END
       | FSTR_SQ_START fstr_sq_parts FSTR_SQ_END

fstr_parts: (FSTR_PIECE | FSTR_BESC | LBRACE expression RBRACE )*
fstr_sq_parts: (FSTR_SQ_PIECE | FSTR_BESC | LBRACE expression RBRACE )*

Description

Collection values

Code Example

with entry {
    squares = {num:num ** 2  for num in range(1, 6)};
    even_squares_set = {num ** 2  for num in range(1, 11) if num % 2 == 0};
    squares_generator = (num ** 2  for num in range(1, 6));
    squares_list = [num ** 2  for num in squares_generator];

    # BREAKS: squares_list = [num**2 for num in squares_generator if num != 9];


    # TODO: Issure with '\n' below, its being escaped
    print("\n".join([str(squares), str(even_squares_set), str(squares_list)]));
    print({"a":"b", "c":"d" },  # Dictionary value
    {"a"}, # Set value
    ("a", ), # Tuple value
    ['a']); # List value
}
squares = {num: num**2 for num in range(1, 6)}
even_squares_set = {num**2 for num in range(1, 11) if num % 2 == 0}
squares_generator = (num**2 for num in range(1, 6))
squares_list = [num**2 for num in squares_generator]

print("\n".join([str(squares), str(even_squares_set), str(squares_list)]))
print(
    {"a": "b", "c": "d"},  # Dictionary value
    {"a"},  # Set value
    ("a",),  # Tuple value
    ["a"],  # List value
)
Jac Grammar Snippet
atom_collection: dict_compr
               | set_compr
               | gen_compr
               | list_compr
               | dict_val
               | set_val
               | tuple_val
               | list_val

list_compr: LSQUARE expression inner_compr+ RSQUARE
gen_compr: LPAREN expression inner_compr+ RPAREN
set_compr: LBRACE expression inner_compr+ RBRACE
dict_compr: LBRACE kv_pair inner_compr+ RBRACE
inner_compr: KW_ASYNC? KW_FOR atomic_chain KW_IN pipe_call (KW_IF walrus_assign)*

dict_val: LBRACE ((kv_pair COMMA)* kv_pair COMMA?)? RBRACE
list_val: LSQUARE (expr_list COMMA?)? RSQUARE
tuple_val: LPAREN tuple_list? RPAREN
set_val: LBRACE expr_list COMMA? RBRACE

kv_pair: expression COLON expression | STAR_POW expression
expr_list: (expr_list COMMA)? expression

Description

Tuples and Jac Tuples

Code Example

can foo(first: int, second: int) -> None {
    print(first, second);
}

with entry {
    val1 = (3, ) + (4, );
    val2 = (val1[0] * val1[1], val1[0] + val1[1]);

    # Investigate: val2 = (val1[0]*val1[1], val1[0]+val1[1]);


    # Jac-style Tuples
    (second=val2[1], first=val2[0]) |> foo;
    (first=val2[0], second=val2[1]) |> foo;
}
1
2
3
4
5
6
7
8
def foo(first: int, second: int) -> None:
    print(first, second)


val1 = (3,) + (4,)
val2 = (val1[0] * val1[1], val1[0] + val1[1])
foo(second=val2[1], first=val2[0])
foo(first=val2[0], second=val2[1])
Jac Grammar Snippet
tuple_list: expression COMMA expr_list COMMA kw_expr_list COMMA?
          | expression COMMA kw_expr_list COMMA?
          | expression COMMA expr_list COMMA?
          | expression COMMA
          | kw_expr_list COMMA?

kw_expr_list: (kw_expr_list COMMA)? kw_expr
kw_expr: named_ref EQ expression | STAR_POW expression

Description

Data Spatial References

Code Example

walker Creator {
    can create with `root entry;
}

node node_a {
    has val: int;

    can make_something with Creator entry;
}

edge connector {
    has value: int = 10;
}

:walker:Creator:can:create {
    end = here;
    for i=0 to i<3 by i+=1  {
        end ++> (end := node_a(val=i));
    }
    end +:connector:value=i:+> (end := node_a(val=i + 10));
    root <+:connector:value=i:+ (end := node_a(val=i + 10));
    visit [-->];
}

:node:node_a:can:make_something {
    i = 0;
    while i < 5 {
        print(f"wlecome to {self}");
        i+=1;
    }
}

with entry {
    root spawn Creator();
}
from __future__ import annotations
from jaclang.plugin.feature import JacFeature as Jac
from jaclang.plugin.builtin import *
from dataclasses import dataclass


@Jac.make_walker(on_entry=[Jac.DSFunc("create")], on_exit=[])
@dataclass(eq=False)
class Creator(Jac.Walker):
    def create(self, _jac_here_: Jac.RootType) -> None:
        end = _jac_here_
        i = 0
        while i < 3:
            Jac.connect(
                left=end,
                right=(end := node_a(val=i)),
                edge_spec=Jac.build_edge(
                    is_undirected=False, conn_type=None, conn_assign=None
                ),
            )
            i += 1
        Jac.connect(
            left=end,
            right=(end := node_a(val=i + 10)),
            edge_spec=Jac.build_edge(
                is_undirected=False, conn_type=connector, conn_assign=(("value",), (i,))
            ),
        )
        Jac.connect(
            left=(end := node_a(val=i + 10)),
            right=Jac.get_root(),
            edge_spec=Jac.build_edge(
                is_undirected=False, conn_type=connector, conn_assign=(("value",), (i,))
            ),
        )
        if Jac.visit_node(
            self,
            Jac.edge_ref(
                _jac_here_,
                target_obj=None,
                dir=Jac.EdgeDir.OUT,
                filter_func=None,
                edges_only=False,
            ),
        ):
            pass


@Jac.make_node(on_entry=[Jac.DSFunc("make_something")], on_exit=[])
@dataclass(eq=False)
class node_a(Jac.Node):
    val: int

    def make_something(self, _jac_here_: Creator) -> None:
        i = 0
        while i < 5:
            print(f"wlecome to {self}")
            i += 1


@Jac.make_edge(on_entry=[], on_exit=[])
@dataclass(eq=False)
class connector(Jac.Edge):
    value: int = Jac.has_instance_default(gen_func=lambda: 10)


Jac.spawn_call(Jac.get_root(), Creator())
Jac Grammar Snippet
edge_ref_chain: (EDGE_OP|NODE_OP)? LSQUARE expression? (edge_op_ref (filter_compr | expression)?)+ RSQUARE
edge_op_ref: edge_any | edge_from | edge_to
edge_to: ARROW_R | ARROW_R_P1 typed_filter_compare_list ARROW_R_P2
edge_from: ARROW_L | ARROW_L_P1 typed_filter_compare_list ARROW_L_P2
edge_any: ARROW_BI | ARROW_L_P1 typed_filter_compare_list ARROW_R_P2
connect_op: connect_from | connect_to | connect_any
disconnect_op: KW_DELETE edge_op_ref
connect_to: CARROW_R | CARROW_R_P1 expression (COLON kw_expr_list)? CARROW_R_P2
connect_from: CARROW_L | CARROW_L_P1 expression (COLON kw_expr_list)? CARROW_L_P2
connect_any: CARROW_BI | CARROW_L_P1 expression (COLON kw_expr_list)? CARROW_R_P2

Description

Special Comprehensions

Code Example

#Filter comprehension
import:py random;

obj TestObj {
    has x: int = random.randint(0, 15),
        y: int = random.randint(0, 15),
        z: int = random.randint(0, 15);
}

with entry {
    random.seed(42);
    apple = [];
    for i=0 to i<10 by i+=1  {
        apple.append(TestObj());
    }
    #To get the instances with the y value less than 7
    print(apple(?y <= 7));
}
#assign comprehension

obj MyObj {
    has apple: int = 0,
        banana: int = 0;
}

with entry {
    x = MyObj();
    y = MyObj();
    mvar = [x, y](=apple=5, banana=7);
    print(mvar);
}
from __future__ import annotations
from jaclang.plugin.feature import JacFeature as Jac
from dataclasses import dataclass as dataclass
import random


@Jac.make_obj(on_entry=[], on_exit=[])
@dataclass(eq=False)
class TestObj:
    x: int = Jac.has_instance_default(gen_func=lambda: random.randint(0, 15))
    y: int = Jac.has_instance_default(gen_func=lambda: random.randint(0, 15))
    z: int = Jac.has_instance_default(gen_func=lambda: random.randint(0, 15))


random.seed(42)
apple = []
i = 0
while i < 10:
    apple.append(TestObj())
    i += 1
print((lambda x: [i for i in x if i.y <= 7])(apple))


@Jac.make_obj(on_entry=[], on_exit=[])
@dataclass(eq=False)
class MyObj:
    apple: int = Jac.has_instance_default(gen_func=lambda: 0)
    banana: int = Jac.has_instance_default(gen_func=lambda: 0)


x = MyObj()
y = MyObj()
mvar = Jac.assign_compr([x, y], (("apple", "banana"), (5, 7)))
print(mvar)
Jac Grammar Snippet
filter_compr: LPAREN NULL_OK filter_compare_list RPAREN
            | LPAREN TYPE_OP NULL_OK typed_filter_compare_list RPAREN
assign_compr: LPAREN EQ kw_expr_list RPAREN
filter_compare_list: (filter_compare_list COMMA)? filter_compare_item
typed_filter_compare_list: expression (COLON filter_compare_list)?
filter_compare_item: named_ref cmp_op expression

Description

Names and references

Code Example

obj Animal {
    has species: str;
    has sound: str;

}

obj Dog :Animal: {
    has breed: str;
    has trick: str by postinit;

    can postinit {
        self.trick = "Roll over";
    }
}

obj Cat :Animal: {
    can init(fur_color: str) {
        super.init(species="Cat", sound="Meow!");
        self.fur_color = fur_color;
    }
}

with entry {
    dog = Dog(breed="Labrador", species="Dog", sound="Woof!");
    cat = Cat(fur_color="Tabby");

    print(dog.breed, dog.sound, dog.trick);
    # print(f"The dog is a {dog.breed} and says '{dog.sound}'");
    # print(f"The cat's fur color is {cat.fur_color}");
}
from dataclasses import dataclass, field


@dataclass
class Animal:
    species: str
    sound: str


@dataclass
class Dog(Animal):
    breed: str
    trick: str = field(init=False)

    def __post_init__(self):
        self.trick = "Roll over"


@dataclass
class Cat(Animal):

    def __init__(self, fur_color: str):
        super().__init__(species="Cat", sound="Meow!")
        self.fur_color = fur_color


dog = Dog(breed="Labrador", species="Dog", sound="Woof!")
cat = Cat(fur_color="Tabby")

print(dog.breed, dog.sound, dog.trick)
# print(f'The dog is a {dog.breed} and says "{dog.sound}"')
# print(f"The cat's fur color is {cat.fur_color}")
Jac Grammar Snippet
named_ref: special_ref
         | KWESC_NAME
         | NAME

special_ref: KW_INIT
            | KW_POST_INIT
            | KW_ROOT
            | KW_SUPER
            | KW_SELF
            | KW_HERE

Description

Builtin types

Code Example

glob a = 9.2;

glob b = 44;

glob c = [2, 4, 6, 10];

glob d = {'name':'john', 'age':28 };

glob e = ("jaseci", 5, 4, 14);

glob f = True;

glob g = "Jaseci";

glob h = {5, 8, 12, "unique"};

with entry {
    print(type(a), '\n', type(b), '\n', type(c), '\n', type(d), '\n', type(e));
    print(type(f), '\n', type(g), '\n', type(h));
}
a = 9.2
b = 44
c = [2, 4, 6, 10]
d = {"name": "john", "age": 28}
e = ("jaseci", 5, 4, 14)
f = True
g = "Jaseci"
h = {5, 8, 12, "unique"}
print(type(a), "\n", type(b), "\n", type(c), "\n", type(d), "\n", type(e))
print(type(f), "\n", type(g), "\n", type(h))
Jac Grammar Snippet
builtin_type: TYP_TYPE
            | TYP_ANY
            | TYP_BOOL
            | TYP_DICT
            | TYP_SET
            | TYP_TUPLE
            | TYP_LIST
            | TYP_FLOAT
            | TYP_INT
            | TYP_BYTES
            | TYP_STRING

Description

Lexer Tokens

Code Example

1
2
3
with entry {
    print("Example not applicable.");
}
print("Example not applicable.")
Jac Grammar Snippet
TYP_STRING: "str"
TYP_INT: "int"
TYP_FLOAT: "float"
TYP_LIST: "list"
TYP_TUPLE: "tuple"
TYP_SET: "set"
TYP_DICT: "dict"
TYP_BOOL: "bool"
TYP_BYTES: "bytes"
TYP_ANY: "any"
TYP_TYPE: "type"
KW_LET: "let"
KW_ABSTRACT: "abs"
KW_CLASS: "class"
KW_OBJECT: "obj"
KW_ENUM: "enum"
KW_NODE: "node"
KW_IGNORE: "ignore"
KW_VISIT: "visit"
KW_REVISIT: "revisit"
KW_SPAWN: "spawn"
KW_WITH: "with"
KW_ENTRY: "entry"
KW_EXIT: "exit"
KW_IMPORT: "import"
KW_INCLUDE: "include"
KW_FROM: "from"
KW_AS: "as"
KW_EDGE: "edge"
KW_WALKER: "walker"
KW_ASYNC: "async"
KW_AWAIT: "await"
KW_TEST: "test"
KW_ASSERT: "assert"
KW_CHECK: "check"
KW_IF: "if"
KW_ELIF: "elif"
KW_ELSE: "else"
KW_FOR: "for"
KW_TO: "to"
KW_BY: "by"
KW_WHILE: "while"
KW_CONTINUE: "continue"
KW_BREAK: "break"
KW_DISENGAGE: "disengage"
KW_YIELD: "yield"
KW_SKIP: "skip"
KW_REPORT: "report"
KW_RETURN: "return"
KW_DELETE: "del"
KW_TRY: "try"
KW_EXCEPT: "except"
KW_FINALLY: "finally"
KW_RAISE: "raise"
KW_IN: "in"
KW_IS: "is"
KW_PRIV: "priv"
KW_PUB: "pub"
KW_PROT: "protect"
KW_HAS: "has"
KW_GLOBAL: "glob"
KW_CAN: "can"
KW_STATIC: "static"
KW_OVERRIDE: "override"
KW_MATCH: "match"
KW_CASE: "case"
KW_HERE: "here"
KW_SELF: "self"
KW_INIT: "init"
KW_POST_INIT: "postinit"
KW_SUPER: "super"
KW_ROOT: "root"

FLOAT: /(\d+(\.\d*)|\.\d+)([eE][+-]?\d+)?|\d+([eE][-+]?\d+)/
DOC_STRING.1: /"""(.|\n|\r)*?"""|'''(.|\n|\r)*?'''/
PYNLINE: /::py::(.|\n|\r)*?::py::/
STRING: /(r?b?|b?r?)"[^"\r\n]*"|(r?b?|b?r?)'[^'\r\n]*'/
BOOL.1: /True|False/
KW_NIN.1: /\bnot\s+in\b/
KW_ISN.1: /\bis\s+not\b/
HEX.1: /0[xX][0-9a-fA-F_]+/
BIN.1: /0[bB][01_]+/
OCT.1: /0[oO][0-7_]+/
INT: /[0-9][0-9_]*/
NULL.1: /None/
KWESC_NAME: /<>[a-zA-Z_][a-zA-Z0-9_]*/
NAME: /[a-zA-Z_][a-zA-Z0-9_]*/

ARROW_BI: /<-->/
ARROW_L: /<--/
ARROW_R: /-->/
ARROW_L_P1: /<-\:/
ARROW_R_P2: /:->/
ARROW_L_P2: /:-/
ARROW_R_P1: /-\:/
CARROW_BI: /<\+\+>/
CARROW_L: /<\+\+/
CARROW_R: /\+\+>/
CARROW_L_P1: /<\+\:/
CARROW_R_P2: /:\+>/
CARROW_L_P2: /:\+/
CARROW_R_P1: /\+\:/

GLOBAL_OP: /:g:|:global:/
NONLOCAL_OP: /:nl:|:nonlocal:/
WALKER_OP: /:w:|:walker:/
NODE_OP: /:n:|:node:/
EDGE_OP: /:e:|:edge:/
CLASS_OP: /:cls:|:class:/
OBJECT_OP: /:o:|:obj:/
TYPE_OP: /`|:t:|:type:/
ENUM_OP: /:enum:/
ABILITY_OP: /:c:|:can:/
A_PIPE_FWD: /:>/
A_PIPE_BKWD: /<:/
PIPE_FWD: /\|>/
PIPE_BKWD: /<\|/
DOT_FWD: /\.>/
DOT_BKWD: /<\./
RETURN_HINT: /->/
ELVIS_OP: /\?:/
NULL_OK: /\?/
MATMUL_EQ: /@=/
DECOR_OP: /@/

KW_AND.1: /&&|and/
KW_OR.1:  /\|\||or/
ADD_EQ: /\+=/
SUB_EQ: /-=/
STAR_POW_EQ: /\*\*\=/
MUL_EQ: /\*=/
FLOOR_DIV_EQ: /\/\/=/
DIV_EQ: /\/=/
MOD_EQ: /%=/
BW_AND_EQ: /&=/
BW_OR_EQ: /\|=/
BW_XOR_EQ: /\^=/
BW_NOT_EQ: /~=/
LSHIFT_EQ: /<<=/
RSHIFT_EQ: />>=/
LSHIFT: /<</
RSHIFT: />>/
LTE: /<=/
GTE: />=/
NE: /!=/
NOT: "not"
WALRUS_EQ: /:=/
COLON: /:/
LBRACE: /{/
RBRACE: /}/
SEMI: /;/
EE: /==/
EQ: /=/
ELLIPSIS: /\.\.\./
DOT: /\./
LT: /</
GT: />/
COMMA: /,/
PLUS: /\+/
MINUS: /-/
STAR_POW: /\*\*/
STAR_MUL: /\*/
FLOOR_DIV: /\/\//
DIV: /\//
MOD: /%/
BW_AND: /&/
BW_OR: /\|/
BW_XOR: /\^/
BW_NOT: /~/
LPAREN: /\(/
RPAREN: /\)/
LSQUARE: /\[/
RSQUARE: /\]/

Description

f-string tokens

Code Example

with entry {
    x = "a";
    y = 25;
    print(f"Hello {x} {y} {{This is an escaped curly brace}}");
    person = {"name":"Jane", "age":25 };
    print(f"Hello, {person['name']}! You're {person['age']} years old.");
    print("This is the first line.\n This is the second line.");
    print("This will not print.\r This will be printed");
    print("This is \t tabbed.");
    print("Line 1\fLine 2");
    words = ["Hello", "World!", "I", "am", "a", "Jactastic!"];
    print(f"{'\n'.join(words)}");
}
x = "a"
y = 25
print(f"Hello {x} {y} {{This is an escaped curly brace}}")
person = {"name": "Jane", "age": 25}
print(f"Hello, {person['name']}! You're {person['age']} years old.")
print("This is the first line.\n This is the second line.")
print("This will not print.\r This will be printed")
print("This is \t tabbed.")
print("Line 1\x0cLine 2")
words = ["Hello", "World!", "I", "am", "a", "Jactastic!"]
print(
    f'''{"""
""".join(words)}'''
)
Jac Grammar Snippet
FSTR_START.1: "f\""
FSTR_END: "\""
FSTR_SQ_START.1: "f'"
FSTR_SQ_END: "'"
FSTR_PIECE.-1: /[^\{\}\"]+/
FSTR_SQ_PIECE.-1: /[^\{\}\']+/
FSTR_BESC.1: /{{|}}/

COMMENT: /#\*(.|\n|\r)*?\*#|#.*/
WS.-2: /[ \t\f\r\n]/+
%ignore COMMENT
%ignore WS

Description