Implemented length operator. This closes #130

This commit is contained in:
Dale Weiler 2014-09-27 04:15:32 -04:00
parent 31cd263e33
commit b08195e2da
6 changed files with 156 additions and 71 deletions

10
fold.c
View file

@ -511,6 +511,7 @@ static GMQCC_INLINE void sfloat_init(sfloat_state_t *state) {
#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))
/*
@ -1337,6 +1338,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)), false);
if (isarray(a))
return fold_constgen_float(fold, vec_size(a->initlist), false);
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];
@ -1397,6 +1406,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");

22
lexer.c
View file

@ -1301,6 +1301,28 @@ int lex_do(lex_file *lex)
return (lex->tok.ttype = TOKEN_OPERATOR);
}
/* length operator */
if (ch == 'l') {
if ((nextch = lex_getch(lex)) == 'e') {
if ((nextch = lex_getch(lex)) == 'n') {
if ((nextch = lex_getch(lex)) == 'g') {
if ((nextch = lex_getch(lex)) == 't') {
if ((nextch = lex_getch(lex)) == 'h') {
lex_tokench(lex, 'l');
lex_tokench(lex, 'e');
lex_tokench(lex, 'n');
lex_tokench(lex, 'g');
lex_tokench(lex, 't');
lex_tokench(lex, 'h');
lex_endtoken(lex);
return (lex->tok.ttype = TOKEN_OPERATOR);
} else lex_ungetch(lex, nextch);
} else lex_ungetch(lex, nextch);
} else lex_ungetch(lex, nextch);
} else lex_ungetch(lex, nextch);
} else lex_ungetch(lex, nextch);
}
if (isident_start(ch))
{
const char *v;

View file

@ -177,6 +177,7 @@ typedef struct {
static const oper_info c_operators[] = {
{ "(", 0, opid1('('), ASSOC_LEFT, 99, OP_PREFIX, false}, /* paren expression - non function call */
{ "length", 1, opid3('l','e','n'), ASSOC_RIGHT, 98, OP_PREFIX, true},
{ "++", 1, opid3('S','+','+'), ASSOC_LEFT, 17, OP_SUFFIX, false},
{ "--", 1, opid3('S','-','-'), ASSOC_LEFT, 17, OP_SUFFIX, false},

View file

@ -1145,6 +1145,22 @@ 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_STRING && exprs[0]->vtype != TYPE_ARRAY) {
ast_type_to_string(exprs[0], ty1, sizeof(ty1));
compile_error(ast_ctx(exprs[0]), "invalid type for length operator: %s", ty1);
return false;
}
/* strings must be const, arrays are statically sized */
if (exprs[0]->vtype == TYPE_STRING &&
!(((ast_value*)exprs[0])->hasvalue && ((ast_value*)exprs[0])->cvq == CV_CONST))
{
compile_error(ast_ctx(exprs[0]), "operand of length operator not a valid constant expression");
return false;
}
out = fold_op(parser->fold, op, exprs);
break;
case opid2('~', 'P'):
if (exprs[0]->vtype != TYPE_FLOAT && exprs[0]->vtype != TYPE_VECTOR) {
ast_type_to_string(exprs[0], ty1, sizeof(ty1));

23
tests/length.qc Normal file
View file

@ -0,0 +1,23 @@
const string a = "hello world"; // 11
float b[] = { 1, 2, 3 }; // 3
float c[5] = { 5, 4, 3, 2, 1 }; // 5
const float d[] = { 1 }; // 1
void main() {
print(ftos(length a), "\n"); // 11
print(ftos(length b), "\n"); // 3
print(ftos(length c), "\n"); // 5
print(ftos(length d), "\n"); // 1
static float al = length(a);
static float bl = length(b);
static float cl = length(c);
static float dl = length(d);
print(ftos(al), "\n"); // 11
print(ftos(bl), "\n"); // 3
print(ftos(cl), "\n"); // 5
print(ftos(dl), "\n"); // 1
print(ftos(length "hello world"), "\n"); // 11
}

13
tests/length.tmpl Normal file
View file

@ -0,0 +1,13 @@
I: length.qc
D: length operator
T: -execute
C: -std=gmqcc
M: 11
M: 3
M: 5
M: 1
M: 11
M: 3
M: 5
M: 1
M: 11