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    Finally,
100    Fn,
101    Spawn,
102    While,
103    TypeKw,
104    Enum,
105    Struct,
106    Interface,
107    Pub,
108    From,
109    Thru,
110    Upto,
111    Guard,
112    Ask,
113    Deadline,
114    Yield,
115    Mutex,
116    Break,
117    Continue,
118    Select,
119    Impl,
120
121    // Literals
122    Identifier(String),
123    StringLiteral(String),
124    InterpolatedString(Vec<StringSegment>),
125    IntLiteral(i64),
126    FloatLiteral(f64),
127    /// Duration literal in milliseconds: 500ms, 5s, 30m, 2h
128    DurationLiteral(u64),
129
130    // Two-character operators
131    Eq,            // ==
132    Neq,           // !=
133    And,           // &&
134    Or,            // ||
135    Pipe,          // |>
136    NilCoal,       // ??
137    QuestionDot,   // ?.
138    Arrow,         // ->
139    Lte,           // <=
140    Gte,           // >=
141    PlusAssign,    // +=
142    MinusAssign,   // -=
143    StarAssign,    // *=
144    SlashAssign,   // /=
145    PercentAssign, // %=
146
147    // Single-character operators
148    Assign,   // =
149    Not,      // !
150    Dot,      // .
151    Plus,     // +
152    Minus,    // -
153    Star,     // *
154    Slash,    // /
155    Percent,  // %
156    Lt,       // <
157    Gt,       // >
158    Question, // ?
159    Bar,      // |  (for union types)
160
161    // Delimiters
162    LBrace,    // {
163    RBrace,    // }
164    LParen,    // (
165    RParen,    // )
166    LBracket,  // [
167    RBracket,  // ]
168    Comma,     // ,
169    Colon,     // :
170    Semicolon, // ;
171
172    // Comments
173    LineComment(String),  // // text
174    BlockComment(String), // /* text */
175
176    // Special
177    Newline,
178    Eof,
179}
180
181impl fmt::Display for TokenKind {
182    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
183        match self {
184            TokenKind::Pipeline => write!(f, "pipeline"),
185            TokenKind::Extends => write!(f, "extends"),
186            TokenKind::Override => write!(f, "override"),
187            TokenKind::Let => write!(f, "let"),
188            TokenKind::Var => write!(f, "var"),
189            TokenKind::If => write!(f, "if"),
190            TokenKind::Else => write!(f, "else"),
191            TokenKind::For => write!(f, "for"),
192            TokenKind::In => write!(f, "in"),
193            TokenKind::Match => write!(f, "match"),
194            TokenKind::Retry => write!(f, "retry"),
195            TokenKind::Parallel => write!(f, "parallel"),
196            TokenKind::ParallelMap => write!(f, "parallel_map"),
197            TokenKind::Return => write!(f, "return"),
198            TokenKind::Import => write!(f, "import"),
199            TokenKind::True => write!(f, "true"),
200            TokenKind::False => write!(f, "false"),
201            TokenKind::Nil => write!(f, "nil"),
202            TokenKind::Try => write!(f, "try"),
203            TokenKind::Catch => write!(f, "catch"),
204            TokenKind::Throw => write!(f, "throw"),
205            TokenKind::Finally => write!(f, "finally"),
206            TokenKind::Fn => write!(f, "fn"),
207            TokenKind::Spawn => write!(f, "spawn"),
208            TokenKind::While => write!(f, "while"),
209            TokenKind::TypeKw => write!(f, "type"),
210            TokenKind::Enum => write!(f, "enum"),
211            TokenKind::Struct => write!(f, "struct"),
212            TokenKind::Interface => write!(f, "interface"),
213            TokenKind::Pub => write!(f, "pub"),
214            TokenKind::From => write!(f, "from"),
215            TokenKind::Thru => write!(f, "thru"),
216            TokenKind::Upto => write!(f, "upto"),
217            TokenKind::Guard => write!(f, "guard"),
218            TokenKind::Ask => write!(f, "ask"),
219            TokenKind::Deadline => write!(f, "deadline"),
220            TokenKind::Yield => write!(f, "yield"),
221            TokenKind::Mutex => write!(f, "mutex"),
222            TokenKind::Break => write!(f, "break"),
223            TokenKind::Continue => write!(f, "continue"),
224            TokenKind::Select => write!(f, "select"),
225            TokenKind::Impl => write!(f, "impl"),
226            TokenKind::Identifier(s) => write!(f, "id({s})"),
227            TokenKind::StringLiteral(s) => write!(f, "str({s})"),
228            TokenKind::InterpolatedString(_) => write!(f, "istr(...)"),
229            TokenKind::IntLiteral(n) => write!(f, "int({n})"),
230            TokenKind::FloatLiteral(n) => write!(f, "float({n})"),
231            TokenKind::DurationLiteral(ms) => write!(f, "duration({ms}ms)"),
232            TokenKind::Eq => write!(f, "=="),
233            TokenKind::Neq => write!(f, "!="),
234            TokenKind::And => write!(f, "&&"),
235            TokenKind::Or => write!(f, "||"),
236            TokenKind::Pipe => write!(f, "|>"),
237            TokenKind::NilCoal => write!(f, "??"),
238            TokenKind::QuestionDot => write!(f, "?."),
239            TokenKind::Arrow => write!(f, "->"),
240            TokenKind::Lte => write!(f, "<="),
241            TokenKind::Gte => write!(f, ">="),
242            TokenKind::PlusAssign => write!(f, "+="),
243            TokenKind::MinusAssign => write!(f, "-="),
244            TokenKind::StarAssign => write!(f, "*="),
245            TokenKind::SlashAssign => write!(f, "/="),
246            TokenKind::PercentAssign => write!(f, "%="),
247            TokenKind::Assign => write!(f, "="),
248            TokenKind::Not => write!(f, "!"),
249            TokenKind::Dot => write!(f, "."),
250            TokenKind::Plus => write!(f, "+"),
251            TokenKind::Minus => write!(f, "-"),
252            TokenKind::Star => write!(f, "*"),
253            TokenKind::Slash => write!(f, "/"),
254            TokenKind::Percent => write!(f, "%"),
255            TokenKind::Lt => write!(f, "<"),
256            TokenKind::Gt => write!(f, ">"),
257            TokenKind::Question => write!(f, "?"),
258            TokenKind::Bar => write!(f, "|"),
259            TokenKind::LBrace => write!(f, "{{"),
260            TokenKind::RBrace => write!(f, "}}"),
261            TokenKind::LParen => write!(f, "("),
262            TokenKind::RParen => write!(f, ")"),
263            TokenKind::LBracket => write!(f, "["),
264            TokenKind::RBracket => write!(f, "]"),
265            TokenKind::Comma => write!(f, ","),
266            TokenKind::Colon => write!(f, ":"),
267            TokenKind::Semicolon => write!(f, ";"),
268            TokenKind::LineComment(s) => write!(f, "// {s}"),
269            TokenKind::BlockComment(s) => write!(f, "/* {s} */"),
270            TokenKind::Newline => write!(f, "\\n"),
271            TokenKind::Eof => write!(f, "EOF"),
272        }
273    }
274}
275
276/// A token with its kind and source location.
277#[derive(Debug, Clone, PartialEq)]
278pub struct Token {
279    pub kind: TokenKind,
280    pub span: Span,
281}
282
283impl Token {
284    pub fn with_span(kind: TokenKind, span: Span) -> Self {
285        Self { kind, span }
286    }
287}