zeolite-lang 0.15.0.0 → 0.16.0.0
raw patch · 145 files changed
+4458/−2129 lines, 145 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Compilation.CompilerState: type ExpressionType = Positional ValueType
- Compilation.ProcedureContext: [_pcIntFilters] :: ProcedureContext c -> [ParamFilter c]
- Compilation.ProcedureContext: [_pcIntParams] :: ProcedureContext c -> Positional (ValueParam c)
- Compilation.ScopeContext: [scExternalFilters] :: ScopeContext c -> [ParamFilter c]
- Compilation.ScopeContext: [scExternalParams] :: ScopeContext c -> Positional (ValueParam c)
- Compilation.ScopeContext: [scInternalFilters] :: ScopeContext c -> [ParamFilter c]
- Compilation.ScopeContext: [scInternalparams] :: ScopeContext c -> Positional (ValueParam c)
- CompilerCxx.Code: BoxedPrimitive :: PrimitiveType -> String -> ExprValue
- CompilerCxx.Code: LazySingle :: ExprValue -> ExprValue
- CompilerCxx.Code: OpaqueMulti :: String -> ExprValue
- CompilerCxx.Code: PrimBool :: PrimitiveType
- CompilerCxx.Code: PrimChar :: PrimitiveType
- CompilerCxx.Code: PrimFloat :: PrimitiveType
- CompilerCxx.Code: PrimInt :: PrimitiveType
- CompilerCxx.Code: PrimString :: PrimitiveType
- CompilerCxx.Code: UnboxedPrimitive :: PrimitiveType -> String -> ExprValue
- CompilerCxx.Code: UnwrappedSingle :: String -> ExprValue
- CompilerCxx.Code: WrappedSingle :: String -> ExprValue
- CompilerCxx.Code: data ExprValue
- CompilerCxx.Code: data PrimitiveType
- CompilerCxx.Code: instance GHC.Classes.Eq CompilerCxx.Code.PrimitiveType
- CompilerCxx.Code: instance GHC.Show.Show CompilerCxx.Code.ExprValue
- CompilerCxx.Code: instance GHC.Show.Show CompilerCxx.Code.PrimitiveType
- CompilerCxx.Code: isPrimType :: ValueType -> Bool
- Parser.Procedure: instance Parser.Common.ParseFromSource (Types.Procedure.WhileLoop Parser.TextParser.SourceContext)
- Test.Common: parseTheTest :: ParseFromSource a => [(String, [String])] -> [String] -> TrackedErrors ([a], ParamFilters)
- Types.Builtin: emptyValue :: ValueType
- Types.DefinedCategory: [dcParamFilter] :: DefinedCategory c -> [ParamFilter c]
- Types.DefinedCategory: [dcParams] :: DefinedCategory c -> [ValueParam c]
- Types.Procedure: data WhileLoop c
- Types.Procedure: instance GHC.Show.Show c => GHC.Show.Show (Types.Procedure.WhileLoop c)
- Types.TypeCategory: [iiParamFilter] :: AnyCategory c -> [ParamFilter c]
- Types.TypeCategory: [viParamFilter] :: AnyCategory c -> [ParamFilter c]
- Types.TypeCategory: instance (GHC.Enum.Bounded a, GHC.Classes.Eq a, GHC.Show.Show a) => GHC.Show.Show (Types.TypeCategory.GuessRange a)
+ Cli.CompileOptions: [etCallLog] :: CompileMode -> Maybe FilePath
+ Cli.CompileOptions: isCompileUnspecified :: CompileMode -> Bool
+ Compilation.ScopeContext: [scFilters] :: ScopeContext c -> [ParamFilter c]
+ Compilation.ScopeContext: [scParams] :: ScopeContext c -> Positional (ValueParam c)
+ CompilerCxx.Naming: hiddenVariableName :: VariableName -> String
+ Parser.Common: kwTraverse :: TextParser ()
+ Parser.Procedure: instance Parser.Common.ParseFromSource (Types.Procedure.IteratedLoop Parser.TextParser.SourceContext)
+ Test.Common: parseTestWithFilters :: ParseFromSource a => [(String, [String])] -> [String] -> TrackedErrors ([a], ParamFilters)
+ Test.Common: showFilters :: [(String, [String])] -> String
+ Types.Builtin: BoxedPrimitive :: PrimitiveType -> String -> ExpressionValue
+ Types.Builtin: LazySingle :: ExpressionValue -> ExpressionValue
+ Types.Builtin: OpaqueMulti :: String -> ExpressionValue
+ Types.Builtin: PrimBool :: PrimitiveType
+ Types.Builtin: PrimChar :: PrimitiveType
+ Types.Builtin: PrimFloat :: PrimitiveType
+ Types.Builtin: PrimInt :: PrimitiveType
+ Types.Builtin: PrimString :: PrimitiveType
+ Types.Builtin: UnboxedPrimitive :: PrimitiveType -> String -> ExpressionValue
+ Types.Builtin: UnwrappedSingle :: String -> ExpressionValue
+ Types.Builtin: WrappedSingle :: String -> ExpressionValue
+ Types.Builtin: data ExpressionValue
+ Types.Builtin: data PrimitiveType
+ Types.Builtin: emptyType :: ValueType
+ Types.Builtin: instance GHC.Classes.Eq Types.Builtin.PrimitiveType
+ Types.Builtin: instance GHC.Show.Show Types.Builtin.ExpressionValue
+ Types.Builtin: instance GHC.Show.Show Types.Builtin.PrimitiveType
+ Types.Builtin: isPrimitiveType :: ValueType -> Bool
+ Types.Builtin: orderOptionalValue :: GeneralInstance -> ValueType
+ Types.DefinedCategory: MembersHidden :: [c] -> [VariableName] -> PragmaDefined c
+ Types.DefinedCategory: MembersReadOnly :: [c] -> [VariableName] -> PragmaDefined c
+ Types.DefinedCategory: [dcPragmas] :: DefinedCategory c -> [PragmaDefined c]
+ Types.DefinedCategory: [mhContext] :: PragmaDefined c -> [c]
+ Types.DefinedCategory: [mhMembers] :: PragmaDefined c -> [VariableName]
+ Types.DefinedCategory: [mroContext] :: PragmaDefined c -> [c]
+ Types.DefinedCategory: [mroMembers] :: PragmaDefined c -> [VariableName]
+ Types.DefinedCategory: data PragmaDefined c
+ Types.DefinedCategory: instance GHC.Show.Show c => GHC.Show.Show (Types.DefinedCategory.PragmaDefined c)
+ Types.DefinedCategory: isMembersHidden :: PragmaDefined c -> Bool
+ Types.DefinedCategory: isMembersReadOnly :: PragmaDefined c -> Bool
+ Types.Procedure: RawExpression :: ExpressionType -> ExpressionValue -> Expression c
+ Types.Procedure: TraverseLoop :: [c] -> Expression c -> [c] -> Assignable c -> Procedure c -> IteratedLoop c
+ Types.Procedure: data IteratedLoop c
+ Types.Procedure: instance GHC.Show.Show c => GHC.Show.Show (Types.Procedure.IteratedLoop c)
+ Types.Procedure: type ExpressionType = Positional ValueType
+ Types.TypeCategory: getCategoryParamSet :: CollectErrorsM m => AnyCategory c -> m (Set ParamName)
+ Types.TypeCategory: instance GHC.Show.Show a => GHC.Show.Show (Types.TypeCategory.GuessRange a)
+ Types.TypeInstance: BuiltinOrder :: CategoryName
+ Types.TypeInstance: validateGeneralInstanceForCall :: (CollectErrorsM m, TypeResolver r) => r -> ParamFilters -> GeneralInstance -> m ()
+ Types.TypeInstance: validateTypeInstanceForCall :: (CollectErrorsM m, TypeResolver r) => r -> ParamFilters -> TypeInstance -> m ()
- Cli.CompileOptions: ExecuteTests :: [FilePath] -> CompileMode
+ Cli.CompileOptions: ExecuteTests :: [FilePath] -> Maybe FilePath -> CompileMode
- Cli.Compiler: runModuleTests :: (PathIOHandler r, CompilerBackend b) => r -> b -> FilePath -> [FilePath] -> LoadedTests -> TrackedErrorsIO [((Int, Int), TrackedErrors ())]
+ Cli.Compiler: runModuleTests :: (PathIOHandler r, CompilerBackend b) => r -> b -> FilePath -> FilePath -> [FilePath] -> LoadedTests -> TrackedErrorsIO [((Int, Int), TrackedErrors ())]
- Cli.TestRunner: runSingleTest :: CompilerBackend b => b -> LanguageModule SourceContext -> FilePath -> [FilePath] -> [CompileMetadata] -> (String, String) -> TrackedErrorsIO ((Int, Int), TrackedErrors ())
+ Cli.TestRunner: runSingleTest :: CompilerBackend b => b -> FilePath -> LanguageModule SourceContext -> FilePath -> [FilePath] -> [CompileMetadata] -> (String, String) -> TrackedErrorsIO ((Int, Int), TrackedErrors ())
- Compilation.CompilerState: ccCheckValueInit :: CompilerContext c m s a => a -> [c] -> TypeInstance -> ExpressionType -> Positional GeneralInstance -> m ()
+ Compilation.CompilerState: ccCheckValueInit :: CompilerContext c m s a => a -> [c] -> TypeInstance -> ExpressionType -> m ()
- Compilation.CompilerState: csCheckValueInit :: CompilerContext c m s a => [c] -> TypeInstance -> ExpressionType -> Positional GeneralInstance -> CompilerState a m ()
+ Compilation.CompilerState: csCheckValueInit :: CompilerContext c m s a => [c] -> TypeInstance -> ExpressionType -> CompilerState a m ()
- Compilation.ProcedureContext: ProcedureContext :: SymbolScope -> CategoryName -> Positional (ValueParam c) -> Positional (ValueParam c) -> [DefinedMember c] -> CategoryMap c -> ParamFilters -> [ParamFilter c] -> [ParamFilter c] -> Map ParamName SymbolScope -> Map FunctionName (ScopedFunction c) -> Map VariableName (VariableValue c) -> ReturnValidation c -> JumpType -> Bool -> [ReturnVariable] -> Set CategoryName -> [String] -> Bool -> LoopSetup [String] -> [Maybe (CleanupBlock c [String])] -> Bool -> [UsedVariable c] -> ExprMap c -> [(MacroName, [c])] -> Bool -> ProcedureContext c
+ Compilation.ProcedureContext: ProcedureContext :: SymbolScope -> CategoryName -> Positional (ValueParam c) -> [DefinedMember c] -> CategoryMap c -> ParamFilters -> [ParamFilter c] -> Map ParamName SymbolScope -> Map FunctionName (ScopedFunction c) -> Map VariableName (VariableValue c) -> ReturnValidation c -> JumpType -> Bool -> [ReturnVariable] -> Set CategoryName -> [String] -> Bool -> LoopSetup [String] -> [Maybe (CleanupBlock c [String])] -> Bool -> [UsedVariable c] -> ExprMap c -> [(MacroName, [c])] -> Bool -> ProcedureContext c
- Compilation.ScopeContext: ScopeContext :: CategoryMap c -> CategoryName -> Positional (ValueParam c) -> Positional (ValueParam c) -> [DefinedMember c] -> [ParamFilter c] -> [ParamFilter c] -> Map FunctionName (ScopedFunction c) -> Map VariableName (VariableValue c) -> ExprMap c -> ScopeContext c
+ Compilation.ScopeContext: ScopeContext :: CategoryMap c -> CategoryName -> Positional (ValueParam c) -> [DefinedMember c] -> [ParamFilter c] -> Map FunctionName (ScopedFunction c) -> Map VariableName (VariableValue c) -> ExprMap c -> ScopeContext c
- CompilerCxx.Code: captureCreationTrace :: String
+ CompilerCxx.Code: captureCreationTrace :: CategoryName -> String
- CompilerCxx.Code: readStoredVariable :: Bool -> ValueType -> String -> ExprValue
+ CompilerCxx.Code: readStoredVariable :: Bool -> ValueType -> String -> ExpressionValue
- CompilerCxx.Code: startFunctionTracing :: ScopedFunction c -> String
+ CompilerCxx.Code: startFunctionTracing :: CategoryName -> ScopedFunction c -> String
- CompilerCxx.Code: useAsArgs :: ExprValue -> String
+ CompilerCxx.Code: useAsArgs :: ExpressionValue -> String
- CompilerCxx.Code: useAsReturns :: ExprValue -> String
+ CompilerCxx.Code: useAsReturns :: ExpressionValue -> String
- CompilerCxx.Code: useAsUnboxed :: PrimitiveType -> ExprValue -> String
+ CompilerCxx.Code: useAsUnboxed :: PrimitiveType -> ExpressionValue -> String
- CompilerCxx.Code: useAsUnwrapped :: ExprValue -> String
+ CompilerCxx.Code: useAsUnwrapped :: ExpressionValue -> String
- CompilerCxx.Code: useAsWhatever :: ExprValue -> String
+ CompilerCxx.Code: useAsWhatever :: ExpressionValue -> String
- CompilerCxx.Code: valueAsUnwrapped :: ExprValue -> ExprValue
+ CompilerCxx.Code: valueAsUnwrapped :: ExpressionValue -> ExpressionValue
- CompilerCxx.Code: valueAsWrapped :: ExprValue -> ExprValue
+ CompilerCxx.Code: valueAsWrapped :: ExpressionValue -> ExpressionValue
- CompilerCxx.Code: writeStoredVariable :: ValueType -> ExprValue -> String
+ CompilerCxx.Code: writeStoredVariable :: ValueType -> ExpressionValue -> String
- CompilerCxx.CxxFiles: generateNativeInterface :: (Ord c, Show c, CollectErrorsM m) => Bool -> AnyCategory c -> m [CxxOutput]
+ CompilerCxx.CxxFiles: generateNativeInterface :: (Ord c, Show c, CollectErrorsM m) => Bool -> Set Namespace -> AnyCategory c -> m [CxxOutput]
- CompilerCxx.CxxFiles: generateStreamlinedExtension :: (Ord c, Show c, CollectErrorsM m) => Bool -> AnyCategory c -> m [CxxOutput]
+ CompilerCxx.CxxFiles: generateStreamlinedExtension :: (Ord c, Show c, CollectErrorsM m) => Bool -> Set Namespace -> AnyCategory c -> m [CxxOutput]
- CompilerCxx.CxxFiles: generateStreamlinedTemplate :: (Ord c, Show c, CollectErrorsM m) => FileContext c -> AnyCategory c -> m [CxxOutput]
+ CompilerCxx.CxxFiles: generateStreamlinedTemplate :: (Ord c, Show c, CollectErrorsM m) => Bool -> CategoryMap c -> AnyCategory c -> m [CxxOutput]
- CompilerCxx.Naming: functionDebugName :: ScopedFunction c -> String
+ CompilerCxx.Naming: functionDebugName :: CategoryName -> ScopedFunction c -> String
- Test.Common: checkDefinesFail :: TypeResolver r => r -> [(String, [String])] -> String -> TrackedErrors ()
+ Test.Common: checkDefinesFail :: TypeResolver r => r -> [String] -> String -> TrackedErrors ()
- Test.Common: checkDefinesSuccess :: TypeResolver r => r -> [(String, [String])] -> String -> TrackedErrors ()
+ Test.Common: checkDefinesSuccess :: TypeResolver r => r -> [String] -> String -> TrackedErrors ()
- Test.Common: checkTypeFail :: TypeResolver r => r -> [(String, [String])] -> String -> TrackedErrors ()
+ Test.Common: checkTypeFail :: TypeResolver r => r -> [String] -> String -> TrackedErrors ()
- Test.Common: checkTypeSuccess :: TypeResolver r => r -> [(String, [String])] -> String -> TrackedErrors ()
+ Test.Common: checkTypeSuccess :: TypeResolver r => r -> [String] -> String -> TrackedErrors ()
- Test.Common: showParams :: [(String, [String])] -> String
+ Test.Common: showParams :: [String] -> String
- Types.DefinedCategory: DefinedCategory :: [c] -> CategoryName -> [ValueParam c] -> [ValueRefine c] -> [ValueDefine c] -> [ParamFilter c] -> [DefinedMember c] -> [ExecutableProcedure c] -> [ScopedFunction c] -> DefinedCategory c
+ Types.DefinedCategory: DefinedCategory :: [c] -> CategoryName -> [PragmaDefined c] -> [ValueRefine c] -> [ValueDefine c] -> [DefinedMember c] -> [ExecutableProcedure c] -> [ScopedFunction c] -> DefinedCategory c
- Types.DefinedCategory: mapMembers :: (Show c, CollectErrorsM m) => [DefinedMember c] -> m (Map VariableName (VariableValue c))
+ Types.DefinedCategory: mapMembers :: (Show c, CollectErrorsM m) => Map VariableName [c] -> Map VariableName [c] -> [DefinedMember c] -> m (Map VariableName (VariableValue c))
- Types.Function: validatateFunctionType :: (CollectErrorsM m, TypeResolver r) => r -> ParamFilters -> ParamVariances -> FunctionType -> m ()
+ Types.Function: validatateFunctionType :: (CollectErrorsM m, TypeResolver r) => r -> Set ParamName -> ParamVariances -> FunctionType -> m ()
- Types.Procedure: InitializeValue :: [c] -> Maybe TypeInstance -> Positional GeneralInstance -> Positional (Expression c) -> Expression c
+ Types.Procedure: InitializeValue :: [c] -> Maybe TypeInstance -> Positional (Expression c) -> Expression c
- Types.Procedure: Loop :: WhileLoop c -> VoidExpression c
+ Types.Procedure: Loop :: IteratedLoop c -> VoidExpression c
- Types.Procedure: WhileLoop :: [c] -> Expression c -> Procedure c -> Maybe (Procedure c) -> WhileLoop c
+ Types.Procedure: WhileLoop :: [c] -> Expression c -> Procedure c -> Maybe (Procedure c) -> IteratedLoop c
- Types.TypeCategory: InstanceInterface :: [c] -> Namespace -> CategoryName -> [ValueParam c] -> [ParamFilter c] -> [ScopedFunction c] -> AnyCategory c
+ Types.TypeCategory: InstanceInterface :: [c] -> Namespace -> CategoryName -> [ValueParam c] -> [ScopedFunction c] -> AnyCategory c
- Types.TypeCategory: ValueInterface :: [c] -> Namespace -> CategoryName -> [ValueParam c] -> [ValueRefine c] -> [ParamFilter c] -> [ScopedFunction c] -> AnyCategory c
+ Types.TypeCategory: ValueInterface :: [c] -> Namespace -> CategoryName -> [ValueParam c] -> [ValueRefine c] -> [ScopedFunction c] -> AnyCategory c
- Types.TypeInstance: validateDefinesInstance :: (CollectErrorsM m, TypeResolver r) => r -> ParamFilters -> DefinesInstance -> m ()
+ Types.TypeInstance: validateDefinesInstance :: (CollectErrorsM m, TypeResolver r) => r -> Set ParamName -> DefinesInstance -> m ()
- Types.TypeInstance: validateGeneralInstance :: (CollectErrorsM m, TypeResolver r) => r -> ParamFilters -> GeneralInstance -> m ()
+ Types.TypeInstance: validateGeneralInstance :: (CollectErrorsM m, TypeResolver r) => r -> Set ParamName -> GeneralInstance -> m ()
- Types.TypeInstance: validateTypeFilter :: (CollectErrorsM m, TypeResolver r) => r -> ParamFilters -> TypeFilter -> m ()
+ Types.TypeInstance: validateTypeFilter :: (CollectErrorsM m, TypeResolver r) => r -> Set ParamName -> TypeFilter -> m ()
- Types.TypeInstance: validateTypeInstance :: (CollectErrorsM m, TypeResolver r) => r -> ParamFilters -> TypeInstance -> m ()
+ Types.TypeInstance: validateTypeInstance :: (CollectErrorsM m, TypeResolver r) => r -> Set ParamName -> TypeInstance -> m ()
Files
- ChangeLog.md +137/−0
- base/Category_Bool.cpp +50/−50
- base/Category_Char.cpp +56/−66
- base/Category_Float.cpp +51/−56
- base/Category_Int.cpp +56/−66
- base/Category_String.cpp +95/−70
- base/builtin.0rp +31/−0
- base/category-header.hpp +1/−5
- base/category-source.cpp +21/−0
- base/category-source.hpp +73/−0
- base/logging.cpp +54/−0
- base/logging.hpp +50/−12
- example/parser/parse-text.0rx +24/−23
- example/parser/test-data.0rx +19/−0
- example/primes/.zeolite-module +11/−0
- example/primes/README.md +57/−0
- example/primes/flag.0rp +32/−0
- example/primes/flag.0rx +64/−0
- example/primes/prime-thread.0rp +8/−0
- example/primes/prime-thread.0rx +14/−0
- example/primes/prime-tracker.0rp +9/−0
- example/primes/prime-tracker.0rx +46/−0
- example/primes/primes-demo.0rx +62/−0
- lib/container/interfaces.0rp +13/−0
- lib/container/search-tree.0rp +19/−1
- lib/container/search-tree.0rt +46/−2
- lib/container/search-tree.0rx +130/−17
- lib/container/src/Extension_Vector.cpp +41/−8
- lib/container/vector.0rp +3/−2
- lib/container/vector.0rt +19/−0
- lib/file/src/Extension_RawFileReader.cpp +7/−7
- lib/file/src/Extension_RawFileWriter.cpp +7/−7
- lib/math/src/Extension_Math.cpp +0/−4
- lib/testing/helpers.0rp +1/−1
- lib/thread/.zeolite-module +14/−0
- lib/thread/README.md +3/−5
- lib/thread/barrier-ext.0rp +23/−0
- lib/thread/barrier.0rp +46/−0
- lib/thread/barrier.0rt +178/−0
- lib/thread/condition.0rp +106/−0
- lib/thread/condition.0rt +179/−0
- lib/thread/mutex.0rt +0/−35
- lib/thread/src/Extension_Enumerated.cpp +194/−0
- lib/thread/src/Extension_MutexLock.cpp +8/−8
- lib/thread/src/Extension_ProcessThread.cpp +13/−13
- lib/thread/src/Extension_Realtime.cpp +69/−0
- lib/thread/src/Extension_SimpleMutex.cpp +4/−4
- lib/thread/src/Extension_ThreadCondition.cpp +164/−0
- lib/thread/testing.0rp +16/−0
- lib/thread/testing.0rx +35/−0
- lib/thread/thread.0rt +52/−8
- lib/thread/time.0rp +23/−0
- lib/thread/time.0rt +35/−0
- lib/util/counters.0rp +33/−0
- lib/util/counters.0rt +69/−0
- lib/util/counters.0rx +86/−0
- lib/util/extra.0rp +0/−1
- lib/util/src/Extension_Argv.cpp +7/−7
- lib/util/src/Extension_SimpleInput.cpp +2/−2
- lib/util/src/Extension_SimpleOutput.cpp +5/−5
- src/Cli/CompileOptions.hs +10/−4
- src/Cli/Compiler.hs +6/−6
- src/Cli/ParseCompileOptions.hs +21/−10
- src/Cli/RunCompiler.hs +11/−3
- src/Cli/TestRunner.hs +6/−6
- src/Compilation/CompilerState.hs +3/−7
- src/Compilation/ProcedureContext.hs +16/−29
- src/Compilation/ScopeContext.hs +24/−35
- src/CompilerCxx/CategoryContext.hs +10/−18
- src/CompilerCxx/Code.hs +35/−63
- src/CompilerCxx/CxxFiles.hs +96/−84
- src/CompilerCxx/LanguageModule.hs +13/−14
- src/CompilerCxx/Naming.hs +9/−5
- src/CompilerCxx/Procedure.hs +70/−22
- src/Module/CompileMetadata.hs +4/−0
- src/Module/ParseMetadata.hs +0/−1
- src/Parser/Common.hs +6/−1
- src/Parser/DefinedCategory.hs +14/−21
- src/Parser/Procedure.hs +25/−23
- src/Parser/TypeCategory.hs +4/−10
- src/Test/Common.hs +22/−13
- src/Test/DefinedCategory.hs +3/−5
- src/Test/ParseMetadata.hs +1/−1
- src/Test/TypeCategory.hs +59/−166
- src/Test/TypeInstance.hs +33/−64
- src/Test/testfiles/allows_variance_left.0rx +5/−0
- src/Test/testfiles/allows_variance_right.0rx +5/−0
- src/Test/testfiles/bad_allows_variance_left.0rx +0/−5
- src/Test/testfiles/bad_allows_variance_right.0rx +0/−5
- src/Test/testfiles/bad_defines_variance_left.0rx +0/−5
- src/Test/testfiles/bad_defines_variance_right.0rx +0/−5
- src/Test/testfiles/bad_requires_variance_left.0rx +0/−5
- src/Test/testfiles/bad_requires_variance_right.0rx +0/−5
- src/Test/testfiles/concrete_instances.0rx +0/−33
- src/Test/testfiles/concrete_missing_define.0rx +0/−22
- src/Test/testfiles/concrete_missing_refine.0rx +0/−23
- src/Test/testfiles/defines_variance_left.0rx +5/−0
- src/Test/testfiles/defines_variance_right.0rx +5/−0
- src/Test/testfiles/filtered_self.0rx +0/−14
- src/Test/testfiles/function_bad_allows_type.0rx +0/−9
- src/Test/testfiles/function_bad_arg.0rx +0/−9
- src/Test/testfiles/function_bad_defines_type.0rx +0/−9
- src/Test/testfiles/function_bad_requires_type.0rx +0/−9
- src/Test/testfiles/function_bad_return.0rx +0/−9
- src/Test/testfiles/function_defines_missed.0rx +0/−2
- src/Test/testfiles/internal_filters.0rx +0/−7
- src/Test/testfiles/internal_params.0rx +0/−3
- src/Test/testfiles/requires_variance_left.0rx +5/−0
- src/Test/testfiles/requires_variance_right.0rx +5/−0
- src/Test/testfiles/type_instances.0rx +0/−33
- src/Test/testfiles/type_interface.0rx +0/−4
- src/Test/testfiles/type_missing_define.0rx +0/−22
- src/Test/testfiles/type_missing_refine.0rx +0/−23
- src/Test/testfiles/value_instances.0rx +0/−33
- src/Test/testfiles/value_interface.0rx +0/−3
- src/Test/testfiles/value_missing_define.0rx +0/−22
- src/Test/testfiles/value_missing_refine.0rx +0/−23
- src/Types/Builtin.hs +44/−4
- src/Types/DefinedCategory.hs +32/−5
- src/Types/Function.hs +10/−10
- src/Types/Procedure.hs +13/−6
- src/Types/TypeCategory.hs +84/−116
- src/Types/TypeInstance.hs +49/−30
- tests/builtin-types.0rt +26/−2
- tests/cli-tests.sh +32/−4
- tests/filters.0rt +253/−5
- tests/function-calls.0rt +4/−2
- tests/inference.0rt +32/−1
- tests/internal-params.0rt +0/−368
- tests/local-rules.0rt +170/−0
- tests/member-init.0rt +50/−1
- tests/module-only4/common-source.cpp +12/−12
- tests/reduce.0rt +0/−24
- tests/regressions.0rt +1/−1
- tests/self-type.0rt +47/−40
- tests/templates/.zeolite-module +4/−0
- tests/templates/README.md +4/−4
- tests/templates/private.0rp +23/−0
- tests/templates/public.0rp +26/−0
- tests/templates/templates.0rp +0/−26
- tests/templates/tests.0rt +8/−8
- tests/tracing.0rt +27/−1
- tests/traverse.0rt +300/−0
- tests/typename.0rt +0/−20
- zeolite-lang.cabal +5/−1
ChangeLog.md view
@@ -1,5 +1,142 @@ # Revision history for zeolite-lang +## 0.16.0.0 -- 2021-04-01++### Language++* **[breaking]** Disallows param filters in `@value interface` and+ `@type interface`. Param filters are only used to allow procedures to call+ `@type` and `@value` functions. Previously, they were enforced in all+ situations where param substitution occurred, but this is no longer the case.+ (See further down in this list.)++* **[breaking]** Removes support for internal type params for values. This was+ an obscure feature that was never documented and was only used in some+ integration tests that had not been touched in over 2 years. This breaks most+ hand-written C++ extensions, but they can be fixed by removing the+ `ParamTuple` argument passed to the base-class constructor in `ExtValue_Foo`+ for C++ extension `Foo`.++* **[breaking]** Adds the `traverse` built-in syntax, which automatically+ iterates over a container that exposes the (new) `Order<|#x>`+ `@value interface`. (This is breaking because `traverse`, `Order`, and+ `DefaultOrder` are now reserved.)++ ```text+ traverse (container.defaultOrder() -> Foo value) {+ // executed once per Foo in the container+ }+ ```++* **[breaking]** Marks `@category` member variables as read-only when+ initializing other member variables. Essentially, this just means that you can+ no longer do something like this:++ ```text+ @category Int foo <- 1+ @category Int bar <- (foo <- 2)+ ```++* **[new]** Removes the requirement that type instances (e.g., `Type<Int>`)+ satisfy the requirements of the type's parameter filters when not being used+ in a function call.++ ```text+ concrete Type<|#x> {+ #x requires Foo+ }+ ```++ In the example above, `Type<Bar>` was universally disallowed if `Bar` could+ not be converted to `Foo`. The new behavior is to enforce that restriction+ only when calling `@type` functions, initializing values (e.g.,+ `Type<#x>{ }`), and using the type as a param in a function call.++ Since `#x` is covariant in this example, you could convert a `Type<Bar>` to a+ `Type<any>`, even though `any` is not a child of `Foo`.++* **[new]** Removes variance checks for category-level param filters. Variance+ was originally *not* checked, but then the checks were added prior to version+ `0.1.0.0` for obscure mathematical reasons that no longer make sense.++ In particular, filters such as `#x defines Equals<#x>` *were not* previously+ allowed except when `#x` was invariant, but now it is allowed for all+ variances.++ The revised perspective is that param filters form a meta-type for param+ substitutions as inputs, with the constructed type as the output. Once the+ output is received, the input constraints are no longer recoverable.++ Note that category-level param variance is still checked when params are used+ on the right side of filters for function params. This is because not doing so+ could result in bad argument and return types when inheriting functions.++ Params also still cannot have *both* upper and lower bounds at the same time.++* **[new]** When inferring type parameters for function calls (e.g.,+ `call<?>(foo)`), allows `all` to be a valid lower bound and `any` to be a+ valid upper bound. Previously, an inferred type of `all` in covariant+ positions and `any` in contravariant positions would cause inference to fail.++* **[new]** Allows `$ReadOnly[...]$` and `$Hidden[...]$` for member variables in+ definitions of `concrete` categories.++* **[new]** Makes `Argv` available to all threads. Previously, it was only+ available to the main thread. (Even though `Argv` is exposed via `lib/util`,+ this change also affects C++ extensions that use `Argv` from `logging.hpp`.)++* **[fix]** Fixes regression with function names used in stack traces.+ Previously, if a function was inherited and the types were not overridden,+ the category name in the trace would be that of the parent, rather than that+ of the one defining the procedure.++### Compiler CLI++* **[breaking]** Removes the default compiler mode when calling `zeolite`. The+ previous default was `-c`, which creates a new `.zeolite-module` for+ incremental library compilation. The default was removed because accidentally+ typing `zeolite -f foo` instead of `zeolite -t foo` would overwrite the+ `.zeolite-module` for `foo` rather than running its tests.++* **[breaking]** Updates how `$TraceCreation$` is implemented in C++. This only+ breaks hand-written C++ extensions that use the `CAPTURE_CREATION` macro,+ which now must pass a string-literal category name as a macro argument,+ e.g., `CAPTURE_CREATION("Foo")`.++* **[new]** Adds the `--log-traces` option for testing mode (`zeolite -t`) to+ capture a record of every line of Zeolite code executed when running tests.++* **[fix]** Fixes dependency resolution for C++ extensions that define+ `$ModuleOnly$` categories.++* **[behavior]** Improves the efficiency of call dispatching and `reduce` calls+ for categories that inherit a lot of `interface`s. This is unlikely to affect+ performance when a category has less than 10 direct or indirect parent+ `interface`s.++### Libraries++* **[new]** Adds `ThreadCondition` to `lib/thread`, which allows threads to wait+ for an arbitrary condition signaled by another thread. (Similar to+ `pthread_cond_t` in POSIX.)++* **[new]** Adds `EnumeratedBarrier` to `lib/thread`, which can be use to+ synchronize a fixed number of threads. (Similar to `pthread_barrier_t` in+ POSIX, but with strict validation to help prevent deadlocks.)++* **[new]** Adds `Realtime` to `lib/thread`, to allow threads to sleep based on+ wall time.++* **[new]** Adds `Counter` and `Repeat` to `lib/util`, to help create sequences+ for use with the new `traverse` built-in syntax.++* **[new]** Implements forward and reverse iteration to `SearchTree` in+ `lib/container`.++### Examples++* Adds `example/primes`, as a demonstration of multithreading.+ ## 0.15.0.0 -- 2021-03-24 ### Language
base/Category_Bool.cpp 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.@@ -41,7 +41,6 @@ class Category_Bool; class Type_Bool; class Value_Bool;-S<TypeValue> CreateValue(Type_Bool& parent, const ParamTuple& params, const ValueTuple& args); struct Category_Bool : public TypeCategory { std::string CategoryName() const final { return "Bool"; } Category_Bool() {@@ -72,25 +71,34 @@ } return true; }+ void Params_Bool(std::vector<S<const TypeInstance>>& args) const {+ args = std::vector<S<const TypeInstance>>{};+ }+ void Params_AsBool(std::vector<S<const TypeInstance>>& args) const {+ args = std::vector<S<const TypeInstance>>{};+ }+ void Params_AsInt(std::vector<S<const TypeInstance>>& args) const {+ args = std::vector<S<const TypeInstance>>{};+ }+ void Params_AsFloat(std::vector<S<const TypeInstance>>& args) const {+ args = std::vector<S<const TypeInstance>>{};+ }+ void Params_Formatted(std::vector<S<const TypeInstance>>& args) const {+ args = std::vector<S<const TypeInstance>>{};+ } bool TypeArgsForParent(const TypeCategory& category, std::vector<S<const TypeInstance>>& args) const final {- if (&category == &GetCategory_Bool()) {- args = std::vector<S<const TypeInstance>>{};- return true;- }- if (&category == &GetCategory_AsBool()) {- args = std::vector<S<const TypeInstance>>{};- return true;- }- if (&category == &GetCategory_AsInt()) {- args = std::vector<S<const TypeInstance>>{};- return true;- }- if (&category == &GetCategory_AsFloat()) {- args = std::vector<S<const TypeInstance>>{};- return true;- }- if (&category == &GetCategory_Formatted()) {- args = std::vector<S<const TypeInstance>>{};+ using CallType = void(Type_Bool::*)(std::vector<S<const TypeInstance>>&)const;+ static DispatchSingle<CallType> all_calls[] = {+ DispatchSingle<CallType>(&GetCategory_AsBool(), &Type_Bool::Params_AsBool),+ DispatchSingle<CallType>(&GetCategory_AsFloat(), &Type_Bool::Params_AsFloat),+ DispatchSingle<CallType>(&GetCategory_AsInt(), &Type_Bool::Params_AsInt),+ DispatchSingle<CallType>(&GetCategory_Bool(), &Type_Bool::Params_Bool),+ DispatchSingle<CallType>(&GetCategory_Formatted(), &Type_Bool::Params_Formatted),+ DispatchSingle<CallType>(),+ };+ const DispatchSingle<CallType>* const call = DispatchSelect(&category, all_calls);+ if (call) {+ (this->*call->value)(args); return true; } return false;@@ -109,18 +117,19 @@ static const CallType Table_Equals[] = { &Type_Bool::Call_equals, };- if (label.collection == Functions_Default) {- if (label.function_num < 0 || label.function_num >= 1) {+ static DispatchTable<CallType> all_tables[] = {+ DispatchTable<CallType>(Functions_Default, Table_Default),+ DispatchTable<CallType>(Functions_Equals, Table_Equals),+ DispatchTable<CallType>(),+ };+ const DispatchTable<CallType>* const table = DispatchSelect(label.collection, all_tables);+ if (table) {+ if (label.function_num < 0 || label.function_num >= table->size) { FAIL() << "Bad function call " << label;+ } else {+ return (this->*table->table[label.function_num])(params, args); }- return (this->*Table_Default[label.function_num])(params, args); }- if (label.collection == Functions_Equals) {- if (label.function_num < 0 || label.function_num >= 1) {- FAIL() << "Bad function call " << label;- }- return (this->*Table_Equals[label.function_num])(params, args);- } return TypeInstance::Dispatch(self, label, params, args); } ReturnTuple Call_default(const ParamTuple& params, const ValueTuple& args);@@ -146,29 +155,20 @@ static const CallType Table_Formatted[] = { &Value_Bool::Call_formatted, };- if (label.collection == Functions_AsBool) {- if (label.function_num < 0 || label.function_num >= 1) {- FAIL() << "Bad function call " << label;- }- return (this->*Table_AsBool[label.function_num])(self, params, args);- }- if (label.collection == Functions_AsFloat) {- if (label.function_num < 0 || label.function_num >= 1) {- FAIL() << "Bad function call " << label;- }- return (this->*Table_AsFloat[label.function_num])(self, params, args);- }- if (label.collection == Functions_AsInt) {- if (label.function_num < 0 || label.function_num >= 1) {- FAIL() << "Bad function call " << label;- }- return (this->*Table_AsInt[label.function_num])(self, params, args);- }- if (label.collection == Functions_Formatted) {- if (label.function_num < 0 || label.function_num >= 1) {+ static DispatchTable<CallType> all_tables[] = {+ DispatchTable<CallType>(Functions_AsBool, Table_AsBool),+ DispatchTable<CallType>(Functions_AsFloat, Table_AsFloat),+ DispatchTable<CallType>(Functions_AsInt, Table_AsInt),+ DispatchTable<CallType>(Functions_Formatted, Table_Formatted),+ DispatchTable<CallType>(),+ };+ const DispatchTable<CallType>* const table = DispatchSelect(label.collection, all_tables);+ if (table) {+ if (label.function_num < 0 || label.function_num >= table->size) { FAIL() << "Bad function call " << label;+ } else {+ return (this->*table->table[label.function_num])(self, params, args); }- return (this->*Table_Formatted[label.function_num])(self, params, args); } return TypeValue::Dispatch(self, label, params, args); }
base/Category_Char.cpp 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.@@ -43,7 +43,6 @@ class Category_Char; class Type_Char; class Value_Char;-S<TypeValue> CreateValue(Type_Char& parent, const ParamTuple& params, const ValueTuple& args); struct Category_Char : public TypeCategory { std::string CategoryName() const final { return "Char"; } Category_Char() {@@ -74,29 +73,38 @@ } return true; }+ void Params_Char(std::vector<S<const TypeInstance>>& args) const {+ args = std::vector<S<const TypeInstance>>{};+ }+ void Params_AsBool(std::vector<S<const TypeInstance>>& args) const {+ args = std::vector<S<const TypeInstance>>{};+ }+ void Params_AsChar(std::vector<S<const TypeInstance>>& args) const {+ args = std::vector<S<const TypeInstance>>{};+ }+ void Params_AsInt(std::vector<S<const TypeInstance>>& args) const {+ args = std::vector<S<const TypeInstance>>{};+ }+ void Params_AsFloat(std::vector<S<const TypeInstance>>& args) const {+ args = std::vector<S<const TypeInstance>>{};+ }+ void Params_Formatted(std::vector<S<const TypeInstance>>& args) const {+ args = std::vector<S<const TypeInstance>>{};+ } bool TypeArgsForParent(const TypeCategory& category, std::vector<S<const TypeInstance>>& args) const final {- if (&category == &GetCategory_Char()) {- args = std::vector<S<const TypeInstance>>{};- return true;- }- if (&category == &GetCategory_AsBool()) {- args = std::vector<S<const TypeInstance>>{};- return true;- }- if (&category == &GetCategory_AsChar()) {- args = std::vector<S<const TypeInstance>>{};- return true;- }- if (&category == &GetCategory_AsInt()) {- args = std::vector<S<const TypeInstance>>{};- return true;- }- if (&category == &GetCategory_AsFloat()) {- args = std::vector<S<const TypeInstance>>{};- return true;- }- if (&category == &GetCategory_Formatted()) {- args = std::vector<S<const TypeInstance>>{};+ using CallType = void(Type_Char::*)(std::vector<S<const TypeInstance>>&)const;+ static DispatchSingle<CallType> all_calls[] = {+ DispatchSingle<CallType>(&GetCategory_AsBool(), &Type_Char::Params_AsBool),+ DispatchSingle<CallType>(&GetCategory_AsChar(), &Type_Char::Params_AsChar),+ DispatchSingle<CallType>(&GetCategory_AsFloat(), &Type_Char::Params_AsFloat),+ DispatchSingle<CallType>(&GetCategory_AsInt(), &Type_Char::Params_AsInt),+ DispatchSingle<CallType>(&GetCategory_Char(), &Type_Char::Params_Char),+ DispatchSingle<CallType>(&GetCategory_Formatted(), &Type_Char::Params_Formatted),+ DispatchSingle<CallType>(),+ };+ const DispatchSingle<CallType>* const call = DispatchSelect(&category, all_calls);+ if (call) {+ (this->*call->value)(args); return true; } return false;@@ -118,24 +126,20 @@ static const CallType Table_LessThan[] = { &Type_Char::Call_lessThan, };- if (label.collection == Functions_Default) {- if (label.function_num < 0 || label.function_num >= 1) {+ static DispatchTable<CallType> all_tables[] = {+ DispatchTable<CallType>(Functions_Default, Table_Default),+ DispatchTable<CallType>(Functions_Equals, Table_Equals),+ DispatchTable<CallType>(Functions_LessThan, Table_LessThan),+ DispatchTable<CallType>(),+ };+ const DispatchTable<CallType>* const table = DispatchSelect(label.collection, all_tables);+ if (table) {+ if (label.function_num < 0 || label.function_num >= table->size) { FAIL() << "Bad function call " << label;+ } else {+ return (this->*table->table[label.function_num])(params, args); }- return (this->*Table_Default[label.function_num])(params, args); }- if (label.collection == Functions_Equals) {- if (label.function_num < 0 || label.function_num >= 1) {- FAIL() << "Bad function call " << label;- }- return (this->*Table_Equals[label.function_num])(params, args);- }- if (label.collection == Functions_LessThan) {- if (label.function_num < 0 || label.function_num >= 1) {- FAIL() << "Bad function call " << label;- }- return (this->*Table_LessThan[label.function_num])(params, args);- } return TypeInstance::Dispatch(self, label, params, args); } ReturnTuple Call_default(const ParamTuple& params, const ValueTuple& args);@@ -165,35 +169,21 @@ static const CallType Table_Formatted[] = { &Value_Char::Call_formatted, };- if (label.collection == Functions_AsBool) {- if (label.function_num < 0 || label.function_num >= 1) {- FAIL() << "Bad function call " << label;- }- return (this->*Table_AsBool[label.function_num])(self, params, args);- }- if (label.collection == Functions_AsChar) {- if (label.function_num < 0 || label.function_num >= 1) {- FAIL() << "Bad function call " << label;- }- return (this->*Table_AsChar[label.function_num])(self, params, args);- }- if (label.collection == Functions_AsFloat) {- if (label.function_num < 0 || label.function_num >= 1) {- FAIL() << "Bad function call " << label;- }- return (this->*Table_AsFloat[label.function_num])(self, params, args);- }- if (label.collection == Functions_AsInt) {- if (label.function_num < 0 || label.function_num >= 1) {- FAIL() << "Bad function call " << label;- }- return (this->*Table_AsInt[label.function_num])(self, params, args);- }- if (label.collection == Functions_Formatted) {- if (label.function_num < 0 || label.function_num >= 1) {+ static DispatchTable<CallType> all_tables[] = {+ DispatchTable<CallType>(Functions_AsBool, Table_AsBool),+ DispatchTable<CallType>(Functions_AsChar, Table_AsChar),+ DispatchTable<CallType>(Functions_AsFloat, Table_AsFloat),+ DispatchTable<CallType>(Functions_AsInt, Table_AsInt),+ DispatchTable<CallType>(Functions_Formatted, Table_Formatted),+ DispatchTable<CallType>(),+ };+ const DispatchTable<CallType>* const table = DispatchSelect(label.collection, all_tables);+ if (table) {+ if (label.function_num < 0 || label.function_num >= table->size) { FAIL() << "Bad function call " << label;+ } else {+ return (this->*table->table[label.function_num])(self, params, args); }- return (this->*Table_Formatted[label.function_num])(self, params, args); } return TypeValue::Dispatch(self, label, params, args); }
base/Category_Float.cpp 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.@@ -42,7 +42,6 @@ class Category_Float; class Type_Float; class Value_Float;-S<TypeValue> CreateValue(Type_Float& parent, const ParamTuple& params, const ValueTuple& args); struct Category_Float : public TypeCategory { std::string CategoryName() const final { return "Float"; } Category_Float() {@@ -73,25 +72,34 @@ } return true; }+ void Params_Float(std::vector<S<const TypeInstance>>& args) const {+ args = std::vector<S<const TypeInstance>>{};+ }+ void Params_AsBool(std::vector<S<const TypeInstance>>& args) const {+ args = std::vector<S<const TypeInstance>>{};+ }+ void Params_AsInt(std::vector<S<const TypeInstance>>& args) const {+ args = std::vector<S<const TypeInstance>>{};+ }+ void Params_AsFloat(std::vector<S<const TypeInstance>>& args) const {+ args = std::vector<S<const TypeInstance>>{};+ }+ void Params_Formatted(std::vector<S<const TypeInstance>>& args) const {+ args = std::vector<S<const TypeInstance>>{};+ } bool TypeArgsForParent(const TypeCategory& category, std::vector<S<const TypeInstance>>& args) const final {- if (&category == &GetCategory_Float()) {- args = std::vector<S<const TypeInstance>>{};- return true;- }- if (&category == &GetCategory_AsBool()) {- args = std::vector<S<const TypeInstance>>{};- return true;- }- if (&category == &GetCategory_AsInt()) {- args = std::vector<S<const TypeInstance>>{};- return true;- }- if (&category == &GetCategory_AsFloat()) {- args = std::vector<S<const TypeInstance>>{};- return true;- }- if (&category == &GetCategory_Formatted()) {- args = std::vector<S<const TypeInstance>>{};+ using CallType = void(Type_Float::*)(std::vector<S<const TypeInstance>>&)const;+ static DispatchSingle<CallType> all_calls[] = {+ DispatchSingle<CallType>(&GetCategory_AsBool(), &Type_Float::Params_AsBool),+ DispatchSingle<CallType>(&GetCategory_AsFloat(), &Type_Float::Params_AsFloat),+ DispatchSingle<CallType>(&GetCategory_AsInt(), &Type_Float::Params_AsInt),+ DispatchSingle<CallType>(&GetCategory_Float(), &Type_Float::Params_Float),+ DispatchSingle<CallType>(&GetCategory_Formatted(), &Type_Float::Params_Formatted),+ DispatchSingle<CallType>(),+ };+ const DispatchSingle<CallType>* const call = DispatchSelect(&category, all_calls);+ if (call) {+ (this->*call->value)(args); return true; } return false;@@ -113,24 +121,20 @@ static const CallType Table_LessThan[] = { &Type_Float::Call_lessThan, };- if (label.collection == Functions_Default) {- if (label.function_num < 0 || label.function_num >= 1) {+ static DispatchTable<CallType> all_tables[] = {+ DispatchTable<CallType>(Functions_Default, Table_Default),+ DispatchTable<CallType>(Functions_Equals, Table_Equals),+ DispatchTable<CallType>(Functions_LessThan, Table_LessThan),+ DispatchTable<CallType>(),+ };+ const DispatchTable<CallType>* const table = DispatchSelect(label.collection, all_tables);+ if (table) {+ if (label.function_num < 0 || label.function_num >= table->size) { FAIL() << "Bad function call " << label;+ } else {+ return (this->*table->table[label.function_num])(params, args); }- return (this->*Table_Default[label.function_num])(params, args); }- if (label.collection == Functions_Equals) {- if (label.function_num < 0 || label.function_num >= 1) {- FAIL() << "Bad function call " << label;- }- return (this->*Table_Equals[label.function_num])(params, args);- }- if (label.collection == Functions_LessThan) {- if (label.function_num < 0 || label.function_num >= 1) {- FAIL() << "Bad function call " << label;- }- return (this->*Table_LessThan[label.function_num])(params, args);- } return TypeInstance::Dispatch(self, label, params, args); } ReturnTuple Call_default(const ParamTuple& params, const ValueTuple& args);@@ -157,29 +161,20 @@ static const CallType Table_Formatted[] = { &Value_Float::Call_formatted, };- if (label.collection == Functions_AsBool) {- if (label.function_num < 0 || label.function_num >= 1) {- FAIL() << "Bad function call " << label;- }- return (this->*Table_AsBool[label.function_num])(self, params, args);- }- if (label.collection == Functions_AsFloat) {- if (label.function_num < 0 || label.function_num >= 1) {- FAIL() << "Bad function call " << label;- }- return (this->*Table_AsFloat[label.function_num])(self, params, args);- }- if (label.collection == Functions_AsInt) {- if (label.function_num < 0 || label.function_num >= 1) {- FAIL() << "Bad function call " << label;- }- return (this->*Table_AsInt[label.function_num])(self, params, args);- }- if (label.collection == Functions_Formatted) {- if (label.function_num < 0 || label.function_num >= 1) {+ static DispatchTable<CallType> all_tables[] = {+ DispatchTable<CallType>(Functions_AsBool, Table_AsBool),+ DispatchTable<CallType>(Functions_AsFloat, Table_AsFloat),+ DispatchTable<CallType>(Functions_AsInt, Table_AsInt),+ DispatchTable<CallType>(Functions_Formatted, Table_Formatted),+ DispatchTable<CallType>(),+ };+ const DispatchTable<CallType>* const table = DispatchSelect(label.collection, all_tables);+ if (table) {+ if (label.function_num < 0 || label.function_num >= table->size) { FAIL() << "Bad function call " << label;+ } else {+ return (this->*table->table[label.function_num])(self, params, args); }- return (this->*Table_Formatted[label.function_num])(self, params, args); } return TypeValue::Dispatch(self, label, params, args); }
base/Category_Int.cpp 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.@@ -43,7 +43,6 @@ class Category_Int; class Type_Int; class Value_Int;-S<TypeValue> CreateValue(Type_Int& parent, const ParamTuple& params, const ValueTuple& args); struct Category_Int : public TypeCategory { std::string CategoryName() const final { return "Int"; } Category_Int() {@@ -74,29 +73,38 @@ } return true; }+ void Params_Int(std::vector<S<const TypeInstance>>& args) const {+ args = std::vector<S<const TypeInstance>>{};+ }+ void Params_AsBool(std::vector<S<const TypeInstance>>& args) const {+ args = std::vector<S<const TypeInstance>>{};+ }+ void Params_AsChar(std::vector<S<const TypeInstance>>& args) const {+ args = std::vector<S<const TypeInstance>>{};+ }+ void Params_AsInt(std::vector<S<const TypeInstance>>& args) const {+ args = std::vector<S<const TypeInstance>>{};+ }+ void Params_AsFloat(std::vector<S<const TypeInstance>>& args) const {+ args = std::vector<S<const TypeInstance>>{};+ }+ void Params_Formatted(std::vector<S<const TypeInstance>>& args) const {+ args = std::vector<S<const TypeInstance>>{};+ } bool TypeArgsForParent(const TypeCategory& category, std::vector<S<const TypeInstance>>& args) const final {- if (&category == &GetCategory_Int()) {- args = std::vector<S<const TypeInstance>>{};- return true;- }- if (&category == &GetCategory_AsBool()) {- args = std::vector<S<const TypeInstance>>{};- return true;- }- if (&category == &GetCategory_AsChar()) {- args = std::vector<S<const TypeInstance>>{};- return true;- }- if (&category == &GetCategory_AsInt()) {- args = std::vector<S<const TypeInstance>>{};- return true;- }- if (&category == &GetCategory_AsFloat()) {- args = std::vector<S<const TypeInstance>>{};- return true;- }- if (&category == &GetCategory_Formatted()) {- args = std::vector<S<const TypeInstance>>{};+ using CallType = void(Type_Int::*)(std::vector<S<const TypeInstance>>&)const;+ static DispatchSingle<CallType> all_calls[] = {+ DispatchSingle<CallType>(&GetCategory_AsBool(), &Type_Int::Params_AsBool),+ DispatchSingle<CallType>(&GetCategory_AsChar(), &Type_Int::Params_AsChar),+ DispatchSingle<CallType>(&GetCategory_AsFloat(), &Type_Int::Params_AsFloat),+ DispatchSingle<CallType>(&GetCategory_AsInt(), &Type_Int::Params_AsInt),+ DispatchSingle<CallType>(&GetCategory_Formatted(), &Type_Int::Params_Formatted),+ DispatchSingle<CallType>(&GetCategory_Int(), &Type_Int::Params_Int),+ DispatchSingle<CallType>(),+ };+ const DispatchSingle<CallType>* const call = DispatchSelect(&category, all_calls);+ if (call) {+ (this->*call->value)(args); return true; } return false;@@ -118,24 +126,20 @@ static const CallType Table_LessThan[] = { &Type_Int::Call_lessThan, };- if (label.collection == Functions_Default) {- if (label.function_num < 0 || label.function_num >= 1) {+ static DispatchTable<CallType> all_tables[] = {+ DispatchTable<CallType>(Functions_Default, Table_Default),+ DispatchTable<CallType>(Functions_Equals, Table_Equals),+ DispatchTable<CallType>(Functions_LessThan, Table_LessThan),+ DispatchTable<CallType>(),+ };+ const DispatchTable<CallType>* const table = DispatchSelect(label.collection, all_tables);+ if (table) {+ if (label.function_num < 0 || label.function_num >= table->size) { FAIL() << "Bad function call " << label;+ } else {+ return (this->*table->table[label.function_num])(params, args); }- return (this->*Table_Default[label.function_num])(params, args); }- if (label.collection == Functions_Equals) {- if (label.function_num < 0 || label.function_num >= 1) {- FAIL() << "Bad function call " << label;- }- return (this->*Table_Equals[label.function_num])(params, args);- }- if (label.collection == Functions_LessThan) {- if (label.function_num < 0 || label.function_num >= 1) {- FAIL() << "Bad function call " << label;- }- return (this->*Table_LessThan[label.function_num])(params, args);- } return TypeInstance::Dispatch(self, label, params, args); } ReturnTuple Call_default(const ParamTuple& params, const ValueTuple& args);@@ -165,35 +169,21 @@ static const CallType Table_Formatted[] = { &Value_Int::Call_formatted, };- if (label.collection == Functions_AsBool) {- if (label.function_num < 0 || label.function_num >= 1) {- FAIL() << "Bad function call " << label;- }- return (this->*Table_AsBool[label.function_num])(self, params, args);- }- if (label.collection == Functions_AsChar) {- if (label.function_num < 0 || label.function_num >= 1) {- FAIL() << "Bad function call " << label;- }- return (this->*Table_AsChar[label.function_num])(self, params, args);- }- if (label.collection == Functions_AsFloat) {- if (label.function_num < 0 || label.function_num >= 1) {- FAIL() << "Bad function call " << label;- }- return (this->*Table_AsFloat[label.function_num])(self, params, args);- }- if (label.collection == Functions_AsInt) {- if (label.function_num < 0 || label.function_num >= 1) {- FAIL() << "Bad function call " << label;- }- return (this->*Table_AsInt[label.function_num])(self, params, args);- }- if (label.collection == Functions_Formatted) {- if (label.function_num < 0 || label.function_num >= 1) {+ static DispatchTable<CallType> all_tables[] = {+ DispatchTable<CallType>(Functions_AsBool, Table_AsBool),+ DispatchTable<CallType>(Functions_AsChar, Table_AsChar),+ DispatchTable<CallType>(Functions_AsFloat, Table_AsFloat),+ DispatchTable<CallType>(Functions_AsInt, Table_AsInt),+ DispatchTable<CallType>(Functions_Formatted, Table_Formatted),+ DispatchTable<CallType>(),+ };+ const DispatchTable<CallType>* const table = DispatchSelect(label.collection, all_tables);+ if (table) {+ if (label.function_num < 0 || label.function_num >= table->size) { FAIL() << "Bad function call " << label;+ } else {+ return (this->*table->table[label.function_num])(self, params, args); }- return (this->*Table_Formatted[label.function_num])(self, params, args); } return TypeValue::Dispatch(self, label, params, args); }
base/Category_String.cpp 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.@@ -31,6 +31,8 @@ #include "Category_Append.hpp" #include "Category_Build.hpp" #include "Category_Default.hpp"+#include "Category_DefaultOrder.hpp"+#include "Category_Order.hpp" #include "Category_Equals.hpp" #include "Category_LessThan.hpp" @@ -48,7 +50,6 @@ class Category_String; class Type_String; class Value_String;-S<TypeValue> CreateValue(Type_String& parent, const ParamTuple& params, const ValueTuple& args); struct Category_String : public TypeCategory { std::string CategoryName() const final { return "String"; } Category_String() {@@ -79,21 +80,38 @@ } return true; }+ void Params_String(std::vector<S<const TypeInstance>>& args) const {+ args = std::vector<S<const TypeInstance>>{};+ }+ void Params_AsBool(std::vector<S<const TypeInstance>>& args) const {+ args = std::vector<S<const TypeInstance>>{};+ }+ void Params_Formatted(std::vector<S<const TypeInstance>>& args) const {+ args = std::vector<S<const TypeInstance>>{};+ }+ void Params_ReadAt(std::vector<S<const TypeInstance>>& args) const {+ args = std::vector<S<const TypeInstance>>{GetType_Char(T_get())};+ }+ void Params_SubSequence(std::vector<S<const TypeInstance>>& args) const {+ args = std::vector<S<const TypeInstance>>{};+ }+ void Params_DefaultOrder(std::vector<S<const TypeInstance>>& args) const {+ args = std::vector<S<const TypeInstance>>{GetType_Char(T_get())};+ } bool TypeArgsForParent(const TypeCategory& category, std::vector<S<const TypeInstance>>& args) const final {- if (&category == &GetCategory_String()) {- args = std::vector<S<const TypeInstance>>{};- return true;- }- if (&category == &GetCategory_AsBool()) {- args = std::vector<S<const TypeInstance>>{};- return true;- }- if (&category == &GetCategory_Formatted()) {- args = std::vector<S<const TypeInstance>>{};- return true;- }- if (&category == &GetCategory_ReadAt()) {- args = std::vector<S<const TypeInstance>>{GetType_Char(T_get())};+ using CallType = void(Type_String::*)(std::vector<S<const TypeInstance>>&)const;+ static DispatchSingle<CallType> all_calls[] = {+ DispatchSingle<CallType>(&GetCategory_String(), &Type_String::Params_String),+ DispatchSingle<CallType>(&GetCategory_AsBool(), &Type_String::Params_AsBool),+ DispatchSingle<CallType>(&GetCategory_Formatted(), &Type_String::Params_Formatted),+ DispatchSingle<CallType>(&GetCategory_ReadAt(), &Type_String::Params_ReadAt),+ DispatchSingle<CallType>(&GetCategory_SubSequence(), &Type_String::Params_SubSequence),+ DispatchSingle<CallType>(&GetCategory_DefaultOrder(), &Type_String::Params_DefaultOrder),+ DispatchSingle<CallType>(),+ };+ const DispatchSingle<CallType>* const call = DispatchSelect(&category, all_calls);+ if (call) {+ (this->*call->value)(args); return true; } return false;@@ -118,30 +136,21 @@ static const CallType Table_String[] = { &Type_String::Call_builder, };- if (label.collection == Functions_Default) {- if (label.function_num < 0 || label.function_num >= 1) {+ static DispatchTable<CallType> all_tables[] = {+ DispatchTable<CallType>(Functions_Default, Table_Default),+ DispatchTable<CallType>(Functions_Equals, Table_Equals),+ DispatchTable<CallType>(Functions_LessThan, Table_LessThan),+ DispatchTable<CallType>(Functions_String, Table_String),+ DispatchTable<CallType>(),+ };+ const DispatchTable<CallType>* const table = DispatchSelect(label.collection, all_tables);+ if (table) {+ if (label.function_num < 0 || label.function_num >= table->size) { FAIL() << "Bad function call " << label;+ } else {+ return (this->*table->table[label.function_num])(params, args); }- return (this->*Table_Default[label.function_num])(params, args); }- if (label.collection == Functions_Equals) {- if (label.function_num < 0 || label.function_num >= 1) {- FAIL() << "Bad function call " << label;- }- return (this->*Table_Equals[label.function_num])(params, args);- }- if (label.collection == Functions_LessThan) {- if (label.function_num < 0 || label.function_num >= 1) {- FAIL() << "Bad function call " << label;- }- return (this->*Table_LessThan[label.function_num])(params, args);- }- if (label.collection == Functions_String) {- if (label.function_num < 0 || label.function_num >= 1) {- FAIL() << "Bad function call " << label;- }- return (this->*Table_String[label.function_num])(params, args);- } return TypeInstance::Dispatch(self, label, params, args); } ReturnTuple Call_default(const ParamTuple& params, const ValueTuple& args);@@ -160,6 +169,9 @@ static const CallType Table_AsBool[] = { &Value_String::Call_asBool, };+ static const CallType Table_DefaultOrder[] = {+ &Value_String::Call_defaultOrder,+ }; static const CallType Table_Formatted[] = { &Value_String::Call_formatted, };@@ -175,48 +187,31 @@ static const CallType Table_SubSequence[] = { &Value_String::Call_subSequence, };- if (label.collection == Functions_AsBool) {- if (label.function_num < 0 || label.function_num >= 1) {+ static DispatchTable<CallType> all_tables[] = {+ DispatchTable<CallType>(Functions_AsBool, Table_AsBool),+ DispatchTable<CallType>(Functions_Container, Table_Container),+ DispatchTable<CallType>(Functions_DefaultOrder, Table_DefaultOrder),+ DispatchTable<CallType>(Functions_Formatted, Table_Formatted),+ DispatchTable<CallType>(Functions_ReadAt, Table_ReadAt),+ DispatchTable<CallType>(Functions_String, Table_String),+ DispatchTable<CallType>(Functions_SubSequence, Table_SubSequence),+ DispatchTable<CallType>(),+ };+ const DispatchTable<CallType>* const table = DispatchSelect(label.collection, all_tables);+ if (table) {+ if (label.function_num < 0 || label.function_num >= table->size) { FAIL() << "Bad function call " << label;+ } else {+ return (this->*table->table[label.function_num])(self, params, args); }- return (this->*Table_AsBool[label.function_num])(self, params, args); }- if (label.collection == Functions_Formatted) {- if (label.function_num < 0 || label.function_num >= 1) {- FAIL() << "Bad function call " << label;- }- return (this->*Table_Formatted[label.function_num])(self, params, args);- }- if (label.collection == Functions_ReadAt) {- if (label.function_num < 0 || label.function_num >= 2) {- FAIL() << "Bad function call " << label;- }- return (this->*Table_ReadAt[label.function_num])(self, params, args);- }- if (label.collection == Functions_Container) {- if (label.function_num < 0 || label.function_num >= 2) {- FAIL() << "Bad function call " << label;- }- return (this->*Table_Container[label.function_num])(self, params, args);- }- if (label.collection == Functions_String) {- if (label.function_num < 0 || label.function_num >= 1) {- FAIL() << "Bad function call " << label;- }- return (this->*Table_String[label.function_num])(self, params, args);- }- if (label.collection == Functions_SubSequence) {- if (label.function_num < 0 || label.function_num >= 1) {- FAIL() << "Bad function call " << label;- }- return (this->*Table_SubSequence[label.function_num])(self, params, args);- } return TypeValue::Dispatch(self, label, params, args); } std::string CategoryName() const final { return parent->CategoryName(); } const PrimString& AsString() const final { return value_; } ReturnTuple Call_asBool(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args); ReturnTuple Call_formatted(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args);+ ReturnTuple Call_defaultOrder(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args); ReturnTuple Call_readAt(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args); ReturnTuple Call_size(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args); ReturnTuple Call_subSequence(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args);@@ -256,6 +251,28 @@ std::ostringstream output_; }; +struct StringOrder : public AnonymousOrder {+ StringOrder(S<TypeValue> container, const std::string& s)+ : AnonymousOrder(container, Function_Order_next, Function_Order_get), value(s) {}++ S<TypeValue> Call_next(const S<TypeValue>& self) final {+ if (index+1 >= value.size()) {+ return Var_empty;+ } else {+ ++index;+ return self;+ }+ }++ S<TypeValue> Call_get(const S<TypeValue>& self) final {+ if (index >= value.size()) FAIL() << "iterated past end of String";+ return Box_Char(value[index]);+ }++ const std::string& value;+ int index = 0;+};+ ReturnTuple Type_String::Call_default(const ParamTuple& params, const ValueTuple& args) { TRACE_FUNCTION("String.default") return ReturnTuple(Box_String(""));@@ -283,6 +300,14 @@ ReturnTuple Value_String::Call_formatted(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) { TRACE_FUNCTION("String.formatted") return ReturnTuple(Var_self);+}+ReturnTuple Value_String::Call_defaultOrder(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) {+ TRACE_FUNCTION("String.defaultOrder")+ if (value_.empty()) {+ return ReturnTuple(Var_empty);+ } else {+ return ReturnTuple(S_get(new StringOrder(Var_self, value_)));+ } } ReturnTuple Value_String::Call_readAt(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) { TRACE_FUNCTION("String.readAt")
base/builtin.0rp view
@@ -93,6 +93,7 @@ // Literals: Quote Char sequence with ". concrete String { refines AsBool+ refines DefaultOrder<Char> refines Formatted refines ReadAt<Char> refines SubSequence@@ -155,6 +156,36 @@ @value interface Build<|#x> { // Build and return a value from the current state. build () -> (#x)+}++// Ordered data, primarily used for the traverse built-in.+//+// Example:+//+// traverse (someIntOrder -> Int i) {+// // code that uses index i+// }+@value interface Order<|#x> {+ // Returns an updated instance, or empty if the end was reached.+ //+ // Notes:+ // - This can return either a mutated self or a new copy. The caller should+ // assume that next() will mutate the instance.+ // - This should not generally be used directly; use the traverse built-in.+ next () -> (optional #self)++ // Returns the value at the current position.+ get () -> (#x)+}++// Provides a default Order for a container.+//+// Notes:+// - The return value is primarily intended for use with the traverse built-in.+// - Also see the documentation for Order and traverse.+@value interface DefaultOrder<|#x> {+ // Returns the default Order for the container.+ defaultOrder () -> (optional Order<#x>) } // Contains a flexible number of values of some type.
base/category-header.hpp 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.@@ -30,9 +30,5 @@ class CategoryFunction; class TypeFunction; class ValueFunction;--#if defined(ZEOLITE_PUBLIC_NAMESPACE) && !defined(ZEOLITE_DYNAMIC_NAMESPACE)-#define ZEOLITE_DYNAMIC_NAMESPACE ZEOLITE_PUBLIC_NAMESPACE-#endif #endif // CATEGORY_HEADER_HPP_
base/category-source.cpp view
@@ -269,3 +269,24 @@ bool TypeValue::Present() const { return true; }++AnonymousOrder::AnonymousOrder(const S<TypeValue> cont,+ const ValueFunction& func_next,+ const ValueFunction& func_get)+ : container(cont), function_next(func_next), function_get(func_get) {}++std::string AnonymousOrder::CategoryName() const { return "AnonymousOrder"; }++ReturnTuple AnonymousOrder::Dispatch(+ const S<TypeValue>& self, const ValueFunction& label,+ const ParamTuple& params, const ValueTuple& args) {+ if (&label == &function_next) {+ TRACE_FUNCTION("AnonymousOrder.next")+ return ReturnTuple(Call_next(self));+ }+ if (&label == &function_get) {+ TRACE_FUNCTION("AnonymousOrder.get")+ return ReturnTuple(Call_get(self));+ }+ return TypeValue::Dispatch(self, label, params, args);+}
base/category-source.hpp view
@@ -19,6 +19,7 @@ #ifndef CATEGORY_SOURCE_HPP_ #define CATEGORY_SOURCE_HPP_ +#include <algorithm> #include <iostream> // For occasional debugging output in generated code. #include <map> #include <mutex>@@ -214,5 +215,77 @@ std::mutex mutex_; std::map<typename ParamsKey<P>::Type, S<T>> cache_; };++class AnonymousOrder : public TypeValue {+ protected:+ // Passing in the function labels allows linking without depending on Order+ // when this class isn't used anywhere.+ AnonymousOrder(const S<TypeValue> cont,+ const ValueFunction& func_next,+ const ValueFunction& func_get);++ std::string CategoryName() const final;+ ReturnTuple Dispatch(const S<TypeValue>& self,+ const ValueFunction& label,+ const ParamTuple& params,+ const ValueTuple& args) final;++ virtual ~AnonymousOrder() = default;++ private:+ virtual S<TypeValue> Call_next(const S<TypeValue>& self) = 0;+ virtual S<TypeValue> Call_get(const S<TypeValue>& self) = 0;++ const S<TypeValue> container;+ const ValueFunction& function_next;+ const ValueFunction& function_get;+};++template<class F>+struct DispatchTable {+ constexpr DispatchTable() : key(nullptr), table(nullptr), size(0) {}++ template<int S>+ DispatchTable(const void* k, const F(&t)[S]) : key(k), table(t), size(S) {}++ bool operator < (const DispatchTable<F>& other) const { return key < other.key; }++ const void* key;+ const F* table;+ int size;+};++template<class F>+struct DispatchSingle {+ constexpr DispatchSingle() : key(nullptr), value() {}++ DispatchSingle(const void* k, const F v) : key(k), value(v) {}++ bool operator < (const DispatchSingle<F>& other) const { return key < other.key; }++ const void* key;+ F value;+ int size;+};++template<class T, int S>+const T* DispatchSelect(const void* key, T(&table)[S]) {+ if (S < 2) return nullptr;+ if (table[0].key != nullptr) {+ std::sort(table, table+S);+ }+ int i = 1, j = S;+ while (j-i > 1) {+ const int k = (i+j)/2;+ if (table[k].key < key) {+ i = k;+ } else if (table[k].key > key) {+ j = k;+ } else {+ return &table[k];+ }+ }+ return (table[i].key == key)? &table[i] : nullptr;+} #endif // CATEGORY_SOURCE_HPP_
base/logging.cpp view
@@ -19,7 +19,9 @@ #include "logging.hpp" #include <cassert>+#include <chrono> #include <csignal>+#include <iomanip> #include <iostream> @@ -116,6 +118,7 @@ void SourceContext::SetLocal(const char* at) { at_ = at;+ LogCalls::MaybeLogCall(name_, at_); } void SourceContext::AppendTrace(TraceList& trace) const {@@ -177,4 +180,55 @@ const std::vector<std::string>& ProgramArgv::GetArgs() const { return argv_;+}++std::string FixCsvString(const char* string) {+ std::string fixed;+ while (*string) {+ switch (*string) {+ case '\\':+ break;+ case '"':+ fixed.push_back('\'');+ break;+ default:+ fixed.push_back(*string);+ break;+ }+ ++string;+ }+ return fixed;+}++unsigned int UniqueId() {+ const auto time = std::chrono::steady_clock::now().time_since_epoch();+ return (1000000009 * std::chrono::duration_cast<std::chrono::microseconds>(time).count());+}++LogCallsToFile::LogCallsToFile(std::string filename)+ : unique_id_(UniqueId()),+ filename_(std::move(filename)),+ log_file_(filename_.empty()?+ nullptr :+ new std::fstream(filename_, std::ios::in |+ std::ios::out |+ std::ios::ate |+ std::ios::app)),+ cross_and_capture_to_(this) {+ if (log_file_) {+ if (!*log_file_) {+ FAIL() << "Failed to open call log " << filename_ << " for writing";+ }+ }+}++void LogCallsToFile::LogCall(const char* name, const char* at) {+ if (log_file_) {+ std::lock_guard<std::mutex> lock(mutex_);+ const auto time = std::chrono::steady_clock::now().time_since_epoch();+ *log_file_ << std::chrono::duration_cast<std::chrono::microseconds>(time).count() << ","+ << unique_id_ << ","+ << "\"" << FixCsvString(name) << "\"" << ","+ << "\"" << FixCsvString(at) << "\"" << std::endl;+ } }
base/logging.hpp 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.@@ -20,7 +20,10 @@ #define LOGGING_HPP_ #include <functional>+#include <fstream> #include <list>+#include <memory>+#include <mutex> #include <sstream> #include <string> #include <vector>@@ -78,11 +81,11 @@ #define PRED_CONTEXT_POINT(point) \ TraceContext::SetContext(point), - #define CAPTURE_CREATION \- CreationTrace creation_context_;+ #define CAPTURE_CREATION(name) \+ CreationTrace creation_context_ = name; #define TRACE_CREATION \- TraceCreation trace_creation(TypeInstance::TypeName(parent), creation_context_);+ TraceCreation trace_creation(creation_context_); #define FAIL_WHEN_NULL(value) \ FailWhenNull(value)@@ -171,35 +174,43 @@ class ProgramArgv : public Argv { public: inline ProgramArgv(int argc, const char** argv)- : argv_(argv, argv + argc), capture_to_(this) {}+ : argv_(argv, argv + argc), cross_and_capture_to_(this) {} private: const std::vector<std::string>& GetArgs() const final; const std::vector<std::string> argv_;- const ScopedCapture capture_to_;+ const AutoThreadCrosser cross_and_capture_to_; }; class CreationTrace { public:- inline CreationTrace() : trace_(TraceContext::GetTrace()) {}+ // NOTE: Using a template with [] here breaks inline member initialization+ // when using CAPTURE_CREATION in g++.+ inline CreationTrace(const char* type)+ : type_(type), trace_(TraceContext::GetTrace()) {} + inline std::string GetType() const {+ return type_;+ }+ inline const TraceList& GetTrace() const { return trace_; } private:+ const char* const type_; const TraceList trace_; }; class TraceCreation : public capture_thread::ThreadCapture<TraceCreation> { public:- inline TraceCreation(std::string type, const CreationTrace& trace)- : type_(type), trace_(trace), capture_to_(this) {}+ inline TraceCreation(const CreationTrace& trace)+ : trace_(trace), capture_to_(this) {} static inline std::string GetType() { if (GetCurrent()) {- return GetCurrent()->type_;+ return GetCurrent()->trace_.GetType(); } else { return std::string(); }@@ -214,10 +225,37 @@ } private:-- const std::string type_; const CreationTrace& trace_; const ScopedCapture capture_to_;+};++class LogCalls : public capture_thread::ThreadCapture<LogCalls> {+ public:+ static inline void MaybeLogCall(const char* name, const char* at) {+ if (GetCurrent()) {+ GetCurrent()->LogCall(name, at);+ }+ }++ protected:+ virtual ~LogCalls() = default;++ private:+ virtual void LogCall(const char* name, const char* at) = 0;+};++class LogCallsToFile : public LogCalls {+ public:+ LogCallsToFile(std::string filename);++ private:+ void LogCall(const char* name, const char* at) final;++ std::mutex mutex_;+ const unsigned int unique_id_;+ const std::string& filename_;+ const std::unique_ptr<std::fstream> log_file_;+ const AutoThreadCrosser cross_and_capture_to_; }; #endif // LOGGING_HPP_
example/parser/parse-text.0rx view
@@ -9,20 +9,16 @@ } String message <- "Failed to match \"" + match + "\" at " + contextOld.getPosition() ParseContext<any> context <- contextOld- scoped {- Int index <- 0- } in while (index < match.size()) {- $ReadOnly[context,index]$+ traverse (Counter.zeroIndexed(match.size()) -> Int index) {+ $ReadOnly[index]$ if (context.atEof() || context.current() != match.readAt(index)) { if (index > 0) { // Partial match => set error context. return context.setBrokenInput(message) } else {- return context.setValue<all>(ErrorOr:error(message))+ return context.setValue<?>(ErrorOr:error(message)) } }- } update {- index <- index+1 context <- context.advance() } return context.setValue<?>(ErrorOr:value<?>(match))@@ -49,27 +45,32 @@ contextOld.getPosition() ParseContext<any> context <- contextOld [Append<String>&Build<String>] builder <- String.builder()++ optional Order<Int> counter <- empty+ if (max == 0) {+ counter <- Counter.unlimited()+ } else {+ counter <- Counter.zeroIndexed(max)+ }+ Int count <- 0- while (!context.atEof() && (max == 0 || count < max)) {- $ReadOnly[context,count]$+ traverse (counter -> count) {+ $Hidden[count,counter]$+ if (context.atEof()) {+ break+ } Bool found <- false- scoped {- Int index <- 0- } in while (index < matches.size()) {- $ReadOnly[index]$+ traverse (Counter.zeroIndexed(matches.size()) -> Int index) {+ $ReadOnly[context,index]$ if (context.current() == matches.readAt(index)) { \ builder.append(matches.readAt(index).formatted()) found <- true break }- } update {- index <- index+1 } if (!found) { break }- } update {- count <- count+1 context <- context.advance() } if (count >= min) {@@ -78,7 +79,7 @@ // Partial match => set error context. return context.setBrokenInput(message) } else {- return context.setValue<all>(ErrorOr:error(message))+ return context.setValue<?>(ErrorOr:error(message)) } } @@ -98,7 +99,7 @@ } if (contextOld.atEof() || contextOld.current() != match) { String message <- "Failed to match '" + match.formatted() + "' at " + contextOld.getPosition()- return contextOld.setValue<all>(ErrorOr:error(message))+ return contextOld.setValue<?>(ErrorOr:error(message)) } else { return contextOld.advance().setValue<?>(ErrorOr:value<?>(match)) }@@ -137,7 +138,7 @@ @value Formatted message run (contextOld) {- return contextOld.setValue<all>(ErrorOr:error(message))+ return contextOld.setValue<?>(ErrorOr:error(message)) } create (message) {@@ -160,7 +161,7 @@ } ParseContext<#x> context <- contextOld.run<#x>(parser) if (context.hasAnyError()) {- return contextOld.setValue<all>(context.getValue().convertError())+ return contextOld.setValue<?>(context.getValue().convertError()) } else { return context.toState() }@@ -216,7 +217,7 @@ if (context.hasAnyError()) { return context.toState() } else {- ParseContext<any> context2 <- context.run<any>(parser2)+ ParseContext<any> context2 <- context.run<?>(parser2) if (context2.hasAnyError()) { return context2.convertError() } else {@@ -244,7 +245,7 @@ if (contextOld.hasAnyError()) { return contextOld.convertError() }- ParseContext<any> context <- contextOld.run<any>(parser1)+ ParseContext<any> context <- contextOld.run<?>(parser1) if (context.hasAnyError()) { return context.convertError() } else {
example/parser/test-data.0rx view
@@ -23,6 +23,25 @@ } define TestDataParser {+ // Mark @category members as read-only, to avoid accidental assignment.+ $ReadOnly[sentenceOrToken,+ acronymOrAardvark,+ fileStart,+ fileEnd,+ nameTag,+ descriptionTag,+ aWordTag]$++ // Mark @category members as hidden, since they should not be used directly.+ $Hidden[whitespace,+ sentenceChars,+ sentence,+ quote,+ quotedSentence,+ token,+ acronym,+ aardvark]$+ refines Parser<TestData> @category Parser<any> whitespace <- SequenceOfParser.create(" \n\t",1,0) `Parse.or<?>` Parse.error("Expected whitespace")
+ example/primes/.zeolite-module view
@@ -0,0 +1,11 @@+root: "../.."+path: "example/primes"+private_deps: [+ "lib/container"+ "lib/thread"+ "lib/util"+]+mode: binary {+ category: PrimesDemo+ function: run+}
+ example/primes/README.md view
@@ -0,0 +1,57 @@+# Zeolite Primes Example++*Also see+[a highlighted version of the example code](https://ta0kira.github.io/zeolite/example/primes).*++This example demonstrates synchronizing two threads using `lib/thread`.++## Notes++There are two threads in this program:++1. The main thread, which deals with user input.+2. The computation thread, which is controlled by the main thread.++When the program starts, the computation thread is stopped, and the main thread+is waiting for user input. Follow the prompts to start, stop, and cancel the+computation thread. The program will print the prime numbers computed during the+time that the computation thread was running.++A few specific points about the example:++- See `flag.0rx` for an example of how `ConditionWait` and `ConditionResume`+ (from `lib/thread`) can be used to start and stop a thread process. (Also+ notice that it uses the type intersection `[ConditionWait&ConditionResume]`.)++- `prime-tracker.0rx` uses both the `$ReadOnly[...]$` and `$Hidden[...]$`+ pragmas to cut down on possible errors when multiple variables of the same+ type are in scope.++- Other than the condition logic in `ThreadFlag`, the other categories in this+ example *are not* thread-safe. On the other hand, the main thread does not+ read or modify any shared state other than the `ThreadFlag` while the+ computation thread is running. Other approaches might require using `Mutex`es+ in other places.++## Running++This example depends on the optional `lib/thread` library. That library is+included in the base package, but you might need to build it first.++```shell+ZEOLITE_PATH=$(zeolite --get-path)+zeolite -p "$ZEOLITE_PATH" -r lib/thread+```++To run the example:++```shell+# This is just to locate the example code. Not for normal use!+ZEOLITE_PATH=$(zeolite --get-path)++# Compile the example.+zeolite -p "$ZEOLITE_PATH" -r example/primes++# Execute the compiled binary.+$ZEOLITE_PATH/example/primes/PrimesDemo+```
+ example/primes/flag.0rp view
@@ -0,0 +1,32 @@+$ModuleOnly$++// A gate for starting, stopping, and canceling thread processes.+@value interface ThreadGate {+ // Start the thread(s).+ start () -> (#self)++ // Stop the thread(s).+ stop () -> (#self)++ // Returns true iff the thread(s) should be running.+ getEnabled () -> (Bool)++ // Permanently cancel the thread(s).+ cancel () -> (#self)+}+++// Determine if a thread should continue or exit.+@value interface ThreadContinue {+ // Blocks until a start or cancel signal is received. If false is returned,+ // the thread should clean up and exit.+ shouldContinue () -> (Bool)+}++// Implementation of thread gating with a flag.+concrete ThreadFlag {+ refines ThreadGate+ refines ThreadContinue++ @type new () -> (ThreadFlag)+}
+ example/primes/flag.0rx view
@@ -0,0 +1,64 @@+define ThreadFlag {+ @value [ConditionWait&ConditionResume] cond+ @value Bool enabled+ @value Bool canceled++ new () {+ return ThreadFlag{ ThreadCondition.new(), false, false }+ }++ start () {+ scoped {+ MutexLock lock <- MutexLock.lock(cond)+ } cleanup {+ \ lock.freeResource()+ } in enabled <- true+ \ cond.resumeAll()+ return self+ }++ stop () {+ scoped {+ MutexLock lock <- MutexLock.lock(cond)+ } cleanup {+ \ lock.freeResource()+ } in enabled <- false+ return self+ }++ getEnabled () {+ scoped {+ MutexLock lock <- MutexLock.lock(cond)+ } cleanup {+ \ lock.freeResource()+ } in return enabled && !canceled+ }++ cancel () {+ scoped {+ MutexLock lock <- MutexLock.lock(cond)+ } cleanup {+ \ lock.freeResource()+ } in canceled <- true+ \ cond.resumeAll()+ return self+ }++ shouldContinue () {+ scoped {+ MutexLock lock <- MutexLock.lock(cond)+ } cleanup {+ \ lock.freeResource()+ } in while (true) {+ if (canceled) {+ return false+ } elif (enabled) {+ break+ } else {+ // The Mutex associated with cond is unlocked during wait().+ \ cond.wait()+ }+ }+ return true+ }+}
+ example/primes/prime-thread.0rp view
@@ -0,0 +1,8 @@+$ModuleOnly$++// Repeatedly checks the next possible prime until canceled.+concrete PrimeThread {+ refines Routine++ @type create (ThreadContinue,PrimeTracker) -> (PrimeThread)+}
+ example/primes/prime-thread.0rx view
@@ -0,0 +1,14 @@+define PrimeThread {+ @value ThreadContinue flag+ @value PrimeTracker tracker++ create (flag,tracker) {+ return PrimeThread{ flag, tracker }+ }++ run () {+ while (flag.shouldContinue()) {+ \ tracker.checkNextPossible(flag)+ }+ }+}
+ example/primes/prime-tracker.0rp view
@@ -0,0 +1,9 @@+$ModuleOnly$++// Incrementally tracks primes.+concrete PrimeTracker {+ @type create () -> (PrimeTracker)+ @value checkNextPossible (ThreadContinue) -> (#self)+ // optional Order<Int> can be used with the traverse built-in for iteration.+ @value getResults () -> (optional Order<Int>)+}
+ example/primes/prime-tracker.0rx view
@@ -0,0 +1,46 @@+define PrimeTracker {+ @value Vector<Int> primes+ @value Int nextPossible++ create () {+ return PrimeTracker{ Vector:create<Int>(), 2 }+ }++ checkNextPossible (flag) {+ Int toCheck <- nextPossible+ $ReadOnly[toCheck]$++ Bool isPrime <- true++ traverse (getResults() -> Int prime) {+ $ReadOnly[prime]$+ $Hidden[nextPossible]$+ if (!flag.shouldContinue()) {+ return self+ }+ if (toCheck%prime == 0) {+ isPrime <- false+ break+ }+ if (prime*prime >= toCheck) {+ break+ }+ }+ // Postpone updating the next possible until we know that there wasn't an+ // early return due to the flag.+ nextPossible <- nextPossible+1++ if (isPrime) {+ \ LazyStream<Formatted>.new()+ .append("\r")+ .append(toCheck)+ .writeTo(SimpleOutput.stderr())+ \ primes.push(toCheck)+ }+ return self+ }++ getResults () {+ return primes.defaultOrder()+ }+}
+ example/primes/primes-demo.0rx view
@@ -0,0 +1,62 @@+concrete PrimesDemo {+ @type run () -> ()+}++define PrimesDemo {+ run () {+ PrimeTracker tracker <- PrimeTracker.create()+ ThreadFlag flag <- ThreadFlag.new()+ Thread thread <- ProcessThread.from(PrimeThread.create(flag,tracker)).start()++ // Interactive input loop.++ scoped {+ TextReader reader <- TextReader.fromBlockReader(SimpleInput.stdin())+ } in while (!reader.pastEnd()) {+ $Hidden[tracker,thread]$++ \ LazyStream<Formatted>.new()+ .append("Press [Enter] to toggle start/stop computation thread. Type \"exit\" to exit.\n")+ .writeTo(SimpleOutput.stderr())+ String input <- reader.readNextLine()+ if (reader.pastEnd()) {+ break+ }++ if (input == "") {+ if (flag.getEnabled()) {+ \ flag.stop()+ \ LazyStream<Formatted>.new()+ .append("Stopped.\n")+ .writeTo(SimpleOutput.stderr())+ } else {+ \ flag.start()+ \ LazyStream<Formatted>.new()+ .append("Started.\n")+ .writeTo(SimpleOutput.stderr())+ }+ } elif (input == "exit") {+ break+ } else {+ \ LazyStream<Formatted>.new()+ .append("Please try again!\n")+ .writeTo(SimpleOutput.stderr())+ }+ }++ // Wait for the thread to exit, then print the results.++ \ flag.cancel()+ \ LazyStream<Formatted>.new()+ .append("Exiting.\n")+ .writeTo(SimpleOutput.stderr())+ \ thread.join()++ traverse (tracker.getResults() -> Int prime) {+ \ LazyStream<Formatted>.new()+ .append(prime)+ .append("\n")+ .writeTo(SimpleOutput.stdout())+ }+ }+}
lib/container/interfaces.0rp view
@@ -50,3 +50,16 @@ // Returns the value associated with the key if present. get (#k) -> (optional #v) }++// A single key-value pair from a KVReader.+@value interface KeyValue<|#k,#v> {+ // Get the key.+ //+ // Notes:+ // - Calling mutating functions on the key could invalidate the structure of+ // the KVReader.+ getKey () -> (#k)++ // Get the value.+ getValue () -> (#v)+}
lib/container/search-tree.0rp view
@@ -22,12 +22,30 @@ // - #k: The key type. // - #v: The value type. concrete SearchTree<#k,#v> {+ refines DefaultOrder<KeyValue<#k,#v>> refines KVWriter<#k,#v> refines KVReader<#k,#v> #k defines LessThan<#k> // Create an empty tree. @type new () -> (#self)++ // Traverse the tree in the reverse order of defaultOrder().+ //+ // Notes:+ // - Traversal of the entire tree is amortized O(n); however, the cost of any+ // particular iteration could be up to O(log n).+ // - The overall memory cost is O(log n).+ @value reverseOrder () -> (optional Order<KeyValue<#k,#v>>)++ // Traverse in the default order.+ //+ // Notes:+ // - This is from DefaultOrder, but is made explicit for documentation.+ // - Traversal of the entire tree is amortized O(n); however, the cost of any+ // particular iteration could be up to O(log n).+ // - The overall memory cost is O(log n).+ @value defaultOrder () -> (optional Order<KeyValue<#k,#v>>) } // A validated binary search tree for key-value storage.@@ -40,7 +58,7 @@ // - This is the same as SearchTree, but it validates the tree structure every // time there is a modification, which is extremely inefficient. This should // therefore only be used in tests.-concrete ValidatedTree<#k,#v> {+concrete ValidatedTree<#k|#v|> { refines KVWriter<#k,#v> refines KVReader<#k,#v> #k defines LessThan<#k>
lib/container/search-tree.0rt view
@@ -16,11 +16,11 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] -testcase "integration test" {+testcase "SearchTree tests" { success } -unittest test {+unittest integrationTest { [KVWriter<Int,Int>&KVReader<Int,Int>] tree <- ValidatedTree<Int,Int>.new() Int count <- 30 @@ -61,4 +61,48 @@ } update { i <- i+1 }+}++unittest defaultOrder {+ SearchTree<Int,Int> tree <- SearchTree<Int,Int>.new()+ Int hash <- 13+ Int max <- 20+ $ReadOnly[hash,max]$++ // Populate the tree in a pseudo-random order.+ traverse (Counter.zeroIndexed(max) -> Int i) {+ \ ((i*hash)%max) `tree.set` i+ }++ // Validate the traversal order.+ Int index <- 0+ traverse (tree.defaultOrder() -> KeyValue<Int,Int> entry) {+ \ Testing.checkEquals<?>(entry.getKey(),index)+ \ Testing.checkEquals<?>((entry.getValue()*hash)%max,entry.getKey())+ index <- index+1+ }++ \ Testing.checkEquals<?>(index,20)+}++unittest reverseOrder {+ SearchTree<Int,Int> tree <- SearchTree<Int,Int>.new()+ Int hash <- 13+ Int max <- 20+ $ReadOnly[hash,max]$++ // Populate the tree in a pseudo-random order.+ traverse (Counter.zeroIndexed(max) -> Int i) {+ \ ((i*hash)%max) `tree.set` i+ }++ // Validate the traversal order.+ Int index <- 20+ traverse (tree.reverseOrder() -> KeyValue<Int,Int> entry) {+ index <- index-1+ \ Testing.checkEquals<?>(entry.getKey(),index)+ \ Testing.checkEquals<?>((entry.getValue()*hash)%max,entry.getKey())+ }++ \ Testing.checkEquals<?>(index,0) }
lib/container/search-tree.0rx view
@@ -36,6 +36,14 @@ get (k) { return Node<#k,#v>.find(root,k) }++ defaultOrder () {+ return ForwardTreeOrder:create<?,?>(root)+ }++ reverseOrder () {+ return ReverseTreeOrder:create<?,?>(root)+ } } define ValidatedTree {@@ -69,6 +77,11 @@ @type delete (optional Node<#k,#v>,#k) -> (optional Node<#k,#v>) @type find (optional Node<#k,#v>,#k) -> (optional #v) @type validate (optional Node<#k,#v>) -> ()++ @value getLower () -> (optional Node<#k,#v>)+ @value getHigher () -> (optional Node<#k,#v>)+ @value getKey () -> (#k)+ @value getValue () -> (#v) } define Node {@@ -134,6 +147,14 @@ } } + getLower () { return lower }++ getHigher () { return higher }++ getKey () { return key }++ getValue () { return value }+ @value validateOrder () -> () validateOrder () { if (present(lower)) {@@ -303,29 +324,121 @@ @value getHeight () -> (Int) getHeight () { return height } - // It is unsafe to change the key after construction, so there is no setter.- //- // Unlike other languages, a member is only accessible by the value that owns- // it. More specifically, @type functions in Node can only access @value- // members via explicit @value getters and setters.- @value getKey () -> (#k)- getKey () { return key }-- @value getValue () -> (#v)- getValue () { return value }- @value setValue (#v) -> () setValue (v) { value <- v } - @value getLower () -> (optional Node<#k,#v>)- getLower () { return lower }- @value setLower (optional Node<#k,#v>) -> () setLower (l) { lower <- l } - @value getHigher () -> (optional Node<#k,#v>)- getHigher () { return higher }- @value setHigher (optional Node<#k,#v>) -> () setHigher (h) { higher <- h }+}++concrete TreeKeyValue<#k,#v> {+ refines KeyValue<#k,#v>++ @category create<#k,#v> (#k,#v) -> (TreeKeyValue<#k,#v>)+}++define TreeKeyValue {+ @value #k key+ @value #v value++ create (key,value) {+ return TreeKeyValue<#k,#v>{ key, value }+ }++ getKey () {+ return key+ }++ getValue () {+ return value+ }+}++concrete ForwardTreeOrder<#k,#v> {+ refines Order<KeyValue<#k,#v>>+ #k defines LessThan<#k>++ @category create<#k,#v>+ #k defines LessThan<#k>+ (optional Node<#k,#v>) -> (optional ForwardTreeOrder<#k,#v>)+}++define ForwardTreeOrder {+ $ReadOnly[node,prev]$++ @value Node<#k,#v> node+ @value optional ForwardTreeOrder<#k,#v> prev++ create (node) {+ optional Node<#k,#v> node2 <- node+ optional ForwardTreeOrder<#k,#v> current <- empty+ while (present(node2)) {+ current <- ForwardTreeOrder<#k,#v>{ require(node2), current }+ node2 <- require(node2).getLower()+ }+ return current+ }++ next () {+ // Algorithm:+ // 1. Pop self from the stack.+ // 2. Traverse lower to the bottom starting from the higher child of self.+ optional Node<#k,#v> node2 <- node.getHigher()+ optional ForwardTreeOrder<#k,#v> current <- prev+ while (present(node2)) {+ current <- ForwardTreeOrder<#k,#v>{ require(node2), current }+ node2 <- require(node2).getLower()+ }+ return current+ }++ get () {+ return TreeKeyValue:create<?,?>(node.getKey(),node.getValue())+ }+}++concrete ReverseTreeOrder<#k,#v> {+ refines Order<KeyValue<#k,#v>>+ #k defines LessThan<#k>++ @category create<#k,#v>+ #k defines LessThan<#k>+ (optional Node<#k,#v>) -> (optional ReverseTreeOrder<#k,#v>)+}++define ReverseTreeOrder {+ $ReadOnly[node,prev]$++ @value Node<#k,#v> node+ @value optional ReverseTreeOrder<#k,#v> prev++ create (node) {+ optional Node<#k,#v> node2 <- node+ optional ReverseTreeOrder<#k,#v> current <- empty+ while (present(node2)) {+ current <- ReverseTreeOrder<#k,#v>{ require(node2), current }+ node2 <- require(node2).getHigher()+ }+ return current+ }++ next () {+ // Algorithm:+ // 1. Pop self from the stack.+ // 2. Traverse higher to the bottom starting from the lower child of self.+ optional Node<#k,#v> node2 <- node.getLower()+ optional ReverseTreeOrder<#k,#v> current <- prev+ while (present(node2)) {+ current <- ReverseTreeOrder<#k,#v>{ require(node2), current }+ node2 <- require(node2).getHigher()+ }+ return current+ }++ get () {+ return TreeKeyValue:create<?,?>(node.getKey(),node.getValue())+ } }
lib/container/src/Extension_Vector.cpp view
@@ -24,7 +24,9 @@ #include "Category_Append.hpp" #include "Category_Container.hpp" #include "Category_Default.hpp"+#include "Category_DefaultOrder.hpp" #include "Category_Formatted.hpp"+#include "Category_Order.hpp" #include "Category_ReadAt.hpp" #include "Category_Stack.hpp" #include "Category_String.hpp"@@ -37,7 +39,7 @@ using VectorType = std::vector<S<TypeValue>>; -S<TypeValue> CreateValue_Vector(S<Type_Vector> parent, const ParamTuple& params, VectorType values);+S<TypeValue> CreateValue_Vector(S<Type_Vector> parent, VectorType values); struct ExtCategory_Vector : public Category_Vector { ReturnTuple Call_copyFrom(const ParamTuple& params, const ValueTuple& args) final {@@ -49,13 +51,13 @@ for (int i = 0; i < size; ++i) { values.push_back(TypeValue::Call(Var_arg1, Function_ReadAt_readAt, ParamTuple(), ArgTuple(Box_Int(i))).Only()); }- return ReturnTuple(CreateValue_Vector(CreateType_Vector(Params<1>::Type(Param_y)), ParamTuple(), values));+ return ReturnTuple(CreateValue_Vector(CreateType_Vector(Params<1>::Type(Param_y)), values)); } ReturnTuple Call_create(const ParamTuple& params, const ValueTuple& args) final { TRACE_FUNCTION("Vector:create") const S<TypeInstance> Param_y = params.At(0);- return ReturnTuple(CreateValue_Vector(CreateType_Vector(Params<1>::Type(Param_y)), ParamTuple(), VectorType()));+ return ReturnTuple(CreateValue_Vector(CreateType_Vector(Params<1>::Type(Param_y)), VectorType())); } ReturnTuple Call_createSize(const ParamTuple& params, const ValueTuple& args) final {@@ -66,7 +68,7 @@ for (int i = 0; i < Var_arg1; ++i) { values.push_back(TypeInstance::Call(Param_y, Function_Default_default, ParamTuple(), ArgTuple()).Only()); }- return ReturnTuple(CreateValue_Vector(CreateType_Vector(Params<1>::Type(Param_y)), ParamTuple(), values));+ return ReturnTuple(CreateValue_Vector(CreateType_Vector(Params<1>::Type(Param_y)), values)); } }; @@ -74,9 +76,31 @@ inline ExtType_Vector(Category_Vector& p, Params<1>::Type params) : Type_Vector(p, params) {} }; +struct VectorOrder : public AnonymousOrder {+ VectorOrder(S<TypeValue> container, const VectorType& v)+ : AnonymousOrder(container, Function_Order_next, Function_Order_get), values(v) {}++ S<TypeValue> Call_next(const S<TypeValue>& self) final {+ if (index+1 >= values.size()) {+ return Var_empty;+ } else {+ ++index;+ return self;+ }+ }++ S<TypeValue> Call_get(const S<TypeValue>& self) final {+ if (index >= values.size()) FAIL() << "iterated past end of Vector";+ return values[index];+ }++ const VectorType& values;+ int index = 0;+};+ struct ExtValue_Vector : public Value_Vector {- inline ExtValue_Vector(S<Type_Vector> p, const ParamTuple& params, VectorType v)- : Value_Vector(p, params), values(std::move(v)) {}+ inline ExtValue_Vector(S<Type_Vector> p, VectorType v)+ : Value_Vector(p), values(std::move(v)) {} ReturnTuple Call_append(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final { TRACE_FUNCTION("Vector.append")@@ -86,6 +110,15 @@ return ReturnTuple(Var_self); } + ReturnTuple Call_defaultOrder(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("Vector.defaultOrder")+ if (values.empty()) {+ return ReturnTuple(Var_empty);+ } else {+ return ReturnTuple(S_get(new VectorOrder(Var_self, values)));+ }+ }+ ReturnTuple Call_pop(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final { TRACE_FUNCTION("Vector.pop") std::lock_guard<std::mutex> lock(mutex);@@ -147,8 +180,8 @@ }); return cache.GetOrCreate(params); }-S<TypeValue> CreateValue_Vector(S<Type_Vector> parent, const ParamTuple& params, VectorType values) {- return S_get(new ExtValue_Vector(parent, params, values));+S<TypeValue> CreateValue_Vector(S<Type_Vector> parent, VectorType values) {+ return S_get(new ExtValue_Vector(parent, values)); } #ifdef ZEOLITE_PUBLIC_NAMESPACE
lib/container/vector.0rp view
@@ -21,10 +21,11 @@ // Params: // - #x: The value type contained. concrete Vector<#x> {+ refines Append<#x>+ refines DefaultOrder<#x> refines Stack<#x> refines ReadAt<#x> refines WriteAt<#x>- refines Append<#x> // Create a copy from another random-access container. @category copyFrom<#y> (ReadAt<#y>) -> (Vector<#y>)@@ -36,7 +37,7 @@ // // Notes: // - #y.default() should return a distinct value each time if #y is mutable.- // This means that modifying one element should not change others.+ // This means that modifying one element should not change others. @category createSize<#y> #y defines Default (Int) -> (Vector<#y>)
lib/container/vector.0rt view
@@ -113,6 +113,25 @@ } } +unittest traverseVector {+ Int index <- 0+ Vector<Int> vector <- Vector:create<Int>()+ \ vector.push(2)+ \ vector.push(6)+ \ vector.push(3)+ \ vector.push(5)+ \ vector.push(4)+ \ vector.push(1)++ traverse (vector.defaultOrder() -> Int i) {+ \ Testing.checkEquals<?>(i,vector.readAt(index))+ index <- index+1+ }++ \ Testing.checkEquals<?>(index,6)+}++ testcase "distinct default values in pre-sized Vector" { success }
lib/file/src/Extension_RawFileReader.cpp view
@@ -25,7 +25,7 @@ namespace ZEOLITE_PUBLIC_NAMESPACE { #endif // ZEOLITE_PUBLIC_NAMESPACE -S<TypeValue> CreateValue_RawFileReader(S<Type_RawFileReader> parent, const ParamTuple& params, const ValueTuple& args);+S<TypeValue> CreateValue_RawFileReader(S<Type_RawFileReader> parent, const ValueTuple& args); struct ExtCategory_RawFileReader : public Category_RawFileReader { };@@ -35,13 +35,13 @@ ReturnTuple Call_open(const S<TypeInstance>& Param_self, const ParamTuple& params, const ValueTuple& args) final { TRACE_FUNCTION("RawFileReader.open")- return ReturnTuple(CreateValue_RawFileReader(CreateType_RawFileReader(Params<0>::Type()), ParamTuple(), args));+ return ReturnTuple(CreateValue_RawFileReader(CreateType_RawFileReader(Params<0>::Type()), args)); } }; struct ExtValue_RawFileReader : public Value_RawFileReader {- inline ExtValue_RawFileReader(S<Type_RawFileReader> p, const ParamTuple& params, const ValueTuple& args)- : Value_RawFileReader(p, params),+ inline ExtValue_RawFileReader(S<Type_RawFileReader> p, const ValueTuple& args)+ : Value_RawFileReader(p), filename(args.At(0)->AsString()), file(new std::ifstream(filename, std::ios::in | std::ios::binary)) {} @@ -107,7 +107,7 @@ std::mutex mutex; const std::string filename; R<std::istream> file;- CAPTURE_CREATION+ CAPTURE_CREATION("RawFileReader") }; Category_RawFileReader& CreateCategory_RawFileReader() {@@ -118,8 +118,8 @@ static const auto cached = S_get(new ExtType_RawFileReader(CreateCategory_RawFileReader(), Params<0>::Type())); return cached; }-S<TypeValue> CreateValue_RawFileReader(S<Type_RawFileReader> parent, const ParamTuple& params, const ValueTuple& args) {- return S_get(new ExtValue_RawFileReader(parent, params, args));+S<TypeValue> CreateValue_RawFileReader(S<Type_RawFileReader> parent, const ValueTuple& args) {+ return S_get(new ExtValue_RawFileReader(parent, args)); } #ifdef ZEOLITE_PUBLIC_NAMESPACE
lib/file/src/Extension_RawFileWriter.cpp view
@@ -25,7 +25,7 @@ namespace ZEOLITE_PUBLIC_NAMESPACE { #endif // ZEOLITE_PUBLIC_NAMESPACE -S<TypeValue> CreateValue_RawFileWriter(S<Type_RawFileWriter> parent, const ParamTuple& params, const ValueTuple& args);+S<TypeValue> CreateValue_RawFileWriter(S<Type_RawFileWriter> parent, const ValueTuple& args); struct ExtCategory_RawFileWriter : public Category_RawFileWriter { };@@ -35,13 +35,13 @@ ReturnTuple Call_open(const S<TypeInstance>& Param_self, const ParamTuple& params, const ValueTuple& args) final { TRACE_FUNCTION("RawFileWriter.open")- return ReturnTuple(CreateValue_RawFileWriter(CreateType_RawFileWriter(Params<0>::Type()), ParamTuple(), args));+ return ReturnTuple(CreateValue_RawFileWriter(CreateType_RawFileWriter(Params<0>::Type()), args)); } }; struct ExtValue_RawFileWriter : public Value_RawFileWriter {- inline ExtValue_RawFileWriter(S<Type_RawFileWriter> p, const ParamTuple& params, const ValueTuple& args)- : Value_RawFileWriter(p, params),+ inline ExtValue_RawFileWriter(S<Type_RawFileWriter> p, const ValueTuple& args)+ : Value_RawFileWriter(p), filename(args.At(0)->AsString()), file(new std::ofstream(filename, std::ios::out | std::ios::binary | std::ios::trunc | std::ios::ate)) {} @@ -89,7 +89,7 @@ std::mutex mutex; const std::string filename; R<std::ostream> file;- CAPTURE_CREATION+ CAPTURE_CREATION("RawFileWriter") }; Category_RawFileWriter& CreateCategory_RawFileWriter() {@@ -100,8 +100,8 @@ static const auto cached = S_get(new ExtType_RawFileWriter(CreateCategory_RawFileWriter(), Params<0>::Type())); return cached; }-S<TypeValue> CreateValue_RawFileWriter(S<Type_RawFileWriter> parent, const ParamTuple& params, const ValueTuple& args) {- return S_get(new ExtValue_RawFileWriter(parent, params, args));+S<TypeValue> CreateValue_RawFileWriter(S<Type_RawFileWriter> parent, const ValueTuple& args) {+ return S_get(new ExtValue_RawFileWriter(parent, args)); } #ifdef ZEOLITE_PUBLIC_NAMESPACE
lib/math/src/Extension_Math.cpp view
@@ -198,10 +198,6 @@ } }; -struct ExtValue_Math : public Value_Math {- inline ExtValue_Math(S<Type_Math> p, const ParamTuple& params, const ValueTuple& args) : Value_Math(p, params) {}-};- Category_Math& CreateCategory_Math() { static auto& category = *new ExtCategory_Math(); return category;
lib/testing/helpers.0rp view
@@ -30,7 +30,7 @@ #x defines Equals<#x> (#x,#x) -> () - // Check that the value is within a range. Crashes if they are not equal.+ // Check that the value is within a range. Crashes if it is not in the range. // // Args: // - #x: Actual value.
lib/thread/.zeolite-module view
@@ -4,6 +4,7 @@ "lib/util" ] private_deps: [+ "lib/container" "lib/testing" ] extra_files: [@@ -16,8 +17,21 @@ categories: [ProcessThread] } category_source {+ source: "lib/thread/src/Extension_Realtime.cpp"+ categories: [Realtime]+ }+ category_source { source: "lib/thread/src/Extension_SimpleMutex.cpp" categories: [SimpleMutex]+ }+ category_source {+ source: "lib/thread/src/Extension_ThreadCondition.cpp"+ categories: [ThreadCondition]+ }+ category_source {+ source: "lib/thread/src/Extension_Enumerated.cpp"+ categories: [EnumeratedBarrier EnumeratedWait]+ requires: [Stack Vector] } ] mode: incremental {
lib/thread/README.md view
@@ -10,12 +10,10 @@ ## Configuring and Building This library *is not* automatically built by `zeolite-setup`; you need to build-it manually. This is because there might be issues with linker dependencies-between different systems.+it manually. This is because there might be issues with thread-library+dependencies between different systems. -1. If you are running Linux, the config should work as-is. If you are running- FreeBSD, you might need to remove or change `"-lpthread"` at the bottom of- `.zeolite-module`.+1. If you are running Linux or FreeBSD, the config should work as-is. To build the library:
+ lib/thread/barrier-ext.0rp view
@@ -0,0 +1,23 @@+/* -----------------------------------------------------------------------------+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]++$ModuleOnly$++concrete EnumeratedWait {+ refines BarrierWait+}
+ lib/thread/barrier.0rp view
@@ -0,0 +1,46 @@+/* -----------------------------------------------------------------------------+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]++// Waits for a thread barrier.+@value interface BarrierWait {+ // Block until the barrier condition is satisfied.+ wait () -> (#self)+}++// A thread barrier validated using thread enumeration.+concrete EnumeratedBarrier {+ // Create a new barrier for a fixed number of threads.+ //+ // Args:+ // - Int: Non-negative number of threads.+ //+ // Returns:+ // - ReadAt<BarrierWait>: A list of the requested number of BarrierWait. These+ // should be passed out to the respective threads.+ //+ // Notes:+ // - Each thread must use its own BarrierWait; otherwise, there will be an+ // error-checking crash. For example, passing readAt(0) to all threads is+ // not allowed.+ // - If a BarrierWait no longer has any references (and thus cannot be used),+ // the barrier will be disabled. This will cause a crash if any thread is+ // waiting for (or subsequently waits for) the barrier. This does not mean+ // that you need to keep the ReadAt<BarrierWait> itself; one thread holding+ // a reference to each individual BarrierWait is sufficient.+ @type new (Int) -> (ReadAt<BarrierWait>)+}
+ lib/thread/barrier.0rt view
@@ -0,0 +1,178 @@+/* -----------------------------------------------------------------------------+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 "EnumeratedBarrier tests" {+ success+}++unittest correctCount {+ ReadAt<BarrierWait> barriers <- EnumeratedBarrier.new(13)+ \ Testing.checkEquals<?>(barriers.size(),13)+}++unittest waitForOneThread {+ ReadAt<BarrierWait> barriers <- EnumeratedBarrier.new(1)+ \ barriers.readAt(0).wait()+}++unittest zeroAllowed {+ ReadAt<BarrierWait> barriers <- EnumeratedBarrier.new(0)+ \ Testing.checkEquals<?>(barriers.size(),0)+}++unittest waitForMultipleThreads {+ Value value <- Value.create()+ Mutex mutex <- SimpleMutex.new()+ ReadAt<BarrierWait> barriers <- EnumeratedBarrier.new(3)++ Thread thread1 <- ProcessThread.from(WaitAndIncrement.create(2,value,mutex,barriers.readAt(1))).start()+ Thread thread2 <- ProcessThread.from(WaitAndIncrement.create(2,value,mutex,barriers.readAt(2))).start()++ \ barriers.readAt(0).wait()+ \ Testing.checkEquals<?>(value.get(),2)++ \ barriers.readAt(0).wait()+ \ Testing.checkEquals<?>(value.get(),4)++ \ thread1.join()+ \ thread2.join()+}++concrete WaitAndIncrement {+ refines Routine++ @type create (Int,Value,Mutex,BarrierWait) -> (WaitAndIncrement)+}++define WaitAndIncrement {+ @value Int count+ @value Value value+ @value Mutex mutex+ @value BarrierWait barrier++ create (count,value,mutex,barrier) {+ return WaitAndIncrement{ count, value, mutex, barrier }+ }++ run () {+ scoped {+ Int i <- 0+ } in while (i < count) {+ $Hidden[i,count]$+ scoped {+ MutexLock lock <- MutexLock.lock(mutex)+ } cleanup {+ \ lock.freeResource()+ } in {+ \ value.increment()+ }+ \ barrier.wait()+ // Gives the main thread time to read the value.+ \ Realtime.sleepSeconds(0.01)+ } update {+ i <- i+1+ }+ }+}+++testcase "EnumeratedBarrier crashes with negative count" {+ crash+ require "-4"+}++unittest test {+ ReadAt<BarrierWait> barriers <- EnumeratedBarrier.new(-4)+}+++testcase "wait() crashes when references are lost" {+ crash+ require "BarrierWait.*destroyed"+}++unittest test {+ scoped {+ ReadAt<BarrierWait> barriers <- EnumeratedBarrier.new(2)+ } in BarrierWait barrier <- barriers.readAt(0)+ \ barrier.wait()+}+++testcase "references lost during wait() causes crash" {+ crash+ require "BarrierWait.*waiting"+}++unittest test {+ scoped {+ ReadAt<BarrierWait> barriers <- EnumeratedBarrier.new(2)+ } in {+ Thread thread <- ProcessThread.from(WaitAndExit.create(barriers.readAt(0))).start()+ // Give the thread time to start.+ \ Realtime.sleepSeconds(0.1)+ }+}++concrete WaitAndExit {+ refines Routine++ @type create (BarrierWait) -> (WaitAndExit)+}++define WaitAndExit {+ @value BarrierWait barrier++ create (barrier) {+ return WaitAndExit{ barrier }+ }++ run () {+ \ barrier.wait()+ }+}+++testcase "wait() crashes when two threads use same BarrierWait" {+ crash+ require "BarrierWait.*in use"+}++unittest test {+ ReadAt<BarrierWait> barriers <- EnumeratedBarrier.new(2)+ Thread thread <- ProcessThread.from(WaitAndExit.create(barriers.readAt(0))).start()+ \ barriers.readAt(0).wait()+}++concrete WaitAndExit {+ refines Routine++ @type create (BarrierWait) -> (WaitAndExit)+}++define WaitAndExit {+ @value BarrierWait barrier++ create (barrier) {+ return WaitAndExit{ barrier }+ }++ run () {+ \ barrier.wait()+ }+}
+ lib/thread/condition.0rp view
@@ -0,0 +1,106 @@+/* -----------------------------------------------------------------------------+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]++// Blocks a thread until a condition is met.+//+// Notes:+// - Mutex logic is exposed so that it can be used to avoid race conditions with+// the thread signalling continuation. (For example, if blocking behavior is+// conditioned on the availability of input from another thread.)+@value interface ConditionWait {+ refines Mutex++ // Block the current thread.+ //+ // Notes:+ // - The current thread *must* lock() before wait() and unlock() after. The+ // program could deadlock or crash otherwise.+ //+ // Example:+ //+ // scoped {+ // MutexLock lock <- MutexLock.lock(threadWait)+ // } cleanup {+ // \ lock.freeResource()+ // } in \ threadWait.wait()+ //+ // // continue processing here+ wait () -> (#self)++ // Block the current thread for at most the specified amount of time.+ //+ // Args:+ // - Float: Timeout in seconds.+ //+ // Returns:+ // - Bool: Set to false iff the timeout was reached.+ //+ // Notes:+ // - The current thread *must* lock() before timedWait() and unlock() after.+ // The program could deadlock or crash otherwise.+ //+ // Example:+ //+ // scoped {+ // MutexLock lock <- MutexLock.lock(threadWait)+ // } cleanup {+ // \ lock.freeResource()+ // } in Bool success <- threadWait.timedWait(10.0)+ //+ // if (success) {+ // // continue processing here+ // } else {+ // // error handling+ // }+ timedWait (Float) -> (Bool)+}++// Resumes thread waiting for a condition.+//+// Example:+//+// ConditionWait cond <- // created elsewhere+//+// scoped {+// MutexLock lock <- MutexLock.lock(cond)+// } cleanup {+// \ lock.freeResource()+// } in {+// // prepare state for threads, e.g., read data from disk+// }+//+// // signal threads to continue+// \ cond.resumeAll()+@value interface ConditionResume {+ refines Mutex++ // Resume all of the threads waiting for the associated condition.+ resumeAll () -> (#self)++ // Resume one of the threads waiting for the associated condition.+ resumeOne () -> (#self)+}++// Provides a single resume mechanism for multiple waiting threads.+concrete ThreadCondition {+ refines ConditionWait+ refines ConditionResume++ // Create a new condition.+ @type new () -> (ThreadCondition)+}
+ lib/thread/condition.0rt view
@@ -0,0 +1,179 @@+/* -----------------------------------------------------------------------------+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 "ThreadCondition tests" {+ success+}++unittest resumeAll {+ Value value <- Value.create()+ ThreadCondition cond <- ThreadCondition.new()++ Thread thread1 <- ProcessThread.from(WaitAndUpdate.create(value,cond)).start()+ Thread thread2 <- ProcessThread.from(WaitAndUpdate.create(value,cond)).start()++ // Wait for both threads to increment Value once, to indicate readiness.+ while (true) {+ scoped {+ MutexLock lock <- MutexLock.lock(cond)+ } cleanup {+ \ lock.freeResource()+ } in if (value.get() >= 2) {+ break+ }+ }++ \ cond.resumeAll()+ \ thread1.join()+ \ thread2.join()++ \ Testing.checkEquals<?>(value.get(),4)+}++unittest resumeOne {+ Value value <- Value.create()+ ThreadCondition cond <- ThreadCondition.new()++ Thread thread1 <- ProcessThread.from(WaitAndUpdate.create(value,cond)).start()+ Thread thread2 <- ProcessThread.from(WaitAndUpdate.create(value,cond)).start()++ \ Realtime.sleepSeconds(0.01)++ // Wait for both threads to increment Value once, to indicate readiness.+ while (true) {+ scoped {+ MutexLock lock <- MutexLock.lock(cond)+ } cleanup {+ \ lock.freeResource()+ } in if (value.get() >= 2) {+ break+ }+ }++ \ cond.resumeOne()+ \ thread1.join()+ \ thread2.join()++ \ Testing.checkEquals<?>(value.get(),3)+}++unittest forceWaitTimeout {+ Value value <- Value.create()+ ThreadCondition cond <- ThreadCondition.new()++ Thread thread <- ProcessThread.from(WaitAndUpdate.create(value,cond)).start()++ \ Realtime.sleepSeconds(0.2)+ \ cond.resumeOne()+ \ thread.join()++ \ Testing.checkEquals<?>(value.get(),1)+}++unittest waitNoTimeout {+ ThreadCondition cond <- ThreadCondition.new()++ Thread thread <- ProcessThread.from(JustWait.create(cond)).start()++ \ Realtime.sleepSeconds(0.1)+ \ cond.resumeOne()+ \ thread.join()+ \ cond.lock().unlock()+}++concrete JustWait {+ refines Routine++ @type create (ConditionWait) -> (JustWait)+}++define JustWait {+ @value ConditionWait cond++ create (cond) {+ return JustWait{ cond }+ }++ run () {+ scoped {+ MutexLock lock <- MutexLock.lock(cond)+ } cleanup {+ \ lock.freeResource()+ } in \ cond.wait()+ }+}++concrete WaitAndUpdate {+ refines Routine++ @type create (Value,ConditionWait) -> (WaitAndUpdate)+}++define WaitAndUpdate {+ @value Value value+ @value ConditionWait cond++ create (value,cond) {+ return WaitAndUpdate{ value, cond }+ }++ run () {+ scoped {+ MutexLock lock <- MutexLock.lock(cond)+ // Increment once, to indicate readiness.+ \ value.increment()+ } cleanup {+ \ lock.freeResource()+ } in {+ // Mutex isn't unlocked until blocked here.+ if (cond.timedWait(0.1)) {+ \ value.increment()+ }+ }+ }+}+++testcase "wait() crashes if not locked first" {+ crash+ require "waiting for condition"+}++unittest test {+ \ ThreadCondition.new().wait()+}+++testcase "timedWait() crashes if not locked first" {+ crash+ require "waiting for condition"+}++unittest test {+ \ ThreadCondition.new().timedWait(0.1)+}+++testcase "timedWait() crashes with negative wait" {+ crash+ require "-0\.1"+}++unittest test {+ \ ThreadCondition.new().lock().timedWait(-0.1)+}
lib/thread/mutex.0rt view
@@ -101,38 +101,3 @@ } } }--concrete Value {- @type create () -> (Value)-- @value get () -> (Int)- @value increment () -> ()-- @value setInUse (Bool) -> ()- @value getInUse () -> (Bool)-}--define Value {- @value Int value- @value Bool inUse-- create () {- return Value{ 0, false }- }-- get () {- return value- }-- increment () {- value <- value+1- }-- setInUse (i) {- inUse <- i- }-- getInUse () {- return inUse- }-}
+ lib/thread/src/Extension_Enumerated.cpp view
@@ -0,0 +1,194 @@+/* -----------------------------------------------------------------------------+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]++#include <atomic>++#include <pthread.h>+#include <string.h>++#include "category-source.hpp"+#include "Streamlined_EnumeratedWait.hpp"+#include "Streamlined_EnumeratedBarrier.hpp"+#include "Category_BarrierWait.hpp"+#include "Category_EnumeratedBarrier.hpp"+#include "Category_Int.hpp"+#include "Category_Stack.hpp"+#include "Category_Vector.hpp"++namespace {++class Barrier {+ public:+ Barrier(int count) : index_usage(new std::atomic_int[count]) {+ alive.store(true);+ wait_count.store(0);+ for (int i = 0; i < count; ++i) {+ index_usage[i].store(0);+ }+ int error = pthread_barrier_init(&barrier, NULL, count);+ if (error != 0) {+ FAIL() << "Error creating barrier: " << strerror(error) << " (error " << error << ")";+ }+ }++ void Wait(int index) {+ TRACE_CREATION+ Enter(index);+ int error = pthread_barrier_wait(&barrier);+ if (error != 0 && error != PTHREAD_BARRIER_SERIAL_THREAD) {+ FAIL() << "Error waiting for barrier: " << strerror(error) << " (error " << error << ")";+ }+ Exit(index);+ }++ void Kill(int index) {+ TRACE_CREATION+ if (alive.exchange(false) && wait_count.load() > 0) {+ FAIL() << "BarrierWait at index " << index << " destroyed while one or more threads were waiting";+ }+ }++ ~Barrier() {+ TRACE_CREATION+ int error = pthread_barrier_destroy(&barrier);+ if (error != 0) {+ FAIL() << "Error cleaning up barrier: " << strerror(error) << " (error " << error << ")";+ }+ }++private:+ void Enter(int index) {+ ++wait_count;+ if (!alive.load()) {+ --wait_count;+ FAIL() << "One or more BarrierWait have been destroyed";+ }+ if (++index_usage[index] > 1) {+ Exit(index);+ FAIL() << "BarrierWait at index " << index << " is already in use";+ }+ }++ void Exit(int index) {+ --wait_count;+ --index_usage[index];+ }++ std::atomic_bool alive;+ std::atomic_int wait_count;+ const R<std::atomic_int[]> index_usage;+ pthread_barrier_t barrier;+ CAPTURE_CREATION("EnumeratedBarrier")+};++} // namespace++#ifdef ZEOLITE_PRIVATE_NAMESPACE+namespace ZEOLITE_PRIVATE_NAMESPACE {+#endif // ZEOLITE_PRIVATE_NAMESPACE++S<TypeValue> CreateValue_EnumeratedWait(+ S<Type_EnumeratedWait> parent, S<Barrier> b, int i);++struct ExtCategory_EnumeratedWait : public Category_EnumeratedWait {+};++struct ExtType_EnumeratedWait : public Type_EnumeratedWait {+ inline ExtType_EnumeratedWait(Category_EnumeratedWait& p, Params<0>::Type params) : Type_EnumeratedWait(p, params) {}+};++struct ExtValue_EnumeratedWait : public Value_EnumeratedWait {+ inline ExtValue_EnumeratedWait(S<Type_EnumeratedWait> p, S<Barrier> b, int i)+ : Value_EnumeratedWait(p), barrier(b), index(i) {}++ ReturnTuple Call_wait(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("EnumeratedWait.wait")+ barrier->Wait(index);+ return ReturnTuple(Var_self);+ }++ ~ExtValue_EnumeratedWait() {+ barrier->Kill(index);+ }++ const S<Barrier> barrier;+ int index;+};++Category_EnumeratedWait& CreateCategory_EnumeratedWait() {+ static auto& category = *new ExtCategory_EnumeratedWait();+ return category;+}+S<Type_EnumeratedWait> CreateType_EnumeratedWait(Params<0>::Type params) {+ static const auto cached = S_get(new ExtType_EnumeratedWait(CreateCategory_EnumeratedWait(), Params<0>::Type()));+ return cached;+}+S<TypeValue> CreateValue_EnumeratedWait(+ S<Type_EnumeratedWait> parent, S<Barrier> b, int i) {+ return S_get(new ExtValue_EnumeratedWait(parent, b, i));+}++#ifdef ZEOLITE_PRIVATE_NAMESPACE+} // namespace ZEOLITE_PRIVATE_NAMESPACE+using namespace ZEOLITE_PRIVATE_NAMESPACE;+#endif // ZEOLITE_PRIVATE_NAMESPACE+++#ifdef ZEOLITE_PUBLIC_NAMESPACE+namespace ZEOLITE_PUBLIC_NAMESPACE {+#endif // ZEOLITE_PUBLIC_NAMESPACE++struct ExtCategory_EnumeratedBarrier : public Category_EnumeratedBarrier {+};++struct ExtType_EnumeratedBarrier : public Type_EnumeratedBarrier {+ inline ExtType_EnumeratedBarrier(Category_EnumeratedBarrier& p, Params<0>::Type params) : Type_EnumeratedBarrier(p, params) {}++ ReturnTuple Call_new(const S<TypeInstance>& Param_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("EnumeratedBarrier.new")+ const PrimInt Var_arg1 = (args.At(0))->AsInt();+ if (Var_arg1 < 0) {+ FAIL() << "Invalid barrier thread count " << Var_arg1;+ }+ S<TypeValue> vector = GetCategory_Vector().Call(+ Function_Vector_create,+ ParamTuple(GetType_EnumeratedWait(Params<0>::Type())),+ ArgTuple()).Only();+ S<Barrier> barrier(Var_arg1? new Barrier(Var_arg1) : nullptr);+ for (int i = 0; i < Var_arg1; ++i) {+ S<TypeValue> wait = CreateValue_EnumeratedWait(+ CreateType_EnumeratedWait(Params<0>::Type()), barrier, i);+ TypeValue::Call(vector, Function_Stack_push, ParamTuple(), ArgTuple(wait));+ }+ return ReturnTuple(vector);+ }+};++Category_EnumeratedBarrier& CreateCategory_EnumeratedBarrier() {+ static auto& category = *new ExtCategory_EnumeratedBarrier();+ return category;+}+S<Type_EnumeratedBarrier> CreateType_EnumeratedBarrier(Params<0>::Type params) {+ static const auto cached = S_get(new ExtType_EnumeratedBarrier(CreateCategory_EnumeratedBarrier(), Params<0>::Type()));+ return cached;+}++#ifdef ZEOLITE_PUBLIC_NAMESPACE+} // namespace ZEOLITE_PUBLIC_NAMESPACE+using namespace ZEOLITE_PUBLIC_NAMESPACE;+#endif // ZEOLITE_PUBLIC_NAMESPACE
lib/thread/src/Extension_MutexLock.cpp view
@@ -28,7 +28,7 @@ namespace ZEOLITE_PUBLIC_NAMESPACE { #endif // ZEOLITE_PUBLIC_NAMESPACE -S<TypeValue> CreateValue_MutexLock(S<Type_MutexLock> parent, const ParamTuple& params, const ValueTuple& args);+S<TypeValue> CreateValue_MutexLock(S<Type_MutexLock> parent, const ValueTuple& args); struct ExtCategory_MutexLock : public Category_MutexLock { };@@ -38,18 +38,18 @@ ReturnTuple Call_lock(const S<TypeInstance>& Param_self, const ParamTuple& params, const ValueTuple& args) final { TRACE_FUNCTION("MutexLock.lock")- return ReturnTuple(CreateValue_MutexLock(CreateType_MutexLock(Params<0>::Type()), ParamTuple(), args));+ return ReturnTuple(CreateValue_MutexLock(CreateType_MutexLock(Params<0>::Type()), args)); } }; struct ExtValue_MutexLock : public Value_MutexLock {- inline ExtValue_MutexLock(S<Type_MutexLock> p, const ParamTuple& params, const ValueTuple& args)- : Value_MutexLock(p, params), mutex(args.Only()) {+ inline ExtValue_MutexLock(S<Type_MutexLock> p, const ValueTuple& args)+ : Value_MutexLock(p), mutex(args.Only()) { TypeValue::Call(mutex, Function_Mutex_lock, ParamTuple(), ArgTuple()); } ReturnTuple Call_freeResource(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final {- TRACE_FUNCTION("PersistentResource.freeResource")+ TRACE_FUNCTION("MutexLock.freeResource") TRACE_CREATION if (!mutex) { FAIL() << "MutexLock freed multiple times";@@ -70,7 +70,7 @@ } S<TypeValue> mutex;- CAPTURE_CREATION+ CAPTURE_CREATION("MutexLock") }; Category_MutexLock& CreateCategory_MutexLock() {@@ -81,8 +81,8 @@ static const auto cached = S_get(new ExtType_MutexLock(CreateCategory_MutexLock(), Params<0>::Type())); return cached; }-S<TypeValue> CreateValue_MutexLock(S<Type_MutexLock> parent, const ParamTuple& params, const ValueTuple& args) {- return S_get(new ExtValue_MutexLock(parent, params, args));+S<TypeValue> CreateValue_MutexLock(S<Type_MutexLock> parent, const ValueTuple& args) {+ return S_get(new ExtValue_MutexLock(parent, args)); } #ifdef ZEOLITE_PUBLIC_NAMESPACE
lib/thread/src/Extension_ProcessThread.cpp view
@@ -31,7 +31,7 @@ namespace ZEOLITE_PUBLIC_NAMESPACE { #endif // ZEOLITE_PUBLIC_NAMESPACE -S<TypeValue> CreateValue_ProcessThread(S<Type_ProcessThread> parent, const ParamTuple& params, const ValueTuple& args);+S<TypeValue> CreateValue_ProcessThread(S<Type_ProcessThread> parent, const ValueTuple& args); struct ExtCategory_ProcessThread : public Category_ProcessThread { };@@ -41,16 +41,16 @@ ReturnTuple Call_from(const S<TypeInstance>& Param_self, const ParamTuple& params, const ValueTuple& args) final { TRACE_FUNCTION("ProcessThread.from")- return ReturnTuple(CreateValue_ProcessThread(CreateType_ProcessThread(Params<0>::Type()), params, args));+ return ReturnTuple(CreateValue_ProcessThread(CreateType_ProcessThread(Params<0>::Type()), args)); } }; struct ExtValue_ProcessThread : public Value_ProcessThread {- inline ExtValue_ProcessThread(S<Type_ProcessThread> p, const ParamTuple& params, const ValueTuple& args)- : Value_ProcessThread(p, params), routine(args.Only()) {}+ inline ExtValue_ProcessThread(S<Type_ProcessThread> p, const ValueTuple& args)+ : Value_ProcessThread(p), routine(args.Only()) {} ReturnTuple Call_detach(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final {- TRACE_FUNCTION("Thread.detach")+ TRACE_FUNCTION("ProcessThread.detach") S<std::thread> temp = thread; thread = nullptr; if (!isJoinable(temp.get())) {@@ -62,12 +62,12 @@ } ReturnTuple Call_isRunning(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final {- TRACE_FUNCTION("Thread.isRunning")+ TRACE_FUNCTION("ProcessThread.isRunning") return ReturnTuple(Box_Bool(isJoinable(thread.get()))); } ReturnTuple Call_join(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final {- TRACE_FUNCTION("Thread.join")+ TRACE_FUNCTION("ProcessThread.join") S<std::thread> temp = thread; thread = nullptr; if (!isJoinable(temp.get())) {@@ -79,7 +79,7 @@ } ReturnTuple Call_start(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final {- TRACE_FUNCTION("Process.start")+ TRACE_FUNCTION("ProcessThread.start") if (isJoinable(thread.get())) { FAIL() << "thread is already running"; } else {@@ -87,10 +87,10 @@ // it's still running. This allows the caller to hold a weak reference to // the thread. thread.reset(new std::thread(- [this,Var_self] {+ capture_thread::ThreadCrosser::WrapCall([this,Var_self] { TRACE_CREATION TypeValue::Call(routine, Function_Routine_run, ParamTuple(), ArgTuple());- }));+ }))); } return ReturnTuple(Var_self); }@@ -109,7 +109,7 @@ const S<TypeValue> routine; S<std::thread> thread;- CAPTURE_CREATION+ CAPTURE_CREATION("ProcessThread") }; Category_ProcessThread& CreateCategory_ProcessThread() {@@ -120,8 +120,8 @@ static const auto cached = S_get(new ExtType_ProcessThread(CreateCategory_ProcessThread(), Params<0>::Type())); return cached; }-S<TypeValue> CreateValue_ProcessThread(S<Type_ProcessThread> parent, const ParamTuple& params, const ValueTuple& args) {- return S_get(new ExtValue_ProcessThread(parent, params, args));+S<TypeValue> CreateValue_ProcessThread(S<Type_ProcessThread> parent, const ValueTuple& args) {+ return S_get(new ExtValue_ProcessThread(parent, args)); } #ifdef ZEOLITE_PUBLIC_NAMESPACE
+ lib/thread/src/Extension_Realtime.cpp view
@@ -0,0 +1,69 @@+/* -----------------------------------------------------------------------------+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]++#include <errno.h>+#include <math.h>+#include <string.h>+#include <time.h>++#include "category-source.hpp"+#include "Streamlined_Realtime.hpp"+#include "Category_Float.hpp"+#include "Category_Realtime.hpp"++#ifdef ZEOLITE_PUBLIC_NAMESPACE+namespace ZEOLITE_PUBLIC_NAMESPACE {+#endif // ZEOLITE_PUBLIC_NAMESPACE++struct ExtCategory_Realtime : public Category_Realtime {+};++struct ExtType_Realtime : public Type_Realtime {+ inline ExtType_Realtime(Category_Realtime& p, Params<0>::Type params) : Type_Realtime(p, params) {}+ ReturnTuple Call_sleepSeconds(const S<TypeInstance>& Param_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("Realtime.sleepSeconds")+ const PrimFloat Var_arg1 = (args.At(0))->AsFloat();+ if (Var_arg1 < 0) {+ FAIL() << "Bad wait time " << Var_arg1;+ }+ struct timespec timeout{ (int) trunc(Var_arg1), (int) (1000000000.0 * (Var_arg1-trunc(Var_arg1))) };+ struct timespec remainder;+ while (nanosleep(&timeout, &remainder) != 0) {+ if (errno == EINTR) {+ timeout = remainder;+ } else {+ FAIL() << "Error sleeping: " << strerror(errno) << " (error " << errno << ")";+ }+ }+ return ReturnTuple();+ }+};++Category_Realtime& CreateCategory_Realtime() {+ static auto& category = *new ExtCategory_Realtime();+ return category;+}+S<Type_Realtime> CreateType_Realtime(Params<0>::Type params) {+ static const auto cached = S_get(new ExtType_Realtime(CreateCategory_Realtime(), Params<0>::Type()));+ return cached;+}++#ifdef ZEOLITE_PUBLIC_NAMESPACE+} // namespace ZEOLITE_PUBLIC_NAMESPACE+using namespace ZEOLITE_PUBLIC_NAMESPACE;+#endif // ZEOLITE_PUBLIC_NAMESPACE
lib/thread/src/Extension_SimpleMutex.cpp view
@@ -42,16 +42,16 @@ }; struct ExtValue_SimpleMutex : public Value_SimpleMutex {- inline ExtValue_SimpleMutex(S<Type_SimpleMutex> p, const ParamTuple& params) : Value_SimpleMutex(p, params) {}+ inline ExtValue_SimpleMutex(S<Type_SimpleMutex> p) : Value_SimpleMutex(p) {} ReturnTuple Call_lock(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final {- TRACE_FUNCTION("Mutex.lock")+ TRACE_FUNCTION("SimpleMutex.lock") mutex.lock(); return ReturnTuple(Var_self); } ReturnTuple Call_unlock(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final {- TRACE_FUNCTION("Mutex.unlock")+ TRACE_FUNCTION("SimpleMutex.unlock") mutex.unlock(); return ReturnTuple(Var_self); }@@ -68,7 +68,7 @@ return cached; } S<TypeValue> CreateValue_SimpleMutex(S<Type_SimpleMutex> parent) {- return S_get(new ExtValue_SimpleMutex(parent, ParamTuple()));+ return S_get(new ExtValue_SimpleMutex(parent)); } #ifdef ZEOLITE_PUBLIC_NAMESPACE
+ lib/thread/src/Extension_ThreadCondition.cpp view
@@ -0,0 +1,164 @@+/* -----------------------------------------------------------------------------+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]++#include <math.h>+#include <pthread.h>+#include <string.h>+#include <time.h>+#include <sys/time.h>++#include "category-source.hpp"+#include "Streamlined_ThreadCondition.hpp"+#include "Category_ThreadCondition.hpp"+#include "Category_ConditionResume.hpp"+#include "Category_ConditionWait.hpp"++#ifdef ZEOLITE_PUBLIC_NAMESPACE+namespace ZEOLITE_PUBLIC_NAMESPACE {+#endif // ZEOLITE_PUBLIC_NAMESPACE++S<TypeValue> CreateValue_ThreadCondition(S<Type_ThreadCondition> parent);++struct ExtCategory_ThreadCondition : public Category_ThreadCondition {+};++struct ExtType_ThreadCondition : public Type_ThreadCondition {+ inline ExtType_ThreadCondition(Category_ThreadCondition& p, Params<0>::Type params) : Type_ThreadCondition(p, params) {}++ ReturnTuple Call_new(const S<TypeInstance>& Param_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("ThreadCondition.new")+ return ReturnTuple(CreateValue_ThreadCondition(CreateType_ThreadCondition(Params<0>::Type())));+ }+};++struct ExtValue_ThreadCondition : public Value_ThreadCondition {+ inline ExtValue_ThreadCondition(S<Type_ThreadCondition> p) : Value_ThreadCondition(p) {+ pthread_mutexattr_t mutex_attr;+ pthread_mutexattr_init(&mutex_attr);+ // NOTE: Error checking is required to catch attempted waits without first+ // locking the mutex.+ pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK);+ pthread_mutex_init(&mutex, &mutex_attr);+ }++ ReturnTuple Call_lock(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("ThreadCondition.lock")+ int error = 0;+ if ((error = pthread_mutex_lock(&mutex)) != 0) {+ FailError("Error locking mutex", error);+ }+ return ReturnTuple(Var_self);+ }++ ReturnTuple Call_resumeAll(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("ThreadCondition.resumeAll")+ int error = 0;+ if ((error = pthread_cond_broadcast(&cond)) != 0) {+ FailError("Error resuming threads", error);+ }+ return ReturnTuple(Var_self);+ }++ ReturnTuple Call_resumeOne(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("ThreadCondition.resumeOne")+ int error = 0;+ if ((error = pthread_cond_signal(&cond)) != 0) {+ FailError("Error resuming thread", error);+ }+ return ReturnTuple(Var_self);+ }++ ReturnTuple Call_timedWait(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("ThreadCondition.timedWait")+ int error = 0;+ const PrimFloat Var_arg1 = (args.At(0))->AsFloat();+ if (Var_arg1 < 0) {+ FAIL() << "Bad wait time " << Var_arg1;+ }+ struct timeval now;+ if (gettimeofday(&now, NULL) != 0) {+ FailError("Error getting current time", errno);+ }+ const PrimFloat abs_time = Var_arg1 + (PrimFloat) now.tv_sec + ((PrimFloat) now.tv_usec / 1000000.0);+ struct timespec timeout{ (int) trunc(abs_time), (int) (1000000000.0 * (abs_time-trunc(abs_time))) };+ error = pthread_cond_timedwait(&cond, &mutex, &timeout);+ if (error == ETIMEDOUT) {+ return ReturnTuple(Box_Bool(false));+ }+ if (error != 0) {+ FailError("Error waiting for condition", error);+ }+ return ReturnTuple(Box_Bool(true));+ }++ ReturnTuple Call_unlock(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("ThreadCondition.unlock")+ int error = 0;+ if ((error = pthread_mutex_unlock(&mutex)) != 0) {+ FailError("Error unlocking mutex", error);+ }+ return ReturnTuple(Var_self);+ }++ ReturnTuple Call_wait(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("ThreadCondition.wait")+ int error = 0;+ if ((error = pthread_cond_wait(&cond, &mutex)) != 0) {+ FailError("Error waiting for condition", error);+ }+ return ReturnTuple(Var_self);+ }++ void FailError(const std::string& context, int error) const {+ TRACE_CREATION+ FAIL() << context << ": " << strerror(error) << " (error " << error << ")";+ }++ ~ExtValue_ThreadCondition() {+ int error = 0;+ // Nothing should be waiting on the condition, because then there would+ // still be a reference to this object.+ if ((error = pthread_cond_destroy(&cond)) != 0) {+ FailError("Error cleaning up condition", error);+ }+ if ((error = pthread_mutex_destroy(&mutex)) != 0) {+ FailError("Error cleaning up mutex", error);+ }+ }++ pthread_cond_t cond = PTHREAD_COND_INITIALIZER;+ pthread_mutex_t mutex;+ CAPTURE_CREATION("ThreadCondition")+};++Category_ThreadCondition& CreateCategory_ThreadCondition() {+ static auto& category = *new ExtCategory_ThreadCondition();+ return category;+}+S<Type_ThreadCondition> CreateType_ThreadCondition(Params<0>::Type params) {+ static const auto cached = S_get(new ExtType_ThreadCondition(CreateCategory_ThreadCondition(), Params<0>::Type()));+ return cached;+}+S<TypeValue> CreateValue_ThreadCondition(S<Type_ThreadCondition> parent) {+ return S_get(new ExtValue_ThreadCondition(parent));+}++#ifdef ZEOLITE_PUBLIC_NAMESPACE+} // namespace ZEOLITE_PUBLIC_NAMESPACE+using namespace ZEOLITE_PUBLIC_NAMESPACE;+#endif // ZEOLITE_PUBLIC_NAMESPACE
lib/thread/testing.0rp view
@@ -24,3 +24,19 @@ @type create () -> (NoOpRoutine) }++concrete InfiniteRoutine {+ refines Routine++ @type create () -> (InfiniteRoutine)+}++concrete Value {+ @type create () -> (Value)++ @value get () -> (Int)+ @value increment () -> ()++ @value setInUse (Bool) -> ()+ @value getInUse () -> (Bool)+}
lib/thread/testing.0rx view
@@ -25,3 +25,38 @@ run () {} }++define InfiniteRoutine {+ create () {+ return InfiniteRoutine{ }+ }++ run () {+ while (true) {}+ }+}++define Value {+ @value Int value+ @value Bool inUse++ create () {+ return Value{ 0, false }+ }++ get () {+ return value+ }++ increment () {+ value <- value+1+ }++ setInUse (i) {+ inUse <- i+ }++ getInUse () {+ return inUse+ }+}
lib/thread/thread.0rt view
@@ -21,7 +21,7 @@ } unittest test {- Counter counter <- Counter.create(10000)+ CountLoop counter <- CountLoop.create(10000) \ Testing.checkEquals<?>(counter.get(),0) \ counter.start() \ Testing.checkEquals<?>(counter.get(),10000)@@ -29,14 +29,14 @@ \ Testing.checkEquals<?>(counter.get(),20000) } -concrete Counter {+concrete CountLoop { refines Process - @type create (Int) -> (Counter)+ @type create (Int) -> (CountLoop) @value get () -> (Int) } -define Counter {+define CountLoop { refines Routine @value Int current@@ -44,7 +44,7 @@ @value weak Thread thread create (c) {- return Counter{ 0, c, empty }+ return CountLoop{ 0, c, empty } } start () {@@ -78,6 +78,32 @@ } +testcase "Argv available in Thread" {+ success+ args "arg1"+}++unittest test {+ \ ProcessThread.from(CheckArgv.create()).start().join()+}++concrete CheckArgv {+ refines Routine++ @type create () -> (CheckArgv)+}++define CheckArgv {+ create () {+ return CheckArgv{ }+ }++ run () {+ \ Testing.checkEquals<?>(Argv.global().readAt(1),"arg1")+ }+}++ testcase "join() crashes if Thread not started yet" { crash require "thread.*started"@@ -88,13 +114,22 @@ } +testcase "join() once" {+ success+}++unittest test {+ \ ProcessThread.from(NoOpRoutine.create()).start().join()+}++ testcase "join() twice crashes" { crash require "thread.*started" } unittest test {- \ ProcessThread.from(NoOpRoutine.create()).join().join()+ \ ProcessThread.from(NoOpRoutine.create()).start().join().join() } @@ -104,17 +139,26 @@ } unittest test {- \ ProcessThread.from(NoOpRoutine.create()).detach()+ \ ProcessThread.from(InfiniteRoutine.create()).detach() } +testcase "detach() once" {+ success+}++unittest test {+ \ ProcessThread.from(InfiniteRoutine.create()).start().detach()+}++ testcase "detach() twice crashes" { crash require "thread.*started" } unittest test {- \ ProcessThread.from(NoOpRoutine.create()).detach().detach()+ \ ProcessThread.from(InfiniteRoutine.create()).start().detach().detach() }
+ lib/thread/time.0rp view
@@ -0,0 +1,23 @@+/* -----------------------------------------------------------------------------+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]++// Functions for realtime computation.+concrete Realtime {+ // Sleep for the given number of seconds.+ @type sleepSeconds (Float) -> ()+}
+ lib/thread/time.0rt view
@@ -0,0 +1,35 @@+/* -----------------------------------------------------------------------------+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 "negative sleepSeconds() crashes" {+ crash+ require "-0\.1"+}++unittest test {+ \ Realtime.sleepSeconds(-0.1)+}+++testcase "zero sleepSeconds() is allowed" {+ success+}++unittest test {+ \ Realtime.sleepSeconds(0.0)+}
+ lib/util/counters.0rp view
@@ -0,0 +1,33 @@+/* -----------------------------------------------------------------------------+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]++// Creates Order<Int> counters, for use with traverse.+concrete Counter {+ // Create a sequence of indices for a Container of the given size.+ @type zeroIndexed (Int) -> (optional Order<Int>)+ // Create an unbounded Int sequence.+ @type unlimited () -> (optional Order<Int>)+}++// Creates an Order<#x> that repeats a single value, for use with traverse.+concrete Repeat<#x> {+ // Repeat the value the specified number of times.+ @category times<#y> (#y,Int) -> (optional Order<#y>)+ // Repeat the value an unlimited number of times.+ @category unlimited<#y> (#y) -> (optional Order<#y>)+}
+ lib/util/counters.0rt view
@@ -0,0 +1,69 @@+/* -----------------------------------------------------------------------------+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 "counter tests" {+ success+}++unittest zeroIndexed {+ Int index <- 0++ traverse (Counter.zeroIndexed(10) -> Int i) {+ \ Testing.checkEquals<?>(i,index)+ index <- index+1+ }++ \ Testing.checkEquals<?>(index,10)+}++unittest unlimitedCount {+ Int index <- 0++ traverse (Counter.unlimited() -> Int i) {+ \ Testing.checkEquals<?>(i,index)+ if ((index <- index+1) >= 10) {+ break+ }+ }++ \ Testing.checkEquals<?>(index,10)+}++unittest times {+ Int index <- 0++ traverse ("message" `Repeat:times<?>` 10 -> String m) {+ \ Testing.checkEquals<?>(m,"message")+ index <- index+1+ }++ \ Testing.checkEquals<?>(index,10)+}++unittest unlimitedValue {+ Int index <- 0++ traverse (Repeat:unlimited<?>("message") -> String m) {+ \ Testing.checkEquals<?>(m,"message")+ if ((index <- index+1) >= 10) {+ break+ }+ }++ \ Testing.checkEquals<?>(index,10)+}
+ lib/util/counters.0rx view
@@ -0,0 +1,86 @@+/* -----------------------------------------------------------------------------+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]++define Counter {+ $ReadOnly[max]$++ refines Order<Int>++ @value Int current+ @value Int max++ zeroIndexed (max) {+ if (max <= 0) {+ return empty+ } else {+ return Counter{ 0, max }+ }+ }++ unlimited () {+ return Counter{ 0, -1 }+ }++ next () {+ if (max < 0 || current+1 < max) {+ current <- current+1+ return self+ } else {+ return empty+ }+ }++ get () {+ return current+ }+}++define Repeat {+ $ReadOnly[max,value]$++ refines Order<#x>++ @value #x value+ @value Int current+ @value Int max++ times (value,max) {+ if (max <= 0) {+ return empty+ } else {+ return Repeat<#y>{ value, 0, max }+ }+ }++ unlimited (value) {+ return Repeat<#y>{ value, 0, -1 }+ }++ next () {+ if (max < 0 || current+1 < max) {+ current <- current+1+ return self+ } else {+ return empty+ }+ }++ get () {+ return value+ }+}
lib/util/extra.0rp view
@@ -60,7 +60,6 @@ // Return the global set of arguments for the program. // // Notes:- // - This is empty outside of the main program thread. // - When used in unit tests, arg 0 is "testcase" and the remaining args are // set from args in the testcase. (See extra.0rt.) @type global () -> ([ReadAt<String>&SubSequence])
lib/util/src/Extension_Argv.cpp view
@@ -22,7 +22,7 @@ namespace ZEOLITE_PUBLIC_NAMESPACE { #endif // ZEOLITE_PUBLIC_NAMESPACE -S<TypeValue> CreateValue_Argv(S<Type_Argv> parent, const ParamTuple& params, int st, int sz);+S<TypeValue> CreateValue_Argv(S<Type_Argv> parent, int st, int sz); namespace { extern const S<TypeValue>& Var_global;@@ -41,8 +41,8 @@ }; struct ExtValue_Argv : public Value_Argv {- inline ExtValue_Argv(S<Type_Argv> p, const ParamTuple& params, int st, int sz)- : Value_Argv(p, params), start(st), size(sz) {}+ inline ExtValue_Argv(S<Type_Argv> p, int st, int sz)+ : Value_Argv(p), start(st), size(sz) {} ReturnTuple Call_readAt(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final { TRACE_FUNCTION("Argv.readAt")@@ -65,7 +65,7 @@ if (Var_arg2 < 0 || Var_arg1 + Var_arg2 > GetSize()) { FAIL() << "size " << Var_arg2 << " is invalid"; }- return ReturnTuple(S<TypeValue>(new ExtValue_Argv(parent, ParamTuple(), start + Var_arg1, Var_arg2)));+ return ReturnTuple(S<TypeValue>(new ExtValue_Argv(parent, start + Var_arg1, Var_arg2))); } inline int GetSize() const { return size < 0 ? Argv::ArgCount() : size; }@@ -75,7 +75,7 @@ }; namespace {-const S<TypeValue>& Var_global = *new S<TypeValue>(new ExtValue_Argv(CreateType_Argv(Params<0>::Type()), ParamTuple(), 0, -1));+const S<TypeValue>& Var_global = *new S<TypeValue>(new ExtValue_Argv(CreateType_Argv(Params<0>::Type()), 0, -1)); } // namespace Category_Argv& CreateCategory_Argv() {@@ -86,8 +86,8 @@ static const auto cached = S_get(new ExtType_Argv(CreateCategory_Argv(), Params<0>::Type())); return cached; }-S<TypeValue> CreateValue_Argv(S<Type_Argv> parent, const ParamTuple& params, int st, int sz) {- return S_get(new ExtValue_Argv(parent, params, st, sz));+S<TypeValue> CreateValue_Argv(S<Type_Argv> parent, int st, int sz) {+ return S_get(new ExtValue_Argv(parent, st, sz)); } #ifdef ZEOLITE_PUBLIC_NAMESPACE
lib/util/src/Extension_SimpleInput.cpp view
@@ -42,7 +42,7 @@ }; struct ExtValue_SimpleInput : public Value_SimpleInput {- inline ExtValue_SimpleInput(S<Type_SimpleInput> p, const ParamTuple& params, const ValueTuple& args) : Value_SimpleInput(p, params) {}+ inline ExtValue_SimpleInput(S<Type_SimpleInput> p, const ValueTuple& args) : Value_SimpleInput(p) {} ReturnTuple Call_pastEnd(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final { TRACE_FUNCTION("SimpleInput.pastEnd")@@ -72,7 +72,7 @@ }; namespace {-const S<TypeValue>& Var_stdin = *new S<TypeValue>(new ExtValue_SimpleInput(CreateType_SimpleInput(Params<0>::Type()), ParamTuple(), ArgTuple()));+const S<TypeValue>& Var_stdin = *new S<TypeValue>(new ExtValue_SimpleInput(CreateType_SimpleInput(Params<0>::Type()), ArgTuple())); } // namespace Category_SimpleInput& CreateCategory_SimpleInput() {
lib/util/src/Extension_SimpleOutput.cpp view
@@ -63,8 +63,8 @@ } // namespace struct ExtValue_SimpleOutput : public Value_SimpleOutput {- inline ExtValue_SimpleOutput(S<Type_SimpleOutput> p, const ParamTuple& params, S<Writer> w)- : Value_SimpleOutput(p, params), writer(w) {}+ inline ExtValue_SimpleOutput(S<Type_SimpleOutput> p, S<Writer> w)+ : Value_SimpleOutput(p), writer(w) {} ReturnTuple Call_flush(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final { TRACE_FUNCTION("SimpleOutput.flush")@@ -115,9 +115,9 @@ std::ostringstream output; }; -const S<TypeValue>& Var_stdout = *new S<TypeValue>(new ExtValue_SimpleOutput(CreateType_SimpleOutput(Params<0>::Type()), ParamTuple(), S_get(new StreamWriter(std::cout))));-const S<TypeValue>& Var_stderr = *new S<TypeValue>(new ExtValue_SimpleOutput(CreateType_SimpleOutput(Params<0>::Type()), ParamTuple(), S_get(new StreamWriter(std::cerr))));-const S<TypeValue>& Var_error = *new S<TypeValue>(new ExtValue_SimpleOutput(CreateType_SimpleOutput(Params<0>::Type()), ParamTuple(), S_get(new ErrorWriter())));+const S<TypeValue>& Var_stdout = *new S<TypeValue>(new ExtValue_SimpleOutput(CreateType_SimpleOutput(Params<0>::Type()), S_get(new StreamWriter(std::cout))));+const S<TypeValue>& Var_stderr = *new S<TypeValue>(new ExtValue_SimpleOutput(CreateType_SimpleOutput(Params<0>::Type()), S_get(new StreamWriter(std::cerr))));+const S<TypeValue>& Var_error = *new S<TypeValue>(new ExtValue_SimpleOutput(CreateType_SimpleOutput(Params<0>::Type()), S_get(new ErrorWriter()))); } // namespace
src/Cli/CompileOptions.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2020 Kevin P. Barry+Copyright 2020-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.@@ -33,6 +33,7 @@ isCompileFast, isCompileIncremental, isCompileRecompile,+ isCompileUnspecified, isCreateTemplates, isExecuteTests, maybeDisableHelp,@@ -110,7 +111,8 @@ cfSource :: FilePath } | ExecuteTests {- etInclude :: [FilePath]+ etInclude :: [FilePath],+ etCallLog :: Maybe FilePath } | CompileIncremental { ciLinkFlags :: [String]@@ -139,12 +141,16 @@ isCompileRecompile _ = False isExecuteTests :: CompileMode -> Bool-isExecuteTests (ExecuteTests _) = True-isExecuteTests _ = False+isExecuteTests (ExecuteTests _ _) = True+isExecuteTests _ = False isCreateTemplates :: CompileMode -> Bool isCreateTemplates CreateTemplates = True isCreateTemplates _ = False++isCompileUnspecified :: CompileMode -> Bool+isCompileUnspecified CompileUnspecified = True+isCompileUnspecified _ = False maybeDisableHelp :: HelpMode -> HelpMode maybeDisableHelp HelpUnspecified = HelpNotNeeded
src/Cli/Compiler.hs view
@@ -281,8 +281,7 @@ mapCompilerM_ writeTemplate ts where generate testing tm n = do (_,t) <- getConcreteCategory tm ([],n)- let ctx = FileContext testing tm Set.empty Map.empty- generateStreamlinedTemplate ctx t+ generateStreamlinedTemplate testing tm t writeTemplate (CxxOutput _ n _ _ _ content) = do let n' = p </> d </> n exists <- errorFromIO $ doesFileExist n'@@ -292,15 +291,16 @@ errorFromIO $ hPutStrLn stderr $ "Writing file " ++ n errorFromIO $ writeFile n' $ concat $ map (++ "\n") content -runModuleTests :: (PathIOHandler r, CompilerBackend b) => r -> b -> FilePath ->- [FilePath] -> LoadedTests -> TrackedErrorsIO [((Int,Int),TrackedErrors ())]-runModuleTests resolver backend base tp (LoadedTests p d m em deps1 deps2) = do+runModuleTests :: (PathIOHandler r, CompilerBackend b) =>+ r -> b -> FilePath -> FilePath -> [FilePath] -> LoadedTests ->+ TrackedErrorsIO [((Int,Int),TrackedErrors ())]+runModuleTests resolver backend cl base tp (LoadedTests p d m em deps1 deps2) = do let paths = base:(cmPublicSubdirs m ++ cmPrivateSubdirs m ++ getIncludePathsForDeps deps1) mapCompilerM_ showSkipped $ filter (not . isTestAllowed) $ cmTestFiles m ts' <- zipWithContents resolver p $ map (d </>) $ filter isTestAllowed $ cmTestFiles m path <- errorFromIO $ canonicalizePath (p </> d) cm <- fmap (createLanguageModule [] [] em) $ loadModuleGlobals resolver path (NoNamespace,NoNamespace) [] (Just m) deps1 []- mapCompilerM (runSingleTest backend cm path paths (m:deps2)) ts' where+ mapCompilerM (runSingleTest backend cl cm path paths (m:deps2)) ts' where allowTests = Set.fromList tp isTestAllowed t = if null allowTests then True else t `Set.member` allowTests showSkipped f = compilerWarningM $ "Skipping tests in " ++ f ++ " due to explicit test filter."
src/Cli/ParseCompileOptions.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2020 Kevin P. Barry+Copyright 2020-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.@@ -35,12 +35,12 @@ optionHelpText :: [String] optionHelpText = [ "",- "zeolite [options...] -m [category(.function)] -o [binary] [path]",- "zeolite [options...] --fast [category(.function)] [.0rx source]", "zeolite [options...] -c [path]",+ "zeolite [options...] -m [category(.function)] (-o [binary]) [path]",+ "zeolite [options...] --fast [category(.function)] [.0rx source]", "zeolite [options...] -r [paths...]", "zeolite [options...] -R [paths...]",- "zeolite [options...] -t [paths...]",+ "zeolite [options...] -t [paths...] (--log-traces [filename])", "", "zeolite [options...] --templates [paths...]", "zeolite --get-path",@@ -48,8 +48,8 @@ "zeolite --version", "", "Normal Modes:",- " -c: Only compile the individual files. (default)",- " -m [category(.function)]: Create a binary that executes the function.",+ " -c: Initialize and compile a new library module.",+ " -m [category(.function)]: Initialize and compile a new binary module.", " --fast [category(.function)] [.0rx source]: Create a binary without needing a module.", " -r: Recompile using the previous compilation options.", " -R: Recursively recompile using the previous compilation options.",@@ -67,6 +67,7 @@ " -I [path]: A single source path to include as a *private* dependency.", " -o [binary]: The name of the binary file to create with -m.", " -p [path]: Set a path prefix for finding the specified source files.",+ " --log-traces [filename]: Log call traces to a file when running tests.", "", "[category]: The name of a concrete category with no params.", "[function]: The name of a @type function (defaults to \"run\") with no args or params.",@@ -117,7 +118,7 @@ parseSingle (CompileOptions h is is2 ds es ep p m f) ((n,"-t"):os) | m /= CompileUnspecified = argError n "-t" "Compiler mode already set."- | otherwise = return (os,CompileOptions (maybeDisableHelp h) is is2 ds es ep p (ExecuteTests []) f)+ | otherwise = return (os,CompileOptions (maybeDisableHelp h) is is2 ds es ep p (ExecuteTests [] Nothing) f) parseSingle (CompileOptions h is is2 ds es ep p m f) ((n,"--templates"):os) | m /= CompileUnspecified = argError n "-t" "Compiler mode already set."@@ -152,6 +153,13 @@ check _ = argError n2 c $ "Invalid entry point." update _ = argError n "--fast" "Requires a category name and a .0rx file." + parseSingle (CompileOptions h is is2 ds es ep p (ExecuteTests tp cl) f) ((n,"--log-traces"):os) = update os where+ update ((_,cl2):os2)+ | cl /= Nothing = argError n "--log-traces" "Trace-log filename already set."+ | otherwise = return (os2,CompileOptions (maybeDisableHelp h) is is2 ds es ep p (ExecuteTests tp (Just cl2)) f)+ update _ = argError n "--log-traces" "Requires an output filename."+ parseSingle _ ((n,"--log-traces"):_) = argError n "--log-traces" "Set mode to test (-t) first."+ parseSingle (CompileOptions h is is2 ds es ep p (CompileBinary t fn o lf) f) ((n,"-o"):os) | not $ null o = argError n "-o" "Output name already set." | otherwise = update os where@@ -159,7 +167,7 @@ checkPathName n2 o2 "-o" return (os2,CompileOptions (maybeDisableHelp h) is is2 ds es ep p (CompileBinary t fn o2 lf) f) update _ = argError n "-o" "Requires an output name."- parseSingle _ ((n,"-o"):_) = argError n "-o" "Set mode to binary (-m) first"+ parseSingle _ ((n,"-o"):_) = argError n "-o" "Set mode to binary (-m) first." parseSingle (CompileOptions h is is2 ds es ep p m f) ((n,"-i"):os) = update os where update ((n2,d):os2)@@ -198,8 +206,8 @@ when (not $ isExecuteTests m) $ argError n d "Test mode (-t) must be enabled before listing any .0rt test files." checkPathName n d ""- let (ExecuteTests tp) = m- return (os,CompileOptions (maybeDisableHelp h) is is2 ds es ep p (ExecuteTests $ tp ++ [d]) f)+ let (ExecuteTests tp cl) = m+ return (os,CompileOptions (maybeDisableHelp h) is is2 ds es ep p (ExecuteTests (tp ++ [d]) cl) f) | otherwise = do checkPathName n d "" return (os,CompileOptions (maybeDisableHelp h) is is2 (ds ++ [d]) es ep p m f)@@ -207,6 +215,9 @@ validateCompileOptions :: CollectErrorsM m => CompileOptions -> m CompileOptions validateCompileOptions co@(CompileOptions h is is2 ds _ _ _ m _) | h /= HelpNotNeeded = return co++ | isCompileUnspecified m =+ compilerErrorM "Compiler mode must be specified explicitly." | (not $ null $ is ++ is2) && (isExecuteTests m) = compilerErrorM "Include paths (-i/-I) are not allowed in test mode (-t)."
src/Cli/RunCompiler.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2020 Kevin P. Barry+Copyright 2020-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.@@ -40,14 +40,22 @@ runCompiler :: (PathIOHandler r, CompilerBackend b) => r -> b -> CompileOptions -> TrackedErrorsIO ()-runCompiler resolver backend (CompileOptions _ _ _ ds _ _ p (ExecuteTests tp) f) = do+runCompiler resolver backend (CompileOptions _ _ _ ds _ _ p (ExecuteTests tp cl) f) = do base <- resolveBaseModule resolver ts <- fmap snd $ foldM (preloadTests base) (Map.empty,[]) ds checkTestFilters ts- allResults <- fmap concat $ mapCompilerM (runModuleTests resolver backend base tp) ts+ cl2 <- prepareCallLog cl+ allResults <- fmap concat $ mapCompilerM (runModuleTests resolver backend cl2 base tp) ts let passed = sum $ map (fst . fst) allResults let failed = sum $ map (snd . fst) allResults processResults passed failed (mapCompilerM_ snd allResults) where+ prepareCallLog (Just cl2) = do+ clFull <- errorFromIO $ canonicalizePath (p </> cl2)+ compilerWarningM $ "Logging calls to " ++ clFull+ errorFromIO $ writeFile clFull (intercalate "," (map show logHeader) ++ "\n")+ return clFull+ prepareCallLog _ = return ""+ logHeader = ["microseconds","pid","function","context"] compilerHash = getCompilerHash backend preloadTests base (ca,ms) d = do m <- loadModuleMetadata compilerHash f ca (p </> d)
src/Cli/TestRunner.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2020 Kevin P. Barry+Copyright 2020-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.@@ -47,10 +47,10 @@ import Types.TypeCategory -runSingleTest :: CompilerBackend b => b -> LanguageModule SourceContext ->- FilePath -> [FilePath] -> [CompileMetadata] -> (String,String) ->- TrackedErrorsIO ((Int,Int),TrackedErrors ())-runSingleTest b cm p paths deps (f,s) = do+runSingleTest :: CompilerBackend b => b -> FilePath ->+ LanguageModule SourceContext -> FilePath -> [FilePath] -> [CompileMetadata] ->+ (String,String) -> TrackedErrorsIO ((Int,Int),TrackedErrors ())+runSingleTest b cl cm p paths deps (f,s) = do errorFromIO $ hPutStrLn stderr $ "\nExecuting tests from " ++ f allResults <- checkAndRun (parseTestSource (f,s)) return $ second (("\nIn test file " ++ f) ??>) allResults where@@ -146,7 +146,7 @@ return results executeTest binary rs es res s2 (f2,c) = printOutcome $ "\nIn unittest " ++ show f2 ++ formatFullContextBrace c ??> do- let command = TestCommand binary (takeDirectory binary) [show f2]+ let command = TestCommand binary (takeDirectory binary) [show f2,cl] (TestCommandResult s2' out err) <- runTestCommand b command case (s2,s2') of (True,False) -> collectAllM_ $ (asCompilerError res):(map compilerErrorM $ err ++ out)
src/Compilation/CompilerState.hs view
@@ -27,7 +27,6 @@ CompilerContext(..), CompiledData(..), CompilerState,- ExpressionType, LoopSetup(..), JumpType(..), MemberValue(..),@@ -90,7 +89,6 @@ import Base.CompilerError import Base.GeneralType-import Base.Positional import Types.DefinedCategory import Types.Procedure import Types.TypeCategory@@ -110,7 +108,7 @@ ccGetRequired :: a -> m (Set.Set CategoryName) ccGetCategoryFunction :: a -> [c] -> Maybe CategoryName -> FunctionName -> m (ScopedFunction c) ccGetTypeFunction :: a -> [c] -> Maybe GeneralInstance -> FunctionName -> m (ScopedFunction c)- ccCheckValueInit :: a -> [c] -> TypeInstance -> ExpressionType -> Positional GeneralInstance -> m ()+ ccCheckValueInit :: a -> [c] -> TypeInstance -> ExpressionType -> m () ccGetVariable :: a -> UsedVariable c -> m (VariableValue c) ccAddVariable :: a -> UsedVariable c -> VariableValue c -> m a ccSetReadOnly :: a -> UsedVariable c -> m a@@ -139,8 +137,6 @@ ccSetNoTrace :: a -> Bool -> m a ccGetNoTrace :: a -> m Bool -type ExpressionType = Positional ValueType- data MemberValue c = MemberValue { mvContext :: [c],@@ -224,8 +220,8 @@ csGetTypeFunction c t n = fmap (\x -> ccGetTypeFunction x c t n) get >>= lift csCheckValueInit :: CompilerContext c m s a =>- [c] -> TypeInstance -> ExpressionType -> Positional GeneralInstance -> CompilerState a m ()-csCheckValueInit c t as ps = fmap (\x -> ccCheckValueInit x c t as ps) get >>= lift+ [c] -> TypeInstance -> ExpressionType -> CompilerState a m ()+csCheckValueInit c t as = fmap (\x -> ccCheckValueInit x c t as) get >>= lift csGetVariable :: CompilerContext c m s a => UsedVariable c -> CompilerState a m (VariableValue c)
src/Compilation/ProcedureContext.hs view
@@ -29,7 +29,7 @@ updateReturnVariables, ) where -import Control.Monad (when)+import Control.Monad (foldM,when) import Lens.Micro hiding (mapped) import Lens.Micro.TH import Data.Maybe (fromJust,isJust)@@ -65,12 +65,10 @@ _pcScope :: SymbolScope, _pcType :: CategoryName, _pcExtParams :: Positional (ValueParam c),- _pcIntParams :: Positional (ValueParam c), _pcMembers :: [DefinedMember c], _pcCategories :: CategoryMap c, _pcAllFilters :: ParamFilters, _pcExtFilters :: [ParamFilter c],- _pcIntFilters :: [ParamFilter c], _pcParamScopes :: Map.Map ParamName SymbolScope, _pcFunctions :: Map.Map FunctionName (ScopedFunction c), _pcVariables :: Map.Map VariableName (VariableValue c),@@ -134,7 +132,7 @@ ccGetTypeFunction ctx c t n = do t' <- case ctx ^. pcScope of CategoryScope -> case t of- Nothing -> compilerErrorM $ "Category " ++ show t +++ Nothing -> compilerErrorM $ "Category " ++ show (ctx ^. pcType) ++ " does not have a category function named " ++ show n ++ formatFullContextBrace c Just t0 -> return t0@@ -190,7 +188,7 @@ 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+ ccCheckValueInit ctx c (TypeInstance t as) ts | t /= ctx ^. pcType = compilerErrorM $ "Category " ++ show (ctx ^. pcType) ++ " cannot initialize values from " ++ show t ++ formatFullContextBrace c@@ -199,26 +197,12 @@ r <- ccResolver ctx allFilters <- ccAllFilters ctx pa <- fmap Map.fromList $ processPairs alwaysPair (fmap vpParam $ ctx ^. pcExtParams) as- pa2 <- fmap Map.fromList $ processPairs alwaysPair (fmap vpParam $ ctx ^. pcIntParams) ps- let pa' = Map.union pa pa2- validateTypeInstance r allFilters t'- -- Check internal param substitution.- let mapped = Map.fromListWith (++) $ map (\f -> (pfParam f,[pfFilter f])) (ctx ^. pcIntFilters)- let positional = map (getFilters mapped) (map vpParam $ pValues $ ctx ^. pcIntParams)- assigned <- fmap Map.fromList $ processPairs alwaysPair (fmap vpParam $ ctx ^. pcIntParams) ps- subbed <- fmap Positional $ mapCompilerM (assignFilters assigned) positional- processPairs_ (validateAssignment r allFilters) ps subbed+ validateTypeInstanceForCall r allFilters t' -- Check initializer types.- ms <- fmap Positional $ mapCompilerM (subSingle pa') (ctx ^. pcMembers)+ ms <- fmap Positional $ mapCompilerM (subSingle pa) (ctx ^. pcMembers) processPairs_ (checkInit r allFilters) ms (Positional $ zip ([1..] :: [Int]) $ pValues ts) return () where- getFilters fm n =- case n `Map.lookup` fm of- (Just fs) -> fs- _ -> []- assignFilters fm fs = do- mapCompilerM (uncheckedSubFilter $ getValueForParam fm) fs checkInit r fa (MemberValue c2 n t0) (i,t1) = do checkValueAssignment r fa t1 t0 <?? "In initializer " ++ show i ++ " for " ++ show n ++ formatFullContextBrace c2@@ -227,6 +211,9 @@ return $ MemberValue c2 n t2' ccGetVariable ctx (UsedVariable c n) = case n `Map.lookup` (ctx ^. pcVariables) of+ (Just (VariableValue _ _ _ (VariableHidden []))) ->+ compilerErrorM $ "Variable " ++ show n ++ formatFullContextBrace c +++ " is hidden" (Just (VariableValue _ _ _ (VariableHidden c2))) -> compilerErrorM $ "Variable " ++ show n ++ formatFullContextBrace c ++ " was explicitly hidden at " ++ formatFullContext c2@@ -391,12 +378,12 @@ updateArgVariables ma as1 as2 = do as <- processPairs alwaysPair as1 (avNames as2) let as' = filter (not . isDiscardedInput . snd) as- foldr update (return ma) as' where- update (PassedValue c t,a) va = do- va' <- va- case ivName a `Map.lookup` va' of- Nothing -> return $ Map.insert (ivName a) (VariableValue c LocalScope t (VariableReadOnly c)) va'+ foldM update ma as' where+ update va (PassedValue _ t,a) = do+ let c = ivContext a+ case ivName a `Map.lookup` va of+ Nothing -> return $ Map.insert (ivName a) (VariableValue c LocalScope t (VariableReadOnly c)) va (Just v) -> compilerErrorM $ "Variable " ++ show (ivName a) ++- formatFullContextBrace (ivContext a) ++- " is already defined" ++- formatFullContextBrace (vvContext v)+ formatFullContextBrace c +++ " is already defined" +++ formatFullContextBrace (vvContext v)
src/Compilation/ScopeContext.hs view
@@ -26,9 +26,8 @@ getProcedureScopes, ) where -import Control.Monad (when)-import Prelude hiding (pi) import qualified Data.Map as Map+import qualified Data.Set as Set import Base.CompilerError import Base.GeneralType@@ -44,11 +43,9 @@ ScopeContext { scCategories :: CategoryMap c, scName :: CategoryName,- scExternalParams :: Positional (ValueParam c),- scInternalparams :: Positional (ValueParam c),+ scParams :: Positional (ValueParam c), scValueMembers :: [DefinedMember c],- scExternalFilters :: [ParamFilter c],- scInternalFilters :: [ParamFilter c],+ scFilters :: [ParamFilter c], scFunctions :: Map.Map FunctionName (ScopedFunction c), scVariables :: Map.Map VariableName (VariableValue c), scExprMap :: ExprMap c@@ -66,17 +63,13 @@ getProcedureScopes :: (Show c, CollectErrorsM m) => CategoryMap c -> ExprMap c -> DefinedCategory c -> m [ProcedureScope c]-getProcedureScopes ta em (DefinedCategory c n pi _ _ fi ms ps fs) = do+getProcedureScopes ta em (DefinedCategory c n pragmas _ _ ms ps fs) = do (_,t) <- getConcreteCategory ta (c,n) let params = Positional $ getCategoryParams t- let params2 = Positional pi let typeInstance = TypeInstance n $ fmap (singleType . JustParamName False . vpParam) params let filters = getCategoryFilters t- let filters2 = fi let r = CategoryResolver ta fa <- setInternalFunctions r t fs- fm <- getCategoryFilterMap t- checkInternalParams pi fi (getCategoryParams t) (Map.elems fa) r fm pa <- pairProceduresToFunctions fa ps let (cp,tp,vp) = partitionByScope (sfScope . fst) pa tp' <- mapCompilerM (firstM $ replaceSelfFunction (instanceFromCategory t)) tp@@ -87,39 +80,35 @@ let cm0 = builtins typeInstance CategoryScope let tm0 = builtins typeInstance TypeScope let vm0 = builtins typeInstance ValueScope- cm2 <- mapMembers cm- tm2 <- mapMembers $ cm ++ tm'- vm2 <- mapMembers $ cm ++ tm' ++ vm'+ cm2 <- mapMembers readOnly hidden cm+ tm2 <- mapMembers readOnly hidden $ cm ++ tm'+ vm2 <- mapMembers readOnly hidden $ cm ++ tm' ++ vm'+ mapCompilerM_ checkPragma pragmas 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+ let ctxC = ScopeContext ta n params vm' filters fa cv em+ let ctxT = ScopeContext ta n params vm' filters fa tv em+ let ctxV = ScopeContext ta n params vm' filters fa vv em return [ProcedureScope ctxC cp,ProcedureScope ctxT tp',ProcedureScope ctxV vp'] where+ checkPragma (MembersReadOnly c2 vs) = do+ let missing = Set.toList $ Set.fromList vs `Set.difference` allMembers+ mapCompilerM_ (\v -> compilerErrorM $ "Member " ++ show v +++ " does not exist (marked ReadOnly at " +++ formatFullContext c2 ++ ")") missing+ checkPragma (MembersHidden c2 vs) = do+ let missing = Set.toList $ Set.fromList vs `Set.difference` allMembers+ mapCompilerM_ (\v -> compilerErrorM $ "Member " ++ show v +++ " does not exist (marked Hidden at " +++ formatFullContext c2 ++ ")") missing+ allMembers = Set.fromList $ map dmName ms+ readOnly = Map.fromListWith (++) $ concat $ map (\m -> zip (mroMembers m) (repeat $ mroContext m)) $ filter isMembersReadOnly pragmas+ hidden = Map.fromListWith (++) $ concat $ map (\m -> zip (mhMembers m) (repeat $ mhContext m)) $ filter isMembersHidden pragmas 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- mapCompilerM_ (checkFunction pm) fs2- mapCompilerM_ (checkParam pm) pe- fa' <- fmap (Map.union fa) $ getFilterMap pi2 fi2- mapCompilerM_ (checkFilter r fa') fi2- checkFilter r fa (ParamFilter c2 n2 f) =- validateTypeFilter r fa f <?? "In " ++ show n2 ++ " " ++ show f ++ formatFullContextBrace c2- checkFunction pm f =- when (sfScope f == ValueScope) $- mapCompilerM_ (checkParam pm) $ pValues $ sfParams f- checkParam pm p =- case vpParam p `Map.lookup` pm of- Nothing -> return ()- (Just c2) -> compilerErrorM $ "Internal param " ++ show (vpParam p) ++- formatFullContextBrace (vpContext p) ++- " is already defined at " ++- formatFullContext c2 -- TODO: This is probably in the wrong module. builtinVariables :: TypeInstance -> Map.Map VariableName (VariableValue c)
src/CompilerCxx/CategoryContext.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.@@ -34,7 +34,7 @@ import Compilation.CompilerState import Compilation.ProcedureContext import Compilation.ScopeContext-import CompilerCxx.Code+import Types.Builtin import Types.DefinedCategory import Types.Procedure import Types.TypeCategory@@ -57,17 +57,16 @@ fm <- getFilterMap (pValues ps) pa let typeInstance = TypeInstance (getCategoryName t) $ fmap (singleType . JustParamName False . vpParam) ps let builtin = Map.filter ((== LocalScope) . vvScope) $ builtinVariables typeInstance- members <- mapMembers $ filter ((<= s) . dmScope) (dcMembers d)+ let readOnly = Map.fromListWith (++) $ map (\m -> (dmName m,[])) $ dcMembers d+ members <- mapMembers readOnly Map.empty $ filter ((<= s) . dmScope) (dcMembers d) return $ ProcedureContext { _pcScope = s, _pcType = getCategoryName t, _pcExtParams = ps,- _pcIntParams = Positional [], _pcMembers = ms, _pcCategories = tm, _pcAllFilters = fm, _pcExtFilters = pa,- _pcIntFilters = [], _pcParamScopes = sa, _pcFunctions = fa, _pcVariables = Map.union builtin members,@@ -89,7 +88,7 @@ getProcedureContext :: (Show c, CollectErrorsM m) => ScopeContext c -> ScopedFunction c -> ExecutableProcedure c -> m (ProcedureContext c)-getProcedureContext (ScopeContext tm t ps pi ms pa fi fa va em)+getProcedureContext (ScopeContext tm t ps ms pa fa va em) ff@(ScopedFunction _ _ _ s as1 rs1 ps1 fs _) (ExecutableProcedure _ _ _ _ as2 rs2 _) = do rs' <- if isUnnamedReturns rs2@@ -102,35 +101,30 @@ else pa ++ fs let localScopes = Map.fromList $ zip (map vpParam $ pValues ps1) (repeat LocalScope) let typeScopes = Map.fromList $ zip (map vpParam $ pValues ps) (repeat TypeScope)- let valueScopes = Map.fromList $ zip (map vpParam $ pValues pi) (repeat ValueScope) let sa = case s of CategoryScope -> localScopes- TypeScope -> Map.union typeScopes localScopes- ValueScope -> Map.unions [localScopes,typeScopes,valueScopes]+ TypeScope -> Map.union typeScopes localScopes+ ValueScope -> Map.union typeScopes localScopes _ -> undefined localFilters <- getFunctionFilterMap ff typeFilters <- getFilterMap (pValues ps) pa- valueFilters <- getFilterMap (pValues pi) fi let allFilters = case s of CategoryScope -> localFilters- TypeScope -> Map.union localFilters typeFilters- ValueScope -> Map.unions [localFilters,typeFilters,valueFilters]+ TypeScope -> Map.union localFilters typeFilters+ ValueScope -> Map.union localFilters typeFilters _ -> undefined let ns0 = if isUnnamedReturns rs2 then [] else zipWith3 ReturnVariable [0..] (map ovName $ pValues $ nrNames rs2) (map pvType $ pValues rs1)- let ns = filter (isPrimType . rvType) ns0+ let ns = filter (isPrimitiveType . rvType) ns0 return $ ProcedureContext { _pcScope = s, _pcType = t, _pcExtParams = ps,- _pcIntParams = pi, _pcMembers = ms, _pcCategories = tm, _pcAllFilters = allFilters, _pcExtFilters = pa',- -- fs is duplicated so value initialization checks work properly.- _pcIntFilters = fi ++ fs, _pcParamScopes = sa, _pcFunctions = fa, _pcVariables = va'',@@ -157,12 +151,10 @@ _pcScope = LocalScope, _pcType = CategoryNone, _pcExtParams = Positional [],- _pcIntParams = Positional [], _pcMembers = [], _pcCategories = tm, _pcAllFilters = Map.empty, _pcExtFilters = [],- _pcIntFilters = [], _pcParamScopes = Map.empty, _pcFunctions = Map.empty, _pcVariables = Map.empty,
src/CompilerCxx/Code.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.@@ -19,8 +19,6 @@ {-# LANGUAGE Safe #-} module CompilerCxx.Code (- ExprValue(..),- PrimitiveType(..), categoryBase, captureCreationTrace, clearCompiled,@@ -29,7 +27,6 @@ escapeChars, functionLabelType, indentCompiled,- isPrimType, newFunctionLabel, noTestsOnlySourceGuard, onlyCode,@@ -88,8 +85,8 @@ clearCompiled :: CompiledData [String] -> CompiledData [String] clearCompiled (CompiledData r _) = CompiledData r [] -startFunctionTracing :: ScopedFunction c -> String-startFunctionTracing f = "TRACE_FUNCTION(" ++ show (functionDebugName f) ++ ")"+startFunctionTracing :: CategoryName -> ScopedFunction c -> String+startFunctionTracing t f = "TRACE_FUNCTION(" ++ show (functionDebugName t f) ++ ")" startMainTracing :: String -> String startMainTracing n = "TRACE_FUNCTION(" ++ show n ++ ")"@@ -113,38 +110,13 @@ | null c = "" | otherwise = "PRED_CONTEXT_POINT(" ++ escapeChars (formatFullContext c) ++ ")" -captureCreationTrace :: String-captureCreationTrace = "CAPTURE_CREATION"+captureCreationTrace :: CategoryName -> String+captureCreationTrace n = "CAPTURE_CREATION(" ++ show (show n) ++ ")" showCreationTrace :: String showCreationTrace = "TRACE_CREATION" -data PrimitiveType =- PrimBool |- PrimString |- PrimChar |- PrimInt |- PrimFloat- deriving (Eq,Show)--isPrimType :: ValueType -> Bool-isPrimType t- | t == boolRequiredValue = True- | t == intRequiredValue = True- | t == floatRequiredValue = True- | t == charRequiredValue = True- | otherwise = False--data ExprValue =- OpaqueMulti String |- WrappedSingle String |- UnwrappedSingle String |- BoxedPrimitive PrimitiveType String |- UnboxedPrimitive PrimitiveType String |- LazySingle ExprValue- deriving (Show)--getFromLazy :: ExprValue -> ExprValue+getFromLazy :: ExpressionValue -> ExpressionValue getFromLazy (OpaqueMulti e) = OpaqueMulti $ e ++ ".Get()" getFromLazy (WrappedSingle e) = WrappedSingle $ e ++ ".Get()" getFromLazy (UnwrappedSingle e) = UnwrappedSingle $ e ++ ".Get()"@@ -152,7 +124,7 @@ getFromLazy (UnboxedPrimitive t e) = UnboxedPrimitive t $ e ++ ".Get()" getFromLazy (LazySingle e) = LazySingle $ getFromLazy e -useAsWhatever :: ExprValue -> String+useAsWhatever :: ExpressionValue -> String useAsWhatever (OpaqueMulti e) = e useAsWhatever (WrappedSingle e) = e useAsWhatever (UnwrappedSingle e) = e@@ -160,7 +132,7 @@ useAsWhatever (UnboxedPrimitive _ e) = e useAsWhatever (LazySingle e) = useAsWhatever $ getFromLazy e -useAsReturns :: ExprValue -> String+useAsReturns :: ExpressionValue -> String useAsReturns (OpaqueMulti e) = "(" ++ e ++ ")" useAsReturns (WrappedSingle e) = "ReturnTuple(" ++ e ++ ")" useAsReturns (UnwrappedSingle e) = "ReturnTuple(" ++ e ++ ")"@@ -176,7 +148,7 @@ useAsReturns (UnboxedPrimitive PrimFloat e) = "ReturnTuple(Box_Float(" ++ e ++ "))" useAsReturns (LazySingle e) = useAsReturns $ getFromLazy e -useAsArgs :: ExprValue -> String+useAsArgs :: ExpressionValue -> String useAsArgs (OpaqueMulti e) = "(" ++ e ++ ")" useAsArgs (WrappedSingle e) = "ArgTuple(" ++ e ++ ")" useAsArgs (UnwrappedSingle e) = "ArgTuple(" ++ e ++ ")"@@ -192,7 +164,7 @@ useAsArgs (UnboxedPrimitive PrimFloat e) = "ArgTuple(Box_Float(" ++ e ++ "))" useAsArgs (LazySingle e) = useAsArgs $ getFromLazy e -useAsUnwrapped :: ExprValue -> String+useAsUnwrapped :: ExpressionValue -> String useAsUnwrapped (OpaqueMulti e) = "(" ++ e ++ ").Only()" useAsUnwrapped (WrappedSingle e) = "(" ++ e ++ ")" useAsUnwrapped (UnwrappedSingle e) = "(" ++ e ++ ")"@@ -203,32 +175,32 @@ useAsUnwrapped (BoxedPrimitive PrimFloat e) = "Box_Float(" ++ e ++ ")" useAsUnwrapped (UnboxedPrimitive PrimBool e) = "Box_Bool(" ++ e ++ ")" useAsUnwrapped (UnboxedPrimitive PrimString e) = "Box_String(" ++ e ++ ")"-useAsUnwrapped (UnboxedPrimitive PrimChar e) = "Box_Char(" ++ e ++ ")"+useAsUnwrapped (UnboxedPrimitive PrimChar e) = "Box_Char(" ++ e ++ ")" useAsUnwrapped (UnboxedPrimitive PrimInt e) = "Box_Int(" ++ e ++ ")" useAsUnwrapped (UnboxedPrimitive PrimFloat e) = "Box_Float(" ++ e ++ ")" useAsUnwrapped (LazySingle e) = useAsUnwrapped $ getFromLazy e -useAsUnboxed :: PrimitiveType -> ExprValue -> String-useAsUnboxed PrimBool (OpaqueMulti e) = "(" ++ e ++ ").Only()->AsBool()"-useAsUnboxed PrimString (OpaqueMulti e) = "(" ++ e ++ ").Only()->AsString()"-useAsUnboxed PrimChar (OpaqueMulti e) = "(" ++ e ++ ").Only()->AsChar()"-useAsUnboxed PrimInt (OpaqueMulti e) = "(" ++ e ++ ").Only()->AsInt()"-useAsUnboxed PrimFloat (OpaqueMulti e) = "(" ++ e ++ ").Only()->AsFloat()"-useAsUnboxed PrimBool (WrappedSingle e) = "(" ++ e ++ ")->AsBool()"-useAsUnboxed PrimString (WrappedSingle e) = "(" ++ e ++ ")->AsString()"-useAsUnboxed PrimChar (WrappedSingle e) = "(" ++ e ++ ")->AsChar()"-useAsUnboxed PrimInt (WrappedSingle e) = "(" ++ e ++ ")->AsInt()"-useAsUnboxed PrimFloat (WrappedSingle e) = "(" ++ e ++ ")->AsFloat()"+useAsUnboxed :: PrimitiveType -> ExpressionValue -> String+useAsUnboxed PrimBool (OpaqueMulti e) = "(" ++ e ++ ").Only()->AsBool()"+useAsUnboxed PrimString (OpaqueMulti e) = "(" ++ e ++ ").Only()->AsString()"+useAsUnboxed PrimChar (OpaqueMulti e) = "(" ++ e ++ ").Only()->AsChar()"+useAsUnboxed PrimInt (OpaqueMulti e) = "(" ++ e ++ ").Only()->AsInt()"+useAsUnboxed PrimFloat (OpaqueMulti e) = "(" ++ e ++ ").Only()->AsFloat()"+useAsUnboxed PrimBool (WrappedSingle e) = "(" ++ e ++ ")->AsBool()"+useAsUnboxed PrimString (WrappedSingle e) = "(" ++ e ++ ")->AsString()"+useAsUnboxed PrimChar (WrappedSingle e) = "(" ++ e ++ ")->AsChar()"+useAsUnboxed PrimInt (WrappedSingle e) = "(" ++ e ++ ")->AsInt()"+useAsUnboxed PrimFloat (WrappedSingle e) = "(" ++ e ++ ")->AsFloat()" useAsUnboxed PrimBool (UnwrappedSingle e) = "(" ++ e ++ ")->AsBool()" useAsUnboxed PrimString (UnwrappedSingle e) = "(" ++ e ++ ")->AsString()" useAsUnboxed PrimChar (UnwrappedSingle e) = "(" ++ e ++ ")->AsChar()" useAsUnboxed PrimInt (UnwrappedSingle e) = "(" ++ e ++ ")->AsInt()" useAsUnboxed PrimFloat (UnwrappedSingle e) = "(" ++ e ++ ")->AsFloat()"-useAsUnboxed _ (BoxedPrimitive _ e) = "(" ++ e ++ ")"-useAsUnboxed _ (UnboxedPrimitive _ e) = "(" ++ e ++ ")"-useAsUnboxed t (LazySingle e) = useAsUnboxed t $ getFromLazy e+useAsUnboxed _ (BoxedPrimitive _ e) = "(" ++ e ++ ")"+useAsUnboxed _ (UnboxedPrimitive _ e) = "(" ++ e ++ ")"+useAsUnboxed t (LazySingle e) = useAsUnboxed t $ getFromLazy e -valueAsWrapped :: ExprValue -> ExprValue+valueAsWrapped :: ExpressionValue -> ExpressionValue valueAsWrapped (UnwrappedSingle e) = WrappedSingle e valueAsWrapped (BoxedPrimitive _ e) = WrappedSingle e valueAsWrapped (UnboxedPrimitive PrimBool e) = WrappedSingle $ "Box_Bool(" ++ e ++ ")"@@ -239,7 +211,7 @@ valueAsWrapped (LazySingle e) = valueAsWrapped $ getFromLazy e valueAsWrapped v = v -valueAsUnwrapped :: ExprValue -> ExprValue+valueAsUnwrapped :: ExpressionValue -> ExpressionValue valueAsUnwrapped (OpaqueMulti e) = UnwrappedSingle $ "(" ++ e ++ ").Only()" valueAsUnwrapped (WrappedSingle e) = UnwrappedSingle e valueAsUnwrapped (UnboxedPrimitive PrimBool e) = UnwrappedSingle $ "Box_Bool(" ++ e ++ ")"@@ -271,21 +243,21 @@ | isWeakValue t = "W<TypeValue>&" | otherwise = "S<TypeValue>&" -readStoredVariable :: Bool -> ValueType -> String -> ExprValue+readStoredVariable :: Bool -> ValueType -> String -> ExpressionValue readStoredVariable True t s = LazySingle $ readStoredVariable False t s readStoredVariable False t s- | t == boolRequiredValue = UnboxedPrimitive PrimBool s- | t == intRequiredValue = UnboxedPrimitive PrimInt s+ | t == boolRequiredValue = UnboxedPrimitive PrimBool s+ | t == intRequiredValue = UnboxedPrimitive PrimInt s | t == floatRequiredValue = UnboxedPrimitive PrimFloat s- | t == charRequiredValue = UnboxedPrimitive PrimChar s+ | t == charRequiredValue = UnboxedPrimitive PrimChar s | otherwise = UnwrappedSingle s -writeStoredVariable :: ValueType -> ExprValue -> String+writeStoredVariable :: ValueType -> ExpressionValue -> String writeStoredVariable t e- | t == boolRequiredValue = useAsUnboxed PrimBool e- | t == intRequiredValue = useAsUnboxed PrimInt e+ | t == boolRequiredValue = useAsUnboxed PrimBool e+ | t == intRequiredValue = useAsUnboxed PrimInt e | t == floatRequiredValue = useAsUnboxed PrimFloat e- | t == charRequiredValue = useAsUnboxed PrimChar e+ | t == charRequiredValue = useAsUnboxed PrimChar e | otherwise = useAsUnwrapped e functionLabelType :: ScopedFunction c -> String
src/CompilerCxx/CxxFiles.hs view
@@ -87,17 +87,17 @@ return (dec:def) generateNativeInterface :: (Ord c, Show c, CollectErrorsM m) =>- Bool -> AnyCategory c -> m [CxxOutput]-generateNativeInterface testing t = do- dec <- compileCategoryDeclaration testing Set.empty t+ Bool -> Set.Set Namespace -> AnyCategory c -> m [CxxOutput]+generateNativeInterface testing ns t = do+ dec <- compileCategoryDeclaration testing ns t def <- generateCategoryDefinition testing (NativeInterface t) return (dec:def) generateStreamlinedExtension :: (Ord c, Show c, CollectErrorsM m) =>- Bool -> AnyCategory c -> m [CxxOutput]-generateStreamlinedExtension testing t = do- dec <- compileCategoryDeclaration testing Set.empty t- def <- generateCategoryDefinition testing (StreamlinedExtension t)+ Bool -> Set.Set Namespace -> AnyCategory c -> m [CxxOutput]+generateStreamlinedExtension testing ns t = do+ dec <- compileCategoryDeclaration testing ns t+ def <- generateCategoryDefinition testing (StreamlinedExtension t ns) return (dec:def) generateVerboseExtension :: (Ord c, Show c, CollectErrorsM m) =>@@ -106,8 +106,8 @@ fmap (:[]) $ compileCategoryDeclaration testing Set.empty t generateStreamlinedTemplate :: (Ord c, Show c, CollectErrorsM m) =>- FileContext c -> AnyCategory c -> m [CxxOutput]-generateStreamlinedTemplate (FileContext testing tm _ _) t =+ Bool -> CategoryMap c -> AnyCategory c -> m [CxxOutput]+generateStreamlinedTemplate testing tm t = generateCategoryDefinition testing (StreamlinedTemplate t tm) compileCategoryDeclaration :: (Ord c, Show c, CollectErrorsM m) =>@@ -160,7 +160,8 @@ ncExprMap :: ExprMap c } | StreamlinedExtension {- seCategory :: AnyCategory c+ seCategory :: AnyCategory c,+ ncNamespaces :: Set.Set Namespace } | StreamlinedTemplate { stCategory :: AnyCategory c,@@ -192,32 +193,21 @@ (Set.fromList [getCategoryNamespace t]) req' (allowTestsOnly $ addSourceIncludes $ addCategoryHeader t $ addIncludes req' out)- common (StreamlinedExtension t) = sequence [streamlinedHeader,streamlinedSource] where+ common (StreamlinedExtension t ns) = sequence [streamlinedHeader,streamlinedSource] where streamlinedHeader = do let filename = headerStreamlined (getCategoryName t) (CompiledData req out) <- fmap (addNamespace t) $ concatM [ defineAbstractCategory t, defineAbstractType t,- defineAbstractValue t defined,+ defineAbstractValue t, declareAbstractGetters t ] return $ CxxOutput (Just $ getCategoryName t) filename (getCategoryNamespace t)- (Set.fromList [getCategoryNamespace t])+ (getCategoryNamespace t `Set.insert` ns) req (headerGuard (getCategoryName t) $ allowTestsOnly $ addSourceIncludes $ addCategoryHeader t $ addIncludes req out)- defined = DefinedCategory {- dcContext = [],- dcName = getCategoryName t,- dcParams = [],- dcRefines = [],- dcDefines = [],- dcParamFilter = [],- dcMembers = [],- dcProcedures = [],- dcFunctions = []- } streamlinedSource = do let filename = sourceStreamlined (getCategoryName t) let (cf,tf,vf) = partitionByScope sfScope $ getCategoryFunctions t@@ -232,7 +222,7 @@ return $ CxxOutput (Just $ getCategoryName t) filename (getCategoryNamespace t)- (Set.fromList [getCategoryNamespace t])+ (getCategoryNamespace t `Set.insert` ns) req' (addSourceIncludes $ addStreamlinedHeader t $ addIncludes req' out) common (StreamlinedTemplate t tm) = fmap (:[]) streamlinedTemplate where@@ -256,11 +246,10 @@ filename = templateStreamlined (getCategoryName t) defined = DefinedCategory { dcContext = [],+ dcPragmas = [], dcName = getCategoryName t,- dcParams = [], dcRefines = [], dcDefines = [],- dcParamFilter = [], dcMembers = [], dcProcedures = map defaultFail (getCategoryFunctions t), dcFunctions = []@@ -276,12 +265,12 @@ } createArg = InputValue [] . VariableName . ("arg" ++) . show failProcedure f = Procedure [] $ [- asLineComment $ "TODO: Implement " ++ functionDebugName f ++ "."+ asLineComment $ "TODO: Implement " ++ functionDebugName (getCategoryName t) f ++ "." ] ++ map asLineComment (formatFunctionTypes f) ++ [- RawFailCall (functionDebugName f ++ " is not implemented (see " ++ filename ++ ")")+ RawFailCall (functionDebugName (getCategoryName t) f ++ " is not implemented (see " ++ filename ++ ")") ] asLineComment = NoValueExpression [] . LineComment- common (NativeConcrete t d@(DefinedCategory _ _ pi _ _ fi ms _ _) ta ns em) = fmap (:[]) singleSource where+ common (NativeConcrete t d@(DefinedCategory _ _ _ _ _ ms _ _) ta ns em) = fmap (:[]) singleSource where singleSource = do let filename = sourceFilename (getCategoryName t) ta' <- mergeInternalInheritance ta d@@ -289,18 +278,16 @@ [cp,tp,vp] <- getProcedureScopes ta' em d let (_,tm,_) = partitionByScope dmScope ms disallowTypeMembers tm- let filters = getCategoryFilters t- let filters2 = fi- allFilters <- getFilterMap (getCategoryParams t ++ pi) $ filters ++ filters2+ params <- getCategoryParamSet t let cf = map fst $ psProcedures cp let tf = map fst $ psProcedures tp let vf = map fst $ psProcedures vp (CompiledData req out) <- fmap (addNamespace t) $ concatM [ defineFunctions t cf tf vf, declareInternalGetters t,- defineConcreteCategory r allFilters cf ta' em t d,+ defineConcreteCategory r cf ta' em t d, defineConcreteType tf t,- defineConcreteValue r allFilters vf t d,+ defineConcreteValue r params vf t d, defineCategoryOverrides t cf, defineTypeOverrides t tf, defineValueOverrides t vf,@@ -385,17 +372,18 @@ return $ onlyCode $ "struct " ++ typeName (getCategoryName t) ++ " : public " ++ typeBase ++ " {", fmap indentCompiled $ inlineTypeConstructor t, return declareTypeOverrides,+ return $ declareTypeArgGetters t, return $ indentCompiled $ createParams $ getCategoryParams t, return $ onlyCode $ " " ++ categoryName (getCategoryName t) ++ "& parent;", return $ onlyCode "};" ] - defineConcreteCategory r allFilters fs tm em t d = concatM [+ defineConcreteCategory r fs tm em t d = concatM [ return $ onlyCode $ "struct " ++ categoryName (getCategoryName t) ++ " : public " ++ categoryBase ++ " {", fmap indentCompiled $ inlineCategoryConstructor t d tm em, return declareCategoryOverrides, fmap indentCompiled $ concatM $ map (procedureDeclaration False) fs,- fmap indentCompiled $ concatM $ map (createMemberLazy r allFilters) members,+ fmap indentCompiled $ concatM $ map (createMemberLazy r) members, return $ onlyCode "};" ] where members = filter ((== CategoryScope). dmScope) $ dcMembers d@@ -403,18 +391,18 @@ return $ onlyCode $ "struct " ++ typeName (getCategoryName t) ++ " : public " ++ typeBase ++ " {", fmap indentCompiled $ inlineTypeConstructor t, return declareTypeOverrides,+ return $ declareTypeArgGetters t, fmap indentCompiled $ concatM $ map (procedureDeclaration False) fs, return $ indentCompiled $ createParams $ getCategoryParams t, return $ onlyCode $ " " ++ categoryName (getCategoryName t) ++ "& parent;", return $ onlyCode "};" ]- defineConcreteValue r allFilters fs t d = concatM [+ defineConcreteValue r params fs t d = concatM [ return $ onlyCode $ "struct " ++ valueName (getCategoryName t) ++ " : public " ++ valueBase ++ " {", fmap indentCompiled $ inlineValueConstructor t d, return declareValueOverrides, fmap indentCompiled $ concatM $ map (procedureDeclaration False) fs,- fmap indentCompiled $ concatM $ map (createMember r allFilters t) members,- return $ indentCompiled $ createParams $ dcParams d,+ fmap indentCompiled $ concatM $ map (createMember r params t) members, return $ onlyCode $ " const S<" ++ typeName (getCategoryName t) ++ "> parent;", return $ onlyCodes traceCreation, return $ onlyCode "};"@@ -422,7 +410,7 @@ members = filter ((== ValueScope). dmScope) $ dcMembers d procedures = dcProcedures d traceCreation- | any isTraceCreation $ concat $ map epPragmas procedures = [captureCreationTrace]+ | any isTraceCreation $ concat $ map epPragmas procedures = [captureCreationTrace $ getCategoryName t] | otherwise = [] defineAbstractCategory t = concatM [@@ -436,15 +424,16 @@ return $ onlyCode $ "struct " ++ typeName (getCategoryName t) ++ " : public " ++ typeBase ++ " {", fmap indentCompiled $ inlineTypeConstructor t, return declareTypeOverrides,+ return $ declareTypeArgGetters t, fmap indentCompiled $ concatM $ map (procedureDeclaration True) $ filter ((== TypeScope). sfScope) $ getCategoryFunctions t, return $ onlyCode $ " virtual inline ~" ++ typeName (getCategoryName t) ++ "() {}", return $ indentCompiled $ createParams $ getCategoryParams t, return $ onlyCode $ " " ++ categoryName (getCategoryName t) ++ "& parent;", return $ onlyCode "};" ]- defineAbstractValue t d = concatM [+ defineAbstractValue t = concatM [ return $ onlyCode $ "struct " ++ valueName (getCategoryName t) ++ " : public " ++ valueBase ++ " {",- fmap indentCompiled $ abstractValueConstructor t d,+ fmap indentCompiled $ abstractValueConstructor t, return declareValueOverrides, fmap indentCompiled $ concatM $ map (procedureDeclaration True) $ filter ((== ValueScope). sfScope) $ getCategoryFunctions t, return $ onlyCode $ " virtual inline ~" ++ valueName (getCategoryName t) ++ "() {}",@@ -511,6 +500,7 @@ onlyCode $ "bool " ++ className ++ "::TypeArgsForParent(const TypeCategory& category, std::vector<S<const TypeInstance>>& args) const {", createTypeArgsForParent t, onlyCode $ "}",+ defineTypeArgGetters t, onlyCode $ "ReturnTuple " ++ className ++ "::Dispatch(const S<TypeInstance>& self, const TypeFunction& label, const ParamTuple& params, const ValueTuple& args) {", createFunctionDispatch (getCategoryName t) TypeScope fs, onlyCode $ "}",@@ -528,13 +518,13 @@ ] where className = valueName (getCategoryName t) - createMember r filters t m = do+ createMember r params t m = do m' <- replaceSelfMember (instanceFromCategory t) m- validateGeneralInstance r filters (vtType $ dmType m') <??+ validateGeneralInstance r params (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) <??+ createMemberLazy r m = do+ validateGeneralInstance r Set.empty (vtType $ dmType m) <?? "In creation of " ++ show (dmName m) ++ " at " ++ formatFullContext (dmContext m) return $ onlyCode $ variableLazyType (dmType m) ++ " " ++ variableName (dmName m) ++ ";" @@ -570,24 +560,20 @@ ] inlineValueConstructor t d = do let argParent = "S<" ++ typeName (getCategoryName t) ++ "> p"- let paramsPassed = "const ParamTuple& params" let argsPassed = "const ValueTuple& args"- let allArgs = intercalate ", " [argParent,paramsPassed,argsPassed]+ let allArgs = intercalate ", " [argParent,argsPassed] let initParent = "parent(p)"- let initParams = map (\(i,p) -> paramName (vpParam p) ++ "(params.At(" ++ show i ++ "))") $ zip ([0..] :: [Int]) $ dcParams d let initArgs = map (\(i,m) -> variableName (dmName m) ++ "(" ++ unwrappedArg i m ++ ")") $ zip ([0..] :: [Int]) members- let allInit = intercalate ", " $ initParent:(initParams ++ initArgs)+ let allInit = intercalate ", " $ initParent:initArgs return $ onlyCode $ "inline " ++ valueName (getCategoryName t) ++ "(" ++ allArgs ++ ") : " ++ allInit ++ " {}" where unwrappedArg i m = writeStoredVariable (dmType m) (UnwrappedSingle $ "args.At(" ++ show i ++ ")") members = filter ((== ValueScope). dmScope) $ dcMembers d - abstractValueConstructor t d = do+ abstractValueConstructor t = do let argParent = "S<" ++ typeName (getCategoryName t) ++ "> p"- let paramsPassed = "const ParamTuple& params"- let allArgs = intercalate ", " [argParent,paramsPassed]+ let allArgs = intercalate ", " [argParent] let initParent = "parent(p)"- let initParams = map (\(i,p) -> paramName (vpParam p) ++ "(params.At(" ++ show i ++ "))") $ zip ([0..] :: [Int]) $ dcParams d- let allInit = intercalate ", " $ initParent:initParams+ let allInit = initParent return $ onlyCode $ "inline " ++ valueName (getCategoryName t) ++ "(" ++ allArgs ++ ") : " ++ allInit ++ " {}" customTypeConstructor t = do@@ -599,10 +585,9 @@ return $ onlyCode $ "inline " ++ typeCustom (getCategoryName t) ++ "(" ++ allArgs ++ ") : " ++ allInit ++ " {}" customValueConstructor t = do let argParent = "S<" ++ typeName (getCategoryName t) ++ "> p"- let paramsPassed = "const ParamTuple& params" let argsPassed = "const ValueTuple& args"- let allArgs = intercalate ", " [argParent,paramsPassed,argsPassed]- let allInit = valueName (getCategoryName t) ++ "(p, params)"+ let allArgs = intercalate ", " [argParent,argsPassed]+ let allInit = valueName (getCategoryName t) ++ "(p)" return $ onlyCode $ "inline " ++ valueCustom (getCategoryName t) ++ "(" ++ allArgs ++ ") : " ++ allInit ++ " {}" allowTestsOnly@@ -664,13 +649,14 @@ ts' <- fmap mconcat $ mapCompilerM (compileTestProcedure tm em) ts (include,sel) <- selectTestFromArgv1 $ map tpName ts let (CompiledData req _) = ts' <> sel- let file = testsOnlySourceGuard ++ createMainCommon "testcase" (onlyCodes include <> ts') (argv <> sel)+ let file = testsOnlySourceGuard ++ createMainCommon "testcase" (onlyCodes include <> ts') (argv <> callLog <> sel) return $ CompiledData req file where args' = map escapeChars args argv = onlyCodes [ "const char* argv2[] = { \"testcase\" " ++ concat (map (", " ++) args') ++ " };", "ProgramArgv program_argv(sizeof argv2 / sizeof(char*), argv2);" ]+ callLog = onlyCode "LogCallsToFile call_logger_((argc < 3)? \"\" : argv[2]);" addNamespace :: AnyCategory c -> CompiledData [String] -> CompiledData [String] addNamespace t cs@@ -709,8 +695,7 @@ createFunctionDispatch :: CategoryName -> SymbolScope -> [ScopedFunction c] -> CompiledData [String] createFunctionDispatch n s fs = onlyCodes $ [typedef] ++ concat (map table $ byCategory) ++- concat (map dispatch $ byCategory) ++- [fallback] where+ metaTable ++ select where filtered = filter ((== s) . sfScope) fs flatten f = f:(concat $ map flatten $ sfMerges f) flattened = concat $ map flatten filtered@@ -732,13 +717,20 @@ [" static const CallType " ++ tableName n2 ++ "[] = {"] ++ map (\f -> " &" ++ name f ++ ",") (Set.toList $ Set.fromList $ map sfName fs2) ++ [" };"]- dispatch (n2,_) = [- " if (label.collection == " ++ collectionName n2 ++ ") {",- " if (label.function_num < 0 || label.function_num >= sizeof " ++ tableName n2 ++ " / sizeof(CallType)) {",+ metaTable = [" static DispatchTable<CallType> all_tables[] = {"] +++ map dispatchKeyValue byCategory +++ [" DispatchTable<CallType>(),"," };"]+ dispatchKeyValue (n2,_) = " DispatchTable<CallType>(" ++ collectionName n2 ++ ", " ++ tableName n2 ++ "),"+ select = [+ " const DispatchTable<CallType>* const table = DispatchSelect(label.collection, all_tables);",+ " if (table) {",+ " if (label.function_num < 0 || label.function_num >= table->size) {", " FAIL() << \"Bad function call \" << label;",+ " } else {",+ " return (this->*table->table[label.function_num])(" ++ args ++ ");", " }",- " return (this->*" ++ tableName n2 ++ "[label.function_num])(" ++ args ++ ");",- " }"+ " }",+ fallback ] args | s == CategoryScope = "params, args"@@ -769,22 +761,42 @@ checkCov i p = " if (!TypeInstance::CanConvert(args[" ++ show i ++ "], " ++ paramName p ++ ")) return false;" checkCon i p = " if (!TypeInstance::CanConvert(" ++ paramName p ++ ", args[" ++ show i ++ "])) return false;" +declareTypeArgGetters :: AnyCategory c -> CompiledData [String]+declareTypeArgGetters t = onlyCodes $ map paramGetter (getCategoryName t:refines) where+ refines = map (tiName . vrType) $ getCategoryRefines t+ paramGetter r = " void Params_" ++ show r ++ "(std::vector<S<const TypeInstance>>& args) const;"++defineTypeArgGetters :: AnyCategory c -> CompiledData [String]+defineTypeArgGetters t = onlyCodes $ concat $ map paramGetter (myType:refines) where+ params = map (\p -> (vpParam p,vpVariance p)) $ getCategoryParams t+ myType = (getCategoryName t,map (singleType . JustParamName False . fst) params)+ refines = map (\r -> (tiName r,pValues $ tiParams r)) $ map vrType $ getCategoryRefines t+ paramGetter (r,ps) = [+ "void " ++ typeName (getCategoryName t) ++ "::Params_" ++ show r ++ "(std::vector<S<const TypeInstance>>& args) const {",+ " args = std::vector<S<const TypeInstance>>{" ++ intercalate ", " (map expandLocalType ps) ++ "};",+ "}"+ ]+ createTypeArgsForParent :: AnyCategory c -> CompiledData [String] createTypeArgsForParent t- | isInstanceInterface t = onlyCode $ " return " ++ typeBase ++ "::TypeArgsForParent(category, args);"- | otherwise = onlyCodes $ allCats ++ [" return false;"] where- params = map (\p -> (vpParam p,vpVariance p)) $ getCategoryParams t- myType = (getCategoryName t,map (singleType . JustParamName False . fst) params)- refines = map (\r -> (tiName r,pValues $ tiParams r)) $ map vrType $ getCategoryRefines t- allCats = concat $ map singleCat (myType:refines)- singleCat (t2,ps) = [- " if (&category == &" ++ categoryGetter t2 ++ "()) {",- " args = std::vector<S<const TypeInstance>>{" ++ expanded ++ "};",- " return true;",- " }"- ]- where- expanded = intercalate ", " $ map expandLocalType ps+ | isInstanceInterface t = onlyCode $ " return false;"+ | otherwise = onlyCodes $ [+ " using CallType = void(" ++ className ++ "::*)(std::vector<S<const TypeInstance>>&)const;",+ " static DispatchSingle<CallType> all_calls[] = {"+ ] ++ map dispatchKeyValue ((getCategoryName t):refines) ++ [+ " DispatchSingle<CallType>(),",+ " };",+ " const DispatchSingle<CallType>* const call = DispatchSelect(&category, all_calls);",+ " if (call) {",+ " (this->*call->value)(args);",+ " return true;",+ " }",+ " return false;"+ ] where+ className = typeName $ getCategoryName t+ refines = map (tiName . vrType) $ getCategoryRefines t+ dispatchKeyValue n = " DispatchSingle<CallType>(&" ++ categoryGetter n +++ "(), &" ++ className ++ "::Params_" ++ show n ++ ")," -- Similar to Procedure.expandGeneralInstance but doesn't account for scope. expandLocalType :: GeneralInstance -> String@@ -881,7 +893,7 @@ onlyCodes [ "S<TypeValue> " ++ valueCreator (getCategoryName t) ++ "(S<" ++ typeName (getCategoryName t) ++ "> parent, " ++- "const ParamTuple& params, const ValueTuple& args);"+ "const ValueTuple& args);" ] defineInternalValue :: AnyCategory c -> CompiledData [String]@@ -891,8 +903,8 @@ defineInternalValue2 className t = onlyCodes [ "S<TypeValue> " ++ valueCreator (getCategoryName t) ++ "(S<" ++ typeName (getCategoryName t) ++ "> parent, " ++- "const ParamTuple& params, const ValueTuple& args) {",- " return S_get(new " ++ className ++ "(parent, params, args));",+ "const ValueTuple& args) {",+ " return S_get(new " ++ className ++ "(parent, args));", "}" ]
src/CompilerCxx/LanguageModule.hs view
@@ -76,19 +76,18 @@ tmPublic <- foldM includeNewTypes defaultCategories [cs0,cs1] tmPrivate <- foldM includeNewTypes tmPublic [ps0,ps1] tmTesting <- foldM includeNewTypes tmPrivate [ts0,ts1]- let nsPublic = ns0 `Set.union` ns2- let nsPrivate = ns1 `Set.union` nsPublic- let nsTesting = nsPrivate xxInterfaces <- fmap concat $ collectAllM $- map (generateNativeInterface False) (onlyNativeInterfaces cs1) ++- map (generateNativeInterface False) (onlyNativeInterfaces ps1) ++- map (generateNativeInterface True) (onlyNativeInterfaces ts1)- xxPrivate <- fmap concat $ mapCompilerM (compilePrivate (tmPrivate,nsPrivate) (tmTesting,nsTesting)) xa+ map (generateNativeInterface False nsPublic) (onlyNativeInterfaces cs1) +++ map (generateNativeInterface False nsPrivate) (onlyNativeInterfaces ps1) +++ map (generateNativeInterface True nsPrivate) (onlyNativeInterfaces ts1)+ xxPrivate <- fmap concat $ mapCompilerM (compilePrivate tmPrivate tmTesting) xa xxStreamlined <- fmap concat $ mapCompilerM (streamlined tmTesting) $ nub ss xxVerbose <- fmap concat $ mapCompilerM (verbose tmTesting) $ nub ex let allFiles = xxInterfaces ++ xxPrivate ++ xxStreamlined ++ xxVerbose noDuplicateFiles $ map (\f -> (coFilename f,coNamespace f)) allFiles return allFiles where+ nsPublic = ns0 `Set.union` ns2+ nsPrivate = ns1 `Set.union` nsPublic extensions = Set.fromList $ ex ++ ss testingCats = Set.fromList $ map getCategoryName ts1 onlyNativeInterfaces = filter (not . (`Set.member` extensions) . getCategoryName) . filter (not . isValueConcrete)@@ -96,25 +95,25 @@ streamlined tm n = do checkLocal localCats ([] :: [String]) n (_,t) <- getConcreteCategory tm ([],n)- generateStreamlinedExtension (n `Set.member` testingCats) t+ generateStreamlinedExtension (n `Set.member` testingCats) nsPrivate t verbose tm n = do checkLocal localCats ([] :: [String]) n (_,t) <- getConcreteCategory tm ([],n) generateVerboseExtension (n `Set.member` testingCats) t- compilePrivate (tmPrivate,nsPrivate) (tmTesting,nsTesting) (PrivateSource ns3 testing cs2 ds) = do- let (tm,ns) = if testing- then (tmTesting,nsTesting)- else (tmPrivate,nsPrivate)+ compilePrivate tmPrivate tmTesting (PrivateSource ns3 testing cs2 ds) = do+ let tm = if testing+ then tmTesting+ else tmPrivate let cs = Set.fromList $ map getCategoryName $ if testing then cs2 ++ cs1 ++ ps1 ++ ts1 else cs2 ++ cs1 ++ ps1 tm' <- includeNewTypes tm cs2- let ctx = FileContext testing tm' (ns3 `Set.insert` ns) em+ let ctx = FileContext testing tm' (ns3 `Set.insert` nsPrivate) em checkLocals ds $ Map.keysSet tm' when testing $ checkTests ds (cs1 ++ ps1) let dm = mapDefByName ds checkDefined dm Set.empty $ filter isValueConcrete cs2- xxInterfaces <- fmap concat $ mapCompilerM (generateNativeInterface testing) (filter (not . isValueConcrete) cs2)+ xxInterfaces <- fmap concat $ mapCompilerM (generateNativeInterface testing nsPrivate) (filter (not . isValueConcrete) cs2) xxConcrete <- fmap concat $ mapCompilerM (generateConcrete cs ctx) ds return $ xxInterfaces ++ xxConcrete generateConcrete cs (FileContext testing tm ns em2) d = do
src/CompilerCxx/Naming.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.@@ -33,6 +33,7 @@ functionName, headerFilename, headerStreamlined,+ hiddenVariableName, initializerName, intersectGetter, mainFilename,@@ -104,6 +105,9 @@ variableName :: VariableName -> String variableName v = "Var_" ++ show v +hiddenVariableName :: VariableName -> String+hiddenVariableName v = "Internal_" ++ show v+ initializerName :: VariableName -> String initializerName v = "Init_" ++ show v @@ -146,10 +150,10 @@ callName :: FunctionName -> String callName f = "Call_" ++ show f -functionDebugName :: ScopedFunction c -> String-functionDebugName f- | sfScope f == CategoryScope = show (sfType f) ++ ":" ++ show (sfName f)- | otherwise = show (sfType f) ++ "." ++ show (sfName f)+functionDebugName :: CategoryName -> ScopedFunction c -> String+functionDebugName t f+ | sfScope f == CategoryScope = show t ++ ":" ++ show (sfName f)+ | otherwise = show t ++ "." ++ show (sfName f) functionName :: ScopedFunction c -> String functionName f = "Function_" ++ show (sfType f) ++ "_" ++ show (sfName f)
src/CompilerCxx/Procedure.hs view
@@ -139,7 +139,7 @@ returnType = "ReturnTuple" setProcedureTrace | any isNoTrace pragmas = return []- | otherwise = return [startFunctionTracing ff]+ | otherwise = return [startFunctionTracing (scName ctx) ff] setCreationTrace | not $ any isTraceCreation pragmas = return [] | s /= ValueScope =@@ -158,7 +158,7 @@ | isUnnamedReturns rs2 = [] | otherwise = map (\(i,(t2,n2)) -> nameReturn i (pvType t2) n2) (zip ([0..] :: [Int]) $ zip (pValues rs1) (pValues $ nrNames rs2)) nameReturn i t2 n2- | isPrimType t2 = variableProxyType t2 ++ " " ++ variableName (ovName n2) ++ ";"+ | isPrimitiveType t2 = variableProxyType t2 ++ " " ++ variableName (ovName n2) ++ ";" | otherwise = variableProxyType t2 ++ " " ++ variableName (ovName n2) ++ " = " ++ writeStoredVariable t2 (UnwrappedSingle $ "returns.At(" ++ show i ++ ")") ++ ";"@@ -298,7 +298,7 @@ self <- autoSelfType t1' <- lift $ replaceSelfValueType self t1 -- TODO: Call csAddRequired for t1'. (Maybe needs a helper function.)- lift $ collectAllM_ [validateGeneralInstance r fa (vtType t1'),+ lift $ collectAllM_ [validateGeneralInstance r (Map.keysSet fa) (vtType t1'), checkValueAssignment r fa t2 t1'] csAddVariable (UsedVariable c2 n) (VariableValue c2 LocalScope t1' VariableDefault) csWrite [variableStoredType t1' ++ " " ++ variableName n ++ ";"]@@ -369,7 +369,7 @@ CompilerContext c m [String] a) => VoidExpression c -> CompilerState a m () compileVoidExpression (Conditional ie) = compileIfElifElse ie-compileVoidExpression (Loop l) = compileWhileLoop l+compileVoidExpression (Loop l) = compileIteratedLoop l compileVoidExpression (WithScope s) = compileScopedBlock s compileVoidExpression (LineComment s) = csWrite $ map ("// " ++) $ lines s compileVoidExpression (Unconditional p) = do@@ -407,10 +407,9 @@ return $ ctx:cs compileIfElifElse _ = undefined -compileWhileLoop :: (Ord c, Show c, CollectErrorsM m,- CompilerContext c m [String] a) =>- WhileLoop c -> CompilerState a m ()-compileWhileLoop (WhileLoop c e p u) = do+compileIteratedLoop :: (Ord c, Show c, CollectErrorsM m, CompilerContext c m [String] a) =>+ IteratedLoop c -> CompilerState a m ()+compileIteratedLoop (WhileLoop c e p u) = do ctx0 <- getCleanContext (e',ctx1) <- compileCondition ctx0 c e csInheritReturns [ctx1]@@ -429,6 +428,38 @@ getAndIndentOutput ctx >>= csWrite csWrite $ ["{"] ++ u' ++ ["}"] csWrite ["}"]+compileIteratedLoop (TraverseLoop c1 e c2 a (Procedure c3 ss)) = "In compilation of traverse at " ++ formatFullContext c1 ??> do+ (Positional ts,e') <- compileExpression e+ checkContainer ts+ r <- csResolver+ fa <- csAllFilters+ let [t] = ts+ let autoParam = ParamName "#auto"+ let autoType = singleType $ JustParamName False autoParam+ (Positional [t2]) <- lift $ guessParams r fa (Positional [orderOptionalValue autoType])+ (Positional [autoParam])+ (Positional [InferredInstance c1])+ (Positional [t])+ let currVar = hiddenVariableName $ VariableName "traverse"+ let currType = orderOptionalValue $ fixTypeParams t2+ let currExpr = BuiltinCall [] $ FunctionCall [] BuiltinRequire (Positional []) (Positional [RawExpression (Positional [currType]) (UnwrappedSingle currVar)])+ let currPresent = BuiltinCall [] $ FunctionCall [] BuiltinPresent (Positional []) (Positional [RawExpression (Positional [currType]) (UnwrappedSingle currVar)])+ let callNext = Expression c1 currExpr [ValueCall c1 $ FunctionCall c1 (FunctionName "next") (Positional []) (Positional [])]+ let callGet = Expression c2 currExpr [ValueCall c2 $ FunctionCall c2 (FunctionName "get") (Positional []) (Positional [])]+ (Positional [typeGet],exprNext) <- compileExpression callNext+ when (typeGet /= currType) $ compilerErrorM $ "Unexpected return type from next(): " ++ show typeGet ++ " (expected) " ++ show currType ++ " (actual)"+ let assnGet = Assignment c2 (Positional [a]) callGet+ csAddRequired $ categoriesFromTypes $ vtType currType+ compileStatement $ NoValueExpression [] $ WithScope $ ScopedBlock []+ (Procedure [] [RawCodeLine $ variableStoredType currType ++ " " ++ currVar ++ " = " ++ writeStoredVariable currType e' ++ ";"]) Nothing []+ (NoValueExpression [] $ Loop $ WhileLoop [] (Expression [] currPresent [])+ (Procedure c3 (assnGet:ss))+ (Just $ Procedure [] [RawCodeLine $ currVar ++ " = " ++ writeStoredVariable currType exprNext ++ ";"]))+ where+ checkContainer [_] = return ()+ checkContainer ts =+ compilerErrorM $ "Expected exactly one Order<?> value but got " +++ intercalate ", " (map show ts) compileScopedBlock :: (Ord c, Show c, CollectErrorsM m, CompilerContext c m [String] a) =>@@ -473,7 +504,7 @@ t' <- replaceSelfValueType self t return (c,t',n) createVariable r fa (c,t,n) = do- lift $ validateGeneralInstance r fa (vtType t) <??+ lift $ validateGeneralInstance r (Map.keysSet fa) (vtType t) <?? "In creation of " ++ show n ++ " at " ++ formatFullContext c csWrite [variableStoredType t ++ " " ++ variableName n ++ ";"] showVariable (c,t,n) = do@@ -502,7 +533,7 @@ compileExpression :: (Ord c, Show c, CollectErrorsM m, CompilerContext c m [String] a) =>- Expression c -> CompilerState a m (ExpressionType,ExprValue)+ Expression c -> CompilerState a m (ExpressionType,ExpressionValue) compileExpression = compile where compile (Literal (StringLiteral _ l)) = do csAddRequired (Set.fromList [BuiltinString])@@ -534,7 +565,7 @@ csAddRequired (Set.fromList [BuiltinBool]) return (Positional [boolRequiredValue],UnboxedPrimitive PrimBool "false") compile (Literal (EmptyLiteral _)) = do- return (Positional [emptyValue],UnwrappedSingle "Var_empty")+ return (Positional [emptyType],UnwrappedSingle "Var_empty") compile (Expression _ s os) = do foldl transform (compileExpressionStart s) os compile (UnaryExpression c (FunctionOperator _ (FunctionSpec _ (CategoryFunction c2 cn) fn ps)) e) =@@ -577,7 +608,7 @@ UnboxedPrimitive PrimInt $ "~" ++ useAsUnboxed PrimInt e2) | otherwise = compilerErrorM $ "Cannot use " ++ show t ++ " with unary ~ operator" ++ formatFullContextBrace c- compile (InitializeValue c t ps es) = do+ compile (InitializeValue c t es) = do scope <- csCurrentScope t' <- case scope of CategoryScope -> case t of@@ -590,15 +621,14 @@ Nothing -> return self es' <- sequence $ map compileExpression $ pValues es (ts,es'') <- lift $ getValues es'- csCheckValueInit c t' (Positional ts) ps+ csCheckValueInit c t' (Positional ts) params <- expandParams $ tiParams t'- params2 <- expandParams2 $ ps sameType <- csSameType t' s <- csCurrentScope 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'' ++ ")")+ UnwrappedSingle $ valueCreator (tiName t') ++ "(" ++ typeInstance ++ ", " ++ es'' ++ ")") where getType _ True ValueScope _ = "parent" getType t2 _ _ params = typeCreator (tiName t2) ++ "(" ++ params ++ ")"@@ -627,6 +657,7 @@ then isolateExpression e2 -- Ignore named-return assignments. else compileExpression e2 bindInfix c e1' o e2'+ compile (RawExpression ts e) = return (ts,e) isolateExpression e = do ctx <- getCleanContext (e',ctx') <- lift $ runStateT (compileExpression e) ctx@@ -719,7 +750,7 @@ compileExpressionStart :: (Ord c, Show c, CollectErrorsM m, CompilerContext c m [String] a) =>- ExpressionStart c -> CompilerState a m (ExpressionType,ExprValue)+ ExpressionStart c -> CompilerState a m (ExpressionType,ExpressionValue) compileExpressionStart (NamedVariable (OutputValue c n)) = do let var = UsedVariable c n (VariableValue _ s t _) <- csGetVariable var@@ -745,7 +776,7 @@ t' <- lift $ replaceSelfInstance self (singleType t) r <- csResolver fa <- csAllFilters- lift $ validateGeneralInstance r fa t' <?? "In function call at " ++ formatFullContext c+ lift $ validateGeneralInstanceForCall 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" ++@@ -796,8 +827,8 @@ [t1,t2] <- lift $ mapCompilerM (replaceSelfInstance self) ps' r <- csResolver fa <- csAllFilters- lift $ validateGeneralInstance r fa t1- lift $ validateGeneralInstance r fa t2+ lift $ validateGeneralInstance r (Map.keysSet fa) t1+ lift $ validateGeneralInstance r (Map.keysSet fa) t2 lift $ (checkValueAssignment r fa t0 (ValueType OptionalValue t1)) <?? "In argument to reduce call at " ++ formatFullContext c -- TODO: If t1 -> t2 then just return e without a Reduce call.@@ -844,7 +875,7 @@ [t] <- lift $ mapCompilerM (replaceSelfInstance self) ps' r <- csResolver fa <- csAllFilters- lift $ validateGeneralInstance r fa t+ lift $ validateGeneralInstance r (Map.keysSet fa) t t' <- expandGeneralInstance t csAddRequired $ Set.unions $ map categoriesFromTypes [t] return $ (Positional [formattedRequiredValue],@@ -873,7 +904,7 @@ compileFunctionCall :: (Ord c, Show c, CollectErrorsM m, CompilerContext c m [String] a) => Maybe String -> ScopedFunction c -> FunctionCall c ->- CompilerState a m (ExpressionType,ExprValue)+ CompilerState a m (ExpressionType,ExpressionValue) compileFunctionCall e f (FunctionCall c _ ps es) = message ??> do r <- csResolver fa <- csAllFilters@@ -952,6 +983,23 @@ toInstance p1 (AssignedInstance _ t) = return (p1,t) toInstance p1 (InferredInstance _) = return (p1,singleType $ JustInferredType p1) +guessParams :: (Ord c, Show c, CollectErrorsM m, TypeResolver r) =>+ r -> ParamFilters -> Positional ValueType -> Positional ParamName ->+ Positional (InstanceOrInferred c) -> Positional ValueType -> m (Positional GeneralInstance)+guessParams r fa args params ps ts = do+ args' <- processPairs (\t1 t2 -> return $ PatternMatch Covariant t1 t2) ts args+ pa <- fmap Map.fromList $ processPairs toInstance params ps+ gs <- inferParamTypes r fa pa args'+ gs' <- mergeInferredTypes r fa (Map.fromList $ zip (pValues params) (repeat [])) pa gs+ let pa3 = guessesAsParams gs' `Map.union` pa+ fmap Positional $ mapCompilerM (subPosition pa3) (pValues params) where+ subPosition pa2 p =+ case p `Map.lookup` pa2 of+ Just t -> return t+ Nothing -> compilerErrorM $ "Something went wrong inferring " ++ show p+ toInstance p1 (AssignedInstance _ t) = return (p1,t)+ toInstance p1 (InferredInstance _) = return (p1,singleType $ JustInferredType p1)+ compileMainProcedure :: (Ord c, Show c, CollectErrorsM m) => CategoryMap c -> ExprMap c -> Expression c -> m (CompiledData [String]) compileMainProcedure tm em e = do@@ -1083,7 +1131,7 @@ where autoPositionalCleanup :: (CollectErrorsM m, CompilerContext c m [String] a) =>- [c] -> ExprValue -> CompilerState a m ()+ [c] -> ExpressionValue -> CompilerState a m () autoPositionalCleanup c e = do named <- csIsNamedReturns (CleanupBlock ss _ _ req) <- csGetCleanup JumpReturn
src/Module/CompileMetadata.hs view
@@ -80,6 +80,10 @@ } deriving (Eq,Ord,Show) +getIdentifierCategory :: CategoryIdentifier -> CategoryName+getIdentifierCategory (CategoryIdentifier _ n _) = n+getIdentifierCategory (UnresolvedCategory n) = n+ mergeObjectFiles :: ObjectFile -> ObjectFile -> ObjectFile mergeObjectFiles (CategoryObjectFile c rs1 fs1) (CategoryObjectFile _ rs2 fs2) = CategoryObjectFile c (nub $ rs1 ++ rs2) (nub $ fs1 ++ fs2)
src/Module/ParseMetadata.hs view
@@ -372,7 +372,6 @@ indent "]", "}" ]- writeConfig CompileUnspecified = writeConfig (CompileIncremental []) writeConfig _ = compilerErrorM "Invalid compile mode" parseExprMacro :: TextParser (MacroName,Expression SourceContext)
src/Parser/Common.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.@@ -62,6 +62,7 @@ kwSelf, kwStrong, kwTestcase,+ kwTraverse, kwTrue, kwType, kwTypename,@@ -263,6 +264,9 @@ kwTestcase :: TextParser () kwTestcase = keyword "testcase" +kwTraverse :: TextParser ()+kwTraverse = keyword "traverse"+ kwTrue :: TextParser () kwTrue = keyword "true" @@ -337,6 +341,7 @@ kwScoped, kwStrong, kwTestcase,+ kwTraverse, kwTrue, kwType, kwTypename,
src/Parser/DefinedCategory.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.@@ -25,15 +25,15 @@ import Base.CompilerError import Parser.Common+import Parser.Pragma (autoPragma) import Parser.Procedure ()-import Parser.TextParser+import Parser.TextParser hiding (hidden) import Parser.TypeCategory import Parser.TypeInstance () import Types.DefinedCategory import Types.Procedure import Types.TypeCategory import Types.TypeInstance-import Types.Variance instance ParseFromSource (DefinedCategory SourceContext) where@@ -42,30 +42,23 @@ kwDefine n <- sourceParser sepAfter (string_ "{")+ pragmas <- sepBy singlePragma optionalSpace (ds,rs) <- parseRefinesDefines- (pi,fi) <- parseInternalParams <|> return ([],[]) (ms,ps,fs) <- parseMemberProcedureFunction n sepAfter (string_ "}")- return $ DefinedCategory [c] n pi ds rs fi ms ps fs+ return $ DefinedCategory [c] n pragmas ds rs ms ps fs where parseRefinesDefines = fmap merge2 $ sepBy refineOrDefine optionalSpace+ singlePragma = readOnly <|> hidden+ readOnly = autoPragma "ReadOnly" $ Right parseAt where+ parseAt c = do+ vs <- labeled "variable names" $ sepBy sourceParser (sepAfter $ string ",")+ return $ MembersReadOnly [c] vs+ hidden = autoPragma "Hidden" $ Right parseAt where+ parseAt c = do+ vs <- labeled "variable names" $ sepBy sourceParser (sepAfter $ string ",")+ return $ MembersHidden [c] vs refineOrDefine = labeled "refine or define" $ put12 singleRefine <|> put22 singleDefine- parseInternalParams = labeled "internal params" $ do- kwTypes- pi <- between (sepAfter $ string_ "<")- (sepAfter $ string_ ">")- (sepBy singleParam (sepAfter $ string_ ","))- fi <- parseInternalFilters- return (pi,fi)- parseInternalFilters = do- try $ sepAfter (string_ "{")- fi <- parseFilters- sepAfter (string_ "}")- return fi- singleParam = labeled "param declaration" $ do- c <- getSourceContext- n <- sourceParser- return $ ValueParam [c] n Invariant instance ParseFromSource (DefinedMember SourceContext) where sourceParser = labeled "defined member" $ do
src/Parser/Procedure.hs view
@@ -225,18 +225,30 @@ p <- between (sepAfter $ string_ "{") (sepAfter $ string_ "}") sourceParser return $ ElseStatement [c] p -instance ParseFromSource (WhileLoop SourceContext) where- sourceParser = labeled "while" $ do- c <- getSourceContext- kwWhile- i <- between (sepAfter $ string_ "(") (sepAfter $ string_ ")") sourceParser- p <- between (sepAfter $ string_ "{") (sepAfter $ string_ "}") sourceParser- u <- fmap Just parseUpdate <|> return Nothing- return $ WhileLoop [c] i p u- where- parseUpdate = do- kwUpdate- between (sepAfter $ string_ "{") (sepAfter $ string_ "}") sourceParser+instance ParseFromSource (IteratedLoop SourceContext) where+ sourceParser = while <|> trav where+ while = labeled "while" $ do+ c <- getSourceContext+ kwWhile+ i <- between (sepAfter $ string_ "(") (sepAfter $ string_ ")") sourceParser+ p <- between (sepAfter $ string_ "{") (sepAfter $ string_ "}") sourceParser+ u <- fmap Just parseUpdate <|> return Nothing+ return $ WhileLoop [c] i p u+ where+ parseUpdate = do+ kwUpdate+ between (sepAfter $ string_ "{") (sepAfter $ string_ "}") sourceParser+ trav = labeled "traverse" $ do+ c1 <- getSourceContext+ kwTraverse+ sepAfter_ $ string "("+ e <- sourceParser+ sepAfter_ $ string "->"+ c2 <- getSourceContext+ a <- sourceParser+ sepAfter_ $ string ")"+ p <- between (sepAfter $ string_ "{") (sepAfter $ string_ "}") sourceParser+ return $ TraverseLoop [c1] e [c2] a p instance ParseFromSource (ScopedBlock SourceContext) where sourceParser = scoped <|> justCleanup where@@ -417,19 +429,9 @@ t2 <- (paramSelf >> return Nothing) <|> fmap Just sourceParser sepAfter (labeled "@value initializer" $ string_ "{") return t2- withParams c t <|> withoutParams c t- withParams c t = do- kwTypes- ps <- between (sepAfter $ string_ "<")- (sepAfter $ string_ ">")- (sepBy sourceParser (sepAfter $ string_ ","))- as <- (sepAfter (string_ ",") >> sepBy sourceParser (sepAfter $ string_ ",")) <|> return []- sepAfter (string_ "}")- return $ InitializeValue [c] t (Positional ps) (Positional as)- withoutParams c t = do as <- sepBy sourceParser (sepAfter $ string_ ",") sepAfter (string_ "}")- return $ InitializeValue [c] t (Positional []) (Positional as)+ return $ InitializeValue [c] t (Positional as) instance ParseFromSource (FunctionQualifier SourceContext) where -- TODO: This is probably better done iteratively.
src/Parser/TypeCategory.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2019 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.@@ -46,20 +46,19 @@ n <- sourceParser ps <- parseCategoryParams open- (rs,vs) <- parseRefinesFilters+ rs <- parseCategoryRefines fs <- flip sepBy optionalSpace $ parseScopedFunction (return ValueScope) (return n) close- return $ ValueInterface [c] NoNamespace n ps rs vs fs+ return $ ValueInterface [c] NoNamespace n ps rs fs parseInstance = labeled "type interface" $ do c <- getSourceContext try $ kwType >> kwInterface n <- sourceParser ps <- parseCategoryParams open- vs <- parseFilters fs <- flip sepBy optionalSpace $ parseScopedFunction (return TypeScope) (return n) close- return $ InstanceInterface [c] NoNamespace n ps vs fs+ return $ InstanceInterface [c] NoNamespace n ps fs parseConcrete = labeled "concrete type" $ do c <- getSourceContext kwConcrete@@ -139,11 +138,6 @@ parseFilters :: TextParser [ParamFilter SourceContext] parseFilters = sepBy singleFilter optionalSpace--parseRefinesFilters :: TextParser ([ValueRefine SourceContext],[ParamFilter SourceContext])-parseRefinesFilters = parsed >>= return . merge2 where- parsed = sepBy anyType optionalSpace- anyType = labeled "refine or param filter" $ put12 singleRefine <|> put22 singleFilter parseRefinesDefinesFilters :: TextParser ([ValueRefine SourceContext],[ValueDefine SourceContext],[ParamFilter SourceContext])
src/Test/Common.hs view
@@ -31,11 +31,12 @@ forceParse, loadFile, parseFilterMap,- parseTheTest,+ parseTestWithFilters, readMulti, readSingle, readSingleWith, runAllTests,+ showFilters, showParams, ) where @@ -93,27 +94,35 @@ fs2 <- mapCompilerM (readSingle "(string)") fs return (ParamName n,fs2) -parseTheTest :: ParseFromSource a => [(String,[String])] -> [String] -> TrackedErrors ([a],ParamFilters)-parseTheTest pa xs = do+parseTestWithFilters :: ParseFromSource a => [(String,[String])] -> [String] -> TrackedErrors ([a],ParamFilters)+parseTestWithFilters pa xs = do ts <- mapCompilerM (readSingle "(string)") xs pa2 <- parseFilterMap pa return (ts,pa2) -showParams :: [(String,[String])] -> String-showParams pa = "[" ++ intercalate "," (concat $ map expand pa) ++ "]" where+parseTestWithParams :: ParseFromSource a => [String] -> [String] -> TrackedErrors ([a],Set.Set ParamName)+parseTestWithParams ps xs = do+ ts <- mapCompilerM (readSingle "(string)") xs+ return (ts,Set.fromList $ map ParamName ps)++showFilters :: [(String,[String])] -> String+showFilters pa = "[" ++ intercalate "," (concat $ map expand pa) ++ "]" where expand (n,ps) = map (\p -> n ++ " " ++ p) ps -checkTypeSuccess :: TypeResolver r => r -> [(String,[String])] -> String -> TrackedErrors ()+showParams :: [String] -> String+showParams ps = "[" ++ intercalate "," ps ++ "]"++checkTypeSuccess :: TypeResolver r => r -> [String] -> String -> TrackedErrors () checkTypeSuccess r pa x = do- ([t],pa2) <- parseTheTest pa [x]+ ([t],pa2) <- parseTestWithParams pa [x] check $ validateGeneralInstance r pa2 t where prefix = x ++ " " ++ showParams pa check x2 = x2 <!! prefix ++ ":" -checkTypeFail :: TypeResolver r => r -> [(String,[String])] -> String -> TrackedErrors ()+checkTypeFail :: TypeResolver r => r -> [String] -> String -> TrackedErrors () checkTypeFail r pa x = do- ([t],pa2) <- parseTheTest pa [x]+ ([t],pa2) <- parseTestWithParams pa [x] check $ validateGeneralInstance r pa2 t where prefix = x ++ " " ++ showParams pa@@ -122,17 +131,17 @@ | isCompilerError c = return () | otherwise = compilerErrorM $ prefix ++ ": Expected failure\n" -checkDefinesSuccess :: TypeResolver r => r -> [(String,[String])] -> String -> TrackedErrors ()+checkDefinesSuccess :: TypeResolver r => r -> [String] -> String -> TrackedErrors () checkDefinesSuccess r pa x = do- ([t],pa2) <- parseTheTest pa [x]+ ([t],pa2) <- parseTestWithParams pa [x] check $ validateDefinesInstance r pa2 t where prefix = x ++ " " ++ showParams pa check x2 = x2 <!! prefix ++ ":" -checkDefinesFail :: TypeResolver r => r -> [(String,[String])] -> String -> TrackedErrors ()+checkDefinesFail :: TypeResolver r => r -> [String] -> String -> TrackedErrors () checkDefinesFail r pa x = do- ([t],pa2) <- parseTheTest pa [x]+ ([t],pa2) <- parseTestWithParams pa [x] check $ validateDefinesInstance r pa2 t where prefix = x ++ " " ++ showParams pa
src/Test/DefinedCategory.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2019 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.@@ -31,9 +31,7 @@ tests :: [IO (TrackedErrors ())] tests = [ checkParseSuccess ("testfiles" </> "definitions.0rx"),- checkParseSuccess ("testfiles" </> "internal_inheritance.0rx"),- checkParseSuccess ("testfiles" </> "internal_params.0rx"),- checkParseSuccess ("testfiles" </> "internal_filters.0rx")+ checkParseSuccess ("testfiles" </> "internal_inheritance.0rx") ] checkParseSuccess :: String -> IO (TrackedErrors ())@@ -55,4 +53,4 @@ check c | isCompilerError c = return () | otherwise = compilerErrorM $ "Parse " ++ f ++ ": Expected failure but got\n" ++- show (getCompilerSuccess c) ++ "\n"+ show (getCompilerSuccess c) ++ "\n"
src/Test/ParseMetadata.hs view
@@ -353,7 +353,7 @@ ] }, - checkWriteFail "compile mode" $ ExecuteTests { etInclude = [] },+ checkWriteFail "compile mode" $ ExecuteTests { etInclude = [], etCallLog = Nothing }, checkWriteFail "compile mode" $ CompileRecompile, checkWriteFail "compile mode" $ CompileRecompileRecursive, checkWriteFail "compile mode" $ CreateTemplates,
src/Test/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.@@ -65,13 +65,13 @@ checkShortParseSuccess "@type interface Type {}", checkShortParseFail "@type interface Type { refines T }", checkShortParseFail "@type interface Type { defines T }",- checkShortParseSuccess "@type interface Type<#x> { #x allows T }",+ checkShortParseFail "@type interface Type<#x> { #x allows T }", checkShortParseSuccess "@value interface Type<#x> {}", checkShortParseSuccess "@value interface Type {}", checkShortParseSuccess "@value interface Type { refines T }", checkShortParseFail "@value interface Type { defines T }",- checkShortParseSuccess "@value interface Type<#x> { #x allows T }",+ checkShortParseFail "@value interface Type<#x> { #x allows T }", checkShortParseSuccess "@value interface Type { call () -> (#self) }", checkShortParseFail "@value interface Type<#self> {}",@@ -98,23 +98,23 @@ checkOperationSuccess ("testfiles" </> "concrete_refines_value.0rx") (checkConnectedTypes $ Map.fromList [- (CategoryName "Parent2",InstanceInterface [] NoNamespace (CategoryName "Parent2") [] [] [])+ (CategoryName "Parent2",InstanceInterface [] NoNamespace (CategoryName "Parent2") [] []) ]), checkOperationFail ("testfiles" </> "concrete_refines_value.0rx") (checkConnectedTypes $ Map.fromList [- (CategoryName "Parent",InstanceInterface [] NoNamespace (CategoryName "Parent") [] [] [])+ (CategoryName "Parent",InstanceInterface [] NoNamespace (CategoryName "Parent") [] []) ]), checkOperationSuccess ("testfiles" </> "partial.0rx") (checkConnectedTypes $ Map.fromList [- (CategoryName "Parent",ValueInterface [] NoNamespace (CategoryName "Parent") [] [] [] [])+ (CategoryName "Parent",ValueInterface [] NoNamespace (CategoryName "Parent") [] [] []) ]), checkOperationFail ("testfiles" </> "partial.0rx") (checkConnectedTypes $ Map.fromList [- (CategoryName "Parent",InstanceInterface [] NoNamespace (CategoryName "Parent") [] [] [])+ (CategoryName "Parent",InstanceInterface [] NoNamespace (CategoryName "Parent") [] []) ]), checkOperationFail ("testfiles" </> "partial.0rx")@@ -165,7 +165,7 @@ ("testfiles" </> "flatten.0rx") (\ts -> do existing <- return $ Map.fromList [- (CategoryName "Parent2",InstanceInterface [] NoNamespace (CategoryName "Parent2") [] [] [])+ (CategoryName "Parent2",InstanceInterface [] NoNamespace (CategoryName "Parent2") [] []) ] ts2 <- topoSortCategories existing ts flattenAllConnections existing ts2),@@ -173,7 +173,7 @@ ("testfiles" </> "flatten.0rx") (\ts -> do existing <- return $ Map.fromList [- (CategoryName "Parent",InstanceInterface [] NoNamespace (CategoryName "Parent") [] [] [])+ (CategoryName "Parent",InstanceInterface [] NoNamespace (CategoryName "Parent") [] []) ] topoSortCategories existing ts), @@ -184,11 +184,11 @@ (CategoryName "Parent", ValueInterface [] NoNamespace (CategoryName "Parent") [] [ValueRefine [] $ TypeInstance (CategoryName "Object1") (Positional []),- ValueRefine [] $ TypeInstance (CategoryName "Object2") (Positional [])] [] []),+ ValueRefine [] $ TypeInstance (CategoryName "Object2") (Positional [])] []), -- NOTE: Object1 deliberately excluded here so that we catch -- unnecessary recursion in existing categories. (CategoryName "Object2",- ValueInterface [] NoNamespace (CategoryName "Object2") [] [] [] [])+ ValueInterface [] NoNamespace (CategoryName "Object2") [] [] []) ] ts2 <- topoSortCategories existing ts ts3 <- flattenAllConnections existing ts2@@ -214,12 +214,12 @@ checkOperationSuccess ("testfiles" </> "concrete_refines_value.0rx") (checkParamVariances $ Map.fromList [- (CategoryName "Parent2",InstanceInterface [] NoNamespace (CategoryName "Parent2") [] [] [])+ (CategoryName "Parent2",InstanceInterface [] NoNamespace (CategoryName "Parent2") [] []) ]), checkOperationFail ("testfiles" </> "concrete_refines_value.0rx") (checkParamVariances $ Map.fromList [- (CategoryName "Parent",InstanceInterface [] NoNamespace (CategoryName "Parent") [] [] [])+ (CategoryName "Parent",InstanceInterface [] NoNamespace (CategoryName "Parent") [] []) ]), checkOperationSuccess@@ -228,7 +228,7 @@ (CategoryName "Parent", ValueInterface [] NoNamespace (CategoryName "Parent") [ValueParam [] (ParamName "#w") Contravariant,- ValueParam [] (ParamName "#z") Covariant] [] [] [])+ ValueParam [] (ParamName "#z") Covariant] [] []) ]), checkOperationFail ("testfiles" </> "partial_params.0rx")@@ -236,7 +236,7 @@ (CategoryName "Parent", ValueInterface [] NoNamespace (CategoryName "Parent") [ValueParam [] (ParamName "#w") Invariant,- ValueParam [] (ParamName "#z") Covariant] [] [] [])+ ValueParam [] (ParamName "#z") Covariant] [] []) ]), checkOperationFail ("testfiles" </> "partial_params.0rx")@@ -244,7 +244,7 @@ (CategoryName "Parent", ValueInterface [] NoNamespace (CategoryName "Parent") [ValueParam [] (ParamName "#w") Contravariant,- ValueParam [] (ParamName "#z") Invariant] [] [] [])+ ValueParam [] (ParamName "#z") Invariant] [] []) ]), checkOperationSuccess@@ -358,56 +358,6 @@ [] ]), - checkOperationSuccess- ("testfiles" </> "value_interface.0rx")- (\ts -> do- rs <- getTypeFilters ts "Type<#a,#b,#c,#d,#e,#f>"- checkPaired containsExactly rs [- ["allows Parent"],- ["requires Type2<#a>"],- ["defines Equals<#c>"],- [],- [],- []- ]),- checkOperationSuccess- ("testfiles" </> "value_interface.0rx")- (\ts -> do- rs <- getTypeFilters ts "Type<Type<#t>,#b,Type3<#x>,#d,#e,#f>"- checkPaired containsExactly rs [- ["allows Parent"],- ["requires Type2<Type<#t>>"],- ["defines Equals<Type3<#x>>"],- [],- [],- []- ]),-- checkOperationSuccess- ("testfiles" </> "type_interface.0rx")- (\ts -> do- rs <- getTypeDefinesFilters ts "Type<#a,#b,#c,#d,#e,#f>"- checkPaired containsExactly rs [- ["allows Parent"],- ["requires Type2<#a>"],- ["defines Equals<#c>"],- [],- [],- []- ]),- checkOperationSuccess- ("testfiles" </> "type_interface.0rx")- (\ts -> do- rs <- getTypeDefinesFilters ts "Type<Type<#t>,#b,Type3<#x>,#d,#e,#f>"- checkPaired containsExactly rs [- ["allows Parent"],- ["requires Type2<Type<#t>>"],- ["defines Equals<Type3<#x>>"],- [],- [],- []- ]),- -- TODO: Clean these tests up. checkOperationSuccess ("testfiles" </> "flatten.0rx")@@ -481,7 +431,7 @@ ta <- flattenAllConnections Map.empty ts2 >>= declareAllTypes Map.empty let r = CategoryResolver ta checkTypeSuccess r [] "Value0<Value1,Value2>"),- checkOperationFail+ checkOperationSuccess ("testfiles" </> "filters.0rx") (\ts -> do ts2 <- topoSortCategories Map.empty ts@@ -495,14 +445,14 @@ ta <- flattenAllConnections Map.empty ts2 >>= declareAllTypes Map.empty let r = CategoryResolver ta checkTypeSuccess r [] "Value0<Value3,Value2>"),- checkOperationFail+ checkOperationSuccess ("testfiles" </> "filters.0rx") (\ts -> do ts2 <- topoSortCategories Map.empty ts ta <- flattenAllConnections Map.empty ts2 >>= declareAllTypes Map.empty let r = CategoryResolver ta checkTypeSuccess r- [("#x",[]),("#y",[])]+ ["#x","#y"] "Value0<#x,#y>"), checkOperationSuccess ("testfiles" </> "filters.0rx")@@ -511,8 +461,7 @@ ta <- flattenAllConnections Map.empty ts2 >>= declareAllTypes Map.empty let r = CategoryResolver ta checkTypeSuccess r- [("#x",["allows #y","requires Function<#x,#y>"]),- ("#y",["requires #x","defines Equals<#y>"])]+ ["#x","#y"] "Value0<#x,#y>"), checkOperationSuccess ("testfiles" </> "filters.0rx")@@ -521,74 +470,19 @@ ta <- flattenAllConnections Map.empty ts2 >>= declareAllTypes Map.empty let r = CategoryResolver ta checkTypeSuccess r- [("#x",["allows Value2","requires Function<#x,Value2>"])]+ ["#x","#y"] "Value0<#x,Value2>"),- checkOperationFail+ checkOperationSuccess ("testfiles" </> "filters.0rx") (\ts -> do ts2 <- topoSortCategories Map.empty ts ta <- flattenAllConnections Map.empty ts2 >>= declareAllTypes Map.empty let r = CategoryResolver ta checkTypeSuccess r- [("#x",["allows Value2","requires Function<#x,Value2>"]),- ("#y",["requires #x","defines Equals<#y>"])]+ ["#x","#y"] "Value0<#x,#y>"), checkOperationSuccess- ("testfiles" </> "concrete_instances.0rx")- (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- ts3 <- flattenAllConnections defaultCategories ts2- checkCategoryInstances defaultCategories ts3),- checkOperationFail- ("testfiles" </> "concrete_missing_define.0rx")- (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- ts3 <- flattenAllConnections defaultCategories ts2- checkCategoryInstances defaultCategories ts3),- checkOperationFail- ("testfiles" </> "concrete_missing_refine.0rx")- (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- ts3 <- flattenAllConnections defaultCategories ts2- checkCategoryInstances defaultCategories ts3),- checkOperationSuccess- ("testfiles" </> "value_instances.0rx")- (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- ts3 <- flattenAllConnections defaultCategories ts2- checkCategoryInstances defaultCategories ts3),- checkOperationFail- ("testfiles" </> "value_missing_define.0rx")- (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- ts3 <- flattenAllConnections defaultCategories ts2- checkCategoryInstances defaultCategories ts3),- checkOperationFail- ("testfiles" </> "value_missing_refine.0rx")- (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- ts3 <- flattenAllConnections defaultCategories ts2- checkCategoryInstances defaultCategories ts3),- checkOperationSuccess- ("testfiles" </> "type_instances.0rx")- (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- ts3 <- flattenAllConnections defaultCategories ts2- checkCategoryInstances defaultCategories ts3),- checkOperationFail- ("testfiles" </> "type_missing_define.0rx")- (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- ts3 <- flattenAllConnections defaultCategories ts2- checkCategoryInstances defaultCategories ts3),- checkOperationFail- ("testfiles" </> "type_missing_refine.0rx")- (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- ts3 <- flattenAllConnections defaultCategories ts2- checkCategoryInstances defaultCategories ts3),- checkOperationSuccess ("testfiles" </> "requires_concrete.0rx") (\ts -> do ts2 <- topoSortCategories defaultCategories ts@@ -641,7 +535,7 @@ ("testfiles" </> "flatten.0rx") (\ts -> do let tm0 = Map.fromList [- (CategoryName "Parent2",InstanceInterface [] NoNamespace (CategoryName "Parent2") [] [] [])+ (CategoryName "Parent2",InstanceInterface [] NoNamespace (CategoryName "Parent2") [] []) ] tm <- includeNewTypes tm0 ts rs <- getRefines tm "Child"@@ -662,30 +556,15 @@ ("testfiles" </> "function_bad_filter_param.0rx") (\ts -> checkCategoryInstances defaultCategories ts), checkOperationFail- ("testfiles" </> "function_bad_allows_type.0rx")- (\ts -> checkCategoryInstances defaultCategories ts),- checkOperationFail ("testfiles" </> "function_bad_allows_variance.0rx") (\ts -> checkCategoryInstances defaultCategories ts), checkOperationFail- ("testfiles" </> "function_bad_requires_type.0rx")- (\ts -> checkCategoryInstances defaultCategories ts),- checkOperationFail ("testfiles" </> "function_bad_requires_variance.0rx") (\ts -> checkCategoryInstances defaultCategories ts), checkOperationFail- ("testfiles" </> "function_bad_defines_type.0rx")- (\ts -> checkCategoryInstances defaultCategories ts),- checkOperationFail ("testfiles" </> "function_bad_defines_variance.0rx") (\ts -> checkCategoryInstances defaultCategories ts), checkOperationFail- ("testfiles" </> "function_bad_arg.0rx")- (\ts -> checkCategoryInstances defaultCategories ts),- checkOperationFail- ("testfiles" </> "function_bad_return.0rx")- (\ts -> checkCategoryInstances defaultCategories ts),- checkOperationFail ("testfiles" </> "weak_arg.0rx") (\ts -> checkCategoryInstances defaultCategories ts), checkOperationFail@@ -695,13 +574,13 @@ checkOperationSuccess ("testfiles" </> "function_filters_satisfied.0rx") (\ts -> checkCategoryInstances defaultCategories ts),- checkOperationFail+ checkOperationSuccess ("testfiles" </> "function_requires_missed.0rx") (\ts -> checkCategoryInstances defaultCategories ts),- checkOperationFail+ checkOperationSuccess ("testfiles" </> "function_allows_missed.0rx") (\ts -> checkCategoryInstances defaultCategories ts),- checkOperationFail+ checkOperationSuccess ("testfiles" </> "function_defines_missed.0rx") (\ts -> checkCategoryInstances defaultCategories ts), @@ -724,23 +603,23 @@ checkOperationSuccess ("testfiles" </> "valid_filter_variance.0rx") (\ts -> checkParamVariances defaultCategories ts),- checkOperationFail- ("testfiles" </> "bad_allows_variance_right.0rx")+ checkOperationSuccess+ ("testfiles" </> "allows_variance_right.0rx") (\ts -> checkParamVariances defaultCategories ts),- checkOperationFail- ("testfiles" </> "bad_defines_variance_right.0rx")+ checkOperationSuccess+ ("testfiles" </> "defines_variance_right.0rx") (\ts -> checkParamVariances defaultCategories ts),- checkOperationFail- ("testfiles" </> "bad_requires_variance_right.0rx")+ checkOperationSuccess+ ("testfiles" </> "requires_variance_right.0rx") (\ts -> checkParamVariances defaultCategories ts),- checkOperationFail- ("testfiles" </> "bad_allows_variance_left.0rx")+ checkOperationSuccess+ ("testfiles" </> "allows_variance_left.0rx") (\ts -> checkParamVariances defaultCategories ts),- checkOperationFail- ("testfiles" </> "bad_defines_variance_left.0rx")+ checkOperationSuccess+ ("testfiles" </> "defines_variance_left.0rx") (\ts -> checkParamVariances defaultCategories ts),- checkOperationFail- ("testfiles" </> "bad_requires_variance_left.0rx")+ checkOperationSuccess+ ("testfiles" </> "requires_variance_left.0rx") (\ts -> checkParamVariances defaultCategories ts), checkOperationFail@@ -808,9 +687,6 @@ 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 ())),@@ -1008,6 +884,23 @@ [("#x","all")]), checkOperationSuccess+ ("testfiles" </> "inference.0rx")+ (\ts -> do+ tm <- includeNewTypes defaultCategories ts+ checkInferenceSuccess tm+ [("#x",[])] ["#x"]+ [("Interface1<all>","Interface1<#x>")]+ [("#x","all")]),+ checkOperationSuccess+ ("testfiles" </> "inference.0rx")+ (\ts -> do+ tm <- includeNewTypes defaultCategories ts+ checkInferenceSuccess tm+ [("#x",[])] ["#x"]+ [("Interface2<any>","Interface2<#x>")]+ [("#x","any")]),++ checkOperationSuccess ("testfiles" </> "delayed_merging.0rx") (\ts -> do tm <- includeNewTypes defaultCategories ts@@ -1206,7 +1099,7 @@ scrapeAllRefines :: [AnyCategory c] -> [(String, String)] scrapeAllRefines = map (show *** show) . concat . map scrapeSingle where- scrapeSingle (ValueInterface _ _ n _ rs _ _) = map ((,) n . vrType) rs+ scrapeSingle (ValueInterface _ _ n _ rs _) = map ((,) n . vrType) rs scrapeSingle (ValueConcrete _ _ n _ rs _ _ _) = map ((,) n . vrType) rs scrapeSingle _ = [] @@ -1291,7 +1184,7 @@ checkInferenceSuccess :: CategoryMap SourceContext -> [(String, [String])] -> [String] -> [(String,String)] -> [(String,String)] -> TrackedErrors () checkInferenceSuccess tm pa is ts gs = checkInferenceCommon check tm pa is ts gs where- prefix = show ts ++ " " ++ showParams pa+ prefix = show ts ++ " " ++ showFilters pa check gs2 c | isCompilerError c = compilerErrorM $ prefix ++ ":\n" ++ show (getCompilerWarnings c) ++ show (getCompilerError c) | otherwise = getCompilerSuccess c `containsExactly` gs2@@ -1299,7 +1192,7 @@ checkInferenceFail :: CategoryMap SourceContext -> [(String, [String])] -> [String] -> [(String,String)] -> TrackedErrors () checkInferenceFail tm pa is ts = checkInferenceCommon check tm pa is ts [] where- prefix = show ts ++ " " ++ showParams pa+ prefix = show ts ++ " " ++ showFilters pa check _ c | isCompilerError c = return () | otherwise = compilerErrorM $ prefix ++ ": Expected failure\n"
src/Test/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.@@ -414,19 +414,19 @@ [] "Type4<Type0>", return $ checkTypeSuccess Resolver- [("#x",["allows Type0"])]+ ["#x"] "Type4<[#x&Type0]>", return $ checkTypeSuccess Resolver- [("#x",["allows Type0"])]+ ["#x"] "Type4<[#x|Type0]>", return $ checkTypeSuccess Resolver- [("#x",["allows Type0"])]+ ["#x"] "Type4<[#x|Type3]>", return $ checkTypeFail Resolver [] "Type5<#x>", return $ checkTypeSuccess Resolver- [("#x",[])]+ ["#x"] "Type5<#x>", checkConvertSuccess@@ -547,69 +547,41 @@ "optional Type3", return $ checkTypeSuccess Resolver- [("#x",[])]+ ["#x"] "#x",- return $ checkTypeFail Resolver- [("#x",[])]- "Type1<#x>",- return $ checkTypeFail Resolver- [("#x",["requires Type3"])]- "Type1<#x>",- return $ checkTypeFail Resolver- [("#x",["defines Instance0"])]+ return $ checkTypeSuccess Resolver+ ["#x"] "Type1<#x>",- return $ checkTypeFail Resolver+ return $ checkTypeSuccess Resolver [] "Type1<all>", return $ checkTypeSuccess Resolver- [("#x",["requires Type3","defines Instance0"])]+ ["#x"] "Type1<#x>", return $ checkTypeSuccess Resolver [] "Type1<Type3>",- return $ checkTypeFail Resolver+ return $ checkTypeSuccess Resolver [] "Type1<Type1<Type3>>", return $ checkTypeSuccess Resolver [] "Type2<Type0,Type0,Type0>",- return $ checkTypeFail Resolver+ return $ checkTypeSuccess Resolver [] "Type2<all,Type0,Type0>",- return $ checkTypeFail Resolver+ return $ checkTypeSuccess Resolver [] "Type2<any,Type0,Type0>", return $ checkTypeSuccess Resolver [] "Type4<any>",- return $ checkTypeFail Resolver+ return $ checkTypeSuccess Resolver [] "Type4<all>", return $ checkTypeSuccess Resolver- [("#x",["defines Instance1<Type0>",- "defines Instance1<#x>",- "defines Instance1<Type3>"])]- "Type2<#x,#x,#x>",- return $ checkTypeFail Resolver- [("#x",["defines Instance1<#x>",- "defines Instance1<Type3>"])]- "Type2<#x,#x,#x>",- return $ checkTypeFail Resolver- [("#x",["defines Instance1<Type0>",- "defines Instance1<Type3>"])]- "Type2<#x,#x,#x>",- return $ checkTypeSuccess Resolver- [("#x",["defines Instance1<Type0>",- "defines Instance1<#x>"])]- "Type2<#x,#x,#x>",- return $ checkTypeSuccess Resolver- [("#x",["allows Type0", -- Type0 -> #x implies Type3 -> #x- "defines Instance1<#x>"])]- "Type2<#x,#x,#x>",- return $ checkTypeFail Resolver- [("#x",["allows Type3", -- Type3 -> #x doesn't imply Type0 -> #x- "defines Instance1<#x>"])]+ ["#x"] "Type2<#x,#x,#x>", return $ checkTypeSuccess Resolver@@ -619,7 +591,7 @@ [] "Type5<#x>", return $ checkTypeSuccess Resolver- [("#x",[])]+ ["#x"] "Type5<#x>", return $ checkTypeSuccess Resolver@@ -629,22 +601,22 @@ [] "[Type4<Type0>&Type1<Type3>]", return $ checkTypeSuccess Resolver- [("#x",[])]+ ["#x"] "[Type5<#x>|Type1<Type3>]", return $ checkTypeSuccess Resolver- [("#x",[])]+ ["#x"] "[Type5<#x>&Type1<Type3>]", return $ checkTypeSuccess Resolver- [("#x",[])]+ ["#x"] "[#x|Type1<Type3>]", return $ checkTypeSuccess Resolver- [("#x",[])]+ ["#x"] "[#x&Type1<Type3>]", return $ checkTypeFail Resolver- [("#x",[])]+ ["#x"] "[Type4<Type0>|Instance0]", return $ checkTypeFail Resolver- [("#x",[])]+ ["#x"] "[Type4<Type0>&Instance0]", return $ checkTypeSuccess Resolver@@ -654,20 +626,17 @@ [] "[[Type4<Type0>|Type1<Type3>]&Type1<Type3>]", return $ checkTypeSuccess Resolver- [("#x",[])]+ ["#x"] "[[Type4<Type0>&#x]|Type1<Type3>]", return $ checkTypeSuccess Resolver- [("#x",[])]+ ["#x"] "[[Type4<Type0>|#x]&Type1<Type3>]", - return $ checkDefinesFail Resolver- [("#x",[])]- "Instance1<#x>", return $ checkDefinesSuccess Resolver- [("#x",["requires Type3"])]+ ["#x"] "Instance1<#x>", return $ checkDefinesFail Resolver- [("#x",["defines Instance1<#x>"])]+ [] "Instance1<#x>", return $ checkDefinesSuccess Resolver []@@ -883,9 +852,9 @@ checkConvertSuccess :: [(String, [String])] -> String -> String -> IO (TrackedErrors ()) checkConvertSuccess pa x y = return checked where- prefix = x ++ " -> " ++ y ++ " " ++ showParams pa+ prefix = x ++ " -> " ++ y ++ " " ++ showFilters pa checked = do- ([t1,t2],pa2) <- parseTheTest pa [x,y]+ ([t1,t2],pa2) <- parseTestWithFilters pa [x,y] check $ checkValueAssignment Resolver pa2 t1 t2 check c | isCompilerError c = compilerErrorM $ prefix ++ ":\n" ++ show (getCompilerError c)@@ -894,7 +863,7 @@ checkInferenceSuccess :: [(String, [String])] -> [String] -> String -> String -> MergeTree (String,String,Variance) -> IO (TrackedErrors ()) checkInferenceSuccess pa is x y gs = checkInferenceCommon check pa is x y gs where- prefix = x ++ " -> " ++ y ++ " " ++ showParams pa+ prefix = x ++ " -> " ++ y ++ " " ++ showFilters pa check gs2 c | isCompilerError c = compilerErrorM $ prefix ++ ":\n" ++ show (getCompilerError c) | otherwise = getCompilerSuccess c `checkEquals` gs2@@ -902,7 +871,7 @@ checkInferenceFail :: [(String, [String])] -> [String] -> String -> String -> IO (TrackedErrors ()) checkInferenceFail pa is x y = checkInferenceCommon check pa is x y (mergeAll []) where- prefix = x ++ " -> " ++ y ++ " " ++ showParams pa+ prefix = x ++ " -> " ++ y ++ " " ++ showFilters pa check _ c | isCompilerError c = return () | otherwise = compilerErrorM $ prefix ++ ": Expected failure\n"@@ -914,7 +883,7 @@ checkInferenceCommon check pa is x y gs = return $ checked <!! context where context = "With params = " ++ show pa ++ ", pair = (" ++ show x ++ "," ++ show y ++ ")" checked = do- ([t1,t2],pa2) <- parseTheTest pa [x,y]+ ([t1,t2],pa2) <- parseTestWithFilters pa [x,y] ia2 <- mapCompilerM readInferred is gs' <- sequence $ fmap parseGuess gs let iaMap = Map.fromList ia2@@ -939,9 +908,9 @@ checkConvertFail :: [(String, [String])] -> String -> String -> IO (TrackedErrors ()) checkConvertFail pa x y = return checked where- prefix = x ++ " /> " ++ y ++ " " ++ showParams pa+ prefix = x ++ " /> " ++ y ++ " " ++ showFilters pa checked = do- ([t1,t2],pa2) <- parseTheTest pa [x,y]+ ([t1,t2],pa2) <- parseTestWithFilters pa [x,y] check $ checkValueAssignment Resolver pa2 t1 t2 check :: TrackedErrors a -> TrackedErrors () check c
+ src/Test/testfiles/allows_variance_left.0rx view
@@ -0,0 +1,5 @@+@value interface Interface {}++concrete Type<|#x> {+ #x allows Interface+}
+ src/Test/testfiles/allows_variance_right.0rx view
@@ -0,0 +1,5 @@+@value interface Interface<|#x> {}++concrete Type<#x|> {+ #x allows Interface<#x>+}
− src/Test/testfiles/bad_allows_variance_left.0rx
@@ -1,5 +0,0 @@-@value interface Interface {}--concrete Type<|#x> {- #x allows Interface-}
− src/Test/testfiles/bad_allows_variance_right.0rx
@@ -1,5 +0,0 @@-@value interface Interface<|#x> {}--concrete Type<#x|> {- #x allows Interface<#x>-}
− src/Test/testfiles/bad_defines_variance_left.0rx
@@ -1,5 +0,0 @@-@type interface Interface {}--concrete Type<#x|> {- #x defines Interface-}
− src/Test/testfiles/bad_defines_variance_right.0rx
@@ -1,5 +0,0 @@-@type interface Interface<|#x> {}--concrete Type<|#x> {- #x defines Interface<#x>-}
− src/Test/testfiles/bad_requires_variance_left.0rx
@@ -1,5 +0,0 @@-@value interface Interface {}--concrete Type<#x|> {- #x requires Interface-}
− src/Test/testfiles/bad_requires_variance_right.0rx
@@ -1,5 +0,0 @@-@value interface Interface<|#x> {}--concrete Type<|#x> {- #x requires Interface<#x>-}
− src/Test/testfiles/concrete_instances.0rx
@@ -1,33 +0,0 @@-// Setup.--@type interface Type<#x|> {- #x requires Value0-}--@value interface Value0 {}--@value interface Value1<|#y> {- #y requires Value0-}--@value interface Value2 {- refines Value0-}--@value interface Value3<|#z> {- #z defines Type<Value0>-}---// Tests.--concrete Object0 {- refines Value2 // -> Value0- defines Type<Object0>- refines Value1<Object0>-}--concrete Object1 {- defines Type<Value0>- refines Value3<Object1>-}
− src/Test/testfiles/concrete_missing_define.0rx
@@ -1,22 +0,0 @@-// Setup.--@type interface Type<#x|> {- #x requires Value0-}--@value interface Value0 {}--@value interface Value1<|#y> {- #y requires Value0-}--@value interface Value3<|#z> {- #z defines Type<Value0>-}---// Tests.--concrete Object1 {- refines Value3<Object1>-}
− src/Test/testfiles/concrete_missing_refine.0rx
@@ -1,23 +0,0 @@-// Setup.--@type interface Type<#x|> {- x requires Value0-}--@value interface Value0 {}--@value interface Value1<|#y> {- y requires Value0-}--@value interface Value2 {- refines Value0-}---// Tests.--concrete Object0 {- defines Type<Object0>- refines Value1<Object0>-}
+ src/Test/testfiles/defines_variance_left.0rx view
@@ -0,0 +1,5 @@+@type interface Interface {}++concrete Type<#x|> {+ #x defines Interface+}
+ src/Test/testfiles/defines_variance_right.0rx view
@@ -0,0 +1,5 @@+@type interface Interface<|#x> {}++concrete Type<|#x> {+ #x defines Interface<#x>+}
− src/Test/testfiles/filtered_self.0rx
@@ -1,14 +0,0 @@-@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/function_bad_allows_type.0rx
@@ -1,9 +0,0 @@-@value interface Interface<#x> {- #x requires Formatted-}--concrete Type<#x> {- @type something<#y>- #y allows Interface<#x>- () -> ()-}
− src/Test/testfiles/function_bad_arg.0rx
@@ -1,9 +0,0 @@-@value interface Type0 {}--@value interface Type1<#x> {- #x requires Type0-}--concrete Type<x> {- @value something (Type1<#x>) -> ()-}
− src/Test/testfiles/function_bad_defines_type.0rx
@@ -1,9 +0,0 @@-@type interface Interface<#x> {- #x requires Formatted-}--concrete Type<#x> {- @type something<#y>- #y defines Interface<#x>- () -> ()-}
− src/Test/testfiles/function_bad_requires_type.0rx
@@ -1,9 +0,0 @@-@type interface Interface<#x> {- #x requires Formatted-}--concrete Type<#x> {- @type something<#y>- #y requires Interface<#x>- () -> ()-}
− src/Test/testfiles/function_bad_return.0rx
@@ -1,9 +0,0 @@-@value interface Type0 {}--@value interface Type1<#x> {- #x requires Type0-}--concrete Type<x> {- @value something () -> (Type1<#x>)-}
src/Test/testfiles/function_defines_missed.0rx view
@@ -6,11 +6,9 @@ concrete Type4<#x> { #x requires Type2- #x allows Type3 #x defines Type1 @type something<#y> #y requires Type2- #y allows Type3 () -> (Type4<#y>) }
− src/Test/testfiles/internal_filters.0rx
@@ -1,7 +0,0 @@-define Type {- types<#x,#y,#z> {- #x requires Type1- #y allows Type2- #z defines Type3- }-}
− src/Test/testfiles/internal_params.0rx
@@ -1,3 +0,0 @@-define Type {- types<#x,#y,#z> {}-}
+ src/Test/testfiles/requires_variance_left.0rx view
@@ -0,0 +1,5 @@+@value interface Interface {}++concrete Type<#x|> {+ #x requires Interface+}
+ src/Test/testfiles/requires_variance_right.0rx view
@@ -0,0 +1,5 @@+@value interface Interface<|#x> {}++concrete Type<|#x> {+ #x requires Interface<#x>+}
− src/Test/testfiles/type_instances.0rx
@@ -1,33 +0,0 @@-// Setup.--@type interface Type<#x|> {- #x requires Value0-}--@value interface Value0 {}--@value interface Value1<|#y> {- #y requires Value0-}--@value interface Value2 {- refines Value0-}--@value interface Value3<|#z> {- #z defines Type<Value0>-}---// Tests.--@type interface Object0<#x> {- #x requires Value2 // -> Value0- #x defines Type<#x>- #x requires Value1<#x>-}--@type interface Object1<#x> {- #x defines Type<Value0>- #x requires Value3<#x>-}
src/Test/testfiles/type_interface.0rx view
@@ -1,8 +1,4 @@ @type interface Type<#a,#b|#c,#d|#e,#f> {- #a allows Parent- #b requires Type2<#a>- #c defines Equals<#c>- create () -> (optional #x) create2<#y>
− src/Test/testfiles/type_missing_define.0rx
@@ -1,22 +0,0 @@-// Setup.--@type interface Type<#x|> {- #x requires Value0-}--@value interface Value0 {}--@value interface Value1<|#y> {- #y requires Value0-}--@value interface Value3<|#z> {- #z defines Type<Value0>-}---// Tests.--@type interface Object1<#x> {- #x requires Value3<#x>-}
− src/Test/testfiles/type_missing_refine.0rx
@@ -1,23 +0,0 @@-// Setup.--@type interface Type<#x|> {- #x requires Value0-}--@value interface Value0 {}--@value interface Value1<|#y> {- #y requires Value0-}--@value interface Value2 {- refines Value0-}---// Tests.--@type interface Object0<#x> {- #x defines Type<#x>- #x requires Value1<#x>-}
− src/Test/testfiles/value_instances.0rx
@@ -1,33 +0,0 @@-// Setup.--@type interface Type<#x|> {- #x requires Value0-}--@value interface Value0 {}--@value interface Value1<|#y> {- #y requires Value0-}--@value interface Value2 {- refines Value0-}--@value interface Value3<|#z> {- #z defines Type<Value0>-}---// Tests.--@value interface Object0<#x> {- #x requires Value2 // -> Value0- #x defines Type<#x>- #x requires Value1<#x>-}--@value interface Object1<#x> {- #x defines Type<Value0>- #x requires Value3<#x>-}
src/Test/testfiles/value_interface.0rx view
@@ -1,9 +1,6 @@ @value interface Type<#a,#b|#c,#d|#e,#f> { refines Parent refines Other<Type2<#a>,#f>- #a allows Parent- #b requires Type2<#a>- #c defines Equals<#c> get () -> (#x) set (#x) -> ()
− src/Test/testfiles/value_missing_define.0rx
@@ -1,22 +0,0 @@-// Setup.--@type interface Type<#x|> {- #x requires Value0-}--@value interface Value0 {}--@value interface Value1<|#y> {- #y requires Value0-}--@value interface Value3<|#z> {- #z defines Type<Value0>-}---// Tests.--@value interface Object1<#x> {- #x requires Value3<#x>-}
− src/Test/testfiles/value_missing_refine.0rx
@@ -1,23 +0,0 @@-// Setup.--@type interface Type<#x|> {- #x requires Value0-}--@value interface Value0 {}--@value interface Value1<|#y> {- #y requires Value0-}--@value interface Value2 {- refines Value0-}---// Tests.--@value interface Object0<#x> {- #x defines Type<#x>- #x requires Value1<#x>-}
src/Types/Builtin.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.@@ -19,20 +19,26 @@ {-# LANGUAGE Safe #-} module Types.Builtin (+ ExpressionValue(..),+ PrimitiveType(..), boolRequiredValue, charRequiredValue, defaultCategories, defaultCategoryDeps,- emptyValue,+ emptyType, floatRequiredValue, formattedRequiredValue, intRequiredValue,+ isPrimitiveType,+ orderOptionalValue, stringRequiredValue, ) where import qualified Data.Map as Map import qualified Data.Set as Set +import Base.GeneralType+import Base.Positional import Types.TypeCategory import Types.TypeInstance @@ -55,5 +61,39 @@ floatRequiredValue = requiredSingleton BuiltinFloat formattedRequiredValue :: ValueType formattedRequiredValue = requiredSingleton BuiltinFormatted-emptyValue :: ValueType-emptyValue = ValueType OptionalValue minBound+orderOptionalValue :: GeneralInstance -> ValueType+orderOptionalValue t = ValueType OptionalValue $ singleType $ JustTypeInstance $ TypeInstance BuiltinOrder (Positional [t])++emptyType :: ValueType+emptyType = ValueType OptionalValue minBound++data PrimitiveType =+ PrimBool |+ PrimString |+ PrimChar |+ PrimInt |+ PrimFloat+ deriving (Eq,Show)++isPrimitiveType :: ValueType -> Bool+isPrimitiveType t+ | t == boolRequiredValue = True+ | t == intRequiredValue = True+ | t == floatRequiredValue = True+ | t == charRequiredValue = True+ | otherwise = False++data ExpressionValue =+ -- Multi argument/return tuple.+ OpaqueMulti String |+ -- Single value that needs to be wrapped. (Can convert to UnwrappedSingle.)+ WrappedSingle String |+ -- Single value that will not be wrapped. (Can convert to WrappedSingle.)+ UnwrappedSingle String |+ -- Primitive value that needs to be boxed. (Can convert to UnboxedPrimitive.)+ BoxedPrimitive PrimitiveType String |+ -- Primitive value that will not be boxed. (Can convert to BoxedPrimitive.)+ UnboxedPrimitive PrimitiveType String |+ -- Value with lazy initialization. Requires indirection to get/set.+ LazySingle ExpressionValue+ deriving (Show)
src/Types/DefinedCategory.hs view
@@ -21,9 +21,12 @@ module Types.DefinedCategory ( DefinedCategory(..), DefinedMember(..),+ PragmaDefined(..), VariableRule(..), VariableValue(..), isInitialized,+ isMembersHidden,+ isMembersReadOnly, mapMembers, mergeInternalInheritance, pairProceduresToFunctions,@@ -46,10 +49,9 @@ DefinedCategory { dcContext :: [c], dcName :: CategoryName,- dcParams :: [ValueParam c],+ dcPragmas :: [PragmaDefined c], dcRefines :: [ValueRefine c], dcDefines :: [ValueDefine c],- dcParamFilter :: [ParamFilter c], dcMembers :: [DefinedMember c], dcProcedures :: [ExecutableProcedure c], dcFunctions :: [ScopedFunction c]@@ -71,6 +73,25 @@ check Nothing = False check _ = True +data PragmaDefined c =+ MembersReadOnly {+ mroContext :: [c],+ mroMembers :: [VariableName]+ } |+ MembersHidden {+ mhContext :: [c],+ mhMembers :: [VariableName]+ }+ deriving (Show)++isMembersReadOnly :: PragmaDefined c -> Bool+isMembersReadOnly (MembersReadOnly _ _) = True+isMembersReadOnly _ = False++isMembersHidden :: PragmaDefined c -> Bool+isMembersHidden (MembersHidden _ _) = True+isMembersHidden _ = False+ data VariableRule c = VariableDefault | VariableReadOnly {@@ -164,8 +185,9 @@ getPair _ _ = undefined mapMembers :: (Show c, CollectErrorsM m) =>- [DefinedMember c] -> m (Map.Map VariableName (VariableValue c))-mapMembers ms = foldr update (return Map.empty) ms where+ Map.Map VariableName [c] -> Map.Map VariableName [c] -> [DefinedMember c] ->+ m (Map.Map VariableName (VariableValue c))+mapMembers readOnly hidden ms = foldr update (return Map.empty) ms where update m ma = do ma' <- ma case dmName m `Map.lookup` ma' of@@ -175,7 +197,12 @@ formatFullContextBrace (dmContext m) ++ " is already defined" ++ formatFullContextBrace (vvContext m0)- return $ Map.insert (dmName m) (VariableValue (dmContext m) (dmScope m) (dmType m) VariableDefault) ma'+ return $ Map.insert (dmName m) (VariableValue (dmContext m) (dmScope m) (dmType m) (memberRule m)) ma'+ memberRule m =+ case (dmName m `Map.lookup` hidden,dmName m `Map.lookup` readOnly) of+ (Just c,_) -> VariableHidden c+ (_,Just c) -> VariableReadOnly c+ _ -> VariableDefault -- TODO: Most of this duplicates parts of flattenAllConnections. mergeInternalInheritance :: (Show c, CollectErrorsM m) =>
src/Types/Function.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.@@ -28,6 +28,7 @@ import Data.List (group,intercalate,sort) import Control.Monad (when) import qualified Data.Map as Map+import qualified Data.Set as Set import Base.CompilerError import Base.GeneralType@@ -55,24 +56,23 @@ showFilters (n,fs) = map (\f -> show n ++ " " ++ show f ++ " ") fs validatateFunctionType :: (CollectErrorsM m, TypeResolver r) =>- r -> ParamFilters -> ParamVariances -> FunctionType -> m ()-validatateFunctionType r fm vm (FunctionType as rs ps fa) = do+ r -> Set.Set ParamName -> ParamVariances -> FunctionType -> m ()+validatateFunctionType r params vm (FunctionType as rs ps fa) = do mapCompilerM_ checkCount $ group $ sort $ pValues ps mapCompilerM_ checkHides $ pValues ps- paired <- processPairs alwaysPair ps fa- let allFilters = Map.union fm (Map.fromList paired)+ let allParams = Set.union params (Set.fromList $ pValues ps) expanded <- fmap concat $ processPairs (\n fs -> return $ zip (repeat n) fs) ps fa- mapCompilerM_ (checkFilterType allFilters) expanded+ mapCompilerM_ (checkFilterType allParams) expanded mapCompilerM_ checkFilterVariance expanded- mapCompilerM_ (checkArg allFilters) $ pValues as- mapCompilerM_ (checkReturn allFilters) $ pValues rs+ mapCompilerM_ (checkArg allParams) $ pValues as+ mapCompilerM_ (checkReturn allParams) $ pValues rs where allVariances = Map.union vm (Map.fromList $ zip (pValues ps) (repeat Invariant)) checkCount xa@(x:_:_) = compilerErrorM $ "Function parameter " ++ show x ++ " occurs " ++ show (length xa) ++ " times" checkCount _ = return () checkHides n =- when (n `Map.member` fm) $+ when (n `Set.member` params) $ compilerErrorM $ "Function parameter " ++ show n ++ " hides a category-level parameter" checkFilterType fa2 (n,f) = validateTypeFilter r fa2 f <?? ("In filter " ++ show n ++ " " ++ show f)@@ -98,7 +98,7 @@ r -> ParamFilters -> ParamValues -> Positional GeneralInstance -> FunctionType -> m FunctionType assignFunctionParams r fm pm ts (FunctionType as rs ps fa) = do- mapCompilerM_ (validateGeneralInstance r fm) $ pValues ts+ mapCompilerM_ (validateGeneralInstanceForCall r fm) $ pValues ts assigned <- fmap Map.fromList $ processPairs alwaysPair ps ts let pa = pm `Map.union` assigned fa' <- fmap Positional $ mapCompilerM (assignFilters pa) (pValues fa)
src/Types/Procedure.hs view
@@ -24,12 +24,14 @@ ExecutableProcedure(..), Expression(..), ExpressionStart(..),+ ExpressionType, FunctionCall(..), FunctionQualifier(..), FunctionSpec(..), IfElifElse(..), InputValue(..), InstanceOrInferred(..),+ IteratedLoop(..), MacroName(..), Operator(..), OutputValue(..),@@ -44,7 +46,6 @@ ValueOperation(..), VariableName(..), VoidExpression(..),- WhileLoop(..), assignableName, getExpressionContext, getOperatorContext,@@ -62,6 +63,7 @@ import Data.List (intercalate) import Base.Positional+import Types.Builtin import Types.TypeCategory import Types.TypeInstance @@ -205,7 +207,7 @@ data VoidExpression c = Conditional (IfElifElse c) |- Loop (WhileLoop c) |+ Loop (IteratedLoop c) | WithScope (ScopedBlock c) | Unconditional (Procedure c) | LineComment String@@ -217,8 +219,9 @@ TerminateConditional deriving (Show) -data WhileLoop c =- WhileLoop [c] (Expression c) (Procedure c) (Maybe (Procedure c))+data IteratedLoop c =+ WhileLoop [c] (Expression c) (Procedure c) (Maybe (Procedure c)) |+ TraverseLoop [c] (Expression c) [c] (Assignable c) (Procedure c) deriving (Show) data ScopedBlock c =@@ -230,9 +233,12 @@ Literal (ValueLiteral c) | UnaryExpression [c] (Operator c) (Expression c) | InfixExpression [c] (Expression c) (Operator c) (Expression c) |- InitializeValue [c] (Maybe TypeInstance) (Positional GeneralInstance) (Positional (Expression c))+ InitializeValue [c] (Maybe TypeInstance) (Positional (Expression c)) |+ RawExpression ExpressionType ExpressionValue deriving (Show) +type ExpressionType = Positional ValueType+ data FunctionQualifier c = CategoryFunction [c] CategoryName | TypeFunction [c] TypeInstanceOrParam |@@ -272,7 +278,8 @@ getExpressionContext (Literal l) = getValueLiteralContext l getExpressionContext (UnaryExpression c _ _) = c getExpressionContext (InfixExpression c _ _ _) = c-getExpressionContext (InitializeValue c _ _ _) = c+getExpressionContext (InitializeValue c _ _) = c+getExpressionContext (RawExpression _ _) = [] data FunctionCall c = FunctionCall [c] FunctionName (Positional (InstanceOrInferred c)) (Positional (Expression c))
src/Types/TypeCategory.hs view
@@ -51,6 +51,7 @@ getCategoryName, getCategoryNamespace, getCategoryParamMap,+ getCategoryParamSet, getCategoryParams, getCategoryRefines, getConcreteCategory,@@ -107,7 +108,6 @@ viName :: CategoryName, viParams :: [ValueParam c], viRefines :: [ValueRefine c],- viParamFilter :: [ParamFilter c], viFunctions :: [ScopedFunction c] } | InstanceInterface {@@ -115,7 +115,6 @@ iiNamespace :: Namespace, iiName :: CategoryName, iiParams :: [ValueParam c],- iiParamFilter :: [ParamFilter c], iiFunctions :: [ScopedFunction c] } | ValueConcrete {@@ -138,17 +137,15 @@ instance Show c => Show (AnyCategory c) where show = format where- format (ValueInterface cs ns n ps rs vs fs) =+ format (ValueInterface cs ns n ps rs fs) = "@value interface " ++ show n ++ formatParams ps ++ namespace ns ++ " { " ++ formatContext cs ++ "\n" ++ (intercalate "\n\n" $ map (\r -> " " ++ formatRefine r) rs ++- map (\v -> " " ++ formatValue v) vs ++ map (\f -> formatInterfaceFunc f) fs) ++ "\n}\n"- format (InstanceInterface cs ns n ps vs fs) =+ format (InstanceInterface cs ns n ps fs) = "@type interface " ++ show n ++ formatParams ps ++ namespace ns ++ " { " ++ formatContext cs ++ (intercalate "\n\n" $- map (\v -> " " ++ formatValue v) vs ++ map (\f -> formatInterfaceFunc f) fs) ++ "\n}\n" format (ValueConcrete cs ns n ps rs ds vs fs) =@@ -178,48 +175,48 @@ formatConcreteFunc f = showFunctionInContext (show (sfScope f) ++ " ") " " f getCategoryName :: AnyCategory c -> CategoryName-getCategoryName (ValueInterface _ _ n _ _ _ _) = n-getCategoryName (InstanceInterface _ _ n _ _ _) = n+getCategoryName (ValueInterface _ _ n _ _ _) = n+getCategoryName (InstanceInterface _ _ n _ _) = n getCategoryName (ValueConcrete _ _ n _ _ _ _ _) = n getCategoryContext :: AnyCategory c -> [c]-getCategoryContext (ValueInterface c _ _ _ _ _ _) = c-getCategoryContext (InstanceInterface c _ _ _ _ _) = c+getCategoryContext (ValueInterface c _ _ _ _ _) = c+getCategoryContext (InstanceInterface c _ _ _ _) = c getCategoryContext (ValueConcrete c _ _ _ _ _ _ _) = c getCategoryNamespace :: AnyCategory c -> Namespace-getCategoryNamespace (ValueInterface _ ns _ _ _ _ _) = ns-getCategoryNamespace (InstanceInterface _ ns _ _ _ _) = ns+getCategoryNamespace (ValueInterface _ ns _ _ _ _) = ns+getCategoryNamespace (InstanceInterface _ ns _ _ _) = ns getCategoryNamespace (ValueConcrete _ ns _ _ _ _ _ _) = ns setCategoryNamespace :: Namespace -> AnyCategory c -> AnyCategory c-setCategoryNamespace ns (ValueInterface c _ n ps rs vs fs) = (ValueInterface c ns n ps rs vs fs)-setCategoryNamespace ns (InstanceInterface c _ n ps vs fs) = (InstanceInterface c ns n ps vs fs)+setCategoryNamespace ns (ValueInterface c _ n ps rs fs) = (ValueInterface c ns n ps rs fs)+setCategoryNamespace ns (InstanceInterface c _ n ps fs) = (InstanceInterface c ns n ps fs) setCategoryNamespace ns (ValueConcrete c _ n ps rs ds vs fs) = (ValueConcrete c ns n ps rs ds vs fs) getCategoryParams :: AnyCategory c -> [ValueParam c]-getCategoryParams (ValueInterface _ _ _ ps _ _ _) = ps-getCategoryParams (InstanceInterface _ _ _ ps _ _) = ps+getCategoryParams (ValueInterface _ _ _ ps _ _) = ps+getCategoryParams (InstanceInterface _ _ _ ps _) = ps getCategoryParams (ValueConcrete _ _ _ ps _ _ _ _) = ps getCategoryRefines :: AnyCategory c -> [ValueRefine c]-getCategoryRefines (ValueInterface _ _ _ _ rs _ _) = rs-getCategoryRefines (InstanceInterface _ _ _ _ _ _) = []+getCategoryRefines (ValueInterface _ _ _ _ rs _) = rs+getCategoryRefines (InstanceInterface _ _ _ _ _) = [] getCategoryRefines (ValueConcrete _ _ _ _ rs _ _ _) = rs getCategoryDefines :: AnyCategory c -> [ValueDefine c]-getCategoryDefines (ValueInterface _ _ _ _ _ _ _) = []-getCategoryDefines (InstanceInterface _ _ _ _ _ _) = []+getCategoryDefines (ValueInterface _ _ _ _ _ _) = []+getCategoryDefines (InstanceInterface _ _ _ _ _) = [] getCategoryDefines (ValueConcrete _ _ _ _ _ ds _ _) = ds getCategoryFilters :: AnyCategory c -> [ParamFilter c]-getCategoryFilters (ValueInterface _ _ _ _ _ vs _) = vs-getCategoryFilters (InstanceInterface _ _ _ _ vs _) = vs+getCategoryFilters (ValueInterface _ _ _ _ _ _) = []+getCategoryFilters (InstanceInterface _ _ _ _ _) = [] getCategoryFilters (ValueConcrete _ _ _ _ _ _ vs _) = vs getCategoryFunctions :: AnyCategory c -> [ScopedFunction c]-getCategoryFunctions (ValueInterface _ _ _ _ _ _ fs) = fs-getCategoryFunctions (InstanceInterface _ _ _ _ _ fs) = fs+getCategoryFunctions (ValueInterface _ _ _ _ _ fs) = fs+getCategoryFunctions (InstanceInterface _ _ _ _ fs) = fs getCategoryFunctions (ValueConcrete _ _ _ _ _ _ _ fs) = fs instanceFromCategory :: AnyCategory c -> GeneralInstance@@ -246,11 +243,11 @@ filters2 = concat $ map (fromFilter . pfFilter) $ sfFilters f isValueInterface :: AnyCategory c -> Bool-isValueInterface (ValueInterface _ _ _ _ _ _ _) = True+isValueInterface (ValueInterface _ _ _ _ _ _) = True isValueInterface _ = False isInstanceInterface :: AnyCategory c -> Bool-isInstanceInterface (InstanceInterface _ _ _ _ _ _) = True+isInstanceInterface (InstanceInterface _ _ _ _ _) = True isInstanceInterface _ = False isValueConcrete :: AnyCategory c -> Bool@@ -513,6 +510,9 @@ defaultMap <- getFilterMap (getCategoryParams t) (getCategoryFilters t) return $ Map.insert ParamSelf (getSelfFilters t) defaultMap +getCategoryParamSet :: CollectErrorsM m => AnyCategory c -> m (Set.Set ParamName)+getCategoryParamSet = return . Set.fromList . ([ParamSelf] ++) . map vpParam . getCategoryParams+ -- TODO: Use this where it's needed in this file. getFunctionFilterMap :: CollectErrorsM m => ScopedFunction c -> m ParamFilters getFunctionFilterMap f = getFilterMap (pValues $ sfParams f) (sfFilters f)@@ -541,7 +541,7 @@ tm <- declareAllTypes tm0 ts collectAllM_ (map (checkSingle tm) ts) where- checkSingle tm (ValueInterface c _ n _ rs _ _) = do+ checkSingle tm (ValueInterface c _ n _ rs _) = do let ts2 = map (\r -> (vrContext r,tiName $ vrType r)) rs is <- mapCompilerM (getCategory tm) ts2 collectAllM_ (map (valueRefinesInstanceError c n) is)@@ -599,7 +599,7 @@ CategoryMap c -> [AnyCategory c] -> m () checkConnectionCycles tm0 ts = collectAllM_ (map (checker []) ts) where tm = Map.union tm0 $ Map.fromList $ zip (map getCategoryName ts) ts- checker us (ValueInterface c _ n _ rs _ _) = do+ checker us (ValueInterface c _ n _ rs _) = do failIfCycle n c us let ts2 = map (\r -> (vrContext r,tiName $ vrType r)) rs is <- mapCompilerM (getValueCategory tm) ts2@@ -627,21 +627,17 @@ categoryContext t = "In " ++ show (getCategoryName t) ++ formatFullContextBrace (getCategoryContext t) checkBounds t = categoryContext t ??> (getCategoryFilterMap t >>= disallowBoundedParams)- checkCategory r t@(ValueInterface c _ n ps rs fa _) = categoryContext t ??> do+ checkCategory r t@(ValueInterface c _ n ps rs _) = categoryContext t ??> do noDuplicates c n ps let vm = Map.fromList $ map (\p -> (vpParam p,vpVariance p)) ps collectAllM_ (map (checkRefine r vm) rs)- mapCompilerM_ (checkFilterVariance r vm) fa- checkCategory r t@(ValueConcrete c _ n ps rs ds fa _) = categoryContext t ??> do+ checkCategory r t@(ValueConcrete c _ n ps rs ds _ _) = categoryContext t ??> do noDuplicates c n ps let vm = Map.fromList $ map (\p -> (vpParam p,vpVariance p)) ps collectAllM_ (map (checkRefine r vm) rs) collectAllM_ (map (checkDefine r vm) ds)- mapCompilerM_ (checkFilterVariance r vm) fa- checkCategory r t@(InstanceInterface c _ n ps fa _) = categoryContext t ??> do+ checkCategory _ t@(InstanceInterface c _ n ps _) = categoryContext t ??> do noDuplicates c n ps- let vm = Map.fromList $ map (\p -> (vpParam p,vpVariance p)) ps- mapCompilerM_ (checkFilterVariance r vm) fa noDuplicates c n ps = collectAllM_ (map checkCount $ group $ sort $ map vpParam ps) where checkCount xa@(x:_:_) = compilerErrorM $ "Param " ++ show x ++ " occurs " ++ show (length xa) ++@@ -653,30 +649,6 @@ checkDefine r vm (ValueDefine c t) = validateDefinesVariance r vm Covariant t <?? "In " ++ show t ++ formatFullContextBrace c- checkFilterVariance r vs (ParamFilter c n f@(TypeFilter FilterRequires t)) =- "In filter " ++ show n ++ " " ++ show f ++ formatFullContextBrace c ??> do- case n `Map.lookup` vs of- Just Contravariant -> compilerErrorM $ "Contravariant param " ++ show n ++- " cannot have a requires filter"- Nothing -> compilerErrorM $ "Param " ++ show n ++ " is undefined"- _ -> return ()- validateInstanceVariance r vs Contravariant t- checkFilterVariance r vs (ParamFilter c n f@(TypeFilter FilterAllows t)) =- "In filter " ++ show n ++ " " ++ show f ++ formatFullContextBrace c ??> do- case n `Map.lookup` vs of- Just Covariant -> compilerErrorM $ "Covariant param " ++ show n ++- " cannot have an allows filter"- Nothing -> compilerErrorM $ "Param " ++ show n ++ " is undefined"- _ -> return ()- validateInstanceVariance r vs Covariant t- checkFilterVariance r vs (ParamFilter c n f@(DefinesFilter t)) =- "In filter " ++ show n ++ " " ++ show f ++ formatFullContextBrace c ??> do- case n `Map.lookup` vs of- Just Contravariant -> compilerErrorM $ "Contravariant param " ++ show n ++- " cannot have a defines filter"- Nothing -> compilerErrorM $ "Param " ++ show n ++ " is undefined"- _ -> return ()- validateDefinesVariance r vs Contravariant t checkCategoryInstances :: (Show c, CollectErrorsM m) => CategoryMap c -> [AnyCategory c] -> m ()@@ -686,12 +658,11 @@ mapCompilerM_ (checkSingle r) ts where checkSingle r t = do- let pa = Set.fromList $ map vpParam $ getCategoryParams t- fm <- getCategoryFilterMap t+ pa <- getCategoryParamSet t mapCompilerM_ (checkFilterParam pa) (getCategoryFilters t)- mapCompilerM_ (checkRefine r fm) (getCategoryRefines t)- mapCompilerM_ (checkDefine r fm) (getCategoryDefines t)- mapCompilerM_ (checkFilter r fm) (getCategoryFilters t)+ mapCompilerM_ (checkRefine r pa) (getCategoryRefines t)+ mapCompilerM_ (checkDefine r pa) (getCategoryDefines t)+ mapCompilerM_ (checkFilter r pa) (getCategoryFilters t) mapCompilerM_ (validateCategoryFunction r t) (getCategoryFunctions t) checkFilterParam pa (ParamFilter c n _) = when (not $ n `Set.member` pa) $@@ -709,14 +680,14 @@ validateCategoryFunction :: (Show c, CollectErrorsM m, TypeResolver r) => r -> AnyCategory c -> ScopedFunction c -> m () validateCategoryFunction r t f = do- fm <- getCategoryFilterMap t+ pa <- getCategoryParamSet t let vm = Map.fromList $ map (\p -> (vpParam p,vpVariance p)) $ getCategoryParams t message ??> do funcType <- parsedToFunctionType f case sfScope f of- CategoryScope -> validatateFunctionType r Map.empty Map.empty funcType- TypeScope -> validatateFunctionType r fm vm funcType- ValueScope -> validatateFunctionType r fm vm funcType+ CategoryScope -> validatateFunctionType r Set.empty Map.empty funcType+ TypeScope -> validatateFunctionType r pa vm funcType+ ValueScope -> validatateFunctionType r pa vm funcType _ -> return () getFunctionFilterMap f >>= disallowBoundedParams where message@@ -805,9 +776,9 @@ tm <- u t' <- preMergeSingle tm t return $ Map.insert (getCategoryName t') t' tm- preMergeSingle tm (ValueInterface c ns n ps rs vs fs) = do+ preMergeSingle tm (ValueInterface c ns n ps rs fs) = do rs' <- fmap concat $ mapCompilerM (getRefines tm) rs- return $ ValueInterface c ns n ps rs' vs fs+ return $ ValueInterface c ns n ps rs' fs preMergeSingle tm (ValueConcrete c ns n ps rs ds vs fs) = do rs' <- fmap concat $ mapCompilerM (getRefines tm) rs return $ ValueConcrete c ns n ps rs' ds vs fs@@ -818,7 +789,7 @@ "In category " ++ show (getCategoryName t) ++ formatFullContextBrace (getCategoryContext t) return (ts2 ++ [t'],Map.insert (getCategoryName t') t' tm)- updateSingle r tm t@(ValueInterface c ns n ps rs vs fs) = do+ updateSingle r tm t@(ValueInterface c ns n ps rs fs) = do fm <- getCategoryFilterMap t let pm = getCategoryParamMap t rs' <- fmap concat $ mapCompilerM (getRefines tm) rs@@ -827,7 +798,7 @@ checkMerged r fm rs rs'' -- Only merge from direct parents. fs' <- mergeFunctions r tm pm fm rs [] fs- return $ ValueInterface c ns n ps rs'' vs fs'+ return $ ValueInterface c ns n ps rs'' fs' -- TODO: Remove duplication below and/or have separate tests. updateSingle r tm t@(ValueConcrete c ns n ps rs ds vs fs) = do fm <- getCategoryFilterMap t@@ -1078,21 +1049,20 @@ data GuessRange a = GuessRange {- grLower :: a,- grUpper :: a+ grLower :: Maybe a,+ grUpper :: Maybe a } deriving (Eq,Ord) -instance (Bounded a, Eq a, Show a) => Show (GuessRange a) where- show (GuessRange lo hi)- | lo == minBound && hi == maxBound = "Literally anything is possible"- | lo == minBound = "Something at or below " ++ show hi- | hi == maxBound = "Something at or above " ++ show lo- | otherwise = "Something between " ++ show lo ++ " and " ++ show hi+instance Show a => Show (GuessRange a) where+ show (GuessRange Nothing Nothing) = "Literally anything is possible"+ show (GuessRange Nothing (Just hi)) = "Something at or below " ++ show hi+ show (GuessRange (Just lo) Nothing) = "Something at or above " ++ show lo+ show (GuessRange (Just lo) (Just hi)) = "Something between " ++ show lo ++ " and " ++ show hi -data GuessUnion a =+data GuessUnion = GuessUnion {- guGuesses :: [GuessRange a]+ guGuesses :: [GuessRange GeneralInstance] } mergeInferredTypes :: (CollectErrorsM m, TypeResolver r) =>@@ -1105,9 +1075,9 @@ (GuessUnion gs) <- reduceMergeTree anyOp allOp leafOp is >>= filterGuesses i t <- takeBest i gs return (InferredTypeGuess i t Invariant)- leafOp (InferredTypeGuess _ t Covariant) = return $ GuessUnion [GuessRange t maxBound]- leafOp (InferredTypeGuess _ t Contravariant) = return $ GuessUnion [GuessRange minBound t]- leafOp (InferredTypeGuess _ t _) = return $ GuessUnion [GuessRange t t]+ leafOp (InferredTypeGuess _ t Covariant) = return $ GuessUnion [GuessRange (Just t) Nothing]+ leafOp (InferredTypeGuess _ t Contravariant) = return $ GuessUnion [GuessRange Nothing (Just t)]+ leafOp (InferredTypeGuess _ t _) = return $ GuessUnion [GuessRange (Just t) (Just t)] anyOp = fmap (GuessUnion . concat . map guGuesses) . collectAllM allOp = collectAllM >=> prodAll prodAll [] = return $ GuessUnion []@@ -1128,13 +1098,17 @@ hiZ <- tryMerge Contravariant hiX hiY return [GuessRange loZ hiZ] else return []- convertsTo t1 t2 = isCompilerSuccessM $ checkGeneralMatch r f Covariant t1 t2- tryMerge v t1 t2 = collectFirstM [- checkGeneralMatch r f v t1 t2 >> return t2,- checkGeneralMatch r f v t2 t1 >> return t1,+ convertsTo Nothing _ = return True+ convertsTo _ Nothing = return True+ convertsTo (Just t1) (Just t2) = isCompilerSuccessM $ checkGeneralMatch r f Covariant t1 t2+ tryMerge _ Nothing t2 = return t2+ tryMerge _ t1 Nothing = return t1+ tryMerge v (Just t1) (Just t2) = collectFirstM [+ checkGeneralMatch r f v t1 t2 >> return (Just t2),+ checkGeneralMatch r f v t2 t1 >> return (Just t1), return $ case v of- Covariant -> mergeAny [t1,t2]- Contravariant -> mergeAll [t1,t2]+ Covariant -> Just $ mergeAny [t1,t2]+ Contravariant -> Just $ mergeAll [t1,t2] _ -> undefined ] simplifyUnion [] = return []@@ -1163,37 +1137,31 @@ (Just lo,Just hi) -> return $ Just $ ms ++ [GuessRange lo hi] ++ gs _ -> tryRangeUnion (ms ++ [g2]) g1 gs tryRangeUnion _ _ _ = return Nothing- takeBest i [g@(GuessRange lo hi)] = do- same <- hi `convertsTo` lo- let openHi = hi == maxBound- let openLo = lo == minBound- case (same,openHi,openLo) of- (True,_,_) -> return lo- (_,True,False) -> return lo- (_,False,True) -> return hi- _ -> compilerErrorM (show g) <!! "Type for param " ++ show i ++ " is ambiguous"+ takeBest _ [(GuessRange (Just lo) Nothing)] = return lo+ takeBest _ [(GuessRange Nothing (Just hi))] = return hi+ takeBest i [g@(GuessRange (Just lo) (Just hi))] = do+ same <- (Just hi) `convertsTo` (Just lo)+ when (not same) $ compilerErrorM (show g) <!! "Type for param " ++ show i ++ " is ambiguous"+ return lo takeBest i gs = mapErrorsM (map show gs) <!! "Type for param " ++ show i ++ " is ambiguous" filterGuesses i (GuessUnion gs) = do let ga = map (filterGuess i) gs collectFirstM_ ga <!! "No valid guesses for param " ++ show i gs' <- collectAnyM ga fmap GuessUnion (simplifyUnion gs')- filterGuess i g@(GuessRange lo hi) = do- case (lo == minBound,hi == maxBound) of- (False,False) -> do- let checkLo = checkSubFilters i lo- let checkHi = checkSubFilters i hi- pLo <- isCompilerErrorM checkLo- pHi <- isCompilerErrorM checkHi- case (pLo,pHi) of- (True,True) -> collectAllM_ [checkLo,checkHi] >> emptyErrorM- (True,_) -> return $ GuessRange hi hi- (_,True) -> return $ GuessRange lo lo- _ -> return $ GuessRange lo hi- (loP,hiP) -> do- when (not loP) $ checkSubFilters i lo- when (not hiP) $ checkSubFilters i hi- return g+ filterGuess i g@(GuessRange (Just lo) Nothing) = checkSubFilters i lo >> return g+ filterGuess i g@(GuessRange Nothing (Just hi)) = checkSubFilters i hi >> return g+ filterGuess i g@(GuessRange (Just lo) (Just hi)) = do+ let checkLo = checkSubFilters i lo+ let checkHi = checkSubFilters i hi+ pLo <- isCompilerErrorM checkLo+ pHi <- isCompilerErrorM checkHi+ case (pLo,pHi) of+ (True,True) -> collectAllM_ [checkLo,checkHi] >> emptyErrorM+ (True,_) -> return $ GuessRange Nothing (Just hi)+ (_,True) -> return $ GuessRange (Just lo) Nothing+ _ -> return g+ filterGuess _ _ = emptyErrorM checkSubFilters i t = "In guess " ++ show t ++ " for param " ++ show i ??> do let ps' = Map.insert i t ps fs <- ff `filterLookup` i
src/Types/TypeInstance.hs view
@@ -71,14 +71,17 @@ validateDefinesInstance, validateDefinesVariance, validateGeneralInstance,+ validateGeneralInstanceForCall, validateInstanceVariance,- validateTypeFilter, validateTypeInstance,+ validateTypeInstanceForCall,+ validateTypeFilter, ) where import Control.Monad (when) import Data.List (intercalate) import qualified Data.Map as Map+import qualified Data.Set as Set import Base.CompilerError import Base.GeneralType@@ -134,6 +137,7 @@ BuiltinFloat | BuiltinString | BuiltinFormatted |+ BuiltinOrder | CategoryNone instance Show CategoryName where@@ -144,6 +148,7 @@ show BuiltinFloat = "Float" show BuiltinString = "String" show BuiltinFormatted = "Formatted"+ show BuiltinOrder = "Order" show CategoryNone = "(none)" instance Eq CategoryName where@@ -349,25 +354,26 @@ checkValueTypeMatch :: (CollectErrorsM m, TypeResolver r) => r -> ParamFilters -> Variance -> ValueType -> ValueType -> m (MergeTree InferredTypeGuess)-checkValueTypeMatch r f v ts1@(ValueType r1 t1) ts2@(ValueType r2 t2) = result <!! message where- message- | v == Covariant = "Cannot convert " ++ show ts1 ++ " -> " ++ show ts2- | v == Contravariant = "Cannot convert " ++ show ts1 ++ " <- " ++ show ts2- | otherwise = "Cannot convert " ++ show ts1 ++ " <-> " ++ show ts2+checkValueTypeMatch r f v (ValueType r1 t1) (ValueType r2 t2) = result where+ result = do+ when (not $ storageDir `allowsVariance` v) $ compilerErrorM "Incompatible storage modifiers"+ checkGeneralMatch r f v t1 t2 storageDir | r1 > r2 = Covariant | r1 < r2 = Contravariant | otherwise = Invariant- result = do- when (not $ storageDir `allowsVariance` v) $ compilerErrorM "Incompatible storage modifiers"- checkGeneralMatch r f v t1 t2 checkGeneralMatch :: (CollectErrorsM m, TypeResolver r) => r -> ParamFilters -> Variance -> GeneralInstance -> GeneralInstance -> m (MergeTree InferredTypeGuess)-checkGeneralMatch r f v t1 t2 = do- ss <- collectFirstM [fmap Just bothSingle,return Nothing]- collectFirstM [matchInferredRight,getMatcher ss] where+checkGeneralMatch r f v t1 t2 = message !!> result where+ result = do+ ss <- collectFirstM [fmap Just bothSingle,return Nothing]+ collectFirstM [matchInferredRight,getMatcher ss]+ message+ | v == Covariant = "Cannot convert " ++ show t1 ++ " -> " ++ show t2+ | v == Contravariant = "Cannot convert " ++ show t1 ++ " <- " ++ show t2+ | otherwise = "Cannot convert " ++ show t1 ++ " <-> " ++ show t2 matchNormal Invariant = mergeAllM [matchNormal Contravariant,matchNormal Covariant] matchNormal Contravariant =@@ -540,32 +546,20 @@ show n1 ++ " <- " ++ show n2 checkConstraintToConstraint _ _ _ = undefined -validateGeneralInstance :: (CollectErrorsM m, TypeResolver r) =>+validateGeneralInstanceForCall :: (CollectErrorsM m, TypeResolver r) => r -> ParamFilters -> GeneralInstance -> m ()-validateGeneralInstance r f = reduceMergeTree collectAllM_ collectAllM_ validateSingle where- validateSingle (JustTypeInstance t) = validateTypeInstance r f t+validateGeneralInstanceForCall r f = reduceMergeTree collectAllM_ collectAllM_ validateSingle where+ validateSingle (JustTypeInstance t) = validateTypeInstanceForCall r f t validateSingle (JustParamName _ n) = when (not $ n `Map.member` f) $ compilerErrorM $ "Param " ++ show n ++ " not found" validateSingle (JustInferredType n) = compilerErrorM $ "Inferred param " ++ show n ++ " is not allowed here" -validateTypeInstance :: (CollectErrorsM m, TypeResolver r) =>+validateTypeInstanceForCall :: (CollectErrorsM m, TypeResolver r) => r -> ParamFilters -> TypeInstance -> m ()-validateTypeInstance r f t@(TypeInstance _ ps) = do+validateTypeInstanceForCall r f t@(TypeInstance _ ps) = do fa <- trTypeFilters r t processPairs_ (validateAssignment r f) ps fa- mapCompilerM_ (validateGeneralInstance r f) (pValues ps) <?? "In " ++ show t--validateDefinesInstance :: (CollectErrorsM m, TypeResolver r) =>- r -> ParamFilters -> DefinesInstance -> m ()-validateDefinesInstance r f t@(DefinesInstance _ ps) = do- fa <- trDefinesFilters r t- processPairs_ (validateAssignment r f) ps fa- mapCompilerM_ (validateGeneralInstance r f) (pValues ps) <?? "In " ++ show t--validateTypeFilter :: (CollectErrorsM m, TypeResolver r) =>- r -> ParamFilters -> TypeFilter -> m ()-validateTypeFilter r f (TypeFilter _ t) = validateGeneralInstance r f t-validateTypeFilter r f (DefinesFilter t) = validateDefinesInstance r f t+ mapCompilerM_ (validateGeneralInstanceForCall r f) (pValues ps) <?? "In " ++ show t validateAssignment :: (CollectErrorsM m, TypeResolver r) => r -> ParamFilters -> GeneralInstance -> [TypeFilter] -> m ()@@ -596,6 +590,31 @@ variance <- trVariance r n2 processPairs_ (\v2 (p1,p2) -> checkGeneralMatch r f v2 p1 p2) variance (Positional paired) | otherwise = compilerErrorM $ "Constraint " ++ show f1 ++ " does not imply " ++ show f2++validateGeneralInstance :: (CollectErrorsM m, TypeResolver r) =>+ r -> Set.Set ParamName -> GeneralInstance -> m ()+validateGeneralInstance r params = reduceMergeTree collectAllM_ collectAllM_ validateSingle where+ validateSingle (JustTypeInstance t) = validateTypeInstance r params t+ validateSingle (JustParamName _ n) = when (not $ n `Set.member` params) $+ compilerErrorM $ "Param " ++ show n ++ " not found"+ validateSingle (JustInferredType n) = compilerErrorM $ "Inferred param " ++ show n ++ " is not allowed here"++validateTypeInstance :: (CollectErrorsM m, TypeResolver r) =>+ r -> Set.Set ParamName -> TypeInstance -> m ()+validateTypeInstance r params t@(TypeInstance _ ps) = do+ _ <- trTypeFilters r t -- This just ensures that t exists.+ mapCompilerM_ (validateGeneralInstance r params) (pValues ps) <?? "In " ++ show t++validateDefinesInstance :: (CollectErrorsM m, TypeResolver r) =>+ r -> Set.Set ParamName -> DefinesInstance -> m ()+validateDefinesInstance r params t@(DefinesInstance _ ps) = do+ _ <- trDefinesFilters r t -- This just ensures that t exists.+ mapCompilerM_ (validateGeneralInstance r params) (pValues ps) <?? "In " ++ show t++validateTypeFilter :: (CollectErrorsM m, TypeResolver r) =>+ r -> Set.Set ParamName -> TypeFilter -> m ()+validateTypeFilter r params (TypeFilter _ t) = validateGeneralInstance r params t+validateTypeFilter r params (DefinesFilter t) = validateDefinesInstance r params t validateInstanceVariance :: (CollectErrorsM m, TypeResolver r) => r -> ParamVariances -> Variance -> GeneralInstance -> m ()
tests/builtin-types.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2020 Kevin P. Barry+Copyright 2020-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.@@ -219,7 +219,7 @@ } } -unittest asFloar {+unittest asFloat { if (present(reduce<String,AsFloat>("a"))) { fail("Failed") }@@ -231,7 +231,19 @@ } } +unittest defaultOrder {+ if (!present(reduce<String,DefaultOrder<Char>>("a"))) {+ fail("Failed")+ }+} +unittest subSequence {+ if (!present(reduce<String,SubSequence>("a"))) {+ fail("Failed")+ }+}++ testcase "interface implementations" { success }@@ -472,6 +484,18 @@ if (("abc\x00def").readAt(4) != 'd') { fail("Failed") }+}++unittest traverseString {+ Int index <- 0+ String value <- "abcdefg"++ traverse (value.defaultOrder() -> Char c) {+ \ Testing.checkEquals<?>(c,value.readAt(index))+ index <- index+1+ }++ \ Testing.checkEquals<?>(index,7) }
tests/cli-tests.sh view
@@ -1,7 +1,7 @@ #!/usr/bin/env bash # -------------------------------------------------------------------------------# Copyright 2020 Kevin P. Barry+# Copyright 2020-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.@@ -38,6 +38,11 @@ "$@" 2>&1 } +execute_noredir() {+ show_message "Executing:" $(printf ' %q' "$@")+ "$@"+}+ do_zeolite() { execute "${ZEOLITE[@]}" "$@" }@@ -205,7 +210,7 @@ test_templates() {- execute rm -f $ZEOLITE_PATH/tests/templates/Extension_Templated.cpp+ execute rm -f $ZEOLITE_PATH/tests/templates/Extension_*.cpp do_zeolite -p "$ZEOLITE_PATH" --templates tests/templates do_zeolite -p "$ZEOLITE_PATH" -r tests/templates do_zeolite -p "$ZEOLITE_PATH" -t tests/templates@@ -303,9 +308,9 @@ local name='Cli Tests' rm -f "$binary" do_zeolite -p "$ZEOLITE_PATH" -I lib/util -m HelloDemo example/hello -f- local output=$(echo "$name" | "$binary" 2>&1)+ local output=$(echo "$name" | execute_noredir "$binary" 2>&1) if ! echo "$output" | egrep -q "\"$name\""; then- show_message "Expected \"$name\" in output:"+ show_message "Expected \"$name\" in HelloDemo output:" echo "$output" 1>&2 return 1 fi@@ -318,6 +323,28 @@ } +test_example_primes() {+ local binary="$ZEOLITE_PATH/example/primes/PrimesDemo"+ local expected='2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,'+ rm -f "$binary"+ local temp=$(execute mktemp)+ do_zeolite -p "$ZEOLITE_PATH" -r example/primes -f+ {+ echo;+ sleep 0.01;+ echo;+ echo "exit";+ } | execute_noredir "$binary" 2> /dev/null | head -n100 | tr $'\n' ',' > "$temp"+ local output=$(cat "$temp")+ rm -f "$temp"+ if [[ "$output" != "$expected" ]]; then+ show_message "Unexpected PrimesDemo output:"+ echo "$output" 1>&2+ return 1+ fi+}++ run_all() { ZEOLITE_PATH=$(do_zeolite --get-path | grep '^/') echo 1>&2@@ -369,6 +396,7 @@ test_global_include test_example_hello test_example_parser+ test_example_primes ) run_all "${ALL_TESTS[@]}" 1>&2
tests/filters.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2020 Kevin P. Barry+Copyright 2020-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.@@ -50,14 +50,16 @@ @value interface Type4 {} -@value interface Value<#x> {+concrete Value<#x> { #x requires Type1 #x requires Type2 #x allows Type3 #x allows Type4 } +define Value {} + testcase "implicit bound from reversing another filter" { error require compiler "#x.+bound"@@ -67,12 +69,14 @@ @value interface Type {} -@value interface Value<#x,#y> {+concrete Value<#x,#y> { #x requires Type #y requires #x } +define Value {} + testcase "defines filter is not an upper bound" { compiles }@@ -81,12 +85,14 @@ @value interface Type2 {} -@value interface Value<#x> {+concrete Value<#x> { #x defines Type1 #x allows Type2 } +define Value {} + testcase "defines filter is not a lower bound" { compiles }@@ -95,12 +101,14 @@ @value interface Type2 {} -@value interface Value<#x> {+concrete Value<#x> { #x defines Type1 #x requires Type2 } +define Value {} + testcase "function param bounded on both sides" { error require compiler "#x.+bound"@@ -115,4 +123,244 @@ #x requires Type1 #x allows Type2 () -> ()+}+++testcase "category-level requires not met in @type call" {+ error+ require "any.+Formatted"+}++concrete Type<#x> {+ #x requires Formatted++ @type call () -> ()+}++define Type {+ call () {}++ @category call2 () -> ()+ call2 () {+ \ Type<any>.call()+ }+}+++testcase "category-level defines not met in @type call" {+ error+ require "any.+Equals"+}++concrete Type<#x> {+ #x defines Equals<#x>++ @type call () -> ()+}++define Type {+ call () {}++ @category call2 () -> ()+ call2 () {+ \ Type<any>.call()+ }+}+++testcase "category-level allows not met in @type call" {+ error+ require "all.+Int"+}++concrete Type<#x> {+ #x allows Int++ @type call () -> ()+}++define Type {+ call () {}++ @category call2 () -> ()+ call2 () {+ \ Type<all>.call()+ }+}+++testcase "category-level requires not met in initialization" {+ error+ require "any.+Formatted"+}++concrete Type<#x> {+ #x requires Formatted++ @category call () -> ()+}++define Type {+ call () {+ \ Type<any>{ }+ }+}+++testcase "category-level defines not met in initialization" {+ error+ require "any.+Equals"+}++concrete Type<#x> {+ #x defines Equals<#x>++ @category call () -> ()+}++define Type {+ call () {+ \ Type<any>{ }+ }+}+++testcase "category-level allows not met in initialization" {+ error+ require "all.+Int"+}++concrete Type<#x> {+ #x allows Int++ @category call () -> ()+}++define Type {+ call () {+ \ Type<all>{ }+ }+}+++testcase "function-level requires not met in call" {+ error+ require "any.+Formatted"+}++concrete Type {+ @type call<#x>+ #x requires Formatted+ () -> ()+}++define Type {+ call () {}++ @category call2 () -> ()+ call2 () {+ \ Type.call<any>()+ }+}+++testcase "function-level defines not met in call" {+ error+ require "any.+Equals"+}++concrete Type {+ @type call<#x>+ #x defines Equals<#x>+ () -> ()+}++define Type {+ call () {}++ @category call2 () -> ()+ call2 () {+ \ Type.call<any>()+ }+}+++testcase "function-level allows not met in call" {+ error+ require "all.+Int"+}++concrete Type {+ @type call<#x>+ #x allows Int+ () -> ()+}++define Type {+ call () {}++ @category call2 () -> ()+ call2 () {+ \ Type.call<all>()+ }+}+++testcase "category-level filters meet function-level filter requirements" {+ compiles+}++concrete Type1 {+ @type call<#i,#j,#k>+ #i requires Formatted+ #j defines Equals<#j>+ #k allows Int+ () -> ()+}++define Type1 {+ call () {}+}++concrete Type2<#x,#y,#z> {+ #x requires Formatted+ #y defines Equals<#y>+ #z allows Int++ @type call () -> ()+}++define Type2 {+ call () {+ \ Type1.call<#x,#y,#z>()+ }+}+++testcase "category-level filters are not checked during function-param substitution" {+ error+ require "Char.+Int"+ exclude "String"+}++concrete Type<|#x> {+ #x requires String+}++define Type {}++concrete Test {+ @type call<#x>+ #x requires Int+ (optional Type<#x>) -> ()+}++define Test {+ call (_) {}++ @type call2 () -> ()+ call2 () {+ \ call<Int>(empty)+ \ call<Char>(empty)+ } }
tests/function-calls.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2020 Kevin P. Barry+Copyright 2020-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.@@ -404,9 +404,11 @@ \ Call.call<Value<Test>>() } -@value interface Value<#x> {+concrete Value<#x> { #x defines Equals<#x> }++define Value {} concrete Call { @type call<#x> () -> ()
tests/inference.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2020 Kevin P. Barry+Copyright 2020-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.@@ -328,4 +328,35 @@ define Test { get (_,_) {}+}+++testcase "all/any as valid lower/upper bounds" {+ compiles+}++concrete Test {+ @type call<#x,#y> (Convert<#x,#y>) -> (#x,#y)+}++define Test {+ call (_) {+ fail("this allows faking the return")+ }++ @value run () -> ()+ run () {+ any x1, all y1 <- call<?,?>(Convert<any,all>.create())+ all x2, any y2 <- call<?,?>(Convert<all,any>.create())+ }+}++concrete Convert<#x|#y> {+ @type create () -> (#self)+}++define Convert {+ create () {+ return #self{ }+ } }
− tests/internal-params.0rt
@@ -1,368 +0,0 @@-/* ------------------------------------------------------------------------------Copyright 2020 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 "internal param not visible from @type" {- error- require "#x"-}--concrete Value {}--define Value {- types<#x> {}-- @type something () -> ()- something () {- optional #x val <- empty- }-}---testcase "internal filter not applied in @type" {- compiles-}--unittest test {- \ Value.something<Bool>()-}--concrete Value {- @type something<#x> () -> ()-}--define Value {- types<#x> {- #x defines LessThan<#x>- }-- something () {}-}---testcase "internal filter not applied in @category" {- compiles-}--unittest test {- \ Value:something<Bool>()-}--concrete Value {- @category something<#x> () -> ()-}--define Value {- types<#x> {- #x defines LessThan<#x>- }-- something () {}-}---testcase "internal params" {- success-}--unittest test {- \ Value.create<Type1,Type2>()-}--concrete Value {- @type create<#x,#y>- () -> (Value)-}--define Value {- types<#x,#y> {}-- create () {- return Value{ types<#x,#y> }- }-}--@value interface Type1 {}-@value interface Type2 {}---testcase "internal params with filters" {- compiles-}--@value interface Get<|#x> {- get () -> (#x)-}--@value interface Set<#x|> {- set (#x) -> ()-}--concrete Value {- @type create<#x,#y>- #x requires Get<#x>- #y allows Set<#y>- () -> (Value)-}--define Value {- types<#x,#y> {- #x requires Get<#x>- #y allows Set<#y>- }-- create () {- return Value{ types<#x,#y> }- }-}---testcase "internal params missing filters" {- error- require "Get|Set"-}--@value interface Get<|#x> {- get () -> (#x)-}--@value interface Set<#x|> {- set (#x) -> ()-}--concrete Value {- @category create<#x,#y>- () -> (Value)-}--define Value {- types<#x,#y> {- #x requires Get<#x>- #y allows Set<#y>- }-- create () {- return Value{ types<#x,#y> }- }-}---testcase "internal params with values" {- compiles-}--concrete Value {- @category create<#x,#y>- () -> (Value)-}--define Value {- types<#x,#y> {}-- @value Bool value-- create () {- return Value{ types<#x,#y>, false }- }-}---testcase "value depends on internal param" {- success-}--unittest test {- \ Value.create<Bool>(Type<Bool>.create())-}--concrete Type<#y> {- @type create () -> (Type<#y>)-}--define Type {- create () {- return Type<#y>{ }- }-}--concrete Value {- @type create<#x>- (Type<#x>) -> (Value)-}--define Value {- types<#z> {}-- @value Type<#z> value-- create (value) {- return Value{ types<#x>, value }- }-}---testcase "value mismatch with internal param" {- error- require "create"- require "Bool"- require "String"-}--unittest test {- \ Value.create<String>(Type<Bool>.create())-}--concrete Type<#y> {- @type create () -> (Type<#y>)-}--define Type {- create () {- return Type<#y>{ }- }-}--concrete Value {- @type create<#x>- (Type<#x>) -> (Value)-}--define Value {- types<#z> {}-- @value Type<#z> value-- create (value) {- return Value{ types<#x>, value }- }-}---testcase "internal param clash with external" {- error- require "#x"-}--concrete Value<#x> {}--define Value {- types<#x> {}-}---testcase "internal param clash with function" {- error- require "#x"-}--concrete Value {- @value check<#x> () -> ()-}--define Value {- types<#x> {}-}---testcase "internal param clash with internal function" {- error- require "#x"-}--concrete Value {}--define Value {- types<#x> {}-- @value check<#x> () -> ()- check () {}-}---testcase "internal param no clash with category" {- compiles-}--concrete Value {- @category create<#x> () -> (Value)-}--define Value {- types<#x> {}-- create () {- return Value { types<#x> }- }-}---testcase "reduce internal param success" {- success-}--unittest test {- Value value <- Value.create<Formatted>()- if (!value.check<String>("")) {- fail("Failed")- }-}--concrete Value {- @type create<#x> () -> (Value)- @value check<#y> (#y) -> (Bool)-}--define Value {- types<#x> {}-- create () {- return Value { types<#x> }- }-- check (y) {- return present(reduce<#y,#x>(y))- }-}---testcase "reduce internal param fail" {- success-}--unittest test {- Value value <- Value.create<Formatted>()- if (value.check<Value>(value)) {- fail("Failed")- }-}--concrete Value {- @type create<#x> () -> (Value)- @value check<#y> (#y) -> (Bool)-}--define Value {- types<#x> {}-- create () {- return Value { types<#x> }- }-- check (y) {- return present(reduce<#y,#x>(y))- }-}
tests/local-rules.0rt view
@@ -256,3 +256,173 @@ $Hidden[foo]$ Int foo <- 1 }+++testcase "ReadOnly @category member" {+ error+ require "foo.+read-only"+ exclude "bar"+}++concrete Type {}++define Type {+ $ReadOnly[foo]$++ @category Int foo <- 1+ @category Int bar <- 1++ @value call () -> ()+ call () {+ bar <- 2+ foo <- 2+ }+}+++testcase "Hidden @category member" {+ error+ require "foo.+hidden"+ exclude "bar"+}++concrete Type {}++define Type {+ $Hidden[foo]$++ @category Int foo <- 1+ @category Int bar <- 1++ @value call () -> ()+ call () {+ bar <- 2+ foo <- 2+ }+}+++testcase "Bad name for Hidden @category member" {+ error+ require "foo.+does not exist"+}++concrete Type {}++define Type {+ $Hidden[foo]$++ @category Int bar <- 1+}+++testcase "Hidden @category member is visible during init" {+ success+}++unittest test {+ \ Testing.checkEquals<?>(Type:get(),2)+}++concrete Type {+ @category get () -> (Int)+}++define Type {+ $Hidden[foo]$+ $ReadOnly[bar]$++ @category Int foo <- 1+ @category Int bar <- foo+1++ get () {+ return bar+ }+}+++testcase "ReadOnly @value member" {+ error+ require "foo.+read-only"+ exclude "bar"+}++concrete Type {}++define Type {+ $ReadOnly[foo]$++ @value Int foo+ @value Int bar++ @value call () -> ()+ call () {+ bar <- 2+ foo <- 2+ }+}+++testcase "Hidden @value member" {+ error+ require "foo.+hidden"+ exclude "bar"+}++concrete Type {}++define Type {+ $Hidden[foo]$++ @value Int foo+ @value Int bar++ @value call () -> ()+ call () {+ bar <- 2+ foo <- 2+ }+}+++testcase "Bad name for Hidden @value member" {+ error+ require "foo.+does not exist"+}++concrete Type {}++define Type {+ $Hidden[foo]$++ @value Int bar+}+++testcase "ReadOnly @value member can be initialized" {+ success+}++unittest test {+ \ Testing.checkEquals<?>(Type.create().get(),1)+}++concrete Type {+ @type create () -> (Type)+ @value get () -> (Int)++}++define Type {+ $ReadOnly[foo]$++ @value Int foo++ create () {+ return Type{ 1 }+ }++ get () {+ return foo+ }+}
tests/member-init.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2020 Kevin P. Barry+Copyright 2020-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.@@ -317,4 +317,53 @@ get () { return value }+}+++testcase "@category members read-only during others' init" {+ error+ require "value1.+read-only"+}++concrete Test {}++define Test {+ @category Int value1 <- 1+ @category Int value2 <- (value1 <- 2)+}+++testcase "bad type in @category member" {+ error+ require "Foo not found"+}++concrete Test {}++define Test {+ @category optional Foo value <- empty+}+++testcase "bad type in @value member" {+ error+ require "Foo not found"+}++concrete Test {}++define Test {+ @value Foo value+}+++testcase "param disallowed in @category member" {+ error+ require "#x not found"+}++concrete Test<#x> {}++define Test {+ @category optional #x value <- empty }
tests/module-only4/common-source.cpp view
@@ -29,7 +29,7 @@ namespace ZEOLITE_PRIVATE_NAMESPACE { #endif // ZEOLITE_PRIVATE_NAMESPACE -S<TypeValue> CreateValue_Type1(S<Type_Type1> parent, const ParamTuple& params, const ValueTuple& args);+S<TypeValue> CreateValue_Type1(S<Type_Type1> parent, const ValueTuple& args); struct ExtCategory_Type1 : public Category_Type1 { };@@ -39,14 +39,14 @@ ReturnTuple Call_create(const S<TypeInstance>& self, const ParamTuple& params, const ValueTuple& args) { TRACE_FUNCTION("Type1.create")- return ReturnTuple(CreateValue_Type1(CreateType_Type1(Params<0>::Type()), ParamTuple(),+ return ReturnTuple(CreateValue_Type1(CreateType_Type1(Params<0>::Type()), TypeInstance::Call(GetType_Type2(Params<0>::Type()), Function_Type2_create, ParamTuple(), ArgTuple()))); } }; struct ExtValue_Type1 : public Value_Type1 {- inline ExtValue_Type1(S<Type_Type1> p, const ParamTuple& params, const ValueTuple& args)- : Value_Type1(p, params), value(args.At(0)) {}+ inline ExtValue_Type1(S<Type_Type1> p, const ValueTuple& args)+ : Value_Type1(p), value(args.At(0)) {} ReturnTuple Call_get(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) { TRACE_FUNCTION("Type1.get")@@ -64,8 +64,8 @@ static const auto cached = S_get(new ExtType_Type1(CreateCategory_Type1(), Params<0>::Type())); return cached; }-S<TypeValue> CreateValue_Type1(S<Type_Type1> parent, const ParamTuple& params, const ValueTuple& args) {- return S_get(new ExtValue_Type1(parent, params, args));+S<TypeValue> CreateValue_Type1(S<Type_Type1> parent, const ValueTuple& args) {+ return S_get(new ExtValue_Type1(parent, args)); } #ifdef ZEOLITE_PRIVATE_NAMESPACE@@ -78,7 +78,7 @@ namespace ZEOLITE_PUBLIC_NAMESPACE { #endif // ZEOLITE_PUBLIC_NAMESPACE -S<TypeValue> CreateValue_Type3(S<Type_Type3> parent, const ParamTuple& params, const ValueTuple& args);+S<TypeValue> CreateValue_Type3(S<Type_Type3> parent, const ValueTuple& args); struct ExtCategory_Type3 : public Category_Type3 { };@@ -88,14 +88,14 @@ ReturnTuple Call_create(const S<TypeInstance>& self, const ParamTuple& params, const ValueTuple& args) { TRACE_FUNCTION("Type3.create")- return ReturnTuple(CreateValue_Type3(CreateType_Type3(Params<0>::Type()), ParamTuple(),+ return ReturnTuple(CreateValue_Type3(CreateType_Type3(Params<0>::Type()), TypeInstance::Call(GetType_Type2(Params<0>::Type()), Function_Type2_create, ParamTuple(), ArgTuple()))); } }; struct ExtValue_Type3 : public Value_Type3 {- inline ExtValue_Type3(S<Type_Type3> p, const ParamTuple& params, const ValueTuple& args)- : Value_Type3(p, params), value(args.At(0)) {}+ inline ExtValue_Type3(S<Type_Type3> p, const ValueTuple& args)+ : Value_Type3(p), value(args.At(0)) {} ReturnTuple Call_get(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) { TRACE_FUNCTION("Type3.get")@@ -113,8 +113,8 @@ static const auto cached = S_get(new ExtType_Type3(CreateCategory_Type3(), Params<0>::Type())); return cached; }-S<TypeValue> CreateValue_Type3(S<Type_Type3> parent, const ParamTuple& params, const ValueTuple& args) {- return S_get(new ExtValue_Type3(parent, params, args));+S<TypeValue> CreateValue_Type3(S<Type_Type3> parent, const ValueTuple& args) {+ return S_get(new ExtValue_Type3(parent, args)); } #ifdef ZEOLITE_PUBLIC_NAMESPACE
tests/reduce.0rt view
@@ -670,30 +670,6 @@ } -testcase "bad instance in reduce param" {- error- require "Test"- require "define"- require "Equals"-}--unittest test {- \ reduce<Value<Test>,Formatted>(empty)-}--@value interface Value<#x> {- #x defines Equals<#x>-}--concrete Call {- @type call<#x> () -> ()-}--define Call {- call () {}-}-- testcase "reduce from interface" { success }
tests/regressions.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2020 Kevin P. Barry+Copyright 2020-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.
tests/self-type.0rt view
@@ -37,16 +37,10 @@ require "#self not found" } -concrete Type {- @type create () -> (#self)-}+concrete Type {} define Type {- @category #self value <- Type.create()-- create () {- return Type{ }- }+ @category optional #self value <- empty } @@ -503,52 +497,25 @@ compiles } -@value interface Base<#x> {- refines Formatted+concrete Type<#x> { #x allows #self } -@value interface Type1 {- refines Base<Type1>-}--@value interface Type2 {- refines Base<Formatted>-}--@value interface Type3 {- refines Type2-}+define Type {} testcase "#self nested in param filter" { compiles } -@value interface Base<#x> {+concrete Type<#x> { #x requires Writer<#self> #x defines Equals<#self> } -@value interface Writer<#x|> {- write (#x) -> (#self)-}--concrete Type {- refines Base<Type>- refines Writer<Type>- defines Equals<Type>-}--define Type {- write (_) {- return self- }+define Type {} - equals (_,_) {- return true- }-}+@value interface Writer<#x|> {} testcase "#self nested in inheritance" {@@ -576,4 +543,44 @@ @type interface Creator<|#x> { create () -> (#x)+}+++testcase "#self allowed in category param filters" {+ compiles+}++concrete Type1<#x> {+ #x allows #self+}++define Type1 {}++concrete Type2<#x> {+ #x requires #self+}++define Type2 {}+++testcase "#self allowed in covavariant position of function param filter" {+ compiles+}++@value interface Type {+ call<#x>+ #x allows #self+ () -> ()+}+++testcase "#self disallowed in contravariant position of function param filter" {+ error+ require "#self.+contravariant"+}++@value interface Type {+ call<#x>+ #x requires #self+ () -> () }
tests/templates/.zeolite-module view
@@ -5,5 +5,9 @@ source: "tests/templates/Extension_Templated.cpp" categories: [Templated] }+ category_source {+ source: "tests/templates/Extension_Templated2.cpp"+ categories: [Templated2]+ } ] mode: incremental {}
tests/templates/README.md view
@@ -6,10 +6,10 @@ ```shell ZEOLITE_PATH=$(zeolite --get-path)-rm -f $ZEOLITE_PATH/tests/templates/Extension_Templated.cpp # Remove the old template.-zeolite -p $ZEOLITE_PATH --templates tests/templates # Create a new template.-zeolite -p $ZEOLITE_PATH -r tests/templates # Recompile.-zeolite -p $ZEOLITE_PATH -t tests/templates # Run the test.+rm -f $ZEOLITE_PATH/tests/templates/Extension_*.cpp # Remove the old templates.+zeolite -p $ZEOLITE_PATH --templates tests/templates # Create a new template.+zeolite -p $ZEOLITE_PATH -r tests/templates # Recompile.+zeolite -p $ZEOLITE_PATH -t tests/templates # Run the test. ``` The most important step above is to delete the *old* template first.
+ tests/templates/private.0rp view
@@ -0,0 +1,23 @@+/* -----------------------------------------------------------------------------+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]++$ModuleOnly$++concrete Templated2 {+ @type create () -> (Templated2)+}
+ tests/templates/public.0rp view
@@ -0,0 +1,26 @@+/* -----------------------------------------------------------------------------+Copyright 2020 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]++concrete Templated<#x> {+ @category create<#y>+ #y requires Formatted+ #y defines Equals<#y>+ () -> (Templated<#y>)++ @value get () -> (#x)+}
− tests/templates/templates.0rp
@@ -1,26 +0,0 @@-/* ------------------------------------------------------------------------------Copyright 2020 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]--concrete Templated<#x> {- @category create<#y>- #y requires Formatted- #y defines Equals<#y>- () -> (Templated<#y>)-- @value get () -> (#x)-}
tests/templates/tests.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2020 Kevin P. Barry+Copyright 2020-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.@@ -22,15 +22,15 @@ } unittest test {- \ Test.run()+ \ Templated:create<Int>() } -define Test {- run () {- \ Templated:create<Int>()- }++testcase "private template generated" {+ crash+ require "Templated2\.create is not implemented" } -concrete Test {- @type run () -> ()+unittest test {+ \ Templated2.create() }
tests/tracing.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2020 Kevin P. Barry+Copyright 2020-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.@@ -180,5 +180,31 @@ call () { $TraceCreation$ \ value.call()+ }+}+++testcase "correct function name used for non-merged function" {+ crash+ require "message"+ require "Type\.call"+ exclude "Base"+}++unittest test {+ \ Type.call()+}++@type interface Base {+ call () -> ()+}++concrete Type {+ defines Base+}++define Type {+ call () {+ fail("message") } }
+ tests/traverse.0rt view
@@ -0,0 +1,300 @@+/* -----------------------------------------------------------------------------+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 "simple traverse tests" {+ success+}++unittest simpleSum {+ Int total <- 0+ traverse (Counter.zeroIndexed(5) -> Int i) {+ total <- total+i+ }+ \ Testing.checkEquals<?>(total,10)+}++unittest ignoreValue {+ Int total <- 0+ traverse (Counter.zeroIndexed(5) -> _) {+ total <- total+1+ }+ \ Testing.checkEquals<?>(total,5)+}++unittest existingVariable {+ Int total <- 0+ Int i <- 0+ traverse (Counter.zeroIndexed(5) -> i) {+ total <- total+i+ }+ \ Testing.checkEquals<?>(total,10)+ \ Testing.checkEquals<?>(i,4)+}++unittest breakAtLimit {+ Int total <- 0+ traverse (Counter.zeroIndexed(10) -> Int i) {+ if (i >= 5) {+ break+ }+ total <- total+i+ }+ \ Testing.checkEquals<?>(total,10)+}++unittest continueOnOdd {+ Int total <- 0+ traverse (Counter.zeroIndexed(10) -> Int i) {+ if (i%2 == 1) {+ continue+ }+ total <- total+i+ }+ \ Testing.checkEquals<?>(total,20)+}++concrete Counter {+ refines Order<Int>++ @type zeroIndexed (Int) -> (optional Counter)+}++define Counter {+ @value Int current+ @value Int max++ zeroIndexed (max) {+ if (max < 1) {+ return empty+ } else {+ return Counter{ 0, max }+ }+ }++ next () {+ if (current+1 < max) {+ current <- current+1+ return self+ } else {+ return empty+ }+ }++ get () {+ return current+ }+}+++testcase "bad traverse container" {+ error+ require "Int.+Order"+}++unittest test {+ traverse (0 -> _) {}+}+++testcase "bad traverse variable" {+ error+ require "String.+Int"+}++concrete Empty<|#x> {+ refines Order<#x>++ @category new<#x> () -> (optional Empty<#x>)+}++define Empty {+ new () {+ return empty+ }++ next () {+ fail("next() not implemented")+ }++ get () {+ fail("get() not implemented")+ }+}++unittest test {+ traverse (Empty:new<String>() -> Int i) {}+}+++// #auto is used internally when compiling traverse.+testcase "no clash when #auto is in category" {+ success+}++unittest test {+ \ Test<String>.run()+}++concrete Test<#auto> {+ @type run () -> ()+}++define Test {+ run () {+ Int total <- 0+ traverse (Counter.new() -> Int i) {+ total <- total+i+ }+ \ Testing.checkEquals<?>(total,10)+ }+}++concrete Counter {+ refines Order<Int>++ @type new () -> (Counter)+}++define Counter {+ @value Int current++ new () {+ return Counter{ 0 }+ }++ next () {+ if (current+1 < 5) {+ current <- current+1+ return self+ } else {+ return empty+ }+ }++ get () {+ return current+ }+}+++// #auto is used internally when compiling traverse.+testcase "no clash when #auto is in function call" {+ success+}++unittest test {+ \ Test.run<String>()+}++concrete Test {+ @type run<#auto> () -> ()+}++define Test {+ run () {+ Int total <- 0+ traverse (Counter.new() -> Int i) {+ total <- total+i+ }+ \ Testing.checkEquals<?>(total,10)+ }+}++concrete Counter {+ refines Order<Int>++ @type new () -> (Counter)+}++define Counter {+ @value Int current++ new () {+ return Counter{ 0 }+ }++ next () {+ if (current+1 < 5) {+ current <- current+1+ return self+ } else {+ return empty+ }+ }++ get () {+ return current+ }+}+++// #auto is used internally when compiling traverse.+testcase "no clash when #auto also the inferred type" {+ success+}++unittest test {+ \ Testing.checkEquals<?>(Test.run<?>("message"),"message")+}++concrete Test {+ @type run<#auto> (#auto) -> (#auto)+}++define Test {+ run (x) (i) {+ i <- x+ Int total <- 0+ traverse (Repeat:times<?>(x,10) -> i) {+ total <- total+1+ }+ \ Testing.checkEquals<?>(total,10)+ }+}++concrete Repeat<|#x> {+ refines Order<#x>++ @category times<#y> (#y,Int) -> (optional Repeat<#y>)+}++define Repeat {+ @value #x value+ @value Int count++ times (value,count) {+ if (count < 1) {+ return empty+ } else {+ return Repeat<#y>{ value, count }+ }+ }++ next () {+ if (count > 1) {+ count <- count-1+ return self+ } else {+ return empty+ }+ }++ get () {+ return value+ }+}
tests/typename.0rt view
@@ -110,23 +110,3 @@ fail(name) } }---testcase "bad instance in typename param" {- error- require "Test"- require "define"- require "Equals"-}--unittest test {- \ typename<Value<Test>>()-}--@value interface Value<#x> {- #x defines Equals<#x>-}--concrete Test {}--define Test {}
zeolite-lang.cabal view
@@ -1,7 +1,7 @@ cabal-version: 2.2 name: zeolite-lang-version: 0.15.0.0+version: 0.16.0.0 synopsis: Zeolite is a statically-typed, general-purpose programming language. description:@@ -80,6 +80,10 @@ example/parser/*.0rt, example/parser/*.0rx, example/parser/*.txt,+ example/primes/.zeolite-module,+ example/primes/README.md,+ example/primes/*.0rp,+ example/primes/*.0rx, lib/container/README.md, lib/container/.zeolite-module, lib/container/*.0rp,