# DWScript Documentation
> Comprehensive documentation for the DWScript language, including guides, references, and practical examples.
---
Source: lang/advanced/database.md
---
title: Database
id: lang/advanced/database
---
# Database Support
DWScript provides a modern database abstraction layer through the `System.Data` unit. It supports multiple drivers, with **SQLite** being natively supported.
## Connecting
Connecting to a database is simple using the `DataBase.Create` factory method.
```pascal
uses System.Data;
var db := DataBase.Create('SQLite', [':memory:']);
// OUTPUT NONE
```
## Querying Data
Use `Query` for SELECT statements. It returns a `DataSet` that you can iterate through.
```pascal
uses System.Data;
var db := DataBase.Create('SQLite', [':memory:']);
db.Exec('CREATE TABLE Users (ID INTEGER, Name TEXT, Active INTEGER)');
db.Exec('INSERT INTO Users VALUES (1, "Alice", 1)');
var ds := db.Query('SELECT ID, Name FROM Users WHERE Active = ?', [1]);
// ds.Step is the preferred way to iterate: it moves to the next record
// and returns True as long as there is data to read.
while ds.Step do begin
PrintLn(ds.AsString(1).ToHtml); // Access by 0-based index
end;
```
**Output:**
```text
Alice
```
## Updating Data
Use `Exec` for commands that modify data (INSERT, UPDATE, DELETE). Always use parameterized queries to prevent SQL injection.
```pascal
uses System.Data;
var db := DataBase.Create('SQLite', [':memory:']);
db.Exec('CREATE TABLE Users (ID INTEGER, Name TEXT)');
db.Exec('INSERT INTO Users (Name) VALUES (?)', ['Alice']);
// OUTPUT NONE
```
## JSON Integration
Datasets can be automatically converted to JSON strings, which is extremely useful for building REST APIs.
```pascal
uses System.Data;
var db := DataBase.Create('SQLite', [':memory:']);
db.Exec('CREATE TABLE Users (ID INTEGER, Name TEXT)');
db.Exec('INSERT INTO Users VALUES (1, "Alice")');
var ds := db.Query('SELECT * FROM Users');
PrintLn(ds.StringifyAll);
```
**Output:**
```text
[{"ID":1,"Name":"Alice"}]
```
:::info
### Related Reference
For a full list of database methods, transaction management, and specialized dataset helpers, see the reference documentation:
* **[Database API Reference](/ref/database)**
:::
---
Source: lang/advanced/helpers.md
---
title: Method Syntax & Helpers
id: lang/advanced/helpers
---
# Method Syntax & Helpers
DWScript provides two powerful features to make your code more readable and to extend existing types without using inheritance.
## Unified Method Syntax
Any function can be called as if it were a method of its first parameter. This leads to cleaner, more readable code that can be easily chained.
```pascal
var s: String = ' hello ';
// Standard style: UpperCase(Trim(s))
// Method style:
PrintLn(s.Trim.UpperCase); // "HELLO"
var i: Integer = 255;
PrintLn(i.ToHexString(4)); // Equivalent to IntToHex(i, 4)
```
**Output:**
```text
HELLO
00FF
```
This works because the compiler automatically maps the call `x.Method(y)` to `Method(x, y)` if a standalone function exists where the first parameter matches the type of `x`.
## Built-in Type Helpers
Most basic types in DWScript have built-in helpers that provide convenient method aliases for standard library functions.
| Type | Common Methods | Equivalent Function |
| :--- | :--- | :--- |
| Integer | `ToString`, `ToHexString`, `ToBin` | `IntToStr`, `IntToHex`, `IntToBin` |
| Float | `ToString`, `ToString(p)` | `FloatToStr` |
| String | `ToInteger`, `ToFloat`, `ToJSON`, `ToHtml` | `StrToInt`, `StrToFloat`, `StrToJSON` |
| Boolean | `ToString` | `BoolToStr` |
## Helpers
Helpers allow you to explicitly extend existing classes, records, and even basic types with new methods and properties.
### Class Helpers
```pascal
type
TUser = class
Name: String;
constructor Create(n: String); begin Name := n; end;
end;
type
TUserHelper = class helper for TUser
procedure Greet;
begin
PrintLn('Hello, ' + Name);
end;
end;
var u := new TUser('Alice');
u.Greet;
```
**Output:**
```text
Hello, Alice
```
### Basic Type Helpers
You can extend primitive types like `Integer`, `Float`, or `String` to enable fluent syntax.
```pascal
type
TIntHelper = record helper for Integer
function Squared: Integer;
begin
Result := Self * Self;
end;
end;
var n := 10;
PrintLn(n.Squared.ToString); // "100"
```
**Output:**
```text
100
```
### Extension Methods
You can map existing functions as methods using the `helper` keyword in the function declaration.
```pascal
function StringLength(s: String): Integer; helper Size;
begin
Result := Length(s);
end;
var s := 'Hello';
PrintLn(s.Size.ToString); // 5
```
**Output:**
```text
5
```
---
Source: lang/advanced/lambdas.md
---
title: Lambdas & Closures
id: lang/advanced/lambdas
---
# Lambdas & Closures
Lambdas (also known as anonymous methods) provide a concise way to create functions and procedures that can be passed as arguments or assigned to variables.
## Syntax Overview
DWScript supports both a modern arrow syntax for brief expressions and a more traditional block syntax for complex logic.
```pascal
// Function lambda
var sqr := lambda (x: Integer): Integer => x * x;
// Procedure lambda
var log := procedure (s: String)
begin
PrintLn('Log: ' + s);
end;
// Traditional function syntax
var add := function (a, b : Integer) : Integer
begin
Result := a + b;
end;
```
## Functional Programming
Lambdas are frequently used with standard library methods for filtering, mapping, and sorting data collections.
```pascal
var list : array of Integer = [1, 2, 3, 4, 5];
// Map: Transform elements
var doubled := list.Map(lambda (x: Integer) => x * 2);
// Filter: Keep elements matching a condition
var evens := list.Filter(lambda (x: Integer) => x mod 2 = 0);
PrintLn('Doubled: ' + doubled.Map(IntToStr).Join(','));
PrintLn('Evens: ' + evens.Map(IntToStr).Join(','));
```
**Output:**
```text
Doubled: 2,4,6,8,10
Evens: 2,4
```
## Closures & Variable Capture
A **closure** is an anonymous method that "captures" variables from its surrounding local scope.
:::warning
**Platform Difference:** Variable capture (closures) is currently only supported when using the **JavaScript Transpiler**.
In **Native Script Mode**, lambdas cannot capture local variables from the outer scope. They must be self-contained or rely solely on their parameters.
:::
### Native Script Mode
In native mode, lambdas are excellent for pure functions, sorting logic, or any operation where the required data is passed in via parameters.
```pascal
// Self-contained lambda works perfectly in native mode
var list : array of Integer = [3, 1, 4, 2];
list.Sort(lambda (a, b: Integer) => a - b);
PrintLn(list.Map(IntToStr).Join(','));
// What DOES NOT work in native mode (uncommenting will cause error):
// var factor := 2;
// var doubled := list.Map(lambda (x: Integer) => x * factor); // 'factor' is external to lambda
```
**Output:**
```text
1,2,3,4
```
## JavaScript Transpilation
For developers targeting the web, DWScript lambdas are a powerful feature. The JavaScript transpiler maps them directly to native **JavaScript closures** and **arrow functions**.
:::info
#### Full Closure Support in JS
When compiling to JavaScript, you can freely capture local variables. The transpiler ensures that the lexical scope is preserved, matching the behavior expected in modern web development.
```pascal
// Supported in JS Mode (Commented out for native compilation check)
/*
function MakeCounter(start : Integer) : function : Integer;
begin
var count := start;
Result := lambda => Inc(count); // 'count' is captured
end;
*/
```
:::
## Memory Management
* **Native Script Mode:** Uses a hybrid approach with **Reference Counting** for immediate release of resources and a **Garbage Collector** to handle circular references.
* **JavaScript Mode:** Relies entirely on the host JavaScript engine's garbage collector.
---
Source: lang/advanced/metaprogramming.md
---
title: Metaprogramming
id: lang/advanced/metaprogramming
---
# Metaprogramming
While DWScript is statically typed, it offers features that support dynamic behavior and metaprogramming styles.
## Variant Types
The `Variant` type allows for late-bound method calls and property access. This is effectively dynamic typing within a static language.
```pascal
var v := JSON.Parse('{"DynamicProp": 123}');
PrintLn(v.DynamicProp);
```
**Output:**
```text
123
```
## JSON as Dynamic Objects
Since JSON objects in DWScript are fully dynamic, they can be used to construct data structures on the fly without defining strict classes.
## Conditional Compilation
DWScript supports conditional compilation directives, allowing you to include or exclude code based on defined symbols.
```pascal
{$DEFINE DEBUG}
{$IFDEF DEBUG}
PrintLn('Debug mode enabled');
{$ELSE}
PrintLn('Release mode');
{$ENDIF}
```
**Output:**
```text
Debug mode enabled
```
---
Source: lang/advanced/rtti.md
---
title: RTTI & Attributes
id: lang/advanced/rtti
---
# Run-Time Type Information
RTTI (Run-Time Type Information) allows your code to inspect types, objects, and metadata while the program is running.
## Inspecting Types
You can get type information using `TypeOf` (for class symbols).
```pascal
type
TUser = class
Name : String;
end;
var info := TypeOf(TUser);
PrintLn('Class Name: ' + info.Name);
```
**Output:**
```text
Class Name: TUser
```
## Attributes
Attributes attach metadata to symbols.
```pascal
type
ColumnAttribute = class(TCustomAttribute)
FName : String;
constructor Create(const name : String); begin FName := name; end;
end;
type
[ColumnAttribute('USERS')]
TUserWithAttr = class
Name : String;
end;
// Iterate through attributes
var attrs := RTTIRawAttributes;
for var i := 0 to attrs.Length - 1 do begin
if attrs[i].T = TypeOf(TUserWithAttr) then begin
if attrs[i].A is ColumnAttribute then
PrintLn('Found column mapping: ' + ColumnAttribute(attrs[i].A).FName);
end;
end;
```
**Output:**
```text
Found column mapping: USERS
```
:::info
### Related Reference
For detailed information on `TTypeInfo` members and the `RTTIRawAttributes` structure, see the reference documentation:
* **[RTTI API Reference](/ref/rtti)**
:::
---
Source: lang/advanced/security.md
---
title: Security Best Practices
id: lang/advanced/security
---
# Security Best Practices
Building secure web applications requires attention to common vulnerability patterns.
## Input Validation
Never trust user input. Always validate and sanitize.
```pascal
// NO_RUN
uses System.WebServer;
// Whitelist validation for expected values
function IsValidSection(s: String): Boolean;
begin
Result := s in ['lang', 'ref', 'examples'];
end;
var section := WebRequest.QueryField['section'];
if not IsValidSection(section) then begin
WebResponse.StatusCode := 400;
exit;
end;
```
## Output Encoding (XSS Prevention)
Always encode user data before rendering to HTML.
```pascal
var userInput := WebRequest.QueryField['name'];
PrintLn('
Hello, ' + userInput.ToHtml + '
');
```
**Output:**
```text
Hello,
```
## SQL Injection Prevention
Always use parameterized queries.
```pascal
// NO_RUN
uses System.Data, System.WebServer;
// CORRECT - Parameterized
var userId := WebRequest.QueryField['id'];
var db := DataBase.Create('SQLite', ['data.db']);
var results := db.Query(#'
SELECT * FROM users WHERE id = ?
', [userId]);
// WRONG - String concatenation (DO NOT USE)
// var results := db.Query('SELECT * FROM users WHERE id = ' + userId);
```
## Secure Redirects
Always whitelist redirect destinations to prevent Open Redirect vulnerabilities.
```pascal
// NO_RUN
const AllowedTargets = ['/home', '/dashboard', '/logout'];
var target := WebRequest.QueryField['next'];
if target in AllowedTargets then
WebResponse.SetStatusRedirect(302, target);
```
## Session Security
Use cryptographic tokens and secure cookie flags.
```pascal
uses System.Net, System.Crypto;
var token := CryptographicToken(32);
// Flags: 2 = HttpOnly
WebResponse.SetCookie('session', token, Now + 1, '/', '', 2, WebCookieSameSite.Strict);
```
---
Source: lang/advanced/tabular.md
# Tabular Data
The `TabularData` class (from `System.Data.Tabular`) provides a high-performance way to work with large, column-oriented datasets. It is ideal for data analysis, feature engineering, and high-throughput processing.
## High-Speed Data Transformation
TabularData supports JIT-compiled expressions for adding columns and calculating aggregates. This is particularly useful for tasks like **Normalization** (scaling values to a [0, 1] range) or applying **Activation Functions** (like ReLU) across millions of rows.
```pascal
uses System.Data, System.Data.Tabular;
var data := new TabularData;
data.AddColumn('Signal', [0.5, 1.2, 3.4, 2.1, 0.8]);
// 1. Define range for normalization (usually pre-calculated or known)
var sMin := 0.5;
var sMax := 3.4;
var sRange := sMax - sMin;
// 2. Apply Min-Max Scaling via JIT expression: (Signal - Min) / Range
data.EvaluateNewColumn('Normalized', [ '"Signal"', sMin, '-', sRange, '/' ]);
PrintLn(data.ExportToSeparated(['Signal', 'Normalized']));
```
**Output:**
```text
Signal,Normalized
0.5,0
1.2,0.241379310344828
3.4,1
2.1,0.551724137931035
0.8,0.103448275862069
```
## Understanding RPN Expressions
Calculations in TabularData use **Reverse Polish Notation (RPN)**, a stack-based logic where operators follow their operands. This allows the JIT engine to evaluate expressions with extreme efficiency without needing complex parenthetical parsing.
### How it Works
Think of a stack where values are pushed. An operator then "pops" the required number of values, performs its calculation, and "pushes" the result back.
| Expression | RPN Array | Logic |
| :--- | :--- | :--- |
| `a + b` | `['"a"', '"b"', '+']` | Push a, Push b, Add them |
| `(a + b) * c` | `['"a"', '"b"', '+', '"c"', '*']` | Add a and b first, then multiply by c |
| `max(0, a + b)` | `['"a"', '"b"', 'relu']` | `relu` is a fused binary operator |
### Practical Examples
```pascal
uses System.Data, System.Data.Tabular;
var data := new TabularData;
data.AddColumn('A', [10.0, 20.0]);
data.AddColumn('B', [5.0, 2.0]);
// Weighted Average: (A * 0.7) + (B * 0.3)
data.EvaluateNewColumn('Weighted', [ '"A"', 0.7, '*', '"B"', 0.3, '*', '+' ]);
// Error Metric (SMAPE): abs(A-B) / (abs(A)+abs(B))
data.EvaluateNewColumn('Error', [ '"A"', '"B"', 'smape' ]);
PrintLn(data.ExportToSeparated(['A', 'B', 'Weighted', 'Error']));
```
**Output:**
```text
A,B,Weighted,Error
10,5,8.5,0.333333333333333
20,2,14.6,0.818181818181818
```
## Neural Network Inference
Because `TabularData` is optimized for batch processing and supports fused activation functions (like `relu`), it is highly effective for running pre-trained neural network inference across large datasets. This is commonly used for **classification** and **prediction** tasks where you need to process thousands of records instantly.
The `relu` opcode is specifically designed for this: it is a **fused binary operator** that calculates `max(0, a + b)`. It pops two values (the sum and the bias), adds them, and pushes the result clamped to zero.
### Example: Titanic Survival Prediction
This snippet demonstrates a simplified inference pipeline using features from the Titanic dataset (Sex, PClass).
```pascal
uses System.Data, System.Data.Tabular;
var model := new TabularData;
// Inputs: Features [Sex, PClass]
// (0.0 = Female, 1.0 = Male | 1.0 = 1st Class, 0.0 = 3rd Class)
model.AddColumn('Sex', [0.0, 1.0]);
model.AddColumn('PClass', [1.0, 0.0]);
// Hidden Layer: ReLU(Sex * -1.5 + PClass * 1.2 + 0.5)
// 'relu' pops the top two values (sum and bias). Here: (Sex*-1.5 + PClass*1.2) and 0.5
model.EvaluateNewColumn('H1', [ '"Sex"', -1.5, '*', '"PClass"', 1.2, '*', '+', 0.5, 'relu' ]);
// Output Layer (Prob): Sigmoid(H1 * 1.5 - 0.5)
model.EvaluateNewColumn('Logit', [ '"H1"', 1.5, '*', 0.5, '-' ]);
model.EvaluateNewColumn('Prob', [ 1, 1, '"Logit"', -1, '*', 'exp', '+', '/' ]);
PrintLn(model.ExportToSeparated(['Sex', 'PClass', 'Prob']));
```
**Output:**
```text
Sex,PClass,Prob
0,1,0.885947618720209
1,0,0.377540668798145
```
### Advanced: Residual Links & Stack Manipulation
Complex architectures like **Residual Networks (ResNets)** can be implemented using stack manipulation opcodes. These allow you to reuse values (like a previous layer's output) without recalculating them or reading from memory.
* `dup0`: Duplicates the top value on the stack.
* `dup1`: Duplicates the value below the top.
In the example below, we calculate a "base feature," duplicate it to use in a non-linear branch, and then add it back (the residual link) before the final activation.
:::info
The output below includes trailing commas. This occurs because `ColumnStrings` returns the full internal capacity of the column (defaulting to 8 for JIT optimization), even if fewer rows are active.
:::
```pascal
uses System.Data, System.Data.Tabular;
var model := new TabularData;
model.AddColumn('X', [0.5, -0.2]);
// Deep Residual Logic: Sigmoid(ReLU(X*1.5 + 0.5) + X - 0.2)
model.EvaluateNewColumn('Res', [
1, 1, // Sigmoid pre-load
'"X"', 1.5, '*', 0.5, '+', // Base calculation
'dup0', // Keep for residual. Stack: [1, 1, base, base]
0, 'relu', // Transform top copy. Stack: [1, 1, base, H1]
'+', // Add base back (Residual). Stack: [1, 1, base+H1]
0.2, '-', // Final bias
-1, '*', 'exp', '+', '/' // Sigmoid
]);
PrintLn('Result: ' + model.ColumnStrings('Res').Join(', '));
```
**Output:**
```text
Result: 0.908877038985144, 0.549833997312478, , , , , ,
```
### Folded Inference Pipelines
For maximum performance, you can "fold" multiple layers into a single RPN expression. This avoids the overhead of writing intermediate results back to column memory, keeping all neuron activations on the CPU stack during the JIT-compiled loop.
```pascal
uses System.Data, System.Data.Tabular;
var data := new TabularData;
data.AddColumn('X', [0.5, -0.2]);
// Calculate a 2-layer result in one pass: Sigmoid(ReLU(X*1.5 + 0.5) * 0.8 - 0.2)
// relu pops two values (sum + bias) and pushes max(0, sum+bias)
data.EvaluateNewColumn('Result', [
1, 1, // Sigmoid pre-load
'"X"', 1.5, '*', 0.5, 'relu', 0.8, '*', 0.2, '-',
-1, '*', 'exp', '+', '/' // Sigmoid final
]);
PrintLn('Result: ' + data.ColumnStrings('Result').Join(', '));
```
**Output:**
```text
Result: 0.689974481127613, 0.490001333120035, , , , , ,
```
## Sharing Data (Web)
In a web environment, you can load a dataset once and share it across all requests using `LockAndShare`. This drastically reduces memory usage and startup time for data-heavy applications.
```pascal
uses System.Data.Tabular;
var sharedData := TabularData.ConnectToShared('AppWideData');
if sharedData = nil then begin
// Load data and share it
// ...
var data := new TabularData;
// ...
data.LockAndShare('AppWideData');
PrintLn('Data loaded and shared.');
end else begin
PrintLn('Connected to shared data.');
end;
```
**Output:**
```text
Connected to shared data.
```
:::info
### Related Reference
For a complete list of aggregation functions and sharing options, see the reference documentation:
* **[Tabular Data API Reference](/ref/tabular)**
:::
---
Source: lang/basics/arrays.md
---
title: Arrays
id: lang/basics/arrays
---
# Arrays
DWScript supports two main types of arrays: **Static** (fixed size) and **Dynamic** (resizable). The distinction is often determined by how the variable is declared and how type inference is applied.
## Static Arrays
Static arrays have a fixed size defined at compile-time. They are efficient and safe when the number of elements is known in advance.
### Type Inference
When you use a simple array literal assignment with `var`, DWScript infers a **Static Array**. Its size is fixed to the number of elements in the literal.
```pascal
// Inferred as a Static Array of 3 Integers
var list := [10, 20, 30];
// list.Add(40); // Error: Static arrays cannot be resized
```
### Explicit Declaration
You can also explicitly define the range of a static array.
```pascal
var matrix : array [0..2, 0..2] of Integer;
matrix[1, 1] := 5;
```
## Dynamic Arrays
Dynamic arrays can grow and shrink at runtime. They are the most flexible and commonly used array type in DWScript.
### Declaration & Initialization
To create a dynamic array, you must explicitly declare its type using the `array of Type` syntax.
```pascal
// Explicitly typed dynamic array
var arr : array of Integer;
// Initialized with 3 elements, but can still grow
var data : array of Integer := [10, 20, 30];
data.Add(40); // Works!
data[0] := 5;
PrintLn('Length: ' + data.Length.ToString);
```
**Output:**
```text
Length: 4
```
### Resizing Methods
Dynamic arrays support several methods for changing their size:
| Method | Description |
| :--- | :--- |
| `Add(value)` | Appends an element to the end. |
| `Delete(index)` | Removes an element. |
| `SetLength(new)` | Resizes the array directly. |
| `Clear` | Removes all elements. |
## Literals & Features
Array literals are powerful and support features like range expansion and concatenation.
```pascal
// Array literal with range expansion
var nums := [1..3, 10, 5..1];
// Result: [1, 2, 3, 10, 5, 4, 3, 2, 1]
// Concatenation
var a := [1, 2] + [3, 4];
a += 5; // Note: This converts 'a' to a Dynamic array if it was static
PrintLn(a.Map(IntToStr).Join(', '));
```
**Output:**
```text
1, 2, 3, 4, 5
```
## Element Access & Manipulation
Arrays in DWScript are **0-indexed**. You can access elements using square brackets. Dynamic arrays also support compound assignment operators directly on their elements.
```pascal
var data : array of Integer := [10, 20, 30];
// Standard access
data[0] := 5;
// Compound assignment
data[1] += 5; // 25
data[2] *= 2; // 60
PrintLn(Format(
'%d, %d, %d',
[ data[0], data[1], data[2] ]
));
```
**Output:**
```text
5, 25, 60
```
:::warning
**Indexing Gotcha:** Arrays are **0-indexed**. See **[Indexing Strategy](/lang/basics/types#indexing-strategy)** for the comparison with Strings.
:::
## Iteration & Bounds
You can iterate through arrays using index-based loops or `for..in`. Index-based loops are generally faster and more explicit when you need the index or specific direction. `for..in` is convenient when you only need the values and want to avoid manual indexing.
```pascal
var list := [10, 20, 30];
// Index-based iteration (fastest)
for var i := 0 to list.High do
PrintLn(list[i].ToString);
// Value-based iteration (for..in)
for var val in list do
PrintLn(val.ToString);
```
**Output:**
```text
10
20
30
10
20
30
```
## Search & Membership
You can check if a value exists in an array using the `.Contains()` method or the more idiomatic `in` operator.
```pascal
var list := [10, 20, 30];
// Using the method
if list.Contains(20) then
PrintLn('Found 20');
// Using the operator (idiomatic)
if 30 in list then
PrintLn('Found 30');
```
**Output:**
```text
Found 20
Found 30
```
## Array Methods
Dynamic arrays come with a rich set of built-in methods for manipulation.
| Method | Description |
| :--- | :--- |
| `Add(value)` / `Push` | Appends an element to the end. `Push` is typically used when treating the array as a stack. |
| `Pop` | Removes and returns the last element. |
| `Peek` | Returns the last element without removing it. |
| `Insert(index, value)` | Inserts an element at a specific position. |
| `Delete(index [, count])` | Removes one or more elements by index. |
| `Remove(value)` | Removes the first occurrence of a specific value. |
| `SetLength(newLength)` | Resizes the array. |
| `Clear` | Removes all elements. |
| `Sort` | Sorts the array **in-place**. Supports an optional lambda for custom comparison. |
| `Reverse` | Reverses the array **in-place**. |
| `IndexOf(value [, from])` | Returns the index of the first occurrence (at or after `from`), or -1 if not found. |
| `Contains(value)` | Returns True if the value exists in the array. |
## Numerical Processing (Float Arrays)
For `array of Float`, DWScript provides high-performance vectorized operations. These methods are **mutating** (they modify the array in-place) and return the array instance to support **fluent method chaining**.
| Method | Parameters | Description |
| :--- | :--- | :--- |
| `Offset` | `v` | Adds `v` to every element. |
| `Offset` | `other [, targetOff, sourceOff, count]` | Element-wise addition of `other` array. |
| `Multiply` | `v` | Multiplies every element by `v`. |
| `Multiply` | `other [, targetOff, sourceOff, count]` | Element-wise multiplication by `other` array. |
| `MultiplyAdd` | `scale, offset` | For each element: `x := x * scale + offset`. |
| `Min` | `v` | Sets each element to `Min(x, v)` (caps values at `v`). |
| `Min` | `other [, targetOff, sourceOff, count]` | Element-wise `x := Min(x, other[i])`. |
| `Max` | `v` | Sets each element to `Max(x, v)` (floors values at `v`). |
| `Max` | `other [, targetOff, sourceOff, count]` | Element-wise `x := Max(x, other[i])`. |
| `Reciprocal` | | Replaces each element with `1 / x`. |
| `DotProduct` | `other` | Returns the dot product (**scalar**) with another float array. |
```pascal
var a : array of Float := [1.0, 2.0, 4.0];
// Fluent chaining (mutating)
a.Offset(1).Multiply(2).Max(5.0);
// Result: [5.0, 6.0, 10.0]
var b : array of Float := [1.0, 2.0, 3.0];
var dot := b.DotProduct([4.0, 5.0, 6.0]); // 32.0 (returns scalar)
```
### High-Performance Array Operations
Many of the numerical processing methods support optional **offset and count** parameters. This allows performing operations on specific segments of the arrays without creating temporary copies, which is critical for high-performance computing.
The global `ArrayDotProduct` function also supports these parameters:
```pascal
var a1 : array of Float := [0, 0, 1, 2, 0];
var a2 : array of Float := [0, 3, 4, 0, 0];
// ArrayDotProduct(arr1, arr2, offset1, offset2, count)
// Performs dot product on segments: [1, 2] . [3, 4] = (1*3 + 2*4) = 11
var dot := ArrayDotProduct(a1, a2, 2, 1, 2);
PrintLn('Dot Product: ' + dot.ToString);
```
**Output:**
```text
Dot Product: 11
```
:::info
#### Semantic Aliases
While `Add` and `Push` perform the same operation (appending to the end), using `Push` and `Pop` conveys a specific architectural intent: that the array is being used as a **Stack** (LIFO - Last In, First Out).
:::
### Comparison & Nil
Dynamic arrays can be compared with `nil` using the `=` and `<>` operators. A dynamic array is considered equal to `nil` if it is empty (length 0) or has not been initialized.
You can also compare two dynamic arrays with each other. This performs a **reference comparison**, meaning it checks if both variables point to the same array instance in memory.
**Important details:**
* Two different empty arrays are **not equal** to each other, even if both are equal to `nil`.
* Assigning `nil` to a dynamic array reinitializes it to an empty state but does not affect other variables still referencing the original data.
```pascal
var a : array of Integer;
var b : array of Integer;
if a = nil then
PrintLn('a is nil/empty');
a := [1, 2, 3];
b := a;
if a = b then
PrintLn('a and b point to the same array');
a := nil; // Reinitialize a
if a = nil then
PrintLn('a is nil again');
if b <> nil then
PrintLn('b still has data: ' + b.Length.ToString);
// Comparing different empty arrays
var c : array of Integer := [];
var d : array of Integer := [];
if (c = nil) and (d = nil) then
PrintLn('Both are "nil"');
if c <> d then
PrintLn('But they are different instances');
```
**Output:**
```text
a is nil/empty
a and b point to the same array
a is nil again
b still has data: 3
Both are "nil"
But they are different instances
```
### Functional & Transformation Methods
DWScript dynamic arrays support functional programming patterns. These methods **return a new array** and do not modify the original.
| Method | Description |
| :--- | :--- |
| `Map(lambda)` | Transforms each element using the provided function. |
| `Filter(lambda)` | Returns an array containing only elements that satisfy the condition. |
| `Join(separator)` | Concats all elements into a single string. |
```pascal
var nums : array of Integer := [1, 2, 3, 4, 5];
// Square numbers
var squares := nums.Map(lambda (x: Integer) => x * x);
PrintLn(squares.Map(lambda (x: Integer) => x.ToString).Join(', '));
// Keep evens
var evens := nums.Filter(lambda (x: Integer) => (x mod 2) = 0);
PrintLn(evens.Map(lambda (x: Integer) => x.ToString).Join(', '));
```
**Output:**
```text
1, 4, 9, 16, 25
2, 4
```
---
Source: lang/basics/associative_arrays.md
---
title: Associative Arrays
id: lang/basics/associative_arrays
---
# Associative Arrays
Associative arrays (also known as maps or dictionaries) use keys instead of numeric indices to store and retrieve values. In DWScript, these are highly efficient and built directly into the language.
## Declaration & Initialization
Use the `array[KeyType] of ValueType` syntax. Strings are the most common key type, but other ordinal types like Integers or Enumerations can also be used.
```pascal
var capitals : array[String] of String;
// Assigning values
capitals['France'] := 'Paris';
capitals['Japan'] := 'Tokyo';
capitals['USA'] := 'Washington D.C.';
// Accessing
PrintLn('The capital of France is ' + capitals['France']);
// Accessing a missing key returns the default value for the type
// (e.g. empty string for String, 0 for Integer)
PrintLn('Missing key: "' + capitals['Mars'] + '"');
// Use the 'in' operator to check for existence
if 'Mars' not in capitals then
PrintLn('Mars is not in the list');
```
**Output:**
```text
The capital of France is Paris
Missing key: ""
Mars is not in the list
```
## Operators
The `in` and `not in` operators provide a clean way to check if a key exists in the array.
```pascal
var capitals : array[String] of String;
capitals['Germany'] := 'Berlin';
if 'Germany' in capitals then
PrintLn('Germany is in the list')
else
PrintLn('Germany is missing');
```
**Output:**
```text
Germany is in the list
```
## Methods
Associative arrays support several built-in methods for management and inspection.
| Method | Description |
| :--- | :--- |
| `Count / Length` | Returns the number of key-value pairs. |
| `Keys` | Returns a dynamic array containing all keys. |
| `Delete(key)` | Removes the entry for the specified key. Returns True if found. |
| `Clear` | Removes all entries from the array. |
```pascal
var capitals : array[String] of String;
capitals['France'] := 'Paris';
PrintLn('Count: ' + capitals.Count.ToString);
capitals.Delete('France');
PrintLn('After delete: ' + capitals.Count.ToString);
```
**Output:**
```text
Count: 1
After delete: 0
```
## Iterating
You can use a `for..in` loop on the array's `Keys` to iterate through the entries. Direct iteration over an associative array is not supported.
```pascal
var capitals : array[String] of String;
capitals['France'] := 'Paris';
capitals['Japan'] := 'Tokyo';
// Iterating keys and accessing values
var keys := capitals.Keys;
keys.Sort;
for var country in keys do
PrintLn(country + ' -> ' + capitals[country]);
```
**Output:**
```text
France -> Paris
Japan -> Tokyo
```
---
Source: lang/basics/bigints.md
---
title: Big Integers
id: lang/basics/bigints
---
# Big Integers
The `BigInteger` type provides arbitrary-precision whole numbers. Unlike the standard 64-bit `Integer`, a `BigInteger` can grow to represent any value, limited only by the available system memory.
## Usage
Big integers are essential for cryptography, high-precision scientific calculations, or any domain where values might exceed the $2^{63}-1$ limit of standard integers.
```pascal
var big := BigInteger('1234567890123456789012345678901234567890');
big := big * 2;
PrintLn(big.ToString);
```
**Output:**
```text
2469135780246913578024691357802469135780
```
## Literals & Initialization
While there is no native "BigInt" literal suffix (like `100n` in JS), you can initialize them from strings or standard integers using the `BigInteger()` constructor-style call.
```pascal
var b1 := BigInteger(100);
var b2 := BigInteger('1' + '0'.Dupe(50)); // 1 followed by 50 zeros
PrintLn(b1.ToString);
```
**Output:**
```text
100
```
## Operations
`BigInteger` supports all standard arithmetic and comparison operators.
* **Arithmetic**: `+`, `-`, `*`, `div`, `mod`
* **Comparison**: `=`, `<>`, `<`, `>`, `<=`, `>=`
* **Bitwise**: `and`, `or`, `xor`, `not`, `shl`, `shr`
```pascal
var a := BigInteger(1000);
var b := BigInteger(3);
var res := (a div b); // 333
PrintLn(res.ToString);
```
**Output:**
```text
333
```
## Method Helpers
The `BigInteger` type includes several useful methods for common mathematical operations.
* **`IsEven` / `IsOdd`**: Check parity.
* **`IsPrime`**: Checks if the number is prime (probabilistic for large numbers).
* **`Abs`**: Returns the absolute value.
* **`Pow(exponent)`**: Raises the number to a power.
* **`ModPow(exponent, modulus)`**: Efficient modular exponentiation (critical for RSA/DH).
* **`Gcd(other)`**: Greatest Common Divisor.
:::info
### Related Reference
For a complete list of BigInteger methods, see the **[Math API Reference](/ref/math)**.
:::
---
Source: lang/basics/binary.md
---
title: Binary Data (ByteBuffer)
id: lang/basics/binary
---
# Binary Data (ByteBuffer)
The `ByteBuffer` type is a specialized dynamic array of bytes (`array of Byte`) optimized for binary data manipulation. It is the primary type for handling network packets, file contents, and cryptographic blobs.
## Initialization
A `ByteBuffer` can be initialized from strings, hex, or by setting its length directly.
```pascal
var buffer: ByteBuffer;
buffer.SetLength(1024); // Allocate 1KB
buffer := ByteBuffer('Hello');
PrintLn(buffer.Length.ToString);
```
**Output:**
```text
5
```
## Accessing Data
You can access individual bytes using `GetByte` and `SetByte` methods.
```pascal
var buffer: ByteBuffer;
buffer.SetLength(2);
buffer.SetByte(0, $FF);
var b := buffer.GetByte(0);
PrintLn(b.ToString);
```
**Output:**
```text
255
```
## Methods
`ByteBuffer` provides many methods for reading and writing multi-byte values.
* **`GetInt32(offset)` / `SetInt32(offset, value)`**: Standard 32-bit integers.
* **`GetFloat(offset)`**: 64-bit doubles.
* **`GetWord(offset)`**: 16-bit unsigned integers.
* **`ToHexString`**: Returns a hex string representation.
* **`Base64Encode` / `Base64Decode`**: Conversion to/from Base64.
```pascal
var buf: ByteBuffer;
buf.SetLength(4);
buf.SetInt32(0, 123456);
var i := buf.GetInt32(0);
PrintLn(i.ToString);
```
**Output:**
```text
123456
```
## ByteBuffer vs DataStrings
In DWScript, **DataStrings** are often used to represent raw data in a string format. However, these are UTF-16 strings where many functions only write or read the **lower byte** of each character.
* **ByteBuffer**: Preferred for all raw binary manipulation and multi-byte operations.
* **DataStrings**: Used for interoperability with legacy APIs or functions that expect a binary stream in string form.
To convert a `ByteBuffer` to a DataString, use `.ToDataString`. To convert back, use the `ByteBuffer()` constructor or `.AssignDataString`.
```pascal
var buffer := ByteBuffer('Hello');
var binStr := buffer.ToDataString; // binStr is a DataString
PrintLn(binStr);
```
**Output:**
```text
Hello
```
:::info
### Related Reference
* **[Encoding Reference](/ref/encoding)** - Base64, Hex, and URL encoding.
* **[Crypto Reference](/ref/crypto)** - Using ByteBuffers for hashing and encryption.
:::
---
Source: lang/basics/bitwise.md
---
title: Bitwise Operators
id: lang/basics/bitwise
---
# Bitwise Operators
Bitwise operators allow you to manipulate individual bits within integer values. These are essential for low-level programming, flags, and certain mathematical optimizations.
## Shift Operators
DWScript provides three shift operators.
| Operator | Name | Description |
| :--- | :--- | :---------------------------------------------------------------------------------- |
| `shl` | Shift Left | Shifts bits to the left, filling with zeros. Equivalent to multiplying by $2^n$. |
| `shr` | Logical Shift Right | Shifts bits to the right, filling with zeros. |
| `sar` | Arithmetic Shift Right | Shifts bits to the right, preserving the sign bit (MSB). |
### Logical vs. Arithmetic Shift
When shifting a negative number (where the high bit is 1), `shr` will fill the high bit with 0 (making it positive), while `sar` will fill it with 1 (maintaining the negative sign).
```pascal
var val := -8;
PrintLn(val shr 1);
PrintLn(val sar 1);
```
**Output:**
```text
9223372036854775804
-4
```
## Bitwise Logic
When applied to integers, standard logical operators perform bitwise operations.
| Operator | Operation |
| :------- | :---------------------------------- |
| `and` | Bitwise AND |
| `or` | Bitwise OR |
| `xor` | Bitwise XOR |
| `not` | Bitwise NOT (One's complement) |
### Example: Masking and Flags
```pascal
const FLAG_READ = %0001;
const FLAG_WRITE = %0010;
const FLAG_EXEC = %0100;
var myFlags := FLAG_READ or FLAG_EXEC; // Combine flags
// Check if a flag is set
if (myFlags and FLAG_READ) <> 0 then
PrintLn('Can Read');
// Toggle a flag
myFlags := myFlags xor FLAG_EXEC;
PrintLn(myFlags);
```
**Output:**
```text
Can Read
1
```
## Binary and Hex Literals
To make bitwise operations more readable, you can use binary and hexadecimal literals.
* **Binary:** Prefix with `%` (e.g., `%101010`)
* **Hexadecimal:** Prefix with `$` (e.g., `$FF00`)
```pascal
var b := %1111; // 15
var h := $A; // 10
PrintLn(b and h);
```
**Output:**
```text
10
```
---
Source: lang/basics/bools.md
---
title: Booleans
id: lang/basics/bools
---
# Boolean Type
The `Boolean` type represents a logical value that can be either `True` or `False`.
## Literals
The two standard boolean constants are `True` and `False`. They are case-insensitive in the source code but conventionally written in PascalCase.
```pascal
// Type inference
var isReady := True;
var hasFinished := False;
// Explicit typing
var isValid : Boolean := True;
var isComplete : Boolean;
isComplete := False;
// OUTPUT NONE
```
## Operations
Booleans are used with logical operators: `not`, `and`, `or`, `xor`, and `implies`. All logical operators in DWScript are **short-circuiting** (evaluated left-to-right, stopping as soon as the result is determined).
```pascal
var a := True;
var b := False;
var result := (a or b) and (not b); // True
// Implies: True implies False is False
var imp := a implies b;
PrintLn('Implies: ' + imp.ToString);
```
**Output:**
```text
Implies: False
```
## Comparisons
Comparison operators (`=`, `<>`, `<`, `>`, `<=`, `>=`) result in a Boolean value.
```pascal
var x := 10;
var y := 20;
var isGreater := x > y; // False
// OUTPUT NONE
```
## String Conversion
Booleans can be converted to strings using `BoolToStr` or the `.ToString` helper.
```pascal
var b := True;
PrintLn(b.ToString); // "True"
PrintLn(BoolToStr(True)); // "True"
```
**Output:**
```text
True
True
```
:::info
### Logic & Control
Booleans are the foundation of decision making.
See
**[Conditionals](/lang/control_flow/control_flow)**
for usage in `if` and `case` statements.
Or explore
**[Basic Operators](/lang/basics/operators)**
for logical operations like `and`, `or`, and `not`.
:::
---
Source: lang/basics/coalesce.md
---
title: Coalesce Operator (??)
id: lang/basics/coalesce
---
# Coalesce Operator (??)
The **??** operator provides a concise way to handle default values. It returns the left-hand operand if it is **not** the default value for its type; otherwise, it returns the right-hand operand.
## Basic Usage
The syntax is `value ?? default`.
```pascal
var name: String := '';
PrintLn(name ?? 'Anonymous');
name := 'Alice';
PrintLn(name ?? 'Anonymous');
```
**Output:**
```text
Anonymous
Alice
```
## Default Values by Type
The operator checks against the language-defined "empty" or "zero" state for each type.
| Type | "Empty" Condition |
| :--- | :--- |
| **String** | `''` (Empty string) |
| **Integer / Float** | `0` / `0.0` |
| **Object / Interface** | `nil` |
| **Boolean** | `False` |
| **Dynamic Array** | `nil` or length `0` |
| **Variant** | `Unassigned` or `Null` |
### Example: Integer and Floats
Note that `0` is considered the default value for numbers.
```pascal
var count := 0;
PrintLn(count ?? 10);
var price := 0.0;
PrintLn(price ?? 19.99);
```
**Output:**
```text
10
19.99
```
### Example: Objects and Arrays
Highly useful for ensuring an object or array is initialized.
```pascal
var list: array of Integer;
// If list is empty/nil, returns a new array
var activeList := list ?? [1, 2, 3];
PrintLn(activeList.Length);
var obj: TObject := nil;
var instance := obj ?? new TObject;
PrintLn(instance.ClassName);
```
**Output:**
```text
3
TObject
```
## Chaining
You can chain multiple `??` operators to find the first non-default value.
```pascal
var input1 := '';
var input2 := '';
var input3 := 'Hello';
var result := input1 ?? input2 ?? input3 ?? 'Default';
PrintLn(result);
```
**Output:**
```text
Hello
```
## Short-circuiting
The right-hand side of a `??` expression is **only evaluated** if the left-hand side is the default value.
```pascal
function GetExpensiveDefault: String;
begin
PrintLn('Computing...');
Result := 'Heavy Value';
end;
var s := 'Quick Value';
// GetExpensiveDefault is NEVER called here
PrintLn(s ?? GetExpensiveDefault());
```
**Output:**
```text
Quick Value
```
## Use with JSON
The coalesce operator is particularly powerful when navigating JSON structures or dynamic data where fields might be missing or null.
```pascal
var data := JSON.Parse('{"id": 123}');
var title := data.title ?? 'Untitled'; // 'title' field is missing
PrintLn(title);
```
**Output:**
```text
Untitled
```
---
Source: lang/basics/compound.md
---
title: Compound Assignment & C-Style Aliases
id: lang/basics/compound
---
# Compound Assignment & Aliases
DWScript provides several operators familiar to developers coming from C-family languages.
## Compound Assignment
Compound assignment operators combine an arithmetic operation with an assignment. They are shorthand for `variable := variable expression`.
| Operator | Equivalent | Description |
| :--- | :--- | :--- |
| `+=` | `a := a + b` | Add and assign |
| `-=` | `a := a - b` | Subtract and assign |
| `*=` | `a := a * b` | Multiply and assign |
| `/=` | `a := a / b` | Divide and assign |
```pascal
var a := 10;
a += 5;
PrintLn(a);
```
**Output:**
```text
15
```
## Comparison Aliases
For convenience, DWScript supports C-style symbols for equality and inequality.
| Operator | Pascal Equivalent | Description |
| :--- | :--- | :--- |
| `==` | `=` | Equality |
| `!=` | `<>` | Inequality |
```pascal
var x := 10;
if (x == 10) then
PrintLn('Matches');
if (x != 0) then
PrintLn('Non-zero');
```
**Output:**
```text
Matches
Non-zero
```
---
Source: lang/basics/constants.md
---
title: Constants
id: lang/basics/constants
---
# Constants
Constants are values that are defined once and cannot be changed during the execution of the script. They are declared using the `const` keyword.
## Declaration
Constants must be assigned a value at the time of declaration. The compiler determines the type of the constant from the value assigned.
```pascal
const PI = 3.14159;
const APP_NAME = 'My Script';
const MAX_RETRIES = 5;
const DEBUG_MODE = True;
PrintLn(APP_NAME);
```
**Output:**
```text
My Script
```
### Typed Constants
While DWScript primarily uses untracked constants (which are effectively replaced by their values at compile-time), it also supports typed constants which behave more like read-only variables.
```pascal
const DEFAULT_TIMEOUT : Integer = 30;
// OUTPUT NONE
```
## Calculated Constants
Constants can be defined using expressions, provided the expression can be evaluated at compile-time. This often involves using other previously defined constants.
```pascal
const BASE_VALUE = 100;
const MULTIPLIER = 5;
const CALCULATED = BASE_VALUE * MULTIPLIER; // 500
const GREETING = 'Hello';
const USER = 'Admin';
const WELCOME_MSG = GREETING + ', ' + USER; // "Hello, Admin"
PrintLn(CALCULATED.ToString);
PrintLn(WELCOME_MSG);
```
**Output:**
```text
500
Hello, Admin
```
## Benefits of Constants
1. **Readability:** Meaningful names instead of "magic numbers".
2. **Maintainability:** Change a value in one place instead of searching through the entire script.
3. **Performance:** Untyped constants are resolved at compile-time, incurring zero runtime overhead.
## Built-in Constants
DWScript provides several built-in constants and functions that behave like constants for common mathematical and system values.
* **`Pi`**: The mathematical constant π (3.14159...).
* **`True`**, **`False`**: Boolean literals.
* **`nil`**: The null pointer/object reference.
```pascal
PrintLn('The value of Pi is ' + FloatToStr(Pi));
```
**Output:**
```text
The value of Pi is 3.14159265358979
```
:::tip
While you can define your own constant named `PI`, it is generally better to use the built-in `Pi` function for maximum precision.
:::
## Global vs. Local Constants
Like variables, constants can be declared at the global level or within the scope of a procedure or function.
```pascal
const GLOBAL_VERSION = '1.0.0';
procedure ShowInfo;
const
LOCAL_PREFIX = 'VER: ';
begin
PrintLn(LOCAL_PREFIX + GLOBAL_VERSION);
end;
ShowInfo;
```
**Output:**
```text
VER: 1.0.0
```
## See Also
* [Variables](/lang/basics/variables)
* [Integers](/lang/basics/ints)
* [Strings](/lang/basics/strings)
---
Source: lang/basics/enums_sets.md
---
title: Enumerated Types & Sets
id: lang/basics/enums_sets
---
# Enumerated Types & Sets
DWScript provides robust support for enumerations and sets, which are core features for writing clear and type-safe Pascal code.
## Enumerated Types
An enumeration defines a set of named constants. DWScript supports three distinct styles of enumerations.
### 1. Classic Enumerations
Symbols are globally scoped within the unit. This is the traditional Pascal style.
```pascal
type TDirection = (North, East, South, West);
// Type inference
var d1 := North;
// Explicit typing
var d2 : TDirection := North;
// OUTPUT NONE
```
### 2. Scoped Enumerations
Using the `enum` keyword requires you to prefix the values with the type name. This prevents name collisions.
```pascal
type TStatus = enum (Ready, Busy, Error);
// Type inference
var s1 := TStatus.Ready;
// Explicit typing
var s2 : TStatus := TStatus.Ready;
// OUTPUT NONE
```
### 3. Flags (Bitmasks)
Using the `flags` keyword automatically assigns power-of-two values (1, 2, 4, 8...). These are designed to be used with bitwise `or` to combine multiple values.
```pascal
type TFileAccess = flags (Read, Write, Execute); // 1, 2, 4
// Type inference
var access1 := TFileAccess.Read or TFileAccess.Write;
// Explicit typing
var access2 : TFileAccess := TFileAccess.Read or TFileAccess.Execute;
// OUTPUT NONE
```
## Sets
Sets are collections of values from an ordinal type (usually an enumeration). A set can hold any combination of its base type's values, or be empty.
A `set of TEnum` is stored efficiently as a bitfield. You can even cast a set to an `Integer` to see its underlying bitmask.
```pascal
type TCards = (Club, Diamond, Heart, Spade);
type THand = set of TCards;
var hand: THand := [Club, Heart];
if Club in hand then
PrintLn('You have a Club');
// Using ranges in sets
var allMinors: THand := [Club..Diamond];
if Heart in [Club..Spade] then
PrintLn('Hearts are in the range');
hand.Include(Spade);
hand.Exclude(Club);
if hand = [] then
PrintLn('Empty hand');
```
**Output:**
```text
You have a Club
Hearts are in the range
```
## Built-in Methods
Enumerations and sets provide several built-in methods for convenience:
* **Enums**:
* `TMyEnum.Low` and `TMyEnum.High` return the first and last values.
* `TMyEnum.ByName('name')` returns the value matching the string.
* `val.Name` returns the name of the enumeration value as a string.
```pascal
// Enum ByName
type TDirection = (North, East, South, West);
var dir := TDirection.ByName('South');
PrintLn(dir.Name);
// Set to Integer Cast
type TCards = (Club, Diamond, Heart, Spade);
type THand = set of TCards;
var mySet : THand := [Club, Spade]; // 0th and 3rd bits
PrintLn(Integer(mySet));
```
**Output:**
```text
South
9
```
* **Sets**:
* `mySet.Include(Value)` adds a value to the set.
* `mySet.Exclude(Value)` removes a value from the set.
* `mySet.Contains(Value)` is equivalent to the `in` operator.
---
Source: lang/basics/files.md
---
title: File Handles
id: lang/basics/files
---
# File Handles
The `File` type represents a handle to an open file on the system. DWScript provides both traditional Pascal-style file I/O and modern stream-based approaches.
## High-level Helpers
For most tasks, it is easier to use high-level helper functions from the standard library. These handle opening and closing the file automatically.
* **`FileExists(path)`**: Returns true if the file exists.
* **`FileRead(path)`**: Reads the entire file into a string.
* **`FileWrite(path, text)`**: Writes a string to a file.
* **`FileReadLines(path)`**: Reads the file into an array of strings.
```pascal
if FileExists('config.json') then begin
var json := FileRead('config.json');
// ...
end;
```
## Binary File I/O (DataStrings)
For binary data, you typically use `ByteBuffer` or **DataStrings**.
:::warning
### The DataString Pattern
Many DWScript functions that accept a "binary" string (like `FileWrite` or certain network functions) expect a **DataString**. In this pattern, only the **lower byte** of each UTF-16 character is processed. To ensure data integrity, always use `ByteBuffer` for raw binary manipulation and convert to a DataString only when required by the API.
:::
```pascal
var buffer := ByteBuffer(FileRead('data.bin'));
// ... process buffer ...
FileWrite('data_out.bin', buffer.ToDataString);
```
:::warning
**Permissions & Safety**: File operations are subject to the security restrictions of the environment where the script is running. In web environments, file access is typically restricted to specific directories.
:::
:::info
### Related Reference
For a complete list of file and directory functions, see the **[Files API Reference](/ref/files)**.
:::
---
Source: lang/basics/floats.md
---
title: Floats
id: lang/basics/floats
---
# Float Type
The `Float` type represents a double-precision 64-bit floating-point number (IEEE 754).
## Literals
Floats are defined using a decimal point. Scientific notation is also supported using the `e` or `E` suffix. You can use type inference or explicit typing.
```pascal
// Type inference
var f1 := 1.234;
var f2 := 1.0;
var f3 := 1e-3; // 0.001
// Explicit typing
var pi : Float := 3.14159;
var avogadro : Float := 6.022e23;
// OUTPUT NONE
```
## Operations
Standard arithmetic operators apply: `+`, `-`, `*`, and `/` (floating-point division).
```pascal
var x := 10 / 3; // 3.33333333333333
// OUTPUT NONE
```
## Formatting
To control the precision when converting to a string, use the `FloatToStr` function or `.ToString` with parameters.
```pascal
var f := 1.234567;
PrintLn(f.ToString); // "1.234567"
PrintLn(FloatToStr(f, 2)); // "1.23"
```
**Output:**
```text
1.234567
1.23
```
## Special Values
The Float type supports IEEE 754 special values for representing infinity and invalid operations.
* `INF`: Positive Infinity (e.g., `1.0 / 0.0`)
* `NegINF`: Negative Infinity (e.g., `-1.0 / 0.0`)
* `NaN`: Not a Number (e.g., `0.0 / 0.0` or `Sqrt(-1)`)
You can check for these values using the helper functions:
* `IsNaN(val)`
* `IsInfinite(val)`
```pascal
var x := 1.0 / 0.0;
if IsInfinite(x) then
PrintLn('Infinity reachable');
```
**Output:**
```text
Infinity reachable
```
:::info
### Related Reference
* **[Math Reference](/ref/math)** - Trigonometry, logarithms, and rounding functions (`Round`, `Trunc`, `Ceil`, `Floor`).
:::
---
Source: lang/basics/from_delphi.md
---
title: Coming from Delphi
id: lang/basics/from_delphi
---
# Coming from Delphi
If you are a Delphi developer, DWScript will feel immediately familiar. You can use standard Pascal syntax, the `begin`/`end` blocks, and the VCL/RTL class naming conventions you are used to. However, DWScript is a distinct language with its own runtime characteristics.
Here are the critical differences you need to know to write effective scripts.
## 1. Automatic Reference Counting (ARC)
The most significant difference is memory management. **DWScript uses ARC (Automatic Reference Counting) for all objects.**
* **Delphi:** You typically create an object and must explicitly `Free` it (unless it's an interface or you are using `FreeAndNil`).
* **DWScript:** You create an object, and it is automatically destroyed when the last reference to it goes out of scope.
```pascal
type TMyClass = class end;
// Delphi Style (Do NOT do this in scripts usually)
// obj := TMyClass.Create;
// try ... finally obj.Free; end;
// DWScript Style
var obj := TMyClass.Create;
// use obj...
// obj is automatically freed here
```
Because ARC is universal, there is no need for `TInterfacedObject`.
Because ARC is complemented by a GC, there is no need for Weak references.
## 2. Dynamic Arrays vs. TList
DWScript's dynamic arrays are far more powerful than Delphi's. They are full-fledged objects with methods for adding, removing, sorting, and finding elements.
**You do not need `TList`, `TList`, or `TStringList`.**
* **Addition:** Use `.Add()` or the `+=` operator.
* **Removal:** Use `.Delete()`, `.Remove()`, or `.Pop()`.
* **Search:** Use `.IndexOf()` or the `in` operator.
* **Manipulation:** Use `.Map()`, `.Filter()`, and `.Sort()`.
## 3. Associative Arrays vs. TDictionary
Instead of `TDictionary`, DWScript provides built-in syntax for associative arrays (maps).
```pascal
var capitals : array[String] of String;
capitals['France'] := 'Paris';
if 'France' in capitals then
PrintLn(capitals['France']);
```
**Output:**
```text
Paris
```
This built-in syntax is more expressive, faster, and avoids the verbosity of generics.
## 4. Strings & Helpers
Strings in DWScript are more capable and reduce the need for external helper functions.
* **Multiline Strings:** You can use double-quoted strings `"..."` for standard multiline strings, or raw strings `#'...'` (heredocs) for multiline strings that automatically strip common indentation, keeping your code readable and well indented.
* **Helpers:** Standard helpers are built-in, making legacy string functions mostly redundant. There is a full suite of helpers to slice, extract, delete left/right and manipulate strings expressively without needing manual index computations.
## 5. JSON Support
JSON is a first-class citizen. Unlike Delphi's verbose `TJSONObject` builders, DWScript provides the `JSONVariant` type (via `JSON.Parse` and `JSON.NewObject`).
It allows dynamic access to fields without constant type casting.
```pascal
var data := JSON.Parse('{"user": "Alice", "id": 42}');
PrintLn(data.user); // "Alice" - No .GetValue('user').Value needed!
```
**Output:**
```text
Alice
```
Anonymous records support stringifying inline with type-safety and compile-time validation.
```pascal
var msg := record
from := 'Alice';
text := 'Hello!';
end;
PrintLn(JSON.Stringify(msg));
```
**Output:**
```text
{"from":"Alice","text":"Hello!"}
```
## 6. Guaranteed Initialization
In Delphi, local variables of ordinal types (Integer, Boolean, etc.) are uninitialized and contain garbage values unless explicitly set.
**In DWScript, all variables are guaranteed to be initialized.**
* Integers, Floats -> 0
* Booleans -> False
* Strings -> ''
* Objects/Arrays -> nil
You can also provide a default value inline:
```pascal
var count : Integer := 10; // Initialized to 10
var total : Integer; // Guaranteed to be 0
```
## 7. Generalized Case Statements
DWScript extends the `case` statement to support Strings and other non-ordinal types.
```pascal
var s := 'hello';
case s of
'hello', 'hi': PrintLn('Greeting');
'bye': PrintLn('Farewell');
else
PrintLn('Unknown');
end;
```
**Output:**
```text
Greeting
```
## 8. Case Sensitivity Hints
While DWScript is case-insensitive (like Delphi), the compiler is stricter about **consistency**.
If you declare a variable as `MyVariable` but use it as `myvariable`, the compiler may emit a **Hint**. This enforces code cleanliness and consistency.
## 9. Type Inference
DWScript encourages the use of `:=` for variable declaration with type inference.
```pascal
// Explicit
var x : Integer = 10;
// Inferred
var y := 10;
```
## 10. Constant Expressions
Constants can be evaluated at compile time from expressions, and can use pure functions (functions without side effects, whose result only depends on their parameters).
---
Source: lang/basics/history.md
---
title: History of DWScript
id: lang/basics/history
---
# History of DWScript
The project began as **Delphi Web Script (DWS)**, originally created by Matthias Ackermann and Hannes Hernler (DWS2) in the late 1990s. Its initial purpose was specific: to provide a way to embed Pascal scripts directly within HTML pages, similar to how PHP operates. This allowed Delphi developers to build dynamic websites using the language they already knew.
In 2010, Eric Grange took over as the primary maintainer and lead developer. While the original name "Delphi Web Script" remains, the "Web" part became less central to its identity, the engine was refocused as a general-purpose scripting solution.
Over the last decade, DWScript has introduced features that rival compiled languages:
* **JIT Compilation:** Leveraging LLVM for native code generation in some targets.
* **Modern Language Features:** Introducing syntax features often ahead of or parallel to Delphi, such as type inference, specialized array operators, and modern OOP constructs.
* **Performance:** A relentless focus on execution speed and memory efficiency, making it one of the fastest Object Pascal scripting engines available.
* **JavaScript Transpilation:** The ability to compile Object Pascal code into JavaScript, a core feature that enabled the creation of Smart Mobile Studio.
Today, DWScript is used not just for web backends, but for game logic, rule engines, and application extensibility, keeping the Pascal spirit alive in modern scripting environments.
---
Source: lang/basics/html_filter.md
---
title: HTML Filter (PHP-style)
id: lang/basics/html_filter
---
# HTML Filter
The **HTML Filter** allows you to use DWScript in a "PHP-style" way, where you can mix HTML and Pascal code in the same file. This is the primary mode for building dynamic web pages in the DWScript WebServer.
When the filter is active, the engine treats the entire file as literal text to be printed, except for code enclosed within special tags.
## Syntax Tags
By default, the HTML filter uses the following tags:
| Tag | Description | Equivalent Pascal |
| :--- | :--- | :--- |
| `` | **Code Block**: Executes the Pascal code inside. | `...` |
| `` | **Evaluation Tag**: Evaluates an expression and prints the result. | `Print(...);` |
### Code Block Example
You can use standard Pascal control flow (loops, conditionals) to generate HTML dynamically.
```pascal
Item Number
```
**Output:**
```text
*
Item Number 1
Item Number 2
Item Number 3
```
### Expression Evaluation
The `` tag is a shorthand for `Print()`. It is commonly used for injecting variables or the results of function calls into the HTML.
```pascal
The current date is:
```
**Output:**
```text
The current date is: *
```
:::tip
#### Automatic HTML Escaping
Unlike some other languages, the HTML filter does not automatically escape output. For security and to prevent XSS, you should use the `.ToHtml` helper on strings: ``.
:::
## Beyond HTML: Versatility
While commonly used for HTML, the "HTML Filter" is actually a general-purpose text preprocessor. Because it does not perform any automatic escaping, you can use it to generate CSS, JSON, XML, or plain text by simply setting the appropriate `ContentType` in the `WebResponse`.
```pascal
body {
background-color: ;
}
```
**Output:**
```text
body {
background-color: #f0f0f0;
}
```
This flexibility is why built-in HTML escaping is omitted; the filter has no way of knowing if your output target requires HTML entities, CSS escaping, or no escaping at all.
## The $FILTER Directive
The `{$FILTER "filename"}` directive (shorthand `{$F "filename"}`) allows you to include an external file and process it through the current filter.
This is different from a standard `include` because the included file will also be treated as HTML with `
Page Header
{$FILTER "sidebar.html"}
```
If `sidebar.html` contains:
```html
```
It will be correctly processed before being injected into the main page.
## Configuration
In a custom host application, the HTML filter is provided by the `TdwsHtmlFilter` component. You can customize the tags if needed:
- **PatternOpen**: Default is ``.
- **PatternEval**: Default is `=`.
## Handling Special Characters
The filter is designed to handle special characters like quotes and newlines gracefully. When it processes text outside of tags, it automatically wraps it in `Print()` calls, escaping any single quotes found in the text so they don't break the Pascal string literals.
Example of filtered output transformation:
`It's a "beautiful" day` -> `Print('It''s a "beautiful" day');`
---
Source: lang/basics/introduction.md
---
title: Introduction
id: lang/basics/introduction
---
# Introduction
Welcome to DWScript. If you are familiar with Pascal or Delphi, you will feel right at home. If you are coming from JavaScript or PHP, you will appreciate the structure and clarity that Pascal brings.
## Hello World
Let's start with the classic example. In DWScript, a standalone script is simply a sequence of statements.
```pascal
PrintLn('Hello World');
```
**Output:**
```text
Hello World
```
When this script runs on the server, it outputs:
Hello World
## Code Structure
Scripts can contain:
* **Statements:** Instructions to be executed (like `PrintLn`).
* **Declarations:** Variables, types, constants, procedures, and functions.
Statements are separated by semicolons `;`. Blocks of code are enclosed in `begin` and `end` keywords.
```pascal
var x : Integer;
x := 10;
if x > 5 then begin
PrintLn('x is greater than 5');
end;
```
**Output:**
```text
x is greater than 5
```
## Comments
Comments are ignored by the compiler and are used to document your code. DWScript supports standard Pascal comments as well as C-style block comments.
```pascal
// Single line comment
{
Multi-line block comment
}
(*
Another style of multi-line comment
*)
/*
C-style block comment
*/
// OUTPUT NONE
```
## Identifiers
Identifiers are names you give to variables, constants, procedures, and other entities. They must start with a letter or underscore, followed by letters, numbers, or underscores.
### Reserved Words & Escaping
You cannot use reserved keywords (like `type`, `begin`, `if`) directly as identifiers. However, you can use them by prefixing them with an ampersand `&`.
```pascal
var &type := 'System'; // 'type' is a reserved word
PrintLn(&type);
```
**Output:**
```text
System
```
## Compiler Directives
Directives are special instructions to the compiler that start with `{$`. They are used for conditional compilation, including files, and controlling compiler behavior.
```pascal
{$IFDEF DEBUG}
// This code only compiles if DEBUG is defined
PrintLn('Debug Mode');
{$ENDIF}
// OUTPUT NONE
```
---
Source: lang/basics/ints.md
---
title: Integers
id: lang/basics/ints
---
# Integer Type
The `Integer` type represents a signed 64-bit integer. It is the primary type for whole numbers in DWScript.
## Literals
Integers can be defined in multiple formats. You can use underscores `_` as digit separators to improve readability of large numbers. DWScript supports both type inference and explicit typing.
| Format | Prefix | Example |
| :--- | :--- | :--- |
| Decimal | (none) | `1_000_000` |
| Hexadecimal | `$` or `0x` | `$FF` or `0xFF` |
| Binary | `%` or `0b` | `%1010` or `0b1010` |
```pascal
// Type inference
var d := 123;
var h := $FF; // 255
var b := %1010; // 10
var big := 1_000_000;
// Explicit typing
var count : Integer := 10;
var status : Integer;
status := 200;
// OUTPUT NONE
```
## Operations
Standard arithmetic operators apply: `+`, `-`, `*`, `div` (integer division), and `mod` (remainder). Bitwise operators like `shl`, `shr`, `and`, `or`, `xor`, and `not` are also supported.
```pascal
var x := 10 div 3; // 3
var y := 10 mod 3; // 1
var z := (1 shl 8); // 256
// OUTPUT NONE
```
## Conversions
You can convert integers to strings or other types using built-in functions or method helpers.
```pascal
var i := 255;
var s := i.ToString; // "255"
var hex := i.ToHexString(2); // "FF"
var val := StrToInt('123');
// OUTPUT NONE
```
## Type Limits
You can retrieve the minimum and maximum possible values for the 64-bit `Integer` type using the `Low` and `High` functions.
```pascal
var min := Low(Integer);
var max := High(Integer);
PrintLn(min.ToString);
PrintLn(max.ToString);
```
**Output:**
```text
-9223372036854775808
9223372036854775807
```
:::info
### Related Reference
* **[Math Reference](/ref/math)** - Absolute value, Min/Max, and more.
* **[Strings Transformation](/ref/strings_transform)** - Detailed conversion options.
:::
---
Source: lang/basics/modes.md
---
title: Operating Modes
id: lang/basics/modes
---
# Operating Modes
DWScript is a versatile language that can run in different environments. Understanding the operating mode is crucial as it affects available features and libraries.
## 1. Native Script Mode
In this mode, DWScript runs directly on the host machine (Windows) via the CLI or an embedded host application.
* **Execution:** Parsed and compiled into an executable abstract syntax tree (with optional partial Just-In-Time compilation).
* **Capabilities:** Full access to the file system, network, and external libraries (DLLs).
* **Memory Management:** Automatic Reference Counting (ARC) and Garbage Collection (depending on configuration).
* **Use Case:** Automation scripts, build tools, backend processing.
## 2. Web Server Mode (Server Pages)
This is the mode used to serve this website. DWScript files (`.dws`) are executed by the web server to generate dynamic HTML content.
* **Syntax:** Usually employs the
[HTML Filter (PHP-style)](/lang/basics/html_filter)
to mix code and markup.
* **Context:** Includes a global `WebRequest` and `WebResponse` object.
* **Output:** `Print` and `PrintLn` functions write directly to the HTTP response stream.
* **Lifecycle:** Scripts are stateless; they run once per request. Standard global variables are reset for every request.
* **Persistence:** For sharing data across requests, see the [Global & Private State](/lang/basics/state) page.
* **Use Case:** Web applications, API endpoints.
## 3. JavaScript Transpilation
DWScript can be compiled into JavaScript to run in a web browser or Node.js environment. This allows you to write the frontend code in the same language as your backend.
* **Compilation:** The Pascal source is translated into equivalent JavaScript code.
* **Integration:** You can interact with the DOM, use JS libraries, and write `asm` blocks containing raw JavaScript.
* **Differences:**
* **Integers:** JavaScript numbers are doubles. `Integer` behaves like a JS number (53-bit precision safe).
* **Memory:** Relies on the JavaScript engine's Garbage Collector.
* **File System:** No direct access to the client's file system (browser security sandbox).
* **Use Case:** Single Page Applications (SPAs), complex client-side logic, game logic sharing.
## Syntax & Compilation Units
Beyond the execution environment, DWScript supports two primary ways of structuring source code: **Script Mode** and **Unit Mode**.
### Script Mode (Mixed Code & Declarations)
This is the most flexible mode, where you can mix variables, types, and procedures directly with executable code. It is ideal for small tasks and web server pages.
* **Top-down execution:** Code is executed from the first line.
* **Inline Declarations:** You can declare a `var` or `type` anywhere before its first use.
* **Interspersed Logic:** You can have `PrintLn` calls between `type` and `procedure` definitions.
```pascal
PrintLn('Starting script');
type TUser = record Name: String; end;
var u: TUser;
u.Name := 'Alice';
procedure SayHello;
begin
PrintLn('Hello ' + u.Name);
end;
SayHello;
```
**Output:**
```text
Starting script
Hello Alice
```
### Unit / Program Mode (Structured)
This mode follows the classic Object Pascal structure and is used for building reusable modules or larger applications. It enforces a strict separation between declarations and implementation.
* **Keyword:** Must start with `unit` or `program`.
* **Sections:** Uses `interface` and `implementation` blocks.
* **Type Blocks:** Types and variables must be grouped into their respective sections (e.g., after the `type` keyword).
```pascal
unit MyUtils;
interface
type
TPoint = record
X, Y: Integer;
end;
implementation
// Code logic goes here...
end.
// OUTPUT NONE
```
:::info
#### Choosing a Mode
Web server `.dws` files always start in **Script Mode**. If you want to use Units, you create separate `.pas` files and include them via `uses`.
:::
---
Source: lang/basics/operators.md
---
title: Operators
id: lang/basics/operators
---
# Operators
DWScript supports standard Pascal operators for arithmetic, logic, and comparisons.
## Assignment & Arithmetic
```pascal
var a := 10;
var b := 20;
PrintLn(a + b);
PrintLn(10 div 3);
PrintLn(10 mod 3);
PrintLn(10 / 3);
```
**Output:**
```text
30
3
1
3.33333333333333
```
## Arithmetic Operators
| Operator | Operation | Example |
| :--- | :--- | :--- |
| `+` | Addition (or Unary +) | `1 + 2` (3) |
| `-` | Subtraction (or Unary -) | `5 - 3` (2) |
| `*` | Multiplication | `2 * 4` (8) |
| `/` | Division (Float) | `10 / 2` (5.0) |
| `div` | Integer Division | `10 div 3` (3) |
| `mod` | Modulus (Remainder) | `10 mod 3` (1) |
## Logical Operators
Used with Boolean values. Logical operators in DWScript are **short-circuiting**, meaning the second operand is only evaluated if the first one doesn't determine the final result.
| Operator | Description |
| :--- | :--- |
| `not` | Negation (True becomes False) |
| `and` | Logical AND (True if both are True) |
| `or` | Logical OR (True if either is True) |
| `xor` | Logical XOR (True if only one is True) |
| `implies` | Material Implication (False only if True implies False) |
## Comparison Operators
| Operator | Description |
| :--- | :--- |
| `=` | Equal to |
| `<>` | Not equal to |
| `<` | Less than |
| `>` | Greater than |
| `<=` | Less than or equal to |
| `>=` | Greater than or equal to |
| `is` | Type compatibility check (for classes and interfaces) |
:::info
#### Reference Comparison
For **Dynamic Arrays** and **Objects**, the `=` and `<>` operators perform a **reference comparison** (checking if both point to the same memory instance) rather than comparing their contents.
:::
| Operator | Description |
| :--- | :--- |
| `as` | Checked type cast |
| `implements` | Checks if an object/class implements an interface |
| `in` | Set membership, array inclusion, or substring check |
| `not in` | Negation of `in` (True if NOT a member) |
### Interface Implementation
The `implements` operator is used to check if a class or object supports a specific interface, which is useful for conditional casting or logic.
```pascal
type ILogger = interface end;
type TMyLogger = class(TObject, ILogger) end;
if TMyLogger implements ILogger then
PrintLn('Implements interface');
```
**Output:**
```text
Implements interface
```
## Collection & String Inclusion
In DWScript, the `in` operator is highly versatile and works with sets, arrays, and strings.
### Set Inclusion & Ranges
You can check if a value belongs to a set of values or a specific range.
```pascal
var c := 'k';
if c in ['a'..'z', '0'..'9', '_'] then
PrintLn('Is Alphanumeric');
var x := 5;
if x in [1..10, 20..30] then
PrintLn('Is in range');
var s := 'Grape';
if s in ['Apple'..'Orange'] then
PrintLn('Between Apple and Orange');
```
**Output:**
```text
Is Alphanumeric
Is in range
Between Apple and Orange
```
### Array Inclusion
You can check if an element exists within an array. This works for simple types, records, and objects.
```pascal
var colors := ['Red', 'Green', 'Blue'];
if 'Green' in colors then
PrintLn('Found Green');
if 'Yellow' not in colors then
PrintLn('Yellow is missing');
```
**Output:**
```text
Found Green
Yellow is missing
```
### String Inclusion
You can check if a string contains another string using the `in` operator or the `.Contains()` method. This is more readable and idiomatic than using `Pos() > 0`.
```pascal
var msg := 'Hello World';
// Using 'in' operator
if 'World' in msg then
PrintLn('Found using in');
// Using .Contains method
if msg.Contains('Hello') then
PrintLn('Found using .Contains');
// Legacy style (not recommended)
if Pos('Hello', msg) > 0 then
PrintLn('Found using Pos');
```
**Output:**
```text
Found using in
Found using .Contains
Found using Pos
```
## Operator Precedence
Higher priority operators are evaluated first. When operators have the same priority, they are evaluated from left to right.
1. `not`, Unary `-`, Unary `+`
2. `*`, `/`, `div`, `mod`, `and`, `shl`, `shr`, `sar`
3. `??` (Coalesce)
4. `+`, `-`, `or`, `xor`
5. `=`, `==`, `<>`, `!=`, `<`, `>`, `<=`, `>=`, `in`, `not in`, `is`, `as`, `implies`
6. `if then else` (Ternary)
## Custom Operators
You can define custom behavior for operators when working with your own types.
* **[Class Operators](/lang/oop/oop)**
Define operators (like `+=`, `in`) for classes.
* **[Record Operators](/lang/basics/records)**
Define global operators for record value types.
:::info
#### Specialized Operators
DWScript also supports several specialized operators for concise expression:
* **[Ternary Operator](/lang/basics/ternary)**: Expression-based `if then else`.
* **[Coalesce Operator](/lang/basics/coalesce)**: Handle default values with `??`.
* **[Bitwise Operators](/lang/basics/bitwise)**: Low-level bit manipulation.
* **[Compound & Aliases](/lang/basics/compound)**: C-style operators like `+=`, `==`, and `===`.
:::
---
Source: lang/basics/overview.md
---
title: Language Overview
id: lang/basics/overview
---
# Language Overview
DWScript is an object-oriented scripting language based on Delphi (Object Pascal). It features a strong type system, high performance, and a rich standard library. This guide is organized into the following sections:
## 1. Getting Started
* **[Welcome](/lang/basics/introduction)**
Basic syntax, comments, and program entry points.
* **[Program Structure](/lang/basics/structure)**
Units, namespaces, and scope.
* **[Operating Modes](/lang/basics/modes)**
Differences between native execution, web server, and JS transpilation.
* **[Coming from Delphi](/lang/basics/from_delphi)**
Key differences for experienced Delphi developers.
## 2. Types & Variables
* **Type System** - [Overview](/lang/basics/types), [Variables](/lang/basics/variables) & [Constants](/lang/basics/constants).
* **Core Types** - [Integers](/lang/basics/ints), [Floats](/lang/basics/floats), [Booleans](/lang/basics/bools), and [Strings](/lang/basics/strings).
* **[Enums & Sets](/lang/basics/enums_sets)**
Enumerated types and bitmasks.
* **[Variants](/lang/basics/variants)**
Dynamic typing support.
## 3. Operators
* **[Arithmetic & Logic](/lang/basics/operators)**
Standard math, comparison, and logical operators.
* **[Bitwise Operators](/lang/basics/bitwise)**
Manipulating data at the bit level.
* **[Ternary](/lang/basics/ternary)**
& **[Coalesce](/lang/basics/coalesce)**
Compact conditional expressions.
## 4. Control Flow
* **[Loops](/lang/control_flow/loops)**
`for`, `while`, and `repeat` loops.
* **[Conditionals](/lang/control_flow/control_flow)**
`if` statements and `case` blocks.
* **[Iteration](/lang/control_flow/iteration)**
Iterating over collections and ranges.
* **[Exceptions](/lang/control_flow/exceptions)**
Error handling with `try...except` and `try...finally`.
## 5. Data Structures
* **[Arrays](/lang/basics/arrays)**
Static and dynamic arrays.
* **[Associative Arrays](/lang/basics/associative_arrays)**
Dictionary-like collections.
* **[Records](/lang/basics/records)**
Value types with methods and operators.
* **[Tabular Data](/lang/advanced/tabular)**
In-memory dataset handling.
## 6. Functions
* **[Subroutines](/lang/functions/subroutines)**
Procedures and functions.
* **[Parameters](/lang/functions/parameters)**
Passing values, constants, and references.
* **[Contracts](/lang/functions/contracts)**
Design-by-contract features (requires/ensures).
* **[Lambdas](/lang/advanced/lambdas)**
Anonymous functions and closures.
## 7. Object Oriented Programming
* **[Classes & Objects](/lang/oop/oop)**
Inheritance, polymorphism, constructors.
* **[Properties](/lang/oop/oop_properties)**
Getters, setters, and array properties.
* **[Interfaces](/lang/oop/interfaces)**
Contract-based programming.
* **[Helpers](/lang/advanced/helpers)**
Extending existing types.
## 8. Files & System
* **[File I/O](/lang/stdlib/std_files)**
Reading and writing files.
* **[Date & Time](/lang/stdlib/std_datetime)**
Temporal operations.
* **[Configuration](/lang/stdlib/std_inifiles)**
INI files and [Registry](/lang/stdlib/std_registry).
## 9. Web & Database
* **[Web Support](/lang/stdlib/std_web)**
Handling HTTP requests and responses.
* **[JSON](/lang/stdlib/std_json)**
Parsing and generating JSON.
* **[Database](/lang/advanced/database)**
SQL integration.
## 10. Advanced Topics
* **[State Management](/lang/basics/state)**
Persistent variables and state management.
* **[RTTI](/lang/advanced/rtti)**
Runtime Type Information and Attributes.
* **[Metaprogramming](/lang/advanced/metaprogramming)**
Compile-time logic.
* **[Style Guide](/lang/tooling/style)**
Best practices for formatting and naming.
* **[Example Gallery](/example/language/oop_demo)**
Practical code samples.
:::info
**Gotcha:** Be aware of the difference between **Array** (0-indexed) and **String** (1-based) indexing. See **[Indexing Strategy](/lang/basics/types#indexing-strategy)** for details.
:::
---
Source: lang/basics/records.md
---
title: Records
id: lang/basics/records
---
# Records
Records are structured types that group related data together. In DWScript, they are powerful **value types** that support methods and operator overloading.
## Basic Records
In its simplest form, a record is a set of data fields. It maps directly to a block of memory.
```pascal
type
TPoint = record
X, Y: Integer;
end;
var p: TPoint;
p.X := 10;
p.Y := 20;
// OUTPUT NONE
```
Fields in a record are public by default.
## Default Field Values
You can specify default values for fields in a record. These values are applied when the record is initialized. Type inference is also supported.
```pascal
type
TSettings = record
Width: Integer := 800;
Height := 600; // Type inferred as Integer
Name: String := 'Untitled';
end;
var s: TSettings;
PrintLn(s.Width);
PrintLn(s.Height);
PrintLn(s.Name);
```
**Output:**
```text
800
600
Untitled
```
## Anonymous Records
Anonymous records allow you to define and initialize a record in a single expression, similar to JSON objects. They are fully compatible with `System.JSON`.
```pascal
var user := record
id := 123;
name := 'Alice';
&type := 'Admin'; // '&' allows using reserved words like 'type'
end;
PrintLn(user.name);
PrintLn(user.&type);
```
**Output:**
```text
Alice
Admin
```
:::info
#### JSON Compatibility
Anonymous records are highly compatible with `JSON.Stringify`. In DWScript, anonymous records have their fields in a `published` section by default, ensuring they are automatically included during serialization.
The `&` prefix is also handled during serialization, so `&type` becomes `"type"` in the resulting JSON.
For more details, see **[JSON Support](/lang/stdlib/std_json)**.
:::
## Advanced Features
Unlike standard Pascal records, DWScript records can have visibility specifiers, methods, and properties.
```pascal
type
TVec2 = record
private
FX, FY: Float;
public
procedure SetPos(x, y: Float);
function Length: Float;
property X: Float read FX;
property Y: Float read FY;
end;
procedure TVec2.SetPos(x, y: Float);
begin
FX := x; FY := y;
end;
function TVec2.Length: Float;
begin
Result := Sqrt(FX*FX + FY*FY);
end;
var v: TVec2;
v.SetPos(3, 4);
PrintLn(v.Length.ToString);
```
**Output:**
```text
5
```
## Value Semantics
Records are **value types**. This means they are copied when assigned to a new variable or passed to a function (unless using `var`). They do not support inheritance.
```pascal
type
TPoint = record
X, Y: Integer;
end;
var a, b: TPoint;
a.X := 10;
// b gets a copy of a's value
b := a;
// Modifying b does not affect a
b.X := 20;
PrintLn('a.X = ' + a.X.ToString);
PrintLn('b.X = ' + b.X.ToString);
```
**Output:**
```text
a.X = 10
b.X = 20
```
## Methods & Operators
Records can have methods and operators, allowing them to behave like light-weight objects while retaining value semantics.
### Pseudo-Constructors
While records do not support traditional `constructor` syntax, you can use a `class function` to create a factory method (pseudo-constructor).
```pascal
type
TMyVector = record
X, Y: Float;
class function Create(aX, aY: Float): TMyVector;
begin
Result.X := aX;
Result.Y := aY;
end;
end;
var v := TMyVector.Create(10, 20);
PrintLn(v.X.ToString + ', ' + v.Y.ToString);
```
**Output:**
```text
10, 20
```
### Operator Overloading
Records can define operators like `+`, `-`, or `implicit` and `explicit` casts.
```pascal
type
TVec2 = record
X, Y: Float;
class function Create(aX, aY: Float): TVec2;
begin
Result.X := aX;
Result.Y := aY;
end;
end;
function AddVec2(a, b: TVec2): TVec2;
begin
Result.X := a.X + b.X;
Result.Y := a.Y + b.Y;
end;
// Overload the + operator
operator + (TVec2, TVec2): TVec2 uses AddVec2;
var v1 := TVec2.Create(10, 20);
var v2 := TVec2.Create(5, 5);
var v3 := v1 + v2;
PrintLn(v3.X.ToString + ', ' + v3.Y.ToString);
```
**Output:**
```text
15, 25
```
## Implicit Operators
DWScript supports **Implicit Operators**, which allow for automatic type conversion between records and other types. This is useful for creating types that behave like primitives.
```pascal
type
TMoney = record
Amount: Float;
Currency: String;
end;
function FloatToMoney(f: Float): TMoney;
begin
Result.Amount := f;
Result.Currency := 'USD';
end;
// Enable automatic conversion from Float to TMoney
operator implicit (Float): TMoney uses FloatToMoney;
var wallet: TMoney;
wallet := 50.0; // Automatically calls FloatToMoney
PrintLn(wallet.Amount.ToString + ' ' + wallet.Currency);
```
**Output:**
```text
50 USD
```
---
Source: lang/basics/state.md
---
title: Global & Private State
id: lang/basics/state
---
# Global & Private State
In web server environments, scripts are typically stateless and reset with every request. DWScript provides specialized mechanisms to maintain state across requests and share data between concurrent users.
## Persistence Mechanisms
These variables are stored in the server's memory and are accessible across different requests. They are ideal for caching, configuration, or application-wide counters.
| Type | Scope | Persistence | Use Case |
| :--- | :--- | :--- | :--- |
| **GlobalVars** | Application-wide | Until server restart | Shared caches, global settings. |
| **PrivateVars** | Unit/Library namespaced | Until server restart | Module-specific data, private counters. |
## Global Variables (GlobalVars)
GlobalVars are shared across the entire web application. Any script can read or write to any GlobalVar.
* `WriteGlobalVar(name, value [, expire])`: Stores a value with optional expiration in seconds.
* `ReadGlobalVar(name)`: Retrieves a value. Returns `Unassigned` if it doesn't exist.
* `ReadGlobalVarDef(name, default)`: Retrieves a value or returns the default.
* `IncrementGlobalVar(name [, amount, expire])`: Atomically increments a numeric value (thread-safe).
## Private Variables (PrivateVars)
PrivateVars work similarly to GlobalVars but are namespaced to the **Unit (Module)** in which they are used. This prevents naming collisions between different libraries.
* `WritePrivateVar(name, value [, expire])`
* `ReadPrivateVar(name [, default])`
* `IncrementPrivateVar(name [, amount, expire])`: Atomically increments a numeric value.
## Example Usage
The following example demonstrates a simple, thread-safe request counter.
```pascal
var count : Integer;
// Atomic increment is the safest way to update shared counters
count := IncrementGlobalVar('VisitorCount');
PrintLn('You are visitor number: ' + IntToStr(count));
// Reset for documentation consistency
WriteGlobalVar('VisitorCount', 0);
```
**Output:**
```text
You are visitor number: 1
```
:::warning
### Concurrency Warning
Since these variables are shared across all concurrent requests, they are subject to race conditions if multiple scripts try to modify them simultaneously. For complex state management, consider using a database or thread-safe primitives.
:::
---
Source: lang/basics/strings.md
---
title: Strings
id: lang/basics/strings
---
# String Type
Strings in DWScript are Unicode-capable (UTF-16) and highly flexible. They support both traditional Pascal functions and modern method-style syntax.
## Literals
DWScript supports several styles of string literals to handle everything from simple labels to large blocks of text.
### Single Quoted Strings
Standard Pascal strings use single quotes `'`. To include a single quote inside the string, use two consecutive single quotes `''`.
Standard C-style escape sequences like `\n` or `\t` are **not** supported in single-quoted strings. Use `#` codes instead (e.g., `#13#10` for newline).
```pascal
// Type inference
var s := 'It''s a beautiful day';
// Explicit typing
var name : String := 'Alice';
var greeting : String;
greeting := 'Hello, world!';
```
### Double Quoted Strings (Multi-line)
Double quotes `"` define strings that can span multiple lines directly.
```pascal
var multi := "This is a
multi-line string.";
PrintLn(multi);
```
**Output:**
```text
This is a
multi-line string.
```
### Triple Quoted Strings (Delphi Compatible)
Triple apostrophes `'''` define multiline strings. DWScript performs **smart indentation stripping** based on the indentation of the closing `'''`.
```pascal
var msg := '''
Hello
World
''';
// The 2-space indent is stripped because the closing ''' matches it.
```
### Raw Strings (Heredocs)
Prefixing a string with `#` (e.g., `#'...'` or `#"..."`) creates a **raw string**.
* **Indentation Stripping:** If a multiline raw string starts with a newline, common leading indentation is automatically removed.
* **No Escaping:** Backslashes are treated as literal characters.
```pascal
// Common indent is stripped
var sql := #"
SELECT *
FROM Users
WHERE Name = 'Admin'
";
// Literal paths (no double backslash needed)
var path := #'C:\Windows\System32';
```
### Resource Strings
Use the `resourcestring` keyword to define strings that are stored as resources. This is traditionally used for localizable text.
```pascal
uses System.WebServer;
resourcestring
rsGreeting = 'Hello, %s!';
resourcestring
rsError = 'An unexpected error occurred.';
PrintLn(Format(rsGreeting, ['Alice']));
```
**Output:**
```text
Hello, Alice!
```
## Character Literals
Individual characters can be represented by their ASCII/Unicode code using the `#` prefix.
```pascal
var lineFeed := #10;
var space := #$20;
var combined := 'First line'#13#10'Second line';
```
## Character Access & Indexing
Strings in DWScript are **1-based**, matching traditional Pascal conventions. The first character is at index `1`, and the last character is at index `s.Length`.
```pascal
var s := 'DWScript';
PrintLn('First char: ' + s[1]);
PrintLn('Last char: ' + s[s.Length]);
// Loop through characters
for var i := 1 to s.Length do
Print(s[i] + ' ');
PrintLn('.');
```
**Output:**
```text
First char: D
Last char: t
D W S c r i p t .
```
:::warning
**Indexing Gotcha:** Strings are **1-based**. See **[Indexing Strategy](/lang/basics/types#indexing-strategy)** for the comparison with Arrays.
:::
## Unicode & Surrogate Pairs
DWScript strings are UTF-16 encoded, but the language provides high-level support for handling characters outside the Basic Multilingual Plane (BMP), such as emojis.
When iterating over a string using a `for in` loop, DWScript iterates over **full Unicode characters** (code points), automatically handling surrogate pairs. The loop variable is of type **String**.
```pascal
var s := 'Ready 🚀';
PrintLn('Length: ' + s.Length.ToString); // Length is in UTF-16 code units
for var c in s do
Print(c + '|');
```
**Output:**
```text
Length: 8
R|e|a|d|y| |🚀|
```
Note that `s.Length` returns the number of UTF-16 code units (where the rocket emoji counts as 2), but the `for in` loop correctly identifies it as a single character.
## Common Operations
DWScript supports **Unified Method Syntax**, allowing you to call string functions as methods.
### Concatenation
Use the `+` operator to join strings. Explicitly convert non-string types using `.ToString`.
```pascal
var count := 42;
var s := 'Count: ' + count.ToString;
var name := 'Alice';
PrintLn('Hello, ' + name + '!');
```
**Output:**
```text
Hello, Alice!
```
### Search & Logic
You can easily check for substrings or patterns.
```pascal
var s := 'The quick brown fox';
if 'quick' in s then
PrintLn('Found it!'); // 'in' operator support
if s.StartsWith('The') then
PrintLn('Starts with The');
if s.Contains('brown') then
PrintLn('Contains brown');
var idx := s.IndexOf('fox'); // 17
PrintLn(idx.ToString);
```
**Output:**
```text
Found it!
Starts with The
Contains brown
17
```
### Manipulation
Methods for modifying or extracting parts of a string return a *new* string. For the complete list of methods, see **[String Manipulation](/ref/strings_manipulation)**.
```pascal
var s := ' DWScript is awesome ';
PrintLn(s.Trim); // "DWScript is awesome"
PrintLn(s.ToUpper); // " DWSCRIPT IS AWESOME "
PrintLn(StrReplace(s, 'awesome', 'powerful'));
// Slicing and Substrings
PrintLn(s.Copy(3, 8)); // "DWScript"
```
**Output:**
```text
DWScript is awesome
DWSCRIPT IS AWESOME
DWScript is powerful
DWScript
```
### Splitting & Joining
Working with lists of strings is seamless.
```pascal
var csv := 'apple,banana,cherry';
var fruits := csv.Split(',');
PrintLn(fruits.Join('; ')); // "apple; banana; cherry"
```
**Output:**
```text
apple; banana; cherry
```
### Formatting
For complex string building, use the `Format` function (similar to printf).
```pascal
var s := Format(
'Name: %s, Age: %d',
[ 'Alice', 30 ]
);
PrintLn(s);
```
**Output:**
```text
Name: Alice, Age: 30
```
## Conversions
Convert strings to numbers using method helpers or standard functions.
```pascal
var i := '123'.ToInteger;
var f := '3.14'.ToFloat;
PrintLn(i.ToString);
PrintLn(f.ToString);
// Safe parsing (returns default if failed)
var val := StrToIntDef('abc', 0);
PrintLn(val.ToString);
```
**Output:**
```text
123
3.14
0
```
:::info
### Related Reference
* **[String Manipulation](/ref/strings_manipulation)** - Core functions, substrings, and splitting.
* **[String Transformation](/ref/strings_transform)** - Case conversion, trimming, and type conversion.
* **[String Formatting](/ref/strings_format)** - Format function and templating.
* **[String Comparisons](/ref/strings_comparison)** - Equality and wildcard matching.
* **[Encodings Reference](/ref/encoding)** - Base64, Hex, and URL encoding.
:::
---
Source: lang/basics/structure.md
# Program Structure
Understanding how to organize your code into units and use them is fundamental to building scalable applications in DWScript.
## Scripts vs Units
DWScript code can be organized as standalone scripts or reusable units.
* **Scripts:** A linear sequence of instructions, typically used for main entry points or simple tasks.
* **Units:** Collections of types, variables, and functions that can be imported by other scripts or units.
## Unit Syntax
A unit consists of an `interface` section (public API) and an `implementation` section (internal logic).
```pascal
unit MyMath;
interface
// Public declarations
function Add(a, b : Integer) : Integer;
implementation
// Internal implementation
function Add(a, b : Integer) : Integer;
begin
Result := a + b;
end;
end.
```
## Unit Lifecycle
Units can optionally include `initialization` and `finalization` blocks:
* **initialization:** Runs once when the unit is first loaded, before the main script starts. Used for setting up global state or caches.
* **finalization:** Runs when the script execution ends. Used for cleaning up resources.
## Uses Clause
To use code from another unit, you must include it in the `uses` clause.
In **Program Mode** (starting with the `program` keyword), you typically have a single `uses` clause at the top. However, in **Script Mode** (the default for `.dws` files), you can have multiple `uses` clauses interspersed throughout your code.
```pascal
// Import the 'System.Crypto' unit
uses System.Crypto;
var hash := HashSHA256.HashData('DWScript');
PrintLn(hash);
```
**Output:**
```text
f7eb27e6c33bb7ac799b8bc5bef374362297160952d322c9a5a1115d293283d5
```
### Multiple Uses Clauses
In Script Mode, you can include units only when they are needed, interspersing them with your logic.
```pascal
// Initial logic using built-in features
var name := 'DWScript';
// First inclusion when crypto is needed
uses System.Crypto;
var token := HashSHA256.HashData(name);
// ... more logic ...
// Second inclusion when web response control is needed
uses System.WebServer;
WebResponse.Header['X-Token'] := token;
PrintLn('Process complete.');
```
**Output:**
```text
Process complete.
```
## Unit Namespaces
While DWScript supports dotted unit names for organization, it also features a unique `unit namespace` construct. This allows you to aggregate multiple existing units into a single identifier, making it easier to manage large libraries.
### Creating a Namespace
A namespace unit uses the `unit namespace` keywords and a `uses` clause to list the units it aggregates.
```pascal
// NO_COMPILE
unit namespace MyLibrary;
uses
MyLibrary.Core,
MyLibrary.Utils;
// OUTPUT NONE
```
### Using a Namespace
When a script `uses` the namespace unit, all public symbols from the aggregated units become available directly.
```pascal
// NO_COMPILE
uses MyLibrary;
// Symbols from Core and Utils are now available
// without needing to import them individually.
var result := Process(FetchData);
// OUTPUT NONE
```
---
Source: lang/basics/ternary.md
---
title: Ternary Operator
id: lang/basics/ternary
---
# Ternary Operator
DWScript supports an expression-based `if` syntax, often called the **ternary operator** in other languages. It allows you to select a value based on a condition within a single expression.
## Basic Syntax
The full syntax is `if condition then expression1 else expression2`.
```pascal
var count := 10;
var status := if count > 0 then 'Active' else 'Empty';
PrintLn(status);
```
**Output:**
```text
Active
```
Unlike the `if` statement, the ternary `if` is an expression that returns a value. Both branches must return compatible types.
## Omitted Else (Default Values)
If the `else` clause is omitted, the expression evaluates to the **default value** for the result type if the condition is false.
| Type | Default Value |
| :--- | :--- |
| **Integer / Float** | `0` |
| **Boolean** | `False` |
| **String** | `''` (Empty string) |
| **Object / Class** | `nil` |
| **Variant** | `Unassigned` |
```pascal
var score := -5;
// If score is not positive, returns 0 (default for Integer)
var positiveScore := if score > 0 then score;
PrintLn(positiveScore);
```
**Output:**
```text
0
```
## Type Inference & Classes
The ternary operator can infer types and even works with class types for polymorphic results.
```pascal
type TBase = class end;
type TChild = class(TBase) end;
var cond := True;
// Result is TBase, even though one branch is TChild
var obj := if cond then TBase.Create else TChild.Create;
PrintLn(obj.ClassName);
```
**Output:**
```text
TBase
```
## Chaining & Nesting
Ternary expressions can be nested to handle multiple conditions.
```pascal
var val := 2;
var description := if val = 1 then 'One'
else if val = 2 then 'Two'
else 'Many';
PrintLn(description);
```
**Output:**
```text
Two
```
## Practical Examples
### In Function Parameters
Pass conditional values directly to functions without temporary variables.
```pascal
procedure Log(msg: String);
begin
PrintLn('LOG: ' + msg);
end;
var priority := True;
Log(if priority then 'URGENT' else 'Normal');
```
**Output:**
```text
LOG: URGENT
```
### With Collections
The ternary operator can return arrays or sets. Note that for arrays, you often need an explicit type to assist inference.
```pascal
var selection: array of String := if True then ['A', 'B'] else ['C'];
PrintLn(selection.Length);
```
**Output:**
```text
2
```
---
Source: lang/basics/types.md
---
title: Data Types
id: lang/basics/types
---
# Data Types
DWScript is a strongly-typed language, meaning every variable and expression has a specific type known at compile time. This ensures better performance, safety, and tooling support.
## Core Primitives
These are the fundamental building blocks of most scripts.
* **[Integers](/lang/basics/ints)**: 64-bit signed whole numbers.
* **[Floats](/lang/basics/floats)**: 64-bit double-precision floating-point numbers.
* **[Booleans](/lang/basics/bools)**: Logical `True` or `False` values.
* **[Strings](/lang/basics/strings)**: Unicode (UTF-16) sequences of characters.
## Structural Types
Types used to organize and group data.
* **[Arrays](/lang/basics/arrays)**: Ordered collections of a single type (Static or Dynamic).
* **[Associative Arrays](/lang/basics/associative_arrays)**: Key-value maps (dictionaries).
* **[Records](/lang/basics/records)**: Lightweight value-type structures.
* **[Classes](/lang/oop/oop)**: Full-featured object-oriented reference types.
* **[Enums & Sets](/lang/basics/enums_sets)**: Named constants and bitfield collections.
## Specialized Types
DWScript includes specialized types for specific domains or dynamic behavior.
* **[Variants](/lang/basics/variants)**: Highly dynamic types that can hold any value.
* **[Big Integers](/lang/basics/bigints)**: Arbitrary-precision whole numbers.
* **[Binary Data](/lang/basics/binary)**: Raw byte buffers for I/O and crypto.
* **[File Handles](/lang/basics/files)**: Handles for low-level file system operations.
## Type Casting & Conversion
DWScript provides several ways to move data between types:
1. **Implicit Conversion**: For safe operations, like assigning an `Integer` to a `Float`.
2. **Explicit Casting**: Using the `Type(Value)` syntax for potentially unsafe conversions.
3. **Method Helpers**: Using `.ToString`, `.ToInt`, etc., for semantic conversions.
```pascal
var i: Integer := 10;
var f: Float := i; // Implicit
var s: String := i.ToString; // Helper method
// OUTPUT NONE
```
## Identifiers
DWScript is fully Unicode-aware. You can use Unicode characters in variable names, function names, and other identifiers.
```pascal
var 測試 := 'Unicode variable';
PrintLn(測試);
```
**Output:**
```text
Unicode variable
```
## Indexing Strategy
DWScript follows a hybrid indexing strategy to balance modern conventions with Pascal compatibility.
:::warning
**Indexing Gotcha**
* **Arrays** are **0-indexed** (start at 0), matching C/C++/C#/Java/JavaScript.
* **Strings** are **1-based** (start at 1), matching standard Pascal/Delphi.
Always be mindful of this distinction when switching between string manipulation and array processing.
:::
---
Source: lang/basics/variables.md
---
title: Variables
id: lang/basics/variables
---
# Variables
Variables are storage locations with a specific type. DWScript supports both modern inline declarations and traditional Pascal-style blocks.
## Explicit Declaration
You can specify the type explicitly using the `name : Type` syntax.
```pascal
var x : Integer;
var name : String;
x := 10;
name := 'Alice';
// OUTPUT NONE
```
### Typed Initialization
You can combine declaration and assignment in a single statement.
```pascal
var f : Float := 10;
var status : String := 'Initializing';
PrintLn(f);
```
**Output:**
```text
10
```
## Type Inference
Modern DWScript can infer the type of a variable from its initial assignment. This is the preferred style for local variables as it reduces redundancy.
```pascal
var count := 42; // Inferred as Integer
var price := 19.99; // Inferred as Float
var message := 'Hello'; // Inferred as String
var active := True; // Inferred as Boolean
// OUTPUT NONE
```
## Declaration Styles
### Modern (Inline)
In script mode, variables can be declared anywhere before their first use.
```pascal
PrintLn('Step 1');
var x := 100;
PrintLn(x);
```
**Output:**
```text
Step 1
100
```
### Classic Pascal Style
DWScript also supports the classic Pascal structure where variables are declared in a `var` block before the `begin` keyword of a procedure or function.
```pascal
procedure ProcessData;
var
i : Integer;
s : String;
begin
i := 5;
s := 'Value: ';
PrintLn(s + IntToStr(i));
end;
ProcessData;
```
**Output:**
```text
Value: 5
```
## Reserved Names & Escaping
If you need to use a reserved Pascal keyword (like `type`, `begin`, `end`, `repeat`, etc.) as an identifier for a variable, field, or function, you can prefix it with an ampersand `&`.
The compiler will treat the identifier as if the ampersand were not there, allowing you to interface with external systems (like JSON APIs) that use these names.
```pascal
var &type := 'System';
var &repeat := True;
PrintLn(&type);
```
**Output:**
```text
System
```
## Scope & Lifetime
Variable visibility and lifetime are determined by where they are declared:
* **Global Scope:** Variables declared at the top level of a script are visible everywhere and persist for the duration of the script execution.
* **Local Scope:** Variables declared inside a `procedure`, `function`, or `block` (like a `for` loop) are only visible within that block. Their lifetime is tied to the procedure they are in.
* **Shadowing:** A local variable can have the same name as a global one; in this case, the local variable "shadows" the global one within its scope.
```pascal
var x := 'Global';
procedure Test;
var x := 'Local'; // Shadows global x
begin
PrintLn(x);
end;
Test;
PrintLn(x);
```
**Output:**
```text
Local
Global
```
:::info
Variables in DWScript are **guaranteed** to be initialized to their default values (0 for numbers, '' for strings, nil for objects/arrays, False for booleans). You do not need to manually initialize them to zero/nil.
:::
## See Also
* **[Data Types](/lang/basics/types)** - Overview of the type system.
* **[Constants](/lang/basics/constants)** - Values that do not change.
* **[Operators](/lang/basics/operators)** - Using variables in expressions.
* **[State Management](/lang/basics/state)** - Persistent variables in web environments.
---
Source: lang/basics/variants.md
---
title: Variants
id: lang/basics/variants
---
# Variants
Variants are dynamic types that can hold values of any other type (Integer, Float, String, Boolean, Objects, etc.). They are useful when the exact type of data is unknown until runtime, such as when processing dynamic API responses or building highly flexible components.
## The Variant Type
A `Variant` variable adapts its behavior based on the value it currently holds.
```pascal
var v: Variant;
v := 10; // Holds an Integer
v := 'Hello'; // Now holds a String
PrintLn(v);
v := 3.14; // Now holds a Float
PrintLn(v);
```
**Output:**
```text
Hello
3.14
```
### Type Switching
You can check the current type of a variant using the `VarType` function or helper functions like `VarIsNumeric`.
```pascal
var v: Variant := 10;
// Check if numeric
if VarIsNumeric(v) then
PrintLn('It is numeric');
```
**Output:**
```text
It is numeric
```
:::warning
**Performance & Safety**: Variants are significantly slower than strongly-typed variables and bypass many compile-time checks. Use them sparingly, primarily for dynamic data or interoperability.
:::
## JSONVariant
`JSONVariant` is a specialized variant optimized for working with JSON data. It supports **late-binding**, allowing you to access properties using dot notation even if they aren't defined at compile time.
For detailed usage, see **[JSON Support](/lang/stdlib/std_json)**.
### Handling Missing Properties
When working with JSON, you can check for field existence using `.Defined()`, standard truthy/falsy checks, or `VarIsClear`.
:::info
**Parenthesis Rule:** When calling built-in methods on a `JSONVariant` (like `.Defined()` or `.Length()`), you **must** use parentheses to distinguish them from potential JSON fields with the same name.
:::
```pascal
var data := JSON.Parse('{"name": "Alice"}');
// Check if defined
if not data.age.Defined() then
PrintLn('Age is missing');
// Truthy check (undefined behaves like False/Null)
if not data.age then
PrintLn('Age is not set');
```
**Output:**
```text
Age is missing
Age is not set
```
## Comparisons
Variants handle mixed-type comparisons by attempting to convert values to a common type.
```pascal
var v1: Variant := 10;
var v2: Variant := '10';
if v1 = v2 then
PrintLn('They are equal'); // True, string converted to integer for comparison
```
**Output:**
```text
They are equal
```
---
Source: lang/control_flow/control_flow.md
---
title: Conditionals
id: lang/control_flow/control_flow
---
# Conditionals
Control the order of execution in your scripts using conditionals and loops. DWScript combines traditional Pascal readability with enhancements like `for..in` and loop `step`.
## If Statements
The `if` statement executes a block if a condition is true. The `else` part is optional.
```pascal
var x := 10;
if x > 5 then
PrintLn('Greater than 5')
else
PrintLn('Less or equal');
// Nested
if x > 0 then begin
if x < 100 then
PrintLn('In range');
end;
```
**Output:**
```text
Greater than 5
In range
```
## Case Statements
`case` is used for multi-way branching. In DWScript, it supports **Integers**, **Characters**, **Enumerations**, **Strings**, **Booleans**, **Variants**, and **Floats**.
```pascal
var val := 7;
case val of
0: PrintLn('Zero'); // Single value
1..5, 7: PrintLn('Range and Seven'); // Mixed range and value
10, 20, 30: PrintLn('Specific list'); // List of values
else
PrintLn('Other'); // Default branch
end;
var fruit := 'Grape';
case fruit of
'Apple', 'Grape', 'Orange': PrintLn('First group');
'Peach', 'Plum', 'Watermelon': PrintLn('Second group');
else
PrintLn('Unknown fruit');
end;
// Case with Floats and Ranges
var f := 2.5;
case f of
0..0.99: PrintLn('Small');
1.0..2.99: PrintLn('Medium'); // Matches
else
PrintLn('Large');
end;
```
**Output:**
```text
Range and Seven
First group
Medium
```
:::info
#### Float Boundary Precision
Floating point ranges in `case` statements use inclusive boundaries (using standard `<=` and `>=` logic).
However, because floating-point math can have precision issues (e.g., `1.0` might be stored as `0.99999999999998`), using `case` for exact boundaries can be risky. For mission-critical boundary logic, using `if` with an explicit epsilon or strict inequalities is recommended.
:::
## With Statements
The `with` statement in DWScript differs from traditional Pascal. It is used as a scoping construct to create local aliases for expressions, improving readability and reducing repetition.
```pascal
// Use 'with' to simplify local access to complex expressions
with fullName := WebRequest.QueryField['first_name'] + ' ' + WebRequest.QueryField['last_name'] do begin
if fullName.Trim <> '' then
PrintLn('Welcome, ' + fullName);
end;
// Declare multiple locals to use within a block
with a := 10, b := 20, c := 30 do begin
PrintLn('Sum: ' + (a + b + c).ToString);
end;
```
**Output:**
```text
Sum: 60
```
:::warning
**Important Difference from Delphi:**
In traditional Delphi, the `with` statement implicitly introduces an object's members into the current scope (e.g., `with myPoint do X := 10;`).
In DWScript, the `with` statement does **not** introduce members into the current scope. Instead, it requires an **explicit alias** (e.g., `with p := myPoint do p.X := 10;`).
This design decision was made to avoid the **"scope pollution"** and ambiguity found in traditional Pascal, where it can be unclear whether a variable name refers to a local variable or a member of the object in the `with` block.
:::
:::info
The variables declared in a `with` statement are only visible within its `do` block.
:::
---
Source: lang/control_flow/exceptions.md
---
title: Exceptions
id: lang/control_flow/exceptions
---
# Exception Handling
Exceptions provide a structured way to handle runtime errors and unexpected conditions.
## Try...Except
Use `try...except` to catch and handle exceptions. This allows your program to recover from errors gracefully rather than crashing.
```pascal
var data : array of Integer := [ 1, 2, 3 ];
try
PrintLn(data[10]);
except
on E: Exception do
PrintLn('Error: ' + E.Message);
end;
```
**Output:**
```text
Error: Upper bound exceeded! Index 10*
```
## Try...Finally
Use `try...finally` to ensure code runs regardless of whether an exception occurs. This is essential for resource cleanup, such as closing files or freeing memory.
```pascal
PrintLn('Starting');
try
PrintLn('Working...');
finally
PrintLn('Cleanup');
end;
```
**Output:**
```text
Starting
Working...
Cleanup
```
## Combined Try...Except...Finally
You can nest try blocks or combine them to handle errors and ensure cleanup. A common pattern is protecting a resource that must be closed even if an operation fails.
```pascal
var connectionOpen := True;
try
try
// Perform work that might fail
raise new Exception('Connection lost');
except
on E: Exception do
PrintLn('Caught: ' + E.Message);
end;
finally
connectionOpen := False;
PrintLn('Connection closed');
end;
```
**Output:**
```text
Caught: Connection lost
Connection closed
```
## Raising Exceptions
You can raise exceptions using the `raise` keyword.
```pascal
procedure CheckAge(age: Integer);
begin
if age < 0 then
raise new Exception('Age cannot be negative');
end;
try
CheckAge(-5);
except
on E: Exception do
PrintLn(E.Message);
end;
```
**Output:**
```text
Age cannot be negative
```
## The "on...do" Syntax
You can handle specific exception types.
```pascal
type EMyError = class(Exception);
try
raise new EMyError('Custom error');
except
on E: EMyError do
PrintLn('Specific catch: ' + E.Message);
on E: Exception do
PrintLn('General catch: ' + E.Message);
end;
```
**Output:**
```text
Specific catch: Custom error
```
### Catch-All "else"
You can use an `else` clause to catch any exception that wasn't matched by previous `on` blocks.
```pascal
try
raise new Exception('Something went wrong');
except
on E: EAssertionFailed do
PrintLn('Assertion failed');
else
PrintLn('Caught unknown error: ' + ExceptObject.Message);
end;
```
**Output:**
```text
Caught unknown error: Something went wrong
```
## Exception Object
Within an `except` block, the `ExceptObject` function returns the exception instance being handled.
```pascal
try
raise new Exception('Fail');
except
PrintLn(ExceptObject.Message);
end;
```
**Output:**
```text
Fail
```
## Re-raising Exceptions
You can re-raise the current exception using `raise` with no arguments.
```pascal
try
try
raise new Exception('Critical failure');
except
PrintLn('Logging error...');
raise; // Re-throw to outer handler
end;
except
on E: Exception do
PrintLn('Outer catch: ' + E.Message);
end;
```
**Output:**
```text
Logging error...
Outer catch: Critical failure
```
:::info
### Exception Best Practices
* **Catch specific exceptions** whenever possible rather than using a general `on E: Exception`.
* **Use finally blocks** to ensure resources like database connections or temporary files are always closed.
* **Don't suppress exceptions** with an empty `except` block unless you have a very specific reason to do so.
:::
---
Source: lang/control_flow/iteration.md
---
title: For..in Iteration
id: lang/control_flow/iteration
---
# For..in Iteration
The `for..in` loop is the modern way to iterate over collections in DWScript. It is more readable than standard range loops and automatically handles the underlying iteration logic.
## Arrays
Iterating over a dynamic or static array returns each element in order.
```pascal
var fruits := ['Apple', 'Banana', 'Cherry'];
for var fruit in fruits do
PrintLn(fruit);
```
**Output:**
```text
Apple
Banana
Cherry
```
## Sets
When iterating over a set, elements are returned in their **ordinal order** (the order defined in the enumeration), regardless of the order they were added to the set.
```pascal
type TDays = (Mon, Tue, Wed, Thu, Fri, Sat, Sun);
var weekend: set of TDays := [Sun, Sat];
for var day in weekend do
PrintLn(day.Name);
```
**Output:**
```text
Sat
Sun
```
## Strings
Iterating over a string returns each **full Unicode codepoint**. Note that the loop variable `c` is of type **String** (containing the full character, which may be a surrogate pair), not `Char`.
```pascal
var msg := 'Ready 🚀';
for var c in msg do
Print(c + '|');
```
**Output:**
```text
R|e|a|d|y| |🚀|
```
This correctly handles multi-byte characters like emojis, treating them as a single logical unit.
## Ranges
You can iterate over numeric ranges directly using the bracketed range syntax.
```pascal
for var i in [1..5] do
Print(i.ToString + ' ');
```
**Output:**
```text
1 2 3 4 5
```
## Type Enumerations
You can iterate over an entire enumeration type to visit all possible values.
```pascal
type TColor = (Red, Green, Blue);
for var c in TColor do
PrintLn(c.Name);
```
**Output:**
```text
Red
Green
Blue
```
## Associative Arrays (Dictionaries)
Direct iteration over an associative array is **not supported**. This is an intentional design choice to avoid ambiguity; iterating directly would yield key-value tuples, whereas most users only need the keys or the values. Forcing the use of `.Keys` makes the code's intent explicit.
```pascal
var data: array [String] of Integer;
data['A'] := 10;
data['B'] := 20;
// Explicitly iterate over keys
var keys := data.Keys;
keys.Sort;
for var k in keys do
PrintLn(k + ': ' + data[k].ToString);
```
**Output:**
```text
A: 10
B: 20
```
:::info
For standard numeric range loops (e.g. `1 to 10`), see **[Basic Loops](/lang/control_flow/loops)**.
:::
---
Source: lang/control_flow/jumps.md
---
title: Jump Statements
id: lang/control_flow/jumps
---
# Jump Statements
DWScript provides several reserved keywords to alter the flow of execution by jumping out of loops or subroutines. Unlike traditional Pascal where some of these might be system procedures, in DWScript they are first-class keywords.
## exit
The `exit` keyword immediately terminates the execution of the current subroutine (procedure or function).
### Basic Usage
In a `procedure`, `exit` simply returns control to the caller.
```pascal
procedure Process(value : Integer);
begin
if value < 0 then
exit; // Stop processing
PrintLn(value);
end;
// OUTPUT NONE
```
### Returning Values
In a `function`, `exit` can be used to return a value immediately. DWScript supports several syntaxes for this, highlighting its status as a keyword:
1. **Standard Pascal**: Assign to `Result` and call `exit`.
2. **Functional style**: Pass the return value directly to `exit`.
3. **Keyword style**: Use `exit` followed by the value (no parentheses).
```pascal
function Calculate(x : Integer) : Integer;
begin
// Method 1: Standard
if x = 0 then begin
Result := 0;
exit;
end;
// Method 2: Parentheses (Delphi style)
if x = 1 then
exit(10);
// Method 3: DWScript Keyword style
if x = 2 then
exit 20;
Result := x * 10;
end;
PrintLn(Calculate(0));
PrintLn(Calculate(1));
PrintLn(Calculate(2));
PrintLn(Calculate(3));
```
**Output:**
```text
0
10
20
30
```
### Global Scope
Using `exit` in the global scope (outside of any subroutine) immediately terminates the execution of the entire script.
```pascal
var stopEarly := True;
PrintLn('Starting script...');
if stopEarly then
exit;
PrintLn('This might not be reached.');
```
**Output:**
```text
Starting script...
```
## break
The `break` keyword immediately terminates the innermost loop (`for`, `while`, or `repeat`) that contains it. Execution resumes at the statement following the loop.
```pascal
var found := False;
for var i := 1 to 10 do begin
if i = 5 then begin
found := True;
break; // Stop the loop
end;
PrintLn(i);
end;
```
**Output:**
```text
1
2
3
4
```
## continue
The `continue` keyword skips the remainder of the current iteration of the innermost loop and proceeds to the next iteration.
* In a `for` loop, the counter is incremented/decremented.
* In a `while` or `repeat` loop, the condition is re-evaluated.
```pascal
for var i := 1 to 5 do begin
if i = 3 then
continue; // Skip 3
PrintLn(i);
end;
```
**Output:**
```text
1
2
4
5
```
---
Source: lang/control_flow/loops.md
---
title: Basic Loops
id: lang/control_flow/loops
---
# Loops
DWScript supports the standard Pascal loops: `for`, `while`, and `repeat`.
## For Loop
The `for` loop is ideal when the number of iterations is known in advance.
```pascal
// Standard counting up
for var i := 1 to 5 do
PrintLn('Count: ' + i.ToString);
// Counting down
for var j := 10 downto 1 do
PrintLn('Countdown: ' + j.ToString);
```
**Output:**
```text
Count: 1
Count: 2
Count: 3
Count: 4
Count: 5
Countdown: 10
Countdown: 9
Countdown: 8
Countdown: 7
Countdown: 6
Countdown: 5
Countdown: 4
Countdown: 3
Countdown: 2
Countdown: 1
```
### Step Clause
DWScript extends the standard `for` loop with an optional `step` clause. Note that the **step value must always be positive**, even when counting down with `downto`.
```pascal
// Count by 2
for var i := 0 to 10 step 2 do
Print(i.ToString + ' ');
PrintLn('');
// Count down by 2 (Step is still positive)
for var j := 10 downto 0 step 2 do
Print(j.ToString + ' ');
```
**Output:**
```text
0 2 4 6 8 10
10 8 6 4 2 0
```
## Variable Scope & Values
DWScript handles loop variables with predictable scoping and post-loop values.
### Inline Scope
When using `for var i := ...`, the variable `i` is scoped **only to the loop body**. It is not accessible after the loop.
### Post-Loop Values
When using a pre-declared variable, its value after the loop is **well-defined**. It will be the first value that failed the loop condition (unlike Delphi, where the value is considered undefined).
```pascal
var k: Integer;
for k := 1 to 3 do begin
// Loop body
end;
// k is now 4 (the value that broke the 'k <= 3' condition)
PrintLn('k after loop: ' + k.ToString);
```
**Output:**
```text
k after loop: 4
```
## While Loop
The `while` loop checks the condition *before* each iteration. It may run zero times if the condition is initially false.
```pascal
var n := 0;
while n < 3 do begin
PrintLn('Running: ' + n.ToString);
Inc(n);
end;
```
**Output:**
```text
Running: 0
Running: 1
Running: 2
```
## Repeat Loop
The `repeat` loop checks the condition *after* each iteration. It is guaranteed to run **at least once**.
```pascal
var i := 0;
repeat
PrintLn('Value: ' + i.ToString);
Inc(i);
until i > 2;
```
**Output:**
```text
Value: 0
Value: 1
Value: 2
```
## Loop Control
You can modify the execution flow within any loop using jump statements:
* **[break](/lang/control_flow/jumps)**: Terminate the loop immediately.
* **[continue](/lang/control_flow/jumps)**: Skip to the next iteration.
:::info
For iterating over collections like arrays, sets, or strings, use the more modern **[for..in iteration](/lang/control_flow/iteration)**.
:::
---
Source: lang/functions/contracts.md
---
title: Contracts (DbC)
id: lang/functions/contracts
---
# Design by Contract
DWScript supports Design by Contract (DbC) natively, allowing you to define preconditions and postconditions for your subroutines. This helps ensure code correctness and robust error handling.
## Preconditions (require)
Use `require` to specify conditions that must be true *before* the subroutine executes. If a condition fails, an `EAssertionFailed` exception is raised.
You can provide a custom error message using the `:` syntax.
```pascal
function Divide(a, b : Integer) : Float;
require
b <> 0 : 'Denominator must not be zero';
begin
Result := a / b;
end;
```
## Postconditions (ensure)
Use `ensure` to specify conditions that must be true *after* the subroutine executes. You can access the result using `Result` and the original value of parameters using the `old` keyword.
```pascal
procedure Deposit(var balance : Float; amount : Float);
require
amount > 0;
begin
balance += amount;
ensure
balance = old balance + amount;
end;
```
:::info
The `old` keyword captures the value of the expression at the moment the subroutine was entered.
:::
## Contract Failures
When a contract is violated, the script engine raises an `EAssertionFailed` exception. This allows you to catch and handle contract violations during development or in specific error-handling blocks.
```pascal
function Divide(a, b : Integer) : Float;
require
b <> 0 : 'Denominator must not be zero';
begin
Result := a / b;
end;
try
Divide(10, 0);
except
on E: EAssertionFailed do
PrintLn('Contract failed: ' + E.Message);
end;
```
**Output:**
```text
Contract failed: *Denominator must not be zero
```
## Contracts & Inheritance
Contracts are inherited and follows the "Liskov Substitution Principle":
* **require**: A subclass can only *weaken* preconditions (i.e., accept more inputs). In practice, this means `require` in an overridden method is ORed with the base class requirement.
* **ensure**: A subclass can only *strengthen* postconditions (i.e., guarantee more outcomes). In practice, this means `ensure` in an overridden method is ANDed with the base class guarantee.
## Production Builds
Contracts are powerful for development and debugging, but they do incur a small performance overhead. In high-performance production environments, contract checking can be disabled via compiler options, effectively turning them into no-ops.
:::info
#### Summary
Design by Contract is a philosophy of "Fail Fast". By explicitly stating assumptions, you make your code self-documenting and much easier to debug.
:::
---
Source: lang/functions/parameters.md
---
title: Parameters & Delegates
id: lang/functions/parameters
---
# Parameters & Delegates
Go beyond simple value passing with advanced parameter modifiers and procedural types.
## Parameter Modifiers
How a value is passed to a subroutine significantly affects both performance and behavior.
| Modifier | Description |
| :--- | :--- |
| (none) | **Value**: A copy of the value is passed. Changes inside the subroutine do not affect the original. |
| `var` | **Reference**: A pointer to the original variable is passed. Changes inside affect the original. |
| `const` | **Constant**: Passed by reference for efficiency, but the compiler prevents modification. |
| `lazy` | **Lazy**: The expression is only evaluated when accessed inside the body. This is useful for conditional logic or logging. |
## Lazy Evaluation
The `lazy` modifier is a unique feature of DWScript that defers the evaluation of an expression passed as a parameter until the moment it is actually accessed within the subroutine body.
**Key behavior:**
1. If the parameter is never accessed, the expression is never evaluated.
2. If the parameter is accessed multiple times, the expression is **re-evaluated each time**.
```pascal
procedure LogIf(condition : Boolean; lazy message : String);
begin
if condition then begin
// 'message' is evaluated here
PrintLn('LOG 1: ' + message);
// ...and re-evaluated here!
PrintLn('LOG 2: ' + message);
end;
end;
var counter := 0;
function GetStatus : String;
begin
Inc(counter);
Result := 'Status ' + IntToStr(counter);
end;
// GetStatus is NOT called here
LogIf(False, GetStatus);
// GetStatus IS called (twice!)
LogIf(True, GetStatus);
```
**Output:**
```text
LOG 1: Status 1
LOG 2: Status 2
```
## Optional Parameters
You can define default values for parameters. Optional parameters must always appear at the end of the parameter list.
```pascal
procedure Connect(host : String; port : Integer = 80);
begin
PrintLn('Connecting to ' + host + ' on port ' + IntToStr(port));
end;
Connect('localhost'); // Uses port 80
Connect('localhost', 443); // Uses port 443
```
**Output:**
```text
Connecting to localhost on port 80
Connecting to localhost on port 443
```
## Procedural Types (Delegates)
Procedural types allow you to treat subroutines as first-class citizens. You can assign them to variables, store them in arrays, or pass them as parameters to other subroutines.
### Standard Delegates
Points to a standalone global procedure or function.
```pascal
type
TNotifyEvent = procedure(msg: String);
// OUTPUT NONE
```
### Method Pointers
In DWScript, the `of object` syntax allows you to point to a method of a specific object instance. When the delegate is called, it executes the method in the context of that object.
```pascal
type
TClickEvent = procedure(x, y : Integer) of object;
type
TButton = class
OnClick : TClickEvent;
procedure Click(x, y : Integer);
begin
if Assigned(OnClick) then
OnClick(x, y);
end;
end;
type
TForm = class
procedure ButtonClicked(x, y : Integer);
begin
PrintLn('Button clicked at ' + IntToStr(x) + ', ' + IntToStr(y));
end;
end;
var f := new TForm;
var b := new TButton;
b.OnClick := f.ButtonClicked;
b.Click(10, 20);
```
**Output:**
```text
Button clicked at 10, 20
```
## Anonymous Methods
For one-off logic, you can use anonymous methods (lambdas) which can capture local variables from their surrounding scope. See the [Lambdas](/lang/advanced/lambdas) page for more details.
---
Source: lang/functions/subroutines.md
---
title: Methods & Functions
id: lang/functions/subroutines
---
# Methods & Functions
Break your code into reusable blocks using procedures and functions.
## Procedures vs Functions
* **Procedures**: Use the `procedure` keyword. They perform an action but do not return a value.
* **Functions**: Use the `function` keyword. They must return a value by assigning it to the implicit `Result` variable.
```pascal
procedure SayHello(name : String);
begin
PrintLn('Hello ' + name);
end;
function Add(a, b : Integer) : Integer;
begin
Result := a + b;
end;
SayHello('World');
var sum := Add(5, 10);
```
**Output:**
```text
Hello World
```
## Common Utility Functions
DWScript includes several built-in procedures for common tasks.
### Swap
The `Swap(var a, b)` procedure efficiently exchanges the values of two variables. Both variables must be of the same type.
```pascal
var x := 10;
var y := 20;
Swap(x, y);
PrintLn(Format('x=%d, y=%d', [x, y]));
```
**Output:**
```text
x=20, y=10
```
## Parameter Options
Parameters can have different semantics defining how they are passed and evaluated.
| Modifier | Description |
| :--- | :--- |
| (none) | **Value**: Passed by value (copied). |
| `var` | **Reference**: Passed by reference. Changes inside the subroutine affect the original variable. |
| `const` | **Constant**: Passed by reference for efficiency (if large), but cannot be modified. |
| `lazy` | **Lazy Evaluation**: The expression is passed without being evaluated. It is evaluated every time the parameter is accessed inside the subroutine. |
:::info
**Note:** The `out` modifier is currently **not supported** in DWScript. Use `var` instead.
:::
## Subroutine Modifiers
Modifiers can be added to the end of a declaration to change its behavior or performance characteristics.
| Modifier | Description |
| :--- | :--- |
| `overload` | Allows multiple subroutines with the same name but different parameter lists. |
| `inline` | Hints to the compiler to replace the call with the actual code for better performance. |
| `forward` | Declares a subroutine that will be implemented later in the same script. |
| `deprecated` | Marks the subroutine as obsolete, triggering a compiler warning if used. |
```pascal
procedure Process(x : Integer); overload;
begin
PrintLn('Integer: ' + x.ToString);
end;
procedure Process(s : String); overload;
begin
PrintLn('String: ' + s);
end;
Process(10);
Process('Hello');
```
**Output:**
```text
Integer: 10
String: Hello
```
## Advanced Subroutines
For more complex scenarios, see the dedicated page for **[Parameters & Delegates](/lang/functions/parameters)**, which covers:
* Parameter modifiers (`var`, `const`, `lazy`).
* Default and optional parameters.
* Procedural types and method pointers (Delegates).
---
Source: lang/oop/interfaces.md
---
title: Interfaces
id: lang/oop/interfaces
---
# Interfaces
Interfaces define a contract that classes can implement. They allow for polymorphism without inheritance.
## Defining an Interface
An interface is declared using the `interface` keyword. It can contain methods and properties, but no fields or implementation logic.
Interfaces can optionally be assigned a GUID (Globally Unique Identifier). In DWScript, the GUID is parsed but ignored by the compiler at runtime. It is primarily supported for source compatibility with Delphi and serves as a useful way to uniquely identify interfaces in documentation or when working with external tools.
```pascal
type
ISerializable = interface
['{7D8B1A20-1F2E-4B3C-A4D5-E6F708192A3B}']
function Serialize: String;
end;
```
### Properties in Interfaces
Interfaces can include properties. These are implemented by the class that supports the interface.
```pascal
type
IShape = interface
function GetArea: Float;
// Standard property mapping to a getter
property Area: Float read GetArea;
// Expression-based property in interface!
// The implementing class must satisfy the expression's requirements (e.g. have a GetArea function).
property DoubleArea: Float read (GetArea * 2);
end;
```
## Implementing an Interface
A class implements an interface by listing it in its declaration and providing implementations for all its methods.
In DWScript, classes implicitly inherit from `TObject` if no base class is specified. While you can explicitly inherit from `TObject` for clarity (as in Delphi), it is not strictly required.
```pascal
type
ISerializable = interface
function Serialize: String;
end;
type
TUser = class(ISerializable)
FName: String;
function Serialize: String;
begin
Result := '{"name": "' + FName + '"}';
end;
end;
var u := new TUser;
u.FName := 'Alice';
var s: ISerializable := u;
PrintLn(s.Serialize);
```
**Output:**
```text
{"name": "Alice"}
```
## The `implements` Operator
DWScript provides the `implements` binary operator to check if an object instance or a class type supports a specific interface at runtime. This is similar to the `is` operator used for classes.
```pascal
type
IMyInterface = interface
procedure DoWork;
end;
type
TWorker = class(IMyInterface)
procedure DoWork; begin end;
end;
var obj := new TWorker;
// Check instance
if obj implements IMyInterface then
PrintLn('Object implements interface');
// Check class type
if TWorker implements IMyInterface then
PrintLn('Class implements interface');
```
**Output:**
```text
Object implements interface
Class implements interface
```
:::info
DWScript uses ARC (Automatic Reference Counting) for all script objects, so interfaces do not require a separate lifetime management implementation like `TInterfacedObject` in Delphi.
:::
---
Source: lang/oop/oop.md
---
title: Classes & Objects
id: lang/oop/oop
---
# Classes & Objects
DWScript is fully object-oriented, supporting classes, inheritance, polymorphism, and encapsulation.
## Usage Examples
```pascal
type
TAnimal = class
FName : String;
constructor Create(const name : String);
begin
FName := name;
end;
procedure Speak; virtual;
begin
PrintLn(FName + ' makes a sound');
end;
end;
type
TDog = class(TAnimal)
procedure Speak; override;
begin
PrintLn(FName + ' barks');
end;
end;
var myPet := new TDog('Buddy');
myPet.Speak;
```
**Output:**
```text
Buddy barks
```
## Classes
A class is a blueprint for objects. In DWScript, classes support several modifiers to control inheritance and instantiation.
### Declaration Syntax
While you can use the standard `procedure` and `function` keywords, DWScript also supports the `method` keyword as a unified alternative for declaring any member subroutine within a class. It is fully interchangeable with `procedure` (if no return type) or `function` (if return type is specified).
```pascal
type
TMyClass = class
method DoSomething; begin end;
method Calculate: Integer; begin Result := 0; end;
class method StaticAction; begin end;
end;
// OUTPUT NONE
```
| Modifier | Description |
| :--- | :--- |
| `abstract` | The class cannot be instantiated directly. It must be inherited. |
| `sealed` | The class cannot be inherited from. |
| `static` | A class that only contains static (class) members. It cannot be instantiated. |
| `partial` | Allows splitting a class definition across multiple files or sections. |
### Static Classes
A static class is used to group related global functions and variables. It cannot be instantiated using `new` or `Create`.
```pascal
type
TUtils = static class
class procedure SayHello;
begin
PrintLn('Hello from Static Class');
end;
end;
TUtils.SayHello;
// var u := new TUtils; // Error: Cannot instantiate static class
```
**Output:**
```text
Hello from Static Class
```
### Partial Classes
The `partial` modifier allows a class to be defined in multiple parts. This is useful for large classes or when combining generated code with manual code.
```pascal
type
TBigClass = partial class
procedure MethodA; begin PrintLn('A'); end;
end;
type
TBigClass = partial class
procedure MethodB; begin PrintLn('B'); end;
end;
var obj := new TBigClass;
obj.MethodA;
obj.MethodB;
```
**Output:**
```text
A
B
```
## Inner Classes (Nested Types)
DWScript supports defining classes within other classes. These are known as inner or nested classes. They are useful for grouping helper classes that are only relevant to the outer class.
```pascal
type
TOuter = class
type
TInner = class
function GetMsg: String;
begin
Result := 'Hello from Inner';
end;
end;
procedure Run;
begin
var i := new TInner;
PrintLn(i.GetMsg);
end;
end;
var o := new TOuter;
o.Run;
```
**Output:**
```text
Hello from Inner
```
## Constructors & Destructors
Constructors initialize new object instances. Unlike many languages that use a fixed name like `constructor` or `__init__`, DWScript supports **named constructors**, following classic Pascal conventions.
### Instantiation Syntax
You can instantiate an object in two ways:
* **Classic Pascal:** `TMyClass.Create(args)`. This is the traditional way to call a specific named constructor.
* **Modern Syntax:** `new TMyClass(args)`. This uses the constructor marked with the `default` keyword.
### The "default" Keyword
A class can designate one constructor as the default. This allows the `new` keyword to be used without specifying the constructor name.
```pascal
type
TUser = class
constructor Create(name: String); default;
begin
inherited Create; // Call parent constructor
// ...
end;
end;
var u := new TUser('Alice'); // Calls TUser.Create
// OUTPUT NONE
```
### Overloaded Constructors
You can have multiple constructors with the same name but different parameters by using the `overload` modifier.
```pascal
type
TPoint = class
constructor Create; overload; begin end;
constructor Create(x, y: Integer); overload; begin end;
end;
// OUTPUT NONE
```
### Virtual Constructors & Metaclasses
Constructors can be `virtual`. When combined with **[Metaclasses](/lang/oop/oop_metaclasses)** (class references), this allows for powerful dynamic instantiation patterns, such as factories, where the specific class to be created is determined at runtime.
```pascal
type
TBase = class(TObject)
constructor Create; virtual; begin end;
end;
type
TDerived = class(TBase)
constructor Create; override; begin end;
end;
type
TBaseClass = class of TBase;
var cls: TBaseClass := TDerived;
var obj := cls.Create;
// OUTPUT NONE
```
This "factory" pattern is a core part of DWScript's metaprogramming capabilities, allowing the system to work with types as first-class values.
### Destructors
Destructors are named `Destroy` and are used to clean up resources.
Because DWScript uses ARC (Automatic Reference Counting), they are called automatically when the reference count reaches zero. For more details, see **[Memory Management](/lang/oop/oop_memory)**.
It is best practice to always mark your destructor with `override` and call `inherited` as the last statement to ensure the base class cleanup also runs.
## Class Operators
Classes can define custom behavior for standard operators using the `class operator` syntax. This allows objects to interact naturally with language operators like `+`, `-`, `in`, and implicit casts.
The syntax maps an operator to a specific method (either a static class method or a standard method).
### Customizing Arithmetic/Assignment
You can define operators like `+=` to handle custom addition logic.
```pascal
type
TLogger = class
Buffer: String;
procedure Append(s: String);
begin
Buffer := Buffer + s + #13#10;
end;
// Map += operator to Append method
class operator += String uses Append;
end;
var log := new TLogger;
log += 'Line 1';
log += 'Line 2';
PrintLn(log.Buffer);
```
**Output:**
```text
Line 1
Line 2
```
### Customizing 'in' Operator
The `in` operator is particularly powerful. You can define how your class responds when checking if a value "is in" the object.
```pascal
type
TRange = class
Min, Max: Integer;
constructor Create(aMin, aMax: Integer);
begin
Min := aMin; Max := aMax;
end;
function Contains(i: Integer): Boolean;
begin
Result := (i >= Min) and (i <= Max);
end;
// Map 'in' operator to Contains method
class operator in Integer uses Contains;
end;
var r := new TRange(10, 20);
if 15 in r then
PrintLn('15 is in range');
if 5 not in r then
PrintLn('5 is outside range');
```
**Output:**
```text
15 is in range
5 is outside range
```
## Advanced Features
Object Pascal in DWScript includes several advanced features for building robust applications:
* **[Properties](/lang/oop/oop_properties)**: Controlled data access.
* **[Metaclasses](/lang/oop/oop_metaclasses)**: Dynamic class references and instantiation.
* **[Memory Management](/lang/oop/oop_memory)**: Understanding ARC and Garbage Collection.
* **[Interfaces](/lang/oop/interfaces)**: Defining contracts for polymorphism.
---
Source: lang/oop/oop_memory.md
---
title: Memory Management
id: lang/oop/oop_memory
---
# Memory Management
DWScript simplifies development by managing the lifecycle of script objects automatically. It uses a hybrid approach to ensure both performance and safety.
## Automatic Reference Counting (ARC)
The primary mechanism for memory management is **ARC**. Every time an object is assigned to a variable or passed as a parameter, its reference count increases. When the variable goes out of scope, the count decreases.
When the count reaches zero, the object is immediately destroyed and its **destructor** is called. This provides deterministic cleanup for resources like file handles or database connections.
## Cycle Detection (Garbage Collection)
A common issue with pure ARC is "circular references" (e.g., Object A points to B, and B points back to A), which prevents reference counts from ever reaching zero.
DWScript includes a **Garbage Collector (GC)** that periodically scans for these isolated "islands" of objects. If an island is unreachable from the rest of the script, the GC will break the cycles and free the memory.
## Manual Control
While automation is the default, you can still exercise manual control when necessary.
* **Free:** You can call `obj.Free` to immediately trigger the destructor. Unlike some other environments, calling `Free` does not set the reference to `nil`. Instead, the object is marked as **destroyed**. Any subsequent attempt to access the object's fields or methods will trigger an `Object already destroyed` exception.
## Memory Safety
Because of these mechanisms, DWScript is largely immune to common memory errors found in languages with manual management:
* **Memory Leaks:** Automated by ARC and the Cycle Collector.
* **Use After Free:** Safely caught by the runtime. If you access an object after it has been freed, the script will throw an exception rather than causing a crash or memory corruption.
* **Double Free:** Calling `Free` on an already destroyed object is safely handled.
---
Source: lang/oop/oop_metaclasses.md
---
title: Metaclasses
id: lang/oop/oop_metaclasses
---
# Metaclasses
A metaclass (or class reference) is a type that refers to a class itself, rather than an instance of a class. This allows for powerful dynamic instantiation patterns and reflective programming.
## Syntax
Metaclasses are declared using the `class of` syntax.
```pascal
type
TBase = class
constructor Create; virtual; begin end;
end;
type
TDerived = class(TBase)
constructor Create; override; begin end;
end;
type
TBaseClass = class of TBase;
// OUTPUT NONE
```
## Dynamic Instantiation
The primary use of metaclasses is to create objects when the exact class is only known at runtime.
```pascal
type
TBase = class
constructor Create; virtual; begin end;
end;
type
TDerived = class(TBase)
constructor Create; override; begin end;
end;
type
TBaseClass = class of TBase;
var cls: TBaseClass := TDerived;
var obj := cls.Create;
PrintLn(obj.ClassName);
```
**Output:**
```text
TDerived
```
### Virtual Constructors
For polymorphic instantiation to work correctly, the constructor must be declared as `virtual` in the base class and `override` in the subclasses. If you call a non-virtual constructor on a metaclass, the base class constructor will be called regardless of the class the metaclass variable currently holds.
## Class Methods and Properties
Metaclasses can be used to call class methods and access static properties.
```pascal
type
TUtility = class
class procedure DoSomething;
begin
PrintLn('Doing something...');
end;
end;
type
TUtilityClass = class of TUtility;
var v: TUtilityClass := TUtility;
v.DoSomething;
```
**Output:**
```text
Doing something...
```
## Type Checking and Casting
The `is` and `as` operators are used to check and cast object instances.
```pascal
type
TBase = class
constructor Create; virtual; begin end;
end;
type
TDerived = class(TBase)
constructor Create; override; begin end;
end;
type
TBaseClass = class of TBase;
var obj: TObject := TDerived.Create;
if obj is TBase then
PrintLn('obj is a TBase');
var cls: TBaseClass := TDerived;
if obj is cls then
PrintLn('obj is an instance of ' + cls.ClassName);
var d := obj as TDerived;
PrintLn(d.ClassName);
```
**Output:**
```text
obj is a TBase
obj is an instance of TDerived
TDerived
```
## TClass and ClassType
Every object has a `ClassType` property that returns its metaclass. `TClass` is the base metaclass for all classes.
```pascal
type
TDerived = class
end;
var obj: TObject := TDerived.Create;
var anyClass: TClass := obj.ClassType;
PrintLn(anyClass.ClassName);
```
**Output:**
```text
TDerived
```
---
Source: lang/oop/oop_properties.md
---
title: Properties
id: lang/oop/oop_properties
---
# Properties
Properties are "virtual fields" that provide controlled access to object data. They can map directly to a field or use getter and setter methods to implement logic when a value is accessed or modified.
## Basic Properties
A property is declared with a `read` and/or `write` specifier.
* **Field-backed:** Directly reads from or writes to a private field.
* **Method-backed:** Calls a getter function or a setter procedure.
```pascal
type
TUser = class
private
FName: String;
FAge: Integer;
procedure SetAge(Value: Integer);
begin
if Value < 0 then
raise new Exception('Age cannot be negative');
FAge := Value;
end;
public
property Name: String read FName write FName;
property Age: Integer read FAge write SetAge;
end;
// OUTPUT NONE
```
### Access Control
You can create read-only or write-only properties by omitting one of the specifiers:
```pascal
type
TExample = class
private
FSecret: String;
public
property Secret: String read FSecret;
end;
// OUTPUT NONE
```
### Auto-Implemented Properties
If you omit the `read` and `write` clauses, DWScript will automatically generate a backing field for the property. This reduces boilerplate code for simple data containers.
```pascal
type
TUser = class
// Automatically creates a private field and getter/setter
property Name: String;
// You can mix auto-implemented properties with standard ones
property Age: Integer;
// Also works for class properties (static fields)
class property Count: Integer;
end;
var u := new TUser;
u.Name := 'Bob';
TUser.Count := 1;
// OUTPUT NONE
```
## Array Properties
Array properties allow you to access data using an index, mimicking array syntax (`obj[index]`).
```pascal
type
TStringList = class
private
FItems: array of String;
function GetItem(index: Integer): String;
begin
Result := FItems[index];
end;
procedure SetItem(index: Integer; value: String);
begin
FItems[index] := value;
end;
public
property Items[index: Integer]: String read GetItem write SetItem;
end;
// OUTPUT NONE
```
### Default Properties
If an array property is marked as `default`, you can omit the property name when accessing it.
```pascal
type
TMyContainer = class
public
function GetItem(index: Integer): String;
begin
Result := 'Item ' + IntToStr(index);
end;
property Items[index: Integer]: String read GetItem; default;
end;
var list := TMyContainer.Create;
PrintLn(list[0]);
```
**Output:**
```text
Item 0
```
## Indexed Properties
Indexed properties allow multiple properties to share the same getter or setter by passing a constant `index` value to the accessor.
```pascal
type
TSensor = class
private
function GetValue(index: Integer): Float;
begin
case index of
0: Result := 22.5;
1: Result := 45.0;
else
Result := 0.0;
end;
end;
public
property Temperature: Float index 0 read GetValue;
property Humidity: Float index 1 read GetValue;
end;
var s := TSensor.Create;
PrintLn(FloatToStr(s.Temperature));
```
**Output:**
```text
22.5
```
## Class Properties
Class properties allow you to access a property directly through the class type without an instance. They must use `class` methods or `class` fields as their accessors.
```pascal
type
TSystem = class
class function GetVersion: String;
begin
Result := '1.0.0';
end;
class property Version: String read GetVersion;
end;
PrintLn(TSystem.Version);
```
**Output:**
```text
1.0.0
```
## Expression-based Properties
DWScript allows you to define properties using expressions directly in the declaration, avoiding the need for boilerplate getter or setter functions. Expressions must be enclosed in parentheses.
```pascal
type
TCircle = class
Radius : Float;
// Read expression
property Diameter : Float read (Radius * 2);
// Read and write expressions
property Area : Float
read (PI * Sqr(Radius))
write (Radius := Sqrt(Value / PI));
end;
var c := new TCircle;
c.Radius := 5;
PrintLn(c.Diameter.ToString);
c.Area := 100;
PrintLn(c.Radius.ToString);
```
**Output:**
```text
10
5.64189583547756
```
## Property Promotion
Subclasses can redeclare a property from a parent class to change its visibility (e.g., from `protected` to `public`) or to provide a new implementation.
```pascal
type
TBase = class
private
FValue : Integer;
protected
property Value: Integer read FValue;
end;
type
TSub = class(TBase)
public
property Value;
end;
// OUTPUT NONE
```
---
Source: lang/stdlib/std_crypto.md
---
title: Crypto
id: lang/stdlib/std_crypto
---
# Cryptography
The `System.Crypto` library provides modern, high-performance cryptographic primitives. It covers hashing, symmetric/asymmetric encryption, and secure token generation.
## Hashing
Hashing converts data into a fixed-length string (digest). Use `HashSHA256` or `HashSHA3_256` for modern applications.
```pascal
uses System.Crypto;
var data := 'Hello World';
var digest := HashSHA256.HashData(data);
PrintLn('SHA256: ' + digest);
```
**Output:**
```text
SHA256: a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e
```
## Authenticated Encryption
Always use "authenticated" encryption (like `AES-CTR` with `HMAC`) to ensure data cannot be modified without detection. `EncryptionAESSHA256Full` simplifies this by handling all the complexity.
```pascal
uses System.Crypto;
var key := 'SuperSecretKey123';
var plain := 'Secret Data';
// Encrypt
var encrypted := EncryptionAESSHA256Full.EncryptData(plain, key);
// Decrypt
var decrypted := EncryptionAESSHA256Full.DecryptData(encrypted, key);
PrintLn('Decrypted: ' + decrypted);
```
**Output:**
```text
Decrypted: Secret Data
```
## Key Derivation (PBKDF2)
Never store passwords in plain text. Use `PBKDF2_HMAC_SHA256` to derive a secure hash with a unique salt and high iteration count.
```pascal
uses System.Crypto;
var salt := 'FixedSaltForDemo';
var pass := 'myPassword';
var hash := PBKDF2_HMAC_SHA256(pass, salt, 10000);
PrintLn('PBKDF2 Hash: ' + hash);
```
**Output:**
```text
PBKDF2 Hash: 1b4be021e88be4692f9475040079a9bb8ee54f2cddf845fdb6820259cc34a424
```
## Asymmetric Crypto (ECC & RSA)
DWScript supports **Elliptic Curve Cryptography** (secp256r1) and **RSA** for digital signatures and public-key encryption.
* Use `ECCsecp256r1` for high-performance signatures.
* Use `TRSAKey` for compatibility with traditional RSA systems.
:::info
### Related Reference
For a full list of supported algorithms (RIPEMD, CRC32, etc.) and low-level encryption details, see the reference documentation:
* **[Crypto API Reference](/ref/crypto)**
:::
---
Source: lang/stdlib/std_datetime.md
---
title: Date & Time
id: lang/stdlib/std_datetime
---
# Date & Time
DWScript represents points in time using the `TDateTime` type. Internally, this is a floating-point number where the integer part is the day and the fractional part is the time.
## Retrieving Time
Use `Now` for local time and `UTCDateTime` for UTC. For interoperability with other systems, `UnixTime` is also available.
```pascal
var dt := EncodeDate(2026, 1, 12) + EncodeTime(12, 0, 0, 0);
PrintLn('Date: ' + FormatDateTime('yyyy-mm-dd hh:nn:ss', dt));
var unix := DateTimeToUnixTime(dt);
PrintLn('Unix Time: ' + IntToStr(unix));
```
**Output:**
```text
Date: 2026-01-12 12:00:00
Unix Time: 1768219200
```
## Formatting Dates
The `FormatDateTime` function provides flexible formatting using standard patterns.
```pascal
var dt := EncodeDate(2026, 1, 12) + EncodeTime(12, 0, 0, 0);
// ISO 8601-like
PrintLn(FormatDateTime('yyyy-mm-dd hh:nn:ss', dt));
// Custom
PrintLn(FormatDateTime('dddd, mmmm d, yyyy', dt));
```
**Output:**
```text
2026-01-12 12:00:00
Monday, January 12, 2026
```
## Date Arithmetic
Since dates are floats, you can add or subtract days directly. Use `IncDay`, `IncMonth`, etc., for more complex adjustments.
```pascal
var today := EncodeDate(2026, 1, 12) + EncodeTime(12, 0, 0, 0);
var nextWeek := IncDay(today, 7);
PrintLn('Next Week: ' + FormatDateTime('yyyy-mm-dd hh:nn:ss', nextWeek));
```
**Output:**
```text
Next Week: 2026-01-19 12:00:00
```
:::info
### Related Reference
For a complete list of all date manipulation functions and encoding options, see the reference documentation:
* **[Date & Time API Reference](/ref/datetime)** - Complete list of functions.
:::
---
Source: lang/stdlib/std_encoding.md
---
title: Encodings
id: lang/stdlib/std_encoding
---
# Data Encodings
DWScript provides built-in classes for converting between different data representations like Base64, Hex, and URL encoding.
## Base64 & Hex
Standard classes provide static `Encode` and `Decode` methods for common formats.
```pascal
var raw := 'Hello World';
var b64 := Base64Encoder.Encode(raw);
PrintLn('Base64: ' + b64);
var hex := HexadecimalEncoder.Encode(raw);
PrintLn('Hex: ' + hex);
```
**Output:**
```text
Base64: SGVsbG8gV29ybGQ=
Hex: 48656c6c6f20576f726c64
```
## Web Encodings
Always use `URLEncodedEncoder` when building URLs with parameters.
```pascal
var param := 'hello world & friends';
var encoded := URLEncodedEncoder.Encode(param);
PrintLn('URL Encoded: ' + encoded);
```
**Output:**
```text
URL Encoded: hello%20world%20%26%20friends
```
:::info
### Related Reference
For a complete list of all supported encoding classes (including Base58, HTML, and XML), see the reference documentation:
* **[Encodings API Reference](/ref/encoding)**
:::
---
Source: lang/stdlib/std_files.md
---
title: Files & Dirs
id: lang/stdlib/std_files
---
# File System
DWScript provides simple functions for reading, writing, and managing files and directories.
## Reading & Writing
For most tasks, `FileRead` and `FileWrite` are the easiest way to handle file content as strings. If you need to process a file line by line, `FileReadLines` returns an array of strings.
```pascal
var content := 'Hello from DWScript';
FileWrite('test.txt', content);
var read := FileRead('test.txt');
PrintLn(read);
// Process line by line
var lines := FileReadLines('test.txt');
for var line in lines do
PrintLn('> ' + line);
DeleteFile('test.txt');
```
**Output:**
```text
Hello from DWScript
> Hello from DWScript
```
## Directory Management
Listing files is done using `EnumerateDir`, which returns an array of strings.
```pascal
var files := EnumerateDir('lang/basics', 'intro*.md', False);
if files.Length > 0 then
PrintLn('Found documentation');
```
**Output:**
```text
Found documentation
```
## Path Manipulation
Functions like `ExtractFileName` and `ChangeFileExt` help you manage file paths without manually parsing strings.
```pascal
var path := 'C:\Data\User.json';
PrintLn(ExtractFileName(path)); // User.json
PrintLn(ExtractFilePath(path)); // C:\Data\
PrintLn(ChangeFileExt(path, '.bak')); // C:\Data\User.bak
```
**Output:**
```text
User.json
C:\Data\
C:\Data\User.bak
```
:::info
### Related Reference
For a complete list of all I/O functions and directory utilities, see the reference documentation:
* **[Files API Reference](/ref/files)** - Complete list of functions.
* **[IniFiles](/lang/stdlib/std_inifiles)** - Working with `.ini` configuration files.
* **[Encoding](/lang/stdlib/std_encoding)** - Reading/Writing text with specific encodings (UTF-8, etc).
:::
---
Source: lang/stdlib/std_graphics.md
---
title: Graphics
id: lang/stdlib/std_graphics
---
# 2D Graphics
DWScript provides built-in support for low-level 2D buffer manipulation through the `TPixmap` class. No `uses` clause is required.
## Creating a Pixmap
A Pixmap is an array of ARGB (Alpha, Red, Green, Blue) values. You can create one with a specific width and height.
```pascal
var bmp := CreatePixmap(100, 100);
// Draw a pixel
bmp.SetPixel(10, 10, $FFFF0000); // Red pixel at 10,10
// OUTPUT NONE
```
## Colors
Colors are represented as 32-bit integers in `$AARRGGBB` format.
```pascal
var red := $FFFF0000;
var transparentGreen := $8000FF00;
// OUTPUT NONE
```
## Exporting Data
You can retrieve the raw buffer data as a hex string for transfer to a browser or saving to a file.
```pascal
var bmp := CreatePixmap(10, 10);
var data := bmp.ToHexString;
PrintLn('Hex data length: ' + IntToStr(data.Length));
```
**Output:**
```text
Hex data length: 800
```
:::info
### Related Reference
For details on coordinate systems and performance-optimized data access, see the reference documentation:
* **[Graphics API Reference](/ref/graphics)** - Complete list of methods.
:::
---
Source: lang/stdlib/std_inifiles.md
---
title: Files & Dirs
id: lang/stdlib/std_inifiles
---
# INI Configuration
The `TIniFile` class provides a simple way to read and write configuration settings using the standard Windows INI format.
## Basic Usage
```pascal
uses System.IniFiles;
var ini := new TIniFile('.data/config.ini');
try
// Writing
ini.WriteString('Server', 'Host', 'localhost');
ini.WriteString('Server', 'Port', '8080');
// Reading
var host := ini.ReadString('Server', 'Host', '127.0.0.1');
finally
ini.Free;
end;
// OUTPUT NONE
```
## In-Memory Parsing
You can also use `CreateInMemory` to parse INI-formatted strings directly without using the file system.
```pascal
uses System.IniFiles;
var raw := '[User]' + #13#10 + 'Name=Alice';
var ini := TIniFile.CreateInMemory(raw);
PrintLn(ini.ReadString('User', 'Name', 'Unknown'));
```
**Output:**
```text
Alice
```
:::info
### Related Reference
For a full list of methods for managing sections and keys, see the reference documentation:
* **[IniFiles API Reference](/ref/inifiles)**
:::
---
Source: lang/stdlib/std_json.md
---
title: JSON Support
id: lang/stdlib/std_json
---
# JSON Support
DWScript has built-in, high-performance support for JSON. You can easily parse JSON strings into dynamic objects or serialize native types like records and arrays into JSON.
## The JSONVariant Type
The core of JSON support in DWScript is the `JSONVariant` type. It is a specialized variant that allows for late-binding and dynamic property access.
```pascal
var raw := '{"id": 1, "name": "Alice", "tags": ["dev", "pascal"]}';
var data : JSONVariant := JSON.Parse(raw);
PrintLn(data.name); // Alice
PrintLn(data.tags[1]); // pascal
```
**Output:**
```text
Alice
pascal
```
## Parsing & Serialization
### Basic Parsing
Use `JSON.Parse` to convert a JSON string into a `JSONVariant`.
```pascal
var raw := '{"user": "Bob", "active": true}';
var data := JSON.Parse(raw);
if data.active then
PrintLn(data.user + ' is online');
```
**Output:**
```text
Bob is online
```
### Serializing to String
Use `JSON.Stringify` to convert any compatible type (records, arrays, classes, variants) back to a JSON string.
You can also create empty JSON objects and arrays programmatically:
```pascal
var data := JSON.NewObject;
data.name := 'Alice';
data.scores := JSON.NewArray;
data.scores.Add(10, 20, 30);
PrintLn(JSON.Stringify(data));
```
**Output:**
```text
{"name":"Alice","scores":[10,20,30]}
```
## Working with Records
Records are automatically serialized based on their **published** fields.
### Named Records
For named records, you must include a `published` section for fields to be serialized.
```pascal
type
TUser = record
published
Name: String;
Age: Integer;
end;
var u: TUser;
u.Name := 'Bob'; u.Age := 25;
PrintLn(JSON.Stringify(u));
```
**Output:**
```text
{"Age":25,"Name":"Bob"}
```
### Anonymous Records
Anonymous records have their fields in a `published` section by default, making them perfect for one-off JSON objects.
```pascal
var msg := record
from := 'Alice';
text := 'Hello!';
end;
PrintLn(JSON.Stringify(msg));
```
**Output:**
```text
{"from":"Alice","text":"Hello!"}
```
### Reserved Keywords (& Prefix)
Many JSON APIs use field names that are reserved keywords in Pascal, such as `type`, `object`, or `array`. You can use these as field names by prefixing them with an ampersand `&`. When serialized to JSON, the ampersand is automatically removed.
```pascal
var data := record
&type := 'Notification';
id := 101;
end;
PrintLn(JSON.Stringify(data));
```
**Output:**
```text
{"id":101,"type":"Notification"}
```
## Special Methods & Ambiguity
`JSONVariant` objects have built-in helper methods for manipulation. Because JSON keys can have any name, there is a potential conflict between a **method name** and a **field name**.
### The Parenthesis Rule
To resolve this, DWScript enforces a strict rule:
* **Field Access:** Use dot notation *without* parentheses (e.g., `v.Length`) to access a JSON field.
* **Method Call:** You **MUST** use parentheses `()` to call a built-in method (e.g., `v.Length()`).
```pascal
var v := JSON.Parse('{"Length": 500, "Defined": "yes"}');
// Field access
PrintLn(v.Length); // 500
PrintLn(v.Defined); // yes
// Method calls
PrintLn(v.Length()); // 2 (number of keys)
if v.Defined() then
PrintLn('Object is defined');
```
**Output:**
```text
500
yes
2
Object is defined
```
## JSONVariant Methods
### Array Manipulation
`JSONVariant` supports standard array operations when it holds a JSON array.
```pascal
var arr := JSON.Parse('[1, 2, 3]');
arr.Add(4);
arr.Push(5);
arr.Delete(0); // Remove first element
PrintLn(JSON.Stringify(arr));
PrintLn('Size: ' + arr.Length().ToString);
```
**Output:**
```text
[2,3,4,5]
Size: 4
```
### Object Manipulation
You can merge objects or delete keys dynamically.
```pascal
var obj := JSON.NewObject;
obj.a := 1;
// Merge with another object
obj.Extend(JSON.Parse('{"b": 2, "c": 3}'));
// Delete a key
obj.Delete('a');
PrintLn(JSON.Stringify(obj));
```
**Output:**
```text
{"b":2,"c":3}
```
### Type Inspection
Use `.TypeName()` to determine the underlying JSON type.
```pascal
var v := JSON.Parse('{"a": 1}');
PrintLn(v.TypeName()); // Object
PrintLn(v.a.TypeName()); // Number
if v.a.Defined() then
PrintLn('Field "a" exists');
```
**Output:**
```text
Object
Number
Field "a" exists
```
## Method Summary
For a complete list of all `JSONVariant` helper methods (such as `.Clone()`, `.Swap()`, `.AsInteger()`, etc.) and specialized high-performance parsers, please refer to the technical reference.
:::info
### Related Reference
* **[JSON API Reference](/ref/json)** - Complete list of methods, specialized parsers, and serialization rules.
:::
---
Source: lang/stdlib/std_math.md
---
title: Math
id: lang/stdlib/std_math
---
# Mathematics
DWScript provides a rich set of mathematical tools, from basic arithmetic to advanced 3D vectors.
## Basic Arithmetic
Most basic math functions are available globally. These include `Abs`, `Sqr`, `Sqrt`, `Round`, and `Trunc`.
```pascal
var x := -10.5;
PrintLn(Abs(x).ToString); // 10.5
PrintLn(Sqr(4).ToString); // 16
PrintLn(Sqrt(16).ToString); // 4
PrintLn(Round(x).ToString); // -10
```
**Output:**
```text
10.5
16
4
-10
```
## Trigonometry
Trigonometric functions like `Sin`, `Cos`, and `Tan` expect angles in **radians**. Use `DegToRad` and `RadToDeg` for conversions.
```pascal
var angle := 45.0;
var rad := DegToRad(angle);
PrintLn('Sin(45): ' + Sin(rad).ToString);
```
**Output:**
```text
Sin(45): 0.707106781186547
```
## Random Numbers
For general-purpose simulation and games, use the `Random` and `RandomInt` functions. For security-related tasks (tokens, keys), use the [Crypto](/lang/stdlib/std_crypto) library instead.
```pascal
// Random float between 0 and 1
var f := Random;
// Random integer between 0 and 99
var i := RandomInt(100);
// OUTPUT NONE
```
:::info
### Related Reference
For a complete list of all available math functions, constants, and advanced libraries, see the reference documentation:
* **[Math API Reference](/ref/math)** - Full list of arithmetic and trig functions.
* **[3D Math Reference](/ref/math3d)** - 3D Vectors.
:::
---
Source: lang/stdlib/std_math3d.md
---
title: 3D Math
id: lang/stdlib/std_math3d
---
# 3D Mathematics
DWScript includes high-performance types for 3D calculations, specifically optimized for graphics and physics applications.
## Vectors
The `TVector` type is a 4-component (X, Y, Z, W) record with overloaded operators, allowing you to perform vector math naturally.
```pascal
var v1 := Vector(1, 0, 0); // X-axis
var v2 := Vector(0, 1, 0); // Y-axis
// Vector Addition
var v3 := v1 + v2;
// Dot Product (Scalar result)
var dot := v1 * v2;
// Cross Product (Vector result)
var cross := v1 ^ v2;
// Normalization
var n := VectorNormalize(v1);
// Conversion to string
PrintLn(VectorToStr(v3));
```
**Output:**
```text
[1.00 1.00 0.00 0.00]
```
## Available Functions
The `TVector` type supports the following operations:
* **`Vector(x, y, z, w=0)`**: Creates a new vector.
* **`VectorToStr(v)`**: Returns a formatted string representation.
* **`VectorNormalize(v)`**: Returns a unit vector in the same direction.
* **`VectorDotProduct(v1, v2)`**: Alternative to `*` operator.
* **`VectorCrossProduct(v1, v2)`**: Alternative to `^` operator.
* **`VectorAdd(v1, v2)`**, **`VectorSub(v1, v2)`**: Alternatives to `+` and `-`.
:::info
### Related Reference
For a complete list of 3D math operations and the reference documentation:
* **[3D Math API Reference](/ref/math3d)**
:::
---
Source: lang/stdlib/std_registry.md
---
title: Registry
id: lang/stdlib/std_registry
---
# Windows Registry
The `Registry` object provides a simple API for interacting with the Windows Registry. It allows you to create, read, and delete keys and values.
## Root Keys (HKEY)
Registry operations use the `HKEY` enumeration to specify the root key:
* `HKEY.ClassesRoot`
* `HKEY.CurrentUser`
* `HKEY.LocalMachine`
* `HKEY.Users`
* `HKEY.PerformanceData`
* `HKEY.CurrentConfig`
* `HKEY.DynData`
## Basic Operations
### Creating and Deleting Keys
```pascal
// Create a new key
Registry.CreateKey(HKEY.CurrentUser, '\Software\MyApp\Settings');
// Delete a key
Registry.DeleteKey(HKEY.CurrentUser, '\Software\MyApp\Settings');
// OUTPUT NONE
```
### Reading and Writing Values
Values can be strings, integers, or other basic types.
```pascal
// Write a string value
Registry.WriteValue(HKEY.CurrentUser, '\Software\MyApp', 'Version', '1.0.0');
// Read a value with a default fallback
var ver := Registry.ReadValue(HKEY.CurrentUser, '\Software\MyApp', 'Version', '0.0.0');
PrintLn('Version: ' + ver);
// Write an integer
Registry.WriteValue(HKEY.CurrentUser, '\Software\MyApp', 'InstallCount', 1);
```
**Output:**
```text
Version: 1.0.0
```
### Enumerating Keys and Values
```pascal
// Get all subkey names
var subKeys := Registry.SubKeys(HKEY.CurrentUser, '\Software');
// Get all value names in a key
var valNames := Registry.ValueNames(HKEY.CurrentUser, '\Software\MyApp');
// OUTPUT NONE
```
:::warning
### Permissions
Modifying the registry typically requires appropriate user permissions. For example, writing to `HKEY.LocalMachine` usually requires administrative privileges.
:::
---
Source: lang/stdlib/std_systeminfo.md
# Environment & Runtime
The `System.Info` unit provides access to the host environment, hardware specifications, and system-level metrics. It is essential for writing environment-aware scripts and performance profiling.
## Application Environment
The `ApplicationInfo` object provides details about the running process.
```pascal
// NO_RUN
PrintLn('User: ' + ApplicationInfo.UserName);
PrintLn('Directory: ' + ApplicationInfo.CurrentDirectory);
// Check if running in a debugger
if ApplicationInfo.IsDebuggerPresent then
PrintLn('Debugging mode active');
```
## Hardware & OS
You can query the CPU model, core count, and operating system details.
```pascal
// NO_RUN
PrintLn('OS: ' + OSVersionInfo.Name + ' (' + OSVersionInfo.Version + ')');
PrintLn('CPU: ' + CPUInfo.Name);
PrintLn('Cores: ' + IntToStr(CPUInfo.Count));
// Monitor CPU usage
PrintLn('Global CPU Usage: ' + FloatToStr(CPUInfo.SystemUsage) + '%');
PrintLn('Process CPU Usage: ' + FloatToStr(CPUInfo.ProcessUsage) + '%');
```
## Memory Monitoring
To check memory usage, instantiate the `MemoryStatus` class.
```pascal
// NO_RUN
var mem := new MemoryStatus;
var freeMB := mem.Physical.Available div (1024 * 1024);
PrintLn('Available Physical Memory: ' + IntToStr(freeMB) + ' MiB');
var counters := ApplicationInfo.MemoryCounters();
PrintLn('Process Working Set: ' + IntToStr(counters.WorkingSetSize div 1024) + ' KiB');
```
## Performance Profiling
The `PerformanceCounter` class provides a high-resolution timer for measuring the execution time of code blocks.
```pascal
var pc := new PerformanceCounter;
// Simulate work
Sleep(150);
pc.Stop;
PrintLn(Format('Task completed in %.3f seconds', [pc.Elapsed]));
```
**Output:**
```text
Task completed in 0.151 seconds
```
:::info
### Detailed Reference
For a complete list of all classes, properties, and records available in the system info unit, see the API reference:
* **[System Info API Reference](/ref/systeminfo)**
:::
---
Source: lang/stdlib/std_timeseries.md
---
title: Time Series
id: lang/stdlib/std_timeseries
---
# Time Series
The `System.Data.TimeSeries` unit provides a high-performance engine for storing and querying time-indexed numerical data. It is optimized for scenarios like sensor logging, financial data, or performance monitoring.
## Core Concepts
* **Sequence:** A named stream of data points.
* **Sample:** A single data point consisting of a time (Integer) and a value (Float).
## Basic Usage
```pascal
// NO_COMPILE
uses System.Data.TimeSeries;
var ts := TimeSeries.Create;
// Add a sequence with a 3-second resolution
ts.AddSequence('cpu_load', 3);
// Store some samples
ts.StoreSample('cpu_load', 1, 10.5);
ts.StoreSample('cpu_load', 4, 15.0);
ts.StoreSample('cpu_load', 7, 12.2);
PrintLn('Stored samples: ' + ts.SequenceCount.ToString);
```
## Extracting Data
You can extract data from a sequence into standard arrays for processing or visualization.
```pascal
// NO_COMPILE
uses System.Data.TimeSeries;
var ts := TimeSeries.Create;
ts.AddSequence('temp', 1);
ts.StoreSample('temp', 10, 22.5);
ts.StoreSample('temp', 11, 23.0);
var times : array of Integer;
var values : array of Float;
// Extract samples from time 0 to 20
ts.ExtractSamples('temp', 0, 20, times, values, [tseoIgnoreNulls]);
PrintLn('Found ' + times.Length.ToString + ' samples');
```
:::info
### Extraction Options
The `ExtractSamples` method supports options like `tseoIgnoreNulls` to filter out gaps in the data where no samples were recorded.
:::
---
Source: lang/stdlib/std_web.md
---
title: Web
id: lang/stdlib/std_web
---
# Web Development
DWScript excels in web environments (CGI or via DWSWebServer), providing native objects to handle HTTP requests and responses via the `System.Net` unit.
## Request & Response (System.Net)
The `WebRequest` object contains client data, while `WebResponse` allows you to control headers and content types.
```pascal
uses System.Net;
var userAgent := WebRequest.UserAgent;
if userAgent <> '' then
PrintLn('Browser info found');
WebResponse.ContentType := 'text/plain';
```
**Output:**
```text
Browser info found
```
## Response Control
DWScript provides several shortcut methods to set the status code and content in a single call.
### Content Shortcuts
These methods automatically set the appropriate `ContentType` and the response body.
```pascal
// NO_RUN
uses System.Net;
// Send a JSON object
var data := JSON.Stringify(record
status := 'ok';
count := 42;
end);
WebResponse.SetContentJSON(data);
// Send plain text with a specific status
WebResponse.SetStatusPlainText(201, 'Resource Created');
// Send a raw JSON string with a status
WebResponse.SetStatusJSON(400, '{"error": "Invalid request"}');
```
### Redirects
Redirecting the client is handled by `SetStatusRedirect`.
```pascal
// NO_RUN
uses System.Net;
// Temporary redirect (302)
WebResponse.SetStatusRedirect(302, '/login.dws');
// Standard redirect (302)
WebResponse.SetStatusRedirect(302, 'https://example.com/new-path');
```
## Cookies
Handling user sessions and persistence is easy with built-in cookie support.
```pascal
// Setting a cookie
WebResponse.SetCookie('SessionID', '12345', Now + 1); // Expires tomorrow
// Getting a cookie
var session := WebRequest.Cookie['SessionID'];
// OUTPUT NONE
```
## Secure Cookies
For session cookies and sensitive data, always use security flags. The `SetCookie` method accepts a bitmask for flags and an enumeration for `SameSite`.
```pascal
uses System.Net, System.Crypto;
// Secure session cookie with all protections
var token := CryptographicToken(32);
// Flags bitmask: 1 = Secure, 2 = HttpOnly
// SameSite: 0 = Unspecified, 1 = Strict, 2 = Lax
WebResponse.SetCookie('Session', token, Now + 1, '/', '', 2, WebCookieSameSite.Strict);
// For HTTPS sites, combine Secure (1) and HttpOnly (2)
// WebResponse.SetCookie('Session', token, Now + 1, '/', '', 1 + 2, WebCookieSameSite.Strict);
// OUTPUT NONE
```
| Flag Value | Name | Description |
| :--- | :--- | :--- |
| `1` | `Secure` | Only sent over HTTPS connections |
| `2` | `HttpOnly` | Blocks JavaScript access (prevents XSS theft) |
| SameSite | Description |
| :--- | :--- |
| `Strict` | Best security; only sent for same-site requests |
| `Lax` | Sent for same-site and top-level cross-site navigations |
| `Unspecified`| Browser default behavior |
## Encoding Utilities
Always encode user-provided text before rendering it to HTML to prevent XSS attacks.
```pascal
var input := '';
PrintLn(StrToHtml(input)); // <script>...
```
**Output:**
```text
<script>alert("XSS")</script>
```
## Server-Sent Events (SSE)
You can push real-time updates to clients using the `ServerSentEvents` API.
```pascal
// NO_RUN
uses System.Net;
// In your event stream handler script
WebResponse.SetContentEventStream('my-stream');
// In your data producer script (e.g. triggered by a timer or another request)
var event := new WebServerSentEvent;
event.Data.Add('Hello World at ' + FloatToStr(Now));
event.Post('my-stream');
```
# Server Control (System.WebServer)
While `System.Net` handles individual requests, `System.WebServer` allows you to control the server environment itself, such as defining URL rewrite rules.
```pascal
// NO_RUN
uses System.WebServer;
WebServer.SetURLRewriteRulesJSON(#'[
{ "pattern": "/api/*", "rewrite": "/api/router.dws?path=$1" }
]');
```
:::info
### Related Reference
For complete object and method lists, see the reference documentation:
* **[System.Net Reference](/ref/net)** - Request, Response, and Networking.
* **[System.WebServer Reference](/ref/webserver)** - Server control and Rewriting.
:::
---
Source: lang/tooling/formatter.md
---
title: Code Formatter
id: lang/tooling/formatter
---
# Code Formatter
DWScript includes a built-in code formatter that helps maintain consistent coding styles. The formatter parses the source code into a Code DOM (Document Object Model) and then regenerates the source code with standardized formatting.
## Configuration
The formatter (`TdwsAutoFormat`) can be configured with the following properties:
* **IndentChar:** The character used for indentation (default is tab `#9`).
* **IndentSize:** The number of characters per indentation level (default is 1).
## Formatting Rules
The formatter applies several structural rules to ensure code readability:
### Indentation
Code blocks are automatically indented. This includes:
* `begin ... end` blocks
* `case ... end` statements
* `try ... finally/except` blocks
* `repeat ... until` loops
### Line Breaks
The formatter is designed to keep code compact while maintaining clarity. It does **not** force a new line after `then`, `else`, or `do`. This allows placing the `begin` on the same line, which is a supported and common style.
* New lines are inserted after semicolons `;`
* Sections like `var`, `const`, `type` are clearly separated.
### Spacing
Spaces are normalized around operators and punctuation:
* Spaces are added around assignment operators `:=`
* Spaces are added after commas `,`
* Spaces are handled around parenthesis to separate them from keywords (e.g., `if (condition)`).
## Example
### Before
`var i:Integer;for i:=1 to 10 do begin PrintLn(i);end;`
### After
```pascal
var i : Integer;
for i := 1 to 10 do begin
PrintLn(i);
end;
```
**Output:**
```text
1
2
3
4
5
6
7
8
9
10
```
---
Source: lang/tooling/js_transpiler.md
---
title: JS Transpiler
id: lang/tooling/js_transpiler
---
# JavaScript Transpiler
DWScript features a powerful **Pascal-to-JavaScript** compiler (`dwsJSCodeGen`). It allows you to write client-side logic in strongly-typed Object Pascal and deploy it as optimized JavaScript.
## Key Features
* **Strong Typing:** Catch errors at compile time before generating JS.
* **Smart Linking:** The `SmartLinker` analyzes your code and removes unused classes, methods, and types from the final output, significantly reducing bundle size.
* **Optimizations:** Loops, conditionals, and expressions are optimized for JS execution.
* **Source Maps:** Debug your Pascal code directly in the browser.
## Code Generation Options
| Option | Description |
| :--- | :--- |
| `cgoSmartLink` | Enables the Smart Linker. Unreachable code is stripped. |
| `cgoObfuscate` | Minifies and obfuscates symbol names to protect intellectual property and reduce size. |
| `cgoPrettify` | Generates readable, indented JavaScript (useful for debugging). |
## Example
```pascal
// Pascal Source
type
TPoint = record x, y : Integer; end;
function Add(a, b : Integer) : Integer;
begin
Result := a + b;
end;
// If "Add" is called, it will be in the JS output.
// If "TPoint" is unused, it will be removed by SmartLinker.
```
## Libraries
Standard libraries like `System`, `Math`, and `Classes` are partially mapped to JS equivalents, allowing for seamless code sharing between server (native) and client (JS).
---
Source: lang/tooling/style.md
---
title: Style Guide & Rules
id: lang/tooling/style
---
# Style Guide & Code Rules
DWScript promotes a consistent coding style through its built-in rules engine (Gabelou). Following these guidelines ensures that your code remains readable and idiomatic.
## Naming Conventions
### CamelCase
* **Parameters:** `procedure DoWork(itemCount : Integer);`
* **Local Variables:** `var userName := 'John';`
### PascalCase
* **Functions/Procedures:** `function CalculateTotal : Float;`
* **Types:** `type TUserRecord = record ... end;`
* **Properties:** `property FullName : String ...`
## Prefixes & Suffixes
| Category | Rule | Example |
| :--- | :--- | :--- |
| **Private Fields** | Start with `F` followed by PascalCase | `FInternalValue` |
| **Class Variables** | Start with `v` followed by PascalCase | `vGlobalCounter` |
| **Constants** | Start with `c` + PascalCase OR ALL_CAPS | `cDefaultPort`, `MAX_RETRY` |
| **Exceptions** | Type names starting with `E` should be Exception classes | `EValidationError` |
| **Attributes** | Should end with `Attribute` and NOT have a `T` prefix | `WebMethodAttribute` |
## Formatting Rules
Consistency is key to a healthy codebase. The following rules are promoted by the formatter:
* **Compact Blocks:** Keeping `begin` on the same line as `then`, `else`, or `do` is encouraged to reduce vertical space.
* **Multiline Strings:** For long or multi-line strings (using `#'` or `#" `), it is recommended to place the closing delimiter on a new line. This improves readability and makes it easier to append content.
* **Indentation:** Content within blocks is always indented to show structure.
* **Case Statements:** The `else` keyword in a `case` statement should be aligned with the `case` keyword, and the code within the `else` block should be indented.
```pascal
var value := 1;
procedure DoSomething; begin end;
procedure DoSomethingElse; begin end;
procedure DoDefault; begin end;
case value of
1: DoSomething;
2: DoSomethingElse;
else
DoDefault;
end;
```
* **Spacing:** Mandatory spaces around assignment `:=` and after commas `,`.
:::info
#### Tip
You can use the `TdwsAutoFormat` class in your own tools to programmatically clean up DWScript source code according to these rules.
:::
---
Source: ref/crypto.md
---
title: Cryptography
description: Secure hashing and AES/ECC encryption.
id: ref/crypto
---
# Cryptography
The `System.Crypto` unit provides a wide range of cryptographic primitives, including secure hashing, symmetric and asymmetric encryption, and cryptographic utilities.
## Hashing Algorithms
All hashing classes inherit from `HashAlgorithm` and provide `HashData` and `HMAC` methods.
| Class | Description |
| :--- | :--- |
| `HashMD5` | Legacy MD5 hashing (128-bit). |
| `HashSHA1` | Legacy SHA-1 hashing (160-bit). |
| `HashSHA256` | Standard SHA-2 256-bit hashing. |
| `HashSHA512` | Standard SHA-2 512-bit hashing. |
| `HashSHA3_256` | Modern SHA-3 256-bit hashing (Keccak). |
| `HashRIPEMD160` | RIPEMD 160-bit hashing. |
| `HashCRC32` | CRC32 checksum. |
```pascal
uses System.Crypto;
// Standard Hashing
var hash := HashSHA256.HashData('Message');
// HMAC (Keyed Hashing)
var hmac := HashSHA256.HMAC('Message', 'SecretKey');
```
## Symmetric Encryption (AES)
Authenticated encryption combining AES with hashing for integrity.
| Class | Description |
| :--- | :--- |
| `EncryptionAESSHA256Full` | AES-CTR with SHA-256 HMAC. Recommended for general use. |
| `EncryptionAESSHA3CTR` | AES-CTR with SHA3-256 HMAC. |
| `EncryptionAESnistCTR` | Low-level AES-CTR (requires manual IV management). |
| `EncryptionCryptProtect` | Windows DPAPI (Machine or User bound encryption). |
## Asymmetric Cryptography
### ECC (secp256r1)
The `ECCsecp256r1` class provides Elliptic Curve Cryptography for signatures and key exchange.
| Method | Description |
| :--- | :--- |
| `MakeKey(var pub, var priv)` | Generates a new key pair. |
| `ECDHSharedSecret(pub, priv)` | Calculates shared secret (Diffie-Hellman). |
| `ECDSASign(priv, hashHex)` | Signs a 256-bit hash. |
| `ECDSAVerify(pub, hashHex, sig)` | Verifies a signature. |
### RSA
The `TRSAKey` class supports RSA encryption and signatures.
| Method | Description |
| :--- | :--- |
| `Generate(bitSize)` | Constructor for new keys (e.g. 2048, 4096). |
| `SignHash(algo, hashHex)` | Signs a hash. |
| `VerifyHash(algo, hashHex, sig)` | Verifies a signature. |
| `Encrypt / Decrypt` | Encrypts or decrypts data using the key. |
| `ExportJSON / ImportJSON` | Serializes the key to/from JSON format. |
## Nonces & One-Time Tokens
The `Nonces` class manages unique, time-limited tokens stored in memory, useful for preventing replay attacks, CSRF protection, or managing temporary sessions.
| Method | Description |
| :--- | :--- |
| `Generate(ms)` | Generates a new nonce with no associated data. |
| `Generate(ms, data)` | Generates a new nonce with associated data string. |
| `Register(nonce, ms, data)` | Registers an existing token string with expiration. |
| `CheckAndRemove(nonce)` | True if valid and has no data. Removes it. |
| `CheckAndRemove(nonce, data)` | True if valid and matches data. Removes it. |
| `CheckAndKeep(nonce)` | True if valid and has no data. Keeps it. |
| `CheckAndKeep(nonce, data)` | True if valid and matches data. Keeps it. |
| `GetData(nonce)` | Retrieves the data string associated with a nonce (or empty if invalid). |
| `Remove(nonce)` | Manually expires a nonce. |
## Cryptographic Utilities
| Function / Method | Description |
| :--- | :--- |
| `PBKDF2_HMAC_SHA256(pass, salt, iters)` | Password-based key derivation. |
| `CryptographicToken(bits)` | Returns a random alphanumeric token. |
| `CryptographicRandom(bytes)` | Returns raw random bytes. |
| `Nonces.Generate(ms, data)` | Generates and registers a time-limited one-time token. |
---
Source: ref/database.md
---
title: Databases
description: Agnostic SQL layer with SQLite support.
id: ref/database
---
# Database Support
The `System.Data` unit provides a database-agnostic layer for executing queries and managing data, with native support for SQLite.
## DataBase Class
| Method | Description |
| :--- | :--- |
| `Create(driver, params)` | Static factory (e.g., `DataBase.Create('SQLite', ['my.db'])`). |
| `Query(sql [, params])` | Executes SELECT and returns a `DataSet`. |
| `Exec(sql [, params])` | Executes non-query (INSERT/UPDATE/DELETE). |
| `BeginTransaction` | Starts a transaction. |
| `Commit / Rollback` | Transaction control. |
## DataSet Class
| Member | Description |
| :--- | :--- |
| `Step` | Moves to next record and returns True if one exists. Practical for loops. |
| `Next` | Advances to next row. Returns False if EOF. |
| `Eof` | Returns True if the last record has been passed. |
| `FieldCount` | Number of columns in the result set. |
| `AsString(name/idx)` | Returns field value as string (using name or 0-based index). |
| `AsInteger(name/idx)` | Returns field value as integer. |
| `AsFloat(name/idx)` | Returns field value as float. |
| `IsNull(name/idx)` | Returns True if the field is NULL. |
| `StringifyAll` | Converts entire set to JSON array string. |
## Example: Querying SQLite
```pascal
uses System.Data;
var db := DataBase.Create('SQLite', [':memory:']);
db.Exec('CREATE TABLE Users (ID INTEGER, Name TEXT)');
db.Exec('INSERT INTO Users VALUES (1, "Alice")');
var ds := db.Query('SELECT Name FROM Users');
while ds.Step do
PrintLn(ds.AsString(0).ToHtml);
```
**Output:**
```text
Alice
```
## Parameterized Updates
```pascal
uses System.Data;
var db := DataBase.Create('SQLite', [':memory:']);
db.Exec('CREATE TABLE Users (ID INTEGER, Name TEXT)');
db.Exec('INSERT INTO Users VALUES (1, "Alice")');
db.Exec('UPDATE Users SET Name = ? WHERE ID = ?', ['Bob', 1]);
// OUTPUT NONE
```
:::info
### Driver Support
The **SQLite** driver is built-in. Other drivers can be registered by the host application to support PostgreSQL, MySQL, or SQL Server.
:::
---
Source: ref/datetime.md
---
title: Date & Time
description: TDateTime and Unix timestamp utilities.
id: ref/datetime
---
# Date & Time
Handling dates and times in DWScript is centered around the `TDateTime` type, which is technically a `Float` where the integer part represents days since Dec 30, 1899, and the fractional part represents the time of day.
## Core Functions
| Function | Parameters | Description |
| :--- | :--- | :--- |
| `Now` | ` ` | Current local date and time. |
| `Date` | ` ` | Current local date only. |
| `Time` | ` ` | Current local time only. |
| `UTCDateTime` | ` ` | Current UTC date and time. |
| `UnixTime` | `[utc]` | Returns current or specific Unix timestamp (seconds). |
| `UnixTimeMSec` | `[utc]` | Returns Unix timestamp in milliseconds. |
| `DateTimeToUnixTime` | `dt` | Converts TDateTime to Unix timestamp. |
| `EncodeDateTime` | `y, m, d, h, n, s, ms` | Creates TDateTime from components. |
| `DecodeDateTime` | `dt, var y, m, d, h, n, s, ms` | Extracts components from TDateTime. |
| `FormatDateTime` | `fmt, dt [, zone]` | Formats date using pattern. |
| `ISO8601ToDateTime` | `s` | Parses ISO8601 string. |
| `DateTimeToISO8601` | `dt` | Converts to ISO8601 string. |
| `DateTimeToRFC822` | `dt` | Converts to RFC 822 string (used in RSS/Email). |
| `IncYear / IncMonth / IncDay` | `dt, n` | Increment/Decrement date components. |
| `DayOfWeek` | `dt` | Returns 1 (Sunday) to 7 (Saturday). |
| `IsLeapYear` | `year` | Primality test. |
| `Sleep` | `msec` | Pauses execution for `msec` milliseconds. |
## Usage Example
```pascal
var dt := EncodeDate(2026, 1, 12) + EncodeTime(12, 0, 0, 0);
PrintLn('Full: ' + FormatDateTime('yyyy-mm-dd hh:nn:ss', dt));
PrintLn('Formatted: ' + FormatDateTime('yyyy-mm-dd', dt));
var tomorrow := dt + 1.0;
PrintLn('Tomorrow: ' + FormatDateTime('yyyy-mm-dd hh:nn:ss', tomorrow));
```
**Output:**
```text
Full: 2026-01-12 12:00:00
Formatted: 2026-01-12
Tomorrow: 2026-01-13 12:00:00
```
:::info
### Technical Note
Since `TDateTime` is a `Float`, you can perform arithmetic directly. For example, `Now + 1.0` represents tomorrow at the same time, and `Now + (1.0 / 24.0)` represents one hour from now.
:::
---
Source: ref/encoding.md
---
title: Encodings
description: Base64, Hex, and URL encoding.
id: ref/encoding
---
# Data Encodings
DWScript provides a consistent API for various data encodings through specialized encoder classes. Each class typically provides `Encode` and `Decode` methods.
## Core Encoders
| Class | Description |
| :--- | :--- |
| `UTF8Encoder` | Standard UTF-8 encoding. |
| `Base64Encoder` | Standard Base64 (RFC 4648). |
| `Base64URIEncoder` | URL-safe Base64 (replaces +/ with -_). |
| `HexadecimalEncoder` | Converts bytes to hex strings. |
| `URLEncodedEncoder` | Standard URL percent-encoding. |
| `HTMLTextEncoder` | Encodes HTML special characters (entities). |
| `Base58Encoder` | Bitcoin-style Base58 encoding. |
## Base64 & Hex Example
```pascal
var s := 'Hello World';
var b64 := Base64Encoder.Encode(s);
PrintLn('Base64: ' + b64);
var raw := Base64Encoder.Decode(b64);
PrintLn('Decoded: ' + raw);
```
**Output:**
```text
Base64: SGVsbG8gV29ybGQ=
Decoded: Hello World
```
## URL Encoding Example
```pascal
var url := 'https://example.com/search?q='
+ URLEncodedEncoder.Encode('DWScript & Pascal');
PrintLn(url);
```
**Output:**
```text
https://example.com/search?q=DWScript%20%26%20Pascal
```
:::info
### Method Syntax
You can also use method syntax for common encodings. For example: `myStr.HTMLEncode` or `myStr.Base64Encode`.
:::
---
Source: ref/files.md
---
title: File System
description: File system I/O and path management.
id: ref/files
---
# File System Access
DWScript provides comprehensive functions for file I/O, directory management, and path manipulation.
## Core File Operations
| Function | Parameters | Description |
| :--- | :--- | :--- |
| `FileExists` | `name` | Check if a file exists. |
| `FileRead` | `name` | Reads entire file into a string. |
| `FileWrite` | `name, content` | Writes string to a file. |
| `FileReadLines` | `name` | Reads file into `array of String`. |
| `FileSize` | `name` | Size in bytes. |
| `DeleteFile` | `name` | Removes a file. |
| `CopyFile` | `src, dest [, failIfExist]` | Copies a file. |
| `MoveFile` | `src, dest` | Moves a file. |
| `RenameFile` | `old, new` | Renames a file or directory. |
## Directories
| Function | Parameters | Description |
| :--- | :--- | :--- |
| `DirectoryExists` | `name` | Check if directory exists. |
| `CreateDir / RemoveDir` | `path` | Create/Remove directory. |
| `RemoveDir` | `path [, recursive]` | Remove directory (optionally even if not empty). |
| `ForceDirectories` | `path` | Creates full directory path recursively. |
| `EnumerateDir` | `path, mask, recursive` | Returns `array of String` of files. |
| `EnumerateSubDirs` | `path` | Returns `array of String` of subdirectories. |
## File Metadata
| Function | Description |
| :--- | :--- |
| `FileDateTime` | Returns last modification timestamp. |
| `FileAccessDateTime` | Returns last access timestamp. |
| `FileCreationDateTime` | Returns file creation timestamp. |
| `FileSetDateTime` | Manually sets modification timestamp. |
## Path Manipulation
These functions operate on strings and do not check the actual file system.
| Function | Description |
| :--- | :--- |
| `ExtractFilePath` | Returns directory part (with trailing backslash). |
| `ExtractFileName` | Returns file name and extension. |
| `ExtractFileExt` | Returns file extension (e.g. ".pas"). |
| `ChangeFileExt` | Replaces file extension. |
## Example: Bulk Processing
```pascal
var files := EnumerateDir('lang/basics', 'intro*.md', False);
for var f in files do begin
if FileSize(f) > 0 then
PrintLn('Found file: ' + ExtractFileName(f));
end;
```
**Output:**
```text
Found file: introduction.md
```
:::warning
### Security
Access to the file system is restricted by the execution environment. In web contexts, access is typically limited to the web root or specific temporary folders.
:::
---
Source: ref/globalvars.md
---
title: Global State
description: Thread-safe shared variables and queues.
id: ref/globalvars
---
# Global Variables & Queues
DWScript provides mechanisms for sharing state across concurrent requests and users in a thread-safe manner.
## Global & Private Variables
Global variables are shared across the entire server, while private variables are scoped to the specific unit or script context.
| Function | Parameters | Description |
| :--- | :--- | :--- |
| `ReadGlobalVar` | `name` | Reads a global variable. Returns Unassigned if not found. |
| `ReadGlobalVarDef` | `name, default` | Reads with a default fallback value. |
| `TryReadGlobalVar` | `name, var v` | Returns True if the variable exists and reads it into `v`. |
| `WriteGlobalVar` | `name, val [, expire]` | Writes a global variable with optional expiration in seconds. |
| `IncrementGlobalVar` | `name [, step, expire]` | Atomically increments a numeric variable with optional expiration in seconds. |
| `CompareExchangeGlobalVar` | `name, val, comp` | Atomic compare-and-swap operation. |
| `DeleteGlobalVar` | `name` | Removes a global variable. |
| `CleanupGlobalVars` | `filter` | Removes global variables matching the mask (default `*`). |
| `GlobalVarsNames` | `filter` | Returns `array of String` with matching names. |
| `SaveGlobalVarsToString` | - | Serializes all global variables without expiration to a string. |
| `LoadGlobalVarsFromString` | `s` | Deserializes global variables from a string. |
## Private Variables
Private variables are similar to global variables but are scoped to the **Unit (Module)** in which they are called. They are persistent across requests but cannot be accessed from the main script or other units directly.
| Function | Parameters | Description |
| :--- | :--- | :--- |
| `ReadPrivateVar` | `name [, default]` | Reads a private variable with an optional default. |
| `WritePrivateVar` | `name, val [, expire]` | Writes a private variable with optional expiration in seconds. |
| `IncrementPrivateVar` | `name [, step, expire]` | Atomically increments a private variable. |
| `CompareExchangePrivateVar`| `name, val, comp` | Atomic compare-and-swap for private variables. |
| `CleanupPrivateVars` | `filter` | Removes private variables matching the mask (default `*`). |
| `PrivateVarsNames` | `filter` | Returns `array of String` with matching names. |
## Global Queues
Thread-safe message queues for inter-request communication.
| Function | Parameters | Description |
| :--- | :--- | :--- |
| `GlobalQueuePush` | `name, val` | Adds item to the end. Returns new length. |
| `GlobalQueueInsert` | `name, val` | Adds item to the front. |
| `GlobalQueuePull` | `name, var v` | Removes and returns first item (FIFO). Returns True if success. |
| `GlobalQueuePop` | `name, var v` | Removes and returns last item (LIFO). |
| `GlobalQueuePeek` | `name, var v` | Gets last item without removing. |
| `GlobalQueueFirst` | `name, var v` | Gets first item without removing. |
| `GlobalQueueLength` | `name` | Current number of items in the queue. |
| `GlobalQueueClear` | `name` | Removes all items from the queue. |
| `GlobalQueueSnapshot` | `name` | Returns a copy of the entire queue as an array. |
## Example: Atomic Counter
```pascal
var count : Integer;
// Atomic increment
WriteGlobalVar('Requests', 0); // Reset for documentation demo
count := IncrementGlobalVar('Requests');
PrintLn('Request #' + IntToStr(count));
```
**Output:**
```text
Request #1
```
---
Source: ref/graphics.md
---
title: Graphics
description: TPixmap for low-level pixel manipulation.
id: ref/graphics
---
# Graphics (Pixmap)
DWScript provides built-in support for low-level 2D buffer manipulation through the `TPixmap` class. No `uses` clause is required.
## TPixmap Class
| `Member` | Description |
| :--- | :--- |
| `GetPixel / SetPixel` | Accesses ARGB color at (x, y). |
| `GetData / SetData` | Accesses ARGB color by linear pixel index (offset). |
| `Resize(w, h)` | Resizes the pixmap (nearest neighbor). |
| `ToPNGData(w, h, alpha)` | Returns PNG data as a string. |
| `ToJPEGData(w, h, qual, opts)`| Returns JPEG data as a string. |
| `ToHexString` | Returns raw buffer data as hex string. |
| `AssignHexString(hex)` | Fills buffer from a hex string. |
## Global Functions
| Function | Description |
| :--- | :--- |
| `CreatePixmap(w, h)` | Creates a new TPixmap instance (initialized to zero/black). |
| `PNGDataToPixmap(data, alpha, @w, @h)` | Creates a pixmap from PNG data, returning dimensions in `w` and `h`. |
| `JPEGDataToPixmap(data, scale, @w, @h)` | Creates a pixmap from JPEG data, returning dimensions in `w` and `h`. |
## Colors
Colors are represented as 32-bit ARGB integers in the format `$AARRGGBB`.
* `$FFFF0000`: Opaque Red
* `$FF00FF00`: Opaque Green
* `$FF0000FF`: Opaque Blue
* `$80000000`: Semi-transparent Black
## Example: Basic Operations
```pascal
// Create a 64x64 pixmap (initialized to black)
var bmp := CreatePixmap(64, 64);
for var i := 0 to 63 do
bmp.SetPixel(i, i, $FFFFFFFF); // White diagonal
var hex := bmp.ToHexString;
// OUTPUT NONE
```
:::info
### Performance
For heavy pixel processing, consider using `GetData` and `SetData` with linear indexing to avoid the overhead of coordinate calculations.
```pascal
// NO_RUN
var bmp := CreatePixmap(100, 100);
// Linear fill (faster for full-buffer operations)
for var i := 0 to (100 * 100) - 1 do
bmp.SetData(i, $FF00FF00); // Fill with green
```
:::
---
Source: ref/inifiles.md
---
title: IniFiles
description: Configuration management (INI format).
id: ref/inifiles
---
# Configuration (INI)
The `TIniFile` class (from `System.IniFiles`) provides a simple way to manage configuration settings in the classic INI format.
## TIniFile Class
### Constructors
| Name | Parameters | Description |
| :--- | :--- | :--- |
| `Create` | `fileName` | Initializes from a file on disk. |
| `CreateInMemory` | `content` | Initializes from a string containing INI data. |
### Methods
| Method | Parameters | Description |
| :--- | :--- | :--- |
| `ReadString` | `section, name, default` | Reads a string value. |
| `WriteString` | `section, name, value` | Writes a string value. |
| `ReadSections` | ` ` | Returns `array of String` with all section names. |
| `ReadSectionNames` | `section` | Returns `array of String` with all keys in a section. |
| `EraseSection` | `section` | Removes an entire section. |
| `DeleteKey` | `section, name` | Removes a specific key. |
| `FileName` | ` ` | Returns the path to the associated INI file. |
| `ToString` | ` ` | Returns the entire INI content as a string. |
:::warning
### Auto-Save
Changes are automatically flushed to disk when the `TIniFile` instance is freed. There is no explicit `UpdateFile` method.
:::
### Properties
| Property | Type | Description |
| :--- | :--- | :--- |
| `Encoding` | `String` | The text encoding used for the file (e.g. 'utf-8'). |
## Example: Basic Operations
```pascal
uses System.IniFiles;
var ini := new TIniFile('.data/config.ini');
try
ini.WriteString('Database', 'User', 'admin');
ini.WriteString('Database', 'Pass', 'secret');
finally
ini.Free; // Flushes to disk
end;
```
:::info
### Typing Note
The DWScript implementation of `TIniFile` primarily handles string values. To read other types, use conversion functions: `StrToInt(ini.ReadString(...))` or `StrToBool(ini.ReadString(...))`.
:::
---
Source: ref/json.md
---
title: JSON
description: High-performance JSON parsing and serialization.
id: ref/json
---
# JSON Support
DWScript provides built-in, high-performance JSON support through the `JSON` object and the `JSONVariant` type.
## Core Methods
| Method | Parameters | Description |
| :--- | :--- | :--- |
| `Parse` | `jsonStr` | Parses JSON string into a `JSONVariant`. |
| `Stringify` | `value` | Converts a value (Record, Class, Array, etc) to a JSON string. |
| `PrettyStringify` | `value [, indent]` | Formats JSON for readability. |
| `Serialize` | `value` | Converts a native value into a `JSONVariant` object. |
| `NewObject / NewArray` | ` ` | Creates a dynamic JSON container. |
### Serializing vs Stringifying
While `Stringify` produces a JSON **String**, `Serialize` converts a native value directly into a `JSONVariant` object. This allows you to manipulate the structure before generating the final string.
```pascal
var p := record x := 10; y := 20; end;
// Convert to JSONVariant, modify, then stringify
var j := JSON.Serialize(p);
j.x := 100;
PrintLn(j.ToString());
```
**Output:**
```text
{"x":100,"y":20}
```
## Serialization Rules
DWScript uses a set of consistent rules for automatic serialization via `JSON.Stringify`:
| Type | Inclusion Rule |
| :--- | :--- |
| **Classes** | Only **published** fields and properties are included. |
| **Named Records** | Only **published** fields are included. |
| **Anonymous Records** | **All** fields are automatically included. |
| **Arrays** | All elements are included as a JSON array. |
### Example: Classes
```pascal
type
TUser = class
published
Name : String;
Age : Integer;
private
InternalId : Integer; // Will be ignored
end;
var u := new TUser;
u.Name := 'Alice'; u.Age := 30;
PrintLn(JSON.Stringify(u));
```
**Output:**
```text
{"Age":30,"Name":"Alice"}
```
## Dynamic Access
Using `JSONVariant`, you can access keys using dot notation or array indexing.
```pascal
var data := JSON.Parse('{"items": [10, 20]}');
PrintLn(data.items[0]);
```
**Output:**
```text
10
```
## JSONVariant Helper Methods
When working with `JSONVariant`, several helper methods are available. Note that these **must** be called with parentheses `()` to avoid conflict with JSON field names.
| Method | Returns | Description |
| :--- | :--- | :--- |
| `Defined()` | `Boolean` | Returns `True` if the value is not `Undefined`. |
| `Length()` | `Integer` | Returns the number of elements (Array) or keys (Object). |
| `Low()` | `Integer` | Returns the lowest index (usually 0). |
| `High()` | `Integer` | Returns the highest index of an array. |
| `Add(item)` | `Integer` | Appends an item to a JSON array. Returns the new index. |
| `Push(item)` | `Integer` | Alias for `Add`. |
| `Delete(id)` | `(none)` | Removes an item by index (Array) or key name (Object). |
| `Swap(i, j)` | `(none)` | Swaps two elements in an array. |
| `Clone()` | `JSONVariant` | Returns a deep copy of the structure. |
| `ToString()` | `String` | Returns the JSON string representation. |
| `TypeName()` | `String` | Returns 'Object', 'Array', 'String', 'Number', 'Boolean', 'Null' or 'Undefined'. |
| `ElementName(i)` | `String` | Returns the key name at the given index (for Objects). |
| `AsInteger / AsFloat` | ` ` | Explicit conversion helpers. |
| `AsString / AsBoolean` | ` ` | Explicit conversion helpers. |
## Specialized Parsers
For high-performance scenarios, these static methods on the `JSON` object parse strings directly into native Pascal arrays, bypassing `JSONVariant` overhead.
| Method | Parameters | Returns |
| :--- | :--- | :--- |
| `ParseIntegerArray` | `(jsonStr)` | `array of Integer` |
| `ParseFloatArray` | `(jsonStr)` | `array of Float` |
| `ParseStringArray` | `(jsonStr)` | `array of String` |
:::info
### Auto-Serialization
DWScript can automatically stringify complex types like **Records** and **Classes**. Simply pass the instance to `JSON.Stringify`.
:::
---
Source: ref/math.md
# Math Functions
The core math library provides standard mathematical functions, constants, and utilities for common calculations.
## Comprehensive Function List
| Function | Parameters | Description |
| :--- | :--- | :--- |
| `Abs` | `v` | Absolute value (supports Int, Float, Variant). |
| `Sqr` | `v` | Square (v * v). |
| `Sqrt` | `v` | Square root. |
| `Exp` | `v` | Exponential (e^v). |
| `Ln` | `v` | Natural logarithm. |
| `Log2` | `v` | Base-2 logarithm. |
| `Log10` | `v` | Base-10 logarithm. |
| `LogN` | `n, x` | Logarithm of x to base n. |
| `Power` | `base, exp` | Exponentiation (float exponent). |
| `IntPower` | `base, exp` | Exponentiation (integer exponent). |
| `Hypot` | `x, y` | Hypotenuse (sqrt(x*x + y*y)). |
| `Haversine` | `lat1, lon1, lat2, lon2, r` | Great-circle distance between two points. |
| `Factorial` | `v` | Returns v!. |
| `GCD` | `a, b` | Greatest Common Divisor. |
| `LCM` | `a, b` | Least Common Multiple. |
| `IsPrime` | `n` | Primality test. |
| `LeastFactor` | `n` | Smallest prime factor. |
| `Floor` | `v` | Largest integer less than or equal to v. |
| `Ceil` | `v` | Smallest integer greater than or equal to v. |
| `Round` | `v` | Rounds to nearest integer. |
| `Trunc` | `v` | Truncates fractional part. |
| `Frac` | `v` | Returns fractional part. |
| `Sign` | `v` | Returns -1, 0, or 1. |
| `Clamp` | `v, min, max` | Clamps float to range. |
| `ClampInt` | `v, min, max` | Clamps integer to range. |
## Vectorized Array Operations (`array of Float`)
DWScript provides high-performance SIMD-optimized operations for float arrays. These are available as both global functions and method helpers.
### Global Functions
| Function | Parameters | Description |
| :--- | :--- | :--- |
| `ArrayDotProduct` | `a1, a2 [, o1, o2, c]` | Returns the scalar dot product of two arrays (or segments). |
### Method Helpers (Mutating)
These methods modify the source array **in-place** and return the array instance to support **fluent method chaining**.
| Method | Parameters | Description |
| :--- | :--- | :--- |
| `.Offset` | `v` or `other [, tO, sO, c]` | Element-wise addition (by scalar or array). |
| `.Multiply` | `v` or `other [, tO, sO, c]` | Element-wise multiplication (by scalar or array). |
| `.Min` | `v` or `other [, tO, sO, c]` | Element-wise `x := Min(x, operand)` (Cap). |
| `.Max` | `v` or `other [, tO, sO, c]` | Element-wise `x := Max(x, operand)` (Floor). |
| `.OffsetScaled`| `other, scale [, tO, sO, c]` | Element-wise `x := x + other * scale`. |
| `.MultiplyAdd`| `scale, offset` | In-place `x := x * scale + offset`. |
| `.Reciprocal` | | In-place `x := 1 / x`. |
| `.DotProduct` | `other` | Returns scalar dot product (convenience alias for global). |
```pascal
var data : array of Float := [1.0, 2.0, 3.0];
var noise : array of Float := [0.1, 0.2, 0.3];
// Chained in-place operations
data.Offset(noise).Multiply(2.0).Min(5.0);
// Using OffsetScaled for signal processing (signal + gain * scale)
var signal : array of Float := [10.0, 20.0, 30.0];
var gain : array of Float := [1.0, 1.0, 1.0];
signal.OffsetScaled(gain, 0.5);
for var v in signal do Print(v.ToString + ' ');
PrintLn('');
```
**Output:**
```text
10.5 20.5 30.5
```
## Trigonometry
Standard trigonometric functions work with radians.
| Function | Parameters | Description |
| :--- | :--- | :--- |
| `Sin` | `v` | Sine. |
| `Cos` | `v` | Cosine. |
| `Tan` | `v` | Tangent. |
| `ASin` | `v` | Arcsine. |
| `ACos` | `v` | Arccosine. |
| `ATan` | `v` | Arctangent. |
| `DegToRad` | `a` | Converts degrees to radians. |
| `RadToDeg` | `a` | Converts radians to degrees. |
```pascal
var rad := DegToRad(90);
PrintLn('Sin(90): ' + Sin(rad).ToString);
```
**Output:**
```text
Sin(90): 1
```
## Randomization
DWScript provides a pseudo-random number generator.
| Function | Parameters | Description |
| :--- | :--- | :--- |
| `Random` | ` ` | Random float in [0..1). |
| `RandomInt` | `range` | Random integer in [0..range-1]. |
| `Randomize` | ` ` | Seeds the random generator with time. |
| `SetRandSeed` | `seed` | Manually sets the random seed. |
| `RandG` | `mean, stdDev` | Gaussian (Normal) random distribution. |
```pascal
var f := Random; // 0.0 <= f < 1.0
var i := RandomInt(10); // 0, 1, ..., 9
```
## Advanced Math Utilities
| Function | Parameters | Description |
| :--- | :--- | :--- |
| `PopCount` | `v` | Returns the number of set bits. |
| `TestBit` | `v, index` | Returns true if the bit at index is set. |
| `CompareNum` | `a, b` | Returns -1, 0, or 1 based on comparison. |
| `DivMod` | `a, b, res, rem`| Performs integer division and modulo in one operation. |
| `IsNaN` | `v` | Returns true if v is Not-a-Number. |
| `IsFinite` | `v` | Returns true if v is a finite number. |
```pascal
// Bit manipulation
var val := 0b1011; // 11
PrintLn('PopCount(11): ' + PopCount(val).ToString);
PrintLn('TestBit(11, 1): ' + TestBit(val, 1).ToString);
// Comparison and clamping
PrintLn('CompareNum(10, 20): ' + CompareNum(10, 20).ToString);
PrintLn('ClampInt(50, 0, 10): ' + ClampInt(50, 0, 10).ToString);
// Division and Modulo in one go
var res, rem : Integer;
DivMod(10, 3, res, rem);
PrintLn('10 / 3 = ' + res.ToString + ' rem ' + rem.ToString);
// Float analysis
var n := NaN;
PrintLn('IsNaN(NaN): ' + IsNaN(n).ToString);
PrintLn('IsFinite(1.0): ' + IsFinite(1.0).ToString);
```
**Output:**
```text
PopCount(11): 3
TestBit(11, 1): True
CompareNum(10, 20): -1
ClampInt(50, 0, 10): 10
10 / 3 = 3 rem 1
IsNaN(NaN): True
IsFinite(1.0): True
```
:::info
### Related Reference
* **[3D Math](/ref/math3d)** - Vectors, Quaternions and Matrices.
:::
---
Source: ref/math3d.md
---
title: 3D Math
description: TVector, TMatrix, and Quaternions.
id: ref/math3d
---
# 3D Math
DWScript provides high-performance types for 3D calculations, optimized for speed and readability.
## TVector Type
A 4-component vector (X, Y, Z, W) implemented as a record with overloaded operators.
| Operator | Meaning |
| :--- | :--- |
| `+`, `-` | Component-wise addition/subtraction. |
| `*` (Vector) | Dot product (Scalar result). |
| `^` (Vector) | Cross product (Vector result). |
| `*`, `/` (Float) | Scalar scaling. |
## Vector Functions
| Function | Description |
| :--- | :--- |
| `Vector(x, y, z, w=0)` | Returns a new `TVector`. |
| `VectorNormalize(v)` | Returns unit vector (length 1.0). |
| `VectorDotProduct(v1, v2)` | Calculates the dot product. |
| `VectorCrossProduct(v1, v2)`| Calculates the cross product. |
| `VectorToStr(v)` | Returns formatted string: `"[X Y Z W]"`. |
## Example: Basic Vectors
```pascal
var v1 := Vector(1, 0, 0);
var v2 := Vector(0, 1, 0);
// Addition
var v3 := v1 + v2;
// Dot product (scalar result)
var dot := v1 * v2;
// Cross product (vector result)
var cross := v1 ^ v2;
PrintLn(VectorToStr(cross));
```
**Output:**
```text
[0.00 0.00 1.00 0.00]
```
---
Source: ref/net.md
# Networking
The `System.Net` unit provides objects for both client-side networking (making requests) and server-side web environment handling (handling incoming requests).
## HttpQuery (Outbound)
`HttpQuery` is used to make HTTP requests from the server to other web services. It is available in any script that uses `System.Net`.
| Method | Description |
| :--- | :--- |
| `GetText(url, var data)` | Performs a GET request. Returns status code. |
| `PostData(url, data, type, var reply)` | Performs a POST request. |
| `Request(method, url, data, type)` | Performs an arbitrary request and returns an `HttpRequest`. |
| `SetConnectTimeoutMSec(ms)` | Sets the connection timeout in milliseconds. |
| `SetSendTimeoutMSec(ms)` | Sets the send timeout in milliseconds. |
| `SetReceiveTimeoutMSec(ms)` | Sets the receive timeout in milliseconds. |
| `SetIgnoreSSLCertificateErrors(bool)`| If true, invalid SSL certificates will be ignored. |
| `SetEnableSSLRevocation(bool)` | Enables or disables SSL certificate revocation checking. |
| `SetProxyName(proxy)` | Sets the proxy server to use. |
| `SetCustomHeaders(headers)` | Sets custom headers for subsequent requests (array of string). |
### Configuring HttpQuery
```pascal
// NO_RUN
uses System.Net;
// Set timeouts in milliseconds
HttpQuery.SetConnectTimeoutMSec(5000);
HttpQuery.SetReceiveTimeoutMSec(30000);
// Security settings
HttpQuery.SetEnableSSLRevocation(True);
HttpQuery.SetIgnoreSSLCertificateErrors(False);
var data: String;
var status := HttpQuery.GetText('https://api.example.com', data);
```
## Web Environment (Inbound)
In a web server context (DWSWebServer or CGI), `System.Net` provides the objects representing the current HTTP transaction.
### WebRequest
Information about the incoming client request.
| Member | Description |
| :--- | :--- |
| `Method` | HTTP verb (GET, POST, etc). |
| `URL` / `FullURL` | The requested URL. |
| `RemoteIP` | Client's IP address. |
| `UserAgent` | Client's browser agent string. |
| `QueryField[name]` | Accesses GET parameters. |
| `ContentField[name]` | Accesses POST parameters (Form data). |
| `Cookie[name]` | Accesses cookies sent by client. |
| `Header[name]` | Accesses arbitrary HTTP headers. |
| `ContentType` | MIME type of the request content. |
| `ContentData` | Raw POST data. |
### WebResponse
Control the response sent back to the client.
| Member | Description |
| :--- | :--- |
| `StatusCode` | HTTP status code (e.g. 200, 404, 301). |
| `ContentType` | MIME type of response (e.g. 'application/json'). |
| `ContentEncoding` | Encoding of the content (e.g. 'gzip'). |
| `ContentData` | Sets the raw response body. |
| `ContentText[type]` | Sets content type and text body. |
| `Header[name]` | Sets a response header. |
| `Compression` | Enables or disables automatic compression. |
| `SetCookie(name, val [, expires])` | Sends a cookie to the client. |
| `SetCookie(name, val, expires, path, ...)` | Sends a cookie with advanced options (domain, flags, sameSite). |
| `SetStatusRedirect(code, url)` | Issues an HTTP redirect. |
| `SetStatusPlainText(code, text)` | Sets status code and text content. |
| `SetStatusJSON(code, json)` | Sets status code and JSON content. |
| `SetContentJSON(j)` | Sends a JSON object as the response. |
| `SetContentFile(fileName [, type])` | Sends a file as the response. |
| `SetETag(etag)` | Sets the ETag header for caching. |
| `SetCacheControl(control)` | Sets the Cache-Control header. |
| `SetLastModified(date)` | Sets the Last-Modified header. |
| `RequestAuthentication(authType)` | Triggers an authentication challenge (e.g. `WebAuthentication.Basic`). |
### Cookie Security Flags
The advanced `SetCookie` overload uses a numeric bitmask for flags and an enum for SameSite.
| Value | Flag | When to Use |
| :--- | :--- | :--- |
| `1` | `Secure` | Always when site uses HTTPS |
| `2` | `HttpOnly` | Always for session cookies (prevents XSS) |
| SameSite | Value | Description |
| :--- | :--- | :--- |
| `Strict` | `1` | Maximum security, no cross-site requests |
| `Lax` | `2` | Balanced, allows top-level navigations |
## Server-Sent Events (SSE)
Support for real-time updates pushed from server to client.
| Method | Description |
| :--- | :--- |
| `WebServerSentEvents.PostRaw(source, data)` | Posts a raw message to the event stream `source`. |
| `WebServerSentEvents.Close(source)` | Closes the event stream `source`. |
| `WebServerSentEvents.Connections(source)` | Returns an array of active connection IDs for `source`. |
| `WebServerSentEvents.SourceNames` | Returns an array of active event source names. |
### WebServerSentEvent
| Member | Description |
| :--- | :--- |
| `ID`, `Name` | Event ID and Event Name. |
| `Data` | Array of data strings (lines). |
| `Retry` | Retry interval in milliseconds. |
| `Post(source)` | Sends the constructed event to `source`. |
---
Source: ref/registry.md
---
title: Registry
description: Windows Registry access.
id: ref/registry
---
# Registry Support
The `System.Registry` unit provides access to the Windows Registry.
## Root Keys
| Constant | Description |
| :--- | :--- |
| `HKEY_CLASSES_ROOT` | HKEY_CLASSES_ROOT |
| `HKEY_CURRENT_USER` | HKEY_CURRENT_USER |
| `HKEY_LOCAL_MACHINE` | HKEY_LOCAL_MACHINE |
| `HKEY_USERS` | HKEY_USERS |
| `HKEY_CURRENT_CONFIG` | HKEY_CURRENT_CONFIG |
## TRegistry Class
| Method | Description |
| :--- | :--- |
| `CreateKey(path)` | Creates a new key. |
| `DeleteKey(path)` | Deletes a key and its subkeys. |
| `ReadValue(root, path, name, def)` | Reads a value from the specified key. |
| `WriteValue(root, path, name, val)` | Writes a value to the specified key. |
| `DeleteValue(root, path, name)` | Deletes a specific value. |
| `SubKeys(root, path)` | Returns an `array of String` containing subkey names. |
| `ValueNames(root, path)` | Returns an `array of String` containing value names. |
```pascaluses System.Registry;
var val := Registry.ReadValue(HKEY.CurrentUser, 'Software\MyApp', 'Version', '1.0');
PrintLn('Version: ' + val);
```
**Output:**
```text
Version: 1.0.0```
---
Source: ref/rtti.md
---
title: RTTI
description: Runtime Type Information and Attributes.
id: ref/rtti
---
# Run-Time Type Information (RTTI)
RTTI provides mechanism to inspect and interact with types and their metadata at runtime.
## Core Functions
| Function | Description |
| :--- | :--- |
| `TypeInfo(type)` | Returns `TTypeInfo` for a given type name. |
| `TypeOf(variable)` | Returns `TTypeInfo` for the runtime type of a variable. |
| `RTTIRawAttributes` | Returns an array of all attribute instances applied in the program. |
## TTypeInfo Members
| Member | Description |
| :--- | :--- |
| `Name` | The name of the type. |
| `Kind` | Type category (e.g. `tkInteger`, `tkClass`). |
| `InheritsFrom(other)` | Checks for inheritance relationship. |
## Symbol Inspection
The `TSymbols` class allows for low-level inspection of the program's symbol table.
| Method | Description |
| :--- | :--- |
| `CreateMain` | Constructor for the root symbol table. |
| `CreateUnit(name)` | Constructor for a specific unit's symbol table. |
| `First / Next / Last` | Iteration methods. |
| `Eof` | True if at the end of the table. |
| `Name / Caption` | Symbol identification. |
| `SymbolType` | Category of the current symbol. |
| `GetMembers` | Returns a symbol table for the members of the current symbol. |
## Example: Type Inspection
```pascal
// NO_COMPILE
type TBase = class end;
type TSub = class(TBase) end;
var info := TypeOf(TSub);
PrintLn('Type: ' + info.Name);
if info.InheritsFrom(TypeOf(TBase)) then
PrintLn('Inherits from TBase');
```
## Accessing Attributes
You can retrieve all attribute instances in a program using `RTTIRawAttributes` and filter them based on their target.
```pascal
// NO_COMPILE
type
TTest = class end;
var attrs := RTTIRawAttributes;
for var i := 0 to attrs.Length - 1 do begin
if attrs[i].T = TypeOf(TTest) then begin
if attrs[i].A is TCustomAttribute then
PrintLn('Found attribute');
end;
end;
```
---
Source: ref/strings_comparison.md
---
title: String Comparisons
description: Equality and wildcard matching.
id: ref/strings_comparison
---
# String Comparisons & Matching
Functions for comparing strings and matching patterns.
## Comparisons
| Function | Method Alias | Description |
| :--- | :--- | :--- |
| `SameText(s1, s2)` | `.EqualsText` | Case-insensitive comparison. |
| `CompareText(s1, s2)` | `.CompareText` | Case-insensitive comparison (returns -1, 0, 1). |
| `StrMatches(s, mask)` | `.Matches(mask)` | Wildcard matching (`*` and `?`). |
```pascal
var filename := 'report_2024.pdf';
if filename.Matches('report_*.pdf') then
PrintLn('Matches!');
```
**Output:**
```text
Matches!
```
---
Source: ref/strings_format.md
---
title: String Formatting
description: Advanced formatting templates.
id: ref/strings_format
---
# String Formatting
Tools for complex string formatting and template replacement.
## Advanced Formatting
### Format
The `Format` function provides powerful template-based formatting similar to C's `printf` or Delphi's `Format`.
| Specifier | Description | Example |
| :--- | :--- | :--- |
| `%d` | Decimal Integer | `Format('%d', [42])` -> `42` |
| `%x` | Hexadecimal | `Format('%x', [255])` -> `FF` |
| `%f` | Floating point | `Format('%.2f', [3.1415])` -> `3.14` |
| `%e` | Scientific notation | `Format('%e', [1000])` -> `1.00E+003` |
| `%g` | General number | `Format('%g', [0.00001])` -> `1E-5` |
| `%n` | Number with separators | `Format('%n', [1234.5])` -> `1,234.50` |
| `%s` | String | `Format('Hi %s', ['Bob'])` -> `Hi Bob` |
| `%m` | Money | `Format('%m', [10.5])` -> `$10.50` |
```pascal
var s := Format(
'Total: %d items in %.2f seconds',
[ 10, 1.234 ]
);
PrintLn(s);
```
**Output:**
```text
Total: 10 items in 1.23 seconds
```
### Pattern Replacement
The `StrReplaceMacros` function (or `.ReplaceMacros` helper) allows for template-style replacements using an array of key-value pairs.
```pascal
var template := 'Hello [NAME], welcome to [PLACE].';
var data := ['NAME', 'Alice', 'PLACE', 'the Compendium'];
var msg := template.ReplaceMacros(data, '[', ']');
PrintLn(msg);
```
**Output:**
```text
Hello Alice, welcome to the Compendium.
```
---
Source: ref/strings_manipulation.md
---
title: String Manipulation
description: Length, substrings, slicing, and structure.
id: ref/strings_manipulation
---
# String Manipulation
Core functions for handling string length, substrings, modification, and structure.
## Core Functions
| Function | Method Alias | Description |
| :--- | :--- | :--- |
| `Length(s)` | `.Length` | Returns the number of characters in the string. |
| `SetLength(var s, len)` | `.SetLength(len)` | Resizes the string to `len` characters. |
| `Copy(s, idx [, len])` | `.Copy(idx [, len])` | Returns a substring starting at 1-based `idx`. |
| `Delete(var s, idx, len)` | - | Removes `len` characters from string variable `s`. |
| `Insert(src, var s, idx)` | - | Inserts `src` into string variable `s` at `idx`. |
| `Pos(sub, s [, offset])` | - | Returns 1-based index of first occurrence. |
| `RevPos(sub, s)` | - | Returns 1-based index of last occurrence. |
| `StrFind(s, sub [, from])`| `.IndexOf(sub [, from])`| Returns 1-based index of `sub` in `s`. |
| `StrDeleteLeft(s, n)` | `.DeleteLeft(n)` | Deletes `n` characters from the left. |
| `StrDeleteRight(s, n)` | `.DeleteRight(n)` | Deletes `n` characters from the right. |
| `StrContains(s, sub)` | `.Contains(sub)` | True if `sub` is present in `s`. |
| `StrBeginsWith(s, sub)` | `.StartsWith(sub)` | True if `s` starts with `sub`. |
| `StrEndsWith(s, sub)` | `.EndsWith(sub)` | True if `s` ends with `sub`. |
| `StrCount(sub, s)` | `.Count(sub)` | Returns number of occurrences of `sub` in `s`. |
| `StrMatches(s, mask)` | `.Matches(mask)` | Wildcard matching (`*` and `?`). |
## Substrings and Slicing
These functions simplify extracting parts of a string relative to a delimiter.
| Function | Method Alias | Description |
| :--- | :--- | :--- |
| `StrBefore(s, delim)` | `.Before(delim)` | Text before the first occurrence of `delim`. |
| `StrBeforeLast(s, delim)` | `.BeforeLast(delim)` | Text before the last occurrence of `delim`. |
| `StrAfter(s, delim)` | `.After(delim)` | Text after the first occurrence of `delim`. |
| `StrAfterLast(s, delim)` | `.AfterLast(delim)` | Text after the last occurrence of `delim`. |
| `StrBetween(s, start, stop)`| `.Between(start, stop)`| Text between `start` and `stop` delimiters. |
| `LeftStr(s, count)` | `.Left(count)` | Returns the first `count` characters. |
| `RightStr(s, count)` | `.Right(count)` | Returns the last `count` characters. |
| `MidStr(s, start, len)`| `.SubString(start, len)` | Returns `len` characters from `start`. |
| `SubStr(s, start, len)`| - | Alias for `MidStr`. |
| `SubString(s, start, end)` | - | Text from `start` to `end` (exclusive of end). **Note:** The method `.SubString` is an alias for `MidStr` (uses length), not this function. |
:::info
### Related Reference
For type conversions (like `FloatToStr`, `IntToStr`) and case transformations, see **[String Transformation](/ref/strings_transform)**.
:::
## Splitting and Joining
| Function | Method Alias | Description |
| :--- | :--- | :--- |
| `StrSplit(s, delim)` | `.Split(delim)` | Splits string into an `array of String`. |
| `StrJoin(arr, delim)` | `.Join(delim)` | Joins an array into a single string. |
| `StrArrayPack(arr)` | `.Pack` | Removes empty strings from an array. |
```pascal
var csv := 'apple,banana,cherry';
var fruits := csv.Split(',');
var joined := fruits.Join('; ');
PrintLn(joined);
```
**Output:**
```text
apple; banana; cherry
```
## Deleting Substrings
```pascal
var s := '--- Content starts here ---';
// Delete multiple characters from the left
var content := s.DeleteLeft(4);
PrintLn('DeleteLeft(4): ' + content);
// Delete multiple characters from the right
var trimmed := content.DeleteRight(4);
PrintLn('DeleteRight(4): ' + trimmed);
// Using functional style
PrintLn('Functional: ' + StrDeleteLeft('banana', 2));
```
**Output:**
```text
DeleteLeft(4): Content starts here ---
DeleteRight(4): Content starts here
Functional: nana
```
---
Source: ref/strings_transform.md
---
title: String Transformation
description: Case conversion, encoding, and type casting.
id: ref/strings_transform
---
# String Transformation
Functions for converting case, encoding, escaping, and type conversion.
## Transformation
| Function | Method Alias | Description |
| :--- | :--- | :--- |
| `LowerCase(s)` | `.ToLower` / `.LowerCase` | Converts to lowercase (Unicode). |
| `ASCIILowerCase(s)` | - | Converts to lowercase (ASCII only). |
| `UpperCase(s)` | `.ToUpper` / `.UpperCase` | Converts to uppercase (Unicode). |
| `ASCIIUpperCase(s)` | - | Converts to uppercase (ASCII only). |
| `Trim(s)` | `.Trim` | Removes whitespace from both ends. |
| `Trim(s, L, R)` | `.Trim(L, R)` | Removes `L` chars from left and `R` from right. |
| `TrimLeft(s) / TrimRight(s)`| `.TrimLeft / .TrimRight`| Removes whitespace from one end. |
| `PadLeft(s, len [, ch])` | `.PadLeft(len [, ch])` | Pads string to `len` with character `ch`. |
| `PadRight(s, len [, ch])` | `.PadRight(len [, ch])` | Pads string to `len` with character `ch`. |
| `StrReplace(s, old, new)` | `.Replace(old, new)` | Replaces all occurrences of `old` with `new`. |
| `ReverseString(s)` | `.Reverse` | Reverses the character order. |
| `DupeString(s, count)` | `.Dupe(count)` | Returns the string repeated `count` times. |
| `NormalizeString(s)` | `.Normalize` | Normalizes Unicode string (NFC default). |
| `StripAccents(s)` | `.StripAccents` | Removes diacritics (e.g. é -> e). |
## Conversion
| Function | Method Alias | Description |
| :--- | :--- | :--- |
| `IntToHex(v, digits)` | `.ToHexString(digits)` | Integer to hexadecimal string. |
| `IntToBin(v, digits)` | `.ToBinaryString(digits)` | Integer to binary string. |
| `HexToInt(s)` | `.HexToInteger` | Hexadecimal string to integer. |
| `FloatToStr(f [, p])` | `.ToString` | Float to string (optional precision `p`). |
| `ByteSizeToStr(v)` | - | Converts a number of bytes into human-readable size (e.g. "1.5 MB"). |
| `BoolToStr(b)` | `.ToString` | Boolean to "True" or "False". |
| `StrToBool(s)` | `.ToBoolean` | String to boolean. |
## Encoding and Escaping
| Function | Method Alias | Description |
| :--- | :--- | :--- |
| `StrToHtml(s)` | `.ToHtml` | HTML entity encoding. |
| `StrToHtmlAttribute(s)` | `.ToHtmlAttribute` | HTML attribute encoding. |
| `StrToJSON(s)` | `.ToJSON` | Escapes string for JSON/JavaScript literal. |
| `StrToCSSText(s)` | `.ToCSSText` | Escapes string for CSS content. |
| `StrToXML(s)` | `.ToXML` | XML text encoding. |
| `QuotedStr(s [, quote])` | `.QuotedString` | Wraps string in quotes (default `'`). |
| `NormalizeString(s [, form])` | `.Normalize` | Unicode normalization (NFC, NFD, etc). |
| `StrIsASCII(s)` | `.IsASCII` | Returns True if all characters in the string are ASCII (0..127). |
## Advanced Transformations
```pascal
// Specialized Trimming
var s := "[[[Hello]]]";
PrintLn('Trim(3, 3): ' + s.Trim(3, 3));
// Array Packing (on dynamic array)
var arr : array of String = ['A', '', 'B', ' ', 'C'];
var packed := arr.Pack();
PrintLn('Packed: ' + packed.Join(', '));
// Unicode Normalization
var accented := 'e'#$0301; // e + combining acute accent
PrintLn('Length pre-normalize: ' + accented.Length.ToString);
var normalized := accented.Normalize();
PrintLn('Length post-normalize: ' + normalized.Length.ToString);
```
**Output:**
```text
Trim(3, 3): Hello
Packed: A, B, , C
Length pre-normalize: 2
Length post-normalize: 1
```
---
Source: ref/system.md
---
title: System Unit
description: Fundamental classes and compiler primitives.
id: ref/system
---
# System Unit
The `System` unit is automatically included in every DWScript program. It defines the fundamental types, base classes, and global functions of the language.
## Core Classes
### TObject
The ultimate ancestor of all classes in DWScript.
| Member | Kind | Description |
| :--- | :--- | :--- |
| `Create` | Constructor | Standard constructor. |
| `Destroy` | Destructor | Virtual destructor. |
| `Free` | Procedure | Safely calls `Destroy`. |
| `ClassName` | Function | Returns the name of the object's class as a string. |
| `ClassType` | Function | Returns the metaclass (TClass) of the object. |
| `ClassParent` | Function | Returns the metaclass of the parent class. |
### Exception
Base class for all error handling.
| Member | Description |
| :--- | :--- |
| `Create(msg)` | Constructor with error message. |
| `Message` | Property containing the error description. |
| `StackTrace` | Property containing the call stack at the point of failure. |
## Global Functions
| Function | Description |
| :--- | :--- |
| `Print(v)` | Outputs a value to the current result stream. |
| `PrintLn(v)` | Outputs a value followed by a newline. |
| `Swap(var a, b)` | Swaps the values of two variables of the same type. |
| `SetLength(var v, len)` | Resizes a dynamic array or string. |
| `Inc(var x [, n])` | Increments a variable (Integer or Float). |
| `Dec(var x [, n])` | Decrements a variable. |
| `Assigned(v)` | Returns True if an object, interface, or procedure variable is not nil. |
| `ExceptObject` | Returns the current exception object in an `except` block. |
| `ParamCount` | Returns the number of command-line parameters. |
| `ParamStr(i)` | Returns a specific command-line parameter. |
## Examples
### Object Inspection
```pascal
var obj := new TObject;
PrintLn(obj.ClassName); // TObject
obj.Free;
```
**Output:**
```text
TObject
```
### Exception Handling
```pascal
try
raise new Exception('An error occurred');
except
on E: Exception do
PrintLn(E.Message);
end;
```
**Output:**
```text
An error occurred
```
### Swapping Variables
```pascal
var a := 10;
var b := 20;
Swap(a, b);
PrintLn(Format('a=%d, b=%d', [a, b]));
```
**Output:**
```text
a=20, b=10
```
```
---
Source: ref/systeminfo.md
# System Information
The `System.Info` unit provides a set of static classes and records to query the execution environment, hardware specifications, and system performance.
## ApplicationInfo
Provides details about the running application and its environment.
| Member | Type | Description |
| :--- | :--- | :--- |
| `Version` | String | Application version string. |
| `ExeName` | String | Full path to the current executable. |
| `UserName` | String | Name of the current user. |
| `RunningAsService` | Boolean | True if the process is running as a Windows service. |
| `IsDebuggerPresent` | Boolean | True if a debugger is attached. |
| `ExeLinkTimeStamp` | Integer | Unix timestamp of the executable link time. |
| `CurrentDirectory` | String | Read/set the current working directory. |
| `EnvironmentVariable[name]` | String | Read/set environment variables. |
| `MemoryCounters()` | Record | Returns a `ProcessMemoryCounters` record. |
### ProcessMemoryCounters Record
| Field | Type | Description |
| :--- | :--- | :--- |
| `WorkingSetSize` | Integer | Memory currently used by the process. |
| `PeakWorkingSetSize` | Integer | Peak memory used by the process. |
| `PagefileUsage` | Integer | Page file space used by the process. |
| `PeakPagefileUsage` | Integer | Peak page file space used by the process. |
## CPUInfo
Hardware and CPU usage information.
| Member | Type | Description |
| :--- | :--- | :--- |
| `Name` | String | CPU model name. |
| `Count` | Integer | Number of logical processors. |
| `FrequencyMHz` | Integer | CPU frequency in MHz. |
| `SystemUsage` | Float | Global CPU usage percentage (0..100). |
| `KernelUsage` | Float | Global kernel-mode CPU usage percentage. |
| `ProcessUsage` | Float | CPU usage percentage for the current process. |
## MemoryStatus
Query system memory usage. Must be instantiated via `new MemoryStatus`.
| Property | Type | Description |
| :--- | :--- | :--- |
| `Physical` | Record | Total and available physical RAM (`MemoryStatusDetail`). |
| `Virtual` | Record | Total and available virtual memory. |
| `PageFile` | Record | Total and available page file space. |
### MemoryStatusDetail Record
| Field | Type | Description |
| :--- | :--- | :--- |
| `Total` | Integer | Total capacity in bytes. |
| `Available` | Integer | Available capacity in bytes. |
## OSVersionInfo
Operating system details.
| Member | Type | Description |
| :--- | :--- | :--- |
| `Name` | String | OS product name (e.g. "Windows 11 Pro"). |
| `Version` | String | OS version string (e.g. "10.0.22631"). |
## HostInfo
Network and host-level information.
| Member | Type | Description |
| :--- | :--- | :--- |
| `Name` | String | NetBIOS name of the machine. |
| `DNSName` | String | DNS hostname. |
| `DNSDomain` | String | DNS domain name. |
| `DNSFullyQualified` | String | Fully qualified DNS name. |
| `Uptime` | Float | System uptime in days. |
| `SystemTime` | Float | Total user-mode time across all processors. |
| `KernelTime` | Float | Total kernel-mode time across all processors. |
| `DomainControllerInfo()` | Record | Returns a `DomainControllerInfo` record. |
### DomainControllerInfo Record
| Field | Type | Description |
| :--- | :--- | :--- |
| `DCName` | String | Name of the domain controller. |
| `DCAddress` | String | Network address of the domain controller. |
| `DCAddressType` | Integer | Type of the DC address (e.g. IPv4). |
| `GUID` | String | GUID of the domain controller. |
| `Name` | String | Name of the domain. |
| `ForestName` | String | Name of the forest. |
| `DCSiteName` | String | Name of the DC site. |
| `ClientSiteName` | String | Name of the client site. |
| `Flags` | Integer | Status and capability flags. |
## PerformanceCounter
High-resolution timer for performance profiling.
| Member | Type | Description |
| :--- | :--- | :--- |
| `Create()` | Constructor | Starts a new counter. |
| `Restart()` | Procedure | Resets the counter to zero and starts it. |
| `Stop()` | Procedure | Stops the counter. |
| `Elapsed()` | Float | Seconds elapsed since start/restart. |
| `Running()` | Boolean | True if the counter is currently running. |
| `Now()` | Static Float | Current raw performance counter value in seconds. |
| `Frequency` | Constant | Frequency of the performance counter (ticks per second). |
## ThreadInfo
Information about the current execution thread.
| Member | Type | Description |
| :--- | :--- | :--- |
| `ID` | Integer | Current thread ID. |
| `Priority` | Integer | Thread priority level. |
| `IsDebugging` | Boolean | True if the script is currently being debugged. |
## Global Functions
| Function | Result | Description |
| :--- | :--- | :--- |
| `SystemMilliseconds` | Integer | Number of milliseconds since the system started. |
## Examples
### Checking Environment
```pascal
// NO_RUN
PrintLn('User: ' + ApplicationInfo.UserName);
PrintLn('OS: ' + OSVersionInfo.Name);
PrintLn('CPU: ' + CPUInfo.Name + ' (' + IntToStr(CPUInfo.Count) + ' cores)');
var mem := new MemoryStatus;
PrintLn('Free RAM: ' + IntToStr(mem.Physical.Available div (1024*1024)) + ' MiB');
```
### Performance Profiling
```pascal
var pc := new PerformanceCounter;
// ... some heavy work ...
pc.Stop;
PrintLn(Format('Work took %.3f ms', [pc.Elapsed * 1000]));
```
**Output:**
```text
Work took 0.002 ms
```
---
Source: ref/tabular.md
---
title: Tabular Data
description: High-performance column-oriented data analysis.
id: ref/tabular
---
# Tabular Data
The `TabularData` class (from `System.Data.Tabular`) provides high-performance, memory-efficient handling of large column-oriented datasets.
## TabularData Class
| Method | Description |
| :--- | :--- |
| `CreateFromDataSet(ds [, opts])` | Initializes from a database `DataSet`. |
| `EvaluateNewColumn(name, rpn_expr)` | Adds a calculated column using an RPN expression array. |
| `EvaluateAggregate(op, rpn_expr)` | Calculates a scalar value (currently supports only `sum`). |
| `LockAndShare(name)` | Makes the dataset globally available in shared memory. |
| `ConnectToShared(name)` | Connects to an existing shared dataset. |
| `ExportToSeparated(sep)` | Exports data to a delimited string (CSV). |
## RPN Expression Reference
The `EvaluateNewColumn` and `EvaluateAggregate` methods use an array of strings/variants representing an RPN expression. These are JIT-compiled for maximum performance.
### Field and Constant Access
| Syntax | Description |
| :--- | :--- |
| `'"ColumnName"'` | Pushes the value of the specified column onto the stack. |
| `'"ColumnName" DefValue'` | Pushes column value, using `DefValue` (float) if the cell is null. |
| `'"Col" Def {"K":V, ...}'` | Pushes a mapped value based on a JSON lookup table. |
| `123.45` | Pushes a literal numeric constant onto the stack. |
### Arithmetic and Comparison
| Opcode | Operation |
| :--- | :--- |
| `+`, `-`, `*`, `/` | Standard binary arithmetic operations. |
| `=`, `>=`, `<>` | Comparison operators (returns 1.0 for True, 0.0 for False). |
### Mathematical Functions
| Opcode | Description |
| :--- | :--- |
| `abs` | Absolute value. |
| `sqr`, `sqrt` | Square and square root. |
| `exp`, `ln` | Exponential and natural logarithm. |
| `min`, `max` | Pops two values and pushes the minimum or maximum (row-wise). |
| `relu` | Rectified Linear Unit: fused binary operator `max(0, a + b)`. |
| `smape` | Symmetric Mean Absolute Percentage Error component. |
### Rounding and Stack
| Opcode | Description |
| :--- | :--- |
| `round` | Rounds to the nearest integer. |
| `floor`, `ceil` | Floor and ceiling functions. |
| `dup` | Duplicates the top value on the stack. |
| `dup0`..`dup9` | Duplicates the value at the specified stack depth. |
## Example: Normalization
```pascal
uses System.Data, System.Data.Tabular;
var data := TabularData.Create;
data.AddColumn('Signal', [0.5, 1.2, 3.4, 2.1, 0.8]);
// Pre-calculate constants (min/max aggregates not supported in current binary)
var sMin := 0.5;
var sMax := 3.4;
var sRange := sMax - sMin;
// JIT expression: (Signal - Min) / Range
data.EvaluateNewColumn('Normalized', [ '"Signal"', sMin, '-', sRange, '/' ]);
// Aggregate sum
var total := data.EvaluateAggregate('sum', [ '"Normalized"' ]);
PrintLn('Total Normalized Sum: ' + FloatToStr(total));
```
**Output:**
```text
Total Normalized Sum: 1.89655172413793
```
:::info
### Performance Features
* **JIT Compilation:** Expressions in `EvaluateNewColumn` and `EvaluateAggregate` are JIT-compiled for native execution speed.
* **Memory Efficiency:** Data is stored in a column-oriented format, reducing overhead and improving cache locality.
* **Zero-Copy Sharing:** `ConnectToShared` provides access to global datasets without duplicating memory.
:::
---
Source: ref/variants.md
---
title: Variant Functions
description: Dynamic typing and JSONVariant details.
id: ref/variants
---
# Variant Functions Reference
Functions for working with the dynamic `Variant` type, which can hold data of any other type.
| Function | Parameters | Description |
| :--- | :--- | :--- |
| `VarClear` | `var v` | Clears variant and sets it to Unassigned. |
| `VarIsNull` | `v` | True if variant is Null. |
| `VarIsEmpty` | `v` | True if variant is Unassigned. |
| `VarIsClear` | `v` | True if variant is Null or Unassigned. |
| `VarIsArray` | `v` | True if variant contains an array. |
| `VarIsStr` | `v` | True if variant contains a string. |
| `VarIsNumeric` | `v` | True if variant contains a number. |
| `VarType` | `v` | Returns the internal type code of the variant. |
| `VarAsType` | `v, type` | Converts variant to a specific type. |
| `VarToStr` | `v` | Converts variant to string (handles Null/Unassigned safely). |
| `VarToIntDef` | `v, def` | Converts to integer or returns default. |
| `VarToFloatDef` | `v, def` | Converts to float or returns default. |
---
Source: ref/web.md
# Web & Network Reference
Documentation for the web and networking capabilities of DWScript is split into two primary units:
## [System.Net Reference](/ref/net)
The **System.Net** unit provides core networking and web transaction objects:
* **HttpQuery**: Client-side outbound HTTP requests.
* **WebRequest / WebResponse**: Inbound HTTP transaction handling.
* **Server-Sent Events**: Real-time server-to-client updates.
## [System.WebServer Reference](/ref/webserver)
The **System.WebServer** unit provides control over the server environment itself:
* **WebServer**: Global server control and configuration.
* **URL Rewriting**: Rules for transparent URL mapping.
* **Server Diagnostics**: Compilation info and program status.
---
Source: ref/webserver.md
# Web Server Control
The `System.WebServer` unit provides global control over the web server hosting the scripts. It is typically used in the server startup script (`.startup.pas`).
## WebServer Object
The `WebServer` object allows controlling global server settings, such as URL rewriting.
| Member | Description |
| :--- | :--- |
| `SetURLRewriteRulesJSON(json)` | Configures URL rewriting rules using a JSON string. |
| `GetURLRewriteRulesJSON()` | Returns the current rewrite rules as a JSON string. |
| `CompiledPrograms()` | Returns a list of all scripts currently compiled in memory. |
| `CompilationInfoJSON(fileName)` | Returns compilation details for a specific script. |
## URL Rewriting
You can define rules to transparently rewrite incoming URLs. This is typically done in the server startup script (`.startup.pas`).
### Rule Format (JSON)
The configuration is an array of rule objects:
* `pattern`: The URL pattern to match. Supports `*` as a wildcard (matches until the next separator in the pattern).
* `rewrite`: The target URL. Supports `$1`, `$2`, ... placeholders corresponding to the `*` wildcards.
### Example
```pascal
// NO_RUN
uses System.WebServer;
WebServer.SetURLRewriteRulesJSON(#'[
{ "pattern": "/lang/*", "rewrite": "/doc.dws?id=lang/$1" },
{ "pattern": "/example/*", "rewrite": "/examples/view.dws?example=$1" },
{ "pattern": "/ref/*", "rewrite": "/ref/index.dws?id=ref/$1" }
]');
```
---
# Examples Compendium
## Example: Sieve of Eratosthenes
Efficiently finds all prime numbers up to a given limit. This example demonstrates basic loop structures, dynamic Boolean arrays, and optimized arithmetic for a classic algorithmic problem.
### Source Code
```pascal
// Sieve of Eratosthenes: Efficiently finds all prime numbers up to a given limit. This example demonstrates basic loop structures, dynamic Boolean arrays, and optimized arithmetic for a classic algorithmic problem.
procedure Sieve(limit : Integer);
var isPrime : array of Boolean;
begin
isPrime.SetLength(limit + 1);
for var i := 2 to limit do begin
if isPrime[i] then continue;
var j := i * i;
while j <= limit do begin
isPrime[j] := True;
j += i;
end;
end;
var count := 0;
for var i := 2 to limit do if not isPrime[i] then begin
Print(IntToStr(i) + ' ');
Inc(count);
end;
PrintLn('');
PrintLn('Total primes: ' + IntToStr(count));
end;
Sieve(50);
```
### Output
```text
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47
Total primes: 15
```
---
## Example: Integer Factorization
Illustrates basic arithmetic and control flow for prime factorization. This example demonstrates nested 'while' loops, the 'mod' operator for divisibility checks, and string building via the '+=' operator to format mathematical results.
### Source Code
```pascal
// Integer Factorization: Illustrates basic arithmetic and control flow for prime factorization. This example demonstrates nested 'while' loops, the 'mod' operator for divisibility checks, and string building via the '+=' operator to format mathematical results.
function Factorize(n : Integer) : String;
begin
if n <= 1 then Exit(IntToStr(n));
var k := 2;
var first := True;
while n >= k do begin
while (n mod k) = 0 do begin
if not first then Result += ' * ';
Result += IntToStr(k);
n := n div k;
first := False;
end;
Inc(k);
end;
end;
for var i := 2 to 10 do PrintLn(IntToStr(i) + ' = ' + Factorize(i));
```
### Output
```text
2 = 2
3 = 3
4 = 2 * 2
5 = 5
6 = 2 * 3
7 = 7
8 = 2 * 2 * 2
9 = 3 * 3
10 = 2 * 5
```
---
## Example: Towers of Hanoi
Classic recursive puzzle solution. This example demonstrates recursive function calls and string concatenation in DWScript to solve the Towers of Hanoi problem.
### Source Code
```pascal
// Towers of Hanoi: Classic recursive puzzle solution. This example demonstrates recursive function calls and string concatenation in DWScript to solve the Towers of Hanoi problem.
procedure Move(n: Integer; fromPeg, toPeg, auxPeg: String);
begin
if n = 1 then begin
PrintLn('Move disk 1 from ' + fromPeg + ' to ' + toPeg);
end else begin
Move(n - 1, fromPeg, auxPeg, toPeg);
PrintLn('Move disk ' + IntToStr(n) + ' from ' + fromPeg + ' to ' + toPeg);
Move(n - 1, auxPeg, toPeg, fromPeg);
end;
end;
PrintLn('Towers of Hanoi (3 Disks)');
PrintLn('-------------------------');
Move(3, 'A', 'C', 'B');
```
### Output
```text
Towers of Hanoi (3 Disks)
-------------------------
Move disk 1 from A to C
Move disk 2 from A to B
Move disk 1 from C to B
Move disk 3 from A to C
Move disk 1 from B to A
Move disk 2 from B to C
Move disk 1 from A to C
```
---
## Example: Levenshtein Distance
Showcases multidimensional arrays and string metric calculations. This example demonstrates the allocation of a 2D integer array ('new Integer[slen + 1, tlen + 1]') and the use of 'MinInt' for dynamic programming calculations.
### Source Code
```pascal
// Levenshtein Distance: Showcases multidimensional arrays and string metric calculations. This example demonstrates the allocation of a 2D integer array ('new Integer[slen + 1, tlen + 1]') and the use of 'MinInt' for dynamic programming calculations.
function LevenshteinDistance(s, t : String) : Integer;
begin
var slen := Length(s);
var tlen := Length(t);
var d := new Integer[slen + 1, tlen + 1];
for var i := 0 to slen do d[i, 0] := i;
for var j := 0 to tlen do d[0, j] := j;
for var j := 1 to tlen do begin
for var i := 1 to slen do begin
if s[i] = t[j] then
d[i, j] := d[i-1, j-1]
else begin
d[i, j] := MinInt(
MinInt(d[i-1, j] + 1, d[i, j-1] + 1),
d[i-1, j-1] + 1
);
end;
end;
end;
Result := d[slen, tlen];
end;
PrintLn('Distance between "kitten" and "sitting": ' + IntToStr(LevenshteinDistance('kitten', 'sitting')));
```
### Output
```text
Distance between "kitten" and "sitting": 3
```
---
## Example: Maze Generation
Demonstrates recursive backtracking and complex array manipulation. This example showcases using an array of records as a manual stack, the 'RandomInt' function for stochastic pathfinding, and custom 'step' increments in 'for' loops for grid rendering.
### Source Code
```pascal
// Maze Generation: Demonstrates recursive backtracking and complex array manipulation. This example showcases using an array of records as a manual stack, the 'RandomInt' function for stochastic pathfinding, and custom 'step' increments in 'for' loops for grid rendering.
SetRandSeed(42);
procedure MakeMaze(size : Integer);
require
size >= 1;
begin
var cells : array of Boolean;
type TMovement = record
Start : Integer;
Direction : Integer;
end;
var stack : array of TMovement;
var m : TMovement;
var n := 2*size + 1;
cells.SetLength(Sqr(2*size + 1));
var toVisit := size*size;
var x := RandomInt(size);
var y := RandomInt(size);
var p := (1 + 2*x) + (1 + 2*y) * n;
while True do begin
x := (p mod n) div 2;
y := (p div n) div 2;
cells[p] := True;
toVisit -= 1;
if toVisit = 0 then break;
var directions : array of Integer = [];
if (x > 0) and not cells[p-2] then
directions.Add(-2);
if (y > 0) and not cells[p-2*n] then
directions.Add(-2*n);
if (x < size-1) and not cells[p+2] then
directions.Add(2);
if (y < size-1) and not cells[p+2*n] then
directions.Add(2*n);
// Shuffle directions
for var i := directions.High downto 1 do
directions.Swap(i, RandomInt(i+1));
for var dir in directions do begin
m.Start := p;
m.Direction := dir;
stack.Add(m); // Use Add instead of Push for standard dynamic array
end;
var found := False;
while stack.Length > 0 do begin
m := stack[stack.High]; // Peek
stack.SetLength(stack.Length - 1); // Pop
p := m.Start;
if not cells[p + m.Direction] then begin
cells[p + m.Direction div 2] := True;
p += m.Direction;
found := True;
break;
end;
end;
if not found then break;
end;
PrintLn('Maze ' + IntToStr(size) + 'x' + IntToStr(size) + ':');
for var i := 0 to cells.High step n do begin
for var j := 0 to n-1 do
if cells[i+j] then
Print(' ')
else Print('##');
PrintLn('');
end;
end;
MakeMaze(10);
```
### Output
```text
Maze 10x10:
##########################################
## ## ##
###### ########################## ## ##
## ## ## ## ## ## ##
## ## ## ###### ###### ## ## ## ##
## ## ## ## ## ## ## ##
########## ########## ## ###### ## ##
## ## ## ## ## ## ##
## ## ###### ###### ###### ## ## ##
## ## ## ## ## ## ##
## ###### ###### ###### ########## ##
## ## ## ## ##
###### ###### ############## ## ## ##
## ## ## ## ## ##
## ###### ###### ## ############## ##
## ## ## ## ## ## ## ##
## ## ## ## ## ## ## ## ## ######
## ## ## ## ## ## ## ## ## ##
## ## ## ## ## ###### ## ###### ##
## ## ## ## ##
##########################################
```
---
## Example: Sorting Algorithms
Implementation of Bubble Sort and Quick Sort. This example demonstrates procedural programming patterns, recursive subroutines, and the performance differences between O(n^2) and O(n log n) algorithms in DWScript.
### Source Code
```pascal
0 then Print(', ');
Print(IntToStr(arr[i]));
end;
PrintLn(']');
end;
// --- Bubble Sort ---
// Simple but inefficient: O(n^2)
procedure BubbleSort(const data: array of Integer);
var
i, j, temp: Integer;
n: Integer;
begin
n := Length(data);
for i := 0 to n - 2 do
for j := 0 to n - i - 2 do
if data[j] > data[j + 1] then begin
// Swap
temp := data[j];
data[j] := data[j + 1];
data[j + 1] := temp;
end;
end;
// --- Quick Sort ---
// Efficient divide and conquer: O(n log n)
procedure QuickSort_Internal(const data: array of Integer; L, R: Integer);
var
i, j, pivot, temp: Integer;
begin
i := L;
j := R;
pivot := data[(L + R) div 2];
repeat
while data[i] < pivot do Inc(i);
while data[j] > pivot do Dec(j);
if i <= j then begin
temp := data[i];
data[i] := data[j];
data[j] := temp;
Inc(i);
Dec(j);
end;
until i > j;
if L < j then QuickSort_Internal(data, L, j);
if i < R then QuickSort_Internal(data, i, R);
end;
procedure QuickSort(const data: array of Integer);
begin
if Length(data) > 0 then
QuickSort_Internal(data, 0, High(data));
end;
// --- Main Execution ---
var data1 := [64, 34, 25, 12, 22, 11, 90];
var data2: array of Integer;
// Clone data for second test
data2.SetLength(Length(data1));
for var i := 0 to High(data1) do data2[i] := data1[i];
PrintLn('
Original: [64, 34, 25, 12, 22, 11, 90]
Sorted: [11, 12, 22, 25, 34, 64, 90]
```
---
## Example: Dynamic Arrays
Demonstrates sophisticated management of dynamic arrays containing records. This example showcases custom sorting logic using lambda comparators, array removal operations, and extracting subsets using slicing techniques for task management scenarios.
### Source Code
```pascal
// Dynamic Arrays: Demonstrates sophisticated management of dynamic arrays containing records. This example showcases custom sorting logic using lambda comparators, array removal operations, and extracting subsets using slicing techniques for task management scenarios.
type
TTask = record
ID: Integer;
Name: String;
Priority: Integer;
end;
var tasks: array of TTask;
procedure AddTask(id: Integer; name: String; priority: Integer);
begin
var t: TTask;
t.ID := id; t.Name := name; t.Priority := priority;
tasks.Add(t);
end;
// Populate list
AddTask(1, 'Fix Compiler Bug', 10);
AddTask(2, 'Update Documentation', 5);
AddTask(3, 'Release Version 1.0', 20);
AddTask(4, 'Refactor Parser', 8);
PrintLn('Initial Tasks:');
for var t in tasks do
PrintLn(Format(
' #%d: %-20s (Priority: %d)',
[ t.ID, t.Name, t.Priority ]
));
// Sort by Priority (High to Low) using lambda
tasks.Sort(lambda (a, b) => b.Priority - a.Priority);
PrintLn(#13#10 + 'Tasks Sorted by Priority:');
for var t in tasks do
PrintLn(Format(
' #%d: %-20s (Priority: %d)',
[ t.ID, t.Name, t.Priority ]
));
// Find and remove a specific task
var indexToRemove := -1;
for var i := 0 to tasks.High do
if tasks[i].ID = 2 then begin
indexToRemove := i;
break;
end;
if indexToRemove >= 0 then begin
PrintLn(#13#10 + 'Removing task: ' + tasks[indexToRemove].Name);
tasks.Delete(indexToRemove);
end;
// Slicing: Get the top 2 urgent tasks
var urgent := tasks.Copy(0, 2);
PrintLn(#13#10 + 'Top 2 Urgent Tasks:');
PrintLn(JSON.Stringify(urgent));
```
### Output
```text
Initial Tasks:
#1: Fix Compiler Bug (Priority: 10)
#2: Update Documentation (Priority: 5)
#3: Release Version 1.0 (Priority: 20)
#4: Refactor Parser (Priority: 8)
Tasks Sorted by Priority:
#3: Release Version 1.0 (Priority: 20)
#1: Fix Compiler Bug (Priority: 10)
#4: Refactor Parser (Priority: 8)
#2: Update Documentation (Priority: 5)
Removing task: Update Documentation
Top 2 Urgent Tasks:
[{},{}]
```
---
## Example: Functional Arrays
Showcases modern functional programming methods on dynamic arrays. This example demonstrates using 'Filter' with lambdas, 'Map' with anonymous functions, and 'Foreach' for concise collection processing and transformations.
### Source Code
```pascal
// Functional Arrays: Showcases modern functional programming methods on dynamic arrays. This example demonstrates using 'Filter' with lambdas, 'Map' with anonymous functions, and 'Foreach' for concise collection processing and transformations.
var data: array of Integer = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// Filter: keep only even numbers using lambda syntax
var evens := data.Filter(lambda (n) => n mod 2 = 0);
PrintLn('Evens: ' + evens.Map(IntToStr).Join(', '));
// Map: square the numbers
var squares := evens.Map(function (n: Integer): Integer
begin
Result := n * n;
end);
PrintLn('Squares of evens: ' + squares.Map(IntToStr).Join(', '));
// Foreach: iterate with a procedure
Print('Iterating squares: ');
squares.Foreach(procedure (n: Integer)
begin
Print(IntToStr(n) + ' ');
end);
PrintLn('');
// Contains and IndexOf
if data.Contains(7) then
PrintLn('Data contains 7 at index ' + IntToStr(data.IndexOf(7)));
```
### Output
```text
Evens: 2, 4, 6, 8, 10
Squares of evens: 4, 16, 36, 64, 100
Iterating squares: 4 16 36 64 100
Data contains 7 at index 6
```
---
## Example: Multidimensional Arrays
Demonstrates the creation and management of nested dynamic arrays (jagged arrays). This example illustrates initializing a matrix, nested 'SetLength' calls, and iterating through high-dimensional data structures.
### Source Code
```pascal
// Multidimensional Arrays: Demonstrates the creation and management of nested dynamic arrays (jagged arrays). This example illustrates initializing a matrix, nested 'SetLength' calls, and iterating through high-dimensional data structures.
var matrix: array of array of Integer;
// Initialize a 3x3 identity matrix
matrix.SetLength(3);
for var i := 0 to 2 do begin
matrix[i].SetLength(3);
for var j := 0 to 2 do begin
if i = j then
matrix[i][j] := 1
else
matrix[i][j] := 0;
end;
end;
// Print the matrix
PrintLn('Identity Matrix:');
for var i := 0 to High(matrix) do begin
var row: array of String;
for var j := 0 to High(matrix[i]) do
row.Add(IntToStr(matrix[i][j]));
PrintLn('[ ' + row.Join(' ') + ' ]');
end;
// Accessing elements
PrintLn('Element at (1,1): ' + IntToStr(matrix[1][1]));
```
### Output
```text
Identity Matrix:
[ 1 0 0 ]
[ 1 0 0 0 1 0 ]
[ 1 0 0 0 1 0 0 0 1 ]
Element at (1,1): 1
```
---
## Example: Array Slicing
Explores subset extraction and array management using the 'Copy' method. This example highlights how to efficiently slice dynamic arrays into smaller segments by specifying starting indices and counts.
### Source Code
```pascal
// Array Slicing: Explores subset extraction and array management using the 'Copy' method. This example highlights how to efficiently slice dynamic arrays into smaller segments by specifying starting indices and counts.
var alphabet: array of String = ['A', 'B', 'C', 'D', 'E', 'F', 'G'];
PrintLn('Full: ' + alphabet.Join(' '));
// Extract a range (slice)
// Note: Range syntax might vary, let's use the Copy function or manual loop if needed,
// but DWScript supports slicing in some contexts. Let's check a standard way.
// Actually, DWScript supports array[start..end] syntax.
var slice := alphabet.Copy(1, 4); // Index 1, count 4
PrintLn('Slice (1, 4): ' + slice.Join(' '));
var fromStart := alphabet.Copy(0, 3); // Indices 0, 1, 2
PrintLn('Slice (0, 3): ' + fromStart.Join(' '));
var toEnd := alphabet.Copy(5, alphabet.Length - 5); // Indices 5 to end
PrintLn('Slice (5, end): ' + toEnd.Join(' '));
```
### Output
```text
Full: A B C D E F G
Slice (1, 4): B C D E
Slice (0, 3): A B C
Slice (5, end): F G
```
---
## Example: Array Sorting
Demonstrates built-in sorting and transformation methods for dynamic arrays. It showcases the 'Sort' method for both integers and strings, the 'Reverse' method, and integration with JSON serialization for debugging.
### Source Code
```pascal
// Array Sorting: Demonstrates built-in sorting and transformation methods for dynamic arrays. It showcases the 'Sort' method for both integers and strings, the 'Reverse' method, and integration with JSON serialization for debugging.
var numbers: array of Integer = [5, 2, 9, 1, 5, 6];
PrintLn('Original: ' + numbers.Map(IntToStr).Join(', '));
// Standard sort
numbers.Sort;
PrintLn('Sorted (JSON): ' + JSON.Stringify(numbers));
// Reverse
numbers.Reverse;
PrintLn('Reversed: ' + numbers.Map(IntToStr).Join(', '));
// Natural sort for strings
var files: array of String = ['file10.txt', 'file2.txt', 'file1.txt', 'file20.txt'];
PrintLn('Strings Original: ' + files.Join(', '));
files.Sort;
PrintLn('Strings Standard Sort: ' + files.Join(', '));
```
### Output
```text
Original: 5, 2, 9, 1, 5, 6
Sorted (JSON): [1,2,5,5,6,9]
Reversed: 9, 6, 5, 5, 2, 1
Strings Original: file10.txt, file2.txt, file1.txt, file20.txt
Strings Standard Sort: file1.txt, file10.txt, file2.txt, file20.txt
```
---
## Example: Stacks & Queues
Illustrates implementing common data structures using dynamic arrays. This example demonstrates LIFO (Stack) patterns using 'High' and 'Delete', and FIFO (Queue) patterns by adding elements and deleting from index 0.
### Source Code
```pascal
// Stacks & Queues: Illustrates implementing common data structures using dynamic arrays. This example demonstrates LIFO (Stack) patterns using 'High' and 'Delete', and FIFO (Queue) patterns by adding elements and deleting from index 0.
// Stack (Last-In, First-Out)
var stack: array of String;
PrintLn('--- Stack ---');
stack.Add('First');
stack.Add('Second');
stack.Add('Third');
while stack.Length > 0 do begin
var top := stack[High(stack)];
PrintLn('Popping: ' + top);
stack.Delete(High(stack));
end;
// Queue (First-In, First-Out)
var queue: array of String;
PrintLn('--- Queue ---');
queue.Add('Patient A');
queue.Add('Patient B');
queue.Add('Patient C');
while queue.Length > 0 do begin
var front := queue[0];
PrintLn('Serving: ' + front);
queue.Delete(0);
end;
```
### Output
```text
--- Stack ---
Popping: Third
Popping: Second
Popping: First
--- Queue ---
Serving: Patient A
Serving: Patient B
Serving: Patient C
```
---
## Example: Array Statistics
Demonstrates numerical processing and JSON integration. This example shows how to perform aggregate calculations (sum, mean, variance) on numerical arrays and bundle the results into a 'JSONVariant' object for structured reporting.
### Source Code
```pascal
// Array Statistics: Demonstrates numerical processing and JSON integration. This example shows how to perform aggregate calculations (sum, mean, variance) on numerical arrays and bundle the results into a 'JSONVariant' object for structured reporting.
var data: array of Float = [10.0, 20.0, 30.0, 40.0, 50.0];
function CalculateStats(a: array of Float): JSONVariant;
begin
var sum := 0.0;
for var v in a do
sum += v;
var mean := sum / a.Length;
var varianceSum := 0.0;
for var v in a do
varianceSum += Sqr(v - mean);
var variance := varianceSum / a.Length;
Result := JSON.NewObject;
Result.Sum := sum;
Result.Mean := mean;
Result.Variance := variance;
Result.StdDev := Sqrt(variance);
end;
var stats := CalculateStats(data);
PrintLn('Data: ' + JSON.Stringify(data));
PrintLn('Sum: ' + Float(stats.Sum).ToString(2));
PrintLn('Mean: ' + Float(stats.Mean).ToString(2));
PrintLn('Variance: ' + Float(stats.Variance).ToString(2));
PrintLn('StdDev: ' + Float(stats.StdDev).ToString(2));
```
### Output
```text
Data: [10,20,30,40,50]
Sum: 150.00
Mean: 30.00
Variance: 200.00
StdDev: 14.14
```
---
## Example: Associative Arrays
Introduces associative arrays (dictionaries) in DWScript. It demonstrates the 'array [String] of T' syntax, basic key-value pair insertion, value retrieval, existence checking, and entry removal, highlighting the performance and convenience of indexed lookups.
### Source Code
```pascal
// Associative Arrays: Introduces associative arrays (dictionaries) in DWScript. It demonstrates the 'array [String] of T' syntax, basic key-value pair insertion, value retrieval, existence checking, and entry removal, highlighting the performance and convenience of indexed lookups.
var ages: array [String] of Integer;
// Assigning values
ages['Alice'] := 30;
ages['Bob'] := 25;
ages['Charlie'] := 35;
// Accessing values
PrintLn('Alice is ' + IntToStr(ages['Alice']) + ' years old.');
// Checking for existence
if 'Bob' in ages then
PrintLn('Bob is in the dictionary.');
// Count
PrintLn('Number of entries: ' + IntToStr(ages.Length));
// Removing an entry
ages.Delete('Charlie');
PrintLn('After deleting Charlie, length: ' + IntToStr(ages.Length));
```
### Output
```text
Alice is 30 years old.
Bob is in the dictionary.
Number of entries: 3
After deleting Charlie, length: 2
```
---
## Example: Complex Keys
Showcases the flexibility of associative arrays in DWScript. This example demonstrates using 'Integer' and 'Float' types as keys in addition to strings, highlighting the language's support for non-string indexing in dictionaries.
### Source Code
```pascal
// Complex Keys: Showcases the flexibility of associative arrays in DWScript. This example demonstrates using 'Integer' and 'Float' types as keys in addition to strings, highlighting the language's support for non-string indexing in dictionaries.
var idMap: array [Integer] of String;
idMap[101] := 'Product A';
idMap[202] := 'Product B';
idMap[303] := 'Product C';
PrintLn('ID 202 belongs to: ' + idMap[202]);
// Using Float as keys (be careful with precision!)
var floatMap: array [Float] of String;
floatMap[3.14] := 'Pi';
floatMap[2.71] := 'Euler';
PrintLn('3.14 is ' + floatMap[3.14]);
// Checking length
PrintLn('ID Map Length: ' + IntToStr(idMap.Length));
```
### Output
```text
ID 202 belongs to: Product B
3.14 is Pi
ID Map Length: 3
```
---
## Example: Complex Values
Demonstrates storing structured data in associative arrays. This example illustrates mapping string keys to record types, enabling the creation of efficient, type-safe directories and the manipulation of complex values stored within dictionaries.
### Source Code
```pascal
// Complex Values: Demonstrates storing structured data in associative arrays. This example illustrates mapping string keys to record types, enabling the creation of efficient, type-safe directories and the manipulation of complex values stored within dictionaries.
type
TPerson = record
Age: Integer;
City: String;
end;
var directory: array [String] of TPerson;
var p: TPerson;
p.Age := 28;
p.City := 'New York';
directory['John'] := p;
p.Age := 32;
p.City := 'London';
directory['Emma'] := p;
// Accessing fields
PrintLn('John lives in ' + directory['John'].City);
PrintLn('Emma is ' + IntToStr(directory['Emma'].Age) + ' years old.');
// Updates
var updateJohn := directory['John'];
updateJohn.City := 'San Francisco';
directory['John'] := updateJohn;
PrintLn('John moved to ' + directory['John'].City);
```
### Output
```text
John lives in New York
Emma is 32 years old.
John moved to San Francisco
```
---
## Example: Frequency Counting
Demonstrates a classic use case for associative arrays. This example showcases word frequency analysis by combining string splitting with automatic initialization of dictionary values, followed by iteration over the 'Keys' collection.
### Source Code
```pascal
// Frequency Counting: Demonstrates a classic use case for associative arrays. This example showcases word frequency analysis by combining string splitting with automatic initialization of dictionary values, followed by iteration over the 'Keys' collection.
var text := 'the quick brown fox jumps over the lazy dog';
var words := text.Split(' ');
var counts: array [String] of Integer;
for var w in words do
counts[w] := counts[w] + 1;
PrintLn('Word counts:');
for var w in counts.Keys do begin
PrintLn(' ' + w + ': ' + IntToStr(counts[w]));
end;
```
### Output
```text
Word counts:
over: 1
jumps: 1
dog: 1
quick: 1
lazy: 1
brown: 1
the: 2
fox: 1
```
---
## Example: Data Grouping
Showcases advanced nesting of collection types. This example demonstrates how to group records into categories using an associative array where each value is itself a dynamic array, illustrating DWScript's support for complex, nested data structures.
### Source Code
```pascal
// Data Grouping: Showcases advanced nesting of collection types. This example demonstrates how to group records into categories using an associative array where each value is itself a dynamic array, illustrating DWScript's support for complex, nested data structures.
type
TStudent = record
Name: String;
Grade: String;
end;
var students: array of TStudent;
procedure AddStudent(name, grade: String);
var s: TStudent;
begin
s.Name := name; s.Grade := grade;
students.Add(s);
end;
AddStudent('Alice', 'A');
AddStudent('Bob', 'B');
AddStudent('Charlie', 'A');
AddStudent('David', 'C');
AddStudent('Eve', 'B');
// Group students by grade
var groups: array [String] of array of String;
for var s in students do begin
groups[s.Grade].Add(s.Name);
end;
PrintLn('Students by Grade:');
for var g in groups.Keys do begin
PrintLn('Grade ' + g + ': ' + groups[g].Join(', '));
end;
```
### Output
```text
Students by Grade:
Grade C: David
Grade A: Alice, Charlie
Grade B: Bob, Eve
```
---
## Example: Dictionary Iteration
Explores the methods for traversing associative arrays. It demonstrates using the '.Keys' property to access dictionary identifiers and performing key-based lookups during iteration to retrieve associated values.
### Source Code
```pascal
// Dictionary Iteration: Explores the methods for traversing associative arrays. It demonstrates using the '.Keys' property to access dictionary identifiers and performing key-based lookups during iteration to retrieve associated values.
var colors: array [String] of String;
colors['Red'] := '#FF0000';
colors['Green'] := '#00FF00';
colors['Blue'] := '#0000FF';
// Iterating over keys
PrintLn('Keys:');
for var k in colors.Keys do
PrintLn(' ' + k);
// Iterating over both
PrintLn('Entries:');
for var k in colors.Keys do
PrintLn(' ' + k + ' => ' + colors[k]);
```
### Output
```text
Keys:
Blue
Green
Red
Entries:
Blue => #0000FF
Green => #00FF00
Red => #FF0000
```
---
## Example: Manual Array Filtering
Illustrates foundational array manipulation techniques. This example demonstrates using the 'for-in' loop to iterate over elements and the 'Add' method to dynamically build a new collection based on a condition, serving as a base comparison for built-in functional methods.
### Source Code
```pascal
// Manual Array Filtering: Illustrates foundational array manipulation techniques. This example demonstrates using the 'for-in' loop to iterate over elements and the 'Add' method to dynamically build a new collection based on a condition, serving as a base comparison for built-in functional methods.
var numbers : array of Integer = [1, 2, 3, 4, 5];
var evens : array of Integer;
for var n in numbers do
if (n mod 2) = 0 then
evens.Add(n);
Print('Evens: ');
for var n in evens do Print(IntToStr(n) + ' ');
PrintLn('');
```
### Output
```text
Evens: 2 4
```
---
## Example: Binary Data (ByteBuffer)
Deep dive into low-level binary manipulation and memory-efficient data structures. This example showcases the 'ByteBuffer' type for granular byte-level access, illustrating how to set and get multi-byte primitives (Int32, Double, Word) with explicit endianness control, perform hex-encoded diagnostic dumps, and utilize the 'DataString' pattern for seamless binary I/O and type casting between raw memory and managed types.
### Source Code
```pascal
```
### Output
```text
Buffer length: 64
First 4 bytes as Int32: $48454C4C
Double at offset 8: 3.14159265
Word at offset 16: 2025
Hex dump (first 20 bytes):
4C 4C 45 48 00 00 00 4F F1 D4 C8 53 FB 21 09 40 E9 07 00 00
DataString length: 64
Parsed double: 3.14159265
Header Magic: $44575321
```
---
## Example: JSON Processing
Demonstrates first-class JSON support and the seamless integration between Pascal types and dynamic objects. This example showcases the 'JSON' unit's 'NewObject' and 'NewArray' constructors for programmatic building, the 'Stringify' method for serialization, and 'Parse' for transforming external data into navigable objects with native dot-notation property access.
### Source Code
```pascal
Generated JSON:');
PrintLn('
Parsed Data:
Name: DWScript
Active: Yes
First Tag: pascal
```
---
## Example: Neural Inference
Neural Network Inference & Optimization: Using 'TabularData' to find optimal weights for a Titanic survival model. This example demonstrates an automated grid search that evaluates hundreds of model variations in milliseconds to discover non-linear interactions that outperform the standard gender-only baseline.
### Source Code
```pascal
// Neural Network Inference & Optimization: Using 'TabularData' to find optimal weights for a Titanic survival model. This example demonstrates an automated grid search that evaluates hundreds of model variations in milliseconds to discover non-linear interactions that outperform the standard gender-only baseline.
uses System.Data, System.Data.Tabular;
var model := new TabularData;
// 1. Load and Parse Dataset
var csvPath := 'data/titanic.csv';
if not FileExists(csvPath) then begin
PrintLn('Error: Titanic dataset not found at ' + csvPath);
Exit;
end;
var lines := FileReadLines(csvPath);
var colSex, colPclass, colAge, colActual: array of Float;
for var i := 1 to lines.Length - 1 do begin
var line := lines[i];
if line = '' then continue;
var inQuote := False;
for var j := 1 to line.Length do begin
if line[j] = '"' then inQuote := not inQuote;
if inQuote and (line[j] = ',') then line[j] := ';';
end;
var fields := line.Split(',');
if fields.Length < 6 then continue;
colActual.Add(StrToFloatDef(fields[1], 0.0));
colSex.Add(if fields[4].Contains('female') then 0.0 else 1.0);
var pc := StrToIntDef(fields[2], 3);
colPclass.Add(if pc = 1 then 1.0 else if pc = 2 then 0.5 else 0.0);
colAge.Add(StrToFloatDef(fields[5], 28.0) / 80.0);
end;
model.AddColumn('Actual', colActual);
model.AddColumn('Sex', colSex);
model.AddColumn('PClass', colPclass);
model.AddColumn('Age', colAge);
PrintLn('
Titanic Model Optimization
');
PrintLn(Format('Searching for optimal interaction weights on %d passengers...', [colActual.Length]));
// 2. Automated Weight Search
var bestAcc := -1.0;
var bestMaleBoost := 0.0;
var bestChildBoost := 0.0;
var bestPoorFemalePenalty := 0.0;
var bestBias := 0.0;
for var i := 0 to 4 do begin
var mb := Float(i) * 3.0; // Male 1st Class boost
for var j := 0 to 4 do begin
var cb := Float(j) * 3.0; // Child boost
for var l := 0 to 4 do begin
var pfp := Float(l) * 3.0; // Poor Female Penalty
for var k := 0 to 10 do begin
var bias := Float(k) * 0.2;
model.EvaluateNewColumn('TmpProb', [
1, 1, '"Sex"', -10.0, '*', 4.0, '+', 'dup0',
'"Sex"', '"PClass"', '*', mb, '*', '+',
0.2, '"Age"', '-', 0, 'max', cb, '*', '+',
'"Sex"', 0, '=', '"PClass"', 0, '=', '*', pfp, '*', '-',
0, 'relu', '+', bias, '+',
-1, '*', 'exp', '+', '/'
]);
model.EvaluateNewColumn('TmpMatch', [ '"TmpProb"', 0.5, '>=', '"Actual"', '=' ]);
var acc := (model.EvaluateAggregate('sum', ['"TmpMatch"']) / colActual.Length) * 100;
if acc > bestAcc then begin
bestAcc := acc;
bestMaleBoost := mb;
bestChildBoost := cb;
bestPoorFemalePenalty := pfp;
bestBias := bias;
end;
model.DropColumn('TmpProb');
model.DropColumn('TmpMatch');
end;
end;
end;
end;
PrintLn(Format('Search Complete! Found optimal weights: MaleBoost=%.1f, ChildBoost=%.1f, PoorPenalty=%.1f, Bias=%.1f',
[bestMaleBoost, bestChildBoost, bestPoorFemalePenalty, bestBias]));
// 3. Evaluate Final Models
model.EvaluateNewColumn('ProbA', [
1, 1, '"Sex"', -10.0, '*', 5.0, '+', -1, '*', 'exp', '+', '/'
]);
model.EvaluateNewColumn('ProbB', [
1, 1,
'"Sex"', -10.0, '*', 4.0, '+',
'dup0',
'"Sex"', '"PClass"', '*', bestMaleBoost, '*', '+',
0.2, '"Age"', '-', 0, 'max', bestChildBoost, '*', '+',
'"Sex"', 0, '=', '"PClass"', 0, '=', '*', bestPoorFemalePenalty, '*', '-',
0, 'relu', '+', bestBias, '+',
-1, '*', 'exp', '+', '/'
]);
model.EvaluateNewColumn('MatchA', [ '"ProbA"', 0.5, '>=', '"Actual"', '=' ]);
model.EvaluateNewColumn('MatchB', [ '"ProbB"', 0.5, '>=', '"Actual"', '=' ]);
var accA := (model.EvaluateAggregate('sum', ['"MatchA"']) / colActual.Length) * 100;
var accB := (model.EvaluateAggregate('sum', ['"MatchB"']) / colActual.Length) * 100;
PrintLn('
Final Accuracy Comparison
');
PrintLn(Format('Baseline (Gender Only): %.1f%%', [accA]));
PrintLn(Format('Optimized Residual: %.1f%% (Improvement: +%.1f%%)', [accB, accB - accA]));
// 4. Sample Successes
PrintLn(' Outliers correctly identified by the Deep Model:');
var count := 0;
for var i := 0 to colActual.Length - 1 do begin
if (StrToFloat(model.ColumnStrings('MatchA')[i]) = 0.0) and (StrToFloat(model.ColumnStrings('MatchB')[i]) = 1.0) then begin
var sex := if colSex[i] = 0 then 'Female' else 'Male';
var pc := if colPclass[i] = 1 then '1st' else if colPclass[i] = 0.5 then '2nd' else '3rd';
var age := Integer(colAge[i] * 80);
PrintLn(Format('Pass #%d [%s, %s, Age %d] (Survived): Corrected by Residual Model', [i+1, sex, pc, age]));
Inc(count);
if count >= 3 then break;
end;
end;
```
### Output
```text
Titanic Model Optimization
Searching for optimal interaction weights on 891 passengers...
Search Complete! Found optimal weights: MaleBoost=9.0, ChildBoost=9.0, PoorPenalty=0.0, Bias=1.8
Final Accuracy Comparison
Baseline (Gender Only): 78.7%
Optimized Residual: 78.9% (Improvement: +0.2%)
Outliers correctly identified by the Deep Model:
Pass #306 [Male, 1st, Age 1] (Survived): Corrected by Residual Model
Pass #446 [Male, 1st, Age 4] (Survived): Corrected by Residual Model
```
---
## Example: SQLite Foundations
Illustrates the 'System.Data' abstraction layer for robust database interactions. This example demonstrates using the 'DataBase' factory for connection management (in-memory and file-based), executing schema-modifying SQL, implementing secure parameterized queries to prevent SQL injection, and leveraging high-performance result set navigation with the 'TDataSet.Step' pattern.
### Source Code
```pascal
// SQLite Foundations: Illustrates the 'System.Data' abstraction layer for robust database interactions. This example demonstrates using the 'DataBase' factory for connection management (in-memory and file-based), executing schema-modifying SQL, implementing secure parameterized queries to prevent SQL injection, and leveraging high-performance result set navigation with the 'TDataSet.Step' pattern.
uses System.Data;
// Create an in-memory SQLite database
// For a file-based DB, provide the path: DataBase.Create('SQLite', ['c:\path\to\db.sqlite'])
var db := DataBase.Create('SQLite', [':memory:']);
PrintLn('Database created.');
// Create a table
db.Exec('CREATE TABLE Users (ID INTEGER PRIMARY KEY, Name TEXT, Email TEXT)');
// Insert data using parameters (Safe against SQL Injection)
PrintLn('Inserting data...');
// Use a transaction for bulk inserts for better performance and integrity
db.BeginTransaction;
try
db.Exec('INSERT INTO Users (Name, Email) VALUES (?, ?)', ['Alice', 'alice@example.com']);
db.Exec('INSERT INTO Users (Name, Email) VALUES (?, ?)', ['Bob', 'bob@example.com']);
db.Exec('INSERT INTO Users (Name, Email) VALUES (?, ?)', ['Charlie', 'charlie@example.com']);
db.Commit;
except
db.Rollback;
PrintLn('Error inserting data!');
end;
// Query data
PrintLn('Querying data...');
var ds := db.Query('SELECT ID, Name, Email FROM Users WHERE Name LIKE ?', ['%a%']); // Names containing 'a'
// Iterate through results
// ds.Step moves to the next record and returns True if one exists.
while ds.Step do begin
PrintLn(Format(
'ID: %d, Name: %s, Email: %s',
[ ds.AsInteger(0), ds.AsString(1).ToHtml, ds.AsString(2).ToHtml ] // Indexed access avoids field lookups
));
end;
// Export as JSON
PrintLn('');
PrintLn('JSON Export (StringifyAll):');
// StringifyAll returns the entire result set as a JSON string
var json := db.Query('SELECT Name, Email FROM Users').StringifyAll;
PrintLn(json);
```
### Output
```text
Database created.
Inserting data...
Querying data...
ID: 1, Name: Alice, Email: alice@example.com
ID: 3, Name: Charlie, Email: charlie@example.com
JSON Export (StringifyAll):
[{"Name":"Alice","Email":"alice@example.com"},{"Name":"Bob","Email":"bob@example.com"},{"Name":"Charlie","Email":"charlie@example.com"}]
```
---
## Example: SQLite Bulk Operations
Showcases high-throughput data ingestion patterns by bridging managed collections and the database engine. This example highlights serializing an 'array of record' to a single JSON payload and utilizing SQLite's 'json_each' and 'json_extract' functions to perform set-based inserts, significantly reducing round-trip overhead compared to individual 'INSERT' statements.
### Source Code
```pascal
// SQLite Bulk Operations: Showcases high-throughput data ingestion patterns by bridging managed collections and the database engine. This example highlights serializing an 'array of record' to a single JSON payload and utilizing SQLite's 'json_each' and 'json_extract' functions to perform set-based inserts, significantly reducing round-trip overhead compared to individual 'INSERT' statements.
uses System.Data;
// 1. Prepare data on the script side using an array of anonymous records
var users : array of record
Name : String;
Email : String;
Level : Integer;
end;
users.SetLength(4);
users[0].Name := 'Alice'; users[0].Email := 'alice@example.com'; users[0].Level := 5;
users[1].Name := 'Bob'; users[1].Email := 'bob@example.com'; users[1].Level := 12;
users[2].Name := 'Charlie'; users[2].Email := 'charlie@example.com'; users[2].Level := 8;
users[3].Name := 'Dave'; users[3].Email := 'dave@example.com'; users[3].Level := 20;
var db := DataBase.Create('SQLite', [':memory:']);
db.Exec('CREATE TABLE Users (Name TEXT, Email TEXT, Level INTEGER)');
// 2. Convert the entire array to a single JSON string
var jsonData := JSON.Stringify(users);
PrintLn('
High-Performance Bulk Insert
');
PrintLn('
Passing ' + IntToStr(users.Length) + ' records as a single JSON parameter.
');
// 3. Execute bulk insert using a multiline raw string for SQL
db.Exec(#'
INSERT INTO Users (Name, Email, Level)
SELECT json_extract(value, "$.Name"),
json_extract(value, "$.Email"),
json_extract(value, "$.Level")
FROM json_each(?)
', [ jsonData ]
);
// Verify results - Selecting specific fields allows using efficient indexed access
var ds := db.Query(#'
SELECT Name, Email, Level
FROM Users
ORDER BY Level DESC
');
PrintLn('
Resulting Table:
');
PrintLn('
');
PrintLn('
Name
Email
Level
');
// ds.Step() is a convenient way to iterate: it moves to the next record and returns True
while ds.Step do begin
PrintLn(Format(
'
```
---
## Example: SQLite DataSets
In-depth exploration of the 'TDataSet' interface for data consumption and manipulation. This example illustrates advanced field access techniques (named vs. indexed access), type-safe retrieval (AsInteger, AsString), and the 'IsNull' predicate, showcasing the efficiency of forward-only cursors for handling large-scale database results.
### Source Code
```pascal
// SQLite DataSets: In-depth exploration of the 'TDataSet' interface for data consumption and manipulation. This example illustrates advanced field access techniques (named vs. indexed access), type-safe retrieval (AsInteger, AsString), and the 'IsNull' predicate, showcasing the efficiency of forward-only cursors for handling large-scale database results.
uses System.Data;
var db := DataBase.Create('SQLite', [':memory:']);
db.Exec('CREATE TABLE Log (ID INTEGER PRIMARY KEY, Msg TEXT, Level INTEGER)');
for var i := 1 to 5 do
db.Exec(
'INSERT INTO Log (Msg, Level) VALUES (?, ?)',
[ 'Event ' + IntToStr(i), i * 10 ]
);
var ds := db.Query('SELECT * FROM Log');
PrintLn('
');
// ds.Step() is a practical alternative to Eof/Next.
// It moves to the next record and returns True if successful.
while ds.Step do begin
PrintLn(Format(
'[%d] %s (Level: %d)',
[ ds.AsInteger('ID'), ds.AsString('Msg').ToHtml, ds.AsInteger('Level') ]
));
end;
// Field access types
PrintLn('
Typed Access
');
// Execute a new query to reset the cursor to the first record.
ds := db.Query('SELECT Msg, Level FROM Log LIMIT 1');
if ds.Step then begin
PrintLn("AsString('Msg'): " + ds.AsString('Msg').ToHtml);
PrintLn("AsInteger('Level'): " + IntToStr(ds.AsInteger('Level')));
PrintLn("IsNull('Msg'): " + (if ds.IsNull('Msg') then 'True' else 'False'));
end;
```
### Output
```text
AsString('Msg'): Event 1
AsInteger('Level'): 10
IsNull('Msg'): False
```
---
## Example: SQLite JSON Integration
Demonstrates the native bridge between relational data and JSON serialization. This example showcases the 'StringifyAll' method for converting entire result sets into structured JSON arrays and the 'Stringify' method for single-record objects, enabling rapid API development and data exchange.
### Source Code
```pascal
// SQLite JSON Integration: Demonstrates the native bridge between relational data and JSON serialization. This example showcases the 'StringifyAll' method for converting entire result sets into structured JSON arrays and the 'Stringify' method for single-record objects, enabling rapid API development and data exchange.
uses System.Data;
var db := DataBase.Create('SQLite', [':memory:']);
// Setup sample data
db.Exec('CREATE TABLE Products (ID INTEGER, Name TEXT, Price FLOAT, Category TEXT)');
db.Exec('INSERT INTO Products VALUES (1, "Mechanical Keyboard", 120.50, "Peripherals")');
db.Exec('INSERT INTO Products VALUES (2, "Gaming Mouse", 59.99, "Peripherals")');
db.Exec('INSERT INTO Products VALUES (3, "UltraWide Monitor", 450.00, "Display")');
PrintLn('
JSON Stringification
');
// 1. StringifyAll: Convert the entire result set into a JSON array of objects.
PrintLn('
1. StringifyAll (Multiple Records)
');
var dsAll := db.Query('SELECT Name, Price FROM Products WHERE Category = ?', ['Peripherals']);
PrintLn('
' + dsAll.StringifyAll + '
');
// 2. Stringify: Convert the CURRENT record only into a JSON object.
PrintLn('
2. Stringify (Current Record)
');
var dsOne := db.Query('SELECT * FROM Products WHERE ID = 3');
if not dsOne.Eof then
PrintLn('
' + dsOne.Stringify + '
');
// 3. Stringify with parameters
// Some datasets might be large, you can use StringifyAll to quickly build APIs.
PrintLn('
3. Result as Table
');
// You can still use the Dataset normally
var ds := db.Query('SELECT Name, Price FROM Products');
PrintLn('
```
---
## Example: SQLite Transactions
Illustrates the principles of ACID compliance and data integrity in multi-step database operations. This example demonstrates managing atomic blocks with 'BeginTransaction', 'Commit', and 'Rollback', showcasing robust error handling within 'try..except' constructs to prevent data corruption during partial failures.
### Source Code
```pascal
// SQLite Transactions: Illustrates the principles of ACID compliance and data integrity in multi-step database operations. This example demonstrates managing atomic blocks with 'BeginTransaction', 'Commit', and 'Rollback', showcasing robust error handling within 'try..except' constructs to prevent data corruption during partial failures.
uses System.Data;
var db := DataBase.Create('SQLite', [':memory:']);
db.Exec('CREATE TABLE Inventory (Item TEXT, Qty INTEGER)');
PrintLn('
Transaction Management
');
// 1. Successful Transaction
PrintLn('Executing Transaction A...');
db.BeginTransaction;
try
db.Exec('INSERT INTO Inventory VALUES (?, ?)', ['Apples', 50]);
db.Exec('INSERT INTO Inventory VALUES (?, ?)', ['Bananas', 30]);
db.Commit;
PrintLn('Transaction A committed.');
except
on E: Exception do begin
db.Rollback;
PrintLn('Transaction A failed: ' + E.Message);
end;
end;
// 2. Failed Transaction (Rollback)
PrintLn(' Executing Transaction B (will fail)...');
db.BeginTransaction;
try
db.Exec('INSERT INTO Inventory VALUES (?, ?)', ['Oranges', 100]);
// Force an error (Table "NonExistent" doesn't exist)
db.Exec('INSERT INTO NonExistent VALUES (1)');
db.Commit;
PrintLn('Transaction B committed.');
except
on E: Exception do begin
db.Rollback;
PrintLn('Transaction B rolled back due to error.');
end;
end;
// Verify state
PrintLn('
Final Inventory:
');
var ds := db.Query('SELECT Item, Qty FROM Inventory');
while ds.Step do begin
PrintLn(ds.AsString(0) + ': ' + IntToStr(ds.AsInteger(1)));
end;
PrintLn('Note: Oranges are missing because the transaction was rolled back.');
```
### Output
```text
Transaction Management
Executing Transaction A...
Transaction A committed.
Executing Transaction B (will fail)...
Transaction B rolled back due to error.
Final Inventory:
Apples: 50
Bananas: 30
Note: Oranges are missing because the transaction was rolled back.
```
---
## Example: Tabular Data Processing
High-performance data transformation and analysis. This example demonstrates using 'TabularData' for data science tasks like feature normalization, linear modeling with ReLU activation, and error metrics (SMAPE), highlighting the efficiency of JIT-compiled RPN expressions for bulk processing.
### Source Code
```pascal
// Tabular Data Processing: High-performance data transformation and analysis. This example demonstrates using 'TabularData' for data science tasks like feature normalization, linear modeling with ReLU activation, and error metrics (SMAPE), highlighting the efficiency of JIT-compiled RPN expressions for bulk processing.
uses System.Data.Tabular;
// 1. Create a dataset representing sensor readings or predictions
var data := new TabularData;
data.AddColumn('Timestamp', [1000, 1010, 1020, 1030, 1040]);
data.AddColumn('Signal', [0.5, -1.2, 3.4, 2.1, -0.8]);
data.AddColumn('Actual', [0.6, 0.1, 3.0, 2.5, 0.1]);
PrintLn('
Raw Sensor Data
');
PrintLn(data.ExportToSeparated(['Timestamp', 'Signal', 'Actual']).Replace(#10, ' '));
// 2. Data Normalization (Min-Max Scaling)
// Calculate range metrics manually (as 'min'/'max' aggregates are not in this binary)
var signalVals := data.Evaluate(['"Signal"']);
var sMin := signalVals[0];
var sMax := signalVals[0];
for var v in signalVals do begin
if v < sMin then sMin := v;
if v > sMax then sMax := v;
end;
var sRange := sMax - sMin;
// Scale Signal to [0, 1] range: (Signal - Min) / Range
data.EvaluateNewColumn('Normalized', [ '"Signal"', sMin, '-', sRange, '/' ]);
// 3. Simple Linear Model + ReLU Activation
// Simulate a prediction: (Signal * 1.5) + 0.5, clamped to positive values via 'relu'
// In this engine, 'relu' is a fused binary operator that performs max(0, a + b)
data.EvaluateNewColumn('Prediction', [ '"Signal"', 1.5, '*', 0.5, 'relu' ]);
// 4. Error Analysis (SMAPE component)
// 'smape' opcode calculates abs(a-b) / (abs(a)+abs(b)) for each row
data.EvaluateNewColumn('ErrorRate', [ '"Prediction"', '"Actual"', 'smape' ]);
PrintLn('
');
PrintLn('Mean SMAPE Error: ' + Float(avgError).ToString(4));
PrintLn('Peak Signal: ' + Float(sMax).ToString(2));
// Note: While this example uses 5 rows for readability, TabularData
// is designed to process millions of rows using these same JIT expressions.
try
data.LockAndShare('GlobalAnalyticsCache');
except
// Might already be shared
end;
```
### Output
```text
Mean SMAPE Error: 0.5681
Peak Signal: 3.40
```
---
## Example: Mandelbrot Set
Illustrates fractal generation and iterative complex arithmetic. This example demonstrates nested 'for' loops, floating-point math, and character-based mapping to render a visual representation of the Mandelbrot set in ASCII.
### Source Code
```pascal
// Mandelbrot Set: Illustrates fractal generation and iterative complex arithmetic. This example demonstrates nested 'for' loops, floating-point math, and character-based mapping to render a visual representation of the Mandelbrot set in ASCII.
const cWidth = 60;
const cHeight = 30;
const cChars = ' .:-=+*#%@';
for var y := 0 to cHeight - 1 do begin
var im := -1.2 + (y * 2.4 / cHeight);
var line := '';
for var x := 0 to cWidth - 1 do begin
var re := -2.0 + (x * 3.0 / cWidth);
var z_re := re;
var z_im := im;
var iter := 0;
var inside := True;
while (z_re*z_re + z_im*z_im <= 4.0) and (iter < 30) do begin
var next_re := z_re*z_re - z_im*z_im + re;
z_im := 2*z_re*z_im + im;
z_re := next_re;
Inc(iter);
end;
if iter >= 30 then
line += ' '
else
line += cChars[(iter mod Length(cChars)) + 1];
end;
PrintLn(line);
end;
```
### Output
```text
..........:::::::::::::::::::::::::.................
.......:::::::::::::::::----=#==----::::.............
......::::::::::::::::------=+*%*++----::::...........
.....::::::::::::::::------===+#@%@*=-----::::.........
...::::::::::::::::-------===*. @ ##+==----:::::.......
..::::::::::::::::-------==++*#- ##+====--::::::.....
..:::::::::::::::------==+****#@+ =%#*++++=-::::::....
.::::::::::::::-----===+*.:+ : %#%=*=-::::::...
.:::::::::::::---=====+++#@ +-==-::::::..
:::::::::::--========++* = @*+=-:::::::.
.:::::::---==*.*********# @ *%%=--::::::.
::::-----===+*-# @.=@@%%@# @+--:::::::
::------====**%@ =.- =@=---::::::
------====+#%@* :+=---::::::
-==-=+++**% %* +*+=---::::::
.#*+=---::::::
-==-=+++**% %* +*+=---::::::
------====+#%@* :+=---::::::
::------====**%@ =.- =@=---::::::
::::-----===+*-# @.=@@%%@# @+--:::::::
.:::::::---==*.*********# @ *%%=--::::::.
:::::::::::--========++* = @*+=-:::::::.
.:::::::::::::---=====+++#@ +-==-::::::..
.::::::::::::::-----===+*.:+ : %#%=*=-::::::...
..:::::::::::::::------==+****#@+ =%#*++++=-::::::....
..::::::::::::::::-------==++*#- ##+====--::::::.....
...::::::::::::::::-------===*. @ ##+==----:::::.......
.....::::::::::::::::------===+#@%@*=-----::::.........
......::::::::::::::::------=+*%*++----::::...........
.......:::::::::::::::::----=#==----::::.............
```
---
## Example: Pixmap Formats
Demonstrates bitmap manipulation and image encoding/decoding. This example showcases the 'TPixmap' type for pixel-level access, converting images to PNG and JPEG data streams, and performing round-trip transformations between binary data and visual objects.
### Source Code
```pascal
// Pixmap Formats: Demonstrates bitmap manipulation and image encoding/decoding. This example showcases the 'TPixmap' type for pixel-level access, converting images to PNG and JPEG data streams, and performing round-trip transformations between binary data and visual objects.
uses System.Encoding;
// Create a small 32x32 pixmap (implicitly black)
var bmp := CreatePixmap(32, 32);
// Draw a simple red cross
for var i := 0 to 31 do begin
bmp.SetPixel(i, i, $FFFF0000);
bmp.SetPixel(31 - i, i, $FFFF0000);
end;
// Convert to PNG (with alpha)
var pngData := bmp.ToPNGData(-1, -1, True);
PrintLn('PNG Size: ' + IntToStr(pngData.Length) + ' bytes');
PrintLn('PNG Base64: ' + Base64Encoder.Encode(pngData).Copy(1, 40) + '...');
// Convert to JPEG (quality 75)
var jpgData := bmp.ToJPEGData(-1, -1, 75);
PrintLn('JPEG Size: ' + IntToStr(jpgData.Length) + ' bytes');
// Round-trip: PNG to Pixmap
var w, h : Integer;
var bmp2 := PNGDataToPixmap(pngData, True, w, h);
PrintLn('Recovered PNG Dimensions: ' + IntToStr(w) + 'x' + IntToStr(h));
// Round-trip: JPEG to Pixmap (half scale)
var w2, h2 : Integer;
var bmp3 := JPEGDataToPixmap(jpgData, 2, w2, h2);
PrintLn('Recovered JPEG Dimensions (1/2 scale): ' + IntToStr(w2) + 'x' + IntToStr(h2));
// Resize pixmap
bmp.Resize(16, 16);
PrintLn('Pixmap resized to 16x16');
```
### Output
```text
PNG Size: 223 bytes
PNG Base64: iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABz...
JPEG Size: 796 bytes
Recovered PNG Dimensions: 32x32
Recovered JPEG Dimensions (1/2 scale): 16x16
Pixmap resized to 16x16
```
---
## Example: 3D Vectors
Explores high-performance vector mathematics using the native 'TVector' type. This example demonstrates vector addition, scalar multiplication, dot products ('*'), and cross products ('^'), highlighting the language's optimized support for 3D graphics and physics calculations.
### Source Code
```pascal
// 3D Vectors: Explores high-performance vector mathematics using the native 'TVector' type. This example demonstrates vector addition, scalar multiplication, dot products ('*'), and cross products ('^'), highlighting the language's optimized support for 3D graphics and physics calculations.
// Create vectors
var v1 := Vector(1, 0, 0); // X-axis unit vector
var v2 := Vector(0, 1, 0); // Y-axis unit vector
var vUp := Vector(0, 0, 1); // Z-axis unit vector
PrintLn('v1: ' + VectorToStr(v1));
PrintLn('v2: ' + VectorToStr(v2));
// Vector Addition
var v3 := v1 + v2;
PrintLn('v1 + v2: ' + VectorToStr(v3));
// Scalar Multiplication
var v4 := v3 * 2.5;
PrintLn('v3 * 2.5: ' + VectorToStr(v4));
// Dot Product (Scalar product)
// For unit vectors, it is the cosine of the angle between them.
// v1 and v2 are perpendicular, so dot product should be 0.
var dot := v1 * v2;
PrintLn('Dot Product (v1 * v2): ' + dot.ToString);
// Cross Product (Vector product)
// Result is perpendicular to both input vectors.
// X cross Y should be Z.
var cross := v1 ^ v2;
PrintLn('Cross Product (v1 ^ v2): ' + VectorToStr(cross));
// Normalization (Making unit length)
var vArbitrary := Vector(10, 10, 10);
PrintLn('Arbitrary: ' + VectorToStr(vArbitrary));
var vNorm := VectorNormalize(vArbitrary);
PrintLn('Normalized: ' + VectorToStr(vNorm));
// Length check (Dot product with self is length squared)
var lengthSq := vNorm * vNorm;
PrintLn('Length Squared of Normalized: ' + lengthSq.ToString);
```
### Output
```text
v1: [1.00 0.00 0.00 0.00]
v2: [0.00 1.00 0.00 0.00]
v1 + v2: [1.00 1.00 0.00 0.00]
v3 * 2.5: [2.50 2.50 0.00 0.00]
Dot Product (v1 * v2): 0
Cross Product (v1 ^ v2): [0.00 0.00 1.00 0.00]
Arbitrary: [10.00 10.00 10.00 0.00]
Normalized: [0.58 0.58 0.58 0.00]
Length Squared of Normalized: 1
```
---
## Example: Attribute-Based Validation
Practical demonstration of using class-level attributes and RTTI for metadata-driven object validation. This example shows how to define constraints at the class level and build a validation engine that enforces them.
### Source Code
```pascal
// Attribute-Based Validation: Practical demonstration of using class-level attributes and RTTI for metadata-driven object validation. This example shows how to define constraints at the class level and build a validation engine that enforces them.
type
// Define custom attribute classes
RequiredAttribute = class(TCustomAttribute)
FieldName: String;
constructor Create(aFieldName: String);
begin
FieldName := aFieldName;
end;
end;
type
RangeAttribute = class(TCustomAttribute)
FieldName: String;
Min, Max: Integer;
constructor Create(aFieldName: String; aMin, aMax: Integer);
begin
FieldName := aFieldName; Min := aMin; Max := aMax;
end;
end;
type
// A data record with validation constraints defined at the class level
[RequiredAttribute('UserName')]
[RangeAttribute('Age', 18, 120)]
TUserProfile = class
published
UserName: String;
Age: Integer;
Email: String;
end;
// A generic validator that uses RTTI to check objects based on class attributes
function ValidateObject(obj: TObject; typeInfo: TRTTITypeInfo): array of String;
begin
var errors: array of String;
var attrs := RTTIRawAttributes;
// 1. First, collect all available property getters for this type
// In DWScript, we use RTTIPropertyAttribute to access published members dynamically
var props: array [String] of RTTIPropertyAttribute;
for var i := 0 to attrs.Length - 1 do begin
if (attrs[i].T = typeInfo) and (attrs[i].A is RTTIPropertyAttribute) then begin
var p := RTTIPropertyAttribute(attrs[i].A);
props[p.Name] := p;
end;
end;
// 2. Process validation attributes
for var i := 0 to attrs.Length - 1 do begin
if attrs[i].T = typeInfo then begin
var attr := attrs[i].A;
// Process [Required]
if attr is RequiredAttribute then begin
var req := RequiredAttribute(attr);
var p := props[req.FieldName];
if (p <> nil) and (VarToStr(p.Getter(obj)) = '') then
errors.Add(Format('Field "%s" is required but was empty.', [req.FieldName]));
end;
// Process [Range]
if attr is RangeAttribute then begin
var rng := RangeAttribute(attr);
var p := props[rng.FieldName];
if p <> nil then begin
var val := Integer(p.Getter(obj));
if (val < rng.Min) or (val > rng.Max) then
errors.Add(Format('Field "%s" must be between %d and %d (Current: %d).',
[rng.FieldName, rng.Min, rng.Max, val]));
end;
end;
end;
end;
Result := errors;
end;
procedure TestValidation(user: TUserProfile; label: String);
begin
PrintLn('Testing: ' + label + '');
var errors := ValidateObject(user, TypeOf(TUserProfile));
if errors.Length = 0 then
PrintLn('Valid!')
else begin
for var err in errors do
PrintLn('- ' + err + '');
end;
PrintLn('');
end;
// Execution
var user1 := new TUserProfile;
user1.UserName := 'Alice';
user1.Age := 25;
TestValidation(user1, 'Valid User');
var user2 := new TUserProfile;
user2.UserName := ''; // Violation: Required
user2.Age := 12; // Violation: Range
TestValidation(user2, 'Invalid User');
```
### Output
```text
Testing: Valid UserValid!Testing: Invalid User- Field "UserName" is required but was empty.- Field "Age" must be between 18 and 120 (Current: 12).
```
---
## Example: Class Operators
Demonstrates DWScript's advanced syntax for defining domain-specific languages (DSL) via operator overloading. This example showcases the 'class operator' syntax to implement custom membership logic ('in') for complex types like date ranges and fluent increment operators ('+=') for building building builders, illustrating how to create highly readable and expressive APIs.
### Source Code
```pascal
= StartDate) and (d <= EndDate);
end;
class operator in Float uses Contains;
end;
var q1 := TDateRange.Create(
EncodeDate(2024, 1, 1),
EncodeDate(2024, 3, 31)
);
var testDate := EncodeDate(2024, 2, 15);
if testDate in q1 then
PrintLn('Date is in Q1 2024');
// Example 2: Custom '+=' for fluent building
type
TQueryBuilder = class
FSql: String;
procedure AddClause(clause: String);
begin
if FSql <> '' then FSql := FSql + ' ';
FSql := FSql + clause;
end;
class operator += String uses AddClause;
end;
var query := TQueryBuilder.Create;
query += 'SELECT *';
query += 'FROM users';
query += 'WHERE active = 1';
PrintLn('Query: ' + query.FSql);
// Example 3: Custom 'not in' automatically works
var otherDate := EncodeDate(2024, 5, 1);
if otherDate not in q1 then
PrintLn('May 1st is NOT in Q1');
?>
```
### Output
```text
Date is in Q1 2024
Query: SELECT * FROM users WHERE active = 1
May 1st is NOT in Q1
```
---
## Example: Design by Contract (DbC)
Showcases formal verification and defensive programming using built-in contract keywords. This example illustrates the 'require' (pre-conditions) and 'ensure' (post-conditions) syntax to define strict API boundaries, showcasing how to validate input parameters and output results at runtime to catch logic errors early and improve software reliability.
### Source Code
```pascal
0 : 'Divisor cannot be zero';
a >= 0 : 'Dividend must be non-negative';
begin
Result := a / b;
ensure
Result >= 0 : 'Result must be non-negative';
end;
// Valid call
PrintLn('10 / 2 = ' + Divide(10, 2).ToString);
// Contract violation examples
try
Divide(10, 0); // Fails 'require b <> 0'
except
on E: Exception do
PrintLn('Contract violation: ' + E.Message);
end;
// Class invariant example
type
TBankAccount = class
FBalance: Float;
procedure Withdraw(amount: Float);
require
amount > 0 : 'Amount must be positive';
amount <= FBalance : 'Insufficient funds';
begin
FBalance := FBalance - amount;
ensure
FBalance >= 0 : 'Balance cannot go negative';
end;
constructor Create(initial: Float);
require
initial >= 0 : 'Initial balance cannot be negative';
begin
FBalance := initial;
end;
end;
var account := TBankAccount.Create(100);
account.Withdraw(30);
PrintLn('Balance after withdrawal: ' + account.FBalance.ToString);
?>
```
### Output
```text
10 / 2 = 5
Contract violation: Pre-condition failed in Divide [line: 6, column: 3], Divisor cannot be zero
Balance after withdrawal: 70
```
---
## Example: Enums & Sets
Deep dive into Pascal's powerful type-safe constants and bitmask management. This example demonstrates defining enumerations, using the 'set of' construct for efficient collection management, and performing set-theoretic operations (union, intersection, difference) while showcasing the native ability to cast sets to integers for low-level bitmask manipulation.
### Source Code
```pascal
```
### Output
```text
Day index: 2
Weekdays: Monday Tuesday Wednesday Thursday Friday
Today is a workday
Work days count: 5
Permissions bitmask: 3
After changes: 6
Can Write is set
```
---
## Example: Interfaces & Polymorphism
Showcases the power of interface-driven design for creating decoupled and extensible architectures. This example demonstrates defining interfaces, implementing multiple behaviors across disparate class hierarchies, and using the 'implements' operator for safe runtime discovery and casting of interface implementations.
### Source Code
```pascal
```
### Output
```text
[CONSOLE] Processing: Task A
[CONSOLE] Complete
[FILE:app.log] Processing: Task B
[FILE:app.log] Complete
TConsoleLogger supports ILogger
```
---
## Example: Lambdas & Closures
Illustrates modern functional programming paradigms using anonymous subroutines and lexical closures. This example showcases the concise 'lambda' arrow syntax, capturing local state in closures, and utilizing higher-order methods like 'Filter', 'Map', and 'Sort' to perform declarative transformations on dynamic collections.
### Source Code
```pascal
x * x;
PrintLn('Square of 5: ' + square(5).ToString);
// Explicitly typed dynamic array
var names : array of String := ['Charlie', 'Alice', 'Bob'];
// Lambda as callback for sorting (in-place)
names.Sort(lambda(a, b: String): Integer => CompareText(a, b));
PrintLn('Sorted: ' + names.Join(', '));
// Filtering an array (returns a new array)
var numbers : array of Integer := [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
var evens := numbers.Filter(lambda(x: Integer) => (x mod 2) = 0);
PrintLn('Evens: ' + evens.Map(IntToStr).Join(', '));
// Mapping an array (transformation)
var squaredNames := names.Map(
lambda(s: String) => s.ToUpper + ' (' + s.Length.ToString + ')'
);
PrintLn('Mapped names: ' + squaredNames.Join(', '));
// Stateless lambda shorthand
var items : array of Integer := [1, 2, 3];
var doubled := items.Map(lambda(x) => x * 2);
PrintLn('Doubled: ' + doubled.Map(IntToStr).Join(', '));
?>
```
### Output
```text
Square of 5: 25
Sorted: Alice, Bob, Charlie
Evens: 2, 4, 6, 8, 10
Mapped names: ALICE (5), BOB (3), CHARLIE (7)
Doubled: 2, 4, 6
```
---
## Example: Metaclasses
Demonstrates the sophisticated use of class references ('class of') for implementing runtime dynamic behaviors. This example showcases the Factory pattern by treating classes as first-class values, allowing for the instantiation of specific subclasses based on metadata or runtime logic, and illustrating virtual constructor patterns.
### Source Code
```pascal
```
### Output
```text
Creating TCircle
Area: 3.14
Creating TSquare
Created instance of TSquare
```
---
## Example: Object-Oriented Programming (OOP)
A comprehensive introduction to class-based design and polymorphism. This example explores defining class hierarchies, using 'virtual' and 'abstract' methods to define extensible interfaces, overriding constructors, and managing heterogeneous object collections using dynamic arrays of base class references.
### Source Code
```pascal
```
### Output
```text
Shape: Circle, Area: 78.54
Shape: Square, Area: 16.00
Shape: Circle, Area: 19.63
```
---
## Example: Records
Explores advanced record features that differentiate DWScript from traditional Pascal. This example highlights default field values, anonymous record syntax for quick data structures, and the built-in JSON serialization capabilities for complex record hierarchies.
### Source Code
```pascal
// Records: Explores advanced record features that differentiate DWScript from traditional Pascal. This example highlights default field values, anonymous record syntax for quick data structures, and the built-in JSON serialization capabilities for complex record hierarchies.
type
TConfig = record
// Default values
ResolutionX : Integer := 1920;
ResolutionY := 1080; // Inferred type
Fullscreen := True;
// Method in record
function Description : String;
end;
function TConfig.Description: String;
begin
Result := Format(
'%dx%d (Fullscreen: %s)',
[ ResolutionX, ResolutionY, BoolToStr(Fullscreen) ]
);
end;
PrintLn('Default Values:');
var cfg : TConfig;
PrintLn(cfg.Description);
// Override defaults
cfg.ResolutionX := 800;
cfg.ResolutionY := 600;
PrintLn(Format(
'Modified: %dx%d',
[ cfg.ResolutionX, cfg.ResolutionY ]
));
PrintLn('');
PrintLn('Anonymous Records (JSON-like):');
// Anonymous record creation
var player := record
name := 'Hero';
level := 42;
"current-location" := 'Dungeon'; // Quoted identifier (for JSON)
stats := record
str := 18;
dex := 14;
end;
end;
PrintLn('Name: ' + player.name);
// Note: Quoted keys cannot be accessed via dot notation.
// They are primarily used for defining structures for export (e.g. JSON).
// Direct JSON serialization
PrintLn('');
PrintLn('JSON Serialization:');
PrintLn(JSON.Stringify(player));
```
### Output
```text
Default Values:
1920x1080 (Fullscreen: True)
Modified: 800x600
Anonymous Records (JSON-like):
Name: Hero
JSON Serialization:
{"current-location":"Dungeon","level":42,"name":"Hero","stats":{"dex":14,"str":18}}
```
---
## Example: Custom Attributes
Showcases declarative programming and metadata-driven logic. This example demonstrates how to define custom attribute classes inheriting from 'TCustomAttribute', annotate other types with these attributes, and use 'RTTIRawAttributes' to programmatically discover and act upon this metadata at runtime for tasks like mapping classes to database tables.
### Source Code
```pascal
Table: ' + TableAttribute(attrs[i].A).FName);
end;
if attrs[i].T = TypeOf(TOrder) then begin
if attrs[i].A is TableAttribute then
PrintLn('TOrder -> Table: ' + TableAttribute(attrs[i].A).FName);
end;
end;
// Simple TypeOf usage
var info := TypeOf(TUser);
PrintLn('Class name from RTTI: ' + info.Name);
?>
```
### Output
```text
Entity Metadata:
TUser -> Table: users
TOrder -> Table: orders
Class name from RTTI: TUser
```
---
## Example: RTTI Inspection
Illustrates the extensive runtime introspection capabilities of DWScript. This example showcases the use of 'TypeOf' and 'RTTIRawAttributes' to explore class members (fields, properties, methods) at runtime, demonstrating how to dynamically inspect types and perform property access by name without compile-time knowledge.
### Source Code
```pascal
'' then 'function' else 'procedure';
PrintLn(' ' + kind + ' ' + meth.Name);
end;
end;
PrintLn('');
// Dynamic interaction
var user := TUser.Create;
user.Name := 'Alice';
// Find and use property dynamically
for var i := 0 to rtti.Length - 1 do begin
var attr := rtti[i];
if (attr.T = typeID) and (attr.A is RTTIPropertyAttribute) then begin
var prop := RTTIPropertyAttribute(attr.A);
if prop.Name = 'Name' then
PrintLn('Dynamic Name access: ' + VarToStr(prop.Getter(user)));
end;
end;
?>
```
### Output
```text
=== Type Info for TUser ===
Published Fields/Properties:
Email: String
Name: String
Status: TStatus
Methods:
procedure Activate
function IsActive
Dynamic Name access: Alice
```
---
## Example: BigInteger Number Theory
Explores advanced mathematical concepts using arbitrary-precision integers. This example showcases factorials of large numbers, efficient primality testing using the 'IsPrime' method, and the 'ModPow' function for secure numerical transformations, highlighting the efficiency of native BigInt operators.
### Source Code
```pascal
```
### Output
```text
100! = 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
Length: 158 digits
M31 (2^31 - 1) = 2147483647
M31 is prime.
M61 (2^61 - 1) = 2305843009213693951
M61 is prime.
(7^123) mod 100 = 43
```
---
## Example: BigIntegers (Advanced)
Demonstrates high-precision integer math beyond standard 64-bit limits. This example showcases the native 'BigInteger' type, illustrating its use in calculating massive factorials, performing modular exponentiation ('ModPow') for cryptographic applications, and utilizing helper functions like 'GCD' and bit-level inspection.
### Source Code
```pascal
```
### Output
```text
a = 12345678901234567890
b = 98765432109876543210
a + b = 111111111011111111100
a * b = 1219326311370217952237463801111263526900
50! =
30414093201713378043612608166064768844377641568960512000000000000
Digits: 65
2^256 =
115792089237316195423570985008687907853269984665640564039457584007913129639936
a^b mod 1000000007 = 577648646
GCD(48, 18) = 6
Bit length of 2^256: 257
```
---
## Example: Fast Fourier Transform (FFT)
Demonstrates numerical processing and signal analysis concepts. This example showcases array pre-allocation with 'SetLength', floating-point arithmetic, and the use of the standard math library for complex numerical calculations.
### Source Code
```pascal
// Fast Fourier Transform (FFT): Demonstrates numerical processing and signal analysis concepts. This example showcases array pre-allocation with 'SetLength', floating-point arithmetic, and the use of the standard math library for complex numerical calculations.
const N = 8;
var x : array of Float;
x.SetLength(2 * N);
for var i := 0 to N - 1 do begin
x[2 * i] := i;
x[2 * i + 1] := 0;
end;
// Just print input to verify it runs
Print('Input: ');
for var i := 0 to N - 1 do
Print(x[2 * i].ToString(1) + ' ');
PrintLn('');
```
### Output
```text
Input: 0.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0
```
---
## Example: Fibonacci & Memoization
Demonstrates algorithmic optimization and recursive logic in DWScript. This example showcases the implementation of the Fibonacci sequence using both a naive iterative approach and a recursive pattern enhanced with memoization using associative arrays, illustrating how to trade memory for computational speed.
### Source Code
```pascal
Recursive Approach (with Memoization)');
PrintLn('Fibonacci(' + IntToStr(n) + ') = ' + IntToStr(FibonacciRecursive(n)));
PrintLn('');
PrintLn('
');
var seq := '';
for var i := 0 to n do begin
if i > 0 then seq := seq + ', ';
seq := seq + IntToStr(FibonacciIterative(i));
end;
PrintLn(seq);
?>
```
### Output
```text
Recursive Approach (with Memoization)
Fibonacci(10) = 55
Iterative Approach
Fibonacci(10) = 55
Sequence Output (Iterative)
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55
```
---
## Example: Haversine Formula
Demonstrates high-precision floating-point arithmetic and built-in trigonometry functions. This example showcases calculating great-circle distances using 'Haversine', highlighting the standard library's support for geospatial mathematics.
### Source Code
```pascal
// Haversine Formula: Demonstrates high-precision floating-point arithmetic and built-in trigonometry functions. This example showcases calculating great-circle distances using 'Haversine', highlighting the standard library's support for geospatial mathematics.
var nashvilleLat := 36.12;
var nashvilleLon := -86.67;
var losAngelesLat := 33.94;
var losAngelesLon := -118.40;
var earthRadiusKm := 6371.0;
var dist := Haversine(nashvilleLat, nashvilleLon, losAngelesLat, losAngelesLon, earthRadiusKm);
PrintLn('Distance between Nashville and Los Angeles: ' + dist.ToString(2) + ' km');
```
### Output
```text
Distance between Nashville and Los Angeles: 2886.44 km
```
---
## Example: Matrix Multiplication
Demonstrates linear algebra operations and 1D array indexing for performance. This example showcases using records to encapsulate data structures, manual array resizing with 'SetLength', and efficient nested loop patterns for mathematical transformations.
### Source Code
```pascal
// Matrix Multiplication: Demonstrates linear algebra operations and 1D array indexing for performance. This example showcases using records to encapsulate data structures, manual array resizing with 'SetLength', and efficient nested loop patterns for mathematical transformations.
type TMatrix = record Data: array of Float; Rows, Cols: Integer; end;
function CreateMatrix(r, c: Integer; const d: array of Float): TMatrix;
begin Result.Rows := r; Result.Cols := c; Result.Data := d; end;
function MatrixMultiply(const A, B: TMatrix): TMatrix;
var i, j, k: Integer;
begin
Result.Rows := A.Rows; Result.Cols := B.Cols;
Result.Data.SetLength(A.Rows * B.Cols);
for i := 0 to A.Rows - 1 do
for j := 0 to B.Cols - 1 do begin
var sum := 0.0;
for k := 0 to A.Cols - 1 do sum += A.Data[i * A.Cols + k] * B.Data[k * B.Cols + j];
Result.Data[i * Result.Cols + j] := sum;
end;
end;
var A := CreateMatrix(2, 2, [1.0, 2.0, 3.0, 4.0]);
var B := CreateMatrix(2, 2, [5.0, 6.0, 7.0, 8.0]);
var C := MatrixMultiply(A, B);
PrintLn('C[0,0] = ' + C.Data[0].ToString(1));
```
### Output
```text
C[0,0] = 19.0
```
---
## Example: Root Finding
Illustrates numerical methods and floating-point precision. This example demonstrates the Secant method for finding polynomial roots, showcasing the use of the 'Abs' function for convergence checks and high-precision 'Float' arithmetic.
### Source Code
```pascal
// Root Finding: Illustrates numerical methods and floating-point precision. This example demonstrates the Secant method for finding polynomial roots, showcasing the use of the 'Abs' function for convergence checks and high-precision 'Float' arithmetic.
function f(x : Float) : Float; begin Result := x * x * x - 3.0 * x * x + 2.0 * x; end;
function Secant(xA, xB : Float) : Float;
var fA, fB, d : Float; i : Integer;
begin
fA := f(xA);
for i := 0 to 50 do begin
fB := f(xB);
if Abs(fB - fA) < 1e-15 then Break;
d := (xB - xA) / (fB - fA) * fB;
if Abs(d) < 1e-12 then Exit(xB);
xA := xB; fA := fB; xB -= d;
end;
Result := xB;
end;
PrintLn('Root found: ' + Secant(1.5, 2.5).ToString(3));
```
### Output
```text
Root found: 2.000
```
---
## Example: Signal Processing
Mixing & Mastering
### Source Code
```pascal
// Signal Processing: Mixing & Mastering
// This example simulates a real-world audio mastering chain using
// high-performance element-wise array operations.
//
// Key features demonstrated:
// - Mixing (Additive): Combining a carrier signal with noise.
// - Amplitude Modulation: Shaping a signal with a gain envelope.
// - Full-Wave Hard Limiting: Clipping a signal between dynamic bounds (Min and Max).
// - Energy Analysis: Calculating total signal power (RMS) via DotProduct.
const SAMPLES = 2000;
const FREQ = 440.0;
const RATE = 44100;
// 1. Generate Basic Signals
var signal, noise, envelope, ceiling, floor : array of Float;
signal.SetLength(SAMPLES);
noise.SetLength(SAMPLES);
envelope.SetLength(SAMPLES);
ceiling.SetLength(SAMPLES);
floor.SetLength(SAMPLES);
for var i := 0 to SAMPLES - 1 do begin
// Sine wave with intentional overdrive (Amplitude = 1.5)
signal[i] := Sin(2 * Pi * FREQ * i / RATE) * 1.5;
// Subtle white noise
noise[i] := (Random - 0.5) * 0.05;
// Slow fade-out envelope
envelope[i] := 1.0 - (0.5 * i / SAMPLES);
// Variable "safety ceiling" that tightens from 0.9 down to 0.4
ceiling[i] := 0.9 - (0.5 * i / SAMPLES);
floor[i] := -ceiling[i]; // Matching negative floor
end;
PrintLn(Format('Mastering Chain processing %d samples...', [SAMPLES]));
// 2-4. Processing Chain (Mixing, Shaping, and Limiting)
// We use fluent method chaining to perform multiple vectorized operations
// in a single statement. Note that these methods are mutating the 'signal' array.
signal
.Offset(noise) // Additive Mixing
.Multiply(envelope) // Envelope Shaping
.Min(ceiling) // Top-side Clipping
.Max(floor); // Bottom-side Clipping
PrintLn('Step 1-3: Mixing, Modulation, and Full-Wave Limiting complete (via fluent chaining).');
// 5. Total Signal Power (RMS calculation)
var sumSquares := ArrayDotProduct(signal, signal);
var rms := Sqrt(sumSquares / SAMPLES);
PrintLn(Format('Step 4: Total Energy (RMS) calculated: %.4f', [rms]));
// 6. Inspect Results (Middle of the buffer to see clipping in action)
PrintLn(' Waveform Clipping Profile (Samples 1000-1010):');
for var i := 1000 to 1009 do begin
var status := if (signal[i] = ceiling[i]) or (signal[i] = floor[i]) then '[CLIPPED]' else '';
PrintLn(Format(' Sample #%d: %7.4f (Limit: %7.4f) %s', [i, signal[i], ceiling[i], status]));
end;
```
### Output
```text
Mastering Chain processing 2000 samples...
Step 1-3: Mixing, Modulation, and Full-Wave Limiting complete (via fluent chaining).
Step 4: Total Energy (RMS) calculated: 0.5741
Waveform Clipping Profile (Samples 1000-1010):
Sample #1000: -0.1530 (Limit: 0.6500)
Sample #1001: -0.0772 (Limit: 0.6498)
Sample #1002: -0.0308 (Limit: 0.6495)
Sample #1003: 0.0577 (Limit: 0.6493)
Sample #1004: 0.1160 (Limit: 0.6490)
Sample #1005: 0.1914 (Limit: 0.6488)
Sample #1006: 0.2691 (Limit: 0.6485)
Sample #1007: 0.3249 (Limit: 0.6483)
Sample #1008: 0.4098 (Limit: 0.6480)
Sample #1009: 0.4427 (Limit: 0.6478)
```
---
## Example: Pattern Matching
Demonstrates DWScript's built-in string pattern matching capabilities. This example showcases the 'StrMatches' function, which allows for simple yet powerful wildcard-based matching (using '*' and '?') without the complexity of full regular expressions.
### Source Code
```pascal
// Pattern Matching: Demonstrates DWScript's built-in string pattern matching capabilities. This example showcases the 'StrMatches' function, which allows for simple yet powerful wildcard-based matching (using '*' and '?') without the complexity of full regular expressions.
var s := 'DWScript';
PrintLn('Matches "*Script": ' + s.Matches('*Script').ToString);
PrintLn('StrMatches("hello", "h*o"): ' + StrMatches('hello', 'h*o').ToString);
```
### Output
```text
Matches "*Script": True
StrMatches("hello", "h*o"): True
```
---
## Example: Roman Numerals
Demonstrates string building and array-based lookup tables. This example showcases the 'weights' and 'symbols' constant arrays, 'High' property for array bounds, and efficient string concatenation using the '+=' operator.
### Source Code
```pascal
// Roman Numerals: Demonstrates string building and array-based lookup tables. This example showcases the 'weights' and 'symbols' constant arrays, 'High' property for array bounds, and efficient string concatenation using the '+=' operator.
const weights = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1];
const symbols = ["M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"];
function ToRoman(n : Integer) : String;
var i, w : Integer;
begin
if n <= 0 then Exit('N/A');
for i := 0 to weights.High do begin
w := weights[i];
while n >= w do begin
Result += symbols[i];
n -= w;
end;
if n = 0 then Break;
end;
end;
PrintLn('2024 -> ' + ToRoman(2024));
```
### Output
```text
2024 -> MMXXIV
```
---
## Example: String Processing (Modern)
Comprehensive overview of DWScript's modern, fluent string manipulation API. This example showcases method-style transformations including 'Trim', 'Split', and 'Replace', illustrating substring extraction with 'Copy', specialized deletions via 'DeleteLeft' and 'DeleteRight', and the versatile 'Format' function for building complex templated output.
### Source Code
```pascal
Original: "' + rawText + '"');
// Trimming (no parentheses needed)
var trimmed := rawText.Trim;
PrintLn('Trimmed: "' + trimmed + '"');
// Splitting
var parts := trimmed.Split(',');
PrintLn('Split parts:');
PrintLn('
Replaced: "DWScript,Scripting,Web"
Substring (2,3): 234
Substring (5+): 56789
Delete Left (3): 456789
Delete Right (3): 123456
Formatted: Item: Apple, Count: 5, Price: 1.25
```
---
## Example: Vigenere Cipher
Illustrates character-level string manipulation and modular arithmetic. This example demonstrates using 'Ord' and 'Chr' for character conversions, set membership checking for alphabetic filters, and 1-based string indexing in DWScript.
### Source Code
```pascal
// Vigenere Cipher: Illustrates character-level string manipulation and modular arithmetic. This example demonstrates using 'Ord' and 'Chr' for character conversions, set membership checking for alphabetic filters, and 1-based string indexing in DWScript.
function VigenereEncrypt(src, key : String) : String;
begin
const cOrdA = Ord('A');
src := UpperCase(src);
key := UpperCase(key);
var keyLen := Length(key);
var resIdx := 1;
for var i := 1 to Length(src) do begin
if src[i] in ['A'..'Z'] then begin
var srcShift := Ord(src[i]) - cOrdA;
var keyShift := Ord(key[(resIdx - 1) mod keyLen + 1]) - cOrdA;
Result += Chr(((srcShift + keyShift) mod 26) + cOrdA);
Inc(resIdx);
end else Result += src[i];
end;
end;
PrintLn('Encrypted: ' + VigenereEncrypt('HELLO', 'ABC'));
```
### Output
```text
Encrypted: HFNLP
```
---
## Example: ETag Caching
Demonstrates standard-compliant HTTP caching strategies to optimize web performance. This example showcases using 'HashSHA256' to generate content fingerprints, illustrating how to inspect 'WebRequest.Header' for conditional validation and use 'WebResponse.SetETag' to implement efficient 304 Not Modified status handling.
### Source Code
```pascal
```
### Output
```text
Immutable Content v1.0```
---
## Example: Headers & Cookies
In-depth demonstration of managing HTTP state and client metadata. This example illustrates using the 'WebRequest' object to traverse incoming HTTP headers and 'WebResponse.SetCookie' to manage persistent client-side data, highlighting the use of security-critical flags like HttpOnly and SameSite for robust web application security.
### Source Code
```pascal
Cookies');
var lastVisit := WebRequest.Cookie['LastVisit'];
if lastVisit = '' then
PrintLn('No "LastVisit" cookie found. Reload the page to see it.')
else
PrintLn('Last Visit: ' + lastVisit);
PrintLn('
Request Headers
');
PrintLn('
');
PrintLn('
' + WebRequest.Headers + '
');
PrintLn('
');
?>
```
### Output
```text
Cookies
No "LastVisit" cookie found. Reload the page to see it.
```
---
## Example: Rate Limiting
Showcases high-concurrency state management and request throttling using thread-safe global storage. This example demonstrates the 'IncrementGlobalVar' atomic operation, illustrating how to implement sophisticated IP-based rate limiting with automatic temporal expiration (TTL), essential for protecting public API endpoints from denial-of-service and brute-force attacks in a distributed web environment.
### Source Code
```pascal
// Rate Limiting: Showcases high-concurrency state management and request throttling using thread-safe global storage. This example demonstrates the 'IncrementGlobalVar' atomic operation, illustrating how to implement sophisticated IP-based rate limiting with automatic temporal expiration (TTL), essential for protecting public API endpoints from denial-of-service and brute-force attacks in a distributed web environment.
var remoteIP := WebRequest.RemoteIP;
if remoteIP = '' then remoteIP := '127.0.0.1'; // Fallback for testing
// Define the rate limit key
var rateKey := 'RateLimit.Demo.' + remoteIP;
// Increment the counter. The expiration (10.0 seconds) means that
// if the user stops making requests for 10 seconds, the counter is deleted.
var requestCount := IncrementGlobalVar(rateKey, 1, 10.0);
PrintLn('
Rate Limiter Demo
');
PrintLn('
IP Address: ' + remoteIP + '
');
PrintLn('
Request count in the last 10 seconds: ' + IntToStr(requestCount) + '
');
if requestCount > 5 then begin
PrintLn('
');
PrintLn(' Limit Exceeded! You have made more than 5 requests in 10 seconds.');
PrintLn(' Please wait 10 seconds before trying again.');
PrintLn('
');
end else begin
PrintLn('
');
PrintLn(' Access Granted. You are within the allowed limit (5 requests per 10s).');
PrintLn(' Refresh this page rapidly to trigger the rate limit.');
PrintLn('
');
end;
PrintLn('');
PrintLn('
The rate limit is tracked using a thread-safe global variable that expires automatically.
');
```
### Output
```text
Rate Limiter Demo
IP Address: ::1
Request count in the last 10 seconds: 1
Access Granted. You are within the allowed limit (5 requests per 10s).
Refresh this page rapidly to trigger the rate limit.
The rate limit is tracked using a thread-safe global variable that expires automatically.
```
---
## Example: Secure Redirects
Illustrates robust URL routing and input validation patterns for web security. This example demonstrates using 'WebResponse.SetStatusRedirect' for HTTP 302 responses, showcasing a defensive whitelist validation logic to mitigate Open Redirect vulnerabilities and ensure users remain within trusted domain boundaries.
### Source Code
```pascal
```
### Output
```text
Usage: ?target=/doc.dws
```
---
## Example: Response Management
Showcases the versatile 'WebResponse' API for controlling server output and status codes. This example demonstrates high-level shortcuts like 'SetContentJSON' for automated data serialization, 'SetStatusPlainText' for custom error responses, and 'SetStatusRedirect' for seamless navigation control.
### Source Code
```pascal
Response Control Demo
```
---
## Example: Server Diagnostics
Illustrates runtime server introspection using the 'WebServer' object. This example demonstrates how to programmatically retrieve active server configuration, monitor live database queries via JSON status dumps, and inspect the compiled program cache for performance monitoring and troubleshooting.
### Source Code
```pascal
WebServer Information
Server Name:
HTTP Port: 0 then 'Active' else 'Inactive' ?>
HTTPS Port: 0 then 'Active' else 'Inactive' ?>
Active Sessions / Queries
Compiled Programs (Top 5)
0 then begin
?>
0 then
progName := progName.AfterLast('\');
PrintLn(#9'
```
---
## Example: Secure Sessions
Demonstrates robust state management and defense-in-depth strategies for web applications. This example showcases the use of 'Nonces' for session token generation and mandatory CSRF protection, illustrating how to manage secure cookies with HttpOnly and Strict flags to prevent unauthorized access and cross-site attacks.
### Source Code
```pascal
'' then begin
loggedInUser := Nonces.GetData(sessionToken);
end;
// Handle Logout
if action = 'logout' then begin
if sessionToken <> '' then begin
Nonces.Remove(sessionToken); // Invalidate server-side
WebResponse.SetCookie(cookieName, '', Now - 1, '/', '', Integer(WebCookieFlag.HttpOnly), WebCookieSameSite.Strict);
end;
loggedInUser := '';
PrintLn('
Logged out successfully.
');
end;
// Handle Login
if (user <> '') and (pass <> '') then begin
// Validate CSRF Token (One-time use)
if not Nonces.CheckAndRemove(csrfToken, 'csrf-login') then begin
PrintLn('
Security violation: Invalid or expired CSRF token.
');
end else if (user = 'admin') and (pass = 'password') then begin
// Generate secure session token (1 hour expiration)
// We store the username directly in the nonce data
var newToken := Nonces.Generate(3600 * 1000, user);
// Set secure cookie
WebResponse.SetCookie(cookieName, newToken, Now + (1/24), '/', '', Integer(WebCookieFlag.HttpOnly), WebCookieSameSite.Strict);
loggedInUser := user;
PrintLn('
Login successful!
');
end else begin
PrintLn('
Invalid credentials.
');
end;
end;
// Generate new CSRF token for the form (valid for 10 minutes)
var newCsrf := Nonces.Generate(600 * 1000, 'csrf-login');
PrintLn('
```
---
## Example: Server-Sent Events (SSE)
Showcases modern real-time communication patterns between the server and web clients. This example demonstrates using 'WebResponse.SetContentEventStream' to maintain persistent HTTP connections and the 'WebServerSentEvent' class to broadcast live data updates to multiple subscribers using a name-based channel pattern.
### Source Code
```pascal
Server-Sent Events Demo
This page connects to the server and listens for real-time events.
Connecting...
');
end;
?>
```
### Output
```text
Server-Sent Events Demo
This page connects to the server and listens for real-time events.