|
|
@ -6,6 +6,8 @@ import qualified Data.Text.Encoding as T |
|
|
|
import qualified Data.Text as T |
|
|
|
|
|
|
|
import Presyntax.Tokens |
|
|
|
|
|
|
|
import Debug.Trace |
|
|
|
} |
|
|
|
|
|
|
|
%wrapper "monadUserState-bytestring" |
|
|
@ -18,7 +20,7 @@ tokens :- |
|
|
|
$white_nol+ ; |
|
|
|
"--" .* \n ; |
|
|
|
|
|
|
|
<0,prtext> $alpha [$alpha $digit \_ \']* { yield tokVar } |
|
|
|
<0,prtext> $alpha [$alpha $digit \_ \']* { variableOrKeyword } |
|
|
|
|
|
|
|
-- zero state: normal lexing |
|
|
|
<0> \= { always TokEqual } |
|
|
@ -47,11 +49,11 @@ tokens :- |
|
|
|
<0> "&&" { always TokAnd } |
|
|
|
<0> "||" { always TokOr } |
|
|
|
|
|
|
|
<0> "{-" { just $ pushStartCode comment } |
|
|
|
<0> "{-" { just $ pushStartCode comment } |
|
|
|
|
|
|
|
<comment> { |
|
|
|
"-}" { \i l -> popStartCode *> skip i l } |
|
|
|
. ; |
|
|
|
"-}" { \i l -> popStartCode *> skip i l } |
|
|
|
. ; |
|
|
|
} |
|
|
|
|
|
|
|
<0> "{-#" { \i l -> pushStartCode prkw *> always TokOPragma i l } |
|
|
@ -67,6 +69,14 @@ tokens :- |
|
|
|
() { offsideRule } |
|
|
|
} |
|
|
|
|
|
|
|
-- layout: indentation of the next token is context for offside rule |
|
|
|
<layout> { |
|
|
|
\n ; |
|
|
|
() { startLayout } |
|
|
|
} |
|
|
|
|
|
|
|
<empty_layout> () { emptyLayout } |
|
|
|
|
|
|
|
{ |
|
|
|
alexEOF :: Alex Token |
|
|
|
alexEOF = do |
|
|
@ -78,8 +88,8 @@ yield k (AlexPn _ l c, _, s, _) i = pure (Token (k $! (T.decodeUtf8 (Lbs.toStric |
|
|
|
always :: TokenClass -> AlexInput -> Int64 -> Alex Token |
|
|
|
always k x i = yield (const k) x i |
|
|
|
|
|
|
|
data AlexUserState = AlexUserState { layoutColumns :: [Int], startCodes :: [Int] } |
|
|
|
alexInitUserState = AlexUserState [1] [] |
|
|
|
data AlexUserState = AlexUserState { layoutColumns :: [Int], startCodes :: [Int], leastColumn :: Int } |
|
|
|
alexInitUserState = AlexUserState [1] [] 0 |
|
|
|
|
|
|
|
just :: Alex a -> AlexAction Token |
|
|
|
just k _ _ = k *> alexMonadScan |
|
|
@ -109,19 +119,40 @@ offsideRule :: AlexInput -> Int64 -> Alex Token |
|
|
|
offsideRule (AlexPn _ line col, _, s, _) _ |
|
|
|
| Lbs.null s = pure (Token TokEof line col) |
|
|
|
| otherwise = do |
|
|
|
~(col':_) <- layoutColumns <$> getUserState |
|
|
|
popStartCode |
|
|
|
~(col':ctx) <- layoutColumns <$> getUserState |
|
|
|
case col `compare` col' of |
|
|
|
EQ -> do |
|
|
|
popStartCode |
|
|
|
pure (Token TokSemi line col) |
|
|
|
GT -> do |
|
|
|
popStartCode |
|
|
|
alexMonadScan |
|
|
|
LT -> alexError "wrong ass indentation" |
|
|
|
|
|
|
|
tokVar :: T.Text -> TokenClass |
|
|
|
tokVar text = |
|
|
|
EQ -> pure (Token TokSemi line col) |
|
|
|
GT -> alexMonadScan |
|
|
|
LT -> do |
|
|
|
mapUserState $ \s -> s { layoutColumns = ctx } |
|
|
|
pure (Token TokLEnd line col) |
|
|
|
|
|
|
|
emptyLayout :: AlexInput -> Int64 -> Alex Token |
|
|
|
emptyLayout (AlexPn _ line col, _, _, _) _ = do |
|
|
|
popStartCode |
|
|
|
pushStartCode newline |
|
|
|
pure (Token TokLEnd line col) |
|
|
|
|
|
|
|
startLayout :: AlexInput -> Int64 -> Alex Token |
|
|
|
startLayout (AlexPn _ line col, _, s, _) size = do |
|
|
|
popStartCode |
|
|
|
least <- leastColumn <$> getUserState |
|
|
|
~(col':_) <- layoutColumns <$> getUserState |
|
|
|
if (col' >= col) || col <= least |
|
|
|
then pushStartCode empty_layout |
|
|
|
else mapUserState $ \s -> s { layoutColumns = col:layoutColumns s } |
|
|
|
pure (Token TokLStart line col) |
|
|
|
|
|
|
|
variableOrKeyword :: AlexAction Token |
|
|
|
variableOrKeyword (AlexPn _ l c, _, s, _) size = |
|
|
|
let text = T.decodeUtf8 (Lbs.toStrict (Lbs.take size s)) in |
|
|
|
case T.unpack text of |
|
|
|
"as" -> TokAs |
|
|
|
_ -> TokVar text |
|
|
|
"as" -> pure (Token TokAs l c) |
|
|
|
"in" -> pure (Token TokIn l c) |
|
|
|
"let" -> do |
|
|
|
pushStartCode layout |
|
|
|
mapUserState $ \s -> s { leastColumn = c } |
|
|
|
pure (Token TokLet l c) |
|
|
|
_ -> pure (Token (TokVar text) l c) |
|
|
|
} |