Optional dot syntax for anchored keys (#423)
This commit is contained in:
parent
f95a27b412
commit
7e04eb51ff
6 changed files with 36 additions and 18 deletions
|
|
@ -12,10 +12,13 @@ some of its arguments is proved, it means that a valid Merkle proof of the
|
||||||
value behind it exists and was used at some point to construct a `Contains`
|
value behind it exists and was used at some point to construct a `Contains`
|
||||||
statement that introduced that anchored key.
|
statement that introduced that anchored key.
|
||||||
|
|
||||||
|
In PODLang, anchored key indexing can use subscript syntax `foo["bar"]` which
|
||||||
|
allows any string key, or dot syntax `foo.bar` if the key is a valid identifier.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
```
|
```
|
||||||
0: None
|
0: None
|
||||||
1: Contains(foo, bar, 42) <- ContainsFromEntries 0 0 0 mt_proof
|
1: Contains(foo, "bar", 42) <- ContainsFromEntries 0 0 0 mt_proof
|
||||||
2: Lt(foo[bar], 100) <- LtFromEntries 1 0
|
2: Lt(foo["bar"], 100) <- LtFromEntries 1 0
|
||||||
3: NotEqual(foo[bar], 100) <- LtToNotEqual 2
|
3: NotEqual(foo.bar, 100) <- LtToNotEqual 2
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ Equals(a, c)
|
||||||
First, we need to decompose all the anchored keys as (dict, key) pairs. This is the frontend description of the deduction rule.
|
First, we need to decompose all the anchored keys as (dict, key) pairs. This is the frontend description of the deduction rule.
|
||||||
```
|
```
|
||||||
IF
|
IF
|
||||||
Equals(a_or[a_key], b_or[b_key)
|
Equals(a_or[a_key], b_or[b_key])
|
||||||
AND
|
AND
|
||||||
Equals(b_or[b_key], c_or[c_key])
|
Equals(b_or[b_key], c_or[c_key])
|
||||||
THEN
|
THEN
|
||||||
|
|
|
||||||
|
|
@ -82,10 +82,10 @@ pub fn zu_kyc_pod_request(gov_signer: &Value, pay_signer: &Value) -> Result<PodR
|
||||||
let input = format!(
|
let input = format!(
|
||||||
r#"
|
r#"
|
||||||
REQUEST(
|
REQUEST(
|
||||||
SetNotContains({sanction_set}, ?gov["idNumber"])
|
SetNotContains({sanction_set}, ?gov.idNumber)
|
||||||
Lt(?gov["dateOfBirth"], {ZU_KYC_NOW_MINUS_18Y})
|
Lt(?gov.dateOfBirth, {ZU_KYC_NOW_MINUS_18Y})
|
||||||
Equal(?pay["startDate"], {ZU_KYC_NOW_MINUS_1Y})
|
Equal(?pay.startDate, {ZU_KYC_NOW_MINUS_1Y})
|
||||||
Equal(?gov["socialSecurityNumber"], ?pay["socialSecurityNumber"])
|
Equal(?gov.socialSecurityNumber, ?pay.socialSecurityNumber)
|
||||||
SignedBy(?gov, {gov_signer})
|
SignedBy(?gov, {gov_signer})
|
||||||
SignedBy(?pay, {pay_signer})
|
SignedBy(?pay, {pay_signer})
|
||||||
// TODO: Ownership check and watermarking
|
// TODO: Ownership check and watermarking
|
||||||
|
|
|
||||||
|
|
@ -54,8 +54,11 @@ statement_arg_list = { statement_arg ~ ("," ~ statement_arg)* }
|
||||||
|
|
||||||
statement = { identifier ~ "(" ~ statement_arg_list? ~ ")" }
|
statement = { identifier ~ "(" ~ statement_arg_list? ~ ")" }
|
||||||
|
|
||||||
// Anchored Key: ?Var["key_literal"]
|
// Anchored Key: ?Var["key_literal"] or ?Var.key_identifier
|
||||||
anchored_key = { wildcard ~ "[" ~ literal_string ~ "]" }
|
anchored_key = {
|
||||||
|
(wildcard ~ "[" ~ literal_string ~ "]")
|
||||||
|
| (wildcard ~ "." ~ identifier)
|
||||||
|
}
|
||||||
|
|
||||||
// Literal Values (ordered to avoid ambiguity, e.g., string before int)
|
// Literal Values (ordered to avoid ambiguity, e.g., string before int)
|
||||||
literal_value = {
|
literal_value = {
|
||||||
|
|
|
||||||
|
|
@ -89,11 +89,16 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_anchored_key() {
|
fn test_parse_anchored_key() {
|
||||||
assert_parses(Rule::anchored_key, "?PodVar[\"literal_key\"]");
|
assert_parses(Rule::anchored_key, "?PodVar[\"literal key\"]");
|
||||||
|
assert_parses(Rule::anchored_key, "?PodVar.literal_key");
|
||||||
assert_fails(Rule::anchored_key, "PodVar[\"key\"]"); // Needs wildcard for pod
|
assert_fails(Rule::anchored_key, "PodVar[\"key\"]"); // Needs wildcard for pod
|
||||||
assert_fails(Rule::anchored_key, "?PodVar[invalid_key]"); // Key must be literal string or wildcard
|
assert_fails(Rule::anchored_key, "PodVar.key"); // Needs wildcard for pod
|
||||||
|
assert_fails(Rule::anchored_key, "?PodVar[invalid_key]"); // Key must be literal string
|
||||||
|
assert_fails(Rule::anchored_key, "?PodVar.123"); // Key must be valid identifier
|
||||||
assert_fails(Rule::anchored_key, "?PodVar[]"); // Key cannot be empty
|
assert_fails(Rule::anchored_key, "?PodVar[]"); // Key cannot be empty
|
||||||
|
assert_fails(Rule::anchored_key, "?PodVar."); // Key cannot be empty
|
||||||
assert_fails(Rule::anchored_key, "?PodVar[?key]"); // Key cannot be wildcard
|
assert_fails(Rule::anchored_key, "?PodVar[?key]"); // Key cannot be wildcard
|
||||||
|
assert_fails(Rule::anchored_key, "?PodVar.?key"); // Key cannot be wildcard
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -214,7 +219,7 @@ mod tests {
|
||||||
ValueOf(?ConstVal["min_age"], 18)
|
ValueOf(?ConstVal["min_age"], 18)
|
||||||
Gt(?UserPod["age"], ?ConstVal["min_age"])
|
Gt(?UserPod["age"], ?ConstVal["min_age"])
|
||||||
// User must not be banned
|
// User must not be banned
|
||||||
NotContains(?_BANNED_USERS["list"], ?UserPod["userId"])
|
NotContains(?_BANNED_USERS.list, ?UserPod.userId)
|
||||||
)
|
)
|
||||||
|
|
||||||
REQUEST(
|
REQUEST(
|
||||||
|
|
|
||||||
|
|
@ -356,7 +356,14 @@ fn pest_pair_to_builder_arg(
|
||||||
}
|
}
|
||||||
|
|
||||||
let key_part_pair = inner_ak_pairs.next().unwrap();
|
let key_part_pair = inner_ak_pairs.next().unwrap();
|
||||||
let key_str = parse_pest_string_literal(&key_part_pair)?;
|
let key_str = match key_part_pair.as_rule() {
|
||||||
|
Rule::literal_string => parse_pest_string_literal(&key_part_pair)?,
|
||||||
|
Rule::identifier => key_part_pair.as_str().to_string(),
|
||||||
|
_ => unreachable!(
|
||||||
|
"unknown key type in anchored key: {:?}",
|
||||||
|
key_part_pair.as_rule()
|
||||||
|
),
|
||||||
|
};
|
||||||
Ok(BuilderArg::Key(root_wc_str.to_string(), key_str))
|
Ok(BuilderArg::Key(root_wc_str.to_string(), key_str))
|
||||||
}
|
}
|
||||||
_ => unreachable!("Unexpected rule: {:?}", arg_content_pair.as_rule()),
|
_ => unreachable!("Unexpected rule: {:?}", arg_content_pair.as_rule()),
|
||||||
|
|
@ -1065,7 +1072,7 @@ mod processor_tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_fp_only_request() -> Result<(), ProcessorError> {
|
fn test_fp_only_request() -> Result<(), ProcessorError> {
|
||||||
let input = "REQUEST( Equal(?A[\"k\"],?B[\"k\"]) )"; // Escaped quotes
|
let input = "REQUEST( Equal(?A[\"k\"],?B.k) )"; // Escaped quotes
|
||||||
let pairs = get_document_content_pairs(input)?;
|
let pairs = get_document_content_pairs(input)?;
|
||||||
let params = Params::default();
|
let params = Params::default();
|
||||||
let mut ctx = ProcessingContext::new(¶ms);
|
let mut ctx = ProcessingContext::new(¶ms);
|
||||||
|
|
@ -1082,7 +1089,7 @@ mod processor_tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_fp_simple_predicate() -> Result<(), ProcessorError> {
|
fn test_fp_simple_predicate() -> Result<(), ProcessorError> {
|
||||||
let input = "my_pred(A, B) = AND( Equal(?A[\"k\"],?B[\"k\"]) )"; // Escaped quotes
|
let input = "my_pred(A, B) = AND( Equal(?A[\"k\"],?B.k) )"; // Escaped quotes
|
||||||
let pairs = get_document_content_pairs(input)?;
|
let pairs = get_document_content_pairs(input)?;
|
||||||
let params = Params::default();
|
let params = Params::default();
|
||||||
let mut ctx = ProcessingContext::new(¶ms);
|
let mut ctx = ProcessingContext::new(¶ms);
|
||||||
|
|
@ -1104,7 +1111,7 @@ mod processor_tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_fp_multiple_predicates() -> Result<(), ProcessorError> {
|
fn test_fp_multiple_predicates() -> Result<(), ProcessorError> {
|
||||||
let input = r#"
|
let input = r#"
|
||||||
pred1(X) = AND( Equal(?X["k"],?X["k"]) )
|
pred1(X) = AND( Equal(?X["k"],?X.k) )
|
||||||
pred2(Y, Z) = OR( Equal(?Y["v"], 123) )
|
pred2(Y, Z) = OR( Equal(?Y["v"], 123) )
|
||||||
"#;
|
"#;
|
||||||
let pairs = get_document_content_pairs(input)?;
|
let pairs = get_document_content_pairs(input)?;
|
||||||
|
|
@ -1253,7 +1260,7 @@ mod processor_tests {
|
||||||
// Native predicate names are case-sensitive
|
// Native predicate names are case-sensitive
|
||||||
let input = r#"
|
let input = r#"
|
||||||
REQUEST(
|
REQUEST(
|
||||||
EQUAL(?A["b"], ?C["d"])
|
EQUAL(?A["b"], ?C.d)
|
||||||
)
|
)
|
||||||
"#;
|
"#;
|
||||||
let pairs = get_document_content_pairs(input)?;
|
let pairs = get_document_content_pairs(input)?;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue