summaryrefslogtreecommitdiff
path: root/cpp/src/Slice/Parser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/src/Slice/Parser.cpp')
-rw-r--r--cpp/src/Slice/Parser.cpp335
1 files changed, 311 insertions, 24 deletions
diff --git a/cpp/src/Slice/Parser.cpp b/cpp/src/Slice/Parser.cpp
index e701b3dbdbf..75149005e17 100644
--- a/cpp/src/Slice/Parser.cpp
+++ b/cpp/src/Slice/Parser.cpp
@@ -79,6 +79,27 @@ Slice::Builtin::kind() const
return _kind;
}
+string
+Builtin::kindAsString() const
+{
+ return builtinTable[_kind];
+}
+
+const char* Slice::Builtin::builtinTable[] =
+ {
+ "byte",
+ "bool",
+ "short",
+ "int",
+ "long",
+ "float",
+ "double",
+ "string",
+ "Object",
+ "Object*",
+ "LocalObject"
+ };
+
Slice::Builtin::Builtin(const UnitPtr& unit, Kind kind) :
Type(unit),
SyntaxTreeBase(unit),
@@ -631,6 +652,66 @@ Slice::Container::createEnumerator(const string& name)
return p;
}
+ConstDefPtr
+Slice::Container::createConstDef(const string name, const TypePtr& constType,
+ const TypePtr& literalType, const string& value)
+{
+ //
+ // Check that the constant name is legal
+ //
+ ContainedList matches = _unit->findContents(thisScope() + name);
+ if(!matches.empty())
+ {
+ ConstDefPtr p = ConstDefPtr::dynamicCast(matches.front());
+ if(p)
+ {
+ if(_unit->ignRedefs())
+ {
+ return p;
+ }
+ }
+ string msg;
+ if(matches.front()->name() == name)
+ {
+ msg = "redefinition of " + matches.front()->kindOf() + " `" + matches.front()->name();
+ msg += "' as constant";
+ _unit->error(msg);
+ return 0;
+ }
+ msg = "constant `" + name + "' differs only in capitalization from ";
+ msg += matches.front()->kindOf() + " `" + matches.front()->name() + "'";
+ _unit->warning(msg); // TODO: change to error in stable_39
+ }
+
+ //
+ // Check that the constant type is legal
+ //
+ if(!legalConstType(name, constType))
+ {
+ return 0;
+ }
+
+ //
+ // Check that the type of the constant is compatible with the type of the initializer
+ //
+ if(!constTypesAreCompatible(name, constType, literalType))
+ {
+ return 0;
+ }
+
+ //
+ // Check that the initializer is in range
+ //
+ if(!checkRange(name, constType, value))
+ {
+ return 0;
+ }
+
+ ConstDefPtr p = new ConstDef(this, name, constType, value);
+ _contents.push_back(p);
+ return p;
+}
+
TypeList
Slice::Container::lookupType(const string& scoped, bool printError)
{
@@ -647,24 +728,9 @@ Slice::Container::lookupType(const string& scoped, bool printError)
//
// Check for builtin type.
//
- static const char* builtinTable[] =
- {
- "byte",
- "bool",
- "short",
- "int",
- "long",
- "float",
- "double",
- "string",
- "Object",
- "Object*",
- "LocalObject"
- };
-
- for(unsigned int i = 0; i < sizeof(builtinTable) / sizeof(const char*); ++i)
+ for(unsigned int i = 0; i < sizeof(Builtin::builtinTable) / sizeof(const char*); ++i)
{
- if(sc == builtinTable[i])
+ if(sc == Builtin::builtinTable[i])
{
TypeList result;
result.push_back(_unit->builtin(static_cast<Builtin::Kind>(i)));
@@ -1082,6 +1148,11 @@ Slice::Container::hasOtherConstructedOrExceptions() const
return true;
}
+ if(ConstDefPtr::dynamicCast(*p))
+ {
+ return true;
+ }
+
ContainerPtr container = ContainerPtr::dynamicCast(*p);
if(container && container->hasOtherConstructedOrExceptions())
{
@@ -1384,6 +1455,167 @@ Slice::Container::checkPairIntersections(const StringPartitionList& l, const str
}
}
+bool
+Slice::Container::legalConstType(const string& name, const TypePtr& constType, bool printError) const
+{
+ if(constType == 0)
+ {
+ return false;
+ }
+
+ BuiltinPtr ct = BuiltinPtr::dynamicCast(constType);
+ if(ct)
+ {
+ switch(ct->kind())
+ {
+ case Builtin::KindBool:
+ case Builtin::KindByte:
+ case Builtin::KindShort:
+ case Builtin::KindInt:
+ case Builtin::KindLong:
+ case Builtin::KindFloat:
+ case Builtin::KindDouble:
+ case Builtin::KindString:
+ {
+ return true;
+ break;
+ }
+ default:
+ {
+ string msg = "constant `" + name + "' has illegal type: `" + ct->kindAsString() + "'";
+ _unit->error(msg);
+ return false;
+ break;
+ }
+ }
+ }
+
+ EnumPtr ep = EnumPtr::dynamicCast(constType);
+ if(!ep)
+ {
+ string msg = "constant `" + name + "' has illegal type";
+ _unit->error(msg);
+ return false;
+ }
+ return true;
+}
+
+bool
+Slice::Container::constTypesAreCompatible(const string& name,
+ const TypePtr& constType,
+ const TypePtr& literalType,
+ bool printError) const
+{
+ BuiltinPtr ct = BuiltinPtr::dynamicCast(constType);
+ BuiltinPtr lt = BuiltinPtr::dynamicCast(literalType);
+ if(ct && lt)
+ {
+ switch(ct->kind())
+ {
+ case Builtin::KindBool:
+ if(lt->kind() == Builtin::KindBool)
+ {
+ return true;
+ break;
+ }
+ case Builtin::KindByte:
+ case Builtin::KindShort:
+ case Builtin::KindInt:
+ case Builtin::KindLong:
+ {
+ if(lt->kind() == Builtin::KindLong)
+ return true;
+ break;
+ }
+ case Builtin::KindFloat:
+ case Builtin::KindDouble:
+ {
+ if(lt->kind() == Builtin::KindDouble)
+ return true;
+ break;
+ }
+ case Builtin::KindString:
+ {
+ if(lt->kind() == Builtin::KindString)
+ return true;
+ break;
+ }
+ }
+ string msg = "initializer type `" + lt->kindAsString();
+ msg += "' is incompatible with the type `" + ct->kindAsString() + "' of constant `" + name + "'";
+ _unit->error(msg);
+ return false;
+ }
+ if(ct && !lt)
+ {
+ string msg = "initializer type is incompatible with the type `" + ct->kindAsString();
+ msg += "' of constant `" + name + "'";
+ _unit->error(msg);
+ return false;
+ }
+ EnumPtr ep = EnumPtr::dynamicCast(literalType);
+ if(ep)
+ {
+ // TODO: check that the left-hand enum type and the right-hand enum type are the same
+ }
+ // TODO: assert here once the enum problem is fixed -- the right-hand type can only be
+ // a built-in type or an enumeration; Grammar.y makes sure of that.
+ if(!ep)
+ {
+ // TODO: fix this
+ string msg = "hmmm... can't cast to enumerator!";
+ _unit->error(msg);
+ }
+ return true;
+}
+
+bool
+Slice::Container::checkRange(const string& name, const TypePtr& constType, const string& value, bool printError) const
+{
+ BuiltinPtr ct = BuiltinPtr::dynamicCast(constType);
+ if (!ct)
+ return true; // Enums are checked elsewhere
+
+ switch(ct->kind())
+ {
+ case Builtin::KindByte:
+ {
+ // TODO: need to really do all this with 64-bit longs -- what about Windows?
+ long l = strtol(value.c_str(), 0, 0);
+ if(l < 0 || l > 255)
+ {
+ string msg = "initializer for constant `" + name + "' out of range for type byte";
+ _unit->error(msg);
+ return false;
+ }
+ break;
+ }
+ case Builtin::KindShort:
+ {
+ long l = strtol(value.c_str(), 0, 0);
+ if(l < 32768 || l > 32767)
+ {
+ string msg = "initializer for constant `" + name + "' out of range for type short";
+ _unit->error(msg);
+ return false;
+ }
+ break;
+ }
+ case Builtin::KindInt:
+ {
+ long l = strtol(value.c_str(), 0, 0);
+ if(l < 2147483648 || l > 2147483647)
+ {
+ string msg = "initializer for constant `" + name + "' out of range for type int";
+ _unit->error(msg);
+ return false;
+ }
+ break;
+ }
+ }
+ return true; // Everything else is either in range or doesn't need checking
+}
+
// ----------------------------------------------------------------------
// Module
// ----------------------------------------------------------------------
@@ -1656,10 +1888,14 @@ Slice::ClassDef::createOperation(const string& name,
if((*q)->name() == name)
{
string msg = "operation `" + name;
- msg += "' is already defined as ";
- string vowels = "aeiou";
- msg += find(vowels.begin(), vowels.end(), *((*q)->kindOf().begin())) != vowels.end() ? "an " : "a ";
- msg += (*q)->kindOf() + " in a base interface or class";
+ msg += "' is already defined as a";
+ static const string vowels = "aeiou";
+ string kindOf = (*q)->kindOf();
+ if(vowels.find_first_of(kindOf[0]) != string::npos)
+ {
+ msg += "n";
+ }
+ msg += " " + kindOf + " in a base interface or class";
_unit->error(msg);
return 0;
}
@@ -1786,10 +2022,14 @@ Slice::ClassDef::createDataMember(const string& name, const TypePtr& type)
if((*q)->name() == name)
{
string msg = "data member `" + name;
- msg += "' is already defined as ";
+ msg += "' is already defined as a";
static const string vowels = "aeiou";
- msg += vowels.find(*((*q)->kindOf().begin())) != vowels.npos ? "an " : "a ";
- msg += (*q)->kindOf() + " in a base interface or class";
+ string kindOf = (*q)->kindOf();
+ if(vowels.find_first_of(kindOf[0]) != string::npos)
+ {
+ msg += "n";
+ }
+ msg += " " + kindOf + " in a base interface or class";
_unit->error(msg);
return 0;
}
@@ -2564,6 +2804,53 @@ Slice::Enumerator::Enumerator(const ContainerPtr& container, const string& name)
}
// ----------------------------------------------------------------------
+// ConstDef
+// ----------------------------------------------------------------------
+
+TypePtr
+Slice::ConstDef::type() const
+{
+ return _type;
+}
+
+string
+Slice::ConstDef::value() const
+{
+ return _value;
+}
+
+Contained::ContainedType
+Slice::ConstDef::containedType() const
+{
+ return ContainedTypeEnumerator; // TODO: Fix this
+}
+
+bool
+Slice::ConstDef::uses(const ContainedPtr&) const
+{
+ return false; // TODO: fix this?
+}
+
+string
+Slice::ConstDef::kindOf() const
+{
+ return "constant";
+}
+
+void
+Slice::ConstDef::visit(ParserVisitor* visitor)
+{
+ visitor->visitConstDef(this);
+}
+
+Slice::ConstDef::ConstDef(const ContainerPtr& container, const string& name,
+ const TypePtr& type, const string& value) :
+ Contained(container, name),
+ SyntaxTreeBase(container->unit()), _type(type), _value(value)
+{
+}
+
+// ----------------------------------------------------------------------
// Operation
// ----------------------------------------------------------------------