Related
This is a variation of Parsing single-quoted string with escaped quotes with Nom 5 and Parse string with escaped single quotes. I want to parse strings like '1 \' 2 \ 3 \\ 4' (a raw sequence of characters) as "1 \\' 2 \\ 3 \\\\ 4" (a Rust string), so I'm not concerned with any escaping other than the possibility of having \' inside the strings. Attempts using code from the linked questions:
use nom::{
branch::alt,
bytes::complete::{escaped, tag},
character::complete::none_of,
combinator::recognize,
multi::{many0, separated_list0},
sequence::delimited,
IResult,
};
fn parse_quoted_1(input: &str) -> IResult<&str, &str> {
delimited(
tag("'"),
alt((escaped(none_of("\\\'"), '\\', tag("'")), tag(""))),
tag("'"),
)(input)
}
fn parse_quoted_2(input: &str) -> IResult<&str, &str> {
delimited(
tag("'"),
recognize(separated_list0(tag("\\'"), many0(none_of("'")))),
tag("'"),
)(input)
}
fn main() {
println!("{:?}", parse_quoted_1(r#"'1'"#));
println!("{:?}", parse_quoted_2(r#"'1'"#));
println!("{:?}", parse_quoted_1(r#"'1 \' 2'"#));
println!("{:?}", parse_quoted_2(r#"'1 \' 2'"#));
println!("{:?}", parse_quoted_1(r#"'1 \' 2 \ 3'"#));
println!("{:?}", parse_quoted_2(r#"'1 \' 2 \ 3'"#));
println!("{:?}", parse_quoted_1(r#"'1 \' 2 \ 3 \\ 4'"#));
println!("{:?}", parse_quoted_2(r#"'1 \' 2 \ 3 \\ 4'"#));
}
/*
Ok(("", "1"))
Ok(("", "1"))
Ok(("", "1 \\' 2"))
Ok((" 2'", "1 \\"))
Err(Error(Error { input: "1 \\' 2 \\ 3'", code: Tag }))
Ok((" 2 \\ 3'", "1 \\"))
Err(Error(Error { input: "1 \\' 2 \\ 3 \\\\ 4'", code: Tag }))
Ok((" 2 \\ 3 \\\\ 4'", "1 \\"))
*/
Only first 3 cases work as intended.
A non-nice/imperative solution:
use nom::{bytes::complete::take, character::complete::char, sequence::delimited, IResult};
fn parse_quoted(input: &str) -> IResult<&str, &str> {
fn escaped(input: &str) -> IResult<&str, &str> {
let mut pc = 0 as char;
let mut n = 0;
for (i, c) in input.chars().enumerate() {
if c == '\'' && pc != '\\' {
break;
}
pc = c;
n = i + 1;
}
take(n)(input)
}
delimited(char('\''), escaped, char('\''))(input)
}
fn main() {
println!("{:?}", parse_quoted(r#"'' ..."#));
println!("{:?}", parse_quoted(r#"'1' ..."#));
println!("{:?}", parse_quoted(r#"'1 \' 2' ..."#));
println!("{:?}", parse_quoted(r#"'1 \' 2 \ 3' ..."#));
println!("{:?}", parse_quoted(r#"'1 \' 2 \ 3 \\ 4' ..."#));
}
/*
Ok((" ...", ""))
Ok((" ...", "1"))
Ok((" ...", "1 \\' 2"))
Ok((" ...", "1 \\' 2 \\ 3"))
Ok((" ...", "1 \\' 2 \\ 3 \\\\ 4"))
*/
To allow for '...\\' we can similarly store more previous characters:
let mut pc = 0 as char;
let mut ppc = 0 as char;
let mut pppc = 0 as char;
let mut n = 0;
for (i, c) in input.chars().enumerate() {
if (c == '\'' && pc != '\\') || (c == '\'' && pc == '\\' && ppc == '\\' && pppc != '\\') {
break;
}
pppc = ppc;
ppc = pc;
pc = c;
n = i + 1;
}
Here is my way to parse quoted string.
It returns Cow type with reference to original string when there is not strings that require escaping or copy of the string without escaping slashes.
You might need to adjust is_gdtext and is_quited_char to your needs.
// is valid character that do not require escaping
fn is_qdtext(chr: char) -> bool {
match chr {
'\t' => true,
' ' => true,
'!' => true,
'#'..='[' => true,
']'..='~' => true,
_ => {
let x = chr as u8;
x >= 0x80
}
}
}
// check if character can be escaped
fn is_quoted_char(chr: char) -> bool {
match chr {
' '..='~' => true,
'\t' => true,
_ => {
let x = chr as u8;
x >= 0x80
}
}
}
/// parse single escaped character
fn parse_quoted_pair(data: &str) -> IResult<&str, char> {
let (data, (_, chr)) = pair(tag("\\"), satisfy(is_quoted_char))(data)?;
Ok((data, chr))
}
// parse content of quoted string
fn parse_quoted_content(data: &str) -> IResult<&str, Cow<'_, str>> {
let (mut data, content) = data.split_at_position_complete(|item| !is_qdtext(item))?;
if data.chars().next() == Some('\\') {
// we need to escape some characters
let mut content = content.to_string();
while data.chars().next() == Some('\\') {
// unescape next char
let (next_data, chr) = parse_quoted_pair(data)?;
content.push(chr);
data = next_data;
// parse next plain text chunk
let (next_data, extra_content) =
data.split_at_position_complete(|item| !is_qdtext(item))?;
content.push_str(extra_content);
data = next_data;
}
Ok((data, Cow::Owned(content)))
} else {
// quick version, there is no characters to escape
Ok((data, Cow::Borrowed(content)))
}
}
fn parse_quoted_string(data: &str) -> IResult<&str, Cow<'_, str>> {
let (data, (_, content, _)) = tuple((tag("'"), parse_quoted_content, tag("'")))(data)?;
Ok((data, content))
}
I have tried different approaches and asked several specific questions regarding sub-problems of my requirement here. But my solution doesn't really work as expected, so I am taking a step back and ask here from a more general perspective. Please bear in mind that I am not a C++ pro. Not a beginner either, but I am still learning the language.
So, I have the following requirement. I need to read-in text files, which contain conditions, like "Greater" or "Equals", all like functions that return boolean values. The text files also include parameters for these conditions. Note that these parameters can be of different types (integer, decimal, etc.), and each such condition can take different number of parameters (e.g. "Equals" takes 2 paramters, while "Between" would take 3 parameters). Thus the file could look something like this:
Greater, 2, 3
Greater, 2.4, 1.0
Equals, true, true
Between, 20, 10, 30
The logic to read-in that file and parsing it is already done. Now I need to "concatenate" all these boolean functions with their parameters and check if all of them are true.
So I thought I would create functions or a class with static methods to represent these boolean test functions, then create a map of function pointers to these functions, mapped by their name. At runtime I would then read in the file, call the respective function pointer and pass-in the paramteres. That seemed easy to me, but in reality I am struggling mostly with the fact that these boolean functions can take a different number of parameters, and that these can be of different types.
Can you recommend a way to tackle that requirement in C++? I am not asking for a complete solution, but for a suitable C++ approach, or a guideline I could follow. Thanks in advance!
Here's a quick&dirty Spirit grammar for the input shown.
UPDATE
Now added invocation and implementation of the predicate functions (GreaterImpl and EqualsImpl).
I tried to be smart allowing comparisons between mixed arithmetic types (but not e.g. Greater(bool,string). If you compare incompatible types you will get a std::runtime_error exception that provides type feedback to the caller.
Live On Coliru
#include <deque>
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/adapted/struct.hpp>
namespace qi = boost::spirit::qi;
namespace Ast {
using Value = boost::variant<int, double, bool, std::string>;
using BinaryPred = std::function<bool(Value, Value)>;
using TernaryPred = std::function<bool(Value, Value, Value)>;
using Pred = boost::variant<BinaryPred, TernaryPred>;
using Values = std::vector<Value>;
struct Invocation { Pred pred; Values args; };
using Invocations = std::vector<Invocation>;
}
BOOST_FUSION_ADAPT_STRUCT(Ast::Invocation, pred, args)
namespace Predicates {
using Ast::Value;
struct Greater : boost::static_visitor<bool> {
bool operator()(Value const& a, Value const& b) const {
return boost::apply_visitor(*this, a, b);
}
template <typename T> bool operator()(T const& a, T const& b) const { return std::greater<T>{}(a, b); }
template <typename T, typename U>
typename std::enable_if<std::is_arithmetic<T>() && std::is_arithmetic<U>(), bool>::type
operator()(T const& a, U const& b) const { return a > b; }
template <typename T, typename U>
typename std::enable_if<not (std::is_arithmetic<T>() && std::is_arithmetic<U>()), bool>::type
operator()(T const&, U const&) const { throw std::runtime_error("Type Mismatch"); }
};
struct Equals : boost::static_visitor<bool> {
bool operator()(Value const& a, Value const& b) const {
return boost::apply_visitor(*this, a, b);
}
template <typename T> bool operator()(T const& a, T const& b) const { return std::equal_to<T>{}(a, b); }
template <typename T, typename U, typename enable = typename std::enable_if<std::is_arithmetic<T>() && std::is_arithmetic<U>()>::type >
bool operator()(T const& a, U const& b) const { return a == b; }
template <typename T, typename U>
typename std::enable_if<not (std::is_arithmetic<T>() && std::is_arithmetic<U>()), bool>::type
operator()(T const&, U const&) const { throw std::runtime_error("Type Mismatch"); }
};
struct Between {
bool operator()(Value const& v, Value const& lower, Value const& upper) const {
return Greater{}(v,lower) && Greater{}(upper,v);
}
};
}
static inline bool evaluate(Ast::Invocation const& i) {
struct Invoker {
using result_type = bool;
Ast::Values const& args;
result_type operator()(Ast::BinaryPred const& p) const {
if (args.size() != 2) throw std::runtime_error("Arity Mismatch");
return p(args.at(0), args.at(1));
}
result_type operator()(Ast::TernaryPred const& p) const {
if (args.size() != 3) throw std::runtime_error("Arity Mismatch");
return p(args.at(0), args.at(1), args.at(2));
}
};
return boost::apply_visitor(Invoker{i.args}, i.pred);
}
template <typename It>
struct Grammar : qi::grammar<It, Ast::Invocations()> {
Grammar() : Grammar::base_type(start) {
using namespace qi;
start = skip(blank) [ invocation % eol ];
invocation = pred >> -("," >> args);
args = arg % ",";
arg = my_double_ | qi::int_ | qi::bool_ | lexeme['"' > *~char_('"') > '"'];
}
private:
struct pred_t : qi::symbols<char, Ast::Pred> {
pred_t() {
this->add
("Greater", Predicates::Greater{})
("Equals", Predicates::Equals{})
("Between", Predicates::Between{})
;
}
} const pred;
qi::rule<It, Ast::Invocations()> start;
qi::rule<It, Ast::Invocation(), qi::blank_type> invocation;
qi::rule<It, Ast::Values(), qi::blank_type> args;
qi::rule<It, Ast::Value(), qi::blank_type> arg;
qi::real_parser<double, qi::strict_real_policies<double> > my_double_;
};
#include <sstream>
int main() {
using It = boost::spirit::istream_iterator;
std::deque<std::string> testcases {
// one multiline case:
"Between, 20, 10, 30\n"
"Between, NaN, NaN, NaN\n"
"Between, \"q\", \"a\", \"z\""
};
// many single line cases for easy test reporting
for (std::string op : {"Greater","Equals"})
for (auto rhs : { "42", "0.0", "true", "\"hello\"" })
for (auto lhs : { "41", "-0.0", "false", "\"bye\"" }) {
testcases.push_front(op + ", " + lhs + ", " + rhs);
}
for (auto testcase : testcases) {
std::cout << "--- Testcase '" << testcase << "' -> ";
std::istringstream iss(testcase);
It f(iss >> std::noskipws), l;
Ast::Invocations parsed;
if (qi::parse(f, l, Grammar<It>(), parsed)) {
for (auto& invocation : parsed) {
try {
std::cout << std::boolalpha << evaluate(invocation) << "; ";
} catch(std::exception const& e) {
std::cout << e.what() << "; ";
}
}
std::cout << "\n";
} else {
std::cout << "Parse failed\n";
}
if (f != l)
std::cout << "Remaining unparsed input: '" << std::string(f,l) << "'\n";
}
}
Prints:
--- Testcase 'Equals, "bye", "hello"' -> false;
--- Testcase 'Equals, false, "hello"' -> Type Mismatch;
--- Testcase 'Equals, -0.0, "hello"' -> Type Mismatch;
--- Testcase 'Equals, 41, "hello"' -> Type Mismatch;
--- Testcase 'Equals, "bye", true' -> Type Mismatch;
--- Testcase 'Equals, false, true' -> false;
--- Testcase 'Equals, -0.0, true' -> false;
--- Testcase 'Equals, 41, true' -> false;
--- Testcase 'Equals, "bye", 0.0' -> Type Mismatch;
--- Testcase 'Equals, false, 0.0' -> true;
--- Testcase 'Equals, -0.0, 0.0' -> true;
--- Testcase 'Equals, 41, 0.0' -> false;
--- Testcase 'Equals, "bye", 42' -> Type Mismatch;
--- Testcase 'Equals, false, 42' -> false;
--- Testcase 'Equals, -0.0, 42' -> false;
--- Testcase 'Equals, 41, 42' -> false;
--- Testcase 'Greater, "bye", "hello"' -> false;
--- Testcase 'Greater, false, "hello"' -> Type Mismatch;
--- Testcase 'Greater, -0.0, "hello"' -> Type Mismatch;
--- Testcase 'Greater, 41, "hello"' -> Type Mismatch;
--- Testcase 'Greater, "bye", true' -> Type Mismatch;
--- Testcase 'Greater, false, true' -> false;
--- Testcase 'Greater, -0.0, true' -> false;
--- Testcase 'Greater, 41, true' -> true;
--- Testcase 'Greater, "bye", 0.0' -> Type Mismatch;
--- Testcase 'Greater, false, 0.0' -> false;
--- Testcase 'Greater, -0.0, 0.0' -> false;
--- Testcase 'Greater, 41, 0.0' -> true;
--- Testcase 'Greater, "bye", 42' -> Type Mismatch;
--- Testcase 'Greater, false, 42' -> false;
--- Testcase 'Greater, -0.0, 42' -> false;
--- Testcase 'Greater, 41, 42' -> false;
--- Testcase 'Between, 20, 10, 30
Between, NaN, NaN, NaN
Between, "q", "a", "z"' -> true; false; true;
boost variant is the easiest way IMHO:
#include <boost/variant.hpp>
#include <boost/operators.hpp>
#include <string>
#include <iostream>
#include <iomanip>
// define the concept of equality in my scripting language
struct is_equal : boost::static_visitor<bool>
{
// x == x is easy
template<class T>
bool operator()(const T& l, const T& r) const {
return l == r;
}
// define the concept of comparing strings to integers
bool operator()(const std::string& l, const int& r) const {
return l == std::to_string(r);
}
// and integers to strings
bool operator()(const int& l, const std::string& r) const {
return (*this)(r, l);
}
};
struct is_less : boost::static_visitor<bool>
{
// x == x is easy
template<class T>
bool operator()(const T& l, const T& r) const {
return l < r;
}
// define the concept of comparing strings to integers
bool operator()(const std::string& l, const int& r) const {
return std::stoi(l) < r;
}
// and integers to strings
bool operator()(const int& l, const std::string& r) const {
return l < std::stoi(r);
}
};
struct emit : boost::static_visitor<std::ostream&>
{
emit(std::ostream& os) : os_(os) {}
// x == x is easy
template<class T>
std::ostream& operator()(const T& l) const {
return os_ << l;
}
std::ostream& operator()(const std::string& s) const {
return os_ << std::quoted(s);
}
std::ostream& os_;
};
struct scriptable_value
: boost::less_than_comparable<scriptable_value>
, boost::equality_comparable<scriptable_value>
{
using variant_type = boost::variant<std::string, int>;
scriptable_value(std::string v) : variant_(std::move(v)) {}
scriptable_value(int v) : variant_(v) {}
variant_type const& as_variant() const {
return variant_;
}
private:
variant_type variant_;
};
bool operator==(scriptable_value const& l, scriptable_value const& r)
{
return boost::apply_visitor(is_equal(), l.as_variant(), r.as_variant());
}
bool operator<(scriptable_value const& l, scriptable_value const& r)
{
return boost::apply_visitor(is_less(), l.as_variant(), r.as_variant());
}
std::ostream& operator<<(std::ostream& os, scriptable_value const& r)
{
return boost::apply_visitor(emit(os), r.as_variant());
}
int main()
{
auto x = scriptable_value(10);
auto y = scriptable_value("10");
auto x2 = scriptable_value(9);
auto y2 = scriptable_value("9");
std::cout << x << " == " << y << " : " << std::boolalpha << (x == y) << std::endl;
std::cout << x << " != " << y << " : " << std::boolalpha << (x != y) << std::endl;
std::cout << x << " == " << y2 << " : " << std::boolalpha << (x == y2) << std::endl;
std::cout << x << " != " << y2 << " : " << std::boolalpha << (x != y2) << std::endl;
std::cout << x << " < " << y << " : " << std::boolalpha << (x < y) << std::endl;
std::cout << x << " >= " << y << " : " << std::boolalpha << (x >= y) << std::endl;
std::cout << x << " < " << y2 << " : " << std::boolalpha << (x < y2) << std::endl;
std::cout << x << " >= " << y2 << " : " << std::boolalpha << (x >= y2) << std::endl;
std::cout << x << " == " << x2 << " : " << std::boolalpha << (x == x2) << std::endl;
std::cout << x << " != " << x2 << " : " << std::boolalpha << (x != x2) << std::endl;
}
expected output:
10 == "10" : true
10 != "10" : false
10 == "9" : false
10 != "9" : true
10 < "10" : false
10 >= "10" : true
10 < "9" : false
10 >= "9" : true
10 == 9 : false
10 != 9 : true
Your fundamental issue is that C++ is a statically-typed language. General-purpose programming languages tend to fall into two rough categories: statically and dynamically typed. In a dynamically-typed language, like Perl, the type of an object is determined at runtime. In a statically-typed language, like C++, the type of an object is specified at compile-time.
That doesn't mean that this is not possible in C++ in a type-safe manner. It is, but it requires some work.
The usual approach is to encapsulate all types into classes that are derived from some base class that defines virtual methods, with the subclasses implementing them. Let's use just ints and floats.
// Forward declarations
class FloatNumber;
class IntNumber;
class Number {
// virtual methods to be defined later.
};
class FloatNumber : public Number {
float value;
// Implements the virtual methods for float values.
};
class IntNumber : public Number {
int value;
// Implements the virtual methods for int values.
};
Now, you can implement basic operations. In the Number base class, you define the conversion methods:
virtual FloatNumber asFloat() const = 0;
virtual IntNumber asInt() const = 0;
In each subclass you will implement these in the obvious manner, returning either *this, if it's the same type, or constructing the other subclass and returning the newly-constructed class.
Now, you can implement basic operations. Say, equals:
virtual bool equals(const Number &other) const =0;
Now, you get to implement this virtual method in each subclass. In FloatNumber::equals(), for example, you would call other.asFloat(), and compare its val to its own val. Ditto for IntNumber::equals(). If both Numbers that are compared are of the same type, this ends up comparing the two values directly; otherwise an automatic type conversion takes place.
Now, this is not a perfect approach, since if the first number is an IntNumber, the FloatNumber ends up getting down-converted to an int, and you really want the conversion to go the other way. There are classical ways to solve this also, in a type-safe manner. But first, you should get this basic approach implemented first, and then worry about handling the various corner-cases.
In this manner you can proceed and build up a class hierarchy that implements generic operation on numbers. This is likely more work than you expected, but this is how to properly do this kind of thing in C++, in a completely type-safe manner. Modern C++ compilers are quite efficient, and the end result will be quite small, and compact.
The final step for you is to read the file, parse the values, and have a simple lookup table that maps "Equals" to the "equals" method, and so on...
How can you use a boxed closure in a context that requires a FnMut type, e.g.
pub fn main() {
for n in (0..10).map(Box::new(|i| i * 2)) {
println!("{}", n);
}
}
As Box implements the Deref trait, you can simply derefence your boxed function:
fn main() {
let boxed_fn = Box::new(|i| i * 2);
for n in (0..10).map(*boxed_fn) {
println!("{}", n);
}
}
I have a bunch of Grails domain classes that I want to be able to treat as Numbers, Integers in particular. For the most part, they are just numeric values with a few extra properties that are used as meta-data. Here's an example:
class Score {
String meaning
Integer value
static hasMany = [responses:Response]
static constraints = {
meaning blank: false, maxSize: 100, unique: true
value min: 1, unique: true // Assume we're using a base-1 ranking system, where 1 is the lowest
}
}
I tried to add #Delegate to the value field, but it didn't seem to have any impact: I still couldn't do 7 + myScore. All I get is missing method exceptions because Integer doesn't have a signature matching plus(Score).
What is the correct way to go about doing this, since #Delegate doesn't seem to work?
Note: I also have a need to turn my domain classes into various Collections with meta data, but I expect it will be the same solution.
I'm imagining everyone has moved on, now that this question is over a year and a half old, but still, I'm surprised that no one offered up Groovy categories as a solution. Indeed, it seems to me that categories are the most natural solution to this problem. Without changing the "Grailsiness" of the original domain class, you can still instill the desired numeric behavior relatively easily.
First define the category class:
class ScoreCategory {
static asType(Score s, Class newClass) {
switch (newClass) {
case Integer.class:
case Integer.TYPE:
case Number.class: return s?.value ?: 0
default: throw new GroovyCastException("Cannot cast to ${newClass}")
}
}
static boolean equals(Score me, def you) {
you instanceof Score && me as int == you as int
}
static Score plus(Score a, b) { plusImpl(a, b) }
static Score plus(Score a, Number b) { plusImpl(a, b) }
static Score plus(Number a, Score b) { plusImpl(a, b) }
private static plusImpl(a, b) { new Score(value: (a as int) + (b as int)) }
static Score minus(Score a, b) { minusImpl(a, b) }
static Score minus(Score a, Number b) { minusImpl(a, b) }
static Score minus(Number a, Score b) { minusImpl(a, b) }
private static minusImpl(a, b) { a + -b }
static Score multiply(Score a, Number b) { multImpl(a,b) }
static Score multiply(Number a, Score b) { multImpl(a,b) }
private static multImpl(a,b) { new Score(value: (a as int) * (b as int)) }
static Integer div(Score a, b) { (a as int).intdiv(b as int) }
static Score div(Score a, Number b) { new Score(value:(a as int).intdiv(b as int)) }
static Score negative(Score a) { new Score(value: -(a as int)) }
static Score abs(Score a) { new Score(value: (a as int).abs())}
}
Then, at some suitably global place in the application declare the mixins:
Number.metaClass.mixin ScoreCategory
Score.metaClass.mixin ScoreCategory
After all this, as demonstrated below, Score objects should now behave like numeric quantities:
def (w, x, y, z) = [54, 78, 21, 32]
def (s1, s2) = [new Score(value:w), new Score(value:x)]
assert (s1 + s2) == new Score(value: w + x)
assert (s1 + y) == new Score(value: w + y)
assert (z + s2) == new Score(value: z + x)
assert (s1 - s2) == new Score(value: w - x)
assert (s1 - y) == new Score(value: w - y)
assert (z - s2) == new Score(value: z - x)
assert (s1 * y) == new Score(value: w * y)
assert (z * s2) == new Score(value: z * x)
assert (s2 / s1) == x.intdiv(w)
assert (s1 / y) == new Score(value: w / y)
You answer can be operator overloding. Here you are overloading the plus method to operate with integers and doubles:
class Score {
...
int plus(int otherValue){
return otherValue + value
}
double plus(double otherValue){
return (value as double) + otherValue
}
// And you can avoid my pitfall overriding asType method
Object asType(Class clazz) {
if (clazz == Integer) {
return value
}
else if(class == Double){
return value as Double
}
else {
super.asType(clazz)
}
}
}
assert new Score(value: 4) + 15 == 19
assert new Score(value: 4) + 15.32 == 19.32
assert 15.32 + (new Score(value: 4) as Double) == 19.32
assert 15 + (new Score(value: 4) as Integer) == 19
Add an overload for the plus operator on the Number metaclass:
Number.metaClass.plus = { Score s -> delegate + s.value }
Add this in BootStrap.groovy in your app, or in doWithDynamicMethods in a plugin.
Edit:
As pointed out in the comments, this doesn't work if the Score is on the left side of the operation. Add a plus method to the Score class to handle that:
Number plus(Number n) { value + n }
You can also extend Number.
class Score extends Number {
Integer value
public int intValue() { return value }
public double doubleValue() { return value }
public long longValue() { return value }
public float floatValue() { return value }
}
Score sc = new Score( value: 5 );
println 10 + sc
I am using Z3 with c api. Is it possible to find out if a given Z3_ast variable corresponds to a clause like or_b1_b2 bellow?
Z3_ast or_b1_b2 = mk_binary_or(c,mk_bool_var(c,"b1"),mk_bool_var(c,"b2"));
Thank you
Yes, The Z3 API provides several functions for inspecting/traversing ASTs.
The Z3 API is minimalist, but it has all necessary ingredients for writing function such as: is_propositional_variable, is_literal, and is_clause. Here is an example:
// Return true if the given ast is an application of the given kind
int is_app_of(Z3_context c, Z3_ast a, Z3_decl_kind k) {
if (Z3_get_ast_kind(c, a) != Z3_APP_AST)
return 0;
return Z3_get_decl_kind(c, Z3_get_app_decl(c, Z3_to_app(c, a))) == k;
}
// Return true if the given ast is an OR.
int is_or(Z3_context c, Z3_ast a) {
return is_app_of(c, a, Z3_OP_OR);
}
// Return true if the given ast is a NOT.
int is_not(Z3_context c, Z3_ast a) {
return is_app_of(c, a, Z3_OP_NOT);
}
// Return true if the given ast is an application of an unintepreted symbol.
int is_uninterp(Z3_context c, Z3_ast a) {
return is_app_of(c, a, Z3_OP_UNINTERPRETED);
}
// Return true if the given ast is a uninterpreted constant.
// That is, it is application (with zero arguments) of an uninterpreted symbol.
int is_uninterp_const(Z3_context c, Z3_ast a) {
return is_uninterp(c, a) && Z3_get_app_num_args(c, Z3_to_app(c, a)) == 0;
}
// Return true if the given ast has Boolean sort (aka type).
int has_bool_sort(Z3_context c, Z3_ast a) {
return Z3_get_sort_kind(c, Z3_get_sort(c, a)) == Z3_BOOL_SORT;
}
// Return true if the given ast is a "propositional variable".
// That is, it has Boolean sort and it is uninterpreted.
int is_propositional_var(Z3_context c, Z3_ast a) {
return is_uninterp_const(c, a) && has_bool_sort(c, a);
}
// Return true if the given ast is a "literal".
// That is, it is a "propositional variable" or the negation of a propositional variable.
int is_literal(Z3_context c, Z3_ast a) {
if (is_propositional_var(c, a))
return 1;
if (is_not(c, a))
return is_propositional_var(c, Z3_get_app_arg(c, Z3_to_app(c, a), 0));
return 0;
}
// Return true if the given ast is a "clause".
// That is, it is a literal, or a disjuction (OR) of literals.
int is_clause(Z3_context c, Z3_ast a) {
if (is_literal(c, a)) {
return 1; // unit clause
}
else if (is_or(c, a)) {
unsigned num;
unsigned i;
num = Z3_get_app_num_args(c, Z3_to_app(c, a));
for (i = 0; i < num; i++) {
if (!is_literal(c, Z3_get_app_arg(c, Z3_to_app(c, a), i)))
return 0;
}
return 1;
}
else {
return 0;
}
}