mod languages;
mod tasks;
mod templates_core;
mod templates_extended;
mod types;
pub use languages::PROGRAM_LANGUAGES;
pub use tasks::PROGRAM_TASKS;
pub use types::{
ExecutionStatus, ProgramExecution, ProgramLanguage, ProgramSpec, ProgramTask, ProgramTemplate,
};
pub const WRITE_PROGRAM_INTENT: &str = "write_program";
const TEMPLATE_GROUPS: &[&[ProgramTemplate]] = &[
templates_core::TEMPLATES_CORE,
templates_extended::TEMPLATES_EXTENDED,
];
pub fn program_templates() -> impl Iterator<Item = &'static ProgramTemplate> {
TEMPLATE_GROUPS.iter().copied().flatten()
}
#[must_use]
pub fn program_template_count() -> usize {
TEMPLATE_GROUPS.iter().map(|group| group.len()).sum()
}
#[must_use]
pub fn program_language_by_slug(slug: &str) -> Option<&'static ProgramLanguage> {
PROGRAM_LANGUAGES
.iter()
.find(|language| language.slug == slug)
}
#[must_use]
pub fn program_task_by_slug(slug: &str) -> Option<&'static ProgramTask> {
PROGRAM_TASKS.iter().find(|task| task.slug == slug)
}
#[must_use]
pub fn program_template(task_slug: &str, language_slug: &str) -> Option<&'static ProgramTemplate> {
program_templates()
.find(|template| template.task_slug == task_slug && template.language_slug == language_slug)
}
#[must_use]
pub fn program_spec(task_slug: &str, language_slug: &str) -> Option<ProgramSpec> {
Some(ProgramSpec {
task: program_task_by_slug(task_slug)?,
language: program_language_by_slug(language_slug)?,
template: program_template(task_slug, language_slug)?,
})
}
fn alias_surfaces(prefix: &str, slug: &str) -> impl Iterator<Item = &'static str> {
crate::seed::lexicon()
.meaning(&format!("{prefix}_{slug}"))
.into_iter()
.flat_map(crate::seed::Meaning::words)
}
#[must_use]
pub fn program_language_by_alias(normalized: &str) -> Option<&'static ProgramLanguage> {
PROGRAM_LANGUAGES.iter().find(|language| {
alias_surfaces("program_language", language.slug)
.any(|alias| contains_token(normalized, alias))
})
}
#[must_use]
pub fn program_task_by_alias(normalized: &str) -> Option<&'static ProgramTask> {
PROGRAM_TASKS.iter().find(|task| {
alias_surfaces("program_task", task.slug).any(|alias| contains_phrase(normalized, alias))
})
}
#[must_use]
pub fn supported_program_languages() -> String {
PROGRAM_LANGUAGES
.iter()
.map(|language| language.slug)
.collect::<Vec<_>>()
.join(", ")
}
#[must_use]
pub fn supported_program_tasks() -> String {
PROGRAM_TASKS
.iter()
.map(|task| task.slug)
.collect::<Vec<_>>()
.join(", ")
}
pub fn contains_cjk(text: &str) -> bool {
text.chars().any(|ch| {
let cp = ch as u32;
(0x3400..=0x4DBF).contains(&cp)
|| (0x4E00..=0x9FFF).contains(&cp)
|| (0xF900..=0xFAFF).contains(&cp)
|| (0x3040..=0x30FF).contains(&cp)
|| (0x3100..=0x312F).contains(&cp)
})
}
pub fn contains_devanagari(text: &str) -> bool {
text.chars()
.any(|ch| (0x0900..=0x097F).contains(&(ch as u32)))
}
fn contains_token(normalized: &str, expected: &str) -> bool {
if contains_cjk(expected) {
return normalized.contains(expected);
}
normalized.split_whitespace().any(|token| token == expected)
}
fn contains_phrase(normalized: &str, expected: &str) -> bool {
if contains_cjk(expected) {
return normalized.contains(expected);
}
normalized == expected
|| normalized.starts_with(&format!("{expected} "))
|| normalized.ends_with(&format!(" {expected}"))
|| normalized.contains(&format!(" {expected} "))
}