A module is a mapping of identifiers to values and types.

A module may contain pragma that:


  • A module with no exported identifiers is an indicator of a likely mistake.


  • The compiler may validate mismatched valueIdentifer / typeIdentifier in imports and exports and correct this.

After all pragma are declared, top-level statements are evaluated.

Tenet Version Pragma

The verison of Tenet being used, if specified, should be the first pragma to ensure it can be correctly parsed.


tenet 0.1

Metadata Pragmas

The metadata for the language identify the name and version. Versions in tenet follow the Semantic Version specification 2.0.0.

meta name Example_Language
meta version 23.45.67-1.alpha+03f7.7gq44

Import and export pragmas

Identifiers may be imported from other files, and renamed.

import some_dir.some_dir.some_file.one_function
import some_dir.some_dir.some_file.function as renamed_function
import some_dir.some_file(value1, value2 as renamed_value)
import some_dir.some_file.Type_Name
import some_dir.other_file.Type_Name as Renamed_Type
import some_dir.some_file(Type1 as Renamed_List, Type2)

Identifiers may be marked for export, either individually or by prefix pattern.

export value1
export (value1, value2)
export prefix_*
export (prefix1*, name, prefix_*)
export Type_One
export (Type_Two, Type_Three)
export Prefix_*
export (Prefix*, Type)
export *

Generation pragmas

Generation pragmas identify the target languages and enable or disable features.

The use pragma enables a feature. The ban pragma disables it. Using and banning the same feature is an error.

Incompatible exports can be dropped with drop, which accepts a prefix pattern.

Naming conventions can be specified with name. A naming convention must specify a class of identifier: values, functions or types.

One or more mapping actions may be specified, but the same class of mapping action may not be specified twice.

More detail is provided in the identifiers section.

Specific names can be renamed arbitrarily with rename; this will override name clauses.

gen Lisp {
  use feature_one
  ban feature_two
  drop incompatible_*
  drop specific_value
  drop Incompatible_*
  name values(lower, hyphens)
  name types(camel, underscores)
  name functions(prefix "func-", keep case, hyphens)
  rename value1 as "target-name"
  rename (value1 as "target1", value2 as "target2", Type1 as "typeOne")
gen (Python, Ruby)

Control flow

Pragmas must be order-independent as constructed. If two pragmas conflict, this is an error. If a pragma is repeated, this is an error, but an implementation may offer an option to suppress the error.

import module1.my_function
import mudule2.my_function  ;; Error!
import module2.my_function as other_functon ;; OK

Type statements must be order-independent as constructed. As with pragmas, if two type definitions conflict, it is an error. If a type definition is repeated, it is a suppressible error.

Type definitions are visible throughout the module, regardless of order. Type definitions may not form a cycle.

The declarative def, let, bare assignments, and func statements are applied in sequential order.

Then, module exports are applied and, finally, generation pragmas.

If an import is overridden by a let before it is visible to another statement, this is an error. If an import is overridden by a def, this is an error.