@srcdir@/expr.cpp \
type.cpp \
command.h \
- command.cpp
+ command.cpp \
+ declaration_scope.h \
+ declaration_scope.cpp
+
EXTRA_DIST = \
@srcdir@/kind.h \
--- /dev/null
+/********************* */
+/** declaration_scope.cpp
+ ** Original author: cconway
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010 The Analysis of Computer Systems Group (ACSys)
+ ** Courant Institute of Mathematical Sciences
+ ** New York University
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.
+ **
+ ** Convenience class for scoping variable and type declarations (implementation)
+ **/
+
+#include "declaration_scope.h"
+#include "expr.h"
+#include "type.h"
+
+#include "context/cdmap.h"
+#include "context/context.h"
+
+#include <string>
+
+namespace CVC4 {
+
+using namespace context;
+
+DeclarationScope::DeclarationScope() :
+ d_context(new Context()),
+ d_exprMap(new (true) CDMap<std::string,Expr,StringHashFunction>(d_context)),
+ d_typeMap(new (true) CDMap<std::string,Type*,StringHashFunction>(d_context)) {
+}
+
+DeclarationScope::~DeclarationScope() {
+ d_exprMap->deleteSelf();
+ delete d_context;
+}
+
+void DeclarationScope::bind(const std::string& name, const Expr& obj) throw () {
+ d_exprMap->insert(name,obj);
+}
+
+bool DeclarationScope::isBound(const std::string& name) const throw () {
+ return d_exprMap->find(name) != d_exprMap->end();
+}
+
+Expr DeclarationScope::lookup(const std::string& name) const throw () {
+ return (*d_exprMap->find(name)).second;
+}
+
+void DeclarationScope::bindType(const std::string& name, Type* t) throw () {
+ d_typeMap->insert(name,t);
+}
+
+bool DeclarationScope::isBoundType(const std::string& name) const throw () {
+ return d_typeMap->find(name) != d_typeMap->end();
+}
+
+Type* DeclarationScope::lookupType(const std::string& name) const throw () {
+ return (*d_typeMap->find(name)).second;
+}
+
+
+void DeclarationScope::popScope() throw (ScopeException) {
+ if( d_context->getLevel() == 0 ) {
+ throw ScopeException();
+ }
+ d_context->pop();
+}
+
+void DeclarationScope::pushScope() throw () {
+ d_context->push();
+}
+
+} // namespace CVC4
--- /dev/null
+/********************* */
+/** context.h
+ ** Original author: cconway
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010 The Analysis of Computer Systems Group (ACSys)
+ ** Courant Institute of Mathematical Sciences
+ ** New York University
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.
+ **
+ ** Convenience class for scoping variable and type declarations.
+ **/
+
+#ifndef DECLARATION_SCOPE_H_
+#define DECLARATION_SCOPE_H_
+
+#include "expr.h"
+
+#include <ext/hash_map>
+
+namespace CVC4 {
+
+class Type;
+
+namespace context {
+
+class Context;
+
+template <class Key, class Data, class HashFcn>
+class CDMap;
+
+} //namespace context
+
+/** A basic hash function for std::string
+ * TODO: Does this belong somewhere else (like util/)?
+ */
+struct StringHashFunction {
+ size_t operator()(const std::string& str) const {
+ return __gnu_cxx::hash<const char*>()(str.c_str());
+ }
+};
+
+class CVC4_PUBLIC ScopeException : public Exception {
+};
+
+/**
+ * A convenience class for handling scoped declarations. Implements the usual
+ * nested scoping rules for declarations, with separate bindings for expressions
+ * and types.
+ */
+class CVC4_PUBLIC DeclarationScope {
+ /** The context manager for the scope maps. */
+ context::Context *d_context;
+
+ /** A map for expressions. */
+ context::CDMap<std::string,Expr,StringHashFunction> *d_exprMap;
+
+ /** A map for types. */
+ context::CDMap<std::string,Type*,StringHashFunction> *d_typeMap;
+
+public:
+ /** Create a declaration scope. */
+ DeclarationScope();
+
+ /** Destroy a declaration scope. */
+ ~DeclarationScope();
+
+ /** Bind an expression to a name in the current scope level.
+ * If <code>name</code> is already bound in the current level, then the
+ * binding is replaced. If <code>name</code> is bound in a previous
+ * level, then the binding is "covered" by this one until the current
+ * scope is popped.
+ *
+ * @param name an identifier
+ * @param obj the expression to bind to <code>name</code>
+ */
+ void bind(const std::string& name, const Expr& obj) throw ();
+
+ /** Bind a type to a name in the current scope.
+ * If <code>name</code> is already bound to a type in the current level,
+ * then the binding is replaced. If <code>name</code> is bound in a
+ * previous level, then the binding is "covered" by this one until the
+ * current scope is popped.
+ *
+ * @param name an identifier
+ * @param t the type to bind to <code>name</code>
+ */
+ void bindType(const std::string& name, Type* t) throw ();
+
+ /** Check whether a name is bound to an expression.
+ *
+ * @param name the identifier to check.
+ * @returns true iff name is bound in the current scope.
+ */
+ bool isBound(const std::string& name) const throw ();
+
+ /** Check whether a name is bound to a type.
+ *
+ * @param name the identifier to check.
+ * @returns true iff name is bound to a type in the current scope.
+ */
+ bool isBoundType(const std::string& name) const throw ();
+
+ /** Lookup a bound expression.
+ *
+ * @param name the identifier to lookup
+ * @returns the expression bound to <code>name</code> in the current scope.
+ */
+ Expr lookup(const std::string& name) const throw ();
+
+ /** Lookup a bound type.
+ *
+ * @param name the identifier to lookup
+ * @returns the type bound to <code>name</code> in the current scope.
+ */
+ Type* lookupType(const std::string& name) const throw ();
+
+ /** Pop a scope level. Deletes all bindings since the last call to
+ * <code>pushScope</code>. Calls to <code>pushScope</code> and
+ * <code>popScope</code> must be "properly nested." I.e., a call to
+ * <code>popScope</code> is only legal if the number of prior calls to
+ * <code>pushScope</code> on this <code>DeclarationScope</code> is strictly
+ * greater than then number of prior calls to <code>popScope</code>. */
+ void popScope() throw (ScopeException);
+
+ /** Push a scope level. */
+ void pushScope() throw ();
+};
+
+} // namespace CVC4
+
+#endif /* DECLARATION_SCOPE_H_ */
switch( type ) {
case SYM_VARIABLE: // Functions share var namespace
- return d_varTable.getObject(name);
+ return d_declScope.lookup(name);
default:
Unhandled(type);
Type* ParserState::getSort(const std::string& name) {
Assert( isDeclared(name, SYM_SORT) );
- Type* t = d_sortTable.getObject(name);
+ Type *t = d_declScope.lookupType(name);
return t;
}
void
ParserState::defineVar(const std::string& name, const Expr& val) {
Assert(!isDeclared(name));
- d_varTable.bindName(name,val);
+ d_declScope.bind(name,val);
Assert(isDeclared(name));
}
+/*
void
ParserState::undefineVar(const std::string& name) {
Assert(isDeclared(name));
- d_varTable.unbindName(name);
+ d_declScope.unbind(name);
Assert(!isDeclared(name));
}
+*/
void
ParserState::setLogic(const std::string& name) {
Debug("parser") << "newSort(" << name << ")" << std::endl;
Assert( !isDeclared(name, SYM_SORT) ) ;
Type* type = d_exprManager->mkSort(name);
- d_sortTable.bindName(name, type);
+ d_declScope.bindType(name, type);
Assert( isDeclared(name, SYM_SORT) ) ;
return type;
}
bool ParserState::isDeclared(const std::string& name, SymbolType type) {
switch(type) {
case SYM_VARIABLE:
- return d_varTable.isBound(name);
+ return d_declScope.isBound(name);
case SYM_SORT:
- return d_sortTable.isBound(name);
+ return d_declScope.isBoundType(name);
default:
Unhandled(type);
}
#include <string>
+#include "expr/declaration_scope.h"
#include "expr/expr.h"
#include "expr/kind.h"
#include "parser/input.h"
/** The input that we're parsing. */
Input *d_input;
- /** The symbol table lookup */
- SymbolTable<Expr> d_varTable;
-
- /** The sort table */
- SymbolTable<Type*> d_sortTable;
+ /** The symbol table */
+ DeclarationScope d_declScope;
/** The name of the input file. */
std::string d_filename;
return d_input;
}
+ /** Set the declaration scope manager for this input. NOTE: This should <em>only</me> be
+ * called before parsing begins. Otherwise, previous declarations will be lost. */
+ inline void setDeclarationScope(DeclarationScope declScope) {
+ d_declScope = declScope;
+ }
+
/**
* Check if we are done -- either the end of input has been reached, or some
* error has been encountered.
d_input->parseError(msg);
}
+ inline void pushScope() { d_declScope.pushScope(); }
+ inline void popScope() { d_declScope.popScope(); }
}; // class ParserState
} // namespace parser
(LET_TOK LPAREN_TOK let_identifier[name,CHECK_UNDECLARED]
| FLET_TOK LPAREN_TOK flet_identifier[name,CHECK_UNDECLARED] )
annotatedFormula[expr] RPAREN_TOK
- { PARSER_STATE->defineVar(name,expr); }
+ { PARSER_STATE->pushScope();
+ PARSER_STATE->defineVar(name,expr); }
annotatedFormula[expr]
RPAREN_TOK
- { PARSER_STATE->undefineVar(name); }
+ { PARSER_STATE->popScope(); }
| /* a variable */
( identifier[name,CHECK_DECLARED,SYM_VARIABLE]
expr/node_manager_white \
expr/attribute_white \
expr/attribute_black \
+ expr/declaration_scope_black \
parser/parser_white \
context/context_black \
context/context_white \
--- /dev/null
+/********************* */
+/** declaration_scope_black.h
+ ** Original author: cconway
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010 The Analysis of Computer Systems Group (ACSys)
+ ** Courant Institute of Mathematical Sciences
+ ** New York University
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.
+ **
+ ** Black box testing of CVC4::DeclarationScope.
+ **/
+
+#include <cxxtest/TestSuite.h>
+
+#include <sstream>
+#include <string>
+
+#include "context/context.h"
+#include "expr/declaration_scope.h"
+#include "expr/expr_manager.h"
+#include "expr/expr.h"
+#include "expr/type.h"
+#include "util/Assert.h"
+#include "util/exception.h"
+
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::context;
+using namespace std;
+
+class DeclarationScopeBlack : public CxxTest::TestSuite {
+private:
+
+ ExprManager* d_exprManager;
+
+public:
+
+ void setUp() {
+ try {
+ d_exprManager = new ExprManager;
+ } catch(Exception e) {
+ cerr << "Exception during setUp():" << endl << e;
+ throw;
+ }
+ }
+
+ void tearDown() {
+ try {
+ delete d_exprManager;
+ } catch(Exception e) {
+ cerr << "Exception during tearDown():" << endl << e;
+ throw;
+ }
+ }
+
+ void testBind() {
+ DeclarationScope declScope;
+ Type *booleanType = d_exprManager->booleanType();
+ Expr x = d_exprManager->mkVar(booleanType);
+ declScope.bind("x",x);
+ TS_ASSERT( declScope.isBound("x") );
+ TS_ASSERT_EQUALS( declScope.lookup("x"), x );
+ }
+
+ void testBind2() {
+ DeclarationScope declScope;
+ Type *booleanType = d_exprManager->booleanType();
+ // var name attribute shouldn't matter
+ Expr y = d_exprManager->mkVar("y", booleanType);
+ declScope.bind("x",y);
+ TS_ASSERT( declScope.isBound("x") );
+ TS_ASSERT_EQUALS( declScope.lookup("x"), y );
+ }
+
+ void testBind3() {
+ DeclarationScope declScope;
+ Type *booleanType = d_exprManager->booleanType();
+ Expr x = d_exprManager->mkVar(booleanType);
+ declScope.bind("x",x);
+ Expr y = d_exprManager->mkVar(booleanType);
+ // new binding covers old
+ declScope.bind("x",y);
+ TS_ASSERT( declScope.isBound("x") );
+ TS_ASSERT_EQUALS( declScope.lookup("x"), y );
+ }
+
+ void testBind4() {
+ DeclarationScope declScope;
+ Type *booleanType = d_exprManager->booleanType();
+ Expr x = d_exprManager->mkVar(booleanType);
+ declScope.bind("x",x);
+
+ Type *t = d_exprManager->mkSort("T");
+ // duplicate binding for type is OK
+ declScope.bindType("x",t);
+
+ TS_ASSERT( declScope.isBound("x") );
+ TS_ASSERT_EQUALS( declScope.lookup("x"), x );
+ TS_ASSERT( declScope.isBoundType("x") );
+ TS_ASSERT_EQUALS( declScope.lookupType("x"), t );
+ }
+
+ void testBindType() {
+ DeclarationScope declScope;
+ Type *s = d_exprManager->mkSort("S");
+ declScope.bindType("S",s);
+ TS_ASSERT( declScope.isBoundType("S") );
+ TS_ASSERT_EQUALS( declScope.lookupType("S"), s );
+ }
+
+ void testBindType2() {
+ DeclarationScope declScope;
+ // type name attribute shouldn't matter
+ Type *s = d_exprManager->mkSort("S");
+ declScope.bindType("T",s);
+ TS_ASSERT( declScope.isBoundType("T") );
+ TS_ASSERT_EQUALS( declScope.lookupType("T"), s );
+ }
+
+ void testBindType3() {
+ DeclarationScope declScope;
+ Type *s = d_exprManager->mkSort("S");
+ declScope.bindType("S",s);
+ Type *t = d_exprManager->mkSort("T");
+ // new binding covers old
+ declScope.bindType("S",t);
+ TS_ASSERT( declScope.isBoundType("S") );
+ TS_ASSERT_EQUALS( declScope.lookupType("S"), t );
+ }
+
+ void testPushScope() {
+ DeclarationScope declScope;
+ Type *booleanType = d_exprManager->booleanType();
+ Expr x = d_exprManager->mkVar(booleanType);
+ declScope.bind("x",x);
+ declScope.pushScope();
+
+ TS_ASSERT( declScope.isBound("x") );
+ TS_ASSERT_EQUALS( declScope.lookup("x"), x );
+
+ Expr y = d_exprManager->mkVar(booleanType);
+ declScope.bind("x",y);
+
+ TS_ASSERT( declScope.isBound("x") );
+ TS_ASSERT_EQUALS( declScope.lookup("x"), y );
+
+ declScope.popScope();
+ TS_ASSERT( declScope.isBound("x") );
+ TS_ASSERT_EQUALS( declScope.lookup("x"), x );
+ }
+
+ void testBadPop() {
+ DeclarationScope declScope;
+ // TODO: What kind of exception gets thrown here?
+ TS_ASSERT_THROWS( declScope.popScope(), ScopeException );
+ }
+};
delete d_exprManager;
}
+ void testBs() {
+ DeclarationScope declScope;
+ declScope.bind("foo", d_exprManager->mkVar("foo",d_exprManager->booleanType()));
+
+ }
+
void testGoodCvc4Inputs() {
tryGoodInputs(LANG_CVC4,goodCvc4Inputs,numGoodCvc4Inputs);
}