5 releases

Uses new Rust 2024

0.1.8 Jul 23, 2026
0.1.6 May 12, 2026
0.1.5 May 6, 2026
0.1.4 May 6, 2026
0.1.3 Apr 18, 2026

#271 in Programming languages


Used in 3 crates

AGPL-3.0-or-later

370KB
9K SLoC

Rust 7.5K SLoC // 0.0% comments LALRPOP 1K SLoC // 0.1% comments

rowl

rowl is a Rust parser for the Dolfin Ontology Language (.dlf files).

It is the core parsing library used by CLI tools, code generators, and other crates in the Dolfin ecosystem.

Overview

Dolfin is an indentation-based language for defining ontologies: concepts, properties, inference rules, and enumerations. rowl turns Dolfin source files into a typed AST that downstream crates can traverse, validate, or transform.

prefix com.example.common:
  Address

concept Department:
  one of:
    engineering
    sales
    marketing
    hr

concept Person:
  has firstName: string
  has lastName: string
  has email: string
  has address: Address

concept Employee:
  sub Person
  has key employeeId: string
  has department: Department
  has salary: float

property worksFor: Employee -> Organization
property manages: optional Manager -> some Employee

Installation

Add rowl to your Cargo.toml. If you only need the Rust library (no Python bindings), disable the default features:

[dependencies]
rowl = { version = "0.1.3", default-features = false }

The python and extension-module features (enabled by default) are only needed when building a PyO3 extension module.

Usage

Parse a string

use rowl::parser::parse_ontology;

let source = r#"
concept Person:
    has name: string
    has age: optional int
"#;

let result = parse_ontology(source);

match result.ontology {
    Some(ontology) if !result.has_errors() => {
        println!("Parsed {} declarations", ontology.declarations.len());
        for concept in ontology.concepts() {
            println!("Concept: {}", concept.name.get());
        }
    }
    _ => eprintln!("{}", result.format_diagnostics(None, None)),
}

Parse a file

use rowl::parser::parse_ontology_file;

let result = parse_ontology_file("path/to/ontology.dlf");

Parse a package (directory of .dlf files)

use rowl::parser::parse_package;

let package = parse_package("path/to/package/").unwrap();

Preserve comments (for formatters / linters)

use rowl::parser::parse_ontology_with_comments;

let parsed = parse_ontology_with_comments(source);
// parsed.result : the AST
// parsed.comments: comments with their source positions

AST

The root node returned by a successful parse is OntologyFile:

Field Type Description
prefixes Vec<PrefixDecl> Namespace prefix aliases
declarations Vec<Declaration> All top-level declarations
iri_name Option<String> Optional IRI override via @iri_name

Declaration is an enum with three variants: Concept, Property, and Rule: each holding its own definition struct.

Convenience accessors on OntologyFile:

ontology.concepts()    // Vec<ConceptDef>
ontology.properties()  // Vec<PropertyDef>
ontology.rules()       // Vec<RuleDef>

Concepts

pub struct ConceptDef {
    pub name: SpannedString,
    pub parents: Vec<TypeRef>,          // `sub` declarations
    pub has_declarations: Vec<HasDeclaration>,
    pub one_of: Option<Vec<OneOfVariant>>, // closed-world individuals
}

Properties

pub struct PropertyDef {
    pub name: SpannedString,
    pub domain: TypeRef,
    pub domain_cardinality: Option<Cardinality>,
    pub range: TypeRef,
    pub range_cardinality: Option<Cardinality>,
}

Cardinality

Variant Dolfin syntax
One (default, omitted)
Optional optional
Some some
Any any
Exact(n) 3
Range(min, max) 2..5 / 2..*

Rules

Rules express inference logic via match/then blocks:

rule EmployeeHasManager:
  match:
    ?e worksFor ?org
    ?e is Employee
  then:
    ?e reportsTo ?manager
pub struct RuleDef {
    pub name: String,
    pub match_block: MatchBlock,  // Vec<Pattern>
    pub then_block: ThenBlock,    // Vec<ThenItem>
}

Diagnostics

Parsing always succeeds structurally: errors are collected into the ParseResult rather than panicking:

let result = parse_ontology(source);

if result.has_errors() {
    // Human-readable, with source context
    eprintln!("{}", result.format_diagnostics(Some("file.dlf"), Some(source)));
}

Each diagnostic carries a Location (line, column, offset) and an ErrorCode.

Features

Feature Default Description
python yes Enables PyO3 bindings
extension-module yes Enables PyO3 extension-module (required for .so builds)

Disable both when using rowl as a pure Rust library.

Python bindings

rowl ships with optional Python bindings built with PyO3. The python and extension-module features (enabled by default) expose the full parser and AST to Python.

Installation

pip install rowl

Usage

import rowl

source = """
concept Person:
  has name: string
  has age: optional int
"""

ontology = rowl.parse(source)

for decl in ontology.declarations:
    print(decl.kind, decl.name)
    if decl.kind == "concept":
        for prop in decl.concept.has_declarations:
            print(f"  has {prop.name}: {prop.type_ref}")

Parse from a file:

ontology = rowl.parse_file("path/to/ontology.dlf")

Tokenize (debugging):

tokens = rowl.tokenize("concept Person:\n  has name: string\n")
print(tokens)
# ['concept', 'Person', ':', 'NEWLINE', 'INDENT', 'has', 'name', ':', 'string', ...]

Version:

print(rowl.version())  # e.g. "0.1.3"

Available classes

All AST types are exposed as Python classes with read-only attributes mirroring the Rust structs: OntologyFile, Declaration, ConceptDef, HasDeclaration, PropertyDef, RuleDef, MatchBlock, ThenBlock, ThenItem, Pattern, Subject, Object, Assertion, TypeRef, Cardinality, Quantifier, Literal, QualifiedName, and more.

Language documentation

Full language reference: dolfin.fr/docs

License

AGPL-3.0-or-later


lib.rs:

Dolfin - A parser for the Dolfin ontology language.

This crate provides a parser for the Dolfin language, which is an indentation-based language for defining ontologies.

Example (Rust)

use rowl::parser;

let source = r#"
concept Person:
    has name: string
    has age: optional int
"#;
let result = parser::parse_ontology(source);
match result.ontology {
    Some(ontology) if !result.has_errors() => println!("Parsed {} statements", ontology.declarations.len()),
    _ => eprintln!("Parse error: {}", result.format_diagnostics(None, None)),
}

Example (Python)

import rowl

source = """
namespace com.example

ontology MyOntology:
  concept Person:
    has name: string
"""

program = rowl.parse(source)
for stmt in program.statements:
    print(stmt)

Dependencies

~7–13MB
~182K SLoC