json: encode
parent
a9a8f8c804
commit
1185f04868
|
@ -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)
|
||||
}
|
||||
// ///////////////////////
|
||||
|
|
|
@ -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"));')
|
||||
|
|
263
vlib/v/gen/fn.v
263
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)
|
||||
}
|
||||
|
|
|
@ -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'
|
||||
}
|
|
@ -9,7 +9,6 @@
|
|||
// 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,7 +136,6 @@ pub fn is_number(typ Type) bool {
|
|||
}
|
||||
|
||||
pub const (
|
||||
// primitive types
|
||||
void_type_idx = 1
|
||||
voidptr_type_idx = 2
|
||||
byteptr_type_idx = 3
|
||||
|
@ -155,16 +153,17 @@ pub const (
|
|||
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
|
||||
)
|
||||
|
||||
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]
|
||||
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]
|
||||
)
|
||||
|
||||
|
@ -192,9 +191,9 @@ pub const (
|
|||
)
|
||||
|
||||
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
|
||||
}
|
||||
|
@ -564,6 +562,7 @@ mut:
|
|||
default_expr ast.Expr
|
||||
has_default_expr bool
|
||||
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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue