Fix: Nesting an object in a template causes the template to become non-abstract

fixes #7537
This commit is contained in:
Gunnar Beutner 2014-11-01 06:25:58 +01:00
parent 93b66a0c4a
commit d300ceaaf7

View File

@ -206,23 +206,32 @@ void yyerror(YYLTYPE *locp, ConfigCompiler *, const char *err)
int yyparse(ConfigCompiler *context); int yyparse(ConfigCompiler *context);
static bool m_Abstract; static std::stack<bool> m_Abstract;
static std::stack<TypeRuleList::Ptr> m_RuleLists; static std::stack<TypeRuleList::Ptr> m_RuleLists;
static ConfigType::Ptr m_Type; static ConfigType::Ptr m_Type;
static Dictionary::Ptr m_ModuleScope; static Dictionary::Ptr m_ModuleScope;
static bool m_Apply; static std::stack<bool> m_Apply;
static bool m_ObjectAssign; static std::stack<bool> m_ObjectAssign;
static bool m_SeenAssign; static std::stack<bool> m_SeenAssign;
static Expression::Ptr m_Assign; static std::stack<Expression::Ptr> m_Assign;
static Expression::Ptr m_Ignore; static std::stack<Expression::Ptr> m_Ignore;
void ConfigCompiler::Compile(void) void ConfigCompiler::Compile(void)
{ {
m_ModuleScope = make_shared<Dictionary>(); m_ModuleScope = make_shared<Dictionary>();
m_Abstract = std::stack<bool>();
m_RuleLists = std::stack<TypeRuleList::Ptr>();
m_Type.reset();
m_Apply = std::stack<bool>();
m_ObjectAssign = std::stack<bool>();
m_SeenAssign = std::stack<bool>();
m_Assign = std::stack<Expression::Ptr>();
m_Ignore = std::stack<Expression::Ptr>();
try { try {
yyparse(this); yyparse(this);
} catch (const ConfigError& ex) { } catch (const ConfigError& ex) {
@ -415,19 +424,20 @@ type: T_TYPE_DICTIONARY
object: object:
{ {
m_Abstract = false; m_Abstract.push(false);
m_ObjectAssign = true; m_ObjectAssign.push(true);
m_SeenAssign = false; m_SeenAssign.push(false);
m_Assign = make_shared<Expression>(&Expression::OpLiteral, false, DebugInfo()); m_Assign.push(make_shared<Expression>(&Expression::OpLiteral, false, DebugInfo()));
m_Ignore = make_shared<Expression>(&Expression::OpLiteral, false, DebugInfo()); m_Ignore.push(make_shared<Expression>(&Expression::OpLiteral, false, DebugInfo()));
} }
object_declaration identifier rterm rterm_scope object_declaration identifier rterm rterm_scope
{ {
m_ObjectAssign = false; m_ObjectAssign.pop();
Array::Ptr args = make_shared<Array>(); Array::Ptr args = make_shared<Array>();
args->Add(m_Abstract); args->Add(m_Abstract.top());
m_Abstract.pop();
String type = $3; String type = $3;
args->Add(type); args->Add(type);
@ -440,27 +450,29 @@ object:
delete $5; delete $5;
exprl->MakeInline(); exprl->MakeInline();
if (m_SeenAssign && !ObjectRule::IsValidSourceType(type)) if (m_SeenAssign.top() && !ObjectRule::IsValidSourceType(type))
BOOST_THROW_EXCEPTION(ConfigError("object rule 'assign' cannot be used for type '" + type + "'") << errinfo_debuginfo(DebugInfoRange(@2, @3))); BOOST_THROW_EXCEPTION(ConfigError("object rule 'assign' cannot be used for type '" + type + "'") << errinfo_debuginfo(DebugInfoRange(@2, @3)));
Expression::Ptr rex = make_shared<Expression>(&Expression::OpLogicalNegate, m_Ignore, DebugInfoRange(@2, @5)); m_SeenAssign.pop();
Expression::Ptr filter = make_shared<Expression>(&Expression::OpLogicalAnd, m_Assign, rex, DebugInfoRange(@2, @5));
Expression::Ptr rex = make_shared<Expression>(&Expression::OpLogicalNegate, m_Ignore.top(), DebugInfoRange(@2, @5));
m_Ignore.pop();
Expression::Ptr filter = make_shared<Expression>(&Expression::OpLogicalAnd, m_Assign.top(), rex, DebugInfoRange(@2, @5));
m_Assign.pop();
args->Add(filter); args->Add(filter);
args->Add(context->GetZone()); args->Add(context->GetZone());
$$ = new Value(make_shared<Expression>(&Expression::OpObject, args, exprl, DebugInfoRange(@2, @5))); $$ = new Value(make_shared<Expression>(&Expression::OpObject, args, exprl, DebugInfoRange(@2, @5)));
m_Assign.reset();
m_Ignore.reset();
} }
; ;
object_declaration: T_OBJECT object_declaration: T_OBJECT
| T_TEMPLATE | T_TEMPLATE
{ {
m_Abstract = true; m_Abstract.top() = true;
} }
identifier_items: identifier_items_inner identifier_items: identifier_items_inner
@ -583,23 +595,22 @@ lterm: identifier lbinary_op rterm
} }
| T_ASSIGN T_WHERE rterm | T_ASSIGN T_WHERE rterm
{ {
if (!(m_Apply || m_ObjectAssign)) if ((m_Apply.empty() || !m_Apply.top()) && (m_ObjectAssign.empty() || !m_ObjectAssign.top()))
BOOST_THROW_EXCEPTION(ConfigError("'assign' keyword not valid in this context.")); BOOST_THROW_EXCEPTION(ConfigError("'assign' keyword not valid in this context."));
m_SeenAssign = true; m_SeenAssign.top() = true;
m_Assign = make_shared<Expression>(&Expression::OpLogicalOr, m_Assign, *$3, DebugInfoRange(@1, @3)); m_Assign.top() = make_shared<Expression>(&Expression::OpLogicalOr, m_Assign.top(), *$3, DebugInfoRange(@1, @3));
delete $3; delete $3;
$$ = new Value(make_shared<Expression>(&Expression::OpLiteral, Empty, DebugInfoRange(@1, @3))); $$ = new Value(make_shared<Expression>(&Expression::OpLiteral, Empty, DebugInfoRange(@1, @3)));
} }
| T_IGNORE T_WHERE rterm | T_IGNORE T_WHERE rterm
{ {
if (!(m_Apply || m_ObjectAssign)) if ((m_Apply.empty() || !m_Apply.top()) && (m_ObjectAssign.empty() || !m_ObjectAssign.top()))
BOOST_THROW_EXCEPTION(ConfigError("'ignore' keyword not valid in this context.")); BOOST_THROW_EXCEPTION(ConfigError("'ignore' keyword not valid in this context."));
m_Ignore = make_shared<Expression>(&Expression::OpLogicalOr, m_Ignore, *$3, DebugInfoRange(@1, @3)); m_Ignore.top() = make_shared<Expression>(&Expression::OpLogicalOr, m_Ignore.top(), *$3, DebugInfoRange(@1, @3));
delete $3; delete $3;
$$ = new Value(make_shared<Expression>(&Expression::OpLiteral, Empty, DebugInfoRange(@1, @3))); $$ = new Value(make_shared<Expression>(&Expression::OpLiteral, Empty, DebugInfoRange(@1, @3)));
@ -827,14 +838,14 @@ target_type_specifier: /* empty */
apply: apply:
{ {
m_Apply = true; m_Apply.push(true);
m_SeenAssign = false; m_SeenAssign.push(false);
m_Assign = make_shared<Expression>(&Expression::OpLiteral, false, DebugInfo()); m_Assign.push(make_shared<Expression>(&Expression::OpLiteral, false, DebugInfo()));
m_Ignore = make_shared<Expression>(&Expression::OpLiteral, false, DebugInfo()); m_Ignore.push(make_shared<Expression>(&Expression::OpLiteral, false, DebugInfo()));
} }
T_APPLY identifier rterm target_type_specifier rterm T_APPLY identifier rterm target_type_specifier rterm
{ {
m_Apply = false; m_Apply.pop();
String type = $3; String type = $3;
free($3); free($3);
@ -873,11 +884,16 @@ apply:
exprl->MakeInline(); exprl->MakeInline();
// assign && !ignore // assign && !ignore
if (!m_SeenAssign) if (!m_SeenAssign.top())
BOOST_THROW_EXCEPTION(ConfigError("'apply' is missing 'assign'") << errinfo_debuginfo(DebugInfoRange(@2, @3))); BOOST_THROW_EXCEPTION(ConfigError("'apply' is missing 'assign'") << errinfo_debuginfo(DebugInfoRange(@2, @3)));
Expression::Ptr rex = make_shared<Expression>(&Expression::OpLogicalNegate, m_Ignore, DebugInfoRange(@2, @5)); m_SeenAssign.pop();
Expression::Ptr filter = make_shared<Expression>(&Expression::OpLogicalAnd, m_Assign, rex, DebugInfoRange(@2, @5));
Expression::Ptr rex = make_shared<Expression>(&Expression::OpLogicalNegate, m_Ignore.top(), DebugInfoRange(@2, @5));
m_Ignore.pop();
Expression::Ptr filter = make_shared<Expression>(&Expression::OpLogicalAnd, m_Assign.top(), rex, DebugInfoRange(@2, @5));
m_Assign.pop();
Array::Ptr args = make_shared<Array>(); Array::Ptr args = make_shared<Array>();
args->Add(type); args->Add(type);
@ -886,9 +902,6 @@ apply:
args->Add(filter); args->Add(filter);
$$ = new Value(make_shared<Expression>(&Expression::OpApply, args, exprl, DebugInfoRange(@2, @5))); $$ = new Value(make_shared<Expression>(&Expression::OpApply, args, exprl, DebugInfoRange(@2, @5)));
m_Assign.reset();
m_Ignore.reset();
} }
; ;