Move Item verification to be a method of TokenFmt.

This commit is contained in:
Nick Mathewson 2020-05-09 11:10:15 -04:00
parent d9513492fe
commit 56694d4fc8
2 changed files with 44 additions and 37 deletions

View File

@ -149,38 +149,6 @@ impl<'a, T: Keyword> Section<'a, T> {
}
}
/// Check whether a single Item matches a TokenFmt rule, with respect
/// to its number of arguments.
///
/// TODO: Move this to rules?
fn item_matches_fmt_args<'a, T: Keyword>(t: T, fmt: &TokenFmt<T>, item: &Item<'a>) -> Result<()> {
let n_args = item.n_args();
if let Some(max) = fmt.max_args {
if n_args > max {
return Err(Error::TooManyArguments(t.to_str(), item.pos()));
}
}
if let Some(min) = fmt.min_args {
if n_args < min {
return Err(Error::TooFewArguments(t.to_str(), item.pos()));
}
}
Ok(())
}
/// Check whether a single Item matches a TokenFmt rule, with respect
/// to its object's presence and type.
///
/// TODO: Move this to rules?
fn item_matches_fmt_obj<'a, T: Keyword>(t: T, fmt: &TokenFmt<T>, item: &Item<'a>) -> Result<()> {
match (&fmt.obj, item.has_obj()) {
(ObjKind::NoObj, true) => Err(Error::UnexpectedObject(t.to_str(), item.pos())),
(ObjKind::RequireObj, false) => Err(Error::MissingObject(t.to_str(), item.pos())),
(_, _) => Ok(()),
}
}
impl<T: Keyword> SectionRules<T> {
/// Create a new SectionRules with no rules.
///
@ -265,8 +233,7 @@ impl<T: Keyword> SectionRules<T> {
// The number is right. Check each individual item.
for item in t.as_slice() {
let tok = T::from_idx(idx).unwrap();
item_matches_fmt_args(tok, rule, item)?;
item_matches_fmt_obj(tok, rule, item)?;
rule.check_item(tok, item)?
}
}
}

View File

@ -1,3 +1,5 @@
use crate::tokenize::Item;
use crate::{Error, Result};
use std::hash::Hash;
pub trait Keyword: Hash + Eq + PartialEq + Copy + Clone {
@ -24,11 +26,49 @@ pub enum ObjKind {
#[derive(Clone)]
pub struct TokenFmt<T: Keyword> {
pub kwd: T,
pub min_args: Option<usize>,
pub max_args: Option<usize>,
min_args: Option<usize>,
max_args: Option<usize>,
pub required: bool,
pub may_repeat: bool,
pub obj: ObjKind,
obj: ObjKind,
}
impl<T: Keyword> TokenFmt<T> {
/// Check whether a single Item matches this TokenFmt rule, with respect
/// to its number of arguments.
fn item_matches_args<'a>(&self, t: T, item: &Item<'a>) -> Result<()> {
let n_args = item.n_args();
if let Some(max) = self.max_args {
if n_args > max {
return Err(Error::TooManyArguments(t.to_str(), item.pos()));
}
}
if let Some(min) = self.min_args {
if n_args < min {
return Err(Error::TooFewArguments(t.to_str(), item.pos()));
}
}
Ok(())
}
/// Check whether a single Item matches a TokenFmt rule, with respect
/// to its object's presence and type.
///
/// TODO: Move this to rules?
fn item_matches_obj<'a>(&self, t: T, item: &Item<'a>) -> Result<()> {
match (&self.obj, item.has_obj()) {
(ObjKind::NoObj, true) => Err(Error::UnexpectedObject(t.to_str(), item.pos())),
(ObjKind::RequireObj, false) => Err(Error::MissingObject(t.to_str(), item.pos())),
(_, _) => Ok(()),
}
}
/// Check whether a single item has the right number of arguments
/// and object.
pub fn check_item<'a>(&self, t: T, item: &Item<'a>) -> Result<()> {
self.item_matches_args(t, item)?;
self.item_matches_obj(t, item)
}
}
pub struct TokenFmtBuilder<T: Keyword>(TokenFmt<T>);