diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index c8266b04608df2303428520c0c40a85feb971203..b890df02db1dd0ff315ba1c81227df458faf256e 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -50,6 +50,18 @@
                 "kind": "build",
                 "isDefault": true
             }
+        },
+        {
+            "type": "shell",
+            "label": "cargo run --example tmp",
+            "command": "cargo run --example tmp",
+            "problemMatcher": [
+                "$rustc"
+            ],
+            "group": {
+                "kind": "build",
+                "isDefault": true
+            }
         }
     ]
 }
\ No newline at end of file
diff --git a/Cargo.lock b/Cargo.lock
index 2e2899c867e521b006534f256466ce84c5ec7f0a..701c2b4afb31729ad1531c5e6c4535bd04d95608 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -11,7 +11,7 @@ version = "0.1.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
-name = "first"
+name = "crust"
 version = "0.1.0"
 dependencies = [
  "nom 5.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/Cargo.toml b/Cargo.toml
index 5c023919cd2950b14c34c928319e263a6924dec6..7ee290b5dc918f4666d365b25d09891e041dda55 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,5 +1,5 @@
 [package]
-name = "first"
+name = "crust"
 version = "0.1.0"
 authors = ["Per Lindgren <per.lindgren@ltu.se>"]
 edition = "2018"
diff --git a/examples/tmp.rs b/examples/tmp.rs
new file mode 100644
index 0000000000000000000000000000000000000000..ec7393d6cf7d267561468839a8a9a05f1ff2f81e
--- /dev/null
+++ b/examples/tmp.rs
@@ -0,0 +1,185 @@
+extern crate nom;
+
+use std::iter::Peekable;
+use std::slice::Iter;
+
+use nom::{
+    branch::alt,
+    bytes::complete::tag,
+    character::complete::char,
+    character::complete::{digit1, multispace0},
+    combinator::{cut, map},
+    error::ParseError,
+    multi::many1,
+    sequence::{delimited, preceded},
+    IResult,
+};
+
+use crust::ast::{Op, Expr};
+
+
+pub fn parse_i32(i: &str) -> IResult<&str, i32> {
+    map(digit1, |digit_str: &str| digit_str.parse::<i32>().unwrap())(i)
+}
+
+fn parse_op(i: &str) -> IResult<&str, Op> {
+    alt((
+        map(tag("=="), |_| Op::Eq),
+        map(tag("!="), |_| Op::Neq),
+        map(tag("**"), |_| Op::Pow),
+        map(tag("&&"), |_| Op::And),
+        map(tag("||"), |_| Op::Or),
+        map(tag("+"), |_| Op::Add),
+        map(tag("-"), |_| Op::Sub),
+        map(tag("*"), |_| Op::Mul),
+        map(tag("/"), |_| Op::Div),
+        map(tag("!"), |_| Op::Not),
+    ))(i)
+}
+
+#[derive(Debug, Clone, PartialEq)]
+pub enum Token {
+    Num(i32),
+    Par(Vec<Token>),
+    Op(Op),
+}
+
+fn parse_terminal(i: &str) -> IResult<&str, Token> {
+    alt((
+        map(parse_i32, |v| Token::Num(v)),
+        map(parse_par(parse_tokens), |tokens| Token::Par(tokens)),
+    ))(i)
+}
+
+fn parse_token(i: &str) -> IResult<&str, Token> {
+    preceded(
+        multispace0,
+        alt((map(parse_op, |op| Token::Op(op)), parse_terminal)),
+    )(i)
+}
+
+fn parse_tokens(i: &str) -> IResult<&str, Vec<Token>> {
+    many1(parse_token)(i)
+}
+
+fn compute_atom(t: &mut Peekable<Iter<Token>>) -> Expr {
+    match t.next() {
+        Some(Token::Num(i)) => Expr::Num(*i),
+        Some(Token::Par(v)) => climb(&mut v.iter().peekable(), 0),
+        Some(Token::Op(op)) => Expr::UnaryOp(*op, Box::new(climb(t, 4))), // assume highest precedence
+        _ => panic!("error in compute atom"),
+    }
+}
+
+fn climb(t: &mut Peekable<Iter<Token>>, min_prec: u8) -> Expr {
+    let mut result = compute_atom(t);
+
+    loop {
+        match t.peek() {
+            Some(Token::Op(op)) => {
+                let (prec, ass) = get_prec(op);
+                if prec < min_prec {
+                    break;
+                };
+                let next_prec = prec
+                    + match ass {
+                        Ass::Left => 1,
+                        _ => 0,
+                    };
+                t.next();
+                let rhs = climb(t, next_prec);
+                result = Expr::BinOp(*op, Box::new(result), Box::new(rhs))
+            }
+            _ => {
+                break;
+            }
+        }
+    }
+    result
+}
+
+fn test(s: &str, v: i32) {
+    match parse_tokens(s) {
+        Ok(("", t)) => {
+            let mut t = t.iter().peekable();
+            println!("{:?}", &t);
+            let e = climb(&mut t, 0);
+            println!("{:?}", &e);
+            println!("eval {} {}", math_eval(&e), v);
+            assert_eq!(math_eval(&e), v);
+        }
+        Ok((s, t)) => println!(
+            "parse incomplete, \n parsed tokens \t{:?}, \n remaining \t{:?}",
+            t, s
+        ),
+        Err(err) => println!("{:?}", err),
+    }
+}
+
+fn main() {
+    test("- -1 + + 1", - -1 + 1);  // rust does not allow + as a unary op (I do ;)
+    test("(-1-1)+(-1+3)", (-1 - 1) + (-1) + 3);
+    // just to check that right associative works (you don't need to implement pow)
+    test("2+3**2**3*5+1", 2 + 3i32.pow(2u32.pow(3)) * 5 + 1);
+    test("(12*2)/3-4", (12 * 2) / 3 - 4);
+    test("1*2+3", 1 * 2 + 3);
+    // just to check that we get a parse error
+    test("1*2+3+3*21-a12+2", 1 * 2 + 3 + 3 * 21 - 12 + 2);
+}
+
+// helpers
+fn parse_par<'a, O, F, E>(
+    inner: F,
+) -> impl Fn(&'a str) -> IResult<&'a str, O, E>
+where
+    F: Fn(&'a str) -> IResult<&'a str, O, E>,
+    E: ParseError<&'a str>,
+{
+    // delimited allows us to split up the input
+    // cut allwos us to consume the input (and prevent backtracking)
+    delimited(char('('), preceded(multispace0, inner), cut(char(')')))
+}
+
+fn math_eval(e: &Expr) -> i32 {
+    match e {
+        Expr::Num(i) => *i,
+        Expr::BinOp(op, l, r) => {
+            let lv = math_eval(l);
+            let rv = math_eval(r);
+            match op {
+                Op::Add => lv + rv,
+                Op::Sub => lv - rv,
+                Op::Mul => lv * rv,
+                Op::Div => lv / rv,
+                Op::Pow => lv.pow(rv as u32),
+                _ => unimplemented!(),
+            }
+        }
+        Expr::UnaryOp(op, e) => {
+            let e = math_eval(e);
+            match op {
+                Op::Add => e,
+                Op::Sub => -e,
+                _ => unimplemented!(),
+            }
+        }
+        _ => unimplemented!(),
+    }
+}
+
+#[derive(Debug, Copy, Clone, PartialEq)]
+enum Ass {
+    Left,
+    Right,
+}
+
+fn get_prec(op: &Op) -> (u8, Ass) {
+    match op {
+        Op::Add => (1, Ass::Left),
+        Op::Sub => (1, Ass::Left),
+        Op::Mul => (2, Ass::Left),
+        Op::Div => (2, Ass::Left),
+        Op::Pow => (3, Ass::Right),
+        _ => unimplemented!(),
+    }
+}
diff --git a/src/ast.rs b/src/ast.rs
new file mode 100644
index 0000000000000000000000000000000000000000..3c2f8b41459bac8bfe773ef894b26a9499f4fa64
--- /dev/null
+++ b/src/ast.rs
@@ -0,0 +1,33 @@
+// AST
+
+use nom_locate::LocatedSpan;
+
+type Span<'a> = LocatedSpan<&'a str>;
+
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub enum Op {
+    Eq,
+    Neq,
+    And,
+    Or,
+    Add,
+    Sub,
+    Mul,
+    Div,
+    Pow,
+    Not,
+}
+
+type SpanOp<'a> = (Span<'a>, Op);
+
+#[derive(Debug, Clone, PartialEq)]
+pub enum Expr {
+    Num(i32),
+    Par(Box<Expr>),
+    // Identifier
+    // Function application
+    BinOp(Op, Box<Expr>, Box<Expr>),
+    UnaryOp(Op, Box<Expr>),
+}
+
+type SpanExpr<'a> = (Span<'a>, Expr);
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..95787c26b88a62b43f78980ce41580778a495ae1
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,3 @@
+// lib
+
+pub mod ast;
\ No newline at end of file