Getting Started

Before starting playing with Oak, let's create a skeleton project. There are some requirements:

Once both are installed, we can set up a project using Oak. We first need a Cargo.toml for Oak dependencies:

fn main() { [package] name = "oak_skeleton" version = "0.0.1" authors = ["Pierre Talbot <ptalbot@hyc.io>"] [dependencies] oak = "*" oak_runtime = "*" }
[package]
name = "oak_skeleton"
version = "0.0.1"
authors = ["Pierre Talbot <ptalbot@hyc.io>"]

[dependencies]
oak = "*"
oak_runtime = "*"

The [package] section describe the usual information about your project, here named oak_skeleton and the [dependencies] section lists the libraries available on crates.io that you depend on. You can also directly depend on the git repository:

fn main() { [dependencies.oak] git = "https://github.com/ptal/oak.git" [dependencies.oak_runtime] git = "https://github.com/ptal/oak.git" path = "runtime" }
[dependencies.oak]
git = "https://github.com/ptal/oak.git"

[dependencies.oak_runtime]
git = "https://github.com/ptal/oak.git"
path = "runtime"

Oak is now usable from your main.rs:

#![feature(plugin, str_char)] #![plugin(oak)] grammar! sum{ #![show_api] sum = value ("+" value)* > add value = ["0-9"]+ > to_digit fn add(x: u32, rest: Vec<u32>) -> u32 { rest.iter().fold(x, |x,y| x+y) } fn to_digit(raw_text: Vec<char>) -> u32 { use std::str::FromStr; let text: String = raw_text.into_iter().collect(); u32::from_str(&*text).unwrap() } } fn main() { let input = "7+2+1"; assert_eq!(sum::parse_sum(input, 0).into_result(input).unwrap().data, 10); }
#![feature(plugin, str_char)]
#![plugin(oak)]

grammar! sum{
  #![show_api]

  sum = value ("+" value)* > add
  value = ["0-9"]+ > to_digit

  fn add(x: u32, rest: Vec<u32>) -> u32 {
    rest.iter().fold(x, |x,y| x+y)
  }

  fn to_digit(raw_text: Vec<char>) -> u32 {
    use std::str::FromStr;
    let text: String = raw_text.into_iter().collect();
    u32::from_str(&*text).unwrap()
  }
}

fn main() {
  let input = "7+2+1";
  assert_eq!(sum::parse_sum(input, 0).into_result(input).unwrap().data, 10);
}

We organized the library into two packages: oak and oak_runtime. The oak dependency is the macro compiling your grammar description into Rust code, the attribute #![plugin(oak)] exposes the macro grammar! which is the only thing you will use from oak. The generated code depends on the library oak_runtime, it also contains structures used by the generated code such as ParseResult. The attribute #![feature(plugin, str_char)] tells the Rust compiler that we are using unstable features, and that's why we need to use the nightly channel. Keep reading to learn more about the language used in the macro grammar!.