table: allow type hold 8 flags at once

pull/5210/head
joe-conigliaro 2020-06-04 22:38:54 +10:00
parent 2230cbae01
commit edd56bc080
No known key found for this signature in database
GPG Key ID: C12F7136C08206F1
7 changed files with 58 additions and 54 deletions

View File

@ -19,7 +19,7 @@ pub fn (c &Checker) check_basic(got, expected table.Type) bool {
// and the other is not, is this correct behaviour?
return true
}
if got_idx == table.none_type_idx && expected.flag_is(.optional) {
if got_idx == table.none_type_idx && expected.has_flag(.optional) {
return true
}
// allow pointers to be initialized with 0. TODO: use none instead

View File

@ -826,7 +826,7 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type {
c.expected_type = exp_arg_typ
got_arg_typ := c.expr(arg.expr)
call_expr.args[i].typ = got_arg_typ
if method.is_variadic && got_arg_typ.flag_is(.variadic) && call_expr.args.len -
if method.is_variadic && got_arg_typ.has_flag(.variadic) && call_expr.args.len -
1 > i {
c.error('when forwarding a varg variable, it must be the final argument', call_expr.pos)
}
@ -1027,7 +1027,7 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type {
call_expr.args[i].typ = typ
typ_sym := c.table.get_type_symbol(typ)
arg_typ_sym := c.table.get_type_symbol(arg.typ)
if f.is_variadic && typ.flag_is(.variadic) && call_expr.args.len - 1 > i {
if f.is_variadic && typ.has_flag(.variadic) && call_expr.args.len - 1 > i {
c.error('when forwarding a varg variable, it must be the final argument', call_expr.pos)
}
if arg.is_mut && !call_arg.is_mut {
@ -1100,7 +1100,7 @@ fn (mut c Checker) type_implements(typ, inter_typ table.Type, pos token.Position
pub fn (mut c Checker) check_expr_opt_call(expr ast.Expr, ret_type table.Type) table.Type {
if expr is ast.CallExpr {
call_expr := expr as ast.CallExpr
if call_expr.return_type.flag_is(.optional) {
if call_expr.return_type.has_flag(.optional) {
if call_expr.or_block.kind == .absent {
if ret_type != table.void_type {
c.error('${call_expr.name}() returns an option, but you missed to add an `or {}` block to it',
@ -1110,7 +1110,7 @@ pub fn (mut c Checker) check_expr_opt_call(expr ast.Expr, ret_type table.Type) t
c.check_or_expr(call_expr.or_block, ret_type)
}
// remove optional flag
return ret_type.set_flag(.unset)
return ret_type.clear_flag(.optional)
} else if call_expr.or_block.kind == .block {
c.error('unexpected `or` block, the function `$call_expr.name` does not return an optional',
call_expr.pos)
@ -1124,7 +1124,7 @@ pub fn (mut c Checker) check_expr_opt_call(expr ast.Expr, ret_type table.Type) t
pub fn (mut c Checker) check_or_expr(mut or_expr ast.OrExpr, ret_type table.Type) {
if or_expr.kind == .propagate {
if !c.cur_fn.return_type.flag_is(.optional) && c.cur_fn.name != 'main' {
if !c.cur_fn.return_type.has_flag(.optional) && c.cur_fn.name != 'main' {
c.error('to propagate the optional call, `${c.cur_fn.name}` must itself return an optional',
or_expr.pos)
}
@ -1193,7 +1193,7 @@ pub fn (mut c Checker) selector_expr(mut selector_expr ast.SelectorExpr) table.T
sym := c.table.get_type_symbol(c.unwrap_generic(typ))
field_name := selector_expr.field_name
// variadic
if typ.flag_is(.variadic) {
if typ.has_flag(.variadic) {
if field_name == 'len' {
return table.int_type
}
@ -1228,7 +1228,7 @@ pub fn (mut c Checker) return_stmt(mut return_stmt ast.Return) {
}
expected_type := c.expected_type
expected_type_sym := c.table.get_type_symbol(expected_type)
exp_is_optional := expected_type.flag_is(.optional)
exp_is_optional := expected_type.has_flag(.optional)
mut expected_types := [expected_type]
if expected_type_sym.kind == .multi_return {
mr_info := expected_type_sym.info as table.MultiReturn
@ -1258,8 +1258,8 @@ pub fn (mut c Checker) return_stmt(mut return_stmt ast.Return) {
}
for i, exp_type in expected_types {
got_typ := got_types[i]
if got_typ.flag_is(.optional) &&
(!exp_type.flag_is(.optional) || c.table.type_to_str(got_typ) != c.table.type_to_str(exp_type)) {
if got_typ.has_flag(.optional) &&
(!exp_type.has_flag(.optional) || c.table.type_to_str(got_typ) != c.table.type_to_str(exp_type)) {
pos := return_stmt.exprs[i].position()
c.error('cannot use `${c.table.type_to_str(got_typ)}` as type `${c.table.type_to_str(exp_type)}` in return argument', pos)
}
@ -1977,7 +1977,7 @@ pub fn (mut c Checker) ident(mut ident ast.Ident) table.Type {
}
typ = c.expr(it.expr)
}
is_optional := typ.flag_is(.optional)
is_optional := typ.has_flag(.optional)
ident.kind = .variable
ident.info = ast.IdentVar{
typ: typ
@ -1993,7 +1993,7 @@ pub fn (mut c Checker) ident(mut ident ast.Ident) table.Type {
it.typ = typ
// unwrap optional (`println(x)`)
if is_optional {
return typ.set_flag(.unset)
return typ.clear_flag(.optional)
}
return typ
}

View File

@ -324,7 +324,7 @@ fn (g &Gen) typ(t table.Type) string {
// T => int etc
return g.typ(g.cur_generic_type)
}
if t.flag_is(.optional) {
if t.has_flag(.optional) {
// Register an optional if it's not registered yet
return g.register_optional(t)
}
@ -844,7 +844,7 @@ fn (mut g Gen) for_in(it ast.ForInStmt) {
}
g.stmts(it.stmts)
g.writeln('}')
} else if it.cond_type.flag_is(.variadic) {
} else if it.cond_type.has_flag(.variadic) {
g.writeln('// FOR IN cond_type/variadic')
i := if it.key_var in ['', '_'] { g.new_tmp_var() } else { it.key_var }
styp := g.typ(it.cond_type)
@ -901,7 +901,7 @@ fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type, expected_type table.Type)
got_deref_type := got_type.deref()
deref_sym := g.table.get_type_symbol(got_deref_type)
deref_will_match := expected_type in [got_type, got_deref_type, deref_sym.parent_idx]
got_is_opt := got_type.flag_is(.optional)
got_is_opt := got_type.has_flag(.optional)
if deref_will_match || got_is_opt {
g.write('*')
}
@ -1015,7 +1015,7 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
1 {
// multi return
// TODO Handle in if_expr
is_optional := return_type.flag_is(.optional)
is_optional := return_type.has_flag(.optional)
mr_var_name := 'mr_$assign_stmt.pos.pos'
mr_styp := g.typ(return_type)
g.write('$mr_styp $mr_var_name = ')
@ -1289,7 +1289,7 @@ fn (mut g Gen) autofree_scope_vars(pos int) string {
// continue
// }
v := *it
is_optional := v.typ.flag_is(.optional)
is_optional := v.typ.has_flag(.optional)
if is_optional {
// TODO: free optionals
continue
@ -1644,7 +1644,7 @@ fn (mut g Gen) assign_expr(node ast.AssignExpr) {
}
else {}
}
gen_or := is_call && return_type.flag_is(.optional)
gen_or := is_call && return_type.has_flag(.optional)
tmp_opt := if gen_or { g.new_tmp_var() } else { '' }
if gen_or {
rstyp := g.typ(return_type)
@ -1662,7 +1662,7 @@ fn (mut g Gen) assign_expr(node ast.AssignExpr) {
}
} else {
g.is_assign_lhs = true
if node.right_type.flag_is(.optional) {
if node.right_type.has_flag(.optional) {
g.right_is_opt = true
}
mut str_add := false
@ -1719,7 +1719,7 @@ fn (mut g Gen) assign_expr(node ast.AssignExpr) {
if gen_or {
// g.write('/*777 $tmp_opt*/')
g.or_block(tmp_opt, or_block, return_type)
unwrapped_type_str := g.typ(return_type.set_flag(.unset))
unwrapped_type_str := g.typ(return_type.clear_flag(.optional))
ident := node.left as ast.Ident
if ident.kind != .blank_ident && ident.info is ast.IdentVar {
ident_var := ident.info as ast.IdentVar
@ -2207,7 +2207,7 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) {
if !is_range {
sym := g.table.get_type_symbol(node.left_type)
left_is_ptr := node.left_type.is_ptr()
if node.left_type.flag_is(.variadic) {
if node.left_type.has_flag(.variadic) {
g.expr(node.left)
g.write('.args')
g.write('[')
@ -2339,7 +2339,7 @@ fn (mut g Gen) return_statement(node ast.Return) {
// got to do a correct check for multireturn
sym := g.table.get_type_symbol(g.fn_decl.return_type)
fn_return_is_multi := sym.kind == .multi_return
fn_return_is_optional := g.fn_decl.return_type.flag_is(.optional)
fn_return_is_optional := g.fn_decl.return_type.has_flag(.optional)
// handle promoting none/error/function returning 'Option'
if fn_return_is_optional {
optional_none := node.exprs[0] is ast.None
@ -2418,7 +2418,7 @@ fn (mut g Gen) return_statement(node ast.Return) {
// normal return
return_sym := g.table.get_type_symbol(node.types[0])
// `return opt_ok(expr)` for functions that expect an optional
if fn_return_is_optional && !node.types[0].flag_is(.optional) && return_sym.name !=
if fn_return_is_optional && !node.types[0].has_flag(.optional) && return_sym.name !=
'Option' {
styp := g.base_type(g.fn_decl.return_type)
opt_type := g.typ(g.fn_decl.return_type)
@ -2631,7 +2631,7 @@ fn (mut g Gen) struct_init(struct_init ast.StructInit) {
// unions thould have exactly one explicit initializer
continue
}
if field.typ.flag_is(.optional) {
if field.typ.has_flag(.optional) {
// TODO handle/require optionals in inits
continue
}
@ -2813,7 +2813,7 @@ fn (mut g Gen) write_types(types []table.TypeSymbol) {
// if this is the case then we are going to
// buffer manip out in front of the struct
// write the optional in and then continue
if field.typ.flag_is(.optional) {
if field.typ.has_flag(.optional) {
// Dont use g.typ() here becuase it will register
// optional and we dont want that
last_text := g.type_definitions.after(start_pos).clone()
@ -3102,7 +3102,7 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype table.Type) ?bool {
sym := g.table.get_type_symbol(etype)
sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info()
if etype.flag_is(.variadic) {
if etype.has_flag(.variadic) {
str_fn_name := g.gen_str_for_type(etype)
g.write('${str_fn_name}(')
g.expr(expr)
@ -3294,7 +3294,7 @@ fn (mut g Gen) or_block(var_name string, or_block ast.OrExpr, return_type table.
expr_stmt := stmt as ast.ExprStmt
g.stmt_path_pos << g.out.len
g.write('*(${mr_styp}*) ${cvar_name}.data = ')
is_opt_call := expr_stmt.expr is ast.CallExpr && expr_stmt.typ.flag_is(.optional)
is_opt_call := expr_stmt.expr is ast.CallExpr && expr_stmt.typ.has_flag(.optional)
if is_opt_call {
g.write('*(${mr_styp}*) ')
}
@ -3858,7 +3858,7 @@ fn (mut g Gen) gen_str_for_type_with_styp(typ table.Type, styp string) string {
}
}
// if varg, generate str for varg
if typ.flag_is(.variadic) {
if typ.has_flag(.variadic) {
varg_already_generated_key := 'varg_$already_generated_key'
if varg_already_generated_key !in g.str_types {
g.gen_str_for_varg(styp, str_fn_name, sym_has_str_method)

View File

@ -430,7 +430,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
}
g.expr(node.left)
is_variadic := node.expected_arg_types.len > 0 && node.expected_arg_types[node.expected_arg_types.len -
1].flag_is(.variadic)
1].has_flag(.variadic)
if node.args.len > 0 || is_variadic {
g.write(', ')
}
@ -523,7 +523,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
styp = styp.replace('*', '')
}
mut str_fn_name := g.gen_str_for_type_with_styp(typ, styp)
if g.autofree && !typ.flag_is(.optional) {
if g.autofree && !typ.has_flag(.optional) {
// Create a temporary variable so that the value can be freed
tmp := g.new_tmp_var()
// tmps << tmp
@ -565,7 +565,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
g.write('*')
}
g.expr(expr)
if !typ.flag_is(.variadic) && sym.kind == .struct_ && styp != 'ptr' && !sym.has_method('str') {
if !typ.has_flag(.variadic) && sym.kind == .struct_ && styp != 'ptr' && !sym.has_method('str') {
g.write(', 0') // trailing 0 is initial struct indent count
}
}
@ -599,8 +599,8 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
}
fn (mut g Gen) call_args(args []ast.CallArg, expected_types []table.Type) {
is_variadic := expected_types.len > 0 && expected_types[expected_types.len - 1].flag_is(.variadic)
is_forwarding_varg := args.len > 0 && args[args.len - 1].typ.flag_is(.variadic)
is_variadic := expected_types.len > 0 && expected_types[expected_types.len - 1].has_flag(.variadic)
is_forwarding_varg := args.len > 0 && args[args.len - 1].typ.has_flag(.variadic)
gen_vargs := is_variadic && !is_forwarding_varg
for i, arg in args {
if gen_vargs && i == expected_types.len - 1 {

View File

@ -908,7 +908,7 @@ fn (mut g JsGen) gen_for_in_stmt(it ast.ForInStmt) {
g.inside_loop = false
g.stmts(it.stmts)
g.writeln('}')
} else if it.kind == .array || it.cond_type.flag_is(.variadic) {
} else if it.kind == .array || it.cond_type.has_flag(.variadic) {
// `for num in nums {`
i := if it.key_var == '' { g.new_tmp_var() } else { it.key_var }
// styp := g.typ(it.val_type)

View File

@ -36,8 +36,8 @@ pub mut:
is_public bool
}
// max of 8
pub enum TypeFlag {
unset
optional
variadic
generic
@ -99,29 +99,33 @@ pub fn (t Type) deref() Type {
return (((int(t) >> 24) & 0xff) << 24) | ((nr_muls - 1) << 16) | (u16(t) & 0xffff)
}
// return the flag that is set on `t`
[inline]
pub fn (t Type) flag() TypeFlag {
return (int(t) >> 24) & 0xff
}
// set the flag on `t` to `flag` and return it
// set `flag` on `t` and return `t`
[inline]
pub fn (t Type) set_flag(flag TypeFlag) Type {
return (int(flag) << 24) | (((int(t) >> 16) & 0xff) << 16) | (u16(t) & 0xffff)
return ((((int(t) >> 24) & 0xff) | 1 << int(flag)) << 24) | (((int(t) >> 16) & 0xff) << 16) | (u16(t) & 0xffff)
}
// return true if the flag set on `t` is `flag`
// clear `flag` on `t` and return `t`
pub fn (t Type) clear_flag(flag TypeFlag) Type {
return (((((int(t) >> 24) & 0xff) & ~(1 << int(flag))) << 24) ) | (((int(t) >> 16) & 0xff) << 16) | (u16(t) & 0xffff)
}
// clear all flags
pub fn (t Type) clear_flags() Type {
return 0 | (((int(t) >> 16) & 0xff) << 16) | (u16(t) & 0xffff)
}
// return true if `flag` is set in `t`
[inline]
pub fn (t Type) flag_is(flag TypeFlag) bool {
return (int(t) >> 24) & 0xff == flag
pub fn (t Type) has_flag(flag TypeFlag) bool {
return (((int(t) >> 24) & 0xff) >> int(flag)) & 1 == 1
}
// return new type with TypeSymbol idx set to `idx`
[inline]
pub fn new_type(idx int) Type {
if idx < 1 || idx > 65536 {
panic('new_type_id: idx must be between 1 & 65536')
if idx < 1 || idx > 65535 {
panic('new_type_id: idx must be between 1 & 65535')
}
return idx
}
@ -129,8 +133,8 @@ pub fn new_type(idx int) Type {
// return new type with TypeSymbol idx set to `idx` & nr_muls set to `nr_muls`
[inline]
pub fn new_type_ptr(idx, nr_muls int) Type {
if idx < 1 || idx > 65536 {
panic('new_type_ptr: idx must be between 1 & 65536')
if idx < 1 || idx > 65535 {
panic('new_type_ptr: idx must be between 1 & 65535')
}
if nr_muls < 0 || nr_muls > 255 {
panic('new_type_ptr: nr_muls must be between 0 & 255')
@ -673,7 +677,7 @@ pub fn (table &Table) type_to_str(t Type) string {
mut res := sym.name
if sym.kind == .multi_return {
res = '('
if t.flag_is(.optional) {
if t.has_flag(.optional) {
res = '?' + res
}
mr_info := sym.info as MultiReturn
@ -706,7 +710,7 @@ pub fn (table &Table) type_to_str(t Type) string {
if nr_muls > 0 {
res = strings.repeat(`&`, nr_muls) + res
}
if t.flag_is(.optional) {
if t.has_flag(.optional) {
if sym.kind == .void {
res = '?'
} else {

View File

@ -417,9 +417,9 @@ pub fn (mut t Table) add_placeholder_type(name string) int {
[inline]
pub fn (t &Table) value_type(typ Type) Type {
typ_sym := t.get_type_symbol(typ)
if typ.flag_is(.variadic) {
if typ.has_flag(.variadic) {
// ...string => string
return typ.set_flag(.unset)
return typ.clear_flag(.variadic)
}
if typ_sym.kind == .array {
// Check index type