Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/release-plz.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
steps:
- &checkout
name: Checkout repository
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
fetch-depth: 0
persist-credentials: false
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
args: "--all-features"
steps:
- name: Checkout repository
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Build
Expand All @@ -49,7 +49,7 @@ jobs:
args: "--all-features"
steps:
- name: Checkout repository
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
Expand All @@ -62,7 +62,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@nightly
with:
Expand All @@ -77,7 +77,7 @@ jobs:
RUSTDOCFLAGS: -D warnings
steps:
- name: Checkout repository
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Build documentation
Expand Down
35 changes: 23 additions & 12 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions corpus/json/encapsulated_string.debug.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ FlatZinc {
id: "myAnn",
args: [
Literal(
String(
"my string",
Literal(
String(
"my string",
),
),
),
],
Expand Down
53 changes: 51 additions & 2 deletions corpus/json/unit_test_example.debug.txt
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,40 @@ FlatZinc {
id: "int_search",
args: [
ArrayNamed(
(Weak),
Array {
name: "X_INTRODUCED_5_",
contents: [
Variable(
Variable {
name: "x",
ty: Int(
Some(
RangeList::from(1..=3),
),
),
ann: [],
defined: false,
introduced: false,
},
),
Variable(
Variable {
name: "y",
ty: Int(
Some(
RangeList::from(1..=3),
),
),
ann: [],
defined: false,
introduced: false,
},
),
],
ann: [],
defined: false,
introduced: false,
},
),
Literal(
Annotation(
Expand Down Expand Up @@ -387,7 +420,23 @@ FlatZinc {
id: "bool_search",
args: [
ArrayNamed(
(Weak),
Array {
name: "X_INTRODUCED_4_",
contents: [
Variable(
Variable {
name: "b",
ty: Bool,
ann: [],
defined: true,
introduced: false,
},
),
],
ann: [],
defined: false,
introduced: false,
},
),
Literal(
Annotation(
Expand Down
89 changes: 63 additions & 26 deletions src/fzn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -625,16 +625,16 @@ mod tests {
Stream, array_item, constraint, predicate_item, solve_objective, variable_declaration,
},
intermediate::{
Annotation, AnnotationArgument, AnnotationCall, AnnotationLiteral, Argument, Array,
Constraint, Literal, Method, NameId, NameStore, ParserState, SolveObjective, Variable,
Annotation, AnnotationCall, AnnotationLiteral, Argument, Array, Constraint, Literal,
Method, NameId, NameStore, ParserState, SolveObjective, Variable,
},
};

pub(crate) fn annotation_identifier(
names: &NameStore<String>,
name: &str,
) -> AnnotationLiteral<String> {
AnnotationLiteral::Reference(name_id(names, name))
AnnotationLiteral::Literal(Literal::Reference(name_id(names, name)))
}

#[test]
Expand Down Expand Up @@ -991,23 +991,66 @@ mod tests {
vec![crate::Annotation::Call(crate::AnnotationCall {
id: "int_search".to_owned(),
args: vec![
crate::AnnotationArgument::Array(vec![crate::AnnotationLiteral::Variable(
Arc::downgrade(&fzn.variables[0]),
crate::Argument::Array(vec![crate::AnnotationLiteral::Literal(
crate::Literal::Variable(Arc::clone(&fzn.variables[0])),
)]),
crate::AnnotationArgument::Literal(crate::AnnotationLiteral::Annotation(
crate::Argument::Literal(crate::AnnotationLiteral::Annotation(
crate::Annotation::Atom("input_order".to_owned()),
)),
crate::AnnotationArgument::Literal(crate::AnnotationLiteral::Annotation(
crate::Argument::Literal(crate::AnnotationLiteral::Annotation(
crate::Annotation::Atom("indomain_min".to_owned()),
)),
crate::AnnotationArgument::Literal(crate::AnnotationLiteral::Annotation(
crate::Argument::Literal(crate::AnnotationLiteral::Annotation(
crate::Annotation::Atom("complete".to_owned()),
)),
],
})]
);
}

#[test]
fn self_referential_annotation_is_dropped() {
let fzn =
FlatZinc::<String>::from_fzn(Cursor::new("var int: x :: foo(x);\nsolve satisfy;"))
.expect("failed to parse self-referential annotation");
assert!(
fzn.variables[0].ann.is_empty(),
"self-referential annotation should be dropped, got {:?}",
fzn.variables[0].ann
);
}

#[test]
fn cyclic_annotation_keeps_non_cyclic_direction() {
let fzn = FlatZinc::<String>::from_fzn(Cursor::new(
"var int: x :: foo(y);\nvar int: y :: foo(x);\nsolve satisfy;",
))
.expect("failed to parse mutually referential annotations");
let x = fzn.variables.iter().find(|v| v.name == "x").unwrap();
let y = fzn.variables.iter().find(|v| v.name == "y").unwrap();
// Exactly one direction is kept (whichever variable is resolved first);
// the other would close the reference cycle and is silently dropped.
let (kept, dropped, target) = if x.ann.is_empty() {
(y, x, x)
} else {
(x, y, y)
};
assert!(
dropped.ann.is_empty(),
"cyclic annotation should be dropped, got {:?}",
dropped.ann
);
assert_eq!(
kept.ann,
vec![crate::Annotation::Call(crate::AnnotationCall {
id: "foo".to_owned(),
args: vec![crate::Argument::Literal(crate::AnnotationLiteral::Literal(
crate::Literal::Variable(Arc::clone(target))
))],
})]
);
}

#[test]
fn solve_items_are_parsed() {
let (actual, names) = parse_with_names(solve_objective, "solve minimize w;");
Expand All @@ -1030,17 +1073,14 @@ mod tests {
ann: vec![Annotation::Call(AnnotationCall {
id: "int_search".to_owned(),
args: vec![
AnnotationArgument::Array(vec![
Argument::Array(vec![
annotation_identifier(&names, "x"),
annotation_identifier(&names, "y"),
annotation_identifier(&names, "z"),
]),
AnnotationArgument::Literal(annotation_identifier(&names, "first_fail")),
AnnotationArgument::Literal(annotation_identifier(
&names,
"indomain_split",
)),
AnnotationArgument::Literal(annotation_identifier(&names, "complete")),
Argument::Literal(annotation_identifier(&names, "first_fail")),
Argument::Literal(annotation_identifier(&names, "indomain_split",)),
Argument::Literal(annotation_identifier(&names, "complete")),
],
})],
},
Expand Down Expand Up @@ -1093,10 +1133,10 @@ mod tests {
ann: vec![Annotation::Call(AnnotationCall {
id: "int_search".to_owned(),
args: vec![
AnnotationArgument::Literal(annotation_identifier(&names, "xs",)),
AnnotationArgument::Literal(annotation_identifier(&names, "input_order",)),
AnnotationArgument::Literal(annotation_identifier(&names, "indomain_min",)),
AnnotationArgument::Literal(annotation_identifier(&names, "complete",)),
Argument::Literal(annotation_identifier(&names, "xs",)),
Argument::Literal(annotation_identifier(&names, "input_order",)),
Argument::Literal(annotation_identifier(&names, "indomain_min",)),
Argument::Literal(annotation_identifier(&names, "complete",)),
],
})],
},
Expand All @@ -1113,17 +1153,14 @@ mod tests {
ann: vec![Annotation::Call(AnnotationCall {
id: "int_search".to_owned(),
args: vec![
AnnotationArgument::Array(vec![
Argument::Array(vec![
annotation_identifier(&names, "x"),
annotation_identifier(&names, "y"),
annotation_identifier(&names, "z"),
]),
AnnotationArgument::Literal(annotation_identifier(&names, "first_fail",)),
AnnotationArgument::Literal(annotation_identifier(
&names,
"indomain_split",
)),
AnnotationArgument::Literal(annotation_identifier(&names, "complete",)),
Argument::Literal(annotation_identifier(&names, "first_fail",)),
Argument::Literal(annotation_identifier(&names, "indomain_split",)),
Argument::Literal(annotation_identifier(&names, "complete",)),
],
})],
},
Expand Down
Loading