mod ast;
mod error;
mod lexer;
mod parser;
mod source;
mod span;
mod token;
pub use ast::{
BinaryOp, Block, Expr, ExprKind, FieldDecl, Function, Ident, Item, ModDecl, Param, Program,
Stmt, StructDecl, TypeExpr, UnaryOp,
};
pub use error::{FixIt, SyntaxError, V0001, V0002, V0003, V0010, V0011, V0012};
pub use lexer::lex;
pub use parser::parse;
pub use source::SourceFile;
pub use span::{FileId, Span};
pub use token::{Token, TokenKind};
pub fn parse_source(file: &SourceFile) -> (Program, Vec<SyntaxError>) {
let (tokens, lex_errors) = lex(file);
if !lex_errors.is_empty() {
return (Program { items: Vec::new() }, lex_errors);
}
parse(&tokens, file.id)
}
#[cfg(test)]
mod tests {
use super::*;
use std::path::{Path, PathBuf};
fn example_files() -> Vec<PathBuf> {
let examples_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("../../examples");
let mut files = Vec::new();
collect_vr_files(&examples_dir, &mut files);
files
}
fn collect_vr_files(dir: &Path, files: &mut Vec<PathBuf>) {
let entries = std::fs::read_dir(dir)
.unwrap_or_else(|e| panic!("failed to read directory {dir:?}: {e}"));
for entry in entries {
let path = entry
.unwrap_or_else(|e| panic!("bad directory entry: {e}"))
.path();
if path.is_dir() {
collect_vr_files(&path, files);
} else if path.extension().and_then(|ext| ext.to_str()) == Some("vr") {
files.push(path);
}
}
}
#[test]
fn every_example_file_parses_with_zero_errors() {
let files = example_files();
assert!(
!files.is_empty(),
"found no .vr files under examples/; check the path"
);
for path in files {
let text = std::fs::read_to_string(&path)
.unwrap_or_else(|e| panic!("failed to read {path:?}: {e}"));
let file = SourceFile::new(FileId(0), path.clone(), text);
let (_program, errors) = parse_source(&file);
assert!(
errors.is_empty(),
"unexpected errors parsing {path:?}: {errors:?}"
);
}
}
}