use std::{collections::HashMap, fmt};
use crate::{
dialogue::{builder::BuildError, expr::Expr},
parser::{Spanned, ast},
};
pub(crate) mod builder;
pub mod compiler;
pub(crate) mod expr;
#[derive(Debug, Clone)]
pub struct Dialogue {
nodes: HashMap<NodeName, DialogueNode>,
}
impl Dialogue {
pub fn new(nodes: Vec<DialogueNode>) -> Self {
let nodes = nodes.into_iter().map(|n| (n.name.clone(), n)).collect();
Self { nodes }
}
pub fn get_node(&self, name: &NodeName) -> Option<&DialogueNode> {
self.nodes.get(name)
}
}
#[derive(Clone, Copy, PartialEq, Debug, Default)]
pub(crate) struct StepId(pub(crate) u32);
impl StepId {
pub fn id(&self) -> u32 {
self.0
}
}
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
pub struct NodeName(pub String);
impl NodeName {
pub fn new(name: impl Into<String>) -> Self {
Self(name.into())
}
}
impl std::fmt::Display for NodeName {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.0)
}
}
impl From<Spanned<String>> for NodeName {
fn from(value: Spanned<String>) -> Self {
Self(value.value)
}
}
impl From<&NodeName> for NodeName {
fn from(value: &NodeName) -> Self {
value.clone()
}
}
impl<T: AsRef<str>> From<T> for NodeName {
fn from(value: T) -> Self {
Self(value.as_ref().to_owned())
}
}
#[derive(Debug, Clone)]
pub struct DialogueNode {
pub name: NodeName,
pub(crate) entry: StepId,
pub(crate) steps: Vec<Step>,
}
impl DialogueNode {
pub(crate) fn get_step(&self, id: &StepId) -> &Step {
&self.steps[id.0 as usize]
}
}
#[derive(Debug, Clone)]
pub(crate) struct Step {
pub kind: StepKind,
}
#[derive(Debug, Clone)]
pub(crate) enum StepKind {
Say { line: TextLine, next: StepId },
Choice { choices: Vec<ChoiceDef> },
Jump(NodeName),
Command { command: Command, next: StepId },
Set {
name: String,
attrs: Vec<String>,
value: Expr,
next: StepId,
},
Branch {
condition: Expr,
then: StepId,
otherwise: StepId,
},
End,
}
#[derive(Debug, Clone)]
pub(crate) struct TextLine {
pub speaker: Option<String>,
pub text: Vec<TextPart>,
}
#[derive(Debug, Clone)]
pub(crate) enum TextPart {
Text(String),
Expression(Expr),
}
impl TryFrom<ast::TextPart> for TextPart {
type Error = BuildError;
fn try_from(value: ast::TextPart) -> Result<Self, BuildError> {
match value {
ast::TextPart::Text(s) => Ok(TextPart::Text(s)),
ast::TextPart::Expression(expr) => Ok(TextPart::Expression(expr.try_into()?)),
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct ChoiceDef {
pub text: Vec<TextPart>,
pub target: StepId,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ValueType {
Bool,
Int,
Float,
String,
Dict,
}
impl ValueType {
pub fn type_of(value: &Value) -> Self {
match value {
Value::Bool(_) => Self::Bool,
Value::Int(_) => Self::Int,
Value::Float(_) => Self::Float,
Value::String(_) => Self::String,
Value::Dict(_) => Self::Dict,
}
}
}
impl ValueType {
pub fn is_number(&self) -> bool {
matches!(self, Self::Int | Self::Float)
}
}
impl fmt::Display for ValueType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let type_str = match self {
ValueType::Bool => "bool",
ValueType::Int => "int",
ValueType::Float => "float",
ValueType::String => "string",
ValueType::Dict => "dict",
};
f.write_str(type_str)
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum Value {
Bool(bool),
Int(i64),
Float(f64),
String(String),
Dict(HashMap<String, Value>),
}
impl From<ast::Value> for Value {
fn from(value: ast::Value) -> Self {
match value {
ast::Value::Bool(val) => Value::Bool(val),
ast::Value::String(val) => Value::String(val),
ast::Value::Float(val) => Value::Float(val),
ast::Value::Int(val) => Value::Int(val),
}
}
}
impl fmt::Display for Value {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Value::Bool(val) => write!(f, "{val}"),
Value::Int(val) => write!(f, "{val}"),
Value::Float(val) => write!(f, "{val}"),
Value::String(val) => f.write_str(val),
Value::Dict(hash_map) => {
let mut attrs = hash_map
.iter()
.map(|(k, v)| format!("{k}: {v}"))
.collect::<Vec<_>>();
attrs.sort();
write!(f, "{{{}}}", attrs.join(", "))
}
}
}
}
impl Value {
pub fn vtype(&self) -> ValueType {
ValueType::type_of(self)
}
}
#[derive(Debug, Clone)]
pub(crate) struct Command {
pub name: String,
pub args: Vec<Expr>,
pub awaited: bool,
}