Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Getting Started

Installation

Add synkit and logos to your Cargo.toml:

[dependencies]
synkit = "0.1"
logos = "0.15"
thiserror = "2"  # recommended for error types

Optional Features

# For async streaming with tokio
synkit = { version = "0.1", features = ["tokio"] }

# For async streaming with futures (runtime-agnostic)
synkit = { version = "0.1", features = ["futures"] }

# For std::error::Error implementations
synkit = { version = "0.1", features = ["std"] }

Minimal Example

A complete parser in ~30 lines:

use thiserror::Error;

#[derive(Error, Debug, Clone, Default, PartialEq)]
pub enum LexError {
    #[default]
    #[error("unknown token")]
    Unknown,
    #[error("expected {expect}, found {found}")]
    Expected { expect: &'static str, found: String },
    #[error("expected {expect}")]
    Empty { expect: &'static str },
}

synkit::parser_kit! {
    error: LexError,
    skip_tokens: [Space],
    tokens: {
        #[token(" ")]
        Space,

        #[token("=")]
        Eq,

        #[regex(r"[a-z]+", |lex| lex.slice().to_string())]
        #[fmt("identifier")]
        Ident(String),

        #[regex(r"[0-9]+", |lex| lex.slice().parse().ok())]
        #[fmt("number")]
        Number(i64),
    },
    delimiters: {},
    span_derives: [Debug, Clone, PartialEq],
    token_derives: [Debug, Clone, PartialEq],
}

Using the Generated Code

After parser_kit!, you have access to:

use crate::{
    // Span types
    Span, Spanned,
    // Token enum and structs
    tokens::{Token, EqToken, IdentToken, NumberToken},
    // Parsing infrastructure
    stream::TokenStream,
    // Traits
    Parse, Peek, ToTokens, Diagnostic,
};

// Lex source into tokens
let mut stream = TokenStream::lex("x = 42")?;

// Parse tokens
let name: Spanned<IdentToken> = stream.parse()?;
let eq: Spanned<EqToken> = stream.parse()?;
let value: Spanned<NumberToken> = stream.parse()?;

assert_eq!(*name.value, "x");
assert_eq!(value.value.0, 42);

Generated Modules

parser_kit! generates these modules in your crate:

ModuleContents
spanSpan, RawSpan, Spanned<T>
tokensToken enum, *Token structs, Tok!/SpannedTok! macros
streamTokenStream, MutTokenStream
printerPrinter implementation
delimitersDelimiter structs (e.g., Bracket, Brace)
traitsParse, Peek, ToTokens, Diagnostic

Error Type Requirements

Your error type must:

  1. Implement Default (for unknown token errors from logos)
  2. Have variants for parse errors (recommended pattern):
#[derive(Error, Debug, Clone, Default, PartialEq)]
pub enum MyError {
    #[default]
    #[error("unknown")]
    Unknown,

    #[error("expected {expect}, found {found}")]
    Expected { expect: &'static str, found: String },

    #[error("expected {expect}")]
    Empty { expect: &'static str },
}

Next Steps