packages feed

penrose-0.1.1.0: src/Tokenizer.hs

-- | "Tokenizer" contains all the functions for tokenization of Substance
--   programs and patterns as part of the syntactic sugar mechanism
--    Author: Dor Ma'ayan, August 2018

{-# OPTIONS_HADDOCK prune #-}
module Tokenizer where
--module Main (main) where -- for debugging purposes

import Utils
import System.Process
import Control.Monad (void)
import Data.Void
import System.IO -- read/write to file
import System.Environment
import Control.Arrow ((>>>))
import Debug.Trace
import Data.Functor.Classes
import Data.List
import Data.List.Split
import Data.Maybe (fromMaybe)
import Data.Typeable
import Text.Megaparsec
import Text.Megaparsec.Char
import Control.Monad.Combinators.Expr
import Env

import qualified Data.Map.Strict as M
import qualified Text.Megaparsec.Char.Lexer as L
import qualified SubstanceTokenizer         as T

------------------------------ Tokenization ------------------------------------
-- | Get as an input from and to string notataions and returns refined tokenized
--   versions of them

-- | Tokenize the given string using the Substance tokenizer, returns pure token
--   list as it is given from the tokenizer itself
tokenize :: String -> [T.Token]
tokenize = T.alexScanTokens

-- | Given a string representing a sugared Substance program, tokenize it and
--   and refine the tokens into patterns and entities
tokenizeSugaredSubstance :: String -> VarEnv -> [T.Token]
tokenizeSugaredSubstance prog dsllEnv =
  let allDsllEntities = typeCtorNames dsllEnv
      allSnrEntities = concatMap entitiesSnr (stmtNotations dsllEnv)
      tokenized = tokenize prog
      tokenized' = foldl (refineByEntity allDsllEntities allSnrEntities) [] tokenized
  in tokenized'

-- getEntities :: StmtNotationRule -> [T.Token]
-- getEntities s = entitiesSnr s

-- | Translate string notation patterns into tokenized patterns which ignores
--   spaces and properly recognize patterns and Dsll entities
translatePatterns :: (String,String) -> VarEnv -> ([T.Token],[T.Token],[T.Token],[T.Token])
translatePatterns (fromStr, toStr) dsllEnv =
  let from = refineByRecursivePatternElement (foldl (refineDSLLToken dsllEnv) [] (tokenize fromStr))
      patterns = filter notPatterns from
      to = foldl (refineByPattern patterns) [] (tokenize toStr)
      entities = filter notEntities to
  in (from, to, patterns, entities)

refineByRecursivePatternElement :: [T.Token] -> [T.Token]
refineByRecursivePatternElement tokens = let dividedToLines =  split (onSublist [T.NewLine]) tokens
                                             refinedDividedToLines = map replaceToRecursivePattern dividedToLines
                                         in concat refinedDividedToLines

replaceToRecursivePattern chunk =
  if T.RecursivePatternElement [] `elem` chunk then
    [T.RecursivePatternElement (wrap1 chunk)]
  else chunk

wrap1 :: [T.Token] -> [T.Token]
wrap1 tokens = map replaceToSingleElement tokens

replaceToSingleElement (T.RecursivePatternElement l) = T.SinglePatternElement l
replaceToSingleElement a = a


notPatterns :: T.Token -> Bool
notPatterns (T.Pattern t b) = True
notPatterns token = False

notAllPatterns :: T.Token -> Bool
notAllPatterns (T.RecursivePattern t) = True
notAllPatterns (T.RecursivePatternElement t) = True
notAllPatterns token = notPatterns token

notEntities :: T.Token -> Bool
notEntities (T.Entitiy e) = True
notEntities token = False

spaces :: T.Token -> Bool
spaces T.Space  = False
spaces token = True

newLines :: T.Token -> Bool
newLines T.NewLine  = False
newLines token = True

refineByPattern :: [T.Token] -> [T.Token] -> T.Token -> [T.Token]
refineByPattern patterns tokens (T.Var v) =
   if v `elem` map (\(T.Pattern p b) -> p) patterns
    then tokens ++ [T.Pattern v False]
    else tokens ++ [T.Entitiy v]

refineByPattern patterns tokens t = tokens ++ [t]

refineByEntity :: [String] -> [T.Token] -> [T.Token] -> T.Token -> [T.Token]
refineByEntity dsllEntities snrEntities tokens (T.Var v) =
   if v `elem` dsllEntities || T.Entitiy v `elem` snrEntities
    then tokens ++ [T.Entitiy v]
    else tokens ++ [T.Pattern v False]

refineByEntity _ _ tokens t = tokens ++ [t]


refineDSLLToken :: VarEnv -> [T.Token] -> T.Token -> [T.Token]
refineDSLLToken dsllEnv tokens (T.Var v) = if isDeclared v dsllEnv then
                                          tokens ++ [T.DSLLEntity v]
                                       else tokens ++ [T.Pattern v False]
refineDSLLToken dsllEnv tokens t = tokens ++ [t]

-- |This function identify the pattern vars in the sugared notatation in the
--  StmtNotation in the DSLL
identifyPatterns :: [T.Token] -> [T.Token] -> [T.Token]
identifyPatterns tokensSugared tokenDesugared =
   foldl (identifyPattern tokenDesugared) [] tokensSugared

identifyPattern :: [T.Token] -> [T.Token] -> T.Token -> [T.Token]
identifyPattern tokenDesugared tokensSugared (T.Var v) =
   if T.Var v `elem` tokenDesugared then
     tokensSugared ++ [T.Pattern v False]
  else
    tokensSugared ++ [T.Var v]
identifyPattern tokenDesugared tokensSugared token = tokensSugared ++ [token]

-- | Retranslate a token list into a program
reTokenize :: [T.Token] -> String
reTokenize = foldl translate ""

-- | Translation function from a specific token back into String
--   In use after the notation replacements in order to translate back to
--   a Substance program
translate :: String -> T.Token -> String
translate prog T.Bind = prog ++ ":= "
translate prog T.NewLine = prog ++ "\n"
translate prog T.PredEq = prog ++ "<->"
translate prog T.ExprEq = prog ++ "="
translate prog T.Comma = prog ++ ","
translate prog T.Lparen = prog ++ "("
translate prog T.Rparen = prog ++ ")"
translate prog T.Space = prog ++ " "
translate prog (T.Sym c) = prog ++ [c] ++ " "
translate prog (T.Var v) = prog ++ v
translate prog (T.Comment c) = prog ++ c
translate prog (T.StartMultiComment c) = prog ++ c
translate prog (T.EndMultiComment c) = prog ++ c
translate prog (T.Label l) = prog ++ l
translate prog (T.AutoLabel l) = prog ++ l
translate prog (T.DSLLEntity d) = prog ++ d
translate prog (T.Pattern p b) = prog ++ p ++ " "
translate prog (T.Entitiy e) = prog ++ e ++ " "
translate prog (T.RecursivePatternElement lst) = prog ++ concatMap (translate "") lst
translate prog (T.RecursivePattern lst) = prog ++ concatMap (translate "") lst
translate prog (T.SinglePatternElement lst) = prog ++ concatMap (translate "") lst