Skip to content

Commit

Permalink
frontend: Add test helper for multiple packages
Browse files Browse the repository at this point in the history
  • Loading branch information
dinfuehr committed Nov 17, 2024
1 parent 57c4f34 commit dc01435
Show file tree
Hide file tree
Showing 11 changed files with 191 additions and 70 deletions.
2 changes: 1 addition & 1 deletion dora-frontend/src/generator/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ fn positions(fct: &BytecodeFunction) -> Vec<(u32, u32)> {
}

fn sema(code: &'static str) -> Sema {
let args: SemaFlags = SemaFlags::for_test(code);
let args: SemaFlags = SemaFlags::for_test(code, &[]);
let mut sa = Sema::new(args);

let result = check_program(&mut sa);
Expand Down
69 changes: 40 additions & 29 deletions dora-frontend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,8 +225,8 @@ pub fn report_sym_shadow_span(sa: &Sema, name: Name, file: SourceFileId, span: S
#[cfg(test)]
pub mod tests {
use crate::error::msg::{ErrorDescriptor, ErrorMessage};
use crate::sema::Sema;
use crate::test;
use crate::sema::{Sema, SemaFlags};
use crate::{check_program, test};
use dora_parser::{compute_line_column, compute_line_starts};

pub fn ok(code: &'static str) {
Expand Down Expand Up @@ -260,39 +260,50 @@ pub mod tests {
}

pub fn errors(code: &'static str, vec: &[((u32, u32), ErrorMessage)]) {
test::check(code, |sa| {
println!("expected errors:");
for ((line, col), err) in vec {
println!("{}:{}: {:?} -> {}", line, col, err, err.message());
}
println!("");
test_with_pkgs(code, &[], vec);
}

println!("actual errors:");
report_errors(sa);
pub fn test_with_pkgs(
code: &str,
packages: &[(&str, &str)],
vec: &[((u32, u32), ErrorMessage)],
) {
let args: SemaFlags = SemaFlags::for_test(code, packages);
let mut sa = Sema::new(args);

check_program(&mut sa);

println!("expected errors:");
for ((line, col), err) in vec {
println!("{}:{}: {:?} -> {}", line, col, err, err.message());
}
println!("");

let diag = sa.diag.borrow();
let errors = diag.errors();
println!("actual errors:");
report_errors(&sa);

let diag = sa.diag.borrow();
let errors = diag.errors();

assert_eq!(
vec.len(),
errors.len(),
"test expects {} errors but actually got {} errors.",
vec.len(),
errors.len()
);

for (ind, error) in errors.iter().enumerate() {
println!("compare error {}", ind);
assert_eq!(Some(vec[ind].0), compute_pos(code, error));
assert_eq!(
vec.len(),
errors.len(),
"test expects {} errors but actually got {} errors.",
vec.len(),
errors.len()
vec[ind].1, error.msg,
"\nexpected: {:?}\n but got: {:?}",
vec[ind].1, error.msg
);
}

for (ind, error) in errors.iter().enumerate() {
println!("compare error {}", ind);
assert_eq!(Some(vec[ind].0), compute_pos(code, error));
assert_eq!(
vec[ind].1, error.msg,
"\nexpected: {:?}\n but got: {:?}",
vec[ind].1, error.msg
);
}

println!("============\n\n");
});
println!("============\n\n");
}

fn report_errors(sa: &Sema) {
Expand Down
62 changes: 40 additions & 22 deletions dora-frontend/src/program_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ use crate::interner::Name;
use crate::sema::{
AliasBound, AliasDefinition, AliasDefinitionId, AliasParent, ClassDefinition, ConstDefinition,
EnumDefinition, EnumField, EnumVariant, ExtensionDefinition, ExtensionDefinitionId,
FctDefinition, FctDefinitionId, FctParent, Field, FieldId, GlobalDefinition, ImplDefinition,
ImplDefinitionId, ModuleDefinition, ModuleDefinitionId, PackageDefinition, PackageDefinitionId,
PackageName, Param, Params, Sema, SourceFile, SourceFileId, StructDefinition,
StructDefinitionField, StructDefinitionFieldId, TraitDefinition, TraitDefinitionId,
TypeParamDefinition, UseDefinition, Visibility,
FctDefinition, FctDefinitionId, FctParent, Field, FieldId, FileContent, GlobalDefinition,
ImplDefinition, ImplDefinitionId, ModuleDefinition, ModuleDefinitionId, PackageDefinition,
PackageDefinitionId, PackageName, Param, Params, Sema, SourceFile, SourceFileId,
StructDefinition, StructDefinitionField, StructDefinitionFieldId, TraitDefinition,
TraitDefinitionId, TypeParamDefinition, UseDefinition, Visibility,
};
use crate::sym::{SymTable, Symbol, SymbolKind};
use crate::{report_sym_shadow_span, ty, ParsedType, SourceType};
Expand All @@ -33,7 +33,7 @@ pub fn parse(sa: &mut Sema) -> HashMap<ModuleDefinitionId, SymTable> {
struct ProgramParser<'a> {
sa: &'a mut Sema,
worklist: VecDeque<SourceFileId>,
packages: HashMap<String, PathBuf>,
packages: HashMap<String, FileContent>,
module_symtables: HashMap<ModuleDefinitionId, SymTable>,
}

Expand Down Expand Up @@ -93,8 +93,8 @@ impl<'a> ProgramParser<'a> {
}

fn get_stdlib_path(&self) -> Option<PathBuf> {
if let Some(path) = self.packages.get("stdlib") {
Some(path.clone())
if let Some(file_content) = self.packages.get("stdlib") {
Some(file_content.to_path().cloned().expect("path expected"))
} else {
let path = std::env::current_exe().expect("illegal path");
let path = path.as_path();
Expand Down Expand Up @@ -134,8 +134,8 @@ impl<'a> ProgramParser<'a> {
}

fn get_boots_path(&self) -> Option<PathBuf> {
if let Some(path) = self.packages.get("boots") {
Some(path.clone())
if let Some(file_content) = self.packages.get("boots") {
Some(file_content.to_path().cloned().expect("path expected"))
} else {
let path = std::env::current_exe().expect("illegal path");
let path = path.as_path();
Expand All @@ -157,16 +157,21 @@ impl<'a> ProgramParser<'a> {
self.sa.set_program_module_id(module_id);
self.sa.set_program_package_id(package_id);

if let Some(ref file) = self.sa.flags.program_file {
let path = PathBuf::from(file);
self.add_file(package_id, module_id, path, None);
} else if let Some(ref content) = self.sa.flags.test_file_as_string {
self.create_source_file_for_content(
package_id,
module_id,
PathBuf::from("<<code>>"),
content.to_string(),
);
if let Some(ref file_content) = self.sa.flags.program_file {
match file_content {
FileContent::Path(path) => {
self.add_file(package_id, module_id, path.clone(), None);
}

FileContent::Content(ref content) => {
self.create_source_file_for_content(
package_id,
module_id,
PathBuf::from("<<code>>"),
content.to_string(),
);
}
}
} else {
self.sa
.report_without_location(ErrorMessage::MissingFileArgument);
Expand All @@ -176,13 +181,26 @@ impl<'a> ProgramParser<'a> {
fn add_dependency_packages(&mut self) {
let packages = std::mem::replace(&mut self.packages, HashMap::new());

for (name, path) in packages {
for (name, file_content) in packages {
let iname = self.sa.interner.intern(&name);
let package_name = PackageName::External(name.clone());
let (package_id, module_id) = add_package(self.sa, package_name, Some(iname));
self.sa.package_names.insert(name, package_id);

self.add_file(package_id, module_id, path, None);
match file_content {
FileContent::Path(path) => {
self.add_file(package_id, module_id, path.clone(), None);
}

FileContent::Content(ref content) => {
self.create_source_file_for_content(
package_id,
module_id,
PathBuf::from("<<code>>"),
content.to_string(),
);
}
}
}
}

Expand Down
32 changes: 25 additions & 7 deletions dora-frontend/src/sema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,19 +71,37 @@ mod tuples;
mod type_params;
mod uses;

#[derive(Clone, Debug)]
pub enum FileContent {
Path(PathBuf),
Content(String),
}

impl FileContent {
pub fn to_path(&self) -> Option<&PathBuf> {
match self {
FileContent::Path(ref path) => Some(path),
_ => None,
}
}
}

pub struct SemaFlags {
pub packages: Vec<(String, PathBuf)>,
pub program_file: Option<PathBuf>,
pub test_file_as_string: Option<String>,
pub packages: Vec<(String, FileContent)>,
pub program_file: Option<FileContent>,
pub boots: bool,
}

impl SemaFlags {
pub fn for_test(input: &'static str) -> SemaFlags {
pub fn for_test(input: &str, packages: &[(&str, &str)]) -> SemaFlags {
let packages = packages
.iter()
.map(|(name, content)| (name.to_string(), FileContent::Content(content.to_string())))
.collect::<Vec<_>>();

SemaFlags {
packages: Vec::new(),
program_file: None,
test_file_as_string: Some(input.into()),
packages,
program_file: Some(FileContent::Content(input.to_string())),
boots: false,
}
}
Expand Down
2 changes: 1 addition & 1 deletion dora-frontend/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ pub fn check<F, T>(code: &'static str, f: F) -> T
where
F: FnOnce(&Sema) -> T,
{
let args: SemaFlags = SemaFlags::for_test(code);
let args: SemaFlags = SemaFlags::for_test(code, &[]);
let mut sa = Sema::new(args);

let result = check_program(&mut sa);
Expand Down
64 changes: 64 additions & 0 deletions dora-frontend/src/typeck/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5370,3 +5370,67 @@ fn class_index_set_wrong_item_type() {
ErrorMessage::WrongTypeForArgument("Float64".into(), "Float32".into()),
);
}

#[test]
fn trait_import_missing() {
errors(
"
fn f(a: Int, b: Int): Int {
a.add(b)
}
",
&[(
(3, 13),
ErrorMessage::UnknownMethod("Int64".into(), "add".into()),
)],
);
}

#[test]
fn import_trait_for_impl_call() {
ok("
use std::traits::Add;
fn f(a: Int, b: Int): Int {
a.add(b)
}
");
}

#[test]
#[ignore]
fn impl_trait_for_type_in_dependency() {
test_with_pkgs(
"
extern package dep1;
use dep1::MyClass;
pub trait Bar {
fn f();
}
impl Bar for MyClass {
fn f() {}
}
",
&[(
"dep1",
"
pub trait Foo {
fn f();
}
pub class MyClass
impl Foo for MyClass {
fn f() {}
}
fn f(x: MyClass) {
x.f();
}
",
)],
&[],
);
}
5 changes: 2 additions & 3 deletions dora-language-server/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,11 +301,10 @@ fn did_save_notification(server_state: &mut ServerState, notification: Notificat
}

fn compile_project(project: ProjectConfig, sender: Sender<MainLoopTask>) {
use dora_frontend::sema::{Sema, SemaFlags};
use dora_frontend::sema::{FileContent, Sema, SemaFlags};
let sem_args = SemaFlags {
program_file: Some(project.main.clone()),
program_file: Some(FileContent::Path(project.main.clone())),
packages: Vec::new(),
test_file_as_string: None,
boots: false,
};

Expand Down
1 change: 1 addition & 0 deletions dora-parser/src/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,7 @@ fn keywords_in_map() -> HashMap<&'static str, TokenKind> {
keywords.insert("mod", MOD_KW);
keywords.insert("use", USE_KW);
keywords.insert("package", PACKAGE_KW);
keywords.insert("extern", EXTERN_KW);

// "small" shapes
keywords.insert("fn", FN_KW);
Expand Down
6 changes: 6 additions & 0 deletions dora-parser/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ impl Parser {
} else {
None
};
self.expect(SEMICOLON);

let green = self.builder.finish_node(EXTERN);

Expand Down Expand Up @@ -4006,4 +4007,9 @@ mod tests {
parse_expr("x is Foo::Bar");
parse_expr("x is Foo::Bar(a, b, c)");
}

#[test]
fn parse_extern_decl() {
parse("extern package foo;");
}
}
5 changes: 2 additions & 3 deletions dora-sema-fuzzer/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#[macro_use]
extern crate afl;

use dora_frontend::sema::{Sema, SemaFlags};
use dora_frontend::sema::{FileContent, Sema, SemaFlags};

fn main() {
fuzz!(|data: &[u8]| {
Expand All @@ -13,9 +13,8 @@ fn main() {

fn check_program(program: String) {
let sem_args = SemaFlags {
program_file: None,
program_file: Some(FileContent::Content(program)),
packages: Vec::new(),
test_file_as_string: Some(program),
boots: false,
};

Expand Down
Loading

0 comments on commit dc01435

Please sign in to comment.