| Crates.io | doke |
| lib.rs | doke |
| version | 0.3.0 |
| created_at | 2025-09-02 15:26:04.572959+00 |
| updated_at | 2025-09-06 18:23:19.60067+00 |
| description | The parsing library of `Dokedex`, a game content authoring tool that uses natural-looking language to define a game's objects. This rust crate defines an API to make `doke` parsers by using a simple pipeline syntax, and provides helpers for things like templating, debugging, and common syntax elements. |
| homepage | https://github.com/Hasenn/Doke-parser.git |
| repository | https://github.com/Hasenn/Doke-parser.git |
| max_upload_size | |
| id | 1821276 |
| size | 139,690 |
DokePipe is a powerful, extensible semantic parsing pipeline for Markdown.
It transforms plain Markdown text into a structured DokeDocument, which can then be validated and converted into Godot-ready data (GodotValue).
Think of it as a bridge between Markdown notes and typed, validated game-ready data.
๐ Frontmatter Extraction โ Parse YAML frontmatter straight from Markdown ๐ณ Semantic Parsing โ Convert Markdown AST into a tree of customizable DokeNodes ๐ Extensible Pipeline โ Add your own parsers to interpret and transform nodes ๐ง Hypothesis System โ Compete multiple interpretations with confidence scoring ๐ฎ Godot Integration โ Output GodotValues for GDNative/GDExtension โ Validation Layer โ Ensure documents are well-formed and structurally sound ๐ฏ Typed Sentences Parser โ Route nodes to specialized parsers based on type hierarchies and parent-child constraints
In your Cargo.toml:
[dependencies]
doke = "0.1.0"
use std::io::{self, Read};
use doke::{parsers, DokePipe, GodotValue};
fn main() -> Result<(), std::io::Error> {
// Read stdin into a string
let mut input = String::new();
io::stdin().read_to_string(&mut input)?;
// Build the pipeline
let pipe = DokePipe::new()
.add(parsers::FrontmatterTemplateParser)
.add(parsers::DebugPrinter); // ๐ Debug: prints nodes with emojis
// Parse the input (for debugging)
let doc = pipe.run_markdown(&input);
// Validate & extract Godot values
let values: Vec<GodotValue> = pipe.validate(&input).unwrap();
dbg!(doc);
dbg!(values);
Ok(())
}
The sentence parser lets you define simple rules in YAML, avoiding the need to handcraft full grammars. Itโs designed for fast prototyping and structured natural language parsing.
Its main use should be with the typed sentences parser
DamageEffect :
- "Deals {damage : int} damage to {target : Target}."
- "{damage_effect : DamageEffect}. On Hit :" : OnHitDamageEffect
- "Deals {multi : int}*{damage : int} damage to {target : Target}." : MultiDamageEffect
PrintEffect :
- "Prints {message : String}." : f"The man said {message}"
Target :
- "allies" : 1
- "enemies" : 2
- "self" : 0
โ๏ธ Pros:
โ Limitations:
Sentence rules can double as translation keys:
"DAMAGE_EFFECT_TXT_1" "Deals {damage} damage to {target}."
"DAMAGE_EFFECT_TXT_2" "Damages {target} for {damage}."
"DAMAGE_EFFECT_TXT_3" "Inflicts {damage} damage to {target}."
In Godot:
func describe():
tr(tr_key).format({
damage = self.damage,
target = self.target
})
This allows you to build entire translation tables automatically.
This is the main workflow when you don't want any re-compilation. it uses sentence parsers
it can pull all the definitions from .dokedef.yaml files into a sentence parser for an abstract type,
and allows abstract types to define what children they allow and where they go.
rules:
- for: ItemEffect
parser: "**/*Effect.dokedef.yaml"
children:
animations: [Animation]
modifiers: [Modifier]
- for: Animation
parser: "**/*Animation.dokedef.yaml"
- for: Modifier
parser: "**/*Modifier.dokedef.yaml"
children : Modifier
deal 10 fire damage
- play animation: anims/fire on target
heal 20 health
- play animation: anims/heal on self
apply burning for 5 seconds
- play animation: anims/smoke on target
You can implement your own semantic parsers by implementing DokeParser.
For example, hereโs a Hello World parser:
#[derive(Debug)]
pub struct HelloWorldParser;
impl DokeParser for HelloWorldParser {
fn process(&self, node: &mut DokeNode, _frontmatter: &HashMap<String, GodotValue>) {
if !matches!(node.state, DokeNodeState::Unresolved) {
return;
}
if node.statement.contains("Hello World") {
let hypothesis = HelloWorldHypothesis::new(node.statement.clone(), 1.0);
node.state = DokeNodeState::Hypothesis(vec![Box::new(hypothesis)]);
}
for child in &mut node.children {
self.process(child, _frontmatter);
}
}
}
DokePipe โ the pipeline runner.DokeNode โ AST node with statement + children.DokeParser โ trait for pluggable parsers.Hypo โ trait for hypotheses with confidence scoring.DokeOut โ trait for resolved semantic objects.GodotValue โ typed values for Godot integration.MyType.dokeconf.yaml which pulls all MySubType.dokedef.yaml in your repo.lalrpop grammar generation from YAML types.Because Markdown is great for writing content, but not great for structured semantics. Doke bridges that gap: