Anonymous avatar Anonymous committed c508dad

Added concationation operator.

Comments (0)

Files changed (12)

     "GTE",
     "LT",
     "LTE",
+    "CONCAT",
     "ADD",
     "SUB",
     "MUL",

arana/_opcode_targets.h

     &&TARGET_UNSET,
     &&TARGET_AND,
     &&TARGET_OR,
+    &&TARGET_CONCAT,
     &&TARGET_ADD,
     &&TARGET_SUB,
     &&TARGET_MUL,
     &&TARGET_UNKNOWN,
     &&TARGET_UNKNOWN,
     &&TARGET_UNKNOWN,
-    &&TARGET_UNKNOWN,
     &&TARGET_LOAD_CONST,
     &&TARGET_LOAD_FAST,
     &&TARGET_STORE_FAST,
     "UNSET",
     "AND",
     "OR",
+    "CONCAT",
     "ADD",
     "SUB",
     "MUL",
     NULL,
     NULL,
     NULL,
-    NULL,
     "LOAD_CONST",
     "LOAD_FAST",
     "STORE_FAST",
     AR_ASTOP_GTE,
     AR_ASTOP_LT,
     AR_ASTOP_LTE,
+    AR_ASTOP_CONCAT,
     AR_ASTOP_ADD,
     AR_ASTOP_SUB,
     AR_ASTOP_MUL,
         ON_OPCODE(NOT):
         ON_OPCODE(GET_ITERATOR):
             RECORD(0);
+        ON_OPCODE(CONCAT):
         ON_OPCODE(ADD):
         ON_OPCODE(SUB):
         ON_OPCODE(MUL):
     VISIT(node->v.BinaryOp.left);
     VISIT(node->v.BinaryOp.right);
     switch (node->v.BinaryOp.op) {
-    case AR_ASTOP_AND:    OP1(AND); break;
-    case AR_ASTOP_OR:     OP1(OR);  break;
-    case AR_ASTOP_ADD:    OP1(ADD); break;
-    case AR_ASTOP_SUB:    OP1(SUB); break;
-    case AR_ASTOP_MUL:    OP1(MUL); break;
-    case AR_ASTOP_DIV:    OP1(DIV); break;
-    case AR_ASTOP_MOD:    OP1(MOD); break;
-    case AR_ASTOP_POW:    OP1(POW); break;
+    case AR_ASTOP_AND:    OP1(AND);     break;
+    case AR_ASTOP_OR:     OP1(OR);      break;
+    case AR_ASTOP_CONCAT: OP1(CONCAT);  break;
+    case AR_ASTOP_ADD:    OP1(ADD);     break;
+    case AR_ASTOP_SUB:    OP1(SUB);     break;
+    case AR_ASTOP_MUL:    OP1(MUL);     break;
+    case AR_ASTOP_DIV:    OP1(DIV);     break;
+    case AR_ASTOP_MOD:    OP1(MOD);     break;
+    case AR_ASTOP_POW:    OP1(POW);     break;
     default: AR_FATAL("arana_compile_binary: unhandled operator %s\n",
                       AR_ASTOPMAP[node->v.BinaryOp.op]);
     }
 
     AR_OP_AND                   = 1,
     AR_OP_OR                    = 2,
-    AR_OP_ADD                   = 3,
-    AR_OP_SUB                   = 4,
-    AR_OP_MUL                   = 5,
-    AR_OP_DIV                   = 6,
-    AR_OP_MOD                   = 7,
-    AR_OP_POW                   = 8,
-    AR_OP_POS                   = 9,
-    AR_OP_NEG                   = 10,
-    AR_OP_NOT                   = 11,
+    AR_OP_CONCAT                = 3,
+    AR_OP_ADD                   = 4,
+    AR_OP_SUB                   = 5,
+    AR_OP_MUL                   = 6,
+    AR_OP_DIV                   = 7,
+    AR_OP_MOD                   = 8,
+    AR_OP_POW                   = 9,
+    AR_OP_POS                   = 10,
+    AR_OP_NEG                   = 11,
+    AR_OP_NOT                   = 12,
 
     AR_OP_LOAD_CONST            = 101,
     AR_OP_LOAD_FAST             = 102,
             PUSH(arg0);
             NEXT();
         /* binary expressions */
+        DISPATCH(CONCAT):
+            arg2 = POP();
+            arg1 = TOP();
+            arg0 = AR_CALL_METHOD(arg1, ":concat", arg2);
+            SET_TOP(arg0);
+            NEXT();
         DISPATCH(ADD):
             arg2 = POP();
             arg1 = TOP();
 %left     BITL BITR.
 %left     ADD SUB.
 %left     MUL DIV MOD.
+%left     TILDE.
 %right    POW.
 %nonassoc MADD MSUB.
-%right    NOT TILDE.
+%right    NOT.
 %left     LPAREN LBRACKET DOT.
 
 %type module       { ArStmtSeq *  }
 expr(A) ::= NOT expr(B).               { A = AR_AST(UnaryOp, B, AR_ASTOP_NOT); }
 
 // binary ops
+expr(A) ::= expr(B) TILDE expr(C).
+                                { A = AR_AST(BinaryOp, B, C, AR_ASTOP_CONCAT); }
 expr(A) ::= expr(B) ADD expr(C).   { A = AR_AST(BinaryOp, B, C, AR_ASTOP_ADD); }
 expr(A) ::= expr(B) SUB expr(C).   { A = AR_AST(BinaryOp, B, C, AR_ASTOP_SUB); }
 expr(A) ::= expr(B) MUL expr(C).   { A = AR_AST(BinaryOp, B, C, AR_ASTOP_MUL); }
     return (AR)self;
 }
 
+/* invoked by AR_LIST_CONCAT */
+AR
+_arana_api_string_concat(AR_SIG, AR self, AR other)
+{
+    if (!AR_IS_STRING(other))
+        other = AR_TO_STRING(other);
+    Ar_size_t length = AR_STRING_SIZE(self) + AR_STRING_SIZE(other);
+    char *result = AR_ALLOC(length + 1);
+    if (!result)
+        AR_RAISE_OOM();
+    memcpy(result, AR_AS_CHARP(self), AR_STRING_SIZE(self));
+    memcpy(result + AR_STRING_SIZE(self), AR_AS_CHARP(other),
+           AR_STRING_SIZE(other) + 1);
+    return AR_STRING2_NOCOPY(result, length);
+}
+
+static AR
+arana_string_concat(AR_SIG, AR self, AR args)
+{
+    AR other;
+    AR_PARSE(args, "O::concat", &other);
+    return AR_STRING_CONCAT(self, other);
+}
+
 static AR
 arana_string_to_string(AR_SIG, AR self, AR args)
 {
 arana_create_string_type(AR_SIG)
 {
     AR type = AR_CREATE_TYPE(ArStringType);
+    AR_BIND_METHOD(type, ":concat", arana_string_concat);
     AR_BIND_METHOD(type, "to_string", arana_string_to_string);
     AR_BIND_METHOD(type, "to_repr", arana_string_to_repr);
     AR_BIND_METHOD(type, "get_iterator", arana_string_get_iterator);
 #define AR_STRING2(x, l) arana_string_new(AR_ISIG, x, l, 0)
 #define AR_STRING_NOCOPY(x) arana_string_new(AR_ISIG, x, 0, 1)
 #define AR_STRING2_NOCOPY(x, l) arana_string_new(AR_ISIG, x, l, 1)
+#define AR_STRING_CONCAT(x, o) _arana_api_string_concat(AR_ISIG, x, o)
 
 #define AR_AS_CHARP(x) ((struct _ArCharPSequence *)(x))->value
 #define AR_STRING_SIZE(x) ((struct _ArCharPSequence *)(x))->size
 
 AR_API_FUNC(AR) arana_string_new(AR_SIG, const char *value,
                                  Ar_size_t size, int nocopy);
+AR_API_FUNC(AR) _arana_api_string_concat(AR_SIG, AR self, AR other);
 AR_API_FUNC(AR) arana_create_string_type(AR_SIG);
 AR_API_FUNC(AR) arana_create_string_iterator_type(AR_SIG);
 
     return (AR)result;
 }
 
+AR
+_arana_api_tuple_concat(AR_SIG, AR self, AR other)
+{
+    Ar_size_t i;
+    Ar_size_t size = AR_TUPLE_SIZE(self) + AR_TUPLE_SIZE(other);
+    AR result = AR_TUPLE(size);
+    for (i = 0; i < AR_TUPLE_SIZE(self); i++)
+        AR_TUPLE_PUT(result, i, AR_TUPLE_GET(self, i));
+    for (; i < size; i++)
+        AR_TUPLE_PUT(result, i, AR_TUPLE_GET(other, AR_TUPLE_SIZE(self) - i));
+    return result;
+}
+
+static AR
+arana_tuple_concat(AR_SIG, AR self, AR args)
+{
+    AR other;
+    AR_PARSE(args, "O::concat", &other);
+    if (!AR_IS_TUPLE(other))
+        AR_RAISE(AR_ARGUMENT_ERROR(NULL, 0, "tuples can only be concatenated "
+                                   "with other tuples."));
+    return AR_TUPLE_CONCAT(self, other);
+}
+
 static AR
 arana_tuple_get(AR_SIG, AR self, AR args)
 {
 {
     AR type = AR_CREATE_TYPE(ArTupleType);
     AR_BIND_METHOD(type, ":getitem", arana_tuple_get);
+    AR_BIND_METHOD(type, ":concat", arana_tuple_concat);
     AR_BIND_METHOD(type, "length", arana_tuple_length);
     AR_BIND_METHOD(type, "to_string", arana_tuple_to_string);
     AR_BIND_METHOD(type, "get_iterator", arana_tuple_get_iterator);
 #define AR_TUPLE_GET(t, i) (((ArTuple *)t)->items[i])
 #define AR_TUPLE_SIZE(t) (((ArTuple *)t)->size)
 #define AR_TUPLE_EMPTY(t) (AR_TUPLE_SIZE(t) == 0)
+#define AR_TUPLE_CONCAT(t, o) _arana_api_tuple_concat(AR_ISIG, t, o)
 
 #define AR_IS_TUPLE(x) (AR_TYPE(x) == &ArTupleType)
 
 AR_API_FUNC(AR) arana_tuple_new(AR_SIG, Ar_size_t size);
 AR_API_FUNC(AR) arana_tuple_pack(AR_SIG, ...);
 AR_API_FUNC(AR) arana_tuple_from_list(AR_SIG, AR list);
+AR_API_FUNC(AR) _arana_api_tuple_concat(AR_SIG, AR self, AR other);
 AR_API_FUNC(AR) arana_create_tuple_type(AR_SIG);
 AR_API_FUNC(AR) arana_create_tuple_iterator_type(AR_SIG);
 
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.