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)]
74pub enum Source {
75    /// Reference to a declared input or previous node by ID.
76    Id(u16),
77    /// Constant true.
78    True,
79    /// Constant false.
80    False,
81}
82
83/// Binary boolean operator.
84#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
85pub enum BoolOp {
86    /// Logical OR: A ∨ B
87    Or,
88    /// Logical NOR: ¬(A ∨ B)
89    Nor,
90    /// Logical XOR: A ⊕ B
91    Xor,
92}
93
94impl BoolOp {
95    /// Evaluate this operation on two boolean values.
96    #[inline]
97    pub fn eval(self, a: bool, b: bool) -> bool {
98        match self {
99            BoolOp::Or => a || b,
100            BoolOp::Nor => !(a || b),
101            BoolOp::Xor => a ^ b,
102        }
103    }
104}
105
106#[cfg(test)]
107mod tests {
108    use super::*;
109
110    #[test]
111    fn test_bool_op_or() {
112        assert!(!BoolOp::Or.eval(false, false));
113        assert!(BoolOp::Or.eval(false, true));
114        assert!(BoolOp::Or.eval(true, false));
115        assert!(BoolOp::Or.eval(true, true));
116    }
117
118    #[test]
119    fn test_bool_op_nor() {
120        assert!(BoolOp::Nor.eval(false, false));
121        assert!(!BoolOp::Nor.eval(false, true));
122        assert!(!BoolOp::Nor.eval(true, false));
123        assert!(!BoolOp::Nor.eval(true, true));
124    }
125
126    #[test]
127    fn test_bool_op_xor() {
128        assert!(!BoolOp::Xor.eval(false, false));
129        assert!(BoolOp::Xor.eval(false, true));
130        assert!(BoolOp::Xor.eval(true, false));
131        assert!(!BoolOp::Xor.eval(true, true));
132    }
133
134    #[test]
135    fn test_token_as_bool_op() {
136        assert_eq!(Token::Or.as_bool_op(), Some(BoolOp::Or));
137        assert_eq!(Token::Nor.as_bool_op(), Some(BoolOp::Nor));
138        assert_eq!(Token::Xor.as_bool_op(), Some(BoolOp::Xor));
139        assert_eq!(Token::NodeStart.as_bool_op(), None);
140        assert_eq!(Token::Id(0).as_bool_op(), None);
141    }
142
143    #[test]
144    fn test_token_as_source() {
145        assert_eq!(Token::Id(42).as_source(), Some(Source::Id(42)));
146        assert_eq!(Token::True.as_source(), Some(Source::True));
147        assert_eq!(Token::False.as_source(), Some(Source::False));
148        assert_eq!(Token::Or.as_source(), None);
149        assert_eq!(Token::NodeStart.as_source(), None);
150    }
151}