torg_core/
token.rs

1//! Token vocabulary for TØR-G IR.
2//!
3//! This module defines the closed, finite set of tokens that comprise
4//! the TØR-G intermediate representation. LLMs emit these tokens
5//! directly, with no text parsing required.
6
7/// TØR-G token vocabulary - closed, finite set.
8///
9/// These tokens are the atomic units of the IR. An LLM constrained
10/// to emit only valid tokens at each step (via logit masking) will
11/// produce syntactically correct boolean circuits.
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
13pub enum Token {
14    // === Logic Operators ===
15    /// Logical OR: A ∨ B
16    Or,
17    /// Logical NOR: ¬(A ∨ B)
18    Nor,
19    /// Logical XOR: A ⊕ B
20    Xor,
21
22    // === Structural ===
23    /// Begin node definition: ●
24    NodeStart,
25    /// End node definition: ○
26    NodeEnd,
27    /// Declare external input: ◎IN
28    InputDecl,
29    /// Mark as graph output: ◎OUT
30    OutputDecl,
31
32    // === Literals ===
33    /// Constant true: ◎T
34    True,
35    /// Constant false: ◎F
36    False,
37
38    // === Identifiers ===
39    /// Identifier (0..65535)
40    Id(u16),
41}
42
43impl Token {
44    /// Convert to BoolOp if this is an operator token.
45    pub fn as_bool_op(&self) -> Option<BoolOp> {
46        match self {
47            Token::Or => Some(BoolOp::Or),
48            Token::Nor => Some(BoolOp::Nor),
49            Token::Xor => Some(BoolOp::Xor),
50            _ => None,
51        }
52    }
53
54    /// Check if this is an operator token.
55    pub fn is_operator(&self) -> bool {
56        matches!(self, Token::Or | Token::Nor | Token::Xor)
57    }
58
59    /// Convert to Source if this can be a source operand.
60    pub fn as_source(&self) -> Option<Source> {
61        match self {
62            Token::Id(id) => Some(Source::Id(*id)),
63            Token::True => Some(Source::True),
64            Token::False => Some(Source::False),
65            _ => None,
66        }
67    }
68}
69
70/// Source operand for a node.
71///
72/// Represents where a node gets its input value from.
73#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
74#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
75pub enum Source {
76    /// Reference to a declared input or previous node by ID.
77    Id(u16),
78    /// Constant true.
79    True,
80    /// Constant false.
81    False,
82}
83
84/// Binary boolean operator.
85#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
86#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
87pub enum BoolOp {
88    /// Logical OR: A ∨ B
89    Or,
90    /// Logical NOR: ¬(A ∨ B)
91    Nor,
92    /// Logical XOR: A ⊕ B
93    Xor,
94}
95
96impl BoolOp {
97    /// Evaluate this operation on two boolean values.
98    #[inline]
99    pub fn eval(self, a: bool, b: bool) -> bool {
100        match self {
101            BoolOp::Or => a || b,
102            BoolOp::Nor => !(a || b),
103            BoolOp::Xor => a ^ b,
104        }
105    }
106}
107
108#[cfg(test)]
109mod tests {
110    use super::*;
111
112    #[test]
113    fn test_bool_op_or() {
114        assert!(!BoolOp::Or.eval(false, false));
115        assert!(BoolOp::Or.eval(false, true));
116        assert!(BoolOp::Or.eval(true, false));
117        assert!(BoolOp::Or.eval(true, true));
118    }
119
120    #[test]
121    fn test_bool_op_nor() {
122        assert!(BoolOp::Nor.eval(false, false));
123        assert!(!BoolOp::Nor.eval(false, true));
124        assert!(!BoolOp::Nor.eval(true, false));
125        assert!(!BoolOp::Nor.eval(true, true));
126    }
127
128    #[test]
129    fn test_bool_op_xor() {
130        assert!(!BoolOp::Xor.eval(false, false));
131        assert!(BoolOp::Xor.eval(false, true));
132        assert!(BoolOp::Xor.eval(true, false));
133        assert!(!BoolOp::Xor.eval(true, true));
134    }
135
136    #[test]
137    fn test_token_as_bool_op() {
138        assert_eq!(Token::Or.as_bool_op(), Some(BoolOp::Or));
139        assert_eq!(Token::Nor.as_bool_op(), Some(BoolOp::Nor));
140        assert_eq!(Token::Xor.as_bool_op(), Some(BoolOp::Xor));
141        assert_eq!(Token::NodeStart.as_bool_op(), None);
142        assert_eq!(Token::Id(0).as_bool_op(), None);
143    }
144
145    #[test]
146    fn test_token_as_source() {
147        assert_eq!(Token::Id(42).as_source(), Some(Source::Id(42)));
148        assert_eq!(Token::True.as_source(), Some(Source::True));
149        assert_eq!(Token::False.as_source(), Some(Source::False));
150        assert_eq!(Token::Or.as_source(), None);
151        assert_eq!(Token::NodeStart.as_source(), None);
152    }
153}