Initial Dever 0.0.1
This commit is contained in:
commit
81233d098c
1479 files changed
+163782
No files matched your search
@@ -0,0 +1,138 @@
|
||||
use dever::compiler::{check, model::Program};
|
||||
use dever::syntax::{diagnostic::Diagnostic, source::Source};
|
||||
|
||||
fn linked(text: &str, identity: &str) -> Result<Program, Diagnostic> {
|
||||
let sources = [
|
||||
Source::new(0, "main.dever", text.into()),
|
||||
Source::new(
|
||||
1,
|
||||
"lib/dever/io.dever",
|
||||
include_str!("../../../../lib/dever/io.dever").into(),
|
||||
),
|
||||
];
|
||||
let modules = sources
|
||||
.iter()
|
||||
.map(dever::syntax::parse)
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
check::check(modules, &[identity.into(), "dever.io".into()])
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pure_rejects_direct_transitive_captured_and_handler_io() {
|
||||
let prefix = "write(value: Text) (answer: Text) { dever.io.println(value)\n answer = value }\napply(route: handler(value: Text) (answer: Text), value: Text) (answer: Text) { answer = route(value) }\n";
|
||||
for source in [
|
||||
"main(path: Text) () pure { file = dever.io.open(path) }".into(),
|
||||
"main(path: Text) (answer: dever.io.OpenResult) pure { answer = result(dever.io.open(path)) }".into(),
|
||||
"main() () pure { dever.io.println(\"hello\") }".into(),
|
||||
prefix.to_owned() + "main() (answer: Text) pure { answer = write(\"hello\") }",
|
||||
prefix.to_owned() + "main() (answer: Text) pure { answer = apply(write, \"hello\") }",
|
||||
prefix.to_owned() + "main() (answer: List<Text>) pure { answer = each(write, [\"hello\"]) }",
|
||||
"unused(route: handler() ()) () pure { route() }".into(),
|
||||
] {
|
||||
let error = linked(&source, "main").unwrap_err();
|
||||
assert_eq!(error.code, "C013", "{source}: {error:?}");
|
||||
}
|
||||
let source = "identity(value: Text) (answer: Text) { answer = value }\napply(route: handler(value: Text) (answer: Text), value: Text) (answer: Text) { answer = route(value) }\nmain() (answer: Text) pure { answer = apply(identity, \"hello\") }";
|
||||
assert!(linked(source, "main").is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resource_equality_cannot_hide_inside_value_containers() {
|
||||
for source in [
|
||||
"main(file: dever.system.File) (answer: Bool) { answer = file == file }",
|
||||
"main(file: dever.system.File) (answer: Bool) { answer = [file] == [file] }",
|
||||
"type Box { file: dever.system.File }\nmain(value: Box) (answer: Bool) { answer = value == value }",
|
||||
"type Box { Some(file: dever.system.File)\n None }\nmain(value: Box) (answer: Bool) { answer = value == value }",
|
||||
"main(file: dever.system.File?) (answer: Bool) { answer = file == null }",
|
||||
"main(files: Map<dever.system.File, Int>) () {}",
|
||||
] {
|
||||
assert_eq!(linked(source, "main").unwrap_err().code, "C005", "{source}");
|
||||
}
|
||||
assert!(linked("type Box { files: List<dever.system.File> }\nmain(value: Box) (answer: Box) { answer = value }", "main").is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn file_errors_keep_nominal_identity_and_handling_obligations() {
|
||||
let source =
|
||||
"main(path: Text) (answer: dever.io.OpenResult) { answer = result(dever.io.open(path)) }";
|
||||
assert!(linked(source, "main").is_ok());
|
||||
assert_eq!(
|
||||
linked(
|
||||
"main(path: Text) () { lost = result(dever.io.open(path)) }",
|
||||
"main"
|
||||
)
|
||||
.unwrap_err()
|
||||
.code,
|
||||
"C012"
|
||||
);
|
||||
assert_eq!(linked("type OpenResult { Opened(file: dever.system.File)\n error Failed(message: Text) }\nmain(path: Text) (answer: OpenResult) { answer = result(dever.io.open(path)) }", "main").unwrap_err().code, "C005");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn raw_file_intrinsics_and_unmediated_app_effects_are_rejected() {
|
||||
assert_eq!(
|
||||
linked(
|
||||
"main() () { value = dever.system.fileOpen(\"file\") }",
|
||||
"main"
|
||||
)
|
||||
.unwrap_err()
|
||||
.code,
|
||||
"C006"
|
||||
);
|
||||
for identity in ["app.docs.app.files", "app.docs.domain.files"] {
|
||||
let source = "helper(path: Text) (file: dever.system.File) { file = dever.io.open(path) }\nmain(path: Text) (file: dever.system.File) { file = helper(path) }";
|
||||
assert_eq!(linked(source, identity).unwrap_err().code, "C013");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stream_operations_remain_lazy_and_effectful() {
|
||||
let prefix = "count(item: Int, state: Int) (next: Int) { next = state + item }\n";
|
||||
for source in [
|
||||
"main(stream: Stream<Int>) () pure { close(stream) }".into(),
|
||||
prefix.to_owned()
|
||||
+ "main(stream: Stream<Int>) (answer: Int) pure { answer = reduce(count, stream, 0) }",
|
||||
] {
|
||||
assert_eq!(
|
||||
linked(&source, "main").unwrap_err().code,
|
||||
"C013",
|
||||
"{source}"
|
||||
);
|
||||
}
|
||||
for source in [
|
||||
"same(item: Int) (answer: Int) { answer = item }\nmain(stream: Stream<Int>) (answer: List<Int>) { answer = each(same, stream) }",
|
||||
"yes(item: Int) (answer: Bool) { answer = true }\nmain(stream: Stream<Int>) (answer: Int?) { answer = find(yes, stream) }",
|
||||
"main(stream: Stream<Int>) (answer: Int) { answer = length(stream) }",
|
||||
"main(stream: Stream<Int>) (answer: Bool) { answer = stream == stream }",
|
||||
"main(file: dever.system.File) () { close(file) }",
|
||||
] {
|
||||
assert_eq!(linked(source, "main").unwrap_err().code, "C005", "{source}");
|
||||
}
|
||||
assert!(linked("main(file: dever.system.File) () { stream = dever.io.chunks(file, 1)\n close(stream) }", "main").is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stream_events_cannot_drop_failures_or_leak_private_types() {
|
||||
for source in [
|
||||
"ignore(event: dever.io.ReadEvent) () {}\nmain(stream: Stream<dever.io.ReadEvent>) () { each(ignore, stream) }",
|
||||
"ignore(event: dever.io.ReadEvent, state: Int) (next: Int) { next = state }\nmain(stream: Stream<dever.io.ReadEvent>) (answer: Int) { answer = reduce(ignore, stream, 0) }",
|
||||
"main(file: dever.system.File) () { lost = result(dever.io.chunks(file, 0)) }",
|
||||
] {
|
||||
assert_eq!(linked(source, "main").unwrap_err().code, "C012", "{source}");
|
||||
}
|
||||
assert_eq!(
|
||||
linked(
|
||||
"type Hidden { value: Int }\npublic type Visible { stream: Stream<Hidden> }",
|
||||
"main"
|
||||
)
|
||||
.unwrap_err()
|
||||
.code,
|
||||
"C006"
|
||||
);
|
||||
assert_eq!(
|
||||
linked("type Cycle { stream: Stream<Cycle> }", "main")
|
||||
.unwrap_err()
|
||||
.code,
|
||||
"C007"
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user