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 { pub fn decode() voidptr {
// compiler implementation
return 0 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) return C.cJSON_CreateNumber(val)
} }
fn jsencode_i8(val i8) &C.cJSON { fn encode_i8(val i8) &C.cJSON {
return C.cJSON_CreateNumber(val) return C.cJSON_CreateNumber(val)
} }
fn jsencode_i16(val i16) &C.cJSON { fn encode_i16(val i16) &C.cJSON {
return C.cJSON_CreateNumber(val) return C.cJSON_CreateNumber(val)
} }
fn jsencode_i64(val i64) &C.cJSON { fn encode_i64(val i64) &C.cJSON {
return C.cJSON_CreateNumber(val) return C.cJSON_CreateNumber(val)
} }
fn jsencode_byte(val byte) &C.cJSON { fn encode_byte(val byte) &C.cJSON {
return C.cJSON_CreateNumber(val) return C.cJSON_CreateNumber(val)
} }
fn jsencode_u16(val u16) &C.cJSON { fn encode_u16(val u16) &C.cJSON {
return C.cJSON_CreateNumber(val) return C.cJSON_CreateNumber(val)
} }
fn jsencode_u32(val u32) &C.cJSON { fn encode_u32(val u32) &C.cJSON {
return C.cJSON_CreateNumber(val) return C.cJSON_CreateNumber(val)
} }
fn jsencode_u64(val u64) &C.cJSON { fn encode_u64(val u64) &C.cJSON {
return C.cJSON_CreateNumber(val) return C.cJSON_CreateNumber(val)
} }
fn jsencode_f32(val f32) &C.cJSON { fn encode_f32(val f32) &C.cJSON {
return C.cJSON_CreateNumber(val) return C.cJSON_CreateNumber(val)
} }
fn jsencode_f64(val f64) &C.cJSON { fn encode_f64(val f64) &C.cJSON {
return C.cJSON_CreateNumber(val) return C.cJSON_CreateNumber(val)
} }
fn jsencode_bool(val bool) &C.cJSON { fn encode_bool(val bool) &C.cJSON {
return C.cJSON_CreateBool(val) 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) return C.cJSON_CreateString(val.str)
} }
// /////////////////////// // ///////////////////////

View File

@ -60,6 +60,7 @@ mut:
str_types []string // types that need automatic str() generation str_types []string // types that need automatic str() generation
threaded_fns []string // for generating unique wrapper types and fns for `go xxx()` threaded_fns []string // for generating unique wrapper types and fns for `go xxx()`
array_fn_definitions []string // array equality functions that have been defined array_fn_definitions []string // array equality functions that have been defined
is_json_fn bool // inside json.encode()
} }
const ( 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) { fn (g mut Gen) generate_array_equality_fn(ptr_typ string, styp table.Type, sym &table.TypeSymbol) {
g.array_fn_definitions << ptr_typ g.array_fn_definitions << ptr_typ
g.definitions.writeln('bool ${ptr_typ}_arr_eq(array_${ptr_typ} a, array_${ptr_typ} b) {') 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('}') 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) { fn verror(s string) {
util.verror('cgen error', s) util.verror('cgen error', s)
} }
@ -2377,182 +2309,6 @@ fn (g mut Gen) insert_before(s string) {
g.write(cur_line) 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 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 // If the user is not using the optional return value. We need to pass a temp var
// to access its fields (`.ok`, `.error` etc) // 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) g.gen_str_for_struct(it, styp)
} }
else { 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) { fn (g mut Gen) gen_str_default(sym table.TypeSymbol, styp string) {
mut convertor := '' mut convertor := ''
mut typename := '' mut typename := ''
if sym.parent_idx in table.integer_type_idxs { if sym.parent_idx in table.integer_type_idxs {
convertor = 'int' convertor = 'int'
typename = 'int' typename = 'int'
} } else if sym.parent_idx == table.f32_type_idx {
else if sym.parent_idx == table.f32_type_idx {
convertor = 'float' convertor = 'float'
typename = 'f32' typename = 'f32'
} } else if sym.parent_idx == table.f64_type_idx {
else if sym.parent_idx == table.f64_type_idx {
convertor = 'double' convertor = 'double'
typename = 'f64' typename = 'f64'
} } else if sym.parent_idx == table.bool_type_idx {
else if sym.parent_idx == table.bool_type_idx {
convertor = 'bool' convertor = 'bool'
typename = '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) {') g.definitions.writeln('string ${styp}_str($styp it) {')
if convertor == 'bool' { if convertor == 'bool' {
g.definitions.writeln('\tstring tmp1 = string_add(tos3("${styp}("), (${convertor})it ? tos3("true") : tos3("false"));') 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

@ -9,7 +9,6 @@
// flag: (int(type)>>24) & 0xff // flag: (int(type)>>24) & 0xff
// nr_muls: (int(type)>>16) & 0xff // nr_muls: (int(type)>>16) & 0xff
// idx: u16(type) & 0xffff // idx: u16(type) & 0xffff
module table module table
import ( import (
@ -19,8 +18,7 @@ import (
pub type Type int pub type Type int
pub type TypeInfo = Array | ArrayFixed | Map | Struct | pub type TypeInfo = Array | ArrayFixed | Map | Struct | MultiReturn | Alias | Enum | SumType | FnType
MultiReturn | Alias | Enum | SumType | FnType
pub struct TypeSymbol { pub struct TypeSymbol {
pub: pub:
@ -64,6 +62,7 @@ pub fn type_nr_muls(t Type) int {
pub fn type_is_ptr(t Type) bool { 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 // set nr_muls on `t` and return it
[inline] [inline]
pub fn type_set_nr_muls(t Type, nr_muls int) Type { pub fn type_set_nr_muls(t Type, nr_muls int) Type {
@ -122,7 +121,7 @@ pub fn new_type(idx int) Type {
// return new type with TypeSymbol idx set to `idx` & nr_muls set to `nr_muls` // return new type with TypeSymbol idx set to `idx` & nr_muls set to `nr_muls`
[inline] [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 { if idx < 1 || idx > 65536 {
panic('new_type_ptr: idx must be between 1 & 65536') panic('new_type_ptr: idx must be between 1 & 65536')
} }
@ -137,7 +136,6 @@ pub fn is_number(typ Type) bool {
} }
pub const ( pub const (
// primitive types
void_type_idx = 1 void_type_idx = 1
voidptr_type_idx = 2 voidptr_type_idx = 2
byteptr_type_idx = 3 byteptr_type_idx = 3
@ -155,16 +153,17 @@ pub const (
char_type_idx = 15 char_type_idx = 15
bool_type_idx = 16 bool_type_idx = 16
none_type_idx = 17 none_type_idx = 17
// advanced / defined from v structs
string_type_idx = 18 string_type_idx = 18
array_type_idx = 19 array_type_idx = 19
map_type_idx = 20 map_type_idx = 20
) )
pub const ( 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] 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] 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] 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] pointer_type_idxs = [voidptr_type_idx, byteptr_type_idx, charptr_type_idx]
) )
@ -192,9 +191,9 @@ pub const (
) )
pub const ( pub const (
builtin_type_names = ['void', 'voidptr', 'charptr', 'byteptr', 'i8', 'i16', 'int', 'i64', 'u16', 'u32', 'u64', builtin_type_names = ['void', 'voidptr', 'charptr', 'byteptr', 'i8', 'i16', 'int', 'i64',
'f32', 'f64', 'string', 'char', 'byte', 'bool', 'none', 'array', 'array_fixed', 'map', 'struct', 'u16', 'u32', 'u64', 'f32', 'f64', 'string', 'char', 'byte', 'bool', 'none', 'array', 'array_fixed',
'mapnode', 'ustring', 'size_t'] 'map', 'struct', 'mapnode', 'ustring', 'size_t']
) )
pub struct MultiReturn { pub struct MultiReturn {
@ -311,8 +310,6 @@ pub fn (t TypeSymbol) str() string {
return t.name return t.name
} }
*/ */
pub fn (t mut Table) register_builtin_type_symbols() { pub fn (t mut Table) register_builtin_type_symbols() {
// reserve index 0 so nothing can go there // reserve index 0 so nothing can go there
// save index check, 0 will mean not found // save index check, 0 will mean not found
@ -523,7 +520,8 @@ pub fn (k Kind) str() string {
'enum' 'enum'
} }
else { else {
'unknown'} 'unknown'
}
} }
return k_str return k_str
} }
@ -564,6 +562,7 @@ mut:
default_expr ast.Expr default_expr ast.Expr
has_default_expr bool has_default_expr bool
default_val string default_val string
attr string
} }
pub struct Array { pub struct Array {
@ -609,8 +608,7 @@ pub fn (table &Table) type_to_str(t Type) string {
mut res := sym.name mut res := sym.name
if sym.kind == .array { if sym.kind == .array {
res = res.replace('array_', '[]') res = res.replace('array_', '[]')
} } else if sym.kind == .map {
else if sym.kind == .map {
res = res.replace('map_string_', 'map[string]') res = res.replace('map_string_', 'map[string]')
} }
// mod.submod.submod2.Type => submod2.Type // mod.submod.submod2.Type => submod2.Type
@ -635,6 +633,5 @@ pub fn (table &Table) type_to_str(t Type) string {
res = res[cur_mod.len+1.. ] res = res[cur_mod.len+1.. ]
} }
*/ */
return res return res
} }

View File

@ -76,6 +76,13 @@ pub fn (t &Table) find_fn(name string) ?Fn {
return none 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) { pub fn (t mut Table) register_fn(new_fn Fn) {
// println('reg fn $new_fn.name nr_args=$new_fn.args.len') // println('reg fn $new_fn.name nr_args=$new_fn.args.len')
t.fns[new_fn.name] = new_fn t.fns[new_fn.name] = new_fn