From b09382fcd1baa62df37253594a65cef6dfb4fa48 Mon Sep 17 00:00:00 2001 From: Nicolas Pierron Date: Mon, 13 Jul 2009 16:18:52 +0000 Subject: [PATCH] Extract properties.nix and modules.nix from options.nix. svn path=/nixpkgs/trunk/; revision=16339 --- pkgs/lib/default.nix | 6 +- pkgs/lib/modules.nix | 71 +++++++ pkgs/lib/options.nix | 419 +--------------------------------------- pkgs/lib/properties.nix | 371 +++++++++++++++++++++++++++++++++++ 4 files changed, 448 insertions(+), 419 deletions(-) create mode 100644 pkgs/lib/modules.nix create mode 100644 pkgs/lib/properties.nix diff --git a/pkgs/lib/default.nix b/pkgs/lib/default.nix index f3682f9f365..01f01d5cb16 100644 --- a/pkgs/lib/default.nix +++ b/pkgs/lib/default.nix @@ -6,7 +6,9 @@ let stringsWithDeps = import ./strings-with-deps.nix; attrsets = import ./attrsets.nix; sources = import ./sources.nix; + modules = import ./modules.nix; options = import ./options.nix; + properties = import ./properties.nix; types = import ./types.nix; meta = import ./meta.nix; debug = import ./debug.nix; @@ -15,9 +17,9 @@ let in { inherit trivial lists strings stringsWithDeps attrsets sources options - types meta debug maintainers; + properties modules types meta debug maintainers; } # !!! don't include everything at top-level; perhaps only the most # commonly used functions. // trivial // lists // strings // stringsWithDeps // attrsets // sources - // options // types // meta // debug // misc + // properties // options // types // meta // debug // misc diff --git a/pkgs/lib/modules.nix b/pkgs/lib/modules.nix new file mode 100644 index 00000000000..0b92462ee3e --- /dev/null +++ b/pkgs/lib/modules.nix @@ -0,0 +1,71 @@ +# NixOS module handling. + +let lib = import ./default.nix; in + +with { inherit (builtins) head tail; }; +with import ./trivial.nix; +with import ./lists.nix; +with import ./misc.nix; +with import ./attrsets.nix; +with import ./properties.nix; + +rec { + + # Unfortunately this can also be a string. + isPath = x: !( + builtins.isFunction x + || builtins.isAttrs x + || builtins.isInt x + || builtins.isBool x + || builtins.isList x + ); + + importIfPath = path: + if isPath path then + import path + else + path; + + applyIfFunction = f: arg: + if builtins.isFunction f then + f arg + else + f; + + moduleClosure = initModules: args: + let + moduleImport = m: + (applyIfFunction (importIfPath m) args) // { + # used by generic closure to avoid duplicated imports. + key = m; + }; + + removeKeys = list: map (m: removeAttrs m ["key"]) list; + + getImports = m: + if m ? config || m ? options then + attrByPath ["imports"] [] m + else + toList (rmProperties (attrByPath ["require"] [] (delayProperties m))); + + getImportedPaths = m: filter isPath (getImports m); + getImportedSets = m: filter (x: !isPath x) (getImports m); + + inlineImportedSets = list: + lib.concatMap (m:[m] ++ map moduleImport (getImportedSets m)) list; + in + removeKeys (inlineImportedSets (lazyGenericClosure { + startSet = map moduleImport initModules; + operator = m: map moduleImport (getImportedPaths m); + })); + + selectDeclsAndDefs = modules: + lib.concatMap (m: + if m ? config || m ? options then + attrByPath ["options"] [] m + ++ attrByPath ["config"] [] m + else + [ m ] + ) modules; + +} \ No newline at end of file diff --git a/pkgs/lib/options.nix b/pkgs/lib/options.nix index f674b399415..34492b289df 100644 --- a/pkgs/lib/options.nix +++ b/pkgs/lib/options.nix @@ -7,6 +7,8 @@ with import ./trivial.nix; with import ./lists.nix; with import ./misc.nix; with import ./attrsets.nix; +with import ./properties.nix; +with import ./modules.nix; rec { @@ -253,64 +255,6 @@ rec { }; - # Unfortunately this can also be a string. - isPath = x: !( - builtins.isFunction x - || builtins.isAttrs x - || builtins.isInt x - || builtins.isBool x - || builtins.isList x - ); - - importIfPath = path: - if isPath path then - import path - else - path; - - applyIfFunction = f: arg: - if builtins.isFunction f then - f arg - else - f; - - moduleClosure = initModules: args: - let - moduleImport = m: - (applyIfFunction (importIfPath m) args) // { - # used by generic closure to avoid duplicated imports. - key = m; - }; - - removeKeys = list: map (m: removeAttrs m ["key"]) list; - - getImports = m: - if m ? config || m ? options then - attrByPath ["imports"] [] m - else - toList (rmProperties (attrByPath ["require"] [] (delayProperties m))); - - getImportedPaths = m: filter isPath (getImports m); - getImportedSets = m: filter (x: !isPath x) (getImports m); - - inlineImportedSets = list: - lib.concatMap (m:[m] ++ map moduleImport (getImportedSets m)) list; - in - removeKeys (inlineImportedSets (lazyGenericClosure { - startSet = map moduleImport initModules; - operator = m: map moduleImport (getImportedPaths m); - })); - - selectDeclsAndDefs = modules: - lib.concatMap (m: - if m ? config || m ? options then - attrByPath ["options"] [] m - ++ attrByPath ["config"] [] m - else - [ m ] - ) modules; - - fixableMergeFun = merge: f: config: merge ( # remove require because this is not an option. @@ -384,363 +328,4 @@ rec { ) [] options; - /* Option Properties */ - # Generalize the problem of delayable properties. Any property can be created - - - # Tell that nothing is defined. When properties are evaluated, this type - # is used to remove an entry. Thus if your property evaluation semantic - # implies that you have to mute the content of an attribute, then your - # property should produce this value. - isNotdef = attrs: (typeOf attrs) == "notdef"; - mkNotdef = {_type = "notdef";}; - - # General property type, it has a property attribute and a content - # attribute. The property attribute refer to an attribute set which - # contains a _type attribute and a list of functions which are used to - # evaluate this property. The content attribute is used to stack property - # on top of each other. - # - # The optional functions which may be contained in the property attribute - # are: - # - onDelay: run on a copied property. - # - onGlobalDelay: run on all copied properties. - # - onEval: run on an evaluated property. - # - onGlobalEval: run on a list of property stack on top of their values. - isProperty = attrs: (typeOf attrs) == "property"; - mkProperty = p@{property, content, ...}: p // { - _type = "property"; - }; - - # Go throw the stack of properties and apply the function `op' on all - # property and call the function `nul' on the final value which is not a - # property. The stack is traversed in reversed order. The `op' function - # should expect a property with a content which have been modified. - # - # Warning: The `op' function expects only one argument in order to avoid - # calls to mkProperties as the argument is already a valid property which - # contains the result of the folding inside the content attribute. - foldProperty = op: nul: attrs: - if isProperty attrs then - op (attrs // { - content = foldProperty op nul attrs.content; - }) - else - nul attrs; - - # Simple function which can be used as the `op' argument of the - # foldProperty function. Properties that you don't want to handle can be - # ignored with the `id' function. `isSearched' is a function which should - # check the type of a property and return a boolean value. `thenFun' and - # `elseFun' are functions which behave as the `op' argument of the - # foldProperty function. - foldFilter = isSearched: thenFun: elseFun: attrs: - if isSearched attrs.property then - thenFun attrs - else - elseFun attrs; - - - # Move properties from the current attribute set to the attribute - # contained in this attribute set. This trigger property handlers called - # `onDelay' and `onGlobalDelay'. - delayProperties = attrs: - let cleanAttrs = rmProperties attrs; in - if isProperty attrs then - lib.mapAttrs (a: v: - lib.addErrorContext "while moving properties on the attribute `${a}'." ( - triggerPropertiesGlobalDelay a ( - triggerPropertiesDelay a ( - copyProperties attrs v - )))) cleanAttrs - else - attrs; - - # Call onDelay functions. - triggerPropertiesDelay = name: attrs: - let - callOnDelay = p@{property, ...}: - lib.addErrorContext "while calling a onDelay function." ( - if property ? onDelay then - property.onDelay name p - else - p - ); - in - foldProperty callOnDelay id attrs; - - # Call onGlobalDelay functions. - triggerPropertiesGlobalDelay = name: attrs: - let - globalDelayFuns = uniqListExt { - getter = property: property._type; - inputList = foldProperty (p@{property, content, ...}: - if property ? onGlobalDelay then - [ property ] ++ content - else - content - ) (a: []) attrs; - }; - - callOnGlobalDelay = property: content: - lib.addErrorContext "while calling a onGlobalDelay function." ( - property.onGlobalDelay name content - ); - in - fold callOnGlobalDelay attrs globalDelayFuns; - - # Expect a list of values which may have properties and return the same - # list of values where all properties have been evaluated and where all - # ignored values are removed. This trigger property handlers called - # `onEval' and `onGlobalEval'. - evalProperties = valList: - if valList != [] then - filter (x: !isNotdef x) ( - lib.addErrorContext "while evaluating properties an attribute." ( - triggerPropertiesGlobalEval ( - map triggerPropertiesEval valList - ))) - else - valList; - - # Call onEval function - triggerPropertiesEval = val: - foldProperty (p@{property, ...}: - lib.addErrorContext "while calling a onEval function." ( - if property ? onEval then - property.onEval p - else - p - ) - ) id val; - - # Call onGlobalEval function - triggerPropertiesGlobalEval = valList: - let - globalEvalFuns = uniqListExt { - getter = property: property._type; - inputList = - fold (attrs: list: - foldProperty (p@{property, content, ...}: - if property ? onGlobalEval then - [ property ] ++ content - else - content - ) (a: list) attrs - ) [] valList; - }; - - callOnGlobalEval = property: valList: - lib.addErrorContext "while calling a onGlobalEval function." ( - property.onGlobalEval valList - ); - in - fold callOnGlobalEval valList globalEvalFuns; - - # Remove all properties on top of a value and return the value. - rmProperties = - foldProperty (p@{content, ...}: content) id; - - # Copy properties defined on a value on another value. - copyProperties = attrs: newAttrs: - foldProperty id (x: newAttrs) attrs; - - /* If. ThenElse. Always. */ - - # create "if" statement that can be delayed on sets until a "then-else" or - # "always" set is reached. When an always set is reached the condition - # is ignore. - - # Create a "If" property which only contains a condition. - isIf = attrs: (typeOf attrs) == "if"; - mkIf = condition: content: mkProperty { - property = { - _type = "if"; - onGlobalDelay = onIfGlobalDelay; - onEval = onIfEval; - inherit condition; - }; - inherit content; - }; - - # Create a "ThenElse" property which contains choices which can choosed by - # the evaluation of an "If" statement. - isThenElse = attrs: (typeOf attrs) == "then-else"; - mkThenElse = attrs: - assert attrs ? thenPart && attrs ? elsePart; - mkProperty { - property = { - _type = "then-else"; - onEval = val: throw "Missing mkIf statement."; - inherit (attrs) thenPart elsePart; - }; - content = mkNotdef; - }; - - # Create an "Always" property remove ignore all "If" statement. - isAlways = attrs: (typeOf attrs) == "always"; - mkAlways = value: - mkProperty { - property = { - _type = "always"; - onEval = p@{content, ...}: content; - inherit value; - }; - content = mkNotdef; - }; - - # Remove all "If" statement defined on a value. - rmIf = foldProperty ( - foldFilter isIf - ({content, ...}: content) - id - ) id; - - # Evaluate the "If" statements when either "ThenElse" or "Always" - # statement is encounter. Otherwise it remove multiple If statement and - # replace them by one "If" staement where the condition is the list of all - # conditions joined with a "and" operation. - onIfGlobalDelay = name: content: - let - # extract if statements and non-if statements and repectively put them - # in the attribute list and attrs. - ifProps = - foldProperty - (foldFilter (p: isIf p || isThenElse p || isAlways p) - # then, push the codition inside the list list - (p@{property, content, ...}: - { inherit (content) attrs; - list = [property] ++ content.list; - } - ) - # otherwise, add the propertie. - (p@{property, content, ...}: - { inherit (content) list; - attrs = p // { content = content.attrs; }; - } - ) - ) - (attrs: { list = []; inherit attrs; }) - content; - - # compute the list of if statements. - evalIf = content: condition: list: - if list == [] then - mkIf condition content - else - let p = head list; in - - # evaluate the condition. - if isThenElse p then - if condition then - copyProperties content p.thenPart - else - copyProperties content p.elsePart - # ignore the condition. - else if isAlways p then - copyProperties content p.value - # otherwise (isIf) - else - evalIf content (condition && p.condition) (tail list); - in - evalIf ifProps.attrs true ifProps.list; - - # Evaluate the condition of the "If" statement to either get the value or - # to ignore the value. - onIfEval = p@{property, content, ...}: - if property.condition then - content - else - mkNotdef; - - /* mkOverride */ - - # Create an "Override" statement which allow the user to define - # prioprities between values. The default priority is 100 and the lowest - # priorities are kept. The template argument must reproduce the same - # attribute set hierachy to override leaves of the hierarchy. - isOverride = attrs: (typeOf attrs) == "override"; - mkOverride = priority: template: content: mkProperty { - property = { - _type = "override"; - onDelay = onOverrideDelay; - onGlobalEval = onOverrideGlobalEval; - inherit priority template; - }; - inherit content; - }; - - # Sugar to override the default value of the option by making a new - # default value based on the configuration. - mkDefaultValue = content: mkOverride 1000 {} content; - - # Make the template traversal in function of the property traversal. If - # the template define a non-empty attribute set, then the property is - # copied only on all mentionned attributes inside the template. - # Otherwise, the property is kept on all sub-attribute definitions. - onOverrideDelay = name: p@{property, content, ...}: - let inherit (property) template; in - if isAttrs template && template != {} then - if hasAttr name template then - p // { - property = p.property // { - template = builtins.getAttr name template; - }; - } - # Do not override the attribute \name\ - else - content - # Override values defined inside the attribute \name\. - else - p; - - # Ignore all values which have a higher value of the priority number. - onOverrideGlobalEval = valList: - let - defaultPrio = 100; - - inherit (builtins) lessThan; - - getPrioVal = - foldProperty - (foldFilter isOverride - (p@{property, content, ...}: - if content ? priority && lessThan content.priority property.priority then - content - else - content // { - inherit (property) priority; - } - ) - (p@{property, content, ...}: - content // { - value = p // { content = content.value; }; - } - ) - ) (value: { inherit value; }); - - addDefaultPrio = x: - if x ? priority then x - else x // { priority = defaultPrio; }; - - prioValList = map (x: addDefaultPrio (getPrioVal x)) valList; - - higherPrio = - if prioValList == [] then - defaultPrio - else - fold (x: min: - if lessThan x.priority min then - x.priority - else - min - ) (head prioValList).priority (tail prioValList); - in - map (x: - if x.priority == higherPrio then - x.value - else - mkNotdef - ) prioValList; - } diff --git a/pkgs/lib/properties.nix b/pkgs/lib/properties.nix new file mode 100644 index 00000000000..91f65c448ec --- /dev/null +++ b/pkgs/lib/properties.nix @@ -0,0 +1,371 @@ +# Nixpkgs/NixOS properties. Generalize the problem of delayable (not yet +# evaluable) properties like mkIf. + +let lib = import ./default.nix; in + +with { inherit (builtins) head tail; }; +with import ./trivial.nix; +with import ./lists.nix; +with import ./misc.nix; +with import ./attrsets.nix; + +rec { + + inherit (lib) typeOf; + + # Tell that nothing is defined. When properties are evaluated, this type + # is used to remove an entry. Thus if your property evaluation semantic + # implies that you have to mute the content of an attribute, then your + # property should produce this value. + isNotdef = attrs: (typeOf attrs) == "notdef"; + mkNotdef = {_type = "notdef";}; + + # General property type, it has a property attribute and a content + # attribute. The property attribute refer to an attribute set which + # contains a _type attribute and a list of functions which are used to + # evaluate this property. The content attribute is used to stack property + # on top of each other. + # + # The optional functions which may be contained in the property attribute + # are: + # - onDelay: run on a copied property. + # - onGlobalDelay: run on all copied properties. + # - onEval: run on an evaluated property. + # - onGlobalEval: run on a list of property stack on top of their values. + isProperty = attrs: (typeOf attrs) == "property"; + mkProperty = p@{property, content, ...}: p // { + _type = "property"; + }; + + # Go through the stack of properties and apply the function `op' on all + # property and call the function `nul' on the final value which is not a + # property. The stack is traversed in reversed order. The `op' function + # should expect a property with a content which have been modified. + # + # Warning: The `op' function expects only one argument in order to avoid + # calls to mkProperties as the argument is already a valid property which + # contains the result of the folding inside the content attribute. + foldProperty = op: nul: attrs: + if isProperty attrs then + op (attrs // { + content = foldProperty op nul attrs.content; + }) + else + nul attrs; + + # Simple function which can be used as the `op' argument of the + # foldProperty function. Properties that you don't want to handle can be + # ignored with the `id' function. `isSearched' is a function which should + # check the type of a property and return a boolean value. `thenFun' and + # `elseFun' are functions which behave as the `op' argument of the + # foldProperty function. + foldFilter = isSearched: thenFun: elseFun: attrs: + if isSearched attrs.property then + thenFun attrs + else + elseFun attrs; + + + # Move properties from the current attribute set to the attribute + # contained in this attribute set. This trigger property handlers called + # `onDelay' and `onGlobalDelay'. + delayProperties = attrs: + let cleanAttrs = rmProperties attrs; in + if isProperty attrs then + lib.mapAttrs (a: v: + lib.addErrorContext "while moving properties on the attribute `${a}'." ( + triggerPropertiesGlobalDelay a ( + triggerPropertiesDelay a ( + copyProperties attrs v + )))) cleanAttrs + else + attrs; + + # Call onDelay functions. + triggerPropertiesDelay = name: attrs: + let + callOnDelay = p@{property, ...}: + lib.addErrorContext "while calling a onDelay function." ( + if property ? onDelay then + property.onDelay name p + else + p + ); + in + foldProperty callOnDelay id attrs; + + # Call onGlobalDelay functions. + triggerPropertiesGlobalDelay = name: attrs: + let + globalDelayFuns = uniqListExt { + getter = property: property._type; + inputList = foldProperty (p@{property, content, ...}: + if property ? onGlobalDelay then + [ property ] ++ content + else + content + ) (a: []) attrs; + }; + + callOnGlobalDelay = property: content: + lib.addErrorContext "while calling a onGlobalDelay function." ( + property.onGlobalDelay name content + ); + in + fold callOnGlobalDelay attrs globalDelayFuns; + + # Expect a list of values which may have properties and return the same + # list of values where all properties have been evaluated and where all + # ignored values are removed. This trigger property handlers called + # `onEval' and `onGlobalEval'. + evalProperties = valList: + if valList != [] then + filter (x: !isNotdef x) ( + lib.addErrorContext "while evaluating properties an attribute." ( + triggerPropertiesGlobalEval ( + map triggerPropertiesEval valList + ))) + else + valList; + + # Call onEval function + triggerPropertiesEval = val: + foldProperty (p@{property, ...}: + lib.addErrorContext "while calling a onEval function." ( + if property ? onEval then + property.onEval p + else + p + ) + ) id val; + + # Call onGlobalEval function + triggerPropertiesGlobalEval = valList: + let + globalEvalFuns = uniqListExt { + getter = property: property._type; + inputList = + fold (attrs: list: + foldProperty (p@{property, content, ...}: + if property ? onGlobalEval then + [ property ] ++ content + else + content + ) (a: list) attrs + ) [] valList; + }; + + callOnGlobalEval = property: valList: + lib.addErrorContext "while calling a onGlobalEval function." ( + property.onGlobalEval valList + ); + in + fold callOnGlobalEval valList globalEvalFuns; + + # Remove all properties on top of a value and return the value. + rmProperties = + foldProperty (p@{content, ...}: content) id; + + # Copy properties defined on a value on another value. + copyProperties = attrs: newAttrs: + foldProperty id (x: newAttrs) attrs; + + /* If. ThenElse. Always. */ + + # create "if" statement that can be delayed on sets until a "then-else" or + # "always" set is reached. When an always set is reached the condition + # is ignore. + + # Create a "If" property which only contains a condition. + isIf = attrs: (typeOf attrs) == "if"; + mkIf = condition: content: mkProperty { + property = { + _type = "if"; + onGlobalDelay = onIfGlobalDelay; + onEval = onIfEval; + inherit condition; + }; + inherit content; + }; + + # Create a "ThenElse" property which contains choices which can choosed by + # the evaluation of an "If" statement. + isThenElse = attrs: (typeOf attrs) == "then-else"; + mkThenElse = attrs: + assert attrs ? thenPart && attrs ? elsePart; + mkProperty { + property = { + _type = "then-else"; + onEval = val: throw "Missing mkIf statement."; + inherit (attrs) thenPart elsePart; + }; + content = mkNotdef; + }; + + # Create an "Always" property remove ignore all "If" statement. + isAlways = attrs: (typeOf attrs) == "always"; + mkAlways = value: + mkProperty { + property = { + _type = "always"; + onEval = p@{content, ...}: content; + inherit value; + }; + content = mkNotdef; + }; + + # Remove all "If" statement defined on a value. + rmIf = foldProperty ( + foldFilter isIf + ({content, ...}: content) + id + ) id; + + # Evaluate the "If" statements when either "ThenElse" or "Always" + # statement is encounter. Otherwise it remove multiple If statement and + # replace them by one "If" staement where the condition is the list of all + # conditions joined with a "and" operation. + onIfGlobalDelay = name: content: + let + # extract if statements and non-if statements and repectively put them + # in the attribute list and attrs. + ifProps = + foldProperty + (foldFilter (p: isIf p || isThenElse p || isAlways p) + # then, push the codition inside the list list + (p@{property, content, ...}: + { inherit (content) attrs; + list = [property] ++ content.list; + } + ) + # otherwise, add the propertie. + (p@{property, content, ...}: + { inherit (content) list; + attrs = p // { content = content.attrs; }; + } + ) + ) + (attrs: { list = []; inherit attrs; }) + content; + + # compute the list of if statements. + evalIf = content: condition: list: + if list == [] then + mkIf condition content + else + let p = head list; in + + # evaluate the condition. + if isThenElse p then + if condition then + copyProperties content p.thenPart + else + copyProperties content p.elsePart + # ignore the condition. + else if isAlways p then + copyProperties content p.value + # otherwise (isIf) + else + evalIf content (condition && p.condition) (tail list); + in + evalIf ifProps.attrs true ifProps.list; + + # Evaluate the condition of the "If" statement to either get the value or + # to ignore the value. + onIfEval = p@{property, content, ...}: + if property.condition then + content + else + mkNotdef; + + /* mkOverride */ + + # Create an "Override" statement which allow the user to define + # prioprities between values. The default priority is 100 and the lowest + # priorities are kept. The template argument must reproduce the same + # attribute set hierachy to override leaves of the hierarchy. + isOverride = attrs: (typeOf attrs) == "override"; + mkOverride = priority: template: content: mkProperty { + property = { + _type = "override"; + onDelay = onOverrideDelay; + onGlobalEval = onOverrideGlobalEval; + inherit priority template; + }; + inherit content; + }; + + # Sugar to override the default value of the option by making a new + # default value based on the configuration. + mkDefaultValue = content: mkOverride 1000 {} content; + + # Make the template traversal in function of the property traversal. If + # the template define a non-empty attribute set, then the property is + # copied only on all mentionned attributes inside the template. + # Otherwise, the property is kept on all sub-attribute definitions. + onOverrideDelay = name: p@{property, content, ...}: + let inherit (property) template; in + if isAttrs template && template != {} then + if hasAttr name template then + p // { + property = p.property // { + template = builtins.getAttr name template; + }; + } + # Do not override the attribute \name\ + else + content + # Override values defined inside the attribute \name\. + else + p; + + # Ignore all values which have a higher value of the priority number. + onOverrideGlobalEval = valList: + let + defaultPrio = 100; + + inherit (builtins) lessThan; + + getPrioVal = + foldProperty + (foldFilter isOverride + (p@{property, content, ...}: + if content ? priority && lessThan content.priority property.priority then + content + else + content // { + inherit (property) priority; + } + ) + (p@{property, content, ...}: + content // { + value = p // { content = content.value; }; + } + ) + ) (value: { inherit value; }); + + addDefaultPrio = x: + if x ? priority then x + else x // { priority = defaultPrio; }; + + prioValList = map (x: addDefaultPrio (getPrioVal x)) valList; + + higherPrio = + if prioValList == [] then + defaultPrio + else + fold (x: min: + if lessThan x.priority min then + x.priority + else + min + ) (head prioValList).priority (tail prioValList); + in + map (x: + if x.priority == higherPrio then + x.value + else + mkNotdef + ) prioValList; + +} \ No newline at end of file