http://code.google.com/p/prettyprint/source/detail?r=584
Modified:
/trunk/language/environment.h
/trunk/language/syntax_tree.cpp
/trunk/language/syntax_tree.h
=======================================
--- /trunk/language/environment.h Thu Jun 24 17:50:36 2010
+++ /trunk/language/environment.h Sun Jul 4 10:58:50 2010
@@ -106,7 +106,7 @@
void
new_symbol_scope()
{
- m_symtab.new_context();
+ m_symtab.push_context();
}
// Add a symbol to the current nested scope. This is used while
@@ -122,7 +122,7 @@
void
end_symbol_scope()
{
- m_symtab.end_context();
+ m_symtab.pop_context();
}
// Look up a symbol by name in the current nested scope hierarchy.
=======================================
--- /trunk/language/syntax_tree.cpp Wed Jun 30 17:44:21 2010
+++ /trunk/language/syntax_tree.cpp Sun Jul 4 10:58:50 2010
@@ -302,7 +302,7 @@
string
FunctionCallExpression::to_string() const
{
- string ret = "(" + m_expr->to_string() + ")" + "(";
+ string ret = "(" + m_callee->to_string() + ")" + "(";
if (m_args) {
for (size_t i = 0; i < m_args->size(); i++) {
if (i > 0) {
=======================================
--- /trunk/language/syntax_tree.h Fri Jul 2 17:29:57 2010
+++ /trunk/language/syntax_tree.h Sun Jul 4 10:58:50 2010
@@ -95,21 +95,32 @@
{
}
- virtual ~Expression()
+ virtual
+ ~Expression()
{
}
// Evaluate this expression, producing a result.
- virtual void evaluate(Variable *out_result) = 0;
+ virtual void
+ evaluate(Variable *out_result) = 0;
// Get the resulting type of this expression.
- virtual const Type &result_type() const
+ virtual const Type &
+ result_type() const
{
return m_result_type;
}
+
+ // Test whether this expression is compile-time evaluatable.
+ virtual bool
+ is_constexpr() const
+ {
+ return false;
+ }
protected:
- void set_result_type(const Type &type)
+ void
+ set_result_type(const Type &type)
{
m_result_type = type;
}
@@ -802,11 +813,24 @@
}
int warnings = def->validate_once(flags, env);
set_result_type(*(def->type()));
+ m_definition = def;
return warnings;
}
+
+ //FIXME: comments/docs - All nodes MUST be validated before any other
+ // methods are called on them.
+ virtual bool
+ is_constexpr() const
+ {
+ if (result_type().is_const()) {
+ return true;
+ }
+ return false;
+ }
private:
util::NeverNullScopedPtr<Identifier> m_ident;
+ DefinitionStatement *m_definition; // cached for easy access
};
class SubscriptExpression : public Expression {
@@ -835,19 +859,72 @@
{
int warnings = m_expr->validate_once(flags, env)
+ m_index->validate_once(flags, env);
+
+ // Make sure it can be subscripted.
const Type &expr_type = m_expr->result_type();
Type::Primitive expr_prim = expr_type.primitive();
if (expr_prim != Type::LIST && expr_prim != Type::TUPLE
&& expr_prim != Type::VAR) {
- string why = "can't subscript type '" + expr_type.to_string() + "'";
+ string why = "can't subscript type '"
+ + expr_type.to_string() + "'";
throw SyntaxError(parse_position(), why);
}
+
+ // Make sure the subscript is legit.
+ const Type &index_type = m_index->result_type();
+ Type::Primitive index_prim = index_type.primitive();
+ if (index_prim != Type::INT && index_prim != Type::VAR) {
+ string why = "subscript index must be type '"
+ + Type::primitive_to_string(Type::INT)
+ + "', found type '" + index_type.to_string() + "'";
+ throw SyntaxError(parse_position(), why);
+ }
+
+ // Lists have at most 1 type-arg.
if (expr_prim == Type::LIST) {
- set_result_type(expr_type.argument(0));
- }
- //FIXME: tuple -> need to tell a constexpr from non
+ // See if it is a list<>, which can be any list type.
+ if (expr_type.n_arguments() == 0) {
+ //FIXME: const list l = [0,1,2]; bool b = l[0]; must fail.
+ set_result_type(Type::VAR);
+ } else {
+ set_result_type(expr_type.argument(0));
+ }
+ }
+
+ // Tuples have zero or more type-args. If the index is a constexpr,
+ // we know the type. If it is not, this expression must be runtime
+ // evaluated.
+ if (expr_prim == Type::TUPLE && m_index->is_constexpr()) {
+ //FIXME: const tuple t = [ false ]; bool b = t[0]; must succeed.
+ //FIXME: const tuple t = [ false ]; int i = t[0]; must fail.
+ try {
+ Variable v(Type::INT);
+ m_index->evaluate(&v);
+ size_t index = v.int_value().get_int();
+ if (index >= expr_type.n_arguments()) {
+ string why = sprintfxx("type '%s' has no [%d] member",
+ expr_type.to_string(),
+ index);
+ throw SyntaxError(parse_position(), why);
+ }
+ set_result_type(expr_type.argument(index));
+ } catch (Variable::TypeError &type_error) {
+ string why = "subscript index must be type '"
+ + Type::primitive_to_string(Type::INT)
+ + "', found type '" + index_type.to_string() + "'";
+ throw SyntaxError(parse_position(), why);
+ }
+ } else {
+ set_result_type(Type::VAR);
+ }
return warnings;
}
+
+ virtual bool
+ is_constexpr() const
+ {
+ return (m_expr->is_constexpr() && m_index->is_constexpr());
+ }
private:
util::NeverNullScopedPtr<Expression> m_expr;
@@ -856,19 +933,20 @@
class FunctionCallExpression : public Expression {
public:
- FunctionCallExpression(const Parser::Position &pos, Expression *expr)
- : Expression(pos), m_expr(expr), m_args(NULL)
+ //FIXME: reduce to 1 ctor
+ FunctionCallExpression(const Parser::Position &pos, Expression *callee)
+ : Expression(pos), m_callee(callee), m_args(NULL)
{
}
FunctionCallExpression(const Parser::Position &pos,
- Expression *expr, ArgumentList *args)
- : Expression(pos), m_expr(expr), m_args(args)
+ Expression *callee, ArgumentList *args)
+ : Expression(pos), m_callee(callee), m_args(args)
{
}
- Expression *expression() const
- {
- return m_expr.get();
+ Expression *callee() const
+ {
+ return m_callee.get();
}
ArgumentList *args() const
@@ -888,7 +966,7 @@
virtual int validate(const ValidateOptions &flags, Environment *env)
{
- int warnings = m_expr->validate_once(flags, env);
+ int warnings = m_callee->validate_once(flags, env);
if (m_args) {
for (size_t i = 0; i < m_args->size(); i++) {
warnings += m_args->at(i)->validate_once(flags, env);
@@ -898,7 +976,7 @@
}
private:
- util::NeverNullScopedPtr<Expression> m_expr;
+ util::NeverNullScopedPtr<Expression> m_callee;
util::MaybeNullScopedPtr<ArgumentList> m_args;
};
@@ -959,9 +1037,8 @@
case OP_POSTDEC:
// These ops require non-const expressions.
if (expr_type.is_const()) {
- throw syntax_error(
- "expected non-const int expression,"
- " found '%s'", expr_type);
+ throw syntax_error("expected non-const expression, found '%s'",
+ expr_type);
}
// fall through
case OP_POS:
@@ -970,9 +1047,8 @@
// These ops do not about constness.
if (expr_prim != Type::INT
&& expr_prim != Type::VAR) {
- throw syntax_error(
- "expected int expression, found '%s'",
- expr_type);
+ throw syntax_error("expected int expression, found '%s'",
+ expr_type);
}
set_result_type(Type::INT);
break;
@@ -980,6 +1056,23 @@
return warnings;
}
+
+ virtual bool
+ is_constexpr() const
+ {
+ if (m_expr->is_constexpr()) {
+ switch (m_op) {
+ case OP_POS:
+ case OP_NEG:
+ case OP_NOT:
+ case OP_BITNOT:
+ return true;
+ default:
+ break;
+ }
+ }
+ return false;
+ }
private:
SyntaxError
@@ -1130,6 +1223,36 @@
return warnings;
}
+
+ virtual bool
+ is_constexpr() const
+ {
+ if (m_lhs->is_constexpr() && m_rhs->is_constexpr()) {
+ switch (m_op) {
+ case OP_EQ:
+ case OP_NEQ:
+ case OP_LT:
+ case OP_GT:
+ case OP_LE:
+ case OP_GE:
+ case OP_MUL:
+ case OP_DIV:
+ case OP_MOD:
+ case OP_ADD:
+ case OP_SUB:
+ case OP_SHL:
+ case OP_SHR:
+ case OP_AND:
+ case OP_OR:
+ case OP_XOR:
+ case OP_COMMA:
+ return true;
+ default:
+ break;
+ }
+ }
+ return false;
+ }
private:
SyntaxError
@@ -1195,6 +1318,13 @@
return warnings;
}
+
+ virtual bool
+ is_constexpr() const
+ {
+ return (m_condition->is_constexpr()
+ && m_true->is_constexpr() && m_false->is_constexpr());
+ }
private:
util::NeverNullScopedPtr<Expression> m_condition;
@@ -1248,6 +1378,12 @@
{
return 0;
}
+
+ virtual bool
+ is_constexpr() const
+ {
+ return true;
+ }
private:
util::NeverNullScopedPtr<const Variable::Datum> m_value;
@@ -1311,6 +1447,12 @@
env->end_symbol_scope();
return warnings;
}
+
+ virtual bool
+ is_constexpr() const
+ {
+ return true;
+ }
private:
// Make a new DefinitionStatement that is the built-in function args list.
@@ -1365,6 +1507,12 @@
return warnings;
}
+
+ virtual bool
+ is_constexpr() const
+ {
+ return true;
+ }
private:
util::NeverNullScopedPtr<ArgumentList> m_contents;