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