SESI LANGUAGE SPECIFICATION

Sesi Built-in Functions Reference

I/O Functions

print(...args)

Print values to standard output, separated by spaces.

print "Hello"
print 42
print "Value:", 10 + 20
print [1, 2, 3]

Returns: null

---

input(prompt) -> string

Prompt the user for terminal input, wait for them to press Enter, and return their response.

let name = input("Enter your name: ")
print "Hello," name

Parameters:

  • prompt (string): The text to display as a prompt before reading input. Optional.

Returns: string

---

Type Functions

type(value) -> string

Get the type name of a value.

type(42)           // "number"
type("hello")      // "string"
type(true)         // "bool"
type(null)         // "null"
type([1, 2, 3])    // "array"
type({})           // "object"

Returns: string - one of: "number", "string", "bool", "null", "array", "object", "unknown"

---

str(value) -> string

Convert any value to a string.

str(42)            // "42"
str(3.14)          // "3.14"
str(true)          // "true"
str([1, 2, 3])     // "[1, 2, 3]"
str({ "a": 1 })        // "{'a': 1}"

Returns: string

---

to_json(value) -> string

Convert an array or object into a valid, formatted JSON string.

to_json({ "a": 1, "b": [1, 2] })
/*
{
  "a": 1,
  "b": [1, 2]
}
*/

Returns: string (valid JSON)

---

from_json(string) -> any

Parse a valid JSON string back into a native Sesi primitive, array, or object.

let raw = "{\"a\": 1, \"b\": [1, 2]}"
let obj = from_json(raw)
print obj["a"]     // 1

Returns: any - native Sesi primitive, array, or object, or null if parsing fails

---

num(value) -> number

Convert a value to a number.

num("42")          // 42
num("3.14")        // 3.14
num(true)          // 1
num(false)         // 0
num("hello")       // null (can't convert)

Returns: number or null if conversion fails

---

bool(value) -> bool

Convert a value to boolean.

bool(1)            // true
bool(0)            // false
bool("")           // false
bool("hello")      // true
bool([])           // true
bool(null)         // false

Returns: bool - Uses truthiness rules

---

Collection Functions

len(collection) -> number

Get the length of a string, array, or object.

len("hello")       // 5
len([1, 2, 3])     // 3
len({ "a": 1, "b": 2 })  // 2
len(null)          // null (invalid)

Returns: number or null if not a collection

---

range(n) -> array

Create an array of numbers from 0 up to (but not including) n.

range(5)           // [0, 1, 2, 3, 4]

Returns: array

---

push(array, value) -> array

Add an element to the end of an array.

let arr = [1, 2, 3]
push(arr, 4)
print arr          // [1, 2, 3, 4]

Note: Modifies array in-place and returns it.

Returns: array

---

pop(array) -> any

Remove and return the last element of an array.

let arr = [1, 2, 3]
let last = pop(arr)
print last         // 3
print arr          // [1, 2]

Returns: The removed element, or null if array is empty

---

join(array, separator) -> string

Join array elements into a string with separator.

let arr = [1, 2, 3]
join(arr, "-")     // "1-2-3"
join(["a", "b"], ", ")  // "a, b"

Returns: string

---

split(string, separator) -> array

Split a string into an array by separator.

split("a,b,c", ",")     // ["a", "b", "c"]
split("hello world", " ")  // ["hello", "world"]

Returns: array

---

to_upper(string) -> string

Converts all alphabetic characters in a string to uppercase.

to_upper("hello")      // "HELLO"
to_upper("Sesi V2.0")  // "SESI V2.0"

Returns: string or null if not a string

---

to_lower(string) -> string

Converts all alphabetic characters in a string to lowercase.

to_lower("WORLD")      // "world"
to_lower("Sesi V2.0")  // "sesi v2.0"

Returns: string or null if not a string

---

trim(string) -> string

Removes whitespace from both ends of a string.

trim("  spaces  ")  // "spaces"

Returns: string or null if not a string

---

slice(collection, start, end = null) -> string | array

Extracts a section of a string or array and returns it as a new string or array, without modifying the original.

slice("abcdef", 1, 4)         // "bcd"
slice([10, 20, 30, 40], 2)    // [30, 40]

Parameters:

  • collection (string or array): The collection to slice.
  • start (number): The zero-based index at which to begin extraction.
  • end (number, optional): The zero-based index before which to end extraction. If omitted, slices to the end of the collection.

Returns: string or array based on the input collection type, or null if arguments are invalid

---

swap(string, target, replacement) -> string

Replaces all occurrences of a target substring within a string with a replacement substring.

swap("a_b_c", "_", "-")    // "a-b-c"

Parameters:

  • string (string): The source string.
  • target (string): The substring to be replaced.
  • replacement (string): The substring that replaces the target.

Returns: string or null if arguments are invalid

---

contains(string, sub) -> bool

Returns true if the string contains the given substring, false otherwise.

contains("hello.sesi", ".sesi")  // true
contains("hello.sesi", ".ts")    // false

Parameters:

  • string (string): The string to search within.
  • sub (string): The substring to search for.

Returns: bool or null if arguments are invalid

---

locate(string, sub) -> number

Returns the index of the first occurrence of a substring within a string. Returns -1 if the substring is not found.

locate("hello.sesi", ".")    // 5
locate("hello.sesi", "ts")   // -1

Parameters:

  • string (string): The string to search within.
  • sub (string): The substring to find.

Returns: number (zero-based index, or -1 if not found), or null if arguments are invalid

---

keys(object) -> array

Get all keys of an object.

let obj = { "name": "Alice", "age": 30 }
keys(obj)          // ["name", "age"]

Returns: array or null if not an object

---

values(object) -> array

Get all values of an object.

let obj = {"name": "Alice", "age": 30}
values(obj)        // ["Alice", 30]

Returns: array or null if not an object

---

map(array, callback) -> array

Creates a new array populated with the results of calling a provided function on every element in the calling array.

let numbers = [1, 2, 3]
fn square(x) { return x * x }
let squares = map(numbers, square) // [1, 4, 9]

Parameters:

  • array (array): The source array.
  • callback (fn): Function to execute on each element. Receives arguments: (item, index, array).

Returns: array

---

filter(array, callback) -> array

Creates a shallow copy of a portion of a given array, filtered down to just the elements from the given array that pass the test implemented by the provided function.

let numbers = [1, 2, 3, 4]
fn isEven(x) { return x % 2 == 0 }
let evens = filter(numbers, isEven) // [2, 4]

Parameters:

  • array (array): The source array.
  • callback (fn): Function is a predicate, to test each element of the array. Return a truthy value to keep the element. Receives arguments: (item, index, array).

Returns: array

---

reduce(array, callback, initialValue = null) -> any

Executes a user-supplied "reducer" callback function on each element of the array, in order, passing in the return value from the calculation on the preceding element. The final result of running the reducer across all elements of the array is a single value.

let numbers = [1, 2, 3, 4]
fn sum(acc, x) { return acc + x }
let total = reduce(numbers, sum) // 10
let totalWithInitial = reduce(numbers, sum, 10) // 20

Parameters:

  • array (array): The source array.
  • callback (fn): A function to execute on each element in the array (except the first, if no initialValue is provided). Receives arguments: (accumulator, currentValue, index, array).
  • initialValue (any, optional): A value to which accumulator is initialized on the first call. If no initial value is supplied, the first element in the array is used as the initial accumulator value, and reduce() starts executing the callback from the second element (index 1).

Returns: any

---

find(array, callback) -> any

Returns the first element in the provided array that satisfies the provided testing function. If no values satisfy the testing function, null is returned.

let numbers = [1, 3, 4, 7]
fn isEven(x) { return x % 2 == 0 }
let match = find(numbers, isEven) // 4

Parameters:

  • array (array): The source array.
  • callback (fn): Function to execute on each value in the array. Receives arguments: (item, index, array).

Returns: any or null

---

File System Functions

read_file(path) -> string

Read the contents of a file as a string.

let text = read_file("input.txt")
print text

Note: Paths are resolved relative to the current working directory.

Returns: string

---

write_file(path, content) -> bool

Write string content to a file. Overwrites the file if it exists.

let success = write_file("output.txt", "Hello, Sesi!")
if success {print "File written successfully"}

Note: Paths are resolved relative to the current working directory.

Returns: bool (true on success, throws on error)

---

write_image(path, base64_content) -> bool

Write base64 encoded string content as an image file. Overwrites the file if it exists.

let success = write_image("logo.png", logo_data)
if success {print "Image safely stored"}

Note: Paths are resolved relative to the current working directory.

Returns: bool (true on success, throws on error)

---

list_dir(path) -> array

List the contents of a directory as an array of strings.

let files = list_dir(".")
print files

Note: Paths are resolved relative to the current working directory.

Returns: array

---

make_dir(path) -> bool

Create a new directory recursively. Returns true on success, false or throws on failure.

let success = make_dir("new_directory")
if success {print "Directory created successfully"}

Note: Paths are resolved relative to the current working directory.

Returns: bool (true on success, throws on error)

---

rename(oldPath, newPath) -> bool

Rename or move a file or directory.

let success = rename("old_name.txt", "new_name.txt")
if success {print "File renamed successfully"}

Parameters:

  • oldPath (string): The current path of the file or directory.
  • newPath (string): The target path.

Returns: bool (true on success, throws on error)

---

archive(sourcePath, destPath = null) -> bool

Recursively backup/copy a file or directory.

// Backs up to a target destination
archive("src/index.ts", "backup/index.ts")

// Automatically backs up to the hidden `.archive` directory in project root
archive("src/index.ts") // Saves to .archive/index.ts

Parameters:

  • sourcePath (string): The file or directory to back up.
  • destPath (string, optional): The destination path. Defaults to .archive/ in the current working directory if omitted.

Returns: bool (true on success, throws on error)

---

trash(path, autoRemove = false) -> bool

Delete a file or directory. By default, moves the item to a local .trash recycle bin directory, uniquely naming it with a timestamp. Can optionally delete permanently.

// Moves file to project's .trash folder with a unique timestamp (e.g. temp_1719253450000.txt)
trash("temp.txt")

// Permanently and recursively deletes the file/directory immediately
trash("temp.txt", true)

Parameters:

  • path (string): The path of the file or directory to delete.
  • autoRemove (bool, optional): If true, permanently deletes the item instead of moving it to the trash folder. Defaults to false.

Returns: bool (true on success, returns false if path doesn't exist, throws on error)

convert(type) { config } { file } -> string

Convert file or document content between formats.

  • type: doc (documents/text), media (images/video), or audio.
  • config: Object containing conversion parameters:

- file_type: Input format extension (e.g. "md", "csv", "png", "wav"). Optional when input is a local file path (inferred from extension).

- output_type: Target output format extension (e.g. "html", "json", "jpg", "mp3"). Required.

  • file: Input string content or input local file path.

If the input is a local file path, the converted content is saved to a file of the same name and directory with the target extension, and the path to the output file is returned. If the input is raw string content, the converted content is returned directly.

// Raw content conversion
let html = convert(doc) {file_type: "md", output_type: "html"} {"# Hello"}
print html // "

Hello

" // File path conversion let out_path = convert(doc) {output_type: "html"} {"document.md"} print out_path // "document.html"

Returns: string (converted content or path to the converted file)

---

Network Functions

web_get(url, headers = {}) -> string

Perform a synchronous HTTP GET request and return the response body as a string.

let response = web_get("https://jsonplaceholder.typicode.com/posts/1")
print response

Returns: string

---

web_send(url, body, headers = {}) -> string

Perform a synchronous HTTP POST request with a request body and return the response as a string.

let payload = "{\"title\": \"foo\"}"
let response = web_send("https://jsonplaceholder.typicode.com/posts", payload)
print response

Returns: string

---

listen(port, handler) -> object

Starts a native HTTP server listening on the specified port. Requests are passed to the handler function (which can be a synchronous function or an async fn).

The handler receives a request object with the following properties:

  • method: The HTTP method (e.g. "GET", "POST").
  • path: The path portion of the URL (e.g. "/test-route").
  • headers: A map of the HTTP request headers.
  • body: The request body as a string.
  • query: A map of the URL query parameters.

The handler can return:

  • A simple string: Sent as the HTTP response body with status 200 and Content-Type: text/html.
  • A structured response object containing:

- "status": HTTP status code (default: 200).

- "headers": Map of response headers (default: Content-Type: text/html).

- "body": Response body (string, or object which gets serialized to JSON).

Returns a server control object with a close() function to stop the server programmatically.

async fn handleRequest(req) {
  print "Request path is:" req.path
  return {
    "status": 200,
    "body": "Hello from Sesi Server!"
  }
}

let server = listen(8080, handleRequest)
// ...
server.close()

Returns: object containing a close function.

---

api(port, handler) -> object

Starts a native WebSocket server listening on the specified port. Incoming client messages are passed to the handler function (which can be a synchronous function or an async fn).

The handler receives two arguments:

  • client: A controller object for the connected client containing:

- send(message): Sends a message to the client (automatically converted to a string).

- close(): Closes the connection to this client.

  • message: The incoming message payload as a string.

Returns a server control object with a close() function to stop the server programmatically.

fn handleMessage(client, msg) {
  print "WS received:" msg
  client.send("Echo: " + msg)
}

let server = api(8989, handleMessage)
// ...
server.close()

Returns: object containing a close function.

---

Audio Functions (std/audio)

The std/audio module provides functions for sound synthesis and playback.

allow "std/audio" in with Audio

// Play a simple beep (frequency in Hz, duration in ms)
Audio.beep(440, 200)

// Play a musical note
Audio.play("C4", 500)
Audio.play("E4", 500)
Audio.play("G4", 500)

// Synthesize a waveform and get base64 WAV data
let b64 = Audio.synth(440, 1000, "square")

// Save a synthesized tone to a file
Audio.save("tone.wav", "A4", 2000, "sine", {"attack": 50, "release": 500})

// Professional Sample-Based Synthesis (SoundFonts)
let piano = Audio.sf2("GeneralUser-GS.sf2", {"instrument": 0, "gain": 1.5})
let string_pad = Audio.sf2("GeneralUser-GS.sf2", {"instrument": 49})

// Native Physical Modeling (Drums)
let kick = {"note": "C1", "ms": 500, "type": "kick"}
let snare = {"note": "C4", "ms": 500, "type": "snare"}
let hat = {"note": "G8", "ms": 250, "type": "hat", "pan": 0.3}

// Save a sequence (song) of notes
let song = [
  {"note": "C4", ms: 500, "vol": 0.8},
  {"note": "E4", ms: 500, "pan": -0.5},
  {"note": "G4", ms: 1000, "cutoff": 5000} // LPF Filter
]
Audio.sequence("song.wav", song, "triangle")

// Save tracks to a MIDI file
Audio.midi("song.mid", song)

// Mix multiple tracks (Native Synthesis and SoundFonts) into a single stereo WAV
let lead = [piano("C4", 500), piano("E4", 500)]
let bass = [kick, snare]
Audio.mix("mix.wav", [lead, bass], "sine", {"saturate": 1.5})

beep(frequency, duration)

Plays a simple sine wave beep.

play(note, duration, options)

Plays a musical note (e.g., "C4", "A#3", "Bb5"). Accepts options for ADSR, volume, and panning.

synth(frequency_or_note, duration, type, options)

Returns a base64 encoded WAV string. type can be "sine", "square", "saw", "triangle", "noise", "kick", "snare", "hat", or "clap".

save(path, frequency_or_note, duration, type, options)

Saves a synthesized WAV file to the specified path.

sequence(path, notes_array, type, options)

Saves a multi-note sequence to a single WAV file. notes_array can be an array of note strings (e.g., ["C4", "D4"]), objects (e.g., [{note: "C4", ms: 250, pan: 0.5}]), or pre-rendered SF2 notes.

mix(path, tracks_array, type, options)

Saves a Stereo WAV file by mixing multiple tracks together. tracks_array is an array of note arrays. The mixer supports real-time ADSR envelopes, low-pass filtering (cutoff), stereo pan, soft-clipping saturation (saturate), and automatic high-speed batch rendering of SoundFont instruments.

midi(path, tracks)

Saves one or more tracks (arrays of note objects/strings) directly as a standard MIDI (.mid) file on disk.

sf2(path, options) -> fn(note, duration)

Returns a high-level instrument constructor function bound to a specific SoundFont file.

  • options: {"instrument": 0, "channel": 0, "gain": 1.5}
  • The returned function takes (note, ms) and generates a Sesi-native note object that the mixer will automatically batch-render using FluidSynth.

---

Music Theory Functions (std/theory)

The std/theory module abstracts the mathematics of music into simple, reusable logic, perfect for algorithmic composition.

allow "std/theory" in with Music

// Generate a C Major 7 chord array
let c_maj7 = Music.chord("C4", "M7") // ["C4", "E4", "G4", "B4"]

// Generate an A minor scale array
let a_minor = Music.scale("A3", "minor")

// Transpose notes up by 5 semitones (Perfect 4th)
let shifted = Music.transpose(c_maj7, 5) // ["F4", "A4", "C5", "E5"]

chord(root, type) -> array

Generates an array of notes for a given chord type.

  • Supported types: "M", "m", "dim", "aug", "7", "M7", "m7", "sus2", "sus4".

scale(root, type) -> array

Generates an array of notes for a given scale/mode.

  • Supported types: "major", "minor", "dorian", "phrygian", "lydian", "mixolydian", "locrian".

transpose(notes, semitones) -> array

Shifts a note or an array of notes up or down by the specified number of semitones.

duration(minutes, seconds) -> number

Converts minutes and seconds into Sesi-native absolute milliseconds.

bar(bars, bpm, beatsPerBar = 4) -> number

Converts a number of musical bars into milliseconds based on BPM and time signature (default: 4/4).

---

Drawing Functions (std/draw)

The std/draw module provides a comprehensive API for creating static or animated SVG graphics.

allow "std/draw" in with Draw

// Setup gradients
Draw.gradient("linear", "sky", [
  {"offset": "0%", "color": "blue"},
  {"offset": "100%", "color": "black"}
])

// Setup CSS keyframe animations
Draw.style("
  @keyframes spin {
    to { transform: rotate(360deg); }
  }
  .spinner { animation: spin 4s infinite linear; transform-origin: 50px 50px; }
")

// Render shapes with styling options
Draw.rect(0, 0, 100, 100, "url(#sky)")
Draw.circle(50, 50, 40, "red", {"class": "spinner"})
Draw.ellipse(50, 50, 20, 10, "gold")
Draw.polygon("30,20 85,20 90,75 25,75", "green")
Draw.path("M 10 10 C 20 20, 40 20, 50 10", "none", {"stroke": "white", "stroke-width": 2})

// Get the SVG string
let svg = Draw.render(100, 100)

// Save to a file
Draw.save_svg("drawing.svg", 100, 100)

clear()

Clears the current drawing and definition buffers.

circle(x, y, radius, fill, options = {})

Adds a circle to the drawing.

  • options (object, optional): Custom SVG attributes (e.g. {"id": "c1", "class": "pulse", "stroke-width": 2}).

rect(x, y, width, height, fill, options = {})

Adds a rectangle to the drawing.

  • options (object, optional): Custom SVG attributes.

line(x1, y1, x2, y2, stroke, options = {})

Adds a line to the drawing.

  • options (object, optional): Custom SVG attributes.

text(x, y, content, size, fill, options = {})

Adds text to the drawing.

  • options (object, optional): Custom SVG attributes.

ellipse(cx, cy, rx, ry, fill, options = {})

Adds an ellipse to the drawing.

  • options (object, optional): Custom SVG attributes.

polygon(points, fill, options = {})

Adds a polygon to the drawing.

  • points (string): A space-separated list of coordinate pairs (e.g. "100,10 250,190 10,190").
  • options (object, optional): Custom SVG attributes.

path(d, fill, options = {})

Adds an SVG path to the drawing.

  • d (string): Path data command string (e.g. "M 10 10 L 90 90").
  • options (object, optional): Custom SVG attributes.

gradient(type, id, stops, options = {})

Defines a linear or radial gradient in the section.

  • type (string): "linear" or "radial".
  • id (string): The identifier to use when referencing the gradient (e.g. "url(#my-id)").
  • stops (array): An array of stop configurations (e.g. [{"offset": "0%", "color": "red"}, {"offset": "100%", "color": "blue"}]).
  • options (object, optional): Custom gradient attributes.
  • style(cssText)

    Defines a