checker: eval `const a = 1024 * 1024` and other simple integer expressions at compile time

pull/9225/head
Delyan Angelov 2021-03-09 20:06:34 +02:00
parent f1469a8761
commit 26cfd0eda9
No known key found for this signature in database
GPG Key ID: 66886C0F12D595ED
2 changed files with 58 additions and 11 deletions

View File

@ -3056,7 +3056,7 @@ pub fn (mut c Checker) array_init(mut array_init ast.ArrayInit) table.Type {
}
ast.Ident {
if init_expr.obj is ast.ConstField {
if cint := const_int_value(init_expr.obj) {
if cint := eval_int_expr(init_expr.obj.expr, 0) {
fixed_size = cint
}
} else {
@ -3080,17 +3080,43 @@ pub fn (mut c Checker) array_init(mut array_init ast.ArrayInit) table.Type {
return array_init.typ
}
fn const_int_value(cfield ast.ConstField) ?int {
if cint := is_const_integer(cfield) {
return cint.val.int()
fn eval_int_expr(expr ast.Expr, nlevel int) ?int {
if nlevel > 100 {
// protect against a too deep comptime eval recursion:
return none
}
return none
}
fn is_const_integer(cfield ast.ConstField) ?ast.IntegerLiteral {
match cfield.expr {
ast.IntegerLiteral { return cfield.expr }
else {}
match expr {
ast.IntegerLiteral {
return expr.val.int()
}
ast.InfixExpr {
left := eval_int_expr(expr.left, nlevel + 1) ?
right := eval_int_expr(expr.right, nlevel + 1) ?
match expr.op {
.plus { return left + right }
.minus { return left - right }
.mul { return left * right }
.div { return left / right }
.mod { return left % right }
.xor { return left ^ right }
.pipe { return left | right }
.amp { return left & right }
.left_shift { return left << right }
.right_shift { return left >> right }
else { return none }
}
}
ast.Ident {
if expr.obj is ast.ConstField {
// an int constant?
cint := eval_int_expr(expr.obj.expr, nlevel + 1) ?
return cint
}
}
else {
// dump(expr)
return none
}
}
return none
}

View File

@ -0,0 +1,21 @@
const kb = 1024
const buf_siz = 1024 * kb
fn test_consts() {
assert kb == 1024
assert buf_siz == 1024 * kb
assert buf_siz == 1048576
println(buf_siz)
}
fn test_fixed_size_arrays_can_use_known_comptime_consts_as_their_size() {
buf := [buf_siz]byte{}
println(buf.len)
assert buf.len == 1048576
}
// zbuf := [1024*1024]byte{}
// error: fixed size cannot be zero or negative
// buf := [1048576]byte{}