packages feed

zeolite-lang 0.13.0.0 → 0.14.0.0

raw patch · 32 files changed

+918/−166 lines, 32 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Compilation.ScopeContext: [scMembers] :: ScopeContext c -> [DefinedMember c]
- Types.TypeInstance: newtype ParamName
+ Compilation.CompilerState: autoSelfType :: CompilerContext c m s a => CompilerState a m GeneralInstance
+ Compilation.CompilerState: ccSelfType :: CompilerContext c m s a => a -> m TypeInstance
+ Compilation.CompilerState: csSelfType :: CompilerContext c m s a => CompilerState a m TypeInstance
+ Compilation.ScopeContext: [scValueMembers] :: ScopeContext c -> [DefinedMember c]
+ Parser.Common: noParamSelf :: TextParser ()
+ Parser.Common: paramSelf :: TextParser ()
+ Types.DefinedCategory: replaceSelfMember :: (Show c, CollectErrorsM m) => GeneralInstance -> DefinedMember c -> m (DefinedMember c)
+ Types.TypeCategory: instanceFromCategory :: AnyCategory c -> GeneralInstance
+ Types.TypeCategory: replaceSelfFunction :: (Show c, CollectErrorsM m) => GeneralInstance -> ScopedFunction c -> m (ScopedFunction c)
+ Types.TypeInstance: ParamSelf :: ParamName
+ Types.TypeInstance: data ParamName
+ Types.TypeInstance: replaceSelfFilter :: CollectErrorsM m => GeneralInstance -> TypeFilter -> m TypeFilter
+ Types.TypeInstance: replaceSelfInstance :: CollectErrorsM m => GeneralInstance -> GeneralInstance -> m GeneralInstance
+ Types.TypeInstance: replaceSelfSingle :: CollectErrorsM m => GeneralInstance -> TypeInstance -> m TypeInstance
+ Types.TypeInstance: replaceSelfValueType :: CollectErrorsM m => GeneralInstance -> ValueType -> m ValueType
+ Types.TypeInstance: selfType :: GeneralInstance
- Types.Procedure: InitializeValue :: [c] -> TypeInstance -> Positional GeneralInstance -> Positional (Expression c) -> Expression c
+ Types.Procedure: InitializeValue :: [c] -> Maybe TypeInstance -> Positional GeneralInstance -> Positional (Expression c) -> Expression c

Files

ChangeLog.md view
@@ -1,5 +1,22 @@ # Revision history for zeolite-lang +## 0.14.0.0  -- 2021-03-19++### Language++* **[breaking]** Adds the `#self` meta-type. This is an implicit type param that+  is dynamically replaced with the type of the object a function is called on.+  For example, if a `@value interface` function has a return type of `#self`+  then any implementation must return an object of *its own type* from that+  function. (This is a breaking change because it reserves the param name+  `#self`.)++### Libraries++* **[breaking]** Removes the type parameters from `IterateForward` and+  `IterateReverse` in `lib/util`. This was made possible by the addition of the+  `#self` meta-type.+ ## 0.13.0.0  -- 2021-03-17  ### Language
base/builtin.0rp view
@@ -65,7 +65,6 @@   defines Equals<String>   defines LessThan<String> -  @value subSequence (Int,Int) -> (String)   @type builder () -> (Builder<String>) } @@ -92,11 +91,11 @@ @value interface ReadPosition<|#x> {   readPosition (Int) -> (#x)   readSize () -> (Int)-  subSequence (Int,Int) -> (ReadPosition<#x>)+  subSequence (Int,Int) -> (#self) }  @value interface Builder<#x> {-  append (#x) -> (Builder<#x>)+  append (#x) -> (#self)   build () -> (#x) } 
example/parser/README.md view
@@ -57,6 +57,13 @@   This is useful when the parameter value can be easily guessed by the reader of   the code from its context. +- **The `#self` Param.** Using `#self` as a return type in an `interface` allows+  it to require that an implementation returns *its own type*, rather than+  *the type of the `interface`*. `ParseContext.advance` uses this to allow+  callers of `advance` to get an instance of the derived type rather than an+  instance of `ParseContext`. This is useful because `ParseContext` lacks other+  functions that the derived type defines.+ ## Running  (Included with compiler package starting with version `0.6.0.0`.)
example/parser/parse-text.0rx view
@@ -123,7 +123,7 @@   }    create (value) {-    return ConstParser<#x>{ value }+    return #self{ value }   } } @@ -167,7 +167,7 @@   }    create (parser) {-    return TryParser<#x>{ parser }+    return #self{ parser }   } } @@ -194,7 +194,7 @@   }    create (parser1,parser2) {-    return OrParser<#x>{ parser1, parser2 }+    return #self{ parser1, parser2 }   } } @@ -226,7 +226,7 @@   }    create (parser1,parser2) {-    return LeftParser<#x>{ parser1, parser2 }+    return #self{ parser1, parser2 }   } } @@ -253,7 +253,7 @@   }    create (parser1,parser2) {-    return RightParser<#x>{ parser1, parser2 }+    return #self{ parser1, parser2 }   } } 
example/parser/parser.0rp view
@@ -44,5 +44,5 @@    // Reading data.   current () -> (Char)-  advance () -> (ParseContext<#x>)+  advance () -> (#self) }
example/parser/parser.0rx view
@@ -86,9 +86,9 @@   advance () {     \ sanityCheck()     if (data.readPosition(index) == '\n') {-      return ParseState<#x>{ data, index+1, line+1, 1, value, error }+      return #self{ data, index+1, line+1, 1, value, error }     } else {-      return ParseState<#x>{ data, index+1, line, char+1, value, error }+      return #self{ data, index+1, line, char+1, value, error }     }   } 
example/tree/tree.0rp view
@@ -1,8 +1,12 @@ /* An interface for updating a key-value index.  */ @value interface KVWriter<#k,#v|> {-  set (#k,#v) -> (KVWriter<#k,#v>)-  remove (#k) -> (KVWriter<#k,#v>)+  // #self below always means the type of value that the function is being+  // called from. For example, the type of foo.remove(key) is the same type as+  // foo is.++  set (#k,#v) -> (#self)+  remove (#k) -> (#self) }  /* An interface for looking up values from a key-value index.@@ -21,10 +25,6 @@   // Creates a new Tree, e.g., Tree.new().   @type new () -> (Tree<#k,#v>) -  // Normally you do not need to redeclare functions inherited from interfaces.-  // The two redeclarations below are used to refine the return type from-  // KVWriter to Tree.--  @value set (#k,#v) -> (Tree<#k,#v>)-  @value remove (#k) -> (Tree<#k,#v>)+  // Since set and remove return #self, their implementations in Tree must+  // return Tree<#k,#v>. }
example/tree/tree.0rx view
@@ -2,7 +2,7 @@   @value optional Node<#k,#v> root    new () {-    return Tree<#k,#v>{ empty }+    return #self{ empty }   }    set (k,v) {@@ -49,7 +49,7 @@    insert (node,k,v) {     if (!present(node)) {-      return Node<#k,#v>{ 1, k, v, empty, empty }+      return #self{ 1, k, v, empty, empty }     }     Node<#k,#v> node2 <- require(node)     if (k `#k.lessThan` node2.getKey()) {
lib/util/util.0rp view
@@ -31,20 +31,20 @@   readCurrent () -> (#x) } -@value interface IterateForward<|#x> {-  forward () -> (#x)+@value interface IterateForward {+  forward () -> (#self)   pastForwardEnd () -> (Bool) } -@value interface IterateReverse<|#x> {-  reverse () -> (#x)+@value interface IterateReverse {+  reverse () -> (#self)   pastReverseEnd () -> (Bool) }  concrete ReadIterator<|#x> {   refines ReadCurrent<#x>-  refines IterateForward<ReadIterator<#x>>-  refines IterateReverse<ReadIterator<#x>>+  refines IterateForward+  refines IterateReverse    @category fromReadPosition<#y> (ReadPosition<#y>) -> (ReadIterator<#y>)   @category fromReadPositionAt<#y> (ReadPosition<#y>,Int) -> (ReadIterator<#y>)
src/Compilation/CompilerState.hs view
@@ -33,6 +33,7 @@   MemberValue(..),   ReturnVariable(..),   UsedVariable(..),+  autoSelfType,   concatM,   csAddRequired,   csAddUsed,@@ -62,6 +63,7 @@   csReserveExprMacro,   csResolver,   csSameType,+  csSelfType,   csSetHidden,   csSetJumpType,   csSetNoTrace,@@ -87,6 +89,7 @@ #endif  import Base.CompilerError+import Base.GeneralType import Base.Positional import Types.DefinedCategory import Types.Procedure@@ -100,6 +103,7 @@   ccCurrentScope :: a -> m SymbolScope   ccResolver :: a -> m AnyTypeResolver   ccSameType :: a -> TypeInstance -> m Bool+  ccSelfType :: a -> m TypeInstance   ccAllFilters :: a -> m ParamFilters   ccGetParamScope :: a -> ParamName -> m SymbolScope   ccAddRequired :: a -> Set.Set CategoryName -> m a@@ -196,6 +200,9 @@ csSameType :: CompilerContext c m s a => TypeInstance -> CompilerState a m Bool csSameType t = fmap (\x -> ccSameType x t) get >>= lift +csSelfType :: CompilerContext c m s a => CompilerState a m TypeInstance+csSelfType = fmap ccSelfType get >>= lift+ csAllFilters :: CompilerContext c m s a => CompilerState a m ParamFilters csAllFilters = fmap ccAllFilters get >>= lift @@ -337,3 +344,10 @@  getCleanContext :: CompilerContext c m s a => CompilerState a m a getCleanContext = get >>= lift . ccClearOutput++autoSelfType :: CompilerContext c m s a => CompilerState a m GeneralInstance+autoSelfType = do+  scope <- csCurrentScope+  case scope of+       CategoryScope -> return selfType+       _ -> fmap (singleType . JustTypeInstance) csSelfType
src/Compilation/ProcedureContext.hs view
@@ -96,13 +96,18 @@   CompilerContext c m [String] (ProcedureContext c) where   ccCurrentScope = return . (^. pcScope)   ccResolver = return . AnyTypeResolver . CategoryResolver . (^. pcCategories)-  ccSameType ctx = return . (== same) where-    same = TypeInstance (ctx ^. pcType) (fmap (singleType . JustParamName False . vpParam) $ ctx ^. pcExtParams)+  ccSameType ctx t+    | ctx ^. pcScope == CategoryScope = return False+    | otherwise = ccSelfType ctx >>= return . (== t)+  ccSelfType ctx+    | ctx ^. pcScope == CategoryScope = compilerErrorM $ "Param " ++ show ParamSelf ++ " not found"+    | otherwise = return $ TypeInstance (ctx ^. pcType)+                                        (fmap (singleType . JustParamName False . vpParam) $ ctx ^. pcExtParams)   ccAllFilters = return . (^. pcAllFilters)   ccGetParamScope ctx p = do     case p `Map.lookup` (ctx ^. pcParamScopes) of             (Just s) -> return s-            _ -> compilerErrorM $ "Param " ++ show p ++ " does not exist"+            _ -> compilerErrorM $ "Param " ++ show p ++ " not found"   ccAddRequired ctx ts = return $ ctx & pcRequiredTypes <>~ ts   ccGetRequired = return . (^. pcRequiredTypes)   ccGetCategoryFunction ctx c Nothing n = ccGetCategoryFunction ctx c (Just $ ctx ^. pcType) n@@ -124,58 +129,67 @@       return f     checkFunction _ =       compilerErrorM $ "Category " ++ show t ++-                     " does not have a category function named " ++ show n ++-                     formatFullContextBrace c-  ccGetTypeFunction ctx c t n = getFunction t where-    getFunction (Just t2) = reduceMergeTree getFromAny getFromAll getFromSingle t2-    getFunction Nothing = do-      let ps = fmap (singleType . JustParamName False . vpParam) $ ctx ^. pcExtParams-      getFunction (Just $ singleType $ JustTypeInstance $ TypeInstance (ctx ^. pcType) ps)-    getFromAny _ =-      compilerErrorM $ "Use explicit type conversion to call " ++ show n ++ " from " ++ show t-    getFromAll ts = do-      collectFirstM ts <!!-        "Function " ++ show n ++ " not available for type " ++ show t ++ formatFullContextBrace c-    getFromSingle (JustParamName _ p) = do-      fa <- ccAllFilters ctx-      fs <- case p `Map.lookup` fa of-                (Just fs) -> return fs-                _ -> compilerErrorM $ "Param " ++ show p ++ " does not exist"-      let ts = map tfType $ filter isRequiresFilter fs-      let ds = map dfType $ filter isDefinesFilter  fs-      collectFirstM (map (getFunction . Just) ts ++ map checkDefine ds) <!!-        "Function " ++ show n ++ " not available for param " ++ show p ++ formatFullContextBrace c-    getFromSingle (JustTypeInstance t2)-      -- Same category as the procedure itself.-      | tiName t2 == ctx ^. pcType =-        subAndCheckFunction (tiName t2) (fmap vpParam $ ctx ^. pcExtParams) (tiParams t2) $ n `Map.lookup` (ctx ^. pcFunctions)-      -- A different category than the procedure.-      | otherwise = do-        (_,ca) <- getCategory (ctx ^. pcCategories) (c,tiName t2)+                       " does not have a category function named " ++ show n +++                       formatFullContextBrace c+  ccGetTypeFunction ctx c t n = do+    t' <- case ctx ^. pcScope of+               CategoryScope -> case t of+                                     Nothing -> compilerErrorM $ "Category " ++ show t +++                                                                  " does not have a category function named " ++ show n +++                                                                  formatFullContextBrace c+                                     Just t0 -> return t0+               _ -> do+                 self <- fmap (singleType . JustTypeInstance) $ ccSelfType ctx+                 case t of+                      Just t0 -> replaceSelfInstance self t0+                      Nothing -> return self+    getFunction t' t' where+      getFunction t0 t2 = reduceMergeTree getFromAny getFromAll (getFromSingle t0) t2+      getFromAny _ =+        compilerErrorM $ "Use explicit type conversion to call " ++ show n ++ " from " ++ show t+      getFromAll ts = do+        collectFirstM ts <!!+          "Function " ++ show n ++ " not available for type " ++ show t ++ formatFullContextBrace c+      getFromSingle t0 (JustParamName _ p) = do+        fa <- ccAllFilters ctx+        fs <- case p `Map.lookup` fa of+                   (Just fs) -> return fs+                   _ -> compilerErrorM $ "Param " ++ show p ++ " not found"+        let ts = map tfType $ filter isRequiresFilter fs+        let ds = map dfType $ filter isDefinesFilter  fs+        collectFirstM (map (getFunction t0) ts ++ map (checkDefine t0) ds) <!!+          "Function " ++ show n ++ " not available for param " ++ show p ++ formatFullContextBrace c+      getFromSingle t0 (JustTypeInstance t2)+        -- Same category as the procedure itself.+        | tiName t2 == ctx ^. pcType =+          subAndCheckFunction t0 (tiName t2) (fmap vpParam $ ctx ^. pcExtParams) (tiParams t2) $ n `Map.lookup` (ctx ^. pcFunctions)+        -- A different category than the procedure.+        | otherwise = do+          (_,ca) <- getCategory (ctx ^. pcCategories) (c,tiName t2)+          let params = Positional $ map vpParam $ getCategoryParams ca+          let fa = Map.fromList $ map (\f -> (sfName f,f)) $ getCategoryFunctions ca+          subAndCheckFunction t0 (tiName t2) params (tiParams t2) $ n `Map.lookup` fa+      getFromSingle _ _ = compilerErrorM $ "Type " ++ show t ++ " contains unresolved types"+      checkDefine t0 t2 = do+        (_,ca) <- getCategory (ctx ^. pcCategories) (c,diName t2)         let params = Positional $ map vpParam $ getCategoryParams ca         let fa = Map.fromList $ map (\f -> (sfName f,f)) $ getCategoryFunctions ca-        subAndCheckFunction (tiName t2) params (tiParams t2) $ n `Map.lookup` fa-    getFromSingle _ = compilerErrorM $ "Type " ++ show t ++ " contains unresolved types"-    checkDefine t2 = do-      (_,ca) <- getCategory (ctx ^. pcCategories) (c,diName t2)-      let params = Positional $ map vpParam $ getCategoryParams ca-      let fa = Map.fromList $ map (\f -> (sfName f,f)) $ getCategoryFunctions ca-      subAndCheckFunction (diName t2) params (diParams t2) $ n `Map.lookup` fa-    subAndCheckFunction t2 ps1 ps2 (Just f) = do-      when (ctx ^. pcDisallowInit && t2 == ctx ^. pcType) $-        compilerErrorM $ "Function " ++ show n ++-                       " disallowed during initialization" ++ formatFullContextBrace c-      when (sfScope f == CategoryScope) $-        compilerErrorM $ "Function " ++ show n ++ " in " ++ show t2 ++-                       " is a category function" ++ formatFullContextBrace c-      paired <- processPairs alwaysPair ps1 ps2 <??-        "In external function call at " ++ formatFullContext c-      let assigned = Map.fromList paired-      uncheckedSubFunction assigned f-    subAndCheckFunction t2 _ _ _ =-      compilerErrorM $ "Category " ++ show t2 ++-                     " does not have a type or value function named " ++ show n ++-                     formatFullContextBrace c+        subAndCheckFunction t0 (diName t2) params (diParams t2) $ n `Map.lookup` fa+      subAndCheckFunction t0 t2 ps1 ps2 (Just f) = do+        when (ctx ^. pcDisallowInit && t2 == ctx ^. pcType) $+          compilerErrorM $ "Function " ++ show n +++                           " disallowed during initialization" ++ formatFullContextBrace c+        when (sfScope f == CategoryScope) $+          compilerErrorM $ "Function " ++ show n ++ " in " ++ show t2 +++                           " is a category function" ++ formatFullContextBrace c+        paired <- processPairs alwaysPair ps1 ps2 <??+          "In external function call at " ++ formatFullContext c+        let assigned = Map.fromList paired+        uncheckedSubFunction assigned f >>= replaceSelfFunction (fixTypeParams t0)+      subAndCheckFunction _ t2 _ _ _ =+        compilerErrorM $ "Category " ++ show t2 +++                         " does not have a type or value function named " ++ show n +++                         formatFullContextBrace c   ccCheckValueInit ctx c (TypeInstance t as) ts ps     | t /= ctx ^. pcType =       compilerErrorM $ "Category " ++ show (ctx ^. pcType) ++ " cannot initialize values from " ++
src/Compilation/ScopeContext.hs view
@@ -46,7 +46,7 @@     scName :: CategoryName,     scExternalParams :: Positional (ValueParam c),     scInternalparams :: Positional (ValueParam c),-    scMembers :: [DefinedMember c],+    scValueMembers :: [DefinedMember c],     scExternalFilters :: [ParamFilter c],     scInternalFilters :: [ParamFilter c],     scFunctions :: Map.Map FunctionName (ScopedFunction c),@@ -79,21 +79,28 @@   checkInternalParams pi fi (getCategoryParams t) (Map.elems fa) r fm   pa <- pairProceduresToFunctions fa ps   let (cp,tp,vp) = partitionByScope (sfScope . fst) pa+  tp' <- mapErrorsM (firstM $ replaceSelfFunction (instanceFromCategory t)) tp+  vp' <- mapErrorsM (firstM $ replaceSelfFunction (instanceFromCategory t)) vp   let (cm,tm,vm) = partitionByScope dmScope ms+  tm' <- mapErrorsM (replaceSelfMember (instanceFromCategory t)) tm+  vm' <- mapErrorsM (replaceSelfMember (instanceFromCategory t)) vm   let cm0 = builtins typeInstance CategoryScope   let tm0 = builtins typeInstance TypeScope   let vm0 = builtins typeInstance ValueScope-  cm' <- mapMembers cm-  tm' <- mapMembers $ cm ++ tm-  vm' <- mapMembers $ cm ++ tm ++ vm-  let cv = Map.union cm0 cm'-  let tv = Map.union tm0 tm'-  let vv = Map.union vm0 vm'-  let ctxC = ScopeContext ta n params params2 vm filters filters2 fa cv em-  let ctxT = ScopeContext ta n params params2 vm filters filters2 fa tv em-  let ctxV = ScopeContext ta n params params2 vm filters filters2 fa vv em-  return [ProcedureScope ctxC cp,ProcedureScope ctxT tp,ProcedureScope ctxV vp]+  cm2 <- mapMembers cm+  tm2 <- mapMembers $ cm ++ tm'+  vm2 <- mapMembers $ cm ++ tm' ++ vm'+  let cv = Map.union cm0 cm2+  let tv = Map.union tm0 tm2+  let vv = Map.union vm0 vm2+  let ctxC = ScopeContext ta n params params2 vm' filters filters2 fa cv em+  let ctxT = ScopeContext ta n params params2 vm' filters filters2 fa tv em+  let ctxV = ScopeContext ta n params params2 vm' filters filters2 fa vv em+  return [ProcedureScope ctxC cp,ProcedureScope ctxT tp',ProcedureScope ctxV vp']   where+    firstM f (x,y) = do+      x' <- f x+      return (x',y)     builtins t s0 = Map.filter ((<= s0) . vvScope) $ builtinVariables t     checkInternalParams pi2 fi2 pe fs2 r fa = do       let pm = Map.fromList $ map (\p -> (vpParam p,vpContext p)) pi2
src/CompilerCxx/CxxFiles.hs view
@@ -411,7 +411,7 @@       fmap indentCompiled $ inlineValueConstructor t d,       return declareValueOverrides,       fmap indentCompiled $ concatM $ map (procedureDeclaration False) fs,-      fmap indentCompiled $ concatM $ map (createMember r allFilters) members,+      fmap indentCompiled $ concatM $ map (createMember r allFilters t) members,       return $ indentCompiled $ createParams $ dcParams d,       return $ onlyCode $ "  const S<" ++ typeName (getCategoryName t) ++ "> parent;",       return $ onlyCodes traceCreation,@@ -526,10 +526,11 @@     ] where       className = valueName (getCategoryName t) -  createMember r filters m = do-    validateGeneralInstance r filters (vtType $ dmType m) <??-      "In creation of " ++ show (dmName m) ++ " at " ++ formatFullContext (dmContext m)-    return $ onlyCode $ variableStoredType (dmType m) ++ " " ++ variableName (dmName m) ++ ";"+  createMember r filters t m = do+    m' <- replaceSelfMember (instanceFromCategory t) m+    validateGeneralInstance r filters (vtType $ dmType m') <??+      "In creation of " ++ show (dmName m') ++ " at " ++ formatFullContext (dmContext m')+    return $ onlyCode $ variableStoredType (dmType m') ++ " " ++ variableName (dmName m') ++ ";"   createMemberLazy r filters m = do     validateGeneralInstance r filters (vtType $ dmType m) <??       "In creation of " ++ show (dmName m) ++ " at " ++ formatFullContext (dmContext m)
src/CompilerCxx/Naming.hs view
@@ -98,7 +98,7 @@ mainSourceIncludes = ["#include \"logging.hpp\""]  paramName :: ParamName -> String-paramName p = "Param_" ++ tail (pnName p) -- Remove leading '#'.+paramName p = "Param_" ++ tail (show p) -- Remove leading '#'.  variableName :: VariableName -> String variableName v = "Var_" ++ show v
src/CompilerCxx/Procedure.hs view
@@ -285,11 +285,13 @@     getVariableType (ExistingVariable (DiscardInput _)) t = return t     createVariable r fa (CreateVariable c2 t1 n) t2 =       "In creation of " ++ show n ++ " at " ++ formatFullContext c2 ??> do-        -- TODO: Call csAddRequired for t1. (Maybe needs a helper function.)-        lift $ collectAllM_ [validateGeneralInstance r fa (vtType t1),-                             checkValueAssignment r fa t2 t1]-        csAddVariable (UsedVariable c2 n) (VariableValue c2 LocalScope t1 VariableDefault)-        csWrite [variableStoredType t1 ++ " " ++ variableName n ++ ";"]+        self <- autoSelfType+        t1' <- lift $ replaceSelfValueType self t1+        -- TODO: Call csAddRequired for t1'. (Maybe needs a helper function.)+        lift $ collectAllM_ [validateGeneralInstance r fa (vtType t1'),+                             checkValueAssignment r fa t2 t1']+        csAddVariable (UsedVariable c2 n) (VariableValue c2 LocalScope t1' VariableDefault)+        csWrite [variableStoredType t1' ++ " " ++ variableName n ++ ";"]     createVariable r fa (ExistingVariable (InputValue c2 n)) t2 =       "In assignment to " ++ show n ++ " at " ++ formatFullContext c2 ??> do         (VariableValue _ _ t1 _) <- getWritableVariable c2 n@@ -423,15 +425,17 @@   ScopedBlock c -> CompilerState a m () compileScopedBlock s@(ScopedBlock _ _ _ c2 _) = do   let (vs,p,cl,st) = rewriteScoped s+  self <- autoSelfType+  vs' <- lift $ mapErrorsM (replaceSelfVariable self) vs   -- Capture context so we can discard scoped variable names.   ctx0 <- getCleanContext   r <- csResolver   fa <- csAllFilters-  sequence_ $ map (createVariable r fa) vs+  sequence_ $ map (createVariable r fa) vs'   ctxP0 <- compileProcedure ctx0 p   -- Make variables to be created visible *after* p has been compiled so that p   -- can't refer to them.-  ctxP <- lift $ execStateT (sequence $ map showVariable vs) ctxP0+  ctxP <- lift $ execStateT (sequence $ map showVariable vs') ctxP0   ctxCl0 <- lift $ ccClearOutput ctxP >>= flip ccStartCleanup c2   ctxP' <-     case cl of@@ -453,8 +457,11 @@   unreachable <- csIsUnreachable   when (not unreachable) $ autoInsertCleanup c2 NextStatement ctxP'   csWrite ["}"]-  sequence_ $ map showVariable vs+  sequence_ $ map showVariable vs'   where+    replaceSelfVariable self (c,t,n) = do+      t' <- replaceSelfValueType self t+      return (c,t',n)     createVariable r fa (c,t,n) = do       lift $ validateGeneralInstance r fa (vtType t) <??         "In creation of " ++ show n ++ " at " ++ formatFullContext c@@ -561,20 +568,30 @@         | otherwise = compilerErrorM $ "Cannot use " ++ show t ++ " with unary ~ operator" ++                                              formatFullContextBrace c   compile (InitializeValue c t ps es) = do+    scope <- csCurrentScope+    t' <- case scope of+               CategoryScope -> case t of+                                     Nothing -> compilerErrorM $ "Param " ++ show ParamSelf ++ " not found"+                                     Just t0 -> return t0+               _ -> do+                 self <- csSelfType+                 case t of+                      Just t0 -> lift $ replaceSelfSingle (singleType $ JustTypeInstance self) t0+                      Nothing -> return self     es' <- sequence $ map compileExpression $ pValues es     (ts,es'') <- lift $ getValues es'-    csCheckValueInit c t (Positional ts) ps-    params <- expandParams $ tiParams t+    csCheckValueInit c t' (Positional ts) ps+    params <- expandParams $ tiParams t'     params2 <- expandParams2 $ ps-    sameType <- csSameType t+    sameType <- csSameType t'     s <- csCurrentScope-    let typeInstance = getType sameType s params+    let typeInstance = getType t' sameType s params     -- TODO: This is unsafe if used in a type or category constructor.-    return (Positional [ValueType RequiredValue $ singleType $ JustTypeInstance t],-            UnwrappedSingle $ valueCreator (tiName t) ++ "(" ++ typeInstance ++ ", " ++ params2 ++ ", " ++ es'' ++ ")")+    return (Positional [ValueType RequiredValue $ singleType $ JustTypeInstance t'],+            UnwrappedSingle $ valueCreator (tiName t') ++ "(" ++ typeInstance ++ ", " ++ params2 ++ ", " ++ es'' ++ ")")     where-      getType True ValueScope _      = "parent"-      getType _    _          params = typeCreator (tiName t) ++ "(" ++ params ++ ")"+      getType _  True ValueScope _      = "parent"+      getType t2 _    _          params = typeCreator (tiName t2) ++ "(" ++ params ++ ")"       -- Single expression, but possibly multi-return.       getValues [(Positional ts,e)] = return (ts,useAsArgs e)       -- Multi-expression => must all be singles.@@ -712,17 +729,19 @@   t' <- expandCategory t   compileFunctionCall (Just t') f' f compileExpressionStart (TypeCall c t f@(FunctionCall _ n _ _)) = do+  self <- autoSelfType+  t' <- lift $ replaceSelfInstance self (singleType t)   r <- csResolver   fa <- csAllFilters-  lift $ validateGeneralInstance r fa (singleType t) <?? "In function call at " ++ formatFullContext c-  f' <- csGetTypeFunction c (Just $ singleType t) n+  lift $ validateGeneralInstance r fa t' <?? "In function call at " ++ formatFullContext c+  f' <- csGetTypeFunction c (Just t') n   when (sfScope f' /= TypeScope) $ compilerErrorM $ "Function " ++ show n ++-                                          " cannot be used as a type function" ++-                                          formatFullContextBrace c-  csAddRequired $ Set.unions $ map categoriesFromTypes [singleType t]+                                                    " cannot be used as a type function" +++                                                    formatFullContextBrace c+  csAddRequired $ Set.unions $ map categoriesFromTypes [t']   csAddRequired $ Set.fromList [sfType f']-  t' <- expandGeneralInstance $ singleType t-  compileFunctionCall (Just t') f' f+  t2 <- expandGeneralInstance t'+  compileFunctionCall (Just t2) f' f compileExpressionStart (UnqualifiedCall c f@(FunctionCall _ n _ _)) = do   ctx <- get   f' <- lift $ collectFirstM [tryCategory ctx,tryNonCategory ctx]@@ -760,7 +779,9 @@   when (length (pValues $ fst $ head es') /= 1) $     compilerErrorM $ "Expected single return in argument" ++ formatFullContextBrace c   let (Positional [t0],e) = head es'-  [t1,t2] <- lift $ disallowInferred ps+  self <- autoSelfType+  ps' <- lift $ disallowInferred ps+  [t1,t2] <- lift $ mapErrorsM (replaceSelfInstance self) ps'   r <- csResolver   fa <- csAllFilters   lift $ validateGeneralInstance r fa t1@@ -806,7 +827,9 @@     compilerErrorM $ "Expected 1 type parameter" ++ formatFullContextBrace c   when (length (pValues es) /= 0) $     compilerErrorM $ "Expected 0 arguments" ++ formatFullContextBrace c-  [t] <- lift $ disallowInferred ps+  self <- autoSelfType+  ps' <- lift $ disallowInferred ps+  [t] <- lift $ mapErrorsM (replaceSelfInstance self) ps'   r <- csResolver   fa <- csAllFilters   lift $ validateGeneralInstance r fa t@@ -844,8 +867,10 @@   fa <- csAllFilters   es' <- sequence $ map compileExpression $ pValues es   (ts,es'') <- lift $ getValues es'-  ps2 <- lift $ guessParamsFromArgs r fa f ps (Positional ts)-  lift $ mapErrorsM_ backgroundMessage $ zip3 (map vpParam $ pValues $ sfParams f) (pValues ps) (pValues ps2)+  self <- autoSelfType+  ps' <- lift $ fmap Positional $ mapErrorsM (replaceSelfParam self) $ pValues ps+  ps2 <- lift $ guessParamsFromArgs r fa f ps' (Positional ts)+  lift $ mapErrorsM_ backgroundMessage $ zip3 (map vpParam $ pValues $ sfParams f) (pValues ps') (pValues ps2)   f' <- lift $ parsedToFunctionType f   f'' <- lift $ assignFunctionParams r fa Map.empty ps2 f'   -- Called an extra time so arg count mismatches have reasonable errors.@@ -859,6 +884,10 @@   call <- assemble e scoped scope (sfScope f) params es''   return $ (ftReturns f'',OpaqueMulti call)   where+    replaceSelfParam self (AssignedInstance c2 t) = do+      t' <- replaceSelfInstance self t+      return $ AssignedInstance c2 t'+    replaceSelfParam _ t = return t     message = "In call to " ++ show (sfName f) ++ " at " ++ formatFullContext c     backgroundMessage (n,(InferredInstance c2),t) =       compilerBackgroundM $ "Parameter " ++ show n ++ " (from " ++ show (sfType f) ++ "." ++
src/Parser/Common.hs view
@@ -77,10 +77,12 @@   merge2,   merge3,   noKeywords,+  noParamSelf,   notAllowed,   nullParse,   operator,   optionalSpace,+  paramSelf,   parseAny2,   parseAny3,   parseBin,@@ -118,6 +120,7 @@  import Base.CompilerError import Parser.TextParser+import Types.TypeInstance (ParamName(ParamSelf))   class ParseFromSource a where@@ -286,6 +289,14 @@  kwWhile :: TextParser () kwWhile = keyword "while"++paramSelf :: TextParser ()+paramSelf = keyword (show ParamSelf)++noParamSelf :: TextParser ()+noParamSelf = (<|> return ()) $ do+    try paramSelf+    compilerErrorM "#self is not allowed here"  operatorSymbol :: TextParser Char operatorSymbol = labeled "operator symbol" $ satisfy (`Set.member` Set.fromList "+-*/%=!<>&|?")
src/Parser/Procedure.hs view
@@ -414,7 +414,7 @@       initalize = do         c <- getSourceContext         t <- try $ do  -- Avoids consuming the type name if { isn't present.-          t2 <- sourceParser+          t2 <- (paramSelf >> return Nothing) <|> fmap Just sourceParser           sepAfter (labeled "@value initializer" $ string_ "{")           return t2         withParams c t <|> withoutParams c t
src/Parser/TypeCategory.hs view
@@ -106,6 +106,7 @@                      (sepBy singleParam (sepAfter $ string_ ","))       return (con,inv,cov)     singleParam = labeled "param declaration" $ do+      noParamSelf       c <- getSourceContext       n <- sourceParser       return (c,n)@@ -128,6 +129,7 @@ singleFilter :: TextParser (ParamFilter SourceContext) singleFilter = try $ do   c <- getSourceContext+  noParamSelf   n <- sourceParser   f <- sourceParser   return $ ParamFilter [c] n f@@ -179,6 +181,7 @@                          (sepAfter $ string_ ">")                          (sepBy singleParam (sepAfter $ string ","))     singleParam = labeled "param declaration" $ do+      noParamSelf       c <- getSourceContext       n <- sourceParser       return $ ValueParam [c] n Invariant
src/Parser/TypeInstance.hs view
@@ -84,12 +84,16 @@         | otherwise = CategoryName n  instance ParseFromSource ParamName where-  sourceParser = labeled "param name" $ do-    noKeywords-    char_ '#'-    b <- lowerChar-    e <- sepAfter $ many alphaNumChar-    return $ ParamName ('#':b:e)+  sourceParser = labeled "param name" $ self <|> custom where+    self = do+      paramSelf+      return ParamSelf+    custom = do+      noKeywords+      char_ '#'+      b <- lowerChar+      e <- sepAfter $ many alphaNumChar+      return $ ParamName ('#':b:e)  instance ParseFromSource TypeInstance where   sourceParser = labeled "type instance" $ do
src/Test/TypeCategory.hs view
@@ -20,6 +20,7 @@ module Test.TypeCategory (tests) where  import Control.Arrow+import Control.Monad ((>=>)) import System.FilePath import qualified Data.Map as Map import qualified Data.Set as Set@@ -72,6 +73,11 @@     checkShortParseFail "@value interface Type { defines T }",     checkShortParseSuccess "@value interface Type<#x> { #x allows T }", +    checkShortParseSuccess "@value interface Type { call () -> (#self) }",+    checkShortParseFail "@value interface Type<#self> {}",+    checkShortParseFail "@value interface Type { #self refines Foo }",+    checkShortParseFail "@value interface Type { call<#self> () -> () }",+     checkOperationSuccess ("testfiles" </> "value_refines_value.0rx") (checkConnectedTypes defaultCategories),     checkOperationFail ("testfiles" </> "value_refines_instance.0rx") (checkConnectedTypes defaultCategories),     checkOperationFail ("testfiles" </> "value_refines_concrete.0rx") (checkConnectedTypes defaultCategories),@@ -792,6 +798,22 @@       (\ts -> do         ts2 <- topoSortCategories defaultCategories ts         flattenAllConnections defaultCategories ts2 >> return ()),++    checkOperationSuccess+      ("testfiles" </> "valid_self.0rx")+      (includeNewTypes defaultCategories >=> const (return ())),+    checkOperationSuccess+      ("testfiles" </> "filtered_self.0rx")+      (includeNewTypes defaultCategories >=> const (return ())),+    checkOperationFail+      ("testfiles" </> "bad_merge_self.0rx")+      (includeNewTypes defaultCategories >=> const (return ())),+    checkOperationFail+      ("testfiles" </> "contravariant_self.0rx")+      (includeNewTypes defaultCategories >=> const (return ())),+    checkOperationFail+      ("testfiles" </> "invariant_self.0rx")+      (includeNewTypes defaultCategories >=> const (return ())),      checkOperationSuccess       ("testfiles" </> "inference.0rx")
src/Test/TypeInstance.hs view
@@ -47,6 +47,14 @@     checkParseSuccess       "#x"       (singleType $ JustParamName False $ ParamName "#x"),+    checkParseSuccess+      "#self"+      (singleType $ JustParamName False $ ParamSelf),+    checkParseSuccess+      "Type0<#self>"+      (singleType $ JustTypeInstance $ TypeInstance (CategoryName "Type0") (Positional [+          singleType $ JustParamName False $ ParamSelf+        ])),     checkParseFail "x",     checkParseFail "", 
+ src/Test/testfiles/bad_merge_self.0rx view
@@ -0,0 +1,8 @@+@value interface Value {+  call () -> (#self)+}++concrete Child {+  refines Value+  @value call () -> (Child)+}
+ src/Test/testfiles/contravariant_self.0rx view
@@ -0,0 +1,3 @@+@value interface Value<#x|#y|#z> {+  call (#self) -> ()+}
+ src/Test/testfiles/filtered_self.0rx view
@@ -0,0 +1,14 @@+@value interface Foo {}++@type interface Bar {}++@value interface Base<|#x> {+  #x requires Foo+  #x defines Bar+}++concrete Value<#y|> {+  refines Base<#self>+  refines Foo+  defines Bar+}
+ src/Test/testfiles/invariant_self.0rx view
@@ -0,0 +1,6 @@+@value interface Base<#x> {}++@value interface Value<#x|#y|#z> {+  refines Base<#self>+  call () -> (#self)+}
+ src/Test/testfiles/valid_self.0rx view
@@ -0,0 +1,16 @@+@value interface Base<|#x> {}++@value interface Value<#x|#y|#z> {+  refines Base<#self>+  call () -> (#self)+}++concrete Child1 {+  refines Value<all,all,all>+  @value call () -> (#self)+}++concrete Child2 {+  refines Value<all,all,all>+  @value call () -> (all)+}
src/Types/DefinedCategory.hs view
@@ -27,6 +27,7 @@   mapMembers,   mergeInternalInheritance,   pairProceduresToFunctions,+  replaceSelfMember,   setInternalFunctions, ) where @@ -197,3 +198,9 @@   let tm0 = (dcName d) `Map.delete` tm   checkCategoryInstances tm0 [c2']   return $ Map.insert (dcName d) c2' tm++replaceSelfMember :: (Show c, CollectErrorsM m) =>+  GeneralInstance -> DefinedMember c -> m (DefinedMember c)+replaceSelfMember self (DefinedMember c s t n i) = do+  t' <- replaceSelfValueType self t+  return $ DefinedMember c s t' n i
src/Types/Procedure.hs view
@@ -228,7 +228,7 @@   Literal (ValueLiteral c) |   UnaryExpression [c] (Operator c) (Expression c) |   InfixExpression [c] (Expression c) (Operator c) (Expression c) |-  InitializeValue [c] TypeInstance (Positional GeneralInstance) (Positional (Expression c))+  InitializeValue [c] (Maybe TypeInstance) (Positional GeneralInstance) (Positional (Expression c))   deriving (Show)  data FunctionQualifier c =
src/Types/TypeCategory.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2019-2020 Kevin P. Barry+Copyright 2019-2021 Kevin P. Barry  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -61,6 +61,7 @@   guessesAsParams,   includeNewTypes,   inferParamTypes,+  instanceFromCategory,   isInstanceInterface,   isNoNamespace,   isPrivateNamespace,@@ -76,6 +77,7 @@   noDuplicateRefines,   parsedToFunctionType,   partitionByScope,+  replaceSelfFunction,   setCategoryNamespace,   topoSortCategories,   uncheckedSubFunction,@@ -220,6 +222,11 @@ getCategoryFunctions (InstanceInterface _ _ _ _ _ fs) = fs getCategoryFunctions (ValueConcrete _ _ _ _ _ _ _ fs) = fs +instanceFromCategory :: AnyCategory c -> GeneralInstance+instanceFromCategory t = singleType $ JustTypeInstance $ TypeInstance n (Positional ps) where+  n = getCategoryName t+  ps = map (singleType . JustParamName True . vpParam) $ getCategoryParams t+ getCategoryDeps :: AnyCategory c -> Set.Set CategoryName getCategoryDeps t = Set.fromList $ filter (/= getCategoryName t) $ refines ++ defines ++ filters ++ functions where   refines = concat $ map (fromInstance . singleType . JustTypeInstance . vrType) $ getCategoryRefines t@@ -384,12 +391,12 @@ checkFilters :: CollectErrorsM m =>   AnyCategory c -> Positional GeneralInstance -> m (Positional [TypeFilter]) checkFilters t ps = do-  let params = map vpParam $ getCategoryParams t-  assigned <- fmap Map.fromList $ processPairs alwaysPair (Positional params) ps-  fs <- mapErrorsM (subSingleFilter assigned . \f -> (pfParam f,pfFilter f))-                                  (getCategoryFilters t)+  assigned <- fmap (Map.insert ParamSelf selfType . Map.fromList) $ processPairs alwaysPair (Positional params) ps+  fs <- mapErrorsM (subSingleFilter assigned . \f -> (pfParam f,pfFilter f)) allFilters   let fa = Map.fromListWith (++) $ map (second (:[])) fs   fmap Positional $ mapErrorsM (assignFilter fa) params where+    params = map vpParam $ getCategoryParams t+    allFilters = getCategoryFilters t ++ map (ParamFilter (getCategoryContext t) ParamSelf) (getSelfFilters t)     subSingleFilter pa (n,(TypeFilter v t2)) = do       t3<- uncheckedSubInstance (getValueForParam pa) t2       return (n,(TypeFilter v t3))@@ -401,6 +408,20 @@             (Just x) -> return x             _ -> return [] +getSelfFilters :: AnyCategory c -> [TypeFilter]+getSelfFilters t = selfFilters where+  params = map vpParam $ getCategoryParams t+  selfParams = Positional $ map (singleType . JustParamName False) params+  selfFilters+    | isInstanceInterface t = [+        DefinesFilter $ DefinesInstance (getCategoryName t) selfParams+      ] ++ inheritedFilters+    | otherwise = [+        TypeFilter FilterRequires $ singleType $ JustTypeInstance $ TypeInstance (getCategoryName t) selfParams+      ] ++ inheritedFilters+  inheritedFilters = map (DefinesFilter . vdType) (getCategoryDefines t) +++                     map (TypeFilter FilterRequires . singleType . JustTypeInstance . vrType) (getCategoryRefines t)+ subAllParams :: CollectErrorsM m =>   ParamValues -> GeneralInstance -> m GeneralInstance subAllParams pa = uncheckedSubInstance (getValueForParam pa)@@ -465,9 +486,9 @@   update t tm =     case getCategoryName t `Map.lookup` tm of         (Just t2) -> compilerErrorM $ "Type " ++ show (getCategoryName t) ++-                                     formatFullContextBrace (getCategoryContext t) ++-                                     " has already been declared" ++-                                     formatFullContextBrace (getCategoryContext t2)+                                      formatFullContextBrace (getCategoryContext t) +++                                      " has already been declared" +++                                      formatFullContextBrace (getCategoryContext t2)         _ -> return $ Map.insert (getCategoryName t) t tm  getFilterMap :: CollectErrorsM m => [ValueParam c] -> [ParamFilter c] -> m ParamFilters@@ -488,7 +509,9 @@                              Map.fromListWith (++) $ map (second (:[])) fs' ++ pa0  getCategoryFilterMap :: CollectErrorsM m => AnyCategory c -> m ParamFilters-getCategoryFilterMap t = getFilterMap (getCategoryParams t) (getCategoryFilters t)+getCategoryFilterMap t = do+  defaultMap <- getFilterMap (getCategoryParams t) (getCategoryFilters t)+  return $ Map.insert ParamSelf (getSelfFilters t) defaultMap  -- TODO: Use this where it's needed in this file. getFunctionFilterMap :: CollectErrorsM m => ScopedFunction c -> m ParamFilters@@ -496,7 +519,7 @@  getCategoryParamMap :: AnyCategory c -> ParamValues getCategoryParamMap t = let ps = map vpParam $ getCategoryParams t in-                          Map.fromList $ zip ps (map (singleType . JustParamName False) ps)+  Map.fromList $ zip ps (map (singleType . JustParamName False) ps) ++ [(ParamSelf,selfType)]  disallowBoundedParams :: CollectErrorsM m => ParamFilters -> m () disallowBoundedParams = mapErrorsM_ checkBounds . Map.toList where@@ -672,7 +695,7 @@       mapErrorsM_ (validateCategoryFunction r t) (getCategoryFunctions t)     checkFilterParam pa (ParamFilter c n _) =       when (not $ n `Set.member` pa) $-        compilerErrorM $ "Param " ++ show n ++ formatFullContextBrace c ++ " does not exist"+        compilerErrorM $ "Param " ++ show n ++ formatFullContextBrace c ++ " not found"     checkRefine r fm (ValueRefine c t) =       validateTypeInstance r fm t <??         ("In " ++ show t ++ formatFullContextBrace c)@@ -831,7 +854,7 @@       (_,v) <- getValueCategory tm (c,n)       let ns = map vpParam $ getCategoryParams v       paired <- processPairs alwaysPair (Positional ns) ps-      return $ Map.fromList paired+      return $ Map.insert ParamSelf selfType $ Map.fromList paired     checkMerged r fm rs rs2 = do       let rm = Map.fromList $ map (\t -> (tiName $ vrType t,t)) rs       mapErrorsM_ (\t -> checkConvert r fm (tiName (vrType t) `Map.lookup` rm) t) rs2@@ -858,14 +881,14 @@       let ps = map vpParam $ getCategoryParams t       let fs2 = getCategoryFunctions t       paired <- processPairs alwaysPair (Positional ps) ts2-      let assigned = Map.fromList paired+      let assigned = Map.fromList $ (ParamSelf,selfType):paired       mapErrorsM (unfixedSubFunction assigned) fs2     getDefinesFuncs tm2 (ValueDefine c (DefinesInstance n ts2)) = do       (_,t) <- getInstanceCategory tm2 (c,n)       let ps = map vpParam $ getCategoryParams t       let fs2 = getCategoryFunctions t       paired <- processPairs alwaysPair (Positional ps) ts2-      let assigned = Map.fromList paired+      let assigned = Map.fromList $ (ParamSelf,selfType):paired       mapErrorsM (unfixedSubFunction assigned) fs2     mergeByName r2 fm2 im em n =       tryMerge r2 fm2 n (n `Map.lookup` im) (n `Map.lookup` em)@@ -873,15 +896,15 @@     tryMerge _ _ n (Just is) Nothing       | length is == 1 = return $ head is       | otherwise = compilerErrorM $ "Function " ++ show n ++ " is inherited " ++-                                   show (length is) ++ " times:\n---\n" ++-                                   intercalate "\n---\n" (map show is)+                                     show (length is) ++ " times:\n---\n" +++                                     intercalate "\n---\n" (map show is)     -- Not inherited.     tryMerge r2 fm2 n Nothing es = tryMerge r2 fm2 n (Just []) es     -- Explicit override, possibly inherited.     tryMerge r2 fm2 n (Just is) (Just es)       | length es /= 1 = compilerErrorM $ "Function " ++ show n ++ " is declared " ++-                                        show (length es) ++ " times:\n---\n" ++-                                        intercalate "\n---\n" (map show es)+                                          show (length es) ++ " times:\n---\n" +++                                          intercalate "\n---\n" (map show es)       | otherwise = do         let ff@(ScopedFunction c n2 t s as rs2 ps fa ms) = head es         mapErrorsM_ (checkMerge r2 fm2 ff) is@@ -890,8 +913,8 @@           checkMerge r3 fm3 f1 f2             | sfScope f1 /= sfScope f2 =               compilerErrorM $ "Cannot merge " ++ show (sfScope f2) ++ " with " ++-                             show (sfScope f1) ++ " in function merge:\n---\n" ++-                             show f2 ++ "\n  ->\n" ++ show f1+                               show (sfScope f1) ++ " in function merge:\n---\n" +++                               show f2 ++ "\n  ->\n" ++ show f1             | otherwise =               ("In function merge:\n---\n" ++ show f2 ++                "\n  ->\n" ++ show f1 ++ "\n---\n") ??> do@@ -1005,6 +1028,23 @@         return $ PassedValue c2 t'       subFilter pa2 (ParamFilter c2 n2 f) = do         f' <- uncheckedSubFilter (getValueForParam pa2) f+        return $ ParamFilter c2 n2 f'++replaceSelfFunction :: (Show c, CollectErrorsM m) =>+  GeneralInstance -> ScopedFunction c -> m (ScopedFunction c)+replaceSelfFunction self ff@(ScopedFunction c n t s as rs ps fa ms) =+  ("In function:\n---\n" ++ show ff ++ "\n---\n") ??> do+    as' <- fmap Positional $ mapErrorsM subPassed $ pValues as+    rs' <- fmap Positional $ mapErrorsM subPassed $ pValues rs+    fa' <- mapErrorsM subFilter fa+    ms' <- mapErrorsM (replaceSelfFunction self) ms+    return $ (ScopedFunction c n t s as' rs' ps fa' ms')+    where+      subPassed (PassedValue c2 t2) = do+        t' <- replaceSelfValueType self t2+        return $ PassedValue c2 t'+      subFilter (ParamFilter c2 n2 f) = do+        f' <- replaceSelfFilter self f         return $ ParamFilter c2 n2 f'  data PatternMatch a =
src/Types/TypeInstance.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2019-2020 Kevin P. Barry+Copyright 2019-2021 Kevin P. Barry  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -54,8 +54,13 @@   isWeakValue,   mapTypeGuesses,   noInferredTypes,+  replaceSelfFilter,+  replaceSelfInstance,+  replaceSelfSingle,+  replaceSelfValueType,   requiredParam,   requiredSingleton,+  selfType,   uncheckedSubFilter,   uncheckedSubFilters,   uncheckedSubInstance,@@ -147,15 +152,20 @@ instance Ord CategoryName where   c1 <= c2 = show c1 <= show c2 -newtype ParamName =+data ParamName =   ParamName {     pnName :: String-  }+  } |+  ParamSelf   deriving (Eq,Ord)  instance Show ParamName where   show (ParamName n) = n+  show ParamSelf     = "#self" +selfType :: GeneralInstance+selfType = singleType $ JustParamName True ParamSelf+ data TypeInstance =   TypeInstance {     tiName :: CategoryName,@@ -271,7 +281,7 @@   -- Performs parameter substitution for defines.   trDefines :: CollectErrorsM m =>     r -> TypeInstance -> CategoryName -> m InstanceParams-  -- Get the parameter variances for the category.+  -- Gets the parameter variances for the category.   trVariance :: CollectErrorsM m =>     r -> CategoryName -> m InstanceVariances   -- Gets filters for the assigned parameters.@@ -305,7 +315,7 @@ getValueForParam pa n =   case n `Map.lookup` pa of        (Just x) -> return x-       _ -> compilerErrorM $ "Param " ++ show n ++ " does not exist"+       _ -> compilerErrorM $ "Param " ++ show n ++ " not found"  fixTypeParams :: GeneralInstance -> GeneralInstance fixTypeParams = setParamsFixed True@@ -535,7 +545,7 @@ validateGeneralInstance r f = reduceMergeTree collectAllM_ collectAllM_ validateSingle where   validateSingle (JustTypeInstance t) = validateTypeInstance r f t   validateSingle (JustParamName _ n) = when (not $ n `Map.member` f) $-      compilerErrorM $ "Param " ++ show n ++ " does not exist"+      compilerErrorM $ "Param " ++ show n ++ " not found"   validateSingle (JustInferredType n) = compilerErrorM $ "Inferred param " ++ show n ++ " is not allowed here"  validateTypeInstance :: (CollectErrorsM m, TypeResolver r) =>@@ -590,12 +600,13 @@ validateInstanceVariance :: (CollectErrorsM m, TypeResolver r) =>   r -> ParamVariances -> Variance -> GeneralInstance -> m () validateInstanceVariance r vm v = reduceMergeTree collectAllM_ collectAllM_ validateSingle where+  vm' = Map.insert ParamSelf Covariant vm   validateSingle (JustTypeInstance (TypeInstance n ps)) = do     vs <- trVariance r n     paired <- processPairs alwaysPair vs ps-    mapErrorsM_ (\(v2,p) -> validateInstanceVariance r vm (v `composeVariance` v2) p) paired+    mapErrorsM_ (\(v2,p) -> validateInstanceVariance r vm' (v `composeVariance` v2) p) paired   validateSingle (JustParamName _ n) =-    case n `Map.lookup` vm of+    case n `Map.lookup` vm' of         Nothing -> compilerErrorM $ "Param " ++ show n ++ " is undefined"         (Just v0) -> when (not $ v0 `allowsVariance` v) $                           compilerErrorM $ "Param " ++ show n ++ " cannot be " ++ show v@@ -607,7 +618,8 @@ validateDefinesVariance r vm v (DefinesInstance n ps) = do   vs <- trVariance r n   paired <- processPairs alwaysPair vs ps-  mapErrorsM_ (\(v2,p) -> validateInstanceVariance r vm (v `composeVariance` v2) p) paired+  mapErrorsM_ (\(v2,p) -> validateInstanceVariance r vm' (v `composeVariance` v2) p) paired where+    vm' = Map.insert ParamSelf Covariant vm  uncheckedSubValueType :: CollectErrorsM m =>   (ParamName -> m GeneralInstance) -> ValueType -> m ValueType@@ -621,10 +633,11 @@   -- NOTE: Don't use mergeAnyM because it will fail if the union is empty.   subAny = fmap mergeAny . sequence   subAll = fmap mergeAll . sequence-  subSingle p@(JustParamName True _) = return $ singleType p-  subSingle (JustParamName _ n)      = replace n-  subSingle (JustInferredType n)     = replace n-  subSingle (JustTypeInstance t)     = fmap (singleType . JustTypeInstance) $ uncheckedSubSingle replace t+  subSingle p@(JustParamName _ ParamSelf) = return $ singleType p+  subSingle p@(JustParamName True _)      = return $ singleType p+  subSingle (JustParamName _ n)           = replace n+  subSingle (JustInferredType n)          = replace n+  subSingle (JustTypeInstance t)          = fmap (singleType . JustTypeInstance) $ uncheckedSubSingle replace t  uncheckedSubSingle :: CollectErrorsM m => (ParamName -> m GeneralInstance) ->   TypeInstance -> m TypeInstance@@ -650,3 +663,34 @@     subParam (n,fs) = do       fs' <- mapErrorsM (uncheckedSubFilter replace) fs       return (n,fs')++replaceSelfValueType :: CollectErrorsM m =>+  GeneralInstance -> ValueType -> m ValueType+replaceSelfValueType self (ValueType s t) = do+  t' <- replaceSelfInstance self t+  return $ ValueType s t'++replaceSelfInstance :: CollectErrorsM m =>+  GeneralInstance -> GeneralInstance -> m GeneralInstance+replaceSelfInstance self = reduceMergeTree subAny subAll subSingle where+  -- NOTE: Don't use mergeAnyM because it will fail if the union is empty.+  subAny = fmap mergeAny . sequence+  subAll = fmap mergeAll . sequence+  subSingle (JustParamName _ ParamSelf) = return self+  subSingle (JustTypeInstance t)        = fmap (singleType . JustTypeInstance) $ replaceSelfSingle self t+  subSingle p                           = return $ singleType p++replaceSelfSingle :: CollectErrorsM m =>+  GeneralInstance -> TypeInstance -> m TypeInstance+replaceSelfSingle self (TypeInstance n (Positional ts)) = do+  ts' <- mapErrorsM (replaceSelfInstance self) ts+  return $ TypeInstance n (Positional ts')++replaceSelfFilter :: CollectErrorsM m =>+  GeneralInstance -> TypeFilter -> m TypeFilter+replaceSelfFilter self (TypeFilter d t) = do+  t' <- replaceSelfInstance self t+  return (TypeFilter d t')+replaceSelfFilter self (DefinesFilter (DefinesInstance n ts)) = do+  ts' <- mapErrorsM (replaceSelfInstance self) (pValues ts)+  return (DefinesFilter (DefinesInstance n (Positional ts')))
+ tests/self-type.0rt view
@@ -0,0 +1,478 @@+/* -----------------------------------------------------------------------------+Copyright 2021 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++    http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++testcase "disallowed in @category functions" {+  error+  require "#self not found"+}++concrete Type {+  @category call () -> (#self)+}++define Type {+  call () {+    fail("")+  }+}+++testcase "disallowed in @category members" {+  error+  require "#self not found"+}++concrete Type {+  @type create () -> (#self)+}++define Type {+  @category #self value <- Type.create()++  create () {+    return Type{ }+  }+}+++testcase "disallowed in @category procedures" {+  error+  require "#self not found"+}++concrete Type {+  @category call () -> ()+}++define Type {+  call () {+    optional #self value <- empty+  }+}+++testcase "in @type functions" {+  success+}++unittest test {+  Type value <- Type.create()+}++concrete Type {+  @type create () -> (#self)+}++define Type {+  create () {+    return Type{ }+  }+}+++testcase "as base for @type call" {+  success+}++unittest test {+  Type value <- Type.create()+}++concrete Type {+  @type create () -> (Type)+}++define Type {+  create () {+    return #self.new()+  }++  @type new () -> (Type)+  new () {+    return Type{ }+  }+}+++testcase "in @value functions" {+  success+}++unittest test {+  Type value <- Type.create().call()+}++concrete Type {+  @type create () -> (Type)+  @value call () -> (#self)+}++define Type {+  create () {+    return Type{ }+  }++  call () {+    return self+  }+}+++testcase "in @value members" {+  success+}++unittest test {+  Type value <- Type.create(Type.create(empty))+}++concrete Type {+  @type create (optional Type) -> (Type)+}++define Type {+  @value optional #self parent++  create (p) {+    return Type{ p }+  }+}+++testcase "in local variables in @type procedures" {+  success+}++unittest test {+  Type value <- Type.create()+}++concrete Type {+  @type create () -> (Type)+}++define Type {+  create () {+    #self new <- Type{ }+    return new+  }+}+++testcase "in local variables in @value procedures" {+  success+}++unittest test {+  Type value <- Type.create()+}++concrete Type {+  @type create () -> (Type)+  @value get () -> (Type)+}++define Type {+  create () {+    return Type{ }+  }++  get () {+    #self me <- self+    return me+  }+}+++testcase "in local variables in scoped" {+  success+}++unittest test {+  Type value <- Type.create()+}++concrete Type {+  @type create () -> (Type)+}++define Type {+  create () {+    scoped {+    } in #self new <- Type{ }+    return new+  }+}+++testcase "in reduce" {+  success+}++unittest test {+  Type<String>    value1 <- Type<String>.create()+  Type<Formatted> value2 <- Type<Formatted>.create()+  \ Testing.checkEquals<?>(value1.checkFrom<Type<Formatted>>(),true)+  \ Testing.checkEquals<?>(value2.checkFrom<Type<String>>(),false)+  \ Testing.checkEquals<?>(value1.checkTo<?>(value2),false)+  \ Testing.checkEquals<?>(value2.checkTo<?>(value1),true)+}++concrete Type<|#x> {+  @type create () -> (Type<#x>)+  @value checkFrom<#y> () -> (Bool)+  @value checkTo<#y> (#y) -> (Bool)+}++define Type {+  create () {+    return Type<#x>{ }+  }++  checkFrom () {+    return present(reduce<#self,#y>(self))+  }++  checkTo (from) {+    return present(reduce<#y,#self>(from))+  }+}+++testcase "in typename" {+  success+}++unittest test {+  \ Testing.checkEquals<?>(Type<Bool>.get(),"Type<Type<Bool>>")+}++concrete Type<#x> {+  @type get () -> (String)+}++define Type {+  get () {+    return typename<Type<#self>>().formatted()+  }+}+++testcase "with type inference" {+  success+}++unittest test {+  \ Type.create().call<?>("message")+}++concrete Type {+  @type create () -> (Type)+  @value call<#x> (#x) -> (#self)+}++define Type {+  create () {+    return Type{ }+  }++  call (_) {+    return self+  }+}+++testcase "as an explicit function param" {+  success+}++unittest test {+  \ Type.create().call()+}++concrete Test {+  @type identity<#x> (#x) -> (#x)+}++define Test {+  identity (x) {+    return x+  }+}++concrete Type {+  @type create () -> (Type)+  @value call () -> ()+}++define Type {+  create () {+    return Type{ }+  }++  call () {+    Type me <- Test.identity<#self>(self)+  }+}+++testcase "nested in initializer type" {+  success+}++unittest test {+  Type<Type<String>> value <- Type<String>.create().nest()+}++concrete Type<|#x> {+  @type create () -> (#self)+  @value nest () -> (Type<#self>)+}++define Type {+  create () {+    return Type<#x>{ }+  }++  nest () {+    return Type<#self>{ }+  }+}+++testcase "top level initializer type" {+  success+}++unittest test {+  Type<String> value <- Type<String>.create()+}++concrete Type<|#x> {+  @type create () -> (#self)+}++define Type {+  create () {+    return #self{ }+  }+}+++testcase "preserves type in implementations" {+  success+}++unittest test {+  Type value <- Type.create()+  \ Testing.checkEquals<?>(value.next().prev().prev().next().next().get(),1)+}++@value interface Forward {+  next () -> (#self)+}++@value interface Reverse {+  prev () -> (#self)+}++concrete Type {+  refines Forward+  refines Reverse++  @type create () -> (Type)+  @value get () -> (Int)+}++define Type {+  @value Int num++  create () {+    return Type{ 0 }+  }++  get () {+    return num+  }++  next () {+    num <- num+1+    return self+  }++  prev () {+    num <- num-1+    return self+  }+}+++testcase "preserves type in function param filter" {+  success+}++unittest test {+  Type value <- Type.create()+  \ Testing.checkEquals<?>((value `Advance.by<?>` 3).get(),3)+}++@value interface Forward {+  next () -> (#self)+}++concrete Advance {+  @type by<#x>+    #x requires Forward+  (#x,Int) -> (#x)+}++define Advance {+  by (x,i) (x2) {+    x2 <- x+    scoped {+      Int count <- 0+    } in while (count < i) {+      x2 <- x2.next()+    } update {+      count <- count+1+    }+  }+}++concrete Type {+  refines Forward++  @type create () -> (Type)+  @value get () -> (Int)+}++define Type {+  @value Int num++  create () {+    return Type{ 0 }+  }++  get () {+    return num+  }++  next () {+    return Type{ num+1 }+  }+}
zeolite-lang.cabal view
@@ -1,7 +1,7 @@ cabal-version:       2.2  name:                zeolite-lang-version:             0.13.0.0+version:             0.14.0.0 synopsis:            Zeolite is a statically-typed, general-purpose programming language.  description: