You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
63 lines
1.6 KiB
63 lines
1.6 KiB
//
|
|
// Lexer.swift
|
|
// Kaleidoscope
|
|
//
|
|
// Created by Matthew Cheok on 15/11/15.
|
|
// Copyright © 2015 Matthew Cheok. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
|
|
public enum Token {
|
|
case identifier(String, CountableRange<Int>)
|
|
case number(Float, CountableRange<Int>)
|
|
case parensOpen(CountableRange<Int>)
|
|
case parensClose(CountableRange<Int>)
|
|
case comma(CountableRange<Int>)
|
|
case other(String, CountableRange<Int>)
|
|
}
|
|
|
|
typealias TokenGenerator = (String, CountableRange<Int>) -> Token?
|
|
let tokenList: [(String, TokenGenerator)] = [
|
|
("[ \t\n]", { _, _ in nil }),
|
|
("[a-zA-Z][a-zA-Z0-9]*", { .identifier($0, $1) }),
|
|
("\\-?[0-9.]+", { .number(Float($0)!, $1) }),
|
|
("\\(", { .parensOpen($1) }),
|
|
("\\)", { .parensClose($1) }),
|
|
(",", { .comma($1) })
|
|
]
|
|
|
|
public class Lexer {
|
|
let input: String
|
|
public init(input: String) {
|
|
self.input = input
|
|
}
|
|
public func tokenize() -> [Token] {
|
|
var tokens = [Token]()
|
|
var content = input
|
|
|
|
while !content.isEmpty {
|
|
var matched = false
|
|
|
|
for (pattern, generator) in tokenList {
|
|
if let (m, r) = content.match(regex: pattern) {
|
|
if let t = generator(m, r) {
|
|
tokens.append(t)
|
|
}
|
|
|
|
content = String(content[content.index(content.startIndex, offsetBy: m.count)...])
|
|
matched = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !matched {
|
|
let index = content.index(content.startIndex, offsetBy: 1)
|
|
let intIndex = content.distance(from: content.startIndex, to: index)
|
|
tokens.append(.other(String(content[..<index]), intIndex..<intIndex+1))
|
|
content = String(content[index...])
|
|
}
|
|
}
|
|
return tokens
|
|
}
|
|
}
|