Compare changes

Choose any two refs to compare.

+1
.gitignore
···
#
# SPDX-License-Identifier: MPL-2.0
+
.jj/*
.DS_Store
/.build
/Packages
-1
Package.swift
···
name: "PterodactylBuildTests",
dependencies: [
"PterodactylBuild",
-
"PterodactylSyntax",
.product(name: "llbuild2fx", package: "swift-llbuild2")
]
),
+14 -42
Sources/PterodactylBuild/Keys/AnalyseImports.swift
···
import Foundation
import TSCBasic
import llbuild2fx
-
import PterodactylSyntax
-
-
private struct ImportParser {
-
private var lexer: PterodactylSyntax.Lexer
-
public private(set) var imports: [String] = []
-
-
public init(input: String) {
-
self.lexer = PterodactylSyntax.Lexer(input: input)
-
}
-
-
public mutating func parseHeader() {
-
while true {
-
let token = nextSignificantToken()
-
switch token.kind {
-
case .keyword(.import): parseImportStatement()
-
default: return
-
}
-
}
-
}
-
-
/// Returns the next non-whitespace token.
-
private mutating func nextSignificantToken() -> Token {
-
var token = lexer.nextToken()
-
while case .whitespace = token.kind {
-
token = lexer.nextToken()
-
}
-
return token
-
}
-
-
/// Parses a single `import xyz` line.
-
private mutating func parseImportStatement() {
-
let next = nextSignificantToken()
-
guard next.kind == .identifier else { return }
-
imports.append(next.text)
-
}
-
}
-
extension Keys {
struct AnalyseImports: BuildKey {
···
func computeValue(_ ctx: BuildContext<Self>) async throws -> [UnitName] {
let contents = try await ctx.load(blobId)
let code = try await String(decoding: Data(ctx.read(blob: contents.blob!)), as: UTF8.self)
-
var importParser = ImportParser(input: code)
-
importParser.parseHeader()
-
-
return importParser.imports.map { name in
-
UnitName(basename: name)
+
+
var results: [UnitName] = []
+
let lines = code.split(separator: "\n", omittingEmptySubsequences: false)
+
+
for line in lines {
+
let trimmed = line.trimmingCharacters(in: .whitespaces)
+
guard trimmed.hasPrefix("import ") else { continue }
+
let parts = trimmed.split(separator: " ", maxSplits: 1, omittingEmptySubsequences: true)
+
if parts.count == 2 {
+
let name = parts[1].trimmingCharacters(in: .whitespaces)
+
results.append(UnitName(name: name))
+
}
}
+
+
return results
}
}
}
+7
Sources/PterodactylBuild/Keys/Keys.swift
···
+
// SPDX-FileCopyrightText: 2025 The Project Pterodactyl Developers
+
//
+
// SPDX-License-Identifier: MPL-2.0
+
+
import Foundation
+
+
enum Keys {}
-7
Sources/PterodactylBuild/Keys.swift
···
-
// SPDX-FileCopyrightText: 2025 The Project Pterodactyl Developers
-
//
-
// SPDX-License-Identifier: MPL-2.0
-
-
import Foundation
-
-
enum Keys {}
+5 -5
Sources/PterodactylBuild/Types/UnitName.swift
···
// SPDX-License-Identifier: MPL-2.0
import Foundation
-
import TSCBasic
import llbuild2fx
+
import TSCBasic
struct UnitName: Codable, Equatable, Hashable {
-
var basename: String
+
var name: String
}
extension UnitName: FXValue {}
extension UnitName {
-
static func fromPath(_ path: AbsolutePath) -> Self {
-
Self(basename: path.basenameWithoutExt)
-
}
+
static func fromPath(_ path: AbsolutePath) -> Self {
+
Self(name: path.basenameWithoutExt)
+
}
}
-100
Sources/PterodactylSyntax/BlockLayoutProcessor.swift
···
-
// SPDX-FileCopyrightText: 2025 The Project Pterodactyl Developers
-
//
-
// SPDX-License-Identifier: MPL-2.0
-
-
import Foundation
-
-
fileprivate struct TokenLocation {
-
let startLine: Int
-
let startColumn: Int
-
}
-
-
fileprivate struct LocatedToken {
-
let token: Token
-
let location: TokenLocation
-
let lines: [String.SubSequence]
-
-
init(token: Token, location: TokenLocation) {
-
self.token = token
-
self.location = location
-
self.lines = token.text.split(separator: "\n", omittingEmptySubsequences: false)
-
}
-
-
var nextLocation: TokenLocation {
-
let startLine = location.startLine + lines.count - 1
-
let startColumn = if lines.count > 1 { lines.last!.utf16.count } else { lines.last?.utf16.count ?? location.startColumn }
-
return TokenLocation(startLine: startLine, startColumn: startColumn)
-
}
-
}
-
-
public struct BlockLayoutProcessor {
-
private let locatedTokens: [LocatedToken]
-
-
public init(tokens: [Token]) {
-
var locatedTokens: [LocatedToken] = []
-
var location = TokenLocation(startLine: 0, startColumn: 0)
-
for token in tokens {
-
let locatedToken = LocatedToken(token: token, location: location)
-
locatedTokens.append(locatedToken)
-
location = locatedToken.nextLocation
-
}
-
-
self.locatedTokens = locatedTokens
-
}
-
-
-
public func layout() -> [Token] {
-
var result: [Token] = []
-
var indentStack: [Int] = [0]
-
var previousLine = 0
-
var firstTokenInBlock = false
-
-
for (index, locatedToken) in locatedTokens.enumerated() {
-
guard locatedToken.token.kind != .eof else { break }
-
guard locatedToken.token.kind.canDetermineLayoutColumn else {
-
result.append(locatedToken.token)
-
continue
-
}
-
-
if locatedToken.location.startLine > previousLine {
-
while indentStack.count > 1 && locatedToken.location.startColumn < indentStack.last! {
-
indentStack.removeLast()
-
result.append(Token(kind: .blockEnd, text: ""))
-
}
-
-
if !firstTokenInBlock && indentStack.count > 1 && locatedToken.location.startColumn == indentStack.last! {
-
result.append(Token(kind: .blockSep, text: ""))
-
}
-
}
-
-
result.append(locatedToken.token)
-
-
if locatedToken.token.kind.isBlockHerald {
-
firstTokenInBlock = true
-
-
if let nextToken = locatedTokens[index...].first(where: { $0.location.startLine > locatedToken.location.startLine && $0.token.kind.canDetermineLayoutColumn }) {
-
result.append(Token(kind: .blockBegin, text: ""))
-
indentStack.append(nextToken.location.startColumn)
-
} else {
-
result.append(Token(kind: .blockBegin, text: ""))
-
result.append(Token(kind: .blockEnd, text: ""))
-
}
-
} else {
-
firstTokenInBlock = false
-
}
-
-
previousLine = locatedToken.location.startLine
-
}
-
-
while indentStack.count > 1 {
-
indentStack.removeLast()
-
result.append(Token(kind: .blockEnd, text: ""))
-
}
-
-
if let eof = locatedTokens.last, eof.token.kind == .eof {
-
result.append(eof.token)
-
}
-
-
return result
-
}
-
}
-25
Sources/PterodactylSyntax/Diagnostic.swift
···
-
// SPDX-FileCopyrightText: 2025 The Project Pterodactyl Developers
-
//
-
// SPDX-License-Identifier: MPL-2.0
-
-
public struct Diagnostic: Equatable {
-
enum Severity: Equatable {
-
case error
-
case warning
-
case note
-
}
-
let message: String
-
let severity: Severity
-
/// Absolute UTF-16 code unit offsets from start of source
-
let absoluteRange: Range<Int>
-
-
init(message: String, severity: Severity, absoluteRange: Range<Int>) {
-
self.message = message
-
self.severity = severity
-
self.absoluteRange = absoluteRange
-
}
-
-
init(message: String, absoluteRange: Range<Int>) {
-
self.init(message: message, severity: Severity.error, absoluteRange: absoluteRange)
-
}
-
}
-76
Sources/PterodactylSyntax/Lexer.swift
···
-
// SPDX-FileCopyrightText: 2025 The Project Pterodactyl Developers
-
//
-
// SPDX-License-Identifier: MPL-2.0
-
-
//
-
// SPDX-License-Identifier: MPL-2.0
-
-
import Foundation
-
-
public struct Lexer {
-
private let input: String
-
private var index: String.Index
-
private var tokens: [PterodactylSyntax.Token]
-
-
public init(input: String) {
-
self.input = input
-
self.index = input.startIndex
-
self.tokens = []
-
}
-
-
static let keywords: [String: Keyword] = [
-
"import": .import
-
]
-
-
public mutating func nextToken() -> Token {
-
guard !isAtEnd else {
-
return Token(kind: .eof, text: "")
-
}
-
-
let char = currentChar
-
-
if char.isNewline {
-
advance()
-
return Token(kind: .whitespace(.newline), text: String(char))
-
}
-
-
if char.isWhitespace {
-
let text = readWhile { $0.isWhitespace && !$0.isNewline }
-
return Token(kind: .whitespace(.other), text: text)
-
}
-
-
if char.isLetter {
-
let word = readWhile { $0.isLetter || $0.isNumber || $0 == "_" }
-
let kind: TokenKind =
-
if let keyword = Self.keywords[word] {
-
.keyword(keyword)
-
} else {
-
.identifier
-
}
-
return Token(kind: kind, text: word)
-
}
-
-
advance()
-
return Token(kind: .error, text: String(char))
-
}
-
-
private mutating func readWhile(_ condition: (Character) -> Bool) -> String {
-
var result = ""
-
while !isAtEnd && condition(currentChar) {
-
result.append(currentChar)
-
advance()
-
}
-
return result
-
}
-
-
private var currentChar: Character { input[index] }
-
-
private var isAtEnd: Bool {
-
index == input.endIndex
-
}
-
-
private mutating func advance() {
-
guard index < input.endIndex else { return }
-
index = input.index(after: index)
-
}
-
}
+10 -12
Sources/PterodactylSyntax/SyntaxTree.swift
···
import Foundation
public struct SyntaxTree: Codable, Sendable {
-
public var kind: SyntaxTreeKind
-
public var metadata: SyntaxTreeMetadata?
-
public var children: [Child]
-
-
public var utf16Length: Int {
-
children.reduce(0) { length, child in
-
length + child.utf16Length
-
}
-
}
-
+
public let kind: SyntaxTreeKind
+
public let metadata: SyntaxTreeMetadata?
+
public let children: [Child]
+
public let utf16Length: Int
+
public enum Child: Codable, Sendable {
-
case token(Token, metadata: TokenMetadata? = nil)
+
case token(Token, metadata: TokenMetadata?)
case tree(SyntaxTree)
}
-
public init(kind: SyntaxTreeKind, metadata: SyntaxTreeMetadata? = nil, children: [SyntaxTree.Child]) {
+
public init(kind: SyntaxTreeKind, metadata: SyntaxTreeMetadata?, children: [SyntaxTree.Child]) {
self.kind = kind
self.metadata = metadata
self.children = children
+
self.utf16Length = children.reduce(0) { length, child in
+
length + child.utf16Length
+
}
}
}
+2 -47
Sources/PterodactylSyntax/Types.swift
···
import Foundation
-
public enum Keyword: Codable, Equatable, Sendable {
-
case `import`
-
case theory
-
case `where`
-
}
-
-
public enum Whitespace: Codable, Equatable, Sendable {
-
case newline
-
case other
-
}
-
public enum TokenKind: Codable, Equatable, Sendable {
case eof
-
case keyword(Keyword)
-
case error
-
case identifier
-
case whitespace(Whitespace)
-
case blockBegin
-
case blockEnd
-
case blockSep
}
-
public final class SyntaxTreeKind: Codable, Equatable, Sendable {
-
static let error: SyntaxTreeKind = .init(name: "error")
-
-
public static func == (lhs: SyntaxTreeKind, rhs: SyntaxTreeKind) -> Bool {
-
lhs === rhs
-
}
-
-
let name: String
-
var description: String { name }
-
-
required init(name: String) {
-
self.name = name
-
}
+
public enum SyntaxTreeKind: Codable, Equatable, Sendable {
+
case error
}
public struct TokenMetadata: Codable, Equatable, Sendable {
···
public struct SyntaxTreeMetadata: Codable, Equatable, Sendable {
}
-
-
extension TokenKind {
-
var canDetermineLayoutColumn: Bool {
-
switch self {
-
case .whitespace, .eof: false
-
default: true
-
}
-
}
-
-
var isBlockHerald: Bool {
-
switch self {
-
case .keyword(.where): true
-
default: false
-
}
-
}
-
}
-4
license.sh
···
-
#!/bin/bash
-
-
reuse annotate --recursive --license MPL-2.0 --copyright "The Project Pterodactyl Developers" Tests Sources
-