diff --git a/src/builtins.h b/src/builtins.h index 28d7d1fa..c325c2d2 100644 --- a/src/builtins.h +++ b/src/builtins.h @@ -4,20 +4,11 @@ const char* __BUILTINS_CODE = R"( def len(x): return x.__len__() -def __str4join(self, seq): - s = "" - for i in seq: - s += str(i) + self # in Python3, it uses 'i' instead of 'str(i)' - if len(self) > 0: - s = s[:-len(self)] - return s -str.join = __str4join - def __str4__mul__(self, n): - s = "" + a = [] for i in range(n): - s += self - return s + a.append(self) + return ''.join(a) str.__mul__ = __str4__mul__ def __str4split(self, sep): @@ -40,9 +31,16 @@ def __list4__str__(self): a = [] for i in self: a.append(str(i)) - return "[" + ", ".join(a) + "]" + return '[' + ', '.join(a) + ']' list.__str__ = __list4__str__ +def __tuple4__str__(self): + a = [] + for i in self: + a.append(str(i)) + return '(' + ', '.join(a) + ')' +tuple.__str__ = __tuple4__str__ + def __list4extend(self, other): for i in other: self.append(i) @@ -91,7 +89,7 @@ class dict: if self._a[i][0] == key: return [True, i] i = ((5*i) + 1) % self._capacity - return [False, i] + return False,i def __getitem__(self, key): ret = self.__probe(key) diff --git a/src/compiler.h b/src/compiler.h index 7349d4b7..f029345d 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -72,39 +72,39 @@ public: // http://journal.stuffwithstuff.com/2011/03/19/pratt-parsers-expression-parsing-made-easy/ #define METHOD(name) &Compiler::name -#define NO_INFIX PREC_NONE - for(_TokenType i=0; i<__TOKENS_LEN; i++) rules[i] = { nullptr, nullptr, PREC_NONE }; - rules[TK(".")] = { nullptr, METHOD(exprAttrib), PREC_ATTRIB }; - rules[TK("(")] = { METHOD(exprGrouping), METHOD(exprCall), PREC_CALL }; - rules[TK("[")] = { METHOD(exprList), METHOD(exprSubscript), PREC_SUBSCRIPT }; - rules[TK("{")] = { METHOD(exprMap), nullptr, NO_INFIX }; - rules[TK("%")] = { nullptr, METHOD(exprBinaryOp), PREC_FACTOR }; - rules[TK("+")] = { nullptr, METHOD(exprBinaryOp), PREC_TERM }; - rules[TK("-")] = { METHOD(exprUnaryOp), METHOD(exprBinaryOp), PREC_TERM }; - rules[TK("*")] = { nullptr, METHOD(exprBinaryOp), PREC_FACTOR }; - rules[TK("/")] = { nullptr, METHOD(exprBinaryOp), PREC_FACTOR }; - rules[TK("//")] = { nullptr, METHOD(exprBinaryOp), PREC_FACTOR }; - rules[TK("**")] = { nullptr, METHOD(exprBinaryOp), PREC_EXPONENT }; - rules[TK(">")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION }; - rules[TK("<")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION }; - rules[TK("==")] = { nullptr, METHOD(exprBinaryOp), PREC_EQUALITY }; - rules[TK("!=")] = { nullptr, METHOD(exprBinaryOp), PREC_EQUALITY }; - rules[TK(">=")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION }; - rules[TK("<=")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION }; - rules[TK("lambda")] = { METHOD(exprLambda), nullptr, NO_INFIX }; - rules[TK("None")] = { METHOD(exprValue), nullptr, NO_INFIX }; - rules[TK("in")] = { nullptr, METHOD(exprBinaryOp), PREC_TEST }; - rules[TK("is")] = { nullptr, METHOD(exprBinaryOp), PREC_TEST }; - rules[TK("not in")] = { nullptr, METHOD(exprBinaryOp), PREC_TEST }; - rules[TK("is not")] = { nullptr, METHOD(exprBinaryOp), PREC_TEST }; - rules[TK("and")] = { nullptr, METHOD(exprAnd), PREC_LOGICAL_AND }; - rules[TK("or")] = { nullptr, METHOD(exprOr), PREC_LOGICAL_OR }; - rules[TK("not")] = { METHOD(exprUnaryOp), nullptr, PREC_UNARY }; - rules[TK("True")] = { METHOD(exprValue), nullptr, NO_INFIX }; - rules[TK("False")] = { METHOD(exprValue), nullptr, NO_INFIX }; - rules[TK("@id")] = { METHOD(exprName), nullptr, NO_INFIX }; - rules[TK("@num")] = { METHOD(exprLiteral), nullptr, NO_INFIX }; - rules[TK("@str")] = { METHOD(exprLiteral), nullptr, NO_INFIX }; +#define NO_INFIX nullptr, PREC_NONE + for(_TokenType i=0; i<__TOKENS_LEN; i++) rules[i] = { nullptr, NO_INFIX }; + rules[TK(".")] = { nullptr, METHOD(exprAttrib), PREC_ATTRIB }; + rules[TK("(")] = { METHOD(exprGrouping), METHOD(exprCall), PREC_CALL }; + rules[TK("[")] = { METHOD(exprList), METHOD(exprSubscript), PREC_SUBSCRIPT }; + rules[TK("{")] = { METHOD(exprMap), NO_INFIX }; + rules[TK("%")] = { nullptr, METHOD(exprBinaryOp), PREC_FACTOR }; + rules[TK("+")] = { nullptr, METHOD(exprBinaryOp), PREC_TERM }; + rules[TK("-")] = { METHOD(exprUnaryOp), METHOD(exprBinaryOp), PREC_TERM }; + rules[TK("*")] = { nullptr, METHOD(exprBinaryOp), PREC_FACTOR }; + rules[TK("/")] = { nullptr, METHOD(exprBinaryOp), PREC_FACTOR }; + rules[TK("//")] = { nullptr, METHOD(exprBinaryOp), PREC_FACTOR }; + rules[TK("**")] = { nullptr, METHOD(exprBinaryOp), PREC_EXPONENT }; + rules[TK(">")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION }; + rules[TK("<")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION }; + rules[TK("==")] = { nullptr, METHOD(exprBinaryOp), PREC_EQUALITY }; + rules[TK("!=")] = { nullptr, METHOD(exprBinaryOp), PREC_EQUALITY }; + rules[TK(">=")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION }; + rules[TK("<=")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION }; + rules[TK("in")] = { nullptr, METHOD(exprBinaryOp), PREC_TEST }; + rules[TK("is")] = { nullptr, METHOD(exprBinaryOp), PREC_TEST }; + rules[TK("not in")] = { nullptr, METHOD(exprBinaryOp), PREC_TEST }; + rules[TK("is not")] = { nullptr, METHOD(exprBinaryOp), PREC_TEST }; + rules[TK("and") ] = { nullptr, METHOD(exprAnd), PREC_LOGICAL_AND }; + rules[TK("or")] = { nullptr, METHOD(exprOr), PREC_LOGICAL_OR }; + rules[TK("not")] = { METHOD(exprUnaryOp), nullptr, PREC_UNARY }; + rules[TK("True")] = { METHOD(exprValue), NO_INFIX }; + rules[TK("False")] = { METHOD(exprValue), NO_INFIX }; + rules[TK("lambda")] = { METHOD(exprLambda), NO_INFIX }; + rules[TK("None")] = { METHOD(exprValue), NO_INFIX }; + rules[TK("@id")] = { METHOD(exprName), NO_INFIX }; + rules[TK("@num")] = { METHOD(exprLiteral), NO_INFIX }; + rules[TK("@str")] = { METHOD(exprLiteral), NO_INFIX }; #undef METHOD #undef NO_INFIX } @@ -313,7 +313,7 @@ public: _TokenType assignment = parser->previous.type; matchNewLines(); if (assignment == TK("=")) { // name = (expr); - compileExpression(); + compileExpressionTuple(); } else { // name += / -= / *= ... = (expr); emitCode(OP_LOAD_NAME, index); compileExpression(); @@ -392,7 +392,7 @@ public: void exprGrouping() { matchNewLines(); - compileExpression(); + compileExpressionTuple(); matchNewLines(); consume(TK(")")); } @@ -442,7 +442,7 @@ public: compileExpression(); emitAssignOp(assignment); } else { - compileExpression(); + compileExpressionTuple(); } emitCode(OP_STORE_ATTR, index); } else { @@ -488,7 +488,7 @@ public: if (assignment != TK("=")) { UNREACHABLE(); } else { - compileExpression(); + compileExpressionTuple(); } emitCode(OP_STORE_SUBSCR); } else { @@ -593,6 +593,17 @@ public: parsePrecedence(PREC_LOWEST); } + // Compiles an expression. Support tuple syntax. + void compileExpressionTuple() { + int size = 0; + while (true) { + compileExpression(); + size++; + if (!match(TK(","))) break; + } + if(size > 1) emitCode(OP_BUILD_TUPLE, size); + } + void compileIfStatement() { matchNewLines(); compileExpression(); //< Condition. @@ -642,7 +653,7 @@ public: const _Str& iterName = parser->previous.str(); int iterIndex = getCode()->addName(iterName); consume(TK("in")); - compileExpression(); + compileExpressionTuple(); emitCode(OP_GET_ITER); Loop& loop = enterLoop(true); int patch = emitCode(OP_FOR_ITER); @@ -672,7 +683,7 @@ public: if(matchEndStatement()){ emitCode(OP_LOAD_NONE); }else{ - compileExpression(); + compileExpressionTuple(); consumeEndStatement(); } emitCode(OP_RETURN_VALUE); @@ -706,7 +717,7 @@ public: } else if(match(TK("pass"))){ consumeEndStatement(); } else { - compileExpression(); + compileExpressionTuple(); consumeEndStatement(); // If last op is not an assignment, pop the result. diff --git a/src/main.cpp b/src/main.cpp index e78bc3a3..66f497c4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,7 +4,7 @@ #include #include "pocketpy.h" -//#define PK_DEBUG +#define PK_DEBUG //#define PK_DEBUG_TIME class Timer{ diff --git a/src/parser.h b/src/parser.h index ffa2effe..64980c2a 100644 --- a/src/parser.h +++ b/src/parser.h @@ -26,7 +26,7 @@ constexpr const char* __TOKENS[] = { const _TokenType __TOKENS_LEN = sizeof(__TOKENS) / sizeof(__TOKENS[0]); -constexpr _TokenType __tokenIndex(const char* token) { +constexpr _TokenType TK(const char* const token) { for(int k=0; k<__TOKENS_LEN; k++){ const char* i = __TOKENS[k]; const char* j = token; @@ -38,12 +38,10 @@ constexpr _TokenType __tokenIndex(const char* token) { return 0; } - -#define TK(s) __tokenIndex(s) #define TK_STR(t) __TOKENS[t] -const _TokenType __KW_BEGIN = __tokenIndex("class"); -const _TokenType __KW_END = __tokenIndex("raise"); +const _TokenType __KW_BEGIN = TK("class"); +const _TokenType __KW_END = TK("raise"); const std::unordered_map __KW_MAP = [](){ std::unordered_map map; diff --git a/src/pocketpy.h b/src/pocketpy.h index c7b41c96..3fd416f3 100644 --- a/src/pocketpy.h +++ b/src/pocketpy.h @@ -277,6 +277,17 @@ void __initializeBuiltinFunctions(VM* _vm) { return vm->PyBool(_self.str().rfind(_suffix.str()) == _self.str().length() - _suffix.str().length()); }); + _vm->bindMethod("str", "join", [](VM* vm, PyVarList args) { + const _Str& _self = vm->PyStr_AS_C(args[0]); + const PyVarList& _list = vm->PyList_AS_C(args[1]); + _StrStream ss; + for(int i = 0; i < _list.size(); i++){ + if(i > 0) ss << _self; + ss << vm->PyStr_AS_C(vm->asStr(_list[i])); + } + return vm->PyStr(ss); + }); + /************ PyList ************/ _vm->bindMethod("list", "__iter__", [](VM* vm, PyVarList args) { vm->__checkType(args.at(0), vm->_tp_list);