|
@@ -26,19 +26,18 @@ struct Loop {
|
|
|
Loop(bool forLoop, int start) : forLoop(forLoop), start(start) {}
|
|
Loop(bool forLoop, int start) : forLoop(forLoop), start(start) {}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
-#define ExprCommaSplitArgs(end) \
|
|
|
|
|
- int ARGC = 0; \
|
|
|
|
|
- do { \
|
|
|
|
|
- matchNewLines(); \
|
|
|
|
|
- if (peek() == TK(end)) break; \
|
|
|
|
|
- compileExpression(); \
|
|
|
|
|
- ARGC++; \
|
|
|
|
|
- matchNewLines(); \
|
|
|
|
|
- } while (match(TK(","))); \
|
|
|
|
|
- matchNewLines(); \
|
|
|
|
|
|
|
+#define ExprCommaSplitArgs(end) \
|
|
|
|
|
+ int ARGC = 0; \
|
|
|
|
|
+ do { \
|
|
|
|
|
+ matchNewLines(); \
|
|
|
|
|
+ if (peek() == TK(end)) break; \
|
|
|
|
|
+ EXPR(); \
|
|
|
|
|
+ ARGC++; \
|
|
|
|
|
+ matchNewLines(); \
|
|
|
|
|
+ } while (match(TK(","))); \
|
|
|
|
|
+ matchNewLines(); \
|
|
|
consume(TK(end));
|
|
consume(TK(end));
|
|
|
|
|
|
|
|
-
|
|
|
|
|
class Compiler {
|
|
class Compiler {
|
|
|
public:
|
|
public:
|
|
|
std::unique_ptr<Parser> parser;
|
|
std::unique_ptr<Parser> parser;
|
|
@@ -104,14 +103,19 @@ public:
|
|
|
rules[TK("@id")] = { METHOD(exprName), NO_INFIX };
|
|
rules[TK("@id")] = { METHOD(exprName), NO_INFIX };
|
|
|
rules[TK("@num")] = { METHOD(exprLiteral), NO_INFIX };
|
|
rules[TK("@num")] = { METHOD(exprLiteral), NO_INFIX };
|
|
|
rules[TK("@str")] = { METHOD(exprLiteral), NO_INFIX };
|
|
rules[TK("@str")] = { METHOD(exprLiteral), NO_INFIX };
|
|
|
- rules[TK("=")] = { nullptr, METHOD(exprAssign), PREC_LOWEST };
|
|
|
|
|
- rules[TK("+=")] = { nullptr, METHOD(exprAssign), PREC_LOWEST };
|
|
|
|
|
- rules[TK("-=")] = { nullptr, METHOD(exprAssign), PREC_LOWEST };
|
|
|
|
|
- rules[TK("*=")] = { nullptr, METHOD(exprAssign), PREC_LOWEST };
|
|
|
|
|
- rules[TK("/=")] = { nullptr, METHOD(exprAssign), PREC_LOWEST };
|
|
|
|
|
- rules[TK("//=")] = { nullptr, METHOD(exprAssign), PREC_LOWEST };
|
|
|
|
|
|
|
+ rules[TK("=")] = { nullptr, METHOD(exprAssign), PREC_ASSIGNMENT };
|
|
|
|
|
+ rules[TK("+=")] = { nullptr, METHOD(exprAssign), PREC_ASSIGNMENT };
|
|
|
|
|
+ rules[TK("-=")] = { nullptr, METHOD(exprAssign), PREC_ASSIGNMENT };
|
|
|
|
|
+ rules[TK("*=")] = { nullptr, METHOD(exprAssign), PREC_ASSIGNMENT };
|
|
|
|
|
+ rules[TK("/=")] = { nullptr, METHOD(exprAssign), PREC_ASSIGNMENT };
|
|
|
|
|
+ rules[TK("//=")] = { nullptr, METHOD(exprAssign), PREC_ASSIGNMENT };
|
|
|
|
|
+ rules[TK(",")] = { nullptr, METHOD(exprComma), PREC_COMMA };
|
|
|
#undef METHOD
|
|
#undef METHOD
|
|
|
#undef NO_INFIX
|
|
#undef NO_INFIX
|
|
|
|
|
+
|
|
|
|
|
+#define EXPR() parsePrecedence(PREC_COMMA) // no '=' and ',' just a simple expression
|
|
|
|
|
+#define EXPR_TUPLE() parsePrecedence(PREC_ASSIGNMENT) // no '=', but ',' is allowed
|
|
|
|
|
+#define EXPR_ANY() parsePrecedence(PREC_NONE)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void eatString(bool single_quote) {
|
|
void eatString(bool single_quote) {
|
|
@@ -297,15 +301,15 @@ public:
|
|
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- void exprAssign(){
|
|
|
|
|
|
|
+ void exprAssign() {
|
|
|
_TokenType op = parser->previous.type;
|
|
_TokenType op = parser->previous.type;
|
|
|
if(op == TK("=")) { // a = (expr)
|
|
if(op == TK("=")) { // a = (expr)
|
|
|
- compileExpressionTuple();
|
|
|
|
|
|
|
+ EXPR_TUPLE();
|
|
|
emitCode(OP_STORE_PTR);
|
|
emitCode(OP_STORE_PTR);
|
|
|
}else{ // a += (expr) -> a = a + (expr)
|
|
}else{ // a += (expr) -> a = a + (expr)
|
|
|
// TODO: optimization is needed for inplace operators
|
|
// TODO: optimization is needed for inplace operators
|
|
|
emitCode(OP_DUP_TOP);
|
|
emitCode(OP_DUP_TOP);
|
|
|
- compileExpression();
|
|
|
|
|
|
|
+ EXPR();
|
|
|
switch (op) {
|
|
switch (op) {
|
|
|
case TK("+="): emitCode(OP_BINARY_OP, 0); break;
|
|
case TK("+="): emitCode(OP_BINARY_OP, 0); break;
|
|
|
case TK("-="): emitCode(OP_BINARY_OP, 1); break;
|
|
case TK("-="): emitCode(OP_BINARY_OP, 1); break;
|
|
@@ -318,6 +322,15 @@ public:
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ void exprComma() {
|
|
|
|
|
+ int size = 1; // an expr is in the stack now
|
|
|
|
|
+ do {
|
|
|
|
|
+ EXPR(); // NOTE: "1," will fail, "1,2" will be ok
|
|
|
|
|
+ size++;
|
|
|
|
|
+ } while(match(TK(",")));
|
|
|
|
|
+ emitCode(OP_BUILD_SMART_TUPLE, size);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
void exprOr() {
|
|
void exprOr() {
|
|
|
int patch = emitCode(OP_JUMP_IF_TRUE_OR_POP);
|
|
int patch = emitCode(OP_JUMP_IF_TRUE_OR_POP);
|
|
|
parsePrecedence(PREC_LOGICAL_OR);
|
|
parsePrecedence(PREC_LOGICAL_OR);
|
|
@@ -371,7 +384,7 @@ public:
|
|
|
|
|
|
|
|
void exprGrouping() {
|
|
void exprGrouping() {
|
|
|
matchNewLines();
|
|
matchNewLines();
|
|
|
- compileExpressionTuple();
|
|
|
|
|
|
|
+ EXPR_TUPLE();
|
|
|
matchNewLines();
|
|
matchNewLines();
|
|
|
consume(TK(")"));
|
|
consume(TK(")"));
|
|
|
}
|
|
}
|
|
@@ -386,8 +399,8 @@ public:
|
|
|
do {
|
|
do {
|
|
|
matchNewLines();
|
|
matchNewLines();
|
|
|
if (peek() == TK("}")) break;
|
|
if (peek() == TK("}")) break;
|
|
|
- compileExpression();consume(TK(":"));compileExpression();
|
|
|
|
|
- emitCode(OP_BUILD_TUPLE, 2);
|
|
|
|
|
|
|
+ EXPR();consume(TK(":"));EXPR();
|
|
|
|
|
+ emitCode(OP_BUILD_SMART_TUPLE, 2);
|
|
|
size++;
|
|
size++;
|
|
|
matchNewLines();
|
|
matchNewLines();
|
|
|
} while (match(TK(",")));
|
|
} while (match(TK(",")));
|
|
@@ -425,17 +438,17 @@ public:
|
|
|
if(match(TK("]"))){
|
|
if(match(TK("]"))){
|
|
|
emitCode(OP_LOAD_NONE);
|
|
emitCode(OP_LOAD_NONE);
|
|
|
}else{
|
|
}else{
|
|
|
- compileExpression();
|
|
|
|
|
|
|
+ EXPR();
|
|
|
consume(TK("]"));
|
|
consume(TK("]"));
|
|
|
}
|
|
}
|
|
|
emitCode(OP_BUILD_SLICE);
|
|
emitCode(OP_BUILD_SLICE);
|
|
|
}else{
|
|
}else{
|
|
|
- compileExpression();
|
|
|
|
|
|
|
+ EXPR();
|
|
|
if(match(TK(":"))){
|
|
if(match(TK(":"))){
|
|
|
if(match(TK("]"))){
|
|
if(match(TK("]"))){
|
|
|
emitCode(OP_LOAD_NONE);
|
|
emitCode(OP_LOAD_NONE);
|
|
|
}else{
|
|
}else{
|
|
|
- compileExpression();
|
|
|
|
|
|
|
+ EXPR();
|
|
|
consume(TK("]"));
|
|
consume(TK("]"));
|
|
|
}
|
|
}
|
|
|
emitCode(OP_BUILD_SLICE);
|
|
emitCode(OP_BUILD_SLICE);
|
|
@@ -457,23 +470,6 @@ public:
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- void parsePrecedence(Precedence precedence) {
|
|
|
|
|
- lexToken();
|
|
|
|
|
- GrammarFn prefix = rules[parser->previous.type].prefix;
|
|
|
|
|
-
|
|
|
|
|
- if (prefix == nullptr) {
|
|
|
|
|
- throw SyntaxError(path, parser->previous, "expected an expression");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- (this->*prefix)();
|
|
|
|
|
- while (rules[peek()].precedence >= precedence) {
|
|
|
|
|
- lexToken();
|
|
|
|
|
- _TokenType op = parser->previous.type;
|
|
|
|
|
- GrammarFn infix = rules[op].infix;
|
|
|
|
|
- (this->*infix)();
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
void keepOpcodeLine(){
|
|
void keepOpcodeLine(){
|
|
|
int i = getCode()->co_code.size() - 1;
|
|
int i = getCode()->co_code.size() - 1;
|
|
|
getCode()->co_code[i].line = getCode()->co_code[i-1].line;
|
|
getCode()->co_code[i].line = getCode()->co_code[i-1].line;
|
|
@@ -527,29 +523,30 @@ public:
|
|
|
}
|
|
}
|
|
|
int index = getCode()->addName(tkmodule.str(), NAME_GLOBAL);
|
|
int index = getCode()->addName(tkmodule.str(), NAME_GLOBAL);
|
|
|
emitCode(OP_STORE_NAME_PTR, index);
|
|
emitCode(OP_STORE_NAME_PTR, index);
|
|
|
- } while (match(TK(",")) && (matchNewLines(), true));
|
|
|
|
|
|
|
+ } while (match(TK(",")));
|
|
|
consumeEndStatement();
|
|
consumeEndStatement();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Compiles an expression. An expression will result a value on top of the stack.
|
|
|
|
|
- void compileExpression() {
|
|
|
|
|
- parsePrecedence(PREC_LOWEST);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ void parsePrecedence(Precedence precedence) {
|
|
|
|
|
+ lexToken();
|
|
|
|
|
+ GrammarFn prefix = rules[parser->previous.type].prefix;
|
|
|
|
|
|
|
|
- // Compiles an expression. Support tuple syntax.
|
|
|
|
|
- void compileExpressionTuple() {
|
|
|
|
|
- int size = 0;
|
|
|
|
|
- while (true) {
|
|
|
|
|
- compileExpression();
|
|
|
|
|
- size++;
|
|
|
|
|
- if (!match(TK(","))) break;
|
|
|
|
|
|
|
+ if (prefix == nullptr) {
|
|
|
|
|
+ throw SyntaxError(path, parser->previous, "expected an expression");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ (this->*prefix)();
|
|
|
|
|
+ while (rules[peek()].precedence > precedence) {
|
|
|
|
|
+ lexToken();
|
|
|
|
|
+ _TokenType op = parser->previous.type;
|
|
|
|
|
+ GrammarFn infix = rules[op].infix;
|
|
|
|
|
+ (this->*infix)();
|
|
|
}
|
|
}
|
|
|
- if(size > 1) emitCode(OP_BUILD_TUPLE, size);
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void compileIfStatement() {
|
|
void compileIfStatement() {
|
|
|
matchNewLines();
|
|
matchNewLines();
|
|
|
- compileExpression(); //< Condition.
|
|
|
|
|
|
|
+ EXPR_TUPLE();
|
|
|
|
|
|
|
|
int ifpatch = emitCode(OP_POP_JUMP_IF_FALSE);
|
|
int ifpatch = emitCode(OP_POP_JUMP_IF_FALSE);
|
|
|
compileBlockBody();
|
|
compileBlockBody();
|
|
@@ -583,7 +580,7 @@ public:
|
|
|
|
|
|
|
|
void compileWhileStatement() {
|
|
void compileWhileStatement() {
|
|
|
Loop& loop = enterLoop(false);
|
|
Loop& loop = enterLoop(false);
|
|
|
- compileExpression();
|
|
|
|
|
|
|
+ EXPR_TUPLE();
|
|
|
int patch = emitCode(OP_POP_JUMP_IF_FALSE);
|
|
int patch = emitCode(OP_POP_JUMP_IF_FALSE);
|
|
|
compileBlockBody();
|
|
compileBlockBody();
|
|
|
emitCode(OP_JUMP_ABSOLUTE, loop.start); keepOpcodeLine();
|
|
emitCode(OP_JUMP_ABSOLUTE, loop.start); keepOpcodeLine();
|
|
@@ -598,7 +595,7 @@ public:
|
|
|
codes.size()>1 ? NAME_LOCAL : NAME_GLOBAL
|
|
codes.size()>1 ? NAME_LOCAL : NAME_GLOBAL
|
|
|
);
|
|
);
|
|
|
consume(TK("in"));
|
|
consume(TK("in"));
|
|
|
- compileExpressionTuple();
|
|
|
|
|
|
|
+ EXPR_TUPLE();
|
|
|
emitCode(OP_GET_ITER);
|
|
emitCode(OP_GET_ITER);
|
|
|
Loop& loop = enterLoop(true);
|
|
Loop& loop = enterLoop(true);
|
|
|
int patch = emitCode(OP_FOR_ITER);
|
|
int patch = emitCode(OP_FOR_ITER);
|
|
@@ -628,7 +625,7 @@ public:
|
|
|
if(matchEndStatement()){
|
|
if(matchEndStatement()){
|
|
|
emitCode(OP_LOAD_NONE);
|
|
emitCode(OP_LOAD_NONE);
|
|
|
}else{
|
|
}else{
|
|
|
- compileExpressionTuple();
|
|
|
|
|
|
|
+ EXPR_TUPLE();
|
|
|
consumeEndStatement();
|
|
consumeEndStatement();
|
|
|
}
|
|
}
|
|
|
emitCode(OP_RETURN_VALUE);
|
|
emitCode(OP_RETURN_VALUE);
|
|
@@ -639,23 +636,23 @@ public:
|
|
|
} else if (match(TK("for"))) {
|
|
} else if (match(TK("for"))) {
|
|
|
compileForStatement();
|
|
compileForStatement();
|
|
|
} else if(match(TK("assert"))){
|
|
} else if(match(TK("assert"))){
|
|
|
- compileExpression();
|
|
|
|
|
|
|
+ EXPR();
|
|
|
emitCode(OP_ASSERT);
|
|
emitCode(OP_ASSERT);
|
|
|
consumeEndStatement();
|
|
consumeEndStatement();
|
|
|
} else if(match(TK("raise"))){
|
|
} else if(match(TK("raise"))){
|
|
|
consume(TK("@id")); // dummy exception type
|
|
consume(TK("@id")); // dummy exception type
|
|
|
emitCode(OP_LOAD_CONST, getCode()->addConst(vm->PyStr(parser->previous.str())));
|
|
emitCode(OP_LOAD_CONST, getCode()->addConst(vm->PyStr(parser->previous.str())));
|
|
|
- consume(TK("("));compileExpression();consume(TK(")"));
|
|
|
|
|
|
|
+ consume(TK("("));EXPR();consume(TK(")"));
|
|
|
emitCode(OP_RAISE_ERROR);
|
|
emitCode(OP_RAISE_ERROR);
|
|
|
consumeEndStatement();
|
|
consumeEndStatement();
|
|
|
} else if(match(TK("del"))){
|
|
} else if(match(TK("del"))){
|
|
|
- compileExpression();
|
|
|
|
|
|
|
+ EXPR();
|
|
|
emitCode(OP_DELETE_PTR);
|
|
emitCode(OP_DELETE_PTR);
|
|
|
consumeEndStatement();
|
|
consumeEndStatement();
|
|
|
} else if(match(TK("pass"))){
|
|
} else if(match(TK("pass"))){
|
|
|
consumeEndStatement();
|
|
consumeEndStatement();
|
|
|
} else {
|
|
} else {
|
|
|
- compileExpressionTuple();
|
|
|
|
|
|
|
+ EXPR_ANY();
|
|
|
consumeEndStatement();
|
|
consumeEndStatement();
|
|
|
|
|
|
|
|
// If last op is not an assignment, pop the result.
|
|
// If last op is not an assignment, pop the result.
|