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     findStartupFunction,
   90     getLuaBlockFromSources,
   91     processStatement,
   92 ) where
   93 
   94 import Control.Monad.State
   95 import Data.HashMap.Strict qualified as HM
   96 import Data.Hashable
   97 import Data.Maybe
   98 import Data.String
   99 import Data.String.ToString
  100 import Data.Text qualified as T
  101 import Language.Lua hiding (Var)
  102 import NITTA.Frontends.Common
  103 import NITTA.Intermediate.DataFlow
  104 import NITTA.Intermediate.Functions qualified as F
  105 import NITTA.Intermediate.Types
  106 import NITTA.Utils.Base
  107 
  108 getUniqueLuaVariableName LuaValueInstance{lviName, lviIsConstant = True} luaValueAccessCount = "!" <> lviName <> "#" <> showText luaValueAccessCount
  109 getUniqueLuaVariableName LuaValueInstance{lviName, lviAssignCount} luaValueAccessCount
  110     | T.head lviName == '_' = lviName
  111     | otherwise = lviName <> "^" <> showText lviAssignCount <> "#" <> showText luaValueAccessCount
  112 
  113 data LuaStatement x = LuaStatement
  114     { fIn :: [T.Text]
  115     , fOut :: [LuaValueInstance]
  116     , fName :: T.Text
  117     , fValues :: [x]
  118     , fInt :: [Int]
  119     }
  120     deriving (Show, Eq)
  121 
  122 -- | Stores information about a particular version of a variable. The version of a variable changes after assigning a new value to it.
  123 data LuaValueInstance = LuaValueInstance
  124     { lviName :: T.Text
  125     , lviAssignCount :: Int
  126     , lviIsConstant :: Bool
  127     }
  128     deriving (Show, Eq)
  129 
  130 instance Hashable LuaValueInstance where
  131     hashWithSalt i LuaValueInstance{lviName, lviAssignCount, lviIsConstant} =
  132         ( (hashWithSalt i lviName * 31)
  133             + hashWithSalt i lviAssignCount
  134         )
  135             * 31
  136             + hashWithSalt i lviIsConstant
  137 
  138 data LuaAlgBuilder x = LuaAlgBuilder
  139     { algGraph :: [LuaStatement x]
  140     -- ^ A list containing all expressions to be added to the final graph.
  141     , algLatestLuaValueInstance :: HM.HashMap T.Text LuaValueInstance
  142     -- ^ A table that maps a variable name to the most recent corresponding LuaValueInstance.
  143     , algVarCounters :: HM.HashMap T.Text Int
  144     -- ^ A table needed to generate unique temporary variable names.
  145     , algVars :: HM.HashMap LuaValueInstance [T.Text]
  146     -- ^ A table lists all uses of a particular LuaValueInstance.
  147     , algStartupArgs :: HM.HashMap Int (T.Text, T.Text)
  148     -- ^ Map argument index to the variable name and initial value (in text).
  149     , algConstants :: HM.HashMap T.Text LuaValueInstance
  150     -- ^ A table correlating constant with LuaValueInstance which store this constant.
  151     , algTraceFuncs :: [([T.Text], Maybe T.Text)]
  152     -- ^ A list that stores debug information about monitored variables and their display formats.
  153     }
  154     deriving (Show)
  155 
  156 -- left part of lua statement
  157 parseLeftExp (VarName (Name v)) = v
  158 parseLeftExp var = error $ "unexpected lua variable declaration format : " <> show var
  159 
  160 -- right part of lua statement
  161 parseRightExp [fOut] (Binop ShiftL a (Number IntNum s)) = do
  162     varName <- parseExpArg fOut a
  163     addVariable [varName] [fOut] [] "shiftL" [readText s]
  164 parseRightExp [fOut] (Binop ShiftR a (Number IntNum s)) = do
  165     varName <- parseExpArg fOut a
  166     addVariable [varName] [fOut] [] "shiftR" [readText s]
  167 parseRightExp [fOut] (Number _ valueString) = do
  168     addVariable [] [fOut] [readText valueString] "constant" []
  169 parseRightExp fOut@(x : _) (Binop op a b) = do
  170     varNameA <- parseExpArg x a
  171     varNameB <- parseExpArg x b
  172     addVariable [varNameA, varNameB] fOut [] (getBinopFuncName op) []
  173     where
  174         getBinopFuncName Add = "add"
  175         getBinopFuncName Sub = "sub"
  176         getBinopFuncName Mul = "multiply"
  177         getBinopFuncName Div = "divide"
  178         getBinopFuncName o = error $ "unknown binop: " <> show o
  179 parseRightExp fOut (PrefixExp (Paren e)) = parseRightExp fOut e
  180 parseRightExp fOut (Unop Neg (Number numType name)) = parseRightExp fOut (Number numType ("-" <> name))
  181 parseRightExp [fOut] (Unop Neg expr@(PrefixExp _)) = do
  182     varName <- parseExpArg fOut expr
  183     addVariable [varName] [fOut] [] "neg" []
  184 parseRightExp
  185     [fOut]
  186     ( PrefixExp
  187             ( PEFunCall
  188                     ( NormalFunCall
  189                             (PEVar (VarName (Name fname)))
  190                             (Args args)
  191                         )
  192                 )
  193         ) = do
  194         fIn <- mapM (parseExpArg fOut) args
  195         addFunction fname fIn [fOut]
  196 parseRightExp [fOut] (PrefixExp (PEVar (VarName (Name name)))) = do
  197     addAlias fOut name
  198 parseRightExp _ expr = error $ "unknown expression : " <> show expr
  199 
  200 parseExpArg _ n@(Number _ _) = do
  201     addConstant n
  202 parseExpArg fOut expr@(Unop Neg _) = do
  203     name <- getNextTmpVarName fOut
  204     _ <- parseRightExp [name] expr
  205     addVariableAccess name
  206 parseExpArg _ (PrefixExp (PEVar (VarName (Name name)))) = do
  207     addVariableAccess name
  208 parseExpArg fOut binop@Binop{} = do
  209     name <- getNextTmpVarName fOut
  210     _ <- parseRightExp [name] binop
  211     addVariableAccess name
  212 parseExpArg fOut (PrefixExp (Paren arg)) = parseExpArg fOut arg
  213 parseExpArg fOut call@(PrefixExp (PEFunCall _)) = do
  214     name <- getNextTmpVarName fOut
  215     _ <- parseRightExp [name] call
  216     addVariableAccess name
  217 parseExpArg _ _ = undefined
  218 
  219 getNextTmpVarName fOut
  220     | T.isInfixOf "#" fOut = getNextTmpVarName (T.splitOn "#" fOut !! 1)
  221     | otherwise = do
  222         luaAlgBuilder@LuaAlgBuilder{algVarCounters} <- get
  223         case HM.lookup fOut algVarCounters of
  224             Just value -> do
  225                 put luaAlgBuilder{algVarCounters = HM.insert fOut (value + 1) algVarCounters}
  226                 return $ "_" <> showText value <> "#" <> fOut
  227             Nothing -> do
  228                 put luaAlgBuilder{algVarCounters = HM.insert fOut 1 algVarCounters}
  229                 return $ "_0#" <> fOut
  230 
  231 addStartupFuncArgs (FunCall (NormalFunCall _ (Args exps))) (FunAssign _ (FunBody names _ _)) = do
  232     mapM_
  233         ( \case
  234             (Name name, Number _ valueString, serialNumber) -> addToBuffer name valueString serialNumber
  235             _ -> error "addStartupFuncArgs: internal error"
  236         )
  237         $ zip3 names exps [0 ..]
  238     return ""
  239     where
  240         addToBuffer name valueString serialNumber = do
  241             luaAlgBuilder@LuaAlgBuilder{algVars, algLatestLuaValueInstance, algStartupArgs} <- get
  242             let value = LuaValueInstance{lviName = name, lviAssignCount = 0, lviIsConstant = False}
  243             put luaAlgBuilder{algLatestLuaValueInstance = HM.insert name value algLatestLuaValueInstance, algVars = HM.insert value [] algVars, algStartupArgs = HM.insert serialNumber (name, valueString) algStartupArgs}
  244             return value
  245 addStartupFuncArgs _ _ = undefined
  246 
  247 -- Lua language Stat structure parsing
  248 -- LocalAssign
  249 processStatement _ (LocalAssign _names Nothing) = do
  250     return ()
  251 processStatement fn (LocalAssign names (Just exps)) =
  252     processStatement fn $ Assign (map VarName names) exps
  253 -- Assign
  254 processStatement fn (Assign lexps@[_] [Unop Neg (Number ntype ntext)]) =
  255     processStatement fn (Assign lexps [Number ntype ("-" <> ntext)])
  256 processStatement _ (Assign lexp [rexp]) = do
  257     parseRightExp (map parseLeftExp lexp) rexp
  258 processStatement startupFunctionName (Assign vars exps) | length vars == length exps = do
  259     mapM_
  260         ( \case
  261             (VarName (Name name), expr) -> processStatement startupFunctionName (Assign [VarName (Name (getTempAlias name))] [expr])
  262             _ -> error "processStatement: internal error"
  263         )
  264         $ zip vars exps
  265     mapM_ (\(VarName (Name name)) -> addAlias name (getTempAlias name)) vars
  266     where
  267         getTempAlias name = name <> "&"
  268 -- startup function recursive call
  269 processStatement fn (FunCall (NormalFunCall (PEVar (VarName (Name fName))) (Args args)))
  270     | fn == fName = do
  271         LuaAlgBuilder{algStartupArgs} <- get
  272         let startupVarsNames = map (fromMaybe (error "processStatement: internal error") . (`HM.lookup` algStartupArgs)) [0 .. (HM.size algStartupArgs)]
  273         let startupVarsVersions = map (\x -> LuaValueInstance{lviName = fst x, lviAssignCount = 0, lviIsConstant = False}) startupVarsNames
  274         mapM_ parseStartupArg $ zip3 args startupVarsVersions (map (readText . snd) startupVarsNames)
  275     where
  276         parseStartupArg (arg, valueVersion, index) = do
  277             varName <- parseExpArg "loop" arg
  278             luaAlgBuilder@LuaAlgBuilder{algGraph} <- get
  279             put luaAlgBuilder{algGraph = LuaStatement{fIn = [varName], fOut = [valueVersion], fValues = [index], fName = "loop", fInt = []} : algGraph}
  280 processStatement _ (FunCall (NormalFunCall (PEVar (VarName (Name fName))) (Args args))) = do
  281     fIn <- mapM (parseExpArg "tmp") args
  282     addFunction (fromText fName) fIn [fromString ""]
  283 processStatement _fn (FunCall (NormalFunCall (PEVar (SelectName (PEVar (VarName (Name "debug"))) (Name fName))) (Args args))) = do
  284     let fIn = map parseTraceArg args
  285     luaAlgBuilder@LuaAlgBuilder{algTraceFuncs, algLatestLuaValueInstance} <- get
  286     case (fName, fIn) of
  287         ("trace", tFmt : vs)
  288             | T.isPrefixOf "\"" tFmt && T.isPrefixOf "\"" tFmt -> do
  289                 let vars = map (\x -> T.pack $ takeWhile (/= '#') $ T.unpack $ getUniqueLuaVariableName (fromMaybe undefined $ HM.lookup x algLatestLuaValueInstance) 0) vs
  290                 put luaAlgBuilder{algTraceFuncs = (vars, Just $ T.replace "\"" "" tFmt) : algTraceFuncs}
  291         ("trace", vs) -> do
  292             let vars = map (\x -> T.pack $ takeWhile (/= '#') $ T.unpack $ getUniqueLuaVariableName (fromMaybe undefined $ HM.lookup x algLatestLuaValueInstance) 0) vs
  293             put luaAlgBuilder{algTraceFuncs = (vars, Nothing) : algTraceFuncs}
  294         _ -> error $ "unknown debug method: " <> show fName <> " " <> show args
  295     where
  296         parseTraceArg (String s) = s
  297         parseTraceArg (PrefixExp (PEVar (VarName (Name name)))) = name
  298         parseTraceArg _ = undefined
  299 processStatement _ _stat = error $ "unknown statement: " <> show _stat
  300 
  301 addFunction funcName [i] fOut | toString funcName == "buffer" = do
  302     addVariable [i] fOut [] "buffer" []
  303 addFunction funcName [i] fOut | toString funcName == "brokenBuffer" = do
  304     addVariable [i] fOut [] "brokenBuffer" []
  305 addFunction funcName [i] _ | toString funcName == "send" = do
  306     luaAlgBuilder@LuaAlgBuilder{algGraph} <- get
  307     put luaAlgBuilder{algGraph = LuaStatement{fIn = [i], fOut = [], fValues = [], fName = "send", fInt = []} : algGraph}
  308 addFunction funcName _ fOut | toString funcName == "receive" = do
  309     addVariable [] fOut [] "receive" []
  310 addFunction fName _ _ = error $ "unknown function" <> T.unpack fName
  311 
  312 addConstant (Number _valueType valueString) = do
  313     luaAlgBuilder@LuaAlgBuilder{algGraph, algVars, algConstants} <- get
  314     let lvv = LuaValueInstance{lviName = valueString, lviAssignCount = 0, lviIsConstant = True}
  315     case HM.lookup valueString algConstants of
  316         Just value -> do
  317             let names = fromMaybe (error "lua constants parsing error") $ HM.lookup value algVars
  318             let resultName = getUniqueLuaVariableName lvv $ length names
  319             put luaAlgBuilder{algVars = HM.insert value (resultName : names) algVars}
  320             return resultName
  321         Nothing -> do
  322             let resultName = getUniqueLuaVariableName lvv 0
  323             put
  324                 luaAlgBuilder
  325                     { algGraph = LuaStatement{fIn = [], fOut = [lvv], fValues = [readText valueString], fName = "constant", fInt = []} : algGraph
  326                     , algVars = HM.insert lvv [resultName] algVars
  327                     , algConstants = HM.insert valueString lvv algConstants
  328                     }
  329             return resultName
  330 addConstant _ = undefined
  331 
  332 addVariable fIn fOut fValues fName fInt = do
  333     LuaAlgBuilder{algLatestLuaValueInstance} <- get
  334     let luaValueInstances = map (\x -> nameToLuaValueInstance algLatestLuaValueInstance x) fOut
  335     let func = LuaStatement{fIn, fValues, fName, fInt, fOut = luaValueInstances}
  336     mapM_ (uncurry addItemToBuffer) $ zip fOut luaValueInstances
  337     mapM_ addItemToVars luaValueInstances
  338     luaAlgBuilder@LuaAlgBuilder{algGraph, algConstants, algLatestLuaValueInstance = algLatestLuaValueInstance'} <- get
  339     case fName of
  340         "constant" -> do
  341             case HM.lookup (showText $ head fValues) algConstants of
  342                 Just lvv -> do
  343                     put luaAlgBuilder{algLatestLuaValueInstance = HM.insert (head fOut) lvv algLatestLuaValueInstance'}
  344                 Nothing -> do
  345                     put luaAlgBuilder{algGraph = func : algGraph, algConstants = HM.insert (showText $ head fValues) (head luaValueInstances) algConstants}
  346         _ -> do
  347             put luaAlgBuilder{algGraph = func : algGraph}
  348     where
  349         nameToLuaValueInstance algLatestLuaValueInstance name =
  350             case getLuaValueByName name algLatestLuaValueInstance of
  351                 Just lvv@LuaValueInstance{lviAssignCount} -> lvv{lviAssignCount = lviAssignCount + 1}
  352                 Nothing -> LuaValueInstance{lviName = name, lviAssignCount = 0, lviIsConstant = False}
  353         addItemToBuffer name lvv = do
  354             luaAlgBuilder@LuaAlgBuilder{algLatestLuaValueInstance} <- get
  355             put luaAlgBuilder{algLatestLuaValueInstance = HM.insert name lvv algLatestLuaValueInstance}
  356         addItemToVars name = do
  357             luaAlgBuilder@LuaAlgBuilder{algVars} <- get
  358             put luaAlgBuilder{algVars = HM.insert name [] algVars}
  359 
  360 addVariableAccess name = do
  361     luaAlgBuilder@LuaAlgBuilder{algVars} <- get
  362     luaValueInstance <- getLatestLuaValueInstanceByName name
  363     case HM.lookup luaValueInstance algVars of
  364         Just value -> do
  365             let len = length value
  366             let resultName = getUniqueLuaVariableName luaValueInstance len
  367             put luaAlgBuilder{algVars = HM.insert luaValueInstance (resultName : value) algVars}
  368             return resultName
  369         Nothing -> error ("variable '" <> show (lviName luaValueInstance) <> " not found. Constants list : " <> show algVars)
  370 
  371 getLatestLuaValueInstanceByName name = do
  372     LuaAlgBuilder{algLatestLuaValueInstance} <- get
  373     case HM.lookup name algLatestLuaValueInstance of
  374         Just value -> return value
  375         Nothing -> error $ "variable not found : '" <> show name <> "'."
  376 
  377 addAlias from to = do
  378     luaAlgBuilder@LuaAlgBuilder{algLatestLuaValueInstance} <- get
  379     case getLuaValueByName to algLatestLuaValueInstance of
  380         Just value -> do
  381             put luaAlgBuilder{algLatestLuaValueInstance = HM.insert from value algLatestLuaValueInstance}
  382         Nothing -> error ("variable '" <> show to <> " not found. Constants list : " <> show algLatestLuaValueInstance)
  383 
  384 getLuaValueByName name buffer = HM.lookup name buffer
  385 
  386 buildAlg syntaxTree =
  387     flip execState emptyLuaAlgBuilder $ do
  388         let (startupFunctionName, startupFunctionCall, startupFunctionDef) = findStartupFunction syntaxTree
  389             statements = funAssignStatements startupFunctionDef
  390         _ <- addStartupFuncArgs startupFunctionCall startupFunctionDef
  391         mapM_ (processStatement startupFunctionName) statements
  392     where
  393         emptyLuaAlgBuilder =
  394             LuaAlgBuilder
  395                 { algGraph = []
  396                 , algLatestLuaValueInstance = HM.empty
  397                 , algVarCounters = HM.empty
  398                 , algVars = HM.empty
  399                 , algStartupArgs = HM.empty
  400                 , algConstants = HM.empty
  401                 , algTraceFuncs = []
  402                 }
  403         funAssignStatements (FunAssign _ (FunBody _ _ (Block statements _))) = statements
  404         funAssignStatements _ = error "funAssignStatements : not a function assignment"
  405 
  406 findStartupFunction (Block statements Nothing)
  407     | [call] <- filter (\case FunCall{} -> True; _ -> False) statements
  408     , [funAssign] <- filter (\case FunAssign{} -> True; _ -> False) statements
  409     , (FunCall (NormalFunCall (PEVar (VarName (Name fnCall))) _)) <- call
  410     , (FunAssign (FunName (Name fnAssign) _ _) _) <- funAssign
  411     , fnCall == fnAssign =
  412         (fnCall, call, funAssign)
  413 findStartupFunction _ = error "can't find startup function in lua source code"
  414 
  415 getLuaBlockFromSources src = either (\e -> error $ "Exception while parsing Lua sources: " <> show e) id $ parseText chunk src
  416 
  417 alg2graph LuaAlgBuilder{algGraph, algLatestLuaValueInstance, algVars} = flip execState (DFCluster []) $ do
  418     mapM addToGraph algGraph
  419     where
  420         addToGraph item = do
  421             graph <- get
  422             put (addFuncToDataFlowGraph (function2nitta item) graph)
  423             return $ fromString ""
  424         function2nitta LuaStatement{fName = "buffer", fIn = [i], fOut = [o], fValues = [], fInt = []} = F.buffer (fromText i) $ output o
  425         function2nitta LuaStatement{fName = "brokenBuffer", fIn = [i], fOut = [o], fValues = [], fInt = []} = F.brokenBuffer (fromText i) $ output o
  426         function2nitta LuaStatement{fName = "constant", fIn = [], fOut = [o], fValues = [x], fInt = []} = F.constant x $ output o
  427         function2nitta LuaStatement{fName = "send", fIn = [i], fOut = [], fValues = [], fInt = []} = F.send (fromText i)
  428         function2nitta LuaStatement{fName = "add", fIn = [a, b], fOut = [c], fValues = [], fInt = []} = F.add (fromText a) (fromText b) $ output c
  429         function2nitta LuaStatement{fName = "sub", fIn = [a, b], fOut = [c], fValues = [], fInt = []} = F.sub (fromText a) (fromText b) $ output c
  430         function2nitta LuaStatement{fName = "multiply", fIn = [a, b], fOut = [c], fValues = [], fInt = []} = F.multiply (fromText a) (fromText b) $ output c
  431         function2nitta LuaStatement{fName = "divide", fIn = [d, n], fOut = [q], fValues = [], fInt = []} = F.division (fromText d) (fromText n) (output q) []
  432         function2nitta LuaStatement{fName = "divide", fIn = [d, n], fOut = [q, r], fValues = [], fInt = []} = F.division (fromText d) (fromText n) (output q) (output r)
  433         function2nitta LuaStatement{fName = "neg", fIn = [i], fOut = [o], fValues = [], fInt = []} = F.neg (fromText i) $ output o
  434         function2nitta LuaStatement{fName = "receive", fIn = [], fOut = [o], fValues = [], fInt = []} = F.receive $ output o
  435         function2nitta LuaStatement{fName = "shiftL", fIn = [a], fOut = [c], fValues = [], fInt = [s]} = F.shiftL s (fromText a) $ output c
  436         function2nitta LuaStatement{fName = "shiftR", fIn = [a], fOut = [c], fValues = [], fInt = [s]} = F.shiftR s (fromText a) $ output c
  437         function2nitta LuaStatement{fName = "loop", fIn = [a], fOut = [c], fValues = [x], fInt = []} = F.loop x (fromText a) $ output c
  438         function2nitta f = error $ "function not found: " <> show f
  439         output v =
  440             case HM.lookup v algVars of
  441                 Just names -> map fromText names
  442                 _ -> error $ "variable not found : " <> show v <> ", buffer : " <> show algLatestLuaValueInstance
  443 
  444 translateLua :: (Var v, Val x) => T.Text -> FrontendResult v x
  445 translateLua src =
  446     let syntaxTree = getLuaBlockFromSources src
  447         luaAlgBuilder = buildAlg syntaxTree
  448         frTrace = getFrTrace $ getAllTraceFuncs luaAlgBuilder
  449      in FrontendResult{frDataFlow = alg2graph luaAlgBuilder, frTrace, frPrettyLog = prettyLog frTrace}
  450     where
  451         getAllTraceFuncs algBuilder =
  452             let traceFuncs = algTraceFuncs algBuilder
  453                 startupArgNames =
  454                     map
  455                         (\(_idx, (varName, _initValue)) -> varName)
  456                         $ HM.toList
  457                         $ algStartupArgs algBuilder
  458              in map (\name -> ([name <> "^0"], Nothing)) startupArgNames <> traceFuncs
  459 
  460 getFrTrace traceFuncs = [TraceVar fmt var | (vars, fmt) <- traceFuncs, var <- vars]