mirror of
https://github.com/openai/codex.git
synced 2026-05-03 21:01:55 +03:00
refactor to test positive matches
This commit is contained in:
@@ -2,7 +2,7 @@ use thiserror::Error;
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
#[derive(Debug, Error, PartialEq, Eq)]
|
||||
pub enum Error {
|
||||
#[error("invalid decision: {0}")]
|
||||
InvalidDecision(String),
|
||||
@@ -10,8 +10,14 @@ pub enum Error {
|
||||
InvalidPattern(String),
|
||||
#[error("invalid example: {0}")]
|
||||
InvalidExample(String),
|
||||
#[error("expected example to match rule `{rule}`: {example}")]
|
||||
ExampleDidNotMatch { rule: String, example: String },
|
||||
#[error(
|
||||
"expected every example to match at least one rule. rules: {rules:?}; unmatched examples: \
|
||||
{examples:?}"
|
||||
)]
|
||||
ExampleDidNotMatch {
|
||||
rules: Vec<String>,
|
||||
examples: Vec<String>,
|
||||
},
|
||||
#[error("expected example to not match rule `{rule}`: {example}")]
|
||||
ExampleDidMatch { rule: String, example: String },
|
||||
#[error("starlark error: {0}")]
|
||||
|
||||
@@ -17,6 +17,7 @@ use std::sync::Arc;
|
||||
use crate::decision::Decision;
|
||||
use crate::error::Error;
|
||||
use crate::error::Result;
|
||||
use crate::policy::validate_match_examples;
|
||||
use crate::rule::PatternToken;
|
||||
use crate::rule::PrefixPattern;
|
||||
use crate::rule::PrefixRule;
|
||||
@@ -203,17 +204,28 @@ fn policy_builtins(builder: &mut GlobalsBuilder) {
|
||||
|
||||
let rest: Arc<[PatternToken]> = remaining_tokens.to_vec().into();
|
||||
|
||||
for head in first_token.alternatives() {
|
||||
let rule = Rule::Prefix(PrefixRule {
|
||||
pattern: PrefixPattern {
|
||||
first: Arc::from(head.as_str()),
|
||||
rest: rest.clone(),
|
||||
},
|
||||
decision,
|
||||
});
|
||||
rule.validate_examples(&matches, ¬_matches)?;
|
||||
builder.add_rule(rule);
|
||||
}
|
||||
let rules: Vec<Rule> = first_token
|
||||
.alternatives()
|
||||
.iter()
|
||||
.zip(std::iter::repeat(rest.clone()))
|
||||
.map(|(head, rest)| {
|
||||
Rule::Prefix(PrefixRule {
|
||||
pattern: PrefixPattern {
|
||||
first: Arc::from(head.as_str()),
|
||||
rest,
|
||||
},
|
||||
decision,
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
|
||||
rules
|
||||
.iter()
|
||||
.try_for_each(|rule| rule.validate_not_matches(¬_matches))?;
|
||||
|
||||
validate_match_examples(&rules, &matches)?;
|
||||
|
||||
rules.into_iter().for_each(|rule| builder.add_rule(rule));
|
||||
Ok(NoneType)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
use crate::decision::Decision;
|
||||
use crate::error::Error;
|
||||
use crate::error::Result;
|
||||
use crate::rule::Rule;
|
||||
use crate::rule::RuleMatch;
|
||||
use multimap::MultiMap;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use shlex::try_join;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Policy {
|
||||
@@ -55,3 +58,33 @@ impl Evaluation {
|
||||
matches!(self, Self::Match { .. })
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn validate_match_examples(rules: &[Rule], matches: &[Vec<String>]) -> Result<()> {
|
||||
let match_counts = rules.iter().fold(vec![0; matches.len()], |counts, rule| {
|
||||
counts
|
||||
.iter()
|
||||
.zip(rule.validate_matches(matches))
|
||||
.map(|(count, matched)| if matched { count + 1 } else { *count })
|
||||
.collect()
|
||||
});
|
||||
|
||||
let unmatched_examples: Vec<String> = matches
|
||||
.iter()
|
||||
.zip(&match_counts)
|
||||
.filter(|(_, count)| **count == 0)
|
||||
.map(|(example, _)| {
|
||||
try_join(example.iter().map(String::as_str))
|
||||
.unwrap_or_else(|_| "unable to render example".to_string())
|
||||
})
|
||||
.collect();
|
||||
|
||||
if unmatched_examples.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let rules: Vec<String> = rules.iter().map(|rule| format!("{rule:?}")).collect();
|
||||
Err(Error::ExampleDidNotMatch {
|
||||
rules,
|
||||
examples: unmatched_examples,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -101,19 +101,14 @@ impl PrefixRule {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn validate_examples(
|
||||
&self,
|
||||
matches: &[Vec<String>],
|
||||
not_matches: &[Vec<String>],
|
||||
) -> Result<()> {
|
||||
for example in matches {
|
||||
if self.matches(example).is_none() {
|
||||
return Err(Error::ExampleDidNotMatch {
|
||||
rule: format!("{self:?}"),
|
||||
example: join_command(example),
|
||||
});
|
||||
}
|
||||
}
|
||||
pub fn validate_matches(&self, matches: &[Vec<String>]) -> Vec<bool> {
|
||||
matches
|
||||
.iter()
|
||||
.map(|example| self.matches(example).is_some())
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn validate_not_matches(&self, not_matches: &[Vec<String>]) -> Result<()> {
|
||||
for example in not_matches {
|
||||
if self.matches(example).is_some() {
|
||||
return Err(Error::ExampleDidMatch {
|
||||
@@ -144,13 +139,15 @@ impl Rule {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn validate_examples(
|
||||
&self,
|
||||
matches: &[Vec<String>],
|
||||
not_matches: &[Vec<String>],
|
||||
) -> Result<()> {
|
||||
pub fn validate_matches(&self, matches: &[Vec<String>]) -> Vec<bool> {
|
||||
match self {
|
||||
Self::Prefix(rule) => rule.validate_examples(matches, not_matches),
|
||||
Self::Prefix(rule) => rule.validate_matches(matches),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn validate_not_matches(&self, not_matches: &[Vec<String>]) -> Result<()> {
|
||||
match self {
|
||||
Self::Prefix(rule) => rule.validate_not_matches(not_matches),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user