From 26cfd0eda93e59e3311c46c1302b5da7a38b2053 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Tue, 9 Mar 2021 20:06:34 +0200 Subject: [PATCH] checker: eval `const a = 1024 * 1024` and other simple integer expressions at compile time --- vlib/v/checker/checker.v | 48 ++++++++++++++----- ..._simple_int_expressions_at_comptime_test.v | 21 ++++++++ 2 files changed, 58 insertions(+), 11 deletions(-) create mode 100644 vlib/v/tests/const_eval_simple_int_expressions_at_comptime_test.v diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 839693077b..fe655a0204 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -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 } diff --git a/vlib/v/tests/const_eval_simple_int_expressions_at_comptime_test.v b/vlib/v/tests/const_eval_simple_int_expressions_at_comptime_test.v new file mode 100644 index 0000000000..d91f52f6f9 --- /dev/null +++ b/vlib/v/tests/const_eval_simple_int_expressions_at_comptime_test.v @@ -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{}