never executed always true always false
    1 {-# LANGUAGE FlexibleContexts #-}
    2 {-# LANGUAGE ImportQualifiedPost #-}
    3 {-# LANGUAGE LambdaCase #-}
    4 {-# LANGUAGE NamedFieldPuns #-}
    5 {-# LANGUAGE OverloadedStrings #-}
    6 {-# OPTIONS_GHC -Wno-type-defaults -Wno-incomplete-uni-patterns #-}
    7 
    8 {- |
    9 Module      : NITTA.Frontends.Lua
   10 Description : Lua frontend prototype
   11 Copyright   : (c) Aleksandr Penskoi, 2019
   12 License     : BSD3
   13 Maintainer  : aleksandr.penskoi@gmail.com
   14 Stability   : experimental
   15 
   16 This module analyzes an abstract syntax tree of the Lua language source code, provided by Language.Lua module,
   17 and stores it into a NITTA's data flow graph.
   18 
   19 Supported Lua costructions are:
   20 
   21 - Simple math operators (addition, subtraction, multiplication and division);
   22 - Variable assignments;
   23 - Bitwise left and right shifts;
   24 - Recursive calls.
   25 
   26 The naming of variables in the output dataflow graph:
   27 
   28 @
   29     x^1#2 -- for variables
   30     | | |
   31     | | +-- value access number (one for each), e.g.
   32     | |     x = 1; send(x); reg(x) -- two accesses
   33     | |
   34     | +---- value assignment number (one for each, optional)
   35     |       x = f(1); x = g(2) -- two assignments
   36     |
   37     +------ original variable name
   38 
   39     !123#3 -- for constant
   40       |  |
   41       |  +--- value access number
   42       |
   43       +------ value: 123
   44 
   45     _a#4 -- for an unnamed variable (example see below)
   46      | |
   47      | +--- value access number
   48      |
   49      +----- char of unnamed variable (a, b..., aa, ab, ...)
   50 @
   51 
   52 Example:
   53 
   54 >>> :{
   55 void $ mapM print $ functions (frDataFlow $ translateLua $ T.pack $ unlines
   56     [ "function f()"
   57     , "    local a = 1 + 2 + 3"
   58     , "    local b = a + 4 + 5"
   59     , "    b = b * 1 + 2"
   60     , "    c, d = b / 2"
   61     , "    send(b)"
   62     , "end"
   63     , "f()"
   64     ] :: DataFlowGraph String Int)
   65 :}
   66 const(1) = !1#0 = !1#1
   67 const(2) = !2#0 = !2#1 = !2#2
   68 !1#0 + !2#0 = _0#a
   69 const(3) = !3#0
   70 _0#a + !3#0 = a^0#0
   71 const(4) = !4#0
   72 a^0#0 + !4#0 = _0#b
   73 const(5) = !5#0
   74 _0#b + !5#0 = b^0#0
   75 b^0#0 * !1#1 = _1#b
   76 _1#b + !2#1 = b^1#0 = b^1#1
   77 !2#2 / b^1#0 = _; !2#2 mod b^1#0 = _
   78 send(b^1#1)
   79 -}
   80 module NITTA.Frontends.Lua (
   81     translateLua,
   82     FrontendResult (..),
   83     TraceVar (..),
   84 
   85     -- * Internal
   86     LuaAlgBuilder (..),
   87     LuaStatement (..),
   88     LuaValueInstance (..),
   89     buildAlg,
   90     findStartupFunction,
   91     getLuaBlockFromSources,
   92     processStatement,
   93 ) where
   94 
   95 import Control.Monad.State
   96 import Data.HashMap.Strict qualified as HM
   97 import Data.Hashable
   98 import Data.Maybe
   99 import Data.String
  100 import Data.String.ToString
  101 import Data.Text qualified as T
  102 import Language.Lua hiding (Var)
  103 import NITTA.Frontends.Common
  104 import NITTA.Intermediate.DataFlow
  105 import NITTA.Intermediate.Functions qualified as F
  106 import NITTA.Intermediate.Types
  107 import NITTA.Utils.Base
  108 import Prelude hiding (EQ, GT, LT)
  109 
  110 getUniqueLuaVariableName LuaValueInstance{lviName, lviIsConstant = True} luaValueAccessCount = "!" <> lviName <> "#" <> showText luaValueAccessCount
  111 getUniqueLuaVariableName LuaValueInstance{lviName, lviAssignCount} luaValueAccessCount
  112     | T.head lviName == '_' = lviName
  113     | otherwise = lviName <> "^" <> showText lviAssignCount <> "#" <> showText luaValueAccessCount
  114 
  115 data LuaStatement x = LuaStatement
  116     { fIn :: [T.Text]
  117     , fOut :: [LuaValueInstance]
  118     , fName :: T.Text
  119     , fValues :: [x]
  120     , fInt :: [Int]
  121     }
  122     deriving (Show, Eq)
  123 
  124 -- | Stores information about a particular version of a variable. The version of a variable changes after assigning a new value to it.
  125 data LuaValueInstance = LuaValueInstance
  126     { lviName :: T.Text
  127     , lviAssignCount :: Int
  128     , lviIsConstant :: Bool
  129     }
  130     deriving (Show, Eq)
  131 
  132 instance Hashable LuaValueInstance where
  133     hashWithSalt i LuaValueInstance{lviName, lviAssignCount, lviIsConstant} =
  134         ( (hashWithSalt i lviName * 31)
  135             + hashWithSalt i lviAssignCount
  136         )
  137             * 31
  138             + hashWithSalt i lviIsConstant
  139 
  140 data LuaAlgBuilder x = LuaAlgBuilder
  141     { algGraph :: [LuaStatement x]
  142     -- ^ A list containing all expressions to be added to the final graph.
  143     , algLatestLuaValueInstance :: HM.HashMap T.Text LuaValueInstance
  144     -- ^ A table that maps a variable name to the most recent corresponding LuaValueInstance.
  145     , algVarCounters :: HM.HashMap T.Text Int
  146     -- ^ A table needed to generate unique temporary variable names.
  147     , algVars :: HM.HashMap LuaValueInstance [T.Text]
  148     -- ^ A table lists all uses of a particular LuaValueInstance.
  149     , algStartupArgs :: HM.HashMap Int (T.Text, T.Text)
  150     -- ^ Map argument index to the variable name and initial value (in text).
  151     , algConstants :: HM.HashMap T.Text LuaValueInstance
  152     -- ^ A table correlating constant with LuaValueInstance which store this constant.
  153     , algTraceFuncs :: [([T.Text], Maybe T.Text)]
  154     -- ^ A list that stores debug information about monitored variables and their display formats.
  155     }
  156     deriving (Show)
  157 
  158 -- left part of lua statement
  159 parseLeftExp (VarName (Name v)) = v
  160 parseLeftExp var = error $ "unexpected lua variable declaration format : " <> show var
  161 
  162 -- right part of lua statement
  163 parseRightExp [fOut] (Binop ShiftL a (Number IntNum s)) = do
  164     varName <- parseExpArg fOut a
  165     addVariable [varName] [fOut] [] "shiftL" [readText s]
  166 parseRightExp [fOut] (Binop ShiftR a (Number IntNum s)) = do
  167     varName <- parseExpArg fOut a
  168     addVariable [varName] [fOut] [] "shiftR" [readText s]
  169 parseRightExp [fOut] (Number _ valueString) = do
  170     addVariable [] [fOut] [readText valueString] "constant" []
  171 parseRightExp fOut@(x : _) (Binop op a b) = do
  172     varNameA <- parseExpArg x a
  173     varNameB <- parseExpArg x b
  174     addVariable [varNameA, varNameB] fOut [] (getBinopFuncName op) []
  175     where
  176         getBinopFuncName Add = "add"
  177         getBinopFuncName Sub = "sub"
  178         getBinopFuncName Mul = "multiply"
  179         getBinopFuncName Div = "divide"
  180         getBinopFuncName LT = "lessThan"
  181         getBinopFuncName LTE = "lessThanOrEqual"
  182         getBinopFuncName EQ = "equal"
  183         getBinopFuncName GTE = "greaterThanOrEqual"
  184         getBinopFuncName GT = "greaterThan"
  185         getBinopFuncName And = "and"
  186         getBinopFuncName Or = "or"
  187         getBinopFuncName o = error $ "unknown binop: " <> show o
  188 parseRightExp fOut (PrefixExp (Paren e)) = parseRightExp fOut e
  189 parseRightExp fOut (Unop Neg (Number numType name)) = parseRightExp fOut (Number numType ("-" <> name))
  190 parseRightExp [fOut] (Unop Neg expr@(PrefixExp _)) = do
  191     varName <- parseExpArg fOut expr
  192     addVariable [varName] [fOut] [] "neg" []
  193 parseRightExp fOut (Unop Not (Number numType name)) = parseRightExp fOut (Number numType ("not" <> name))
  194 parseRightExp [fOut] (Unop Not expr@(PrefixExp _)) = do
  195     varName <- parseExpArg fOut expr
  196     addVariable [varName] [fOut] [] "not" []
  197 parseRightExp
  198     [fOut]
  199     ( PrefixExp
  200             ( PEFunCall
  201                     ( NormalFunCall
  202                             (PEVar (VarName (Name fname)))
  203                             (Args args)
  204                         )
  205                 )
  206         ) = do
  207         fIn <- mapM (parseExpArg fOut) args
  208         addFunction fname fIn [fOut]
  209 parseRightExp [fOut] (PrefixExp (PEVar (VarName (Name name)))) = do
  210     addAlias fOut name
  211 parseRightExp _ expr = error $ "unknown expression : " <> show expr
  212 
  213 parseExpArg _ n@(Number _ _) = do
  214     addConstant n
  215 parseExpArg fOut expr@(Unop Neg _) = do
  216     name <- getNextTmpVarName fOut
  217     _ <- parseRightExp [name] expr
  218     addVariableAccess name
  219 parseExpArg _ (PrefixExp (PEVar (VarName (Name name)))) = do
  220     addVariableAccess name
  221 parseExpArg fOut binop@Binop{} = do
  222     name <- getNextTmpVarName fOut
  223     _ <- parseRightExp [name] binop
  224     addVariableAccess name
  225 parseExpArg fOut (PrefixExp (Paren arg)) = parseExpArg fOut arg
  226 parseExpArg fOut call@(PrefixExp (PEFunCall _)) = do
  227     name <- getNextTmpVarName fOut
  228     _ <- parseRightExp [name] call
  229     addVariableAccess name
  230 parseExpArg _ _ = undefined
  231 
  232 getNextTmpVarName fOut
  233     | T.isInfixOf "#" fOut = getNextTmpVarName (T.splitOn "#" fOut !! 1)
  234     | otherwise = do
  235         luaAlgBuilder@LuaAlgBuilder{algVarCounters} <- get
  236         case HM.lookup fOut algVarCounters of
  237             Just value -> do
  238                 put luaAlgBuilder{algVarCounters = HM.insert fOut (value + 1) algVarCounters}
  239                 return $ "_" <> showText value <> "#" <> fOut
  240             Nothing -> do
  241                 put luaAlgBuilder{algVarCounters = HM.insert fOut 1 algVarCounters}
  242                 return $ "_0#" <> fOut
  243 
  244 addStartupFuncArgs (FunCall (NormalFunCall _ (Args exps))) (FunAssign _ (FunBody names _ _)) = do
  245     mapM_
  246         ( \case
  247             (Name name, Number _ valueString, serialNumber) -> addToBuffer name valueString serialNumber
  248             (Name name, Unop Neg (Number _ valueString), serialNumber) -> addToBuffer name ("-" <> valueString) serialNumber
  249             _ -> error "addStartupFuncArgs: internal error"
  250         )
  251         $ zip3 names exps [0 ..]
  252     return ""
  253     where
  254         addToBuffer name valueString serialNumber = do
  255             luaAlgBuilder@LuaAlgBuilder{algVars, algLatestLuaValueInstance, algStartupArgs} <- get
  256             let value = LuaValueInstance{lviName = name, lviAssignCount = 0, lviIsConstant = False}
  257             put luaAlgBuilder{algLatestLuaValueInstance = HM.insert name value algLatestLuaValueInstance, algVars = HM.insert value [] algVars, algStartupArgs = HM.insert serialNumber (name, valueString) algStartupArgs}
  258             return value
  259 addStartupFuncArgs _ _ = undefined
  260 
  261 -- Lua language Stat structure parsing
  262 -- LocalAssign
  263 processStatement _ (LocalAssign _names Nothing) = do
  264     return ()
  265 processStatement fn (LocalAssign names (Just exps)) =
  266     processStatement fn $ Assign (map VarName names) exps
  267 -- Assign
  268 processStatement fn (Assign lexps@[_] [Unop Neg (Number ntype ntext)]) =
  269     processStatement fn (Assign lexps [Number ntype ("-" <> ntext)])
  270 processStatement _ (Assign lexp [rexp]) = do
  271     parseRightExp (map parseLeftExp lexp) rexp
  272 processStatement startupFunctionName (Assign vars exps) | length vars == length exps = do
  273     mapM_
  274         ( \case
  275             (VarName (Name name), expr) -> processStatement startupFunctionName (Assign [VarName (Name (getTempAlias name))] [expr])
  276             _ -> error "processStatement: internal error"
  277         )
  278         $ zip vars exps
  279     mapM_ (\(VarName (Name name)) -> addAlias name (getTempAlias name)) vars
  280     where
  281         getTempAlias name = name <> "&"
  282 -- startup function recursive call
  283 processStatement fn (FunCall (NormalFunCall (PEVar (VarName (Name fName))) (Args args)))
  284     | fn == fName = do
  285         LuaAlgBuilder{algStartupArgs} <- get
  286         let startupVarsNames = map (fromMaybe (error "processStatement: internal error") . (`HM.lookup` algStartupArgs)) [0 .. (HM.size algStartupArgs)]
  287         let startupVarsVersions = map (\x -> LuaValueInstance{lviName = fst x, lviAssignCount = 0, lviIsConstant = False}) startupVarsNames
  288         mapM_ parseStartupArg $ zip3 args startupVarsVersions (map (readText . snd) startupVarsNames)
  289     where
  290         parseStartupArg (arg, valueVersion, index) = do
  291             varName <- parseExpArg "loop" arg
  292             luaAlgBuilder@LuaAlgBuilder{algGraph} <- get
  293             put luaAlgBuilder{algGraph = LuaStatement{fIn = [varName], fOut = [valueVersion], fValues = [index], fName = "loop", fInt = []} : algGraph}
  294 processStatement _ (FunCall (NormalFunCall (PEVar (VarName (Name fName))) (Args args))) = do
  295     fIn <- mapM (parseExpArg "tmp") args
  296     addFunction (fromText fName) fIn [fromString ""]
  297 processStatement _fn (FunCall (NormalFunCall (PEVar (SelectName (PEVar (VarName (Name "debug"))) (Name fName))) (Args args))) = do
  298     let fIn = map parseTraceArg args
  299     luaAlgBuilder@LuaAlgBuilder{algTraceFuncs, algLatestLuaValueInstance} <- get
  300     case (fName, fIn) of
  301         ("trace", tFmt : vs)
  302             | T.isPrefixOf "\"" tFmt && T.isPrefixOf "\"" tFmt -> do
  303                 let vars = map (\x -> T.pack $ takeWhile (/= '#') $ T.unpack $ getUniqueLuaVariableName (fromMaybe undefined $ HM.lookup x algLatestLuaValueInstance) 0) vs
  304                 put luaAlgBuilder{algTraceFuncs = (vars, Just $ T.replace "\"" "" tFmt) : algTraceFuncs}
  305         ("trace", vs) -> do
  306             let vars = map (\x -> T.pack $ takeWhile (/= '#') $ T.unpack $ getUniqueLuaVariableName (fromMaybe undefined $ HM.lookup x algLatestLuaValueInstance) 0) vs
  307             put luaAlgBuilder{algTraceFuncs = (vars, Nothing) : algTraceFuncs}
  308         _ -> error $ "unknown debug method: " <> show fName <> " " <> show args
  309     where
  310         parseTraceArg (String s) = s
  311         parseTraceArg (PrefixExp (PEVar (VarName (Name name)))) = name
  312         parseTraceArg _ = undefined
  313 processStatement _ _stat = error $ "unknown statement: " <> show _stat
  314 
  315 addFunction funcName [i] fOut | toString funcName == "buffer" = do
  316     addVariable [i] fOut [] "buffer" []
  317 addFunction funcName [i] fOut | toString funcName == "brokenBuffer" = do
  318     addVariable [i] fOut [] "brokenBuffer" []
  319 addFunction funcName [i] _ | toString funcName == "send" = do
  320     luaAlgBuilder@LuaAlgBuilder{algGraph} <- get
  321     put luaAlgBuilder{algGraph = LuaStatement{fIn = [i], fOut = [], fValues = [], fName = "send", fInt = []} : algGraph}
  322 addFunction funcName _ fOut | toString funcName == "receive" = do
  323     addVariable [] fOut [] "receive" []
  324 addFunction "if_mux" [cond, a, b] [c] = do
  325     addVariable [cond, a, b] [c] [] "if_mux" []
  326 addFunction fName _ _ = error $ "unknown function" <> T.unpack fName
  327 
  328 addConstant (Number _valueType valueString) = do
  329     luaAlgBuilder@LuaAlgBuilder{algGraph, algVars, algConstants} <- get
  330     let lvv = LuaValueInstance{lviName = valueString, lviAssignCount = 0, lviIsConstant = True}
  331     case HM.lookup valueString algConstants of
  332         Just value -> do
  333             let names = fromMaybe (error "lua constants parsing error") $ HM.lookup value algVars
  334             let resultName = getUniqueLuaVariableName lvv $ length names
  335             put luaAlgBuilder{algVars = HM.insert value (resultName : names) algVars}
  336             return resultName
  337         Nothing -> do
  338             let resultName = getUniqueLuaVariableName lvv 0
  339             put
  340                 luaAlgBuilder
  341                     { algGraph = LuaStatement{fIn = [], fOut = [lvv], fValues = [readText valueString], fName = "constant", fInt = []} : algGraph
  342                     , algVars = HM.insert lvv [resultName] algVars
  343                     , algConstants = HM.insert valueString lvv algConstants
  344                     }
  345             return resultName
  346 addConstant _ = undefined
  347 
  348 addVariable fIn fOut fValues fName fInt = do
  349     LuaAlgBuilder{algLatestLuaValueInstance} <- get
  350     let luaValueInstances = map (\x -> nameToLuaValueInstance algLatestLuaValueInstance x) fOut
  351     let func = LuaStatement{fIn, fValues, fName, fInt, fOut = luaValueInstances}
  352     mapM_ (uncurry addItemToBuffer) $ zip fOut luaValueInstances
  353     mapM_ addItemToVars luaValueInstances
  354     luaAlgBuilder@LuaAlgBuilder{algGraph, algConstants, algLatestLuaValueInstance = algLatestLuaValueInstance'} <- get
  355     case fName of
  356         "constant" -> do
  357             case HM.lookup (showText $ head fValues) algConstants of
  358                 Just lvv -> do
  359                     put luaAlgBuilder{algLatestLuaValueInstance = HM.insert (head fOut) lvv algLatestLuaValueInstance'}
  360                 Nothing -> do
  361                     put luaAlgBuilder{algGraph = func : algGraph, algConstants = HM.insert (showText $ head fValues) (head luaValueInstances) algConstants}
  362         _ -> do
  363             put luaAlgBuilder{algGraph = func : algGraph}
  364     where
  365         nameToLuaValueInstance algLatestLuaValueInstance name =
  366             case getLuaValueByName name algLatestLuaValueInstance of
  367                 Just lvv@LuaValueInstance{lviAssignCount} -> lvv{lviAssignCount = lviAssignCount + 1}
  368                 Nothing -> LuaValueInstance{lviName = name, lviAssignCount = 0, lviIsConstant = False}
  369         addItemToBuffer name lvv = do
  370             luaAlgBuilder@LuaAlgBuilder{algLatestLuaValueInstance} <- get
  371             put luaAlgBuilder{algLatestLuaValueInstance = HM.insert name lvv algLatestLuaValueInstance}
  372         addItemToVars name = do
  373             luaAlgBuilder@LuaAlgBuilder{algVars} <- get
  374             put luaAlgBuilder{algVars = HM.insert name [] algVars}
  375 
  376 addVariableAccess name = do
  377     luaAlgBuilder@LuaAlgBuilder{algVars} <- get
  378     luaValueInstance <- getLatestLuaValueInstanceByName name
  379     case HM.lookup luaValueInstance algVars of
  380         Just value -> do
  381             let len = length value
  382             let resultName = getUniqueLuaVariableName luaValueInstance len
  383             put luaAlgBuilder{algVars = HM.insert luaValueInstance (resultName : value) algVars}
  384             return resultName
  385         Nothing -> error ("variable '" <> show (lviName luaValueInstance) <> " not found. Constants list : " <> show algVars)
  386 
  387 getLatestLuaValueInstanceByName name = do
  388     LuaAlgBuilder{algLatestLuaValueInstance} <- get
  389     case HM.lookup name algLatestLuaValueInstance of
  390         Just value -> return value
  391         Nothing -> error $ "variable not found : '" <> show name <> "'."
  392 
  393 addAlias from to = do
  394     luaAlgBuilder@LuaAlgBuilder{algLatestLuaValueInstance} <- get
  395     case getLuaValueByName to algLatestLuaValueInstance of
  396         Just value -> do
  397             put luaAlgBuilder{algLatestLuaValueInstance = HM.insert from value algLatestLuaValueInstance}
  398         Nothing -> error ("variable '" <> show to <> " not found. Constants list : " <> show algLatestLuaValueInstance)
  399 
  400 getLuaValueByName name buffer = HM.lookup name buffer
  401 
  402 buildAlg syntaxTree =
  403     flip execState emptyLuaAlgBuilder $ do
  404         let (startupFunctionName, startupFunctionCall, startupFunctionDef) = findStartupFunction syntaxTree
  405             statements = funAssignStatements startupFunctionDef
  406         _ <- addStartupFuncArgs startupFunctionCall startupFunctionDef
  407         mapM_ (processStatement startupFunctionName) statements
  408     where
  409         emptyLuaAlgBuilder =
  410             LuaAlgBuilder
  411                 { algGraph = []
  412                 , algLatestLuaValueInstance = HM.empty
  413                 , algVarCounters = HM.empty
  414                 , algVars = HM.empty
  415                 , algStartupArgs = HM.empty
  416                 , algConstants = HM.empty
  417                 , algTraceFuncs = []
  418                 }
  419         funAssignStatements (FunAssign _ (FunBody _ _ (Block statements _))) = statements
  420         funAssignStatements _ = error "funAssignStatements : not a function assignment"
  421 
  422 findStartupFunction (Block statements Nothing)
  423     | [call] <- filter (\case FunCall{} -> True; _ -> False) statements
  424     , [funAssign] <- filter (\case FunAssign{} -> True; _ -> False) statements
  425     , (FunCall (NormalFunCall (PEVar (VarName (Name fnCall))) _)) <- call
  426     , (FunAssign (FunName (Name fnAssign) _ _) _) <- funAssign
  427     , fnCall == fnAssign =
  428         (fnCall, call, funAssign)
  429 findStartupFunction _ = error "can't find startup function in lua source code"
  430 
  431 getLuaBlockFromSources src = either (\e -> error $ "Exception while parsing Lua sources: " <> show e) id $ parseText chunk src
  432 
  433 alg2graph LuaAlgBuilder{algGraph, algLatestLuaValueInstance, algVars} = flip execState (DFCluster []) $ do
  434     mapM addToGraph algGraph
  435     where
  436         addToGraph item = do
  437             graph <- get
  438             put (addFuncToDataFlowGraph (function2nitta item) graph)
  439             return $ fromString ""
  440         function2nitta LuaStatement{fName = "buffer", fIn = [i], fOut = [o], fValues = [], fInt = []} = F.buffer (fromText i) $ output o
  441         function2nitta LuaStatement{fName = "brokenBuffer", fIn = [i], fOut = [o], fValues = [], fInt = []} = F.brokenBuffer (fromText i) $ output o
  442         function2nitta LuaStatement{fName = "constant", fIn = [], fOut = [o], fValues = [x], fInt = []} = F.constant x $ output o
  443         function2nitta LuaStatement{fName = "send", fIn = [i], fOut = [], fValues = [], fInt = []} = F.send (fromText i)
  444         function2nitta LuaStatement{fName = "add", fIn = [a, b], fOut = [c], fValues = [], fInt = []} = F.add (fromText a) (fromText b) $ output c
  445         function2nitta LuaStatement{fName = "sub", fIn = [a, b], fOut = [c], fValues = [], fInt = []} = F.sub (fromText a) (fromText b) $ output c
  446         function2nitta LuaStatement{fName = "multiply", fIn = [a, b], fOut = [c], fValues = [], fInt = []} = F.multiply (fromText a) (fromText b) $ output c
  447         function2nitta LuaStatement{fName = "divide", fIn = [d, n], fOut = [q], fValues = [], fInt = []} = F.division (fromText d) (fromText n) (output q) []
  448         function2nitta LuaStatement{fName = "divide", fIn = [d, n], fOut = [q, r], fValues = [], fInt = []} = F.division (fromText d) (fromText n) (output q) (output r)
  449         function2nitta LuaStatement{fName = "neg", fIn = [i], fOut = [o], fValues = [], fInt = []} = F.neg (fromText i) $ output o
  450         function2nitta LuaStatement{fName = "receive", fIn = [], fOut = [o], fValues = [], fInt = []} = F.receive $ output o
  451         function2nitta LuaStatement{fName = "shiftL", fIn = [a], fOut = [c], fValues = [], fInt = [s]} = F.shiftL s (fromText a) $ output c
  452         function2nitta LuaStatement{fName = "shiftR", fIn = [a], fOut = [c], fValues = [], fInt = [s]} = F.shiftR s (fromText a) $ output c
  453         function2nitta LuaStatement{fName = "loop", fIn = [a], fOut = [c], fValues = [x], fInt = []} = F.loop x (fromText a) $ output c
  454         function2nitta LuaStatement{fName = "lessThan", fIn = [a, b], fOut = [c], fValues = [], fInt = []} = F.cmp F.CmpLt (fromText a) (fromText b) (output c)
  455         function2nitta LuaStatement{fName = "lessThanOrEqual", fIn = [a, b], fOut = [c], fValues = [], fInt = []} = F.cmp F.CmpLte (fromText a) (fromText b) $ output c
  456         function2nitta LuaStatement{fName = "equal", fIn = [a, b], fOut = [c], fValues = [], fInt = []} = F.cmp F.CmpEq (fromText a) (fromText b) $ output c
  457         function2nitta LuaStatement{fName = "greaterThanOrEqual", fIn = [a, b], fOut = [c], fValues = [], fInt = []} = F.cmp F.CmpGte (fromText a) (fromText b) $ output c
  458         function2nitta LuaStatement{fName = "greaterThan", fIn = [a, b], fOut = [c], fValues = [], fInt = []} = F.cmp F.CmpGt (fromText a) (fromText b) $ output c
  459         function2nitta LuaStatement{fName = "and", fIn = [a, b], fOut = [c], fValues = [], fInt = []} = F.logicAnd (fromText a) (fromText b) $ output c
  460         function2nitta LuaStatement{fName = "or", fIn = [a, b], fOut = [c], fValues = [], fInt = []} = F.logicOr (fromText a) (fromText b) $ output c
  461         function2nitta LuaStatement{fName = "not", fIn = [a], fOut = [c], fValues = [], fInt = []} = F.logicNot (fromText a) $ output c
  462         function2nitta LuaStatement{fName = "if_mux", fIn = [cond, b, a], fOut = [c], fValues = [], fInt = []} = F.mux [fromText a, fromText b] (fromText cond) $ output c
  463         function2nitta f = error $ "function not found: " <> show f
  464         output v =
  465             case HM.lookup v algVars of
  466                 Just names -> map fromText names
  467                 _ -> error $ "variable not found : " <> show v <> ", buffer : " <> show algLatestLuaValueInstance
  468 
  469 translateLua :: (Var v, Val x) => T.Text -> FrontendResult v x
  470 translateLua src =
  471     let syntaxTree = getLuaBlockFromSources src
  472         luaAlgBuilder = buildAlg syntaxTree
  473         frTrace = getFrTrace $ getAllTraceFuncs luaAlgBuilder
  474      in FrontendResult{frDataFlow = alg2graph luaAlgBuilder, frTrace, frPrettyLog = prettyLog frTrace}
  475     where
  476         getAllTraceFuncs algBuilder =
  477             let traceFuncs = algTraceFuncs algBuilder
  478                 startupArgNames =
  479                     map
  480                         (\(_idx, (varName, _initValue)) -> varName)
  481                         $ HM.toList
  482                         $ algStartupArgs algBuilder
  483              in map (\name -> ([name <> "^0"], Nothing)) startupArgNames <> traceFuncs
  484 
  485 getFrTrace traceFuncs = [TraceVar fmt var | (vars, fmt) <- traceFuncs, var <- vars]