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