Revert "Intern all strings and dotted names in the DAML-LF protobuf encoding (#3067)" (#3114)

This reverts commit 68e4453324.
This commit is contained in:
Remy 2019-10-04 16:13:27 +02:00 committed by Moritz Kiefer
parent 156edf7432
commit 449500bad8
20 changed files with 238 additions and 893 deletions

View File

@ -67,18 +67,10 @@ featureAnyTemplate = Feature
, featureCppFlag = "DAML_ANY_TEMPLATE"
}
featureStringInterning :: Feature
featureStringInterning = Feature
{ featureName = "String interning"
, featureMinVersion = version1_7
, featureCppFlag = "DAML_STRING_INTERNING"
}
allFeatures :: [Feature]
allFeatures =
[ featureNumeric
, featureAnyTemplate
, featureStringInterning
]
allFeaturesForVersion :: Version -> [Feature]

View File

@ -3,7 +3,6 @@
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE TypeFamilies #-}
module DA.Daml.LF.Proto3.DecodeV1
( decodePackage
@ -12,11 +11,10 @@ module DA.Daml.LF.Proto3.DecodeV1
import DA.Daml.LF.Ast as LF
import DA.Daml.LF.Proto3.Error
import qualified DA.Daml.LF.Proto3.Util as Util
import Control.Monad
import Control.Monad.Except
import Control.Monad.Reader
import Data.Int
import Data.Word
import Text.Read
import Data.List
import DA.Daml.LF.Mangling
@ -28,9 +26,8 @@ import qualified Data.Vector as V
import qualified Proto3.Suite as Proto
data DecodeEnv = DecodeEnv
{ internedStrings :: !(V.Vector T.Text)
, internedDottedNames :: !(V.Vector [T.Text])
newtype DecodeEnv = DecodeEnv
{ internedStrings :: V.Vector T.Text
}
newtype Decode a = Decode{unDecode :: ReaderT DecodeEnv (Except Error) a}
@ -39,21 +36,15 @@ newtype Decode a = Decode{unDecode :: ReaderT DecodeEnv (Except Error) a}
runDecode :: DecodeEnv -> Decode a -> Either Error a
runDecode env act = runExcept $ runReaderT (unDecode act) env
lookupInterned :: V.Vector a -> (Int32 -> Error) -> Int32 -> Decode a
lookupInterned interned mkError id = do
case interned V.!? fromIntegral id of
Nothing -> throwError $ mkError id
Just x -> pure x
lookupString :: Int32 -> Decode T.Text
lookupString strId = do
lookupString :: Word64 -> Decode T.Text
lookupString strIdW = do
let strIdI = toInteger strIdW
when (strIdI > toInteger (maxBound :: Int)) $
throwError $ MissingPackageRefId strIdW
DecodeEnv{internedStrings} <- ask
lookupInterned internedStrings BadStringId strId
lookupDottedName :: Int32 -> Decode [T.Text]
lookupDottedName id = do
DecodeEnv{internedDottedNames} <- ask
lookupInterned internedDottedNames BadDottedNameId id
case internedStrings V.!? fromInteger strIdI of
Nothing -> throwError $ MissingPackageRefId strIdW
Just str -> pure str
------------------------------------------------------------------------
-- Decodings of things related to string interning
@ -65,30 +56,15 @@ decodeString :: TL.Text -> T.Text
decodeString = TL.toStrict
-- | Decode a string that will be interned in DAML-LF 1.7 and onwards.
-- At the protobuf level, we represent internable non-empty lists of strings
-- by a repeatable string and a number. If there's at least one string,
-- then the number must not be set, i.e. zero. If there are no strings,
-- then the number is treated as an index into the interning table.
decodeInternableStrings :: V.Vector TL.Text -> Int32 -> Decode [T.Text]
decodeInternableStrings strs id
| V.null strs = lookupDottedName id
| id == 0 = pure $ map decodeString (V.toList strs)
| otherwise = throwError $ ParseError "items and interned id both set for string list"
decodeInternableString :: TL.Text -> Decode T.Text
decodeInternableString = pure . decodeString
-- | Decode the name of a syntactic object, e.g., a variable or a data
-- constructor. These strings are mangled to escape special characters. All
-- names will be interned in DAML-LF 1.7 and onwards.
decodeName
:: Util.EitherLike TL.Text Int32 e
=> (T.Text -> a) -> Maybe e -> Decode a
decodeName wrapName mbStrOrId = mayDecode "name" mbStrOrId $ \strOrId -> do
mangled <- case Util.toEither strOrId of
Left str -> pure $ decodeString str
Right strId -> lookupString strId
decodeNameString wrapName mangled
decodeNameString :: (T.Text -> a) -> T.Text -> Decode a
decodeNameString wrapName mangled =
decodeName :: (T.Text -> a) -> TL.Text -> Decode a
decodeName wrapName mangled = do
mangled <- decodeInternableString mangled
case unmangleIdentifier mangled of
Left err -> throwError $ ParseError $ "Could not unmangle name " ++ show mangled ++ ": " ++ err
Right unmangled -> pure $ wrapName unmangled
@ -97,31 +73,29 @@ decodeNameString wrapName mangled =
-- constructor. All compononents are mangled. Dotted names will be interned
-- in DAML-LF 1.7 and onwards.
decodeDottedName :: ([T.Text] -> a) -> LF1.DottedName -> Decode a
decodeDottedName wrapDottedName (LF1.DottedName mangled dnId) =
wrapDottedName <$> (decodeInternableStrings mangled dnId >>= mapM (decodeNameString id))
decodeDottedName wrapDottedName (LF1.DottedName mangled) = do
wrapDottedName <$> mapM (decodeName id) (V.toList mangled)
-- | Decode the name of a top-level value. The name is mangled and will be
-- interned in DAML-LF 1.7 and onwards.
decodeValueName :: String -> V.Vector TL.Text -> Int32 -> Decode ExprValName
decodeValueName ident mangledV dnId = do
mangled <- decodeInternableStrings mangledV dnId
case mangled of
[] -> throwError $ MissingField ident
[unmangled] -> do
mangled <- decodeNameString id unmangled
decodeValueName :: String -> V.Vector TL.Text -> Decode ExprValName
decodeValueName ident mangledV = case V.length mangledV of
0 -> throwError $ MissingField ident
1 -> do
mangled <- decodeInternableString $ V.head mangledV
case unmangleIdentifier mangled of
Right unmangled -> pure $ ExprValName unmangled
-- NOTE(MH): This is an ugly hack to keep backwards compatibility.
-- We need to fix this in DAML-LF 2.
Left _ -> pure $ ExprValName mangled
_ -> throwError $ ParseError $ "Unexpected multi-segment def name: " ++ show mangledV ++ "//" ++ show mangled
_ -> throwError $ ParseError $ "Unexpected multi-segment def name: " ++ show mangledV
-- | Decode a reference to a top-level value. The name is mangled and will be
-- interned in DAML-LF 1.7 and onwards.
decodeValName :: LF1.ValName -> Decode (Qualified ExprValName)
decodeValName LF1.ValName{..} = do
(pref, mname) <- mayDecode "valNameModule" valNameModule decodeModuleRef
name <- decodeValueName "valNameName" valNameName valNameNameInternedId
name <- decodeValueName "valNameName" valNameName
pure $ Qualified pref mname name
-- | Decode a reference to a package. Package names are not mangled. Package
@ -139,8 +113,7 @@ decodePackageRef (LF1.PackageRef pref) =
decodeVersion :: T.Text -> Either Error Version
decodeVersion minorText = do
let unsupported :: Either Error a
unsupported = throwError (UnsupportedMinorVersion minorText)
let unsupported = throwError (UnsupportedMinorVersion minorText)
-- we translate "no version" to minor version 0, since we introduced
-- minor versions once DAML-LF v1 was already out, and we want to be
-- able to parse packages that were compiled before minor versions
@ -152,19 +125,12 @@ decodeVersion minorText = do
let version = V1 minor
if version `elem` LF.supportedInputVersions then pure version else unsupported
decodeInternedDottedName :: LF1.InternedDottedName -> Decode [T.Text]
decodeInternedDottedName (LF1.InternedDottedName ids) =
mapM lookupString $ V.toList ids
decodePackage :: TL.Text -> LF1.Package -> Either Error Package
decodePackage minorText (LF1.Package mods internedStringsV internedDottedNamesV) = do
decodePackage minorText (LF1.Package mods internedList) = do
version <- decodeVersion (decodeString minorText)
let internedStrings = V.map decodeString internedStringsV
let internedDottedNames = V.empty
let env0 = DecodeEnv{..}
internedDottedNames <- runDecode env0 $ mapM decodeInternedDottedName internedDottedNamesV
let env = DecodeEnv{..}
runDecode env $ do
let internedStrings = V.map decodeString internedList
let env = DecodeEnv{internedStrings}
runDecode env $
Package version <$> decodeNM DuplicateModule decodeModule mods
decodeModule :: LF1.Module -> Decode Module
@ -201,16 +167,12 @@ decodeDataCons = \case
DataRecord <$> mapM (decodeFieldWithType FieldName) (V.toList fs)
LF1.DefDataTypeDataConsVariant (LF1.DefDataType_Fields fs) ->
DataVariant <$> mapM (decodeFieldWithType VariantConName) (V.toList fs)
LF1.DefDataTypeDataConsEnum (LF1.DefDataType_EnumConstructors cs cIds) -> do
mangled <- if
| V.null cIds -> pure $ map decodeString (V.toList cs)
| V.null cs -> mapM lookupString (V.toList cIds)
| otherwise -> throwError $ ParseError "strings and interned string ids both set for enum constructor"
DataEnum <$> mapM (decodeNameString VariantConName) mangled
LF1.DefDataTypeDataConsEnum (LF1.DefDataType_EnumConstructors cs) ->
DataEnum <$> mapM (decodeName VariantConName) (V.toList cs)
decodeDefValueNameWithType :: LF1.DefValue_NameWithType -> Decode (ExprValName, Type)
decodeDefValueNameWithType LF1.DefValue_NameWithType{..} = (,)
<$> decodeValueName "defValueName" defValue_NameWithTypeName defValue_NameWithTypeNameInternedId
<$> decodeValueName "defValueName" defValue_NameWithTypeName
<*> mayDecode "defValueType" defValue_NameWithTypeType decodeType
decodeDefValue :: LF1.DefValue -> Decode DefValue
@ -409,8 +371,7 @@ decodeExpr (LF1.Expr mbLoc exprSum) = case mbLoc of
decodeExprSum :: Maybe LF1.ExprSum -> Decode Expr
decodeExprSum exprSum = mayDecode "exprSum" exprSum $ \case
LF1.ExprSumVar var -> EVar <$> decodeNameString ExprVarName (decodeString var)
LF1.ExprSumVarInternedId strId -> EVar <$> (lookupString strId >>= decodeNameString ExprVarName)
LF1.ExprSumVar var -> EVar <$> decodeName ExprVarName var
LF1.ExprSumVal val -> EVal <$> decodeValName val
LF1.ExprSumBuiltin (Proto.Enumerated (Right bi)) -> EBuiltin <$> decodeBuiltinFunction bi
LF1.ExprSumBuiltin (Proto.Enumerated (Left num)) -> throwError (UnknownEnum "ExprSumBuiltin" num)
@ -628,15 +589,11 @@ decodeVarWithType LF1.VarWithType{..} =
decodePrimLit :: LF1.PrimLit -> Decode BuiltinExpr
decodePrimLit (LF1.PrimLit mbSum) = mayDecode "primLitSum" mbSum $ \case
LF1.PrimLitSumInt64 sInt -> pure $ BEInt64 sInt
LF1.PrimLitSumDecimal sDec -> decodeDecimalLit $ decodeString sDec
LF1.PrimLitSumDecimalInternedId strId -> lookupString strId >>= decodeDecimalLit
LF1.PrimLitSumNumeric sNum -> decodeNumericLit $ decodeString sNum
LF1.PrimLitSumNumericInternedId strId -> lookupString strId >>= decodeNumericLit
LF1.PrimLitSumDecimal sDec -> decodeInternableString sDec >>= decodeDecimalLit
LF1.PrimLitSumNumeric sNum -> decodeInternableString sNum >>= decodeNumericLit
LF1.PrimLitSumTimestamp sTime -> pure $ BETimestamp sTime
LF1.PrimLitSumText x -> pure $ BEText $ decodeString x
LF1.PrimLitSumTextInternedId strId -> BEText <$> lookupString strId
LF1.PrimLitSumParty p -> pure $ BEParty $ PartyLiteral $ decodeString p
LF1.PrimLitSumPartyInternedId strId -> BEParty . PartyLiteral <$> lookupString strId
LF1.PrimLitSumText x -> BEText <$> decodeInternableString x
LF1.PrimLitSumParty p -> BEParty . PartyLiteral <$> decodeInternableString p
LF1.PrimLitSumDate days -> pure $ BEDate days
decodeDecimalLit :: T.Text -> Decode BuiltinExpr

View File

@ -1,8 +1,7 @@
-- Copyright (c) 2019 The DAML Authors. All rights reserved.
-- SPDX-License-Identifier: Apache-2.0
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}
-- | Encoding of the LF package into LF version 1 format.
module DA.Daml.LF.Proto3.EncodeV1
( encodeModuleWithoutInterning
@ -13,20 +12,17 @@ import Control.Lens ((^.), matching)
import Control.Lens.Ast (rightSpine)
import Control.Monad.State.Strict
import Data.Coerce
import Data.Functor.Identity
import qualified Data.HashMap.Strict as HMS
import qualified Data.List as L
import qualified Data.NameMap as NM
import qualified Data.Text as T
import qualified Data.Text.Lazy as TL
import qualified Data.Vector as V
import Data.Int
import Data.Word
import DA.Pretty
import DA.Daml.LF.Ast
import DA.Daml.LF.Mangling
import qualified DA.Daml.LF.Proto3.Util as Util
import qualified Da.DamlLf1 as P
import qualified Proto3.Suite as P (Enumerated (..))
@ -43,52 +39,24 @@ newtype WithInterning = WithInterning{getWithInterning :: Bool}
data EncodeEnv = EncodeEnv
{ version :: !Version
, withInterning :: !WithInterning
, internedStrings :: !(HMS.HashMap T.Text Int32)
, nextInternedStringId :: !Int32
-- ^ We track the size of `internedStrings` explicitly since `HMS.size` is `O(n)`.
, internedDottedNames :: !(HMS.HashMap [Int32] Int32)
, nextInternedDottedNameId :: !Int32
-- ^ We track the size of `internedDottedNames` explicitly since `HMS.size` is `O(n)`.
, internedStrings :: !(HMS.HashMap T.Text Word64)
}
initEncodeEnv :: Version -> WithInterning -> EncodeEnv
initEncodeEnv version withInterning =
EncodeEnv
{ nextInternedStringId = 0
, internedStrings = HMS.empty
, internedDottedNames = HMS.empty
, nextInternedDottedNameId = 0
, ..
}
initEncodeEnv version withInterning = EncodeEnv{internedStrings = HMS.empty, ..}
-- | Find or allocate a string in the interning table. Return the index of
-- the string in the resulting interning table.
allocString :: T.Text -> Encode Int32
allocString :: T.Text -> Encode Word64
allocString t = do
env@EncodeEnv{internedStrings, nextInternedStringId = n} <- get
env@EncodeEnv{internedStrings} <- get
case t `HMS.lookup` internedStrings of
Just n -> pure n
Nothing -> do
when (n == maxBound) $
error "String interning table grew too large"
put $! env
{ internedStrings = HMS.insert t n internedStrings
, nextInternedStringId = n + 1
}
pure n
allocDottedName :: [Int32] -> Encode Int32
allocDottedName ids = do
env@EncodeEnv{internedDottedNames, nextInternedDottedNameId = n} <- get
case ids `HMS.lookup` internedDottedNames of
Just n -> pure n
Nothing -> do
when (n == maxBound) $
error "Dotted name interning table grew too large"
put $! env
{ internedDottedNames = HMS.insert ids n internedDottedNames
, nextInternedDottedNameId = n + 1
}
-- NOTE(MH): We assumie that the number of interned strings fits
-- in a `Word64`. (More than that would require A LOT of memory.)
let n = fromIntegral (HMS.size internedStrings)
put $! env{internedStrings = HMS.insert t n internedStrings}
pure n
------------------------------------------------------------------------
@ -101,54 +69,23 @@ encodeString :: T.Text -> TL.Text
encodeString = TL.fromStrict
-- | Encode a string that will be interned in DAML-LF 1.7 and onwards.
encodeInternableString :: T.Text -> Encode (Either TL.Text Int32)
encodeInternableString = coerce (encodeInternableStrings @Identity)
-- | Encode a string that will be interned in DAML-LF 1.7 and onwards.
encodeInternableStrings :: Traversable t => t T.Text -> Encode (Either (t TL.Text) (t Int32))
encodeInternableStrings strs = do
EncodeEnv{..} <- get
if getWithInterning withInterning && version `supports` featureStringInterning
then Right <$> mapM allocString strs
else pure $ Left $ fmap encodeString strs
encodeInternableString :: T.Text -> Encode TL.Text
encodeInternableString = pure . encodeString
-- | Encode the name of a syntactic object, e.g., a variable or a data
-- constructor. These strings are mangled to escape special characters. All
-- names will be interned in DAML-LF 1.7 and onwards.
encodeName
:: Util.EitherLike TL.Text Int32 e
=> (a -> T.Text) -> a -> Encode (Just e)
encodeName unwrapName = fmap Just . encodeName' unwrapName
encodeName'
:: Util.EitherLike TL.Text Int32 e
=> (a -> T.Text) -> a -> Encode e
encodeName' unwrapName (unwrapName -> unmangled) = do
Util.fromEither @TL.Text @Int32 <$> coerce (encodeNames @Identity) unmangled
encodeNames :: Traversable t => t T.Text -> Encode (Either (t TL.Text) (t Int32))
encodeNames = encodeInternableStrings . fmap mangleName
where
mangleName :: T.Text -> T.Text
mangleName unmangled = case mangleIdentifier unmangled of
encodeName :: (a -> T.Text) -> a -> Encode TL.Text
encodeName unwrapName (unwrapName -> unmangled) = case mangleIdentifier unmangled of
Left err -> error $ "IMPOSSIBLE: could not mangle name " ++ show unmangled ++ ": " ++ err
Right mangled -> mangled
Right mangled -> encodeInternableString mangled
-- | Encode the multi-component name of a syntactic object, e.g., a type
-- constructor. All compononents are mangled. Dotted names will be interned
-- in DAML-LF 1.7 and onwards.
encodeDottedName :: (a -> [T.Text]) -> a -> Encode (Just P.DottedName)
encodeDottedName unwrapDottedName (unwrapDottedName -> unmangled) =
Just . uncurry P.DottedName <$> encodeDottedName' unmangled
encodeDottedName' :: [T.Text] -> Encode (V.Vector TL.Text, Int32)
encodeDottedName' unmangled = do
mangledAndInterned <- encodeNames unmangled
case mangledAndInterned of
Left mangled -> pure (V.fromList mangled, 0)
Right ids -> do
id <- allocDottedName ids
pure (V.empty, id)
encodeDottedName unwrapDottedName =
fmap (Just . P.DottedName) . encodeList (encodeName id) . unwrapDottedName
-- | Encode the name of a top-level value. The name is mangled and will be
-- interned in DAML-LF 1.7 and onwards.
@ -158,8 +95,8 @@ encodeDottedName' unmangled = do
-- because currently GenDALF generates weird names like `.` that we'd
-- have to handle separatedly. So for now, considering that we do not
-- use values in codegen, just mangle the entire thing.
encodeValueName :: ExprValName -> Encode (V.Vector TL.Text, Int32)
encodeValueName valName = encodeDottedName' [unExprValName valName]
encodeValueName :: ExprValName -> Encode (V.Vector TL.Text)
encodeValueName = fmap V.singleton . encodeName unExprValName
-- | Encode a reference to a package. Package names are not mangled. Package
-- name are interned since DAML-LF 1.6.
@ -312,19 +249,11 @@ encodeTypeConApp (TypeConApp tycon args) = do
encodeBuiltinExpr :: BuiltinExpr -> Encode P.ExprSum
encodeBuiltinExpr = \case
BEInt64 x -> pureLit $ P.PrimLitSumInt64 x
BEDecimal dec ->
lit . either P.PrimLitSumDecimal P.PrimLitSumDecimalInternedId
<$> encodeInternableString (T.pack (show dec))
BENumeric n ->
lit . either P.PrimLitSumNumeric P.PrimLitSumNumericInternedId
<$> encodeInternableString (T.pack (show n))
BEText x ->
lit . either P.PrimLitSumText P.PrimLitSumTextInternedId
<$> encodeInternableString x
BEDecimal dec -> lit . P.PrimLitSumDecimal <$> encodeInternableString (T.pack (show dec))
BENumeric n -> lit . P.PrimLitSumNumeric <$> encodeInternableString (T.pack (show n))
BEText x -> lit . P.PrimLitSumText <$> encodeInternableString x
BETimestamp x -> pureLit $ P.PrimLitSumTimestamp x
BEParty x ->
lit . either P.PrimLitSumParty P.PrimLitSumPartyInternedId
<$> encodeInternableString (unPartyLiteral x)
BEParty x -> lit . P.PrimLitSumParty <$> encodeInternableString (unPartyLiteral x)
BEDate x -> pureLit $ P.PrimLitSumDate x
BEUnit -> pure $ P.ExprSumPrimCon $ P.Enumerated $ Right P.PrimConCON_UNIT
@ -461,10 +390,10 @@ encodeBuiltinExpr = \case
encodeExpr' :: Expr -> Encode P.Expr
encodeExpr' = \case
EVar v -> expr . either P.ExprSumVar P.ExprSumVarInternedId <$> encodeName' unExprVarName v
EVar v -> expr . P.ExprSumVar <$> encodeName unExprVarName v
EVal (Qualified pkgRef modName val) -> do
valNameModule <- encodeModuleRef pkgRef modName
(valNameName, valNameNameInternedId) <- encodeValueName val
valNameName <- encodeValueName val
pureExpr $ P.ExprSumVal P.ValName{..}
EBuiltin bi -> expr <$> encodeBuiltinExpr bi
ERecCon{..} -> do
@ -694,10 +623,7 @@ encodeDefDataType DefDataType{..} = do
defDataType_FieldsFields <- encodeFieldsWithTypes unVariantConName fs
pure $ P.DefDataTypeDataConsVariant P.DefDataType_Fields{..}
DataEnum cs -> do
mangledAndInterned <- encodeNames (map unVariantConName cs)
let (defDataType_EnumConstructorsConstructors, defDataType_EnumConstructorsConstructorsInternedIds) = case mangledAndInterned of
Left mangled -> (V.fromList mangled, V.empty)
Right mangledIds -> (V.empty, V.fromList mangledIds)
defDataType_EnumConstructorsConstructors <- encodeList (encodeName unVariantConName) cs
pure $ P.DefDataTypeDataConsEnum P.DefDataType_EnumConstructors{..}
let defDataTypeSerializable = getIsSerializable dataSerializable
defDataTypeLocation <- traverse encodeSourceLoc dataLocation
@ -705,7 +631,7 @@ encodeDefDataType DefDataType{..} = do
encodeDefValue :: DefValue -> Encode P.DefValue
encodeDefValue DefValue{..} = do
(defValue_NameWithTypeName, defValue_NameWithTypeNameInternedId) <- encodeValueName (fst dvalBinder)
defValue_NameWithTypeName <- encodeValueName (fst dvalBinder)
defValue_NameWithTypeType <- encodeType (snd dvalBinder)
let defValueNameWithType = Just P.DefValue_NameWithType{..}
defValueExpr <- encodeExpr dvalBody
@ -774,12 +700,9 @@ encodeModule Module{..} = do
encodePackage :: Package -> P.Package
encodePackage (Package version mods) =
let env = initEncodeEnv version (WithInterning True)
(packageModules, EncodeEnv{internedStrings, internedDottedNames}) =
runState (encodeNameMap encodeModule mods) env
packageInternedStrings =
(packageModules, EncodeEnv{internedStrings}) = runState (encodeNameMap encodeModule mods) env
packageInternedPackageIds =
V.fromList $ map (encodeString . fst) $ L.sortOn snd $ HMS.toList internedStrings
packageInternedDottedNames =
V.fromList $ map (P.InternedDottedName . V.fromList . fst) $ L.sortOn snd $ HMS.toList internedDottedNames
in
P.Package{..}

View File

@ -7,6 +7,7 @@ module DA.Daml.LF.Proto3.Error
import qualified Data.Text as T
import Data.Int (Int32)
import Data.Word (Word64)
import DA.Daml.LF.Ast
@ -20,7 +21,6 @@ data Error
| EDuplicateTemplate TypeConName
| DuplicateChoice ChoiceName
| UnsupportedMinorVersion T.Text
| BadStringId Int32
| BadDottedNameId Int32
| MissingPackageRefId Word64
| ExpectedTCon Type
deriving (Show, Eq)

View File

@ -1,63 +0,0 @@
-- Copyright (c) 2019 The DAML Authors. All rights reserved.
-- SPDX-License-Identifier: Apache-2.0
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
module DA.Daml.LF.Proto3.Util (
EitherLike,
toEither,
fromEither,
) where
import Data.Int
import qualified Data.Text.Lazy as TL
import GHC.Generics
import qualified Da.DamlLf1 as P
class EitherLike a b e where
toEither :: e -> Either a b
fromEither :: Either a b -> e
default toEither
:: (Generic e, Rep e ~ D1 m1 (C1 m2 (S1 m3 (Rec0 a)) :+: C1 m4 (S1 m5 (Rec0 b))))
=> e -> Either a b
toEither e =
case unM1 $ from e of
L1 x -> Left $ unK1 $ unM1 $ unM1 x
R1 y -> Right $ unK1 $ unM1 $ unM1 y
default fromEither
:: (Generic e, Rep e ~ D1 m1 (C1 m2 (S1 m3 (Rec0 a)) :+: C1 m4 (S1 m5 (Rec0 b))))
=> Either a b -> e
fromEither = to . M1 . either (L1 . M1 . M1 . K1) (R1 . M1 . M1 . K1)
instance EitherLike a b (Either a b) where
toEither = id
fromEither = id
instance EitherLike TL.Text Int32 P.CaseAlt_ConsVarHead
instance EitherLike TL.Text Int32 P.CaseAlt_ConsVarTail
instance EitherLike TL.Text Int32 P.CaseAlt_EnumConstructor
instance EitherLike TL.Text Int32 P.CaseAlt_OptionalSomeVarBody
instance EitherLike TL.Text Int32 P.CaseAlt_VariantBinder
instance EitherLike TL.Text Int32 P.CaseAlt_VariantVariant
instance EitherLike TL.Text Int32 P.DefTemplateParam
instance EitherLike TL.Text Int32 P.Expr_EnumConEnumCon
instance EitherLike TL.Text Int32 P.Expr_RecProjField
instance EitherLike TL.Text Int32 P.Expr_RecUpdField
instance EitherLike TL.Text Int32 P.Expr_TupleProjField
instance EitherLike TL.Text Int32 P.Expr_TupleUpdField
instance EitherLike TL.Text Int32 P.Expr_VariantConVariantCon
instance EitherLike TL.Text Int32 P.FieldWithExprField
instance EitherLike TL.Text Int32 P.FieldWithTypeField
instance EitherLike TL.Text Int32 P.KeyExpr_ProjectionField
instance EitherLike TL.Text Int32 P.KeyExpr_RecordFieldField
instance EitherLike TL.Text Int32 P.TemplateChoiceName
instance EitherLike TL.Text Int32 P.TemplateChoiceSelfBinder
instance EitherLike TL.Text Int32 P.Type_VarVar
instance EitherLike TL.Text Int32 P.TypeVarWithKindVar
instance EitherLike TL.Text Int32 P.Update_ExerciseChoice
instance EitherLike TL.Text Int32 P.VarWithTypeVar

View File

@ -1,9 +1,6 @@
-- Copyright (c) 2019 The DAML Authors. All rights reserved.
-- SPDX-License-Identifier: Apache-2.0
-- Check that the interning tables don't contain duplicates:
-- @QUERY-LF .interned_strings // [] | (unique | length == length)
-- @QUERY-LF .interned_dotted_names // [] | (unique | length == length)
daml 1.2
module Test where

View File

@ -4,8 +4,8 @@
-- Check that enum types get translated to DAML-LF's enum types.
-- @SINCE-LF 1.6
-- @QUERY-LF .modules[] | .data_types[] | select(.name | lf::get_dotted_name($pkg) == ["Color"]) | has("enum")
-- @QUERY-LF .modules[] | .values[] | select(.name_with_type | lf::get_value_name($pkg) == ["red"]) | .expr | has("enum_con")
-- @QUERY-LF .modules[] | .values[] | select(.name_with_type | lf::get_value_name($pkg) == ["isRed"]) | .expr.abs.body.case.alts | .[0] | has("enum")
-- @QUERY-LF .modules[] | .values[] | select(.name_with_type | lf::get_name($pkg) == ["red"]) | .expr | has("enum_con")
-- @QUERY-LF .modules[] | .values[] | select(.name_with_type | lf::get_name($pkg) == ["isRed"]) | .expr.abs.body.case.alts | .[0] | has("enum")
-- @QUERY-LF .modules[] | .data_types[] | select(.name | lf::get_dotted_name($pkg) == ["Tag"]) | (has("enum") | not)
daml 1.2
module EnumLF where

View File

@ -6,7 +6,7 @@
-- uses actors as a sanity check.
-- @SINCE-LF 1.5
-- @QUERY-LF [.modules[] | .values[] | select(.name_with_type | lf::get_value_name($pkg) == ["$$fFooInstance"]) | .expr | .. | objects | select(has("exercise")) | .exercise | has("actor") | not] | (length > 0 and all)
-- @QUERY-LF [.modules[] | .values[] | select(.name_with_type | lf::get_name($pkg) == ["$$fFooInstance"]) | .expr | .. | objects | select(has("exercise")) | .exercise | has("actor") | not] | all
daml 1.2
module ExerciseWithoutActors where

View File

@ -2,8 +2,8 @@
-- All rights reserved.
-- @ SINCE-LF 1.6
-- @QUERY-LF [.modules[] | .values[] | .expr.val.module.package_ref | select(has("interned_id"))] | length == 2
-- @QUERY-LF .interned_strings | length >= 2
-- @QUERY-LF [ .modules[] | .values[] | .expr.val.module.package_ref.interned_id ] | sort == ["0", "1"]
-- @QUERY-LF .interned_package_ids | length == 2
-- We test that interning of package ids works. The two packages we reference are
-- daml-prim and daml-stdlib.

View File

@ -173,7 +173,7 @@ testCase args version getService outdir registerTODO (name, file) = singleTest n
for_ [file ++ ", " ++ x | Todo x <- anns] (registerTODO . TODO)
resDiag <- checkDiagnostics log [fields | DiagnosticFields fields <- anns] $
[ideErrorText "" $ T.pack $ show e | Left e <- [ex], not $ "_IGNORE_" `isInfixOf` show e] ++ diags
resQueries <- runJqQuery log version outdir file [q | QueryLF q <- anns]
resQueries <- runJqQuery log outdir file [q | QueryLF q <- anns]
let failures = catMaybes $ resDiag : resQueries
case failures of
err : _others -> pure $ testFailed err
@ -185,19 +185,15 @@ testCase args version getService outdir registerTODO (name, file) = singleTest n
UntilLF maxVersion -> version > maxVersion
_ -> False
runJqQuery :: (String -> IO ()) -> LF.Version -> FilePath -> FilePath -> [String] -> IO [Maybe String]
runJqQuery log version outdir file qs = do
runJqQuery :: (String -> IO ()) -> FilePath -> FilePath -> [String] -> IO [Maybe String]
runJqQuery log outdir file qs = do
let proj = takeBaseName file
forM qs $ \q -> do
log $ "running jq query: " ++ q
let jqKey = "external" </> "jq_dev_env" </> "bin" </> if isWindows then "jq.exe" else "jq"
jq <- locateRunfiles $ mainWorkspace </> jqKey
queryLfDir <- locateRunfiles $ mainWorkspace </> "compiler/damlc/tests/src"
let queryLfMod
| version `supports` featureStringInterning = "query-lf-interned"
| otherwise = "query-lf-non-interned"
let fullQuery = "import \"./" ++ queryLfMod ++ "\" as lf; . as $pkg | " ++ q
out <- readProcess jq ["-L", queryLfDir, fullQuery, outdir </> proj <.> "json"] ""
queryLfLib <- locateRunfiles $ mainWorkspace </> "compiler/damlc/tests/src"
out <- readProcess jq ["-L", queryLfLib, "import \"./query-lf-non-interned\" as lf; . as $pkg | " ++ q, outdir </> proj <.> "json"] ""
case trim out of
"true" -> pure Nothing
other -> pure $ Just $ "jq query failed: got " ++ other

View File

@ -1,9 +0,0 @@
def get_value_name(pkg): pkg.interned_dotted_names[.name_interned_id] | .segment_ids | map(pkg.interned_strings[.]);
def get_int64(pkg): .int64;
def get_dotted_name(pkg): pkg.interned_dotted_names[.segments_interned_id // 0] | .segment_ids | map(pkg.interned_strings[.]);
def get_field(pkg): pkg.interned_strings[.interned_id];
def get_name(pkg): .name;

View File

@ -4,6 +4,6 @@ def get_int64(pkg): .int64;
def get_dotted_name(pkg): .segments;
def get_field(pkg): .name;
def get_field(pkg): .field;
def get_name(pkg): .name;

View File

@ -6,7 +6,6 @@ load("//bazel_tools:pkg.bzl", "pkg_tar")
load("//bazel_tools:proto.bzl", "proto_gen")
load(
"//bazel_tools:scala.bzl",
"da_scala_binary",
"da_scala_library",
"da_scala_test_suite",
"lf_scalacopts",
@ -227,16 +226,3 @@ pkg_tar(
package_dir = "daml-lf-archive-protos/protobuf/da",
visibility = ["//visibility:public"],
)
# An ad-hoc tool for testing, benchmarking and profiling package decoding performance in isolation.
da_scala_binary(
name = "decode-tester",
srcs = ["src/test/scala/com/digitalasset/daml/lf/archive/DecodeMain.scala"],
main_class = "com.digitalasset.daml.lf.archive.DecodeMain",
deps = [
":daml_lf_archive_scala",
":daml_lf_java_proto",
"//daml-lf/data",
"//daml-lf/language",
],
)

View File

@ -36,7 +36,6 @@
// 2019-07-29: Add nat kind and Nat types, Numeric types and Numeric builtins
// 2019-09-17: Add Any type and, To_Any and From_Any builtins
// 2019-09-17: Drop support for Decimal
// 2019-09-30: Add interning of strings and dotted names
syntax = "proto3";
package daml_lf_1;
@ -63,17 +62,16 @@ message PackageRef {
// An index into `interned_package_ids` of the Package containing
// this reference.
int32 interned_id = 3; // *Available in versions >= 1.6*
uint64 interned_id = 3; // *Available in versions >= 1.6*
}
}
// A `name`, e.g. Util.Either.isLeft
message DottedName {
// *Must be a non-empty list of a valid identifiers unless `segments_interned_id` is set.*
// *Must be a non-empty list of a valid identifiers*
repeated string segments = 1;
// *Must be set if and only if `segments` is an empty list.*
int32 segments_interned_id = 2; // *Available in versions >= 1.dev*
}
// A fully qualified module reference
@ -104,11 +102,8 @@ message ValName {
// Module where the value is defined
ModuleRef module = 1;
// *Must be a non-empty list of a valid identifiers unless `interned_id` is set.*
// value name.
repeated string name = 2;
// *Must be set if and only if `segments` is an empty list.*
int32 name_interned_id = 3; // *Available in versions >= 1.dev*
}
// A field name definition in a record or a variant associated with a type.
@ -116,10 +111,7 @@ message FieldWithType {
// Name of the field .
// *Must be a valid identifier*
oneof field {
string name = 1;
int32 interned_id = 3; // *Available in versions >= 1.dev*
}
string field = 1;
// Type associated
Type type = 2;
@ -130,10 +122,7 @@ message VarWithType {
// Name of the bound expression variable.
// *Must be a valid identifier*
oneof var {
string name = 1;
int32 interned_id = 3; // *Available in versions >= 1.dev*
}
string var = 1;
// Type of the bound variable
Type type = 2;
@ -143,11 +132,7 @@ message VarWithType {
message TypeVarWithKind {
// Name of the bound expression variable
// *Must be a valid identifier*
oneof var {
string name = 1;
int32 interned_id = 3; // *Available in versions >= 1.dev*
}
string var = 1;
// Kind of the bound variable
Kind kind = 2;
}
@ -156,11 +141,7 @@ message TypeVarWithKind {
message FieldWithExpr {
// Name of the field
// *Must be a valid identifier*
oneof field {
string name = 1;
int32 interned_id = 3; // *Available in versions >= 1.dev*
}
string field = 1;
// Value of the field
Expr expr = 2;
}
@ -268,10 +249,7 @@ message Type {
// Name of the variable.
// *Must be a valid identifier*
oneof var {
string var_name = 1;
int32 var_interned_id = 3; // *Available in versions >= 1.dev*
}
string var = 1;
// Types to which the variable is applied
repeated Type args = 2;
@ -495,11 +473,9 @@ message PrimLit {
// one. so, string it is. note that we can't store the whole and
// decimal part in two numbers either, because 10^28 > 2^63.
string decimal = 2; // *Available in versions < 1.dev*
int32 decimal_interned_id = 10; // *Available in versions >= 1.dev*
// Unicode string literal ('LitText')
string text = 4;
int32 text_interned_id = 11; // *Available in versions >= 1.dev*
// UTC timestamp literal ('LitTimestamp')
//
@ -516,7 +492,6 @@ message PrimLit {
// Party literal ('LitParty')
// *Must be a PartyId string*
string party = 7;
int32 party_interned_id = 12; // *Available in versions >= 1.dev*
// Date literal ('Date')
// Serialization of the number of days since the unix epoch. can go backwards.
@ -533,7 +508,6 @@ message PrimLit {
//
// The number of decimal digits indicate the scale of the number.
string numeric = 9; // *Available in versions >= 1.dev*
int32 numeric_interned_id = 13; // *Available in versions >= 1.dev*
}
reserved 3; // This was char.
@ -577,10 +551,7 @@ message Expr {
// Name of the record field to be projected on.
// *must be a valid Identifier*
oneof field {
string name = 2;
int32 interned_id = 4; // *Available in versions >= 1.dev*
}
string field = 2;
// projected expression
Expr record = 3;
@ -594,10 +565,7 @@ message Expr {
// Name of the updated field.
// *must be a valid identifier*
oneof field {
string name = 2;
int32 interned_id = 5; // *Available in versions >= 1.dev*
}
string field = 2;
// Actual record being updated
Expr record = 3;
@ -614,10 +582,7 @@ message Expr {
// name of the variant constructor
// *Must be a valid identifier*
oneof variant_con {
string name = 2;
int32 interned_id = 4; // *Available in versions >= 1.dev*
}
string variant_con = 2;
// Argument of the variant.
Expr variant_arg = 3;
@ -632,10 +597,7 @@ message Expr {
// name of the enum constructor
// *Must be a valid identifier*
oneof enum_con {
string name = 2;
int32 interned_id = 3; // *Available in versions >= 1.dev*
}
string enum_con = 2;
}
// Tuple Construction ('ExpTupleCon')
@ -649,10 +611,7 @@ message Expr {
// Name of the field to be projected on.
// *Must be a valid Identifier*
oneof field {
string name = 1;
int32 interned_id = 3; // *Available in versions >= 1.dev*
}
string field = 1;
// tuple to be projected.
Expr tuple = 2;
@ -663,10 +622,7 @@ message Expr {
// Name of the updated field.
// *must be a valid identifier*.
oneof field {
string name = 1;
int32 interned_id = 4; // *Available in versions >= 1.dev*
}
string field = 1;
// Actual tuple being updated.
Expr tuple = 2;
@ -787,7 +743,6 @@ message Expr {
// Expression variable ('ExpVar')
// *must be a valid identifier*
string var = 1;
int32 var_interned_id = 31; // *Available in versions >= 1.dev*
// Defined value ('ExpVal')
ValName val = 2;
@ -887,17 +842,11 @@ message CaseAlt {
// name of the variant constructor
// *Must be a valid identifier*
oneof variant {
string variant_name = 2;
int32 variant_interned_id = 4; // *Available in versions >= 1.dev*
}
string variant = 2;
// name of the variant binder
// *Must be a valid identifier*
oneof binder {
string binder_name = 3;
int32 binder_interned_id = 5; // *Available in versions >= 1.dev*
}
string binder = 3;
}
// Enum pattern
@ -909,36 +858,24 @@ message CaseAlt {
// name of the variant constructor
// *Must be a valid identifier*
oneof constructor {
string name = 2;
int32 interned_id = 3; // *Available in versions >= 1.dev*
}
string constructor = 2;
}
// Non empty list pattern
message Cons {
// name of the binder for the head
// *Must be a valid identifier*
oneof var_head {
string var_head_name = 1;
int32 var_head_interned_id = 3; // *Available in versions >= 1.dev*
}
string var_head = 1;
// name of the binder for the tail
// *Must be a valid identifier*
oneof var_tail {
string var_tail_name = 2;
int32 var_tail_interned_id = 4; // *Available in versions >= 1.dev*
}
string var_tail = 2;
}
// Non empty option patterm
// *Available in versions >= 1.1*
message OptionalSome {
oneof var_body {
string name = 1;
int32 interned_id = 2; // *Available in versions >= 1.dev*
}
string var_body = 1;
}
oneof Sum {
@ -990,10 +927,7 @@ message Update {
// Template type
TypeConName template = 1;
// name of the exercised template choice
oneof choice {
string name = 2;
int32 interned_id = 6; // *Available in versions >= 1.dev*
}
string choice = 2;
// contract id
Expr cid = 3;
// actors
@ -1012,7 +946,7 @@ message Update {
reserved 3; // was actor, we thought we'd need this, but we don't
}
// Embedded Expression Update
// Embeded Exression Update
message EmbedExpr {
// Expression type
Type type = 1;
@ -1084,10 +1018,7 @@ message Scenario {
message TemplateChoice {
// *Must be a valid identifier*
oneof name {
string choice_name = 1;
int32 choice_interned_id = 9; // *Available in versions >= 1.dev*
}
string name = 1;
// Choice type
bool consuming = 2;
@ -1109,10 +1040,7 @@ message TemplateChoice {
Expr update = 6;
// Name to bind the ContractId of the contract this choice is exercised on to.
oneof self_binder {
string self_binder_name = 7;
int32 self_binder_interned_id = 10; // *Available in versions >= 1.dev*
}
string self_binder = 7;
Location location = 8;
}
@ -1121,10 +1049,7 @@ message TemplateChoice {
message KeyExpr {
message Projection {
Type.Con tycon = 1; // Always fully applied
oneof field {
string name = 2;
int32 interned_id = 3; // *Available in versions >= 1.dev*
}
string field = 2;
}
// note that the projection is always referring to the template parameter.
@ -1133,10 +1058,7 @@ message KeyExpr {
}
message RecordField {
oneof field {
string name = 1;
int32 interned_id = 3; // *Available in versions >= 1.dev*
}
string field = 1;
KeyExpr expr = 2;
}
@ -1171,10 +1093,7 @@ message DefTemplate {
DottedName tycon = 1;
// Name to which the template argument is bound.
oneof param {
string param_name = 2;
int32 param_interned_id = 11; // *Available in versions >= 1.dev*
}
string param = 2;
// NOTE(MH): The new runtime authorization check for DAML 1.0 does not rely
// on the stakeholder signatures produced by the obligables computation
@ -1218,7 +1137,6 @@ message DefDataType {
// *Available in versions >= 1.6*
message EnumConstructors {
repeated string constructors = 1;
repeated int32 constructors_interned_ids = 2; // *Available in versions >= 1.dev*
}
// name of the defined data type
@ -1255,9 +1173,7 @@ message DefValue {
// Name of the value
// *each element of name must be a valid identifier*
// `name` can be empty if and only if `name_interned_id` is set.
repeated string name = 1;
int32 name_interned_id = 6; // *Available in versions >= 1.dev*
// Type of the value
Type type = 2;
@ -1298,12 +1214,7 @@ message Module {
repeated DefTemplate templates = 7;
}
message InternedDottedName {
repeated int32 segment_ids = 1; // *Available in versions >= 1.dev*
}
message Package {
repeated Module modules = 1;
repeated string interned_strings = 2; // *Available in versions >= 1.6*
repeated InternedDottedName interned_dotted_names = 3; // *Available in versions >= 1.dev*
repeated string interned_package_ids = 2; // *Available in versions >= 1.6*
}

View File

@ -24,28 +24,17 @@ private[archive] class DecodeV1(minor: LV.Minor) extends Decode.OfPackage[PLF.Pa
private val languageVersion = LV(LV.Major.V1, minor)
private def name(s: String): Name = eitherToParseError(Name.fromString(s))
override def decodePackage(
packageId: PackageId,
lfPackage: PLF.Package,
onlySerializableDataDefs: Boolean
): Package = {
val internedStrings: ImmArraySeq[String] = ImmArraySeq(
lfPackage.getInternedStringsList.asScala: _*)
if (internedStrings.nonEmpty)
assertSince(LV.Features.internedPackageId, "interned strings table")
val internedDottedNames: ImmArraySeq[DottedName] =
decodeInternedDottedNames(lfPackage.getInternedDottedNamesList.asScala, internedStrings)
val interned = decodeInternedPackageIds(lfPackage.getInternedPackageIdsList.asScala)
Package(
lfPackage.getModulesList.asScala
.map(
ModuleDecoder(
packageId,
internedStrings,
internedDottedNames,
_,
onlySerializableDataDefs).decode))
.map(ModuleDecoder(packageId, interned, _, onlySerializableDataDefs).decode))
}
type ProtoModule = PLF.Module
@ -54,29 +43,15 @@ private[archive] class DecodeV1(minor: LV.Minor) extends Decode.OfPackage[PLF.Pa
PLF.Module.parser().parseFrom(cis)
override def decodeScenarioModule(packageId: PackageId, lfModule: ProtoModule): Module =
ModuleDecoder(
packageId,
ImmArraySeq.empty,
ImmArraySeq.empty,
lfModule,
onlySerializableDataDefs = false).decode()
ModuleDecoder(packageId, ImmArraySeq.empty, lfModule, onlySerializableDataDefs = false).decode()
private[this] def decodeInternedDottedNames(
internedList: Seq[PLF.InternedDottedName],
internedStrings: ImmArraySeq[String]): ImmArraySeq[DottedName] = {
private[this] def eitherToParseError[A](x: Either[String, A]): A =
x.fold(err => throw new ParseError(err), identity)
private[this] def decodeInternedPackageIds(internedList: Seq[String]): ImmArraySeq[PackageId] = {
if (internedList.nonEmpty)
assertSince(LV.Features.internedDottedNames, "interned dotted names table")
def outOfRange(id: Int) =
ParseError(s"invalid string table index $id")
internedList
.map(
idn =>
decodeSegments(
idn.getSegmentIdsList.asScala
.map(id => internedStrings.lift(id).getOrElse(throw outOfRange(id)))(breakOut))
)(breakOut)
assertSince(LV.Features.internedIds, "interned package ID table")
internedList.map(s => eitherToParseError(PackageId.fromString(s)))(breakOut)
}
private[this] def decodeSegments(segments: ImmArray[String]): DottedName =
@ -87,16 +62,16 @@ private[archive] class DecodeV1(minor: LV.Minor) extends Decode.OfPackage[PLF.Pa
case class ModuleDecoder(
packageId: PackageId,
internedStrings: ImmArraySeq[String],
internedDottedNames: ImmArraySeq[DottedName],
internedPackageIds: ImmArraySeq[PackageId],
lfModule: PLF.Module,
onlySerializableDataDefs: Boolean
) {
val moduleName: ModuleName =
decodeDottedName(lfModule.getName)
val moduleName = eitherToParseError(
ModuleName.fromSegments(lfModule.getName.getSegmentsList.asScala))
private var currentDefinitionRef: Option[DefinitionRef] = None
// FIXME(JM): rewrite.
var currentDefinitionRef: Option[DefinitionRef] = None
def decode(): Module = {
val defs = mutable.ArrayBuffer[(DottedName, Definition)]()
@ -106,7 +81,8 @@ private[archive] class DecodeV1(minor: LV.Minor) extends Decode.OfPackage[PLF.Pa
lfModule.getDataTypesList.asScala
.filter(!onlySerializableDataDefs || _.getSerializable)
.foreach { defn =>
val defName = decodeDottedName(defn.getName)
val defName =
eitherToParseError(DottedName.fromSegments(defn.getName.getSegmentsList.asScala))
currentDefinitionRef = Some(DefinitionRef(packageId, QualifiedName(moduleName, defName)))
val d = decodeDefDataType(defn)
defs += (defName -> d)
@ -115,14 +91,8 @@ private[archive] class DecodeV1(minor: LV.Minor) extends Decode.OfPackage[PLF.Pa
if (!onlySerializableDataDefs) {
// collect values
lfModule.getValuesList.asScala.foreach { defn =>
val nameWithType = defn.getNameWithType
val defName =
if (nameWithType.getNameCount == 0) {
assertSince(LV.Features.internedDottedNames, "interned dotted names table")
getInternedDottedName(nameWithType.getNameInternedId)
} else {
decodeSegments(ImmArray(nameWithType.getNameList.asScala))
}
decodeSegments(ImmArray(defn.getNameWithType.getNameList.asScala))
currentDefinitionRef = Some(DefinitionRef(packageId, QualifiedName(moduleName, defName)))
val d = decodeDefValue(defn)
defs += (defName -> d)
@ -131,7 +101,8 @@ private[archive] class DecodeV1(minor: LV.Minor) extends Decode.OfPackage[PLF.Pa
// collect templates
lfModule.getTemplatesList.asScala.foreach { defn =>
val defName = decodeDottedName(defn.getTycon)
val defName =
eitherToParseError(DottedName.fromSegments(defn.getTycon.getSegmentsList.asScala))
currentDefinitionRef = Some(DefinitionRef(packageId, QualifiedName(moduleName, defName)))
templates += ((defName, decodeTemplate(defn)))
}
@ -140,53 +111,6 @@ private[archive] class DecodeV1(minor: LV.Minor) extends Decode.OfPackage[PLF.Pa
}
// -----------------------------------------------------------------------
private[this] def getInternedString(id: Int) =
internedStrings.lift(id).getOrElse {
throw ParseError(s"invalid internedString table index $id")
}
private[this] def getInternedPackageId(id: Int): PackageId = {
assertSince(LV.Features.internedPackageId, "interned PackageId")
toPackageId(getInternedString(id))
}
private[this] def getInternedName(id: Int): Name = {
assertSince(LV.Features.internedStrings, "interned Name")
toName(getInternedString(id))
}
private[this] def getInternedText(id: Int): PLText = {
assertSince(LV.Features.internedStrings, "interned Text")
PLText(getInternedString(id))
}
private[this] def getInternedNumeric(id: Int): PrimLit = {
assertSince(LV.Features.internedStrings, "interned Numeric")
toNumericLiteral(getInternedString(id))
}
private[this] def getInternedDecimal(id: Int): PLNumeric = {
assertSince(LV.Features.internedStrings, "interned Decimal")
toDecimalLiteral(getInternedString(id))
}
private[this] def getInternedParty(id: Int): PLParty = {
assertSince(LV.Features.internedStrings, "interned Party")
toPartyLiteral(getInternedString(id))
}
private[this] def getInternedDottedName(id: Int): DottedName =
internedDottedNames.lift(id).getOrElse {
assertSince(LV.Features.internedDottedNames, "interned DottedNames")
throw ParseError(s"invalid dotted name table index $id")
}
private[this] def decodeDottedName(name: PLF.DottedName): DottedName =
if (name.getSegmentsCount == 0) {
getInternedDottedName(name.getSegmentsInternedId)
} else {
decodeSegments(ImmArray(name.getSegmentsList.asScala))
}
private[this] def decodeFeatureFlags(flags: PLF.FeatureFlags): FeatureFlags = {
// NOTE(JM, #157): We disallow loading packages with these flags because they impact the Ledger API in
@ -212,7 +136,7 @@ private[archive] class DecodeV1(minor: LV.Minor) extends Decode.OfPackage[PLF.Pa
case PLF.DefDataType.DataConsCase.ENUM =>
assertSince(LV.Features.enum, "DefDataType.DataCons.Enum")
assertEmpty(params.toSeq, "params")
DataEnum(decodeEnumCon(lfDataType.getEnum))
DataEnum(decodeEnumCons(ImmArray(lfDataType.getEnum.getConstructorsList.asScala)))
case PLF.DefDataType.DataConsCase.DATACONS_NOT_SET =>
throw ParseError("DefDataType.DATACONS_NOT_SET")
@ -220,46 +144,14 @@ private[archive] class DecodeV1(minor: LV.Minor) extends Decode.OfPackage[PLF.Pa
)
}
private[this] def decodeFieldWithType(lfFieldWithType: PLF.FieldWithType): (Name, Type) =
(lfFieldWithType.getFieldCase match {
case PLF.FieldWithType.FieldCase.NAME =>
toName(lfFieldWithType.getName)
case PLF.FieldWithType.FieldCase.INTERNED_ID =>
getInternedName(lfFieldWithType.getInternedId)
case PLF.FieldWithType.FieldCase.FIELD_NOT_SET =>
throw ParseError("FieldWithType.FIELD_NOT_SET")
}) -> decodeType(lfFieldWithType.getType)
private[this] def decodeFields(lfFields: ImmArray[PLF.FieldWithType]): ImmArray[(Name, Type)] =
lfFields.map(decodeFieldWithType)
lfFields.map(field => name(field.getField) -> decodeType(field.getType))
private[this] def decodeFieldWithExpr(
lfFieldWithExpr: PLF.FieldWithExpr,
definition: String
): (Name, Expr) =
(lfFieldWithExpr.getFieldCase match {
case PLF.FieldWithExpr.FieldCase.NAME => toName(lfFieldWithExpr.getName)
case PLF.FieldWithExpr.FieldCase.INTERNED_ID =>
getInternedName(lfFieldWithExpr.getInternedId)
case PLF.FieldWithExpr.FieldCase.FIELD_NOT_SET =>
throw ParseError("FieldWithExpr.FIELD_NOT_SET")
}) -> decodeExpr(lfFieldWithExpr.getExpr, definition)
private[this] def decodeEnumCon(
enumCon: PLF.DefDataType.EnumConstructors): ImmArray[EnumConName] =
if (enumCon.getConstructorsCount == 0)
enumCon.getConstructorsInternedIdsList.asScala
.map(id => getInternedName(id))(breakOut)
else
enumCon.getConstructorsList.asScala.map(toName)(breakOut)
private[this] def decodeEnumCons(cons: ImmArray[String]): ImmArray[EnumConName] =
cons.map(name)
private[this] def decodeDefValue(lfValue: PLF.DefValue): DValue = {
val nameWithType = lfValue.getNameWithType
val definition =
if (nameWithType.getNameCount == 0)
getInternedDottedName(nameWithType.getNameInternedId).segments.toSeq.mkString(".")
else
nameWithType.getNameList.asScala.mkString(".")
val definition = lfValue.getNameWithType.getNameList.asScala.mkString(".")
DValue(
typ = decodeType(lfValue.getNameWithType.getType),
noPartyLiterals = lfValue.getNoPartyLiterals,
@ -290,7 +182,7 @@ private[archive] class DecodeV1(minor: LV.Minor) extends Decode.OfPackage[PLF.Pa
}
private[this] def decodeTemplateKey(
tpl: DottedName,
tpl: String,
key: PLF.DefTemplate.DefKey,
tplVar: ExprVarName): TemplateKey = {
assertSince(LV.Features.contractKeys, "DefTemplate.DefKey")
@ -318,32 +210,13 @@ private[archive] class DecodeV1(minor: LV.Minor) extends Decode.OfPackage[PLF.Pa
ERecCon(
tycon = decodeTypeConApp(recCon.getTycon),
fields = ImmArray(recCon.getFieldsList.asScala).map(field =>
(field.getFieldCase match {
case PLF.KeyExpr.RecordField.FieldCase.NAME =>
toName(field.getName)
case PLF.KeyExpr.RecordField.FieldCase.INTERNED_ID =>
getInternedName(field.getInternedId)
case PLF.KeyExpr.RecordField.FieldCase.FIELD_NOT_SET =>
throw ParseError("KeyExpr.Record.Field.FIELD_NOT_SET")
}) -> decodeKeyExpr(field.getExpr, tplVar))
name(field.getField) -> decodeKeyExpr(field.getExpr, tplVar))
)
case PLF.KeyExpr.SumCase.PROJECTIONS =>
val lfProjs = expr.getProjections.getProjectionsList.asScala
lfProjs.foldLeft(EVar(tplVar): Expr)(
(acc, lfProj) =>
ERecProj(
decodeTypeConApp(lfProj.getTycon),
lfProj.getFieldCase match {
case PLF.KeyExpr.Projection.FieldCase.NAME => toName(lfProj.getName)
case PLF.KeyExpr.Projection.FieldCase.INTERNED_ID =>
getInternedName(lfProj.getInternedId)
case PLF.KeyExpr.Projection.FieldCase.FIELD_NOT_SET =>
throw ParseError("KeyExpr.Projection.Field.FIELD_NOT_SET")
},
acc
))
lfProjs.foldLeft(EVar(tplVar): Expr)((acc, lfProj) =>
ERecProj(decodeTypeConApp(lfProj.getTycon), name(lfProj.getField), acc))
case PLF.KeyExpr.SumCase.SUM_NOT_SET =>
throw ParseError("KeyExpr.SUM_NOT_SET")
@ -351,17 +224,10 @@ private[archive] class DecodeV1(minor: LV.Minor) extends Decode.OfPackage[PLF.Pa
}
private[this] def decodeTemplate(lfTempl: PLF.DefTemplate): Template = {
val tpl = decodeDottedName(lfTempl.getTycon)
val paramName = lfTempl.getParamCase match {
case PLF.DefTemplate.ParamCase.PARAM_NAME =>
toName(lfTempl.getParamName)
case PLF.DefTemplate.ParamCase.PARAM_INTERNED_ID =>
getInternedName(lfTempl.getParamInternedId)
case PLF.DefTemplate.ParamCase.PARAM_NOT_SET =>
throw ParseError("DefTemplate.PARAM_NOT_SET")
}
val tpl = lfTempl.getTycon.getSegmentsList.asScala.mkString(".")
Template(
param = paramName,
param = name(lfTempl.getParam),
precond = if (lfTempl.hasPrecond) decodeExpr(lfTempl.getPrecond, s"$tpl:ensure") else ETrue,
signatories = decodeExpr(lfTempl.getSignatories, s"$tpl.signatory"),
agreementText = decodeExpr(lfTempl.getAgreement, s"$tpl:agreement"),
@ -370,38 +236,20 @@ private[archive] class DecodeV1(minor: LV.Minor) extends Decode.OfPackage[PLF.Pa
.map(ch => (ch.name, ch)),
observers = decodeExpr(lfTempl.getObservers, s"$tpl:observer"),
key =
if (lfTempl.hasKey) Some(decodeTemplateKey(tpl, lfTempl.getKey, paramName))
if (lfTempl.hasKey) Some(decodeTemplateKey(tpl, lfTempl.getKey, name(lfTempl.getParam)))
else None
)
}
private[this] def decodeChoice(
tpl: DottedName,
lfChoice: PLF.TemplateChoice): TemplateChoice = {
private[this] def decodeChoice(tpl: String, lfChoice: PLF.TemplateChoice): TemplateChoice = {
val (v, t) = decodeBinder(lfChoice.getArgBinder)
val chName: Name = lfChoice.getNameCase match {
case PLF.TemplateChoice.NameCase.CHOICE_NAME =>
toName(lfChoice.getChoiceName)
case PLF.TemplateChoice.NameCase.CHOICE_INTERNED_ID =>
getInternedName(lfChoice.getChoiceInternedId)
case PLF.TemplateChoice.NameCase.NAME_NOT_SET =>
throw ParseError("TemplateChoice.NAME_NOT_SET")
}
val selfBinder: Name = lfChoice.getSelfBinderCase match {
case PLF.TemplateChoice.SelfBinderCase.SELF_BINDER_NAME =>
toName(lfChoice.getSelfBinderName)
case PLF.TemplateChoice.SelfBinderCase.SELF_BINDER_INTERNED_ID =>
getInternedName(lfChoice.getSelfBinderInternedId)
case PLF.TemplateChoice.SelfBinderCase.SELFBINDER_NOT_SET =>
throw ParseError("TemplateChoice.SELFBINDER_NOT_SET")
}
val chName = lfChoice.getName
TemplateChoice(
name = chName,
name = name(chName),
consuming = lfChoice.getConsuming,
controllers = decodeExpr(lfChoice.getControllers, s"$tpl:$chName:controller"),
selfBinder = selfBinder,
selfBinder = name(lfChoice.getSelfBinder),
argBinder = Some(v) -> t,
returnType = decodeType(lfChoice.getRetType),
update = decodeExpr(lfChoice.getUpdate, s"$tpl:$chName:choice")
@ -427,16 +275,8 @@ private[archive] class DecodeV1(minor: LV.Minor) extends Decode.OfPackage[PLF.Pa
lfType.getSumCase match {
case PLF.Type.SumCase.VAR =>
val tvar = lfType.getVar
val varName = tvar.getVarCase match {
case PLF.Type.Var.VarCase.VAR_NAME =>
toName(tvar.getVarName)
case PLF.Type.Var.VarCase.VAR_INTERNED_ID =>
getInternedName(tvar.getVarInternedId)
case PLF.Type.Var.VarCase.VAR_NOT_SET =>
throw ParseError("Type.VAR_NOT_SET")
}
tvar.getArgsList.asScala
.foldLeft[Type](TVar(varName))((typ, arg) => TApp(typ, decodeType(arg)))
.foldLeft[Type](TVar(name(tvar.getVar)))((typ, arg) => TApp(typ, decodeType(arg)))
case PLF.Type.SumCase.NAT =>
assertSince(LV.Features.numeric, "Type.NAT")
Numeric.Scale
@ -479,23 +319,33 @@ private[archive] class DecodeV1(minor: LV.Minor) extends Decode.OfPackage[PLF.Pa
val tuple = lfType.getTuple
val fields = tuple.getFieldsList.asScala
assertNonEmpty(fields, "fields")
TTuple(fields.map(decodeFieldWithType)(breakOut))
TTuple(
ImmArray(fields.map(ft => name(ft.getField) -> decodeType(ft.getType)))
)
case PLF.Type.SumCase.SUM_NOT_SET =>
throw ParseError("Type.SUM_NOT_SET")
}
private[this] def decodeModuleRef(lfRef: PLF.ModuleRef): (PackageId, ModuleName) = {
val modName = decodeDottedName(lfRef.getModuleName)
val modName = eitherToParseError(
ModuleName.fromSegments(lfRef.getModuleName.getSegmentsList.asScala))
import PLF.PackageRef.{SumCase => SC}
val pkgId = lfRef.getPackageRef.getSumCase match {
case SC.SELF =>
this.packageId
case SC.PACKAGE_ID =>
toPackageId(lfRef.getPackageRef.getPackageId)
val rawPid = lfRef.getPackageRef.getPackageId
PackageId
.fromString(rawPid)
.getOrElse(throw ParseError(s"invalid packageId '$rawPid'"))
case SC.INTERNED_ID =>
getInternedPackageId(lfRef.getPackageRef.getInternedId)
assertSince(LV.Features.internedIds, "interned package ID")
val iidl = lfRef.getPackageRef.getInternedId
def outOfRange = ParseError(s"invalid package ID table index $iidl")
val iid = iidl.toInt
if (iidl != iid.toLong) throw outOfRange
internedPackageIds.lift(iid).getOrElse(throw outOfRange)
case SC.SUM_NOT_SET =>
throw ParseError("PackageRef.SUM_NOT_SET")
}
@ -504,18 +354,14 @@ private[archive] class DecodeV1(minor: LV.Minor) extends Decode.OfPackage[PLF.Pa
private[this] def decodeValName(lfVal: PLF.ValName): ValueRef = {
val (packageId, module) = decodeModuleRef(lfVal.getModule)
val name: DottedName =
if (lfVal.getNameCount == 0) {
getInternedDottedName(lfVal.getNameInternedId)
} else {
decodeSegments(ImmArray(lfVal.getNameList.asScala))
}
val name = decodeSegments(ImmArray(lfVal.getNameList.asScala))
ValueRef(packageId, QualifiedName(module, name))
}
private[this] def decodeTypeConName(lfTyConName: PLF.TypeConName): TypeConName = {
val (packageId, module) = decodeModuleRef(lfTyConName.getModule)
val name = decodeDottedName(lfTyConName.getName)
val name = eitherToParseError(
DottedName.fromSegments(lfTyConName.getName.getSegmentsList.asScala))
Identifier(packageId, QualifiedName(module, name))
}
@ -534,10 +380,7 @@ private[archive] class DecodeV1(minor: LV.Minor) extends Decode.OfPackage[PLF.Pa
private[this] def decodeExprBody(lfExpr: PLF.Expr, definition: String): Expr =
lfExpr.getSumCase match {
case PLF.Expr.SumCase.VAR =>
EVar(toName(lfExpr.getVar))
case PLF.Expr.SumCase.VAR_INTERNED_ID =>
EVar(getInternedName(lfExpr.getVarInternedId))
EVar(name(lfExpr.getVar))
case PLF.Expr.SumCase.VAL =>
EVal(decodeValName(lfExpr.getVal))
@ -567,36 +410,22 @@ private[archive] class DecodeV1(minor: LV.Minor) extends Decode.OfPackage[PLF.Pa
val recCon = lfExpr.getRecCon
ERecCon(
tycon = decodeTypeConApp(recCon.getTycon),
fields = ImmArray(recCon.getFieldsList.asScala).map(decodeFieldWithExpr(_, definition))
fields = ImmArray(recCon.getFieldsList.asScala).map(field =>
name(field.getField) -> decodeExpr(field.getExpr, definition))
)
case PLF.Expr.SumCase.REC_PROJ =>
val recProj = lfExpr.getRecProj
ERecProj(
tycon = decodeTypeConApp(recProj.getTycon),
field = recProj.getFieldCase match {
case PLF.Expr.RecProj.FieldCase.NAME =>
toName(recProj.getName)
case PLF.Expr.RecProj.FieldCase.INTERNED_ID =>
getInternedName(recProj.getInternedId)
case PLF.Expr.RecProj.FieldCase.FIELD_NOT_SET =>
throw ParseError("Expr.RecProj.FIELD_NOT_SET")
},
record = decodeExpr(recProj.getRecord, definition)
)
field = name(recProj.getField),
record = decodeExpr(recProj.getRecord, definition))
case PLF.Expr.SumCase.REC_UPD =>
val recUpd = lfExpr.getRecUpd
ERecUpd(
tycon = decodeTypeConApp(recUpd.getTycon),
field = (recUpd.getFieldCase match {
case PLF.Expr.RecUpd.FieldCase.NAME =>
toName(recUpd.getName)
case PLF.Expr.RecUpd.FieldCase.INTERNED_ID =>
getInternedName(recUpd.getInternedId)
case PLF.Expr.RecUpd.FieldCase.FIELD_NOT_SET =>
throw ParseError("Expr.RecUpd.FIELD_NOT_SET")
}),
field = name(recUpd.getField),
record = decodeExpr(recUpd.getRecord, definition),
update = decodeExpr(recUpd.getUpdate, definition)
)
@ -605,66 +434,34 @@ private[archive] class DecodeV1(minor: LV.Minor) extends Decode.OfPackage[PLF.Pa
val varCon = lfExpr.getVariantCon
EVariantCon(
decodeTypeConApp(varCon.getTycon),
varCon.getVariantConCase match {
case PLF.Expr.VariantCon.VariantConCase.NAME =>
toName(varCon.getName)
case PLF.Expr.VariantCon.VariantConCase.INTERNED_ID =>
getInternedName(varCon.getInternedId)
case PLF.Expr.VariantCon.VariantConCase.VARIANTCON_NOT_SET =>
throw ParseError("Expr.VariantCon.VARIANTCON_NOT_SET")
},
decodeExpr(varCon.getVariantArg, definition)
)
name(varCon.getVariantCon),
decodeExpr(varCon.getVariantArg, definition))
case PLF.Expr.SumCase.ENUM_CON =>
assertSince(LV.Features.enum, "Expr.Enum")
val enumCon = lfExpr.getEnumCon
EEnumCon(
decodeTypeConName(enumCon.getTycon),
enumCon.getEnumConCase match {
case PLF.Expr.EnumCon.EnumConCase.NAME =>
toName(enumCon.getName)
case PLF.Expr.EnumCon.EnumConCase.INTERNED_ID =>
getInternedName(enumCon.getInternedId)
case PLF.Expr.EnumCon.EnumConCase.ENUMCON_NOT_SET =>
throw ParseError("Expr.EnumCon.ENUMCON_NOT_SET")
}
name(enumCon.getEnumCon)
)
case PLF.Expr.SumCase.TUPLE_CON =>
val tupleCon = lfExpr.getTupleCon
ETupleCon(
ImmArray(tupleCon.getFieldsList.asScala).map(decodeFieldWithExpr(_, definition))
ImmArray(tupleCon.getFieldsList.asScala).map(field =>
name(field.getField) -> decodeExpr(field.getExpr, definition))
)
case PLF.Expr.SumCase.TUPLE_PROJ =>
val tupleProj = lfExpr.getTupleProj
ETupleProj(
tupleProj.getFieldCase match {
case PLF.Expr.TupleProj.FieldCase.NAME =>
toName(tupleProj.getName)
case PLF.Expr.TupleProj.FieldCase.INTERNED_ID =>
getInternedName(tupleProj.getInternedId)
case PLF.Expr.TupleProj.FieldCase.FIELD_NOT_SET =>
throw ParseError("Expr.TupleProj.FIELD_NOT_SET")
},
decodeExpr(tupleProj.getTuple, definition)
)
ETupleProj(name(tupleProj.getField), decodeExpr(tupleProj.getTuple, definition))
case PLF.Expr.SumCase.TUPLE_UPD =>
val tupleUpd = lfExpr.getTupleUpd
ETupleUpd(
field = tupleUpd.getFieldCase match {
case PLF.Expr.TupleUpd.FieldCase.NAME =>
toName(tupleUpd.getName)
case PLF.Expr.TupleUpd.FieldCase.INTERNED_ID =>
getInternedName(tupleUpd.getInternedId)
case PLF.Expr.TupleUpd.FieldCase.FIELD_NOT_SET =>
throw ParseError("Expr.TupleUpd.FIELD_NOT_SET")
},
field = name(tupleUpd.getField),
tuple = decodeExpr(tupleUpd.getTuple, definition),
update = decodeExpr(tupleUpd.getUpdate, definition)
)
update = decodeExpr(tupleUpd.getUpdate, definition))
case PLF.Expr.SumCase.APP =>
val app = lfExpr.getApp
@ -769,61 +566,19 @@ private[archive] class DecodeV1(minor: LV.Minor) extends Decode.OfPackage[PLF.Pa
val variant = lfCaseAlt.getVariant
CPVariant(
decodeTypeConName(variant.getCon),
variant.getVariantCase match {
case PLF.CaseAlt.Variant.VariantCase.VARIANT_NAME =>
toName(variant.getVariantName)
case PLF.CaseAlt.Variant.VariantCase.VARIANT_INTERNED_ID =>
getInternedName(variant.getVariantInternedId)
case PLF.CaseAlt.Variant.VariantCase.VARIANT_NOT_SET =>
throw ParseError("CaseAlt.Variant.VARIANT_NOT_SET")
},
variant.getBinderCase match {
case PLF.CaseAlt.Variant.BinderCase.BINDER_NAME =>
toName(variant.getBinderName)
case PLF.CaseAlt.Variant.BinderCase.BINDER_INTERNED_ID =>
getInternedName(variant.getBinderInternedId)
case PLF.CaseAlt.Variant.BinderCase.BINDER_NOT_SET =>
throw ParseError("CaseAlt.Variant.BINDER_NOT_SET")
}
)
name(variant.getVariant),
name(variant.getBinder))
case PLF.CaseAlt.SumCase.ENUM =>
assertSince(LV.Features.enum, "CaseAlt.Enum")
val enum = lfCaseAlt.getEnum
CPEnum(
decodeTypeConName(enum.getCon),
enum.getConstructorCase match {
case PLF.CaseAlt.Enum.ConstructorCase.NAME =>
toName(enum.getName)
case PLF.CaseAlt.Enum.ConstructorCase.INTERNED_ID =>
getInternedName(enum.getInternedId)
case PLF.CaseAlt.Enum.ConstructorCase.CONSTRUCTOR_NOT_SET =>
throw ParseError("CaseAlt.Enum.CONSTRUCTOR_NOT_SET")
}
)
CPEnum(decodeTypeConName(enum.getCon), name(enum.getConstructor))
case PLF.CaseAlt.SumCase.PRIM_CON =>
CPPrimCon(decodePrimCon(lfCaseAlt.getPrimCon))
case PLF.CaseAlt.SumCase.NIL =>
CPNil
case PLF.CaseAlt.SumCase.CONS =>
val cons = lfCaseAlt.getCons
CPCons(
cons.getVarHeadCase match {
case PLF.CaseAlt.Cons.VarHeadCase.VAR_HEAD_NAME =>
toName(cons.getVarHeadName)
case PLF.CaseAlt.Cons.VarHeadCase.VAR_HEAD_INTERNED_ID =>
getInternedName(cons.getVarHeadInternedId)
case PLF.CaseAlt.Cons.VarHeadCase.VARHEAD_NOT_SET =>
throw ParseError("CaseAlt.Cons.VARHEAD_NOT_SET")
},
cons.getVarTailCase match {
case PLF.CaseAlt.Cons.VarTailCase.VAR_TAIL_NAME =>
toName(cons.getVarTailName)
case PLF.CaseAlt.Cons.VarTailCase.VAR_TAIL_INTERNED_ID =>
getInternedName(cons.getVarTailInternedId)
case PLF.CaseAlt.Cons.VarTailCase.VARTAIL_NOT_SET =>
throw ParseError("CaseAlt.Cons.VARTAIL_NOT_SET")
}
)
CPCons(name(cons.getVarHead), name(cons.getVarTail))
case PLF.CaseAlt.SumCase.OPTIONAL_NONE =>
assertSince(LV.Features.optional, "CaseAlt.OptionalNone")
@ -831,14 +586,7 @@ private[archive] class DecodeV1(minor: LV.Minor) extends Decode.OfPackage[PLF.Pa
case PLF.CaseAlt.SumCase.OPTIONAL_SOME =>
assertSince(LV.Features.optional, "CaseAlt.OptionalSome")
CPSome(lfCaseAlt.getOptionalSome.getVarBodyCase match {
case PLF.CaseAlt.OptionalSome.VarBodyCase.NAME =>
toName(lfCaseAlt.getOptionalSome.getName)
case PLF.CaseAlt.OptionalSome.VarBodyCase.INTERNED_ID =>
getInternedName(lfCaseAlt.getOptionalSome.getInternedId)
case PLF.CaseAlt.OptionalSome.VarBodyCase.VARBODY_NOT_SET =>
throw ParseError("CaseAlt.OptionalSome.VARBODY_NOT_SET")
})
CPSome(name(lfCaseAlt.getOptionalSome.getVarBody))
case PLF.CaseAlt.SumCase.SUM_NOT_SET =>
throw ParseError("CaseAlt.SUM_NOT_SET")
@ -878,14 +626,7 @@ private[archive] class DecodeV1(minor: LV.Minor) extends Decode.OfPackage[PLF.Pa
val exercise = lfUpdate.getExercise
UpdateExercise(
templateId = decodeTypeConName(exercise.getTemplate),
choice = exercise.getChoiceCase match {
case PLF.Update.Exercise.ChoiceCase.NAME =>
toName(exercise.getName)
case PLF.Update.Exercise.ChoiceCase.INTERNED_ID =>
getInternedName(exercise.getInternedId)
case PLF.Update.Exercise.ChoiceCase.CHOICE_NOT_SET =>
throw ParseError("Update.Exercise.CHOICE_NOT_SET")
},
choice = name(exercise.getChoice),
cidE = decodeExpr(exercise.getCid, definition),
actorsE =
if (exercise.hasActor)
@ -969,15 +710,7 @@ private[archive] class DecodeV1(minor: LV.Minor) extends Decode.OfPackage[PLF.Pa
private[this] def decodeTypeVarWithKind(
lfTypeVarWithKind: PLF.TypeVarWithKind): (TypeVarName, Kind) =
(lfTypeVarWithKind.getVarCase match {
case PLF.TypeVarWithKind.VarCase.NAME =>
toName(lfTypeVarWithKind.getName)
case PLF.TypeVarWithKind.VarCase.INTERNED_ID =>
getInternedName(lfTypeVarWithKind.getInternedId)
case PLF.TypeVarWithKind.VarCase.VAR_NOT_SET =>
throw ParseError("TypeVarWithKind.VAR_NOT_SET")
}) -> decodeKind(lfTypeVarWithKind.getKind)
name(lfTypeVarWithKind.getVar) -> decodeKind(lfTypeVarWithKind.getKind)
private[this] def decodeBinding(lfBinding: PLF.Binding, definition: String): Binding = {
val (binder, typ) = decodeBinder(lfBinding.getBinder)
@ -985,14 +718,7 @@ private[archive] class DecodeV1(minor: LV.Minor) extends Decode.OfPackage[PLF.Pa
}
private[this] def decodeBinder(lfBinder: PLF.VarWithType): (ExprVarName, Type) =
(lfBinder.getVarCase match {
case PLF.VarWithType.VarCase.NAME =>
toName(lfBinder.getName)
case PLF.VarWithType.VarCase.INTERNED_ID =>
getInternedName(lfBinder.getInternedId)
case PLF.VarWithType.VarCase.VAR_NOT_SET =>
throw ParseError("VarWithType.VAR_NOT_SET")
}) -> decodeType(lfBinder.getType)
name(lfBinder.getVar) -> decodeType(lfBinder.getType)
private[this] def decodePrimCon(lfPrimCon: PLF.PrimCon): PrimCon =
lfPrimCon match {
@ -1011,51 +737,50 @@ private[archive] class DecodeV1(minor: LV.Minor) extends Decode.OfPackage[PLF.Pa
PLInt64(lfPrimLit.getInt64)
case PLF.PrimLit.SumCase.DECIMAL =>
assertUntil(LV.Features.numeric, "PrimLit.decimal")
toDecimalLiteral(lfPrimLit.getDecimal)
Decimal
.fromString(lfPrimLit.getDecimal)
.flatMap(Numeric.fromBigDecimal(Decimal.scale, _))
.fold(e => throw ParseError("error parsing decimal: " + e), PLNumeric)
case PLF.PrimLit.SumCase.NUMERIC =>
assertSince(LV.Features.numeric, "PrimLit.numeric")
toNumericLiteral(lfPrimLit.getNumeric)
Numeric
.fromString(lfPrimLit.getNumeric)
.fold(e => throw ParseError("error parsing numeric: " + e), PLNumeric)
case PLF.PrimLit.SumCase.TEXT =>
PLText(lfPrimLit.getText)
case PLF.PrimLit.SumCase.PARTY =>
toPartyLiteral(lfPrimLit.getParty)
val p = Party
.fromString(lfPrimLit.getParty)
.getOrElse(throw ParseError(s"invalid party '${lfPrimLit.getParty}'"))
PLParty(p)
case PLF.PrimLit.SumCase.TIMESTAMP =>
val t = Time.Timestamp.fromLong(lfPrimLit.getTimestamp)
t.fold(e => throw ParseError("error decoding timestamp: " + e), PLTimestamp)
case PLF.PrimLit.SumCase.DATE =>
val d = Time.Date.fromDaysSinceEpoch(lfPrimLit.getDate)
d.fold(e => throw ParseError("error decoding date: " + e), PLDate)
case PLF.PrimLit.SumCase.TEXT_INTERNED_ID =>
getInternedText(lfPrimLit.getTextInternedId)
case PLF.PrimLit.SumCase.DECIMAL_INTERNED_ID =>
assertUntil(LV.Features.numeric, "PrimLit.decimal")
getInternedDecimal(lfPrimLit.getDecimalInternedId)
case PLF.PrimLit.SumCase.NUMERIC_INTERNED_ID =>
assertSince(LV.Features.numeric, "PrimLit.numeric")
getInternedNumeric(lfPrimLit.getNumericInternedId)
case PLF.PrimLit.SumCase.PARTY_INTERNED_ID =>
getInternedParty(lfPrimLit.getPartyInternedId)
case PLF.PrimLit.SumCase.SUM_NOT_SET =>
throw ParseError("PrimLit.SUM_NOT_SET")
case unknown =>
throw ParseError("Unknown PrimLit: " + unknown.toString)
}
}
private def versionIsOlderThan(minVersion: LV): Boolean =
LV.ordering.lt(languageVersion, minVersion)
private def assertUntil(maxVersion: LV, description: => String): Unit =
private def assertUntil(maxVersion: LV, description: String): Unit =
if (!versionIsOlderThan(maxVersion))
throw ParseError(s"$description is not supported by DAML-LF 1.$minor")
private def assertSince(minVersion: LV, description: => String): Unit =
private def assertSince(minVersion: LV, description: String): Unit =
if (versionIsOlderThan(minVersion))
throw ParseError(s"$description is not supported by DAML-LF 1.$minor")
private def assertNonEmpty(s: Seq[_], description: => String): Unit =
private def assertNonEmpty(s: Seq[_], description: String): Unit =
if (s.isEmpty) throw ParseError(s"Unexpected empty $description")
private def assertEmpty(s: Seq[_], description: => String): Unit =
private def assertEmpty(s: Seq[_], description: String): Unit =
if (s.nonEmpty) throw ParseError(s"Unexpected non-empty $description")
}
private[lf] object DecodeV1 {
@ -1064,22 +789,6 @@ private[lf] object DecodeV1 {
private def ntimes[A](n: Int, f: A => A, a: A): A =
if (n == 0) a else ntimes(n - 1, f, f(a))
private def eitherToParseError[A](x: Either[String, A]): A =
x.fold(err => throw new ParseError(err), identity)
private def toName(s: String): Name = eitherToParseError(Name.fromString(s))
private def toPackageId(s: String): PackageId = eitherToParseError(PackageId.fromString(s))
private def toNumericLiteral(s: String): PrimLit =
PLNumeric(eitherToParseError(Numeric.fromString(s)))
private def toDecimalLiteral(s: String): PLNumeric =
PLNumeric(eitherToParseError(Decimal.fromString(s)))
private def toPartyLiteral(s: String): PLParty =
PLParty(eitherToParseError(Party.fromString(s)))
case class BuiltinTypeInfo(
proto: PLF.PrimType,
bTyp: BuiltinType,

View File

@ -1,43 +0,0 @@
// Copyright (c) 2019 The DAML Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package com.digitalasset.daml.lf.archive
import java.io.File
import java.util.concurrent.TimeUnit
import com.digitalasset.daml.lf.data.Ref
import com.digitalasset.daml.lf.language.Ast
/**
* Test application for decoding DARs. Useful for testing decoder performance and memory usage.
*/
object DecodeMain extends App {
if (args.length != 1) {
println("usage: decode <dar file>")
System.exit(1)
}
def toMillis(a: Long, b: Long) = TimeUnit.NANOSECONDS.toMillis(b - a)
(1 to 3).foreach { _ =>
val t0 = System.nanoTime()
val archives =
DarReader().readArchiveFromFile(new File(args(0))).get
val t1 = System.nanoTime()
val _: (Ref.PackageId, Ast.Package) =
Decode.readArchivePayload(archives.main._1, archives.main._2)
val t2 = System.nanoTime()
println(s"parseFrom in ${toMillis(t0, t1)}ms, decoded in ${toMillis(t1, t2)}ms.")
// Wait a while to allow for running e.g. jmap -heap etc.
//val pid = Integer.parseInt(new File("/proc/self").getCanonicalFile.getName)
//println(s"sleeping 5s, pid is $pid.")
//Thread.sleep(5000)
System.gc()
}
}

View File

@ -49,7 +49,6 @@ class DecodeV1Spec
.ModuleDecoder(
Ref.PackageId.assertFromString("noPkgId"),
ImmArray.empty.toSeq,
ImmArray.empty.toSeq,
dummyModule,
onlySerializableDataDefs = false)
@ -509,7 +508,7 @@ class DecodeV1Spec
pr.getInternedId
}
.value
dalf1.getInternedStringsList.asScala.lift(iix.toInt).value
dalf1.getInternedPackageIdsList.asScala.lift(iix.toInt).value
}
"take a dalf with interned IDs" in {

View File

@ -141,17 +141,13 @@ private[digitalasset] class EncodeV1(val minor: LV.Minor) {
@inline
private implicit def encodeTypeBinder(binder: (String, Kind)): PLF.TypeVarWithKind = {
val (varName, kind) = binder
PLF.TypeVarWithKind
.newBuilder()
.setName(varName)
.setKind(kind)
.build()
PLF.TypeVarWithKind.newBuilder().setVar(varName).setKind(kind).build()
}
@inline
private implicit def encodeFieldWithType(nameWithType: (String, Type)): PLF.FieldWithType = {
val (name, typ) = nameWithType
PLF.FieldWithType.newBuilder().setName(name).setType(typ).build()
PLF.FieldWithType.newBuilder().setField(name).setType(typ).build()
}
private val TForalls = RightRecMatcher[(TypeVarName, Kind), Type]({
@ -181,7 +177,7 @@ private[digitalasset] class EncodeV1(val minor: LV.Minor) {
typ match {
case TVar(varName) =>
builder.setVar(
PLF.Type.Var.newBuilder().setVarName(varName).accumulateLeft(args)(_ addArgs _))
PLF.Type.Var.newBuilder().setVar(varName).accumulateLeft(args)(_ addArgs _))
case TNat(n) =>
assertSince(LV.Features.numeric, "Type.TNat")
builder.setNat(n.toLong)
@ -240,13 +236,13 @@ private[digitalasset] class EncodeV1(val minor: LV.Minor) {
@inline
private implicit def encodeFieldWithExpr(fieldWithExpr: (Name, Expr)): PLF.FieldWithExpr = {
val (name, expr) = fieldWithExpr
PLF.FieldWithExpr.newBuilder().setName(name).setExpr(expr).build()
PLF.FieldWithExpr.newBuilder().setField(name).setExpr(expr).build()
}
@inline
private implicit def encodeExprBinder(binder: (String, Type)): PLF.VarWithType = {
val (varName, typ) = binder
PLF.VarWithType.newBuilder().setName(varName).setType(typ).build()
PLF.VarWithType.newBuilder().setVar(varName).setType(typ).build()
}
private implicit def encodeLocation(loc: Location): PLF.Location = {
@ -298,7 +294,7 @@ private[digitalasset] class EncodeV1(val minor: LV.Minor) {
PLF.Update.Exercise
.newBuilder()
.setTemplate(templateId)
.setName(choice)
.setChoice(choice)
.setCid(cid)
.accumulateLeft(actors)(_ setActor _)
.setArg(arg)
@ -373,26 +369,22 @@ private[digitalasset] class EncodeV1(val minor: LV.Minor) {
alt.pattern match {
case CPVariant(tyCon, variant, binder) =>
builder.setVariant(
PLF.CaseAlt.Variant
.newBuilder()
.setCon(tyCon)
.setVariantName(variant)
.setBinderName(binder))
PLF.CaseAlt.Variant.newBuilder().setCon(tyCon).setVariant(variant).setBinder(binder))
case CPEnum(tyCon, con) =>
assertSince(LV.Features.enum, "CaseAlt.Enum")
builder.setEnum(PLF.CaseAlt.Enum.newBuilder().setCon(tyCon).setName(con))
builder.setEnum(PLF.CaseAlt.Enum.newBuilder().setCon(tyCon).setConstructor(con))
case CPPrimCon(primCon) =>
builder.setPrimCon(primCon)
case CPNil =>
builder.setNil(unit)
case CPCons(head, tail) =>
builder.setCons(PLF.CaseAlt.Cons.newBuilder().setVarHeadName(head).setVarTailName(tail))
builder.setCons(PLF.CaseAlt.Cons.newBuilder().setVarHead(head).setVarTail(tail))
case CPNone =>
assertSince(LV.Features.optional, "CaseAlt.OptionalNone")
builder.setOptionalNone(unit)
case CPSome(x) =>
assertSince(LV.Features.optional, "CaseAlt.OptionalSome")
builder.setOptionalSome(PLF.CaseAlt.OptionalSome.newBuilder().setName(x))
builder.setOptionalSome(PLF.CaseAlt.OptionalSome.newBuilder().setVarBody(x))
case CPDefault =>
builder.setDefault(unit)
}
@ -437,13 +429,13 @@ private[digitalasset] class EncodeV1(val minor: LV.Minor) {
PLF.Expr.RecCon.newBuilder().setTycon(tyCon).accumulateLeft(fields)(_ addFields _))
case ERecProj(tycon, field, expr) =>
newBuilder.setRecProj(
PLF.Expr.RecProj.newBuilder().setTycon(tycon).setName(field).setRecord(expr))
PLF.Expr.RecProj.newBuilder().setTycon(tycon).setField(field).setRecord(expr))
case ERecUpd(tyCon, field, expr, update) =>
newBuilder.setRecUpd(
PLF.Expr.RecUpd
.newBuilder()
.setTycon(tyCon)
.setName(field)
.setField(field)
.setRecord(expr)
.setUpdate(update))
case EVariantCon(tycon, variant, arg) =>
@ -451,19 +443,19 @@ private[digitalasset] class EncodeV1(val minor: LV.Minor) {
PLF.Expr.VariantCon
.newBuilder()
.setTycon(tycon)
.setName(variant)
.setVariantCon(variant)
.setVariantArg(arg))
case EEnumCon(tyCon, con) =>
assertSince(LV.Features.enum, "Expr.Enum")
newBuilder.setEnumCon(PLF.Expr.EnumCon.newBuilder().setTycon(tyCon).setName(con))
newBuilder.setEnumCon(PLF.Expr.EnumCon.newBuilder().setTycon(tyCon).setEnumCon(con))
case ETupleCon(fields) =>
newBuilder.setTupleCon(
PLF.Expr.TupleCon.newBuilder().accumulateLeft(fields)(_ addFields _))
case ETupleProj(field, expr) =>
newBuilder.setTupleProj(PLF.Expr.TupleProj.newBuilder().setName(field).setTuple(expr))
newBuilder.setTupleProj(PLF.Expr.TupleProj.newBuilder().setField(field).setTuple(expr))
case ETupleUpd(field, tuple, update) =>
newBuilder.setTupleUpd(
PLF.Expr.TupleUpd.newBuilder().setName(field).setTuple(tuple).setUpdate(update))
PLF.Expr.TupleUpd.newBuilder().setField(field).setTuple(tuple).setUpdate(update))
case EApps(fun, args) =>
newBuilder.setApp(PLF.Expr.App.newBuilder().setFun(fun).accumulateLeft(args)(_ addArgs _))
case ETyApps(expr, typs1) =>
@ -559,13 +551,13 @@ private[digitalasset] class EncodeV1(val minor: LV.Minor) {
val (name, choice) = nameWithChoice
PLF.TemplateChoice
.newBuilder()
.setChoiceName(name)
.setName(name)
.setConsuming(choice.consuming)
.setControllers(choice.controllers)
.setArgBinder(choice.argBinder._1.getOrElse("") -> choice.argBinder._2)
.setRetType(choice.returnType)
.setUpdate(choice.update)
.setSelfBinderName(choice.selfBinder)
.setSelfBinder(choice.selfBinder)
.build()
}
@ -583,7 +575,7 @@ private[digitalasset] class EncodeV1(val minor: LV.Minor) {
PLF.DefTemplate
.newBuilder()
.setTycon(name)
.setParamName(template.param)
.setParam(template.param)
.setPrecond(template.precond)
.setSignatories(template.signatories)
.setAgreement(template.agreementText)

View File

@ -17,15 +17,15 @@ sealed abstract class LanguageMajorVersion(
with Product
with Serializable {
final val maxSupportedStableMinorVersion: LanguageMinorVersion.Stable =
val maxSupportedStableMinorVersion: LanguageMinorVersion.Stable =
LanguageMinorVersion.Stable(stableAscending.last)
// do *not* use implicitly unless type `LanguageMinorVersion` becomes
// indexed by the enclosing major version's singleton type --SC
final val minorVersionOrdering: Ordering[LanguageMinorVersion] =
final def minorVersionOrdering: Ordering[LanguageMinorVersion] =
Ordering.by(acceptedVersions.zipWithIndex.toMap)
final val supportedMinorVersions: List[LanguageMinorVersion] =
val supportedMinorVersions: List[LanguageMinorVersion] =
acceptedVersions
final def supportsMinorVersion(fromLFFile: String): Boolean =

View File

@ -23,10 +23,10 @@ object LanguageVersion {
private[lf] def apply(major: LanguageMajorVersion, minor: String): LanguageVersion =
apply(major, Minor fromProtoIdentifier minor)
val default: LanguageVersion =
def default: LanguageVersion =
defaultV1
final val ordering: Ordering[LanguageVersion] =
def ordering: Ordering[LanguageVersion] =
(left, right) =>
(left, right) match {
case (LanguageVersion(leftMajor, leftMinor), LanguageVersion(rightMajor, rightMinor))
@ -54,9 +54,7 @@ object LanguageVersion {
val coerceContractId = v1_5
val textPacking = v1_6
val enum = v1_6
val internedPackageId = v1_6
val internedStrings = v1_dev
val internedDottedNames = v1_dev
val internedIds = v1_6
val numeric = v1_dev
val anyTemplate = v1_dev