module checker import v.ast fn eval_comptime_const_expr(expr ast.Expr, nlevel int) ?ast.ComptTimeConstValue { if nlevel > 100 { // protect against a too deep comptime eval recursion return none } match expr { ast.IntegerLiteral { x := expr.val.u64() if x > 9223372036854775807 { return x } return expr.val.i64() } ast.StringLiteral { return expr.val } ast.CharLiteral { runes := expr.val.runes() if runes.len > 0 { return runes[0] } return none } ast.Ident { if expr.obj is ast.ConstField { // an existing constant? return eval_comptime_const_expr(expr.obj.expr, nlevel + 1) } } ast.CastExpr { cast_expr_value := eval_comptime_const_expr(expr.expr, nlevel + 1) or { return none } if expr.typ == ast.i8_type { return cast_expr_value.i8() or { return none } } if expr.typ == ast.i16_type { return cast_expr_value.i16() or { return none } } if expr.typ == ast.int_type { return cast_expr_value.int() or { return none } } if expr.typ == ast.i64_type { return cast_expr_value.i64() or { return none } } // if expr.typ == ast.byte_type { return cast_expr_value.byte() or { return none } } if expr.typ == ast.u16_type { return cast_expr_value.u16() or { return none } } if expr.typ == ast.u32_type { return cast_expr_value.u32() or { return none } } if expr.typ == ast.u64_type { return cast_expr_value.u64() or { return none } } // if expr.typ == ast.f32_type { return cast_expr_value.f32() or { return none } } if expr.typ == ast.f64_type { return cast_expr_value.f64() or { return none } } } ast.InfixExpr { left := eval_comptime_const_expr(expr.left, nlevel + 1) ? right := eval_comptime_const_expr(expr.right, nlevel + 1) ? if left is string && right is string { match expr.op { .plus { return left + right } else { return none } } } else if left is u64 && right is i64 { match expr.op { .plus { return i64(left) + i64(right) } .minus { return i64(left) - i64(right) } .mul { return i64(left) * i64(right) } .div { return i64(left) / i64(right) } .mod { return i64(left) % i64(right) } .xor { return i64(left) ^ i64(right) } .pipe { return i64(left) | i64(right) } .amp { return i64(left) & i64(right) } .left_shift { return i64(left) << i64(right) } .right_shift { return i64(left) >> i64(right) } else { return none } } } else if left is i64 && right is u64 { match expr.op { .plus { return i64(left) + i64(right) } .minus { return i64(left) - i64(right) } .mul { return i64(left) * i64(right) } .div { return i64(left) / i64(right) } .mod { return i64(left) % i64(right) } .xor { return i64(left) ^ i64(right) } .pipe { return i64(left) | i64(right) } .amp { return i64(left) & i64(right) } .left_shift { return i64(left) << i64(right) } .right_shift { return i64(left) >> i64(right) } else { return none } } } else if left is u64 && right is u64 { 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 } } } else if left is i64 && right is i64 { 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 } } } else if left is byte && right is byte { 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 } } } } else { // eprintln('>>> nlevel: $nlevel | another $expr.type_name() | $expr ') return none } } return none }