Website Summary Files Commits Branches @commit @diff @stats
diff options
context:
space:
mode:
Commit5a4403ef23e17a3da84f1ec9feb3ab294d23c198 (patch)
Author
 Georgi Bojinov <georgi.bojinov@hotmail.com>
2018-11-07 12:48:13 +0200
Committer
 dtrendafilov <trendafilov.dn@gmail.com>
2018-11-07 12:48:13 +0200
Files84959e0253a2a2be296dc53c580899e1be197319
IPL-5a4403ef23e17a3da84f1ec9feb3ab294d23c198.tar
IPL-5a4403ef23e17a3da84f1ec9feb3ab294d23c198.tar.gz
IPL-5a4403ef23e17a3da84f1ec9feb3ab294d23c198.zip
Parent65c7618c2a8834616b009195f10c6cd762f43b8a (diff)
Add golang ot html highlighter (#28)
diff --git a/homework/81333/golang-highlighter/.gitignore b/homework/81333/golang-highlighter/.gitignore
new file mode 100644
index 0000000..9cd93b8
--- /dev/null
+++ b/homework/81333/golang-highlighter/.gitignore
@@ -0,0 +1,8 @@
+# stack files
+.stack-work/
+highlighter.cabal
+*~
+
+# test files
+*.txt
+*.html
diff --git a/homework/81333/golang-highlighter/ChangeLog.md b/homework/81333/golang-highlighter/ChangeLog.md
new file mode 100644
index 0000000..959500a
--- /dev/null
+++ b/homework/81333/golang-highlighter/ChangeLog.md
@@ -0,0 +1,3 @@
+# Changelog for highlighter
+
+## Unreleased changes
diff --git a/homework/81333/golang-highlighter/LICENSE b/homework/81333/golang-highlighter/LICENSE
new file mode 100644
index 0000000..e037c72
--- /dev/null
+++ b/homework/81333/golang-highlighter/LICENSE
@@ -0,0 +1,30 @@
+Copyright Author name here (c) 2018
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+
+ * Neither the name of Author name here nor the names of other
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/homework/81333/golang-highlighter/README.md b/homework/81333/golang-highlighter/README.md
new file mode 100644
index 0000000..c2666bf
--- /dev/null
+++ b/homework/81333/golang-highlighter/README.md
@@ -0,0 +1,23 @@
+# Go2Html Highlighter (WIP)
+
+Library that takes in Go code, passes it through a lexer and outputs it highlighted in an html file
+
+# How to build
+
+Install [stack](https://docs.haskellstack.org/en/stable/README/) build tool
+
+Run following commands from root of project:
+
+Building:
+
+```
+stack build
+```
+
+Executing:
+
+```
+stack exec golangToHtml <file_with_code>
+```
+
+Result will be in `source.html`
diff --git a/homework/81333/golang-highlighter/Setup.hs b/homework/81333/golang-highlighter/Setup.hs
new file mode 100644
index 0000000..9a994af
--- /dev/null
+++ b/homework/81333/golang-highlighter/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/homework/81333/golang-highlighter/app/Main.hs b/homework/81333/golang-highlighter/app/Main.hs
new file mode 100644
index 0000000..c8e0af7
--- /dev/null
+++ b/homework/81333/golang-highlighter/app/Main.hs
@@ -0,0 +1,16 @@
+module Main where
+
+import qualified Data.Text.IO as TI
+import System.Environment (getArgs)
+
+import Lib (golangToHtml)
+
+main :: IO ()
+main = do
+ args <- getArgs
+ case args of
+ [] -> putStrLn "Usage: ./golangToHtml <file_with_code>"
+ _ -> do
+ code <- TI.readFile $ args !! 0
+ TI.writeFile "source.html" (golangToHtml code)
+ putStrLn "Source written."
diff --git a/homework/81333/golang-highlighter/package.yaml b/homework/81333/golang-highlighter/package.yaml
new file mode 100644
index 0000000..36995a2
--- /dev/null
+++ b/homework/81333/golang-highlighter/package.yaml
@@ -0,0 +1,50 @@
+name: highlighter
+version: 0.1.0.0
+github: "githubuser/highlighter"
+license: BSD3
+author: "Author name here"
+maintainer: "example@example.com"
+copyright: "2018 Author name here"
+
+extra-source-files:
+- README.md
+- ChangeLog.md
+
+# Metadata used when publishing your package
+# synopsis: Short description of your package
+# category: Web
+
+# To avoid duplicated efforts in documentation and dealing with the
+# complications of embedding Haddock markup inside cabal files, it is
+# common to point users to the README.md file.
+description: Please see the README on GitHub at <https://github.com/githubuser/highlighter#readme>
+
+dependencies:
+- base >= 4.7 && < 5
+- containers
+- text
+
+library:
+ source-dirs: src
+
+executables:
+ golangToHtml:
+ main: Main.hs
+ source-dirs: app
+ ghc-options:
+ - -threaded
+ - -rtsopts
+ - -with-rtsopts=-N
+ dependencies:
+ - highlighter
+
+tests:
+ highlighter-test:
+ main: Spec.hs
+ source-dirs: test
+ ghc-options:
+ - -threaded
+ - -rtsopts
+ - -with-rtsopts=-N
+ dependencies:
+ - highlighter
diff --git a/homework/81333/golang-highlighter/src/Data/Highlighter.hs b/homework/81333/golang-highlighter/src/Data/Highlighter.hs
new file mode 100644
index 0000000..80921f2
--- /dev/null
+++ b/homework/81333/golang-highlighter/src/Data/Highlighter.hs
@@ -0,0 +1,54 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Data.Highlighter
+ ( tokensToHtml
+ ) where
+
+import qualified Data.Text as T
+import qualified Data.Text.IO as TI
+
+import Data.Token
+import Data.TokenTypes
+
+initialHtml :: T.Text
+initialHtml =
+ T.unlines
+ [ "<html>"
+ , "<head>"
+ , "<style>"
+ , ".keyword { color: orange; }"
+ , ".comment { color: grey; }"
+ , ".preident { color: red; }"
+ , ".operator { color: black; }"
+ , ".ident { color: blue; }"
+ , ".string { color: green; }"
+ , ".number { color: purple; }"
+ , "</style>"
+ , "</head>"
+ , "<body>"
+ ]
+
+toHtml :: Token -> T.Text
+toHtml (Token {tokenType = Space _, lexeme = lex, location = (line, col)}) = lex
+toHtml (Token {tokenType = Comment _, lexeme = lex, location = (line, col)}) =
+ "<span class=comment>" <> lex <> "</span>"
+toHtml (Token {tokenType = Keyword _, lexeme = lex, location = (line, col)}) =
+ "<span class=keyword>" <> lex <> "</span>"
+toHtml (Token {tokenType = PredeclIdent _, lexeme = lex, location = (line, col)}) =
+ "<span class=preident>" <> lex <> "</span>"
+toHtml (Token {tokenType = Operator _, lexeme = lex, location = (line, col)}) =
+ "<span class=operator>" <> lex <> "</span>"
+toHtml (Token {tokenType = Ident _, lexeme = lex, location = (line, col)}) =
+ "<span class=ident>" <> lex <> "</span>"
+toHtml (Token { tokenType = Literal (StringLiteral _)
+ , lexeme = lex
+ , location = (line, col)
+ }) = "<span class=string>" <> lex <> "</span>"
+toHtml (Token { tokenType = Literal (Number _)
+ , lexeme = lex
+ , location = (line, col)
+ }) = "<span class=number>" <> lex <> "</span>"
+
+tokensToHtml :: [Token] -> T.Text
+tokensToHtml tokens =
+ initialHtml <> T.concat (map toHtml tokens) <> "</body><br></html>"
diff --git a/homework/81333/golang-highlighter/src/Data/Lexer.hs b/homework/81333/golang-highlighter/src/Data/Lexer.hs
new file mode 100644
index 0000000..defc73b
--- /dev/null
+++ b/homework/81333/golang-highlighter/src/Data/Lexer.hs
@@ -0,0 +1,89 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Data.Lexer
+ ( tokenize
+ ) where
+
+import Data.Char (isAlpha, isAlphaNum)
+import qualified Data.Map.Strict as MapS
+import Data.Maps (keywords, operators, predeclIdentifiers)
+import qualified Data.Text as T
+import Data.Token
+import Data.TokenTypes
+import Data.Utils
+import Debug.Trace
+
+parseIdent :: T.Text -> Line -> Column -> Token
+parseIdent ident line column
+ | MapS.member ident keywords = token keywords ident line column
+ | MapS.member ident predeclIdentifiers =
+ token predeclIdentifiers ident line column
+ | otherwise =
+ Token
+ { tokenType = Ident (Identifier ident)
+ , lexeme = ident
+ , location = (line, column)
+ }
+
+parseSingleOperator :: Char -> Line -> Column -> Token
+parseSingleOperator c line column = singleOp
+ where
+ singleOp = token operators (T.singleton c) line (column + 1)
+
+parseDoubleOperator :: T.Text -> Line -> Column -> Token
+parseDoubleOperator op line column = doubleOp
+ where
+ doubleOp = token operators op line (column + 2)
+
+parseTripleOperator :: T.Text -> Line -> Column -> Token
+parseTripleOperator op line column = tripleOp
+ where
+ tripleOp = token operators op line (column + 3)
+
+tokenizeChar :: Char -> T.Text -> Line -> Column -> [Token]
+tokenizeChar c code line column
+ | isAlpha c || c == '_' =
+ parseIdent (T.strip ident) line (column + T.length ident) :
+ tokenize (stripPrefix code) line (column + T.length ident)
+ | T.length code >= 2 && twoAhead == "//" =
+ tokenSingleComment comment line column :
+ tokenize (next comment code) line (column + T.length comment)
+ | T.length code >= 3 && isThreePlaceOperator threeAhead =
+ parseTripleOperator threeAhead line column :
+ tokenize skipThree line (column + 3)
+ | T.length code >= 2 && isTwoPlaceOperator twoAhead =
+ parseDoubleOperator twoAhead line column :
+ tokenize skipTwo line (column + 2)
+ | isOnePlaceOperator c =
+ parseSingleOperator c line column : tokenize (T.tail code) line (column + 1)
+ | isTab c =
+ tokenSpace "\t" line column : tokenize (T.tail code) line (column + 1)
+ | isWhitespace c =
+ tokenSpace " " line column : tokenize (T.tail code) line (column + 1)
+ | isNewLine c =
+ tokenSpace "\n" line column : tokenize (T.tail code) (line + 1) 0
+ | isAlphaNum c =
+ tokenNumber num line column :
+ tokenize (next num code) line (column + T.length num)
+ | c == '"' =
+ tokenStringLiteral stringLit line column :
+ tokenize (next stringLit code) line (column + T.length stringLit)
+ | otherwise = tokenize (T.tail code) line column
+ where
+ ident = getPrefix code
+ next string = T.drop (T.length string)
+ twoAhead = T.pack ([c] <> [(T.head (T.tail code))])
+ threeAhead = twoAhead <> T.pack ([T.head (T.tail (T.tail code))])
+ comment = getSingleLineComment code
+ skipTwo = T.tail $ T.tail code
+ skipThree = T.tail $ T.tail $ T.tail code
+ num = getDecNumber code
+ stringLit = getStringLiteral (T.drop 1 code)
+
+tokenize :: T.Text -> Line -> Column -> [Token]
+-- tokenize code line column
+-- | trace ("\nCode is: " <> (T.unpack code)) False = undefined
+tokenize code line column =
+ case safeHead code of
+ Nothing -> []
+ Just c -> tokenizeChar c code line column
diff --git a/homework/81333/golang-highlighter/src/Data/Maps.hs b/homework/81333/golang-highlighter/src/Data/Maps.hs
new file mode 100644
index 0000000..f444ffb
--- /dev/null
+++ b/homework/81333/golang-highlighter/src/Data/Maps.hs
@@ -0,0 +1,21 @@
+module Data.Maps where
+
+import qualified Data.Map.Strict as MapS
+import qualified Data.Text as T
+
+import Data.TokenTypes
+
+keywords :: MapS.Map T.Text TokenType
+keywords =
+ let keywords = [Break ..]
+ in MapS.fromList $ zip (map (T.pack . show) keywords) (map Keyword keywords)
+
+predeclIdentifiers :: MapS.Map T.Text TokenType
+predeclIdentifiers =
+ let idents = [Boolean ..]
+ in MapS.fromList $ zip (map (T.pack . show) idents) (map PredeclIdent idents)
+
+operators :: MapS.Map T.Text TokenType
+operators =
+ let ops = [Plus ..]
+ in MapS.fromList $ zip (map (T.pack . show) ops) (map Operator ops)
diff --git a/homework/81333/golang-highlighter/src/Data/Token.hs b/homework/81333/golang-highlighter/src/Data/Token.hs
new file mode 100644
index 0000000..3683a7f
--- /dev/null
+++ b/homework/81333/golang-highlighter/src/Data/Token.hs
@@ -0,0 +1,16 @@
+module Data.Token where
+
+import qualified Data.Text as T
+import Data.TokenTypes (TokenType)
+
+type Lexeme = T.Text
+
+type Line = Int
+
+type Column = Int
+
+data Token = Token
+ { tokenType :: TokenType
+ , lexeme :: Lexeme
+ , location :: (Line, Column)
+ } deriving (Show)
diff --git a/homework/81333/golang-highlighter/src/Data/TokenTypes.hs b/homework/81333/golang-highlighter/src/Data/TokenTypes.hs
new file mode 100644
index 0000000..e0af38e
--- /dev/null
+++ b/homework/81333/golang-highlighter/src/Data/TokenTypes.hs
@@ -0,0 +1,289 @@
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+module Data.TokenTypes where
+
+import qualified Data.Text as T
+
+data TokenKeyword
+ = Break
+ | Case
+ | Chan
+ | Const
+ | Continue
+ | Default
+ | Defer
+ | Else
+ | Fallthrough
+ | For
+ | Func
+ | Go
+ | Goto
+ | If
+ | Import
+ | Interface
+ | Map
+ | Package
+ | Range
+ | Return
+ | Select
+ | Struct
+ | Switch
+ | Type
+ | Var
+ deriving (Enum)
+
+instance Show TokenKeyword where
+ show Break = "break"
+ show Case = "case"
+ show Chan = "chan"
+ show Const = "const"
+ show Continue = "continue"
+ show Default = "default"
+ show Defer = "defer"
+ show Else = "else"
+ show Fallthrough = "fallthrough"
+ show For = "for"
+ show Func = "func"
+ show Go = "go"
+ show Goto = "goto"
+ show If = "if"
+ show Import = "import"
+ show Interface = "interface"
+ show Map = "map"
+ show Package = "package"
+ show Range = "range"
+ show Return = "return"
+ show Select = "select"
+ show Struct = "struct"
+ show Switch = "switch"
+ show Type = "type"
+ show Var = "var"
+
+data TokenPredeclIdentifier
+ = Boolean
+ | Byte
+ | Complex64
+ | Complex128
+ | Error
+ | Float32
+ | Float64
+ | PlainInt
+ | Int8
+ | Int16
+ | Int32
+ | Int64
+ | Rune
+ | Str
+ | Uint
+ | Uint8
+ | Uint16
+ | Uint32
+ | Uint64
+ | UintPointer
+ | BoolTrue
+ | BoolFalse
+ | Iota
+ | Nil
+ | Append
+ | Cap
+ | Close
+ | Complex
+ | Copy
+ | Delete
+ | Imag
+ | Len
+ | Make
+ | New
+ | Panic
+ | Print
+ | Println
+ | Real
+ | Recover
+ deriving (Enum)
+
+instance Show TokenPredeclIdentifier where
+ show Boolean = "bool"
+ show Byte = "byte"
+ show Complex64 = "complex64"
+ show Complex128 = "complex128"
+ show Error = "error"
+ show Float32 = "float32"
+ show Float64 = "float64"
+ show PlainInt = "int"
+ show Int8 = "int8"
+ show Int16 = "int16"
+ show Int32 = "int32"
+ show Int64 = "int64"
+ show Rune = "rune"
+ show Str = "string"
+ show Uint = "uint"
+ show Uint8 = "uint8"
+ show Uint16 = "uint16"
+ show Uint32 = "uint32"
+ show Uint64 = "uint64"
+ show UintPointer = "uintptr"
+ show BoolTrue = "true"
+ show BoolFalse = "false"
+ show Iota = "iota"
+ show Nil = "nil"
+ show Append = "append"
+ show Cap = "cap"
+ show Close = "close"
+ show Complex = "complex"
+ show Copy = "copy"
+ show Delete = "delete"
+ show Imag = "imag"
+ show Len = "len"
+ show Make = "make"
+ show New = "new"
+ show Panic = "panic"
+ show Print = "print"
+ show Println = "println"
+ show Real = "real"
+ show Recover = "recover"
+
+data TokenIdentifier =
+ Identifier T.Text
+
+instance Show TokenIdentifier where
+ show (Identifier s) = show s
+
+data TokenOperator
+ = Plus
+ | Minus
+ | Mult
+ | Div
+ | Mod
+ | BitAnd
+ | BitOr
+ | XOR
+ | LShift
+ | RShift
+ | PlusEq
+ | MinusEq
+ | MultEq
+ | DivEq
+ | ModEq
+ | BitAndEq
+ | BitOrEq
+ | XorEq
+ | LShiftEq
+ | MShiftEq
+ | And
+ | Or
+ | Recv
+ | PlusPlus
+ | MinusMinus
+ | Equal
+ | LessThan
+ | GreaterThan
+ | Assign
+ | Bang
+ | Diff
+ | LessThanOrEq
+ | GreaterThanOrEq
+ | TypeAssign
+ | TripleDot
+ | LParen
+ | RParen
+ | LSqParen
+ | RSqParen
+ | LBlockParen
+ | RBlockParen
+ | Comma
+ | SemiColon
+ | Colon
+ | Dot
+ deriving (Enum)
+
+instance Show TokenOperator where
+ show Plus = "+"
+ show Minus = "-"
+ show Mult = "*"
+ show Div = "/"
+ show Mod = "%"
+ show BitAnd = "&"
+ show BitOr = "|"
+ show XOR = "^"
+ show LShift = "<<"
+ show RShift = ">>"
+ show PlusEq = "+="
+ show MinusEq = "-="
+ show MultEq = "*="
+ show DivEq = "/="
+ show ModEq = "%="
+ show BitAndEq = "&="
+ show BitOrEq = "|="
+ show XorEq = "^="
+ show LShiftEq = "<<="
+ show MShiftEq = ">>="
+ show And = "&&"
+ show Or = "||"
+ show Recv = "<-"
+ show PlusPlus = "++"
+ show MinusMinus = "--"
+ show Equal = "=="
+ show LessThan = "<"
+ show GreaterThan = ">"
+ show Assign = "="
+ show Bang = "!"
+ show Diff = "!="
+ show LessThanOrEq = "<="
+ show GreaterThanOrEq = ">="
+ show TypeAssign = ":="
+ show TripleDot = "..."
+ show LParen = "("
+ show RParen = ")"
+ show LSqParen = "["
+ show RSqParen = "]"
+ show LBlockParen = "{"
+ show RBlockParen = "}"
+ show Comma = ","
+ show SemiColon = ";"
+ show Colon = ":"
+ show Dot = "."
+
+data TokenWhitespace
+ = Whitespace
+ | NewLine
+ | Tab
+
+instance Show TokenWhitespace where
+ show Whitespace = "&nbsp;"
+ show NewLine = "<br>"
+ show Tab = "&emsp;"
+
+data TokenLiteral
+ = Number T.Text
+ | FloatNumber T.Text
+ | OctNumber T.Text
+ | HexNumber T.Text
+ | RuneLiteral T.Text
+ | StringLiteral T.Text
+
+instance Show TokenLiteral where
+ show (Number num) = show num
+ show (FloatNumber num) = show num
+ show (OctNumber num) = "0" <> show num
+ show (HexNumber num) = "0x" <> show num
+ show (RuneLiteral rune) = show rune
+ show (StringLiteral string) = show string
+
+data TokenComment
+ = SingleLine T.Text
+ | MultiLine T.Text
+
+instance Show TokenComment where
+ show (SingleLine t) = "//" <> show t
+ show (MultiLine t) = "/*" <> show t <> "*/"
+
+data TokenType where
+ PredeclIdent :: TokenPredeclIdentifier -> TokenType
+ Ident :: TokenIdentifier -> TokenType
+ Keyword :: TokenKeyword -> TokenType
+ Operator :: TokenOperator -> TokenType
+ Literal :: TokenLiteral -> TokenType
+ Space :: TokenWhitespace -> TokenType
+ Comment :: TokenComment -> TokenType
+ deriving (Show)
diff --git a/homework/81333/golang-highlighter/src/Data/Utils.hs b/homework/81333/golang-highlighter/src/Data/Utils.hs
new file mode 100644
index 0000000..393d23d
--- /dev/null
+++ b/homework/81333/golang-highlighter/src/Data/Utils.hs
@@ -0,0 +1,124 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Data.Utils where
+
+import Data.Char (isAlpha, isAlphaNum)
+import qualified Data.Map.Strict as MapS
+import Data.Maps (keywords, operators, predeclIdentifiers)
+import qualified Data.Text as T
+import Data.Token
+import Data.TokenTypes
+import Debug.Trace
+
+safeHead :: T.Text -> Maybe Char
+safeHead s =
+ if s == ""
+ then Nothing
+ else Just $ T.head s
+
+safeTail :: T.Text -> Maybe T.Text
+safeTail s =
+ if s == ""
+ then Nothing
+ else Just $ T.tail s
+
+token :: MapS.Map T.Text TokenType -> T.Text -> Line -> Column -> Token
+token m ident line column =
+ Token
+ {tokenType = (MapS.!) m ident, lexeme = ident, location = (line, column)}
+
+tokenNumber :: T.Text -> Line -> Column -> Token
+tokenNumber num line column =
+ Token
+ { tokenType = Literal (Number num)
+ , lexeme = num
+ , location = (line, column + T.length num)
+ }
+
+tokenStringLiteral :: T.Text -> Line -> Column -> Token
+tokenStringLiteral str line column =
+ Token
+ { tokenType = Literal (StringLiteral str)
+ , lexeme = str
+ , location = (line, column + T.length str)
+ }
+
+tokenSpace :: T.Text -> Line -> Column -> Token
+tokenSpace str line column
+ | str == " " =
+ Token
+ { tokenType = Space Whitespace
+ , lexeme = "&nbsp;"
+ , location = (line, column + 1)
+ }
+ | str == "\n" =
+ Token {tokenType = Space NewLine, lexeme = "<br>", location = (line + 1, 0)}
+ | str == "\t" =
+ Token
+ { tokenType = Space Tab
+ , lexeme = T.replicate 8 "&nbsp;"
+ , location = (line, column + 8)
+ }
+
+tokenSingleComment :: T.Text -> Line -> Column -> Token
+tokenSingleComment str line column =
+ Token
+ { tokenType = Comment (SingleLine str)
+ , lexeme = str
+ , location = (line, column + T.length str)
+ }
+
+tokenMultiComment :: T.Text -> Line -> Column -> Token
+tokenMultiComment str line column =
+ Token
+ { tokenType = Comment (MultiLine str)
+ , lexeme = str
+ , location = (line, column + T.length str)
+ }
+
+hasNewLine :: T.Text -> Bool
+hasNewLine "" = False
+hasNewLine s =
+ if T.head s == '\n'
+ then True
+ else False
+
+stripPrefix :: T.Text -> T.Text
+stripPrefix = T.dropWhile (\x -> x /= ' ' && x /= '\n' && (not $ isOperator x))
+
+getPrefix :: T.Text -> T.Text
+getPrefix = T.takeWhile (\x -> x /= ' ' && x /= '\n' && (not $ isOperator x))
+
+isOperator :: Char -> Bool
+isOperator c = any (== c) (map (T.head . T.pack . show) [Plus ..])
+
+isOnePlaceOperator :: Char -> Bool
+isOnePlaceOperator c =
+ c `elem`
+ map (T.head . T.pack . show) (filter (\x -> (length $ show x) == 1) [Plus ..])
+
+isWhitespace :: Char -> Bool
+isWhitespace c = [c] == " "
+
+isNewLine :: Char -> Bool
+isNewLine c = [c] == "\n"
+
+isTab :: Char -> Bool
+isTab c = [c] == "\t"
+
+isTwoPlaceOperator :: T.Text -> Bool
+isTwoPlaceOperator s =
+ s `elem` map (T.pack . show) (filter (\x -> (length $ show x) == 2) [Plus ..])
+
+isThreePlaceOperator :: T.Text -> Bool
+isThreePlaceOperator s =
+ s `elem` map (T.pack . show) (filter (\x -> (length $ show x) == 3) [Plus ..])
+
+getDecNumber :: T.Text -> T.Text
+getDecNumber code = T.takeWhile isAlphaNum code
+
+getStringLiteral :: T.Text -> T.Text
+getStringLiteral code = "\"" <> T.takeWhile (/= '"') code <> "\""
+
+getSingleLineComment :: T.Text -> T.Text
+getSingleLineComment = T.takeWhile (/= '\n')
diff --git a/homework/81333/golang-highlighter/src/Lib.hs b/homework/81333/golang-highlighter/src/Lib.hs
new file mode 100644
index 0000000..f999329
--- /dev/null
+++ b/homework/81333/golang-highlighter/src/Lib.hs
@@ -0,0 +1,11 @@
+module Lib
+ ( golangToHtml
+ ) where
+
+import qualified Data.Text as T
+
+import Data.Highlighter (tokensToHtml)
+import Data.Lexer (tokenize)
+
+golangToHtml :: T.Text -> T.Text
+golangToHtml code = tokensToHtml $ tokenize code 0 0
diff --git a/homework/81333/golang-highlighter/stack.yaml b/homework/81333/golang-highlighter/stack.yaml
new file mode 100644
index 0000000..34ad9e9
--- /dev/null
+++ b/homework/81333/golang-highlighter/stack.yaml
@@ -0,0 +1,65 @@
+# This file was automatically generated by 'stack init'
+#
+# Some commonly used options have been documented as comments in this file.
+# For advanced use and comprehensive documentation of the format, please see:
+# https://docs.haskellstack.org/en/stable/yaml_configuration/
+
+# Resolver to choose a 'specific' stackage snapshot or a compiler version.
+# A snapshot resolver dictates the compiler version and the set of packages
+# to be used for project dependencies. For example:
+#
+# resolver: lts-3.5
+# resolver: nightly-2015-09-21
+# resolver: ghc-7.10.2
+# resolver: ghcjs-0.1.0_ghc-7.10.2
+#
+# The location of a snapshot can be provided as a file or url. Stack assumes
+# a snapshot provided as a file might change, whereas a url resource does not.
+#
+# resolver: ./custom-snapshot.yaml
+# resolver: https://example.com/snapshots/2018-01-01.yaml
+resolver: lts-12.13
+
+# User packages to be built.
+# Various formats can be used as shown in the example below.
+#
+# packages:
+# - some-directory
+# - https://example.com/foo/bar/baz-0.0.2.tar.gz
+# - location:
+# git: https://github.com/commercialhaskell/stack.git
+# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a
+# - location: https://github.com/commercialhaskell/stack/commit/e7b331f14bcffb8367cd58fbfc8b40ec7642100a
+# subdirs:
+# - auto-update
+# - wai
+packages:
+- .
+# Dependency packages to be pulled from upstream that are not in the resolver
+# using the same syntax as the packages field.
+# (e.g., acme-missiles-0.3)
+# extra-deps: []
+
+# Override default flag values for local packages and extra-deps
+# flags: {}
+
+# Extra package databases containing global packages
+# extra-package-dbs: []
+
+# Control whether we use the GHC we find on the path
+# system-ghc: true
+#
+# Require a specific version of stack, using version ranges
+# require-stack-version: -any # Default
+# require-stack-version: ">=1.7"
+#
+# Override the architecture used by stack, especially useful on Windows
+# arch: i386
+# arch: x86_64
+#
+# Extra directories used by stack for building
+# extra-include-dirs: [/path/to/dir]
+# extra-lib-dirs: [/path/to/dir]
+#
+# Allow a newer minor version of GHC than the snapshot specifies
+# compiler-check: newer-minor \ No newline at end of file
diff --git a/homework/81333/golang-highlighter/test/Spec.hs b/homework/81333/golang-highlighter/test/Spec.hs
new file mode 100644
index 0000000..cd4753f
--- /dev/null
+++ b/homework/81333/golang-highlighter/test/Spec.hs
@@ -0,0 +1,2 @@
+main :: IO ()
+main = putStrLn "Test suite not yet implemented"