solar-parse 0.1.8

Solidity and Yul lexer and parser
Documentation
use super::*;
use snapbox::{IntoData, str};
use std::fmt::Write;

fn check(src: &str, data: impl IntoData) {
    let mut actual = String::new();
    for token in Cursor::new(src) {
        writeln!(actual, "{token:?}").unwrap();
    }
    snapbox::assert_data_eq!(actual.trim(), data);
}

#[test]
fn smoke_test() {
    check(
        "/* my source file */ fn main() { print(\"zebra\"); }\n",
        str![[r#"
RawToken { kind: BlockComment { is_doc: false, terminated: true }, len: 20 }
RawToken { kind: Whitespace, len: 1 }
RawToken { kind: Ident, len: 2 }
RawToken { kind: Whitespace, len: 1 }
RawToken { kind: Ident, len: 4 }
RawToken { kind: OpenDelim(Parenthesis), len: 1 }
RawToken { kind: CloseDelim(Parenthesis), len: 1 }
RawToken { kind: Whitespace, len: 1 }
RawToken { kind: OpenDelim(Brace), len: 1 }
RawToken { kind: Whitespace, len: 1 }
RawToken { kind: Ident, len: 5 }
RawToken { kind: OpenDelim(Parenthesis), len: 1 }
RawToken { kind: Literal { kind: Str { kind: Str, terminated: true } }, len: 7 }
RawToken { kind: CloseDelim(Parenthesis), len: 1 }
RawToken { kind: Semi, len: 1 }
RawToken { kind: Whitespace, len: 1 }
RawToken { kind: CloseDelim(Brace), len: 1 }
RawToken { kind: Whitespace, len: 1 }
"#]],
    );
}

#[test]
fn comment_flavors() {
    check(
        r"
// line
//// line as well
/// doc line
/* block */
/**/
/*** also block */
/** doc block */
",
        str![[r#"
RawToken { kind: Whitespace, len: 1 }
RawToken { kind: LineComment { is_doc: false }, len: 7 }
RawToken { kind: Whitespace, len: 1 }
RawToken { kind: LineComment { is_doc: false }, len: 17 }
RawToken { kind: Whitespace, len: 1 }
RawToken { kind: LineComment { is_doc: true }, len: 12 }
RawToken { kind: Whitespace, len: 1 }
RawToken { kind: BlockComment { is_doc: false, terminated: true }, len: 11 }
RawToken { kind: Whitespace, len: 1 }
RawToken { kind: BlockComment { is_doc: false, terminated: true }, len: 4 }
RawToken { kind: Whitespace, len: 1 }
RawToken { kind: BlockComment { is_doc: false, terminated: true }, len: 18 }
RawToken { kind: Whitespace, len: 1 }
RawToken { kind: BlockComment { is_doc: true, terminated: true }, len: 16 }
RawToken { kind: Whitespace, len: 1 }
"#]],
    )
}

#[test]
fn single_str() {
    check(
        "'a' ' ' '\\n'",
        str![[r#"
RawToken { kind: Literal { kind: Str { kind: Str, terminated: true } }, len: 3 }
RawToken { kind: Whitespace, len: 1 }
RawToken { kind: Literal { kind: Str { kind: Str, terminated: true } }, len: 3 }
RawToken { kind: Whitespace, len: 1 }
RawToken { kind: Literal { kind: Str { kind: Str, terminated: true } }, len: 4 }
"#]],
    );
}

#[test]
fn double_str() {
    check(
        r#""a" " " "\n""#,
        str![[r#"
RawToken { kind: Literal { kind: Str { kind: Str, terminated: true } }, len: 3 }
RawToken { kind: Whitespace, len: 1 }
RawToken { kind: Literal { kind: Str { kind: Str, terminated: true } }, len: 3 }
RawToken { kind: Whitespace, len: 1 }
RawToken { kind: Literal { kind: Str { kind: Str, terminated: true } }, len: 4 }
"#]],
    );
}

#[test]
fn hex_str() {
    check(
        r#"hex'' hex"ab" h"a" he"a"#,
        str![[r#"
RawToken { kind: Literal { kind: Str { kind: Hex, terminated: true } }, len: 5 }
RawToken { kind: Whitespace, len: 1 }
RawToken { kind: Literal { kind: Str { kind: Hex, terminated: true } }, len: 7 }
RawToken { kind: Whitespace, len: 1 }
RawToken { kind: Ident, len: 1 }
RawToken { kind: Literal { kind: Str { kind: Str, terminated: true } }, len: 3 }
RawToken { kind: Whitespace, len: 1 }
RawToken { kind: Ident, len: 2 }
RawToken { kind: Literal { kind: Str { kind: Str, terminated: false } }, len: 2 }
"#]],
    );
}

#[test]
fn unicode_str() {
    check(
        r#"unicode'' unicode"ab" u"a" uni"a"#,
        str![[r#"
RawToken { kind: Literal { kind: Str { kind: Unicode, terminated: true } }, len: 9 }
RawToken { kind: Whitespace, len: 1 }
RawToken { kind: Literal { kind: Str { kind: Unicode, terminated: true } }, len: 11 }
RawToken { kind: Whitespace, len: 1 }
RawToken { kind: Ident, len: 1 }
RawToken { kind: Literal { kind: Str { kind: Str, terminated: true } }, len: 3 }
RawToken { kind: Whitespace, len: 1 }
RawToken { kind: Ident, len: 3 }
RawToken { kind: Literal { kind: Str { kind: Str, terminated: false } }, len: 2 }
"#]],
    );
}

#[test]
fn random_unicode() {
    check(
        r#"
è

"è"
hex"è"
unicode"è"

'è'
hex'è'
unicode'è'

hex👀
unicode👀

//è
/*è */

///è
/**è */

.è
0.è
1.eè
1.e1è
"#,
        str![[r#"
RawToken { kind: Whitespace, len: 1 }
RawToken { kind: Unknown, len: 2 }
RawToken { kind: Whitespace, len: 2 }
RawToken { kind: Literal { kind: Str { kind: Str, terminated: true } }, len: 4 }
RawToken { kind: Whitespace, len: 1 }
RawToken { kind: Literal { kind: Str { kind: Hex, terminated: true } }, len: 7 }
RawToken { kind: Whitespace, len: 1 }
RawToken { kind: Literal { kind: Str { kind: Unicode, terminated: true } }, len: 11 }
RawToken { kind: Whitespace, len: 2 }
RawToken { kind: Literal { kind: Str { kind: Str, terminated: true } }, len: 4 }
RawToken { kind: Whitespace, len: 1 }
RawToken { kind: Literal { kind: Str { kind: Hex, terminated: true } }, len: 7 }
RawToken { kind: Whitespace, len: 1 }
RawToken { kind: Literal { kind: Str { kind: Unicode, terminated: true } }, len: 11 }
RawToken { kind: Whitespace, len: 2 }
RawToken { kind: Ident, len: 3 }
RawToken { kind: Unknown, len: 4 }
RawToken { kind: Whitespace, len: 1 }
RawToken { kind: Ident, len: 7 }
RawToken { kind: Unknown, len: 4 }
RawToken { kind: Whitespace, len: 2 }
RawToken { kind: LineComment { is_doc: false }, len: 4 }
RawToken { kind: Whitespace, len: 1 }
RawToken { kind: BlockComment { is_doc: false, terminated: true }, len: 7 }
RawToken { kind: Whitespace, len: 2 }
RawToken { kind: LineComment { is_doc: true }, len: 5 }
RawToken { kind: Whitespace, len: 1 }
RawToken { kind: BlockComment { is_doc: true, terminated: true }, len: 8 }
RawToken { kind: Whitespace, len: 2 }
RawToken { kind: Dot, len: 1 }
RawToken { kind: Unknown, len: 2 }
RawToken { kind: Whitespace, len: 1 }
RawToken { kind: Literal { kind: Rational { base: Decimal, empty_exponent: false } }, len: 2 }
RawToken { kind: Unknown, len: 2 }
RawToken { kind: Whitespace, len: 1 }
RawToken { kind: Literal { kind: Int { base: Decimal, empty_int: false } }, len: 1 }
RawToken { kind: Dot, len: 1 }
RawToken { kind: Ident, len: 1 }
RawToken { kind: Unknown, len: 2 }
RawToken { kind: Whitespace, len: 1 }
RawToken { kind: Literal { kind: Int { base: Decimal, empty_int: false } }, len: 1 }
RawToken { kind: Dot, len: 1 }
RawToken { kind: Ident, len: 2 }
RawToken { kind: Unknown, len: 2 }
RawToken { kind: Whitespace, len: 1 }
"#]],
    );
}

#[test]
fn windows_line_ending() {
    check(
        "/// doc line\r\n",
        str![[r#"
RawToken { kind: LineComment { is_doc: true }, len: 12 }
RawToken { kind: Whitespace, len: 2 }
"#]],
    );
}