diff --git a/doc/tutorial/tutorial.md b/doc/tutorial/tutorial.md index ac899a6d8..09ae3a6a1 100644 --- a/doc/tutorial/tutorial.md +++ b/doc/tutorial/tutorial.md @@ -436,9 +436,9 @@ Other string operations are implemented as library [standard library](#the-standard-library), e.g., ``` -extern function string_len(s: string): usize -extern function string_contains(s1: string, s2: string): bool -extern function string_join(strings: Vec, sep: string): string +extern function len(s: string): usize +extern function contains(s1: string, s2: string): bool +extern function join(strings: Vec, sep: string): string ... ``` @@ -758,11 +758,39 @@ EndpointString(addr_port(ip, proto, preferred_port)) :- ### Functions -DDlog functions are pure (side-effect-free) computations. A function -may not modify its arguments. The body of a function is an expression -whose type must match the function's return type. A function call can -be inserted anywhere an expression of the function's return type can -be used. DDlog currently does not allow recursive functions. +We have already encountered several functions in this tutorial. This section +gives some additional details on writing DDlog functions. + +#### Polymorphic functions + +DDlog supports two forms of polymorphism: parametric and ad hoc polymorphism. +The following declarations from `std.dl` illustrate both: + +``` +function size(s: Set<'X>): usize {...} +function size(m: Map<'K, 'V>): usize {...} +``` + +Parametric polymorphism allows declaring functions generic over their argument +types. The `size` functions above work for sets and maps that store values of +arbitrary types. This is indicated by using type arguments (`'X`, `'K`, `'V`) +instead of concrete argument types. + +Ad hoc polymorphism allows multiple functions with the same name but different +arguments. The two `size()` functions above do not introduce any ambiguity, +since the compiler is able to infer the correct function to call in each case +from the type of the argument. Specifically, the compiler uses the number of +arguments and the type of the **first** argument to disambiguate the callee. + +#### Modifying function arguments + +By default, function arguments cannot be modified inside the function. Writable +arguments can be declared using the `mut` qualifier: + +``` +// This function modifies its first argument. +function insert(m: mut Map<'K,'V>, k: 'K, v: 'V): () { ... } +``` > #### Legacy function syntax > @@ -781,14 +809,13 @@ be used. DDlog currently does not allow recursive functions. > ``` -### Extern functions +#### Extern functions Functions that cannot be easily expressed in DDlog can be implemented as *extern* functions. Currently these must be written in Rust; the Rust implementation may in turn invoke implementations in C or any other language. -For instance, DDlog does not provide a substring function. We can -declare such a function as `extern`: +Example: ``` extern function string_slice(x: string, from: bit<64>, to: bit<64>): string @@ -815,6 +842,24 @@ pub fn string_slice(x: &String, from: &u64, to: &u64) -> String { DDlog will automatically pickup this file and inline its contents in the generated `lib.rs`. +#### Functions with side effects + +Functions implemented completely in DDlog without calls to any extern functions +are pure (side-effect-free) computations. It is however possible to declare +extern functions with side effects. The DDlog compiler needs to know about these +side effects, as they may interfere with its optimizations. The programmer is +responsible for labeling such functions with the `#[has_side_effects]` attribute, +e.g., the following function is defined in the `log.dl` library: + +``` +#[has_side_effects] +extern function log(module: module_t, level: log_level_t, msg: string): () +``` + +The compiler automatically infers these annotations for non-extern functions +that invoke extern functions with side effects, so only extern functions must +be annotated. + ### Advanced rules #### Negations and antijoins @@ -900,19 +945,11 @@ are *generic* types that can be parameterized by any other DDlog types, e.g., `Vec` is a vector of strings, `Map` is a map from strings to Booleans. -Let us assume that we have an extern function that splits a string +We will use a DDlog standard library function that splits a string into a list of substrings according to a separator: ``` -extern function split(s: string, sep: string): Vec -``` - -The Rust implementation can be as follows: - -``` -pub fn split_ip_list(s: &String, sep: &String) -> Vec { - s.as_str().split(sep).map(|x| x.to_string()).collect() -} +function split(s: string, sep: string): Vec ``` We define a DDlog function which splits IP addresses at spaces: diff --git a/lib/graph.rs b/lib/graph.rs index 3c43a4cc6..6d5bdd537 100644 --- a/lib/graph.rs +++ b/lib/graph.rs @@ -20,7 +20,7 @@ pub fn graph_SCC( where S: Scope, S::Timestamp: Lattice + Ord, - V: Val + 'static, + V: differential_dataflow::Data, N: differential_dataflow::ExchangeData + std::hash::Hash, E: differential_dataflow::ExchangeData, EF: Fn(V) -> E + 'static, @@ -53,7 +53,7 @@ pub fn graph_ConnectedComponents( where S: Scope, S::Timestamp: Lattice + Ord, - V: Val + 'static, + V: differential_dataflow::Data, N: differential_dataflow::ExchangeData + std::hash::Hash, E: differential_dataflow::ExchangeData, EF: Fn(V) -> E + 'static, @@ -81,7 +81,7 @@ where S: Scope, S::Timestamp: Lattice + Ord, u64: From, - V: Val + 'static, + V: differential_dataflow::Data, N: differential_dataflow::ExchangeData + std::hash::Hash, E: differential_dataflow::ExchangeData, EF: Fn(V) -> E + 'static, @@ -114,7 +114,7 @@ pub fn graph_UnsafeBidirectionalEdges( where S: Scope, S::Timestamp: TotalOrder + Lattice + Ord, - V: Val + 'static, + V: differential_dataflow::Data, N: differential_dataflow::ExchangeData + std::hash::Hash, E: differential_dataflow::ExchangeData, EF: Fn(V) -> E + 'static, diff --git a/lib/internment.dl b/lib/internment.dl index 1d585f2d7..4ed43394c 100644 --- a/lib/internment.dl +++ b/lib/internment.dl @@ -41,3 +41,44 @@ extern function istring_trim(s: istring): string extern function istring_to_lowercase(s: istring): string extern function istring_to_uppercase(s: istring): string extern function istring_reverse(s: istring): string + +function contains(s1: istring, s2: string): bool { + istring_contains(s1, s2) +} + +function join(strings: Vec, sep: string): string { + istring_join(strings, sep) +} +function len(s: istring): usize { + istring_len(s) +} +function replace(s: istring, from: string, to: string): string { + istring_replace(s, from, to) +} +function split(s: istring, sep: string): Vec { + istring_split(s, sep) +} +function starts_with(s: istring, prefix: string): bool { + istring_starts_with(s, prefix) +} +function ends_with(s: istring, suffix: string): bool { + istring_ends_with(s, suffix) +} +function substr(s: istring, start: usize, end: usize): string { + istring_substr(s, start, end) +} +function to_bytes(s: istring): Vec { + istring_to_bytes(s) +} +function trim(s: istring): string { + istring_trim(s) +} +function to_lowercase(s: istring): string { + istring_to_lowercase(s) +} +function to_uppercase(s: istring): string { + istring_to_uppercase(s) +} +function reverse(s: istring): string { + istring_reverse(s) +} diff --git a/lib/json.dl b/lib/json.dl index 14a7d4b26..987950565 100644 --- a/lib/json.dl +++ b/lib/json.dl @@ -151,7 +151,7 @@ function jval_get(v: JsonValue, attr: istring): Option = function jval_get_or(v: JsonValue, attr: istring, def: JsonValue): JsonValue = { match (v) { - JsonObject{o} -> option_unwrap_or(map_get(o, attr), def), + JsonObject{o} -> unwrap_or(map_get(o, attr), def), _ -> def } } diff --git a/lib/regex.rs b/lib/regex.rs index bafc14768..74ecf39d0 100644 --- a/lib/regex.rs +++ b/lib/regex.rs @@ -21,6 +21,12 @@ impl Deref for regex_Regex { } } +impl Default for regex_Regex { + fn default() -> Self { + Self::new("").unwrap() + } +} + impl PartialOrd for regex_Regex { fn partial_cmp(&self, other: ®ex_Regex) -> Option { self.as_str().partial_cmp(other.as_str()) diff --git a/lib/std.dl b/lib/std.dl index 3e4e326be..203566182 100644 --- a/lib/std.dl +++ b/lib/std.dl @@ -100,24 +100,27 @@ function is_some(x: Option<'A>): bool = { } } -function option_unwrap_or(x: Option<'A>, def: 'A): 'A = { +function unwrap_or(x: Option<'A>, def: 'A): 'A = { match (x) { Some{v} -> v, None -> def } } -// Returns the default value for the given type if `opt` is -// `None`. -extern function option_unwrap_or_default(opt: Option<'A>): 'A +/* Returns the default value for the given type if `opt` is + * `None`. + */ +function unwrap_or_default(opt: Option<'A>): 'A { + option_unwrap_or_default(opt) +} -function option2set(o: Option<'X>): Set<'X> = { +function to_set(o: Option<'X>): Set<'X> = { match (o) { Some{x} -> set_singleton(x), None -> set_empty() } } -function option2vec(o: Option<'X>): Vec<'X> = { +function to_vec(o: Option<'X>): Vec<'X> = { match (o) { Some{x} -> vec_singleton(x), None -> vec_empty() @@ -150,16 +153,19 @@ function is_err(res: Result<'V,'E>): bool = { } } -function result_unwrap_or(res: Result<'V,'E>, def: 'V): 'V = { +function unwrap_or(res: Result<'V,'E>, def: 'V): 'V = { match (res) { Ok{v} -> v, Err{} -> def } } -// Returns the default value for the given type if `res` is -// an error. -extern function result_unwrap_or_default(res: Result<'V,'E>): 'V +/* Returns the default value for the given type if `res` is + * an error. + */ +function unwrap_or_default(res: Result<'V,'E>): 'V { + result_unwrap_or_default(res) +} /* * Range @@ -175,9 +181,17 @@ extern function hex(x: 'X): string extern function parse_dec_u64(s: string): Option> extern function parse_dec_i64(s: string): Option> -extern function string_contains(s1: string, s2: string): bool -extern function string_join(strings: Vec, sep: string): string -extern function string_len(s: string): usize +function contains(s1: string, s2: string): bool { + string_contains(s1, s2) +} + +function join(strings: Vec, sep: string): string { + string_join(strings, sep) +} + +function len(s: string): usize { + string_len(s) +} /* Replaces all matches of `from` with `to`. * @@ -185,39 +199,60 @@ extern function string_len(s: string): usize * doing so, it attempts to find matches of a pattern. If it finds any, it * replaces them with `to`. */ -extern function string_replace(s: string, from: string, to: string): string -extern function string_split(s: string, sep: string): Vec +function replace(s: string, from: string, to: string): string { + string_replace(s, from, to) +} -extern function string_starts_with(s: string, prefix: string): bool -extern function string_ends_with(s: string, suffix: string): bool +function split(s: string, sep: string): Vec { + string_split(s, sep) +} + +function starts_with(s: string, prefix: string): bool { + string_starts_with(s, prefix) +} + +function ends_with(s: string, suffix: string): bool { + string_ends_with(s, suffix) +} /* Substring of `s` that begins at `start` and continues up to, but not * including, `end`.*/ -extern function string_substr(s: string, start: usize, end: usize): string +function substr(s: string, start: usize, end: usize): string { + string_substr(s, start, end) +} -extern function string_to_bytes(s: string): Vec +function to_bytes(s: string): Vec { + string_to_bytes(s) +} /* Returns a string slice with leading and trailing whitespace removed. * * 'Whitespace' is defined according to the terms of the Unicode Derived * Core Property White_Space */ -extern function string_trim(s: string): string +function trim(s: string): string { + string_trim(s) +} /* Returns the lowercase equivalent of `s` as a new string. * * 'Lowercase' is defined according to the terms of the Unicode Derived * Core Property Lowercase. */ -extern function string_to_lowercase(s: string): string -extern function str_to_lower(s: string): string +function to_lowercase(s: string): string { + string_to_lowercase(s) +} /* Returns the uppercase equivalent of `s` as a new string. */ -extern function string_to_uppercase(s: string): string +function to_uppercase(s: string): string { + string_to_uppercase(s) +} -extern function string_reverse(s: string): string +function reverse(s: string): string { + string_reverse(s) +} /* * hashing @@ -252,12 +287,54 @@ extern function group_first(g: Group<'K, 'V>): 'V */ extern function group_nth(g: Group<'K,'V>, n: usize): Option<'V> -extern function group2set(g: Group<'K, 'V>): Set<'V> -extern function group2vec(g: Group<'K, 'V>): Vec<'V> -extern function group2map(g: Group<'K1, ('K2,'V)>): Map<'K2,'V> -extern function group2setmap(g: Group<'K1, ('K2,'V)>): Map<'K2,Set<'V>> +extern function group_to_set(g: Group<'K, 'V>): Set<'V> +extern function group_to_vec(g: Group<'K, 'V>): Vec<'V> +extern function group_to_map(g: Group<'K1, ('K2,'V)>): Map<'K2,'V> +extern function group_to_setmap(g: Group<'K1, ('K2,'V)>): Map<'K2,Set<'V>> extern function group_sum(g: Group<'K, 'V>): 'V +extern function group_set_unions(g: Group<'K, Set<'A>>): Set<'A> + +/* Optimized version of group_set_unions that, when the group consits of + * a single set, simply returns the reference to this set. */ +extern function group_setref_unions(g: Group<'K, Ref>>): Ref> + +/* Smallest and largest group elements. */ +extern function group_min(g: Group<'K, 'V>): 'V +extern function group_max(g: Group<'K, 'V>): 'V + +function key(g: Group<'K, 'V>): 'K { + group_key(g) +} + +function count(g: Group<'K, 'V>): usize { + group_count(g) +} + +function first(g: Group<'K, 'V>): 'V { + group_first(g) +} + +function nth(g: Group<'K,'V>, n: usize): Option<'V> { + group_nth(g, n) +} + +function to_set(g: Group<'K, 'V>): Set<'V> { + group_to_set(g) +} + +function to_vec(g: Group<'K, 'V>): Vec<'V> { + group_to_vec(g) +} + +function to_map(g: Group<'K1, ('K2,'V)>): Map<'K2,'V> { + group_to_map(g) +} + +function to_setmap(g: Group<'K1, ('K2,'V)>): Map<'K2,Set<'V>> { + group_to_setmap(g) +} + function group_unzip(g: Group<'K, ('X,'Y)>): (Vec<'X>, Vec<'Y>) = { var xs: Vec<'X> = vec_empty(); var ys: Vec<'Y> = vec_empty(); @@ -269,15 +346,17 @@ function group_unzip(g: Group<'K, ('X,'Y)>): (Vec<'X>, Vec<'Y>) = { (xs,ys) } -extern function group_set_unions(g: Group<'K, Set<'A>>): Set<'A> +function setref_unions(g: Group<'K, Ref>>): Ref> { + group_setref_unions(g) +} -/* Optimized version of group_set_unions that, when the group consits of - * a single set, simply returns the reference to this set. */ -extern function group_setref_unions(g: Group<'K, Ref>>): Ref> +function min(g: Group<'K, 'V>): 'V { + group_min(g) +} -/* Smallest and largest group elements. */ -extern function group_min(g: Group<'K, 'V>): 'V -extern function group_max(g: Group<'K, 'V>): 'V +function max(g: Group<'K, 'V>): 'V { + group_max(g) +} /* * Vec @@ -287,17 +366,48 @@ extern type Vec<'A> extern function vec_empty(): Vec<'A> extern function vec_with_length(len: usize, x: 'A): Vec<'A> extern function vec_with_capacity(len: usize): Vec<'A> -extern function vec_len(v: Vec<'X>): usize extern function vec_singleton(x: 'X): Vec<'X> -extern function vec_push(v: mut Vec<'X>, x: 'X): () -extern function vec_append(v: mut Vec<'X>, other: Vec<'X>): () -extern function vec_push_imm(v: Vec<'X>, x: 'X): Vec<'X> -extern function vec_contains(v: Vec<'X>, x: 'X): bool -extern function vec_is_empty(v: Vec<'X>): bool -extern function vec_nth(v: Vec<'X>, n: usize): Option<'X> -extern function vec2set(s: Vec<'A>): Set<'A> -extern function vec_sort(v: Vec<'X>): () -extern function vec_sort_imm(v: Vec<'X>): Vec<'X> + +function len(v: Vec<'X>): usize { + vec_len(v) +} + +function push(v: mut Vec<'X>, x: 'X): () { + vec_push(v, x) +} + +function append(v: mut Vec<'X>, other: Vec<'X>): () { + vec_append(v, other) +} + +function push_imm(v: Vec<'X>, x: 'X): Vec<'X> { + vec_push_imm(v, x) +} + +function contains(v: Vec<'X>, x: 'X): bool { + vec_contains(v, x) +} + +function is_empty(v: Vec<'X>): bool { + vec_is_empty(v) +} + +function nth(v: Vec<'X>, n: usize): Option<'X> { + vec_nth(v, n) +} + +function to_set(s: Vec<'A>): Set<'A> { + vec_to_set(s) +} + +function sort(v: mut Vec<'X>): () { + vec_sort(v) +} + +function sort_imm(v: Vec<'X>): Vec<'X> { + vec_sort_imm(v) +} + /* * Map @@ -305,16 +415,40 @@ extern function vec_sort_imm(v: Vec<'X>): Vec<'X> extern type Map<'K,'V> -extern function map_size(m: Map<'K, 'V>): usize extern function map_empty(): Map<'K, 'V> extern function map_singleton(k: 'K, v: 'V): Map<'K, 'V> -extern function map_insert(m: mut Map<'K,'V>, k: 'K, v: 'V): () -extern function map_remove(m: mut Map<'K,'V>, k: 'K): () -extern function map_insert_imm(m: Map<'K,'V>, k: 'K, v: 'V): Map<'K,'V> -extern function map_get(m: Map<'K,'V>, k:'K): Option<'V> -extern function map_contains_key(m: Map<'K,'V>, k: 'K): bool -extern function map_is_empty(m: Map<'K,'V>): bool -extern function map_union(m1: Map<'K, 'V>, m2: Map<'K,'V>): Map<'K, 'V> + +function size(m: Map<'K, 'V>): usize { + map_size(m) +} + +function insert(m: mut Map<'K,'V>, k: 'K, v: 'V): () { + map_insert(m, k, v) +} + +function remove(m: mut Map<'K,'V>, k: 'K): () { + map_remove(m, k) +} + +function insert_imm(m: Map<'K,'V>, k: 'K, v: 'V): Map<'K,'V> { + map_insert_imm(m, k, v) +} + +function get(m: Map<'K,'V>, k:'K): Option<'V> { + map_get(m, k) +} + +function contains_key(m: Map<'K,'V>, k: 'K): bool { + map_contains_key(m, k) +} + +function is_empty(m: Map<'K,'V>): bool { + map_is_empty(m) +} + +function union(m1: Map<'K, 'V>, m2: Map<'K,'V>): Map<'K, 'V> { + map_union(m1, m2) +} /* * Set @@ -322,19 +456,52 @@ extern function map_union(m1: Map<'K, 'V>, m2: Map<'K,'V>): Map<'K, 'V> extern type Set<'A> -extern function set_size(s: Set<'X>): usize extern function set_singleton(x: 'X): Set<'X> extern function set_empty(): Set<'X> -extern function set_insert(s: mut Set<'X>, v: 'X): () -extern function set_insert_imm(s: Set<'X>, v: 'X): Set<'X> -extern function set_contains(s: Set<'X>, v: 'X): bool -extern function set_is_empty(s: Set<'X>): bool -extern function set_nth(s: Set<'X>, n: usize): Option<'X> -extern function set2vec(s: Set<'A>): Vec<'A> -extern function set_union(s1: Set<'X>, s2: Set<'X>): Set<'X> -extern function set_unions(sets: Vec>): Set<'X> -extern function set_intersection(s1: Set<'X>, s2: Set<'X>): Set<'X> -extern function set_difference(s1: Set<'X>, s2: Set<'X>): Set<'X> + +function size(s: Set<'X>): usize { + set_size(s) +} + +function insert(s: mut Set<'X>, v: 'X): () { + set_insert(s, v) +} + +function insert_imm(s: Set<'X>, v: 'X): Set<'X> { + set_insert_imm(s, v) +} + +function contains(s: Set<'X>, v: 'X): bool { + set_contains(s, v) +} + +function is_empty(s: Set<'X>): bool { + set_is_empty(s) +} + +function nth(s: Set<'X>, n: usize): Option<'X> { + set_nth(s, n) +} + +function to_vec(s: Set<'A>): Vec<'A> { + set_to_vec(s) +} + +function union(s1: Set<'X>, s2: Set<'X>): Set<'X> { + set_union(s1, s2) +} + +function unions(sets: Vec>): Set<'X> { + set_unions(sets) +} + +function intersection(s1: Set<'X>, s2: Set<'X>): Set<'X> { + set_intersection(s1, s2) +} + +function difference(s1: Set<'X>, s2: Set<'X>): Set<'X> { + set_difference(s1, s2) +} /* * Endianness @@ -344,3 +511,60 @@ extern function ntohs(x: bit<16>): bit<16> extern function htonl(x: bit<32>): bit<32> extern function htons(x: bit<16>): bit<16> + +/* + * Internals + * + * We currently don't have a way to selectively export functions, but the use of + * these functions outside of this module is discouraged. + */ + +extern function option_unwrap_or_default(opt: Option<'A>): 'A +extern function result_unwrap_or_default(res: Result<'V,'E>): 'V + +extern function string_contains(s1: string, s2: string): bool +extern function string_join(strings: Vec, sep: string): string +extern function string_len(s: string): usize +extern function string_to_lowercase(s: string): string +extern function str_to_lower(s: string): string +extern function string_replace(s: string, from: string, to: string): string +extern function string_split(s: string, sep: string): Vec +extern function string_starts_with(s: string, prefix: string): bool +extern function string_ends_with(s: string, suffix: string): bool +extern function string_substr(s: string, start: usize, end: usize): string +extern function string_to_bytes(s: string): Vec +extern function string_trim(s: string): string +extern function string_to_uppercase(s: string): string +extern function string_reverse(s: string): string + +extern function vec_len(v: Vec<'X>): usize +extern function vec_push(v: mut Vec<'X>, x: 'X): () +extern function vec_append(v: mut Vec<'X>, other: Vec<'X>): () +extern function vec_push_imm(v: Vec<'X>, x: 'X): Vec<'X> +extern function vec_contains(v: Vec<'X>, x: 'X): bool +extern function vec_is_empty(v: Vec<'X>): bool +extern function vec_nth(v: Vec<'X>, n: usize): Option<'X> +extern function vec_to_set(s: Vec<'A>): Set<'A> +extern function vec_sort(v: mut Vec<'X>): () +extern function vec_sort_imm(v: Vec<'X>): Vec<'X> + +extern function map_size(m: Map<'K, 'V>): usize +extern function map_insert(m: mut Map<'K,'V>, k: 'K, v: 'V): () +extern function map_remove(m: mut Map<'K,'V>, k: 'K): () +extern function map_insert_imm(m: Map<'K,'V>, k: 'K, v: 'V): Map<'K,'V> +extern function map_get(m: Map<'K,'V>, k:'K): Option<'V> +extern function map_contains_key(m: Map<'K,'V>, k: 'K): bool +extern function map_is_empty(m: Map<'K,'V>): bool +extern function map_union(m1: Map<'K, 'V>, m2: Map<'K,'V>): Map<'K, 'V> + +extern function set_size(s: Set<'X>): usize +extern function set_insert(s: mut Set<'X>, v: 'X): () +extern function set_insert_imm(s: Set<'X>, v: 'X): Set<'X> +extern function set_contains(s: Set<'X>, v: 'X): bool +extern function set_is_empty(s: Set<'X>): bool +extern function set_nth(s: Set<'X>, n: usize): Option<'X> +extern function set_to_vec(s: Set<'A>): Vec<'A> +extern function set_union(s1: Set<'X>, s2: Set<'X>): Set<'X> +extern function set_unions(sets: Vec>): Set<'X> +extern function set_intersection(s1: Set<'X>, s2: Set<'X>): Set<'X> +extern function set_difference(s1: Set<'X>, s2: Set<'X>): Set<'X> diff --git a/lib/std.rs b/lib/std.rs index 039d915e4..2701b6f25 100644 --- a/lib/std.rs +++ b/lib/std.rs @@ -469,7 +469,7 @@ pub fn std_vec_nth(v: &std_Vec, n: &std_usize) -> std_Option< option2std(v.x.get(*n as usize).cloned()) } -pub fn std_vec2set(s: &std_Vec) -> std_Set { +pub fn std_vec_to_set(s: &std_Vec) -> std_Set { std_Set { x: s.x.iter().cloned().collect(), } @@ -698,7 +698,7 @@ pub fn std_set_nth(s: &std_Set, n: &std_usize) -> std_Option< option2std(s.x.iter().nth(*n as usize).cloned()) } -pub fn std_set2vec(s: &std_Set) -> std_Vec { +pub fn std_set_to_vec(s: &std_Set) -> std_Vec { std_Vec { x: s.x.iter().cloned().collect(), } @@ -1157,7 +1157,7 @@ pub fn std_group_nth(g: &std_Group, n: &std_usize) -> std_Option g.nth(*n) } -pub fn std_group2set(g: &std_Group) -> std_Set { +pub fn std_group_to_set(g: &std_Group) -> std_Set { let mut res = std_Set::new(); for v in g.iter() { std_set_insert(&mut res, &v); @@ -1194,7 +1194,7 @@ pub fn std_group_setref_unions( } } -pub fn std_group2vec(g: &std_Group) -> std_Vec { +pub fn std_group_to_vec(g: &std_Group) -> std_Vec { let mut res = std_Vec::with_capacity(g.size() as usize); for v in g.iter() { std_vec_push(&mut res, &v); @@ -1202,7 +1202,9 @@ pub fn std_group2vec(g: &std_Group) -> std_Vec { res } -pub fn std_group2map(g: &std_Group) -> std_Map { +pub fn std_group_to_map( + g: &std_Group, +) -> std_Map { let mut res = std_Map::new(); for (k, v) in g.iter() { std_map_insert(&mut res, &k, &v); @@ -1210,7 +1212,7 @@ pub fn std_group2map(g: &std_Group) res } -pub fn std_group2setmap( +pub fn std_group_to_setmap( g: &std_Group, ) -> std_Map> { let mut res = std_Map::new(); diff --git a/lib/tinyset.dl b/lib/tinyset.dl index 9b2d0b12d..b0b5e6208 100644 --- a/lib/tinyset.dl +++ b/lib/tinyset.dl @@ -20,7 +20,7 @@ extern function intersection(s1: Set64<'X>, s2: Set64<'X>): Set64<'X> extern function difference(s1: Set64<'X>, s2: Set64<'X>): Set64<'X> /* Aggregates */ -extern function group2set(g: Group<'K, 'V>): Set64<'V> +extern function group_to_set(g: Group<'K, 'V>): Set64<'V> extern function group_set_unions(g: Group<'K, Set64<'V>>): Set64<'V> /* Optimized version of group_set_unions that, when the group consits of diff --git a/lib/tinyset.rs b/lib/tinyset.rs index 84cb9e281..37d2f1212 100644 --- a/lib/tinyset.rs +++ b/lib/tinyset.rs @@ -345,7 +345,7 @@ pub fn tinyset_difference( } } -pub fn tinyset_group2set(g: &std_Group) -> tinyset_Set64 { +pub fn tinyset_group_to_set(g: &std_Group) -> tinyset_Set64 { let mut res = tinyset_Set64::new(); for ref v in g.iter() { tinyset_insert(&mut res, v); diff --git a/package.yaml b/package.yaml index dd4c91eeb..4f6de6ca0 100644 --- a/package.yaml +++ b/package.yaml @@ -24,6 +24,7 @@ dependencies: - containers - binary - bytestring +- extra - fgl - split - MissingH diff --git a/rust/template/differential_datalog/program.rs b/rust/template/differential_datalog/program.rs index 8770c0799..552e56d85 100644 --- a/rust/template/differential_datalog/program.rs +++ b/rust/template/differential_datalog/program.rs @@ -2224,23 +2224,23 @@ impl RunningProgram { /// Insert one record into input relation. Relations have set semantics, i.e., /// adding an existing record is a no-op. pub fn insert(&mut self, relid: RelId, v: DDValue) -> Response<()> { - self.apply_updates(vec![Update::Insert { relid: relid, v: v }].into_iter()) + self.apply_updates(vec![Update::Insert { relid, v }].into_iter()) } /// Insert one record into input relation or replace existing record with the same /// key. pub fn insert_or_update(&mut self, relid: RelId, v: DDValue) -> Response<()> { - self.apply_updates(vec![Update::InsertOrUpdate { relid: relid, v: v }].into_iter()) + self.apply_updates(vec![Update::InsertOrUpdate { relid, v }].into_iter()) } /// Remove a record if it exists in the relation. pub fn delete_value(&mut self, relid: RelId, v: DDValue) -> Response<()> { - self.apply_updates(vec![Update::DeleteValue { relid: relid, v: v }].into_iter()) + self.apply_updates(vec![Update::DeleteValue { relid, v }].into_iter()) } /// Remove a key if it exists in the relation. pub fn delete_key(&mut self, relid: RelId, k: DDValue) -> Response<()> { - self.apply_updates(vec![Update::DeleteKey { relid: relid, k: k }].into_iter()) + self.apply_updates(vec![Update::DeleteKey { relid, k }].into_iter()) } /// Modify a key if it exists in the relation. @@ -2250,14 +2250,7 @@ impl RunningProgram { k: DDValue, m: Arc + Send + Sync>, ) -> Response<()> { - self.apply_updates( - vec![Update::Modify { - relid: relid, - k: k, - m: m, - }] - .into_iter(), - ) + self.apply_updates(vec![Update::Modify { relid, k, m }].into_iter()) } /// Apply multiple insert and delete operations in one batch. diff --git a/rust/template/types/lib.rs b/rust/template/types/lib.rs index bed586150..89d027bfa 100644 --- a/rust/template/types/lib.rs +++ b/rust/template/types/lib.rs @@ -55,12 +55,21 @@ mod flatbuf_generated; pub mod flatbuf; pub trait Val: - Eq + Ord + Clone + Hash + PartialEq + PartialOrd + Serialize + DeserializeOwned + 'static + Default + Eq + Ord + Clone + Hash + PartialEq + PartialOrd + Serialize + DeserializeOwned + 'static { } impl Val for T where - T: Eq + Ord + Clone + Hash + PartialEq + PartialOrd + Serialize + DeserializeOwned + 'static + T: Default + + Eq + + Ord + + Clone + + Hash + + PartialEq + + PartialOrd + + Serialize + + DeserializeOwned + + 'static { } diff --git a/src/Language/DifferentialDatalog/Attribute.hs b/src/Language/DifferentialDatalog/Attribute.hs index f783bb327..847a1d1e6 100644 --- a/src/Language/DifferentialDatalog/Attribute.hs +++ b/src/Language/DifferentialDatalog/Attribute.hs @@ -43,7 +43,7 @@ progValidateAttributes :: (MonadError String me) => DatalogProgram -> me () progValidateAttributes d = do mapM_ (typedefValidateAttrs d) $ progTypedefs d mapM_ (indexValidateAttrs d) $ progIndexes d - mapM_ (funcValidateAttrs d) $ progFunctions d + mapM_ (mapM_ (funcValidateAttrs d)) $ progFunctions d typedefValidateAttrs :: (MonadError String me) => DatalogProgram -> TypeDef -> me () typedefValidateAttrs d tdef@TypeDef{..} = do @@ -220,13 +220,10 @@ fieldCheckDeserializeArrayAttr :: (MonadError String me) => DatalogProgram -> Fi fieldCheckDeserializeArrayAttr d field@Field{..} = case filter ((== "deserialize_from_array") . name) fieldAttrs of [] -> return Nothing - [attr@Attribute{attrVal = E (EApply _ fname _)}] -> do + [attr@Attribute{attrVal = E (EApply _ [fname] _)}] -> do check d (isMap d field) (pos attr) $ "'deserialize_from_array' attribute is only applicable to fields of type 'Map<>'." let TOpaque _ _ [ktype, vtype] = typ' d field - kfunc@Function{..} <- checkFunc (pos attr) d fname - let nargs = length funcArgs - check d (nargs == 1) (pos attr) - $ "Key function '" ++ fname ++ "' must take one argument of type '" ++ show (fieldType) ++ "', but it takes " ++ show nargs ++ "arguments." + kfunc@Function{..} <- checkFunc (pos attr) d fname [vtype] _ <- funcTypeArgSubsts d (pos attr) kfunc [vtype, ktype] return $ Just fname [Attribute{..}] -> err d attrPos diff --git a/src/Language/DifferentialDatalog/Compile.hs b/src/Language/DifferentialDatalog/Compile.hs index ef89e2ea3..577353181 100644 --- a/src/Language/DifferentialDatalog/Compile.hs +++ b/src/Language/DifferentialDatalog/Compile.hs @@ -554,7 +554,7 @@ compileLib d specname rs_code = (typesLib, valueLib, mainLib) -- Type declarations typedefs = vcat $ map (mkTypedef d) $ M.elems $ progTypedefs d -- Functions - (fdef, fextern) = partition (isJust . funcDef) $ M.elems $ progFunctions d + (fdef, fextern) = partition (isJust . funcDef) $ concat $ M.elems $ progFunctions d funcs = let ?statics = statics in vcat $ (map (mkFunc d) fextern ++ map (mkFunc d) fdef) -- This type stores the set of statically evaluated constant sub-expressions. @@ -584,7 +584,7 @@ collectStatics d = execState (progExprMapCtxM d (checkStaticExpr)) M.empty checkStaticExpr :: ECtx -> ENode -> State (Statics) Expr checkStaticExpr ctx e@EApply{} | null (exprFreeVars d ctx (E e)) && (not $ exprIsPolymorphic d ctx (E e)) - && exprIsPure d (E e) = do + && exprIsPure d ctx (E e) = do modify (addStatic d (E e) ctx) return $ E e checkStaticExpr _ e = return $ E e @@ -677,10 +677,11 @@ mkTypedef d tdef@TypeDef{..} = TOpaque _ _ [ktype, vtype] = typ' d f from_arr_attr = maybe empty (\_ -> "#[serde(with=\"" <> from_array_module_name <> "\")]") $ fieldGetDeserializeArrayAttr d f - from_array_module = maybe empty (\kfunc -> "deserialize_map_from_array!(" <> + from_array_module = maybe empty (\fname -> let kfunc = getFunc d fname [vtype] in + "deserialize_map_from_array!(" <> from_array_module_name <> "," <> mkType ktype <> "," <> mkType vtype <> "," <> - rname kfunc <> ");") + mkFuncName d kfunc <> ");") $ fieldGetDeserializeArrayAttr d f from_array_module_name = "__serde_" <> rname cons <> "_" <> pp (name f) @@ -1168,7 +1169,7 @@ mkIdxIdMapC d = mkFunc :: (?statics::Statics) => DatalogProgram -> Function -> Doc mkFunc d f@Function{..} | isJust funcDef = - "pub fn" <+> rname (name f) <> tvars <> (parens $ hsep $ punctuate comma $ map mkArg funcArgs) <+> "->" <+> mkType funcType $$ + "pub fn" <+> mkFuncName d f <> tvars <> (parens $ hsep $ punctuate comma $ map mkArg funcArgs) <+> "->" <+> mkType funcType $$ "{" $$ (nest' $ mkExpr d (CtxFunc f) (fromJust funcDef) EVal) $$ "}" @@ -1662,8 +1663,10 @@ mkAggregate d filters input_val rl@Rule{..} idx = do -- Aggregate function: -- - compute aggregate -- - return variables still in scope after this term + let ktype = ruleAggregateKeyType d rl idx + let vtype = ruleAggregateValType d rl idx let tmap = ruleAggregateTypeParams d rl idx - let agg_func = getFunc d rhsAggFunc + let agg_func = getFunc d rhsAggFunc [tOpaque gROUP_TYPE [ktype, vtype]] -- Pass group-by variables to the aggregate function. let grp = "&std_Group::new(&" <> (mkExpr d gctx rhsGroupBy EVal) <> "," <+> gROUP_VAR <> "," <+> project <> ")" let tparams = commaSep $ map (\tvar -> mkType (tmap M.! tvar)) $ funcTypeVars agg_func @@ -1739,6 +1742,7 @@ mkValConstructorName d t' = TFloat{} -> "__Floatval" TUser{} -> consuser TOpaque{} -> consuser + TVar{..} -> pp tvarName _ -> error $ "unexpected type " ++ show t ++ " in Compile.mkValConstructorName'" where t = typeNormalize d t' @@ -2346,14 +2350,14 @@ mkExpr' d ctx e | isJust static_idx = (parens $ "&*__STATIC_" <> pp (fromJust st -- All variables are references mkExpr' _ _ EVar{..} = (pp exprVar, EReference) --- Function arguments are passed as read-only references --- Functions return real values. -mkExpr' d _ EApply{..} = - (rname exprFunc <> (parens $ commaSep +-- Function arguments are passed as read-only or mutable references +-- Functions return real values unless they are labeled return-by-reference. +mkExpr' d ctx e@(EApply{..}) = + (mkFuncName d f <> (parens $ commaSep $ map (\(a, mut) -> if mut then mutref a else ref a) $ zip exprArgs (map argMut $ funcArgs f)), kind) where - f = getFunc d exprFunc + f = applyExprGetFunc d ctx $ exprMap (E . sel3) e kind = if funcGetReturnByRefAttr d f then EReference else EVal -- Field access automatically dereferences subexpression @@ -2592,6 +2596,15 @@ mkExpr' d ctx EAs{..} | bothIntegers && narrow_from && narrow_to && width_cmp /= mkExpr' _ _ e = error $ "Compile.mkExpr': unexpected expression at " ++ show (pos e) +mkFuncName :: DatalogProgram -> Function -> Doc +mkFuncName d f | length namesakes == 1 = rname $ name f + | otherwise = + (rname $ name f) <> "_" <> targ0 <> "_" <> pp (length $ funcArgs f) + where + arg0 = funcArgs f !! 0 + targ0 = mkValConstructorName d $ typ arg0 + namesakes = progFunctions d M.! (name f) + mkType :: (WithType a) => a -> Doc mkType x = mkType' empty $ typ x diff --git a/src/Language/DifferentialDatalog/DatalogProgram.hs b/src/Language/DifferentialDatalog/DatalogProgram.hs index 110d4a62a..3efa90df1 100644 --- a/src/Language/DifferentialDatalog/DatalogProgram.hs +++ b/src/Language/DifferentialDatalog/DatalogProgram.hs @@ -1,5 +1,5 @@ {- -Copyright (c) 2018 VMware, Inc. +Copyright (c) 2018-2020 VMware, Inc. SPDX-License-Identifier: MIT Permission is hereby granted, free of charge, to any person obtaining a copy @@ -70,16 +70,14 @@ import {-# SOURCE #-} Language.DifferentialDatalog.Type -- | Map function 'fun' over all expressions in a program progExprMapCtxM :: (Monad m) => DatalogProgram -> (ECtx -> ENode -> m Expr) -> m DatalogProgram progExprMapCtxM d fun = do - rels' <- M.fromList <$> - (mapM (\(rname, rel) -> (rname,) <$> relExprMapCtxM fun rel) $ M.toList $ progRelations d) - idxs' <- M.fromList <$> - (mapM (\(rname, idx) -> do atom' <- atomExprMapCtxM fun (CtxIndex idx) (idxAtom idx) - return (rname, idx{idxAtom = atom'})) $ M.toList $ progIndexes d) - funcs' <- mapM (\f -> do e <- case funcDef f of - Nothing -> return Nothing - Just e -> Just <$> exprFoldCtxM fun (CtxFunc f) e - return f{funcDef = e}) - $ progFunctions d + rels' <- traverse (relExprMapCtxM fun) $ progRelations d + idxs' <- traverse (\idx -> do atom' <- atomExprMapCtxM fun (CtxIndex idx) (idxAtom idx) + return idx{idxAtom = atom'}) $ progIndexes d + funcs' <- traverse (mapM (\f -> do e <- case funcDef f of + Nothing -> return Nothing + Just e -> Just <$> exprFoldCtxM fun (CtxFunc f) e + return f{funcDef = e})) + $ progFunctions d rules' <- mapM (\r -> do lhs <- mapIdxM (\a i -> atomExprMapCtxM fun (CtxRuleL r i) a) $ ruleLHS r rhs <- mapIdxM (\x i -> rhsExprMapCtxM fun r i x) $ ruleRHS r return r{ruleLHS = lhs, ruleRHS = rhs}) @@ -126,21 +124,22 @@ progExprMapCtx d fun = runIdentity $ progExprMapCtxM d (\ctx e -> return $ fun -- | Apply function to all types referenced in the program progTypeMapM :: (Monad m) => DatalogProgram -> (Type -> m Type) -> m DatalogProgram progTypeMapM d@DatalogProgram{..} fun = do - ts <- M.traverseWithKey (\_ (TypeDef p atrs n a t) -> TypeDef p atrs n a <$> mapM (typeMapM fun) t) progTypedefs - fs <- M.traverseWithKey (\_ f -> do ret <- typeMapM fun $ funcType f - as <- mapM (\a -> setType a <$> (typeMapM fun $ typ a)) $ funcArgs f - def <- mapM (exprTypeMapM fun) $ funcDef f - return f{ funcType = ret, funcArgs = as, funcDef = def }) progFunctions - trans <- M.traverseWithKey (\_ t -> do inputs <- mapM (\i -> do t' <- hotypeTypeMapM (hofType i) fun - return i{hofType = t'}) $ transInputs t - outputs <- mapM (\o -> do t' <- hotypeTypeMapM (hofType o) fun - return o{hofType = t'}) $ transOutputs t - return t{ transInputs = inputs, transOutputs = outputs }) progTransformers - rels <- M.traverseWithKey (\_ rel -> setType rel <$> (typeMapM fun $ typ rel)) progRelations - idxs <- M.traverseWithKey (\_ idx -> do vars <- mapM (\v -> setType v <$> (typeMapM fun $ typ v)) $ idxVars idx - atomval <- exprTypeMapM fun $ atomVal $ idxAtom idx - let atom = (idxAtom idx) { atomVal = atomval } - return idx { idxVars = vars, idxAtom = atom }) progIndexes + ts <- traverse(\(TypeDef p atrs n a t) -> TypeDef p atrs n a <$> mapM (typeMapM fun) t) progTypedefs + fs <- traverse (mapM (\f -> do ret <- typeMapM fun $ funcType f + as <- mapM (\a -> setType a <$> (typeMapM fun $ typ a)) $ funcArgs f + def <- mapM (exprTypeMapM fun) $ funcDef f + return f{ funcType = ret, funcArgs = as, funcDef = def })) + progFunctions + trans <- traverse (\t -> do inputs <- mapM (\i -> do t' <- hotypeTypeMapM (hofType i) fun + return i{hofType = t'}) $ transInputs t + outputs <- mapM (\o -> do t' <- hotypeTypeMapM (hofType o) fun + return o{hofType = t'}) $ transOutputs t + return t{ transInputs = inputs, transOutputs = outputs }) progTransformers + rels <- traverse (\rel -> setType rel <$> (typeMapM fun $ typ rel)) progRelations + idxs <- traverse (\idx -> do vars <- mapM (\v -> setType v <$> (typeMapM fun $ typ v)) $ idxVars idx + atomval <- exprTypeMapM fun $ atomVal $ idxAtom idx + let atom = (idxAtom idx) { atomVal = atomval } + return idx { idxVars = vars, idxAtom = atom }) progIndexes rules <- mapM (ruleTypeMapM fun) progRules return d { progTypedefs = ts , progFunctions = fs @@ -317,5 +316,5 @@ progInjectDebuggingHooks d = let rules = progRules d updatedRules = [(rules !! i) {ruleRHS = debugUpdateRHSRules d i (rules !! i)} | i <- [0..length rules - 1]] - debugFuncs = M.fromList $ map (\f -> (name f , f)) $ debugAggregateFunctions d - in d { progRules = updatedRules, progFunctions = M.union (progFunctions d) debugFuncs } + debugFuncs = M.fromList $ map (\f -> (name f, [f])) $ debugAggregateFunctions d + in d { progRules = updatedRules, progFunctions = M.unionWith (++) (progFunctions d) debugFuncs } diff --git a/src/Language/DifferentialDatalog/Expr.hs b/src/Language/DifferentialDatalog/Expr.hs index 852d5cca0..880dbbf65 100644 --- a/src/Language/DifferentialDatalog/Expr.hs +++ b/src/Language/DifferentialDatalog/Expr.hs @@ -1,5 +1,5 @@ {- -Copyright (c) 2018 VMware, Inc. +Copyright (c) 2018-2020 VMware, Inc. SPDX-License-Identifier: MIT Permission is hereby granted, free of charge, to any person obtaining a copy @@ -42,9 +42,9 @@ module Language.DifferentialDatalog.Expr ( exprFreeVars, exprIsConst, exprVarDecls, - exprFuncs, - exprFuncsRec, isLVar, + applyExprGetFunc, + exprFuncsRec, exprIsPattern, exprIsPatternImpl, exprContainsPHolders, @@ -68,6 +68,7 @@ import Control.Monad.State import qualified Data.Set as S --import Debug.Trace +import Language.DifferentialDatalog.Attribute import Language.DifferentialDatalog.Error import Language.DifferentialDatalog.Pos import Language.DifferentialDatalog.Ops @@ -79,7 +80,6 @@ import Language.DifferentialDatalog.Name import {-# SOURCE #-} Language.DifferentialDatalog.Type import Language.DifferentialDatalog.ECtx import Language.DifferentialDatalog.Var -import Language.DifferentialDatalog.Function bUILTIN_2STRING_FUNC :: String bUILTIN_2STRING_FUNC = "std.__builtin_2string" @@ -303,23 +303,41 @@ exprVarDecls d ctx e = _ -> [])) ctx e -- Non-recursively enumerate all functions invoked by the expression -exprFuncs :: Expr -> [String] -exprFuncs e = exprFuncs' [] e +{-exprFuncs :: DatalogProgram -> ECtx -> Expr -> [String] +exprFuncs d ctx e = exprFuncs' [] e exprFuncs' :: [String] -> Expr -> [String] exprFuncs' acc e = nub $ exprCollect (\case EApply _ f _ -> if' (elem f acc) [] [f] _ -> []) (++) e +-} --- Recursively enumerate all functions invoked by the expression -exprFuncsRec :: DatalogProgram -> Expr -> [String] -exprFuncsRec d e = exprFuncsRec' d [] e +-- Given a function application expression, returns the function. +-- Assumes the expression has been validated. +applyExprGetFunc :: DatalogProgram -> ECtx -> ENode -> Function +applyExprGetFunc d ctx e@EApply{exprFunc=[fname], ..} = + getFunc d fname $ mapIdx (\a i -> exprType d (CtxApply e ctx i) a) exprArgs +applyExprGetFunc _ _ e = error $ "applyExprGetFunc " ++ show e -exprFuncsRec' :: DatalogProgram -> [String] -> Expr -> [String] -exprFuncsRec' d acc e = - let new = exprFuncs' acc e in - new ++ foldl' (\acc' f -> maybe acc' ((acc'++) . exprFuncsRec' d (acc++new++acc')) $ funcDef $ getFunc d f) [] new +-- Recursively enumerate all functions invoked by the expression +exprFuncsRec :: DatalogProgram -> ECtx -> Expr -> S.Set Function +exprFuncsRec d ctx e = execState (exprFuncsRec_ d ctx e) S.empty + +exprFuncsRec_ :: DatalogProgram -> ECtx -> Expr -> State (S.Set Function) () +exprFuncsRec_ d ctx e = do + _ <- exprFoldCtxM (\ctx' e' -> do + case e' of + EApply{} -> do let f@Function{..} = applyExprGetFunc d ctx' e' + new <- gets $ S.notMember f + when new $ do modify $ S.insert f + case funcDef of + Nothing -> return () + Just e'' -> exprFuncsRec_ d (CtxFunc f) e'' + _ -> return () + return $ E e') + ctx e + return () isLVar :: DatalogProgram -> ECtx -> String -> Bool isLVar d ctx v = isJust $ find ((==v) . name) $ fst $ ctxVars d ctx @@ -433,18 +451,22 @@ exprIsVarOrField' _ = False -- to distinct outputs. exprIsInjective :: DatalogProgram -> ECtx -> S.Set Var -> Expr -> Bool exprIsInjective d ctx vs e = + exprIsInjective_ d ctx vs e && + all (\f -> case funcDef f of + Nothing -> False + Just e' -> exprIsInjective_ d (CtxFunc f) (S.fromList $ map (ArgVar f . name) $ funcArgs f) e') + (exprFuncsRec d ctx e) + +-- Non-recursive part of exprIsInjective +exprIsInjective_ :: DatalogProgram -> ECtx -> S.Set Var -> Expr -> Bool +exprIsInjective_ d ctx vs e = S.fromList (exprVars d ctx e) == vs && exprFold (exprIsInjective' d) e -- No clever analysis here; just the obvious cases. exprIsInjective' :: DatalogProgram -> ExprNode Bool -> Bool exprIsInjective' _ EVar{} = True -exprIsInjective' d EApply{..} = - -- FIXME: once we add support for recursive functions, be careful to avoid - -- infinite recursion. The simple thing to do is just to return False for - -- recursive functions, as reasoning about them seems tricky otherwise. - and exprArgs && (maybe False (exprIsInjective d (CtxFunc f) (S.fromList $ map (\a -> ArgVar f $ name a) funcArgs)) $ funcDef) - where f@Function{..} = getFunc d exprFunc +exprIsInjective' _ EApply{..} = and exprArgs exprIsInjective' _ EBool{} = True exprIsInjective' _ EInt{} = True exprIsInjective' _ EFloat{} = True @@ -471,11 +493,8 @@ exprIsPolymorphic d ctx e = False -- | True if expression does not contain calls to functions with side effects. -exprIsPure :: DatalogProgram -> Expr -> Bool -exprIsPure d e = - exprCollect (\case - EApply{..} -> funcIsPure d $ getFunc d exprFunc - _ -> True) (&&) e +exprIsPure :: DatalogProgram -> ECtx -> Expr -> Bool +exprIsPure d ctx e = all (\f -> not $ funcGetSideEffectAttr d f) (exprFuncsRec d ctx e) -- | Transform types referenced in the expression exprTypeMapM :: (Monad m) => (Type -> m Type) -> Expr -> m Expr @@ -503,23 +522,17 @@ exprInjectStringConversion d e t = do TOpaque{..} -> return $ mk2string_func typeName TTuple{} -> err d (pos e) "Automatic string conversion for tuples is not supported" TVar{..} -> err d (pos e) $ - "Cannot automatically convert " ++ show e ++ - " of variable type " ++ tvarName ++ " to string" + "Cannot automatically convert '" ++ show e ++ + "' of variable type '" ++ tvarName ++ "' to string" TStruct{} -> error "unexpected TStruct in exprInjectStringConversions" - f <- case lookupFunc d fname of - Nothing -> err d (pos e) $ "Cannot find declaration of function " ++ fname ++ - " needed to convert expression " ++ show e ++ " to string" + f <- case lookupFunc d fname [t] of + Nothing -> err d (pos e) $ "Cannot find declaration of function '" ++ fname ++ + "' needed to convert expression '" ++ show e ++ "' to string" Just fun -> return fun -- validate its signature check d (isString d $ funcType f) (pos f) "string conversion function must return \"string\"" - check d ((length $ funcArgs f) == 1) (pos f) - "string conversion function must take exactly one argument" - let arg0 = funcArgs f !! 0 - _ <- unifyTypes d (pos e) - ("in the call to string conversion function \"" ++ name f ++ "\"") - [(typ arg0, t)] - return $ E $ EApply (pos e) fname [E e] + return $ E $ EApply (pos e) [fname] [E e] where mk2string_func cs = scoped scope $ ((toLower $ head local) : tail local) ++ tOSTRING_FUNC_SUFFIX where scope = nameScope cs local = nameLocal cs diff --git a/src/Language/DifferentialDatalog/Expr.hs-boot b/src/Language/DifferentialDatalog/Expr.hs-boot index a845b06c7..d9fd55ed1 100644 --- a/src/Language/DifferentialDatalog/Expr.hs-boot +++ b/src/Language/DifferentialDatalog/Expr.hs-boot @@ -22,13 +22,11 @@ exprVarOccurrences :: ECtx -> Expr -> [(String, ECtx)] exprVars :: DatalogProgram -> ECtx -> Expr -> [Var] exprVarDecls :: DatalogProgram -> ECtx -> Expr -> [Var] isLVar :: DatalogProgram -> ECtx -> String -> Bool -exprFuncs :: Expr -> [String] -exprFuncsRec :: DatalogProgram -> Expr -> [String] exprIsPattern :: Expr -> Bool exprIsDeconstruct :: DatalogProgram -> Expr -> Bool exprIsVarOrFieldLVal :: DatalogProgram -> ECtx -> Expr -> Bool exprIsInjective :: DatalogProgram -> ECtx -> S.Set Var -> Expr -> Bool exprContainsPHolders :: Expr -> Bool exprTypeMapM :: (Monad m) => (Type -> m Type) -> Expr -> m Expr -exprIsPure :: DatalogProgram -> Expr -> Bool +exprIsPure :: DatalogProgram -> ECtx -> Expr -> Bool exprFreeVars :: DatalogProgram -> ECtx -> Expr -> [Var] diff --git a/src/Language/DifferentialDatalog/Function.hs b/src/Language/DifferentialDatalog/Function.hs index fd87c3703..bf4a789b7 100644 --- a/src/Language/DifferentialDatalog/Function.hs +++ b/src/Language/DifferentialDatalog/Function.hs @@ -26,7 +26,6 @@ SOFTWARE. module Language.DifferentialDatalog.Function( funcTypeArgSubsts, funcGroupArgTypes, - funcIsPure ) where import Control.Monad.Except @@ -35,13 +34,12 @@ import qualified Data.Map as M import Language.DifferentialDatalog.Pos import Language.DifferentialDatalog.Syntax -import Language.DifferentialDatalog.Attribute -import {-# SOURCE #-} Language.DifferentialDatalog.Expr import {-# SOURCE #-} Language.DifferentialDatalog.Type +import {-# SOURCE #-} Language.DifferentialDatalog.TypeInference funcTypeArgSubsts :: (MonadError String me) => DatalogProgram -> Pos -> Function -> [Type] -> me (M.Map String Type) funcTypeArgSubsts d p f@Function{..} argtypes = - unifyTypes d p ("in call to " ++ funcShowProto f) (zip (map typ funcArgs ++ [funcType]) argtypes) + inferTypeArgs d p ("in call to " ++ funcShowProto f) (zip (map typ funcArgs ++ [funcType]) argtypes) -- | Functions that take an argument of type `Group<>` are treated in a special -- way in Compile.hs. This function returns the list of `Group` types passed as @@ -49,8 +47,3 @@ funcTypeArgSubsts d p f@Function{..} argtypes = funcGroupArgTypes :: DatalogProgram -> Function -> [Type] funcGroupArgTypes d Function{..} = nub $ filter (isGroup d) $ map typ funcArgs - -funcIsPure :: DatalogProgram -> Function -> Bool -funcIsPure d f = - (funcGetSideEffectAttr d f == False) && - (maybe True (exprIsPure d) $ funcDef f) diff --git a/src/Language/DifferentialDatalog/Function.hs-boot b/src/Language/DifferentialDatalog/Function.hs-boot index 7d678dfc6..4544c2d21 100644 --- a/src/Language/DifferentialDatalog/Function.hs-boot +++ b/src/Language/DifferentialDatalog/Function.hs-boot @@ -9,4 +9,3 @@ import Language.DifferentialDatalog.Syntax funcTypeArgSubsts :: (MonadError String me) => DatalogProgram -> Pos -> Function -> [Type] -> me (M.Map String Type) funcGroupArgTypes :: DatalogProgram -> Function -> [Type] -funcIsPure :: DatalogProgram -> Function -> Bool diff --git a/src/Language/DifferentialDatalog/Module.hs b/src/Language/DifferentialDatalog/Module.hs index 1394d7027..cee270d40 100644 --- a/src/Language/DifferentialDatalog/Module.hs +++ b/src/Language/DifferentialDatalog/Module.hs @@ -1,5 +1,5 @@ {- -Copyright (c) 2018 VMware, Inc. +Copyright (c) 2018-2020 VMware, Inc. SPDX-License-Identifier: MIT Permission is hereby granted, free of charge, to any person obtaining a copy @@ -44,7 +44,6 @@ import System.FilePath.Posix import Data.List import Data.String.Utils import Data.Maybe -import Data.Char --import Debug.Trace import Text.PrettyPrint @@ -145,15 +144,15 @@ mergeModules mods = do progSources = M.unions $ map progSources mods } jp = Just prog - uniq jp (name2rust . name) (\m -> ("The following function name " ++ (funcName m) ++ " will cause name collisions")) - $ M.elems $ progFunctions prog - uniq jp (name2rust . name) (\m -> "The following transformer name " ++ (transName m) ++ " will cause name collisions") + uniq jp (name2rust . name) (\m -> ("Function name '" ++ funcName m ++ "' will cause name collisions")) + $ map head $ M.elems $ progFunctions prog + uniq jp (name2rust . name) (\m -> "Transformer name '" ++ transName m ++ "' will cause name collisions") $ M.elems $ progTransformers prog - uniq jp (name2rust . name) (\m -> "The following relation name " ++ (relName m) ++ " will cause name collisions") + uniq jp (name2rust . name) (\m -> "Relation name '" ++ relName m ++ "' will cause name collisions") $ M.elems $ progRelations prog - uniq jp (name2rust . name) (\m -> "The following index name " ++ (idxName m) ++ " will cause name collisions") + uniq jp (name2rust . name) (\m -> "Index name '" ++ idxName m ++ "' will cause name collisions") $ M.elems $ progIndexes prog - uniq jp (name2rust . name) (\m -> "The following type name " ++ (tdefName m) ++ " will cause name collisions") + uniq jp (name2rust . name) (\m -> "Type name '" ++ tdefName m ++ "' will cause name collisions") $ M.elems $ progTypedefs prog return prog @@ -212,7 +211,8 @@ flattenNamespace1 :: (MonadError String me) => MMap -> DatalogModule -> me Datal flattenNamespace1 mmap mod@DatalogModule{..} = do -- rename typedefs, functions, and relations declared in this module let types' = namedListToMap $ map (namedFlatten mod) (M.elems $ progTypedefs moduleDefs) - funcs' = namedListToMap $ map (namedFlatten mod) (M.elems $ progFunctions moduleDefs) + funcs' = M.fromList $ (map (\fs -> (name $ head fs, fs))) + $ map (map (namedFlatten mod)) (M.elems $ progFunctions moduleDefs) trans' = namedListToMap $ map (namedFlatten mod) (M.elems $ progTransformers moduleDefs) rels' = namedListToMap $ map (namedFlatten mod) (M.elems $ progRelations moduleDefs) idxs' = namedListToMap $ map (namedFlatten mod) (M.elems $ progIndexes moduleDefs) @@ -231,7 +231,7 @@ flattenNamespace1 mmap mod@DatalogModule{..} = do prog4 <- progExprMapCtxM prog3 (\_ e -> exprFlatten mmap mod e) prog5 <- progRHSMapM prog4 (\case rhs@RHSAggregate{..} -> do - f' <- flattenFuncName mmap mod (pos rhsAggExpr) rhsAggFunc + f' <- flattenFuncName' mmap mod (pos rhsAggExpr) rhsAggFunc 1 return $ rhs{rhsAggFunc = f'} rhs -> return rhs) prog6 <- progAttributeMapM prog5 (attrFlatten mod mmap) @@ -241,20 +241,26 @@ attrFlatten :: (MonadError String me) => DatalogModule -> MMap -> Attribute -> m attrFlatten mod mmap a@Attribute{attrName="deserialize_from_array", attrVal=(E EApply{..})} = do -- The value of deserialize_from_array attribute is the name of the key -- function. - f' <- flattenFuncName mmap mod (pos a) exprFunc - return $ a{attrVal = eApply f' exprArgs} + f' <- flattenFuncName' mmap mod (pos a) (head exprFunc) 1 + return $ a{attrVal = E $ EApply exprPos [f'] exprArgs} attrFlatten _ _ a = return a applyFlattenNames :: (MonadError String me) => DatalogModule -> MMap -> Apply -> me Apply applyFlattenNames mod mmap a@Apply{..} = do - trans <- flattenTransName mmap mod (pos a) applyTransformer - inputs <- mapM (\i -> if isLower $ head i - then flattenFuncName mmap mod (pos a) i - else flattenRelName mmap mod (pos a) i) applyInputs - outputs <- mapM (\o -> if isLower $ head o - then flattenFuncName mmap mod (pos a) o - else flattenRelName mmap mod (pos a) o) applyOutputs - return a { applyTransformer = trans + (trans_name, Transformer{..}) <- flattenTransName mmap mod (pos a) applyTransformer + check (moduleDefs mod) (length applyInputs == length transInputs) (pos a) + $ "Transformer '" ++ transName ++ "' expects " ++ show (length transInputs) ++ " inputs" + inputs <- mapM (\(hot, i) -> case hot of + HOTypeFunction{..} -> flattenFuncName' mmap mod (pos a) i (length hotArgs) + HOTypeRelation{} -> flattenRelName mmap mod (pos a) i) + $ zip (map hofType transInputs) applyInputs + check (moduleDefs mod) (length applyOutputs == length transOutputs) (pos a) + $ "Transformer '" ++ transName ++ "' expects " ++ show (length transOutputs) ++ " outputs" + outputs <- mapM (\(hot, o) -> case hot of + HOTypeFunction{..} -> flattenFuncName' mmap mod (pos a) o (length hotArgs) + HOTypeRelation{} -> flattenRelName mmap mod (pos a) o) + $ zip (map hofType transOutputs) applyOutputs + return a { applyTransformer = trans_name , applyInputs = inputs , applyOutputs = outputs } @@ -276,31 +282,49 @@ candidates DatalogModule{..} p n = do errBrief p $ "Unknown module " ++ show mod ++ ". Did you forget to import it?" return mods -flattenName :: (MonadError String me) => (DatalogProgram -> String -> Maybe a) -> String -> MMap -> DatalogModule -> Pos -> String -> me String +flattenName :: (MonadError String me) => (DatalogProgram -> String -> Maybe a) -> String -> MMap -> DatalogModule -> Pos -> String -> me (String, a) flattenName lookup_fun entity mmap mod p c = do cand_mods <- candidates mod p c let lname = nameLocal c - let cands = filter ((\m -> isJust $ lookup_fun (moduleDefs m) lname)) $ map (mmap M.!) cand_mods + let cands = concatMap (\m -> maybeToList $ (m,) <$> lookup_fun (moduleDefs m) lname) $ map (mmap M.!) cand_mods case cands of - [m] -> return $ scoped (moduleName m) lname + [(m,x)] -> return $ (scoped (moduleName m) lname, x) [] -> errBrief p $ "Unknown " ++ entity ++ " '" ++ c ++ "'" _ -> errBrief p $ "Conflicting definitions of " ++ entity ++ " " ++ c ++ " found in the following modules: " ++ - (intercalate ", " $ map moduleFile cands) + (intercalate ", " $ map (moduleFile . fst) cands) flattenConsName :: (MonadError String me) => MMap -> DatalogModule -> Pos -> String -> me String -flattenConsName = flattenName lookupConstructor "constructor" +flattenConsName mmap mod p c = fst <$> flattenName lookupConstructor "constructor" mmap mod p c flattenTypeName :: (MonadError String me) => MMap -> DatalogModule -> Pos -> String -> me String -flattenTypeName = flattenName lookupType "type" - -flattenFuncName :: (MonadError String me) => MMap -> DatalogModule -> Pos -> String -> me String -flattenFuncName = flattenName lookupFunc "function" +flattenTypeName mmap mod p c = fst <$> flattenName lookupType "type" mmap mod p c + +-- Function 'fname' can be declared in multiple modules. Return all matching function +-- names; postpone disambiguation till type inference. +flattenFuncName :: (MonadError String me) => MMap -> DatalogModule -> Pos -> String -> Int -> me [String] +flattenFuncName mmap mod p fname nargs = do + cand_mods <- candidates mod p fname + let lname = nameLocal fname + let cands = filter (\m -> isJust $ lookupFuncs (moduleDefs m) lname nargs) $ map (mmap M.!) cand_mods + case cands of + [] -> err (moduleDefs mod) p $ "Unknown function '" ++ fname ++ "'" + ms -> return $ map (\m -> scoped (moduleName m) lname) ms + +-- Like 'flattenFuncName', but additionally insists that there is a unique +-- matching function. +flattenFuncName' :: (MonadError String me) => MMap -> DatalogModule -> Pos -> String -> Int -> me String +flattenFuncName' mmap mod p fname nargs = do + fname' <- flattenFuncName mmap mod p fname nargs + check (moduleDefs mod) (length fname' == 1) p + $ "Ambiguous function name '" ++ fname ++ "' may refer to\n " ++ + (intercalate "\n " fname') + return $ head fname' flattenRelName :: (MonadError String me) => MMap -> DatalogModule -> Pos -> String -> me String -flattenRelName = flattenName lookupRelation "relation" +flattenRelName mmap mod p c = fst <$> flattenName lookupRelation "relation" mmap mod p c -flattenTransName :: (MonadError String me) => MMap -> DatalogModule -> Pos -> String -> me String +flattenTransName :: (MonadError String me) => MMap -> DatalogModule -> Pos -> String -> me (String, Transformer) flattenTransName = flattenName lookupTransformer "transformer" namedFlatten :: (WithName a) => DatalogModule -> a -> a @@ -319,8 +343,8 @@ typeFlatten mmap mod t = do exprFlatten :: (MonadError String me) => MMap -> DatalogModule -> ENode -> me Expr exprFlatten mmap mod e@EApply{..} = do - f <- flattenFuncName mmap mod (pos e) exprFunc - return $ E $ e { exprFunc = f } + fs <- flattenFuncName mmap mod (pos e) (head exprFunc) (length exprArgs) + return $ E $ e { exprFunc = fs } exprFlatten mmap mod e@EStruct{..} = do c <- flattenConsName mmap mod (pos e) exprConstructor return $ E $ e { exprConstructor = c } diff --git a/src/Language/DifferentialDatalog/NS.hs b/src/Language/DifferentialDatalog/NS.hs index ff1eeb72b..6004d7541 100644 --- a/src/Language/DifferentialDatalog/NS.hs +++ b/src/Language/DifferentialDatalog/NS.hs @@ -25,6 +25,7 @@ SOFTWARE. module Language.DifferentialDatalog.NS( lookupType, checkType, getType, + lookupFuncs, checkFuncs, getFuncs, lookupFunc, checkFunc, getFunc, lookupTransformer, checkTransformer, getTransformer, lookupVar, checkVar, getVar, @@ -34,9 +35,10 @@ module Language.DifferentialDatalog.NS( ) where import qualified Data.Map as M +import Data.Either import Data.List -import Control.Monad.Except import Data.Maybe +import Control.Monad.Except --import Debug.Trace import {-# SOURCE #-} Language.DifferentialDatalog.Expr @@ -46,6 +48,7 @@ import Language.DifferentialDatalog.Pos import {-# SOURCE #-} Language.DifferentialDatalog.Rule import Language.DifferentialDatalog.Syntax import Language.DifferentialDatalog.Var +import {-# SOURCE #-} Language.DifferentialDatalog.TypeInference lookupType :: DatalogProgram -> String -> Maybe TypeDef lookupType DatalogProgram{..} n = M.lookup n progTypedefs @@ -58,17 +61,37 @@ checkType p d n = case lookupType d n of getType :: DatalogProgram -> String -> TypeDef getType d n = fromJust $ lookupType d n - -lookupFunc :: DatalogProgram -> String -> Maybe Function -lookupFunc DatalogProgram{..} n = M.lookup n progFunctions - -checkFunc :: (MonadError String me) => Pos -> DatalogProgram -> String -> me Function -checkFunc p d n = case lookupFunc d n of - Nothing -> err d p $ "Unknown function: '" ++ n ++ "'" - Just f -> return f - -getFunc :: DatalogProgram -> String -> Function -getFunc d n = fromJust $ lookupFunc d n +-- Given only function name and the number of arguments, lookup can return +-- multiple functions. + +lookupFuncs :: DatalogProgram -> String -> Int -> Maybe [Function] +lookupFuncs DatalogProgram{..} n nargs = + filter ((== nargs) . length . funcArgs) <$> M.lookup n progFunctions + +checkFuncs :: (MonadError String me) => Pos -> DatalogProgram -> String -> Int -> me [Function] +checkFuncs p d n nargs = case lookupFuncs d n nargs of + Nothing -> err d p $ "Unknown function: '" ++ n ++ "'" + Just fs -> return fs + +getFuncs :: DatalogProgram -> String -> Int -> [Function] +getFuncs d n nargs = fromJust $ lookupFuncs d n nargs + +-- Find a function by its name and argument types. This function should only be +-- called after type inference, at which point there should be exactly one such +-- function. +lookupFunc :: DatalogProgram -> String -> [Type] -> Maybe Function +lookupFunc d@DatalogProgram{..} n arg_types = + find (\Function{..} -> isRight $ inferTypeArgs d nopos "" $ zip (map argType funcArgs) arg_types) candidates + where + candidates = maybe [] id $ lookupFuncs d n (length arg_types) + +checkFunc :: (MonadError String me) => Pos -> DatalogProgram -> String -> [Type] -> me Function +checkFunc p d n arg_types = case lookupFunc d n arg_types of + Nothing -> err d p $ "Unknown function: '" ++ n ++ "(" ++ (intercalate "," $ map show arg_types) ++ ")'" + Just f -> return f + +getFunc :: DatalogProgram -> String -> [Type] -> Function +getFunc d n arg_types = fromJust $ lookupFunc d n arg_types lookupTransformer :: DatalogProgram -> String -> Maybe Transformer lookupTransformer DatalogProgram{..} n = M.lookup n progTransformers diff --git a/src/Language/DifferentialDatalog/Parse.hs b/src/Language/DifferentialDatalog/Parse.hs index af0cb89d7..b2394670b 100644 --- a/src/Language/DifferentialDatalog/Parse.hs +++ b/src/Language/DifferentialDatalog/Parse.hs @@ -1,5 +1,5 @@ {- -Copyright (c) 2018 VMware, Inc. +Copyright (c) 2018-2020 VMware, Inc. SPDX-License-Identifier: MIT Permission is hereby granted, free of charge, to any person obtaining a copy @@ -39,6 +39,7 @@ import qualified Text.Parsec.Token as T import qualified Data.Map as M import Data.Maybe import Data.List +import Data.List.Extra (groupSort) import Data.Char import Numeric import GHC.Float @@ -242,7 +243,7 @@ spec = do _ -> Nothing) items let program = DatalogProgram { progImports = imports , progTypedefs = M.fromList types - , progFunctions = M.fromList funcs + , progFunctions = M.fromList $ groupSort funcs , progTransformers = M.fromList transformers , progRelations = M.fromList relations , progIndexes = M.fromList indexes @@ -250,7 +251,7 @@ spec = do , progApplys = applys , progSources = M.empty } let res = do uniqNames (Just program) ("Multiple definitions of type " ++) $ map snd types - uniqNames (Just program) ("Multiple definitions of function " ++) $ map snd funcs + --uniqNames (Just program) ("Multiple definitions of function " ++) $ map snd funcs uniqNames (Just program) ("Multiple definitions of relation " ++) $ map snd relations uniqNames (Just program) ("Multiple definitions of index " ++) $ map snd indexes uniqNames (Just program) ("Multiple definitions of transformer " ++) $ map snd transformers @@ -431,7 +432,7 @@ atom is_head = withPos $ do (withPos $ (E . EStruct nopos rname) <$> (option [] $ parens $ commaSep (namedarg <|> anonarg))) p3 <- getPosition let val' = if isref && is_head - then E (EApply (p2,p3) "ref_new" [val]) + then E (EApply (p2,p3) ["ref_new"] [val]) else if isref then E (ERef (p2,p3) val) else val @@ -569,7 +570,7 @@ estring = equoted_string einterned_string = do e <- try $ string "i" *> estring - return $ E $ EApply (pos e) "intern" [e] + return $ E $ EApply (pos e) ["intern"] [e] eraw_string = eString <$> ((try $ string "[|") *> manyTill anyChar (try $ string "|]" *> whiteSpace)) @@ -721,7 +722,7 @@ pref p = Prefix . chainl1 p $ return (.) postf p = Postfix . chainl1 p $ return (flip (.)) postField = (\f end e -> E $ EField (fst $ pos e, end) e f) <$> field <*> getPosition postTupField = (\f end e -> E $ ETupField (fst $ pos e, end) e (fromIntegral f)) <$> tupField <*> getPosition -postApply = (\(f, args) end e -> E $ EApply (fst $ pos e, end) f (e:args)) <$> dotcall <*> getPosition +postApply = (\(f, args) end e -> E $ EApply (fst $ pos e, end) [f] (e:args)) <$> dotcall <*> getPosition postType = (\t end e -> E $ ETyped (fst $ pos e, end) e t) <$> etype <*> getPosition postAs = (\t end e -> E $ EAs (fst $ pos e, end) e t) <$> eAsType <*> getPosition postSlice = try $ (\(h,l) end e -> E $ ESlice (fst $ pos e, end) e h l) <$> slice <*> getPosition diff --git a/src/Language/DifferentialDatalog/Rule.hs b/src/Language/DifferentialDatalog/Rule.hs index d80a9fa36..3f9e896ae 100644 --- a/src/Language/DifferentialDatalog/Rule.hs +++ b/src/Language/DifferentialDatalog/Rule.hs @@ -33,6 +33,8 @@ module Language.DifferentialDatalog.Rule ( ruleTypeMapM, ruleHasJoins, ruleAggregateTypeParams, + ruleAggregateKeyType, + ruleAggregateValType, ruleIsDistinctByConstruction, ruleHeadIsRecursive, ruleIsRecursive @@ -105,15 +107,27 @@ ruleRHSVars' d rl i = -- compute concrete types for 'K and 'V ruleAggregateTypeParams :: DatalogProgram -> Rule -> Int -> M.Map String Type ruleAggregateTypeParams d rl idx = - case funcTypeArgSubsts d (pos e) f [tOpaque gROUP_TYPE [group_by_type, exprType d ctx e]] of + case funcTypeArgSubsts d (pos e) f [group_type] of Left er -> error $ "ruleAggregateTypeParams: " ++ er Right tmap -> tmap where - RHSAggregate _ group_by fname e = ruleRHS rl !! idx - ctx = CtxRuleRAggregate rl idx + RHSAggregate _ _ fname e = ruleRHS rl !! idx + group_by_type = ruleAggregateKeyType d rl idx + val_type = ruleAggregateValType d rl idx + group_type = tOpaque gROUP_TYPE [group_by_type, val_type] + f = getFunc d fname [group_type] + +ruleAggregateKeyType :: DatalogProgram -> Rule -> Int -> Type +ruleAggregateKeyType d rl idx = + exprType d gctx $ rhsGroupBy $ ruleRHS rl !! idx + where gctx = CtxRuleRGroupBy rl idx - group_by_type = exprType d gctx group_by - f = getFunc d fname + +ruleAggregateValType :: DatalogProgram -> Rule -> Int -> Type +ruleAggregateValType d rl idx = + exprType d ctx $ rhsAggExpr $ ruleRHS rl !! idx + where + ctx = CtxRuleRAggregate rl idx -- | Variables used in a RHS term of a rule. ruleRHSTermVars :: DatalogProgram -> Rule -> Int -> [Var] diff --git a/src/Language/DifferentialDatalog/Rule.hs-boot b/src/Language/DifferentialDatalog/Rule.hs-boot index 7d4a338aa..956cd894b 100644 --- a/src/Language/DifferentialDatalog/Rule.hs-boot +++ b/src/Language/DifferentialDatalog/Rule.hs-boot @@ -15,3 +15,5 @@ ruleIsDistinctByConstruction :: DatalogProgram -> Rule -> Int -> Bool ruleHeadIsRecursive :: DatalogProgram -> Rule -> Int -> Bool ruleIsRecursive :: DatalogProgram -> Rule -> Bool ruleAggregateTypeParams :: DatalogProgram -> Rule -> Int -> M.Map String Type +ruleAggregateKeyType :: DatalogProgram -> Rule -> Int -> Type +ruleAggregateValType :: DatalogProgram -> Rule -> Int -> Type diff --git a/src/Language/DifferentialDatalog/Syntax.hs b/src/Language/DifferentialDatalog/Syntax.hs index 19b24d7c4..f56169fb4 100644 --- a/src/Language/DifferentialDatalog/Syntax.hs +++ b/src/Language/DifferentialDatalog/Syntax.hs @@ -631,7 +631,10 @@ instance Show Rule where show = render . pp data ExprNode e = EVar {exprPos :: Pos, exprVar :: String} - | EApply {exprPos :: Pos, exprFunc :: String, exprArgs :: [e]} + -- After flattening the module hierarchy, a function name can + -- refer to functions in one or more modules. Type inference + -- resolves the ambiguity, leaving exactly one. + | EApply {exprPos :: Pos, exprFunc :: [String], exprArgs :: [e]} | EField {exprPos :: Pos, exprStruct :: e, exprField :: String} | ETupField {exprPos :: Pos, exprTuple :: e, exprTupField :: Int} | EBool {exprPos :: Pos, exprBVal :: Bool} @@ -766,7 +769,8 @@ instance WithPos (ExprNode e) where instance PP e => PP (ExprNode e) where pp (EVar _ v) = pp v - pp (EApply _ f as) = pp f <> (parens $ commaSep $ map pp as) + pp (EApply _ [f] as) = pp f <> (parens $ commaSep $ map pp as) + pp (EApply _ fs as) = "/*" <> commaSep (map pp fs) <> "*/" <> (parens $ commaSep $ map pp as) pp (EField _ s f) = pp s <> char '.' <> pp f pp (ETupField _ s f) = pp s <> char '.' <> pp f pp (EBool _ True) = "true" @@ -835,7 +839,7 @@ instance WithPos Expr where eVar v = E $ EVar nopos v eTypedVar v t = eTyped (eVar v) t -eApply f as = E $ EApply nopos f as +eApply f as = E $ EApply nopos [f] as eField e f = E $ EField nopos e f eTupField e f = E $ ETupField nopos e f eBool b = E $ EBool nopos b @@ -1087,7 +1091,10 @@ instance Eq Import where data DatalogProgram = DatalogProgram { progImports :: [Import] , progTypedefs :: M.Map String TypeDef - , progFunctions :: M.Map String Function + -- There can be multiple functions with + -- the same name. The key in the map is + -- function name and number of arguments. + , progFunctions :: M.Map String [Function] , progTransformers :: M.Map String Transformer , progRelations :: M.Map String Relation , progIndexes :: M.Map String Index @@ -1103,7 +1110,7 @@ instance PP DatalogProgram where ++ (map pp $ M.elems progTypedefs) ++ - (map pp $ M.elems progFunctions) + (map pp $ concat $ M.elems progFunctions) ++ (map pp $ M.elems progTransformers) ++ diff --git a/src/Language/DifferentialDatalog/Type.hs b/src/Language/DifferentialDatalog/Type.hs index d662557c5..9f9573f5f 100644 --- a/src/Language/DifferentialDatalog/Type.hs +++ b/src/Language/DifferentialDatalog/Type.hs @@ -37,7 +37,6 @@ module Language.DifferentialDatalog.Type( typeUserTypes, typeStaticMemberTypes, typeIsPolymorphic, - unifyTypes, exprType, exprType', exprType'', @@ -157,55 +156,6 @@ typeIsPolymorphic TUser{..} = any typeIsPolymorphic typeArgs typeIsPolymorphic TVar{} = True typeIsPolymorphic TOpaque{..} = any typeIsPolymorphic typeArgs --- | Matches function parameter types against concrete argument types, e.g., --- given --- > [(t<'A>, t>)] --- derives --- > 'A = q<'B> --- --- Returns mapping from type variables to concrete types or an error --- if no such mapping was found due to a conflict, e.g.: --- > [(t<'A>, t>), ('A, int)] // conflict --- --- Note that concrete argument types can contain type variables. --- Concrete and abstract type variables belong to different --- namespaces (i.e., the same name represents different variables in --- concrete and abstract types). -unifyTypes :: (MonadError String me) => DatalogProgram -> Pos -> String -> [(Type, Type)] -> me (M.Map String Type) -unifyTypes d p ctx ts = do - m0 <- M.unionsWith (++) <$> mapM ((M.map return <$>) . unifyTypes' d p ctx) ts - M.traverseWithKey (\v ts' -> checkConflicts d p ctx v ts') m0 - -checkConflicts :: (MonadError String me) => DatalogProgram -> Pos -> String -> String -> [Type] -> me Type -checkConflicts d p ctx v (t:ts) = do - mapM_ (\t' -> when (not $ typesMatch d t t') - $ err d p $ "Conflicting bindings " ++ show t ++ " and " ++ show t' ++ " for type variable '" ++ v ++ " " ++ ctx) ts - return t -checkConflicts _ _ _ _ [] = error $ "Type.checkConflicts: invalid input" - -unifyTypes' :: (MonadError String me) => DatalogProgram -> Pos -> String -> (Type, Type) -> me (M.Map String Type) -unifyTypes' d p ctx (a, c) = - case (a',c') of - (TBool{} , TBool{}) -> return M.empty - (TInt{} , TInt{}) -> return M.empty - (TString{} , TString{}) -> return M.empty - (TDouble{} , TDouble{}) -> return M.empty - (TFloat{} , TFloat{}) -> return M.empty - (TBit _ w1 , TBit _ w2) | w1 == w2 - -> return M.empty - (TSigned _ w1 , TSigned _ w2) | w1 == w2 - -> return M.empty - (TTuple _ as1 , TTuple _ as2) | length as1 == length as2 - -> unifyTypes d p ctx $ zip as1 as2 - (TUser _ n1 as1 , TUser _ n2 as2) | n1 == n2 - -> unifyTypes d p ctx $ zip as1 as2 - (TOpaque _ n1 as1, TOpaque _ n2 as2) | n1 == n2 - -> unifyTypes d p ctx $ zip as1 as2 - (TVar _ n1 , t) -> return $ M.singleton n1 t - _ -> err d p $ "Cannot match expected type " ++ show a ++ " and actual type " ++ show c ++ " " ++ ctx - where a' = typ'' d a - c' = typ'' d c - -- | Compute type of an expression. The expression must be previously -- validated. exprType :: DatalogProgram -> ECtx -> Expr -> Type @@ -257,10 +207,12 @@ exprNodeType' d ctx (EVar p v) = -> varType d $ ExprVar ctx $ EVar p v _ -> error $ "exprNodeType': unknown variable " ++ v ++ " at " ++ show p -exprNodeType' d ctx (EApply _ f _) | -- Type inference engine annotates calls to functions whose return type is polymorphic. - typeIsPolymorphic t = ctxExpectType ctx - | otherwise = t - where t = funcType $ getFunc d f +exprNodeType' d ctx (EApply _ [f] ts) | -- Type inference engine annotates calls to functions whose return type is polymorphic. + typeIsPolymorphic t = ctxExpectType ctx + | otherwise = t + where t = funcType $ getFunc d f ts + +exprNodeType' _ _ e@EApply{} = error $ "exprNodeType' called with unresolved function name: " ++ show e exprNodeType' d _ (EField _ e f) = let t@TStruct{} = typDeref' d e @@ -506,7 +458,7 @@ typeNormalize' d t = TTuple{..} -> t'{typeTupArgs = map (typeNormalize d) typeTupArgs} TUser{..} -> t'{typeArgs = map (typeNormalize d) typeArgs} TOpaque{..} -> t'{typeArgs = map (typeNormalize d) typeArgs} - TVar{} -> t' + TVar{..} -> t' _ -> error $ "Type.typeNormalize': unexpected type " ++ show t' where t' = typ'' d t @@ -715,7 +667,9 @@ varType d (FlatMapVar rl i) = case typ' d $ exprType d (CtxRuleRF TOpaque _ tname [kt,vt] | tname == mAP_TYPE -> tTuple [kt,vt] _ -> error $ "varType FlatMapVar " ++ show rl ++ " " ++ show i -varType d (AggregateVar rl i) = let f = getFunc d (rhsAggFunc $ ruleRHS rl !! i) +varType d (AggregateVar rl i) = let ktype = ruleAggregateKeyType d rl i + vtype = ruleAggregateValType d rl i + f = getFunc d (rhsAggFunc $ ruleRHS rl !! i) [tOpaque gROUP_TYPE [ktype, vtype]] tmap = ruleAggregateTypeParams d rl i in typeSubstTypeArgs tmap $ funcType f varType _ WeightVar = tUser wEIGHT_TYPE [] diff --git a/src/Language/DifferentialDatalog/Type.hs-boot b/src/Language/DifferentialDatalog/Type.hs-boot index 2d9cd8dbb..eb5bae01f 100644 --- a/src/Language/DifferentialDatalog/Type.hs-boot +++ b/src/Language/DifferentialDatalog/Type.hs-boot @@ -6,7 +6,6 @@ import Control.Monad.Except import Language.DifferentialDatalog.Syntax import Language.DifferentialDatalog.Pos import Language.DifferentialDatalog.Var -import qualified Data.Map as M data ConsTree @@ -37,7 +36,6 @@ wEIGHT_TYPE :: String checkIterable :: (MonadError String me, WithType a) => String -> Pos -> DatalogProgram -> a -> me () typeIterType :: DatalogProgram -> Type -> (Type, Bool) exprNodeType :: DatalogProgram -> ECtx -> ExprNode Type -> Type -unifyTypes :: (MonadError String me) => DatalogProgram -> Pos -> String -> [(Type, Type)] -> me (M.Map String Type) isBool :: (WithType a) => DatalogProgram -> a -> Bool isBit :: (WithType a) => DatalogProgram -> a -> Bool isSigned :: (WithType a) => DatalogProgram -> a -> Bool diff --git a/src/Language/DifferentialDatalog/TypeInference.hs b/src/Language/DifferentialDatalog/TypeInference.hs index e208802c8..f30809d43 100644 --- a/src/Language/DifferentialDatalog/TypeInference.hs +++ b/src/Language/DifferentialDatalog/TypeInference.hs @@ -23,18 +23,25 @@ SOFTWARE. {-# LANGUAGE FlexibleContexts, RecordWildCards, TupleSections, ImplicitParams, RankNTypes #-} +{-| +Module: TypeInference +Description: Type inference engine: generates type constraints and solves them using + the algorithm in Unification.hs. +-} + module Language.DifferentialDatalog.TypeInference( - DDExpr(..), - tvObject, - inferTypes + inferTypes, + inferTypeArgs, + unifyTypes ) where import qualified Data.Map as M -import Data.List --import Data.List.Utils import Control.Monad.Except import Control.Monad.State.Lazy +import Data.Either +import Data.List import Data.Maybe import GHC.Float --import Debug.Trace @@ -43,6 +50,7 @@ import Language.DifferentialDatalog.Attribute import Language.DifferentialDatalog.ECtx import Language.DifferentialDatalog.Error import Language.DifferentialDatalog.Expr +import Language.DifferentialDatalog.Module import Language.DifferentialDatalog.Name import Language.DifferentialDatalog.NS import Language.DifferentialDatalog.Ops @@ -218,6 +226,49 @@ typeToTExpr__ (Just de) TVar{..} = teTVarAux de tvarName typeToTExpr__ mde TOpaque{..} = TEExtern typeName <$> mapM (typeToTExpr_ mde) typeArgs typeToTExpr__ _ t@TStruct{} = error $ "typeToTExpr__: unexpected '" ++ show t ++ "'" + +-- | Matches function parameter types against concrete argument types, e.g., +-- given +-- > [(t<'A>, t>)] +-- derives +-- > 'A = q<'B> +-- +-- Returns mapping from type variables to concrete types or an error +-- if no such mapping was found due to a conflict, e.g.: +-- > [(t<'A>, t>), ('A, int)] // conflict +-- +-- Note that concrete argument types can contain type variables. +-- Concrete and abstract type variables belong to different +-- namespaces (i.e., the same name represents different variables in +-- concrete and abstract types). +inferTypeArgs :: (MonadError String me) => DatalogProgram -> Pos -> String -> [(Type, Type)] -> me (M.Map String Type) +inferTypeArgs d p ctx ts = do + let ?d = d + let constraints = -- Manufacture a bogus expression for typeToTExpr'. + evalState (mapM (\(t1,t2) -> do te1 <- typeToTExpr' (DDExpr CtxTop eTrue) t1 + let te2 = typeToTExpr t2 + return $ CPredicate $ PEq te1 te2 $ ExplanationString p ctx) + ts) + emptyGenerator + typing <- solve d constraints True + return $ M.fromList $ map (\(TVarAux{..}, t) -> (tvarName, t)) $ M.toList typing + +-- Check if two types are compatible (i.e., both can be concretized to the same type). +unifyTypes :: DatalogProgram -> Type -> Type -> Bool +unifyTypes d t1 t2 = + let ?d = d in + let constraints = -- Manufacture bogus expressions for typeToTExpr'. + evalState (do te1 <- typeToTExpr' (DDExpr CtxTop eTrue) t1 + te2 <- typeToTExpr' (DDExpr CtxTop eFalse) t2 + return [CPredicate $ PEq te1 te2 $ ExplanationString nopos ""]) + emptyGenerator + in isRight $ solve d constraints False + +-- Check if to type expressions are compatible (i.e., both can be concretized to the same type). +unifyTExprs :: (?d::DatalogProgram) => TExpr -> TExpr -> Bool +unifyTExprs te1 te2 = + isRight $ solve ?d [CPredicate $ PEq te1 te2 $ ExplanationString nopos ""] False + -- Type expression is a struct of the specified user-defined type: 'is_MyStruct |e|'. deIsStruct :: (?d::DatalogProgram) => DDExpr -> String -> GeneratorMonad Constraint deIsStruct de n = CPredicate <$> deIsStruct_ de n @@ -238,8 +289,9 @@ deIsFP :: (?d::DatalogProgram) => DDExpr -> GeneratorMonad Constraint deIsFP de = do isdouble <- tvarTypeOfExpr de <==== TEDouble ce <- teTypeOfExpr de - let expand TEFloat = return [] - expand TEDouble = return [] + let expand TETVar{} = return Nothing + expand TEFloat = return $ Just [] + expand TEDouble = return $ Just [] expand te = err ?d (pos de) $ "floating point expression '" ++ show de ++ "' is used in a context where type '" ++ show te ++ "' is expected" return $ CLazy ce expand (Just [isdouble]) de @@ -249,8 +301,9 @@ deIsFP de = do deIsBits :: (?d::DatalogProgram) => DDExpr -> GeneratorMonad Constraint deIsBits de = do ce <- teTypeOfExpr de - let expand TEBit{} = return [] - expand TESigned{} = return [] + let expand TETVar{} = return Nothing + expand TEBit{} = return $ Just [] + expand TESigned{} = return $ Just [] expand te = err ?d (pos de) $ "expression '" ++ show de ++ "' must be of a fixed-width integer type ('bit<>' or 'signed<>'), but its type is " ++ show te return $ CLazy ce expand Nothing de @@ -259,9 +312,10 @@ deIsBits de = do -- 'is_int t = is_bits t || is_BigInt t'. deIsInt :: (?d::DatalogProgram) => DDExpr -> GeneratorMonad Constraint deIsInt de = do - let expand TEBit{} = return [] - expand TESigned{} = return [] - expand TEBigInt{} = return [] + let expand TETVar{} = return Nothing + expand TEBit{} = return $ Just [] + expand TESigned{} = return $ Just [] + expand TEBigInt{} = return $ Just [] expand te = err ?d (pos de) $ "expression '" ++ show de ++ "' must be of an integer type ('bit<>', 'signed<>', or 'bigint'), but its type is " ++ show te ce <- teTypeOfExpr de @@ -269,13 +323,14 @@ deIsInt de = do $ "expression '" ++ show de ++ "' must be of an integer type ('bit<>', 'signed<>', or 'bigint')" -- 'is_num t = is_int t || is_fp t'. -deIsNum :: (?d::DatalogProgram) => DDExpr -> Maybe [Constraint] -> (forall me . (MonadError String me) => TExpr -> me [Constraint]) -> GeneratorMonad Constraint +deIsNum :: (?d::DatalogProgram) => DDExpr -> Maybe [Constraint] -> (forall me . (MonadError String me) => TExpr -> me (Maybe [Constraint])) -> GeneratorMonad Constraint deIsNum de def ferr = do - let expand TEBit{} = return [] - expand TESigned{} = return [] - expand TEBigInt{} = return [] - expand TEFloat = return [] - expand TEDouble = return [] + let expand TETVar{} = return Nothing + expand TEBit{} = return $ Just [] + expand TESigned{} = return $ Just [] + expand TEBigInt{} = return $ Just [] + expand TEFloat = return $ Just [] + expand TEDouble = return $ Just [] expand te = ferr te ce <- teTypeOfExpr de return $ CLazy ce expand def de @@ -285,7 +340,8 @@ deIsNum de def ferr = do deIsSharedRef :: (?d::DatalogProgram) => DDExpr -> TypeVar -> GeneratorMonad Constraint deIsSharedRef de tv = do ce <- teTypeOfExpr de - let expand (TEExtern n [t']) | elem n sref_types = return [tv ~~~~ t'] + let expand TETVar{} = return Nothing + expand (TEExtern n [t']) | elem n sref_types = return $ Just [tv ~~~~ t'] expand te = err ?d (pos de) $ "expression '" ++ show de ++ "' must be of a shared reference type, e.g., 'Intern<>' or 'Ref<>', but its type is " ++ show te return $ CLazy ce expand Nothing de @@ -300,9 +356,10 @@ deIsSharedRef de tv = do -- for-loop). deIsIterable :: (?d::DatalogProgram) => DDExpr -> TypeVar -> GeneratorMonad Constraint deIsIterable de tv = do - let expand (TEExtern n [t']) | elem n sET_TYPES = return $ [tv ~~~~ t'] - expand (TEExtern n [_, t']) | n == gROUP_TYPE = return $ [tv ~~~~ t'] - expand (TEExtern n [k,v]) | n == mAP_TYPE = return $ [tv ~~~~ teTuple [k,v]] + let expand TETVar{} = return Nothing + expand (TEExtern n [t']) | elem n sET_TYPES = return $ Just [tv ~~~~ t'] + expand (TEExtern n [_, t']) | n == gROUP_TYPE = return $ Just [tv ~~~~ t'] + expand (TEExtern n [k,v]) | n == mAP_TYPE = return $ Just [tv ~~~~ teTuple [k,v]] expand te = err ?d (pos de) $ "expression '" ++ show de ++ "' must be of an iterable type, e.g., 'Set<>', 'Map<>', 'Vec<>', or 'Group<>', but its type is " ++ show te ce <- teTypeOfExpr de @@ -334,35 +391,37 @@ deIsIterable de tv = do --short :: String -> String --short = (\x -> if length x < 100 then x else take (100 - 3) x ++ "...") . replace "\n" " " -inferTypes :: (MonadError String me) => DatalogProgram -> [DDExpr] -> me [Expr] +inferTypes :: (MonadError String me) => DatalogProgram -> [(ECtx, Expr)] -> me [Expr] inferTypes d es = do let ?d = d - let GeneratorState{..} = execState (do mapM_ contextConstraints es - mapM_ exprConstraints es) + let es' = map (\(ctx, e) -> DDExpr ctx e) es + let GeneratorState{..} = execState (do mapM_ contextConstraints es' + mapM_ exprConstraints es') emptyGenerator typing <- --trace ("inferTypes " ++ show es ++ "\nConstraints:\n" ++ constraintsShow genConstraints) $ - solve d genConstraints + solve d genConstraints True -- Extract ECtx -> Type mapping from 'typing'. let ctxtypes = foldl' (\m (tv, t) -> case tv of TVarTypeOfExpr _ (DDExpr ctx _) -> M.insert ctx t m _ -> m) M.empty $ M.toList typing - let add_types :: (MonadError String me) => ECtx -> ENode -> me Expr + let add_types :: (MonadError String me) => ECtx -> ExprNode (Expr, Type) -> me (Expr, Type) add_types ctx e = -- String conversion. case ctx of CtxBinOpR _ ctx' | ctxtypes M.! ctx' == tString && t /= tString -> do e'' <- exprInjectStringConversion d (enode e') t - return $ E $ ETyped (pos e') e'' tString - _ -> return e' + return (E $ ETyped (pos e') e'' tString, t) + _ -> return (e', t) where t = case M.lookup ctx ctxtypes of Just t' -> t' Nothing -> error $ "inferTypes: context has not been assigned a type:\n" ++ show ctx + expr = exprMap fst e annotated = if ctxIsTyped ctx - then E e - else E $ ETyped (pos e) (E e) t + then E expr + else E $ ETyped (pos e) (E expr) t e' = case e of -- Convert integer literals to bit vectors if necessary. EInt{..} -> case t of @@ -370,12 +429,12 @@ inferTypes d es = do TSigned{..} -> E $ ESigned (pos e) typeWidth exprIVal TFloat{} -> E $ EFloat (pos e) $ fromInteger exprIVal TDouble{} -> E $ EDouble (pos e) $ fromInteger exprIVal - TInt{} -> E e + TInt{} -> E expr _ -> error $ "inferTypes: unexpected integer type '" ++ show t ++ "'" -- Convert doubles to floats if necessary. EDouble{..} -> case t of TFloat{..} -> E $ EFloat (pos e) $ double2Float exprDVal - TDouble{} -> E e + TDouble{} -> E expr _ -> error $ "inferTypes: unexpected floating point type '" ++ show t ++ "'" -- Annotate all expressions whose type cannot be derived in a bottom-up manner: -- var decls, placeholders, function calls, structs, etc. @@ -385,15 +444,24 @@ inferTypes d es = do EVar{} | ctxInRuleRHSPattern ctx -> annotated EPHolder{} -> annotated - EApply{..} | typeIsPolymorphic (funcType $ getFunc ?d exprFunc) - -> annotated + EApply{..} -> do + let fs = mapMaybe (\fname -> lookupFunc d fname $ map snd exprArgs) exprFunc + let f = case fs of + [f'] -> f' + _ -> error $ "TypeInference.add_types: e=" ++ show expr ++ "\nfs = " ++ show (map name fs) + if typeIsPolymorphic (funcType f) + then if ctxIsTyped ctx + then E $ expr{exprFunc = [name f]} + else E $ ETyped (pos e) (E $ expr{exprFunc = [name f]}) t + else E $ expr{exprFunc = [name f]} EStruct{} -> annotated EContinue{} -> annotated EBreak{} -> annotated EReturn{} -> annotated ERef{} -> annotated - _ -> E e - mapM (\(DDExpr ctx e) -> exprFoldCtxM add_types ctx e) es + _ -> E expr + --trace ("\nctxtypes:\n" ++ (intercalate "\n" $ map (\(ctx, t) -> show ctx ++ ": " ++ show t) $ M.toList ctxtypes)) $ + mapM (\(DDExpr ctx e) -> fst <$> exprFoldCtxM add_types ctx e) es' {-trace ("inferTypes " ++ (intercalate "\n\n" $ map show es) ++ "\nconstraints:\n" ++ (constraintsShow genConstraints))$-} {- Context-specific constraints. -} @@ -450,14 +518,15 @@ contextConstraints de@(DDExpr (CtxRuleRAggregate rl i) _) = do addConstraint =<< tvarTypeOfVar (AggregateVar rl i) <====> typeToTExpr' de ret_type where RHSAggregate{..} = ruleRHS rl !! i - Function{funcArgs = [grp_type], funcType = ret_type} = getFunc ?d rhsAggFunc + -- 'ruleRHSValidate' makes sure that there's only one. + [Function{funcArgs = [grp_type], funcType = ret_type}] = getFuncs ?d rhsAggFunc 1 TOpaque{typeArgs = [_, vtype]} = typ' ?d grp_type contextConstraints de@(DDExpr ctx@(CtxRuleRGroupBy rl i) _) = addConstraint =<< tvarTypeOfExpr (DDExpr ctx rhsGroupBy) <~~~~> typeToTExpr' de ktype where RHSAggregate{..} = ruleRHS rl !! i - Function{funcArgs = [grp_type]} = getFunc ?d rhsAggFunc + [Function{funcArgs = [grp_type]}] = getFuncs ?d rhsAggFunc 1 TOpaque{typeArgs = [ktype, _]} = typ' ?d grp_type @@ -549,11 +618,40 @@ exprConstraints_ de@(DDExpr _ (E EDouble{})) = -- |de|=f_ret |a1|...|aj| and -- |e1|=f_arg_1 |a1|...|aj| and ... and |en|=f_arg_n |a1|...|aj|, where |a1|...|aj| are fresh type variables exprConstraints_ de@(DDExpr ctx (E e@EApply{..})) = do - addConstraint =<< tvarTypeOfExpr de <====> typeToTExpr' de funcType - addConstraints =<< (mapIdxM (\(farg, earg) i -> tvarTypeOfExpr (DDExpr (CtxApply e ctx i) earg) <~~~~> typeToTExpr' de (typ farg)) - $ zip funcArgs exprArgs) + -- Generate argument and return-type constraints for all candidate + -- functions. + constraints <- mapM (\Function{..} -> do + ret_c <- tvarTypeOfExpr de <====> typeToTExpr' de funcType + arg_cs <- mapIdxM (\(farg, earg) i -> tvarTypeOfExpr (DDExpr (CtxApply e ctx i) earg) <~~~~> typeToTExpr' de (typ farg)) + $ zip funcArgs exprArgs + return $ ret_c : arg_cs) + candidates + case constraints of + [cs] -> addConstraints cs + _ -> do + -- Type expression for the first argument of each candidate function. + te_arg0 <- mapM (typeToTExpr' de . typ . head . funcArgs) candidates + let -- Match the first argument against the first formal argument of each candidate + -- function. If a unique match is found, we've found our candidate and can expand the lazy + -- constraint. If multiple potential matches remain, return Nothing and try again later, when + -- the argument type has been further concretized, but if the argument is already fully + -- concretized, complain. If there are no matches, signal type conflict. + expand te = case findIndices (\(Function{..}, arg0) -> unifyTExprs te arg0) $ zip candidates te_arg0 of + [] -> err ?d (pos e) $ "Unknown function '" ++ fname ++ "(" ++ show te ++ (concat $ replicate (length exprArgs - 1) ",_") ++ ")'" + [i] -> return $ Just $ constraints !! i + is | teIsConstant te -> err ?d (pos e) + $ "Ambiguous call to function '" ++ fname ++ + "(" ++ show te ++ (concat $ replicate (length exprArgs - 1) ",_") ++ ")' may refer to:\n " ++ + (intercalate "\n " $ map (\i -> (name $ candidates !! i) ++ " at " ++ (spos $ candidates !! i)) is) + | otherwise -> return Nothing + ce <- teTypeOfExpr efirst_arg + addConstraint $ CLazy ce expand Nothing efirst_arg + $ "Function '" ++ fname ++ "(" ++ show efirst_arg ++ ", ...)'" where - Function{..} = getFunc ?d exprFunc + -- All functions that 'exprFunc' may be referring to. + candidates = concatMap (\f -> getFuncs ?d f (length exprArgs)) exprFunc + efirst_arg = DDExpr (CtxApply e ctx 0) (head exprArgs) + fname = nameLocal $ head exprFunc -- Struct field access: 'e1.f', where field 'f' is present in user-defined -- structs in 'S1',...,'Sn'. @@ -569,12 +667,14 @@ exprConstraints_ de@(DDExpr ctx (E e@EApply{..})) = do exprConstraints_ de@(DDExpr ctx (E e@EField{..})) = do dv <- tvarTypeOfExpr de let expand t' = case teDeref t' of + -- Type has not been sufficiently expanded yet. + TETVar{} -> return Nothing te@(TEUser n _) | elem n (map name candidates) -> do let t'' = fromJust $ tdefType $ getType ?d n let guarded = structFieldGuarded t'' exprField check ?d (not guarded) (pos e) $ "Access to guarded field \'" ++ exprField ++ "\' (not all constructors of type '" ++ n ++ "' have this field)." let fld_type = typeToTExpr $ typ $ fromJust $ find ((==exprField) . name) $ structFields $ typ' ?d $ teToType te - return [dv ==== fld_type] + return $ Just [dv ==== fld_type] _ -> err ?d (pos estruct) $ "expression '" ++ show estruct ++ "' must have a field named '" ++ exprField ++ "', but its type '" ++ show t' ++ "' doesn't" ce <- teTypeOfExpr estruct @@ -599,10 +699,12 @@ exprConstraints_ de@(DDExpr ctx (E e@EField{..})) = do exprConstraints_ de@(DDExpr ctx (E e@ETupField{..})) = do dvar <- tvarTypeOfExpr de let expand te = case teDeref te of + -- Type has not been sufficiently expanded yet. + TETVar{} -> return Nothing TETuple as -> do check ?d (length as >= (exprTupField + 1)) (pos e) $ "Expected tuple with at least " ++ show (exprTupField+1) ++ " fields, but expression '" ++ show e ++ "' of type '" ++ show te ++ "' only has " ++ show (length as) - return [dvar ==== (as !! exprTupField)] + return $ Just [dvar ==== (as !! exprTupField)] _ -> err ?d (pos de) $ "expression '" ++ show etuple ++ "' must be a tuple, but its type is '" ++ show te ++ "'" ce <- teTypeOfExpr etuple @@ -759,8 +861,9 @@ exprConstraints_ de@(DDExpr ctx (E e@EBinOp{..})) | elem exprBOp [Eq, Neq, Lt, L isstring <- tvarTypeOfExpr de <==== TEString dte <- tvarTypeOfExpr de ce <- teTypeOfExpr l - let expand TEString = return [isstring] - expand (TEBit w) = return [isbit_r, dte ==== TEBit (IPlus w (IVar $ WidthOfExpr r))] + let expand TETVar{} = return Nothing + expand TEString = return $ Just [isstring] + expand (TEBit w) = return $ Just [isbit_r, dte ==== TEBit (IPlus w (IVar $ WidthOfExpr r))] expand te = err ?d (pos l) $ "expression '" ++ show l ++ "' must be of type that supports concatenation operator (++), i.e., 'bit<>' or 'string', but its type '" ++ show te ++ "' doesn't" addConstraint $ CLazy ce expand Nothing l diff --git a/src/Language/DifferentialDatalog/TypeInference.hs-boot b/src/Language/DifferentialDatalog/TypeInference.hs-boot new file mode 100644 index 000000000..6c2addf83 --- /dev/null +++ b/src/Language/DifferentialDatalog/TypeInference.hs-boot @@ -0,0 +1,13 @@ +{-# LANGUAGE FlexibleContexts #-} + +module Language.DifferentialDatalog.TypeInference where + +import qualified Data.Map as M +import Control.Monad.Except + +import Language.DifferentialDatalog.Pos +import Language.DifferentialDatalog.Syntax + +inferTypes :: (MonadError String me) => DatalogProgram -> [(ECtx, Expr)] -> me [Expr] +inferTypeArgs :: (MonadError String me) => DatalogProgram -> Pos -> String -> [(Type, Type)] -> me (M.Map String Type) +unifyTypes :: DatalogProgram -> Type -> Type -> Bool diff --git a/src/Language/DifferentialDatalog/Unification.hs b/src/Language/DifferentialDatalog/Unification.hs index 0fd2da219..c86895e43 100644 --- a/src/Language/DifferentialDatalog/Unification.hs +++ b/src/Language/DifferentialDatalog/Unification.hs @@ -22,7 +22,8 @@ SOFTWARE. -} {-| -Unification-based type inference algorithm. +Module: Unification +Description: Unification-based type inference solver. -} {-# LANGUAGE FlexibleContexts, RecordWildCards, TupleSections, ImplicitParams, RankNTypes #-} @@ -41,9 +42,9 @@ module Language.DifferentialDatalog.Unification( TExpr(..), teToType, teDeref, + teIsConstant, Predicate(..), - solve -) + solve) where import Control.Monad.Except @@ -82,8 +83,8 @@ data Constraint = CPredicate {cPred::Predicate} -- 'expr1' and 'expr2'. | CWidthEq {cLHS::IExpr, cRHS::IExpr, cWidthExplanation::WidthExplanation} -- A lazy constraint gets activated once the type of a - -- specified "trigger" expression ('cExpr') is fully resolved. It is - -- used to represent disjunctive constraints, where the set + -- specified "trigger" expression ('cExpr') is fully or partially resolved. + -- It is used to represent disjunctive constraints, where the set -- of predicates depends on the type of the trigger. E.g., -- the type of 'x.f' depends on the type of 'x', e.g., '(x: -- Struct1 && x.f is bool || x:Struct2 && x.f: string || @@ -95,28 +96,22 @@ data Constraint = CPredicate {cPred::Predicate} -- 'cType' - type expression that represents our current -- knowledge of the type of 'cExpr'. Gets refined as the -- solver performs substitutions. - -- 'cExpand' - once 'cType' is resolved into a constant type - -- expression, this function is invoked to generate a set of - -- constraints that this lazy constraint resolves into. + -- 'cExpand' - once 'cType' is concretized, this function is invoked + -- to generate a set of constraints that this lazy constraint resolves + -- into. The function may return + -- * 'Nothing', meaning that the trigger type has not yet been + -- sufficiently concretized to resolve the constraint, + -- * An error indicating type conflict, or + -- * A list of constraints that the lazy constraint resolves + -- into. -- 'cDefault' - optional default set of constraints to be used -- if the program does not contain enough information to resolve -- the type of the trigger expression, e.g., an integer literal -- can be interpreted as 'u64' by default. -- 'cExplanation' - description of the constraint for -- debugging purposes. - -- - -- TODO: currently, a lazy constraint is only triggered once - -- the type has been completely resolved, at which point it is - -- required to produce a set of constraints of fail. Some use - -- cases may benefit from a more subtle design where a partial - -- expansion of the trigger expression is sufficient to - -- trigger the constraint. To support this we will need to - -- change the 'cExpand' signature to return - -- 'Option<[Constraint]>', with 'Nothing' meaning that 'cType' - -- is not yet sufficiently concretized to expand the - -- constraint. | CLazy { cType::TExpr - , cExpand::(forall me . (MonadError String me) => TExpr -> me [Constraint]) + , cExpand::(forall me . (MonadError String me) => TExpr -> me (Maybe [Constraint])) , cDefault::Maybe [Constraint] , cExpr::DDExpr , cExplanation::String @@ -473,6 +468,7 @@ instance Show Predicate where -- . -- ~~~~~~~~~ data PredicateExplanation = + ExplanationString Pos String | ExplanationParent Predicate | ExplanationTVar TypeVar ExplanationKind @@ -486,6 +482,7 @@ data PredicateExplanation = data ExplanationKind = Expected | Actual deriving (Eq) instance WithPos PredicateExplanation where + pos (ExplanationString p _) = p pos (ExplanationParent p) = pos (predExplanation p) pos (ExplanationTVar tv _) = pos tv atPos _ _ = error "PredicateExplanation.atPos not implemented" @@ -497,9 +494,11 @@ explanationSubstituteAll :: SolverState -> PredicateExplanation -> PredicateExpl -- Do not apply substitution to the original explanation, which points to the -- variable or expression the predicate constrains. explanationSubstituteAll _ e@ExplanationTVar{} = e +explanationSubstituteAll _ e@ExplanationString{} = e explanationSubstituteAll st (ExplanationParent p) = ExplanationParent $ head $ predSubstituteAll st p explanationShow :: PredicateExplanation -> TVarShortcuts String +explanationShow (ExplanationString _ s) = return s explanationShow (ExplanationTVar tv _) = return $ tvObject tv explanationShow (ExplanationParent (PEq te1 te2 e)) = do ts1 <- teShow te1 @@ -510,6 +509,7 @@ explanationShow (ExplanationParent (PEq te1 te2 e)) = do else "expected type: " ++ ts1 ++ "\nactual type: " ++ ts2 ++ "\nin\n" ++ es explanationKind :: PredicateExplanation -> ExplanationKind +explanationKind ExplanationString{} = Expected explanationKind (ExplanationTVar _ k) = k explanationKind (ExplanationParent p) = explanationKind (predExplanation p) @@ -615,22 +615,28 @@ data SolverState = SolverState { solverConstraints :: [Constraint] } -solve :: (MonadError String me) => DatalogProgram -> [Constraint] -> me Typing -solve d cs = let ?d = d in solve' init_state - where - init_state = SolverState { - solverPartialTyping = M.empty, - solverPartialWidth = M.empty, - solverConstraints = cs - } +emptySolverState :: SolverState +emptySolverState = SolverState { + solverPartialTyping = M.empty, + solverPartialWidth = M.empty, + solverConstraints = [] +} -solve' :: (?d::DatalogProgram, MonadError String me) => SolverState -> me Typing -solve' st | null (solverConstraints st) = do - -- Check that a complete typing has been found: all assignments in 'TA' and - -- 'IA' are constant expressions (no variables). Otherwise, FAIL: underspecified types. - mapM_ (\(tv, te) -> teCheckConstant tv te) $ M.toList $ solverPartialTyping st +-- Solve a set of type constraint by finding a satisfying assignment to +-- type variables and width variables. +-- +-- When 'full' is True, the function only succeeds if, after resolvin all constraints, +-- a complete typing is obtained: i.e., all variable assignments are constant expressions +-- that don't depend on other variables. +solve :: (MonadError String me) => DatalogProgram -> [Constraint] -> Bool -> me Typing +solve d cs full = let ?d = d in solve' (emptySolverState {solverConstraints = cs}) full + +solve' :: (?d::DatalogProgram, MonadError String me) => SolverState -> Bool -> me Typing +solve' st full | null (solverConstraints st) = do + when full + $ mapM_ (\(tv, te) -> teCheckConstant tv te) $ M.toList $ solverPartialTyping st return $ M.map teToType $ solverPartialTyping st - | otherwise = + | otherwise = -- 1. Pick 'c in C' s.t. 'c = (tv == te)', 'tv in TV', 'te in TE'. -- - If such 'c' does not exist, pick any predicate constraint in -- 'C' and apply Unification to it. @@ -644,7 +650,7 @@ solve' st | null (solverConstraints st) = do Just i -> do let st' = removeConstraint i st let CLazy _ _ (Just def) _ _ = solverConstraints st !! i let st'' = addConstraints (concatMap (constraintSubstituteAll st') def) st' - solve' st'' + solve' st'' full Nothing -> case solverConstraints st !! 0 of CLazy{..} -> err ?d (pos cExpr) $ "Failed to infer type of expression '" ++ show cExpr ++ "'" c@CWidthEq{} -> cwidthReportConflict c @@ -655,7 +661,7 @@ solve' st | null (solverConstraints st) = do Just i -> do let st' = removeConstraint i st new_constraints <- unify st $ cPred $ solverConstraints st !! i let st'' = addConstraints new_constraints st' - solve' st'' + solve' st'' full -- 2. Variable substitution: -- - remove 'c' from 'C' -- - apply Substitution to replace 'tv' with 'te' in all remaining @@ -665,11 +671,11 @@ solve' st | null (solverConstraints st) = do CPredicate (PEq (TETVar v) te _) -> do let st' = removeConstraint i st st'' <- substitute v te st' - solve' st'' + solve' st'' full CWidthEq (IVar v) ie2 _ -> do let st' = removeConstraint i st st'' <- substituteIVar v ie2 st' - solve' st'' + solve' st'' full c -> error $ "Unification.solve: unexpected constraint " ++ show c -- Do _not_ normalize the constraint before unification, as swapping RHS and LHS @@ -732,11 +738,13 @@ constraintSubstitute _ v with (CPredicate p) = return $ map CPredicate $ predSu constraintSubstitute _ _ _ c@CWidthEq{} = return [c] constraintSubstitute st v with c@(CLazy obj expand _ _ _) = do let obj' = teSubstitute v with obj - -- The object of the lazy constraint has been fully evaluated -- expand the - -- constraint. - if teIsConstant obj' - then (concatMap (constraintSubstituteAll st)) <$> expand obj' - else return [c{cType = obj'}] + -- If 'cType' got at least partially concretized, try to expand the + -- lazy constraint. + if obj' /= obj + then maybe [c{cType = obj'}] + (concatMap (constraintSubstituteAll st)) + <$> expand obj' + else return [c] constraintSubstituteAll :: (?d::DatalogProgram) => SolverState -> Constraint -> [Constraint] constraintSubstituteAll st (CPredicate p) = map CPredicate $ predSubstituteAll st p @@ -809,8 +817,10 @@ constraintSubstituteIVar _ v with (CWidthEq ie1 ie2 e) = do return $ cWidthEq ie1' ie2' e constraintSubstituteIVar st v with c@CLazy{..} = do let obj' = teSubstituteIVar v with cType - -- The object of the lazy constraint has been fully evaluated -- expand the - -- constraint. - if teIsConstant obj' - then (concatMap (constraintSubstituteAll st)) <$> cExpand obj' - else return [c{cType = obj'}] + -- If 'cType' got at least partially concretized, try to expand the + -- lazy constraint. + if obj' /= cType + then maybe [c{cType = obj'}] + (concatMap (constraintSubstituteAll st)) + <$> cExpand obj' + else return [c] diff --git a/src/Language/DifferentialDatalog/Validate.hs b/src/Language/DifferentialDatalog/Validate.hs index 83b7d3db2..b6bf67d89 100644 --- a/src/Language/DifferentialDatalog/Validate.hs +++ b/src/Language/DifferentialDatalog/Validate.hs @@ -38,6 +38,7 @@ import Language.DifferentialDatalog.Syntax import Language.DifferentialDatalog.NS import Language.DifferentialDatalog.Util import Language.DifferentialDatalog.Pos +import Language.DifferentialDatalog.Module import Language.DifferentialDatalog.Name import {-# SOURCE #-} Language.DifferentialDatalog.Type import Language.DifferentialDatalog.TypeInference @@ -62,7 +63,7 @@ validate d = do -- Validate function prototypes mapM_ (funcValidateProto d') $ M.elems $ progFunctions d' -- Validate function implementations - fs' <- sequence $ M.map (funcValidateDefinition d') $ progFunctions d' + fs' <- mapM (mapM (funcValidateDefinition d')) $ progFunctions d' -- Validate relation declarations rels' <- sequence $ M.map (relValidate d') $ progRelations d' -- Validate indexes @@ -80,32 +81,11 @@ validate d = do } -- Validate dependency graph depGraphValidate d'' - -- This check must be done after 'depGraphValidate', which may - -- introduce recursion - checkNoRecursion d'' -- Attributes do not affect the semantics of the program and can therefore -- be validated last. progValidateAttributes d'' return d'' --- Reject program with recursion -checkNoRecursion :: (MonadError String me) => DatalogProgram -> me () -checkNoRecursion d = do - case grCycle (funcGraph d) of - Nothing -> return () - Just t -> err d (pos $ getFunc d $ snd $ head t) - $ "Recursive function definition: " ++ (intercalate "->" $ map (name . snd) t) - -funcGraph :: DatalogProgram -> G.Gr String () -funcGraph DatalogProgram{..} = - let g0 = foldl' (\g (i,f) -> G.insNode (i,f) g) - G.empty $ zip [0..] (M.keys progFunctions) in - foldl' (\g (i,f) -> case funcDef f of - Nothing -> g - Just e -> foldl' (\g' f' -> G.insEdge (i, M.findIndex f' progFunctions, ()) g') - g (exprFuncs e)) - g0 $ zip [0..] $ M.elems progFunctions - -- Remove syntactic sugar progDesugar :: (MonadError String me) => DatalogProgram -> me DatalogProgram progDesugar d = progExprMapCtxM d (exprDesugar d) @@ -218,13 +198,31 @@ checkAcyclicTypes d@DatalogProgram{..} = do (intercalate " -> " $ map snd cyc)) $ grCycle gfull -funcValidateProto :: (MonadError String me) => DatalogProgram -> Function -> me () -funcValidateProto d f@Function{..} = do - uniqNames (Just d) ("Multiple definitions of argument " ++) funcArgs - let tvars = funcTypeVars f - mapM_ (typeValidate d tvars . argType) funcArgs - typeValidate d tvars funcType - +funcValidateProto :: (MonadError String me) => DatalogProgram -> [Function] -> me () +funcValidateProto d fs = do + let fname = name $ head fs + let extern_idx = findIndex (isNothing . funcDef) fs + let extern_fun = fs !! fromJust extern_idx + check d (length fs == 1 || extern_idx == Nothing) (pos extern_fun) + $ "Extern function '" ++ name extern_fun ++ "' clashes with function declaration(s) at\n " ++ + (intercalate "\n " $ map spos $ take (fromJust extern_idx) fs ++ drop (fromJust extern_idx + 1) fs) ++ + "\nOnly non-extern functions can be overloaded." + mapIdxM_ (\f i -> mapM_ (\j -> -- If functions have the same number of arguments, then their first arguments + -- must have different types. + when ((length $ funcArgs f) == (length $ funcArgs $ fs !! j)) $ do + check d ((length $ funcArgs f) /= 0) (pos f) + $ "Multiple declarations of function '" ++ fname ++ "()' at\n " ++ (spos f) ++ "\n " ++ (spos $ fs !! j) + check d (not $ unifyTypes d (typ $ head $ funcArgs f) (typ $ head $ funcArgs $ fs !! j)) (pos $ head $ funcArgs f) + $ "Conflicting declarations of function '" ++ name f ++ "' at\n " ++ (spos f) ++ "\n " ++ (spos $ fs !! j) ++ + "\nFunctions that share the same name and number of arguments must differ in the type of their first argument.") + [0..i-1]) fs + -- Validate individual prototypes. + mapM_ (\f@Function{..} -> do + uniqNames (Just d) ("Multiple definitions of argument " ++) funcArgs + let tvars = funcTypeVars f + mapM_ (typeValidate d tvars . argType) funcArgs + typeValidate d tvars funcType) + fs funcValidateDefinition :: (MonadError String me) => DatalogProgram -> Function -> me Function funcValidateDefinition d f@Function{..} = do @@ -338,10 +336,11 @@ ruleRHSValidate d rl RHSAggregate{} idx = do let RHSAggregate v group_by fname e = ruleRHS rl !! idx let gctx = CtxRuleRGroupBy rl idx check d (notElem v $ map name $ exprVars d gctx group_by) (pos e) $ "Aggregate variable " ++ v ++ " already declared in this scope" - -- Aggregation function exists and takes a group as its sole argument. - f <- checkFunc (pos e) d fname - check d (length (funcArgs f) == 1) (pos e) $ "Aggregation function must take one argument, but " ++ - fname ++ " takes " ++ (show $ length $ funcArgs f) ++ " arguments" + case lookupFuncs d fname 1 of + Nothing -> err d (pos e) $ "Aggregation function not found. '" ++ fname ++ "' must refer to a function that takes one argument of type Group<>" + Just [_] -> return () + Just fs -> err d (pos e) $ "Ambiguous aggregation function name '" ++ fname ++ "' may refer to:\n " ++ + (intercalate "\n " $ map name fs) return () ruleLHSValidate :: (MonadError String me) => DatalogProgram -> Rule -> Atom -> me () @@ -377,35 +376,33 @@ applyValidate :: (MonadError String me) => DatalogProgram -> Apply -> me () applyValidate d a@Apply{..} = do trans@Transformer{..} <- checkTransformer (pos a) d applyTransformer check d (length applyInputs == length transInputs) (pos a) - $ "Transformer " ++ name trans ++ " expects " ++ show (length transInputs) ++ " input arguments, but" ++ + $ "Transformer " ++ name trans ++ " expects " ++ show (length transInputs) ++ " input arguments, but " ++ show (length applyInputs) ++ " arguments are specified" check d (length applyOutputs == length transOutputs) (pos a) - $ "Transformer " ++ name trans ++ " returns " ++ show (length transOutputs) ++ " outputs, but" ++ + $ "Transformer " ++ name trans ++ " returns " ++ show (length transOutputs) ++ " outputs, but " ++ show (length applyOutputs) ++ " outputs are provided" types <- mapM (\(decl, conc) -> case hofType decl of HOTypeFunction{..} -> do - f@Function{..} <- checkFunc (pos a) d conc - -- FIXME: we don't have a proper unification checker; therefore insist on transformer arguments - -- using no type variables. - -- A proper unification checker should handle constraints of the form - -- '(exists T1 . forall T2 . E(T1,T2))', where 'T1' and 'T2' are lists of type arguments, and 'E' is - -- a conjunction of type congruence expressions. + fs' <- checkFuncs (pos a) d conc (length hotArgs) + let (f@Function{..}):fs = fs' + check d (null fs) (pos a) + $ "Multiple definitions of function '" ++ conc ++ "' found" + -- FIXME: Use the unification solver to match formal and + -- actual type transformer arguments. + -- For now, insist on transformer arguments using no type variables. check d (null $ funcTypeVars f) (pos a) - $ "Generic function " ++ conc ++ " cannot be passed as an argument to relation transformer" - check d (length hotArgs == length funcArgs) (pos a) - $ "Transformer " ++ name trans ++ " expects a function that takes " ++ show (length hotArgs) ++ " arguments " ++ - " but function " ++ name f ++ " takes " ++ show (length funcArgs) ++ " arguments" + $ "Generic function '" ++ conc ++ "' cannot be passed as an argument to relation transformer" mapM_ (\(farg, carg) -> check d (argMut farg == argMut carg) (pos a) $ - "Argument " ++ name farg ++ " of formal argument " ++ name decl ++ " of transformer " ++ name trans ++ - " differs in mutability from argument " ++ name carg ++ " of function " ++ name f) + "Argument '" ++ name farg ++ "' of formal argument '" ++ name decl ++ "' of transformer '" ++ name trans ++ + "' differs in mutability from argument '" ++ name carg ++ "' of function '" ++ name f ++ "'") $ zip hotArgs funcArgs return $ (zip (map typ hotArgs) (map typ funcArgs)) ++ [(hotType, funcType)] HOTypeRelation{..} -> do rel <- checkRelation (pos a) d conc return [(hotType, relType rel)] ) $ zip (transInputs ++ transOutputs) (applyInputs ++ applyOutputs) - bindings <- unifyTypes d (pos a) ("in transformer application " ++ show a) $ concat types + bindings <- inferTypeArgs d (pos a) ("in transformer application " ++ show a) $ concat types mapM_ (\ta -> case M.lookup ta bindings of Nothing -> err d (pos a) $ "Unable to bind type argument '" ++ ta ++ " to a concrete type in transformer application " ++ show a @@ -434,7 +431,7 @@ hotypeValidate :: (MonadError String me) => DatalogProgram -> HOType -> me () hotypeValidate d HOTypeFunction{..} = do -- FIXME: hacky way to validate function type by converting it into a function. let f = Function hotPos [] "" hotArgs hotType Nothing - funcValidateProto d f + funcValidateProto d [f] hotypeValidate d HOTypeRelation{..} = typeValidate d (typeTypeVars hotType) hotType @@ -513,7 +510,7 @@ exprsTypeCheck d tvars es = {-trace ("exprValidate " ++ show e ++ " in \n" ++ sh -- type inference. mapM_ (\(ctx, e) -> exprTraverseCtxM (exprValidate1 d tvars) ctx e) es -- Second pass: type inference. - inferTypes d $ map (\(ctx, e) -> DDExpr ctx e) es + inferTypes d es exprsPostCheck :: (MonadError String me) => DatalogProgram -> [(ECtx, Expr)] -> me () exprsPostCheck d es = do @@ -529,10 +526,10 @@ exprValidate1 _ _ ctx EVar{..} | ctxInRuleRHSPositivePattern ctx = return () exprValidate1 d _ ctx (EVar p v) = do _ <- checkVar p d ctx v return () -exprValidate1 d _ _ (EApply p f as) = do - fun <- checkFunc p d f - check d (length as == length (funcArgs fun)) p - "Number of arguments does not match function declaration" +exprValidate1 d _ _ (EApply p fnames as) = do + fs <- concat <$> mapM (\fname -> checkFuncs p d fname (length as)) fnames + check d (length fs == 1 || (not $ null as)) p $ "Ambiguous function name '" ++ (nameLocal $ head fnames) ++ "' may refer to:\n " ++ + (intercalate "\n " $ map (\f -> name f ++ " at " ++ spos f) fs) exprValidate1 _ _ _ EField{} = return () exprValidate1 _ _ _ ETupField{} = return () exprValidate1 _ _ _ EBool{} = return () @@ -558,11 +555,7 @@ exprValidate1 _ _ _ EMatch{} = return () exprValidate1 d _ ctx (EVarDecl p v) = do check d (ctxInSetL ctx || ctxInMatchPat ctx) p "Variable declaration is not allowed in this context" checkNoVar p d ctx v -{- | otherwise - = do checkNoVar p d ctx v - check (ctxIsTyped ctx) p "Variable declared without a type" - check (ctxIsSeq1 $ ctxParent ctx) p - "Variable declaration is not allowed in this context"-} + exprValidate1 _ _ _ ESeq{} = return () exprValidate1 _ _ _ EITE{} = return () exprValidate1 d _ ctx EFor{..} = checkNoVar exprPos d ctx exprLoopVar @@ -653,8 +646,8 @@ exprValidate3 d ctx e@(EMatch _ x cs) = do ct0 (map fst cs) check d (consTreeEmpty ct) (pos x) "Non-exhaustive match patterns" exprValidate3 d ctx (ESet _ l _) = checkLExpr d ctx l -exprValidate3 d ctx (EApply _ f as) = do - let fun = getFunc d f +exprValidate3 d ctx e@(EApply _ _ as) = do + let fun = applyExprGetFunc d ctx e mapM_ (\(a, mut) -> when mut $ checkLExpr d ctx a) $ zip as (map argMut $ funcArgs fun) diff --git a/test/antrea/networkpolicy_controller.dl b/test/antrea/networkpolicy_controller.dl index bf78574db..e6598aa03 100644 --- a/test/antrea/networkpolicy_controller.dl +++ b/test/antrea/networkpolicy_controller.dl @@ -558,7 +558,7 @@ AppliedToGroupPod(appliedToGroup, k8s.PodReference{pod.name, pod.namespace}, pod AppliedToGroupPodsByNode(appliedToGroup, nodeName, pods) :- AppliedToGroupPod(appliedToGroup, pod, nodeName), - var pods = Aggregate((appliedToGroup, nodeName), group2set(pod)). + var pods = Aggregate((appliedToGroup, nodeName), group_to_set(pod)). //var podsByNode = Aggregate((appliedToGroup), group2map((nodeName, podsOnNode))). AppliedToGroupSpan(appliedToGroup, nodeName) :- diff --git a/test/antrea/types.dl b/test/antrea/types.dl index 82a6fa6d5..69e133bd3 100644 --- a/test/antrea/types.dl +++ b/test/antrea/types.dl @@ -54,7 +54,7 @@ function selectorToString(selector: Ref): string = } } }; - string_join(set2vec(selSlice), " And ") + string_join(set_to_vec(selSlice), " And ") } // A namespace selector is either a namespace name (or "") @@ -102,7 +102,7 @@ function generateNormalizedName(nsSelector: NSSelector, podSelector: Option set_insert(normalizedName, "podSelector=${selectorToString(ls)}"), _ -> () }; - string_join(set2vec(normalizedName), " And ") + string_join(set_to_vec(normalizedName), " And ") } // toGroupSelector converts the podSelector and namespaceSelector @@ -241,12 +241,12 @@ function cidrStrToIPNet(cidr: string): Result = Err{"invalid format for IPBlock CIDR: ${cidr}"} } else { // Convert prefix length to int32 - match (parse_dec_i64(option_unwrap_or(vec_nth(s,1),""))) { - None -> Err{"invalid prefix length: ${option_unwrap_or(vec_nth(s,1),\"\")}"}, + match (parse_dec_i64(unwrap_or(vec_nth(s,1),""))) { + None -> Err{"invalid prefix length: ${unwrap_or(vec_nth(s,1),\"\")}"}, Some{prefixLen64} -> { Ok { IPNet { - .ip = ipStrToIPAddress(option_unwrap_or(vec_nth(s,0),"")), + .ip = ipStrToIPAddress(unwrap_or(vec_nth(s,0),"")), .prefixLength = prefixLen64 as signed<32> } } diff --git a/test/datalog_tests/dcm1.dl b/test/datalog_tests/dcm1.dl index d3cb15332..1d726cd7a 100644 --- a/test/datalog_tests/dcm1.dl +++ b/test/datalog_tests/dcm1.dl @@ -272,7 +272,7 @@ relation PodAllLabels(pod_name: IString, node_name: IString, labels: Mapf2->f1 -function f1(arg: bigint): bigint = { -^ - error: ./test/datalog_tests/function.fail.dl:6:5-6:17: Type constructor in the left-hand side of an assignment is only allowed for types with one constructor, but "std.Option" has multiple constructors Some{var s} = x ^^^^^^^^^^^^ @@ -113,3 +109,9 @@ in expression 'bool_identity(any)' (Tagg{.col = bool_identity(any)}) ^^^^^^^^^^^^^^^^^^ + +error: ./test/datalog_tests/function.fail.dl:5:1-6:1: Extern function 'foo' clashes with function declaration(s) at + ./test/datalog_tests/function.fail.dl:6:1-7:1 +Only non-extern functions can be overloaded. +extern function foo(x: u32): () +^ diff --git a/test/datalog_tests/function.fail.dl b/test/datalog_tests/function.fail.dl index ed54b9442..3541ba423 100644 --- a/test/datalog_tests/function.fail.dl +++ b/test/datalog_tests/function.fail.dl @@ -65,19 +65,6 @@ function shadow(): () = { var b = a.x } -//--- - -// recursive functions - -function f1(arg: bigint): bigint = { - f2(arg) -} - -function f2(arg: bigint): bigint = { - f1(arg) -} - - //--- // non-unique constructor in the LHS of assignment @@ -211,3 +198,10 @@ typedef Tagg = Tagg{col:bool} function agg():Tagg = (var any = Some{false}: Option); (Tagg{.col = bool_identity(any)}) + +//--- + +// Extern function name clash + +extern function foo(x: u32): () +extern function foo(x: Vec): () diff --git a/test/datalog_tests/lib_test.debug.ast.expected b/test/datalog_tests/lib_test.debug.ast.expected index 4f1a452a4..7104e5230 100644 --- a/test/datalog_tests/lib_test.debug.ast.expected +++ b/test/datalog_tests/lib_test.debug.ast.expected @@ -106,10 +106,10 @@ typedef tinyset_test.Sets = tinyset_test.Sets{setid: string, set: tinyset.Set64< typedef uuid.Error = string extern type uuid.Uuid typedef uuid_test.UUID = uuid_test.UUID{description: string, result: string} -function __debug_287_1_tinyset.group2set (g: std.Group)>): (std.Vec<'I>, tinyset.Set64>) +function __debug_287_1_tinyset.group_to_set (g: std.Group)>): (std.Vec<'I>, tinyset.Set64>) { (((var inputs: std.Vec<'I>), (var original_group: std.Group>)) = debug.debug_split_group(g); - (inputs, tinyset.group2set(original_group))) + (inputs, tinyset.group_to_set(original_group))) } extern function debug.debug_event (operator_id: debug.DDlogOpId, w: std.DDWeight, ts: 'T1, operator_type: string, input1: 'A1, out: 'A2): () extern function debug.debug_event_join (operator_id: debug.DDlogOpId, w: std.DDWeight, ts: 'T1, input1: 'A1, input2: 'A2, out: 'A3): () @@ -194,6 +194,14 @@ extern function fp.to_radians_d (f: double): double extern function fp.to_radians_f (f: float): float extern function fp.trunc_d (f: double): double extern function fp.trunc_f (f: float): float +function internment.contains (s1: internment.istring, s2: string): bool +{ + internment.istring_contains(s1, s2) +} +function internment.ends_with (s: internment.istring, suffix: string): bool +{ + internment.istring_ends_with(s, suffix) +} extern function internment.intern (s: 'A): internment.Intern<'A> extern function internment.istring_contains (s1: internment.istring, s2: string): bool extern function internment.istring_ends_with (s: internment.istring, suffix: string): bool @@ -210,6 +218,50 @@ extern function internment.istring_to_uppercase (s: internment.istring): string extern function internment.istring_trim (s: internment.istring): string #[return_by_ref = true] extern function internment.ival (s: internment.Intern<'A>): 'A +function internment.join (strings: std.Vec, sep: string): string +{ + internment.istring_join(strings, sep) +} +function internment.len (s: internment.istring): std.usize +{ + internment.istring_len(s) +} +function internment.replace (s: internment.istring, from: string, to: string): string +{ + internment.istring_replace(s, from, to) +} +function internment.reverse (s: internment.istring): string +{ + internment.istring_reverse(s) +} +function internment.split (s: internment.istring, sep: string): std.Vec +{ + internment.istring_split(s, sep) +} +function internment.starts_with (s: internment.istring, prefix: string): bool +{ + internment.istring_starts_with(s, prefix) +} +function internment.substr (s: internment.istring, start: std.usize, end: std.usize): string +{ + internment.istring_substr(s, start, end) +} +function internment.to_bytes (s: internment.istring): std.Vec +{ + internment.istring_to_bytes(s) +} +function internment.to_lowercase (s: internment.istring): string +{ + internment.istring_to_lowercase(s) +} +function internment.to_uppercase (s: internment.istring): string +{ + internment.istring_to_uppercase(s) +} +function internment.trim (s: internment.istring): string +{ + internment.istring_trim(s) +} function internment_test.istruct2struct (i: internment_test.IStruct): internment_test.Struct { (internment_test.Struct{.u=(internment.ival(i.u): internment_test.IUnion), .t=(internment.ival(i.t): (signed<32>, double)), .x=i.x}: internment_test.Struct) @@ -295,7 +347,7 @@ function json.jval_get (v: json.JsonValue, attr: internment.istring): std.Option function json.jval_get_or (v: json.JsonValue, attr: internment.istring, def: json.JsonValue): json.JsonValue { match (v) { - (json.JsonObject{.o=(var o: std.Map,json.JsonValue>)}: json.JsonValue) -> (std.option_unwrap_or((std.map_get(o, attr): std.Option), def): json.JsonValue), + (json.JsonObject{.o=(var o: std.Map,json.JsonValue>)}: json.JsonValue) -> (std.unwrap_or((std.map_get(o, attr): std.Option), def): json.JsonValue), (_: json.JsonValue) -> def } } @@ -520,16 +572,52 @@ extern function regex.regex_checked (pattern: string): std.Result extern function regex.regex_match (regex: regex.Regex, text: string): bool extern function std.__builtin_2string (x: 'X): string +function std.append (v: mut std.Vec<'X>, other: std.Vec<'X>): () +{ + std.vec_append(v, other) +} +function std.contains (s1: string, s2: string): bool +{ + std.string_contains(s1, s2) +} +function std.contains (v: std.Vec<'X>, x: 'X): bool +{ + std.vec_contains(v, x) +} +function std.contains (s: std.Set<'X>, v: 'X): bool +{ + std.set_contains(s, v) +} +function std.contains_key (m: std.Map<'K,'V>, k: 'K): bool +{ + std.map_contains_key(m, k) +} +function std.count (g: std.Group<'K,'V>): std.usize +{ + std.group_count(g) +} function std.dDNestedTS2string (ts: std.DDNestedTS): string { (((("(" ++ (std.__builtin_2string(ts.epoch): string)) ++ ",") ++ (std.__builtin_2string(ts.iter): string)) ++ ")") } #[return_by_ref = true] extern function std.deref (x: std.Ref<'A>): 'A -extern function std.group2map (g: std.Group<'K1,('K2, 'V)>): std.Map<'K2,'V> -extern function std.group2set (g: std.Group<'K,'V>): std.Set<'V> -extern function std.group2setmap (g: std.Group<'K1,('K2, 'V)>): std.Map<'K2,std.Set<'V>> -extern function std.group2vec (g: std.Group<'K,'V>): std.Vec<'V> +function std.difference (s1: std.Set<'X>, s2: std.Set<'X>): std.Set<'X> +{ + (std.set_difference(s1, s2): std.Set<'X>) +} +function std.ends_with (s: string, suffix: string): bool +{ + std.string_ends_with(s, suffix) +} +function std.first (g: std.Group<'K,'V>): 'V +{ + (std.group_first(g): 'V) +} +function std.get (m: std.Map<'K,'V>, k: 'K): std.Option<'V> +{ + (std.map_get(m, k): std.Option<'V>) +} extern function std.group_count (g: std.Group<'K,'V>): std.usize extern function std.group_first (g: std.Group<'K,'V>): 'V extern function std.group_key (g: std.Group<'K,'V>): 'K @@ -539,6 +627,10 @@ extern function std.group_nth (g: std.Group<'K,'V>, n: std.usize): std.Option<'V extern function std.group_set_unions (g: std.Group<'K,std.Set<'A>>): std.Set<'A> extern function std.group_setref_unions (g: std.Group<'K,std.Ref>>): std.Ref> extern function std.group_sum (g: std.Group<'K,'V>): 'V +extern function std.group_to_map (g: std.Group<'K1,('K2, 'V)>): std.Map<'K2,'V> +extern function std.group_to_set (g: std.Group<'K,'V>): std.Set<'V> +extern function std.group_to_setmap (g: std.Group<'K1,('K2, 'V)>): std.Map<'K2,std.Set<'V>> +extern function std.group_to_vec (g: std.Group<'K,'V>): std.Vec<'V> function std.group_unzip (g: std.Group<'K,('X, 'Y)>): (std.Vec<'X>, std.Vec<'Y>) { ((var xs: std.Vec<'X>) = (std.vec_empty(): std.Vec<'X>); @@ -555,6 +647,38 @@ extern function std.hash64 (x: 'X): bit<64> extern function std.hex (x: 'X): string extern function std.htonl (x: bit<32>): bit<32> extern function std.htons (x: bit<16>): bit<16> +function std.insert (m: mut std.Map<'K,'V>, k: 'K, v: 'V): () +{ + std.map_insert(m, k, v) +} +function std.insert (s: mut std.Set<'X>, v: 'X): () +{ + std.set_insert(s, v) +} +function std.insert_imm (m: std.Map<'K,'V>, k: 'K, v: 'V): std.Map<'K,'V> +{ + (std.map_insert_imm(m, k, v): std.Map<'K,'V>) +} +function std.insert_imm (s: std.Set<'X>, v: 'X): std.Set<'X> +{ + (std.set_insert_imm(s, v): std.Set<'X>) +} +function std.intersection (s1: std.Set<'X>, s2: std.Set<'X>): std.Set<'X> +{ + (std.set_intersection(s1, s2): std.Set<'X>) +} +function std.is_empty (v: std.Vec<'X>): bool +{ + std.vec_is_empty(v) +} +function std.is_empty (m: std.Map<'K,'V>): bool +{ + std.map_is_empty(m) +} +function std.is_empty (s: std.Set<'X>): bool +{ + std.set_is_empty(s) +} function std.is_err (res: std.Result<'V,'E>): bool { match (res) { @@ -583,6 +707,22 @@ function std.is_some (x: std.Option<'A>): bool (_: std.Option<'A>) -> false } } +function std.join (strings: std.Vec, sep: string): string +{ + std.string_join(strings, sep) +} +function std.key (g: std.Group<'K,'V>): 'K +{ + (std.group_key(g): 'K) +} +function std.len (s: string): std.usize +{ + std.string_len(s) +} +function std.len (v: std.Vec<'X>): std.usize +{ + std.vec_len(v) +} extern function std.map_contains_key (m: std.Map<'K,'V>, k: 'K): bool extern function std.map_empty (): std.Map<'K,'V> extern function std.map_get (m: std.Map<'K,'V>, k: 'K): std.Option<'V> @@ -601,6 +741,10 @@ function std.max (x: 'A, y: 'A): 'A y } } +function std.max (g: std.Group<'K,'V>): 'V +{ + (std.group_max(g): 'V) +} function std.min (x: 'A, y: 'A): 'A { if (x < y) { @@ -609,44 +753,51 @@ function std.min (x: 'A, y: 'A): 'A y } } -extern function std.ntohl (x: bit<32>): bit<32> -extern function std.ntohs (x: bit<16>): bit<16> -function std.option2set (o: std.Option<'X>): std.Set<'X> +function std.min (g: std.Group<'K,'V>): 'V { - match (o) { - (std.Some{.x=(var x: 'X)}: std.Option<'X>) -> (std.set_singleton(x): std.Set<'X>), - (std.None{}: std.Option<'X>) -> (std.set_empty(): std.Set<'X>) - } + (std.group_min(g): 'V) } -function std.option2vec (o: std.Option<'X>): std.Vec<'X> +function std.nth (g: std.Group<'K,'V>, n: std.usize): std.Option<'V> { - match (o) { - (std.Some{.x=(var x: 'X)}: std.Option<'X>) -> (std.vec_singleton(x): std.Vec<'X>), - (std.None{}: std.Option<'X>) -> (std.vec_empty(): std.Vec<'X>) - } + (std.group_nth(g, n): std.Option<'V>) } -function std.option_unwrap_or (x: std.Option<'A>, def: 'A): 'A +function std.nth (v: std.Vec<'X>, n: std.usize): std.Option<'X> { - match (x) { - (std.Some{.x=(var v: 'A)}: std.Option<'A>) -> v, - (std.None{}: std.Option<'A>) -> def - } + (std.vec_nth(v, n): std.Option<'X>) } +function std.nth (s: std.Set<'X>, n: std.usize): std.Option<'X> +{ + (std.set_nth(s, n): std.Option<'X>) +} +extern function std.ntohl (x: bit<32>): bit<32> +extern function std.ntohs (x: bit<16>): bit<16> extern function std.option_unwrap_or_default (opt: std.Option<'A>): 'A extern function std.parse_dec_i64 (s: string): std.Option> extern function std.parse_dec_u64 (s: string): std.Option> extern function std.pow32 (base: 'A, exp: bit<32>): 'A +function std.push (v: mut std.Vec<'X>, x: 'X): () +{ + std.vec_push(v, x) +} +function std.push_imm (v: std.Vec<'X>, x: 'X): std.Vec<'X> +{ + (std.vec_push_imm(v, x): std.Vec<'X>) +} extern function std.range (from: 'A, to: 'A, step: 'A): std.Vec<'A> extern function std.ref_new (x: 'A): std.Ref<'A> -function std.result_unwrap_or (res: std.Result<'V,'E>, def: 'V): 'V +function std.remove (m: mut std.Map<'K,'V>, k: 'K): () { - match (res) { - (std.Ok{.res=(var v: 'V)}: std.Result<'V,'E>) -> v, - (std.Err{.err=(_: 'E)}: std.Result<'V,'E>) -> def - } + std.map_remove(m, k) +} +function std.replace (s: string, from: string, to: string): string +{ + std.string_replace(s, from, to) } extern function std.result_unwrap_or_default (res: std.Result<'V,'E>): 'V -extern function std.set2vec (s: std.Set<'A>): std.Vec<'A> +function std.reverse (s: string): string +{ + std.string_reverse(s) +} extern function std.set_contains (s: std.Set<'X>, v: 'X): bool extern function std.set_difference (s1: std.Set<'X>, s2: std.Set<'X>): std.Set<'X> extern function std.set_empty (): std.Set<'X> @@ -657,8 +808,37 @@ extern function std.set_is_empty (s: std.Set<'X>): bool extern function std.set_nth (s: std.Set<'X>, n: std.usize): std.Option<'X> extern function std.set_singleton (x: 'X): std.Set<'X> extern function std.set_size (s: std.Set<'X>): std.usize +extern function std.set_to_vec (s: std.Set<'A>): std.Vec<'A> extern function std.set_union (s1: std.Set<'X>, s2: std.Set<'X>): std.Set<'X> extern function std.set_unions (sets: std.Vec>): std.Set<'X> +function std.setref_unions (g: std.Group<'K,std.Ref>>): std.Ref> +{ + (std.group_setref_unions(g): std.Ref>) +} +function std.size (m: std.Map<'K,'V>): std.usize +{ + std.map_size(m) +} +function std.size (s: std.Set<'X>): std.usize +{ + std.set_size(s) +} +function std.sort (v: mut std.Vec<'X>): () +{ + std.vec_sort(v) +} +function std.sort_imm (v: std.Vec<'X>): std.Vec<'X> +{ + (std.vec_sort_imm(v): std.Vec<'X>) +} +function std.split (s: string, sep: string): std.Vec +{ + std.string_split(s, sep) +} +function std.starts_with (s: string, prefix: string): bool +{ + std.string_starts_with(s, prefix) +} extern function std.str_to_lower (s: string): string extern function std.string_contains (s1: string, s2: string): bool extern function std.string_ends_with (s: string, suffix: string): bool @@ -673,7 +853,98 @@ extern function std.string_to_bytes (s: string): std.Vec extern function std.string_to_lowercase (s: string): string extern function std.string_to_uppercase (s: string): string extern function std.string_trim (s: string): string -extern function std.vec2set (s: std.Vec<'A>): std.Set<'A> +function std.substr (s: string, start: std.usize, end: std.usize): string +{ + std.string_substr(s, start, end) +} +function std.to_bytes (s: string): std.Vec +{ + std.string_to_bytes(s) +} +function std.to_lowercase (s: string): string +{ + std.string_to_lowercase(s) +} +function std.to_map (g: std.Group<'K1,('K2, 'V)>): std.Map<'K2,'V> +{ + (std.group_to_map(g): std.Map<'K2,'V>) +} +function std.to_set (o: std.Option<'X>): std.Set<'X> +{ + match (o) { + (std.Some{.x=(var x: 'X)}: std.Option<'X>) -> (std.set_singleton(x): std.Set<'X>), + (std.None{}: std.Option<'X>) -> (std.set_empty(): std.Set<'X>) + } +} +function std.to_set (g: std.Group<'K,'V>): std.Set<'V> +{ + (std.group_to_set(g): std.Set<'V>) +} +function std.to_set (s: std.Vec<'A>): std.Set<'A> +{ + (std.vec_to_set(s): std.Set<'A>) +} +function std.to_setmap (g: std.Group<'K1,('K2, 'V)>): std.Map<'K2,std.Set<'V>> +{ + (std.group_to_setmap(g): std.Map<'K2,std.Set<'V>>) +} +function std.to_uppercase (s: string): string +{ + std.string_to_uppercase(s) +} +function std.to_vec (o: std.Option<'X>): std.Vec<'X> +{ + match (o) { + (std.Some{.x=(var x: 'X)}: std.Option<'X>) -> (std.vec_singleton(x): std.Vec<'X>), + (std.None{}: std.Option<'X>) -> (std.vec_empty(): std.Vec<'X>) + } +} +function std.to_vec (g: std.Group<'K,'V>): std.Vec<'V> +{ + (std.group_to_vec(g): std.Vec<'V>) +} +function std.to_vec (s: std.Set<'A>): std.Vec<'A> +{ + (std.set_to_vec(s): std.Vec<'A>) +} +function std.trim (s: string): string +{ + std.string_trim(s) +} +function std.union (m1: std.Map<'K,'V>, m2: std.Map<'K,'V>): std.Map<'K,'V> +{ + (std.map_union(m1, m2): std.Map<'K,'V>) +} +function std.union (s1: std.Set<'X>, s2: std.Set<'X>): std.Set<'X> +{ + (std.set_union(s1, s2): std.Set<'X>) +} +function std.unions (sets: std.Vec>): std.Set<'X> +{ + (std.set_unions(sets): std.Set<'X>) +} +function std.unwrap_or (x: std.Option<'A>, def: 'A): 'A +{ + match (x) { + (std.Some{.x=(var v: 'A)}: std.Option<'A>) -> v, + (std.None{}: std.Option<'A>) -> def + } +} +function std.unwrap_or (res: std.Result<'V,'E>, def: 'V): 'V +{ + match (res) { + (std.Ok{.res=(var v: 'V)}: std.Result<'V,'E>) -> v, + (std.Err{.err=(_: 'E)}: std.Result<'V,'E>) -> def + } +} +function std.unwrap_or_default (opt: std.Option<'A>): 'A +{ + (std.option_unwrap_or_default(opt): 'A) +} +function std.unwrap_or_default (res: std.Result<'V,'E>): 'V +{ + (std.result_unwrap_or_default(res): 'V) +} extern function std.vec_append (v: mut std.Vec<'X>, other: std.Vec<'X>): () extern function std.vec_contains (v: std.Vec<'X>, x: 'X): bool extern function std.vec_empty (): std.Vec<'A> @@ -683,16 +954,17 @@ extern function std.vec_nth (v: std.Vec<'X>, n: std.usize): std.Option<'X> extern function std.vec_push (v: mut std.Vec<'X>, x: 'X): () extern function std.vec_push_imm (v: std.Vec<'X>, x: 'X): std.Vec<'X> extern function std.vec_singleton (x: 'X): std.Vec<'X> -extern function std.vec_sort (v: std.Vec<'X>): () +extern function std.vec_sort (v: mut std.Vec<'X>): () extern function std.vec_sort_imm (v: std.Vec<'X>): std.Vec<'X> +extern function std.vec_to_set (s: std.Vec<'A>): std.Set<'A> extern function std.vec_with_capacity (len: std.usize): std.Vec<'A> extern function std.vec_with_length (len: std.usize, x: 'A): std.Vec<'A> extern function tinyset.contains (s: tinyset.Set64<'X>, v: 'X): bool extern function tinyset.difference (s1: tinyset.Set64<'X>, s2: tinyset.Set64<'X>): tinyset.Set64<'X> extern function tinyset.empty (): tinyset.Set64<'X> -extern function tinyset.group2set (g: std.Group<'K,'V>): tinyset.Set64<'V> extern function tinyset.group_set_unions (g: std.Group<'K,tinyset.Set64<'V>>): tinyset.Set64<'V> extern function tinyset.group_setref_unions (g: std.Group<'K,std.Ref>>): std.Ref> +extern function tinyset.group_to_set (g: std.Group<'K,'V>): tinyset.Set64<'V> extern function tinyset.insert (s: mut tinyset.Set64<'X>, v: 'X): () extern function tinyset.insert_imm (s: tinyset.Set64<'X>, v: 'X): tinyset.Set64<'X> extern function tinyset.intersection (s1: tinyset.Set64<'X>, s2: tinyset.Set64<'X>): tinyset.Set64<'X> @@ -727,11 +999,11 @@ function uuid_test.test_uuid_from_bytes (): uuid.Uuid (for (i in (std.range((8'd0: bit<8>), (8'd15: bit<8>), (8'd1: bit<8>)): std.Vec>)) { std.vec_push(bytes, (i as bit<8>)) }; - (std.result_unwrap_or(uuid.from_bytes(bytes), uuid.nil()): uuid.Uuid))) + (std.unwrap_or(uuid.from_bytes(bytes), uuid.nil()): uuid.Uuid))) } function uuid_test.uuid_parse_or_nil (str: string): uuid.Uuid { - (std.result_unwrap_or(uuid.parse_str(str), uuid.nil()): uuid.Uuid) + (std.unwrap_or(uuid.parse_str(str), uuid.nil()): uuid.Uuid) } output relation fp_test.BB [fp_test.BB] output relation fp_test.D [fp_test.D] @@ -812,9 +1084,9 @@ uuid_test.UUID[(uuid_test.UUID{.description="uuid.new_v5(\"5a5e7dd9-e3fb-49bb-b2 uuid_test.UUID[(uuid_test.UUID{.description="uuid.new_v5(\"5a5e7dd9-e3fb-49bb-b263-9bab25c95841\", \"namespace=nsA And podSelector=group In [appliedTo] And role In [db app]\")", .result=uuid.to_hyphenated_lower(uuid.new_v5(uuid_test.uuid_parse_or_nil("5a5e7dd9-e3fb-49bb-b263-9bab25c95841"), std.string_to_bytes("namespace=nsA And podSelector=group In [appliedTo] And role In [db app]")))}: uuid_test.UUID)]. net_test.NetChecks[(net_test.NetChecks{.description="ipv4_new(192, 168, 0, 1)", .value=("" ++ (net.ipv4.ipv4Addr2string(net.ipv4.ipv4_new(8'd192, 8'd168, 8'd0, 8'd1)): string))}: net_test.NetChecks)]. net_test.NetChecks[(net_test.NetChecks{.description="ipv4_from_u32('h0a0b0c0d)", .value=("" ++ (net.ipv4.ipv4Addr2string(net.ipv4.ipv4_from_u32(32'd168496141)): string))}: net_test.NetChecks)]. -net_test.NetChecks[(net_test.NetChecks{.description="ipv4_from_str(10.10.10.101)", .value=("" ++ (net.ipv4.ipv4Addr2string((std.result_unwrap_or(net.ipv4.ipv4_from_str("10.10.10.101"), net.ipv4.iPV4_UNSPECIFIED()): net.ipv4.Ipv4Addr)): string))}: net_test.NetChecks)]. -net_test.NetChecks[(net_test.NetChecks{.description="ipv4_from_str(10.10.10.10.1)", .value=("" ++ (net.ipv4.ipv4Addr2string((std.result_unwrap_or(net.ipv4.ipv4_from_str("10.10.10.10.1"), net.ipv4.iPV4_UNSPECIFIED()): net.ipv4.Ipv4Addr)): string))}: net_test.NetChecks)]. -net_test.NetChecks[(net_test.NetChecks{.description="ipv4_from_octet_vec(ipv4_octet_vec(ipv4_new(192, 168, 0, 1)))", .value=("" ++ (net.ipv4.ipv4Addr2string((std.option_unwrap_or(net.ipv4.ipv4_from_octet_vec(net.ipv4.ipv4_octet_vec(net.ipv4.ipv4_new(8'd192, 8'd168, 8'd0, 8'd1))), net.ipv4.iPV4_UNSPECIFIED()): net.ipv4.Ipv4Addr)): string))}: net_test.NetChecks)]. +net_test.NetChecks[(net_test.NetChecks{.description="ipv4_from_str(10.10.10.101)", .value=("" ++ (net.ipv4.ipv4Addr2string((std.unwrap_or(net.ipv4.ipv4_from_str("10.10.10.101"), net.ipv4.iPV4_UNSPECIFIED()): net.ipv4.Ipv4Addr)): string))}: net_test.NetChecks)]. +net_test.NetChecks[(net_test.NetChecks{.description="ipv4_from_str(10.10.10.10.1)", .value=("" ++ (net.ipv4.ipv4Addr2string((std.unwrap_or(net.ipv4.ipv4_from_str("10.10.10.10.1"), net.ipv4.iPV4_UNSPECIFIED()): net.ipv4.Ipv4Addr)): string))}: net_test.NetChecks)]. +net_test.NetChecks[(net_test.NetChecks{.description="ipv4_from_octet_vec(ipv4_octet_vec(ipv4_new(192, 168, 0, 1)))", .value=("" ++ (net.ipv4.ipv4Addr2string((std.unwrap_or(net.ipv4.ipv4_from_octet_vec(net.ipv4.ipv4_octet_vec(net.ipv4.ipv4_new(8'd192, 8'd168, 8'd0, 8'd1))), net.ipv4.iPV4_UNSPECIFIED()): net.ipv4.Ipv4Addr)): string))}: net_test.NetChecks)]. net_test.NetChecks[(net_test.NetChecks{.description="iPV4_LOCALHOST()", .value=("" ++ (net.ipv4.ipv4Addr2string(net.ipv4.iPV4_LOCALHOST()): string))}: net_test.NetChecks)]. net_test.NetChecks[(net_test.NetChecks{.description="iPV4_UNSPECIFIED()", .value=("" ++ (net.ipv4.ipv4Addr2string(net.ipv4.iPV4_UNSPECIFIED()): string))}: net_test.NetChecks)]. net_test.NetChecks[(net_test.NetChecks{.description="iPV4_BROADCAST()", .value=("" ++ (net.ipv4.ipv4Addr2string(net.ipv4.iPV4_BROADCAST()): string))}: net_test.NetChecks)]. @@ -859,41 +1131,41 @@ net_test.NetChecks[(net_test.NetChecks{.description="ipv4_to_u32(ipv4_new(192,16 net_test.NetChecks[(net_test.NetChecks{.description="ipv6_new(0, 0, 0, 0, 0, 'hffff, 'hc00a, 'h2ff)", .value=("" ++ (net.ipv6.ipv6Addr2string(net.ipv6.ipv6_new(16'd0, 16'd0, 16'd0, 16'd0, 16'd0, 16'd65535, 16'd49162, 16'd767)): string))}: net_test.NetChecks)]. net_test.NetChecks[(net_test.NetChecks{.description="iPV6_LOCALHOST()", .value=("" ++ (net.ipv6.ipv6Addr2string(net.ipv6.iPV6_LOCALHOST()): string))}: net_test.NetChecks)]. net_test.NetChecks[(net_test.NetChecks{.description="iPV6_UNSPECIFIED()", .value=("" ++ (net.ipv6.ipv6Addr2string(net.ipv6.iPV6_UNSPECIFIED()): string))}: net_test.NetChecks)]. -net_test.NetChecks[(net_test.NetChecks{.description="ipv6_from_segment_vec(ipv6_segment_vec(ipv6_new(0, 0, 0, 0, 0, 'hffff, 'hc00a, 'h2ff)))", .value=("" ++ (net.ipv6.ipv6Addr2string((std.option_unwrap_or(net.ipv6.ipv6_from_segment_vec(net.ipv6.ipv6_segment_vec(net.ipv6.ipv6_new(16'd0, 16'd0, 16'd0, 16'd0, 16'd0, 16'd65535, 16'd49162, 16'd767))), net.ipv6.iPV6_UNSPECIFIED()): net.ipv6.Ipv6Addr)): string))}: net_test.NetChecks)]. -net_test.NetChecks[(net_test.NetChecks{.description="ipv6_from_segment_vec(ipv6_segment_vec(ipv6_new(0, 0, 0, 0, 0, 'hffff, 'hc00a, 'h2ff, 'h10)))", .value=("" ++ (net.ipv6.ipv6Addr2string((std.option_unwrap_or(net.ipv6.ipv6_from_segment_vec((std.vec_push_imm(net.ipv6.ipv6_segment_vec(net.ipv6.ipv6_new(16'd0, 16'd0, 16'd0, 16'd0, 16'd0, 16'd65535, 16'd49162, 16'd767)), 16'd16): std.Vec>)), net.ipv6.iPV6_UNSPECIFIED()): net.ipv6.Ipv6Addr)): string))}: net_test.NetChecks)]. +net_test.NetChecks[(net_test.NetChecks{.description="ipv6_from_segment_vec(ipv6_segment_vec(ipv6_new(0, 0, 0, 0, 0, 'hffff, 'hc00a, 'h2ff)))", .value=("" ++ (net.ipv6.ipv6Addr2string((std.unwrap_or(net.ipv6.ipv6_from_segment_vec(net.ipv6.ipv6_segment_vec(net.ipv6.ipv6_new(16'd0, 16'd0, 16'd0, 16'd0, 16'd0, 16'd65535, 16'd49162, 16'd767))), net.ipv6.iPV6_UNSPECIFIED()): net.ipv6.Ipv6Addr)): string))}: net_test.NetChecks)]. +net_test.NetChecks[(net_test.NetChecks{.description="ipv6_from_segment_vec(ipv6_segment_vec(ipv6_new(0, 0, 0, 0, 0, 'hffff, 'hc00a, 'h2ff, 'h10)))", .value=("" ++ (net.ipv6.ipv6Addr2string((std.unwrap_or(net.ipv6.ipv6_from_segment_vec((std.vec_push_imm(net.ipv6.ipv6_segment_vec(net.ipv6.ipv6_new(16'd0, 16'd0, 16'd0, 16'd0, 16'd0, 16'd65535, 16'd49162, 16'd767)), 16'd16): std.Vec>)), net.ipv6.iPV6_UNSPECIFIED()): net.ipv6.Ipv6Addr)): string))}: net_test.NetChecks)]. net_test.NetChecks[(net_test.NetChecks{.description="ipv6_from_octets(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'hff, 'hff, 'hc0, 'h0a, 'h2, 'hff)", .value=("" ++ (net.ipv6.ipv6Addr2string(net.ipv6.ipv6_from_octets(8'd0, 8'd0, 8'd0, 8'd0, 8'd0, 8'd0, 8'd0, 8'd0, 8'd0, 8'd0, 8'd255, 8'd255, 8'd192, 8'd10, 8'd2, 8'd255)): string))}: net_test.NetChecks)]. -net_test.NetChecks[(net_test.NetChecks{.description="ipv6_from_octet_vec(ipv6_octet_vec(ipv6_new(0, 0, 0, 0, 0, 'hffff, 'hc00a, 'h2ff)))", .value=("" ++ (net.ipv6.ipv6Addr2string((std.option_unwrap_or(net.ipv6.ipv6_from_octet_vec(net.ipv6.ipv6_octet_vec(net.ipv6.ipv6_new(16'd0, 16'd0, 16'd0, 16'd0, 16'd0, 16'd65535, 16'd49162, 16'd767))), net.ipv6.iPV6_UNSPECIFIED()): net.ipv6.Ipv6Addr)): string))}: net_test.NetChecks)]. +net_test.NetChecks[(net_test.NetChecks{.description="ipv6_from_octet_vec(ipv6_octet_vec(ipv6_new(0, 0, 0, 0, 0, 'hffff, 'hc00a, 'h2ff)))", .value=("" ++ (net.ipv6.ipv6Addr2string((std.unwrap_or(net.ipv6.ipv6_from_octet_vec(net.ipv6.ipv6_octet_vec(net.ipv6.ipv6_new(16'd0, 16'd0, 16'd0, 16'd0, 16'd0, 16'd65535, 16'd49162, 16'd767))), net.ipv6.iPV6_UNSPECIFIED()): net.ipv6.Ipv6Addr)): string))}: net_test.NetChecks)]. net_test.NetChecks[(net_test.NetChecks{.description="ipv6_from_u128(128'h102030405060708090A0B0C0D0E0F00)", .value=("" ++ (net.ipv6.ipv6Addr2string(net.ipv6.ipv6_from_u128(128'd1339673755198158349044581307228491520)): string))}: net_test.NetChecks)]. -net_test.NetChecks[(net_test.NetChecks{.description="ipv6_from_str(102:304:506:708:90a:b0c:d0e:f00)", .value=("" ++ (net.ipv6.ipv6Addr2string((std.result_unwrap_or(net.ipv6.ipv6_from_str("102:304:506:708:90a:b0c:d0e:f00"), net.ipv6.iPV6_UNSPECIFIED()): net.ipv6.Ipv6Addr)): string))}: net_test.NetChecks)]. -net_test.NetChecks[(net_test.NetChecks{.description="ipv6_from_str(::ffff:192.10.2.255)", .value=("" ++ (net.ipv6.ipv6Addr2string((std.result_unwrap_or(net.ipv6.ipv6_from_str("::ffff:192.10.2.255"), net.ipv6.iPV6_UNSPECIFIED()): net.ipv6.Ipv6Addr)): string))}: net_test.NetChecks)]. -net_test.NetChecks[(net_test.NetChecks{.description="ipv6_from_str(::175.16.1.2)", .value=("" ++ (net.ipv6.ipv6Addr2string((std.result_unwrap_or(net.ipv6.ipv6_from_str("::175.16.1.2"), net.ipv6.iPV6_UNSPECIFIED()): net.ipv6.Ipv6Addr)): string))}: net_test.NetChecks)]. -net_test.NetChecks[(net_test.NetChecks{.description="ipv6_from_str(ffff:192.10.2.255)", .value=("" ++ (net.ipv6.ipv6Addr2string((std.result_unwrap_or(net.ipv6.ipv6_from_str("ffff:192.10.2.255"), net.ipv6.iPV6_UNSPECIFIED()): net.ipv6.Ipv6Addr)): string))}: net_test.NetChecks)]. -net_test.NetChecks[(net_test.NetChecks{.description="ipv6_from_str(::)", .value=("" ++ (net.ipv6.ipv6Addr2string((std.result_unwrap_or(net.ipv6.ipv6_from_str("::"), net.ipv6.iPV6_LOCALHOST()): net.ipv6.Ipv6Addr)): string))}: net_test.NetChecks)]. -net_test.NetChecks[(net_test.NetChecks{.description="ipv6_to_u128(ipv6_from_str(::ffff:192.10.2.255))", .value=("" ++ std.hex(net.ipv6.ipv6_to_u128((std.result_unwrap_or(net.ipv6.ipv6_from_str("::ffff:192.10.2.255"), net.ipv6.iPV6_UNSPECIFIED()): net.ipv6.Ipv6Addr))))}: net_test.NetChecks)]. -net_test.NetChecks[(net_test.NetChecks{.description="ipv6_segments(ipv6_from_str(::ffff:192.10.2.255))", .value=(((var a: bit<16>), (var b: bit<16>), (var c: bit<16>), (var d: bit<16>), (var e: bit<16>), (var f: bit<16>), (var g: bit<16>), (var h: bit<16>)) = net.ipv6.ipv6_segments((std.result_unwrap_or(net.ipv6.ipv6_from_str("::ffff:192.10.2.255"), net.ipv6.iPV6_UNSPECIFIED()): net.ipv6.Ipv6Addr)); +net_test.NetChecks[(net_test.NetChecks{.description="ipv6_from_str(102:304:506:708:90a:b0c:d0e:f00)", .value=("" ++ (net.ipv6.ipv6Addr2string((std.unwrap_or(net.ipv6.ipv6_from_str("102:304:506:708:90a:b0c:d0e:f00"), net.ipv6.iPV6_UNSPECIFIED()): net.ipv6.Ipv6Addr)): string))}: net_test.NetChecks)]. +net_test.NetChecks[(net_test.NetChecks{.description="ipv6_from_str(::ffff:192.10.2.255)", .value=("" ++ (net.ipv6.ipv6Addr2string((std.unwrap_or(net.ipv6.ipv6_from_str("::ffff:192.10.2.255"), net.ipv6.iPV6_UNSPECIFIED()): net.ipv6.Ipv6Addr)): string))}: net_test.NetChecks)]. +net_test.NetChecks[(net_test.NetChecks{.description="ipv6_from_str(::175.16.1.2)", .value=("" ++ (net.ipv6.ipv6Addr2string((std.unwrap_or(net.ipv6.ipv6_from_str("::175.16.1.2"), net.ipv6.iPV6_UNSPECIFIED()): net.ipv6.Ipv6Addr)): string))}: net_test.NetChecks)]. +net_test.NetChecks[(net_test.NetChecks{.description="ipv6_from_str(ffff:192.10.2.255)", .value=("" ++ (net.ipv6.ipv6Addr2string((std.unwrap_or(net.ipv6.ipv6_from_str("ffff:192.10.2.255"), net.ipv6.iPV6_UNSPECIFIED()): net.ipv6.Ipv6Addr)): string))}: net_test.NetChecks)]. +net_test.NetChecks[(net_test.NetChecks{.description="ipv6_from_str(::)", .value=("" ++ (net.ipv6.ipv6Addr2string((std.unwrap_or(net.ipv6.ipv6_from_str("::"), net.ipv6.iPV6_LOCALHOST()): net.ipv6.Ipv6Addr)): string))}: net_test.NetChecks)]. +net_test.NetChecks[(net_test.NetChecks{.description="ipv6_to_u128(ipv6_from_str(::ffff:192.10.2.255))", .value=("" ++ std.hex(net.ipv6.ipv6_to_u128((std.unwrap_or(net.ipv6.ipv6_from_str("::ffff:192.10.2.255"), net.ipv6.iPV6_UNSPECIFIED()): net.ipv6.Ipv6Addr))))}: net_test.NetChecks)]. +net_test.NetChecks[(net_test.NetChecks{.description="ipv6_segments(ipv6_from_str(::ffff:192.10.2.255))", .value=(((var a: bit<16>), (var b: bit<16>), (var c: bit<16>), (var d: bit<16>), (var e: bit<16>), (var f: bit<16>), (var g: bit<16>), (var h: bit<16>)) = net.ipv6.ipv6_segments((std.unwrap_or(net.ipv6.ipv6_from_str("::ffff:192.10.2.255"), net.ipv6.iPV6_UNSPECIFIED()): net.ipv6.Ipv6Addr)); (((((((((((((((("(" ++ (std.__builtin_2string(a): string)) ++ ",") ++ (std.__builtin_2string(b): string)) ++ ",") ++ (std.__builtin_2string(c): string)) ++ ",") ++ (std.__builtin_2string(d): string)) ++ ",") ++ (std.__builtin_2string(e): string)) ++ ",") ++ (std.__builtin_2string(f): string)) ++ ",") ++ (std.__builtin_2string(g): string)) ++ ",") ++ (std.__builtin_2string(h): string)) ++ ")"))}: net_test.NetChecks)]. -net_test.NetChecks[(net_test.NetChecks{.description="ipv6_octets(ipv6_from_str(::ffff:192.10.2.255))", .value=(((var a: bit<8>), (var b: bit<8>), (var c: bit<8>), (var d: bit<8>), (var e: bit<8>), (var f: bit<8>), (var g: bit<8>), (var h: bit<8>), (var i: bit<8>), (var j: bit<8>), (var k: bit<8>), (var l: bit<8>), (var m: bit<8>), (var n: bit<8>), (var o: bit<8>), (var p: bit<8>)) = net.ipv6.ipv6_octets((std.result_unwrap_or(net.ipv6.ipv6_from_str("::ffff:192.10.2.255"), net.ipv6.iPV6_UNSPECIFIED()): net.ipv6.Ipv6Addr)); +net_test.NetChecks[(net_test.NetChecks{.description="ipv6_octets(ipv6_from_str(::ffff:192.10.2.255))", .value=(((var a: bit<8>), (var b: bit<8>), (var c: bit<8>), (var d: bit<8>), (var e: bit<8>), (var f: bit<8>), (var g: bit<8>), (var h: bit<8>), (var i: bit<8>), (var j: bit<8>), (var k: bit<8>), (var l: bit<8>), (var m: bit<8>), (var n: bit<8>), (var o: bit<8>), (var p: bit<8>)) = net.ipv6.ipv6_octets((std.unwrap_or(net.ipv6.ipv6_from_str("::ffff:192.10.2.255"), net.ipv6.iPV6_UNSPECIFIED()): net.ipv6.Ipv6Addr)); (((((((((((((((((((((((((((((((("(" ++ (std.__builtin_2string(a): string)) ++ ",") ++ (std.__builtin_2string(b): string)) ++ ",") ++ (std.__builtin_2string(c): string)) ++ ",") ++ (std.__builtin_2string(d): string)) ++ ",") ++ (std.__builtin_2string(e): string)) ++ ",") ++ (std.__builtin_2string(f): string)) ++ ",") ++ (std.__builtin_2string(g): string)) ++ ",") ++ (std.__builtin_2string(h): string)) ++ ",") ++ (std.__builtin_2string(i): string)) ++ ",") ++ (std.__builtin_2string(j): string)) ++ ",") ++ (std.__builtin_2string(k): string)) ++ ",") ++ (std.__builtin_2string(l): string)) ++ ",") ++ (std.__builtin_2string(m): string)) ++ ",") ++ (std.__builtin_2string(n): string)) ++ ",") ++ (std.__builtin_2string(o): string)) ++ ",") ++ (std.__builtin_2string(p): string)) ++ ")"))}: net_test.NetChecks)]. -net_test.NetChecks[(net_test.NetChecks{.description="ipv6_from_segment_vec(ipv6_segment_vec(ipv6_from_str(::ffff:192.10.2.255)))", .value=("" ++ (net.ipv6.ipv6Addr2string((std.option_unwrap_or(net.ipv6.ipv6_from_segment_vec(net.ipv6.ipv6_segment_vec((std.result_unwrap_or(net.ipv6.ipv6_from_str("::ffff:192.10.2.255"), net.ipv6.iPV6_UNSPECIFIED()): net.ipv6.Ipv6Addr))), net.ipv6.iPV6_UNSPECIFIED()): net.ipv6.Ipv6Addr)): string))}: net_test.NetChecks)]. -net_test.NetChecks[(net_test.NetChecks{.description="ipv6_from_octet_vec(ipv6_octet_vec(ipv6_from_str(::ffff:192.10.2.255)))", .value=("" ++ (net.ipv6.ipv6Addr2string((std.option_unwrap_or(net.ipv6.ipv6_from_octet_vec(net.ipv6.ipv6_octet_vec((std.result_unwrap_or(net.ipv6.ipv6_from_str("::ffff:192.10.2.255"), net.ipv6.iPV6_UNSPECIFIED()): net.ipv6.Ipv6Addr))), net.ipv6.iPV6_UNSPECIFIED()): net.ipv6.Ipv6Addr)): string))}: net_test.NetChecks)]. +net_test.NetChecks[(net_test.NetChecks{.description="ipv6_from_segment_vec(ipv6_segment_vec(ipv6_from_str(::ffff:192.10.2.255)))", .value=("" ++ (net.ipv6.ipv6Addr2string((std.unwrap_or(net.ipv6.ipv6_from_segment_vec(net.ipv6.ipv6_segment_vec((std.unwrap_or(net.ipv6.ipv6_from_str("::ffff:192.10.2.255"), net.ipv6.iPV6_UNSPECIFIED()): net.ipv6.Ipv6Addr))), net.ipv6.iPV6_UNSPECIFIED()): net.ipv6.Ipv6Addr)): string))}: net_test.NetChecks)]. +net_test.NetChecks[(net_test.NetChecks{.description="ipv6_from_octet_vec(ipv6_octet_vec(ipv6_from_str(::ffff:192.10.2.255)))", .value=("" ++ (net.ipv6.ipv6Addr2string((std.unwrap_or(net.ipv6.ipv6_from_octet_vec(net.ipv6.ipv6_octet_vec((std.unwrap_or(net.ipv6.ipv6_from_str("::ffff:192.10.2.255"), net.ipv6.iPV6_UNSPECIFIED()): net.ipv6.Ipv6Addr))), net.ipv6.iPV6_UNSPECIFIED()): net.ipv6.Ipv6Addr)): string))}: net_test.NetChecks)]. net_test.NetChecks[(net_test.NetChecks{.description="ipv6_is_unspecified(iPV6_UNSPECIFIED())", .value=("" ++ (std.__builtin_2string(net.ipv6.ipv6_is_unspecified(net.ipv6.iPV6_UNSPECIFIED())): string))}: net_test.NetChecks)]. net_test.NetChecks[(net_test.NetChecks{.description="ipv6_is_unspecified(ipv6_new(0, 0, 0, 0, 0, 'hffff, 'hc00a, 'h2ff))", .value=("" ++ (std.__builtin_2string(net.ipv6.ipv6_is_unspecified(net.ipv6.ipv6_new(16'd0, 16'd0, 16'd0, 16'd0, 16'd0, 16'd65535, 16'd49162, 16'd767))): string))}: net_test.NetChecks)]. net_test.NetChecks[(net_test.NetChecks{.description="ipv6_is_loopback(iPV6_LOCALHOST())", .value=("" ++ (std.__builtin_2string(net.ipv6.ipv6_is_loopback(net.ipv6.iPV6_LOCALHOST())): string))}: net_test.NetChecks)]. net_test.NetChecks[(net_test.NetChecks{.description="ipv6_is_loopback(ipv6_new(0, 0, 0, 0, 0, 'hffff, 'hc00a, 'h2ff))", .value=("" ++ (std.__builtin_2string(net.ipv6.ipv6_is_loopback(net.ipv6.ipv6_new(16'd0, 16'd0, 16'd0, 16'd0, 16'd0, 16'd65535, 16'd49162, 16'd767))): string))}: net_test.NetChecks)]. net_test.NetChecks[(net_test.NetChecks{.description="ipv6_is_multicast(ipv6_new('hff01, 0, 0, 0, 0, 'hffff, 'hc00a, 'h2ff))", .value=("" ++ (std.__builtin_2string(net.ipv6.ipv6_is_multicast(net.ipv6.ipv6_new(16'd65281, 16'd0, 16'd0, 16'd0, 16'd0, 16'd65535, 16'd49162, 16'd767))): string))}: net_test.NetChecks)]. net_test.NetChecks[(net_test.NetChecks{.description="ipv6_is_multicast(ipv6_new(0, 0, 0, 0, 0, 'hffff, 'hc00a, 'h2ff))", .value=("" ++ (std.__builtin_2string(net.ipv6.ipv6_is_multicast(net.ipv6.ipv6_new(16'd0, 16'd0, 16'd0, 16'd0, 16'd0, 16'd65535, 16'd49162, 16'd767))): string))}: net_test.NetChecks)]. -net_test.NetChecks[(net_test.NetChecks{.description="ipv6_to_ipv4(ipv4_to_ipv6_compatible(ipv4_new(192,0,2,10)))", .value=("" ++ (net.ipv4.ipv4Addr2string((std.option_unwrap_or(net.ipv6.ipv6_to_ipv4(net.ipv4.ipv4_to_ipv6_compatible(net.ipv4.ipv4_new(8'd192, 8'd0, 8'd2, 8'd10))), net.ipv4.iPV4_UNSPECIFIED()): net.ipv4.Ipv4Addr)): string))}: net_test.NetChecks)]. -net_test.NetChecks[(net_test.NetChecks{.description="ipv6_to_ipv4(ipv4_to_ipv6_compatible(ipv4_new(198,51,100,5)))", .value=("" ++ (net.ipv4.ipv4Addr2string((std.option_unwrap_or(net.ipv6.ipv6_to_ipv4(net.ipv4.ipv4_to_ipv6_compatible(net.ipv4.ipv4_new(8'd198, 8'd51, 8'd100, 8'd5))), net.ipv4.iPV4_UNSPECIFIED()): net.ipv4.Ipv4Addr)): string))}: net_test.NetChecks)]. -net_test.NetChecks[(net_test.NetChecks{.description="ipv6_to_ipv4(ipv4_to_ipv6_compatible(ipv4_new(203,0,113,101)))", .value=("" ++ (net.ipv4.ipv4Addr2string((std.option_unwrap_or(net.ipv6.ipv6_to_ipv4(net.ipv4.ipv4_to_ipv6_compatible(net.ipv4.ipv4_new(8'd203, 8'd0, 8'd113, 8'd101))), net.ipv4.iPV4_UNSPECIFIED()): net.ipv4.Ipv4Addr)): string))}: net_test.NetChecks)]. -net_test.NetChecks[(net_test.NetChecks{.description="ipv6_to_ipv4(ipv4_to_ipv6_compatible(ipv4_new(175,16,1,2)))", .value=("" ++ (net.ipv4.ipv4Addr2string((std.option_unwrap_or(net.ipv6.ipv6_to_ipv4(net.ipv4.ipv4_to_ipv6_compatible(net.ipv4.ipv4_new(8'd175, 8'd16, 8'd1, 8'd2))), net.ipv4.iPV4_UNSPECIFIED()): net.ipv4.Ipv4Addr)): string))}: net_test.NetChecks)]. -net_test.NetChecks[(net_test.NetChecks{.description="ipv6_to_ipv4(ipv4_to_ipv6_compatible(ipv4_new(192,168,10,12)))", .value=("" ++ (net.ipv4.ipv4Addr2string((std.option_unwrap_or(net.ipv6.ipv6_to_ipv4(net.ipv4.ipv4_to_ipv6_compatible(net.ipv4.ipv4_new(8'd192, 8'd168, 8'd10, 8'd12))), net.ipv4.iPV4_UNSPECIFIED()): net.ipv4.Ipv4Addr)): string))}: net_test.NetChecks)]. -net_test.NetChecks[(net_test.NetChecks{.description="ipv6_to_ipv4(ipv4_to_ipv6_mapped(ipv4_new(192,0,2,10)))", .value=("" ++ (net.ipv4.ipv4Addr2string((std.option_unwrap_or(net.ipv6.ipv6_to_ipv4(net.ipv4.ipv4_to_ipv6_mapped(net.ipv4.ipv4_new(8'd192, 8'd0, 8'd2, 8'd10))), net.ipv4.iPV4_UNSPECIFIED()): net.ipv4.Ipv4Addr)): string))}: net_test.NetChecks)]. -net_test.NetChecks[(net_test.NetChecks{.description="ipv6_to_ipv4(ipv4_to_ipv6_mapped(ipv4_new(198,51,100,5)))", .value=("" ++ (net.ipv4.ipv4Addr2string((std.option_unwrap_or(net.ipv6.ipv6_to_ipv4(net.ipv4.ipv4_to_ipv6_mapped(net.ipv4.ipv4_new(8'd198, 8'd51, 8'd100, 8'd5))), net.ipv4.iPV4_UNSPECIFIED()): net.ipv4.Ipv4Addr)): string))}: net_test.NetChecks)]. -net_test.NetChecks[(net_test.NetChecks{.description="ipv6_to_ipv4(ipv4_to_ipv6_mapped(ipv4_new(203,0,113,101)))", .value=("" ++ (net.ipv4.ipv4Addr2string((std.option_unwrap_or(net.ipv6.ipv6_to_ipv4(net.ipv4.ipv4_to_ipv6_mapped(net.ipv4.ipv4_new(8'd203, 8'd0, 8'd113, 8'd101))), net.ipv4.iPV4_UNSPECIFIED()): net.ipv4.Ipv4Addr)): string))}: net_test.NetChecks)]. -net_test.NetChecks[(net_test.NetChecks{.description="ipv6_to_ipv4(ipv4_to_ipv6_mapped(ipv4_new(175,16,1,2)))", .value=("" ++ (net.ipv4.ipv4Addr2string((std.option_unwrap_or(net.ipv6.ipv6_to_ipv4(net.ipv4.ipv4_to_ipv6_mapped(net.ipv4.ipv4_new(8'd175, 8'd16, 8'd1, 8'd2))), net.ipv4.iPV4_UNSPECIFIED()): net.ipv4.Ipv4Addr)): string))}: net_test.NetChecks)]. -net_test.NetChecks[(net_test.NetChecks{.description="ipv6_to_ipv4(ipv4_to_ipv6_mapped(ipv4_new(192,168,10,12)))", .value=("" ++ (net.ipv4.ipv4Addr2string((std.option_unwrap_or(net.ipv6.ipv6_to_ipv4(net.ipv4.ipv4_to_ipv6_mapped(net.ipv4.ipv4_new(8'd192, 8'd168, 8'd10, 8'd12))), net.ipv4.iPV4_UNSPECIFIED()): net.ipv4.Ipv4Addr)): string))}: net_test.NetChecks)]. -net_test.NetChecks[(net_test.NetChecks{.description="ipv6_to_ipv4(ipv6_new(0, 0, 0, 0, 0, 'hffff, 'hc00a, 'h2ff)))", .value=("" ++ (net.ipv4.ipv4Addr2string((std.option_unwrap_or(net.ipv6.ipv6_to_ipv4(net.ipv6.ipv6_new(16'd0, 16'd0, 16'd0, 16'd0, 16'd0, 16'd65535, 16'd49162, 16'd767)), net.ipv4.iPV4_UNSPECIFIED()): net.ipv4.Ipv4Addr)): string))}: net_test.NetChecks)]. -net_test.NetChecks[(net_test.NetChecks{.description="ipv6_to_ipv4(ipv6_new('h0a0b, 0, 0, 0, 0, 'hffff, 'hc00a, 'h2ff)))", .value=("" ++ (net.ipv4.ipv4Addr2string((std.option_unwrap_or(net.ipv6.ipv6_to_ipv4(net.ipv6.ipv6_new(16'd2571, 16'd0, 16'd0, 16'd0, 16'd0, 16'd65535, 16'd49162, 16'd767)), net.ipv4.iPV4_UNSPECIFIED()): net.ipv4.Ipv4Addr)): string))}: net_test.NetChecks)]. +net_test.NetChecks[(net_test.NetChecks{.description="ipv6_to_ipv4(ipv4_to_ipv6_compatible(ipv4_new(192,0,2,10)))", .value=("" ++ (net.ipv4.ipv4Addr2string((std.unwrap_or(net.ipv6.ipv6_to_ipv4(net.ipv4.ipv4_to_ipv6_compatible(net.ipv4.ipv4_new(8'd192, 8'd0, 8'd2, 8'd10))), net.ipv4.iPV4_UNSPECIFIED()): net.ipv4.Ipv4Addr)): string))}: net_test.NetChecks)]. +net_test.NetChecks[(net_test.NetChecks{.description="ipv6_to_ipv4(ipv4_to_ipv6_compatible(ipv4_new(198,51,100,5)))", .value=("" ++ (net.ipv4.ipv4Addr2string((std.unwrap_or(net.ipv6.ipv6_to_ipv4(net.ipv4.ipv4_to_ipv6_compatible(net.ipv4.ipv4_new(8'd198, 8'd51, 8'd100, 8'd5))), net.ipv4.iPV4_UNSPECIFIED()): net.ipv4.Ipv4Addr)): string))}: net_test.NetChecks)]. +net_test.NetChecks[(net_test.NetChecks{.description="ipv6_to_ipv4(ipv4_to_ipv6_compatible(ipv4_new(203,0,113,101)))", .value=("" ++ (net.ipv4.ipv4Addr2string((std.unwrap_or(net.ipv6.ipv6_to_ipv4(net.ipv4.ipv4_to_ipv6_compatible(net.ipv4.ipv4_new(8'd203, 8'd0, 8'd113, 8'd101))), net.ipv4.iPV4_UNSPECIFIED()): net.ipv4.Ipv4Addr)): string))}: net_test.NetChecks)]. +net_test.NetChecks[(net_test.NetChecks{.description="ipv6_to_ipv4(ipv4_to_ipv6_compatible(ipv4_new(175,16,1,2)))", .value=("" ++ (net.ipv4.ipv4Addr2string((std.unwrap_or(net.ipv6.ipv6_to_ipv4(net.ipv4.ipv4_to_ipv6_compatible(net.ipv4.ipv4_new(8'd175, 8'd16, 8'd1, 8'd2))), net.ipv4.iPV4_UNSPECIFIED()): net.ipv4.Ipv4Addr)): string))}: net_test.NetChecks)]. +net_test.NetChecks[(net_test.NetChecks{.description="ipv6_to_ipv4(ipv4_to_ipv6_compatible(ipv4_new(192,168,10,12)))", .value=("" ++ (net.ipv4.ipv4Addr2string((std.unwrap_or(net.ipv6.ipv6_to_ipv4(net.ipv4.ipv4_to_ipv6_compatible(net.ipv4.ipv4_new(8'd192, 8'd168, 8'd10, 8'd12))), net.ipv4.iPV4_UNSPECIFIED()): net.ipv4.Ipv4Addr)): string))}: net_test.NetChecks)]. +net_test.NetChecks[(net_test.NetChecks{.description="ipv6_to_ipv4(ipv4_to_ipv6_mapped(ipv4_new(192,0,2,10)))", .value=("" ++ (net.ipv4.ipv4Addr2string((std.unwrap_or(net.ipv6.ipv6_to_ipv4(net.ipv4.ipv4_to_ipv6_mapped(net.ipv4.ipv4_new(8'd192, 8'd0, 8'd2, 8'd10))), net.ipv4.iPV4_UNSPECIFIED()): net.ipv4.Ipv4Addr)): string))}: net_test.NetChecks)]. +net_test.NetChecks[(net_test.NetChecks{.description="ipv6_to_ipv4(ipv4_to_ipv6_mapped(ipv4_new(198,51,100,5)))", .value=("" ++ (net.ipv4.ipv4Addr2string((std.unwrap_or(net.ipv6.ipv6_to_ipv4(net.ipv4.ipv4_to_ipv6_mapped(net.ipv4.ipv4_new(8'd198, 8'd51, 8'd100, 8'd5))), net.ipv4.iPV4_UNSPECIFIED()): net.ipv4.Ipv4Addr)): string))}: net_test.NetChecks)]. +net_test.NetChecks[(net_test.NetChecks{.description="ipv6_to_ipv4(ipv4_to_ipv6_mapped(ipv4_new(203,0,113,101)))", .value=("" ++ (net.ipv4.ipv4Addr2string((std.unwrap_or(net.ipv6.ipv6_to_ipv4(net.ipv4.ipv4_to_ipv6_mapped(net.ipv4.ipv4_new(8'd203, 8'd0, 8'd113, 8'd101))), net.ipv4.iPV4_UNSPECIFIED()): net.ipv4.Ipv4Addr)): string))}: net_test.NetChecks)]. +net_test.NetChecks[(net_test.NetChecks{.description="ipv6_to_ipv4(ipv4_to_ipv6_mapped(ipv4_new(175,16,1,2)))", .value=("" ++ (net.ipv4.ipv4Addr2string((std.unwrap_or(net.ipv6.ipv6_to_ipv4(net.ipv4.ipv4_to_ipv6_mapped(net.ipv4.ipv4_new(8'd175, 8'd16, 8'd1, 8'd2))), net.ipv4.iPV4_UNSPECIFIED()): net.ipv4.Ipv4Addr)): string))}: net_test.NetChecks)]. +net_test.NetChecks[(net_test.NetChecks{.description="ipv6_to_ipv4(ipv4_to_ipv6_mapped(ipv4_new(192,168,10,12)))", .value=("" ++ (net.ipv4.ipv4Addr2string((std.unwrap_or(net.ipv6.ipv6_to_ipv4(net.ipv4.ipv4_to_ipv6_mapped(net.ipv4.ipv4_new(8'd192, 8'd168, 8'd10, 8'd12))), net.ipv4.iPV4_UNSPECIFIED()): net.ipv4.Ipv4Addr)): string))}: net_test.NetChecks)]. +net_test.NetChecks[(net_test.NetChecks{.description="ipv6_to_ipv4(ipv6_new(0, 0, 0, 0, 0, 'hffff, 'hc00a, 'h2ff)))", .value=("" ++ (net.ipv4.ipv4Addr2string((std.unwrap_or(net.ipv6.ipv6_to_ipv4(net.ipv6.ipv6_new(16'd0, 16'd0, 16'd0, 16'd0, 16'd0, 16'd65535, 16'd49162, 16'd767)), net.ipv4.iPV4_UNSPECIFIED()): net.ipv4.Ipv4Addr)): string))}: net_test.NetChecks)]. +net_test.NetChecks[(net_test.NetChecks{.description="ipv6_to_ipv4(ipv6_new('h0a0b, 0, 0, 0, 0, 'hffff, 'hc00a, 'h2ff)))", .value=("" ++ (net.ipv4.ipv4Addr2string((std.unwrap_or(net.ipv6.ipv6_to_ipv4(net.ipv6.ipv6_new(16'd2571, 16'd0, 16'd0, 16'd0, 16'd0, 16'd65535, 16'd49162, 16'd767)), net.ipv4.iPV4_UNSPECIFIED()): net.ipv4.Ipv4Addr)): string))}: net_test.NetChecks)]. net_test.NetChecks[(net_test.NetChecks{.description="ipaddr_from_ipv4addr(ipv4_new(192, 168, 0, 1))", .value=("" ++ (net.ipaddr.ipAddr2string(net.ipaddr.ipaddr_from_ipv4addr(net.ipv4.ipv4_new(8'd192, 8'd168, 8'd0, 8'd1))): string))}: net_test.NetChecks)]. net_test.NetChecks[(net_test.NetChecks{.description="ipaddr_from_ipv6addr(ipv6_new(0, 0, 0, 0, 0, 'hffff, 'hc00a, 'h2ff))", .value=("" ++ (net.ipaddr.ipAddr2string(net.ipaddr.ipaddr_from_ipv6addr(net.ipv6.ipv6_new(16'd0, 16'd0, 16'd0, 16'd0, 16'd0, 16'd65535, 16'd49162, 16'd767))): string))}: net_test.NetChecks)]. net_test.NetChecks[(net_test.NetChecks{.description="ipaddr_is_ipv4(ipaddr_from_ipv4addr(ipv4_new(192, 168, 0, 1)))", .value=("" ++ (std.__builtin_2string(net.ipaddr.ipaddr_is_ipv4(net.ipaddr.ipaddr_from_ipv4addr(net.ipv4.ipv4_new(8'd192, 8'd168, 8'd0, 8'd1)))): string))}: net_test.NetChecks)]. @@ -1040,7 +1312,7 @@ regex_test.RegexTestInput[(regex_test.RegexTestInput{.regex="\\d+", .text="a111b regex_test.RegexTestInput[(regex_test.RegexTestInput{.regex="\\b\\w{13}\\b", .text="I categorically deny having triskaidekaphobia."}: regex_test.RegexTestInput)]. regex_test.RegexTestInput[(regex_test.RegexTestInput{.regex="'([^']+)'\\s+\\((\\d{4})\\)", .text="Not my favorite movie: 'Citizen Kane' (1941)."}: regex_test.RegexTestInput)]. regex_test.RegexTestInput[(regex_test.RegexTestInput{.regex="[", .text="foo"}: regex_test.RegexTestInput)]. -regex_test.RegexTestOutput[(regex_test.RegexTestOutput{.regex=regex, .text=text, .match_found=regex.regex_match(regex.regex(regex), text), .match_found_checked=regex.regex_match((std.result_unwrap_or(regex.regex_checked(regex), regex.regex("")): regex.Regex), text), .first_match=regex.regex_first_match(regex.regex(regex), text), .all_matches=regex.regex_all_matches(regex.regex(regex), text)}: regex_test.RegexTestOutput)] :- regex_test.RegexTestInput[(__regex_test_regextestinput0@ (regex_test.RegexTestInput{.regex=(regex: string), .text=(text: string)}: regex_test.RegexTestInput))], Inspect debug.debug_event((32'd270, 32'd0, 32'd0), ddlog_weight, ddlog_timestamp, "Map", __regex_test_regextestinput0, (regex_test.RegexTestOutput{.regex=regex, .text=text, .match_found=regex.regex_match(regex.regex(regex), text), .match_found_checked=regex.regex_match((std.result_unwrap_or(regex.regex_checked(regex), regex.regex("")): regex.Regex), text), .first_match=regex.regex_first_match(regex.regex(regex), text), .all_matches=regex.regex_all_matches(regex.regex(regex), text)}: regex_test.RegexTestOutput)). +regex_test.RegexTestOutput[(regex_test.RegexTestOutput{.regex=regex, .text=text, .match_found=regex.regex_match(regex.regex(regex), text), .match_found_checked=regex.regex_match((std.unwrap_or(regex.regex_checked(regex), regex.regex("")): regex.Regex), text), .first_match=regex.regex_first_match(regex.regex(regex), text), .all_matches=regex.regex_all_matches(regex.regex(regex), text)}: regex_test.RegexTestOutput)] :- regex_test.RegexTestInput[(__regex_test_regextestinput0@ (regex_test.RegexTestInput{.regex=(regex: string), .text=(text: string)}: regex_test.RegexTestInput))], Inspect debug.debug_event((32'd270, 32'd0, 32'd0), ddlog_weight, ddlog_timestamp, "Map", __regex_test_regextestinput0, (regex_test.RegexTestOutput{.regex=regex, .text=text, .match_found=regex.regex_match(regex.regex(regex), text), .match_found_checked=regex.regex_match((std.unwrap_or(regex.regex_checked(regex), regex.regex("")): regex.Regex), text), .first_match=regex.regex_first_match(regex.regex(regex), text), .all_matches=regex.regex_all_matches(regex.regex(regex), text)}: regex_test.RegexTestOutput)). internment_test.StaticInternedString[(internment_test.StaticInternedString{.ix=(internment.intern("static foo"): internment.Intern)}: internment_test.StaticInternedString)]. internment_test.StaticInternedString[(internment_test.StaticInternedString{.ix=(internment.intern("ifoo"): internment.Intern)}: internment_test.StaticInternedString)]. internment_test.StaticInternedString[(internment_test.StaticInternedString{.ix=(internment.intern("ibar"): internment.Intern)}: internment_test.StaticInternedString)]. @@ -1057,7 +1329,7 @@ internment_test.Projections[(internment_test.Projections{.inp=internment_test.is internment_test.Projections[(internment_test.Projections{.inp=internment_test.istruct2struct((internment.ival(i): internment_test.IStruct)), .p=("f1=" ++ (std.__builtin_2string(f1): string))}: internment_test.Projections)] :- internment_test.IStruct[(i@ ((&(internment_test.IStruct{.u=((&(internment_test.Tag1{.f1=(f1: bool)}: internment_test.IUnion)): internment.Intern), .t=(_: internment.Intern<(signed<32>, double)>), .x=(_: bigint)}: internment_test.IStruct)): internment.Intern))], Inspect debug.debug_event((32'd284, 32'd0, 32'd0), ddlog_weight, ddlog_timestamp, "Map", i, (internment_test.Projections{.inp=internment_test.istruct2struct((internment.ival(i): internment_test.IStruct)), .p=("f1=" ++ (std.__builtin_2string(f1): string))}: internment_test.Projections)). internment_test.Projections[(internment_test.Projections{.inp=internment_test.istruct2struct((internment.ival(i): internment_test.IStruct)), .p=("f2=" ++ (std.__builtin_2string(f2): string))}: internment_test.Projections)] :- internment_test.IStruct[(i@ ((&(internment_test.IStruct{.u=((&(t@ (internment_test.Tag2{.f2=(f2: bit<32>), .f3=(_: string)}: internment_test.IUnion))): internment.Intern), .t=(_: internment.Intern<(signed<32>, double)>), .x=(_: bigint)}: internment_test.IStruct)): internment.Intern))], Inspect debug.debug_event((32'd285, 32'd0, 32'd0), ddlog_weight, ddlog_timestamp, "Map", i, (internment_test.Projections{.inp=internment_test.istruct2struct((internment.ival(i): internment_test.IStruct)), .p=("f2=" ++ (std.__builtin_2string(f2): string))}: internment_test.Projections)). internment_test.Projections[(internment_test.Projections{.inp=internment_test.istruct2struct((internment.ival(i): internment_test.IStruct)), .p=("f3=" ++ f3)}: internment_test.Projections)] :- internment_test.IStruct[(i@ ((&(internment_test.IStruct{.u=(t@ ((&(internment_test.Tag2{.f2=(_: bit<32>), .f3=(f3: string)}: internment_test.IUnion)): internment.Intern)), .t=(_: internment.Intern<(signed<32>, double)>), .x=(_: bigint)}: internment_test.IStruct)): internment.Intern))], Inspect debug.debug_event((32'd286, 32'd0, 32'd0), ddlog_weight, ddlog_timestamp, "Map", i, (internment_test.Projections{.inp=internment_test.istruct2struct((internment.ival(i): internment_test.IStruct)), .p=("f3=" ++ f3)}: internment_test.Projections)). -tinyset_test.Sets[(tinyset_test.Sets{.setid=setid, .set=set}: tinyset_test.Sets)] :- tinyset_test.SetElement[(__tinyset_test_setelement0@ (tinyset_test.SetElement{.setid=(setid: string), .element=(v: bit<32>)}: tinyset_test.SetElement))], var __inputs_set = Aggregate(setid, __debug_287_1_tinyset.group2set((__tinyset_test_setelement0, v))), Inspect debug.debug_event((32'd287, 32'd1, 32'd0), ddlog_weight, ddlog_timestamp, "Aggregate", __inputs_set.0, (__inputs_set, setid)), (var set: tinyset.Set64>) = __inputs_set.1, Inspect debug.debug_event((32'd287, 32'd2, 32'd0), ddlog_weight, ddlog_timestamp, "Condition", (__inputs_set, setid), (tinyset_test.Sets{.setid=setid, .set=set}: tinyset_test.Sets)). +tinyset_test.Sets[(tinyset_test.Sets{.setid=setid, .set=set}: tinyset_test.Sets)] :- tinyset_test.SetElement[(__tinyset_test_setelement0@ (tinyset_test.SetElement{.setid=(setid: string), .element=(v: bit<32>)}: tinyset_test.SetElement))], var __inputs_set = Aggregate(setid, __debug_287_1_tinyset.group_to_set((__tinyset_test_setelement0, v))), Inspect debug.debug_event((32'd287, 32'd1, 32'd0), ddlog_weight, ddlog_timestamp, "Aggregate", __inputs_set.0, (__inputs_set, setid)), (var set: tinyset.Set64>) = __inputs_set.1, Inspect debug.debug_event((32'd287, 32'd2, 32'd0), ddlog_weight, ddlog_timestamp, "Condition", (__inputs_set, setid), (tinyset_test.Sets{.setid=setid, .set=set}: tinyset_test.Sets)). tinyset_test.Intersects[(tinyset_test.Intersects{.setid1=setid1, .setid2=setid2, .set=set}: tinyset_test.Intersects)] :- tinyset_test.Sets[(__tinyset_test_sets0@ (tinyset_test.Sets{.setid=(setid1: string), .set=(set1: tinyset.Set64>)}: tinyset_test.Sets))], tinyset_test.Sets[(__tinyset_test_sets1@ (tinyset_test.Sets{.setid=(setid2: string), .set=(set2: tinyset.Set64>)}: tinyset_test.Sets))], Inspect debug.debug_event_join((32'd288, 32'd1, 32'd0), ddlog_weight, ddlog_timestamp, __tinyset_test_sets0, __tinyset_test_sets1, (setid1, set1, setid2, set2)), (var set: tinyset.Set64>) = ((var set: tinyset.Set64) = (tinyset.empty(): tinyset.Set64>); (for (x in set1) { if tinyset.contains(set2, x) { diff --git a/test/datalog_tests/net_test.dl b/test/datalog_tests/net_test.dl index 08592a251..da015366a 100644 --- a/test/datalog_tests/net_test.dl +++ b/test/datalog_tests/net_test.dl @@ -6,10 +6,10 @@ output relation NetChecks(description: string, value: string) NetChecks("ipv4_new(192, 168, 0, 1)", "${ipv4_new(192, 168, 0, 1)}"). NetChecks("ipv4_from_u32('h0a0b0c0d)", "${ipv4_from_u32('h0a0b0c0d)}"). -NetChecks("ipv4_from_str(10.10.10.101)", "${result_unwrap_or(ipv4_from_str(\"10.10.10.101\"), iPV4_UNSPECIFIED())}"). -NetChecks("ipv4_from_str(10.10.10.10.1)", "${result_unwrap_or(ipv4_from_str(\"10.10.10.10.1\"), iPV4_UNSPECIFIED())}"). +NetChecks("ipv4_from_str(10.10.10.101)", "${unwrap_or(ipv4_from_str(\"10.10.10.101\"), iPV4_UNSPECIFIED())}"). +NetChecks("ipv4_from_str(10.10.10.10.1)", "${unwrap_or(ipv4_from_str(\"10.10.10.10.1\"), iPV4_UNSPECIFIED())}"). NetChecks("ipv4_from_octet_vec(ipv4_octet_vec(ipv4_new(192, 168, 0, 1)))", - "${option_unwrap_or(ipv4_from_octet_vec(ipv4_octet_vec(ipv4_new(192, 168, 0, 1))), iPV4_UNSPECIFIED())}"). + "${unwrap_or(ipv4_from_octet_vec(ipv4_octet_vec(ipv4_new(192, 168, 0, 1))), iPV4_UNSPECIFIED())}"). NetChecks("iPV4_LOCALHOST()", "${iPV4_LOCALHOST()}"). NetChecks("iPV4_UNSPECIFIED()", "${iPV4_UNSPECIFIED()}"). NetChecks("iPV4_BROADCAST()", "${iPV4_BROADCAST()}"). @@ -69,40 +69,40 @@ NetChecks("iPV6_LOCALHOST()", "${iPV6_LOCALHOST()}"). NetChecks("iPV6_UNSPECIFIED()", "${iPV6_UNSPECIFIED()}"). NetChecks("ipv6_from_segment_vec(ipv6_segment_vec(ipv6_new(0, 0, 0, 0, 0, 'hffff, 'hc00a, 'h2ff)))", - "${option_unwrap_or(ipv6_from_segment_vec(ipv6_segment_vec(ipv6_new(0, 0, 0, 0, 0, 'hffff, 'hc00a, 'h2ff))), iPV6_UNSPECIFIED())}"). + "${unwrap_or(ipv6_from_segment_vec(ipv6_segment_vec(ipv6_new(0, 0, 0, 0, 0, 'hffff, 'hc00a, 'h2ff))), iPV6_UNSPECIFIED())}"). NetChecks("ipv6_from_segment_vec(ipv6_segment_vec(ipv6_new(0, 0, 0, 0, 0, 'hffff, 'hc00a, 'h2ff, 'h10)))", - "${option_unwrap_or(ipv6_from_segment_vec(vec_push_imm(ipv6_segment_vec(ipv6_new(0, 0, 0, 0, 0, 'hffff, 'hc00a, 'h2ff)), 16'h10)), iPV6_UNSPECIFIED())}"). + "${unwrap_or(ipv6_from_segment_vec(vec_push_imm(ipv6_segment_vec(ipv6_new(0, 0, 0, 0, 0, 'hffff, 'hc00a, 'h2ff)), 16'h10)), iPV6_UNSPECIFIED())}"). NetChecks("ipv6_from_octets(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'hff, 'hff, 'hc0, 'h0a, 'h2, 'hff)", "${ipv6_from_octets(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'hff, 'hff, 'hc0, 'h0a, 'h2, 'hff)}"). NetChecks("ipv6_from_octet_vec(ipv6_octet_vec(ipv6_new(0, 0, 0, 0, 0, 'hffff, 'hc00a, 'h2ff)))", - "${option_unwrap_or(ipv6_from_octet_vec(ipv6_octet_vec(ipv6_new(0, 0, 0, 0, 0, 'hffff, 'hc00a, 'h2ff))), iPV6_UNSPECIFIED())}"). + "${unwrap_or(ipv6_from_octet_vec(ipv6_octet_vec(ipv6_new(0, 0, 0, 0, 0, 'hffff, 'hc00a, 'h2ff))), iPV6_UNSPECIFIED())}"). NetChecks("ipv6_from_u128(128'h102030405060708090A0B0C0D0E0F00)", "${ipv6_from_u128(128'h102030405060708090A0B0C0D0E0F00)}"). -NetChecks("ipv6_from_str(102:304:506:708:90a:b0c:d0e:f00)", "${result_unwrap_or(ipv6_from_str(\"102:304:506:708:90a:b0c:d0e:f00\"), iPV6_UNSPECIFIED())}"). -NetChecks("ipv6_from_str(::ffff:192.10.2.255)", "${result_unwrap_or(ipv6_from_str(\"::ffff:192.10.2.255\"), iPV6_UNSPECIFIED())}"). -NetChecks("ipv6_from_str(::175.16.1.2)", "${result_unwrap_or(ipv6_from_str(\"::175.16.1.2\"), iPV6_UNSPECIFIED())}"). -NetChecks("ipv6_from_str(ffff:192.10.2.255)", "${result_unwrap_or(ipv6_from_str(\"ffff:192.10.2.255\"), iPV6_UNSPECIFIED())}"). -NetChecks("ipv6_from_str(::)", "${result_unwrap_or(ipv6_from_str(\"::\"), iPV6_LOCALHOST())}"). +NetChecks("ipv6_from_str(102:304:506:708:90a:b0c:d0e:f00)", "${unwrap_or(ipv6_from_str(\"102:304:506:708:90a:b0c:d0e:f00\"), iPV6_UNSPECIFIED())}"). +NetChecks("ipv6_from_str(::ffff:192.10.2.255)", "${unwrap_or(ipv6_from_str(\"::ffff:192.10.2.255\"), iPV6_UNSPECIFIED())}"). +NetChecks("ipv6_from_str(::175.16.1.2)", "${unwrap_or(ipv6_from_str(\"::175.16.1.2\"), iPV6_UNSPECIFIED())}"). +NetChecks("ipv6_from_str(ffff:192.10.2.255)", "${unwrap_or(ipv6_from_str(\"ffff:192.10.2.255\"), iPV6_UNSPECIFIED())}"). +NetChecks("ipv6_from_str(::)", "${unwrap_or(ipv6_from_str(\"::\"), iPV6_LOCALHOST())}"). -NetChecks("ipv6_to_u128(ipv6_from_str(::ffff:192.10.2.255))", "${hex(ipv6_to_u128(result_unwrap_or(ipv6_from_str(\"::ffff:192.10.2.255\"), iPV6_UNSPECIFIED())))}"). +NetChecks("ipv6_to_u128(ipv6_from_str(::ffff:192.10.2.255))", "${hex(ipv6_to_u128(unwrap_or(ipv6_from_str(\"::ffff:192.10.2.255\"), iPV6_UNSPECIFIED())))}"). NetChecks("ipv6_segments(ipv6_from_str(::ffff:192.10.2.255))", { - (var a, var b, var c, var d, var e, var f, var g, var h) = ipv6_segments(result_unwrap_or(ipv6_from_str("::ffff:192.10.2.255"), iPV6_UNSPECIFIED())); + (var a, var b, var c, var d, var e, var f, var g, var h) = ipv6_segments(unwrap_or(ipv6_from_str("::ffff:192.10.2.255"), iPV6_UNSPECIFIED())); "(${a},${b},${c},${d},${e},${f},${g},${h})" }). NetChecks("ipv6_octets(ipv6_from_str(::ffff:192.10.2.255))", { - (var a, var b, var c, var d, var e, var f, var g, var h, var i, var j, var k, var l, var m, var n, var o, var p) = ipv6_octets(result_unwrap_or(ipv6_from_str("::ffff:192.10.2.255"), iPV6_UNSPECIFIED())); + (var a, var b, var c, var d, var e, var f, var g, var h, var i, var j, var k, var l, var m, var n, var o, var p) = ipv6_octets(unwrap_or(ipv6_from_str("::ffff:192.10.2.255"), iPV6_UNSPECIFIED())); "(${a},${b},${c},${d},${e},${f},${g},${h},${i},${j},${k},${l},${m},${n},${o},${p})" }). -NetChecks("ipv6_from_segment_vec(ipv6_segment_vec(ipv6_from_str(::ffff:192.10.2.255)))", "${option_unwrap_or(ipv6_from_segment_vec(ipv6_segment_vec(result_unwrap_or(ipv6_from_str(\"::ffff:192.10.2.255\"), iPV6_UNSPECIFIED()))), iPV6_UNSPECIFIED())}"). +NetChecks("ipv6_from_segment_vec(ipv6_segment_vec(ipv6_from_str(::ffff:192.10.2.255)))", "${unwrap_or(ipv6_from_segment_vec(ipv6_segment_vec(unwrap_or(ipv6_from_str(\"::ffff:192.10.2.255\"), iPV6_UNSPECIFIED()))), iPV6_UNSPECIFIED())}"). -NetChecks("ipv6_from_octet_vec(ipv6_octet_vec(ipv6_from_str(::ffff:192.10.2.255)))", "${option_unwrap_or(ipv6_from_octet_vec(ipv6_octet_vec(result_unwrap_or(ipv6_from_str(\"::ffff:192.10.2.255\"), iPV6_UNSPECIFIED()))), iPV6_UNSPECIFIED())}"). +NetChecks("ipv6_from_octet_vec(ipv6_octet_vec(ipv6_from_str(::ffff:192.10.2.255)))", "${unwrap_or(ipv6_from_octet_vec(ipv6_octet_vec(unwrap_or(ipv6_from_str(\"::ffff:192.10.2.255\"), iPV6_UNSPECIFIED()))), iPV6_UNSPECIFIED())}"). NetChecks("ipv6_is_unspecified(iPV6_UNSPECIFIED())", "${ipv6_is_unspecified(iPV6_UNSPECIFIED())}"). NetChecks("ipv6_is_unspecified(ipv6_new(0, 0, 0, 0, 0, 'hffff, 'hc00a, 'h2ff))", "${ipv6_is_unspecified(ipv6_new(0, 0, 0, 0, 0, 'hffff, 'hc00a, 'h2ff))}"). @@ -113,18 +113,18 @@ NetChecks("ipv6_is_loopback(ipv6_new(0, 0, 0, 0, 0, 'hffff, 'hc00a, 'h2ff))", "$ NetChecks("ipv6_is_multicast(ipv6_new('hff01, 0, 0, 0, 0, 'hffff, 'hc00a, 'h2ff))", "${ipv6_is_multicast(ipv6_new('hff01, 0, 0, 0, 0, 'hffff, 'hc00a, 'h2ff))}"). NetChecks("ipv6_is_multicast(ipv6_new(0, 0, 0, 0, 0, 'hffff, 'hc00a, 'h2ff))", "${ipv6_is_multicast(ipv6_new(0, 0, 0, 0, 0, 'hffff, 'hc00a, 'h2ff))}"). -NetChecks("ipv6_to_ipv4(ipv4_to_ipv6_compatible(ipv4_new(192,0,2,10)))", "${option_unwrap_or(ipv6_to_ipv4(ipv4_to_ipv6_compatible(ipv4_new(192,0,2,10))), iPV4_UNSPECIFIED())}"). -NetChecks("ipv6_to_ipv4(ipv4_to_ipv6_compatible(ipv4_new(198,51,100,5)))", "${option_unwrap_or(ipv6_to_ipv4(ipv4_to_ipv6_compatible(ipv4_new(198,51,100,5))), iPV4_UNSPECIFIED())}"). -NetChecks("ipv6_to_ipv4(ipv4_to_ipv6_compatible(ipv4_new(203,0,113,101)))", "${option_unwrap_or(ipv6_to_ipv4(ipv4_to_ipv6_compatible(ipv4_new(203,0,113,101))), iPV4_UNSPECIFIED())}"). -NetChecks("ipv6_to_ipv4(ipv4_to_ipv6_compatible(ipv4_new(175,16,1,2)))", "${option_unwrap_or(ipv6_to_ipv4(ipv4_to_ipv6_compatible(ipv4_new(175,16,1,2))), iPV4_UNSPECIFIED())}"). -NetChecks("ipv6_to_ipv4(ipv4_to_ipv6_compatible(ipv4_new(192,168,10,12)))", "${option_unwrap_or(ipv6_to_ipv4(ipv4_to_ipv6_compatible(ipv4_new(192,168,10,12))), iPV4_UNSPECIFIED())}"). -NetChecks("ipv6_to_ipv4(ipv4_to_ipv6_mapped(ipv4_new(192,0,2,10)))", "${option_unwrap_or(ipv6_to_ipv4(ipv4_to_ipv6_mapped(ipv4_new(192,0,2,10))), iPV4_UNSPECIFIED())}"). -NetChecks("ipv6_to_ipv4(ipv4_to_ipv6_mapped(ipv4_new(198,51,100,5)))", "${option_unwrap_or(ipv6_to_ipv4(ipv4_to_ipv6_mapped(ipv4_new(198,51,100,5))), iPV4_UNSPECIFIED())}"). -NetChecks("ipv6_to_ipv4(ipv4_to_ipv6_mapped(ipv4_new(203,0,113,101)))", "${option_unwrap_or(ipv6_to_ipv4(ipv4_to_ipv6_mapped(ipv4_new(203,0,113,101))), iPV4_UNSPECIFIED())}"). -NetChecks("ipv6_to_ipv4(ipv4_to_ipv6_mapped(ipv4_new(175,16,1,2)))", "${option_unwrap_or(ipv6_to_ipv4(ipv4_to_ipv6_mapped(ipv4_new(175,16,1,2))), iPV4_UNSPECIFIED())}"). -NetChecks("ipv6_to_ipv4(ipv4_to_ipv6_mapped(ipv4_new(192,168,10,12)))", "${option_unwrap_or(ipv6_to_ipv4(ipv4_to_ipv6_mapped(ipv4_new(192,168,10,12))), iPV4_UNSPECIFIED())}"). -NetChecks("ipv6_to_ipv4(ipv6_new(0, 0, 0, 0, 0, 'hffff, 'hc00a, 'h2ff)))", "${option_unwrap_or(ipv6_to_ipv4(ipv6_new(0, 0, 0, 0, 0, 'hffff, 'hc00a, 'h2ff)), iPV4_UNSPECIFIED())}"). -NetChecks("ipv6_to_ipv4(ipv6_new('h0a0b, 0, 0, 0, 0, 'hffff, 'hc00a, 'h2ff)))", "${option_unwrap_or(ipv6_to_ipv4(ipv6_new('h0a0b, 0, 0, 0, 0, 'hffff, 'hc00a, 'h2ff)), iPV4_UNSPECIFIED())}"). +NetChecks("ipv6_to_ipv4(ipv4_to_ipv6_compatible(ipv4_new(192,0,2,10)))", "${unwrap_or(ipv6_to_ipv4(ipv4_to_ipv6_compatible(ipv4_new(192,0,2,10))), iPV4_UNSPECIFIED())}"). +NetChecks("ipv6_to_ipv4(ipv4_to_ipv6_compatible(ipv4_new(198,51,100,5)))", "${unwrap_or(ipv6_to_ipv4(ipv4_to_ipv6_compatible(ipv4_new(198,51,100,5))), iPV4_UNSPECIFIED())}"). +NetChecks("ipv6_to_ipv4(ipv4_to_ipv6_compatible(ipv4_new(203,0,113,101)))", "${unwrap_or(ipv6_to_ipv4(ipv4_to_ipv6_compatible(ipv4_new(203,0,113,101))), iPV4_UNSPECIFIED())}"). +NetChecks("ipv6_to_ipv4(ipv4_to_ipv6_compatible(ipv4_new(175,16,1,2)))", "${unwrap_or(ipv6_to_ipv4(ipv4_to_ipv6_compatible(ipv4_new(175,16,1,2))), iPV4_UNSPECIFIED())}"). +NetChecks("ipv6_to_ipv4(ipv4_to_ipv6_compatible(ipv4_new(192,168,10,12)))", "${unwrap_or(ipv6_to_ipv4(ipv4_to_ipv6_compatible(ipv4_new(192,168,10,12))), iPV4_UNSPECIFIED())}"). +NetChecks("ipv6_to_ipv4(ipv4_to_ipv6_mapped(ipv4_new(192,0,2,10)))", "${unwrap_or(ipv6_to_ipv4(ipv4_to_ipv6_mapped(ipv4_new(192,0,2,10))), iPV4_UNSPECIFIED())}"). +NetChecks("ipv6_to_ipv4(ipv4_to_ipv6_mapped(ipv4_new(198,51,100,5)))", "${unwrap_or(ipv6_to_ipv4(ipv4_to_ipv6_mapped(ipv4_new(198,51,100,5))), iPV4_UNSPECIFIED())}"). +NetChecks("ipv6_to_ipv4(ipv4_to_ipv6_mapped(ipv4_new(203,0,113,101)))", "${unwrap_or(ipv6_to_ipv4(ipv4_to_ipv6_mapped(ipv4_new(203,0,113,101))), iPV4_UNSPECIFIED())}"). +NetChecks("ipv6_to_ipv4(ipv4_to_ipv6_mapped(ipv4_new(175,16,1,2)))", "${unwrap_or(ipv6_to_ipv4(ipv4_to_ipv6_mapped(ipv4_new(175,16,1,2))), iPV4_UNSPECIFIED())}"). +NetChecks("ipv6_to_ipv4(ipv4_to_ipv6_mapped(ipv4_new(192,168,10,12)))", "${unwrap_or(ipv6_to_ipv4(ipv4_to_ipv6_mapped(ipv4_new(192,168,10,12))), iPV4_UNSPECIFIED())}"). +NetChecks("ipv6_to_ipv4(ipv6_new(0, 0, 0, 0, 0, 'hffff, 'hc00a, 'h2ff)))", "${unwrap_or(ipv6_to_ipv4(ipv6_new(0, 0, 0, 0, 0, 'hffff, 'hc00a, 'h2ff)), iPV4_UNSPECIFIED())}"). +NetChecks("ipv6_to_ipv4(ipv6_new('h0a0b, 0, 0, 0, 0, 'hffff, 'hc00a, 'h2ff)))", "${unwrap_or(ipv6_to_ipv4(ipv6_new('h0a0b, 0, 0, 0, 0, 'hffff, 'hc00a, 'h2ff)), iPV4_UNSPECIFIED())}"). NetChecks("ipaddr_from_ipv4addr(ipv4_new(192, 168, 0, 1))", "${ipaddr_from_ipv4addr(ipv4_new(192, 168, 0, 1))}"). diff --git a/test/datalog_tests/redist.dl b/test/datalog_tests/redist.dl index cf926d03e..d68052eb1 100644 --- a/test/datalog_tests/redist.dl +++ b/test/datalog_tests/redist.dl @@ -48,7 +48,7 @@ relation SCCBinding(scc: entid_t, bindings: Ref>) SCCBinding(scc, ref_new(bindings)) :- DdlogBinding(tn, entity), LabeledNode(entity, scc), - var bindings = Aggregate((scc), TS.group2set(tn)). + var bindings = Aggregate((scc), TS.group_to_set(tn)). /* Compute SCC span. */ diff --git a/test/datalog_tests/redist_opt.dl b/test/datalog_tests/redist_opt.dl index a318cfadb..0db89f427 100644 --- a/test/datalog_tests/redist_opt.dl +++ b/test/datalog_tests/redist_opt.dl @@ -85,7 +85,7 @@ relation SCCBinding(scc: entid_t, bindings: Ref>) SCCBinding(scc, ref_new(bindings)) :- DdlogBinding(tn, entity), LabeledNode(entity, scc), - var bindings = Aggregate((scc), TS.group2set(tn)). + var bindings = Aggregate((scc), TS.group_to_set(tn)). /* Compute SCC span. */ @@ -124,7 +124,7 @@ input relation EdgeTN(tn: tnid_t) relation EdgeTNs(tns: Ref>) EdgeTNs(ref_new(tns)) :- EdgeTN(tn), - var tns = Aggregate((), TS.group2set(tn)). + var tns = Aggregate((), TS.group_to_set(tn)). /* Objects that are part of a LRP{mcast=true} -> LSP -> LS chain. */ relation McastObject(mcast: entid_t) @@ -151,12 +151,12 @@ Tos(from, to) :- FromNode(from), ExtDdlogDependency(from, to). output relation FromsList(froms: Set, to: entid_t) FromsList(froms, to) :- Froms(from, to), - var froms = Aggregate((to), group2set(from)). + var froms = Aggregate((to), group_to_set(from)). output relation TosList(from: entid_t, tos: Set) TosList(from, tos) :- Tos(from, to), - var tos = Aggregate((from), group2set(to)). + var tos = Aggregate((from), group_to_set(to)). /* getSpan() */ input relation QuerySpanNode(entity: entid_t) diff --git a/test/datalog_tests/regex_test.dl b/test/datalog_tests/regex_test.dl index 95439e190..4be60cf48 100644 --- a/test/datalog_tests/regex_test.dl +++ b/test/datalog_tests/regex_test.dl @@ -21,7 +21,7 @@ output relation RegexTestOutput( RegexTestOutput(regex, text, regex_match(regex(regex), text), - regex_match(result_unwrap_or(regex_checked(regex), regex("")), text), + regex_match(unwrap_or(regex_checked(regex), regex("")), text), regex_first_match(regex(regex), text), regex_all_matches(regex(regex), text)) :- RegexTestInput(regex, text). diff --git a/test/datalog_tests/simple.debug.ast.expected b/test/datalog_tests/simple.debug.ast.expected index 2efb11866..fb0b0f554 100644 --- a/test/datalog_tests/simple.debug.ast.expected +++ b/test/datalog_tests/simple.debug.ast.expected @@ -233,20 +233,20 @@ typedef t20 = signed<32> typedef t21 = double typedef t22 = float typedef tnid_t = bit<16> -function __debug_100_1_std.group2vec (g: std.Group): (std.Vec<'I>, std.Vec) +function __debug_100_1_std.group_to_vec (g: std.Group): (std.Vec<'I>, std.Vec) { (((var inputs: std.Vec<'I>), (var original_group: std.Group)) = debug.debug_split_group(g); - (inputs, std.group2vec(original_group))) + (inputs, std.group_to_vec(original_group))) } -function __debug_101_1_std.group2map (g: std.Group): (std.Vec<'I>, std.Map) +function __debug_101_1_std.group_to_map (g: std.Group): (std.Vec<'I>, std.Map) { (((var inputs: std.Vec<'I>), (var original_group: std.Group)) = debug.debug_split_group(g); - (inputs, std.group2map(original_group))) + (inputs, std.group_to_map(original_group))) } -function __debug_102_1_std.group2set (g: std.Group): (std.Vec<'I>, std.Set) +function __debug_102_1_std.group_to_set (g: std.Group): (std.Vec<'I>, std.Set) { (((var inputs: std.Vec<'I>), (var original_group: std.Group)) = debug.debug_split_group(g); - (inputs, std.group2set(original_group))) + (inputs, std.group_to_set(original_group))) } function __debug_103_1_std.group_sum (g: std.Group)>): (std.Vec<'I>, bit<32>) { @@ -263,20 +263,20 @@ function __debug_105_1_concat_ys (g: std.Group<(string, string),('I, string)>): (((var inputs: std.Vec<'I>), (var original_group: std.Group<(string, string),string>)) = debug.debug_split_group(g); (inputs, concat_ys(original_group))) } -function __debug_112_2_std.group2vec (g: std.Group): (std.Vec<'I>, std.Vec) +function __debug_112_2_std.group_to_vec (g: std.Group): (std.Vec<'I>, std.Vec) { (((var inputs: std.Vec<'I>), (var original_group: std.Group)) = debug.debug_split_group(g); - (inputs, std.group2vec(original_group))) + (inputs, std.group_to_vec(original_group))) } -function __debug_113_1_std.group2set (g: std.Group)>): (std.Vec<'I>, std.Set>) +function __debug_113_1_std.group_to_set (g: std.Group)>): (std.Vec<'I>, std.Set>) { (((var inputs: std.Vec<'I>), (var original_group: std.Group>)) = debug.debug_split_group(g); - (inputs, std.group2set(original_group))) + (inputs, std.group_to_set(original_group))) } -function __debug_248_2_std.group2set (g: std.Group,('I, bit<16>)>): (std.Vec<'I>, std.Set>) +function __debug_248_2_std.group_to_set (g: std.Group,('I, bit<16>)>): (std.Vec<'I>, std.Set>) { (((var inputs: std.Vec<'I>), (var original_group: std.Group,bit<16>>)) = debug.debug_split_group(g); - (inputs, std.group2set(original_group))) + (inputs, std.group_to_set(original_group))) } function __debug_249_3_std.group_set_unions (g: std.Group,('I, std.Set>)>): (std.Vec<'I>, std.Set>) { @@ -313,10 +313,10 @@ function __debug_98_2_std.group_sum (g: std.Group<(),('I, bit<64>)>): (std.Vec<' (((var inputs: std.Vec<'I>), (var original_group: std.Group<(),bit<64>>)) = debug.debug_split_group(g); (inputs, std.group_sum(original_group))) } -function __debug_99_1_std.group2set (g: std.Group): (std.Vec<'I>, std.Set) +function __debug_99_1_std.group_to_set (g: std.Group): (std.Vec<'I>, std.Set) { (((var inputs: std.Vec<'I>), (var original_group: std.Group)) = debug.debug_split_group(g); - (inputs, std.group2set(original_group))) + (inputs, std.group_to_set(original_group))) } function a0 (): bigint { @@ -710,6 +710,14 @@ extern function h (a: (bigint, bigint)): (bigint, bigint) extern function intern.istring_ord (s: intern.IString): std.u32 extern function intern.istring_str (s: intern.IString): string extern function intern.string_intern (s: string): intern.IString +function internment.contains (s1: internment.istring, s2: string): bool +{ + internment.istring_contains(s1, s2) +} +function internment.ends_with (s: internment.istring, suffix: string): bool +{ + internment.istring_ends_with(s, suffix) +} extern function internment.intern (s: 'A): internment.Intern<'A> extern function internment.istring_contains (s1: internment.istring, s2: string): bool extern function internment.istring_ends_with (s: internment.istring, suffix: string): bool @@ -726,6 +734,50 @@ extern function internment.istring_to_uppercase (s: internment.istring): string extern function internment.istring_trim (s: internment.istring): string #[return_by_ref = true] extern function internment.ival (s: internment.Intern<'A>): 'A +function internment.join (strings: std.Vec, sep: string): string +{ + internment.istring_join(strings, sep) +} +function internment.len (s: internment.istring): std.usize +{ + internment.istring_len(s) +} +function internment.replace (s: internment.istring, from: string, to: string): string +{ + internment.istring_replace(s, from, to) +} +function internment.reverse (s: internment.istring): string +{ + internment.istring_reverse(s) +} +function internment.split (s: internment.istring, sep: string): std.Vec +{ + internment.istring_split(s, sep) +} +function internment.starts_with (s: internment.istring, prefix: string): bool +{ + internment.istring_starts_with(s, prefix) +} +function internment.substr (s: internment.istring, start: std.usize, end: std.usize): string +{ + internment.istring_substr(s, start, end) +} +function internment.to_bytes (s: internment.istring): std.Vec +{ + internment.istring_to_bytes(s) +} +function internment.to_lowercase (s: internment.istring): string +{ + internment.istring_to_lowercase(s) +} +function internment.to_uppercase (s: internment.istring): string +{ + internment.istring_to_uppercase(s) +} +function internment.trim (s: internment.istring): string +{ + internment.istring_trim(s) +} #[has_side_effects = true] extern function log.log (module: log.module_t, level: log.log_level_t, msg: string): () function mult2 (x: bigint): bigint @@ -949,16 +1001,52 @@ function souffle_lib.utoi (l: bit<32>): signed<32> (l as signed<32>) } extern function std.__builtin_2string (x: 'X): string +function std.append (v: mut std.Vec<'X>, other: std.Vec<'X>): () +{ + std.vec_append(v, other) +} +function std.contains (s1: string, s2: string): bool +{ + std.string_contains(s1, s2) +} +function std.contains (v: std.Vec<'X>, x: 'X): bool +{ + std.vec_contains(v, x) +} +function std.contains (s: std.Set<'X>, v: 'X): bool +{ + std.set_contains(s, v) +} +function std.contains_key (m: std.Map<'K,'V>, k: 'K): bool +{ + std.map_contains_key(m, k) +} +function std.count (g: std.Group<'K,'V>): std.usize +{ + std.group_count(g) +} function std.dDNestedTS2string (ts: std.DDNestedTS): string { (((("(" ++ (std.__builtin_2string(ts.epoch): string)) ++ ",") ++ (std.__builtin_2string(ts.iter): string)) ++ ")") } #[return_by_ref = true] extern function std.deref (x: std.Ref<'A>): 'A -extern function std.group2map (g: std.Group<'K1,('K2, 'V)>): std.Map<'K2,'V> -extern function std.group2set (g: std.Group<'K,'V>): std.Set<'V> -extern function std.group2setmap (g: std.Group<'K1,('K2, 'V)>): std.Map<'K2,std.Set<'V>> -extern function std.group2vec (g: std.Group<'K,'V>): std.Vec<'V> +function std.difference (s1: std.Set<'X>, s2: std.Set<'X>): std.Set<'X> +{ + (std.set_difference(s1, s2): std.Set<'X>) +} +function std.ends_with (s: string, suffix: string): bool +{ + std.string_ends_with(s, suffix) +} +function std.first (g: std.Group<'K,'V>): 'V +{ + (std.group_first(g): 'V) +} +function std.get (m: std.Map<'K,'V>, k: 'K): std.Option<'V> +{ + (std.map_get(m, k): std.Option<'V>) +} extern function std.group_count (g: std.Group<'K,'V>): std.usize extern function std.group_first (g: std.Group<'K,'V>): 'V extern function std.group_key (g: std.Group<'K,'V>): 'K @@ -968,6 +1056,10 @@ extern function std.group_nth (g: std.Group<'K,'V>, n: std.usize): std.Option<'V extern function std.group_set_unions (g: std.Group<'K,std.Set<'A>>): std.Set<'A> extern function std.group_setref_unions (g: std.Group<'K,std.Ref>>): std.Ref> extern function std.group_sum (g: std.Group<'K,'V>): 'V +extern function std.group_to_map (g: std.Group<'K1,('K2, 'V)>): std.Map<'K2,'V> +extern function std.group_to_set (g: std.Group<'K,'V>): std.Set<'V> +extern function std.group_to_setmap (g: std.Group<'K1,('K2, 'V)>): std.Map<'K2,std.Set<'V>> +extern function std.group_to_vec (g: std.Group<'K,'V>): std.Vec<'V> function std.group_unzip (g: std.Group<'K,('X, 'Y)>): (std.Vec<'X>, std.Vec<'Y>) { ((var xs: std.Vec<'X>) = (std.vec_empty(): std.Vec<'X>); @@ -984,6 +1076,38 @@ extern function std.hash64 (x: 'X): bit<64> extern function std.hex (x: 'X): string extern function std.htonl (x: bit<32>): bit<32> extern function std.htons (x: bit<16>): bit<16> +function std.insert (m: mut std.Map<'K,'V>, k: 'K, v: 'V): () +{ + std.map_insert(m, k, v) +} +function std.insert (s: mut std.Set<'X>, v: 'X): () +{ + std.set_insert(s, v) +} +function std.insert_imm (m: std.Map<'K,'V>, k: 'K, v: 'V): std.Map<'K,'V> +{ + (std.map_insert_imm(m, k, v): std.Map<'K,'V>) +} +function std.insert_imm (s: std.Set<'X>, v: 'X): std.Set<'X> +{ + (std.set_insert_imm(s, v): std.Set<'X>) +} +function std.intersection (s1: std.Set<'X>, s2: std.Set<'X>): std.Set<'X> +{ + (std.set_intersection(s1, s2): std.Set<'X>) +} +function std.is_empty (v: std.Vec<'X>): bool +{ + std.vec_is_empty(v) +} +function std.is_empty (m: std.Map<'K,'V>): bool +{ + std.map_is_empty(m) +} +function std.is_empty (s: std.Set<'X>): bool +{ + std.set_is_empty(s) +} function std.is_err (res: std.Result<'V,'E>): bool { match (res) { @@ -1012,6 +1136,22 @@ function std.is_some (x: std.Option<'A>): bool (_: std.Option<'A>) -> false } } +function std.join (strings: std.Vec, sep: string): string +{ + std.string_join(strings, sep) +} +function std.key (g: std.Group<'K,'V>): 'K +{ + (std.group_key(g): 'K) +} +function std.len (s: string): std.usize +{ + std.string_len(s) +} +function std.len (v: std.Vec<'X>): std.usize +{ + std.vec_len(v) +} extern function std.map_contains_key (m: std.Map<'K,'V>, k: 'K): bool extern function std.map_empty (): std.Map<'K,'V> extern function std.map_get (m: std.Map<'K,'V>, k: 'K): std.Option<'V> @@ -1030,6 +1170,10 @@ function std.max (x: 'A, y: 'A): 'A y } } +function std.max (g: std.Group<'K,'V>): 'V +{ + (std.group_max(g): 'V) +} function std.min (x: 'A, y: 'A): 'A { if (x < y) { @@ -1038,44 +1182,51 @@ function std.min (x: 'A, y: 'A): 'A y } } -extern function std.ntohl (x: bit<32>): bit<32> -extern function std.ntohs (x: bit<16>): bit<16> -function std.option2set (o: std.Option<'X>): std.Set<'X> +function std.min (g: std.Group<'K,'V>): 'V { - match (o) { - (std.Some{.x=(var x: 'X)}: std.Option<'X>) -> (std.set_singleton(x): std.Set<'X>), - (std.None{}: std.Option<'X>) -> (std.set_empty(): std.Set<'X>) - } + (std.group_min(g): 'V) } -function std.option2vec (o: std.Option<'X>): std.Vec<'X> +function std.nth (g: std.Group<'K,'V>, n: std.usize): std.Option<'V> { - match (o) { - (std.Some{.x=(var x: 'X)}: std.Option<'X>) -> (std.vec_singleton(x): std.Vec<'X>), - (std.None{}: std.Option<'X>) -> (std.vec_empty(): std.Vec<'X>) - } + (std.group_nth(g, n): std.Option<'V>) } -function std.option_unwrap_or (x: std.Option<'A>, def: 'A): 'A +function std.nth (v: std.Vec<'X>, n: std.usize): std.Option<'X> { - match (x) { - (std.Some{.x=(var v: 'A)}: std.Option<'A>) -> v, - (std.None{}: std.Option<'A>) -> def - } + (std.vec_nth(v, n): std.Option<'X>) } +function std.nth (s: std.Set<'X>, n: std.usize): std.Option<'X> +{ + (std.set_nth(s, n): std.Option<'X>) +} +extern function std.ntohl (x: bit<32>): bit<32> +extern function std.ntohs (x: bit<16>): bit<16> extern function std.option_unwrap_or_default (opt: std.Option<'A>): 'A extern function std.parse_dec_i64 (s: string): std.Option> extern function std.parse_dec_u64 (s: string): std.Option> extern function std.pow32 (base: 'A, exp: bit<32>): 'A +function std.push (v: mut std.Vec<'X>, x: 'X): () +{ + std.vec_push(v, x) +} +function std.push_imm (v: std.Vec<'X>, x: 'X): std.Vec<'X> +{ + (std.vec_push_imm(v, x): std.Vec<'X>) +} extern function std.range (from: 'A, to: 'A, step: 'A): std.Vec<'A> extern function std.ref_new (x: 'A): std.Ref<'A> -function std.result_unwrap_or (res: std.Result<'V,'E>, def: 'V): 'V +function std.remove (m: mut std.Map<'K,'V>, k: 'K): () { - match (res) { - (std.Ok{.res=(var v: 'V)}: std.Result<'V,'E>) -> v, - (std.Err{.err=(_: 'E)}: std.Result<'V,'E>) -> def - } + std.map_remove(m, k) +} +function std.replace (s: string, from: string, to: string): string +{ + std.string_replace(s, from, to) } extern function std.result_unwrap_or_default (res: std.Result<'V,'E>): 'V -extern function std.set2vec (s: std.Set<'A>): std.Vec<'A> +function std.reverse (s: string): string +{ + std.string_reverse(s) +} extern function std.set_contains (s: std.Set<'X>, v: 'X): bool extern function std.set_difference (s1: std.Set<'X>, s2: std.Set<'X>): std.Set<'X> extern function std.set_empty (): std.Set<'X> @@ -1086,8 +1237,37 @@ extern function std.set_is_empty (s: std.Set<'X>): bool extern function std.set_nth (s: std.Set<'X>, n: std.usize): std.Option<'X> extern function std.set_singleton (x: 'X): std.Set<'X> extern function std.set_size (s: std.Set<'X>): std.usize +extern function std.set_to_vec (s: std.Set<'A>): std.Vec<'A> extern function std.set_union (s1: std.Set<'X>, s2: std.Set<'X>): std.Set<'X> extern function std.set_unions (sets: std.Vec>): std.Set<'X> +function std.setref_unions (g: std.Group<'K,std.Ref>>): std.Ref> +{ + (std.group_setref_unions(g): std.Ref>) +} +function std.size (m: std.Map<'K,'V>): std.usize +{ + std.map_size(m) +} +function std.size (s: std.Set<'X>): std.usize +{ + std.set_size(s) +} +function std.sort (v: mut std.Vec<'X>): () +{ + std.vec_sort(v) +} +function std.sort_imm (v: std.Vec<'X>): std.Vec<'X> +{ + (std.vec_sort_imm(v): std.Vec<'X>) +} +function std.split (s: string, sep: string): std.Vec +{ + std.string_split(s, sep) +} +function std.starts_with (s: string, prefix: string): bool +{ + std.string_starts_with(s, prefix) +} extern function std.str_to_lower (s: string): string extern function std.string_contains (s1: string, s2: string): bool extern function std.string_ends_with (s: string, suffix: string): bool @@ -1102,7 +1282,98 @@ extern function std.string_to_bytes (s: string): std.Vec extern function std.string_to_lowercase (s: string): string extern function std.string_to_uppercase (s: string): string extern function std.string_trim (s: string): string -extern function std.vec2set (s: std.Vec<'A>): std.Set<'A> +function std.substr (s: string, start: std.usize, end: std.usize): string +{ + std.string_substr(s, start, end) +} +function std.to_bytes (s: string): std.Vec +{ + std.string_to_bytes(s) +} +function std.to_lowercase (s: string): string +{ + std.string_to_lowercase(s) +} +function std.to_map (g: std.Group<'K1,('K2, 'V)>): std.Map<'K2,'V> +{ + (std.group_to_map(g): std.Map<'K2,'V>) +} +function std.to_set (o: std.Option<'X>): std.Set<'X> +{ + match (o) { + (std.Some{.x=(var x: 'X)}: std.Option<'X>) -> (std.set_singleton(x): std.Set<'X>), + (std.None{}: std.Option<'X>) -> (std.set_empty(): std.Set<'X>) + } +} +function std.to_set (g: std.Group<'K,'V>): std.Set<'V> +{ + (std.group_to_set(g): std.Set<'V>) +} +function std.to_set (s: std.Vec<'A>): std.Set<'A> +{ + (std.vec_to_set(s): std.Set<'A>) +} +function std.to_setmap (g: std.Group<'K1,('K2, 'V)>): std.Map<'K2,std.Set<'V>> +{ + (std.group_to_setmap(g): std.Map<'K2,std.Set<'V>>) +} +function std.to_uppercase (s: string): string +{ + std.string_to_uppercase(s) +} +function std.to_vec (o: std.Option<'X>): std.Vec<'X> +{ + match (o) { + (std.Some{.x=(var x: 'X)}: std.Option<'X>) -> (std.vec_singleton(x): std.Vec<'X>), + (std.None{}: std.Option<'X>) -> (std.vec_empty(): std.Vec<'X>) + } +} +function std.to_vec (g: std.Group<'K,'V>): std.Vec<'V> +{ + (std.group_to_vec(g): std.Vec<'V>) +} +function std.to_vec (s: std.Set<'A>): std.Vec<'A> +{ + (std.set_to_vec(s): std.Vec<'A>) +} +function std.trim (s: string): string +{ + std.string_trim(s) +} +function std.union (m1: std.Map<'K,'V>, m2: std.Map<'K,'V>): std.Map<'K,'V> +{ + (std.map_union(m1, m2): std.Map<'K,'V>) +} +function std.union (s1: std.Set<'X>, s2: std.Set<'X>): std.Set<'X> +{ + (std.set_union(s1, s2): std.Set<'X>) +} +function std.unions (sets: std.Vec>): std.Set<'X> +{ + (std.set_unions(sets): std.Set<'X>) +} +function std.unwrap_or (x: std.Option<'A>, def: 'A): 'A +{ + match (x) { + (std.Some{.x=(var v: 'A)}: std.Option<'A>) -> v, + (std.None{}: std.Option<'A>) -> def + } +} +function std.unwrap_or (res: std.Result<'V,'E>, def: 'V): 'V +{ + match (res) { + (std.Ok{.res=(var v: 'V)}: std.Result<'V,'E>) -> v, + (std.Err{.err=(_: 'E)}: std.Result<'V,'E>) -> def + } +} +function std.unwrap_or_default (opt: std.Option<'A>): 'A +{ + (std.option_unwrap_or_default(opt): 'A) +} +function std.unwrap_or_default (res: std.Result<'V,'E>): 'V +{ + (std.result_unwrap_or_default(res): 'V) +} extern function std.vec_append (v: mut std.Vec<'X>, other: std.Vec<'X>): () extern function std.vec_contains (v: std.Vec<'X>, x: 'X): bool extern function std.vec_empty (): std.Vec<'A> @@ -1112,8 +1383,9 @@ extern function std.vec_nth (v: std.Vec<'X>, n: std.usize): std.Option<'X> extern function std.vec_push (v: mut std.Vec<'X>, x: 'X): () extern function std.vec_push_imm (v: std.Vec<'X>, x: 'X): std.Vec<'X> extern function std.vec_singleton (x: 'X): std.Vec<'X> -extern function std.vec_sort (v: std.Vec<'X>): () +extern function std.vec_sort (v: mut std.Vec<'X>): () extern function std.vec_sort_imm (v: std.Vec<'X>): std.Vec<'X> +extern function std.vec_to_set (s: std.Vec<'A>): std.Set<'A> extern function std.vec_with_capacity (len: std.usize): std.Vec<'A> extern function std.vec_with_length (len: std.usize, x: 'A): std.Vec<'A> function strings (): () @@ -1465,10 +1737,10 @@ Aggregate1[(Aggregate1{.x=x, .cnt=cnt}: Aggregate1)] :- AggregateMe1[(__aggregat AggregateCnt[(AggregateCnt{.cnt=cnt}: AggregateCnt)] :- AggregateMe1[(__aggregateme10@ (AggregateMe1{.x=(x: string), .y=(y: string)}: AggregateMe1))], var __inputs_cnt = Aggregate((), __debug_96_1_std.group_count((__aggregateme10, ()))), Inspect debug.debug_event((32'd96, 32'd1, 32'd0), ddlog_weight, ddlog_timestamp, "Aggregate", __inputs_cnt.0, __inputs_cnt), (var cnt: std.usize) = __inputs_cnt.1, Inspect debug.debug_event((32'd96, 32'd2, 32'd0), ddlog_weight, ddlog_timestamp, "Condition", __inputs_cnt, (AggregateCnt{.cnt=cnt}: AggregateCnt)). AggregateCnt2[(AggregateCnt2{.cnt=cnt}: AggregateCnt2)] :- AggregateMe1[(__aggregateme10@ (AggregateMe1{.x=(x: string), .y=(y: string)}: AggregateMe1))], var __inputs_cnt = Aggregate((), __debug_97_1_std.group_sum((__aggregateme10, (64'd1: bit<64>)))), Inspect debug.debug_event((32'd97, 32'd1, 32'd0), ddlog_weight, ddlog_timestamp, "Aggregate", __inputs_cnt.0, __inputs_cnt), (var cnt: bit<64>) = __inputs_cnt.1, Inspect debug.debug_event((32'd97, 32'd2, 32'd0), ddlog_weight, ddlog_timestamp, "Condition", __inputs_cnt, (AggregateCnt2{.cnt=cnt}: AggregateCnt2)). AggregateCnt3[(AggregateCnt3{.cnt=cnt}: AggregateCnt3)] :- AggregateMe1[(__aggregateme10@ (AggregateMe1{.x=(x: string), .y=(y: string)}: AggregateMe1))], (y != "1"), Inspect debug.debug_event((32'd98, 32'd1, 32'd0), ddlog_weight, ddlog_timestamp, "Condition", __aggregateme10, (__aggregateme10, x, y)), var __inputs_cnt = Aggregate((), __debug_98_2_std.group_sum(((__aggregateme10, x, y), (64'd1: bit<64>)))), Inspect debug.debug_event((32'd98, 32'd2, 32'd0), ddlog_weight, ddlog_timestamp, "Aggregate", __inputs_cnt.0, __inputs_cnt), (var cnt: bit<64>) = __inputs_cnt.1, Inspect debug.debug_event((32'd98, 32'd3, 32'd0), ddlog_weight, ddlog_timestamp, "Condition", __inputs_cnt, (AggregateCnt3{.cnt=cnt}: AggregateCnt3)). -Aggregate2[(Aggregate2{.x=x, .set=set}: Aggregate2)] :- AggregateMe1[(__aggregateme10@ (AggregateMe1{.x=(x: string), .y=(y: string)}: AggregateMe1))], var __inputs_set = Aggregate(x, __debug_99_1_std.group2set((__aggregateme10, y))), Inspect debug.debug_event((32'd99, 32'd1, 32'd0), ddlog_weight, ddlog_timestamp, "Aggregate", __inputs_set.0, (__inputs_set, x)), (var set: std.Set) = __inputs_set.1, Inspect debug.debug_event((32'd99, 32'd2, 32'd0), ddlog_weight, ddlog_timestamp, "Condition", (__inputs_set, x), (Aggregate2{.x=x, .set=set}: Aggregate2)). -Aggregate3[(Aggregate3{.x=x, .vec=vec}: Aggregate3)] :- AggregateMe1[(__aggregateme10@ (AggregateMe1{.x=(x: string), .y=(y: string)}: AggregateMe1))], var __inputs_vec = Aggregate(x, __debug_100_1_std.group2vec((__aggregateme10, y))), Inspect debug.debug_event((32'd100, 32'd1, 32'd0), ddlog_weight, ddlog_timestamp, "Aggregate", __inputs_vec.0, (__inputs_vec, x)), (var vec: std.Vec) = __inputs_vec.1, Inspect debug.debug_event((32'd100, 32'd2, 32'd0), ddlog_weight, ddlog_timestamp, "Condition", (__inputs_vec, x), (Aggregate3{.x=x, .vec=vec}: Aggregate3)). -Aggregate4[(Aggregate4{.x=x, .map=map}: Aggregate4)] :- AggregateMe1[(__aggregateme10@ (AggregateMe1{.x=(x: string), .y=(y: string)}: AggregateMe1))], var __inputs_map = Aggregate(x, __debug_101_1_std.group2map((__aggregateme10, (x, y)))), Inspect debug.debug_event((32'd101, 32'd1, 32'd0), ddlog_weight, ddlog_timestamp, "Aggregate", __inputs_map.0, (__inputs_map, x)), (var map: std.Map) = __inputs_map.1, Inspect debug.debug_event((32'd101, 32'd2, 32'd0), ddlog_weight, ddlog_timestamp, "Condition", (__inputs_map, x), (Aggregate4{.x=x, .map=map}: Aggregate4)). -Disaggregate[(Disaggregate{.x=x, .y=y}: Disaggregate)] :- AggregateMe1[(__aggregateme10@ (AggregateMe1{.x=(x: string), .y=(y: string)}: AggregateMe1))], var __inputs_set = Aggregate(x, __debug_102_1_std.group2set((__aggregateme10, y))), Inspect debug.debug_event((32'd102, 32'd1, 32'd0), ddlog_weight, ddlog_timestamp, "Aggregate", __inputs_set.0, (__inputs_set, x)), (var set: std.Set) = __inputs_set.1, Inspect debug.debug_event((32'd102, 32'd2, 32'd0), ddlog_weight, ddlog_timestamp, "Condition", (__inputs_set, x), (x, set)), var y = FlatMap(set), Inspect debug.debug_event((32'd102, 32'd3, 32'd0), ddlog_weight, ddlog_timestamp, "Flatmap", (x, set), (Disaggregate{.x=x, .y=y}: Disaggregate)). +Aggregate2[(Aggregate2{.x=x, .set=set}: Aggregate2)] :- AggregateMe1[(__aggregateme10@ (AggregateMe1{.x=(x: string), .y=(y: string)}: AggregateMe1))], var __inputs_set = Aggregate(x, __debug_99_1_std.group_to_set((__aggregateme10, y))), Inspect debug.debug_event((32'd99, 32'd1, 32'd0), ddlog_weight, ddlog_timestamp, "Aggregate", __inputs_set.0, (__inputs_set, x)), (var set: std.Set) = __inputs_set.1, Inspect debug.debug_event((32'd99, 32'd2, 32'd0), ddlog_weight, ddlog_timestamp, "Condition", (__inputs_set, x), (Aggregate2{.x=x, .set=set}: Aggregate2)). +Aggregate3[(Aggregate3{.x=x, .vec=vec}: Aggregate3)] :- AggregateMe1[(__aggregateme10@ (AggregateMe1{.x=(x: string), .y=(y: string)}: AggregateMe1))], var __inputs_vec = Aggregate(x, __debug_100_1_std.group_to_vec((__aggregateme10, y))), Inspect debug.debug_event((32'd100, 32'd1, 32'd0), ddlog_weight, ddlog_timestamp, "Aggregate", __inputs_vec.0, (__inputs_vec, x)), (var vec: std.Vec) = __inputs_vec.1, Inspect debug.debug_event((32'd100, 32'd2, 32'd0), ddlog_weight, ddlog_timestamp, "Condition", (__inputs_vec, x), (Aggregate3{.x=x, .vec=vec}: Aggregate3)). +Aggregate4[(Aggregate4{.x=x, .map=map}: Aggregate4)] :- AggregateMe1[(__aggregateme10@ (AggregateMe1{.x=(x: string), .y=(y: string)}: AggregateMe1))], var __inputs_map = Aggregate(x, __debug_101_1_std.group_to_map((__aggregateme10, (x, y)))), Inspect debug.debug_event((32'd101, 32'd1, 32'd0), ddlog_weight, ddlog_timestamp, "Aggregate", __inputs_map.0, (__inputs_map, x)), (var map: std.Map) = __inputs_map.1, Inspect debug.debug_event((32'd101, 32'd2, 32'd0), ddlog_weight, ddlog_timestamp, "Condition", (__inputs_map, x), (Aggregate4{.x=x, .map=map}: Aggregate4)). +Disaggregate[(Disaggregate{.x=x, .y=y}: Disaggregate)] :- AggregateMe1[(__aggregateme10@ (AggregateMe1{.x=(x: string), .y=(y: string)}: AggregateMe1))], var __inputs_set = Aggregate(x, __debug_102_1_std.group_to_set((__aggregateme10, y))), Inspect debug.debug_event((32'd102, 32'd1, 32'd0), ddlog_weight, ddlog_timestamp, "Aggregate", __inputs_set.0, (__inputs_set, x)), (var set: std.Set) = __inputs_set.1, Inspect debug.debug_event((32'd102, 32'd2, 32'd0), ddlog_weight, ddlog_timestamp, "Condition", (__inputs_set, x), (x, set)), var y = FlatMap(set), Inspect debug.debug_event((32'd102, 32'd3, 32'd0), ddlog_weight, ddlog_timestamp, "Flatmap", (x, set), (Disaggregate{.x=x, .y=y}: Disaggregate)). Sum[(Sum{.x=x, .sum=sum}: Sum)] :- AggregateMeInts[(__aggregatemeints0@ (AggregateMeInts{.x=(x: string), .y=(y: bit<32>)}: AggregateMeInts))], var __inputs_sum = Aggregate(x, __debug_103_1_std.group_sum((__aggregatemeints0, y))), Inspect debug.debug_event((32'd103, 32'd1, 32'd0), ddlog_weight, ddlog_timestamp, "Aggregate", __inputs_sum.0, (__inputs_sum, x)), (var sum: bit<32>) = __inputs_sum.1, Inspect debug.debug_event((32'd103, 32'd2, 32'd0), ddlog_weight, ddlog_timestamp, "Condition", (__inputs_sum, x), (Sum{.x=x, .sum=sum}: Sum)). AggregateByX[(AggregateByX{.x=x, .cnt=cnt}: AggregateByX)] :- AggregateMe3[(__aggregateme30@ (AggregateMe3{.x=(x: string), .y=(y: string), .z=(z: string)}: AggregateMe3))], AggregateMe1[(__aggregateme11@ (AggregateMe1{.x=(x: string), .y=(y: string)}: AggregateMe1))], Inspect debug.debug_event_join((32'd104, 32'd1, 32'd0), ddlog_weight, ddlog_timestamp, __aggregateme30, __aggregateme11, (__aggregateme30, x, y, z, __aggregateme11)), var __inputs_cnt = Aggregate(x, __debug_104_2_std.group_count(((__aggregateme30, x, y, z, __aggregateme11), ()))), Inspect debug.debug_event((32'd104, 32'd2, 32'd0), ddlog_weight, ddlog_timestamp, "Aggregate", __inputs_cnt.0, (__inputs_cnt, x)), (var cnt: std.usize) = __inputs_cnt.1, Inspect debug.debug_event((32'd104, 32'd3, 32'd0), ddlog_weight, ddlog_timestamp, "Condition", (__inputs_cnt, x), (AggregateByX{.x=x, .cnt=cnt}: AggregateByX)). Concat[(Concat{.s=s}: Concat)] :- AggregateMe3[(__aggregateme30@ (AggregateMe3{.x=(x: string), .y=(y: string), .z=(z: string)}: AggregateMe3))], var __inputs_s = Aggregate((x, z), __debug_105_1_concat_ys((__aggregateme30, y))), Inspect debug.debug_event((32'd105, 32'd1, 32'd0), ddlog_weight, ddlog_timestamp, "Aggregate", __inputs_s.0, __inputs_s), (var s: string) = __inputs_s.1, Inspect debug.debug_event((32'd105, 32'd2, 32'd0), ddlog_weight, ddlog_timestamp, "Condition", __inputs_s, (Concat{.s=s}: Concat)). @@ -1478,8 +1750,8 @@ ValidDestination[(ValidDestination{.addr=addr}: ValidDestination)] :- Address[(_ HostAddress[(HostAddress{.host=host, .addr=addr}: HostAddress)] :- HostAddresses[(__hostaddresses0@ (HostAddresses{.host=(host: bit<64>), .addrs=(addrs: std.Set)}: HostAddresses))], var addr = FlatMap(addrs), Inspect debug.debug_event((32'd109, 32'd1, 32'd0), ddlog_weight, ddlog_timestamp, "Flatmap", __hostaddresses0, (HostAddress{.host=host, .addr=addr}: HostAddress)). ExternalId[(ExternalId{.host=host, .id=id}: ExternalId)] :- ExternalIds[(__externalids0@ (ExternalIds{.host=(host: bit<64>), .ids=(ids: std.Map)}: ExternalIds))], var id = FlatMap(ids), Inspect debug.debug_event((32'd110, 32'd1, 32'd0), ddlog_weight, ddlog_timestamp, "Flatmap", __externalids0, (ExternalId{.host=host, .id=id}: ExternalId)). Allocation[(Allocation{.name=name, .id=id, .x=x}: Allocation)] :- Request[(__request0@ (Request{.name=(name: string), .id=(id: string)}: Request))], Realized[(__realized1@ (Realized{.name=(name: string), .id=(id: string), .x=(x: bit<32>)}: Realized))], Inspect debug.debug_event_join((32'd111, 32'd1, 32'd0), ddlog_weight, ddlog_timestamp, __request0, __realized1, (Allocation{.name=name, .id=id, .x=x}: Allocation)). -ToAllocate[(ToAllocate{.name=name, .ids=ids}: ToAllocate)] :- Request[(__request0@ (Request{.name=(name: string), .id=(id: string)}: Request))], not Realized[(Realized{.name=(name: string), .id=(id: string), .x=(_: bit<32>)}: Realized)], Inspect debug.debug_event((32'd112, 32'd1, 32'd0), ddlog_weight, ddlog_timestamp, "Antijoin", __request0, (__request0, name, id)), var __inputs_ids = Aggregate(name, __debug_112_2_std.group2vec(((__request0, name, id), id))), Inspect debug.debug_event((32'd112, 32'd2, 32'd0), ddlog_weight, ddlog_timestamp, "Aggregate", __inputs_ids.0, (__inputs_ids, name)), (var ids: std.Vec) = __inputs_ids.1, Inspect debug.debug_event((32'd112, 32'd3, 32'd0), ddlog_weight, ddlog_timestamp, "Condition", (__inputs_ids, name), (ToAllocate{.name=name, .ids=ids}: ToAllocate)). -Allocated[(Allocated{.name=name, .xs=xs}: Allocated)] :- Realized[(__realized0@ (Realized{.name=(name: string), .id=(_: string), .x=(x: bit<32>)}: Realized))], var __inputs_xs = Aggregate(name, __debug_113_1_std.group2set((__realized0, x))), Inspect debug.debug_event((32'd113, 32'd1, 32'd0), ddlog_weight, ddlog_timestamp, "Aggregate", __inputs_xs.0, (__inputs_xs, name)), (var xs: std.Set>) = __inputs_xs.1, Inspect debug.debug_event((32'd113, 32'd2, 32'd0), ddlog_weight, ddlog_timestamp, "Condition", (__inputs_xs, name), (Allocated{.name=name, .xs=xs}: Allocated)). +ToAllocate[(ToAllocate{.name=name, .ids=ids}: ToAllocate)] :- Request[(__request0@ (Request{.name=(name: string), .id=(id: string)}: Request))], not Realized[(Realized{.name=(name: string), .id=(id: string), .x=(_: bit<32>)}: Realized)], Inspect debug.debug_event((32'd112, 32'd1, 32'd0), ddlog_weight, ddlog_timestamp, "Antijoin", __request0, (__request0, name, id)), var __inputs_ids = Aggregate(name, __debug_112_2_std.group_to_vec(((__request0, name, id), id))), Inspect debug.debug_event((32'd112, 32'd2, 32'd0), ddlog_weight, ddlog_timestamp, "Aggregate", __inputs_ids.0, (__inputs_ids, name)), (var ids: std.Vec) = __inputs_ids.1, Inspect debug.debug_event((32'd112, 32'd3, 32'd0), ddlog_weight, ddlog_timestamp, "Condition", (__inputs_ids, name), (ToAllocate{.name=name, .ids=ids}: ToAllocate)). +Allocated[(Allocated{.name=name, .xs=xs}: Allocated)] :- Realized[(__realized0@ (Realized{.name=(name: string), .id=(_: string), .x=(x: bit<32>)}: Realized))], var __inputs_xs = Aggregate(name, __debug_113_1_std.group_to_set((__realized0, x))), Inspect debug.debug_event((32'd113, 32'd1, 32'd0), ddlog_weight, ddlog_timestamp, "Aggregate", __inputs_xs.0, (__inputs_xs, name)), (var xs: std.Set>) = __inputs_xs.1, Inspect debug.debug_event((32'd113, 32'd2, 32'd0), ddlog_weight, ddlog_timestamp, "Condition", (__inputs_xs, name), (Allocated{.name=name, .xs=xs}: Allocated)). Allocation[(Allocation{.name=name, .id=id, .x=x}: Allocation)] :- ToAllocate[(__toallocate0@ (ToAllocate{.name=(name: string), .ids=(ids: std.Vec)}: ToAllocate))], Allocated[(__allocated1@ (Allocated{.name=(name: string), .xs=(xs: std.Set>)}: Allocated))], Inspect debug.debug_event_join((32'd114, 32'd1, 32'd0), ddlog_weight, ddlog_timestamp, __toallocate0, __allocated1, (name, ids, xs)), var allocation = FlatMap((allocate.allocate(xs, ids, 32'd1, ((32'd1 << 32'd24) - 32'd1)): std.Vec<(string, bit<32>)>)), Inspect debug.debug_event((32'd114, 32'd2, 32'd0), ddlog_weight, ddlog_timestamp, "Flatmap", (name, ids, xs), (allocation, name)), ((var id: string), (var x: bit<32>)) = allocation, Inspect debug.debug_event((32'd114, 32'd3, 32'd0), ddlog_weight, ddlog_timestamp, "Condition", (allocation, name), (Allocation{.name=name, .id=id, .x=x}: Allocation)). Referee[(Referee{.r=(std.ref_new(r): std.Ref)}: Referee)] :- Referenced[(r@ (Referenced{.x=(_: bool), .y=(std.Some{.x=(_: string)}: std.Option)}: Referenced))], Inspect debug.debug_event((32'd115, 32'd0, 32'd0), ddlog_weight, ddlog_timestamp, "Map", r, (Referee{.r=(std.ref_new(r): std.Ref)}: Referee)). Filtered[(Filtered{.r=r.r}: Filtered)] :- Referee[(r@ (Referee{.r=((&(Referenced{.x=true, .y=(_: std.Option)}: Referenced)): std.Ref)}: Referee))], Inspect debug.debug_event((32'd116, 32'd0, 32'd0), ddlog_weight, ddlog_timestamp, "Map", r, (Filtered{.r=r.r}: Filtered)). @@ -1630,7 +1902,7 @@ UMinus_s32[(UMinus_s32{.description="-32768", .n=(- 32'sd32768)}: UMinus_s32)]. UMinus_bigint[(UMinus_bigint{.description="-100", .n=(- 100)}: UMinus_bigint)]. UMinus_bigint[(UMinus_bigint{.description="- -100", .n=(- (- 100))}: UMinus_bigint)]. UMinus_bigint[(UMinus_bigint{.description="-32768", .n=(- 32768)}: UMinus_bigint)]. -Span[(Span{.entity=(entity: entid_t), .tns=bindings}: Span)] :- DdlogNode[(__ddlognode0@ (DdlogNode{.id=(entity: bit<32>)}: DdlogNode))], DdlogBinding[(__ddlogbinding1@ (DdlogBinding{.tn=(tn: bit<16>), .entity=(entity: bit<32>)}: DdlogBinding))], Inspect debug.debug_event_join((32'd248, 32'd1, 32'd0), ddlog_weight, ddlog_timestamp, __ddlognode0, __ddlogbinding1, (__ddlognode0, entity, __ddlogbinding1, tn)), var __inputs_bindings = Aggregate(entity, __debug_248_2_std.group2set(((__ddlognode0, entity, __ddlogbinding1, tn), tn))), Inspect debug.debug_event((32'd248, 32'd2, 32'd0), ddlog_weight, ddlog_timestamp, "Aggregate", __inputs_bindings.0, (__inputs_bindings, entity)), (var bindings: std.Set>) = __inputs_bindings.1, Inspect debug.debug_event((32'd248, 32'd3, 32'd0), ddlog_weight, ddlog_timestamp, "Condition", (__inputs_bindings, entity), (Span{.entity=(entity: entid_t), .tns=bindings}: Span)). +Span[(Span{.entity=(entity: entid_t), .tns=bindings}: Span)] :- DdlogNode[(__ddlognode0@ (DdlogNode{.id=(entity: bit<32>)}: DdlogNode))], DdlogBinding[(__ddlogbinding1@ (DdlogBinding{.tn=(tn: bit<16>), .entity=(entity: bit<32>)}: DdlogBinding))], Inspect debug.debug_event_join((32'd248, 32'd1, 32'd0), ddlog_weight, ddlog_timestamp, __ddlognode0, __ddlogbinding1, (__ddlognode0, entity, __ddlogbinding1, tn)), var __inputs_bindings = Aggregate(entity, __debug_248_2_std.group_to_set(((__ddlognode0, entity, __ddlogbinding1, tn), tn))), Inspect debug.debug_event((32'd248, 32'd2, 32'd0), ddlog_weight, ddlog_timestamp, "Aggregate", __inputs_bindings.0, (__inputs_bindings, entity)), (var bindings: std.Set>) = __inputs_bindings.1, Inspect debug.debug_event((32'd248, 32'd3, 32'd0), ddlog_weight, ddlog_timestamp, "Condition", (__inputs_bindings, entity), (Span{.entity=(entity: entid_t), .tns=bindings}: Span)). Span[(Span{.entity=parent, .tns=tns}: Span)] :- DdlogNode[(__ddlognode0@ (DdlogNode{.id=(parent: bit<32>)}: DdlogNode))], DdlogDependency[(__ddlogdependency1@ (DdlogDependency{.parent=(child: bit<32>), .child=(parent: bit<32>)}: DdlogDependency))], Inspect debug.debug_event_join((32'd249, 32'd1, 32'd0), ddlog_weight, ddlog_timestamp, __ddlognode0, __ddlogdependency1, (__ddlognode0, parent, __ddlogdependency1, child)), Span[(__span2@ (Span{.entity=(child: bit<32>), .tns=(child_tns: std.Set>)}: Span))], Inspect debug.debug_event_join((32'd249, 32'd2, 32'd0), ddlog_weight, ddlog_timestamp, (__ddlognode0, parent, __ddlogdependency1, child), __span2, (__ddlognode0, parent, __ddlogdependency1, child, __span2, child_tns)), var __inputs_tns = Aggregate(parent, __debug_249_3_std.group_set_unions(((__ddlognode0, parent, __ddlogdependency1, child, __span2, child_tns), child_tns))), Inspect debug.debug_event((32'd249, 32'd3, 32'd0), ddlog_weight, ddlog_timestamp, "Aggregate", __inputs_tns.0, (__inputs_tns, parent)), (var tns: std.Set>) = __inputs_tns.1, Inspect debug.debug_event((32'd249, 32'd4, 32'd0), ddlog_weight, ddlog_timestamp, "Condition", (__inputs_tns, parent), (Span{.entity=parent, .tns=tns}: Span)). R13[(R13{.t=(1, true, "", 32'd1)}: R13)]. R14[(R14{.t=(1, (true, ("", 32'd1)))}: R14)]. diff --git a/test/datalog_tests/simple.dl b/test/datalog_tests/simple.dl index ad377c86c..834ed6c6f 100644 --- a/test/datalog_tests/simple.dl +++ b/test/datalog_tests/simple.dl @@ -709,16 +709,16 @@ output relation AggregateCnt3(cnt: bit<64>) AggregateCnt3(cnt) :- AggregateMe1(x,y), y != "1", var cnt = Aggregate((), group_sum(1: bit<64>)). output relation Aggregate2(x: string, set: Set) -Aggregate2(x, set) :- AggregateMe1(x,y), var set = Aggregate((x), group2set(y)). +Aggregate2(x, set) :- AggregateMe1(x,y), var set = Aggregate((x), group_to_set(y)). output relation Aggregate3(x: string, vec: Vec) -Aggregate3(x, vec) :- AggregateMe1(x,y), var vec = Aggregate((x), group2vec(y)). +Aggregate3(x, vec) :- AggregateMe1(x,y), var vec = Aggregate((x), group_to_vec(y)). output relation Aggregate4(x: string, map: Map) -Aggregate4(x, map) :- AggregateMe1(x,y), var map = Aggregate((x), group2map((x,y))). +Aggregate4(x, map) :- AggregateMe1(x,y), var map = Aggregate((x), group_to_map((x,y))). output relation Disaggregate(x: string, y: string) -Disaggregate(x,y) :- AggregateMe1(x,y), var set = Aggregate((x), group2set(y)), var y = FlatMap(set). +Disaggregate(x,y) :- AggregateMe1(x,y), var set = Aggregate((x), group_to_set(y)), var y = FlatMap(set). input relation AggregateMeInts(x: string, y: bit<32>) @@ -800,11 +800,11 @@ Allocation(name, id, x) :- relation ToAllocate(name: string, ids: Vec) ToAllocate(name, ids) :- - Request(name, id), not Realized(name, id, _), var ids = Aggregate((name), group2vec(id)). + Request(name, id), not Realized(name, id, _), var ids = Aggregate((name), group_to_vec(id)). relation Allocated(name: string, xs: Set>) Allocated(name, xs) :- - Realized(name, _, x), var xs = Aggregate((name), group2set(x)). + Realized(name, _, x), var xs = Aggregate((name), group_to_set(x)). Allocation(name, id, x) :- ToAllocate(name, ids), @@ -1152,7 +1152,7 @@ output relation Span(entity: entid_t, tns: Set) Span(entity: entid_t, bindings) :- DdlogNode(entity), DdlogBinding(tn, entity), - var bindings = Aggregate((entity), group2set(tn)). + var bindings = Aggregate((entity), group_to_set(tn)). /* Recursive step: propagate span along graph edges */ Span(parent, tns) :- diff --git a/test/datalog_tests/simple2.dat b/test/datalog_tests/simple2.dat index f33fd006b..a3fd97aeb 100644 --- a/test/datalog_tests/simple2.dat +++ b/test/datalog_tests/simple2.dat @@ -87,3 +87,6 @@ insert Chunk("{\"fild\": 1}"), insert Chunk("{\"field\": 2}"), commit dump_changes; + +dump Fib; +dump Ack; diff --git a/test/datalog_tests/simple2.debug.ast.expected b/test/datalog_tests/simple2.debug.ast.expected index 5063e72c0..af2d44c29 100644 --- a/test/datalog_tests/simple2.debug.ast.expected +++ b/test/datalog_tests/simple2.debug.ast.expected @@ -1,3 +1,4 @@ +typedef Ack = Ack{m: std.u64, n: std.u64, a: std.u64} typedef Arrng1 = Arrng1{f1: std.Ref>>, f2: bigint} typedef Arrng1Arrng2 = Arrng1Arrng2{x: bigint} typedef Arrng1Arrng2_2 = Arrng1Arrng2_2{x: bigint} @@ -6,6 +7,7 @@ typedef Chunk = Chunk{json: string} typedef ChunkParseError = ChunkParseError{err: string} typedef CompressedChunk = CompressedChunk{json: string} typedef Doubles = Doubles{xs: std.Vec} +typedef Fib = Fib{x: std.u64, f: std.u64} typedef FilteredRelation = FilteredRelation{y: bit<32>} typedef FuncTest = FuncTest{x: string} typedef InputInspectNot1 = InputInspectNot1{x: bit<32>, y: bit<32>} @@ -80,6 +82,18 @@ function __debug_8_1_std.group_sum (g: std.Group,('I, bit<32>)>): (std.V (((var inputs: std.Vec<'I>), (var original_group: std.Group,bit<32>>)) = debug.debug_split_group(g); (inputs, std.group_sum(original_group))) } +function ack (m: std.u64, n: std.u64): std.u64 +{ + if (m == 64'd0) { + (n + 64'd1) + } else { + if (n == 64'd0) { + ack((m - 64'd1), 64'd1) + } else { + ack((m - 64'd1), ack(m, (n - 64'd1))) + } + } +} function agg_avg_double_N (aggregate: std.Option<(double, double)>, item: std.Option): std.Option<(double, double)> { match ((aggregate, item)) { @@ -92,6 +106,18 @@ function agg_avg_double_N (aggregate: std.Option<(double, double)>, item: std.Op extern function debug.debug_event (operator_id: debug.DDlogOpId, w: std.DDWeight, ts: 'T1, operator_type: string, input1: 'A1, out: 'A2): () extern function debug.debug_event_join (operator_id: debug.DDlogOpId, w: std.DDWeight, ts: 'T1, input1: 'A1, input2: 'A2, out: 'A3): () extern function debug.debug_split_group (g: std.Group<'K,('I, 'V)>): (std.Vec<'I>, std.Group<'K,'V>) +function fib (x: std.u64): std.u64 +{ + if (x == 64'd0) { + 64'd0 + } else { + if (x == 64'd1) { + 64'd1 + } else { + (fib((x - 64'd1)) + fib((x - 64'd2))) + } + } +} extern function fp.abs_d (f: double): double extern function fp.abs_f (f: float): float extern function fp.acos_d (f: double): double @@ -181,6 +207,14 @@ function ftoi_ (l: double): signed<32> } #[has_side_effects = true] extern function inspect_log.log (filename: string, msg: string): () +function internment.contains (s1: internment.istring, s2: string): bool +{ + internment.istring_contains(s1, s2) +} +function internment.ends_with (s: internment.istring, suffix: string): bool +{ + internment.istring_ends_with(s, suffix) +} extern function internment.intern (s: 'A): internment.Intern<'A> extern function internment.istring_contains (s1: internment.istring, s2: string): bool extern function internment.istring_ends_with (s: internment.istring, suffix: string): bool @@ -197,6 +231,50 @@ extern function internment.istring_to_uppercase (s: internment.istring): string extern function internment.istring_trim (s: internment.istring): string #[return_by_ref = true] extern function internment.ival (s: internment.Intern<'A>): 'A +function internment.join (strings: std.Vec, sep: string): string +{ + internment.istring_join(strings, sep) +} +function internment.len (s: internment.istring): std.usize +{ + internment.istring_len(s) +} +function internment.replace (s: internment.istring, from: string, to: string): string +{ + internment.istring_replace(s, from, to) +} +function internment.reverse (s: internment.istring): string +{ + internment.istring_reverse(s) +} +function internment.split (s: internment.istring, sep: string): std.Vec +{ + internment.istring_split(s, sep) +} +function internment.starts_with (s: internment.istring, prefix: string): bool +{ + internment.istring_starts_with(s, prefix) +} +function internment.substr (s: internment.istring, start: std.usize, end: std.usize): string +{ + internment.istring_substr(s, start, end) +} +function internment.to_bytes (s: internment.istring): std.Vec +{ + internment.istring_to_bytes(s) +} +function internment.to_lowercase (s: internment.istring): string +{ + internment.istring_to_lowercase(s) +} +function internment.to_uppercase (s: internment.istring): string +{ + internment.istring_to_uppercase(s) +} +function internment.trim (s: internment.istring): string +{ + internment.istring_trim(s) +} extern function json.from_json_string (json: string): std.Result<'T,string> function json.jval_as_array (v: json.JsonValue): std.Option> { @@ -278,7 +356,7 @@ function json.jval_get (v: json.JsonValue, attr: internment.istring): std.Option function json.jval_get_or (v: json.JsonValue, attr: internment.istring, def: json.JsonValue): json.JsonValue { match (v) { - (json.JsonObject{.o=(var o: std.Map,json.JsonValue>)}: json.JsonValue) -> (std.option_unwrap_or((std.map_get(o, attr): std.Option), def): json.JsonValue), + (json.JsonObject{.o=(var o: std.Map,json.JsonValue>)}: json.JsonValue) -> (std.unwrap_or((std.map_get(o, attr): std.Option), def): json.JsonValue), (_: json.JsonValue) -> def } } @@ -290,16 +368,52 @@ function myfunc (x: string): string x } extern function std.__builtin_2string (x: 'X): string +function std.append (v: mut std.Vec<'X>, other: std.Vec<'X>): () +{ + std.vec_append(v, other) +} +function std.contains (s1: string, s2: string): bool +{ + std.string_contains(s1, s2) +} +function std.contains (v: std.Vec<'X>, x: 'X): bool +{ + std.vec_contains(v, x) +} +function std.contains (s: std.Set<'X>, v: 'X): bool +{ + std.set_contains(s, v) +} +function std.contains_key (m: std.Map<'K,'V>, k: 'K): bool +{ + std.map_contains_key(m, k) +} +function std.count (g: std.Group<'K,'V>): std.usize +{ + std.group_count(g) +} function std.dDNestedTS2string (ts: std.DDNestedTS): string { (((("(" ++ (std.__builtin_2string(ts.epoch): string)) ++ ",") ++ (std.__builtin_2string(ts.iter): string)) ++ ")") } #[return_by_ref = true] extern function std.deref (x: std.Ref<'A>): 'A -extern function std.group2map (g: std.Group<'K1,('K2, 'V)>): std.Map<'K2,'V> -extern function std.group2set (g: std.Group<'K,'V>): std.Set<'V> -extern function std.group2setmap (g: std.Group<'K1,('K2, 'V)>): std.Map<'K2,std.Set<'V>> -extern function std.group2vec (g: std.Group<'K,'V>): std.Vec<'V> +function std.difference (s1: std.Set<'X>, s2: std.Set<'X>): std.Set<'X> +{ + (std.set_difference(s1, s2): std.Set<'X>) +} +function std.ends_with (s: string, suffix: string): bool +{ + std.string_ends_with(s, suffix) +} +function std.first (g: std.Group<'K,'V>): 'V +{ + (std.group_first(g): 'V) +} +function std.get (m: std.Map<'K,'V>, k: 'K): std.Option<'V> +{ + (std.map_get(m, k): std.Option<'V>) +} extern function std.group_count (g: std.Group<'K,'V>): std.usize extern function std.group_first (g: std.Group<'K,'V>): 'V extern function std.group_key (g: std.Group<'K,'V>): 'K @@ -309,6 +423,10 @@ extern function std.group_nth (g: std.Group<'K,'V>, n: std.usize): std.Option<'V extern function std.group_set_unions (g: std.Group<'K,std.Set<'A>>): std.Set<'A> extern function std.group_setref_unions (g: std.Group<'K,std.Ref>>): std.Ref> extern function std.group_sum (g: std.Group<'K,'V>): 'V +extern function std.group_to_map (g: std.Group<'K1,('K2, 'V)>): std.Map<'K2,'V> +extern function std.group_to_set (g: std.Group<'K,'V>): std.Set<'V> +extern function std.group_to_setmap (g: std.Group<'K1,('K2, 'V)>): std.Map<'K2,std.Set<'V>> +extern function std.group_to_vec (g: std.Group<'K,'V>): std.Vec<'V> function std.group_unzip (g: std.Group<'K,('X, 'Y)>): (std.Vec<'X>, std.Vec<'Y>) { ((var xs: std.Vec<'X>) = (std.vec_empty(): std.Vec<'X>); @@ -325,6 +443,38 @@ extern function std.hash64 (x: 'X): bit<64> extern function std.hex (x: 'X): string extern function std.htonl (x: bit<32>): bit<32> extern function std.htons (x: bit<16>): bit<16> +function std.insert (m: mut std.Map<'K,'V>, k: 'K, v: 'V): () +{ + std.map_insert(m, k, v) +} +function std.insert (s: mut std.Set<'X>, v: 'X): () +{ + std.set_insert(s, v) +} +function std.insert_imm (m: std.Map<'K,'V>, k: 'K, v: 'V): std.Map<'K,'V> +{ + (std.map_insert_imm(m, k, v): std.Map<'K,'V>) +} +function std.insert_imm (s: std.Set<'X>, v: 'X): std.Set<'X> +{ + (std.set_insert_imm(s, v): std.Set<'X>) +} +function std.intersection (s1: std.Set<'X>, s2: std.Set<'X>): std.Set<'X> +{ + (std.set_intersection(s1, s2): std.Set<'X>) +} +function std.is_empty (v: std.Vec<'X>): bool +{ + std.vec_is_empty(v) +} +function std.is_empty (m: std.Map<'K,'V>): bool +{ + std.map_is_empty(m) +} +function std.is_empty (s: std.Set<'X>): bool +{ + std.set_is_empty(s) +} function std.is_err (res: std.Result<'V,'E>): bool { match (res) { @@ -353,6 +503,22 @@ function std.is_some (x: std.Option<'A>): bool (_: std.Option<'A>) -> false } } +function std.join (strings: std.Vec, sep: string): string +{ + std.string_join(strings, sep) +} +function std.key (g: std.Group<'K,'V>): 'K +{ + (std.group_key(g): 'K) +} +function std.len (s: string): std.usize +{ + std.string_len(s) +} +function std.len (v: std.Vec<'X>): std.usize +{ + std.vec_len(v) +} extern function std.map_contains_key (m: std.Map<'K,'V>, k: 'K): bool extern function std.map_empty (): std.Map<'K,'V> extern function std.map_get (m: std.Map<'K,'V>, k: 'K): std.Option<'V> @@ -371,6 +537,10 @@ function std.max (x: 'A, y: 'A): 'A y } } +function std.max (g: std.Group<'K,'V>): 'V +{ + (std.group_max(g): 'V) +} function std.min (x: 'A, y: 'A): 'A { if (x < y) { @@ -379,44 +549,51 @@ function std.min (x: 'A, y: 'A): 'A y } } -extern function std.ntohl (x: bit<32>): bit<32> -extern function std.ntohs (x: bit<16>): bit<16> -function std.option2set (o: std.Option<'X>): std.Set<'X> +function std.min (g: std.Group<'K,'V>): 'V { - match (o) { - (std.Some{.x=(var x: 'X)}: std.Option<'X>) -> (std.set_singleton(x): std.Set<'X>), - (std.None{}: std.Option<'X>) -> (std.set_empty(): std.Set<'X>) - } + (std.group_min(g): 'V) } -function std.option2vec (o: std.Option<'X>): std.Vec<'X> +function std.nth (g: std.Group<'K,'V>, n: std.usize): std.Option<'V> { - match (o) { - (std.Some{.x=(var x: 'X)}: std.Option<'X>) -> (std.vec_singleton(x): std.Vec<'X>), - (std.None{}: std.Option<'X>) -> (std.vec_empty(): std.Vec<'X>) - } + (std.group_nth(g, n): std.Option<'V>) } -function std.option_unwrap_or (x: std.Option<'A>, def: 'A): 'A +function std.nth (v: std.Vec<'X>, n: std.usize): std.Option<'X> { - match (x) { - (std.Some{.x=(var v: 'A)}: std.Option<'A>) -> v, - (std.None{}: std.Option<'A>) -> def - } + (std.vec_nth(v, n): std.Option<'X>) +} +function std.nth (s: std.Set<'X>, n: std.usize): std.Option<'X> +{ + (std.set_nth(s, n): std.Option<'X>) } +extern function std.ntohl (x: bit<32>): bit<32> +extern function std.ntohs (x: bit<16>): bit<16> extern function std.option_unwrap_or_default (opt: std.Option<'A>): 'A extern function std.parse_dec_i64 (s: string): std.Option> extern function std.parse_dec_u64 (s: string): std.Option> extern function std.pow32 (base: 'A, exp: bit<32>): 'A +function std.push (v: mut std.Vec<'X>, x: 'X): () +{ + std.vec_push(v, x) +} +function std.push_imm (v: std.Vec<'X>, x: 'X): std.Vec<'X> +{ + (std.vec_push_imm(v, x): std.Vec<'X>) +} extern function std.range (from: 'A, to: 'A, step: 'A): std.Vec<'A> extern function std.ref_new (x: 'A): std.Ref<'A> -function std.result_unwrap_or (res: std.Result<'V,'E>, def: 'V): 'V +function std.remove (m: mut std.Map<'K,'V>, k: 'K): () { - match (res) { - (std.Ok{.res=(var v: 'V)}: std.Result<'V,'E>) -> v, - (std.Err{.err=(_: 'E)}: std.Result<'V,'E>) -> def - } + std.map_remove(m, k) +} +function std.replace (s: string, from: string, to: string): string +{ + std.string_replace(s, from, to) } extern function std.result_unwrap_or_default (res: std.Result<'V,'E>): 'V -extern function std.set2vec (s: std.Set<'A>): std.Vec<'A> +function std.reverse (s: string): string +{ + std.string_reverse(s) +} extern function std.set_contains (s: std.Set<'X>, v: 'X): bool extern function std.set_difference (s1: std.Set<'X>, s2: std.Set<'X>): std.Set<'X> extern function std.set_empty (): std.Set<'X> @@ -427,8 +604,37 @@ extern function std.set_is_empty (s: std.Set<'X>): bool extern function std.set_nth (s: std.Set<'X>, n: std.usize): std.Option<'X> extern function std.set_singleton (x: 'X): std.Set<'X> extern function std.set_size (s: std.Set<'X>): std.usize +extern function std.set_to_vec (s: std.Set<'A>): std.Vec<'A> extern function std.set_union (s1: std.Set<'X>, s2: std.Set<'X>): std.Set<'X> extern function std.set_unions (sets: std.Vec>): std.Set<'X> +function std.setref_unions (g: std.Group<'K,std.Ref>>): std.Ref> +{ + (std.group_setref_unions(g): std.Ref>) +} +function std.size (m: std.Map<'K,'V>): std.usize +{ + std.map_size(m) +} +function std.size (s: std.Set<'X>): std.usize +{ + std.set_size(s) +} +function std.sort (v: mut std.Vec<'X>): () +{ + std.vec_sort(v) +} +function std.sort_imm (v: std.Vec<'X>): std.Vec<'X> +{ + (std.vec_sort_imm(v): std.Vec<'X>) +} +function std.split (s: string, sep: string): std.Vec +{ + std.string_split(s, sep) +} +function std.starts_with (s: string, prefix: string): bool +{ + std.string_starts_with(s, prefix) +} extern function std.str_to_lower (s: string): string extern function std.string_contains (s1: string, s2: string): bool extern function std.string_ends_with (s: string, suffix: string): bool @@ -443,7 +649,98 @@ extern function std.string_to_bytes (s: string): std.Vec extern function std.string_to_lowercase (s: string): string extern function std.string_to_uppercase (s: string): string extern function std.string_trim (s: string): string -extern function std.vec2set (s: std.Vec<'A>): std.Set<'A> +function std.substr (s: string, start: std.usize, end: std.usize): string +{ + std.string_substr(s, start, end) +} +function std.to_bytes (s: string): std.Vec +{ + std.string_to_bytes(s) +} +function std.to_lowercase (s: string): string +{ + std.string_to_lowercase(s) +} +function std.to_map (g: std.Group<'K1,('K2, 'V)>): std.Map<'K2,'V> +{ + (std.group_to_map(g): std.Map<'K2,'V>) +} +function std.to_set (o: std.Option<'X>): std.Set<'X> +{ + match (o) { + (std.Some{.x=(var x: 'X)}: std.Option<'X>) -> (std.set_singleton(x): std.Set<'X>), + (std.None{}: std.Option<'X>) -> (std.set_empty(): std.Set<'X>) + } +} +function std.to_set (g: std.Group<'K,'V>): std.Set<'V> +{ + (std.group_to_set(g): std.Set<'V>) +} +function std.to_set (s: std.Vec<'A>): std.Set<'A> +{ + (std.vec_to_set(s): std.Set<'A>) +} +function std.to_setmap (g: std.Group<'K1,('K2, 'V)>): std.Map<'K2,std.Set<'V>> +{ + (std.group_to_setmap(g): std.Map<'K2,std.Set<'V>>) +} +function std.to_uppercase (s: string): string +{ + std.string_to_uppercase(s) +} +function std.to_vec (o: std.Option<'X>): std.Vec<'X> +{ + match (o) { + (std.Some{.x=(var x: 'X)}: std.Option<'X>) -> (std.vec_singleton(x): std.Vec<'X>), + (std.None{}: std.Option<'X>) -> (std.vec_empty(): std.Vec<'X>) + } +} +function std.to_vec (g: std.Group<'K,'V>): std.Vec<'V> +{ + (std.group_to_vec(g): std.Vec<'V>) +} +function std.to_vec (s: std.Set<'A>): std.Vec<'A> +{ + (std.set_to_vec(s): std.Vec<'A>) +} +function std.trim (s: string): string +{ + std.string_trim(s) +} +function std.union (m1: std.Map<'K,'V>, m2: std.Map<'K,'V>): std.Map<'K,'V> +{ + (std.map_union(m1, m2): std.Map<'K,'V>) +} +function std.union (s1: std.Set<'X>, s2: std.Set<'X>): std.Set<'X> +{ + (std.set_union(s1, s2): std.Set<'X>) +} +function std.unions (sets: std.Vec>): std.Set<'X> +{ + (std.set_unions(sets): std.Set<'X>) +} +function std.unwrap_or (x: std.Option<'A>, def: 'A): 'A +{ + match (x) { + (std.Some{.x=(var v: 'A)}: std.Option<'A>) -> v, + (std.None{}: std.Option<'A>) -> def + } +} +function std.unwrap_or (res: std.Result<'V,'E>, def: 'V): 'V +{ + match (res) { + (std.Ok{.res=(var v: 'V)}: std.Result<'V,'E>) -> v, + (std.Err{.err=(_: 'E)}: std.Result<'V,'E>) -> def + } +} +function std.unwrap_or_default (opt: std.Option<'A>): 'A +{ + (std.option_unwrap_or_default(opt): 'A) +} +function std.unwrap_or_default (res: std.Result<'V,'E>): 'V +{ + (std.result_unwrap_or_default(res): 'V) +} extern function std.vec_append (v: mut std.Vec<'X>, other: std.Vec<'X>): () extern function std.vec_contains (v: std.Vec<'X>, x: 'X): bool extern function std.vec_empty (): std.Vec<'A> @@ -453,8 +750,9 @@ extern function std.vec_nth (v: std.Vec<'X>, n: std.usize): std.Option<'X> extern function std.vec_push (v: mut std.Vec<'X>, x: 'X): () extern function std.vec_push_imm (v: std.Vec<'X>, x: 'X): std.Vec<'X> extern function std.vec_singleton (x: 'X): std.Vec<'X> -extern function std.vec_sort (v: std.Vec<'X>): () +extern function std.vec_sort (v: mut std.Vec<'X>): () extern function std.vec_sort_imm (v: std.Vec<'X>): std.Vec<'X> +extern function std.vec_to_set (s: std.Vec<'A>): std.Set<'A> extern function std.vec_with_capacity (len: std.usize): std.Vec<'A> extern function std.vec_with_length (len: std.usize, x: 'A): std.Vec<'A> function ti_f (value: std.Option): std.Option<(string, string)> @@ -491,6 +789,7 @@ function zero_test (): std.usize { weird_zero(32'd0) } +output relation Ack [Ack] input relation Arrng1 [Arrng1] output relation Arrng1Arrng2 [Arrng1Arrng2] output relation Arrng1Arrng2_2 [Arrng1Arrng2_2] @@ -499,6 +798,7 @@ input multiset Chunk [Chunk] output multiset ChunkParseError [ChunkParseError] output multiset CompressedChunk [CompressedChunk] input relation Doubles [Doubles] +output relation Fib [Fib] output relation FilteredRelation [FilteredRelation] output relation FuncTest [std.Ref] input relation InputInspectNot1 [InputInspectNot1] @@ -553,4 +853,12 @@ ChunkParseError[(ChunkParseError{.err=err}: ChunkParseError)] :- ParsedChunk[(__ ParsedChunk[(ParsedChunk{.data=(json.from_json_string(json): std.Result)}: ParsedChunk)] :- Chunk[(__chunk0@ (Chunk{.json=(json: string)}: Chunk))], Inspect debug.debug_event((32'd13, 32'd0, 32'd0), ddlog_weight, ddlog_timestamp, "Map", __chunk0, (ParsedChunk{.data=(json.from_json_string(json): std.Result)}: ParsedChunk)). Objects[(Objects{.chunk=objs}: Objects)] :- ParsedChunk[(__parsedchunk0@ (ParsedChunk{.data=(std.Ok{.res=(objs: Object)}: std.Result)}: ParsedChunk))], Inspect debug.debug_event((32'd14, 32'd0, 32'd0), ddlog_weight, ddlog_timestamp, "Map", __parsedchunk0, (Objects{.chunk=objs}: Objects)). CompressedChunk[(CompressedChunk{.json=json}: CompressedChunk)] :- Objects[(__objects0@ (Objects{.chunk=(objs: Object)}: Objects))], (std.Ok{.res=(var json: string)}: std.Result) = json.to_json_string(objs), Inspect debug.debug_event((32'd15, 32'd1, 32'd0), ddlog_weight, ddlog_timestamp, "Condition", __objects0, (CompressedChunk{.json=json}: CompressedChunk)). +Fib[(Fib{.x=64'd0, .f=fib(64'd0)}: Fib)]. +Fib[(Fib{.x=64'd1, .f=fib(64'd1)}: Fib)]. +Fib[(Fib{.x=64'd2, .f=fib(64'd2)}: Fib)]. +Fib[(Fib{.x=64'd3, .f=fib(64'd3)}: Fib)]. +Fib[(Fib{.x=64'd4, .f=fib(64'd4)}: Fib)]. +Fib[(Fib{.x=64'd10, .f=fib(64'd10)}: Fib)]. +Fib[(Fib{.x=64'd20, .f=fib(64'd20)}: Fib)]. +Ack[(Ack{.m=64'd2, .n=64'd1, .a=ack(64'd2, 64'd1)}: Ack)]. diff --git a/test/datalog_tests/simple2.dl b/test/datalog_tests/simple2.dl index 72112f0a7..5daf98218 100644 --- a/test/datalog_tests/simple2.dl +++ b/test/datalog_tests/simple2.dl @@ -206,3 +206,43 @@ output multiset CompressedChunk(json: string) CompressedChunk(json) :- Objects(objs), Ok{var json} = to_json_string(objs). + +/* + * Recursive functions + */ + +// Fibonacci sequence +function fib(x: u64): u64 { + if (x == 0) { + 0 + } else if (x == 1) { + 1 + } else { + fib(x-1) + fib(x-2) + } +} + +output relation Fib(x: u64, f: u64) + +Fib(0, fib(0)). +Fib(1, fib(1)). +Fib(2, fib(2)). +Fib(3, fib(3)). +Fib(4, fib(4)). +Fib(10, fib(10)). +Fib(20, fib(20)). + +// Ackerman-Peter function +function ack(m: u64, n: u64): u64 { + if (m == 0) { + n + 1 + } else if (n == 0) { + ack(m-1, 1) + } else { + ack(m-1, ack(m, n-1)) + } +} + +output relation Ack(m: u64, n: u64, a: u64) + +Ack(2, 1, ack(2,1)). diff --git a/test/datalog_tests/simple2.dump.expected b/test/datalog_tests/simple2.dump.expected index 8587baeef..0305a571f 100644 --- a/test/datalog_tests/simple2.dump.expected +++ b/test/datalog_tests/simple2.dump.expected @@ -1,3 +1,13 @@ +Ack: +Ack{.m = 2, .n = 1, .a = 5}: +1 +Fib: +Fib{.x = 0, .f = 0}: +1 +Fib{.x = 1, .f = 1}: +1 +Fib{.x = 2, .f = 1}: +1 +Fib{.x = 3, .f = 2}: +1 +Fib{.x = 4, .f = 3}: +1 +Fib{.x = 10, .f = 55}: +1 +Fib{.x = 20, .f = 6765}: +1 FuncTest: FuncTest{.x = "foo"}: +1 RFloatToInt: @@ -41,3 +51,11 @@ ChunkParseError{.err = "missing field `field` at line 1 column 11"}: +1 CompressedChunk: CompressedChunk{.json = "{\"field\":1}"}: +2 CompressedChunk{.json = "{\"field\":2}"}: +1 +Fib{.x = 0, .f = 0} +Fib{.x = 1, .f = 1} +Fib{.x = 2, .f = 1} +Fib{.x = 3, .f = 2} +Fib{.x = 4, .f = 3} +Fib{.x = 10, .f = 55} +Fib{.x = 20, .f = 6765} +Ack{.m = 2, .n = 1, .a = 5} diff --git a/test/datalog_tests/strings.fail.ast.expected b/test/datalog_tests/strings.fail.ast.expected index c13170c8f..916d94598 100644 --- a/test/datalog_tests/strings.fail.ast.expected +++ b/test/datalog_tests/strings.fail.ast.expected @@ -21,7 +21,7 @@ expression '"string"' var s = "string"; ^^^^^^^^ -error: ./test/datalog_tests/strings.fail.dl:7:18-7:19: Cannot find declaration of function type12string needed to convert expression x to string +error: ./test/datalog_tests/strings.fail.dl:7:18-7:19: Cannot find declaration of function 'type12string' needed to convert expression 'x' to string var err = "${x}"; // don't know how to convert x to string ^ @@ -29,6 +29,6 @@ error: ./test/datalog_tests/strings.fail.dl:6:24-6:28: Unknown variable: str1 var err = "${str2++str1}"; // str1 is not declared in this scope ^^^^ -error: ./test/datalog_tests/strings.fail.dl:19:52-19:53: Cannot match expected type bigint and actual type serializable_t in the call to string conversion function "serializable_t2string" +error: ./test/datalog_tests/strings.fail.dl:19:52-19:53: Cannot find declaration of function 'serializable_t2string' needed to convert expression 'e' to string var err = "a=${a}, b=${b}, c=${c}, d=${d}, e:${e}"; ^ diff --git a/test/datalog_tests/tinyset_test.dl b/test/datalog_tests/tinyset_test.dl index 340e598b6..2f1dc207e 100644 --- a/test/datalog_tests/tinyset_test.dl +++ b/test/datalog_tests/tinyset_test.dl @@ -5,7 +5,7 @@ input relation SetElement(setid: string, element: u32) output relation Sets(setid: string, set: TS.Set64) Sets(setid, set) :- SetElement(setid, v), - var set = Aggregate((setid), TS.group2set(v)). + var set = Aggregate((setid), TS.group_to_set(v)). output relation Intersects(setid1: string, setid2: string, set: TS.Set64) diff --git a/test/datalog_tests/tutorial.debug.ast.expected b/test/datalog_tests/tutorial.debug.ast.expected index 829319ec1..6e46d7a48 100644 --- a/test/datalog_tests/tutorial.debug.ast.expected +++ b/test/datalog_tests/tutorial.debug.ast.expected @@ -153,10 +153,10 @@ function __debug_32_1_std.group_max (g: std.Group)>): (std.V (((var inputs: std.Vec<'I>), (var original_group: std.Group>)) = debug.debug_split_group(g); (inputs, std.group_max(original_group))) } -function __debug_33_1_std.group2vec (g: std.Group,('I, bit<64>)>): (std.Vec<'I>, std.Vec>) +function __debug_33_1_std.group_to_vec (g: std.Group,('I, bit<64>)>): (std.Vec<'I>, std.Vec>) { (((var inputs: std.Vec<'I>), (var original_group: std.Group,bit<64>>)) = debug.debug_split_group(g); - (inputs, std.group2vec(original_group))) + (inputs, std.group_to_vec(original_group))) } function addr_port (ip: ip_addr_t, proto: string, preferred_port: bit<16>): string { @@ -221,6 +221,14 @@ function evens (vec: std.Vec): std.Vec } #[has_side_effects = true] extern function inspect_log.log (filename: string, msg: string): () +function internment.contains (s1: internment.istring, s2: string): bool +{ + internment.istring_contains(s1, s2) +} +function internment.ends_with (s: internment.istring, suffix: string): bool +{ + internment.istring_ends_with(s, suffix) +} extern function internment.intern (s: 'A): internment.Intern<'A> extern function internment.istring_contains (s1: internment.istring, s2: string): bool extern function internment.istring_ends_with (s: internment.istring, suffix: string): bool @@ -237,6 +245,50 @@ extern function internment.istring_to_uppercase (s: internment.istring): string extern function internment.istring_trim (s: internment.istring): string #[return_by_ref = true] extern function internment.ival (s: internment.Intern<'A>): 'A +function internment.join (strings: std.Vec, sep: string): string +{ + internment.istring_join(strings, sep) +} +function internment.len (s: internment.istring): std.usize +{ + internment.istring_len(s) +} +function internment.replace (s: internment.istring, from: string, to: string): string +{ + internment.istring_replace(s, from, to) +} +function internment.reverse (s: internment.istring): string +{ + internment.istring_reverse(s) +} +function internment.split (s: internment.istring, sep: string): std.Vec +{ + internment.istring_split(s, sep) +} +function internment.starts_with (s: internment.istring, prefix: string): bool +{ + internment.istring_starts_with(s, prefix) +} +function internment.substr (s: internment.istring, start: std.usize, end: std.usize): string +{ + internment.istring_substr(s, start, end) +} +function internment.to_bytes (s: internment.istring): std.Vec +{ + internment.istring_to_bytes(s) +} +function internment.to_lowercase (s: internment.istring): string +{ + internment.istring_to_lowercase(s) +} +function internment.to_uppercase (s: internment.istring): string +{ + internment.istring_to_uppercase(s) +} +function internment.trim (s: internment.istring): string +{ + internment.istring_trim(s) +} function ip_addr_t2string (ip: ip_addr_t): string { ((((((("" ++ (std.__builtin_2string(ip.addr[31:24]): string)) ++ ".") ++ (std.__builtin_2string(ip.addr[23:16]): string)) ++ ".") ++ (std.__builtin_2string(ip.addr[15:8]): string)) ++ ".") ++ (std.__builtin_2string(ip.addr[7:0]): string)) @@ -306,22 +358,57 @@ function prefixBefore (vec: std.Vec<'A>, v: 'A): std.Vec<'A> }; res)) } -extern function split (s: string, sep: string): std.Vec function split_ip_list (x: string): std.Vec { - split(x, " ") + std.split(x, " ") } extern function std.__builtin_2string (x: 'X): string +function std.append (v: mut std.Vec<'X>, other: std.Vec<'X>): () +{ + std.vec_append(v, other) +} +function std.contains (s1: string, s2: string): bool +{ + std.string_contains(s1, s2) +} +function std.contains (v: std.Vec<'X>, x: 'X): bool +{ + std.vec_contains(v, x) +} +function std.contains (s: std.Set<'X>, v: 'X): bool +{ + std.set_contains(s, v) +} +function std.contains_key (m: std.Map<'K,'V>, k: 'K): bool +{ + std.map_contains_key(m, k) +} +function std.count (g: std.Group<'K,'V>): std.usize +{ + std.group_count(g) +} function std.dDNestedTS2string (ts: std.DDNestedTS): string { (((("(" ++ (std.__builtin_2string(ts.epoch): string)) ++ ",") ++ (std.__builtin_2string(ts.iter): string)) ++ ")") } #[return_by_ref = true] extern function std.deref (x: std.Ref<'A>): 'A -extern function std.group2map (g: std.Group<'K1,('K2, 'V)>): std.Map<'K2,'V> -extern function std.group2set (g: std.Group<'K,'V>): std.Set<'V> -extern function std.group2setmap (g: std.Group<'K1,('K2, 'V)>): std.Map<'K2,std.Set<'V>> -extern function std.group2vec (g: std.Group<'K,'V>): std.Vec<'V> +function std.difference (s1: std.Set<'X>, s2: std.Set<'X>): std.Set<'X> +{ + (std.set_difference(s1, s2): std.Set<'X>) +} +function std.ends_with (s: string, suffix: string): bool +{ + std.string_ends_with(s, suffix) +} +function std.first (g: std.Group<'K,'V>): 'V +{ + (std.group_first(g): 'V) +} +function std.get (m: std.Map<'K,'V>, k: 'K): std.Option<'V> +{ + (std.map_get(m, k): std.Option<'V>) +} extern function std.group_count (g: std.Group<'K,'V>): std.usize extern function std.group_first (g: std.Group<'K,'V>): 'V extern function std.group_key (g: std.Group<'K,'V>): 'K @@ -331,6 +418,10 @@ extern function std.group_nth (g: std.Group<'K,'V>, n: std.usize): std.Option<'V extern function std.group_set_unions (g: std.Group<'K,std.Set<'A>>): std.Set<'A> extern function std.group_setref_unions (g: std.Group<'K,std.Ref>>): std.Ref> extern function std.group_sum (g: std.Group<'K,'V>): 'V +extern function std.group_to_map (g: std.Group<'K1,('K2, 'V)>): std.Map<'K2,'V> +extern function std.group_to_set (g: std.Group<'K,'V>): std.Set<'V> +extern function std.group_to_setmap (g: std.Group<'K1,('K2, 'V)>): std.Map<'K2,std.Set<'V>> +extern function std.group_to_vec (g: std.Group<'K,'V>): std.Vec<'V> function std.group_unzip (g: std.Group<'K,('X, 'Y)>): (std.Vec<'X>, std.Vec<'Y>) { ((var xs: std.Vec<'X>) = (std.vec_empty(): std.Vec<'X>); @@ -347,6 +438,38 @@ extern function std.hash64 (x: 'X): bit<64> extern function std.hex (x: 'X): string extern function std.htonl (x: bit<32>): bit<32> extern function std.htons (x: bit<16>): bit<16> +function std.insert (m: mut std.Map<'K,'V>, k: 'K, v: 'V): () +{ + std.map_insert(m, k, v) +} +function std.insert (s: mut std.Set<'X>, v: 'X): () +{ + std.set_insert(s, v) +} +function std.insert_imm (m: std.Map<'K,'V>, k: 'K, v: 'V): std.Map<'K,'V> +{ + (std.map_insert_imm(m, k, v): std.Map<'K,'V>) +} +function std.insert_imm (s: std.Set<'X>, v: 'X): std.Set<'X> +{ + (std.set_insert_imm(s, v): std.Set<'X>) +} +function std.intersection (s1: std.Set<'X>, s2: std.Set<'X>): std.Set<'X> +{ + (std.set_intersection(s1, s2): std.Set<'X>) +} +function std.is_empty (v: std.Vec<'X>): bool +{ + std.vec_is_empty(v) +} +function std.is_empty (m: std.Map<'K,'V>): bool +{ + std.map_is_empty(m) +} +function std.is_empty (s: std.Set<'X>): bool +{ + std.set_is_empty(s) +} function std.is_err (res: std.Result<'V,'E>): bool { match (res) { @@ -375,6 +498,22 @@ function std.is_some (x: std.Option<'A>): bool (_: std.Option<'A>) -> false } } +function std.join (strings: std.Vec, sep: string): string +{ + std.string_join(strings, sep) +} +function std.key (g: std.Group<'K,'V>): 'K +{ + (std.group_key(g): 'K) +} +function std.len (s: string): std.usize +{ + std.string_len(s) +} +function std.len (v: std.Vec<'X>): std.usize +{ + std.vec_len(v) +} extern function std.map_contains_key (m: std.Map<'K,'V>, k: 'K): bool extern function std.map_empty (): std.Map<'K,'V> extern function std.map_get (m: std.Map<'K,'V>, k: 'K): std.Option<'V> @@ -393,6 +532,10 @@ function std.max (x: 'A, y: 'A): 'A y } } +function std.max (g: std.Group<'K,'V>): 'V +{ + (std.group_max(g): 'V) +} function std.min (x: 'A, y: 'A): 'A { if (x < y) { @@ -401,44 +544,51 @@ function std.min (x: 'A, y: 'A): 'A y } } -extern function std.ntohl (x: bit<32>): bit<32> -extern function std.ntohs (x: bit<16>): bit<16> -function std.option2set (o: std.Option<'X>): std.Set<'X> +function std.min (g: std.Group<'K,'V>): 'V { - match (o) { - (std.Some{.x=(var x: 'X)}: std.Option<'X>) -> (std.set_singleton(x): std.Set<'X>), - (std.None{}: std.Option<'X>) -> (std.set_empty(): std.Set<'X>) - } + (std.group_min(g): 'V) } -function std.option2vec (o: std.Option<'X>): std.Vec<'X> +function std.nth (g: std.Group<'K,'V>, n: std.usize): std.Option<'V> { - match (o) { - (std.Some{.x=(var x: 'X)}: std.Option<'X>) -> (std.vec_singleton(x): std.Vec<'X>), - (std.None{}: std.Option<'X>) -> (std.vec_empty(): std.Vec<'X>) - } + (std.group_nth(g, n): std.Option<'V>) } -function std.option_unwrap_or (x: std.Option<'A>, def: 'A): 'A +function std.nth (v: std.Vec<'X>, n: std.usize): std.Option<'X> { - match (x) { - (std.Some{.x=(var v: 'A)}: std.Option<'A>) -> v, - (std.None{}: std.Option<'A>) -> def - } + (std.vec_nth(v, n): std.Option<'X>) } +function std.nth (s: std.Set<'X>, n: std.usize): std.Option<'X> +{ + (std.set_nth(s, n): std.Option<'X>) +} +extern function std.ntohl (x: bit<32>): bit<32> +extern function std.ntohs (x: bit<16>): bit<16> extern function std.option_unwrap_or_default (opt: std.Option<'A>): 'A extern function std.parse_dec_i64 (s: string): std.Option> extern function std.parse_dec_u64 (s: string): std.Option> extern function std.pow32 (base: 'A, exp: bit<32>): 'A +function std.push (v: mut std.Vec<'X>, x: 'X): () +{ + std.vec_push(v, x) +} +function std.push_imm (v: std.Vec<'X>, x: 'X): std.Vec<'X> +{ + (std.vec_push_imm(v, x): std.Vec<'X>) +} extern function std.range (from: 'A, to: 'A, step: 'A): std.Vec<'A> extern function std.ref_new (x: 'A): std.Ref<'A> -function std.result_unwrap_or (res: std.Result<'V,'E>, def: 'V): 'V +function std.remove (m: mut std.Map<'K,'V>, k: 'K): () { - match (res) { - (std.Ok{.res=(var v: 'V)}: std.Result<'V,'E>) -> v, - (std.Err{.err=(_: 'E)}: std.Result<'V,'E>) -> def - } + std.map_remove(m, k) +} +function std.replace (s: string, from: string, to: string): string +{ + std.string_replace(s, from, to) } extern function std.result_unwrap_or_default (res: std.Result<'V,'E>): 'V -extern function std.set2vec (s: std.Set<'A>): std.Vec<'A> +function std.reverse (s: string): string +{ + std.string_reverse(s) +} extern function std.set_contains (s: std.Set<'X>, v: 'X): bool extern function std.set_difference (s1: std.Set<'X>, s2: std.Set<'X>): std.Set<'X> extern function std.set_empty (): std.Set<'X> @@ -449,8 +599,37 @@ extern function std.set_is_empty (s: std.Set<'X>): bool extern function std.set_nth (s: std.Set<'X>, n: std.usize): std.Option<'X> extern function std.set_singleton (x: 'X): std.Set<'X> extern function std.set_size (s: std.Set<'X>): std.usize +extern function std.set_to_vec (s: std.Set<'A>): std.Vec<'A> extern function std.set_union (s1: std.Set<'X>, s2: std.Set<'X>): std.Set<'X> extern function std.set_unions (sets: std.Vec>): std.Set<'X> +function std.setref_unions (g: std.Group<'K,std.Ref>>): std.Ref> +{ + (std.group_setref_unions(g): std.Ref>) +} +function std.size (m: std.Map<'K,'V>): std.usize +{ + std.map_size(m) +} +function std.size (s: std.Set<'X>): std.usize +{ + std.set_size(s) +} +function std.sort (v: mut std.Vec<'X>): () +{ + std.vec_sort(v) +} +function std.sort_imm (v: std.Vec<'X>): std.Vec<'X> +{ + (std.vec_sort_imm(v): std.Vec<'X>) +} +function std.split (s: string, sep: string): std.Vec +{ + std.string_split(s, sep) +} +function std.starts_with (s: string, prefix: string): bool +{ + std.string_starts_with(s, prefix) +} extern function std.str_to_lower (s: string): string extern function std.string_contains (s1: string, s2: string): bool extern function std.string_ends_with (s: string, suffix: string): bool @@ -465,7 +644,98 @@ extern function std.string_to_bytes (s: string): std.Vec extern function std.string_to_lowercase (s: string): string extern function std.string_to_uppercase (s: string): string extern function std.string_trim (s: string): string -extern function std.vec2set (s: std.Vec<'A>): std.Set<'A> +function std.substr (s: string, start: std.usize, end: std.usize): string +{ + std.string_substr(s, start, end) +} +function std.to_bytes (s: string): std.Vec +{ + std.string_to_bytes(s) +} +function std.to_lowercase (s: string): string +{ + std.string_to_lowercase(s) +} +function std.to_map (g: std.Group<'K1,('K2, 'V)>): std.Map<'K2,'V> +{ + (std.group_to_map(g): std.Map<'K2,'V>) +} +function std.to_set (o: std.Option<'X>): std.Set<'X> +{ + match (o) { + (std.Some{.x=(var x: 'X)}: std.Option<'X>) -> (std.set_singleton(x): std.Set<'X>), + (std.None{}: std.Option<'X>) -> (std.set_empty(): std.Set<'X>) + } +} +function std.to_set (g: std.Group<'K,'V>): std.Set<'V> +{ + (std.group_to_set(g): std.Set<'V>) +} +function std.to_set (s: std.Vec<'A>): std.Set<'A> +{ + (std.vec_to_set(s): std.Set<'A>) +} +function std.to_setmap (g: std.Group<'K1,('K2, 'V)>): std.Map<'K2,std.Set<'V>> +{ + (std.group_to_setmap(g): std.Map<'K2,std.Set<'V>>) +} +function std.to_uppercase (s: string): string +{ + std.string_to_uppercase(s) +} +function std.to_vec (o: std.Option<'X>): std.Vec<'X> +{ + match (o) { + (std.Some{.x=(var x: 'X)}: std.Option<'X>) -> (std.vec_singleton(x): std.Vec<'X>), + (std.None{}: std.Option<'X>) -> (std.vec_empty(): std.Vec<'X>) + } +} +function std.to_vec (g: std.Group<'K,'V>): std.Vec<'V> +{ + (std.group_to_vec(g): std.Vec<'V>) +} +function std.to_vec (s: std.Set<'A>): std.Vec<'A> +{ + (std.set_to_vec(s): std.Vec<'A>) +} +function std.trim (s: string): string +{ + std.string_trim(s) +} +function std.union (m1: std.Map<'K,'V>, m2: std.Map<'K,'V>): std.Map<'K,'V> +{ + (std.map_union(m1, m2): std.Map<'K,'V>) +} +function std.union (s1: std.Set<'X>, s2: std.Set<'X>): std.Set<'X> +{ + (std.set_union(s1, s2): std.Set<'X>) +} +function std.unions (sets: std.Vec>): std.Set<'X> +{ + (std.set_unions(sets): std.Set<'X>) +} +function std.unwrap_or (x: std.Option<'A>, def: 'A): 'A +{ + match (x) { + (std.Some{.x=(var v: 'A)}: std.Option<'A>) -> v, + (std.None{}: std.Option<'A>) -> def + } +} +function std.unwrap_or (res: std.Result<'V,'E>, def: 'V): 'V +{ + match (res) { + (std.Ok{.res=(var v: 'V)}: std.Result<'V,'E>) -> v, + (std.Err{.err=(_: 'E)}: std.Result<'V,'E>) -> def + } +} +function std.unwrap_or_default (opt: std.Option<'A>): 'A +{ + (std.option_unwrap_or_default(opt): 'A) +} +function std.unwrap_or_default (res: std.Result<'V,'E>): 'V +{ + (std.result_unwrap_or_default(res): 'V) +} extern function std.vec_append (v: mut std.Vec<'X>, other: std.Vec<'X>): () extern function std.vec_contains (v: std.Vec<'X>, x: 'X): bool extern function std.vec_empty (): std.Vec<'A> @@ -475,8 +745,9 @@ extern function std.vec_nth (v: std.Vec<'X>, n: std.usize): std.Option<'X> extern function std.vec_push (v: mut std.Vec<'X>, x: 'X): () extern function std.vec_push_imm (v: std.Vec<'X>, x: 'X): std.Vec<'X> extern function std.vec_singleton (x: 'X): std.Vec<'X> -extern function std.vec_sort (v: std.Vec<'X>): () +extern function std.vec_sort (v: mut std.Vec<'X>): () extern function std.vec_sort_imm (v: std.Vec<'X>): std.Vec<'X> +extern function std.vec_to_set (s: std.Vec<'A>): std.Set<'A> extern function std.vec_with_capacity (len: std.usize): std.Vec<'A> extern function std.vec_with_length (len: std.usize, x: 'A): std.Vec<'A> extern function string_slice_unsafe (x: string, from: bit<64>, to: bit<64>): string @@ -588,7 +859,7 @@ TargetAudience[person] :- Person[(__person0@ (person: Person))], is_target_audie StudentInfo[(StudentInfo{.student=student, .school=school}: StudentInfo)] :- Student[(student@ ((&(Student{.id=(_: bit<64>), .name=(_: string), .school=(school_name: string), .sat_score=(_: bit<16>)}: Student)): std.Ref))], School[(school@ ((&(School{.name=(school_name: string), .address=(_: string)}: School)): std.Ref))], Inspect debug.debug_event_join((32'd30, 32'd1, 32'd0), ddlog_weight, ddlog_timestamp, student, school, (StudentInfo{.student=student, .school=school}: StudentInfo)). TopScore[(TopScore{.school=school, .top_score=top_score}: TopScore)] :- StudentInfo[(__studentinfo0@ (StudentInfo{.student=((&(Student{.id=(_: bit<64>), .name=(_: string), .school=(_: string), .sat_score=(sat: bit<16>)}: Student)): std.Ref), .school=((&(School{.name=(school: string), .address=(_: string)}: School)): std.Ref)}: StudentInfo))], var __inputs_top_score = Aggregate(school, __debug_31_1_std.group_max((__studentinfo0, sat))), Inspect debug.debug_event((32'd31, 32'd1, 32'd0), ddlog_weight, ddlog_timestamp, "Aggregate", __inputs_top_score.0, (__inputs_top_score, school)), (var top_score: bit<16>) = __inputs_top_score.1, Inspect debug.debug_event((32'd31, 32'd2, 32'd0), ddlog_weight, ddlog_timestamp, "Condition", (__inputs_top_score, school), (TopScore{.school=school, .top_score=top_score}: TopScore)). TopScore[(TopScore{.school=school, .top_score=top_score}: TopScore)] :- StudentInfo[(__studentinfo0@ (StudentInfo{.student=(student: std.Ref), .school=((&(School{.name=(school: string), .address=(_: string)}: School)): std.Ref)}: StudentInfo))], var __inputs_top_score = Aggregate(school, __debug_32_1_std.group_max((__studentinfo0, student.sat_score))), Inspect debug.debug_event((32'd32, 32'd1, 32'd0), ddlog_weight, ddlog_timestamp, "Aggregate", __inputs_top_score.0, (__inputs_top_score, school)), (var top_score: bit<16>) = __inputs_top_score.1, Inspect debug.debug_event((32'd32, 32'd2, 32'd0), ddlog_weight, ddlog_timestamp, "Condition", (__inputs_top_score, school), (TopScore{.school=school, .top_score=top_score}: TopScore)). -ItemInOrders[(ItemInOrders{.item=(internment.ival(item): string), .orders=orders}: ItemInOrders)] :- OnlineOrder[(__onlineorder0@ (OnlineOrder{.order_id=(order: bit<64>), .item=(item: internment.Intern)}: OnlineOrder))], var __inputs_orders = Aggregate(item, __debug_33_1_std.group2vec((__onlineorder0, order))), Inspect debug.debug_event((32'd33, 32'd1, 32'd0), ddlog_weight, ddlog_timestamp, "Aggregate", __inputs_orders.0, (__inputs_orders, item)), (var orders: std.Vec>) = __inputs_orders.1, Inspect debug.debug_event((32'd33, 32'd2, 32'd0), ddlog_weight, ddlog_timestamp, "Condition", (__inputs_orders, item), (ItemInOrders{.item=(internment.ival(item): string), .orders=orders}: ItemInOrders)). +ItemInOrders[(ItemInOrders{.item=(internment.ival(item): string), .orders=orders}: ItemInOrders)] :- OnlineOrder[(__onlineorder0@ (OnlineOrder{.order_id=(order: bit<64>), .item=(item: internment.Intern)}: OnlineOrder))], var __inputs_orders = Aggregate(item, __debug_33_1_std.group_to_vec((__onlineorder0, order))), Inspect debug.debug_event((32'd33, 32'd1, 32'd0), ddlog_weight, ddlog_timestamp, "Aggregate", __inputs_orders.0, (__inputs_orders, item)), (var orders: std.Vec>) = __inputs_orders.1, Inspect debug.debug_event((32'd33, 32'd2, 32'd0), ddlog_weight, ddlog_timestamp, "Condition", (__inputs_orders, item), (ItemInOrders{.item=(internment.ival(item): string), .orders=orders}: ItemInOrders)). OrderFormatted[(OrderFormatted{.order=formatted}: OrderFormatted)] :- OnlineOrder[(__onlineorder0@ (OnlineOrder{.order_id=(order: bit<64>), .item=(item: internment.Intern)}: OnlineOrder))], (var formatted: string) = ((("order: " ++ (std.__builtin_2string(order): string)) ++ ", item: ") ++ (internment.ival(item): string)), Inspect debug.debug_event((32'd34, 32'd1, 32'd0), ddlog_weight, ddlog_timestamp, "Condition", __onlineorder0, (OrderFormatted{.order=formatted}: OrderFormatted)). MilkOrders[(MilkOrders{.order=order}: MilkOrders)] :- OnlineOrder[(__onlineorder0@ (OnlineOrder{.order_id=(order: bit<64>), .item=(internment.intern("milk"): internment.Intern)}: OnlineOrder))], Inspect debug.debug_event((32'd35, 32'd0, 32'd0), ddlog_weight, ddlog_timestamp, "Map", __onlineorder0, (MilkOrders{.order=order}: MilkOrders)). InventoryItemName[(InventoryItemName{.name=name}: InventoryItemName)] :- StoreInventory[(__storeinventory0@ (StoreInventory{.item=(item: internment.Intern)}: StoreInventory))], (var name: string) = (internment.ival(item): StoreItem).name, Inspect debug.debug_event((32'd36, 32'd1, 32'd0), ddlog_weight, ddlog_timestamp, "Condition", __storeinventory0, (InventoryItemName{.name=name}: InventoryItemName)). diff --git a/test/datalog_tests/tutorial.dl b/test/datalog_tests/tutorial.dl index fb713faf9..5474ace5d 100644 --- a/test/datalog_tests/tutorial.dl +++ b/test/datalog_tests/tutorial.dl @@ -192,7 +192,6 @@ BookByAuthor(b, author) :- * Example: FlatMap, extern functions */ -extern function split(s: string, sep: string): Vec function split_ip_list(x: string): Vec { split(x, " ") } @@ -514,7 +513,7 @@ output relation ItemInOrders(item: string, orders: Vec) ItemInOrders(ival(item), orders) :- OnlineOrder(order, item), - var orders = Aggregate((item), group2vec(order)). + var orders = Aggregate((item), group_to_vec(order)). output relation OrderFormatted(order: string) diff --git a/test/datalog_tests/tutorial.rs b/test/datalog_tests/tutorial.rs index 27b16f760..584f9bc68 100644 --- a/test/datalog_tests/tutorial.rs +++ b/test/datalog_tests/tutorial.rs @@ -1,9 +1,3 @@ - - -pub fn split(x: &String, sep: &String) -> std_Vec { - std_Vec{x: x.as_str().split(sep).map(|x| x.to_string()).collect()} -} - pub fn string_slice_unsafe(x: &String, from: &u64, to: &u64) -> String { x.as_str()[(*from as usize)..(*to as usize)].to_string() } diff --git a/test/datalog_tests/uuid_test.dl b/test/datalog_tests/uuid_test.dl index d5bc340a0..313ea2930 100644 --- a/test/datalog_tests/uuid_test.dl +++ b/test/datalog_tests/uuid_test.dl @@ -29,7 +29,7 @@ function test_uuid_from_bytes(): uuid.Uuid = for (i in range(0: bit<8>, 15: bit<8>, 1: bit<8>)) { vec_push(bytes, i as bit<8>) }; - result_unwrap_or(uuid.from_bytes(bytes), uuid.nil()) + unwrap_or(uuid.from_bytes(bytes), uuid.nil()) } UUID("uuid.to_hyphenated_lower(test_uuid_from_bytes())", uuid.to_hyphenated_lower(test_uuid_from_bytes())). @@ -40,7 +40,7 @@ UUID("uuid.to_urn_lower(test_uuid_from_bytes())", uuid.to_urn_lower(test_uuid_fr UUID("uuid.to_urn_upper(test_uuid_from_bytes())", uuid.to_urn_upper(test_uuid_from_bytes())). function uuid_parse_or_nil(str: string): uuid.Uuid = { - result_unwrap_or(uuid.parse_str(str), uuid.nil()) + unwrap_or(uuid.parse_str(str), uuid.nil()) } UUID("uuid.to_hyphenated_lower(uuid_parse_or_nil(\"936DA01F-9ABD-4D9D-80C7-02AF85C822A8\"))", uuid.to_hyphenated_lower(uuid_parse_or_nil("936DA01F-9ABD-4D9D-80C7-02AF85C822A8"))). diff --git a/test/test-ovn.sh b/test/test-ovn.sh index 0b864b0ae..44b69794a 100755 --- a/test/test-ovn.sh +++ b/test/test-ovn.sh @@ -15,7 +15,7 @@ set -e # TODO: use -j6 once build script is fixed # TODO: use primary OVN repo (cd ovn && - git checkout ddlog_ci4 && + git checkout ddlog_ci5 && ./boot.sh && ./configure --with-ddlog=../../lib --with-ovs-source=../ovs --enable-shared && (make northd/ddlog.stamp && make check -j1 NORTHD_CLI=1 ||