# 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('

Bubble Sort

'); Print('Original: '); PrintArray(data1); BubbleSort(data1); Print('Sorted: '); PrintArray(data1); PrintLn('
'); PrintLn('

Quick Sort

'); Print('Original: '); PrintArray(data2); QuickSort(data2); Print('Sorted: '); PrintArray(data2); ?> ``` ### Output ```text

Bubble Sort

Original: [64, 34, 25, 12, 22, 11, 90] Sorted: [64, 34, 25, 12, 22, 11, 90]

Quick Sort

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('
' + JSON.Stringify(jsonObj) + '
'); // Parsing JSON var jsonStr := JSON.Stringify(jsonObj); var parsedObj := JSON.Parse(jsonStr); PrintLn('Parsed Data:'); PrintLn('Name: ' + parsedObj.name); PrintLn('Active: ' + (if parsedObj.active then 'Yes' else 'No')); PrintLn('First Tag: ' + parsedObj.tags[0]); ?> ``` ### Output ```text Generated JSON:
{"name":"DWScript","version":2,"active":true,"tags":["pascal","web","scripting"]}
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(''); // ds.Step() is a convenient way to iterate: it moves to the next record and returns True while ds.Step do begin PrintLn(Format( '', [ ds.AsString(0).ToHtml, ds.AsString(1).ToHtml, ds.AsInteger(2) ] )); end; PrintLn('
NameEmailLevel
%s%s%d
'); ``` ### Output ```text

High-Performance Bulk Insert

Passing 4 records as a single JSON parameter.

Resulting Table:

NameEmailLevel
Davedave@example.com20
Bobbob@example.com12
Charliecharlie@example.com8
Alicealice@example.com5
``` --- ## 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('

DataSet Operations

'); PrintLn('Field Count: ' + IntToStr(ds.FieldCount)); PrintLn(''); // Forward-only iteration PrintLn('

Forward Iteration

'); // 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

DataSet Operations

Field Count: 3

Forward Iteration

[1] Event 1 (Level: 10) [2] Event 2 (Level: 20) [3] Event 3 (Level: 30) [4] Event 4 (Level: 40) [5] Event 5 (Level: 50)

Typed Access

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(''); PrintLn(''); while ds.Step do begin PrintLn(Format( '', [ ds.AsString(0).ToHtml, ds.AsFloat(1) ] )); end; PrintLn('
NamePrice
%s$%.2f
'); ``` ### Output ```text

JSON Stringification

1. StringifyAll (Multiple Records)

[{"Name":"Mechanical Keyboard","Price":120.5},{"Name":"Gaming Mouse","Price":59.99}]

2. Stringify (Current Record)

{"ID":3,"Name":"UltraWide Monitor","Price":450,"Category":"Display"}

3. Result as Table

NamePrice
Mechanical Keyboard$120.50
Gaming Mouse$59.99
UltraWide Monitor$450.00
``` --- ## 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('

Processed Features & Predictions

'); PrintLn(data.ExportToSeparated(['Timestamp', 'Normalized', 'Prediction', 'ErrorRate']).Replace(#10, '
')); // 5. Aggregate Metrics var avgError := data.EvaluateAggregate('sum', [ '"ErrorRate"' ]) / 5; PrintLn('

Summary Metrics

'); 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

Raw Sensor Data

Timestamp,Signal,Actual
1000,0.5,0.6
1010,-1.2,0.1
1020,3.4,3
1030,2.1,2.5
1040,-0.8,0.1

Processed Features & Predictions

Timestamp,Normalized,Prediction,ErrorRate
1000,0.369565217391304,1.25,0.351351351351351
1010,0,0,1
1020,1,5.6,0.302325581395349
1030,0.717391304347826,3.65,0.186991869918699
1040,0.0869565217391304,0,1

Summary Metrics

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 User Valid! 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('

Iterative Approach

'); PrintLn('Fibonacci(' + IntToStr(n) + ') = ' + IntToStr(FibonacciIterative(n))); PrintLn('
'); PrintLn('

Sequence Output (Iterative)

'); 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('
    '); for var s in parts do PrintLn('
  • ' + s + '
  • '); PrintLn('
'); // Replacing var replaced := trimmed.Replace('Pascal', 'DWScript'); PrintLn('Replaced: "' + replaced + '"'); // Substrings and Deletion var s := '123456789'; PrintLn('Substring (2,3): ' + s.Copy(2, 3)); // 234 PrintLn('Substring (5+): ' + s.Copy(5)); // 56789 PrintLn('Delete Left (3): ' + s.DeleteLeft(3)); // 456789 PrintLn('Delete Right (3): ' + s.DeleteRight(3)); // 123456 // Formatting var formatted := Format( 'Item: %s, Count: %d, Price: %.2f', [ 'Apple', 5, 1.25 ] ); PrintLn('Formatted: ' + formatted); ?> ``` ### Output ```text Original: " Pascal,Scripting,Web " Trimmed: "Pascal,Scripting,Web" Split parts:
  • Pascal
  • Scripting
  • Web
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.

Request Headers

Cache-Control=no-cache
Connection=Keep-Alive
Pragma=no-cache
Accept=*/*
Host=localhost:888
User-Agent=Mozilla/5.0 (Windows; Synopse DWScript)
``` --- ## 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 '); end; ?> ``` ### Output ```text

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'
  • ' + progName.ToHtml + '
  • '); end; ?>

No programs currently in cache.

``` ### Output ```text

WebServer Information

  • Server Name: DWScript
  • HTTP Port: Active
  • HTTPS Port: Inactive

Active Sessions / Queries

[
	{
		"id" : 18011696,
		"path" : "\/examples\/web_server_info_845465_tmp.dws",
		"query" : "",
		"ip" : "::1",
		"ms" : 0,
		"sleeping" : false,
		"options" : [ ]
	},
	{
		"id" : 18011634,
		"path" : "\/test\/index.dws",
		"query" : "action=update_examples&api=1",
		"ip" : "::1",
		"ms" : 1734,
		"sleeping" : false,
		"options" : [ ]
	}
]

Compiled Programs (Top 5)

  • assoc_iteration.dws
  • attribute_validation.dws
  • json_demo.dws
  • sqlite_basics.dws
  • math_biginteger_demo_653454_tmp.dws
``` --- ## 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('

Session State

'); if loggedInUser <> '' then begin PrintLn('

Welcome back, ' + StrToHtml(loggedInUser) + '!

'); PrintLn('

Session Token: ' + sessionToken + '

'); PrintLn('Logout'); end else begin PrintLn('

You are not logged in.

'); PrintLn('
'); // CSRF Protection PrintLn(' '); PrintLn('
'); PrintLn(' '); PrintLn(' '); PrintLn('
'); PrintLn('
'); PrintLn(' '); PrintLn(' '); PrintLn('
'); PrintLn(' '); PrintLn('
'); end; ?> ``` ### Output ```text

Session State

You are not logged in.

``` --- ## 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.

Connecting...
``` ---