/*
- * Copyright (C) 2012, 2013
+ * Copyright (C) 2012, 2013, 2014
* Wolfgang Bumiller
* Dale Weiler
*
case opid2('<','<'):
case opid2('>','>'):
+ if (NotSameType(TYPE_FLOAT)) {
+ compile_error(ctx, "invalid types used in expression: cannot perform shift between types %s and %s",
+ type_name[exprs[0]->vtype],
+ type_name[exprs[1]->vtype]);
+ return false;
+ }
+
+ if (!(out = fold_op(parser->fold, op, exprs))) {
+ ast_expression *shift = intrin_func(parser->intrin, (op->id == opid2('<','<')) ? "__builtin_lshift" : "__builtin_rshift");
+ ast_call *call = ast_call_new(parser_ctx(parser), shift);
+ vec_push(call->params, exprs[0]);
+ vec_push(call->params, exprs[1]);
+ out = (ast_expression*)call;
+ }
+ break;
+
case opid3('<','<','='):
case opid3('>','>','='):
- if(!(out = fold_op(parser->fold, op, exprs))) {
- compile_error(ast_ctx(exprs[0]), "Not Yet Implemented: bit-shifts");
+ if (NotSameType(TYPE_FLOAT)) {
+ compile_error(ctx, "invalid types used in expression: cannot perform shift operation between types %s and %s",
+ type_name[exprs[0]->vtype],
+ type_name[exprs[1]->vtype]);
return false;
}
+
+ if(!(out = fold_op(parser->fold, op, exprs))) {
+ ast_expression *shift = intrin_func(parser->intrin, (op->id == opid3('<','<','=')) ? "__builtin_lshift" : "__builtin_rshift");
+ ast_call *call = ast_call_new(parser_ctx(parser), shift);
+ vec_push(call->params, exprs[0]);
+ vec_push(call->params, exprs[1]);
+ out = (ast_expression*)ast_store_new(
+ parser_ctx(parser),
+ INSTR_STORE_F,
+ exprs[0],
+ (ast_expression*)call
+ );
+ }
+
break;
case opid2('|','|'):
/* returns true when it was a variable qualifier, false otherwise!
* on error, cvq is set to CV_WRONG
*/
+typedef struct {
+ const char *name;
+ size_t flag;
+} attribute_t;
+
static bool parse_qualifiers(parser_t *parser, bool with_local, int *cvq, bool *noref, bool *is_static, uint32_t *_flags, char **message)
{
bool had_const = false;
bool had_static = false;
uint32_t flags = 0;
- *cvq = CV_NONE;
+ static attribute_t attributes[] = {
+ { "noreturn", AST_FLAG_NORETURN },
+ { "inline", AST_FLAG_INLINE },
+ { "eraseable", AST_FLAG_ERASEABLE },
+ { "accumulate", AST_FLAG_ACCUMULATE },
+ { "last", AST_FLAG_FINAL_DECL }
+ };
+
+ *cvq = CV_NONE;
+
for (;;) {
+ size_t i;
if (parser->tok == TOKEN_ATTRIBUTE_OPEN) {
had_attrib = true;
/* parse an attribute */
*cvq = CV_WRONG;
return false;
}
- if (!strcmp(parser_tokval(parser), "noreturn")) {
- flags |= AST_FLAG_NORETURN;
- if (!parser_next(parser) || parser->tok != TOKEN_ATTRIBUTE_CLOSE) {
- parseerror(parser, "`noreturn` attribute has no parameters, expected `]]`");
- *cvq = CV_WRONG;
- return false;
+
+ for (i = 0; i < GMQCC_ARRAY_COUNT(attributes); i++) {
+ if (!strcmp(parser_tokval(parser), attributes[i].name)) {
+ flags |= attributes[i].flag;
+ if (!parser_next(parser) || parser->tok != TOKEN_ATTRIBUTE_CLOSE) {
+ parseerror(parser, "`%s` attribute has no parameters, expected `]]`",
+ attributes[i].name);
+ *cvq = CV_WRONG;
+ return false;
+ }
+ break;
}
}
- else if (!strcmp(parser_tokval(parser), "noref")) {
+
+ if (i != GMQCC_ARRAY_COUNT(attributes))
+ goto leave;
+
+
+ if (!strcmp(parser_tokval(parser), "noref")) {
had_noref = true;
if (!parser_next(parser) || parser->tok != TOKEN_ATTRIBUTE_CLOSE) {
parseerror(parser, "`noref` attribute has no parameters, expected `]]`");
return false;
}
}
- else if (!strcmp(parser_tokval(parser), "inline")) {
- flags |= AST_FLAG_INLINE;
- if (!parser_next(parser) || parser->tok != TOKEN_ATTRIBUTE_CLOSE) {
- parseerror(parser, "`inline` attribute has no parameters, expected `]]`");
- *cvq = CV_WRONG;
- return false;
- }
- }
- else if (!strcmp(parser_tokval(parser), "eraseable")) {
- flags |= AST_FLAG_ERASEABLE;
- if (!parser_next(parser) || parser->tok != TOKEN_ATTRIBUTE_CLOSE) {
- parseerror(parser, "`eraseable` attribute has no parameters, expected `]]`");
- *cvq = CV_WRONG;
- return false;
- }
- }
- else if (!strcmp(parser_tokval(parser), "accumulate")) {
- flags |= AST_FLAG_ACCUMULATE;
- if (!parser_next(parser) || parser->tok != TOKEN_ATTRIBUTE_CLOSE) {
- parseerror(parser, "`accumulate` attribute has no parameters, expected `]]`");
- *cvq = CV_WRONG;
- return false;
- }
- }
else if (!strcmp(parser_tokval(parser), "alias") && !(flags & AST_FLAG_ALIAS)) {
flags |= AST_FLAG_ALIAS;
*message = NULL;
}
else
break;
+
+ leave:
if (!parser_next(parser))
goto onerr;
}
retval = false;
goto cleanup;
}
+ if (old->flags & AST_FLAG_FINAL_DECL) {
+ parseerror(parser, "cannot redeclare variable `%s`, declared final here: %s:%i",
+ var->name, ast_ctx(old).file, ast_ctx(old).line);
+ retval = false;
+ goto cleanup;
+ }
proto = (ast_value*)old;
if (!ast_istype(old, ast_value)) {
parseerror(parser, "internal error: not an ast_value");
goto cleanup;
}
proto->expression.flags |= var->expression.flags;
+ /* copy the context for finals,
+ * so the error can show where it was actually made 'final'
+ */
+ if (proto->expression.flags & AST_FLAG_FINAL_DECL)
+ ast_ctx(old) = ast_ctx(var);
ast_delete(var);
var = proto;
}
*/
char *defname = NULL;
size_t prefix_len, ln;
+ size_t sn, sn_size;
ln = strlen(parser->function->name);
vec_append(defname, ln, parser->function->name);
/* now rename the global */
ln = strlen(var->name);
vec_append(defname, ln, var->name);
+ /* if a variable of that name already existed, add the
+ * counter value.
+ * The counter is incremented either way.
+ */
+ sn_size = vec_size(parser->function->static_names);
+ for (sn = 0; sn != sn_size; ++sn) {
+ if (strcmp(parser->function->static_names[sn], var->name) == 0)
+ break;
+ }
+ if (sn != sn_size) {
+ char *num = NULL;
+ int len = util_asprintf(&num, "#%u", parser->function->static_count);
+ vec_append(defname, len, num);
+ mem_d(num);
+ }
+ else
+ vec_push(parser->function->static_names, util_strdup(var->name));
+ parser->function->static_count++;
ast_value_set_name(var, defname);
/* push it to the to-be-generated globals */
if (!cexp)
break;
- if (!localblock) {
+ if (!localblock || is_static) {
cval = (ast_value*)cexp;
if (cval != parser->nil &&
(!ast_istype(cval, ast_value) || ((!cval->hasvalue || cval->cvq != CV_CONST) && !cval->isfield))
)
{
- parseerror(parser, "cannot initialize a global constant variable with a non-constant expression");
+ parseerror(parser, "initializer is non constant");
}
else
{
- if (!OPTS_FLAG(INITIALIZED_NONCONSTANTS) &&
+ if (!is_static &&
+ !OPTS_FLAG(INITIALIZED_NONCONSTANTS) &&
qualifier != CV_VAR)
{
var->cvq = CV_CONST;