Add raise, break, continue, and a hacky attempt at for loops.

for loops currently generate a core dump.
This commit is contained in:
Darryl Pogue
2011-01-01 02:31:31 -08:00
parent 7e4de4e612
commit f1205548e5
4 changed files with 179 additions and 9 deletions

View File

@@ -21,7 +21,7 @@ void ASTNodeList::removeFirst()
const char* ASTUnary::op_str() const
{
static const char* s_op_strings[] = {
"+", "-", "~", "not ", "`"
"+", "-", "~", "not "
};
return s_op_strings[op()];
}
@@ -50,6 +50,17 @@ const char* ASTCompare::op_str() const
return s_cmp_strings[op()];
}
/* ASTKeyword */
const char* ASTKeyword::word_str() const
{
static const char* s_word_strings[] = {
"break", "continue"
};
return s_word_strings[key()];
}
/* ASTBlock */
void ASTBlock::removeLast()
{

View File

@@ -12,7 +12,8 @@ public:
NODE_INVALID, NODE_NODELIST, NODE_OBJECT, NODE_UNARY, NODE_BINARY,
NODE_COMPARE, NODE_STORE, NODE_RETURN, NODE_NAME, NODE_DELETE,
NODE_FUNCTION, NODE_CLASS, NODE_CALL, NODE_IMPORT, NODE_TUPLE,
NODE_LIST, NODE_MAP, NODE_SUBSCR, NODE_PRINT, NODE_BLOCK,
NODE_LIST, NODE_MAP, NODE_SUBSCR, NODE_PRINT, NODE_CONVERT,
NODE_KEYWORD, NODE_RAISE, NODE_BLOCK,
// Empty nodes
NODE_PASS, NODE_LOCALS
@@ -68,7 +69,7 @@ private:
class ASTUnary : public ASTNode {
public:
enum UnOp {
UN_POSITIVE, UN_NEGATIVE, UN_INVERT, UN_NOT, UN_CONVERT
UN_POSITIVE, UN_NEGATIVE, UN_INVERT, UN_NOT
};
ASTUnary(PycRef<ASTNode> operand, int op)
@@ -315,6 +316,47 @@ private:
};
class ASTConvert : public ASTNode {
public:
ASTConvert(PycRef<ASTNode> name)
: ASTNode(NODE_CONVERT), m_name(name) { }
PycRef<ASTNode> name() const { return m_name; }
private:
PycRef<ASTNode> m_name;
};
class ASTKeyword : public ASTNode {
public:
enum Word {
KW_BREAK, KW_CONTINUE
};
ASTKeyword(Word key) : ASTNode(NODE_KEYWORD), m_key(key) { }
Word key() const { return m_key; }
const char* word_str() const;
private:
Word m_key;
};
class ASTRaise : public ASTNode {
public:
typedef std::list<PycRef<ASTNode> > param_t;
ASTRaise(param_t params) : ASTNode(NODE_RAISE), m_params(params) { }
const param_t& params() const { return m_params; }
private:
param_t m_params;
};
class ASTBlock : public ASTNode {
public:
typedef std::list<PycRef<ASTNode> > list_t;
@@ -342,18 +384,40 @@ private:
list_t m_nodes;
};
class ASTCondBlock : public ASTBlock {
public:
ASTCondBlock(ASTBlock::BlkType blktype, unsigned int end, PycRef<ASTNode> cond,
bool negative = false)
: ASTBlock(blktype, end), m_cond(cond), m_negative(negative) { }
ASTCondBlock(ASTBlock::BlkType blktype, unsigned int end, PycRef<ASTNode> cond, bool negative = false)
: ASTBlock(blktype, end), m_cond(cond), m_negative(negative), m_popped(false) { }
PycRef<ASTNode> cond() const { return m_cond; }
bool negative() const { return m_negative; }
bool popped() const { return m_popped; }
void popCondition() { m_popped = true; }
private:
PycRef<ASTNode> m_cond;
bool m_negative;
bool m_popped; /* Has the condition been popped off the stack? */
};
class ASTIterBlock : public ASTBlock {
public:
ASTIterBlock(ASTBlock::BlkType blktype, unsigned int end, PycRef<ASTNode> iter)
: ASTBlock(blktype, end), m_iter(iter), m_idx(), m_idx_set(false) { }
PycRef<ASTNode> iter() const { return m_iter; }
PycRef<ASTNode> index() const { return m_idx; }
bool idxset() const { return m_idx_set; }
void setIndex(PycRef<ASTNode> idx) { m_idx = idx; m_idx_set = true; }
private:
PycRef<ASTNode> m_iter;
PycRef<ASTNode> m_idx;
bool m_idx_set;
};
/*class ASTTryBlock : public ASTBlock {

View File

@@ -165,6 +165,9 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
stack.push(new ASTBinary(left, right, ASTBinary::BIN_XOR));
}
break;
case Pyc::BREAK_LOOP:
stack.push(new ASTKeyword(ASTKeyword::KW_BREAK));
break;
case Pyc::BUILD_CLASS:
{
PycRef<ASTNode> code = stack.top();
@@ -229,6 +232,9 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
stack.push(new ASTCall(func, pparamList, kwparamList));
}
break;
case Pyc::CONTINUE_LOOP_A:
stack.push(new ASTKeyword(ASTKeyword::KW_CONTINUE));
break;
case Pyc::COMPARE_OP_A:
{
PycRef<ASTNode> right = stack.top();
@@ -251,6 +257,27 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
}
}
break;
case Pyc::FOR_LOOP_A:
{
PycRef<ASTNode> curidx = stack.top(); // Current index
stack.pop();
PycRef<ASTNode> iter = stack.top(); // Iterable
stack.pop();
PycRef<ASTBlock> top = blocks.top();
blocks.pop();
PycRef<ASTIterBlock> forblk = new ASTIterBlock(ASTBlock::BLK_FOR, top->end(), iter);
blocks.push(forblk.cast<ASTBlock>());
curblock = blocks.top();
/* Python Docs say:
"push the sequence, the incremented counter,
and the current item onto the stack." */
stack.push(iter);
stack.push(curidx);
stack.push(Node_NULL); // We can totally hack this >_>
}
break;
case Pyc::IMPORT_NAME_A:
if (mod->majorVer() == 1) {
stack.push(new ASTImport(new ASTName(code->getName(operand)), Node_NULL));
@@ -299,12 +326,14 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
case Pyc::POP_JUMP_IF_TRUE_A:
{
PycRef<ASTNode> cond = stack.top();
PycRef<ASTBlock> ifblk;
PycRef<ASTCondBlock> ifblk;
bool popped = false;
if (opcode == Pyc::POP_JUMP_IF_FALSE_A
|| opcode == Pyc::POP_JUMP_IF_TRUE_A) {
/* Pop condition before the jump */
stack.pop();
popped = true;
}
/* Store the current stack for the else statement(s) */
stack_hist.push(stack);
@@ -312,6 +341,7 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|| opcode == Pyc::JUMP_IF_TRUE_OR_POP_A) {
/* Pop condition only if condition is met */
stack.pop();
popped = true;
}
/* "Jump if true" means "Jump if not false" */
@@ -345,6 +375,10 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
/* Plain old if statement */
ifblk = new ASTCondBlock(ASTBlock::BLK_IF, offs, cond, neg);
}
if (popped)
ifblk->popCondition();
blocks.push(ifblk.cast<ASTBlock>());
curblock = blocks.top();
}
@@ -457,6 +491,9 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
{
PycRef<ASTBlock> tmp = curblock;
if (tmp->blktype() == ASTBlock::BLK_FOR)
break;
blocks.pop();
curblock = blocks.top();
curblock->append(tmp.cast<ASTNode>());
@@ -476,6 +513,14 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
{
PycRef<ASTNode> value = stack.top();
stack.pop();
if (curblock->blktype() == ASTBlock::BLK_IF
|| curblock->blktype() == ASTBlock::BLK_ELIF
|| curblock->blktype() == ASTBlock::BLK_ELSE)
{
curblock.cast<ASTCondBlock>()->popCondition();
break;
}
if (value->type() == ASTNode::NODE_CALL) {
curblock->append(value);
}
@@ -488,6 +533,16 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
case Pyc::PRINT_NEWLINE:
curblock->append(new ASTPrint(Node_NULL));
break;
case Pyc::RAISE_VARARGS_A:
{
ASTRaise::param_t paramList;
for (int i = 0; i < operand; i++) {
paramList.push_front(stack.top());
stack.pop();
}
curblock->append(new ASTRaise(paramList));
}
break;
case Pyc::RETURN_VALUE:
{
PycRef<ASTNode> value = stack.top();
@@ -558,11 +613,19 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
PycRef<ASTNode> value = stack.top();
stack.pop();
PycRef<ASTNode> name;
if (mod->majorVer() == 1 && mod->minorVer() < 3)
name = new ASTName(code->getName(operand));
else
name = new ASTName(code->getVarName(operand));
curblock->append(new ASTStore(value, name));
if (curblock->blktype() == ASTBlock::BLK_FOR
&& !curblock.cast<ASTIterBlock>()->idxset())
{
curblock.cast<ASTIterBlock>()->setIndex(name);
} else {
curblock->append(new ASTStore(value, name));
}
}
break;
case Pyc::STORE_GLOBAL_A:
@@ -603,6 +666,13 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
stack.push(new ASTCall(func, ASTCall::pparam_t(), ASTCall::kwparam_t()));
}
break;
case Pyc::UNARY_CONVERT:
{
PycRef<ASTNode> name = stack.top();
stack.pop();
stack.push(new ASTConvert(name));
}
break;
case Pyc::UNARY_INVERT:
{
PycRef<ASTNode> arg = stack.top();
@@ -792,6 +862,11 @@ void print_src(PycRef<ASTNode> node, PycModule* mod)
printf(")");
}
break;
case ASTNode::NODE_KEYWORD:
{
printf("%s", node.cast<ASTKeyword>()->word_str());
}
break;
case ASTNode::NODE_LIST:
{
ASTList::value_t values = node.cast<ASTList>()->values();
@@ -901,6 +976,18 @@ void print_src(PycRef<ASTNode> node, PycModule* mod)
print_src(node.cast<ASTPrint>()->value(), mod);
}
break;
case ASTNode::NODE_RAISE:
{
PycRef<ASTRaise> raise = node.cast<ASTRaise>();
printf("raise ");
bool first = true;
for (ASTRaise::param_t::const_iterator p = raise->params().begin(); p != raise->params().end(); ++p) {
if (!first) printf(", ");
print_src(*p, mod);
first = false;
}
}
break;
case ASTNode::NODE_RETURN:
printf("return ");
print_src(node.cast<ASTReturn>()->value(), mod);
@@ -1014,6 +1101,13 @@ void print_src(PycRef<ASTNode> node, PycModule* mod)
printf("]");
}
break;
case ASTNode::NODE_CONVERT:
{
printf("`");
print_src(node.cast<ASTConvert>()->name(), mod);
printf("`");
}
break;
case ASTNode::NODE_TUPLE:
{
ASTTuple::value_t values = node.cast<ASTTuple>()->values();

View File

@@ -141,7 +141,8 @@ bool Pyc::IsJumpOffsetArg(int opcode)
{
return (opcode == Pyc::JUMP_FORWARD_A) || (opcode == Pyc::JUMP_IF_FALSE_A) ||
(opcode == Pyc::JUMP_IF_TRUE_A) || (opcode == Pyc::SETUP_LOOP_A) ||
(opcode == Pyc::SETUP_FINALLY_A) || (opcode == Pyc::SETUP_EXCEPT_A);
(opcode == Pyc::SETUP_FINALLY_A) || (opcode == Pyc::SETUP_EXCEPT_A) ||
(opcode == Pyc::FOR_LOOP_A);
}