// Copyright 2025 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
///|
/// Position in source code (0-based)
///
/// `offset` is a 0-based codepoint offset within the source string.
pub struct Position {
line : Int // 0-based line
column : Int // 0-based column (in characters)
offset : Int // 0-based codepoint offset
} derive(Eq, Debug)
///|
/// A range in source code from start to end position.
/// `path` may be empty for in-memory sources.
pub struct Range {
path : String
start : Position
end : Position
} derive(Eq, Debug)
///|
/// Token types for the diago language
pub enum TokenKind {
// Literals
Ident(String) // identifiers and unquoted strings
StringLit(StringType, String) // string literals with type
Number(String) // numeric literals (kept as string for precision)
// Keywords / special identifiers handled at parse level
// Operators and punctuation
Colon // :
Semicolon // ;
Dot // .
Comma // ,
LeftBrace // {
RightBrace // }
LeftBracket // [
RightBracket // ]
LeftParen // (
RightParen // )
Pipe // |
Ampersand // &
// Arrows
Arrow // ->
ReverseArrow // <-
BidirectionalArrow // <->
DoubleDash // --
// Comments
Comment(String) // # single line comment
BlockComment(String) // /* block comment */
// Special
At // @ for imports
DotDotDot // ... for spread imports
Dollar // $ for substitutions
DollarBrace // ${ for substitutions
Star // * for glob patterns
DoubleStar // ** for glob patterns
TripleStar // *** for glob patterns
// Whitespace and structure
Newline // significant newlines
// End of file
Eof
} derive(Eq, Debug)
///|
/// String literal types
pub enum StringType {
SingleQuoted
DoubleQuoted
} derive(Eq, Debug)
///|
/// A token with its kind, range, and raw text
pub struct Token {
kind : TokenKind
range : Range
raw : String // original source text
} derive(Eq, Debug)
///|
pub fn Position::new(line : Int, column : Int, offset : Int) -> Position {
{ line, column, offset }
}
///|
pub fn Range::new(start : Position, end : Position) -> Range {
{ path: "", start, end }
}
///|
pub fn Range::with_path(
path : String,
start : Position,
end : Position,
) -> Range {
{ path, start, end }
}
///|
/// Create a range from the start of `a` to the end of `b`.
pub fn Range::between(a : Range, b : Range) -> Range {
let path = if a.path != "" { a.path } else { b.path }
{ path, start: a.start, end: b.end }
}
///|
pub fn Token::new(kind : TokenKind, range : Range, raw : String) -> Token {
{ kind, range, raw }
}
///|
/// Create a simple position at the origin
pub fn Position::zero() -> Position {
{ line: 0, column: 0, offset: 0 }
}
///|
/// Check if a token is a trivia token (whitespace, comments)
pub fn Token::is_trivia(self : Token) -> Bool {
match self.kind {
Comment(_) | BlockComment(_) | Newline => true
_ => false
}
}
///|
/// Check if a token is an arrow
pub fn Token::is_arrow(self : Token) -> Bool {
match self.kind {
Arrow | ReverseArrow | BidirectionalArrow => true
_ => false
}
}
///|
/// Check if a token can start an edge
pub fn Token::is_edge_op(self : Token) -> Bool {
match self.kind {
Arrow | ReverseArrow | BidirectionalArrow | DoubleDash => true
_ => false
}
}