astmaker 0.2.0

Build Abstract Syntax Trees and tree-walking models quickly in Rust.
Documentation
use syn::parse::{Parse, ParseStream, Result};
use syn::{Error, Token, Visibility, Ident, Type, braced};

pub struct AbstractSyntaxTree {
  pub location: LocationInfo,
  pub nodes: Vec<Node>,
}

pub struct LocationInfo {
  pub datatype: Type,
}

pub struct Node {
  pub visibility: Visibility,
  pub name: Ident,
  pub attrs: Option<NodeAttributes>,
  pub data: NodeData,
}

pub struct NodeAttributes {
  pub datatype: Type,
}

pub enum NodeData {
  Struct(NodeDataStruct),
  Enum(NodeDataEnum),
}

pub struct NodeDataStruct {
  pub members: Vec<NodeDataStructField>,
}

pub struct NodeDataStructField {
  pub name: Ident,
  pub datatype: Type,
}

pub struct NodeDataEnum {
  pub variants: Vec<NodeDataEnumVariant>,
}

pub struct NodeDataEnumVariant {
  pub name: Ident,
  pub datatype: Type,
}

impl Parse for AbstractSyntaxTree {
  fn parse(input: ParseStream) -> Result<Self> {
    let location: LocationInfo = input.parse()?;
    let mut nodes = vec![];

    while !input.is_empty() {
      let node: Node = input.parse()?;
      nodes.push(node);
    }

    Ok(Self { location, nodes })
  }
}

impl Parse for LocationInfo {
  fn parse(input: ParseStream) -> Result<Self> {
    let location_token: Ident = input.parse()?;
    if location_token != "location" {
      return Err(Error::new(location_token.span(), "expected `location`"));
    }

    input.parse::<Token![=]>()?;

    let datatype: Type = input.parse()?;

    input.parse::<Token![;]>()?;

    Ok(Self { datatype })
  }
}

impl Parse for Node {
  fn parse(input: ParseStream) -> Result<Self> {
    let visibility: Visibility = input.parse()?;

    let node_token: Ident = input.parse()?;
    if node_token != "node" {
      return Err(Error::new(node_token.span(), "expected `node`"));
    }

    let name: Ident = input.parse()?;

    input.lookahead1();

    let attrs = if input.peek(Token![where]) {
      Some(input.parse()?)
    }
    else {
      None
    };

    input.parse::<Token![=]>()?;
    let data: NodeData = input.parse()?;

    Ok(Self { visibility, name, attrs, data })
  }
}

impl Parse for NodeAttributes {
  fn parse(input: ParseStream) -> Result<Self> {
    input.parse::<Token![where]>()?;

    let attrs_token: Ident = input.parse()?;
    if attrs_token != "attrs" {
      return Err(Error::new(attrs_token.span(), "expected `attrs`"));
    }

    input.parse::<Token![:]>()?;

    let datatype: Type = input.parse()?;

    Ok(Self { datatype })
  }
}

impl Parse for NodeData {
  fn parse(input: ParseStream) -> Result<Self> {
    input.lookahead1();

    if input.peek(Token![|]) {
      input.parse().map(NodeData::Enum)
    }
    else {
      input.parse().map(NodeData::Struct)
    }
  }
}

impl Parse for NodeDataStruct {
  fn parse(input: ParseStream) -> Result<Self> {
    let content;
    braced!(content in input);

    let members = content
      .parse_terminated(NodeDataStructField::parse, Token![,])?
      .into_iter()
      .collect();

    Ok(Self { members })
  }
}

impl Parse for NodeDataStructField {
  fn parse(input: ParseStream) -> Result<Self> {
    let name: Ident = input.parse()?;
    input.parse::<Token![:]>()?;
    let datatype: Type = input.parse()?;

    Ok(Self { name, datatype })
  }
}

impl Parse for NodeDataEnum {
  fn parse(input: ParseStream) -> Result<Self> {
    let mut variants = vec![];

    loop {
      input.lookahead1();
      if input.peek(Token![;]) {
        break;
      }

      input.parse::<Token![|]>()?;
      let variant: NodeDataEnumVariant = input.parse()?;
      variants.push(variant);
    }

    input.parse::<Token![;]>()?;
    Ok(Self { variants })
  }
}

impl Parse for NodeDataEnumVariant {
  fn parse(input: ParseStream) -> Result<Self> {
    let name: Ident = input.parse()?;
    input.parse::<Token![->]>()?;
    let datatype: Type = input.parse()?;
    Ok(Self { name, datatype })
  }
}