Language Syntax
Complete reference for Zenoscript syntax and language features.
Variables and Constants
Let Bindings
typescript
// Immutable bindings (recommended)
let name = "Alice"
let age = 30
let isActive = true
// Type annotations (optional)
let score: number = 95.5
let message: string = "Hello"
let items: string[] = ["a", "b", "c"]Variable Declarations
typescript
// Mutable variables (use sparingly)
var counter = 0
counter = counter + 1Data Types
Basic Types
typescript
// Numbers
let integer = 42
let float = 3.14
let negative = -10
// Strings
let greeting = "Hello, World!"
let template = `Hello, ${name}!`
let multiline = `
This is a
multiline string
`
// Booleans
let isTrue = true
let isFalse = false
// Arrays
let numbers = [1, 2, 3, 4, 5]
let mixed = [1, "hello", true]
let empty: number[] = []
// Objects
let user = {
name: "Alice",
age: 30,
active: true
}Atoms
Type-safe constants using symbol syntax:
typescript
// Atom declaration
let :success = Symbol.for("success")
let :error = Symbol.for("error")
let :pending = Symbol.for("pending")
// Using atoms
let status = :pending
let result = :success
// Atoms in pattern matching
let message = match status {
:pending => "Loading..."
:success => "Done!"
:error => "Failed!"
_ => "Unknown"
}Function Call Syntax
Optional Parentheses
Zenoscript supports optional parentheses for function calls, inspired by functional languages like Elixir:
typescript
// Traditional function calls
console.log("Hello")
processValue(42)
validateInput(userData)
// Optional parentheses syntax
console.log "Hello"
processValue 42
validateInput userData
// Works with different argument types
myFunction "string argument"
calculate 3.14
handleUser userObject
processArray [1, 2, 3]
// Multiple arguments still require parentheses
add(5, 10) // Multiple args need parenthesesSmart keyword detection ensures control flow statements work correctly:
typescript
// Keywords are preserved
if condition { doSomething() }
let value = expression
return result
// Compiles correctly to:
if (condition) { doSomething(); }
const value = expression;
return result;Function Return Statements
Functions automatically return their last expression, eliminating boilerplate:
typescript
// Concise single-expression functions
let add = (a, b) => { a + b }
let square = (x) => { x * x }
let greet = (name) => { `Hello, ${name}!` }
// Multi-statement functions with automatic return
let processUser = (user) => {
let validated = validateUser(user)
let normalized = normalizeData(validated)
let enriched = enrichUserData(normalized)
enriched // Automatically returned
}
// Explicit returns still work
let explicitReturn = (x) => {
if (x < 0) {
return "negative"
}
return "positive"
}
// Mixed statements with automatic return
let complexFunction = (data) => {
console.log("Processing data...")
let result = processData(data)
console.log("Processing complete")
result // This gets returned automatically
}Compiles to TypeScript with explicit returns:
typescript
const add = (a, b) => { return a + b };
const square = (x) => { return x * x };
const processUser = (user) => {
const validated = validateUser(user);
const normalized = normalizeData(validated);
const enriched = enrichUserData(normalized);
return enriched;
};Structs
Define structured data types:
typescript
// Simple struct
struct User {
id: number;
name: string;
email: string;
}
// Generic struct
struct Container<T> {
value: T;
timestamp: number;
}
// Struct with optional fields
struct Config {
host: string;
port?: number;
ssl?: boolean;
}
// Using structs
let user: User = {
id: 1,
name: "Alice",
email: "alice@example.com"
}
let config: Config = {
host: "localhost",
port: 8080
}Traits
Define interfaces and contracts:
typescript
// Simple trait
trait Drawable {
draw(): void;
}
// Generic trait
trait Serializable<T> {
serialize(): T;
deserialize(data: T): this;
}
// Trait with default methods
trait Logger {
log(message: string): void;
// Default implementation
logError(error: string): void {
this.log(`ERROR: ${error}`)
}
}Functions
Function Declarations
typescript
// Arrow functions
let add = (a: number, b: number) => a + b
let greet = (name: string) => `Hello, ${name}!`
// Multi-line functions
let complexFunction = (x: number, y: number) => {
let sum = x + y
let product = x * y
return { sum, product }
}
// Function with destructuring
let getName = ({ first, last }: { first: string, last: string }) =>
`${first} ${last}`
// Higher-order functions
let map = <T, U>(array: T[], fn: (T) => U): U[] =>
array.map(fn)
let filter = <T>(array: T[], predicate: (T) => boolean): T[] =>
array.filter(predicate)Currying
typescript
// Curried function
let multiply = (a: number) => (b: number) => a * b
let double = multiply(2)
let triple = multiply(3)
let result1 = double(5) // 10
let result2 = triple(4) // 12
// Partial application
let greetWith = (greeting: string) => (name: string) =>
`${greeting}, ${name}!`
let sayHello = greetWith("Hello")
let sayGoodbye = greetWith("Goodbye")Pattern Matching
Basic Matching
typescript
// Match expressions
let describe = (value) => match value {
0 => "zero"
1 => "one"
2 => "two"
_ => "many"
}
// Match with guards
let classify = (n: number) => match n {
x if x < 0 => "negative"
0 => "zero"
x if x > 0 && x < 10 => "small positive"
_ => "large positive"
}Destructuring
typescript
// Array destructuring
let [first, second, ...rest] = [1, 2, 3, 4, 5]
// Object destructuring
let { name, age } = user
let { name: userName, age: userAge } = user
// Nested destructuring
let { user: { name }, config: { port } } = response
// Pattern matching with destructuring
let processResult = (result) => match result {
{ type: "success", data } => `Success: ${data}`
{ type: "error", message, code } => `Error ${code}: ${message}`
{ type: "pending" } => "Processing..."
_ => "Unknown result"
}List Patterns
typescript
// Match list patterns
let processItems = (items) => match items {
[] => "empty list"
[single] => `one item: ${single}`
[first, second] => `two items: ${first}, ${second}`
[head, ...tail] => `${head} and ${tail.length} more`
}
// Recursive list processing
let sum = (numbers) => match numbers {
[] => 0
[head, ...tail] => head + sum(tail)
}Pipe Operations
Chain operations for readable data flow:
typescript
// Basic piping
let result = value
|> transform
|> validate
|> process
// With function calls
let processed = data
|> filter(x => x > 0)
|> map(x => x * 2)
|> reduce((a, b) => a + b, 0)
// String processing
let cleaned = input
|> trim
|> toLowerCase
|> replace(/\s+/g, "-")
// Async piping
let response = await url
|> fetch
|> (res => res.json())
|> validateResponseControl Flow
Conditionals
typescript
// If expressions
let message = if (user.active) "Welcome!" else "Please activate"
// Multi-line if
let status = if (score >= 90) {
"excellent"
} else if (score >= 70) {
"good"
} else {
"needs improvement"
}
// Ternary operator
let label = isActive ? "Active" : "Inactive"Loops
typescript
// For loops (avoid in functional style)
for (let i = 0; i < items.length; i++) {
console.log(items[i])
}
// For-of loops
for (let item of items) {
console.log(item)
}
// Functional alternatives (preferred)
items |> forEach(item => console.log(item))
items |> map(item => item.toUpperCase())
items |> filter(item => item.length > 3)Error Handling
Option Type Pattern
typescript
// Option type
let findUser = (id: number) =>
users.find(u => u.id === id) ?
{ type: :some, value: users.find(u => u.id === id) } :
{ type: :none }
// Using option
let userResult = match findUser(123) {
{ type: :some, value } => `Found: ${value.name}`
{ type: :none } => "User not found"
}Result Type Pattern
typescript
// Result type for operations that can fail
let parseJson = (text: string) => {
try {
let data = JSON.parse(text)
return { type: :ok, value: data }
} catch (error) {
return { type: :error, message: error.message }
}
}
// Using result
let handleJson = (text) => match parseJson(text) {
{ type: :ok, value } => processData(value)
{ type: :error, message } => logError(message)
}Modules and Imports
Importing
typescript
// ES module imports
import { readFile } from "fs/promises"
import express from "express"
import * as utils from "./utils"
// Zenoscript module imports
import { User, createUser } from "./models/user.zs"
import { DatabaseConfig } from "./config.zs"Exporting
typescript
// Named exports
export let PI = 3.14159
export let square = (x: number) => x * x
export struct Point {
x: number;
y: number;
}
// Default export
let main = () => {
console.log("Hello from Zenoscript!")
}
export default mainComments
typescript
// Single line comment
/*
Multi-line comment
spanning multiple lines
*/
/**
* Documentation comment
* @param name The user's name
* @returns A greeting message
*/
let greet = (name: string) => `Hello, ${name}!`Type Annotations
typescript
// Variable annotations
let name: string = "Alice"
let age: number = 30
let active: boolean = true
// Function annotations
let add = (a: number, b: number): number => a + b
let greet = (name: string): string => `Hello, ${name}!`
// Generic annotations
let identity = <T>(value: T): T => value
let map = <T, U>(array: T[], fn: (T) => U): U[] => array.map(fn)
// Complex types
let user: { name: string; age: number } = { name: "Alice", age: 30 }
let callback: (error: Error | null, data?: any) => void = () => {}Operators
Arithmetic
typescript
let a = 10 + 5 // Addition
let b = 10 - 5 // Subtraction
let c = 10 * 5 // Multiplication
let d = 10 / 5 // Division
let e = 10 % 3 // Modulo
let f = 2 ** 3 // ExponentiationComparison
typescript
let eq = a === b // Strict equality
let neq = a !== b // Strict inequality
let lt = a < b // Less than
let lte = a <= b // Less than or equal
let gt = a > b // Greater than
let gte = a >= b // Greater than or equalLogical
typescript
let and = a && b // Logical AND
let or = a || b // Logical OR
let not = !a // Logical NOT
let nullish = a ?? b // Nullish coalescingAssignment
typescript
let x = 5 // Assignment
x += 3 // Add and assign
x -= 2 // Subtract and assign
x *= 4 // Multiply and assign
x /= 2 // Divide and assignThis covers the essential syntax of Zenoscript. For more advanced patterns, check out the Advanced Examples.