{"id":44708288,"url":"https://github.com/ikelaiah/toml-fp","last_synced_at":"2026-02-15T11:13:37.094Z","repository":{"id":270687210,"uuid":"911148447","full_name":"ikelaiah/toml-fp","owner":"ikelaiah","description":"Simplify parsing and writing TOML config files in Free Pascal","archived":false,"fork":false,"pushed_at":"2025-05-18T09:54:12.000Z","size":310,"stargazers_count":13,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-18T10:32:44.102Z","etag":null,"topics":["free-pascal","freepascal","lazarus-ide","object-pascal","toml","toml-parser"],"latest_commit_sha":null,"homepage":"https://github.com/ikelaiah/toml-fp","language":"Pascal","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ikelaiah.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-01-02T10:56:35.000Z","updated_at":"2025-05-18T09:54:15.000Z","dependencies_parsed_at":"2025-05-10T21:23:05.600Z","dependency_job_id":"5f076428-6a31-4651-bb3c-bea1a77d5e3a","html_url":"https://github.com/ikelaiah/toml-fp","commit_stats":null,"previous_names":["ikelaiah/toml-fp"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ikelaiah/toml-fp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ikelaiah%2Ftoml-fp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ikelaiah%2Ftoml-fp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ikelaiah%2Ftoml-fp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ikelaiah%2Ftoml-fp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ikelaiah","download_url":"https://codeload.github.com/ikelaiah/toml-fp/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ikelaiah%2Ftoml-fp/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29476300,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-15T10:25:47.032Z","status":"ssl_error","status_checked_at":"2026-02-15T10:25:01.815Z","response_time":118,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["free-pascal","freepascal","lazarus-ide","object-pascal","toml","toml-parser"],"created_at":"2026-02-15T11:13:36.553Z","updated_at":"2026-02-15T11:13:37.082Z","avatar_url":"https://github.com/ikelaiah.png","language":"Pascal","funding_links":[],"categories":[],"sub_categories":[],"readme":"# TOML Parser for Free Pascal\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![Free Pascal](https://img.shields.io/badge/Free%20Pascal-3.2.2-blue.svg)](https://www.freepascal.org/)\n[![Lazarus](https://img.shields.io/badge/Lazarus-4.0-orange.svg)](https://www.lazarus-ide.org/)\n[![TOML](https://img.shields.io/badge/TOML-1.0.0-green.svg)](https://toml.io/)\n[![Version](https://img.shields.io/badge/Version-1.0.3-blueviolet.svg)]()\n\nA robust [TOML (Tom's Obvious, Minimal Language)](https://toml.io/) parser and serializer for Free Pascal, _almost_ fully compliant with the TOML v1.0.0 specification.\n\n\u003e [!NOTE] \n\u003e \n\u003e Our extensive test suite (60 tests) ensures that TOML-FP adheres to the TOML v1.0.0 specification, covering all essential data types, structures, and edge cases.\n\n## Table of Contents\n\n- [TOML Parser for Free Pascal](#toml-parser-for-free-pascal)\n  - [Table of Contents](#table-of-contents)\n  - [Overview](#overview)\n  - [Features](#features)\n  - [To Do / In Progress](#to-do--in-progress)\n  - [Requirements](#requirements)\n  - [Installation](#installation)\n    - [Steps](#steps)\n  - [Quick Start](#quick-start)\n    - [Basic Usage](#basic-usage)\n    - [Writing TOML Files](#writing-toml-files)\n  - [Documentation](#documentation)\n    - [Common Use Cases](#common-use-cases)\n      - [Working with Arrays](#working-with-arrays)\n      - [Nested Tables](#nested-tables)\n      - [Hierarchical Paths vs Literal Dotted Keys](#hierarchical-paths-vs-literal-dotted-keys)\n      - [Serializing Complex Structures](#serializing-complex-structures)\n    - [Memory Management](#memory-management)\n      - [Creating Tables](#creating-tables)\n      - [Adding Nested Tables or Values](#adding-nested-tables-or-values)\n      - [Freeing Tables:](#freeing-tables)\n      - [Avoid Explicitly Freeing Nested Objects:](#avoid-explicitly-freeing-nested-objects)\n  - [API Reference](#api-reference)\n    - [Types](#types)\n    - [Helper Functions for Creating TOML Values](#helper-functions-for-creating-toml-values)\n    - [Parsing Functions](#parsing-functions)\n    - [Serialization Functions](#serialization-functions)\n  - [Testing](#testing)\n    - [Test Coverage Overview](#test-coverage-overview)\n    - [Sample Test Output](#sample-test-output)\n  - [Examples](#examples)\n  - [Contributing](#contributing)\n  - [License](#license)\n  - [Acknowledgments](#acknowledgments)\n\n\n\n## Overview\n\nTOML-FP provides a complete solution for working with TOML configuration files in Free Pascal applications. Whether you need to read configuration files or generate them, TOML-FP offers an intuitive API with comprehensive type support and robust error handling.\n\n## Features\n\n- **Full TOML v1.0.0 Compliance:** Supports all TOML data types and structures, including proper serialization of nested (dotted) tables.\n- **Type-Safe API:** Strong typing with compile-time checks\n- **Memory Management:** Automatic cleanup with proper object lifecycle management\n- **Error Handling:** Detailed error messages and exception handling\n- **Serialization:** Convert Pascal objects to TOML and back\n- **Documentation:** Comprehensive examples and API documentation\n- **Test Suite:** Comprehensive test suite (60 items)\n\n## To Do / In Progress\n\n- [ ] More tests for error handling: Robust testing of invalid inputs and ensuring appropriate error messages or handling mechanisms.\n- [ ] Performance optimization for large TOML files\n- [ ] Additional examples for common use cases\n\n## Requirements\n\n- Free Pascal Compiler 3.2.2 or later\n- Lazarus IDE 4.0 (for running tests)\n\n## Installation\n\n\n### Steps\n\n1. Clone the repository:\n   \n   ```bash\n   git clone https://github.com/ikelaiah/toml-fp.git\n   ```\n\n2. Add to your project:\n   - Copy the `src` directory to your project.\n   - Add the `src` directory to your project's unit search path.\n   - Add the main `TOML` unit to your `uses` clause:\n     ```pascal\n     uses\n       TOML; \n     ```\n   - For direct access to specific types like `TTOMLValueType` or if you prefer explicit qualification, you might also include `TOML.Types`:\n     ```pascal\n     uses\n       TOML, TOML.Types; // If needing TTOMLValueType, etc.\n     ```\n     However, for most common operations (parsing, serializing, using helper functions like `TOMLTable`), `uses TOML;` is sufficient.\n\n## Quick Start\n\n### Basic Usage\n\n```pascal\nprogram BasicParseTOML;\n\n{$mode objfpc}{$H+}{$J-}\n\nuses\n  TOML;\n\nvar\n  Config: TTOMLTable;\n  RevisionValue, ProjectValue, ProjectName: TTOMLValue;\n  ProjectTable: TTOMLTable;\n\nbegin\n  // Parse TOML from file\n  Config := ParseTOMLFromFile('config.toml');\n  try\n\n    // Access a string value\n    if (Config.TryGetValue('revision', RevisionValue)) then\n      WriteLn('The value of ''revision'' is ', RevisionValue.AsString);\n\n    // Access nested values safely\n    if Config.TryGetValue('project', ProjectValue) and\n      (ProjectValue is TTOMLTable) then\n    begin\n      ProjectTable := TTOMLTable(ProjectValue);\n      if ProjectTable.TryGetValue('name', ProjectName) then\n        WriteLn('Project Name: ', ProjectName.AsString)\n      else\n        WriteLn('Project name not found');\n    end\n    else\n      WriteLn('Project configuration not found');\n  finally\n    Config.Free;\n  end;\nend.\n```\n\nExample `config.toml`:\n\n```toml\n# config.toml\n\nrevision = \"1.2.1af\"\n\n[project]\nname = \"My Amazing Project\"\nversion = \"1.0.0\"\n```\n\n\n### Writing TOML Files\n```pascal\nprogram BasicSerializeTOML;\n\n{$mode objfpc}{$H+}{$J-}\n\nuses\n  TOML;\n\nvar\n  Config: TTOMLTable;\n  Database: TTOMLTable;\nbegin\n  Config := TOMLTable;\n  try\n    Database := TOMLTable;\n    Database.Add('host', TOMLString('localhost'));\n    Database.Add('port', TOMLInteger(5432));\n    Config.Add('database', Database);\n\n    if SerializeTOMLToFile(Config, 'config.toml') then\n      WriteLn('Configuration saved successfully')\n    else\n      WriteLn('Error saving configuration');\n  finally\n    Config.Free;\n  end.\nend.\n```\n\n## Documentation\n\n### Common Use Cases\n\n#### Working with Arrays\n```pascal\nvar\n  Config: TTOMLTable;\n  Tags: TTOMLArray;\nbegin\n  Config := TOMLTable;\n  try\n    Tags := TOMLArray;\n    Tags.Add(TOMLString('pascal'));\n    Tags.Add(TOMLString('toml'));\n    Config.Add('tags', Tags);\n    \n    WriteLn(SerializeTOML(Config));\n  finally\n    Config.Free;\n  end.\nend.\n```\n\n#### Nested Tables\n```pascal\nvar\n  Config: TTOMLTable;\n  Database, Server: TTOMLTable;\n  SerializedTOML: string;\nbegin\n  Config := TOMLTable;\n  try\n    Database := TOMLTable;\n    Database.Add('host', TOMLString('localhost'));\n    Database.Add('port', TOMLInteger(5432));\n    \n    Server := TOMLTable;\n    Server.Add('database', Database); // Nest Database table under Server\n    \n    Config.Add('server', Server);     // Nest Server table under Config\n    \n    SerializedTOML := SerializeTOML(Config);\n    WriteLn(SerializedTOML);\n    // Expected output:\n    // [server.database]\n    // host = \"localhost\"\n    // port = 5432\n  finally\n    Config.Free; // Frees Config, Server, and Database tables\n  end.\nend.\n```\n\n#### Hierarchical Paths vs Literal Dotted Keys\n\nTOML-FP correctly handles the distinction between hierarchical paths and literal dotted keys as per the TOML specification:\n\n1. **Hierarchical Table Paths**:\n   ```pascal\n   // This creates a nested hierarchy: [server.database]\n   ServerTable := TOMLTable;\n   DatabaseTable := TOMLTable;\n   DatabaseTable.Add('port', TOMLInteger(5432));\n   \n   ServerTable.Add('database', DatabaseTable);\n   Config.Add('server', ServerTable);\n   ```\n   Serializes to:\n   ```toml\n   [server.database]\n   port = 5432\n   ```\n\n2. **Literal Dotted Keys**:\n   ```pascal\n   // This creates a literal dotted key: [\"server.database\"]\n   LiteralTable := TOMLTable;\n   LiteralTable.Add('port', TOMLInteger(5432));\n   \n   Config.Add('server.database', LiteralTable);\n   ```\n   Serializes to:\n   ```toml\n   [\"server.database\"]\n   port = 5432\n   ```\n\nThe serializer automatically determines whether to quote key components based on the TOML specification rules.\n\n\u003e [!TIP]  \n\u003e According to the TOML specification: \"Quoted keys follow the exact same rules as either basic strings or literal strings and allow you to use a much broader set of key names. **Best practice is to use bare keys except when absolutely necessary.**\"\n\u003e\n\u003e In practice, this means you should design your configuration to use hierarchical nesting with simple key names rather than relying on keys with dots or special characters.\n\n#### Serializing Complex Structures\n```pascal\nprogram BasicSerializeTOML;\n\n{$mode objfpc}{$H+}{$J-}\n\nuses\n  TOML, SysUtils;\n\nvar\n  Config, ServerConfig: TTOMLTable;\n  Ports: TTOMLArray;\n  SerializedTOML: string;\nbegin\n  Config := TOMLTable;\n  try\n    // Create a nested table\n    ServerConfig := TOMLTable;\n    ServerConfig.Add('host', TOMLString('127.0.0.1'));\n    ServerConfig.Add('enabled', TOMLBoolean(True));\n\n    // Create and populate an array\n    Ports := TOMLArray;\n    Ports.Add(TOMLInteger(80));\n    Ports.Add(TOMLInteger(443));\n    ServerConfig.Add('ports', Ports);\n\n    // Add the server config to main config\n    Config.Add('server', ServerConfig);\n\n    // Add some basic metadata\n    Config.Add('version', TOMLFloat(1.0));\n    Config.Add('last_updated', TOMLDateTime(Now));\n\n    // Serialize to TOML format\n    SerializedTOML := SerializeTOML(Config);\n    WriteLn('Generated TOML:');\n    WriteLn(SerializedTOML);\n\n    // Save to file\n    if SerializeTOMLToFile(Config, 'config.toml') then\n      WriteLn('Successfully saved to file')\n    else\n      WriteLn('Error saving to file');\n\n  finally\n    Config.Free;\n  end.\nend.\n```\n\nThis will generate TOML like:\n```toml\nversion = 1.0\nlast_updated = 2024-03-20T15:30:45Z\n\n[server]\nhost = \"127.0.0.1\"\nenabled = true\nports = [ 80, 443 ]\n```\n\nNote: All values are properly type-checked and memory-managed. The library ensures that:\n- Each value has the correct TOML type\n- Arrays maintain type consistency\n- All objects are properly freed\n- Type conversions are validated\n\n\n### Memory Management\n\n\u003e [!NOTE]\n\u003e\n\u003e **Only free the top-level owner table** to avoid memory management issues.\n\n- Proper memory management is essential to prevent memory leaks in your applications. TOML-FP follows a clear ownership hierarchy where parent tables own their nested tables and values. Here's how it works:\n\n#### Creating Tables\n- When you create a `TTOMLTable`, it acts as an owner for any nested tables or values you add to it.\n\n#### Adding Nested Tables or Values\n- Use the `Add` method to insert nested tables or values into a parent table.\n- Example:\n\n```pascal\nvar\n  Config: TTOMLTable;\n  Database: TTOMLTable;\nbegin\n  Config := TOMLTable;\n  Database := TOMLTable;\n  Config.Add('database', Database);\n  // ...\n  Config.Free; // This frees all nested tables and values\nend.\n``` \n\n#### Freeing Tables:\n- **Only free the top-level owner table**.\n- Frees all nested tables and values automatically.\n- Example:\n\n```pascal\nvar\n  Config: TTOMLTable;\nbegin\n  Config := TOMLTable;\n  // ... add nested tables and values ...\n  Config.Free; // This frees all nested tables and values\nend.\n```\n\n#### Avoid Explicitly Freeing Nested Objects:\n\n- Do not manually free nested tables or values to prevent memory management issues.\n\n## API Reference\n\n### Types\n\n- `TTOMLValue` - Base type for all TOML values\n- `TTOMLTable` - Represents a TOML table\n- `TTOMLArray` - Represents a TOML array\n- `TTOMLString` - Represents a TOML string value\n- `TTOMLInteger` - Represents a TOML integer value\n- `TTOMLFloat` - Represents a TOML float value\n- `TTOMLBoolean` - Represents a TOML boolean value\n- `TTOMLDateTime` - Represents a TOML datetime value\n\n### Helper Functions for Creating TOML Values\n\n- `TOMLString`\n\n```pascal\n  function TOMLString(const AValue: string): TTOMLString;\n```\nCreates a TOML string value.\n\n- `TOMLInteger`\n\n```pascal\n  function TOMLInteger(const AValue: Int64): TTOMLInteger;\n```\nCreates a TOML integer value.\n\n- `TOMLFloat`\n\n```pascal\n  function TOMLFloat(const AValue: Double): TTOMLFloat;\n```\nCreates a TOML float value.\n\n- `TOMLBoolean` \n\n```pascal\n    function TOMLBoolean(const AValue: Boolean): TTOMLBoolean;\n```\nCreates a TOML boolean value.\n\n- `TOMLDateTime`\n\n```pascal\n    function TOMLDateTime(const AValue: TDateTime): TTOMLDateTime;\n```\nCreates a TOML datetime value.\n\n- `TOMLArray` \n\n```pascal\n  function TOMLArray: TTOMLArray;\n```\nCreates a TOML array.\n\n- `TOMLTable`\n\n```pascal\n  function TOMLTable: TTOMLTable;\n```\nCreates a TOML table.\n\n### Parsing Functions\n\n- `ParseTOML`\n\n```pascal\n  function ParseTOML(const ATOML: string): TTOMLTable;\n```\nParses a TOML-formatted string into a `TTOMLTable` object. Raises `ETOMLParserException` on error.\n\n- `ParseTOMLFromFile`\n\n```pascal\n  function ParseTOMLFromFile(const AFileName: string): TTOMLTable;\n```\nParses a TOML file into a `TTOMLTable` object. Reads the file content and then parses it. Raises `ETOMLParserException` on parsing errors or file system errors.\n\n### Serialization Functions\n- `SerializeTOML`\n\n```pascal\n  function SerializeTOML(const AValue: TTOMLValue): string;\n```\nSerializes a `TTOMLValue` (typically a `TTOMLTable` for a whole document) into a TOML-formatted string.\n\n- `SerializeTOMLToFile`\n\n```pascal\n  function SerializeTOMLToFile(const AValue: TTOMLValue; const AFileName: string): Boolean;\n```\nSerializes a `TTOMLValue` and saves it to the specified file. Returns `True` on success, `False` on failure (e.g., file I/O error).\n\n## Testing\n\nThe library includes a comprehensive test suite (60 items). \n\nTo run the tests:\n\n1. Open `tests/TestRunner.lpi` in Lazarus\n2. Build and run the project\n\n### Test Coverage Overview\n\nSee [Test-Coverage-Overview.md](docs/Test-Coverage-Overview.md) for details.\n\n- Basic Types:\n  - Strings, Integers, Floats, Booleans, DateTime\n- Advanced Structures:\n  - Multiline and Literal Strings\n  - Homogeneous and Mixed-Type Arrays\n  - Nested and Inline Tables\n- Serialization:\n  - Accurate conversion of Pascal objects to TOML format and vice versa\n- Error Handling:\n  - Robust tests for invalid inputs, duplicate keys, and other edge cases\n\n### Sample Test Output\n\n```bash\n$ ./TestRunner.exe -a --format=plain\n Time:00.049 N:60 E:0 F:0 I:0\n  TTOMLTestCase Time:00.049 N:60 E:0 F:0 I:0\n    Test01_StringValue\n    Test02_IntegerValue\n    ...\n    Test72_LiteralDottedKeyTable\n\nNumber of run tests: 60\nNumber of errors:    0\nNumber of failures:  0\n\nHeap dump by heaptrc unit of path\\to\\TestRunner.exe\n3871 memory blocks allocated : 248475/265224\n3871 memory blocks freed     : 248475/265224\n0 unfreed memory blocks : 0\nTrue heap size : 294912 (256 used in System startup)\nTrue free heap : 294656\n``` \n\n## Examples\n\nCheck out the `examples` directory and the test cases, `tests/TestCaseTOML.pas`, for more detailed usage examples:\n\n- Basic Configuration Reading\n- Writing Complex Data Structures\n- Error Handling Patterns\n- Integration Examples\n\n## Contributing\n\n1. Fork the repository\n2. Create your feature branch (`git checkout -b feature/AmazingFeature`)\n3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)\n4. Push to the branch (`git push origin feature/AmazingFeature`)\n5. Open a Pull Request\n\nPlease ensure:\n\n- Code follows the project's style guidelines\n- All tests pass\n- New features include appropriate tests\n- Documentation is updated\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details.\n\n## Acknowledgments\n\n- TOML specification creators and maintainers\n- Free Pascal and Lazarus communities\n- [SilenceCFF](https://github.com/SilenceCCF)\n- All contributors to this project\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fikelaiah%2Ftoml-fp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fikelaiah%2Ftoml-fp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fikelaiah%2Ftoml-fp/lists"}