diff --git a/compiler/src/AtomFolding.hs b/compiler/src/AtomFolding.hs index 1aad7ba8..ffe51a4c 100644 --- a/compiler/src/AtomFolding.hs +++ b/compiler/src/AtomFolding.hs @@ -2,19 +2,27 @@ module AtomFolding ( visitProg ) where import Basics import Direct -import Data.Maybe import Control.Monad +import Data.List (find, any) visitProg :: Prog -> Prog -visitProg (Prog imports (Atoms atms) tm) = - Prog imports (Atoms atms) (visitTerm atms tm) +visitProg (Prog imports (DataTypes datatypes) tm) = + let tcs = concat $ map snd datatypes + in Prog imports (DataTypes datatypes) (visitTerm tcs tm) -visitTerm :: [AtomName] -> Term -> Term +visitTerm :: [TypeConstructor] -> Term -> Term visitTerm atms (Lit lit) = Lit lit visitTerm atms (Var nm) = - if (elem nm atms) - then Lit (LAtom nm) - else Var nm + let tag = "tag" + value = "value" + var = "v" + in case find (\x -> (fst x) == nm) atms of + Nothing -> Var nm + Just (t, []) -> Record [(tag, Just (Lit (LString nm)))] True -- Convert atom into a tagged record + Just (t, _) -> + Abs (Lambda [VarPattern var] (Record [(tag, Just (Lit (LString nm))) + , (value, Just (Var var)) + ] True)) visitTerm atms (Abs lam) = Abs (visitLambda atms lam) visitTerm atms (Hnd (Handler pat maybePat maybeTerm term)) = @@ -38,7 +46,7 @@ visitTerm atms (If t1 t2 t3) = If (visitTerm atms t1) (visitTerm atms t2) (visitTerm atms t3) visitTerm atms (Tuple terms) = Tuple (map (visitTerm atms) terms) -visitTerm atms (Record fields) = Record (visitFields atms fields) +visitTerm atms (Record fields tag) = Record (visitFields atms fields) tag visitTerm atms (WithRecord e fields) = WithRecord (visitTerm atms e) (visitFields atms fields) visitTerm atms (ProjField t f) = @@ -63,10 +71,10 @@ visitFields atms fs = map visitField fs where visitField (f, Nothing) = (f, Nothing) visitField (f, Just t) = (f, Just (visitTerm atms t)) -visitPattern :: [AtomName] -> DeclPattern -> DeclPattern +visitPattern :: [TypeConstructor] -> DeclPattern -> DeclPattern visitPattern atms pat@(VarPattern nm) = - if (elem nm atms) - then ValPattern (LAtom nm) + if any (\x -> x == (nm, [])) atms + then RecordPattern [("tag", Just (ValPattern (LString nm)))] ExactMatch -- Convert atom match into a record match else pat visitPattern _ pat@(ValPattern _) = pat visitPattern atms (AtPattern p l) = AtPattern (visitPattern atms p) l @@ -77,7 +85,12 @@ visitPattern atms (ListPattern pats) = ListPattern (map (visitPattern atms) pats visitPattern atms (RecordPattern fields mode) = RecordPattern (map visitField fields) mode where visitField pat@(_, Nothing) = pat visitField (f, Just p) = (f, Just (visitPattern atms p)) +visitPattern atms (DataTypePattern nm pat) = + RecordPattern [("tag", Just (ValPattern (LString nm))) + ,("value", Just (visitPattern atms pat))] ExactMatch + -visitLambda :: [AtomName] -> Lambda -> Lambda +visitLambda :: [TypeConstructor] -> Lambda -> Lambda visitLambda atms (Lambda pats term) = (Lambda (map (visitPattern atms) pats) (visitTerm atms term)) + diff --git a/compiler/src/Basics.hs b/compiler/src/Basics.hs index 622e31a0..067dee4c 100644 --- a/compiler/src/Basics.hs +++ b/compiler/src/Basics.hs @@ -10,7 +10,12 @@ import Data.Serialize (Serialize) type VarName = String type AtomName = String +type DataTypeName = String +type TypeConstructorName = String +type TypeConstructor = (TypeConstructorName, [VarName]) +type DataTypeDef = (DataTypeName, [TypeConstructor]) type FieldName = String +type ADTTag = Bool -- | Eq and Neq: deep equality check on the two parameters, including the types (any type inequality results in false being returned). data BinOp = Plus | Minus | Mult | Div | Mod | Eq | Neq | Le | Lt | Ge | Gt | And | Or | RaisedTo | FlowsTo | Concat| IntDiv | BinAnd | BinOr | BinXor | BinShiftLeft | BinShiftRight | BinZeroShiftRight | HasField | LatticeJoin | LatticeMeet diff --git a/compiler/src/CPSOpt.hs b/compiler/src/CPSOpt.hs index de68c0d8..b7028ed3 100644 --- a/compiler/src/CPSOpt.hs +++ b/compiler/src/CPSOpt.hs @@ -78,7 +78,7 @@ instance Substitutable SimpleTerm where Bin op v1 v2 -> Bin op (fwd v1) (fwd v2) Un op v -> Un op (fwd v) Tuple vs -> Tuple (map fwd vs) - Record fields -> Record $ fwdFields fields + Record fields tag -> Record (fwdFields fields) tag WithRecord x fields -> WithRecord (fwd x) $ fwdFields fields ProjField x f -> ProjField (fwd x) f ProjIdx x idx -> ProjIdx (fwd x) idx @@ -146,7 +146,7 @@ instance CensusCollectible SimpleTerm where Un _ v -> updateCensus v ValSimpleTerm sv -> updateCensus sv Tuple vs -> updateCensus vs - Record fs -> let (_,vs) = unzip fs in updateCensus vs + Record fs _ -> let (_,vs) = unzip fs in updateCensus vs WithRecord v fs -> updateCensus v >> (let (_,vs) = unzip fs in updateCensus vs ) ProjField v _ -> updateCensus v ProjIdx v _ -> updateCensus v @@ -256,14 +256,14 @@ censusInfo x = do fields x = do w <- look x case w of - St (Record xs) -> return xs + St (Record xs _) -> return xs St (WithRecord y ys) -> do xs <- fields y return $ xs ++ ys _ -> return [] -isRecordTerm (St (Record _)) = True +isRecordTerm (St (Record _ _)) = True isRecordTerm (St (WithRecord _ _ )) = True isRecordTerm _ = False @@ -327,14 +327,14 @@ simplifySimpleTerm t = -- TODO should write out all cases case (op,v) of (Basics.IsTuple, St (Tuple _)) -> _ret __trueLit - (Basics.IsTuple, St (Record _)) -> _ret __falseLit + (Basics.IsTuple, St (Record _ _)) -> _ret __falseLit (Basics.IsTuple, St (WithRecord _ _)) -> _ret __falseLit (Basics.IsTuple, St (List _)) -> _ret __falseLit (Basics.IsTuple, St (ListCons _ _)) -> _ret __falseLit (Basics.IsTuple, St (ValSimpleTerm _)) -> _ret __falseLit - (Basics.IsRecord, St (Record _)) -> _ret __trueLit + (Basics.IsRecord, St (Record _ _)) -> _ret __trueLit (Basics.IsRecord, St (WithRecord _ _)) -> _ret __trueLit (Basics.IsRecord, St (Tuple _)) -> _ret __falseLit (Basics.IsRecord, St (List _)) -> _ret __falseLit @@ -344,7 +344,7 @@ simplifySimpleTerm t = (Basics.IsList, St (List _)) -> _ret __trueLit (Basics.IsList, St (ListCons _ _)) -> _ret __trueLit - (Basics.IsList, St (Record _)) -> _ret __falseLit + (Basics.IsList, St (Record _ _)) -> _ret __falseLit (Basics.IsList, St (WithRecord _ _)) -> _ret __falseLit (Basics.IsList, St (Tuple _)) -> _ret __falseLit (Basics.IsList, St (ValSimpleTerm _)) -> _ret __falseLit @@ -410,7 +410,7 @@ failFree st = case st of Un _ _ -> False -- Unary operations can fail (e.g., head on empty list, arithmetic on non-numbers) ValSimpleTerm _ -> True Tuple _ -> True - Record _ -> True + Record _ _ -> True WithRecord _ _ -> True ProjField _ _ -> False -- Field projection can fail if field doesn't exist ProjIdx _ _ -> False -- Index projection can fail if index out of bounds @@ -546,4 +546,4 @@ iter kt = rewrite :: Prog -> Prog rewrite (Prog atoms kterm) = - Prog atoms (iter kterm) \ No newline at end of file + Prog atoms (iter kterm) diff --git a/compiler/src/CaseElimination.hs b/compiler/src/CaseElimination.hs index a50c1547..ecd753a9 100644 --- a/compiler/src/CaseElimination.hs +++ b/compiler/src/CaseElimination.hs @@ -31,8 +31,8 @@ trans mode (S.Prog imports atms tm) = do tm'' <- transTerm tm' return (T.Prog imports atms' tm'') -transAtoms :: S.Atoms -> Trans T.Atoms -transAtoms (S.Atoms atms) = return (T.Atoms atms) +transAtoms :: S.DataTypes -> Trans T.DataTypes +transAtoms (S.DataTypes atms) = return (T.DataTypes atms) transLit :: S.Lit -> T.Lit transLit (S.LInt n pi) = T.LInt n pi @@ -41,7 +41,7 @@ transLit (S.LLabel s) = T.LLabel s transLit (S.LDCLabel dc) = T.LDCLabel dc transLit (S.LUnit) = T.LUnit transLit (S.LBool b) = T.LBool b -transLit (S.LAtom a) = T.LAtom a +transLit (S.LDataType a) = T.LDataType a transLambda_aux :: S.Lambda -> ReaderT T.Term Trans Lambda @@ -260,9 +260,9 @@ transTerm (S.If t1 t2 t3) = do transTerm (S.Tuple tms) = do tms' <- mapM transTerm tms return (T.Tuple tms') -transTerm (S.Record fields) = do +transTerm (S.Record fields tag) = do fields' <- transFields fields - return (T.Record fields') + return (T.Record fields' tag) transTerm (S.WithRecord e fields) = do e' <- transTerm e fields' <- transFields fields @@ -302,4 +302,4 @@ transFields = mapM $ \case (f, Nothing) -> return (f, T.Var f) (f, Just t) -> do t' <- transTerm t - return (f, t') \ No newline at end of file + return (f, t') diff --git a/compiler/src/ClosureConv.hs b/compiler/src/ClosureConv.hs index d92d4024..ced98840 100644 --- a/compiler/src/ClosureConv.hs +++ b/compiler/src/ClosureConv.hs @@ -165,9 +165,9 @@ cpsToIR (CPS.LetSimple vname@(VN ident) st kt) = do CPS.Tuple lst -> do lst' <- transVars lst _assign (Tuple lst') - CPS.Record fields -> do + CPS.Record fields tag -> do fields' <- transFields fields - _assign (Record fields') + _assign (Record fields' tag) CPS.WithRecord x fields -> do x' <- transVar x fields' <- transFields fields diff --git a/compiler/src/Core.hs b/compiler/src/Core.hs index 72af085f..ef4b2a82 100644 --- a/compiler/src/Core.hs +++ b/compiler/src/Core.hs @@ -34,6 +34,7 @@ import ShowIndent import TroupePositionInfo import DCLabels +import Data.List (find) -------------------------------------------------- -- AST is the same as Direct, but lambda are unary (or nullary) @@ -57,7 +58,7 @@ data Lit | LDCLabel DCLabelExp | LUnit | LBool Bool - | LAtom AtomName + | LAtom TypeConstructorName deriving (Show, Generic) instance Serialize Lit instance Eq Lit where @@ -108,7 +109,7 @@ data Term | If Term Term Term | AssertElseError Term Term Term PosInf | Tuple [Term] - | Record Fields + | Record Fields ADTTag | WithRecord Term Fields | ProjField Term FieldName | ProjIdx Term Word @@ -157,8 +158,8 @@ lowerProg (D.Prog imports atms term) = Prog imports (trans atms) (lower term) -- the rest of the declarations in this part are not exported -trans :: D.Atoms -> Atoms -trans (D.Atoms atms) = Atoms atms +trans :: D.DataTypes -> Atoms +trans (D.DataTypes atms) = Atoms [] -- (concat $ map snd atms) lowerLam (D.Lambda vs t) = case vs of @@ -172,7 +173,7 @@ lowerLit (D.LLabel s) = LLabel s lowerLit (D.LDCLabel dc) = LDCLabel dc lowerLit D.LUnit = LUnit lowerLit (D.LBool b) = LBool b -lowerLit (D.LAtom n) = LAtom n +lowerLit (D.LDataType n) = LAtom n lower :: D.Term -> Core.Term lower (D.Lit l) = Lit (lowerLit l) @@ -199,7 +200,7 @@ lower (D.Let decls e) = lower (D.If e1 e2 e3) = If (lower e1) (lower e2) (lower e3) lower (D.AssertElseError e1 e2 e3 p) = AssertElseError (lower e1 ) (lower e2) (lower e3) p lower (D.Tuple terms) = Tuple (map lower terms) -lower (D.Record fields) = Record (map (\(f, t) -> (f, lower t)) fields) +lower (D.Record fields tag) = Record (map (\(f, t) -> (f, lower t)) fields) tag lower (D.WithRecord e fields) = WithRecord (lower e) (map (\(f, t) -> (f, lower t)) fields) lower (D.ProjField t f) = ProjField (lower t) f lower (D.ProjIdx t idx) = ProjIdx (lower t) idx @@ -333,8 +334,8 @@ rename (AssertElseError t1 t2 t3 p) m = do rename (Tuple terms) m = Tuple <$> mapM (flip rename m) terms -rename (Record fields) m = - Record <$> mapM renameField fields +rename (Record fields tag) m = + (\x -> Record x tag) <$> mapM renameField fields where renameField (f, t) = do t' <- rename t m return (f, t') @@ -448,7 +449,12 @@ ppTerm' (List ts) = PP.hcat $ PP.punctuate (text ",") (map (ppTerm 0) ts) -ppTerm' (Record fs) = PP.braces $ qqFields fs +ppTerm' (Record fs False) = PP.braces $ qqFields fs +ppTerm' (Record fs True) = -- We should not be able to git the "MissingADT" cases - 2025-08-08: ASL + case find (\x -> fst x == "tag") fs of + Just (_, Lit (LString nm)) -> text nm + Just _ -> text "MissingADT" + Nothing -> text "MissingADT" ppTerm' (WithRecord e fs) = PP.braces $ PP.hsep [ ppTerm 0 e, text "with", qqFields fs] diff --git a/compiler/src/Direct.hs b/compiler/src/Direct.hs index 6df77c46..c07b7949 100644 --- a/compiler/src/Direct.hs +++ b/compiler/src/Direct.hs @@ -5,8 +5,9 @@ module Direct ( Lambda (..) , Lit(..) , DeclPattern(..) , RecordPatternMode(..) - , AtomName - , Atoms(..) + , DataTypeName + , TypeConstructor + , DataTypes(..) , Prog(..) , Handler(..) , FieldName @@ -21,6 +22,7 @@ import Text.PrettyPrint.HughesPJ ( (<+>), ($$), text, hsep, vcat, nest) import ShowIndent import TroupePositionInfo +import Data.List (find) data PrimType @@ -48,7 +50,6 @@ type Guard = Maybe Term data Handler = Handler DeclPattern (Maybe DeclPattern) Guard Term deriving (Eq) - data DeclPattern = VarPattern VarName --SrcPosInf | ValPattern Lit @@ -58,6 +59,7 @@ data DeclPattern | ConsPattern DeclPattern DeclPattern --SrcPosInf | ListPattern [DeclPattern] --SrcPosInf | RecordPattern [(FieldName, Maybe DeclPattern)] RecordPatternMode + | DataTypePattern TypeConstructorName DeclPattern deriving (Eq) data RecordPatternMode = ExactMatch | WildcardMatch @@ -78,7 +80,7 @@ data Lit | LString String --SrcPosInf | LLabel String --SrcPosInf | LDCLabel DCLabelExp - | LAtom AtomName --SrcPosInf + | LDataType TypeConstructorName --SrcPosInf deriving (Eq, Show) @@ -94,7 +96,7 @@ data Term | Case Term [(DeclPattern, Term)] PosInf | If Term Term Term | Tuple [Term] - | Record Fields + | Record Fields ADTTag | WithRecord Term Fields | ProjField Term FieldName | ProjIdx Term Word @@ -106,11 +108,11 @@ data Term | Error Term deriving (Eq) -data Atoms = Atoms [AtomName] +data DataTypes = DataTypes [DataTypeDef] deriving (Eq, Show) -data Prog = Prog Imports Atoms Term +data Prog = Prog Imports DataTypes Term deriving (Eq, Show) @@ -130,13 +132,16 @@ instance ShowIndent Prog where ppProg :: Prog -> PP.Doc -ppProg (Prog (Imports imports) (Atoms atoms) term) = - let ppAtoms = - if null atoms - then PP.empty - else (text "datatype Atoms = ") <+> - (hsep $ PP.punctuate (text " |") (map text atoms)) - +ppProg (Prog (Imports imports) (DataTypes datatypes) term) = + let ppDataTypes = + if null datatypes + then PP.empty + else vcat $ flip map datatypes (\dt -> (text "datatype ") <+> + (text $ fst dt) <+> + (hsep $ PP.punctuate (text " |") (map ppConstructor $ snd dt))) + where ppConstructor (s, []) = text s + ppConstructor (s, x:[]) = text s <+> text " of " <+> text x + ppConstructor (s, xs) = text s <+> text " of " <+> PP.parens (hsep $ PP.punctuate (text " *") (map text xs)) ppImports = if null imports then PP.empty else @@ -144,7 +149,7 @@ ppProg (Prog (Imports imports) (Atoms atoms) term) = in (vcat $ (map ppLibName imports)) $$ PP.text "" in vcat [ ppImports - , ppAtoms + , ppDataTypes , ppTerm 0 term ] @@ -167,8 +172,14 @@ ppTerm' (Tuple ts) = PP.hcat $ PP.punctuate (text ",") (map (ppTerm 0) ts) -ppTerm' (Record fs) = - PP.braces $ qqFields fs +ppTerm' (Record fs False) = + PP.braces $ qqFields fs +ppTerm' (Record fs True) = -- We should not be able to git the "MissingADT" cases - 2025-08-08: ASL + case find (\x -> fst x == "tag") fs of + Just (_, Just (Lit (LString nm))) -> text nm + Just _ -> text "MissingADT" + Nothing -> text "MissingADT" + ppTerm' (WithRecord t fs) = PP.braces $ PP.hsep [ppTerm 0 t, text "with", qqFields fs] @@ -346,7 +357,7 @@ ppLit (LUnit ) = text "()" ppLit (LBool True ) = text "true" ppLit (LBool False) = text "false" ppLit (LLabel s ) = PP.braces (text s) -ppLit (LAtom s) = text s +ppLit (LDataType s) = text s termPrec :: Term -> Precedence diff --git a/compiler/src/DirectWOPats.hs b/compiler/src/DirectWOPats.hs index 3fd5e022..3487e405 100644 --- a/compiler/src/DirectWOPats.hs +++ b/compiler/src/DirectWOPats.hs @@ -3,8 +3,9 @@ module DirectWOPats ( Lambda (..) , Decl (..) , FunDecl (..) , Lit(..) - , AtomName - , Atoms(..) + , DataTypeName + , TypeConstructor + , DataTypes(..) , Prog(..) ) where @@ -16,6 +17,7 @@ import Text.PrettyPrint.HughesPJ ( import ShowIndent import DCLabels import TroupePositionInfo +import Data.List (find) data Decl = ValDecl VarName Term @@ -32,7 +34,7 @@ data Lit | LDCLabel DCLabelExp | LUnit | LBool Bool - | LAtom AtomName + | LDataType DataTypeName deriving (Eq, Show) @@ -51,7 +53,7 @@ data Term | If Term Term Term | AssertElseError Term Term Term PosInf | Tuple [Term] - | Record Fields + | Record Fields ADTTag | WithRecord Term Fields | ProjField Term FieldName | ProjIdx Term Word @@ -62,17 +64,13 @@ data Term | Error Term PosInf deriving (Eq) -data Atoms = Atoms [AtomName] +data DataTypes = DataTypes [DataTypeDef] deriving (Eq, Show) -data Prog = Prog Imports Atoms Term +data Prog = Prog Imports DataTypes Term deriving (Eq, Show) - - - - -------------------------------------------------- -- show is defined via pretty printing instance Show Term @@ -88,14 +86,18 @@ instance ShowIndent Prog where ppProg :: Prog -> PP.Doc -ppProg (Prog (Imports imports) (Atoms atoms) term) = - let ppAtoms = - if null atoms - then PP.empty - else (text "datatype Atoms = ") <+> - (hsep $ PP.punctuate (text " |") (map text atoms)) +ppProg (Prog (Imports imports) (DataTypes datatypes) term) = + let ppDataTypes = + if null datatypes + then PP.empty + else vcat $ flip map datatypes (\dt -> (text "datatype ") <+> + (text $ fst dt) <+> + (hsep $ PP.punctuate (text " |") (map ppConstructor $ snd dt))) + where ppConstructor (s, []) = text s + ppConstructor (s, x:[]) = text s <+> text " of " <+> text x + ppConstructor (s, xs) = text s <+> text " of " <+> PP.parens (hsep $ PP.punctuate (text " *") (map text xs)) ppImports = if null imports then PP.empty else text "<>\n" - in ppImports $$ ppAtoms $$ ppTerm 0 term + in ppImports $$ ppDataTypes $$ ppTerm 0 term ppTerm :: Precedence -> Term -> PP.Doc @@ -117,8 +119,13 @@ ppTerm' (Tuple ts) = PP.hcat $ PP.punctuate (text ",") (map (ppTerm 0) ts) -ppTerm' (Record fs) = +ppTerm' (Record fs False) = PP.braces $ qqFields fs +ppTerm' (Record fs True) = -- We should not be able to git the "MissingADT" cases - 2025-08-08: ASL + case find (\x -> fst x == "tag") fs of + Just (_, Lit (LString nm)) -> text nm + Just _ -> text "MissingADT" + Nothing -> text "MissingADT" ppTerm' (WithRecord e fs) = PP.braces $ PP.hsep [ ppTerm 0 e, text "with", qqFields fs ] @@ -223,9 +230,7 @@ ppLit (LDCLabel dc) = ppDCLabelExpLit dc ppLit LUnit = text "()" ppLit (LBool True) = text "true" ppLit (LBool False) = text "false" -ppLit (LAtom a) = text a - - +ppLit (LDataType a) = text a termPrec :: Term -> Precedence diff --git a/compiler/src/IR.hs b/compiler/src/IR.hs index 3a4f1a77..eb31c92b 100644 --- a/compiler/src/IR.hs +++ b/compiler/src/IR.hs @@ -53,7 +53,7 @@ data IRExpr = Bin Basics.BinOp VarAccess VarAccess | Un Basics.UnaryOp VarAccess | Tuple [VarAccess] - | Record Fields + | Record Fields Basics.ADTTag | WithRecord VarAccess Fields | ProjField VarAccess Basics.FieldName -- | Projection of a tuple field at the given index. The maximum allowed index @@ -416,7 +416,7 @@ ppIRExpr (Base v) = if v == "$$authorityarg" -- special casing; hack; 2018-10-18 then text v else text v <> text "$base" ppIRExpr (Lib (Basics.LibName l) v) = text l <> text "." <> text v -ppIRExpr (Record fields) = PP.braces $ qqFields fields +ppIRExpr (Record fields _) = PP.braces $ qqFields fields ppIRExpr (WithRecord x fields) = PP.braces $ PP.hsep[ ppId x, text "with", qqFields fields] ppIRExpr (ProjField x f) = (ppId x) PP.<> PP.text "." PP.<> PP.text f diff --git a/compiler/src/IR2Raw.hs b/compiler/src/IR2Raw.hs index 7f663c17..b5faf8bb 100644 --- a/compiler/src/IR2Raw.hs +++ b/compiler/src/IR2Raw.hs @@ -428,9 +428,9 @@ expr2rawComp = \case , cValLbl = PC , cTyLbl = PC } - IR.Record fs -> + IR.Record fs tag -> return SimpleRawComp - { cVal = RExpr $ Record fs + { cVal = RExpr $ Record fs tag , cValLbl = PC , cTyLbl = PC } diff --git a/compiler/src/IROpt.hs b/compiler/src/IROpt.hs index 610c1f24..f318b81b 100644 --- a/compiler/src/IROpt.hs +++ b/compiler/src/IROpt.hs @@ -38,7 +38,7 @@ instance Substitutable IRExpr where Bin op x y -> Bin op (apply subst x) (apply subst y) Un op x -> Un op (apply subst x) Tuple xs -> Tuple (map (apply subst) xs) - Record fields -> Record (_ff fields) + Record fields tag -> Record (_ff fields) tag WithRecord x fields -> WithRecord (apply subst x) (_ff fields) ProjField x f -> ProjField (apply subst x) f ProjIdx x idx -> ProjIdx (apply subst x) idx @@ -194,7 +194,7 @@ canFailOrHasEffects expr = case expr of -- These are generally safe Tuple _ -> False - Record _ -> False + Record _ _ -> False WithRecord _ _ -> False -- Assuming the base is a record List _ -> False Const _ -> False @@ -295,8 +295,8 @@ irExprPeval e = markUsed' x markUsed' y def_ - Record fields -> do mapM pevalField fields - r_ (RecordVal fields, e) + Record fields _tag -> do mapM pevalField fields + r_ (RecordVal fields, e) -- def_ where pevalField (_, x) = markUsed' x WithRecord r fields -> do diff --git a/compiler/src/Lexer.x b/compiler/src/Lexer.x index 5a205744..318ab1e4 100644 --- a/compiler/src/Lexer.x +++ b/compiler/src/Lexer.x @@ -102,7 +102,6 @@ tokens:- <0> andb { mkL TokenBinAnd } <0> orb { mkL TokenBinOr } <0> xorb { mkL TokenBinXor } -<0> Atoms { mkL TokenAtoms } <0> "#true" { mkL TokenDCTrue } <0> "#false" { mkL TokenDCFalse } "#root-confidentiality" { mkL TokenDCRootConf } @@ -196,7 +195,6 @@ data Token | TokenWhen | TokenWith | TokenDatatype - | TokenAtoms | TokenIntDiv | TokenMod | TokenFn diff --git a/compiler/src/Parser.y b/compiler/src/Parser.y index 3d67eb45..4eb26071 100644 --- a/compiler/src/Parser.y +++ b/compiler/src/Parser.y @@ -41,7 +41,6 @@ import Control.Monad.Except of { L _ TokenOf } import { L _ TokenImport } datatype { L _ TokenDatatype } - Atoms { L _ TokenAtoms } fn { L _ TokenFn } hn { L _ TokenHn } pini { L _ TokenPini } @@ -134,18 +133,24 @@ import Control.Monad.Except -Prog : ImportDecl AtomsDecl Expr { Prog (Imports $1) (Atoms $2) $3 } +Prog : ImportDecl DataTypeDecl Expr { Prog (Imports $1) (DataTypes $2) $3 } ImportDecl: import VAR ImportDecl { ((LibName (varTok $2), Nothing)): $3 } | { [] } -AtomsDecl : datatype Atoms '=' VAR AtomsList { (varTok $4):$5 } +DataTypeDecl : datatype VAR '=' DataTypeConstructor DataTypeList DataTypeDecl { (varTok $2, $4:$5):$6 } | {[]} + +DataTypeList : { [] } + | '|' DataTypeConstructor DataTypeList { $2: $3 } -AtomsList : { [] } - | '|' VAR AtomsList { (varTok $2): $3 } +DataTypeConstructor : VAR { (varTok $1, []) } + | VAR of DataTypeConstructorArgs { (varTok $1, $3) } +DataTypeConstructorArgs : VAR { (varTok $1):[] } + | VAR '*' DataTypeConstructorArgs { (varTok $1):$3 } + | '(' DataTypeConstructorArgs ')' { $2 } Expr: Form { $1 } | let pini Expr Decs in Expr end { Let (piniDecl $3 $4) $6 } @@ -190,6 +195,8 @@ Expr: Form { $1 } Match : Pattern '=>' Expr { [($1,$3)] } | Pattern '=>' Expr '|' Match { ($1,$3):$5 } + | DataTypePattern '=>' Expr { [($1,$3)] } + | DataTypePattern '=>' Expr '|' Match { ($1,$3):$5 } Form :: { Term } @@ -234,7 +241,7 @@ Atom : '(' Expr ')' { $2 } | VAR { Var (varTok $1) } | '(' ')' { Lit LUnit } | '(' CSExpr Expr ')' { Tuple (reverse ($3:$2)) } - | '{' '}' { Record [] } + | '{' '}' { Record [] False } | RecordExpr { $1 } | ListExpr { $1 } | Atom '.' VAR { ProjField $1 (varTok $3) } @@ -242,7 +249,7 @@ Atom : '(' Expr ')' { $2 } RecordExpr - : '{' RecordFields '}' { Record $2 } + : '{' RecordFields '}' { Record $2 False } | '{' Atom with RecordFields'}' { WithRecord $2 $4 } @@ -265,6 +272,8 @@ ListExpr : '[' ']' { List [] } CSExpr : Expr ',' { [$1] } | CSExpr Expr ',' { ($2:$1) } +DataTypePattern : VAR Pattern { DataTypePattern (varTok $1) $2 } + | VAR '(' DataTypePattern ')' { DataTypePattern (varTok $1) $3 } Pattern : VAR { VarPattern (varTok $1) } | '(' Pattern ')' { $2 } @@ -274,8 +283,7 @@ Pattern : VAR { VarPattern (varTok $1) } | Lit { ValPattern $1 } | '(' CSPattern Pattern ')' { TuplePattern (reverse ($3:$2)) } | FieldPattern { $1 } - | ListPattern { $1} - + | ListPattern { $1 } FieldPattern : '{' '}' { RecordPattern [] ExactMatch } @@ -334,8 +342,10 @@ OtherFunOption : '|' VAR FunArgs '=' Expr { Lambda $3 $5} FunDecl : fun VAR FunOptions { FunDecl (varTok $2) $3 (pos $2) } AndFunDecl : and VAR FunOptions { FunDecl (varTok $2) $3 (pos $2) } -FunArgs : Pattern { [$1] } - | Pattern FunArgs { $1 : $2} +FunArgs : Pattern { [$1] } + | Pattern FunArgs { $1 : $2} + | '(' DataTypePattern ')' { [$2] } + | '(' DataTypePattern ')' FunArgs { $2 : $4 } { diff --git a/compiler/src/Raw.hs b/compiler/src/Raw.hs index 3992b02f..afd449f5 100644 --- a/compiler/src/Raw.hs +++ b/compiler/src/Raw.hs @@ -104,7 +104,7 @@ data RawExpr | ProjectLVal VarAccess LValField | ProjectState MonComponent | Tuple [VarAccess] - | Record Fields + | Record Fields Basics.ADTTag | WithRecord RawVar Fields | ProjField RawVar Basics.FieldName | ProjIdx RawVar Word @@ -290,7 +290,7 @@ ppRawExpr (Const lit) = ppLit lit -- then text v -- else text v <> text "$base" ppRawExpr (Lib (Basics.LibName l) v) = text l <> text "." <> text v -ppRawExpr (Record fields) = PP.braces $ qqFields fields +ppRawExpr (Record fields _) = PP.braces $ qqFields fields ppRawExpr (WithRecord x fields) = PP.braces $ PP.hsep[ ppId x, text "with", qqFields fields] ppRawExpr (ProjField x f) = PP.text "ProjField" PP.<+> (ppId x) PP.<+> PP.text f diff --git a/compiler/src/RawDefUse.hs b/compiler/src/RawDefUse.hs index c6b7314f..39845dc3 100644 --- a/compiler/src/RawDefUse.hs +++ b/compiler/src/RawDefUse.hs @@ -197,7 +197,7 @@ instance Usable RawExpr b where Raw.ProjectLVal x _ -> use x Raw.ProjectState _ -> return () Raw.Tuple xs -> use xs - Raw.Record fields -> use (snd (unzip fields)) + Raw.Record fields _ -> use (snd (unzip fields)) Raw.WithRecord x fields -> do use x use (snd (unzip fields)) diff --git a/compiler/src/RawOpt.hs b/compiler/src/RawOpt.hs index 937dc8be..372b05fb 100644 --- a/compiler/src/RawOpt.hs +++ b/compiler/src/RawOpt.hs @@ -147,7 +147,7 @@ instance MarkUsed RawExpr where ProjectLVal x _ -> markUsed x ProjectState _ -> return () Tuple xs -> markUsed xs - Record fields -> markUsed (snd (unzip fields)) + Record fields _ -> markUsed (snd (unzip fields)) WithRecord x fields -> do markUsed x markUsed (snd (unzip fields)) @@ -244,7 +244,7 @@ guessType = \case Tuple _ -> Just RawTuple List _ -> Just RawList ListCons _ _ -> Just RawList - Record _ -> Just RawRecord + Record _ _ -> Just RawRecord WithRecord _ _ -> Just RawRecord -- Revision 2023-08: Added missing cases ProjField _ _ -> Nothing diff --git a/compiler/src/RetCPS.hs b/compiler/src/RetCPS.hs index 15cec1e4..ab9c3736 100644 --- a/compiler/src/RetCPS.hs +++ b/compiler/src/RetCPS.hs @@ -61,7 +61,7 @@ data SimpleTerm | Un UnaryOp VarName | ValSimpleTerm SVal | Tuple [VarName] - | Record Fields + | Record Fields Basics.ADTTag | WithRecord VarName Fields | ProjField VarName Basics.FieldName | ProjIdx VarName Word @@ -149,7 +149,7 @@ ppSimpleTerm (ListCons v1 v2) = PP.parens $ textv v1 PP.<> text "::" PP.<> textv v2 ppSimpleTerm (Base b) = text b PP.<> text "$base" ppSimpleTerm (Lib (Basics.LibName lib) v) = text lib <+> text "." <+> text v -ppSimpleTerm (Record fields) = PP.braces $ qqFields fields +ppSimpleTerm (Record fields _) = PP.braces $ qqFields fields ppSimpleTerm (WithRecord x fields) = PP.braces $ PP.hsep [textv x, text "with", qqFields fields] @@ -264,4 +264,4 @@ termPrec (LetFun _ _) = 0 --termPrec (Case _ _) = 0 termPrec (LetRet _ _) = 0 termPrec (AssertElseError _ _ _ _) = 0 -termPrec (Error _ _) = 0 \ No newline at end of file +termPrec (Error _ _) = 0 diff --git a/compiler/src/RetDFCPS.hs b/compiler/src/RetDFCPS.hs index b7b6e64f..5ff2c54f 100644 --- a/compiler/src/RetDFCPS.hs +++ b/compiler/src/RetDFCPS.hs @@ -134,8 +134,8 @@ transExplicit (Core.Tuple ts) = transTuple (t:ts) acc = trans t (\v -> transTuple ts (v:acc) ) -transExplicit (Core.Record fields) = - transFieldsExplicit Record fields +transExplicit (Core.Record fields tag) = + transFieldsExplicit (\fds -> Record fds tag) fields transExplicit (Core.WithRecord e fields) = trans e (\x -> transFieldsExplicit (WithRecord x) fields) @@ -268,7 +268,7 @@ trans (Core.Tuple ts) context = transTuple (t:ts) acc context = trans t (\v -> transTuple ts (v:acc) context) -trans (Core.Record fields) context = transFields Record fields context +trans (Core.Record fields tag) context = transFields (\fds -> Record fds tag) fields context trans (Core.WithRecord e fields) context = trans e (\ rr -> transFields (WithRecord rr) fields context ) diff --git a/compiler/src/RetFreeVars.hs b/compiler/src/RetFreeVars.hs index ff24c221..ade6ee4f 100644 --- a/compiler/src/RetFreeVars.hs +++ b/compiler/src/RetFreeVars.hs @@ -56,7 +56,7 @@ instance FreeNames SimpleTerm where freeVars (ListCons v1 v2) = FreeVars (Set.fromList [v1, v2]) freeVars (Base _ ) = FreeVars $ Set.empty freeVars (Lib _ _) = FreeVars $ Set.empty - freeVars (Record fields) = unionMany $ + freeVars (Record fields _) = unionMany $ map (\(f,x) -> FreeVars (if x == VN f then Set.empty else Set.singleton x)) fields freeVars (WithRecord x fields) = diff --git a/compiler/src/RetRewrite.hs b/compiler/src/RetRewrite.hs index cb18eb73..82d1e298 100644 --- a/compiler/src/RetRewrite.hs +++ b/compiler/src/RetRewrite.hs @@ -66,7 +66,7 @@ instance Substitutable SimpleTerm where Bin op v1 v2 -> Bin op (fwd v1) (fwd v2) Un op v -> Un op (fwd v) Tuple vs -> Tuple (map fwd vs) - Record fields -> Record $ fwdFields fields + Record fields tag -> Record (fwdFields fields) tag WithRecord x fields -> WithRecord (fwd x) $ fwdFields fields ProjField x f -> ProjField (fwd x) f ProjIdx x idx -> ProjIdx (fwd x) idx diff --git a/compiler/src/Stack2JS.hs b/compiler/src/Stack2JS.hs index 53647fa9..0dcf3789 100644 --- a/compiler/src/Stack2JS.hs +++ b/compiler/src/Stack2JS.hs @@ -591,10 +591,12 @@ instance ToJS RawExpr where Un op v -> return $ text (unaryOpToJS op) <> PP.parens (ppId v) Tuple vars -> return $ text "rt.mkTuple" <> PP.parens (PP.brackets $ PP.hsep $ PP.punctuate (text ",") (map ppVarName vars)) - Record fields -> do + Record fields tag -> do jsFields <- fieldsToJS fields return $ - PP.parens $ text "rt.mkRecord" <> PP.parens (PP.brackets $ PP.hsep $ jsFields ) + PP.parens $ text "rt.mkRecord" <> PP.parens (PP.hsep [PP.brackets $ PP.hsep $ jsFields, text ",", tagToJS tag]) + where tagToJS True = text "true" + tagToJS False = text "false" WithRecord r fields -> do jsFields <- fieldsToJS fields return $ diff --git a/compiler/test/ir2raw-test/testcases/Expr.hs b/compiler/test/ir2raw-test/testcases/Expr.hs index 1cc519ae..44e9a2b3 100644 --- a/compiler/test/ir2raw-test/testcases/Expr.hs +++ b/compiler/test/ir2raw-test/testcases/Expr.hs @@ -30,9 +30,9 @@ tcs = map (second mkP) $ , ("List0", List []) , ("List1", List [mkV "v"]) , ("List2", List [mkV "v1", mkV "v2"]) - , ("Record0", Record []) - , ("Record1", Record [("field1", mkV "v1")]) - , ("Record2", Record [("field1", mkV "v1"), ("field2", mkV "v2")]) + , ("Record0", Record [] False) + , ("Record1", Record [("field1", mkV "v1")] False) + , ("Record2", Record [("field1", mkV "v1"), ("field2", mkV "v2")] False) , ("ListCons", ListCons (mkV "x") (mkV "xs")) , ("WithRecord0", WithRecord (mkV "x") []) , ("WithRecord1", WithRecord (mkV "x") [("field1", mkV "v1")]) diff --git a/rt/src/Record.mts b/rt/src/Record.mts index 5d688e1a..51dae8df 100644 --- a/rt/src/Record.mts +++ b/rt/src/Record.mts @@ -10,21 +10,33 @@ export class Record implements TroupeAggregateRawValue { _troupeType = TroupeType.RECORD _dataLevel: Level = levels.TOP // TODO compute data level? __obj : Map + _isADT: boolean stringRep (omitLevels?: boolean, taintRef?: any) { - // return ("{" + listStringRep(this.toArray(), omitLevels, taintRef) + "}") - let s = "{" - let spaceOrComma = "" - for (let [k,v] of this.__obj.entries()) { - s += spaceOrComma + k + "=" + v.stringRep(omitLevels, taintRef) - spaceOrComma = ", " - } - s += "}" - return s + if (this._isADT) { + if (this.__obj.has("value")) { + let tag = this.__obj.get("tag").val.toString() + let val = this.__obj.get("value").stringRep(omitLevels, taintRef) + return "(" + tag + " " + "(" + val + ")" + ")" + } else { + return this.__obj.get("tag").val.toString() + } + } else { + // return ("{" + listStringRep(this.toArray(), omitLevels, taintRef) + "}") + let s = "{" + let spaceOrComma = "" + for (let [k,v] of this.__obj.entries()) { + s += spaceOrComma + k + "=" + v.stringRep(omitLevels, taintRef) + spaceOrComma = ", " + } + s += "}" + return s + } } - constructor(fields: Iterable) { + constructor(fields: Iterable, isADT: boolean) { this.__obj = new Map (fields) + this._isADT = isADT } hasField (fieldName:string):boolean { @@ -39,13 +51,13 @@ export class Record implements TroupeAggregateRawValue { return this._dataLevel } - static mkRecord(fields: Iterable): Record { - return new Record(fields) + static mkRecord(fields: Iterable, isADT): Record { + return new Record(fields, isADT) } static mkWithRecord(r: Record, fields: ConcatArray<[string, LVal]>): Record { let a = Array.from(r.__obj) let b = a.concat(fields) - return new Record(b) + return new Record(b, false) } } diff --git a/rt/src/deserialize.mts b/rt/src/deserialize.mts index 2c194875..78b57b2d 100644 --- a/rt/src/deserialize.mts +++ b/rt/src/deserialize.mts @@ -243,10 +243,10 @@ function constructCurrent(compilerOutput: string) { case Ty.TroupeType.RECORD: // for reords, the serialization format is [[key, value_json], ...] let a = []; - for (let i = 0; i < obj.length; i++) { - a.push ([ obj[i][0], mkValue(obj[i][1]) ]) + for (let i = 0; i < obj.fields.length; i++) { + a.push ([ obj.fields[i][0], mkValue(obj.fields[i][1]) ]) } - return Record.mkRecord(a); + return Record.mkRecord(a, obj.isADT); // 2025-08-08 ASL: This is a place holder case Ty.TroupeType.LIST: return mkList(deserializeArray(obj)) case Ty.TroupeType.TUPLE: diff --git a/rt/src/runtimeMonitored.mts b/rt/src/runtimeMonitored.mts index 1c54578c..4a319a1e 100644 --- a/rt/src/runtimeMonitored.mts +++ b/rt/src/runtimeMonitored.mts @@ -510,7 +510,7 @@ export async function start(f) { if (__p2pRunning) { let service_arg = new LVal ( new Record([ ["authority", mainAuthority], - ["options", __unit]]), + ["options", __unit]], false), levels.BOT); __sched.scheduleNewThreadAtLevel(__service['service'] , service_arg diff --git a/rt/src/serialize.mts b/rt/src/serialize.mts index 75c9ee77..93725f53 100644 --- a/rt/src/serialize.mts +++ b/rt/src/serialize.mts @@ -72,9 +72,9 @@ export function serialize(w:LVal, pclev:Level) { switch (_tt) { case Ty.TroupeType.RECORD: - jsonObj = []; + jsonObj = { fields: [], isADT: x._isADT }; for (let [k,v] of x.__obj.entries()) { - jsonObj.push ([k, walk(v)]) + jsonObj.fields.push ([k, walk(v)]) } break; case Ty.TroupeType.LIST: diff --git a/tests/rt/pos/core/adt-arith.golden b/tests/rt/pos/core/adt-arith.golden new file mode 100644 index 00000000..bbb82cb6 --- /dev/null +++ b/tests/rt/pos/core/adt-arith.golden @@ -0,0 +1,2 @@ +2025-08-13T10:05:00.321Z [RTM] info: Skipping network creation. Observe that all external IO operations will yield a runtime error. +>>> Main thread finished with value: 16@{}%{} diff --git a/tests/rt/pos/core/adt-arith.trp b/tests/rt/pos/core/adt-arith.trp new file mode 100644 index 00000000..75363b29 --- /dev/null +++ b/tests/rt/pos/core/adt-arith.trp @@ -0,0 +1,17 @@ +datatype binop = ADD | SUB | MUL | DIV +datatype expr = LIT of int | BINOP of binop * expr * expr + +let fun eval (LIT i) = i + | eval (BINOP (oper, e1, e2)) = + let val v1 = eval e1 + val v2 = eval e2 + in case oper of ADD => v1 + v2 + | SUB => v1 - v2 + | MUL => v1 * v2 + | DIV => v1 div v2 + end +in eval (BINOP (ADD, + (BINOP (SUB, LIT 8, LIT 4)), + (BINOP (MUL, LIT 6, + (BINOP (DIV, LIT 6, LIT 3)))))) +end diff --git a/tests/rt/pos/core/adt-atom-day1.golden b/tests/rt/pos/core/adt-atom-day1.golden new file mode 100644 index 00000000..a46cb9b7 --- /dev/null +++ b/tests/rt/pos/core/adt-atom-day1.golden @@ -0,0 +1,4 @@ +2025-08-08T15:27:52.050Z [RTM] info: Skipping network creation. Observe that all external IO operations will yield a runtime error. +"friday" +"tuesday" +>>> Main thread finished with value: ()@{}%{} diff --git a/tests/rt/pos/core/adt-atom-day1.trp b/tests/rt/pos/core/adt-atom-day1.trp new file mode 100644 index 00000000..34eb6263 --- /dev/null +++ b/tests/rt/pos/core/adt-atom-day1.trp @@ -0,0 +1,18 @@ +datatype Day = MONDAY + | TUESDAY + | WEDNESDAY + | THURSDAY + | FRIDAY + | SATURDAY + | SUNDAY + +let fun print_day MONDAY = print "monday" + | print_day TUESDAY = print "tuesday" + | print_day WEDNESDAY = print "wednesday" + | print_day THURSDAY = print "thursday" + | print_day FRIDAY = print "friday" + | print_day SATURDAY = print "saturday" + | print_day SUNDAY = print "sunday" +in print_day FRIDAY; + print_day TUESDAY +end diff --git a/tests/rt/pos/core/adt-atom-day2.golden b/tests/rt/pos/core/adt-atom-day2.golden new file mode 100644 index 00000000..82110025 --- /dev/null +++ b/tests/rt/pos/core/adt-atom-day2.golden @@ -0,0 +1,2 @@ +2025-08-08T15:27:54.468Z [RTM] info: Skipping network creation. Observe that all external IO operations will yield a runtime error. +>>> Main thread finished with value: WEDNESDAY@{}%{} diff --git a/tests/rt/pos/core/adt-atom-day2.trp b/tests/rt/pos/core/adt-atom-day2.trp new file mode 100644 index 00000000..4d015f94 --- /dev/null +++ b/tests/rt/pos/core/adt-atom-day2.trp @@ -0,0 +1,17 @@ +datatype Day = MONDAY + | TUESDAY + | WEDNESDAY + | THURSDAY + | FRIDAY + | SATURDAY + | SUNDAY + +let fun next_day MONDAY = TUESDAY + | next_day TUESDAY = WEDNESDAY + | next_day WEDNESDAY = THURSDAY + | next_day THURSDAY = FRIDAY + | next_day FRIDAY = SATURDAY + | next_day SATURDAY = SUNDAY + | next_day SUNDAY = MONDAY +in next_day TUESDAY +end diff --git a/tests/rt/pos/core/adt-atom-multiple-declarations.golden b/tests/rt/pos/core/adt-atom-multiple-declarations.golden new file mode 100644 index 00000000..0f59f148 --- /dev/null +++ b/tests/rt/pos/core/adt-atom-multiple-declarations.golden @@ -0,0 +1,4 @@ +2025-08-08T15:27:27.445Z [RTM] info: Skipping network creation. Observe that all external IO operations will yield a runtime error. +COLD +HOT +>>> Main thread finished with value: ()@{}%{} diff --git a/tests/rt/pos/core/adt-atom-multiple-declarations.trp b/tests/rt/pos/core/adt-atom-multiple-declarations.trp new file mode 100644 index 00000000..43585101 --- /dev/null +++ b/tests/rt/pos/core/adt-atom-multiple-declarations.trp @@ -0,0 +1,8 @@ +datatype Temperature = HOT | COLD +datatype Food = SOUP | ICECREAM + +let fun serving_temperature SOUP = HOT + | serving_temperature ICECREAM = COLD +in print (serving_temperature ICECREAM); + print (serving_temperature SOUP) +end diff --git a/tests/rt/pos/core/adt-option1.golden b/tests/rt/pos/core/adt-option1.golden new file mode 100644 index 00000000..74c9b378 --- /dev/null +++ b/tests/rt/pos/core/adt-option1.golden @@ -0,0 +1,2 @@ +2025-08-13T09:50:43.426Z [RTM] info: Skipping network creation. Observe that all external IO operations will yield a runtime error. +>>> Main thread finished with value: 5@{}%{} diff --git a/tests/rt/pos/core/adt-option1.trp b/tests/rt/pos/core/adt-option1.trp new file mode 100644 index 00000000..ab01c20e --- /dev/null +++ b/tests/rt/pos/core/adt-option1.trp @@ -0,0 +1,6 @@ +datatype option = NONE | SOME of a +let fun sum_of_some_tuple (SOME (a, b)) = SOME (a + b) + | sum_of_some_tuple NONE = NONE + fun get_with_default (SOME a) _ = a + | get_with_default NONE d = d +in get_with_default (sum_of_some_tuple (SOME (2,3))) 0 end diff --git a/tests/rt/pos/core/adt-option2.golden b/tests/rt/pos/core/adt-option2.golden new file mode 100644 index 00000000..5a69f863 --- /dev/null +++ b/tests/rt/pos/core/adt-option2.golden @@ -0,0 +1,2 @@ +2025-08-13T09:50:21.033Z [RTM] info: Skipping network creation. Observe that all external IO operations will yield a runtime error. +>>> Main thread finished with value: (NONE@{}%{}, (SOME (28@{}%{}))@{}%{})@{}%{} diff --git a/tests/rt/pos/core/adt-option2.trp b/tests/rt/pos/core/adt-option2.trp new file mode 100644 index 00000000..9eefe9fe --- /dev/null +++ b/tests/rt/pos/core/adt-option2.trp @@ -0,0 +1,2 @@ +datatype option = NONE | SOME of a +(NONE, SOME 28)