Skip to content

Commit

Permalink
Formula engine: new concatenate and range operators
Browse files Browse the repository at this point in the history
str .. str = concatenation
list .. list = concatenation
int ~ int = range (as a list)
  • Loading branch information
CelticMinstrel committed Mar 18, 2016
1 parent 03bbc79 commit 1ae426c
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 3 deletions.
14 changes: 12 additions & 2 deletions src/formula.cpp
Expand Up @@ -342,6 +342,8 @@ class operator_expression : public formula_expression {
op_ = MULL;
} else if(op == "./") {
op_ = DIVL;
} else if(op == "..") {
op_ = CAT;
}
}

Expand Down Expand Up @@ -378,6 +380,8 @@ class operator_expression : public formula_expression {
return left.list_elements_mul(right);
case DIVL:
return left.list_elements_div(right);
case CAT:
return left.concatenate(right);
case EQ:
return left == right ? variant(1) : variant(0);
case NEQ:
Expand All @@ -392,9 +396,13 @@ class operator_expression : public formula_expression {
return left > right ? variant(1) : variant(0);
case MOD:
return left % right;
case RAN:
return left.build_range(right);
case DICE:
default:
return variant(dice_roll(left.as_int(), right.as_int()));
default:
std::cerr << "ERROR: Unimplemented operator!" << std::endl;
return variant();
}
}

Expand All @@ -407,7 +415,7 @@ class operator_expression : public formula_expression {
return res;
}

enum OP { AND, OR, NEQ, LTE, GTE, GT='>', LT='<', EQ='=',
enum OP { AND, OR, NEQ, LTE, GTE, CAT, GT='>', LT='<', EQ='=', RAN='~',
ADD='+', SUB='-', MUL='*', DIV='/', ADDL, SUBL, MULL, DIVL, DICE='d', POW='^', MOD='%' };

OP op_;
Expand Down Expand Up @@ -631,8 +639,10 @@ int operator_precedence(const token& t)
precedence_map[">"] = n;
precedence_map["<="] = n;
precedence_map[">="] = n;
precedence_map["~"] = ++n;
precedence_map["+"] = ++n;
precedence_map["-"] = n;
precedence_map[".."] = n;
precedence_map["*"] = ++n;
precedence_map["/"] = n;
precedence_map["%"] = ++n;
Expand Down
13 changes: 12 additions & 1 deletion src/formula_tokenizer.cpp
Expand Up @@ -99,6 +99,11 @@ token get_token(iterator& i1, iterator i2) {
if( *i1 == '^' )
return token( it, ++i1, TOKEN_OPERATOR );

if( *i1 == '~' )
return token( it, ++i1, TOKEN_OPERATOR );

//unused characters in this range:
// \ ` { | }
}
} else {
//limit search to the lower-half of the ASCII table
Expand Down Expand Up @@ -147,6 +152,8 @@ token get_token(iterator& i1, iterator i2) {
//current character is between ':' and '@'
//possible tokens at this point that we are interested in:
// ; < = > <= >=
//unused characters in this range:
// : ? @

if( *i1 == ';' ) {
return token( it, ++i1, TOKEN_SEMICOLON);
Expand All @@ -173,14 +180,18 @@ token get_token(iterator& i1, iterator i2) {
}
}
//current character is between '!' and '/'
//possible tokens:
// , . .+ .- .* ./ .. ( ) ' # + - -> * / % !=
//unused characters:
// ! " $ &
} else if ( *i1 == ',' ) {
return token( it, ++i1, TOKEN_COMMA);

} else if ( *i1 == '.' ) {
++i1;

if( i1 != i2 ) {
if( *i1 == '+' || *i1 == '-' || *i1 == '*' || *i1 == '/')
if( *i1 == '+' || *i1 == '-' || *i1 == '*' || *i1 == '/' || *i1 == '.')
return token( it, ++i1, TOKEN_OPERATOR );
else
return token( it, i1, TOKEN_OPERATOR );
Expand Down
49 changes: 49 additions & 0 deletions src/variant.cpp
Expand Up @@ -893,6 +893,55 @@ variant variant::list_elements_div(const variant& v) const
return variant( &res );
}

variant variant::concatenate(const variant& v) const
{
if(type_ == TYPE_LIST) {
v.must_be(TYPE_LIST);

std::vector< variant > res;
res.reserve(num_elements() + v.num_elements());

for(size_t i = 0; i < num_elements(); ++i) {
res.push_back( (*this)[i] );
}

for(size_t i = 0; i < v.num_elements(); ++i) {
res.push_back( v[i] );
}

return variant( &res );
} else if(type_ == TYPE_STRING) {
v.must_be(TYPE_STRING);
std::string res = as_string() + v.as_string();
return variant( res );
} else {
throw type_error((formatter() << "type error: " << " expected two "
<< variant_type_to_string(TYPE_LIST) << " or two "
<< variant_type_to_string(TYPE_STRING) << " but found "
<< variant_type_to_string(type_)
<< " (" << to_debug_string() << ")"
<< " and " << variant_type_to_string(v.type_)
<< " (" << v.to_debug_string() << ")").str());
}
}

variant variant::build_range(const variant& v) const {
must_be(TYPE_INT);
v.must_be(TYPE_INT);

int lhs = as_int(), rhs = v.as_int();
int len = abs(rhs - lhs) + 1;

std::vector< variant > res;
res.reserve(len);

for(size_t i = lhs; res.size() != res.capacity(); lhs < rhs ? ++i : --i) {
res.push_back( variant(i) );
}

return variant( &res );
}

void variant::must_be(variant::TYPE t) const
{
if(type_ != t) {
Expand Down
2 changes: 2 additions & 0 deletions src/variant.hpp
Expand Up @@ -136,6 +136,8 @@ class variant {
variant list_elements_sub(const variant& v) const;
variant list_elements_mul(const variant& v) const;
variant list_elements_div(const variant& v) const;
variant concatenate(const variant& v) const;
variant build_range(const variant& v) const;

variant get_keys() const;
variant get_values() const;
Expand Down

0 comments on commit 1ae426c

Please sign in to comment.