Skip to content

Commit

Permalink
feat: add syntax highlightings
Browse files Browse the repository at this point in the history
  • Loading branch information
x86y committed Oct 16, 2023
1 parent b380ae9 commit 159bada
Show file tree
Hide file tree
Showing 8 changed files with 291 additions and 113 deletions.
12 changes: 12 additions & 0 deletions Beacon.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@
F361BF0C2AD2A76700200F72 /* DashboardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3DF82892A4EF33A00F6CD19 /* DashboardView.swift */; };
F379CEC32ADD94BC00164F76 /* LexK.swift in Sources */ = {isa = PBXBuildFile; fileRef = F379CEC22ADD94BC00164F76 /* LexK.swift */; };
F379CEC42ADD94BC00164F76 /* LexK.swift in Sources */ = {isa = PBXBuildFile; fileRef = F379CEC22ADD94BC00164F76 /* LexK.swift */; };
F379CEC62ADDB24D00164F76 /* LexBQN.swift in Sources */ = {isa = PBXBuildFile; fileRef = F379CEC52ADDB24D00164F76 /* LexBQN.swift */; };
F379CEC72ADDB24D00164F76 /* LexBQN.swift in Sources */ = {isa = PBXBuildFile; fileRef = F379CEC52ADDB24D00164F76 /* LexBQN.swift */; };
F379CEC92ADDD2A700164F76 /* Tokenizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F379CEC82ADDD2A700164F76 /* Tokenizer.swift */; };
F379CECA2ADDD2A700164F76 /* Tokenizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F379CEC82ADDD2A700164F76 /* Tokenizer.swift */; };
F3877C8E29952A6600E2FCB5 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F3877C8D29952A6600E2FCB5 /* Assets.xcassets */; };
F38F03A92A323F8500F66354 /* libksim.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F38F03A82A323F8500F66354 /* libksim.a */; };
F3AC4D262A4F6C3100B4FECD /* curl.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = F3AC4D252A4F6C3000B4FECD /* curl.xcframework */; };
Expand Down Expand Up @@ -107,6 +111,8 @@
F35FE0AD2A44387C00653849 /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; };
F35FE0AF2A44387D00653849 /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; };
F379CEC22ADD94BC00164F76 /* LexK.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LexK.swift; sourceTree = "<group>"; };
F379CEC52ADDB24D00164F76 /* LexBQN.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LexBQN.swift; sourceTree = "<group>"; };
F379CEC82ADDD2A700164F76 /* Tokenizer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tokenizer.swift; sourceTree = "<group>"; };
F3877C8B29952A5400E2FCB5 /* ContentView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
F3877C8D29952A6600E2FCB5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
F38F03A82A323F8500F66354 /* libksim.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libksim.a; path = Beacon/libs/libksim.a; sourceTree = "<group>"; };
Expand Down Expand Up @@ -201,6 +207,8 @@
F3E1DFF62A3216C000B4A553 /* k.h */,
F312CF8729951C49008EC197 /* Beacon-Bridging-Header.h */,
F379CEC22ADD94BC00164F76 /* LexK.swift */,
F379CEC52ADDB24D00164F76 /* LexBQN.swift */,
F379CEC82ADDD2A700164F76 /* Tokenizer.swift */,
);
path = Utilities;
sourceTree = "<group>";
Expand Down Expand Up @@ -449,10 +457,12 @@
F31BCE792A33B33E00A6116D /* Utils.swift in Sources */,
F3E1DFF52A31F9D800B4A553 /* ConfigView.swift in Sources */,
F32D9E8429966FCD007BC97C /* Beacon-Bridging-Header.h in Sources */,
F379CEC72ADDB24D00164F76 /* LexBQN.swift in Sources */,
F379CEC42ADD94BC00164F76 /* LexK.swift in Sources */,
F30A7B8B2A370B7800503966 /* BuffersView.swift in Sources */,
F31BCE7F2A348B7500A6116D /* HelpView.swift in Sources */,
F32D9E8529966FCD007BC97C /* ArraygroundApp.swift in Sources */,
F379CECA2ADDD2A700164F76 /* Tokenizer.swift in Sources */,
F327CA1B2ADD0A2F00FD72D9 /* ReplInput.swift in Sources */,
F32D9E8629966FCD007BC97C /* ContentView.swift in Sources */,
);
Expand All @@ -467,10 +477,12 @@
F3DF828A2A4EF33A00F6CD19 /* DashboardView.swift in Sources */,
F3E1DFF42A31F9D800B4A553 /* ConfigView.swift in Sources */,
F312CF8829951C89008EC197 /* Beacon-Bridging-Header.h in Sources */,
F379CEC62ADDB24D00164F76 /* LexBQN.swift in Sources */,
F379CEC32ADD94BC00164F76 /* LexK.swift in Sources */,
F30A7B8A2A370B7800503966 /* BuffersView.swift in Sources */,
F31BCE7E2A348B7500A6116D /* HelpView.swift in Sources */,
F3B198CE299517DA00FE664F /* ArraygroundApp.swift in Sources */,
F379CEC92ADDD2A700164F76 /* Tokenizer.swift in Sources */,
F327CA1A2ADD0A2F00FD72D9 /* ReplInput.swift in Sources */,
F32D9E972996710A007BC97C /* ContentView.swift in Sources */,
);
Expand Down
5 changes: 3 additions & 2 deletions Beacon/Models/History.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ struct Entry: Hashable, Codable, Identifiable {
var id: String = UUID().uuidString
var src: String
var out: String
var lang: Language
}

enum Buffers {
Expand Down Expand Up @@ -38,8 +39,8 @@ enum Buffers {
class HistoryModel: ObservableObject {
@Published var history: [String: [Entry]] = ["default": []]

func addMessage(with src: String, out: String, for key: String) {
let entry = Entry(src: src, out: out)
func addMessage(with src: String, out: String, lang: Language, for key: String) {
let entry = Entry(src: src, out: out, lang: lang)
if var entries = history[key] {
entries.append(entry)
history[key] = entries
Expand Down
95 changes: 95 additions & 0 deletions Beacon/Utilities/LexBQN.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
//
// LexBQN.swift
// Beacon
//

import Foundation
import SwiftUI

func parseBQN(code: String) -> [String] {
let regC = "0"
let fnsC = "1"
let fns = "!+-×÷⋆*√⌊⌈∧∨¬|=≠≤<>≥≡≢⊣⊢⥊∾≍⋈↑↓↕⌽⍉/⍋⍒⊏⊑⊐⊒∊⍷⊔«»⍎⍕"
let mopC = "2"
let mop = "`˜˘¨⁼⌜´˝˙"
let dopC = "3"
let dop = "∘⊸⟜○⌾⎉⚇⍟⊘◶⎊"
let namC = "4"
let nam = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_"
let digC = "5"
let dig = "0123456789π∞"
let digS = dig + "¯."
let digM = "eEiI"
let arrC = "6"
let arr = "·⍬‿⦃⦄⟨⟩[]@"
let dfnC = "7"
let dfn = "𝕨𝕩𝔽𝔾𝕎𝕏𝕗𝕘𝕣ℝ𝕤𝕊{}:"
let strC = "8"
let dmdC = "D"
let dmd = "←↩,⋄→⇐"
let comC = "C"
let newL = "E"

var res = Array(repeating: "", count: code.count)
var i = code.startIndex

while i < code.endIndex {
let c = code[i]
if digS.contains(c) {
res[i.utf16Offset(in: code)] = digC
i = code.index(after: i)
while dig.contains(code[safe: i] ?? "\0") || code[safe: i] == "." || digM.contains(code[safe: i] ?? "\0") && digS.contains(code[safe: code.index(after: i)] ?? "\0") {
i = code.index(after: i)
}
continue
} else if fns.contains(c) {
res[i.utf16Offset(in: code)] = fnsC
} else if mop.contains(c) {
res[i.utf16Offset(in: code)] = mopC
} else if dop.contains(c) {
res[i.utf16Offset(in: code)] = dopC
} else if dfn.contains(c) {
res[i.utf16Offset(in: code)] = dfnC
} else if arr.contains(c) {
res[i.utf16Offset(in: code)] = arrC
} else if dmd.contains(c) {
res[i.utf16Offset(in: code)] = dmdC
} else if nam.contains(c) || c == "" {
let fst = i
if code[safe: i] == "" {
i = code.index(after: i)
}
let cs = code[safe: i] ?? "\0"
while nam.contains(code[safe: i] ?? "\0") || dig.contains(code[safe: i] ?? "\0") {
i = code.index(after: i)
}
let ce = code[safe: code.index(before: i)] ?? "\0"
res[fst.utf16Offset(in: code)] = cs == "_" ? (ce == "_" ? dopC : mopC) : (cs >= "A" && cs <= "Z" ? fnsC : namC)
continue
} else if c == "'" || c == "\"" {
res[i.utf16Offset(in: code)] = strC
i = code.index(after: i)
let q = c
while code[safe: i] != nil, code[safe: i] != q, code[safe: i] != "\n" {
i = code.index(after: i)
}
} else if c == "#" {
res[i.utf16Offset(in: code)] = comC
while code[safe: i] != nil, code[safe: i] != "\n" {
i = code.index(after: i)
}
} else if !" \t".contains(c) {
res[i.utf16Offset(in: code)] = regC
} else if c == "\n" {
res[i.utf16Offset(in: code)] = newL
}
i = code.index(after: i)
}
return res
}

extension String {
subscript(safe index: Index) -> Character? {
return indices.contains(index) ? self[index] : nil
}
}
132 changes: 64 additions & 68 deletions Beacon/Utilities/LexK.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,85 +3,81 @@
// Arrayground
//

import Foundation
import SwiftUI

enum TokenType {
case number, function, variable, string, statement, comment, other
}
func parseK(_ str: String) -> [String] {
let regC = "0"
let fnsC = "1"
let fns = "+-*%!&|<>=~,^#_?@."
let mopC = "2"
let mop = "/'\\"
let namC = "4"
let nam = "⎕⍞∆⍙ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
let digC = "5"
let dig = "0123456789¯∞"
let parC = "6"
let dfnC = "7"
let strC = "8"
let dmdC = "D"
let dmd = ":$"
let comC = "C"
let endL = "E"

struct Token {
let value: String
let type: TokenType
}
var res = Array(repeating: "", count: str.count)
res[0] = regC

func tokenize(code: String) -> [Token] {
var tokens: [Token] = []
var currentToken = ""
var isComment = false
var isString = false
var i = 0

for char in code {
if isComment {
currentToken.append(char)
if char == "\n" {
tokens.append(Token(value: currentToken, type: .comment))
currentToken = ""
isComment = false
}
continue
}
while i < str.count {
let p = i - 1 >= 0 ? String(str[str.index(str.startIndex, offsetBy: i - 1) ... str.index(str.startIndex, offsetBy: i - 1)]) : "\0"
let c = String(str[str.index(str.startIndex, offsetBy: i) ... str.index(str.startIndex, offsetBy: i)])
let n = i + 1 < str.count ? String(str[str.index(str.startIndex, offsetBy: i + 1) ... str.index(str.startIndex, offsetBy: i + 1)]) : "\0"

if isString {
currentToken.append(char)
if char == "\"" {
tokens.append(Token(value: currentToken, type: .string))
currentToken = ""
isString = false
if dig.contains(c) || (c == "." && dig.contains(n)) {
res[i] = digC
while i < str.count, dig.contains(String(str[str.index(str.startIndex, offsetBy: i) ... str.index(str.startIndex, offsetBy: i)])) || ".eEnNbiwW".contains(String(str[str.index(str.startIndex, offsetBy: i) ... str.index(str.startIndex, offsetBy: i)])) {
i += 1
}
continue
}

if char == "#" || char == "/" {
isComment = true
currentToken.append(char)
continue
}

if char == "\"" {
isString = true
currentToken.append(char)
} else if (c == " " && n == "/") || ((p == "\n" || p == "\0") && c == "/") {
res[i] = comC
while str[str.index(str.startIndex, offsetBy: i) ... str.index(str.startIndex, offsetBy: i)] != "\n" {
i += 1
}
} else if fns.contains(c) || c.unicodeScalars.first!.value >= 0x80 {
res[i] = fnsC
} else if mop.contains(c) {
res[i] = mopC
if n == ":" {
i += 1
res[i] = mopC
}
} else if "{xyz}".contains(c) {
res[i] = dfnC
} else if "([])".contains(c) {
res[i] = parC
} else if dmd.contains(c) {
res[i] = dmdC
} else if nam.contains(c) {
res[i] = namC
while nam.contains(String(str[str.index(str.startIndex, offsetBy: i) ... str.index(str.startIndex, offsetBy: i)])) || dig.contains(String(str[str.index(str.startIndex, offsetBy: i) ... str.index(str.startIndex, offsetBy: i)])) {
i += 1
}
continue
}

if char.isWhitespace {
if !currentToken.isEmpty {
tokens.append(Token(value: currentToken, type: determineType(token: currentToken)))
} else if c == "\"" {
res[i] = strC
i += 1
while str[str.index(str.startIndex, offsetBy: i) ... str.index(str.startIndex, offsetBy: i)] != "\"", str[str.index(str.startIndex, offsetBy: i) ... str.index(str.startIndex, offsetBy: i)] != "\n" {
i += String(str[str.index(str.startIndex, offsetBy: i) ... str.index(str.startIndex, offsetBy: i)]) == "\\" ? 2 : 1
}
currentToken = ""
} else {
currentToken.append(char)
} else if !" \t".contains(c) {
res[i] = regC
} else if c == "\n" {
res[i] = endL
}
i += 1
}

if !currentToken.isEmpty {
tokens.append(Token(value: currentToken, type: determineType(token: currentToken)))
}

return tokens
}

func determineType(token: String) -> TokenType {
if Double(token) != nil {
return .number
}
if token.last == ":" {
return .function
}
if token.first?.isLetter == true {
return .variable
}
if token == ":" {
return .statement
}
return .other
return res
}
Loading

0 comments on commit 159bada

Please sign in to comment.