]> git.xonotic.org Git - xonotic/gmqcc.git/commitdiff
Initial idea at implementing type-generic length operator like C's sizeof. The follow... graphitemaster/length-operator
authorDale Weiler <killfieldengine@gmail.com>
Thu, 17 Oct 2013 11:40:51 +0000 (07:40 -0400)
committerDale Weiler <killfieldengine@gmail.com>
Thu, 17 Oct 2013 11:40:51 +0000 (07:40 -0400)
fold.c
lexer.c
lexer.h
parser.c

diff --git a/fold.c b/fold.c
index 4664487a3eb776ec6251483fe3180614081337dc..18fa496391b17f504ffd8c17cfc5777d41159040 100644 (file)
--- a/fold.c
+++ b/fold.c
@@ -41,6 +41,7 @@
 #define isfloat(X)      (((ast_expression*)(X))->vtype == TYPE_FLOAT)
 #define isvector(X)     (((ast_expression*)(X))->vtype == TYPE_VECTOR)
 #define isstring(X)     (((ast_expression*)(X))->vtype == TYPE_STRING)
+#define isarray(X)      (((ast_expression*)(X))->vtype == TYPE_ARRAY)
 #define isfloats(X,Y)   (isfloat  (X) && isfloat (Y))
 
 /*
@@ -632,6 +633,14 @@ static GMQCC_INLINE ast_expression *fold_op_cross(fold_t *fold, ast_value *a, as
     return NULL;
 }
 
+static GMQCC_INLINE ast_expression *fold_op_length(fold_t *fold, ast_value *a) {
+    if (fold_can_1(a) && isstring(a))
+        return fold_constgen_float(fold, strlen(fold_immvalue_string(a)));
+    if (isarray(a))
+        return fold_constgen_float(fold, vec_size(a->initlist));
+    return NULL;
+}
+
 ast_expression *fold_op(fold_t *fold, const oper_info *info, ast_expression **opexprs) {
     ast_value      *a = (ast_value*)opexprs[0];
     ast_value      *b = (ast_value*)opexprs[1];
@@ -690,6 +699,7 @@ ast_expression *fold_op(fold_t *fold, const oper_info *info, ast_expression **op
         fold_op_case(2, ('=', '='),    cmp,    (fold, a, b, false));
         fold_op_case(2, ('~', 'P'),    bnot,   (fold, a));
         fold_op_case(2, ('>', '<'),    cross,  (fold, a, b));
+        fold_op_case(3, ('l','e','n'), length, (fold, a));
     }
     #undef fold_op_case
     compile_error(fold_ctx(fold), "internal error: attempted to constant-fold for unsupported operator");
diff --git a/lexer.c b/lexer.c
index b6d5ceb6d3bd94aed4e4cc0bb0d2926d932b9b6a..5030e7835d2b69c09e87877b50a26f1de058b682 100644 (file)
--- a/lexer.c
+++ b/lexer.c
@@ -1396,6 +1396,23 @@ int lex_do(lex_file *lex)
         return (lex->tok.ttype = TOKEN_OPERATOR);
     }
 
+    /* len operator */
+    if (ch == 'l') {
+        if ((nextch = lex_getch(lex)) == 'e') {
+            if ((nextch = lex_getch(lex)) == 'n') {
+                lex_tokench(lex, 'l');
+                lex_tokench(lex, 'e');
+                lex_tokench(lex, 'n');
+                lex_endtoken(lex);
+                return (lex->tok.ttype = TOKEN_OPERATOR);
+            } else {
+                lex_ungetch(lex, nextch);
+            }
+        } else {
+            lex_ungetch(lex, nextch);
+        }
+    }
+
     if (isident_start(ch))
     {
         const char *v;
diff --git a/lexer.h b/lexer.h
index 44f6491725c17a5dc458cdf789a0e2b8cf248450..28e05ec5f923823858ac25384e278764af3f7b18 100644 (file)
--- a/lexer.h
+++ b/lexer.h
@@ -175,6 +175,7 @@ typedef struct {
 
 static const oper_info c_operators[] = {
     { "(",   0, opid1('('),         ASSOC_LEFT,  99, OP_PREFIX, false}, /* paren expression - non function call */
+    { "len", 1, opid3('l','e','n'), ASSOC_RIGHT, 98, OP_PREFIX, true},  /* len operator */
 
     { "++",  1, opid3('S','+','+'), ASSOC_LEFT,  17, OP_SUFFIX, false},
     { "--",  1, opid3('S','-','-'), ASSOC_LEFT,  17, OP_SUFFIX, false},
index 82ce53b0a47a84deeb0b422fc32c1558c8412681..acad4be1f40dfabf1d20a086ec94fb0c8b6f0bae 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -1109,6 +1109,18 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
             out = (ast_expression*)asbinstore;
             break;
 
+        case opid3('l', 'e', 'n'):
+            if (exprs[0]->vtype != TYPE_ARRAY && exprs[0]->vtype != TYPE_STRING) {
+                ast_type_to_string(exprs[0], ty1, sizeof(ty1));
+                compile_error(ast_ctx(exprs[0]), "invalid type for length operator: %s", ty1);
+                return false;
+            }
+            if (!(out = fold_op(parser->fold, op, exprs))) {
+                compile_error(ast_ctx(exprs[0]), "expected constant expression as operand to length operator");
+                return false;
+            }
+            break;
+
         case opid2('~', 'P'):
             if (exprs[0]->vtype != TYPE_FLOAT && exprs[0]->vtype != TYPE_VECTOR) {
                 ast_type_to_string(exprs[0], ty1, sizeof(ty1));