From a47dfd3d1417412f4d55ffa964d9fc98d8d53a9d Mon Sep 17 00:00:00 2001 From: johannst Date: Mon, 13 Sep 2021 22:26:20 +0000 Subject: deploy: 743f301eef632a41bd870529a9e838ce4974f9eb --- src/llvm_kaleidoscope_rs/codegen.rs.html | 275 ++++++++ src/llvm_kaleidoscope_rs/lexer.rs.html | 367 ++++++++++ src/llvm_kaleidoscope_rs/lib.rs.html | 223 +++++++ src/llvm_kaleidoscope_rs/llvm.rs.html | 1073 ++++++++++++++++++++++++++++++ src/llvm_kaleidoscope_rs/parser.rs.html | 925 ++++++++++++++++++++++++++ 5 files changed, 2863 insertions(+) create mode 100644 src/llvm_kaleidoscope_rs/codegen.rs.html create mode 100644 src/llvm_kaleidoscope_rs/lexer.rs.html create mode 100644 src/llvm_kaleidoscope_rs/lib.rs.html create mode 100644 src/llvm_kaleidoscope_rs/llvm.rs.html create mode 100644 src/llvm_kaleidoscope_rs/parser.rs.html (limited to 'src') diff --git a/src/llvm_kaleidoscope_rs/codegen.rs.html b/src/llvm_kaleidoscope_rs/codegen.rs.html new file mode 100644 index 0000000..bcaa770 --- /dev/null +++ b/src/llvm_kaleidoscope_rs/codegen.rs.html @@ -0,0 +1,275 @@ +codegen.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+
+use std::collections::HashMap;
+
+use crate::llvm::{Builder, FnValue, Module, Value};
+use crate::parser::{ExprAST, FunctionAST, PrototypeAST};
+use crate::Either;
+
+type CodegenResult<T> = Result<T, String>;
+
+/// Code generator from kaleidoscope AST to LLVM IR.
+pub struct Codegen<'llvm, 'a> {
+    module: &'llvm Module,
+    builder: &'a Builder<'llvm>,
+}
+
+impl<'llvm, 'a> Codegen<'llvm, 'a> {
+    /// Compile either a [`PrototypeAST`] or a [`FunctionAST`] into the LLVM `module`.
+    pub fn compile(
+        module: &'llvm Module,
+        compilee: Either<&PrototypeAST, &FunctionAST>,
+    ) -> CodegenResult<FnValue<'llvm>> {
+        let cg = Codegen {
+            module,
+            builder: &Builder::with_ctx(module),
+        };
+        let mut variables = HashMap::new();
+
+        match compilee {
+            Either::A(proto) => Ok(cg.codegen_prototype(proto)),
+            Either::B(func) => cg.codegen_function(func, &mut variables),
+        }
+    }
+
+    fn codegen_expr(
+        &self,
+        expr: &ExprAST,
+        named_values: &mut HashMap<&'llvm str, Value<'llvm>>,
+    ) -> CodegenResult<Value<'llvm>> {
+        match expr {
+            ExprAST::Number(num) => Ok(self.module.type_f64().const_f64(*num)),
+            ExprAST::Variable(name) => match named_values.get(name.as_str()) {
+                Some(value) => Ok(*value),
+                None => Err("Unknown variable name".into()),
+            },
+            ExprAST::Binary(binop, lhs, rhs) => {
+                let l = self.codegen_expr(lhs, named_values)?;
+                let r = self.codegen_expr(rhs, named_values)?;
+
+                match binop {
+                    '+' => Ok(self.builder.fadd(l, r)),
+                    '-' => Ok(self.builder.fsub(l, r)),
+                    '*' => Ok(self.builder.fmul(l, r)),
+                    '<' => {
+                        let res = self.builder.fcmpult(l, r);
+                        // Turn bool into f64.
+                        Ok(self.builder.uitofp(res, self.module.type_f64()))
+                    }
+                    _ => Err("invalid binary operator".into()),
+                }
+            }
+            ExprAST::Call(callee, args) => match self.module.get_fn(callee) {
+                Some(callee) => {
+                    if callee.args() != args.len() {
+                        return Err("Incorrect # arguments passed".into());
+                    }
+
+                    // Generate code for function argument expressions.
+                    let mut args: Vec<Value<'_>> = args
+                        .iter()
+                        .map(|arg| self.codegen_expr(arg, named_values))
+                        .collect::<CodegenResult<_>>()?;
+
+                    Ok(self.builder.call(callee, &mut args))
+                }
+                None => Err("Unknown function referenced".into()),
+            },
+        }
+    }
+
+    fn codegen_prototype(&self, PrototypeAST(name, args): &PrototypeAST) -> FnValue<'llvm> {
+        let type_f64 = self.module.type_f64();
+
+        let mut doubles = Vec::new();
+        doubles.resize(args.len(), type_f64);
+
+        // Build the function type: fn(f64, f64, ..) -> f64
+        let ft = self.module.type_fn(&mut doubles, type_f64);
+
+        // Create the function declaration.
+        let f = self.module.add_fn(name, ft);
+
+        // Set the names of the function arguments.
+        for idx in 0..f.args() {
+            f.arg(idx).set_name(&args[idx]);
+        }
+
+        f
+    }
+
+    fn codegen_function(
+        &self,
+        FunctionAST(proto, body): &FunctionAST,
+        named_values: &mut HashMap<&'llvm str, Value<'llvm>>,
+    ) -> CodegenResult<FnValue<'llvm>> {
+        let the_function = match self.module.get_fn(&proto.0) {
+            Some(f) => f,
+            None => self.codegen_prototype(proto),
+        };
+
+        if the_function.basic_blocks() > 0 {
+            return Err("Function cannot be redefined.".into());
+        }
+
+        // Create entry basic block to insert code.
+        let bb = self.module.append_basic_block(the_function);
+        self.builder.pos_at_end(bb);
+
+        // New scope, clear the map with the function args.
+        named_values.clear();
+
+        // Update the map with the current functions args.
+        for idx in 0..the_function.args() {
+            let arg = the_function.arg(idx);
+            named_values.insert(arg.get_name(), arg);
+        }
+
+        // Codegen function body.
+        if let Ok(ret) = self.codegen_expr(body, named_values) {
+            self.builder.ret(ret);
+            assert!(the_function.verify());
+            Ok(the_function)
+        } else {
+            todo!("Failed to codegen function body, erase from module!");
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/src/llvm_kaleidoscope_rs/lexer.rs.html b/src/llvm_kaleidoscope_rs/lexer.rs.html new file mode 100644 index 0000000..3524648 --- /dev/null +++ b/src/llvm_kaleidoscope_rs/lexer.rs.html @@ -0,0 +1,367 @@ +lexer.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+
+#[derive(Debug, PartialEq)]
+pub enum Token {
+    Eof,
+    Def,
+    Extern,
+    Identifier(String),
+    Number(f64),
+    Char(char),
+}
+
+pub struct Lexer<I>
+where
+    I: Iterator<Item = char>,
+{
+    input: I,
+    last_char: Option<char>,
+}
+
+impl<I> Lexer<I>
+where
+    I: Iterator<Item = char>,
+{
+    pub fn new(mut input: I) -> Lexer<I> {
+        let last_char = input.next();
+        Lexer { input, last_char }
+    }
+
+    fn step(&mut self) -> Option<char> {
+        self.last_char = self.input.next();
+        self.last_char
+    }
+
+    /// Lex and return the next token.
+    ///
+    /// Implement `int gettok();` from the tutorial.
+    pub fn gettok(&mut self) -> Token {
+        // Eat up whitespaces.
+        while matches!(self.last_char, Some(c) if c.is_ascii_whitespace()) {
+            self.step();
+        }
+
+        // Unpack last char or return EOF.
+        let last_char = if let Some(c) = self.last_char {
+            c
+        } else {
+            return Token::Eof;
+        };
+
+        // Identifier: [a-zA-Z][a-zA-Z0-9]*
+        if last_char.is_ascii_alphabetic() {
+            let mut ident = String::new();
+            ident.push(last_char);
+
+            while let Some(c) = self.step() {
+                if c.is_ascii_alphanumeric() {
+                    ident.push(c)
+                } else {
+                    break;
+                }
+            }
+
+            match ident.as_ref() {
+                "def" => return Token::Def,
+                "extern" => return Token::Extern,
+                _ => {}
+            }
+
+            return Token::Identifier(ident);
+        }
+
+        // Number: [0-9.]+
+        if last_char.is_ascii_digit() || last_char == '.' {
+            let mut num = String::new();
+            num.push(last_char);
+
+            while let Some(c) = self.step() {
+                if c.is_ascii_digit() || c == '.' {
+                    num.push(c)
+                } else {
+                    break;
+                }
+            }
+
+            let num: f64 = num.parse().unwrap_or_default();
+            return Token::Number(num);
+        }
+
+        // Eat up comment.
+        if last_char == '#' {
+            loop {
+                match self.step() {
+                    Some(c) if c == '\r' || c == '\n' => return self.gettok(),
+                    None => return Token::Eof,
+                    _ => { /* consume comment */ }
+                }
+            }
+        }
+
+        // Advance last char and return currently last char.
+        self.step();
+        Token::Char(last_char)
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::{Lexer, Token};
+
+    #[test]
+    fn test_identifier() {
+        let mut lex = Lexer::new("a b c".chars());
+        assert_eq!(Token::Identifier("a".into()), lex.gettok());
+        assert_eq!(Token::Identifier("b".into()), lex.gettok());
+        assert_eq!(Token::Identifier("c".into()), lex.gettok());
+        assert_eq!(Token::Eof, lex.gettok());
+    }
+
+    #[test]
+    fn test_keyword() {
+        let mut lex = Lexer::new("def extern".chars());
+        assert_eq!(Token::Def, lex.gettok());
+        assert_eq!(Token::Extern, lex.gettok());
+        assert_eq!(Token::Eof, lex.gettok());
+    }
+
+    #[test]
+    fn test_number() {
+        let mut lex = Lexer::new("12.34".chars());
+        assert_eq!(Token::Number(12.34f64), lex.gettok());
+        assert_eq!(Token::Eof, lex.gettok());
+
+        let mut lex = Lexer::new(" 1.0   2.0 3.0".chars());
+        assert_eq!(Token::Number(1.0f64), lex.gettok());
+        assert_eq!(Token::Number(2.0f64), lex.gettok());
+        assert_eq!(Token::Number(3.0f64), lex.gettok());
+        assert_eq!(Token::Eof, lex.gettok());
+
+        let mut lex = Lexer::new("12.34.56".chars());
+        assert_eq!(Token::Number(0f64), lex.gettok());
+        assert_eq!(Token::Eof, lex.gettok());
+    }
+
+    #[test]
+    fn test_comment() {
+        let mut lex = Lexer::new("# some comment".chars());
+        assert_eq!(Token::Eof, lex.gettok());
+
+        let mut lex = Lexer::new("abc # some comment \n xyz".chars());
+        assert_eq!(Token::Identifier("abc".into()), lex.gettok());
+        assert_eq!(Token::Identifier("xyz".into()), lex.gettok());
+        assert_eq!(Token::Eof, lex.gettok());
+    }
+
+    #[test]
+    fn test_chars() {
+        let mut lex = Lexer::new("a+b-c".chars());
+        assert_eq!(Token::Identifier("a".into()), lex.gettok());
+        assert_eq!(Token::Char('+'), lex.gettok());
+        assert_eq!(Token::Identifier("b".into()), lex.gettok());
+        assert_eq!(Token::Char('-'), lex.gettok());
+        assert_eq!(Token::Identifier("c".into()), lex.gettok());
+        assert_eq!(Token::Eof, lex.gettok());
+    }
+
+    #[test]
+    fn test_whitespaces() {
+        let mut lex = Lexer::new("    +a  b      c!    ".chars());
+        assert_eq!(Token::Char('+'), lex.gettok());
+        assert_eq!(Token::Identifier("a".into()), lex.gettok());
+        assert_eq!(Token::Identifier("b".into()), lex.gettok());
+        assert_eq!(Token::Identifier("c".into()), lex.gettok());
+        assert_eq!(Token::Char('!'), lex.gettok());
+        assert_eq!(Token::Eof, lex.gettok());
+
+        let mut lex = Lexer::new("\n    a \n\r  b \r \n     c \r\r  \n   ".chars());
+        assert_eq!(Token::Identifier("a".into()), lex.gettok());
+        assert_eq!(Token::Identifier("b".into()), lex.gettok());
+        assert_eq!(Token::Identifier("c".into()), lex.gettok());
+        assert_eq!(Token::Eof, lex.gettok());
+    }
+}
+
+
\ No newline at end of file diff --git a/src/llvm_kaleidoscope_rs/lib.rs.html b/src/llvm_kaleidoscope_rs/lib.rs.html new file mode 100644 index 0000000..d2fcdb6 --- /dev/null +++ b/src/llvm_kaleidoscope_rs/lib.rs.html @@ -0,0 +1,223 @@ +lib.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+
+use std::convert::TryFrom;
+
+pub mod codegen;
+pub mod lexer;
+pub mod llvm;
+pub mod parser;
+
+/// Fixed size of [`SmallCStr`] including the trailing `\0` byte.
+pub const SMALL_STR_SIZE: usize = 16;
+
+/// Small C string on the stack with fixed size [`SMALL_STR_SIZE`].
+#[derive(Debug, PartialEq)]
+pub struct SmallCStr([u8; SMALL_STR_SIZE]);
+
+impl SmallCStr {
+    /// Create a new C string from `src`.
+    /// Returns [`None`] if `src` exceeds the fixed size or contains any `\0` bytes.
+    pub fn new<T: AsRef<[u8]>>(src: &T) -> Option<SmallCStr> {
+        let src = src.as_ref();
+        let len = src.len();
+
+        // Check for \0 bytes.
+        let contains_null = unsafe { !libc::memchr(src.as_ptr().cast(), 0, len).is_null() };
+
+        if contains_null || len > SMALL_STR_SIZE - 1 {
+            None
+        } else {
+            let mut dest = [0; SMALL_STR_SIZE];
+            dest[..len].copy_from_slice(src);
+            Some(SmallCStr(dest))
+        }
+    }
+
+    /// Return pointer to C string.
+    pub const fn as_ptr(&self) -> *const libc::c_char {
+        self.0.as_ptr().cast()
+    }
+}
+
+impl TryFrom<&str> for SmallCStr {
+    type Error = ();
+
+    fn try_from(value: &str) -> Result<Self, Self::Error> {
+        SmallCStr::new(&value).ok_or(())
+    }
+}
+
+/// Either type, for APIs accepting two types.
+pub enum Either<A, B> {
+    A(A),
+    B(B),
+}
+
+#[cfg(test)]
+mod test {
+    use super::{SmallCStr, SMALL_STR_SIZE};
+    use std::convert::TryInto;
+
+    #[test]
+    fn test_create() {
+        let src = "\x30\x31\x32\x33";
+        let scs = SmallCStr::new(&src).unwrap();
+        assert_eq!(&scs.0[..5], &[0x30, 0x31, 0x32, 0x33, 0x00]);
+
+        let src = b"abcd1234";
+        let scs = SmallCStr::new(&src).unwrap();
+        assert_eq!(
+            &scs.0[..9],
+            &[0x61, 0x62, 0x63, 0x64, 0x31, 0x32, 0x33, 0x34, 0x00]
+        );
+    }
+
+    #[test]
+    fn test_contain_null() {
+        let src = "\x30\x00\x32\x33";
+        let scs = SmallCStr::new(&src);
+        assert_eq!(scs, None);
+
+        let src = "\x30\x31\x32\x33\x00";
+        let scs = SmallCStr::new(&src);
+        assert_eq!(scs, None);
+    }
+
+    #[test]
+    fn test_too_large() {
+        let src = (0..SMALL_STR_SIZE).map(|_| 'a').collect::<String>();
+        let scs = SmallCStr::new(&src);
+        assert_eq!(scs, None);
+
+        let src = (0..SMALL_STR_SIZE + 10).map(|_| 'a').collect::<String>();
+        let scs = SmallCStr::new(&src);
+        assert_eq!(scs, None);
+    }
+
+    #[test]
+    fn test_try_into() {
+        let src = "\x30\x31\x32\x33";
+        let scs: Result<SmallCStr, ()> = src.try_into();
+        assert!(scs.is_ok());
+
+        let src = (0..SMALL_STR_SIZE).map(|_| 'a').collect::<String>();
+        let scs: Result<SmallCStr, ()> = src.as_str().try_into();
+        assert!(scs.is_err());
+
+        let src = (0..SMALL_STR_SIZE + 10).map(|_| 'a').collect::<String>();
+        let scs: Result<SmallCStr, ()> = src.as_str().try_into();
+        assert!(scs.is_err());
+    }
+}
+
+
\ No newline at end of file diff --git a/src/llvm_kaleidoscope_rs/llvm.rs.html b/src/llvm_kaleidoscope_rs/llvm.rs.html new file mode 100644 index 0000000..2da418a --- /dev/null +++ b/src/llvm_kaleidoscope_rs/llvm.rs.html @@ -0,0 +1,1073 @@ +llvm.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+
+//! Safe wrapper around the LLVM C API.
+//!
+//! References returned from the LLVM API are tied to the `'llvm` lifetime which is bound to the
+//! context where the objects are created in.
+//! We do not offer wrappers to remove or delete any objects in the context and therefore all the
+//! references will be valid for the liftime of the context.
+
+use llvm_sys::analysis::{LLVMVerifierFailureAction, LLVMVerifyFunction};
+use llvm_sys::core::{
+    LLVMAddFunction, LLVMAppendBasicBlockInContext, LLVMBuildFAdd, LLVMBuildFCmp, LLVMBuildFMul,
+    LLVMBuildFSub, LLVMBuildRet, LLVMBuildUIToFP, LLVMConstReal, LLVMContextCreate,
+    LLVMContextDispose, LLVMCountBasicBlocks, LLVMCountParams, LLVMCreateBuilderInContext,
+    LLVMDisposeBuilder, LLVMDisposeModule, LLVMDoubleTypeInContext, LLVMDumpModule, LLVMDumpType,
+    LLVMDumpValue, LLVMGetNamedFunction, LLVMGetParam, LLVMGetReturnType, LLVMGetTypeKind,
+    LLVMGetValueKind, LLVMGetValueName2, LLVMModuleCreateWithNameInContext,
+    LLVMPositionBuilderAtEnd, LLVMSetValueName2, LLVMTypeOf,
+};
+use llvm_sys::prelude::{
+    LLVMBasicBlockRef, LLVMBool, LLVMBuilderRef, LLVMContextRef, LLVMModuleRef, LLVMTypeRef,
+    LLVMValueRef,
+};
+use llvm_sys::{LLVMRealPredicate, LLVMTypeKind, LLVMValueKind};
+
+use std::convert::TryFrom;
+use std::ffi::CStr;
+use std::marker::PhantomData;
+use std::ops::Deref;
+
+use crate::SmallCStr;
+
+// Definition of LLVM C API functions using our `repr(transparent)` types.
+extern "C" {
+    fn LLVMFunctionType(
+        ReturnType: Type<'_>,
+        ParamTypes: *mut Type<'_>,
+        ParamCount: ::libc::c_uint,
+        IsVarArg: LLVMBool,
+    ) -> LLVMTypeRef;
+    fn LLVMBuildCall2(
+        arg1: LLVMBuilderRef,
+        arg2: Type<'_>,
+        Fn: FnValue<'_>,
+        Args: *mut Value<'_>,
+        NumArgs: ::libc::c_uint,
+        Name: *const ::libc::c_char,
+    ) -> LLVMValueRef;
+}
+
+// ====================
+//   Module / Context
+// ====================
+
+/// Wrapper for a LLVM Module with its own LLVM Context.
+pub struct Module {
+    ctx: LLVMContextRef,
+    module: LLVMModuleRef,
+}
+
+impl<'llvm> Module {
+    /// Create a new Module instance.
+    ///
+    /// # Panics
+    ///
+    /// Panics if creating the context or the module fails.
+    pub fn new() -> Self {
+        let (ctx, module) = unsafe {
+            let c = LLVMContextCreate();
+            let m = LLVMModuleCreateWithNameInContext(b"module\0".as_ptr().cast(), c);
+            assert!(!c.is_null() && !m.is_null());
+            (c, m)
+        };
+
+        Module { ctx, module }
+    }
+
+    /// Dump LLVM IR emitted into the Module to stdout.
+    pub fn dump(&self) {
+        unsafe { LLVMDumpModule(self.module) };
+    }
+
+    /// Get a type reference representing a `f64` float.
+    ///
+    /// # Panics
+    ///
+    /// Panics if LLVM API returns a `null` pointer.
+    pub fn type_f64(&self) -> Type<'llvm> {
+        let type_ref = unsafe { LLVMDoubleTypeInContext(self.ctx) };
+        Type::new(type_ref)
+    }
+
+    /// Get a type reference representing a `fn(args) -> ret` function.
+    ///
+    /// # Panics
+    ///
+    /// Panics if LLVM API returns a `null` pointer.
+    pub fn type_fn(&'llvm self, args: &mut [Type<'llvm>], ret: Type<'llvm>) -> Type<'llvm> {
+        let type_ref = unsafe {
+            LLVMFunctionType(
+                ret,
+                args.as_mut_ptr(),
+                args.len() as libc::c_uint,
+                0, /* IsVarArg */
+            )
+        };
+        Type::new(type_ref)
+    }
+
+    /// Add a function with the given `name` and `fn_type` to the module and return a value
+    /// reference representing the function.
+    ///
+    /// # Panics
+    ///
+    /// Panics if LLVM API returns a `null` pointer or `name` could not be converted to a
+    /// [`SmallCStr`].
+    pub fn add_fn(&'llvm self, name: &str, fn_type: Type<'llvm>) -> FnValue<'llvm> {
+        debug_assert_eq!(
+            fn_type.kind(),
+            LLVMTypeKind::LLVMFunctionTypeKind,
+            "Expected a function type when adding a function!"
+        );
+
+        let name = SmallCStr::try_from(name)
+            .expect("Failed to convert 'name' argument to small C string!");
+
+        let value_ref = unsafe { LLVMAddFunction(self.module, name.as_ptr(), fn_type.0) };
+        FnValue::new(value_ref)
+    }
+
+    /// Get a function value reference to the function with the given `name` if it was previously
+    /// added to the module with [`add_fn`][Module::add_fn].
+    ///
+    /// # Panics
+    ///
+    /// Panics if `name` could not be converted to a [`SmallCStr`].
+    pub fn get_fn(&'llvm self, name: &str) -> Option<FnValue<'llvm>> {
+        let name = SmallCStr::try_from(name)
+            .expect("Failed to convert 'name' argument to small C string!");
+
+        let value_ref = unsafe { LLVMGetNamedFunction(self.module, name.as_ptr()) };
+
+        (!value_ref.is_null()).then(|| FnValue::new(value_ref))
+    }
+
+    /// Append a Basic Block to the end of the function referenced by the value reference
+    /// `fn_value`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if LLVM API returns a `null` pointer.
+    pub fn append_basic_block(&'llvm self, fn_value: FnValue<'llvm>) -> BasicBlock<'llvm> {
+        let block = unsafe {
+            LLVMAppendBasicBlockInContext(
+                self.ctx,
+                fn_value.value_ref(),
+                b"block\0".as_ptr().cast(),
+            )
+        };
+        assert!(!block.is_null());
+
+        BasicBlock(block, PhantomData)
+    }
+}
+
+impl Drop for Module {
+    fn drop(&mut self) {
+        unsafe {
+            LLVMDisposeModule(self.module);
+            LLVMContextDispose(self.ctx);
+        }
+    }
+}
+
+// ===========
+//   Builder
+// ===========
+
+/// Wrapper for a LLVM IR Builder.
+pub struct Builder<'llvm> {
+    builder: LLVMBuilderRef,
+    _ctx: PhantomData<&'llvm ()>,
+}
+
+impl<'llvm> Builder<'llvm> {
+    /// Create a new LLVM IR Builder with the `module`s context.
+    ///
+    /// # Panics
+    ///
+    /// Panics if creating the IR Builder fails.
+    pub fn with_ctx(module: &'llvm Module) -> Builder<'llvm> {
+        let builder = unsafe { LLVMCreateBuilderInContext(module.ctx) };
+        assert!(!builder.is_null());
+
+        Builder {
+            builder,
+            _ctx: PhantomData,
+        }
+    }
+
+    /// Position the IR Builder at the end of the given Basic Block.
+    pub fn pos_at_end(&self, bb: BasicBlock<'llvm>) {
+        unsafe {
+            LLVMPositionBuilderAtEnd(self.builder, bb.0);
+        }
+    }
+
+    /// Emit a [fadd](https://llvm.org/docs/LangRef.html#fadd-instruction) instruction.
+    ///
+    /// # Panics
+    ///
+    /// Panics if LLVM API returns a `null` pointer.
+    pub fn fadd(&self, lhs: Value<'llvm>, rhs: Value<'llvm>) -> Value<'llvm> {
+        debug_assert!(lhs.is_f64(), "fadd: Expected f64 as lhs operand!");
+        debug_assert!(rhs.is_f64(), "fadd: Expected f64 as rhs operand!");
+
+        let value_ref = unsafe {
+            LLVMBuildFAdd(
+                self.builder,
+                lhs.value_ref(),
+                rhs.value_ref(),
+                b"fadd\0".as_ptr().cast(),
+            )
+        };
+        Value::new(value_ref)
+    }
+
+    /// Emit a [fsub](https://llvm.org/docs/LangRef.html#fsub-instruction) instruction.
+    ///
+    /// # Panics
+    ///
+    /// Panics if LLVM API returns a `null` pointer.
+    pub fn fsub(&self, lhs: Value<'llvm>, rhs: Value<'llvm>) -> Value<'llvm> {
+        debug_assert!(lhs.is_f64(), "fsub: Expected f64 as lhs operand!");
+        debug_assert!(rhs.is_f64(), "fsub: Expected f64 as rhs operand!");
+
+        let value_ref = unsafe {
+            LLVMBuildFSub(
+                self.builder,
+                lhs.value_ref(),
+                rhs.value_ref(),
+                b"fsub\0".as_ptr().cast(),
+            )
+        };
+        Value::new(value_ref)
+    }
+
+    /// Emit a [fmul](https://llvm.org/docs/LangRef.html#fmul-instruction) instruction.
+    ///
+    /// # Panics
+    ///
+    /// Panics if LLVM API returns a `null` pointer.
+    pub fn fmul(&self, lhs: Value<'llvm>, rhs: Value<'llvm>) -> Value<'llvm> {
+        debug_assert!(lhs.is_f64(), "fmul: Expected f64 as lhs operand!");
+        debug_assert!(rhs.is_f64(), "fmul: Expected f64 as rhs operand!");
+
+        let value_ref = unsafe {
+            LLVMBuildFMul(
+                self.builder,
+                lhs.value_ref(),
+                rhs.value_ref(),
+                b"fmul\0".as_ptr().cast(),
+            )
+        };
+        Value::new(value_ref)
+    }
+
+    /// Emit a [fcmult](https://llvm.org/docs/LangRef.html#fcmp-instruction) instruction.
+    ///
+    /// # Panics
+    ///
+    /// Panics if LLVM API returns a `null` pointer.
+    pub fn fcmpult(&self, lhs: Value<'llvm>, rhs: Value<'llvm>) -> Value<'llvm> {
+        debug_assert!(lhs.is_f64(), "fcmplt: Expected f64 as lhs operand!");
+        debug_assert!(rhs.is_f64(), "fcmplt: Expected f64 as rhs operand!");
+
+        let value_ref = unsafe {
+            LLVMBuildFCmp(
+                self.builder,
+                LLVMRealPredicate::LLVMRealULT,
+                lhs.value_ref(),
+                rhs.value_ref(),
+                b"fcmplt\0".as_ptr().cast(),
+            )
+        };
+        Value::new(value_ref)
+    }
+
+    /// Emit a [uitofp](https://llvm.org/docs/LangRef.html#uitofp-to-instruction) instruction.
+    ///
+    /// # Panics
+    ///
+    /// Panics if LLVM API returns a `null` pointer.
+    pub fn uitofp(&self, val: Value<'llvm>, dest_type: Type<'llvm>) -> Value<'llvm> {
+        debug_assert!(val.is_int(), "uitofp: Expected integer operand!");
+
+        let value_ref = unsafe {
+            LLVMBuildUIToFP(
+                self.builder,
+                val.value_ref(),
+                dest_type.0,
+                b"uitofp\0".as_ptr().cast(),
+            )
+        };
+        Value::new(value_ref)
+    }
+
+    /// Emit a [call](https://llvm.org/docs/LangRef.html#call-instruction) instruction.
+    ///
+    /// # Panics
+    ///
+    /// Panics if LLVM API returns a `null` pointer.
+    pub fn call(&self, fn_value: FnValue<'llvm>, args: &mut [Value<'llvm>]) -> Value<'llvm> {
+        let value_ref = unsafe {
+            LLVMBuildCall2(
+                self.builder,
+                fn_value.ret_type(),
+                fn_value,
+                args.as_mut_ptr(),
+                args.len() as libc::c_uint,
+                b"call\0".as_ptr().cast(),
+            )
+        };
+        Value::new(value_ref)
+    }
+
+    /// Emit a [ret](https://llvm.org/docs/LangRef.html#ret-instruction) instruction.
+    ///
+    /// # Panics
+    ///
+    /// Panics if LLVM API returns a `null` pointer.
+    pub fn ret(&self, ret: Value<'llvm>) {
+        let ret = unsafe { LLVMBuildRet(self.builder, ret.value_ref()) };
+        assert!(!ret.is_null());
+    }
+}
+
+impl Drop for Builder<'_> {
+    fn drop(&mut self) {
+        unsafe { LLVMDisposeBuilder(self.builder) }
+    }
+}
+
+// ==============
+//   BasicBlock
+// ==============
+
+/// Wrapper for a LLVM Basic Block.
+#[derive(Copy, Clone)]
+pub struct BasicBlock<'llvm>(LLVMBasicBlockRef, PhantomData<&'llvm ()>);
+
+// ========
+//   Type
+// ========
+
+/// Wrapper for a LLVM Type Reference.
+#[derive(Copy, Clone)]
+#[repr(transparent)]
+pub struct Type<'llvm>(LLVMTypeRef, PhantomData<&'llvm ()>);
+
+impl<'llvm> Type<'llvm> {
+    fn new(type_ref: LLVMTypeRef) -> Self {
+        assert!(!type_ref.is_null());
+        Type(type_ref, PhantomData)
+    }
+
+    fn kind(&self) -> LLVMTypeKind {
+        unsafe { LLVMGetTypeKind(self.0) }
+    }
+
+    /// Dump the LLVM Type to stdout.
+    pub fn dump(&self) {
+        unsafe { LLVMDumpType(self.0) };
+    }
+
+    /// Get a value reference representing the const `f64` value.
+    ///
+    /// # Panics
+    ///
+    /// Panics if LLVM API returns a `null` pointer.
+    pub fn const_f64(self, n: f64) -> Value<'llvm> {
+        debug_assert_eq!(
+            self.kind(),
+            LLVMTypeKind::LLVMDoubleTypeKind,
+            "Expected a double type when creating const f64 value!"
+        );
+
+        let value_ref = unsafe { LLVMConstReal(self.0, n) };
+        Value::new(value_ref)
+    }
+}
+
+// =========
+//   Value
+// =========
+
+/// Wrapper for a LLVM Value Reference.
+#[derive(Copy, Clone)]
+#[repr(transparent)]
+pub struct Value<'llvm>(LLVMValueRef, PhantomData<&'llvm ()>);
+
+impl<'llvm> Value<'llvm> {
+    fn new(value_ref: LLVMValueRef) -> Self {
+        assert!(!value_ref.is_null());
+        Value(value_ref, PhantomData)
+    }
+
+    #[inline]
+    fn value_ref(&self) -> LLVMValueRef {
+        self.0
+    }
+
+    fn kind(&self) -> LLVMValueKind {
+        unsafe { LLVMGetValueKind(self.value_ref()) }
+    }
+
+    /// Dump the LLVM Value to stdout.
+    pub fn dump(&self) {
+        unsafe { LLVMDumpValue(self.value_ref()) };
+    }
+
+    /// Get a type reference representing for the given value reference.
+    ///
+    /// # Panics
+    ///
+    /// Panics if LLVM API returns a `null` pointer.
+    pub fn type_of(&self) -> Type<'llvm> {
+        let type_ref = unsafe { LLVMTypeOf(self.value_ref()) };
+        Type::new(type_ref)
+    }
+
+    /// Set the name for the given value reference.
+    ///
+    /// # Panics
+    ///
+    /// Panics if LLVM API returns a `null` pointer.
+    pub fn set_name(&self, name: &str) {
+        unsafe { LLVMSetValueName2(self.value_ref(), name.as_ptr().cast(), name.len()) };
+    }
+
+    /// Get the name for the given value reference.
+    ///
+    /// # Panics
+    ///
+    /// Panics if LLVM API returns a `null` pointer.
+    pub fn get_name(&self) -> &'llvm str {
+        let name = unsafe {
+            let mut len: libc::size_t = 0;
+            let name = LLVMGetValueName2(self.0, &mut len as _);
+            assert!(!name.is_null());
+
+            CStr::from_ptr(name)
+        };
+
+        // TODO: Does this string live for the time of the LLVM context?!
+        name.to_str()
+            .expect("Expected valid UTF8 string from LLVM API")
+    }
+
+    /// Check if value is of `f64` type.
+    pub fn is_f64(&self) -> bool {
+        self.type_of().kind() == LLVMTypeKind::LLVMDoubleTypeKind
+    }
+
+    /// Check if value is of integer type.
+    pub fn is_int(&self) -> bool {
+        self.type_of().kind() == LLVMTypeKind::LLVMIntegerTypeKind
+    }
+}
+
+/// Wrapper for a LLVM Value Reference specialized for contexts where function values are needed.
+#[derive(Copy, Clone)]
+#[repr(transparent)]
+pub struct FnValue<'llvm>(Value<'llvm>);
+
+impl<'llvm> Deref for FnValue<'llvm> {
+    type Target = Value<'llvm>;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+impl<'llvm> FnValue<'llvm> {
+    fn new(value_ref: LLVMValueRef) -> Self {
+        let value = Value::new(value_ref);
+        debug_assert_eq!(
+            value.kind(),
+            LLVMValueKind::LLVMFunctionValueKind,
+            "Expected a fn value when constructing FnValue!"
+        );
+
+        FnValue(value)
+    }
+
+    /// Get a type reference representing the return value of the given function value.
+    ///
+    /// # Panics
+    ///
+    /// Panics if LLVM API returns a `null` pointer.
+    pub fn ret_type(&self) -> Type<'llvm> {
+        let type_ref = unsafe { LLVMGetReturnType(LLVMTypeOf(self.value_ref())) };
+        Type::new(type_ref)
+    }
+
+    /// Get the number of function arguments for the given function value.
+    pub fn args(&self) -> usize {
+        unsafe { LLVMCountParams(self.value_ref()) as usize }
+    }
+
+    /// Get a value reference for the function argument at index `idx`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if LLVM API returns a `null` pointer or indexed out of bounds.
+    pub fn arg(&self, idx: usize) -> Value<'llvm> {
+        assert!(idx < self.args());
+
+        let value_ref = unsafe { LLVMGetParam(self.value_ref(), idx as libc::c_uint) };
+        Value::new(value_ref)
+    }
+
+    /// Get the number of Basic Blocks for the given function value.
+    pub fn basic_blocks(&self) -> usize {
+        unsafe { LLVMCountBasicBlocks(self.value_ref()) as usize }
+    }
+
+    /// Verify that the given function is valid.
+    pub fn verify(&self) -> bool {
+        unsafe {
+            LLVMVerifyFunction(
+                self.value_ref(),
+                LLVMVerifierFailureAction::LLVMPrintMessageAction,
+            ) == 0
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/src/llvm_kaleidoscope_rs/parser.rs.html b/src/llvm_kaleidoscope_rs/parser.rs.html new file mode 100644 index 0000000..3bd0dc8 --- /dev/null +++ b/src/llvm_kaleidoscope_rs/parser.rs.html @@ -0,0 +1,925 @@ +parser.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+
+use crate::lexer::{Lexer, Token};
+
+#[derive(Debug, PartialEq)]
+pub enum ExprAST {
+    /// Number - Expression class for numeric literals like "1.0".
+    Number(f64),
+
+    /// Variable - Expression class for referencing a variable, like "a".
+    Variable(String),
+
+    /// Binary - Expression class for a binary operator.
+    Binary(char, Box<ExprAST>, Box<ExprAST>),
+
+    /// Call - Expression class for function calls.
+    Call(String, Vec<ExprAST>),
+}
+
+/// PrototypeAST - This class represents the "prototype" for a function,
+/// which captures its name, and its argument names (thus implicitly the number
+/// of arguments the function takes).
+#[derive(Debug, PartialEq)]
+pub struct PrototypeAST(pub String, pub Vec<String>);
+
+/// FunctionAST - This class represents a function definition itself.
+#[derive(Debug, PartialEq)]
+pub struct FunctionAST(pub PrototypeAST, pub ExprAST);
+
+/// Parse result with String as Error type (to be compliant with tutorial).
+type ParseResult<T> = Result<T, String>;
+
+/// Parser for the `kaleidoscope` language.
+pub struct Parser<I>
+where
+    I: Iterator<Item = char>,
+{
+    lexer: Lexer<I>,
+    cur_tok: Option<Token>,
+}
+
+impl<I> Parser<I>
+where
+    I: Iterator<Item = char>,
+{
+    pub fn new(lexer: Lexer<I>) -> Self {
+        Parser {
+            lexer,
+            cur_tok: None,
+        }
+    }
+
+    // -----------------------
+    //   Simple Token Buffer
+    // -----------------------
+
+    /// Implement the global variable `int CurTok;` from the tutorial.
+    ///
+    /// # Panics
+    /// Panics if the parser doesn't have a current token.
+    pub fn cur_tok(&self) -> &Token {
+        self.cur_tok.as_ref().expect("Parser: Expected cur_token!")
+    }
+
+    /// Advance the `cur_tok` by getting the next token from the lexer.
+    ///
+    /// Implement the fucntion `int getNextToken();` from the tutorial.
+    pub fn get_next_token(&mut self) {
+        self.cur_tok = Some(self.lexer.gettok());
+    }
+
+    // ----------------------------
+    //   Basic Expression Parsing
+    // ----------------------------
+
+    /// numberexpr ::= number
+    ///
+    /// Implement `std::unique_ptr<ExprAST> ParseNumberExpr();` from the tutorial.
+    fn parse_num_expr(&mut self) -> ParseResult<ExprAST> {
+        match *self.cur_tok() {
+            Token::Number(num) => {
+                // Consume the number token.
+                self.get_next_token();
+                Ok(ExprAST::Number(num))
+            }
+            _ => unreachable!(),
+        }
+    }
+
+    /// parenexpr ::= '(' expression ')'
+    ///
+    /// Implement `std::unique_ptr<ExprAST> ParseParenExpr();` from the tutorial.
+    fn parse_paren_expr(&mut self) -> ParseResult<ExprAST> {
+        // Eat '(' token.
+        assert_eq!(*self.cur_tok(), Token::Char('('));
+        self.get_next_token();
+
+        let v = self.parse_expression()?;
+
+        if *self.cur_tok() == Token::Char(')') {
+            // Eat ')' token.
+            self.get_next_token();
+            Ok(v)
+        } else {
+            Err("expected ')'".into())
+        }
+    }
+
+    /// identifierexpr
+    ///   ::= identifier
+    ///   ::= identifier '(' expression* ')'
+    ///
+    /// Implement `std::unique_ptr<ExprAST> ParseIdentifierExpr();` from the tutorial.
+    fn parse_identifier_expr(&mut self) -> ParseResult<ExprAST> {
+        let id_name = match self.cur_tok.take() {
+            Some(Token::Identifier(id)) => {
+                // Consume identifier.
+                self.get_next_token();
+                id
+            }
+            _ => unreachable!(),
+        };
+
+        if *self.cur_tok() != Token::Char('(') {
+            // Simple variable reference.
+            Ok(ExprAST::Variable(id_name))
+        } else {
+            // Call.
+
+            // Eat '(' token.
+            self.get_next_token();
+
+            let mut args: Vec<ExprAST> = Vec::new();
+
+            // If there are arguments collect them.
+            if *self.cur_tok() != Token::Char(')') {
+                loop {
+                    let arg = self.parse_expression()?;
+                    args.push(arg);
+
+                    if *self.cur_tok() == Token::Char(')') {
+                        // Eat ')' token.
+                        self.get_next_token();
+                        break;
+                    }
+
+                    if *self.cur_tok() != Token::Char(',') {
+                        return Err("Expected ')' or ',' in argument list".into());
+                    }
+
+                    self.get_next_token();
+                }
+            }
+
+            Ok(ExprAST::Call(id_name, args))
+        }
+    }
+
+    /// primary
+    ///   ::= identifierexpr
+    ///   ::= numberexpr
+    ///   ::= parenexpr
+    ///
+    /// Implement `std::unique_ptr<ExprAST> ParsePrimary();` from the tutorial.
+    fn parse_primary(&mut self) -> ParseResult<ExprAST> {
+        match *self.cur_tok() {
+            Token::Identifier(_) => self.parse_identifier_expr(),
+            Token::Number(_) => self.parse_num_expr(),
+            Token::Char('(') => self.parse_paren_expr(),
+            _ => Err("unknown token when expecting an expression".into()),
+        }
+    }
+
+    // -----------------------------
+    //   Binary Expression Parsing
+    // -----------------------------
+
+    /// /// expression
+    ///   ::= primary binoprhs
+    ///
+    /// Implement `std::unique_ptr<ExprAST> ParseExpression();` from the tutorial.
+    fn parse_expression(&mut self) -> ParseResult<ExprAST> {
+        let lhs = self.parse_primary()?;
+        self.parse_bin_op_rhs(0, lhs)
+    }
+
+    /// binoprhs
+    ///   ::= ('+' primary)*
+    ///
+    /// Implement `std::unique_ptr<ExprAST> ParseBinOpRHS(int ExprPrec, std::unique_ptr<ExprAST> LHS);` from the tutorial.
+    fn parse_bin_op_rhs(&mut self, expr_prec: isize, mut lhs: ExprAST) -> ParseResult<ExprAST> {
+        loop {
+            let tok_prec = get_tok_precedence(self.cur_tok());
+
+            // Not a binary operator or precedence is too small.
+            if tok_prec < expr_prec {
+                return Ok(lhs);
+            }
+
+            let binop = match self.cur_tok.take() {
+                Some(Token::Char(c)) => {
+                    // Eat binary operator.
+                    self.get_next_token();
+                    c
+                }
+                _ => unreachable!(),
+            };
+
+            // lhs BINOP1 rhs BINOP2 remrhs
+            //     ^^^^^^     ^^^^^^
+            //     tok_prec   next_prec
+            //
+            // In case BINOP1 has higher precedence, we are done here and can build a 'Binary' AST
+            // node between 'lhs' and 'rhs'.
+            //
+            // In case BINOP2 has higher precedence, we take 'rhs' as 'lhs' and recurse into the
+            // 'remrhs' expression first.
+
+            // Parse primary expression after binary operator.
+            let mut rhs = self.parse_primary()?;
+
+            let next_prec = get_tok_precedence(self.cur_tok());
+            if tok_prec < next_prec {
+                // BINOP2 has higher precedence thatn BINOP1, recurse into 'remhs'.
+                rhs = self.parse_bin_op_rhs(tok_prec + 1, rhs)?
+            }
+
+            lhs = ExprAST::Binary(binop, Box::new(lhs), Box::new(rhs));
+        }
+    }
+
+    // --------------------
+    //   Parsing the Rest
+    // --------------------
+
+    /// prototype
+    ///   ::= id '(' id* ')'
+    ///
+    /// Implement `std::unique_ptr<PrototypeAST> ParsePrototype();` from the tutorial.
+    fn parse_prototype(&mut self) -> ParseResult<PrototypeAST> {
+        let id_name = match self.cur_tok.take() {
+            Some(Token::Identifier(id)) => {
+                // Consume the identifier.
+                self.get_next_token();
+                id
+            }
+            other => {
+                // Plug back current token.
+                self.cur_tok = other;
+                return Err("Expected function name in prototype".into());
+            }
+        };
+
+        if *self.cur_tok() != Token::Char('(') {
+            return Err("Expected '(' in prototype".into());
+        }
+
+        let mut args: Vec<String> = Vec::new();
+        loop {
+            self.get_next_token();
+
+            match self.cur_tok.take() {
+                Some(Token::Identifier(arg)) => args.push(arg),
+                Some(Token::Char(',')) => {}
+                other => {
+                    self.cur_tok = other;
+                    break;
+                }
+            }
+        }
+
+        if *self.cur_tok() != Token::Char(')') {
+            return Err("Expected ')' in prototype".into());
+        }
+
+        // Consume ')'.
+        self.get_next_token();
+
+        Ok(PrototypeAST(id_name, args))
+    }
+
+    /// definition ::= 'def' prototype expression
+    ///
+    /// Implement `std::unique_ptr<FunctionAST> ParseDefinition();` from the tutorial.
+    pub fn parse_definition(&mut self) -> ParseResult<FunctionAST> {
+        // Consume 'def' token.
+        assert_eq!(*self.cur_tok(), Token::Def);
+        self.get_next_token();
+
+        let proto = self.parse_prototype()?;
+        let expr = self.parse_expression()?;
+
+        Ok(FunctionAST(proto, expr))
+    }
+
+    /// external ::= 'extern' prototype
+    ///
+    /// Implement `std::unique_ptr<PrototypeAST> ParseExtern();` from the tutorial.
+    pub fn parse_extern(&mut self) -> ParseResult<PrototypeAST> {
+        // Consume 'extern' token.
+        assert_eq!(*self.cur_tok(), Token::Extern);
+        self.get_next_token();
+
+        self.parse_prototype()
+    }
+
+    /// toplevelexpr ::= expression
+    ///
+    /// Implement `std::unique_ptr<FunctionAST> ParseTopLevelExpr();` from the tutorial.
+    pub fn parse_top_level_expr(&mut self) -> ParseResult<FunctionAST> {
+        let e = self.parse_expression()?;
+        let proto = PrototypeAST("".into(), Vec::new());
+        Ok(FunctionAST(proto, e))
+    }
+}
+
+/// Get the binary operator precedence.
+///
+/// Implement `int GetTokPrecedence();` from the tutorial.
+fn get_tok_precedence(tok: &Token) -> isize {
+    match tok {
+        Token::Char('<') => 10,
+        Token::Char('+') => 20,
+        Token::Char('-') => 20,
+        Token::Char('*') => 40,
+        _ => -1,
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::{ExprAST, FunctionAST, Parser, PrototypeAST};
+    use crate::lexer::Lexer;
+
+    fn parser(input: &str) -> Parser<std::str::Chars> {
+        let l = Lexer::new(input.chars());
+        let mut p = Parser::new(l);
+
+        // Drop initial coin, initialize cur_tok.
+        p.get_next_token();
+
+        p
+    }
+
+    #[test]
+    fn parse_number() {
+        let mut p = parser("13.37");
+
+        assert_eq!(p.parse_num_expr(), Ok(ExprAST::Number(13.37f64)));
+    }
+
+    #[test]
+    fn parse_variable() {
+        let mut p = parser("foop");
+
+        assert_eq!(
+            p.parse_identifier_expr(),
+            Ok(ExprAST::Variable("foop".into()))
+        );
+    }
+
+    #[test]
+    fn parse_primary() {
+        let mut p = parser("1337 foop \n bla(123)");
+
+        assert_eq!(p.parse_primary(), Ok(ExprAST::Number(1337f64)));
+
+        assert_eq!(p.parse_primary(), Ok(ExprAST::Variable("foop".into())));
+
+        assert_eq!(
+            p.parse_primary(),
+            Ok(ExprAST::Call("bla".into(), vec![ExprAST::Number(123f64)]))
+        );
+    }
+
+    #[test]
+    fn parse_binary_op() {
+        // Operator before RHS has higher precedence, expected AST
+        //
+        //       -
+        //      / \
+        //     +     c
+        //    / \
+        //   a   b
+        let mut p = parser("a + b - c");
+
+        let binexpr_ab = ExprAST::Binary(
+            '+',
+            Box::new(ExprAST::Variable("a".into())),
+            Box::new(ExprAST::Variable("b".into())),
+        );
+
+        let binexpr_abc = ExprAST::Binary(
+            '-',
+            Box::new(binexpr_ab),
+            Box::new(ExprAST::Variable("c".into())),
+        );
+
+        assert_eq!(p.parse_expression(), Ok(binexpr_abc));
+    }
+
+    #[test]
+    fn parse_binary_op2() {
+        // Operator after RHS has higher precedence, expected AST
+        //
+        //       +
+        //      / \
+        //     a   *
+        //        / \
+        //       b   c
+        let mut p = parser("a + b * c");
+
+        let binexpr_bc = ExprAST::Binary(
+            '*',
+            Box::new(ExprAST::Variable("b".into())),
+            Box::new(ExprAST::Variable("c".into())),
+        );
+
+        let binexpr_abc = ExprAST::Binary(
+            '+',
+            Box::new(ExprAST::Variable("a".into())),
+            Box::new(binexpr_bc),
+        );
+
+        assert_eq!(p.parse_expression(), Ok(binexpr_abc));
+    }
+
+    #[test]
+    fn parse_prototype() {
+        let mut p = parser("foo(a,b)");
+
+        let proto = PrototypeAST("foo".into(), vec!["a".into(), "b".into()]);
+
+        assert_eq!(p.parse_prototype(), Ok(proto));
+    }
+
+    #[test]
+    fn parse_definition() {
+        let mut p = parser("def bar( arg0 , arg1 ) arg0 + arg1");
+
+        let proto = PrototypeAST("bar".into(), vec!["arg0".into(), "arg1".into()]);
+
+        let body = ExprAST::Binary(
+            '+',
+            Box::new(ExprAST::Variable("arg0".into())),
+            Box::new(ExprAST::Variable("arg1".into())),
+        );
+
+        let func = FunctionAST(proto, body);
+
+        assert_eq!(p.parse_definition(), Ok(func));
+    }
+
+    #[test]
+    fn parse_extern() {
+        let mut p = parser("extern baz()");
+
+        let proto = PrototypeAST("baz".into(), vec![]);
+
+        assert_eq!(p.parse_extern(), Ok(proto));
+    }
+}
+
+
\ No newline at end of file -- cgit v1.2.3