sassc 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/ext/libsass/Readme.md +1 -1
- data/ext/libsass/ast.cpp +264 -0
- data/ext/libsass/ast.hpp +52 -133
- data/ext/libsass/bind.cpp +23 -1
- data/ext/libsass/constants.cpp +3 -1
- data/ext/libsass/constants.hpp +3 -0
- data/ext/libsass/context.cpp +0 -1
- data/ext/libsass/debugger.hpp +84 -2
- data/ext/libsass/error_handling.cpp +14 -4
- data/ext/libsass/error_handling.hpp +3 -0
- data/ext/libsass/eval.cpp +44 -14
- data/ext/libsass/functions.cpp +37 -37
- data/ext/libsass/functions.hpp +0 -2
- data/ext/libsass/inspect.cpp +9 -2
- data/ext/libsass/output.cpp +7 -14
- data/ext/libsass/output.hpp +1 -2
- data/ext/libsass/parser.cpp +16 -4
- data/ext/libsass/position.hpp +5 -0
- data/ext/libsass/prelexer.cpp +5 -1
- data/ext/libsass/sass_values.cpp +15 -0
- data/ext/libsass/sass_values.h +3 -0
- data/ext/libsass/util.cpp +63 -7
- data/ext/libsass/util.hpp +2 -0
- data/lib/sassc/engine.rb +2 -0
- data/lib/sassc/native.rb +1 -1
- data/lib/sassc/version.rb +1 -1
- data/test/engine_test.rb +7 -0
- data/test/native_test.rb +10 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cba905c4a611564a30f673941af311b360e64f79
|
4
|
+
data.tar.gz: 83bfb6df3c6ebb5e086badf0a950ebc839cbc6f7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bd8dbb02e65de541608e51da7738824d1de7a8db2429d4b05396173a861ec2bbcd4d191ab39b426427b7ed5f31bcacf94a22782295827d736b1c0c1e8bd44212
|
7
|
+
data.tar.gz: e6c839d26054ff6bba74ab525e357f3161a25416748baacc0a2abd416ad21d0a9dafeb6d8d038e8a929d08eac12e28a53d109b0a2aaa4e4902b89abd715be1ac
|
data/README.md
CHANGED
data/ext/libsass/Readme.md
CHANGED
@@ -7,7 +7,7 @@ by Aaron Leung ([@akhleung]) and Hampton Catlin ([@hcatlin])
|
|
7
7
|
[![Windows CI](https://ci.appveyor.com/api/projects/status/github/sass/libsass?svg=true)](https://ci.appveyor.com/project/sass/libsass/branch/master)
|
8
8
|
[![Bountysource](https://www.bountysource.com/badge/tracker?tracker_id=283068)](https://www.bountysource.com/trackers/283068-libsass?utm_source=283068&utm_medium=shield&utm_campaign=TRACKER_BADGE)
|
9
9
|
[![Coverage Status](https://img.shields.io/coveralls/sass/libsass.svg)](https://coveralls.io/r/sass/libsass?branch=feature%2Ftest-travis-ci-3)
|
10
|
-
[![Join us](https://
|
10
|
+
[![Join us](https://libsass-slack.herokuapp.com/badge.svg)](https://libsass-slack.herokuapp.com/)
|
11
11
|
|
12
12
|
https://github.com/sass/libsass
|
13
13
|
|
data/ext/libsass/ast.cpp
CHANGED
@@ -589,6 +589,270 @@ namespace Sass {
|
|
589
589
|
return result;
|
590
590
|
}*/
|
591
591
|
|
592
|
+
Number::Number(ParserState pstate, double val, string u, bool zero)
|
593
|
+
: Expression(pstate),
|
594
|
+
value_(val),
|
595
|
+
zero_(zero),
|
596
|
+
numerator_units_(vector<string>()),
|
597
|
+
denominator_units_(vector<string>()),
|
598
|
+
hash_(0)
|
599
|
+
{
|
600
|
+
size_t l = 0, r = 0;
|
601
|
+
if (!u.empty()) {
|
602
|
+
bool nominator = true;
|
603
|
+
while (true) {
|
604
|
+
r = u.find_first_of("*/", l);
|
605
|
+
string unit(u.substr(l, r - l));
|
606
|
+
if (nominator) numerator_units_.push_back(unit);
|
607
|
+
else denominator_units_.push_back(unit);
|
608
|
+
if (u[r] == '/') nominator = false;
|
609
|
+
if (r == string::npos) break;
|
610
|
+
else l = r + 1;
|
611
|
+
}
|
612
|
+
}
|
613
|
+
concrete_type(NUMBER);
|
614
|
+
}
|
615
|
+
|
616
|
+
string Number::unit() const
|
617
|
+
{
|
618
|
+
stringstream u;
|
619
|
+
for (size_t i = 0, S = numerator_units_.size(); i < S; ++i) {
|
620
|
+
if (i) u << '*';
|
621
|
+
u << numerator_units_[i];
|
622
|
+
}
|
623
|
+
if (!denominator_units_.empty()) u << '/';
|
624
|
+
for (size_t i = 0, S = denominator_units_.size(); i < S; ++i) {
|
625
|
+
if (i) u << '*';
|
626
|
+
u << denominator_units_[i];
|
627
|
+
}
|
628
|
+
return u.str();
|
629
|
+
}
|
630
|
+
|
631
|
+
bool Number::is_unitless()
|
632
|
+
{ return numerator_units_.empty() && denominator_units_.empty(); }
|
633
|
+
|
634
|
+
void Number::normalize(const string& prefered)
|
635
|
+
{
|
636
|
+
|
637
|
+
// first make sure same units cancel each other out
|
638
|
+
// it seems that a map table will fit nicely to do this
|
639
|
+
// we basically construct exponents for each unit
|
640
|
+
// has the advantage that they will be pre-sorted
|
641
|
+
map<string, int> exponents;
|
642
|
+
|
643
|
+
// initialize by summing up occurences in unit vectors
|
644
|
+
for (size_t i = 0, S = numerator_units_.size(); i < S; ++i) ++ exponents[numerator_units_[i]];
|
645
|
+
for (size_t i = 0, S = denominator_units_.size(); i < S; ++i) -- exponents[denominator_units_[i]];
|
646
|
+
|
647
|
+
// the final conversion factor
|
648
|
+
double factor = 1;
|
649
|
+
|
650
|
+
// get the first entry of numerators
|
651
|
+
// forward it when entry is converted
|
652
|
+
vector<string>::iterator nom_it = numerator_units_.begin();
|
653
|
+
vector<string>::iterator nom_end = numerator_units_.end();
|
654
|
+
vector<string>::iterator denom_it = denominator_units_.begin();
|
655
|
+
vector<string>::iterator denom_end = denominator_units_.end();
|
656
|
+
|
657
|
+
// main normalization loop
|
658
|
+
// should be close to optimal
|
659
|
+
while (denom_it != denom_end)
|
660
|
+
{
|
661
|
+
// get and increment afterwards
|
662
|
+
const string denom = *(denom_it ++);
|
663
|
+
// skip already canceled out unit
|
664
|
+
if (exponents[denom] >= 0) continue;
|
665
|
+
// skip all units we don't know how to convert
|
666
|
+
if (string_to_unit(denom) == INCOMMENSURABLE) continue;
|
667
|
+
// now search for nominator
|
668
|
+
while (nom_it != nom_end)
|
669
|
+
{
|
670
|
+
// get and increment afterwards
|
671
|
+
const string nom = *(nom_it ++);
|
672
|
+
// skip already canceled out unit
|
673
|
+
if (exponents[nom] <= 0) continue;
|
674
|
+
// skip all units we don't know how to convert
|
675
|
+
if (string_to_unit(nom) == INCOMMENSURABLE) continue;
|
676
|
+
// we now have two convertable units
|
677
|
+
// add factor for current conversion
|
678
|
+
factor *= conversion_factor(nom, denom);
|
679
|
+
// update nominator/denominator exponent
|
680
|
+
-- exponents[nom]; ++ exponents[denom];
|
681
|
+
// inner loop done
|
682
|
+
break;
|
683
|
+
}
|
684
|
+
}
|
685
|
+
|
686
|
+
// now we can build up the new unit arrays
|
687
|
+
numerator_units_.clear();
|
688
|
+
denominator_units_.clear();
|
689
|
+
|
690
|
+
// build them by iterating over the exponents
|
691
|
+
for (auto exp : exponents)
|
692
|
+
{
|
693
|
+
// maybe there is more effecient way to push
|
694
|
+
// the same item multiple times to a vector?
|
695
|
+
for(size_t i = 0, S = abs(exp.second); i < S; ++i)
|
696
|
+
{
|
697
|
+
// opted to have these switches in the inner loop
|
698
|
+
// makes it more readable and should not cost much
|
699
|
+
if (exp.second < 0) denominator_units_.push_back(exp.first);
|
700
|
+
else if (exp.second > 0) numerator_units_.push_back(exp.first);
|
701
|
+
}
|
702
|
+
}
|
703
|
+
|
704
|
+
// apply factor to value_
|
705
|
+
// best precision this way
|
706
|
+
value_ *= factor;
|
707
|
+
|
708
|
+
// maybe convert to other unit
|
709
|
+
// easier implemented on its own
|
710
|
+
convert(prefered);
|
711
|
+
|
712
|
+
}
|
713
|
+
|
714
|
+
void Number::convert(const string& prefered)
|
715
|
+
{
|
716
|
+
// abort if unit is empty
|
717
|
+
if (prefered.empty()) return;
|
718
|
+
|
719
|
+
// first make sure same units cancel each other out
|
720
|
+
// it seems that a map table will fit nicely to do this
|
721
|
+
// we basically construct exponents for each unit
|
722
|
+
// has the advantage that they will be pre-sorted
|
723
|
+
map<string, int> exponents;
|
724
|
+
|
725
|
+
// initialize by summing up occurences in unit vectors
|
726
|
+
for (size_t i = 0, S = numerator_units_.size(); i < S; ++i) ++ exponents[numerator_units_[i]];
|
727
|
+
for (size_t i = 0, S = denominator_units_.size(); i < S; ++i) -- exponents[denominator_units_[i]];
|
728
|
+
|
729
|
+
// the final conversion factor
|
730
|
+
double factor = 1;
|
731
|
+
|
732
|
+
vector<string>::iterator denom_it = denominator_units_.begin();
|
733
|
+
vector<string>::iterator denom_end = denominator_units_.end();
|
734
|
+
|
735
|
+
// main normalization loop
|
736
|
+
// should be close to optimal
|
737
|
+
while (denom_it != denom_end)
|
738
|
+
{
|
739
|
+
// get and increment afterwards
|
740
|
+
const string denom = *(denom_it ++);
|
741
|
+
// check if conversion is needed
|
742
|
+
if (denom == prefered) continue;
|
743
|
+
// skip already canceled out unit
|
744
|
+
if (exponents[denom] >= 0) continue;
|
745
|
+
// skip all units we don't know how to convert
|
746
|
+
if (string_to_unit(denom) == INCOMMENSURABLE) continue;
|
747
|
+
// we now have two convertable units
|
748
|
+
// add factor for current conversion
|
749
|
+
factor *= conversion_factor(denom, prefered);
|
750
|
+
// update nominator/denominator exponent
|
751
|
+
++ exponents[denom]; -- exponents[prefered];
|
752
|
+
}
|
753
|
+
|
754
|
+
vector<string>::iterator nom_it = numerator_units_.begin();
|
755
|
+
vector<string>::iterator nom_end = numerator_units_.end();
|
756
|
+
|
757
|
+
// now search for nominator
|
758
|
+
while (nom_it != nom_end)
|
759
|
+
{
|
760
|
+
// get and increment afterwards
|
761
|
+
const string nom = *(nom_it ++);
|
762
|
+
// check if conversion is needed
|
763
|
+
if (nom == prefered) continue;
|
764
|
+
// skip already canceled out unit
|
765
|
+
if (exponents[nom] <= 0) continue;
|
766
|
+
// skip all units we don't know how to convert
|
767
|
+
if (string_to_unit(nom) == INCOMMENSURABLE) continue;
|
768
|
+
// we now have two convertable units
|
769
|
+
// add factor for current conversion
|
770
|
+
factor *= conversion_factor(nom, prefered);
|
771
|
+
// update nominator/denominator exponent
|
772
|
+
-- exponents[nom]; ++ exponents[prefered];
|
773
|
+
}
|
774
|
+
|
775
|
+
// now we can build up the new unit arrays
|
776
|
+
numerator_units_.clear();
|
777
|
+
denominator_units_.clear();
|
778
|
+
|
779
|
+
// build them by iterating over the exponents
|
780
|
+
for (auto exp : exponents)
|
781
|
+
{
|
782
|
+
// maybe there is more effecient way to push
|
783
|
+
// the same item multiple times to a vector?
|
784
|
+
for(size_t i = 0, S = abs(exp.second); i < S; ++i)
|
785
|
+
{
|
786
|
+
// opted to have these switches in the inner loop
|
787
|
+
// makes it more readable and should not cost much
|
788
|
+
if (exp.second < 0) denominator_units_.push_back(exp.first);
|
789
|
+
else if (exp.second > 0) numerator_units_.push_back(exp.first);
|
790
|
+
}
|
791
|
+
}
|
792
|
+
|
793
|
+
// apply factor to value_
|
794
|
+
// best precision this way
|
795
|
+
value_ *= factor;
|
796
|
+
|
797
|
+
}
|
798
|
+
|
799
|
+
// useful for making one number compatible with another
|
800
|
+
string Number::find_convertible_unit() const
|
801
|
+
{
|
802
|
+
for (size_t i = 0, S = numerator_units_.size(); i < S; ++i) {
|
803
|
+
string u(numerator_units_[i]);
|
804
|
+
if (string_to_unit(u) != INCOMMENSURABLE) return u;
|
805
|
+
}
|
806
|
+
for (size_t i = 0, S = denominator_units_.size(); i < S; ++i) {
|
807
|
+
string u(denominator_units_[i]);
|
808
|
+
if (string_to_unit(u) != INCOMMENSURABLE) return u;
|
809
|
+
}
|
810
|
+
return string();
|
811
|
+
}
|
812
|
+
|
813
|
+
|
814
|
+
bool Number::operator== (Expression* rhs) const
|
815
|
+
{
|
816
|
+
try
|
817
|
+
{
|
818
|
+
Number l(pstate_, value_, unit());
|
819
|
+
Number& r = dynamic_cast<Number&>(*rhs);
|
820
|
+
l.normalize(find_convertible_unit());
|
821
|
+
r.normalize(find_convertible_unit());
|
822
|
+
return l.unit() == r.unit() &&
|
823
|
+
l.value() == r.value();
|
824
|
+
}
|
825
|
+
catch (std::bad_cast&) {}
|
826
|
+
catch (...) { throw; }
|
827
|
+
return false;
|
828
|
+
}
|
829
|
+
|
830
|
+
bool Number::operator== (Expression& rhs) const
|
831
|
+
{
|
832
|
+
return operator==(&rhs);
|
833
|
+
}
|
834
|
+
|
835
|
+
bool List::operator==(Expression* rhs) const
|
836
|
+
{
|
837
|
+
try
|
838
|
+
{
|
839
|
+
List* r = dynamic_cast<List*>(rhs);
|
840
|
+
if (!r || length() != r->length()) return false;
|
841
|
+
if (separator() != r->separator()) return false;
|
842
|
+
for (size_t i = 0, L = r->length(); i < L; ++i)
|
843
|
+
if (*elements()[i] != *(*r)[i]) return false;
|
844
|
+
return true;
|
845
|
+
}
|
846
|
+
catch (std::bad_cast&) {}
|
847
|
+
catch (...) { throw; }
|
848
|
+
return false;
|
849
|
+
}
|
850
|
+
|
851
|
+
bool List::operator== (Expression& rhs) const
|
852
|
+
{
|
853
|
+
return operator==(&rhs);
|
854
|
+
}
|
855
|
+
|
592
856
|
Expression* Hashed::at(Expression* k) const
|
593
857
|
{
|
594
858
|
if (elements_.count(k))
|
data/ext/libsass/ast.hpp
CHANGED
@@ -113,6 +113,7 @@ namespace Sass {
|
|
113
113
|
static string type_name() { return ""; }
|
114
114
|
virtual bool is_false() { return false; }
|
115
115
|
virtual bool operator==( Expression& rhs) const { return false; }
|
116
|
+
virtual void set_delayed(bool delayed) { is_delayed(delayed); }
|
116
117
|
virtual size_t hash() { return 0; }
|
117
118
|
};
|
118
119
|
}
|
@@ -756,23 +757,8 @@ namespace Sass {
|
|
756
757
|
bool is_invisible() { return !length(); }
|
757
758
|
Expression* value_at_index(size_t i);
|
758
759
|
|
759
|
-
virtual bool operator==(Expression& rhs) const
|
760
|
-
|
761
|
-
try
|
762
|
-
{
|
763
|
-
List& l = dynamic_cast<List&>(rhs);
|
764
|
-
if (!(l && length() == l.length() && separator() == l.separator())) return false;
|
765
|
-
for (size_t i = 0, L = l.length(); i < L; ++i)
|
766
|
-
if (!(*(elements()[i]) == *(l[i]))) return false;
|
767
|
-
return true;
|
768
|
-
}
|
769
|
-
catch (std::bad_cast&)
|
770
|
-
{
|
771
|
-
return false;
|
772
|
-
}
|
773
|
-
catch (...) { throw; }
|
774
|
-
|
775
|
-
}
|
760
|
+
virtual bool operator==(Expression& rhs) const;
|
761
|
+
virtual bool operator==(Expression* rhs) const;
|
776
762
|
|
777
763
|
virtual size_t hash()
|
778
764
|
{
|
@@ -786,6 +772,13 @@ namespace Sass {
|
|
786
772
|
return hash_;
|
787
773
|
}
|
788
774
|
|
775
|
+
virtual void set_delayed(bool delayed)
|
776
|
+
{
|
777
|
+
for (size_t i = 0, L = length(); i < L; ++i)
|
778
|
+
(elements()[i])->set_delayed(delayed);
|
779
|
+
is_delayed(delayed);
|
780
|
+
}
|
781
|
+
|
789
782
|
ATTACH_OPERATIONS();
|
790
783
|
};
|
791
784
|
|
@@ -857,6 +850,31 @@ namespace Sass {
|
|
857
850
|
Type t, Expression* lhs, Expression* rhs)
|
858
851
|
: Expression(pstate), type_(t), left_(lhs), right_(rhs), hash_(0)
|
859
852
|
{ }
|
853
|
+
const string type_name() {
|
854
|
+
switch (type_) {
|
855
|
+
case AND: return "and"; break;
|
856
|
+
case OR: return "or"; break;
|
857
|
+
case EQ: return "eq"; break;
|
858
|
+
case NEQ: return "neq"; break;
|
859
|
+
case GT: return "gt"; break;
|
860
|
+
case GTE: return "gte"; break;
|
861
|
+
case LT: return "lt"; break;
|
862
|
+
case LTE: return "lte"; break;
|
863
|
+
case ADD: return "add"; break;
|
864
|
+
case SUB: return "sub"; break;
|
865
|
+
case MUL: return "mul"; break;
|
866
|
+
case DIV: return "div"; break;
|
867
|
+
case MOD: return "mod"; break;
|
868
|
+
case NUM_OPS: return "num_ops"; break;
|
869
|
+
default: return "invalid"; break;
|
870
|
+
}
|
871
|
+
}
|
872
|
+
virtual void set_delayed(bool delayed)
|
873
|
+
{
|
874
|
+
right()->set_delayed(delayed);
|
875
|
+
left()->set_delayed(delayed);
|
876
|
+
is_delayed(delayed);
|
877
|
+
}
|
860
878
|
virtual bool operator==(Expression& rhs) const
|
861
879
|
{
|
862
880
|
try
|
@@ -896,6 +914,14 @@ namespace Sass {
|
|
896
914
|
Unary_Expression(ParserState pstate, Type t, Expression* o)
|
897
915
|
: Expression(pstate), type_(t), operand_(o), hash_(0)
|
898
916
|
{ }
|
917
|
+
const string type_name() {
|
918
|
+
switch (type_) {
|
919
|
+
case PLUS: return "plus"; break;
|
920
|
+
case MINUS: return "minus"; break;
|
921
|
+
case NOT: return "not"; break;
|
922
|
+
default: return "invalid"; break;
|
923
|
+
}
|
924
|
+
}
|
899
925
|
virtual bool operator==(Expression& rhs) const
|
900
926
|
{
|
901
927
|
try
|
@@ -1161,129 +1187,22 @@ namespace Sass {
|
|
1161
1187
|
vector<string> denominator_units_;
|
1162
1188
|
size_t hash_;
|
1163
1189
|
public:
|
1164
|
-
Number(ParserState pstate, double val, string u = "", bool zero = true)
|
1165
|
-
: Expression(pstate),
|
1166
|
-
value_(val),
|
1167
|
-
zero_(zero),
|
1168
|
-
numerator_units_(vector<string>()),
|
1169
|
-
denominator_units_(vector<string>()),
|
1170
|
-
hash_(0)
|
1171
|
-
{
|
1172
|
-
if (!u.empty()) numerator_units_.push_back(u);
|
1173
|
-
concrete_type(NUMBER);
|
1174
|
-
}
|
1190
|
+
Number(ParserState pstate, double val, string u = "", bool zero = true);
|
1175
1191
|
bool zero() { return zero_; }
|
1176
1192
|
vector<string>& numerator_units() { return numerator_units_; }
|
1177
1193
|
vector<string>& denominator_units() { return denominator_units_; }
|
1178
1194
|
string type() { return "number"; }
|
1179
1195
|
static string type_name() { return "number"; }
|
1180
|
-
string unit() const
|
1181
|
-
|
1182
|
-
|
1183
|
-
|
1184
|
-
|
1185
|
-
u << numerator_units_[i];
|
1186
|
-
}
|
1187
|
-
if (!denominator_units_.empty()) u << '/';
|
1188
|
-
for (size_t i = 0, S = denominator_units_.size(); i < S; ++i) {
|
1189
|
-
if (i) u << '*';
|
1190
|
-
u << denominator_units_[i];
|
1191
|
-
}
|
1192
|
-
return u.str();
|
1193
|
-
}
|
1194
|
-
bool is_unitless()
|
1195
|
-
{ return numerator_units_.empty() && denominator_units_.empty(); }
|
1196
|
-
void normalize(string to = "")
|
1197
|
-
{
|
1198
|
-
// (multiple passes because I'm too tired to think up something clever)
|
1199
|
-
// Find a unit to convert everything to, if one isn't provided.
|
1200
|
-
if (to.empty()) {
|
1201
|
-
for (size_t i = 0, S = numerator_units_.size(); i < S; ++i) {
|
1202
|
-
string u(numerator_units_[i]);
|
1203
|
-
if (string_to_unit(u) == INCOMMENSURABLE) {
|
1204
|
-
continue;
|
1205
|
-
}
|
1206
|
-
else {
|
1207
|
-
to = u;
|
1208
|
-
break;
|
1209
|
-
}
|
1210
|
-
}
|
1211
|
-
}
|
1212
|
-
if (to.empty()) {
|
1213
|
-
for (size_t i = 0, S = denominator_units_.size(); i < S; ++i) {
|
1214
|
-
string u(denominator_units_[i]);
|
1215
|
-
if (string_to_unit(u) == INCOMMENSURABLE) {
|
1216
|
-
continue;
|
1217
|
-
}
|
1218
|
-
else {
|
1219
|
-
to = u;
|
1220
|
-
break;
|
1221
|
-
}
|
1222
|
-
}
|
1223
|
-
}
|
1224
|
-
// Now loop through again and do all the conversions.
|
1225
|
-
for (size_t i = 0, S = numerator_units_.size(); i < S; ++i) {
|
1226
|
-
string from(numerator_units_[i]);
|
1227
|
-
if (string_to_unit(from) == INCOMMENSURABLE) continue;
|
1228
|
-
value_ *= conversion_factor(from, to);
|
1229
|
-
numerator_units_[i] = to;
|
1230
|
-
}
|
1231
|
-
for (size_t i = 0, S = denominator_units_.size(); i < S; ++i) {
|
1232
|
-
string from(denominator_units_[i]);
|
1233
|
-
if (string_to_unit(from) == INCOMMENSURABLE) continue;
|
1234
|
-
value_ /= conversion_factor(from, to);
|
1235
|
-
denominator_units_[i] = to;
|
1236
|
-
}
|
1237
|
-
// Now divide out identical units in the numerator and denominator.
|
1238
|
-
vector<string> ncopy;
|
1239
|
-
ncopy.reserve(numerator_units_.size());
|
1240
|
-
for (vector<string>::iterator n = numerator_units_.begin();
|
1241
|
-
n != numerator_units_.end();
|
1242
|
-
++n) {
|
1243
|
-
vector<string>::iterator d = find(denominator_units_.begin(),
|
1244
|
-
denominator_units_.end(),
|
1245
|
-
*n);
|
1246
|
-
if (d != denominator_units_.end()) {
|
1247
|
-
denominator_units_.erase(d);
|
1248
|
-
}
|
1249
|
-
else {
|
1250
|
-
ncopy.push_back(*n);
|
1251
|
-
}
|
1252
|
-
}
|
1253
|
-
numerator_units_ = ncopy;
|
1254
|
-
// Sort the units to make them pretty and, well, normal.
|
1255
|
-
sort(numerator_units_.begin(), numerator_units_.end());
|
1256
|
-
sort(denominator_units_.begin(), denominator_units_.end());
|
1257
|
-
}
|
1196
|
+
string unit() const;
|
1197
|
+
|
1198
|
+
bool is_unitless();
|
1199
|
+
void convert(const string& unit = "");
|
1200
|
+
void normalize(const string& unit = "");
|
1258
1201
|
// useful for making one number compatible with another
|
1259
|
-
string find_convertible_unit() const
|
1260
|
-
{
|
1261
|
-
for (size_t i = 0, S = numerator_units_.size(); i < S; ++i) {
|
1262
|
-
string u(numerator_units_[i]);
|
1263
|
-
if (string_to_unit(u) != INCOMMENSURABLE) return u;
|
1264
|
-
}
|
1265
|
-
for (size_t i = 0, S = denominator_units_.size(); i < S; ++i) {
|
1266
|
-
string u(denominator_units_[i]);
|
1267
|
-
if (string_to_unit(u) != INCOMMENSURABLE) return u;
|
1268
|
-
}
|
1269
|
-
return string();
|
1270
|
-
}
|
1202
|
+
string find_convertible_unit() const;
|
1271
1203
|
|
1272
|
-
virtual bool operator==(Expression& rhs) const
|
1273
|
-
|
1274
|
-
try
|
1275
|
-
{
|
1276
|
-
Number& e(dynamic_cast<Number&>(rhs));
|
1277
|
-
if (!e) return false;
|
1278
|
-
e.normalize(find_convertible_unit());
|
1279
|
-
return unit() == e.unit() && value() == e.value();
|
1280
|
-
}
|
1281
|
-
catch (std::bad_cast&)
|
1282
|
-
{
|
1283
|
-
return false;
|
1284
|
-
}
|
1285
|
-
catch (...) { throw; }
|
1286
|
-
}
|
1204
|
+
virtual bool operator== (Expression& rhs) const;
|
1205
|
+
virtual bool operator== (Expression* rhs) const;
|
1287
1206
|
|
1288
1207
|
virtual size_t hash()
|
1289
1208
|
{
|