json: encode

pull/4389/head
Alexander Medvednikov 2020-04-14 00:37:47 +02:00
parent a9a8f8c804
commit 1185f04868
6 changed files with 522 additions and 371 deletions

View File

@ -13,6 +13,7 @@ struct C.cJSON {
}
pub fn decode() voidptr {
// compiler implementation
return 0
}
@ -129,51 +130,51 @@ fn jsdecode_bool(root &C.cJSON) bool {
}
// ///////////////////
fn jsencode_int(val int) &C.cJSON {
fn encode_int(val int) &C.cJSON {
return C.cJSON_CreateNumber(val)
}
fn jsencode_i8(val i8) &C.cJSON {
fn encode_i8(val i8) &C.cJSON {
return C.cJSON_CreateNumber(val)
}
fn jsencode_i16(val i16) &C.cJSON {
fn encode_i16(val i16) &C.cJSON {
return C.cJSON_CreateNumber(val)
}
fn jsencode_i64(val i64) &C.cJSON {
fn encode_i64(val i64) &C.cJSON {
return C.cJSON_CreateNumber(val)
}
fn jsencode_byte(val byte) &C.cJSON {
fn encode_byte(val byte) &C.cJSON {
return C.cJSON_CreateNumber(val)
}
fn jsencode_u16(val u16) &C.cJSON {
fn encode_u16(val u16) &C.cJSON {
return C.cJSON_CreateNumber(val)
}
fn jsencode_u32(val u32) &C.cJSON {
fn encode_u32(val u32) &C.cJSON {
return C.cJSON_CreateNumber(val)
}
fn jsencode_u64(val u64) &C.cJSON {
fn encode_u64(val u64) &C.cJSON {
return C.cJSON_CreateNumber(val)
}
fn jsencode_f32(val f32) &C.cJSON {
fn encode_f32(val f32) &C.cJSON {
return C.cJSON_CreateNumber(val)
}
fn jsencode_f64(val f64) &C.cJSON {
fn encode_f64(val f64) &C.cJSON {
return C.cJSON_CreateNumber(val)
}
fn jsencode_bool(val bool) &C.cJSON {
fn encode_bool(val bool) &C.cJSON {
return C.cJSON_CreateBool(val)
}
fn jsencode_string(val string) &C.cJSON {
fn encode_string(val string) &C.cJSON {
return C.cJSON_CreateString(val.str)
}
// ///////////////////////

View File

@ -60,6 +60,7 @@ mut:
str_types []string // types that need automatic str() generation
threaded_fns []string // for generating unique wrapper types and fns for `go xxx()`
array_fn_definitions []string // array equality functions that have been defined
is_json_fn bool // inside json.encode()
}
const (
@ -1935,49 +1936,6 @@ fn (g mut Gen) assoc(node ast.Assoc) {
}
}
fn (g mut Gen) call_args(args []ast.CallArg, expected_types []table.Type) {
is_variadic := expected_types.len > 0 && table.type_is(expected_types[expected_types.len -
1], .variadic)
mut arg_no := 0
for arg in args {
if is_variadic && arg_no == expected_types.len - 1 {
break
}
// some c fn definitions dont have args (cfns.v) or are not updated in checker
// when these are fixed we wont need this check
if arg_no < expected_types.len {
g.ref_or_deref_arg(arg, expected_types[arg_no])
} else {
g.expr(arg.expr)
}
if arg_no < args.len - 1 || is_variadic {
g.write(', ')
}
arg_no++
}
if is_variadic {
varg_type := expected_types[expected_types.len - 1]
struct_name := 'varg_' + g.typ(varg_type).replace('*', '_ptr')
variadic_count := args.len - arg_no
varg_type_str := int(varg_type).str()
if variadic_count > g.variadic_args[varg_type_str] {
g.variadic_args[varg_type_str] = variadic_count
}
g.write('($struct_name){.len=$variadic_count,.args={')
if variadic_count > 0 {
for j in arg_no .. args.len {
g.ref_or_deref_arg(args[j], varg_type)
if j < args.len - 1 {
g.write(', ')
}
}
} else {
g.write('0')
}
g.write('}}')
}
}
fn (g mut Gen) generate_array_equality_fn(ptr_typ string, styp table.Type, sym &table.TypeSymbol) {
g.array_fn_definitions << ptr_typ
g.definitions.writeln('bool ${ptr_typ}_arr_eq(array_${ptr_typ} a, array_${ptr_typ} b) {')
@ -1999,32 +1957,6 @@ fn (g mut Gen) generate_array_equality_fn(ptr_typ string, styp table.Type, sym &
g.definitions.writeln('}')
}
[inline]
fn (g mut Gen) ref_or_deref_arg(arg ast.CallArg, expected_type table.Type) {
arg_is_ptr := table.type_is_ptr(expected_type) || table.type_idx(expected_type) in table.pointer_type_idxs
expr_is_ptr := table.type_is_ptr(arg.typ) || table.type_idx(arg.typ) in table.pointer_type_idxs
if arg.is_mut && !arg_is_ptr {
g.write('&/*mut*/')
} else if arg_is_ptr && !expr_is_ptr {
if arg.is_mut {
sym := g.table.get_type_symbol(expected_type)
if sym.kind == .array {
// Special case for mutable arrays. We can't `&` function
// results, have to use `(array[]){ expr }[0]` hack.
g.write('&/*111*/(array[]){')
g.expr(arg.expr)
g.write('}[0]')
return
}
}
g.write('&/*qq*/')
} else if !arg_is_ptr && expr_is_ptr {
// Dereference a pointer if a value is required
g.write('*/*d*/')
}
g.expr_with_cast(arg.expr, arg.typ, expected_type)
}
fn verror(s string) {
util.verror('cgen error', s)
}
@ -2377,182 +2309,6 @@ fn (g mut Gen) insert_before(s string) {
g.write(cur_line)
}
fn (g mut Gen) call_expr(node ast.CallExpr) {
gen_or := !g.is_assign_rhs && node.or_block.stmts.len > 0
tmp_opt := if gen_or { g.new_tmp_var() } else { '' }
if gen_or {
styp := g.typ(node.return_type)
g.write('$styp $tmp_opt = ')
}
if node.is_method {
g.method_call(node)
} else {
g.fn_call(node)
}
if gen_or {
g.or_block(tmp_opt, node.or_block.stmts, node.return_type)
}
}
fn (g mut Gen) method_call(node ast.CallExpr) {
// TODO: there are still due to unchecked exprs (opt/some fn arg)
if node.left_type == 0 {
verror('method receiver type is 0, this means there are some uchecked exprs')
}
typ_sym := g.table.get_type_symbol(node.receiver_type)
// rec_sym := g.table.get_type_symbol(node.receiver_type)
mut receiver_name := typ_sym.name
if typ_sym.kind == .array && node.name == 'filter' {
g.gen_filter(node)
return
}
// TODO performance, detect `array` method differently
if typ_sym.kind == .array && node.name in ['repeat', 'sort_with_compare', 'free', 'push_many',
'trim', 'first', 'last', 'clone', 'reverse', 'slice'] {
// && rec_sym.name == 'array' {
// && rec_sym.name == 'array' && receiver_name.starts_with('array') {
// `array_byte_clone` => `array_clone`
receiver_name = 'array'
if node.name in ['last', 'first'] {
return_type_str := g.typ(node.return_type)
g.write('*($return_type_str*)')
}
}
name := '${receiver_name}_$node.name'.replace('.', '__')
// if node.receiver_type != 0 {
// g.write('/*${g.typ(node.receiver_type)}*/')
// g.write('/*expr_type=${g.typ(node.left_type)} rec type=${g.typ(node.receiver_type)}*/')
// }
g.write('${name}(')
if table.type_is_ptr(node.receiver_type) && !table.type_is_ptr(node.left_type) {
// The receiver is a reference, but the caller provided a value
// Add `&` automatically.
// TODO same logic in call_args()
g.write('&')
} else if !table.type_is_ptr(node.receiver_type) && table.type_is_ptr(node.left_type) {
g.write('/*rec*/*')
}
g.expr(node.left)
is_variadic := node.expected_arg_types.len > 0 && table.type_is(node.expected_arg_types[node.expected_arg_types.len -
1], .variadic)
if node.args.len > 0 || is_variadic {
g.write(', ')
}
// /////////
/*
if name.contains('subkeys') {
println('call_args $name $node.arg_types.len')
for t in node.arg_types {
sym := g.table.get_type_symbol(t)
print('$sym.name ')
}
println('')
}
*/
// ///////
g.call_args(node.args, node.expected_arg_types)
g.write(')')
// if node.or_block.stmts.len > 0 {
// g.or_block(node.or_block.stmts, node.return_type)
// }
}
fn (g mut Gen) fn_call(node ast.CallExpr) {
mut name := node.name
is_print := name == 'println' || name == 'print'
print_method := if name == 'println' { 'println' } else { 'print' }
if node.is_c {
// Skip "C."
g.is_c_call = true
name = name[2..].replace('.', '__')
} else {
name = c_name(name)
}
// Generate tmp vars for values that have to be freed.
/*
mut tmps := []string
for arg in node.args {
if arg.typ == table.string_type_idx || is_print {
tmp := g.new_tmp_var()
tmps << tmp
g.write('string $tmp = ')
g.expr(arg.expr)
g.writeln('; //memory')
}
}
*/
if is_print && node.args[0].typ != table.string_type {
typ := node.args[0].typ
mut styp := g.typ(typ)
sym := g.table.get_type_symbol(typ)
if table.type_is_ptr(typ) {
styp = styp.replace('*', '')
}
g.gen_str_for_type(sym, styp)
if g.autofree && !table.type_is(typ, .optional) {
// Create a temporary variable so that the value can be freed
tmp := g.new_tmp_var()
// tmps << tmp
g.write('string $tmp = ${styp}_str(')
g.expr(node.args[0].expr)
g.writeln('); ${print_method}($tmp); string_free($tmp); //MEM2 $styp')
} else {
expr := node.args[0].expr
is_var := match expr {
ast.SelectorExpr {
true
}
ast.Ident {
true
}
else {
false
}
}
if table.type_is_ptr(typ) && sym.kind != .struct_ {
// ptr_str() for pointers
styp = 'ptr'
}
if sym.kind == .enum_ {
if is_var {
g.write('${print_method}(${styp}_str(')
} else {
// when no var, print string directly
g.write('${print_method}(tos3("')
}
if table.type_is_ptr(typ) {
// dereference
g.write('*')
}
g.enum_expr(expr)
if !is_var {
// end of string
g.write('"')
}
} else {
g.write('${print_method}(${styp}_str(')
if table.type_is_ptr(typ) && sym.kind == .struct_ {
// dereference
g.write('*')
}
g.expr(expr)
if sym.kind == .struct_ && styp != 'ptr' && !sym.has_method('str') {
g.write(', 0') // trailing 0 is initial struct indent count
}
}
g.write('))')
}
} else {
g.write('${name}(')
g.call_args(node.args, node.expected_arg_types)
g.write(')')
}
// if node.or_block.stmts.len > 0 {
// g.or_block(node.or_block.stmts, node.return_type)
// }
g.is_c_call = false
}
// If user is accessing the return value eg. in assigment, pass the variable name.
// If the user is not using the optional return value. We need to pass a temp var
// to access its fields (`.ok`, `.error` etc)
@ -3044,35 +2800,29 @@ fn (g mut Gen) gen_str_for_type(sym table.TypeSymbol, styp string) {
g.gen_str_for_struct(it, styp)
}
else {
verror('could not generate string method for type \'${styp}\'')
verror("could not generate string method for type \'${styp}\'")
}
}
}
fn (g mut Gen) gen_str_default(sym table.TypeSymbol, styp string) {
mut convertor := ''
mut typename := ''
if sym.parent_idx in table.integer_type_idxs {
convertor = 'int'
typename = 'int'
}
else if sym.parent_idx == table.f32_type_idx {
} else if sym.parent_idx == table.f32_type_idx {
convertor = 'float'
typename = 'f32'
}
else if sym.parent_idx == table.f64_type_idx {
} else if sym.parent_idx == table.f64_type_idx {
convertor = 'double'
typename = 'f64'
}
else if sym.parent_idx == table.bool_type_idx {
} else if sym.parent_idx == table.bool_type_idx {
convertor = 'bool'
typename = 'bool'
} else {
verror("could not generate string method for type \'${styp}\'")
}
else {
verror('could not generate string method for type \'${styp}\'')
}
g.definitions.writeln('string ${styp}_str($styp it) {')
if convertor == 'bool' {
g.definitions.writeln('\tstring tmp1 = string_add(tos3("${styp}("), (${convertor})it ? tos3("true") : tos3("false"));')

View File

@ -160,3 +160,266 @@ fn (g mut Gen) fn_args(args []table.Arg, is_variadic bool) {
}
}
}
fn (g mut Gen) call_expr(node ast.CallExpr) {
gen_or := !g.is_assign_rhs && node.or_block.stmts.len > 0
tmp_opt := if gen_or { g.new_tmp_var() } else { '' }
if gen_or {
styp := g.typ(node.return_type)
g.write('$styp $tmp_opt = ')
}
if node.is_method {
g.method_call(node)
} else {
g.fn_call(node)
}
if gen_or {
g.or_block(tmp_opt, node.or_block.stmts, node.return_type)
}
}
fn (g mut Gen) method_call(node ast.CallExpr) {
// TODO: there are still due to unchecked exprs (opt/some fn arg)
if node.left_type == 0 {
verror('method receiver type is 0, this means there are some uchecked exprs')
}
typ_sym := g.table.get_type_symbol(node.receiver_type)
// rec_sym := g.table.get_type_symbol(node.receiver_type)
mut receiver_name := typ_sym.name
if typ_sym.kind == .array && node.name == 'filter' {
g.gen_filter(node)
return
}
// TODO performance, detect `array` method differently
if typ_sym.kind == .array && node.name in ['repeat', 'sort_with_compare', 'free', 'push_many',
'trim', 'first', 'last', 'clone', 'reverse', 'slice'] {
// && rec_sym.name == 'array' {
// && rec_sym.name == 'array' && receiver_name.starts_with('array') {
// `array_byte_clone` => `array_clone`
receiver_name = 'array'
if node.name in ['last', 'first'] {
return_type_str := g.typ(node.return_type)
g.write('*($return_type_str*)')
}
}
name := '${receiver_name}_$node.name'.replace('.', '__')
// if node.receiver_type != 0 {
// g.write('/*${g.typ(node.receiver_type)}*/')
// g.write('/*expr_type=${g.typ(node.left_type)} rec type=${g.typ(node.receiver_type)}*/')
// }
g.write('${name}(')
if table.type_is_ptr(node.receiver_type) && !table.type_is_ptr(node.left_type) {
// The receiver is a reference, but the caller provided a value
// Add `&` automatically.
// TODO same logic in call_args()
g.write('&')
} else if !table.type_is_ptr(node.receiver_type) && table.type_is_ptr(node.left_type) {
g.write('/*rec*/*')
}
g.expr(node.left)
is_variadic := node.expected_arg_types.len > 0 && table.type_is(node.expected_arg_types[node.expected_arg_types.len -
1], .variadic)
if node.args.len > 0 || is_variadic {
g.write(', ')
}
// /////////
/*
if name.contains('subkeys') {
println('call_args $name $node.arg_types.len')
for t in node.arg_types {
sym := g.table.get_type_symbol(t)
print('$sym.name ')
}
println('')
}
*/
// ///////
g.call_args(node.args, node.expected_arg_types)
g.write(')')
// if node.or_block.stmts.len > 0 {
// g.or_block(node.or_block.stmts, node.return_type)
// }
}
fn (g mut Gen) fn_call(node ast.CallExpr) {
mut name := node.name
is_print := name == 'println' || name == 'print'
print_method := if name == 'println' { 'println' } else { 'print' }
g.is_json_fn = name == 'json.encode'
mut json_type_str := ''
if g.is_json_fn {
g.write('json__json_print(')
g.gen_json_for_type(node.args[0].typ)
println('XAXAXAX')
json_type_str = g.table.get_type_symbol(node.args[0].typ).name
}
if node.is_c {
// Skip "C."
g.is_c_call = true
name = name[2..].replace('.', '__')
} else {
name = c_name(name)
}
if g.is_json_fn {
// `json__decode` => `json__decode_User`
name += '_' + json_type_str
}
// Generate tmp vars for values that have to be freed.
/*
mut tmps := []string
for arg in node.args {
if arg.typ == table.string_type_idx || is_print {
tmp := g.new_tmp_var()
tmps << tmp
g.write('string $tmp = ')
g.expr(arg.expr)
g.writeln('; //memory')
}
}
*/
if is_print && node.args[0].typ != table.string_type {
typ := node.args[0].typ
mut styp := g.typ(typ)
sym := g.table.get_type_symbol(typ)
if table.type_is_ptr(typ) {
styp = styp.replace('*', '')
}
g.gen_str_for_type(sym, styp)
if g.autofree && !table.type_is(typ, .optional) {
// Create a temporary variable so that the value can be freed
tmp := g.new_tmp_var()
// tmps << tmp
g.write('string $tmp = ${styp}_str(')
g.expr(node.args[0].expr)
g.writeln('); ${print_method}($tmp); string_free($tmp); //MEM2 $styp')
} else {
expr := node.args[0].expr
is_var := match expr {
ast.SelectorExpr {
true
}
ast.Ident {
true
}
else {
false
}
}
if table.type_is_ptr(typ) && sym.kind != .struct_ {
// ptr_str() for pointers
styp = 'ptr'
}
if sym.kind == .enum_ {
if is_var {
g.write('${print_method}(${styp}_str(')
} else {
// when no var, print string directly
g.write('${print_method}(tos3("')
}
if table.type_is_ptr(typ) {
// dereference
g.write('*')
}
g.enum_expr(expr)
if !is_var {
// end of string
g.write('"')
}
} else {
g.write('${print_method}(${styp}_str(')
if table.type_is_ptr(typ) && sym.kind == .struct_ {
// dereference
g.write('*')
}
g.expr(expr)
if sym.kind == .struct_ && styp != 'ptr' && !sym.has_method('str') {
g.write(', 0') // trailing 0 is initial struct indent count
}
}
g.write('))')
}
} else {
g.write('${name}(')
g.call_args(node.args, node.expected_arg_types)
g.write(')')
}
// if node.or_block.stmts.len > 0 {
// g.or_block(node.or_block.stmts, node.return_type)
// }
g.is_c_call = false
if g.is_json_fn {
g.write(')')
g.is_json_fn = false
}
}
fn (g mut Gen) call_args(args []ast.CallArg, expected_types []table.Type) {
is_variadic := expected_types.len > 0 && table.type_is(expected_types[expected_types.len -
1], .variadic)
mut arg_no := 0
for arg in args {
if is_variadic && arg_no == expected_types.len - 1 {
break
}
// some c fn definitions dont have args (cfns.v) or are not updated in checker
// when these are fixed we wont need this check
if arg_no < expected_types.len {
g.ref_or_deref_arg(arg, expected_types[arg_no])
} else {
g.expr(arg.expr)
}
if arg_no < args.len - 1 || is_variadic {
g.write(', ')
}
arg_no++
}
if is_variadic {
varg_type := expected_types[expected_types.len - 1]
struct_name := 'varg_' + g.typ(varg_type).replace('*', '_ptr')
variadic_count := args.len - arg_no
varg_type_str := int(varg_type).str()
if variadic_count > g.variadic_args[varg_type_str] {
g.variadic_args[varg_type_str] = variadic_count
}
g.write('($struct_name){.len=$variadic_count,.args={')
if variadic_count > 0 {
for j in arg_no .. args.len {
g.ref_or_deref_arg(args[j], varg_type)
if j < args.len - 1 {
g.write(', ')
}
}
} else {
g.write('0')
}
g.write('}}')
}
}
[inline]
fn (g mut Gen) ref_or_deref_arg(arg ast.CallArg, expected_type table.Type) {
arg_is_ptr := table.type_is_ptr(expected_type) || table.type_idx(expected_type) in table.pointer_type_idxs
expr_is_ptr := table.type_is_ptr(arg.typ) || table.type_idx(arg.typ) in table.pointer_type_idxs
if arg.is_mut && !arg_is_ptr {
g.write('&/*mut*/')
} else if arg_is_ptr && !expr_is_ptr {
if arg.is_mut {
sym := g.table.get_type_symbol(expected_type)
if sym.kind == .array {
// Special case for mutable arrays. We can't `&` function
// results, have to use `(array[]){ expr }[0]` hack.
g.write('&/*111*/(array[]){')
g.expr(arg.expr)
g.write('}[0]')
return
}
}
if !g.is_json_fn {
g.write('&/*qq*/')
}
} else if !arg_is_ptr && expr_is_ptr {
// Dereference a pointer if a value is required
g.write('*/*d*/')
}
g.expr_with_cast(arg.expr, arg.typ, expected_type)
}

133
vlib/v/gen/json.v 100644
View File

@ -0,0 +1,133 @@
// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module gen
import (
v.table
strings
)
// TODO replace with comptime code generation.
// TODO remove cJSON dependency.
// OLD: User decode_User(string js) {
// now it's
// User decode_User(cJSON* root) {
// User res;
// res.name = decode_string(js_get(root, "name"));
// res.profile = decode_Profile(js_get(root, "profile"));
// return res;
// }
// Codegen json_decode/encode funcs
fn (g mut Gen) gen_json_for_type(typ table.Type) {
mut dec := strings.new_builder(100)
mut enc := strings.new_builder(100)
sym := g.table.get_type_symbol(typ)
styp := g.typ(typ)
if sym.name in ['int', 'string', 'bool'] {
return
}
// println('gen_json_for_type( $typ.name )')
// Register decoder fn
/*
mut dec_fn := Fn{
mod: p.mod
typ: 'Option_$typ.name'
name: js_dec_name(t)
}
if p.table.known_fn(dec_fn.name) {
// Already registered? Skip.
return
}
// decode_TYPE funcs receive an actual cJSON* object to decode
// cJSON_Parse(str) call is added by the compiler
arg := Var{
typ: 'cJSON*'
}
dec_fn.args << arg
p.table.register_fn(dec_fn)
// Register encoder fn
mut enc_fn := Fn{
mod: p.mod
typ: 'cJSON*'
name: js_enc_name(t)
}
// encode_TYPE funcs receive an object to encode
enc_arg := Var{
typ: t
}
enc_fn.args << enc_arg
p.table.register_fn(enc_fn)
// Code gen decoder
dec += '
//$t $dec_fn.name (cJSON* root) {
Option ${dec_fn.name}(cJSON* root, $t* res) {
// $t res;
if (!root) {
const char *error_ptr = cJSON_GetErrorPtr();
if (error_ptr != NULL) {
fprintf(stderr, "Error in decode() for $t error_ptr=: %%s\\n", error_ptr);
// printf("\\nbad js=%%s\\n", js.str);
return v_error(tos2(error_ptr));
}
}
'
*/
// Code gen encoder
enc_fn_name := js_enc_name(sym.name)
enc.writeln('
cJSON* ${enc_fn_name}($styp val) {
\tcJSON *o = cJSON_CreateObject();')
// Handle arrays
if sym.kind == .array {
// dec += p.decode_array(t)
// enc += p.encode_array(t)
}
// Range through fields
info := sym.info as table.Struct
for field in info.fields {
if field.attr == 'skip' {
continue
}
name := if field.attr.starts_with('json:') { field.attr[5..] } else { field.name }
field_type := g.typ(field.typ)
enc_name := js_enc_name(field_type)
if field.attr == 'raw' {
dec.writeln(' res->$field.name = tos2(cJSON_PrintUnformatted(' + 'js_get(root, "$name")));')
} else {
// Now generate decoders for all field types in this struct
// need to do it here so that these functions are generated first
g.gen_json_for_type(field.typ)
dec_name := js_dec_name(field_type)
if is_js_prim(field_type) {
dec.writeln(' res->$field.name = $dec_name (js_get(' + 'root, "$name"))')
} else {
dec.writeln(' $dec_name (js_get(root, "$name"), & (res->$field.name))')
}
dec.writeln(';')
}
enc.writeln('\tcJSON_AddItemToObject(o, "$name", ${enc_name}(val.$field.name));')
}
// cJSON_delete
// p.cgen.fns << '$dec return opt_ok(res); \n}'
dec.writeln('return opt_ok(res, sizeof(*res)); \n}')
enc.writeln('\treturn o;\n}')
// g.definitions.writeln(dec.str())
g.gowrappers.writeln(enc.str())
}
fn js_enc_name(typ string) string {
name := 'json__encode_$typ'
return name
}
fn js_dec_name(typ string) string {
name := 'json__decode_$typ'
return name
}
fn is_js_prim(typ string) bool {
return typ == 'int' || typ == 'string' || typ == 'bool' || typ == 'f32' || typ == 'f64' ||
typ == 'i8' || typ == 'i16' || typ == 'i64' || typ == 'u16' || typ == 'u32' || typ == 'u64'
}

View File

@ -6,10 +6,9 @@
// flag (8 bits) | nr_muls (8 bits) | idx (16 bits)
// pack: (int(flag)<<24) | (nr_muls<<16) | u16(idx)
// unpack:
// flag: (int(type)>>24) & 0xff
// nr_muls: (int(type)>>16) & 0xff
// idx: u16(type) & 0xffff
// flag: (int(type)>>24) & 0xff
// nr_muls: (int(type)>>16) & 0xff
// idx: u16(type) & 0xffff
module table
import (
@ -19,8 +18,7 @@ import (
pub type Type int
pub type TypeInfo = Array | ArrayFixed | Map | Struct |
MultiReturn | Alias | Enum | SumType | FnType
pub type TypeInfo = Array | ArrayFixed | Map | Struct | MultiReturn | Alias | Enum | SumType | FnType
pub struct TypeSymbol {
pub:
@ -56,59 +54,60 @@ pub fn type_idx(t Type) int {
// return nr_muls for `t`
[inline]
pub fn type_nr_muls(t Type) int {
return (int(t)>>16) & 0xff
return (int(t) >> 16) & 0xff
}
// return true if `t` is a pointer (nr_muls>0)
[inline]
pub fn type_is_ptr(t Type) bool {
return (int(t)>>16) & 0xff > 0
return (int(t) >> 16) & 0xff > 0
}
// set nr_muls on `t` and return it
[inline]
pub fn type_set_nr_muls(t Type, nr_muls int) Type {
if nr_muls < 0 || nr_muls > 255 {
panic('typ_set_nr_muls: nr_muls must be between 0 & 255')
}
return (((int(t)>>24) & 0xff)<<24) | (nr_muls<<16) | (u16(t) & 0xffff)
return (((int(t) >> 24) & 0xff) << 24) | (nr_muls << 16) | (u16(t) & 0xffff)
}
// increments nr_nuls on `t` and return it
[inline]
pub fn type_to_ptr(t Type) Type {
nr_muls := (int(t)>>16) & 0xff
nr_muls := (int(t) >> 16) & 0xff
if nr_muls == 255 {
panic('type_to_pre: nr_muls is already at max of 255')
}
return (((int(t)>>24) & 0xff)<<24) | ((nr_muls + 1)<<16) | (u16(t) & 0xffff)
return (((int(t) >> 24) & 0xff) << 24) | ((nr_muls + 1) << 16) | (u16(t) & 0xffff)
}
// decrement nr_muls on `t` and return it
[inline]
pub fn type_deref(t Type) Type {
nr_muls := (int(t)>>16) & 0xff
nr_muls := (int(t) >> 16) & 0xff
if nr_muls == 0 {
panic('deref: type `$t` is not a pointer')
}
return (((int(t)>>24) & 0xff)<<24) | ((nr_muls - 1)<<16) | (u16(t) & 0xffff)
return (((int(t) >> 24) & 0xff) << 24) | ((nr_muls - 1) << 16) | (u16(t) & 0xffff)
}
// return the flag that is set on `t`
[inline]
pub fn type_flag(t Type) TypeFlag {
return (int(t)>>24) & 0xff
return (int(t) >> 24) & 0xff
}
// set the flag on `t` to `flag` and return it
[inline]
pub fn type_set(t Type, flag TypeFlag) Type {
return (int(flag)<<24) | (((int(t)>>16) & 0xff)<<16) | (u16(t) & 0xffff)
return (int(flag) << 24) | (((int(t) >> 16) & 0xff) << 16) | (u16(t) & 0xffff)
}
// return true if the flag set on `t` is `flag`
[inline]
pub fn type_is(t Type, flag TypeFlag) bool {
return (int(t)>>24) & 0xff == flag
return (int(t) >> 24) & 0xff == flag
}
// return new type with TypeSymbol idx set to `idx`
@ -122,14 +121,14 @@ 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 int, nr_muls int) Type {
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 nr_muls < 0 || nr_muls > 255 {
panic('new_type_ptr: nr_muls must be between 0 & 255')
}
return (nr_muls<<16) | u16(idx)
return (nr_muls << 16) | u16(idx)
}
pub fn is_number(typ Type) bool {
@ -137,64 +136,64 @@ pub fn is_number(typ Type) bool {
}
pub const (
// primitive types
void_type_idx = 1
void_type_idx = 1
voidptr_type_idx = 2
byteptr_type_idx = 3
charptr_type_idx = 4
i8_type_idx = 5
i16_type_idx = 6
int_type_idx = 7
i64_type_idx = 8
byte_type_idx = 9
u16_type_idx = 10
u32_type_idx = 11
u64_type_idx = 12
f32_type_idx = 13
f64_type_idx = 14
char_type_idx = 15
bool_type_idx = 16
none_type_idx = 17
// advanced / defined from v structs
string_type_idx = 18
array_type_idx = 19
map_type_idx = 20
i8_type_idx = 5
i16_type_idx = 6
int_type_idx = 7
i64_type_idx = 8
byte_type_idx = 9
u16_type_idx = 10
u32_type_idx = 11
u64_type_idx = 12
f32_type_idx = 13
f64_type_idx = 14
char_type_idx = 15
bool_type_idx = 16
none_type_idx = 17
string_type_idx = 18
array_type_idx = 19
map_type_idx = 20
)
pub const (
integer_type_idxs = [i8_type_idx, i16_type_idx, int_type_idx, i64_type_idx, byte_type_idx, u16_type_idx, u32_type_idx, u64_type_idx]
float_type_idxs = [f32_type_idx, f64_type_idx]
number_type_idxs = [i8_type_idx, i16_type_idx, int_type_idx, i64_type_idx, byte_type_idx, u16_type_idx, u32_type_idx, u64_type_idx, f32_type_idx, f64_type_idx]
integer_type_idxs = [i8_type_idx, i16_type_idx, int_type_idx, i64_type_idx, byte_type_idx,
u16_type_idx, u32_type_idx, u64_type_idx]
float_type_idxs = [f32_type_idx, f64_type_idx]
number_type_idxs = [i8_type_idx, i16_type_idx, int_type_idx, i64_type_idx, byte_type_idx,
u16_type_idx, u32_type_idx, u64_type_idx, f32_type_idx, f64_type_idx]
pointer_type_idxs = [voidptr_type_idx, byteptr_type_idx, charptr_type_idx]
)
pub const (
void_type = new_type(void_type_idx)
void_type = new_type(void_type_idx)
voidptr_type = new_type(voidptr_type_idx)
byteptr_type = new_type(byteptr_type_idx)
charptr_type = new_type(charptr_type_idx)
i8_type = new_type(i8_type_idx)
int_type = new_type(int_type_idx)
i16_type = new_type(i16_type_idx)
i64_type = new_type(i64_type_idx)
byte_type = new_type(byte_type_idx)
u16_type = new_type(u16_type_idx)
u32_type = new_type(u32_type_idx)
u64_type = new_type(u64_type_idx)
f32_type = new_type(f32_type_idx)
f64_type = new_type(f64_type_idx)
char_type = new_type(char_type_idx)
bool_type = new_type(bool_type_idx)
none_type = new_type(none_type_idx)
string_type = new_type(string_type_idx)
array_type = new_type(array_type_idx)
map_type = new_type(map_type_idx)
i8_type = new_type(i8_type_idx)
int_type = new_type(int_type_idx)
i16_type = new_type(i16_type_idx)
i64_type = new_type(i64_type_idx)
byte_type = new_type(byte_type_idx)
u16_type = new_type(u16_type_idx)
u32_type = new_type(u32_type_idx)
u64_type = new_type(u64_type_idx)
f32_type = new_type(f32_type_idx)
f64_type = new_type(f64_type_idx)
char_type = new_type(char_type_idx)
bool_type = new_type(bool_type_idx)
none_type = new_type(none_type_idx)
string_type = new_type(string_type_idx)
array_type = new_type(array_type_idx)
map_type = new_type(map_type_idx)
)
pub const (
builtin_type_names = ['void', 'voidptr', 'charptr', 'byteptr', 'i8', 'i16', 'int', 'i64', 'u16', 'u32', 'u64',
'f32', 'f64', 'string', 'char', 'byte', 'bool', 'none', 'array', 'array_fixed', 'map', 'struct',
'mapnode', 'ustring', 'size_t']
builtin_type_names = ['void', 'voidptr', 'charptr', 'byteptr', 'i8', 'i16', 'int', 'i64',
'u16', 'u32', 'u64', 'f32', 'f64', 'string', 'char', 'byte', 'bool', 'none', 'array', 'array_fixed',
'map', 'struct', 'mapnode', 'ustring', 'size_t']
)
pub struct MultiReturn {
@ -311,8 +310,6 @@ pub fn (t TypeSymbol) str() string {
return t.name
}
*/
pub fn (t mut Table) register_builtin_type_symbols() {
// reserve index 0 so nothing can go there
// save index check, 0 will mean not found
@ -441,89 +438,90 @@ pub fn (t &TypeSymbol) is_number() bool {
pub fn (k Kind) str() string {
k_str := match k {
.placeholder{
.placeholder {
'placeholder'
}
.void{
.void {
'void'
}
.voidptr{
.voidptr {
'voidptr'
}
.charptr{
.charptr {
'charptr'
}
.byteptr{
.byteptr {
'byteptr'
}
.struct_{
.struct_ {
'struct'
}
.int{
.int {
'int'
}
.i8{
.i8 {
'i8'
}
.i16{
.i16 {
'i16'
}
.i64{
.i64 {
'i64'
}
.byte{
.byte {
'byte'
}
.u16{
.u16 {
'u16'
}
.u32{
.u32 {
'u32'
}
.u64{
.u64 {
'u64'
}
.f32{
.f32 {
'f32'
}
.f64{
.f64 {
'f64'
}
.string{
.string {
'string'
}
.char{
.char {
'char'
}
.bool{
.bool {
'bool'
}
.none_{
.none_ {
'none'
}
.array{
.array {
'array'
}
.array_fixed{
.array_fixed {
'array_fixed'
}
.map{
.map {
'map'
}
.multi_return{
.multi_return {
'multi_return'
}
.sum_type{
.sum_type {
'sum_type'
}
.alias{
.alias {
'alias'
}
.enum_{
.enum_ {
'enum'
}
else {
'unknown'}
'unknown'
}
}
return k_str
}
@ -541,9 +539,9 @@ pub fn (kinds []Kind) str() string {
pub struct Struct {
pub mut:
fields []Field
fields []Field
is_typedef bool // C. [typedef]
is_union bool
is_union bool
}
pub struct Enum {
@ -558,12 +556,13 @@ pub:
pub struct Field {
pub:
name string
name string
mut:
typ Type
default_expr ast.Expr
typ Type
default_expr ast.Expr
has_default_expr bool
default_val string
default_val string
attr string
}
pub struct Array {
@ -609,8 +608,7 @@ pub fn (table &Table) type_to_str(t Type) string {
mut res := sym.name
if sym.kind == .array {
res = res.replace('array_', '[]')
}
else if sym.kind == .map {
} else if sym.kind == .map {
res = res.replace('map_string_', 'map[string]')
}
// mod.submod.submod2.Type => submod2.Type
@ -634,7 +632,6 @@ pub fn (table &Table) type_to_str(t Type) string {
if res.starts_with(cur_mod +'.') {
res = res[cur_mod.len+1.. ]
}
*/
*/
return res
}

View File

@ -76,6 +76,13 @@ pub fn (t &Table) find_fn(name string) ?Fn {
return none
}
pub fn (t &Table) known_fn(name string) bool {
t.find_fn(name) or {
return false
}
return true
}
pub fn (t mut Table) register_fn(new_fn Fn) {
// println('reg fn $new_fn.name nr_args=$new_fn.args.len')
t.fns[new_fn.name] = new_fn
@ -134,7 +141,7 @@ pub fn (t &Table) type_has_method(s &TypeSymbol, name string) bool {
pub fn (t &Table) type_find_method(s &TypeSymbol, name string) ?Fn {
// println('type_find_method($s.name, $name) types.len=$t.types.len s.parent_idx=$s.parent_idx')
mut ts := s
for {
for {
if method := ts.find_method(name) {
return method
}
@ -158,7 +165,7 @@ pub fn (t &Table) struct_has_field(s &TypeSymbol, name string) bool {
pub fn (t &Table) struct_find_field(s &TypeSymbol, name string) ?Field {
// println('struct_find_field($s.name, $name) types.len=$t.types.len s.parent_idx=$s.parent_idx')
mut ts := s
for {
for {
if field := ts.find_field(name) {
return field
}