elmx 0.1.0

elm compiler and runtime
Documentation
use elmx::{Token, TokenKind::{self, *}, Lexer};

fn lex(input: &str) -> Vec<Token> {
    let lexer = Lexer::new(input);
    lexer.collect()
}

fn single_token(input: &str, kind: TokenKind) {
    let token = Token {
        literal: input,
        kind,
        line: 1,
        column: 1,
    };
    assert_eq!(lex(input), vec![token]);
}

#[test]
fn tokens() {
    let tests = [
        ("main", Ident),
        ("let", Let),
        ("in", In),
        ("module", Module),
        ("import", Import),
        ("exposing", Exposing),
        ("type", Type),
        ("case", Case),
        ("of", Of),

        ("=", Assign),
        ("->", Arrow),
        (":", Colon),
        ("|", Pipe),
        (",", Comma),
        (".", Dot),
        ("::", DoubleColon),
        ("++", DoublePlus),

        ("-", Minus),
        ("%", Modulo),
        ("+", Plus),
        ("*", Multiply),
        ("^", Power),

        ("&&", And),
        ("not", Not),
        ("||", Or),
        ("==", Equal),
        (">", Greater),
        (">=", GreaterEq),
        ("<", Less),
        ("<=", LessEq),

        ("42", Int),
        ("True", True),
        ("False", False),
        ("42.0", Float),
        ("'#'", Char),
        ("\"hello\"", Str),

        ("(", OpenParen),
        (")", CloseParen),
        ("[", OpenBracket),
        ("]", CloseBracket),
        ("{", OpenBrace),
        ("}", CloseBrace),
        ("\\", Backslash),

        ("if", If),
        ("then", Then),
        ("else", Else),

        ("-- this is a single line comment", SingleComment),
        (r#"{- this is a multi-line comment 
        this is the second line
        -}"#, MultiComment),
    ];

    for (input, kind) in tests {
        single_token(input, kind);
    }
}

#[test]
fn dot() {
    let tokens = [
        Token { literal: "String", kind: Ident, line: 1, column: 1 },
        Token { literal: ".", kind: Dot, line: 1, column: 7 },
        Token { literal: "fromInt", kind: Ident, line: 1, column: 8 },
    ];

    assert_eq!(lex("String.fromInt"), tokens);
}


#[test]
fn let_stmt() {
    let tokens = vec![
        Token { literal: "module", kind: Module, line: 1, column: 1 },
        Token { literal: "Main", kind: Ident, line: 1, column: 8 },
        Token { literal: "exposing", kind: Exposing, line: 1, column: 13 },
        Token { literal: "(", kind: OpenParen, line: 1, column: 22 },
        Token { literal: "..", kind: DoubleDot, line: 1, column: 23 },
        Token { literal: ")", kind: CloseParen, line: 1, column: 25 },

        Token { literal: "fizzBuzz", kind: Ident, line: 3, column: 1 },
        Token { literal: ":", kind: Colon, line: 3, column: 10 },
        Token { literal: "Int", kind: Ident, line: 3, column: 12 },
        Token { literal: "->", kind: Arrow, line: 3, column: 16 },
        Token { literal: "String", kind: Ident, line: 3, column: 19 },

        Token { literal: "fizzBuzz", kind: Ident, line: 4, column: 1 },
        Token { literal: "n", kind: Ident, line: 4, column: 10 },
        Token { literal: "=", kind: Assign, line: 4, column: 12 },

        Token { literal: "if", kind: If, line: 5, column: 5 },
        Token { literal: "n", kind: Ident, line: 5, column: 8 },
        Token { literal: "%", kind: Modulo, line: 5, column: 10 },
        Token { literal: "3", kind: Int, line: 5, column: 12 },
        Token { literal: "==", kind: Equal, line: 5, column: 14 },
        Token { literal: "0", kind: Int, line: 5, column: 17 },
        Token { literal: "&&", kind: And, line: 5, column: 19 },
        Token { literal: "n", kind: Ident, line: 5, column: 22 },
        Token { literal: "%", kind: Modulo, line: 5, column: 24 },
        Token { literal: "5", kind: Int, line: 5, column: 26 },
        Token { literal: "==", kind: Equal, line: 5, column: 28 },
        Token { literal: "0", kind: Int, line: 5, column: 31 },
        Token { literal: "then", kind: Then, line: 5, column: 33 },

        Token { literal: "\"FizzBuzz\"", kind: Str, line: 6, column: 9 },

        Token { literal: "else", kind: Else, line: 7, column: 5 },
        Token { literal: "if", kind: If, line: 7, column: 10 },
        Token { literal: "n", kind: Ident, line: 7, column: 13 },
        Token { literal: "%", kind: Modulo, line: 7, column: 15 },
        Token { literal: "3", kind: Int, line: 7, column: 17 },
        Token { literal: "==", kind: Equal, line: 7, column: 19 },
        Token { literal: "0", kind: Int, line: 7, column: 22 },
        Token { literal: "then", kind: Then, line: 7, column: 24 },

        Token { literal: "\"Fizz\"", kind: Str, line: 8, column: 9 },

        Token { literal: "else", kind: Else, line: 9, column: 5 },
        Token { literal: "if", kind: If, line: 9, column: 10 },
        Token { literal: "n", kind: Ident, line: 9, column: 13 },
        Token { literal: "%", kind: Modulo, line: 9, column: 15 },
        Token { literal: "5", kind: Int, line: 9, column: 17 },
        Token { literal: "==", kind: Equal, line: 9, column: 19 },
        Token { literal: "0", kind: Int, line: 9, column: 22 },
        Token { literal: "then", kind: Then, line: 9, column: 24 },

        Token { literal: "\"Buzz\"", kind: Str, line: 10, column: 9 },

        Token { literal: "else", kind: Else, line: 11, column: 5 },

        Token { literal: "String", kind: Ident, line: 12, column: 9 },
        Token { literal: ".", kind: Dot, line: 12, column: 15 },
        Token { literal: "fromInt", kind: Ident, line: 12, column: 16 },
        Token { literal: "n", kind: Ident, line: 12, column: 24 },

        Token { literal: "main", kind: Ident, line: 14, column: 1 },
        Token { literal: "=", kind: Assign, line: 14, column: 6 },

        Token { literal: "let", kind: Let, line: 15, column: 5 },

        Token { literal: "numbers", kind: Ident, line: 16, column: 9 },
        Token { literal: "=", kind: Assign, line: 16, column: 17 },
        Token { literal: "List", kind: Ident, line: 16, column: 19 },
        Token { literal: ".", kind: Dot, line: 16, column: 23 },
        Token { literal: "range", kind: Ident, line: 16, column: 24 },
        Token { literal: "1", kind: Int, line: 16, column: 30 },
        Token { literal: "100", kind: Int, line: 16, column: 32 },

        Token { literal: "results", kind: Ident, line: 17, column: 9 },
        Token { literal: "=", kind: Assign, line: 17, column: 17 },
        Token { literal: "List", kind: Ident, line: 17, column: 19 },
        Token { literal: ".", kind: Dot, line: 17, column: 23 },
        Token { literal: "map", kind: Ident, line: 17, column: 24 },
        Token { literal: "fizzBuzz", kind: Ident, line: 17, column: 28 },
        Token { literal: "numbers", kind: Ident, line: 17, column: 37 },

        Token { literal: "in", kind: In, line: 18, column: 5 },

        Token { literal: "List", kind: Ident, line: 19, column: 5 },
        Token { literal: ".", kind: Dot, line: 19, column: 9 },
        Token { literal: "foldl", kind: Ident, line: 19, column: 10 },
        Token { literal: "(", kind: OpenParen, line: 19, column: 16 },
        Token { literal: "\\", kind: Backslash, line: 19, column: 17 },
        Token { literal: "line", kind: Ident, line: 19, column: 18 },
        Token { literal: "acc", kind: Ident, line: 19, column: 23 },
        Token { literal: "->", kind: Arrow, line: 19, column: 27 },
        Token { literal: "acc", kind: Ident, line: 19, column: 30 },
        Token { literal: "++", kind: DoublePlus, line: 19, column: 34 },
        Token { literal: "line", kind: Ident, line: 19, column: 37 },
        Token { literal: "++", kind: DoublePlus, line: 19, column: 42 },
        Token { literal: "\"\\n\"", kind: Str, line: 19, column: 45 },
        Token { literal: ")", kind: CloseParen, line: 19, column: 49 },
        Token { literal: "\"\"", kind: Str, line: 19, column: 51 },
        Token { literal: "results", kind: Ident, line: 19, column: 54 },
        Token { literal: "|>", kind: Pipeline, line: 19, column: 62 },
        Token { literal: "Debug", kind: Ident, line: 19, column: 65 },
        Token { literal: ".", kind: Dot, line: 19, column: 70 },
        Token { literal: "log", kind: Ident, line: 19, column: 71 },
        Token { literal: "\"FizzBuzz Output\"", kind: Str, line: 19, column: 75 },
    ];

    let lexed_tokens = lex(include_str!("Main.elm"));

    assert_eq!(tokens.len(), lexed_tokens.len());

    for (token, lexed_token) in tokens.into_iter().zip(lexed_tokens) {
        assert_eq!(token, lexed_token);
    }
}