diff options
| author | Mirek Kratochvil <exa.exa@gmail.com> | 2023-03-05 21:34:20 +0100 |
|---|---|---|
| committer | Mirek Kratochvil <exa.exa@gmail.com> | 2023-03-05 21:34:20 +0100 |
| commit | 98c40f4bf8849f5cdd3d3c49123bc911b8fa42e1 (patch) | |
| tree | e41a1cd05d17765f9e27b0844580655b2dc1ae95 /app/Parser.hs | |
| parent | 45c3f81891837820aea7c3dbd45e3bae25fc4c22 (diff) | |
| download | prlg-98c40f4bf8849f5cdd3d3c49123bc911b8fa42e1.tar.gz prlg-98c40f4bf8849f5cdd3d3c49123bc911b8fa42e1.tar.bz2 | |
strings and a few other small nice changes
Diffstat (limited to 'app/Parser.hs')
| -rw-r--r-- | app/Parser.hs | 75 |
1 files changed, 45 insertions, 30 deletions
diff --git a/app/Parser.hs b/app/Parser.hs index e6b7a7a..9d11cc8 100644 --- a/app/Parser.hs +++ b/app/Parser.hs @@ -5,7 +5,8 @@ module Parser , parsePrlg , shuntPrlg , PAST - , Lexeme + , Lexeme(..) + , PrlgStr(..) ) where import Control.Monad (void) @@ -42,14 +43,13 @@ import Text.Megaparsec ) import Text.Megaparsec.Char (string) -import IR (PrlgStr(..)) import Operators (ArgKind(..), Fixity(..), Op(..), Ops) singleToks = ",;|()[]{}!" identParts = "_" -notOpToks = "\'" ++ identParts +notOpToks = "'\"" ++ identParts isOperatorlike x = (isSymbol x || isPunctuation x) && not (x `elem` singleToks ++ notOpToks) @@ -64,6 +64,7 @@ data Lexeme = Blank String | Tok String | QTok String String -- unquoted quoted + | DQTok String String -- unquoted quoted deriving (Show, Eq, Ord) blank :: Lexer Lexeme @@ -86,14 +87,15 @@ qtok = do z <- string "'" return $ QTok y (x ++ y ++ z) -cmt :: Lexer Lexeme -cmt = - Blank . concat <$> - sequence - [string "%", many $ satisfy (/= '\n'), choice [string "\n", "" <$ eof]] +dqtok :: Lexer Lexeme +dqtok = do + x <- string "\"" + y <- many $ satisfy (/= '\"') -- TODO actual escaping + z <- string "\"" + return $ DQTok y (x ++ y ++ z) lexeme :: Lexer Lexeme -lexeme = choice [blank, tok, qtok, cmt] +lexeme = choice [blank, tok, qtok, dqtok] lexPrlg :: Lexer [Lexeme] lexPrlg = many lexeme <* (many blank >> eof) @@ -101,6 +103,7 @@ lexPrlg = many lexeme <* (many blank >> eof) showTok (Blank x) = x showTok (Tok x) = x showTok (QTok _ x) = x +showTok (DQTok _ x) = x instance VisualStream [Lexeme] where showTokens _ (a :| b) = concatMap showTok (a : b) @@ -146,9 +149,9 @@ instance TraversableStream [Lexeme] where data PAST = Call String [[PAST]] - | Seq [PAST] + | Group [PAST] | List [[PAST]] (Maybe [PAST]) - | Literal String + | Literal Lexeme deriving (Show, Eq) type Parser = Parsec Void [Lexeme] @@ -165,6 +168,7 @@ isNormalTokStr = (`notElem` [".", "[", "]", "(", "|", ")", "{", "}"]) isNormalTok :: Lexeme -> Bool isNormalTok (Tok x) = isNormalTokStr x isNormalTok (QTok _ _) = True +isNormalTok (DQTok _ _) = True isNormalTok _ = False isCallTok :: Lexeme -> Bool @@ -174,34 +178,35 @@ isCallTok _ = True unTok (Tok t) = t unTok (QTok t _) = t +unTok (DQTok t _) = t literal :: Parser PAST literal = - Literal . unTok <$> + Literal <$> free (choice [ satisfy isCallTok <* notFollowedBy (choice [lParen, lBrace]) , satisfy (\x -> not (isCallTok x) && isNormalTok x) ]) -makeParams (Seq inner) = splitOn [Literal ","] inner +makeParams (Group inner) = splitOn [Literal (Tok ",")] inner call eb contents fmod = do fn <- fmod . unTok <$> satisfy isCallTok -- not free (Call fn [] <$ try eb) <|> (Call fn . makeParams <$> free contents) -parens = Seq <$> (free lParen *> some seqItem <* free rParen) +parens = Group <$> (free lParen *> some seqItem <* free rParen) -braces = Seq <$> (free lBrace *> some seqItem <* free rBrace) +braces = Group <$> (free lBrace *> some seqItem <* free rBrace) -emptyParens = Literal "()" <$ (free lParen >> free rParen) +emptyParens = Literal (QTok "()" "()") <$ (free lParen >> free rParen) -emptyBraces = Literal "{}" <$ (free lBrace >> free rBrace) +emptyBraces = Literal (QTok "{}" "{}") <$ (free lBrace >> free rBrace) list = do free lBracket (List [] Nothing <$ free rBracket) <|> do - items <- splitOn [Literal ","] <$> some seqItem + items <- splitOn [Literal (Tok ",")] <$> some seqItem (List items Nothing <$ free rBracket) <|> (List items . Just <$> (free listTail *> some seqItem <* free rBracket)) @@ -237,7 +242,7 @@ lBrace = simpleTok "{" rBrace = simpleTok "}" clause :: Parser PAST -clause = Seq <$> some (free seqItem) <* free period +clause = Group <$> some (free seqItem) <* free period parsePrlg :: Parser [PAST] parsePrlg = ws *> many clause <* eof @@ -246,6 +251,11 @@ type ShuntError = String type ShuntResult = Either ShuntError PrlgStr +data PrlgStr + = CallS String [PrlgStr] + | LiteralS Lexeme + deriving (Show) + err :: ShuntError -> Either ShuntError a err = Left @@ -254,8 +264,10 @@ shuntPrlg ot = shuntPrlg' (("", Op 0 $ Infix Y X) : ot) shuntPrlg' :: Ops -> PAST -> ShuntResult shuntPrlg' ot (List hs t) = - ListS <$> traverse (shunt ot) hs <*> traverse (shunt ot) t -shuntPrlg' ot (Seq ss) = shunt ot ss + foldr (\x y -> CallS "[]" [x, y]) <$> + (maybe (LiteralS $ Tok "[]") id <$> traverse (shunt ot) t) <*> + traverse (shunt ot) hs +shuntPrlg' ot (Group ss) = shunt ot ss shuntPrlg' ot (Literal s) = pure (LiteralS s) shuntPrlg' ot (Call fn ss) = CallS fn <$> traverse (shunt ot) ss @@ -296,13 +308,13 @@ shunt optable = start (ops', vs') <- pushInfix ops vs x wo ops' vs' xs , do getOperand x - ho ops vs (Literal "" : xs') -- app (see below) + ho ops vs (Literal (Tok "") : xs') -- app (see below) , do getPrefix x - ho ops vs (Literal "" : xs') -- also app! + ho ops vs (Literal (Tok "") : xs') -- also app! , err "expected infix or suffix operator" ] {- incoming non-literal operand; there must be an app in between -} - ho ops vs xs@(_:_) = ho ops vs (Literal "" : xs) + ho ops vs xs@(_:_) = ho ops vs (Literal (Tok "") : xs) {- the last operand was last, pop until finished -} ho [] [res] [] = pure res ho ops vs [] = do @@ -319,11 +331,14 @@ shunt optable = start {- Operator checks -} uniq [x] = pure x uniq _ = err "ambiguous operator" - getPrefix x = uniq [op | (s, op@(Op _ (Prefix _))) <- optable, s == x] - getSuffix x = uniq [op | (s, op@(Op _ (Suffix _))) <- optable, s == x] - getInfix x = uniq [op | (s, op@(Op _ (Infix _ _))) <- optable, s == x] - getOperand x - | null [op | (s, op) <- optable, s == x] = pure () + getPrefix t = + uniq [op | Tok x <- [t], (s, op@(Op _ (Prefix _))) <- optable, s == x] + getSuffix t = + uniq [op | Tok x <- [t], (s, op@(Op _ (Suffix _))) <- optable, s == x] + getInfix t = + uniq [op | Tok x <- [t], (s, op@(Op _ (Infix _ _))) <- optable, s == x] + getOperand t + | null [op | Tok x <- [t], (s, op) <- optable, s == x] = pure () | otherwise = err "expected an operand" {- actual pushery -} canPush :: Ops -> Op -> Either ShuntError Bool @@ -371,7 +386,7 @@ shunt optable = start shunt1 ops vs x op = do cp <- canPush ops op if cp - then pure ((x, op) : ops, vs) + then pure ((unTok x, op) : ops, vs) else do (ops', vs') <- pop ops vs shunt1 ops' vs' x op --prefix would behave differently here but that's impossible by canPush |
