14 个稳定版本 (4 个主要版本)

5.2.0 2022年11月26日
5.1.1 2022年11月25日
4.1.0 2022年5月7日
4.0.0 2022年4月29日
1.2.0 2022年4月9日

#1827解析器实现

Download history 46/week @ 2024-03-11 73/week @ 2024-03-18 26/week @ 2024-03-25 48/week @ 2024-04-01 23/week @ 2024-04-08 59/week @ 2024-04-15 29/week @ 2024-04-22 33/week @ 2024-04-29 35/week @ 2024-05-06 21/week @ 2024-05-13 26/week @ 2024-05-20 45/week @ 2024-05-27 41/week @ 2024-06-03 33/week @ 2024-06-10 42/week @ 2024-06-17 25/week @ 2024-06-24

每月146 次下载
用于 toros

GPL-3.0-only

9MB
15K SLoC

C++ 12K SLoC // 0.1% comments Rust 1.5K SLoC // 0.1% comments Happy 730 SLoC

🐉 NixEL

Nix 表达式语言的解析器。

CI/CD Documentation Coverage Version License

特性

  • ✔️ 快速

    它可以在不到25秒内解析Nixpkgs中的所有文件,单线程。[^基准规范]

    它使用 Rust 和一点 C++FlexGNU Bison 编写。

  • ✔️ 正确

    这个库是Nix的原始词法分析器解析器的复制粘贴,并对一些类型进行了适配,以更好地适应人体工程学。

    没有解析器比这个更接近原始实现。

  • ✔️ 可靠

    高覆盖率,经过实战检验,且内存安全[^内存安全]。

  • ✔️ 有用

    它提供注释、空白、起始和结束位置、自动字符串转义、多行字符串缩进处理、类型化API以及解析Nix语言所需的一切!

使用方法

您可以在docs.rs/nixel查看文档。

这是一个完整的用法示例

let input: String = String::from(
    r#"
        # Greet the user
        "Hello, World!"
        # Bye!
    "#,
);

let parsed: nixel::Parsed = nixel::parse(input);

match &*parsed.expression {
    nixel::Expression::String(string) => {
        assert_eq!(
            &string.span,
            &nixel::Span {
                start: nixel::Position { line: 3, column: 9 }.into(),
                end: nixel::Position { line: 3, column: 24 }.into(),
            }
            .into()
        );
        assert_eq!(
            &parsed.trivia_before(&string.span.start)[1],
            &nixel::Trivia::Comment(nixel::TriviaComment {
                content: "# Greet the user".into(),
                span: nixel::Span {
                    start: nixel::Position { line: 2, column: 9 }.into(),
                    end: nixel::Position { line: 2, column: 25 }.into(),
                }
                .into()
            })
        );
        assert_eq!(
            &string.parts[0],
            &nixel::Part::Raw(nixel::PartRaw {
                content: "Hello, World!".into(),
                span: nixel::Span {
                    start: nixel::Position { line: 3, column: 10 }.into(),
                    end: nixel::Position { line: 3, column: 23 }.into(),
                }
                .into()
            })
        );
        assert_eq!(
            &parsed.trivia_after(&string.span.end)[1],
            &nixel::Trivia::Comment(nixel::TriviaComment {
                content: "# Bye!".into(),
                span: nixel::Span {
                    start: nixel::Position { line: 4, column: 9 }.into(),
                    end: nixel::Position { line: 4, column: 15 }.into(),
                }
                .into()
            })
        );
    },
    expression => unreachable!("Expected a String, got: {expression:#?}"),
}

或从命令行使用Rust的Debug特性

$ echo '1 + 2' | nix run github:kamadorueda/nixel -- --format=debug

BinaryOperation(
    BinaryOperation {
        left: Integer(
            Integer {
                value: "1",
                span: Span {
                    start: Position {
                        line: 1,
                        column: 1,
                    },
                    end: Position {
                        line: 1,
                        column: 2,
                    },
                },
            },
        ),
        operator: Addition,
        right: Integer(
            Integer {
                value: "2",
                span: Span {
                    start: Position {
                        line: 1,
                        column: 5,
                    },
                    end: Position {
                        line: 1,
                        column: 6,
                    },
                },
            },
        ),
    },
)

或从命令行使用JSON格式

$ echo '1 + 2' | nix run github:kamadorueda/nixel -- --format=json

{
  "BinaryOperation": {
    "left": {
      "Integer": {
        "value": "1",
        "span": {
          "start": {
            "line": 1,
            "column": 1
          },
          "end": {
            "line": 1,
            "column": 2
          }
        }
      }
    },
    "operator": "Addition",
    "right": {
      "Integer": {
        "value": "2",
        "span": {
          "start": {
            "line": 1,
            "column": 5
          },
          "end": {
            "line": 1,
            "column": 6
          }
        }
      }
    }
  }
}

您可以在测试文件夹中查看更多示例。

替代方案

许可协议

请阅读LICENSE.md

脚注

[^基准规范]: 在机器上运行

- CPU: 4 physical, 4 logical, 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz
- MHz: from 400 to 4700 MHz
- BogoMips: 5606.40
- Cache L3: 12 MiB

The following command takes around 1 minute:

```bash
$ nix build --system x86_64-linux
$ time find /data/nixpkgs -type f -name '*.nix' \
  -exec ./result/bin/nixel --format=none {} \;

real  0m24.293s
user  0m15.066s
sys   0m8.955s
```

[^内存安全]: 使用Valgrind在真实工作负载下测试,并通过对Nixpkgs运行无限循环的解析周期进行测试。

```bash
$ nix build --system x86_64-linux
$ valgrind ./result/bin/nixel $file

  LEAK SUMMARY:
    definitely lost: 0 bytes in 0 blocks
    indirectly lost: 0 bytes in 0 blocks
      possibly lost: 0 bytes in 0 blocks
         suppressed: 0 bytes in 0 blocks
```

依赖