Commit 06c7d568 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Implement string formatting keys (ex: "%(name)s")

parent fd353841
...@@ -33,6 +33,8 @@ public: ...@@ -33,6 +33,8 @@ public:
BoxedDictIterator(BoxedDict* d, IteratorType type); BoxedDictIterator(BoxedDict* d, IteratorType type);
}; };
Box* dictGetitem(BoxedDict* self, Box* k);
Box* dictIterKeys(Box* self); Box* dictIterKeys(Box* self);
Box* dictIterValues(Box* self); Box* dictIterValues(Box* self);
Box* dictIterItems(Box* self); Box* dictIterItems(Box* self);
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "core/types.h" #include "core/types.h"
#include "core/util.h" #include "core/util.h"
#include "gc/collector.h" #include "gc/collector.h"
#include "runtime/dict.h"
#include "runtime/objmodel.h" #include "runtime/objmodel.h"
#include "runtime/types.h" #include "runtime/types.h"
#include "runtime/util.h" #include "runtime/util.h"
...@@ -54,6 +55,10 @@ extern "C" Box* strMod(BoxedString* lhs, Box* rhs) { ...@@ -54,6 +55,10 @@ extern "C" Box* strMod(BoxedString* lhs, Box* rhs) {
_elts.push_back(rhs); _elts.push_back(rhs);
} }
BoxedDict* dict = NULL;
if (rhs->cls == dict_cls)
dict = static_cast<BoxedDict*>(rhs);
const char* fmt = lhs->s.c_str(); const char* fmt = lhs->s.c_str();
const char* fmt_end = fmt + lhs->s.size(); const char* fmt_end = fmt + lhs->s.size();
...@@ -74,6 +79,32 @@ extern "C" Box* strMod(BoxedString* lhs, Box* rhs) { ...@@ -74,6 +79,32 @@ extern "C" Box* strMod(BoxedString* lhs, Box* rhs) {
int mode = 0; int mode = 0;
while (true) { while (true) {
RELEASE_ASSERT(fmt < fmt_end, ""); RELEASE_ASSERT(fmt < fmt_end, "");
Box* val_to_use = NULL;
if (*fmt == '(') {
if (dict == NULL)
raiseExcHelper(TypeError, "format requires a mapping");
int pcount = 1;
fmt++;
const char* keystart = fmt;
while (pcount > 0 && fmt < fmt_end) {
char c = *fmt;
if (c == ')')
pcount--;
else if (c == '(')
pcount++;
fmt++;
}
if (pcount > 0)
raiseExcHelper(ValueError, "incomplete format key");
BoxedString* key = boxStrConstantSize(keystart, fmt - keystart - 1);
val_to_use = dictGetitem(dict, key);
}
char c = *fmt; char c = *fmt;
fmt++; fmt++;
...@@ -107,19 +138,23 @@ extern "C" Box* strMod(BoxedString* lhs, Box* rhs) { ...@@ -107,19 +138,23 @@ extern "C" Box* strMod(BoxedString* lhs, Box* rhs) {
RELEASE_ASSERT(nzero == 0, ""); RELEASE_ASSERT(nzero == 0, "");
RELEASE_ASSERT(nspace == 0, ""); RELEASE_ASSERT(nspace == 0, "");
RELEASE_ASSERT(elt_num < num_elts, "insufficient number of arguments for format string"); if (!val_to_use) {
Box* b = (*elts)[elt_num]; RELEASE_ASSERT(elt_num < num_elts, "insufficient number of arguments for format string");
elt_num++; val_to_use = (*elts)[elt_num];
elt_num++;
}
BoxedString* s = str(b); BoxedString* s = str(val_to_use);
os << s->s; os << s->s;
break; break;
} else if (c == 'd') { } else if (c == 'd') {
RELEASE_ASSERT(elt_num < num_elts, "insufficient number of arguments for format string"); if (!val_to_use) {
Box* b = (*elts)[elt_num]; RELEASE_ASSERT(elt_num < num_elts, "insufficient number of arguments for format string");
elt_num++; val_to_use = (*elts)[elt_num];
elt_num++;
}
RELEASE_ASSERT(b->cls == int_cls, "unsupported"); RELEASE_ASSERT(val_to_use->cls == int_cls, "unsupported");
std::ostringstream fmt(""); std::ostringstream fmt("");
fmt << '%'; fmt << '%';
...@@ -132,19 +167,21 @@ extern "C" Box* strMod(BoxedString* lhs, Box* rhs) { ...@@ -132,19 +167,21 @@ extern "C" Box* strMod(BoxedString* lhs, Box* rhs) {
fmt << "ld"; fmt << "ld";
char buf[20]; char buf[20];
snprintf(buf, 20, fmt.str().c_str(), static_cast<BoxedInt*>(b)->n); snprintf(buf, 20, fmt.str().c_str(), static_cast<BoxedInt*>(val_to_use)->n);
os << std::string(buf); os << std::string(buf);
break; break;
} else if (c == 'f') { } else if (c == 'f') {
RELEASE_ASSERT(elt_num < num_elts, "insufficient number of arguments for format string"); if (!val_to_use) {
Box* b = (*elts)[elt_num]; RELEASE_ASSERT(elt_num < num_elts, "insufficient number of arguments for format string");
elt_num++; val_to_use = (*elts)[elt_num];
elt_num++;
}
double d; double d;
if (b->cls == float_cls) { if (val_to_use->cls == float_cls) {
d = static_cast<BoxedFloat*>(b)->d; d = static_cast<BoxedFloat*>(val_to_use)->d;
} else if (b->cls == int_cls) { } else if (val_to_use->cls == int_cls) {
d = static_cast<BoxedInt*>(b)->n; d = static_cast<BoxedInt*>(val_to_use)->n;
} else { } else {
RELEASE_ASSERT(0, "unsupported"); RELEASE_ASSERT(0, "unsupported");
} }
......
...@@ -2,3 +2,9 @@ print "%d" % 1 ...@@ -2,3 +2,9 @@ print "%d" % 1
print "%02d" % 2 print "%02d" % 2
print "%f" % 1 print "%f" % 1
print "%s" % 2 print "%s" % 2
print "%(n)d %(x)f %(m)s" % {'x':1.0, 'n':2, 'm':"hello world"}
print "%(a(b))s" % {'a(b)': 1}
# I'm not sure if this is a feature or a bug, but both CPython and PyPy will accept it:
print "%s %(a)s" % {'a': 1}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment