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('|','|'):
return false;
}
}
+ else if (!strcmp(parser_tokval(parser), "final")) {
+ flags |= AST_FLAG_FINAL_DECL;
+ if (!parser_next(parser) || parser->tok != TOKEN_ATTRIBUTE_CLOSE) {
+ parseerror(parser, "`final` 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;
had_var = true;
else if (!strcmp(parser_tokval(parser), "noref"))
had_noref = true;
+ else if (!strcmp(parser_tokval(parser), "final"))
+ flags |= AST_FLAG_FINAL_DECL;
else if (!had_const && !had_var && !had_noref && !had_attrib && !had_static && !flags) {
return false;
}
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;
}