From 762c9a4d481e66d10daa0f558436aafb4a1b621b Mon Sep 17 00:00:00 2001 From: stdweird Date: Wed, 16 Aug 2017 22:55:15 +0200 Subject: [PATCH] pan: support default/fallback value for built-in function value() --- .../standard-functions/standard-functions.rst | 15 +++++- .../org/quattor/pan/dml/functions/Value.java | 49 ++++++++++++------- .../test/pan/Functionality/value/value2.pan | 10 ++++ .../test/pan/Functionality/value/value3.pan | 7 +++ .../test/pan/Functionality/value/value4.pan | 16 ++++++ .../test/pan/Functionality/value/value5.pan | 7 +++ .../test/pan/Functionality/value/value6.pan | 5 ++ .../test/pan/Functionality/value/value7.pan | 4 ++ .../test/pan/Functionality/value/value8.pan | 4 ++ .../test/pan/Functionality/value/value9.pan | 9 ++++ 10 files changed, 106 insertions(+), 20 deletions(-) create mode 100644 panc/src/test/pan/Functionality/value/value2.pan create mode 100644 panc/src/test/pan/Functionality/value/value3.pan create mode 100644 panc/src/test/pan/Functionality/value/value4.pan create mode 100644 panc/src/test/pan/Functionality/value/value5.pan create mode 100644 panc/src/test/pan/Functionality/value/value6.pan create mode 100644 panc/src/test/pan/Functionality/value/value7.pan create mode 100644 panc/src/test/pan/Functionality/value/value8.pan create mode 100644 panc/src/test/pan/Functionality/value/value9.pan diff --git a/panc-docs/source/standard-functions/standard-functions.rst b/panc-docs/source/standard-functions/standard-functions.rst index 3e163c4e..b069236b 100644 --- a/panc-docs/source/standard-functions/standard-functions.rst +++ b/panc-docs/source/standard-functions/standard-functions.rst @@ -1870,15 +1870,28 @@ Synopsis -------- element **value** (string *path*) +element **value** (string *path*, element *default*) Description ----------- This function returns the element identified by the given path, which -can be an external path. An error occurs if there is no such element. +can be an external path. An error occurs if there is no such element +and no (optional) default is provided. +If a `default` element is defined as second argument, +and either there is no element for the given path or +the (current) element of the given path is `undef`, +the default element is returned. :: # /y will be 200 '/x' = 100; '/y' = 2 * value('/x'); + + # /z will be (the default) 10 + '/z' = value('/nopath', 10); + + # /v will be (the default) 5 + '/u' = undef; + '/v' = value('/u', 5); diff --git a/panc/src/main/java/org/quattor/pan/dml/functions/Value.java b/panc/src/main/java/org/quattor/pan/dml/functions/Value.java index 276350f1..e12be900 100644 --- a/panc/src/main/java/org/quattor/pan/dml/functions/Value.java +++ b/panc/src/main/java/org/quattor/pan/dml/functions/Value.java @@ -20,11 +20,12 @@ Centre National de la Recherche Scientifique (CNRS). package org.quattor.pan.dml.functions; -import static org.quattor.pan.utils.MessageUtils.MSG_ONE_STRING_ARG_REQ; +import static org.quattor.pan.utils.MessageUtils.MSG_ONE_OR_TWO_ARGS_REQ; import org.quattor.pan.dml.Operation; import org.quattor.pan.dml.data.Element; import org.quattor.pan.dml.data.StringProperty; +import org.quattor.pan.dml.data.Undef; import org.quattor.pan.exceptions.EvaluationException; import org.quattor.pan.exceptions.SyntaxException; import org.quattor.pan.template.Context; @@ -33,9 +34,9 @@ Centre National de la Recherche Scientifique (CNRS). /** * Extract a value from the configuration tree based on a given path. - * + * * @author loomis - * + * */ final public class Value extends BuiltInFunction { @@ -47,13 +48,12 @@ private Value(SourceRange sourceRange, Operation... operations) public static Operation getInstance(SourceRange sourceRange, Operation... operations) throws SyntaxException { - // Ensure that there is exactly one argument. Since the parser does - // little argument checking for function calls, this explicit check is - // needed. - if (operations.length != 1) { - throw SyntaxException.create(sourceRange, MSG_ONE_STRING_ARG_REQ, + // This must have either one or two arguments. + if (operations.length < 1 || operations.length > 2) { + throw SyntaxException.create(sourceRange, MSG_ONE_OR_TWO_ARGS_REQ, "value"); } + assert (operations.length == 1 || operations.length == 2); return new Value(sourceRange, operations); } @@ -61,37 +61,48 @@ public static Operation getInstance(SourceRange sourceRange, @Override public Element execute(Context context) { - assert (ops.length == 1); + // Retrieve the values of the arguments. + Element[] args = calculateArgs(context); + + assert (ops.length == 1 || ops.length == 2); throwExceptionIfCompileTimeContext(context); Element result = null; Path p = null; try { - String s = ((StringProperty) ops[0].execute(context)).getValue(); + String s = ((StringProperty) args[0]).getValue(); try { p = new Path(s); - result = context.getElement(p); + // errorIfNotFound=false; missing path is handled w optional default below + result = context.getElement(p, false); } catch (SyntaxException se) { throw new EvaluationException(se.getSimpleMessage(), sourceRange, context); } } catch (ClassCastException cce) { - Element element = ops[0].execute(context); throw new EvaluationException( "value() requires one string argument; " - + element.getTypeAsString() + " found", + + args[0].getTypeAsString() + " found", getSourceRange(), context); } + + if (result == null) { + if (ops.length == 2) { + // 2nd arg is default value + result = args[1]; + } else { + throw new EvaluationException("referenced path (" + p + + ") doesn't exist", getSourceRange(), context); + } + } else if (result instanceof Undef && ops.length == 2) { + result = args[1]; + } + // Return the result. ALWAYS duplicate the value to ensure that any // changes to returned resources do not inadvertently change the // referenced part of the configuration. - if (result != null) { - return result.duplicate(); - } else { - throw new EvaluationException("referenced path (" + p - + ") doesn't exist", getSourceRange(), context); - } + return result.duplicate(); } } diff --git a/panc/src/test/pan/Functionality/value/value2.pan b/panc/src/test/pan/Functionality/value/value2.pan new file mode 100644 index 00000000..d4a3d852 --- /dev/null +++ b/panc/src/test/pan/Functionality/value/value2.pan @@ -0,0 +1,10 @@ +# @expect="/nlist[@name="profile"]/long[@name="a"]=0 and /nlist[@name="profile"]/long[@name="value"]=0 and /nlist[@name="profile"]/long[@name="default"]=1" +# @format=pan +# +object template value2; + +variable SOMETHING = dict("key", "abc"); + +"/a" = 0; +"/value" = value("/a", 1); +"/default" = value("/nopath", 1); diff --git a/panc/src/test/pan/Functionality/value/value3.pan b/panc/src/test/pan/Functionality/value/value3.pan new file mode 100644 index 00000000..0393c64d --- /dev/null +++ b/panc/src/test/pan/Functionality/value/value3.pan @@ -0,0 +1,7 @@ +# @expect="/nlist[@name='profile']/boolean[@name='undef']='true' and /nlist[@name='profile']/boolean[@name='null']='true'" +# @format=pan +# +object template value3; + +"/undef" = !is_defined(value("/nopath", undef)); +"/null" = is_null(value("/nopath", null)); diff --git a/panc/src/test/pan/Functionality/value/value4.pan b/panc/src/test/pan/Functionality/value/value4.pan new file mode 100644 index 00000000..30defc3c --- /dev/null +++ b/panc/src/test/pan/Functionality/value/value4.pan @@ -0,0 +1,16 @@ +# @expect="/nlist[@name='profile']/nlist[@name='var']/string[@name='key']='abc' and /nlist[@name='profile']/nlist[@name='othervar']/string[@name='key']='xyz' and /nlist[@name='profile']/nlist[@name='origvar']/string[@name='key']='abc'" +# @format=pan +# +object template value4; + +variable SOMETHING = dict("key", "abc"); + +"/var" = value("/nopath", SOMETHING); +# test copy of variable +"/othervar" = { + t = value("/nopath", SOMETHING); + # modify the value, should not modify the original variable + t['key'] = 'xyz'; + t; +}; +"/origvar" = SOMETHING; diff --git a/panc/src/test/pan/Functionality/value/value5.pan b/panc/src/test/pan/Functionality/value/value5.pan new file mode 100644 index 00000000..c68ddb30 --- /dev/null +++ b/panc/src/test/pan/Functionality/value/value5.pan @@ -0,0 +1,7 @@ +# @expect="/nlist[@name='profile']/string[@name='self']='myself'" +# @format=pan +# +object template value5; + +"/self" = "myself"; +"/self" = value("/nopath", SELF); diff --git a/panc/src/test/pan/Functionality/value/value6.pan b/panc/src/test/pan/Functionality/value/value6.pan new file mode 100644 index 00000000..8cdf8eb3 --- /dev/null +++ b/panc/src/test/pan/Functionality/value/value6.pan @@ -0,0 +1,5 @@ +# @expect=org.quattor.pan.exceptions.EvaluationException +object template value6; + +# reraise Syntax error as Evaluation error +"/a" = value(list(1)); diff --git a/panc/src/test/pan/Functionality/value/value7.pan b/panc/src/test/pan/Functionality/value/value7.pan new file mode 100644 index 00000000..13dc5fe1 --- /dev/null +++ b/panc/src/test/pan/Functionality/value/value7.pan @@ -0,0 +1,4 @@ +# @expect=org.quattor.pan.exceptions.EvaluationException +object template value7; + +"/a" = value("/nopath"); diff --git a/panc/src/test/pan/Functionality/value/value8.pan b/panc/src/test/pan/Functionality/value/value8.pan new file mode 100644 index 00000000..5bdf8fb4 --- /dev/null +++ b/panc/src/test/pan/Functionality/value/value8.pan @@ -0,0 +1,4 @@ +# @expect=org.quattor.pan.exceptions.EvaluationException +object template value8; + +"/a" = value("/nopath", garbage); diff --git a/panc/src/test/pan/Functionality/value/value9.pan b/panc/src/test/pan/Functionality/value/value9.pan new file mode 100644 index 00000000..ab4d791c --- /dev/null +++ b/panc/src/test/pan/Functionality/value/value9.pan @@ -0,0 +1,9 @@ +# @expect="/nlist[@name="profile"]/long[@name="undef"]=0 and /nlist[@name="profile"]/long[@name="value"]=5" +# @format=pan +# +object template value9; + +bind "/undef" = long = 0; + +"/undef" = undef; +"/value" = value("/undef", 5);