Nelumbo documentation

Nelumbo

Nelumbo is a declarative logic programming language that you extend from inside the language. You define the syntax and semantics of your language in a .nl file, and the same file runs and tests it. Because Nelumbo reasons about facts and falsehoods as peers, it has genuine logical negation — not Prolog's negation-as-failure — and produces results as a two-sided [facts][falsehoods] structure.

Status: Nelumbo is at an early stage of development. Some features are still evolving; where that matters, individual pages note it.

This folder contains the user documentation. For the project overview, build instructions, and release notes, see the repository README. For the presentation-deck version of this material, see NELUMBO.md.


The levels

Nelumbo is built in levels, and each piece of syntax belongs to exactly one of them. The reference is organised the same way, so you can always tell where a construct comes from.

Java core               bootstrap grammar, reasoner, natives
 └─ nelumbo.lang        import nelumbo.lang
     └─ nelumbo.logic   import nelumbo.logic
         └─ nelumbo.integers
             └─ nelumbo.strings, nelumbo.rationals, nelumbo.collections, nelumbo.datetime
  • Java core. The tokenizer, the reasoner, @-bound natives, and a small bootstrap grammar that exists only to load lang.nl.
  • nelumbo.lang. The syntax for declaring syntax: types (::), patterns (::=), named patterns, variables, scope blocks, visibility, precedence, and ::> transformations.
  • nelumbo.logic. Three-valued logic: Boolean, the connectives, quantifiers, equality, and the statements that drive execution (fact, <=>, ?).
  • Packages. Integers, rationals, strings, collections and date-times. Import the ones you need.

Importing a level brings in everything above it in the diagram, so import nelumbo.integers also gives you nelumbo.logic and nelumbo.lang. That is why most files start with a single package import.


Start here

  1. Reading a query and test — the first thing to read. Without this, every .nl file in the repo is unreadable because every example ends with tests in the ? [facts][falsehoods] notation.
  2. Your first program — line-by-line walkthrough of fibonacci.nl, exercising imports, patterns, rules with guards, and tests.

Thirty minutes with those two pages is enough to open any .nl file in the repo and follow what's going on.


Reading paths

Different readers want different things. Pick the path that matches your goal.

"I want to understand what Nelumbo is and why."

"I want to write my own DSL using Nelumbo."

"I want to extend Nelumbo with a new primitive in Java."

"I want to read the shipped modules to learn idiom."

"I need to look something up."

Jump straight to the reference sections below, starting at Reference: Core. Everything in reference/ is organised as a lookup, not a read-through.


Full table of contents

Getting started

Reference: Core

The Java level. Always present.

Reference: Lang

nelumbo.lang, the syntax for declaring syntax.

Reference: Logic

nelumbo.logic, three-valued logic and the statements that drive execution.

Reference: Packages

Optional. Each one imports nelumbo.logic, directly or through nelumbo.integers.

Reference: Tooling

  • Formatting — the canonical whitespace layout the LSP formatter produces

Guides

Task-oriented how-tos.

Explanation

Background and design.


Map of the example files

The .nl files under src/main/resources/org/modelingvalue/nelumbo/examples/ are the canonical worked examples. A short guide to what's in each:

File What it demonstrates
fibonacci.nl Integer arithmetic, recursive rule with guards, basic tests
family.nl Types, subtypes, Boolean, literal enumerations, ancestor/descendant recursion
friends.nl Mutually-recursive relations, symmetric + transitive closure
even.nl Simplest useful predicate using an existential quantifier
max.nl, ternary.nl Generic types (Type T), conditional expressions, user-defined operators
power.nl, maxFib.nl Composed recursive definitions
belasting.nl Natural-language DSL (Dutch tax rules) using multi-word pattern syntax
transformation.nl, deHet.nl Language transformations with ::> — defining new top-level keywords
scoping.nl, hidden.nl Scope blocks and hidden-variable patterns
whoIs.nl Importing a user-written module (not just stdlib)
queryOnly.nl Bare queries without [..][..] — useful during development
*Assignment.nl "Fill in the rules" exercise versions of the corresponding examples

Map of the test files

The *Test.nl files under src/main/resources/org/modelingvalue/nelumbo/tests/ are executable specifications — useful to skim for corner cases:

File What it specifies
logicTest.nl The three-valued logic truth tables
integersTest.nl, rationalsTest.nl, stringsTest.nl, collectionsTest.nl Per-stdlib-module behaviour for each data type
datetimeTest.nl Every datetime operator and the parse-time edge cases
langTest.nl Smoke test that imports nelumbo.lang on its own

A note on conventions used in the docs

  • .. is the incompleteness marker — it means "this side of the result may have more bindings than are listed." It is never called a wildcard because it doesn't match values. Inside a collection ({Juliana,..}) it marks that set or list as open.
  • Facts (left bracket) and falsehoods (right bracket) are the two sides of every query result.
  • In-language extensions (rules, transformations, modules) are distinguished from host-language extensions (Java natives bound with @). The docs use these terms consistently.
  • Cross-references in every page point to other pages when a topic is covered in more depth elsewhere. If you follow the links, you end up with a coherent tour of the language.

Feedback and contributing

The documentation is new and will have errors. Corrections and suggestions are welcome via the GitHub issue tracker. The source files for the docs are under docs/ in the repository.