From 1185f048684ed7fa677a05b7dc66d0fdb1f005f3 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Tue, 14 Apr 2020 00:37:47 +0200 Subject: [PATCH] json: encode --- vlib/json/json_primitives.v | 25 ++-- vlib/v/gen/cgen.v | 264 +----------------------------------- vlib/v/gen/fn.v | 263 +++++++++++++++++++++++++++++++++++ vlib/v/gen/json.v | 133 ++++++++++++++++++ vlib/v/table/atypes.v | 197 +++++++++++++-------------- vlib/v/table/table.v | 11 +- 6 files changed, 522 insertions(+), 371 deletions(-) create mode 100644 vlib/v/gen/json.v diff --git a/vlib/json/json_primitives.v b/vlib/json/json_primitives.v index ad274daa21..39f29364af 100644 --- a/vlib/json/json_primitives.v +++ b/vlib/json/json_primitives.v @@ -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) } // /////////////////////// diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 1bee207aea..1a93f72128 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -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"));') diff --git a/vlib/v/gen/fn.v b/vlib/v/gen/fn.v index 8ba6e4a830..d38e74cb7f 100644 --- a/vlib/v/gen/fn.v +++ b/vlib/v/gen/fn.v @@ -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) +} diff --git a/vlib/v/gen/json.v b/vlib/v/gen/json.v new file mode 100644 index 0000000000..296a173a8e --- /dev/null +++ b/vlib/v/gen/json.v @@ -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' +} diff --git a/vlib/v/table/atypes.v b/vlib/v/table/atypes.v index a24131b18a..b52feff73a 100644 --- a/vlib/v/table/atypes.v +++ b/vlib/v/table/atypes.v @@ -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 } diff --git a/vlib/v/table/table.v b/vlib/v/table/table.v index 0701ecd37f..2f40bf1517 100644 --- a/vlib/v/table/table.v +++ b/vlib/v/table/table.v @@ -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 }