Skip to content

Commit

Permalink
Merge pull request #167 from stdweird/value_default
Browse files Browse the repository at this point in the history
pan: support default/fallback value for built-in function value()
  • Loading branch information
jrha authored Mar 28, 2018
2 parents 2211bf4 + 762c9a4 commit 4e64bce
Show file tree
Hide file tree
Showing 10 changed files with 106 additions and 20 deletions.
15 changes: 14 additions & 1 deletion panc-docs/source/standard-functions/standard-functions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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);
49 changes: 30 additions & 19 deletions panc/src/main/java/org/quattor/pan/dml/functions/Value.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 {

Expand All @@ -47,51 +48,61 @@ 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);
}

@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();
}
}
10 changes: 10 additions & 0 deletions panc/src/test/pan/Functionality/value/value2.pan
Original file line number Diff line number Diff line change
@@ -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);
7 changes: 7 additions & 0 deletions panc/src/test/pan/Functionality/value/value3.pan
Original file line number Diff line number Diff line change
@@ -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));
16 changes: 16 additions & 0 deletions panc/src/test/pan/Functionality/value/value4.pan
Original file line number Diff line number Diff line change
@@ -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;
7 changes: 7 additions & 0 deletions panc/src/test/pan/Functionality/value/value5.pan
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# @expect="/nlist[@name='profile']/string[@name='self']='myself'"
# @format=pan
#
object template value5;

"/self" = "myself";
"/self" = value("/nopath", SELF);
5 changes: 5 additions & 0 deletions panc/src/test/pan/Functionality/value/value6.pan
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# @expect=org.quattor.pan.exceptions.EvaluationException
object template value6;

# reraise Syntax error as Evaluation error
"/a" = value(list(1));
4 changes: 4 additions & 0 deletions panc/src/test/pan/Functionality/value/value7.pan
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# @expect=org.quattor.pan.exceptions.EvaluationException
object template value7;

"/a" = value("/nopath");
4 changes: 4 additions & 0 deletions panc/src/test/pan/Functionality/value/value8.pan
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# @expect=org.quattor.pan.exceptions.EvaluationException
object template value8;

"/a" = value("/nopath", garbage);
9 changes: 9 additions & 0 deletions panc/src/test/pan/Functionality/value/value9.pan
Original file line number Diff line number Diff line change
@@ -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);

0 comments on commit 4e64bce

Please sign in to comment.