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

@ -6,10 +6,9 @@
// flag (8 bits) | nr_muls (8 bits) | idx (16 bits) // flag (8 bits) | nr_muls (8 bits) | idx (16 bits)
// pack: (int(flag)<<24) | (nr_muls<<16) | u16(idx) // pack: (int(flag)<<24) | (nr_muls<<16) | u16(idx)
// unpack: // unpack:
// 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:
@ -56,59 +54,60 @@ pub fn type_idx(t Type) int {
// return nr_muls for `t` // return nr_muls for `t`
[inline] [inline]
pub fn type_nr_muls(t Type) int { 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) // return true if `t` is a pointer (nr_muls>0)
[inline] [inline]
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 {
if nr_muls < 0 || nr_muls > 255 { if nr_muls < 0 || nr_muls > 255 {
panic('typ_set_nr_muls: nr_muls must be between 0 & 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 // increments nr_nuls on `t` and return it
[inline] [inline]
pub fn type_to_ptr(t Type) Type { pub fn type_to_ptr(t Type) Type {
nr_muls := (int(t)>>16) & 0xff nr_muls := (int(t) >> 16) & 0xff
if nr_muls == 255 { if nr_muls == 255 {
panic('type_to_pre: nr_muls is already at max of 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 // decrement nr_muls on `t` and return it
[inline] [inline]
pub fn type_deref(t Type) Type { pub fn type_deref(t Type) Type {
nr_muls := (int(t)>>16) & 0xff nr_muls := (int(t) >> 16) & 0xff
if nr_muls == 0 { if nr_muls == 0 {
panic('deref: type `$t` is not a pointer') 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` // return the flag that is set on `t`
[inline] [inline]
pub fn type_flag(t Type) TypeFlag { 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 // set the flag on `t` to `flag` and return it
[inline] [inline]
pub fn type_set(t Type, flag TypeFlag) Type { 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` // return true if the flag set on `t` is `flag`
[inline] [inline]
pub fn type_is(t Type, flag TypeFlag) bool { 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` // 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` // 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')
} }
if nr_muls < 0 || nr_muls > 255 { if nr_muls < 0 || nr_muls > 255 {
panic('new_type_ptr: nr_muls must be between 0 & 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 { pub fn is_number(typ Type) bool {
@ -137,64 +136,64 @@ 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
charptr_type_idx = 4 charptr_type_idx = 4
i8_type_idx = 5 i8_type_idx = 5
i16_type_idx = 6 i16_type_idx = 6
int_type_idx = 7 int_type_idx = 7
i64_type_idx = 8 i64_type_idx = 8
byte_type_idx = 9 byte_type_idx = 9
u16_type_idx = 10 u16_type_idx = 10
u32_type_idx = 11 u32_type_idx = 11
u64_type_idx = 12 u64_type_idx = 12
f32_type_idx = 13 f32_type_idx = 13
f64_type_idx = 14 f64_type_idx = 14
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,
float_type_idxs = [f32_type_idx, f64_type_idx] u16_type_idx, u32_type_idx, u64_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] 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] pointer_type_idxs = [voidptr_type_idx, byteptr_type_idx, charptr_type_idx]
) )
pub const ( pub const (
void_type = new_type(void_type_idx) void_type = new_type(void_type_idx)
voidptr_type = new_type(voidptr_type_idx) voidptr_type = new_type(voidptr_type_idx)
byteptr_type = new_type(byteptr_type_idx) byteptr_type = new_type(byteptr_type_idx)
charptr_type = new_type(charptr_type_idx) charptr_type = new_type(charptr_type_idx)
i8_type = new_type(i8_type_idx) i8_type = new_type(i8_type_idx)
int_type = new_type(int_type_idx) int_type = new_type(int_type_idx)
i16_type = new_type(i16_type_idx) i16_type = new_type(i16_type_idx)
i64_type = new_type(i64_type_idx) i64_type = new_type(i64_type_idx)
byte_type = new_type(byte_type_idx) byte_type = new_type(byte_type_idx)
u16_type = new_type(u16_type_idx) u16_type = new_type(u16_type_idx)
u32_type = new_type(u32_type_idx) u32_type = new_type(u32_type_idx)
u64_type = new_type(u64_type_idx) u64_type = new_type(u64_type_idx)
f32_type = new_type(f32_type_idx) f32_type = new_type(f32_type_idx)
f64_type = new_type(f64_type_idx) f64_type = new_type(f64_type_idx)
char_type = new_type(char_type_idx) char_type = new_type(char_type_idx)
bool_type = new_type(bool_type_idx) bool_type = new_type(bool_type_idx)
none_type = new_type(none_type_idx) none_type = new_type(none_type_idx)
string_type = new_type(string_type_idx) string_type = new_type(string_type_idx)
array_type = new_type(array_type_idx) array_type = new_type(array_type_idx)
map_type = new_type(map_type_idx) map_type = new_type(map_type_idx)
) )
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
@ -441,89 +438,90 @@ pub fn (t &TypeSymbol) is_number() bool {
pub fn (k Kind) str() string { pub fn (k Kind) str() string {
k_str := match k { k_str := match k {
.placeholder{ .placeholder {
'placeholder' 'placeholder'
} }
.void{ .void {
'void' 'void'
} }
.voidptr{ .voidptr {
'voidptr' 'voidptr'
} }
.charptr{ .charptr {
'charptr' 'charptr'
} }
.byteptr{ .byteptr {
'byteptr' 'byteptr'
} }
.struct_{ .struct_ {
'struct' 'struct'
} }
.int{ .int {
'int' 'int'
} }
.i8{ .i8 {
'i8' 'i8'
} }
.i16{ .i16 {
'i16' 'i16'
} }
.i64{ .i64 {
'i64' 'i64'
} }
.byte{ .byte {
'byte' 'byte'
} }
.u16{ .u16 {
'u16' 'u16'
} }
.u32{ .u32 {
'u32' 'u32'
} }
.u64{ .u64 {
'u64' 'u64'
} }
.f32{ .f32 {
'f32' 'f32'
} }
.f64{ .f64 {
'f64' 'f64'
} }
.string{ .string {
'string' 'string'
} }
.char{ .char {
'char' 'char'
} }
.bool{ .bool {
'bool' 'bool'
} }
.none_{ .none_ {
'none' 'none'
} }
.array{ .array {
'array' 'array'
} }
.array_fixed{ .array_fixed {
'array_fixed' 'array_fixed'
} }
.map{ .map {
'map' 'map'
} }
.multi_return{ .multi_return {
'multi_return' 'multi_return'
} }
.sum_type{ .sum_type {
'sum_type' 'sum_type'
} }
.alias{ .alias {
'alias' 'alias'
} }
.enum_{ .enum_ {
'enum' 'enum'
} }
else { else {
'unknown'} 'unknown'
}
} }
return k_str return k_str
} }
@ -541,9 +539,9 @@ pub fn (kinds []Kind) str() string {
pub struct Struct { pub struct Struct {
pub mut: pub mut:
fields []Field fields []Field
is_typedef bool // C. [typedef] is_typedef bool // C. [typedef]
is_union bool is_union bool
} }
pub struct Enum { pub struct Enum {
@ -558,12 +556,13 @@ pub:
pub struct Field { pub struct Field {
pub: pub:
name string name string
mut: mut:
typ Type typ Type
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
@ -634,7 +632,6 @@ pub fn (table &Table) type_to_str(t Type) string {
if res.starts_with(cur_mod +'.') { if res.starts_with(cur_mod +'.') {
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
@ -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 { 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') // println('type_find_method($s.name, $name) types.len=$t.types.len s.parent_idx=$s.parent_idx')
mut ts := s mut ts := s
for { for {
if method := ts.find_method(name) { if method := ts.find_method(name) {
return method 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 { 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') // println('struct_find_field($s.name, $name) types.len=$t.types.len s.parent_idx=$s.parent_idx')
mut ts := s mut ts := s
for { for {
if field := ts.find_field(name) { if field := ts.find_field(name) {
return field return field
} }