Skip to main content

harn_lexer/
token.rs

1use std::fmt;
2
3/// A segment of an interpolated string.
4#[derive(Debug, Clone, PartialEq)]
5pub enum StringSegment {
6    Literal(String),
7    Expression(String),
8}
9
10impl fmt::Display for StringSegment {
11    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
12        match self {
13            StringSegment::Literal(s) => write!(f, "{s}"),
14            StringSegment::Expression(e) => write!(f, "${{{e}}}"),
15        }
16    }
17}
18
19/// Source location for error reporting.
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21pub struct Span {
22    /// Byte offset from start of source (inclusive).
23    pub start: usize,
24    /// Byte offset from start of source (exclusive).
25    pub end: usize,
26    /// 1-based line number of start position.
27    pub line: usize,
28    /// 1-based column number of start position.
29    pub column: usize,
30    /// 1-based line number of end position (for multiline span detection).
31    pub end_line: usize,
32}
33
34impl Span {
35    pub fn with_offsets(start: usize, end: usize, line: usize, column: usize) -> Self {
36        Self {
37            start,
38            end,
39            line,
40            column,
41            end_line: line,
42        }
43    }
44
45    /// Create a span covering two spans (from start of `a` to end of `b`).
46    pub fn merge(a: Span, b: Span) -> Span {
47        Span {
48            start: a.start,
49            end: b.end,
50            line: a.line,
51            column: a.column,
52            end_line: b.end_line,
53        }
54    }
55
56    /// A dummy span for synthetic/generated nodes.
57    pub fn dummy() -> Self {
58        Self {
59            start: 0,
60            end: 0,
61            line: 0,
62            column: 0,
63            end_line: 0,
64        }
65    }
66}
67
68impl fmt::Display for Span {
69    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70        write!(f, "{}:{}", self.line, self.column)
71    }
72}
73
74/// Token kinds produced by the lexer.
75#[derive(Debug, Clone, PartialEq)]
76pub enum TokenKind {
77    // Keywords
78    Pipeline,
79    Extends,
80    Override,
81    Let,
82    Var,
83    If,
84    Else,
85    For,
86    In,
87    Match,
88    Retry,
89    Parallel,
90    ParallelMap,
91    Return,
92    Import,
93    True,
94    False,
95    Nil,
96    Try,
97    Catch,
98    Throw,
99    Fn,
100    Spawn,
101    While,
102    TypeKw,
103    Enum,
104    Struct,
105    Interface,
106    Pub,
107    From,
108    Thru,
109    Upto,
110    Guard,
111    Ask,
112    Deadline,
113    Yield,
114    Mutex,
115    Break,
116    Continue,
117
118    // Literals
119    Identifier(String),
120    StringLiteral(String),
121    InterpolatedString(Vec<StringSegment>),
122    IntLiteral(i64),
123    FloatLiteral(f64),
124    /// Duration literal in milliseconds: 500ms, 5s, 30m, 2h
125    DurationLiteral(u64),
126
127    // Two-character operators
128    Eq,            // ==
129    Neq,           // !=
130    And,           // &&
131    Or,            // ||
132    Pipe,          // |>
133    NilCoal,       // ??
134    QuestionDot,   // ?.
135    Arrow,         // ->
136    Lte,           // <=
137    Gte,           // >=
138    PlusAssign,    // +=
139    MinusAssign,   // -=
140    StarAssign,    // *=
141    SlashAssign,   // /=
142    PercentAssign, // %=
143
144    // Single-character operators
145    Assign,   // =
146    Not,      // !
147    Dot,      // .
148    Plus,     // +
149    Minus,    // -
150    Star,     // *
151    Slash,    // /
152    Percent,  // %
153    Lt,       // <
154    Gt,       // >
155    Question, // ?
156    Bar,      // |  (for union types)
157
158    // Delimiters
159    LBrace,    // {
160    RBrace,    // }
161    LParen,    // (
162    RParen,    // )
163    LBracket,  // [
164    RBracket,  // ]
165    Comma,     // ,
166    Colon,     // :
167    Semicolon, // ;
168
169    // Comments
170    LineComment(String),  // // text
171    BlockComment(String), // /* text */
172
173    // Special
174    Newline,
175    Eof,
176}
177
178impl fmt::Display for TokenKind {
179    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
180        match self {
181            TokenKind::Pipeline => write!(f, "pipeline"),
182            TokenKind::Extends => write!(f, "extends"),
183            TokenKind::Override => write!(f, "override"),
184            TokenKind::Let => write!(f, "let"),
185            TokenKind::Var => write!(f, "var"),
186            TokenKind::If => write!(f, "if"),
187            TokenKind::Else => write!(f, "else"),
188            TokenKind::For => write!(f, "for"),
189            TokenKind::In => write!(f, "in"),
190            TokenKind::Match => write!(f, "match"),
191            TokenKind::Retry => write!(f, "retry"),
192            TokenKind::Parallel => write!(f, "parallel"),
193            TokenKind::ParallelMap => write!(f, "parallel_map"),
194            TokenKind::Return => write!(f, "return"),
195            TokenKind::Import => write!(f, "import"),
196            TokenKind::True => write!(f, "true"),
197            TokenKind::False => write!(f, "false"),
198            TokenKind::Nil => write!(f, "nil"),
199            TokenKind::Try => write!(f, "try"),
200            TokenKind::Catch => write!(f, "catch"),
201            TokenKind::Throw => write!(f, "throw"),
202            TokenKind::Fn => write!(f, "fn"),
203            TokenKind::Spawn => write!(f, "spawn"),
204            TokenKind::While => write!(f, "while"),
205            TokenKind::TypeKw => write!(f, "type"),
206            TokenKind::Enum => write!(f, "enum"),
207            TokenKind::Struct => write!(f, "struct"),
208            TokenKind::Interface => write!(f, "interface"),
209            TokenKind::Pub => write!(f, "pub"),
210            TokenKind::From => write!(f, "from"),
211            TokenKind::Thru => write!(f, "thru"),
212            TokenKind::Upto => write!(f, "upto"),
213            TokenKind::Guard => write!(f, "guard"),
214            TokenKind::Ask => write!(f, "ask"),
215            TokenKind::Deadline => write!(f, "deadline"),
216            TokenKind::Yield => write!(f, "yield"),
217            TokenKind::Mutex => write!(f, "mutex"),
218            TokenKind::Break => write!(f, "break"),
219            TokenKind::Continue => write!(f, "continue"),
220            TokenKind::Identifier(s) => write!(f, "id({s})"),
221            TokenKind::StringLiteral(s) => write!(f, "str({s})"),
222            TokenKind::InterpolatedString(_) => write!(f, "istr(...)"),
223            TokenKind::IntLiteral(n) => write!(f, "int({n})"),
224            TokenKind::FloatLiteral(n) => write!(f, "float({n})"),
225            TokenKind::DurationLiteral(ms) => write!(f, "duration({ms}ms)"),
226            TokenKind::Eq => write!(f, "=="),
227            TokenKind::Neq => write!(f, "!="),
228            TokenKind::And => write!(f, "&&"),
229            TokenKind::Or => write!(f, "||"),
230            TokenKind::Pipe => write!(f, "|>"),
231            TokenKind::NilCoal => write!(f, "??"),
232            TokenKind::QuestionDot => write!(f, "?."),
233            TokenKind::Arrow => write!(f, "->"),
234            TokenKind::Lte => write!(f, "<="),
235            TokenKind::Gte => write!(f, ">="),
236            TokenKind::PlusAssign => write!(f, "+="),
237            TokenKind::MinusAssign => write!(f, "-="),
238            TokenKind::StarAssign => write!(f, "*="),
239            TokenKind::SlashAssign => write!(f, "/="),
240            TokenKind::PercentAssign => write!(f, "%="),
241            TokenKind::Assign => write!(f, "="),
242            TokenKind::Not => write!(f, "!"),
243            TokenKind::Dot => write!(f, "."),
244            TokenKind::Plus => write!(f, "+"),
245            TokenKind::Minus => write!(f, "-"),
246            TokenKind::Star => write!(f, "*"),
247            TokenKind::Slash => write!(f, "/"),
248            TokenKind::Percent => write!(f, "%"),
249            TokenKind::Lt => write!(f, "<"),
250            TokenKind::Gt => write!(f, ">"),
251            TokenKind::Question => write!(f, "?"),
252            TokenKind::Bar => write!(f, "|"),
253            TokenKind::LBrace => write!(f, "{{"),
254            TokenKind::RBrace => write!(f, "}}"),
255            TokenKind::LParen => write!(f, "("),
256            TokenKind::RParen => write!(f, ")"),
257            TokenKind::LBracket => write!(f, "["),
258            TokenKind::RBracket => write!(f, "]"),
259            TokenKind::Comma => write!(f, ","),
260            TokenKind::Colon => write!(f, ":"),
261            TokenKind::Semicolon => write!(f, ";"),
262            TokenKind::LineComment(s) => write!(f, "// {s}"),
263            TokenKind::BlockComment(s) => write!(f, "/* {s} */"),
264            TokenKind::Newline => write!(f, "\\n"),
265            TokenKind::Eof => write!(f, "EOF"),
266        }
267    }
268}
269
270/// A token with its kind and source location.
271#[derive(Debug, Clone, PartialEq)]
272pub struct Token {
273    pub kind: TokenKind,
274    pub span: Span,
275}
276
277impl Token {
278    pub fn with_span(kind: TokenKind, span: Span) -> Self {
279        Self { kind, span }
280    }
281}