| -- | |
| -- Module : Minigent.Syntax.Lexer |
| -- Copyright : (c) Data61 2018-2019 |
| -- Commonwealth Science and Research Organisation (CSIRO) |
| -- ABN 41 687 119 230 |
| -- License : BSD3 |
| -- |
| -- Contains the lexer for the concrete syntax of Minigent. |
| -- |
| -- It expects to be imported qualified, as the keyword tokens clash with expression constructors. |
| |
| module Minigent.Syntax.Lexer |
| ( Token (..) |
| , Bracket (..) |
| , Keyword (..) |
| , lexer |
| ) where |
| |
| import Minigent.Syntax (Op (..)) |
| import Minigent.Syntax.Utils |
| import Data.Char |
| import Data.List (span) |
| |
| data Bracket = Paren | Brace | Square |
| deriving (Show, Eq) |
| |
| |
| data Keyword = Case | Of | If | Then | Else | Take | Put | Let | In | End | Rec |
| deriving (Show, Eq) |
| |
| data Token |
| = LowerIdent String -- ^ @[a-z][a-zA-Z0-9]*@ |
| | UpperIdent String -- ^ @[A-Z][a-zA-Z0-9]*@ |
| | Numeric Integer -- ^ @[0-9]+@ |
| | Open Bracket -- ^ @( or [ or {@ |
| | Close Bracket -- ^ @) or ] or }@ |
| | Keyword Keyword |
| | Operator Op |
| | Bang -- ^ @!@ |
| | Colon -- ^ @:@ |
| | Comma -- ^ @,@ |
| | Bar -- ^ @|@ |
| | Arrow -- ^ @->@ |
| | Hash -- ^ @#@ |
| | Equals -- ^ @=@ |
| | Dot -- ^ @.@ |
| | Semi -- ^ @;@ |
| | Unknown Char -- ^ For errors |
| deriving (Show, Eq) |
| |
| |
| |
| |
| toToken "case" = Keyword Case |
| toToken "of" = Keyword Of |
| toToken "if" = Keyword If |
| toToken "then" = Keyword Then |
| toToken "end" = Keyword End |
| toToken "else" = Keyword Else |
| toToken "take" = Keyword Take |
| toToken "put" = Keyword Put |
| toToken "let" = Keyword Let |
| toToken "in" = Keyword In |
| toToken "rec" = Keyword Rec |
| toToken (x:xs) | isLower x = LowerIdent (x:xs) |
| | otherwise = UpperIdent (x:xs) |
| |
| -- | An error in the lexer will produce 'Unknown' tokens. |
| lexer :: String -> [Token] |
| lexer [] = [] |
| lexer (x:xs) | isSpace x = lexer xs |
| lexer (x:xs) | isLetter x = let |
| (word, rest) = span isAlphaNum (x:xs) |
| in toToken word : lexer rest |
| lexer (x:xs) | isDigit x = let |
| (number, rest) = span isDigit (x:xs) |
| in Numeric (read number) : lexer rest |
| lexer (x:y:xs) | Just o <- lookup [x,y] operators |
| = Operator o : lexer xs |
| lexer ('-':'>':xs) = Arrow : lexer xs |
| lexer (x:xs) | Just o <- lookup [x] operators |
| = Operator o : lexer xs |
| lexer ('(':xs) = Open Paren : lexer xs |
| lexer (')':xs) = Close Paren : lexer xs |
| lexer ('[':xs) = Open Square : lexer xs |
| lexer (']':xs) = Close Square : lexer xs |
| lexer ('{':xs) = Open Brace : lexer xs |
| lexer ('}':xs) = Close Brace : lexer xs |
| lexer ('=':xs) = Equals : lexer xs |
| lexer ('!':xs) = Bang : lexer xs |
| lexer (';':xs) = Semi : lexer xs |
| lexer (':':xs) = Colon : lexer xs |
| lexer ('.':xs) = Dot : lexer xs |
| lexer ('#':xs) = Hash : lexer xs |
| lexer (',':xs) = Comma : lexer xs |
| lexer ('|':xs) = Bar : lexer xs |
| lexer (c:xs) = Unknown c : lexer xs |