json: wrap up decode()

pull/4708/head
Alexander Medvednikov 2020-05-04 16:46:36 +02:00
parent 5eb71c4a13
commit fd8a194df0
6 changed files with 68 additions and 38 deletions

View File

@ -6,6 +6,7 @@ module json
#flag -I @VROOT/thirdparty/cJSON
#flag @VROOT/thirdparty/cJSON/cJSON.o
#include "cJSON.h"
#define js_get(object, key) cJSON_GetObjectItemCaseSensitive((object), (key))
struct C.cJSON {
valueint int
valuedouble f32
@ -22,84 +23,84 @@ pub fn encode(x voidptr) string {
return ''
}
fn jsdecode_int(root &C.cJSON) int {
fn decode_int(root &C.cJSON) int {
if isnil(root) {
return 0
}
return root.valueint
}
fn jsdecode_i8(root &C.cJSON) i8 {
fn decode_i8(root &C.cJSON) i8 {
if isnil(root) {
return i8(0)
}
return i8(root.valueint)
}
fn jsdecode_i16(root &C.cJSON) i16 {
fn decode_i16(root &C.cJSON) i16 {
if isnil(root) {
return i16(0)
}
return i16(root.valueint)
}
fn jsdecode_i64(root &C.cJSON) i64 {
fn decode_i64(root &C.cJSON) i64 {
if isnil(root) {
return i64(0)
}
return i64(root.valuedouble) // i64 is double in C
}
fn jsdecode_byte(root &C.cJSON) byte {
fn decode_byte(root &C.cJSON) byte {
if isnil(root) {
return byte(0)
}
return byte(root.valueint)
}
fn jsdecode_u16(root &C.cJSON) u16 {
fn decode_u16(root &C.cJSON) u16 {
if isnil(root) {
return u16(0)
}
return u16(root.valueint)
}
fn jsdecode_u32(root &C.cJSON) u32 {
fn decode_u32(root &C.cJSON) u32 {
if isnil(root) {
return u32(0)
}
return u32(root.valueint)
}
fn jsdecode_u64(root &C.cJSON) u64 {
fn decode_u64(root &C.cJSON) u64 {
if isnil(root) {
return u64(0)
}
return u64(root.valueint)
}
fn jsdecode_f32(root &C.cJSON) f32 {
fn decode_f32(root &C.cJSON) f32 {
if isnil(root) {
return f32(0)
}
return root.valuedouble
}
fn jsdecode_f64(root &C.cJSON) f64 {
fn decode_f64(root &C.cJSON) f64 {
if isnil(root) {
return f64(0)
}
return f64(root.valuedouble)
}
fn jsdecode_string(root &C.cJSON) string {
fn decode_string(root &C.cJSON) string {
if isnil(root) {
return ''
}
if isnil(root.valuestring) {
return ''
}
// println('jsdecode string valuestring="$root.valuestring"')
// println('decode string valuestring="$root.valuestring"')
// return tos(root.valuestring, _strlen(root.valuestring))
return tos_clone(root.valuestring) // , _strlen(root.valuestring))
}
@ -122,7 +123,7 @@ fn C.cJSON_Parse() &C.cJSON
fn C.cJSON_PrintUnformatted() byteptr
fn jsdecode_bool(root &C.cJSON) bool {
fn decode_bool(root &C.cJSON) bool {
if isnil(root) {
return false
}

View File

@ -721,13 +721,14 @@ pub fn (mut c Checker) call_fn(call_expr mut ast.CallExpr) table.Type {
// println(fn_name)
// }
if fn_name == 'json.encode' {
}
if fn_name == 'json.decode' {
ident := call_expr.args[0].expr as ast.Ident
// sym := c.table.find_type(ident.name)
idx := c.table.find_type_idx(ident.name)
println('js.decode t=$ident.name')
return table.Type(idx)
} else if fn_name == 'json.decode' {
expr := call_expr.args[0].expr
if !(expr is ast.Type) {
c.error('json.decode: first argument needs to be a type', call_expr.pos)
return table.void_type
}
typ := expr as ast.Type
return typ.typ.set_flag(.optional)
}
// look for function in format `mod.fn` or `fn` (main/builtin)
mut f := table.Fn{}

View File

@ -383,12 +383,22 @@ fn (mut g 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'
is_json_encode := name == 'json.encode'
is_json_decode := name == 'json.decode'
g.is_json_fn = is_json_encode || is_json_decode
mut json_type_str := ''
if g.is_json_fn {
g.write('json__json_print(')
g.gen_json_for_type(node.args[0].typ)
json_type_str = g.table.get_type_symbol(node.args[0].typ).name
if name == 'json.encode' {
g.write('json__json_print(')
g.gen_json_for_type(node.args[0].typ)
json_type_str = g.table.get_type_symbol(node.args[0].typ).name
} else {
g.insert_before('// json.decode')
ast_type := node.args[0].expr as ast.Type
// `json.decode(User, s)` => json.decode_User(s)
sym := g.table.get_type_symbol(ast_type.typ)
name += '_' + sym.name
}
}
if node.is_c {
// Skip "C."
@ -397,8 +407,8 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
} else {
name = c_name(name)
}
if g.is_json_fn {
// `json__decode` => `json__decode_User`
if is_json_encode {
// `json__encode` => `json__encode_User`
name += '_' + json_type_str
}
// Generate tmp vars for values that have to be freed.
@ -476,14 +486,25 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
pafn := g.fn_decl.name.after('.')
mut pamod := g.fn_decl.name.all_before_last('.')
if pamod == pafn {
pamod = if g.fn_decl.is_builtin { 'builtin' } else { 'main' }
pamod = if g.fn_decl.is_builtin {
'builtin'
} else {
'main'
}
}
g.write('panic_debug($paline, tos3("$pafile"), tos3("$pamod"), tos3("$pafn"), ')
g.call_args(node.args, node.expected_arg_types)
g.write(')')
} else {
g.write('${name}(')
g.call_args(node.args, node.expected_arg_types)
if is_json_decode {
g.write('json__json_parse(')
// Skip the first argument in json.decode which is a type
// its name was already used to generate the function call
g.call_args(node.args[1..], node.expected_arg_types)
} else {
g.call_args(node.args, node.expected_arg_types)
}
g.write(')')
}
// if node.or_block.stmts.len > 0 {

View File

@ -31,8 +31,9 @@ fn (mut g Gen) gen_json_for_type(typ table.Type) {
// Code gen decoder
dec_fn_name := js_dec_name(sym.name)
dec.writeln('
Option ${dec_fn_name}(cJSON* root, $styp* res) {
// $styp res;
//Option ${dec_fn_name}(cJSON* root, $styp* res) {
Option ${dec_fn_name}(cJSON* root) {
$styp res;
if (!root) {
const char *error_ptr = cJSON_GetErrorPtr();
if (error_ptr != NULL) {
@ -70,7 +71,7 @@ cJSON* ${enc_fn_name}($styp val) {
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"))')
dec.writeln(' res . $field.name = $dec_name (js_get(' + 'root, "$name"))')
} else {
dec.writeln(' $dec_name (js_get(root, "$name"), & (res->$field.name))')
}
@ -80,7 +81,7 @@ cJSON* ${enc_fn_name}($styp val) {
}
// cJSON_delete
// p.cgen.fns << '$dec return opt_ok(res); \n}'
dec.writeln('return opt_ok(res, sizeof(*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())

View File

@ -20,6 +20,11 @@ pub fn (mut p Parser) call_expr(is_c, is_js bool, mod string) ast.CallExpr {
} else {
name
}
if fn_name == 'json.decode' {
// Makes name_expr() parse the type (`User` in `json.decode(User, txt)`)`
p.inside_is = true
p.expr_mod = ''
}
p.check(.lpar)
args := p.call_args()
last_pos := p.tok.position()

View File

@ -32,7 +32,7 @@ mut:
mod string // current module name
attr string
attr_ctdefine string
expr_mod string
expr_mod string // for constructing full type names in parse_type()
scope &ast.Scope
global_scope &ast.Scope
imports map[string]string
@ -104,7 +104,7 @@ pub fn parse_file(path string, b_table &table.Table, comments_mode scanner.Comme
for {
if p.tok.kind == .eof {
if p.pref.is_script && !p.pref.is_test && p.mod == 'main' && !have_fn_main(stmts) {
stmts << ast.FnDecl {
stmts << ast.FnDecl{
name: 'main'
file: p.file_name
return_type: table.void_type
@ -355,7 +355,7 @@ pub fn (mut p Parser) top_stmt() ast.Stmt {
}
else {
if p.pref.is_script && !p.pref.is_test {
p.scanner.add_fn_main_and_rescan(p.tok.pos-1)
p.scanner.add_fn_main_and_rescan(p.tok.pos - 1)
p.read_first_token()
return p.top_stmt()
} else {
@ -588,8 +588,9 @@ pub fn (mut p Parser) name_expr() ast.Expr {
p.inside_is = false
// get type position before moving to next
type_pos := p.tok.position()
typ := p.parse_type()
return ast.Type{
typ: p.parse_type()
typ: typ
pos: type_pos
}
}
@ -1062,8 +1063,8 @@ fn (mut p Parser) return_stmt() ast.Return {
// left hand side of `=` or `:=` in `a,b,c := 1,2,3`
fn (mut p Parser) global_decl() ast.GlobalDecl {
if !p.pref.translated && !p.pref.is_livemain && !p.builtin_mod && !p.pref.building_v && p.mod !=
'ui' && p.mod != 'gg2' && p.mod != 'uiold' && !os.getwd().contains('/volt') && !p.pref.enable_globals {
if !p.pref.translated && !p.pref.is_livemain && !p.builtin_mod && !p.pref.building_v &&
p.mod != 'ui' && p.mod != 'gg2' && p.mod != 'uiold' && !os.getwd().contains('/volt') && !p.pref.enable_globals {
p.error('use `v --enable-globals ...` to enable globals')
}
p.next()