about summary refs log tree commit diff stats
path: root/014literal_noninteger.cc
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2015-05-17 00:52:23 -0700
committerKartik K. Agaram <vc@akkartik.com>2015-05-17 00:52:23 -0700
commit6f8f9fb53b5a7ef26496d496a4b93266c78d6332 (patch)
treedd7c6f97ead76e5a2e9026eb49d72f29de417e86 /014literal_noninteger.cc
parent304963834dbe1e9f019a818e0dbf9c63647fa1c4 (diff)
downloadmu-6f8f9fb53b5a7ef26496d496a4b93266c78d6332.tar.gz
1390 - support non-integer literals
Since '3.14159:literal' looks ugly, we'll just say '3.14159'. It's not
like non-integers can be confused for anything but literals.

Once I tried to turn reagent values into doubles, I uncovered a bug:
arithmetic using signed integers is busted; if either operand of
subtraction is unsigned the result is unsigned as well. If it needs to
be negative: ka-boom. It was only masked because I was eventually
storing the result in a long long int, where it was out of range, and so
overflowing into the correct signed value. Once I switched to doubles
the unsigned value would indeed fit without overflowing. Ka-boom.

Yet another reminder that unsigned integers suck. I started using them
mostly to avoid warnings in loops when comparing with .size(), which is
usually a size_t.

Who knows what other crap lurks here. Just use signed integers
everywhere. (And avoid bitwise operators.)
Diffstat (limited to '014literal_noninteger.cc')
-rw-r--r--014literal_noninteger.cc33
1 files changed, 33 insertions, 0 deletions
diff --git a/014literal_noninteger.cc b/014literal_noninteger.cc
new file mode 100644
index 00000000..94242f41
--- /dev/null
+++ b/014literal_noninteger.cc
@@ -0,0 +1,33 @@
+//: Support literal non-integers.
+//: '3.14159:literal' is ugly, so we'll just say '3.14159' for non-integers.
+
+:(scenarios load)
+:(scenario noninteger_literal)
+recipe main [
+  1:number <- copy 3.14159
+]
++parse:   ingredient: {name: "3.14159", value: 3.14159, type: 0, properties: ["3.14159": "literal-number"]}
+
+:(after "reagent::reagent(string s)")
+  if (is_noninteger(s)) {
+    name = s;
+    types.push_back(0);
+    properties.push_back(pair<string, vector<string> >(name, vector<string>()));
+    properties.back().second.push_back("literal-number");
+    set_value(to_double(s));
+    return;
+  }
+
+:(code)
+bool is_noninteger(const string& s) {
+  return s.find_first_not_of("0123456789-.") == NOT_FOUND
+      && s.find('.') != NOT_FOUND;
+}
+
+double to_double(string n) {
+  char* end = NULL;
+  // safe because string.c_str() is guaranteed to be null-terminated
+  double result = strtod(n.c_str(), &end);
+  assert(*end == '\0');
+  return result;
+}