Describe a regular expression in English. Get one on stdout.
FluentRE is a controlled natural language: a restricted subset of English with a formal grammar and a deterministic translation into regular expressions. There is no language model in this program. It is a compiler.
This is the Odin implementation. It has no dependencies.
$ fluentre "beginning letter of any word starting with a capital letter"
\b[A-Z]
$ echo "Testing NASA and USA against Regular Words." \
| grep -oP "$(fluentre 'beginning letter of any word starting with a capital letter')"
T
N
U
R
WNeeds the Odin compiler and a working clang (Odin uses it to link).
$ cd cli
$ odin build . --out=fluentre
$ cd ..
$ odin test testsBoth must be run from the project root: the isolation tests read LICENSE and
list the source directories by relative path.
The suite runs clean under Odin's memory tracker. FluentRE itself allocates
freely and never frees — the process compiles one description and exits, so the
allocator is an arena on purpose — but each test redirects context.allocator
to a per-test arena and destroys it afterwards. Leave tracking on: a leak report
now means a real defect rather than expected noise.
| Description | Pattern |
|---|---|
a letter or a digit |
[0-9A-Za-z] |
a letter but not a vowel |
[B-DF-HJ-NP-TV-Zb-df-hj-np-tv-z] |
a character that is not a digit |
\D |
three digits then a dash then four digits |
\d{3}-\d{4} |
a word made of capitals |
\b[A-Z]+\b |
a word that starts with a capital and ends with a digit |
\b(?=[A-Z])(?=\w*\d\b)\w+\b |
a word without a vowel |
\b(?!\w*[AEIOUaeiou])\w+\b |
digits preceded by a dollar sign |
(?<=\$)\d+ |
a hyphen between digits |
\d+-\d+ |
twelve T's then the number 5 |
T{12}5 |
[ then a space |
\[\x20 |
The full language is specified in LanguageSpec.md, section by section, and
every section has a test named after it in tests/spec_test.odin.
Coverage is combinatorial, not linear. A phrase table of 571 rows answers 571 questions. 571 terminals under a grammar with alternation, sequencing, quantification, negation and nesting answer effectively unbounded many.
Set algebra actually works. "A letter but not a vowel" is a set difference,
folded at compile time exactly the way a compiler folds 2 + 3 into 5.
It tells you when it does not understand. A model that misreads you emits a confident, plausible, wrong pattern and you find out in production. A parser points at the word:
$ fluentre "three digts"
error: don't know what "digts" means
|
| three digts
| ^^^^^
= did you mean "digits"?
= note: `fluentre --words` lists every phrase the language knows
$ fluentre "capital words"
error: "capital words" could mean two different things, so I won't guess
|
| capital words
| ^^^^^^^^^^^^^
= for a word that is nothing but that: "a word made of capitals"
= for one that merely begins with it: "a word starting with a capital"-f, --flavor <WHICH> pcre | ere | rust [default: pcre]
-t, --test <TEXT> show what the pattern matches in TEXT
-a, --ast print the parse tree on stderr
--words list every phrase and what it produces
-q, --quote wrap the output in single quotes
-n, --no-cache skip the answer cache
--words prints every phrase with what it produces, so the vocabulary is
inspectable rather than opaque. Angle brackets mark grammar words, which produce
structure rather than text. A named pattern matches a shape, not a
specification: email address does not implement RFC 5322.
--ast shows what the compiler understood, which is the counterpart to a good
diagnostic: where an error explains a rejection, the tree explains an acceptance.
FluentRE runs entirely locally and offline. It authenticates to nothing, so there is nothing for a credential to be for.
| Property | Status |
|---|---|
| Dependencies | none — core library only |
| Network syscalls at run time | none |
| Subprocesses spawned | none, by the binary or the tests |
| Environment variables read | XDG_CACHE_HOME, HOME — cache path only |
| Credentials in tree | none |
| Licence | Apache-2.0, header on every source file |
tests/isolation_test.odin re-runs this audit on every odin test, so adding a
network import, a foreign import, or a stray token fails the suite rather than
quietly shipping.
description -> lex -> grammar -> codegen -> dialect -> verify -> stdout
| File | Role |
|---|---|
fluentre/lex.odin |
Scanner. Every token carries a byte span. |
fluentre/vocabulary.odin |
The 571 phrases, in nine labelled sections. |
fluentre/grammar.odin |
Recursive descent, one procedure per precedence level. |
fluentre/ast.odin |
The tree, plus the --ast rendering. |
fluentre/charset.odin |
Set algebra: union, intersect, complement, subtract. |
fluentre/codegen.odin |
Tree to regex. One case per node kind. |
fluentre/diag.odin |
Spans, carets, Levenshtein did-you-mean. |
fluentre/parse_errors.odin |
The prose the parser produces when it refuses. |
fluentre/verify.odin |
Dialects, a validating regex parser, a matcher, the cache. |
fluentre/run.odin |
Arguments in, three streams out. |
cli/main.odin |
Prints what run decided. Nothing else. |
run returns {out, err, code} rather than printing, so the command-line
contract is testable without spawning a process.
| File | Contents |
|---|---|
LanguageSpec.md |
The complete language. Every clause numbered and tested. |
Design.md |
Context, principles and requirements, each with a unique identifier. |
Requirement identifiers from Design.md appear in a Design: comment above
every procedure, so one search finds the requirement, the code that implements
it, and the test that pins it:
$ grep -rn "SEM-006" fluentre/ Design.md LanguageSpec.md tests/Sections of Design.md marked Odin note record where this implementation
differs from the original Rust one, and why.
Apache License, Version 2.0. See LICENSE. Every source file carries the
standard header; tests/isolation_test.odin fails if one does not.