У вас есть мини-язык для выбора вопросов:
- выберите следующий вопрос
- выберите пред вопрос
- Перейти конкретный вопрос
Если ваши требования заканчиваются здесь, решение на основе Regex
идеально подходит.
Если ваш DSL может развиться на основе синтаксического анализаторарешение стоит рассмотреть.
Комбинатор синтаксического анализа nom - это мощный инструмент для построения грамматики, основанной на базовых элементах.
Ваш язык имеет следующие характеристики:
имеет три альтернативных оператора (alt!
): следующий , пред , goto \ d +
самый сложный оператор "goto {number}" состоит из ключевого слова (tag!
) goto перед (preceded!
) a number (digit!
).
любое количество пробелов (ws!
) должно игнорироваться
Эти требования приводятся в данном описанииn:
#[macro_use]
extern crate nom;
use nom::{IResult, digit};
use nom::types::CompleteStr;
// we have for now two types of outcome: absolute or relative cursor move
pub enum QMove {
Abs(i32),
Rel(i32)
}
pub fn question_picker(input: CompleteStr) -> IResult<CompleteStr, QMove> {
ws!(input,
alt!(
map!(
tag!("next"),
|_| QMove::Rel(1)
) |
map!(
tag!("prev"),
|_| QMove::Rel(-1)
) |
preceded!(
tag!("goto"),
map!(
digit,
|s| QMove::Abs(std::str::FromStr::from_str(s.0).unwrap())
)
)
)
)
}
fn main() {
let mut current_question_number = 60;
let first_line = "goto 5";
let outcome = question_picker(CompleteStr(first_line));
match outcome {
Ok((_, QMove::Abs(n))) => current_question_number = n,
Ok((_, QMove::Rel(n))) => current_question_number += n,
Err(err) => {panic!("error: {:?}", err)}
}
println!("Now at question {}", current_question_number);
}