Skip to content

giluis/astray

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

35 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Astray: Effortless parsing

Automatically generate type safe Recursive Descent Parsers (RDP) from Rust structures representing an Abstract Syntax Tree (AST).

This repository brings together astray_core and astray_macro into one crate.

WARNING: Astray is not ready for production yet. Some features are missing and the documentation is very incomplete. I am working hard on these and will deliver on them as soon as possible.

Check the docs for more info.

Features

  • Parse a sequence of types, represented via struct
  • Parse one of many possible types, represented via enum
  • Vec<T>: for consuming multiple types or Tokens
  • Option<T>: for consuming a type if it is can be consumed
  • Box<T>: for consuming and heap allocating a type
  • (T,P): for tuples of types
  • Either<T,P>: from the either crate
  • NonEmpty<T>: from the nonempty crate, allows you to consume at least one type
  • Pattern Matching on any Parsable type

For a more details, check the features page

Quickstart

cargo add astray

Given an AST definition like the below:

    struct AST {
        items: Vec<Item>
    }

    enum Item {
        Assignment(Assignment),
        Return(ReturnStatement),
    }

    struct ReturnStatement {
        return_kw: Token,
        expr: Expr

    }

    struct Assignment {
        let_kw: Token
        ident: String,
        equals_sign: Token,
        body: Expr,
        semicolon: Token,
    }


    struct Expr {
        left: Token
        sign: Token,
        right: Token
    }
  1. Call the set_token! macro with your custom Token type
  2. Annotate each type with the SN (Syntax Node) derive macro
  3. Add an attribute representing the pattern you want to match for each token field
    set_token!(Token);

    #[derive(SN)]
    struct AST {
        items: Vec<Item>,
    }

    #[derive(SN)]
    enum Item {
        Assignment(Assignment),
        Return(ReturnStatement),
    }

    #[derive(SN)]
    struct ReturnStatement {
        #[pat(Token::ReturnKw)]
        return_kw: Token,
        expr: Expr,

    }

    #[derive(SN)]
    struct Assignment {
        #[pat(Token::LetKw)]
        let_kw: Token,

        #[extract(Token::Identifier(ident))]
        ident: String,

        #[pat(Token::EqualsSign)]
        equals_sign: Token,

        body: Expr,

        #[pat(Token::SemiColon)]
        semicolon: Token,
    }


    #[derive(SN)]
    struct Expr {
        #[extract(Token::IntLiteral(left))]
        left: u32,

        #[pat(Token::Plus | Token::Asterisk)]
        sign: Sign,

        #[extract(Token::IntLiteral(left))]
        right: u32,
    }

... Astray will generate a parse function for that AST:

fn main() {
    let source_code = "let a = 1 + 2;";
    let tokens: Vec<Token> = lex(&source_code)
    let result = AST::parse(tokens.into());
    match result {
        Ok(ast)  => println!("{:?}"),
        Err(parse_error) => ()
    }
}

About

Build ASTs from type definitions

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages