sibil/Sibil/Lexer.swift

139 lines
3 KiB
Swift
Raw Normal View History

//
// Lexer.swift
// Sibil
//
// Created by Eryn Wells on 12/16/16.
// Copyright © 2016 Eryn Wells. All rights reserved.
//
import Foundation
2016-12-16 10:10:05 -08:00
struct Token: CustomDebugStringConvertible {
enum Kind {
case LeftParen
case RightParen
}
let kind: Kind
let value: String
2016-12-16 10:10:05 -08:00
// MARK: CustomDebugStringConvertible
var debugDescription: String {
return "Token(kind: .\(kind), value: \"\(value)\")"
}
}
2016-12-16 10:10:05 -08:00
class Lexer {
let input: String
2016-12-16 10:10:05 -08:00
var index: String.Index
init(input: String) {
self.input = input
self.index = input.startIndex
}
2016-12-16 10:10:05 -08:00
}
2016-12-16 10:10:05 -08:00
extension Lexer: Sequence, IteratorProtocol {
typealias Element = Token
2016-12-17 10:04:35 -08:00
private enum State {
case Initial
case Identifier
case Emit
}
2016-12-16 10:10:05 -08:00
func makeIterator() -> Lexer {
return self
}
func next() -> Token? {
2016-12-16 10:10:05 -08:00
guard index != input.endIndex else {
return nil
}
2016-12-17 10:04:35 -08:00
var state = State.Initial
var token: Token?
2016-12-17 10:04:35 -08:00
var forward = index
let toState = { (nextState: State) in
state = nextState
}
let retract = {
forward = self.input.index(before: forward)
}
let advance = {
forward = self.input.index(after: forward)
}
let emit = { (kind: Token.Kind) in
let valueRange = Range(uncheckedBounds: (lower: self.index, upper: forward))
let value = self.input.substring(with: valueRange)
token = Token(kind: kind, value: value)
toState(.Emit)
}
while state != .Emit {
let c = input[index]
2016-12-17 10:04:35 -08:00
switch state {
case .Initial:
if c.isLeftParen {
}
else if c.isRightParen {
}
else if c.isIdentifierInitial {
advance()
toState(.Identifier)
}
case .Identifier:
if c.isIdentifierSubsequent
case .Emit:
// Nothing to do for this state
break
}
}
2016-12-17 10:04:35 -08:00
return token
}
}
2016-12-17 10:04:35 -08:00
extension Character {
static let identifierInitialSet: CharacterSet = {
let letters = CharacterSet.letters
let extras = CharacterSet(charactersIn: "!$%&*/:<=>?~_^")
let initials = letters.union(extras)
return initials
}()
static let identifierSubsequentSet: CharacterSet = {
let initials = Character.identifierInitialSet
let digits = CharacterSet.decimalDigits
let extras = CharacterSet(charactersIn: ".+-")
let subsequents = initials.union(digits).union(extras)
return subsequents
}()
var isLeftParen: Bool {
return self == "("
}
var isRightParen: Bool {
return self == ")"
}
var isIdentifierInitial: Bool {
return false
}
var isIdentifierSubsequent: Bool {
Character.identifierSubsequentSet.contains(<#T##member: UnicodeScalar##UnicodeScalar#>)
}
}