Topaz Language Syntax
Welcome to the official Topaz syntax reference! This document provides a comprehensive overview of the fundamental grammar and syntactic constructs that make up the Topaz language. Topaz is engineered with an emphasis on unambiguous clarity, extreme efficiency, and a LISP-inspired S-expression structure, making it both powerful for developers and exceptionally well-suited for AI tools and applications.
Core Syntactic Philosophy
Before diving into the specifics, understanding these core principles will help you grasp the essence of Topaz syntax:
- S-Expression Based: Like many dialects of Lisp and Scheme, all Topaz code is written as S-expressions (Symbolic Expressions). An S-expression is either an atom (a fundamental data value like a number or symbol) or a list of S-expressions enclosed in parentheses
()
. This uniform, tree-like structure simplifies parsing, makes the language highly regular, and enables powerful metaprogramming capabilities. - Expression-Oriented: In Topaz, almost everything is an expression that evaluates to a value. This contributes to the language's conciseness and functional nature.
- Minimalism and Consistency: The syntax is designed with a small set of core rules that are applied consistently throughout the language.
- Static Typing with Strong Inference: While Topaz is statically typed for safety and performance, explicit type annotations are often unnecessary due to its powerful type inference system. (See Data Types for more).
- Immutability by Default: Data structures are primarily immutable, promoting safer and more predictable code, especially in concurrent environments.
- Functional Programming Principles: Topaz embraces and encourages functional programming paradigms, leveraging pure functions and higher-order processes.
Fundamental Elements
1. S-Expressions
The basic syntactic unit in Topaz.
;; Atoms:
42 ;; An Integer number
3.14159 ;; A Floating-point number
"Hello, Topaz" ;; A String
:my-symbol ;; A Symbol
is-ready? ;; An Identifier (can also be an atom)
#true ;; Boolean true literal
#false ;; Boolean false literal
NULL_SIG ;; The special Null Signal value
;; Lists (which are also S-expressions):
(+ 10 20) ;; A simple operation: operator followed by arguments
($ x 100) ;; A definition: special form, identifier, expression
(λ (a b) (+ a b)) ;; A lambda (anonymous process) definition
The first element of a list is typically an operator (a built-in operation or a user-defined process) or a special form (like $
or λ
). The remaining elements are its arguments.
2. Comments
Comments are ignored by the Topaz interpreter/compiler and are used for human-readable annotations. Topaz uses double semicolons ;;
for single-line comments. Everything from ;;
to the end of the line is a comment.
;; This is a full-line comment.
($ pi 3.14159) ;; This comment follows an expression on the same line.
3. Identifiers
Identifiers are names used for variables, constants, processes, parameters, etc. They typically start with a letter or certain allowed symbols and can contain letters, numbers, and some special characters (e.g., -
, ?
, !
). Conventions will be detailed further in style guides.
$my-variable 10$ process? (λ (x) (> x 0))
$ update-state! (λ (s) (;;...
))
Core Syntactic Forms
These are the primary constructs used to build Topaz programs.
1. Definitions: $
The $
special form binds a value (the result of an expression) to an identifier in the current scope.
Syntax: ($ IDENTIFIER EXPRESSION)
IDENTIFIER
: The name to define.EXPRESSION
: Any Topaz expression. Its evaluated result is bound toIDENTIFIER
.
Examples:
($ age 30)
($ message "Welcome to Topaz")
($ sum (+ 15 27)) ;; sum is bound to 42
;; Defining a named process (function)
($ add-numbers
(λ (x y)
(+ x y)
)
)
2. Operations (Process/Function Calls)
Calling a process (user-defined or built-in) uses prefix notation.
Syntax: (OPERATOR ARGUMENT_1 ARGUMENT_2 ... ARGUMENT_N)
OPERATOR
: An identifier that evaluates to a process, or a built-in operator symbol.ARGUMENT_n
: Expressions that are evaluated before the operator is applied to them.
Examples:
(+ 1 2 3) ;; Evaluates to 6
(CONCAT "Topaz " "is " "fun!") ;; Evaluates to "Topaz is fun!"
(> 10 5) ;; Evaluates to 1 (true in boolean contexts)
;; Using the 'add-numbers' process defined above
(add-numbers 100 200) ;; Evaluates to 300
3. Data Literals
Topaz has direct syntactic representations for its core data types. For a comprehensive guide, see the Data Types page.
- Numbers:
123
,-10
,3.14
,0.0
- Strings:
"A string"
,""
(empty string) * Booleans:#true
(true) and#false
(false) are the official boolean literals.($ is-enabled #true) ($ has-errors #false)
- Symbols: Prefixed with a colon (e.g.,
:active
,:error-code
) or quoted (e.g.,'my-symbol
). Used for unique identifiers or enumerated-like values.($ current-status :pending)
- Vectors (Ordered Lists): Enclosed in square brackets
[]
.($ empty-vec []) ($ primes [2 3 5 7 11]) ($ mixed-data [10 "label" :option-a])
- Maps (Key-Value Pairs): Start with
(#
and then alternating keys and values, enclosed in)
.($ empty-map (#)) ($ point (# :x 10 :y 20)) ($ config (# "host" "localhost" "port" 8080 :retries 3))
NULL_SIG
: A special literal representing the absence of a value.($ no-result NULL_SIG)
4. Conditional Branching: IF
The IF
special form provides conditional evaluation.
Syntax: (IF CONDITION_EXPR TRUE_EXPR FALSE_EXPR)
CONDITION_EXPR
: Evaluated.#true
means the condition is true;#false
orNULL_SIG
means false.TRUE_EXPR
: Evaluated ifCONDITION_EXPR
is true.FALSE_EXPR
: Evaluated ifCONDITION_EXPR
is false. (OmittingFALSE_EXPR
results inNULL_SIG
if the condition is false).
Examples:
($ user-age 25)
($ access-level (IF (>= user-age 18)
:adult
:minor)) ;; access-level becomes :adult
($ temperature 15)
($ weather-advice (IF (< temperature 0)
"Wear a very warm coat!"
(IF (< temperature 15)
"A light jacket should be fine."
"Enjoy the pleasant weather!"
)
))
5. Anonymous Processes (Lambdas): λ
The λ
(lambda) special form creates an anonymous process (function).
Syntax: (λ (PARAM_1 ... PARAM_N) BODY_EXPR_1 ... BODY_EXPR_N)
(PARAM_1 ... PARAM_N)
: A list of parameter identifiers. Use()
for no parameters.BODY_EXPR_n
: One or more expressions forming the process body. The value of the last expression is the return value.
Examples:
;; A process that squares a number
(λ (n) (* n n))
;; Using $ to give a name to a lambda-defined process
($ square (λ (n) (* n n)))
(square 7) ;; Evaluates to 49
($ create-greeter
(λ (greeting)
(λ (name) (string:concat greeting ", " name "!"))
)
)
($ hello-greeter (create-greeter "Hello"))
(hello-greeter "Topaz Developer") ;; Evaluates to "Hello, Topaz Developer!"
6. User-Defined Types: DEFINE-TYPE
The DEFINE-TYPE
special form creates structured data types (similar to structs or records).
Syntax: (DEFINE-TYPE TypeName (# :fieldName1 FieldType1 :fieldName2 FieldType2 ...))
Examples:
;; Define a Point type with x and y coordinates
(DEFINE-TYPE Point (# :x Float :y Float))
;; Create instances using map literals that match the type structure
($ origin (# :x 0.0 :y 0.0))
($ point1 (# :x 10.5 :y -5.0))
;; Define a Person type with multiple field types
(DEFINE-TYPE Person (# :name String :age Integer :active Boolean))
($ user (# :name "Alice" :age 30 :active #true))
7. Enumerated Types: DEFINE-ENUM
The DEFINE-ENUM
special form creates enumerated types with a fixed set of symbol values.
Syntax: (DEFINE-ENUM EnumName :Value1 :Value2 :Value3 ...)
Examples:
;; Define a color enumeration
(DEFINE-ENUM Color :RED :GREEN :BLUE)
;; Define a status enumeration
(DEFINE-ENUM Status :PENDING :COMPLETED :FAILED :CANCELLED)
;; Use enumeration values
($ my-color :RED)
($ task-status :PENDING)
8. Generic Types (Type Parameters): λ [TypeParams]
Generic processes can work with multiple types by declaring type parameters.
Syntax: (λ [TypeParam1 TypeParam2 ...] (param1: Type1 param2: Type2 ...) body-expr ...)
Examples:
;; A generic identity function that works with any type T
($ identity
(λ [T] (value: T)
value
)
)
;; A generic function to get the first element of a vector
($ first-element
(λ [E] (vec: (Vector E))
(vector:first vec)
)
)
;; Using generic functions
($ num-result (identity 42)) ;; T is inferred as Integer
($ str-result (identity "hello")) ;; T is inferred as String
($ first-num (first-element [1 2 3])) ;; E is inferred as Integer
9. Module System
9.1. Module Definition: MODULE
The MODULE
special form defines a module and specifies which symbols to export.
Syntax:
(MODULE module-name
(EXPORT identifier1 identifier2 ...)
;; ... module body with definitions ...
)
Example (math.tpz
):
(MODULE math
(EXPORT PI add square)
($ PI 3.14159)
($ add (λ (a b) (+ a b)))
($ square (λ (n) (* n n)))
($ private-helper (λ () ...)) ;; Not exported, internal use only
)
9.2. Module Import: IMPORT
The IMPORT
special form brings functionality from other modules into the current scope.
Syntax:
(IMPORT module-name (identifier1 identifier2 ...))
: Import specific symbols(IMPORT module-name :as alias)
: Import entire module with alias (recommended)
Examples:
;; Import specific symbols from math module
(IMPORT math (add PI))
(io:print (core:to-string (+ (add 5 10) PI)))
;; Import math module with alias (recommended approach)
(IMPORT math :as m)
(io:print (core:to-string (m:add (m:square 5) m:PI)))
10. Macro System: DEFMACRO
The DEFMACRO
special form enables compile-time code transformation using quasiquote mechanisms.
Syntax: (DEFMACRO macro-name (param1 param2 ...) template-body)
Key Elements:
`
(backtick/quasiquote): Defines a code template where most content is not evaluated,
(comma/unquote): Within quasiquote, evaluates the expression and inserts the result,@
(comma-at/unquote-splicing): Evaluates a list and splices its contents into the template
Examples:
;; Define a 'when' macro that executes body only if condition is true
(DEFMACRO when (condition body-expressions...)
`(IF ,condition
(BEGIN ,@body-expressions)
NULL_SIG
)
)
;; Use the 'when' macro
($ x 10)
(when (> x 5)
(io:print "x is greater than 5")
(io:print "This also gets executed")
)
;; Define a 'unless' macro (opposite of when)
(DEFMACRO unless (condition body-expressions...)
`(IF ,condition
NULL_SIG
(BEGIN ,@body-expressions)
)
)
Standard Library and Naming Conventions
With the introduction of the module system, Topaz follows these naming conventions:
Core Module
The core
module contains essential language operations and is automatically imported in all files:
+
,-
,*
,/
: Arithmetic operations=
,<
,>
,<=
,>=
: Comparison operationsIF
,$
,λ
: Special formscore:to-string
: Type conversion functions
Module-Qualified Functions
Standard library functions use module prefixes:
(io:print ...)
: Input/output operations(string:concat ...)
: String manipulation(vector:map ...)
: Vector operations(result:ok ...)
,(result:err ...)
: Result type constructors(concurrent:spawn ...)
: Concurrency operations
Example Usage:
(IMPORT string :as str)
(IMPORT vector :as vec)
($ numbers [1 2 3 4 5])
($ doubled (vec:map (λ (n) (* n 2)) numbers))
($ result-string (str:concat "Doubled: " (core:to-string doubled)))
(io:print result-string)
Future Language Extensions
This reference covers Topaz v1.0 syntax. Future versions will include:
- Advanced Pattern Matching:
MATCH
expressions for deconstructing complex data types - Type Classes/Interfaces: For defining shared behavior across types
- Async/Await Primitives: For asynchronous programming patterns
- FFI (Foreign Function Interface): For interoperability with other languages
Stay updated by checking our Guides and the main Topaz documentation page.