cairo-lang-parser 2.18.0

Cairo parser.
Documentation
use std::fmt::Display;
use std::vec::IntoIter;

use cairo_lang_filesystem::ids::{FileId, FileKind, FileLongId, SmolStrId, VirtualFile};
use cairo_lang_filesystem::span::TextSpan;
use cairo_lang_primitive_token::{PrimitiveSpan, PrimitiveToken, ToPrimitiveTokenStream};
use cairo_lang_syntax::node::SyntaxNode;
use cairo_lang_test_utils::parse_test_file::TestRunnerResult;
use cairo_lang_utils::Intern;
use cairo_lang_utils::ordered_hash_map::OrderedHashMap;
use salsa::Database;

use crate::utils::{SimpleParserDatabase, get_syntax_root_and_diagnostics};

pub fn get_diagnostics(
    inputs: &OrderedHashMap<String, String>,
    _args: &OrderedHashMap<String, String>,
) -> TestRunnerResult {
    let db = &SimpleParserDatabase::default();
    let code = &inputs["cairo_code"];

    let file_id = create_virtual_file(db, "dummy_file.cairo", code);
    let (_, diagnostics) = get_syntax_root_and_diagnostics(db, file_id);
    TestRunnerResult::success(OrderedHashMap::from([(
        "expected_diagnostics".into(),
        diagnostics.format(db),
    )]))
}

// TODO(yuval): stop virtual files for tests anymore. See semantic tests.
/// Creates a virtual file with the given content and returns its ID.
pub fn create_virtual_file<'a>(
    db: &'a SimpleParserDatabase,
    file_name: impl Into<String>,
    content: &str,
) -> FileId<'a> {
    FileLongId::Virtual(VirtualFile {
        parent: None,
        name: SmolStrId::from(db, file_name.into()),
        content: SmolStrId::from(db, content),
        code_mappings: [].into(),
        kind: FileKind::Module,
        original_item_removed: false,
    })
    .intern(db)
}

/// Mocked struct which implements [cairo_lang_primitive_token::ToPrimitiveTokenStream]
/// Its main purpose is being used for testing the [crate::parser::Parser::parse_token_stream].
#[derive(Debug, Clone)]
pub struct MockTokenStream {
    /// Field that holds all the tokens that are part of the stream.
    pub tokens: Vec<MockToken>,
}

/// Represents a token inside the [MockTokenStream].
#[derive(Debug, Default, Clone)]
pub struct MockToken {
    /// Just a text of a given [MockToken].
    pub content: String,
    /// Its offsets are related to the other tokens present in the same [MockTokenStream].
    pub span: TextSpan,
}

impl MockToken {
    pub fn new(content: String, span: TextSpan) -> Self {
        Self { content, span }
    }

    /// Create a token based on [SyntaxNode].
    pub fn from_syntax_node(db: &dyn Database, node: SyntaxNode<'_>) -> MockToken {
        MockToken::new(node.get_text(db).to_string(), node.span(db))
    }
}

impl MockTokenStream {
    #[doc(hidden)]
    pub fn new(tokens: Vec<MockToken>) -> Self {
        Self { tokens }
    }

    /// Create whole [MockTokenStream] based upon the [SyntaxNode].
    pub fn from_syntax_node(db: &dyn Database, node: SyntaxNode<'_>) -> Self {
        let leaves = node.tokens(db);
        let tokens = leaves.map(|node| MockToken::from_syntax_node(db, node)).collect();
        Self::new(tokens)
    }
}

impl Display for MockTokenStream {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        for token in &self.tokens {
            write!(f, "{}", token.content)?;
        }
        Ok(())
    }
}

impl ToPrimitiveTokenStream for MockTokenStream {
    type Iter = IntoIter<PrimitiveToken>;

    fn to_primitive_token_stream(&self) -> Self::Iter {
        self.tokens
            .iter()
            .map(|token| {
                let span = PrimitiveSpan {
                    start: token.span.start.as_u32() as usize,
                    end: token.span.end.as_u32() as usize,
                };
                PrimitiveToken::new(token.content.clone(), Some(span))
            })
            .collect::<Vec<_>>()
            .into_iter()
    }
}