all: do compile time const evaluation for `const x = "abc" + "xyz"` and `const x = 16 * 1024 + 5` (fix const prealloc_block_size)
parent
3ccde5ce55
commit
48546d0f45
|
@ -13,8 +13,7 @@ module builtin
|
||||||
// NB: `-prealloc` is NOT safe to be used for multithreaded programs!
|
// NB: `-prealloc` is NOT safe to be used for multithreaded programs!
|
||||||
|
|
||||||
// size of the preallocated chunk
|
// size of the preallocated chunk
|
||||||
// TODO: see why comptime calculation of integer expressions fails
|
const prealloc_block_size = 16 * 1024 * 1024
|
||||||
const prealloc_block_size = 16777216
|
|
||||||
|
|
||||||
__global g_memory_block &VMemoryBlock
|
__global g_memory_block &VMemoryBlock
|
||||||
[heap]
|
[heap]
|
||||||
|
|
|
@ -213,6 +213,9 @@ pub:
|
||||||
pub mut:
|
pub mut:
|
||||||
typ Type // the type of the const field, it can be any type in V
|
typ Type // the type of the const field, it can be any type in V
|
||||||
comments []Comment // comments before current const field
|
comments []Comment // comments before current const field
|
||||||
|
// the comptime_expr_value field is filled by the checker, when it has enough
|
||||||
|
// info to evaluate the constant at compile time
|
||||||
|
comptime_expr_value ComptTimeConstValue = empty_comptime_const_expr()
|
||||||
}
|
}
|
||||||
|
|
||||||
// const declaration
|
// const declaration
|
||||||
|
@ -1098,16 +1101,18 @@ pub:
|
||||||
// .in_prexpr is also needed because of that, because the checker needs to
|
// .in_prexpr is also needed because of that, because the checker needs to
|
||||||
// show warnings about the deprecated C->V conversions `string(x)` and
|
// show warnings about the deprecated C->V conversions `string(x)` and
|
||||||
// `string(x,y)`, while skipping the real pointer casts like `&string(x)`.
|
// `string(x,y)`, while skipping the real pointer casts like `&string(x)`.
|
||||||
|
// 2021/07/17: TODO: since 6edfb2c, the above is fixed at the parser level,
|
||||||
|
// we need to remove the hacks/special cases in vfmt and the checker too.
|
||||||
pub struct CastExpr {
|
pub struct CastExpr {
|
||||||
pub:
|
pub:
|
||||||
arg Expr // `n` in `string(buf, n)`
|
arg Expr // `n` in `string(buf, n)`
|
||||||
pub mut:
|
pub mut:
|
||||||
typ Type // `string` TODO rename to `type_to_cast_to`
|
typ Type // `string`
|
||||||
|
expr Expr // `buf` in `string(buf, n)` and `&Type(buf)`
|
||||||
|
typname string // `&Type` in `&Type(buf)`
|
||||||
|
expr_type Type // `byteptr`, the type of the `buf` expression
|
||||||
|
has_arg bool // true for `string(buf, n)`, false for `&Type(buf)`
|
||||||
pos token.Position
|
pos token.Position
|
||||||
expr Expr // `buf` in `string(buf, n)`
|
|
||||||
typname string // TypeSymbol.name
|
|
||||||
expr_type Type // `byteptr`
|
|
||||||
has_arg bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct AsmStmt {
|
pub struct AsmStmt {
|
||||||
|
|
|
@ -0,0 +1,138 @@
|
||||||
|
module ast
|
||||||
|
|
||||||
|
pub type ComptTimeConstValue = EmptyExpr | byte | f64 | i64 | rune | string
|
||||||
|
|
||||||
|
pub fn empty_comptime_const_expr() ComptTimeConstValue {
|
||||||
|
return EmptyExpr{}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (val ComptTimeConstValue) i64() ?i64 {
|
||||||
|
match val {
|
||||||
|
i64, byte {
|
||||||
|
return i64(val)
|
||||||
|
}
|
||||||
|
f64 {
|
||||||
|
if -9223372036854775808.0 <= val && val <= 9223372036854775807.0 {
|
||||||
|
return i64(val)
|
||||||
|
}
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
string {
|
||||||
|
return val.i64()
|
||||||
|
}
|
||||||
|
rune {
|
||||||
|
return int(val)
|
||||||
|
}
|
||||||
|
EmptyExpr {
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (val ComptTimeConstValue) int() ?int {
|
||||||
|
match val {
|
||||||
|
f64 {
|
||||||
|
if -2147483648.0 <= val && val <= 2147483647.0 {
|
||||||
|
return int(val)
|
||||||
|
}
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
i64 {
|
||||||
|
if -2147483648 <= val && val <= 2147483647 {
|
||||||
|
return int(val)
|
||||||
|
}
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
byte {
|
||||||
|
return int(val)
|
||||||
|
}
|
||||||
|
string {
|
||||||
|
return val.int()
|
||||||
|
}
|
||||||
|
rune {
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
EmptyExpr {
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (val ComptTimeConstValue) string() ?string {
|
||||||
|
match val {
|
||||||
|
i64, f64, byte {
|
||||||
|
return val.str()
|
||||||
|
}
|
||||||
|
string {
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
rune {
|
||||||
|
return val.str()
|
||||||
|
}
|
||||||
|
EmptyExpr {
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (val ComptTimeConstValue) f64() ?f64 {
|
||||||
|
match val {
|
||||||
|
f64 {
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
i64, byte {
|
||||||
|
return f64(val)
|
||||||
|
}
|
||||||
|
string {
|
||||||
|
return val.f64()
|
||||||
|
}
|
||||||
|
rune {
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
EmptyExpr {
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (val ComptTimeConstValue) byte() ?byte {
|
||||||
|
match val {
|
||||||
|
byte {
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
f64 {
|
||||||
|
if 0 <= val && val <= 255 {
|
||||||
|
return byte(val)
|
||||||
|
}
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
i64 {
|
||||||
|
if 0 <= val && val <= 255 {
|
||||||
|
return byte(val)
|
||||||
|
}
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
string {
|
||||||
|
x := val.int()
|
||||||
|
if 0 <= x && x <= 255 {
|
||||||
|
return byte(x)
|
||||||
|
}
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
rune {
|
||||||
|
x := u32(val)
|
||||||
|
if 0 <= x && x <= 255 {
|
||||||
|
return byte(x)
|
||||||
|
}
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
EmptyExpr {
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return none
|
||||||
|
}
|
|
@ -358,6 +358,9 @@ pub fn (x Expr) str() string {
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
SelectExpr {
|
||||||
|
return 'ast.SelectExpr'
|
||||||
|
}
|
||||||
SelectorExpr {
|
SelectorExpr {
|
||||||
return '${x.expr.str()}.$x.field_name'
|
return '${x.expr.str()}.$x.field_name'
|
||||||
}
|
}
|
||||||
|
@ -410,7 +413,50 @@ pub fn (x Expr) str() string {
|
||||||
None {
|
None {
|
||||||
return 'none'
|
return 'none'
|
||||||
}
|
}
|
||||||
else {}
|
IsRefType {
|
||||||
|
return 'isreftype(' + if x.is_type {
|
||||||
|
global_table.type_to_str(x.typ)
|
||||||
|
} else {
|
||||||
|
x.expr.str()
|
||||||
|
} + ')'
|
||||||
|
}
|
||||||
|
IfGuardExpr {
|
||||||
|
return x.var_name + ' := ' + x.expr.str()
|
||||||
|
}
|
||||||
|
StructInit {
|
||||||
|
sname := global_table.get_type_symbol(x.typ).name
|
||||||
|
return '$sname{....}'
|
||||||
|
}
|
||||||
|
ArrayDecompose {
|
||||||
|
return 'ast.ArrayDecompose'
|
||||||
|
}
|
||||||
|
Assoc {
|
||||||
|
return 'ast.Assoc'
|
||||||
|
}
|
||||||
|
ChanInit {
|
||||||
|
return 'ast.ChanInit'
|
||||||
|
}
|
||||||
|
ComptimeCall {
|
||||||
|
return 'ast.ComptimeCall'
|
||||||
|
}
|
||||||
|
EmptyExpr {
|
||||||
|
return 'ast.EmptyExpr'
|
||||||
|
}
|
||||||
|
LockExpr {
|
||||||
|
return 'ast.LockExpr'
|
||||||
|
}
|
||||||
|
MatchExpr {
|
||||||
|
return 'ast.MatchExpr'
|
||||||
|
}
|
||||||
|
NodeError {
|
||||||
|
return 'ast.NodeError'
|
||||||
|
}
|
||||||
|
OrExpr {
|
||||||
|
return 'ast.OrExpr'
|
||||||
|
}
|
||||||
|
SqlExpr {
|
||||||
|
return 'ast.SqlExpr'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return '[unhandled expr type $x.type_name()]'
|
return '[unhandled expr type $x.type_name()]'
|
||||||
}
|
}
|
||||||
|
|
|
@ -3608,10 +3608,13 @@ pub fn (mut c Checker) const_decl(mut node ast.ConstDecl) {
|
||||||
}
|
}
|
||||||
mut needs_order := false
|
mut needs_order := false
|
||||||
mut done_fields := []int{}
|
mut done_fields := []int{}
|
||||||
for i, field in node.fields {
|
for i, mut field in node.fields {
|
||||||
c.const_decl = field.name
|
c.const_decl = field.name
|
||||||
c.const_deps << field.name
|
c.const_deps << field.name
|
||||||
typ := c.check_expr_opt_call(field.expr, c.expr(field.expr))
|
typ := c.check_expr_opt_call(field.expr, c.expr(field.expr))
|
||||||
|
if ct_value := eval_comptime_const_expr(field.expr, 0) {
|
||||||
|
field.comptime_expr_value = ct_value
|
||||||
|
}
|
||||||
node.fields[i].typ = c.table.mktyp(typ)
|
node.fields[i].typ = c.table.mktyp(typ)
|
||||||
for cd in c.const_deps {
|
for cd in c.const_deps {
|
||||||
for j, f in node.fields {
|
for j, f in node.fields {
|
||||||
|
@ -4345,7 +4348,7 @@ pub fn (mut c Checker) array_init(mut array_init ast.ArrayInit) ast.Type {
|
||||||
} else if array_init.is_fixed && array_init.exprs.len == 1
|
} else if array_init.is_fixed && array_init.exprs.len == 1
|
||||||
&& array_init.elem_type != ast.void_type {
|
&& array_init.elem_type != ast.void_type {
|
||||||
// [50]byte
|
// [50]byte
|
||||||
mut fixed_size := 0
|
mut fixed_size := i64(0)
|
||||||
init_expr := array_init.exprs[0]
|
init_expr := array_init.exprs[0]
|
||||||
c.expr(init_expr)
|
c.expr(init_expr)
|
||||||
match init_expr {
|
match init_expr {
|
||||||
|
@ -4354,16 +4357,18 @@ pub fn (mut c Checker) array_init(mut array_init ast.ArrayInit) ast.Type {
|
||||||
}
|
}
|
||||||
ast.Ident {
|
ast.Ident {
|
||||||
if init_expr.obj is ast.ConstField {
|
if init_expr.obj is ast.ConstField {
|
||||||
if cint := eval_int_expr(init_expr.obj.expr, 0) {
|
if comptime_value := eval_comptime_const_expr(init_expr.obj.expr,
|
||||||
fixed_size = cint
|
0)
|
||||||
|
{
|
||||||
|
fixed_size = comptime_value.i64() or { fixed_size }
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
c.error('non-constant array bound `$init_expr.name`', init_expr.pos)
|
c.error('non-constant array bound `$init_expr.name`', init_expr.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast.InfixExpr {
|
ast.InfixExpr {
|
||||||
if cint := eval_int_expr(init_expr, 0) {
|
if comptime_value := eval_comptime_const_expr(init_expr, 0) {
|
||||||
fixed_size = cint
|
fixed_size = comptime_value.i64() or { fixed_size }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -4373,7 +4378,7 @@ pub fn (mut c Checker) array_init(mut array_init ast.ArrayInit) ast.Type {
|
||||||
if fixed_size <= 0 {
|
if fixed_size <= 0 {
|
||||||
c.error('fixed size cannot be zero or negative', init_expr.position())
|
c.error('fixed size cannot be zero or negative', init_expr.position())
|
||||||
}
|
}
|
||||||
idx := c.table.find_or_register_array_fixed(array_init.elem_type, fixed_size,
|
idx := c.table.find_or_register_array_fixed(array_init.elem_type, int(fixed_size),
|
||||||
init_expr)
|
init_expr)
|
||||||
if array_init.elem_type.has_flag(.generic) {
|
if array_init.elem_type.has_flag(.generic) {
|
||||||
array_init.typ = ast.new_type(idx).set_flag(.generic)
|
array_init.typ = ast.new_type(idx).set_flag(.generic)
|
||||||
|
@ -4387,47 +4392,6 @@ pub fn (mut c Checker) array_init(mut array_init ast.ArrayInit) ast.Type {
|
||||||
return array_init.typ
|
return array_init.typ
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_int_expr(expr ast.Expr, nlevel int) ?int {
|
|
||||||
if nlevel > 100 {
|
|
||||||
// protect against a too deep comptime eval recursion:
|
|
||||||
return none
|
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
[inline]
|
[inline]
|
||||||
fn (mut c Checker) check_loop_label(label string, pos token.Position) {
|
fn (mut c Checker) check_loop_label(label string, pos token.Position) {
|
||||||
if label.len == 0 {
|
if label.len == 0 {
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
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
|
||||||
|
}
|
||||||
|
x := expr
|
||||||
|
match expr {
|
||||||
|
ast.IntegerLiteral {
|
||||||
|
return expr.val.i64()
|
||||||
|
}
|
||||||
|
ast.StringLiteral {
|
||||||
|
return expr.val
|
||||||
|
}
|
||||||
|
ast.CastExpr {
|
||||||
|
cast_expr_value := eval_comptime_const_expr(expr.expr, nlevel + 1) or { return none }
|
||||||
|
if expr.typ == ast.byte_type {
|
||||||
|
return cast_expr_value.byte() or { return none }
|
||||||
|
}
|
||||||
|
if expr.typ == ast.int_type {
|
||||||
|
match cast_expr_value {
|
||||||
|
byte {
|
||||||
|
eprintln('>>>>>>> byte cast_expr_value: $cast_expr_value | x: $x')
|
||||||
|
return i64(cast_expr_value)
|
||||||
|
}
|
||||||
|
i64 {
|
||||||
|
eprintln('>>>>>>> i64 cast_expr_value: $cast_expr_value | x: $x')
|
||||||
|
if int_min <= cast_expr_value && cast_expr_value <= int_max {
|
||||||
|
return i64(cast_expr_value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {}
|
||||||
|
}
|
||||||
|
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 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 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast.Ident {
|
||||||
|
if expr.obj is ast.ConstField {
|
||||||
|
// an existing constant?
|
||||||
|
return eval_comptime_const_expr(expr.obj.expr, nlevel + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// eprintln('>>> nlevel: $nlevel | another $expr.type_name() | $expr ')
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return none
|
||||||
|
}
|
|
@ -4846,24 +4846,7 @@ fn (mut g Gen) const_decl(node ast.ConstDecl) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
name := c_name(field.name)
|
name := c_name(field.name)
|
||||||
/*
|
|
||||||
if field.typ == ast.byte_type {
|
|
||||||
g.const_decl_simple_define(name, val)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
if ast.is_number(field.typ) {
|
|
||||||
g.const_decl_simple_define(name, val)
|
|
||||||
} else if field.typ == ast.string_type {
|
|
||||||
g.definitions.writeln('string _const_$name; // a string literal, inited later')
|
|
||||||
if g.pref.build_mode != .build_module {
|
|
||||||
g.stringliterals.writeln('\t_const_$name = $val;')
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
*/
|
|
||||||
field_expr := field.expr
|
field_expr := field.expr
|
||||||
match field.expr {
|
match field.expr {
|
||||||
ast.ArrayInit {
|
ast.ArrayInit {
|
||||||
|
@ -4895,6 +4878,11 @@ fn (mut g Gen) const_decl(node ast.ConstDecl) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
if ct_value := comptime_expr_value(field) {
|
||||||
|
if g.const_decl_precomputed(field.mod, name, ct_value, field.typ) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
if is_simple_define_const(field) {
|
if is_simple_define_const(field) {
|
||||||
// "Simple" expressions are not going to need multiple statements,
|
// "Simple" expressions are not going to need multiple statements,
|
||||||
// only the ones which are inited later, so it's safe to use expr_string
|
// only the ones which are inited later, so it's safe to use expr_string
|
||||||
|
@ -4907,6 +4895,15 @@ fn (mut g Gen) const_decl(node ast.ConstDecl) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn comptime_expr_value(obj ast.ScopeObject) ?ast.ComptTimeConstValue {
|
||||||
|
if obj is ast.ConstField {
|
||||||
|
if obj.comptime_expr_value !is ast.EmptyExpr {
|
||||||
|
return obj.comptime_expr_value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
|
||||||
fn is_simple_define_const(obj ast.ScopeObject) bool {
|
fn is_simple_define_const(obj ast.ScopeObject) bool {
|
||||||
if obj is ast.ConstField {
|
if obj is ast.ConstField {
|
||||||
return match obj.expr {
|
return match obj.expr {
|
||||||
|
@ -4917,6 +4914,38 @@ fn is_simple_define_const(obj ast.ScopeObject) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) const_decl_precomputed(mod string, name string, ct_value ast.ComptTimeConstValue, typ ast.Type) bool {
|
||||||
|
mut styp := g.typ(typ)
|
||||||
|
cname := '_const_$name'
|
||||||
|
// eprintln('>> cname: $cname | styp: $styp | $ct_value.type_name() | $ct_value')
|
||||||
|
match ct_value {
|
||||||
|
byte {
|
||||||
|
g.const_decl_write_precomputed(styp, cname, ct_value.str())
|
||||||
|
}
|
||||||
|
rune {
|
||||||
|
g.const_decl_write_precomputed(styp, cname, ct_value.str())
|
||||||
|
}
|
||||||
|
i64 {
|
||||||
|
g.const_decl_write_precomputed(styp, cname, ct_value.str())
|
||||||
|
}
|
||||||
|
f64 {
|
||||||
|
g.const_decl_write_precomputed(styp, cname, ct_value.str())
|
||||||
|
}
|
||||||
|
string {
|
||||||
|
escaped_val := util.smart_quote(ct_value, false)
|
||||||
|
g.const_decl_write_precomputed(styp, cname, '_SLIT("$escaped_val")')
|
||||||
|
}
|
||||||
|
ast.EmptyExpr {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) const_decl_write_precomputed(styp string, cname string, ct_value string) {
|
||||||
|
g.definitions.writeln('$styp $cname = $ct_value; // precomputed')
|
||||||
|
}
|
||||||
|
|
||||||
fn (mut g Gen) const_decl_simple_define(name string, val string) {
|
fn (mut g Gen) const_decl_simple_define(name string, val string) {
|
||||||
// Simple expressions should use a #define
|
// Simple expressions should use a #define
|
||||||
// so that we don't pollute the binary with unnecessary global vars
|
// so that we don't pollute the binary with unnecessary global vars
|
||||||
|
|
|
@ -179,7 +179,7 @@ const c_common_macros = '
|
||||||
# define VNORETURN _Noreturn
|
# define VNORETURN _Noreturn
|
||||||
# elif defined(__GNUC__) && __GNUC__ >= 2
|
# elif defined(__GNUC__) && __GNUC__ >= 2
|
||||||
# define VNORETURN __attribute__((noreturn))
|
# define VNORETURN __attribute__((noreturn))
|
||||||
# endif
|
# endif
|
||||||
#ifndef VNORETURN
|
#ifndef VNORETURN
|
||||||
#define VNORETURN
|
#define VNORETURN
|
||||||
#endif
|
#endif
|
||||||
|
@ -191,7 +191,7 @@ const c_common_macros = '
|
||||||
#if (V_GCC_VERSION >= 40500L)
|
#if (V_GCC_VERSION >= 40500L)
|
||||||
#define VUNREACHABLE() do { __builtin_unreachable(); } while (0)
|
#define VUNREACHABLE() do { __builtin_unreachable(); } while (0)
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#if defined(__clang__) && defined(__has_builtin)
|
#if defined(__clang__) && defined(__has_builtin)
|
||||||
#if __has_builtin(__builtin_unreachable)
|
#if __has_builtin(__builtin_unreachable)
|
||||||
#define VUNREACHABLE() do { __builtin_unreachable(); } while (0)
|
#define VUNREACHABLE() do { __builtin_unreachable(); } while (0)
|
||||||
|
@ -199,7 +199,7 @@ const c_common_macros = '
|
||||||
#endif
|
#endif
|
||||||
#ifndef VUNREACHABLE
|
#ifndef VUNREACHABLE
|
||||||
#define VUNREACHABLE() do { } while (0)
|
#define VUNREACHABLE() do { } while (0)
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//likely and unlikely macros
|
//likely and unlikely macros
|
||||||
|
@ -232,13 +232,17 @@ static inline bool _us64_lt(uint64_t a, int64_t b) { return a < INT64_MAX && (in
|
||||||
const c_helper_macros = '//============================== HELPER C MACROS =============================*/
|
const c_helper_macros = '//============================== HELPER C MACROS =============================*/
|
||||||
// _SLIT0 is used as NULL string for literal arguments
|
// _SLIT0 is used as NULL string for literal arguments
|
||||||
// `"" s` is used to enforce a string literal argument
|
// `"" s` is used to enforce a string literal argument
|
||||||
#define _SLIT0 (string){.len=0}
|
#define _SLIT0 (string){.str=(byteptr)(""), .len=0, .is_lit=1}
|
||||||
#define _SLIT(s) ((string){.str=(byteptr)("" s), .len=(sizeof(s)-1), .is_lit=1})
|
#define _SLIT(s) ((string){.str=(byteptr)("" s), .len=(sizeof(s)-1), .is_lit=1})
|
||||||
|
#define _SLEN(s, n) ((string){.str=(byteptr)("" s), .len=n, .is_lit=1})
|
||||||
|
|
||||||
// take the address of an rvalue
|
// take the address of an rvalue
|
||||||
#define ADDR(type, expr) (&((type[]){expr}[0]))
|
#define ADDR(type, expr) (&((type[]){expr}[0]))
|
||||||
|
|
||||||
// copy something to the heap
|
// copy something to the heap
|
||||||
#define HEAP(type, expr) ((type*)memdup((void*)&((type[]){expr}[0]), sizeof(type)))
|
#define HEAP(type, expr) ((type*)memdup((void*)&((type[]){expr}[0]), sizeof(type)))
|
||||||
#define HEAP_noscan(type, expr) ((type*)memdup_noscan((void*)&((type[]){expr}[0]), sizeof(type)))
|
#define HEAP_noscan(type, expr) ((type*)memdup_noscan((void*)&((type[]){expr}[0]), sizeof(type)))
|
||||||
|
|
||||||
#define _PUSH_MANY(arr, val, tmp, tmp_typ) {tmp_typ tmp = (val); array_push_many(arr, tmp.data, tmp.len);}
|
#define _PUSH_MANY(arr, val, tmp, tmp_typ) {tmp_typ tmp = (val); array_push_many(arr, tmp.data, tmp.len);}
|
||||||
#define _PUSH_MANY_noscan(arr, val, tmp, tmp_typ) {tmp_typ tmp = (val); array_push_many_noscan(arr, tmp.data, tmp.len);}
|
#define _PUSH_MANY_noscan(arr, val, tmp, tmp_typ) {tmp_typ tmp = (val); array_push_many_noscan(arr, tmp.data, tmp.len);}
|
||||||
'
|
'
|
||||||
|
|
Loading…
Reference in New Issue