⚡ merge module/json.cpp into builtins
This commit is contained in:
parent
49ebdc8e19
commit
c59743b2ed
|
@ -24,6 +24,7 @@ set(NASAL_OBJECT_SOURCE_FILE
|
|||
${CMAKE_SOURCE_DIR}/src/fg_props.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/bits_lib.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/io_lib.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/json_lib.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/math_lib.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/dylib_lib.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/unix_lib.cpp
|
||||
|
@ -85,7 +86,3 @@ target_link_libraries(mat module-used-object)
|
|||
add_library(nasock SHARED ${CMAKE_SOURCE_DIR}/module/nasocket.cpp)
|
||||
target_include_directories(nasock PRIVATE ${CMAKE_SOURCE_DIR}/src)
|
||||
target_link_libraries(nasock module-used-object)
|
||||
|
||||
add_library(json SHARED ${CMAKE_SOURCE_DIR}/module/json.cpp)
|
||||
target_include_directories(json PRIVATE ${CMAKE_SOURCE_DIR}/src)
|
||||
target_link_libraries(json module-used-object)
|
||||
|
|
9
makefile
9
makefile
|
@ -32,6 +32,7 @@ NASAL_HEADER = \
|
|||
src/io_lib.h\
|
||||
src/math_lib.h\
|
||||
src/dylib_lib.h\
|
||||
src/json_lib.h\
|
||||
src/unix_lib.h\
|
||||
src/coroutine.h\
|
||||
src/repl.h
|
||||
|
@ -57,6 +58,7 @@ NASAL_OBJECT = \
|
|||
build/math_lib.o\
|
||||
build/unix_lib.o\
|
||||
build/dylib_lib.o\
|
||||
build/json_lib.o\
|
||||
build/coroutine.o\
|
||||
build/nasal_type.o\
|
||||
build/nasal_vm.o\
|
||||
|
@ -161,6 +163,13 @@ build/dylib_lib.o: \
|
|||
src/dylib_lib.h src/dylib_lib.cpp | build
|
||||
$(CXX) $(CXXFLAGS) src/dylib_lib.cpp -o build/dylib_lib.o
|
||||
|
||||
build/json_lib.o: \
|
||||
src/nasal.h\
|
||||
src/nasal_type.h\
|
||||
src/nasal_gc.h\
|
||||
src/json_lib.h src/json_lib.cpp | build
|
||||
$(CXX) $(CXXFLAGS) src/json_lib.cpp -o build/json_lib.o
|
||||
|
||||
build/unix_lib.o: \
|
||||
src/nasal.h\
|
||||
src/nasal_type.h\
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
# module json
|
||||
# 2023/11/27 ValKmjolnir
|
||||
|
||||
use std.dylib;
|
||||
use std.os;
|
||||
|
||||
var _dynamic_lib = dylib.dlopen("libjson."~(os.platform()=="windows"?"dll":"so"));
|
||||
var _stringify = _dynamic_lib.stringify;
|
||||
var _parse = _dynamic_lib.parse;
|
||||
var _get_error = _dynamic_lib.get_error;
|
||||
var _no_param_call = dylib.limitcall(0);
|
||||
var _call = dylib.limitcall(1);
|
||||
|
||||
var stringify = func(object) {
|
||||
return _call(_stringify, object);
|
||||
}
|
||||
|
||||
var parse = func(input_string) {
|
||||
return _call(_parse, input_string);
|
||||
}
|
||||
|
||||
var get_error = func() {
|
||||
return _no_param_call(_get_error);
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
.PHONY = clean all winall
|
||||
|
||||
dynamic_libs_so = libfib.so libkey.so libnasock.so libmat.so libjson.so
|
||||
dynamic_libs_dll = libfib.dll libkey.dll libnasock.dll libmat.dll libjson.dll
|
||||
dynamic_libs_so = libfib.so libkey.so libnasock.so libmat.so
|
||||
dynamic_libs_dll = libfib.dll libkey.dll libnasock.dll libmat.dll
|
||||
|
||||
used_header = ../src/nasal.h ../src/nasal_type.h ../src/nasal_gc.h
|
||||
used_object = ../build/nasal_misc.o ../build/nasal_type.o ../build/nasal_gc.o
|
||||
|
@ -66,25 +66,12 @@ libmat.dll: matrix.cpp $(used_header) $(used_object)
|
|||
@ $(CXX) -shared -o libmat.dll matrix.o $(used_object) -static
|
||||
@ del matrix.o
|
||||
|
||||
libjson.so: json.cpp $(used_header) $(used_object)
|
||||
@ echo "[Compiling] libjson.so"
|
||||
@ $(CXX) $(CXXFLAGS) json.cpp -o json.o
|
||||
@ $(CXX) -shared -o libjson.so json.o $(used_object)
|
||||
@ rm json.o
|
||||
libjson.dll: json.cpp $(used_header) $(used_object)
|
||||
@ echo [Compiling] libjson.dll
|
||||
@ $(CXX) -std=$(STD) -c -O3 json.cpp -fPIC -o json.o -static
|
||||
@ $(CXX) -shared -o libjson.dll json.o $(used_object) -static
|
||||
@ del json.o
|
||||
|
||||
clean:
|
||||
@ echo "[clean] libfib.so" && if [ -e libfib.so ]; then rm libfib.so; fi
|
||||
@ echo "[clean] libkey.so" && if [ -e libkey.so ]; then rm libkey.so; fi
|
||||
@ echo "[clean] libnasock.so" && if [ -e libnasock.so ]; then rm libnasock.so; fi
|
||||
@ echo "[clean] libmat.so" && if [ -e libmat.so ]; then rm libmat.so; fi
|
||||
@ echo "[clean] libjson.so" && if [ -e libjson.so ]; then rm libjson.so; fi
|
||||
@ echo "[clean] libfib.dll" &&if [ -e libfib.dll ]; then rm libfib.dll; fi
|
||||
@ echo "[clean] libkey.dll" &&if [ -e libkey.dll ]; then rm libkey.dll; fi
|
||||
@ echo "[clean] libnasock.dll" &&if [ -e libnasock.dll ]; then rm libnasock.dll; fi
|
||||
@ echo "[clean] libmat.dll" &&if [ -e libmat.dll ]; then rm libmat.dll; fi
|
||||
@ echo "[clean] libjson.dll" && if [ -e libjson.dll ]; then rm libjson.dll; fi
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
#include "../src/nasal.h"
|
||||
#include "../src/nasal_type.h"
|
||||
#include "../src/nasal_gc.h"
|
||||
#include "json_lib.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
|
@ -9,7 +7,7 @@
|
|||
|
||||
namespace nasal {
|
||||
|
||||
enum class token_type {
|
||||
enum class json_token_type {
|
||||
tok_eof,
|
||||
tok_lbrace,
|
||||
tok_rbrace,
|
||||
|
@ -23,26 +21,26 @@ enum class token_type {
|
|||
tok_bool
|
||||
};
|
||||
|
||||
std::string get_content(token_type type) {
|
||||
std::string get_content(json_token_type type) {
|
||||
switch(type) {
|
||||
case token_type::tok_eof: return "eof";
|
||||
case token_type::tok_lbrace: return "`{`";
|
||||
case token_type::tok_rbrace: return "`}`";
|
||||
case token_type::tok_lbrkt: return "`[`";
|
||||
case token_type::tok_rbrkt: return "`]`";
|
||||
case token_type::tok_comma: return "`,`";
|
||||
case token_type::tok_colon: return "`:`";
|
||||
case token_type::tok_str: return "string";
|
||||
case token_type::tok_num: return "number";
|
||||
case token_type::tok_id: return "identifier";
|
||||
case token_type::tok_bool: return "boolean";
|
||||
case json_token_type::tok_eof: return "eof";
|
||||
case json_token_type::tok_lbrace: return "`{`";
|
||||
case json_token_type::tok_rbrace: return "`}`";
|
||||
case json_token_type::tok_lbrkt: return "`[`";
|
||||
case json_token_type::tok_rbrkt: return "`]`";
|
||||
case json_token_type::tok_comma: return "`,`";
|
||||
case json_token_type::tok_colon: return "`:`";
|
||||
case json_token_type::tok_str: return "string";
|
||||
case json_token_type::tok_num: return "number";
|
||||
case json_token_type::tok_id: return "identifier";
|
||||
case json_token_type::tok_bool: return "boolean";
|
||||
}
|
||||
// unreachable
|
||||
return "";
|
||||
}
|
||||
|
||||
struct token {
|
||||
token_type type;
|
||||
json_token_type type;
|
||||
std::string content;
|
||||
};
|
||||
|
||||
|
@ -53,6 +51,7 @@ private:
|
|||
usize ptr = 0;
|
||||
token this_token;
|
||||
var temp_stack = nil;
|
||||
std::string info = "";
|
||||
|
||||
private:
|
||||
std::string var_generate(var&);
|
||||
|
@ -72,21 +71,20 @@ private:
|
|||
c=='-' || c=='+' || is_num(c) || is_id(c);
|
||||
}
|
||||
void next();
|
||||
void match(token_type);
|
||||
void match(json_token_type);
|
||||
void vector_member(nas_vec&, gc*);
|
||||
var vector_object_generate(gc*);
|
||||
void hash_member(nas_hash&, gc*);
|
||||
var hash_object_generate(gc*);
|
||||
void check_eof();
|
||||
static std::string& error_info() {
|
||||
static std::string info = "";
|
||||
std::string& error_info() {
|
||||
return info;
|
||||
}
|
||||
|
||||
public:
|
||||
std::string stringify(var&);
|
||||
var parse(const std::string&, gc*);
|
||||
static const std::string& get_error() { return error_info(); }
|
||||
const std::string& get_error() { return error_info(); }
|
||||
};
|
||||
|
||||
std::string json::var_generate(var& value) {
|
||||
|
@ -164,17 +162,17 @@ void json::next() {
|
|||
++ptr;
|
||||
}
|
||||
if (ptr>=text.length()) {
|
||||
this_token = {token_type::tok_eof, "eof"};
|
||||
this_token = {json_token_type::tok_eof, "eof"};
|
||||
return;
|
||||
}
|
||||
auto c = text[ptr];
|
||||
switch(c) {
|
||||
case '{': this_token = {token_type::tok_lbrace, "{"}; ++ptr; return;
|
||||
case '}': this_token = {token_type::tok_rbrace, "}"}; ++ptr; return;
|
||||
case '[': this_token = {token_type::tok_lbrkt, "["}; ++ptr; return;
|
||||
case ']': this_token = {token_type::tok_rbrkt, "]"}; ++ptr; return;
|
||||
case ',': this_token = {token_type::tok_comma, ","}; ++ptr; return;
|
||||
case ':': this_token = {token_type::tok_colon, ":"}; ++ptr; return;
|
||||
case '{': this_token = {json_token_type::tok_lbrace, "{"}; ++ptr; return;
|
||||
case '}': this_token = {json_token_type::tok_rbrace, "}"}; ++ptr; return;
|
||||
case '[': this_token = {json_token_type::tok_lbrkt, "["}; ++ptr; return;
|
||||
case ']': this_token = {json_token_type::tok_rbrkt, "]"}; ++ptr; return;
|
||||
case ',': this_token = {json_token_type::tok_comma, ","}; ++ptr; return;
|
||||
case ':': this_token = {json_token_type::tok_colon, ":"}; ++ptr; return;
|
||||
default: break;
|
||||
}
|
||||
if (is_num(c) || c=='-' || c=='+') {
|
||||
|
@ -190,7 +188,7 @@ void json::next() {
|
|||
++ptr;
|
||||
}
|
||||
--ptr;
|
||||
this_token = {token_type::tok_num, temp};
|
||||
this_token = {json_token_type::tok_num, temp};
|
||||
} else if (is_id(c)) {
|
||||
auto temp = std::string(1, c);
|
||||
++ptr;
|
||||
|
@ -200,9 +198,9 @@ void json::next() {
|
|||
}
|
||||
--ptr;
|
||||
if (temp=="true" || temp=="false") {
|
||||
this_token = {token_type::tok_bool, temp};
|
||||
this_token = {json_token_type::tok_bool, temp};
|
||||
} else {
|
||||
this_token = {token_type::tok_id, temp};
|
||||
this_token = {json_token_type::tok_id, temp};
|
||||
}
|
||||
} else if (c=='"' || c=='\'') {
|
||||
auto begin = c;
|
||||
|
@ -216,13 +214,13 @@ void json::next() {
|
|||
++ptr;
|
||||
}
|
||||
}
|
||||
this_token = {token_type::tok_str, temp};
|
||||
this_token = {json_token_type::tok_str, temp};
|
||||
}
|
||||
++ptr;
|
||||
return;
|
||||
}
|
||||
|
||||
void json::match(token_type type) {
|
||||
void json::match(json_token_type type) {
|
||||
if (this_token.type!=type) {
|
||||
error_info() += "json::parse: line " + std::to_string(line);
|
||||
error_info() += ": expect " + get_content(type) + " but get `";
|
||||
|
@ -233,14 +231,14 @@ void json::match(token_type type) {
|
|||
}
|
||||
|
||||
void json::vector_member(nas_vec& vec, gc* ngc) {
|
||||
if (this_token.type==token_type::tok_lbrace) {
|
||||
if (this_token.type==json_token_type::tok_lbrace) {
|
||||
vec.elems.push_back(hash_object_generate(ngc));
|
||||
} else if (this_token.type==token_type::tok_lbrkt) {
|
||||
} else if (this_token.type==json_token_type::tok_lbrkt) {
|
||||
vec.elems.push_back(vector_object_generate(ngc));
|
||||
} else if (this_token.type==token_type::tok_str) {
|
||||
} else if (this_token.type==json_token_type::tok_str) {
|
||||
vec.elems.push_back(ngc->newstr(this_token.content));
|
||||
next();
|
||||
} else if (this_token.type==token_type::tok_num) {
|
||||
} else if (this_token.type==json_token_type::tok_num) {
|
||||
vec.elems.push_back(var::num(str_to_num(this_token.content.c_str())));
|
||||
next();
|
||||
}
|
||||
|
@ -249,37 +247,37 @@ void json::vector_member(nas_vec& vec, gc* ngc) {
|
|||
var json::vector_object_generate(gc* ngc) {
|
||||
auto vect_object = ngc->alloc(vm_type::vm_vec);
|
||||
temp_stack.vec().elems.push_back(vect_object);
|
||||
match(token_type::tok_lbrkt);
|
||||
match(json_token_type::tok_lbrkt);
|
||||
vector_member(vect_object.vec(), ngc);
|
||||
while(this_token.type==token_type::tok_comma) {
|
||||
match(token_type::tok_comma);
|
||||
while(this_token.type==json_token_type::tok_comma) {
|
||||
match(json_token_type::tok_comma);
|
||||
vector_member(vect_object.vec(), ngc);
|
||||
}
|
||||
match(token_type::tok_rbrkt);
|
||||
match(json_token_type::tok_rbrkt);
|
||||
temp_stack.vec().elems.pop_back();
|
||||
return vect_object;
|
||||
}
|
||||
|
||||
void json::hash_member(nas_hash& hash, gc* ngc) {
|
||||
const auto name = this_token.content;
|
||||
if (this_token.type==token_type::tok_rbrace) {
|
||||
if (this_token.type==json_token_type::tok_rbrace) {
|
||||
return;
|
||||
}
|
||||
if (this_token.type==token_type::tok_str) {
|
||||
match(token_type::tok_str);
|
||||
if (this_token.type==json_token_type::tok_str) {
|
||||
match(json_token_type::tok_str);
|
||||
} else {
|
||||
match(token_type::tok_id);
|
||||
match(json_token_type::tok_id);
|
||||
}
|
||||
match(token_type::tok_colon);
|
||||
if (this_token.type==token_type::tok_lbrace) {
|
||||
match(json_token_type::tok_colon);
|
||||
if (this_token.type==json_token_type::tok_lbrace) {
|
||||
hash.elems.insert({name, hash_object_generate(ngc)});
|
||||
} else if (this_token.type==token_type::tok_lbrkt) {
|
||||
} else if (this_token.type==json_token_type::tok_lbrkt) {
|
||||
hash.elems.insert({name, vector_object_generate(ngc)});
|
||||
} else if (this_token.type==token_type::tok_str ||
|
||||
this_token.type==token_type::tok_bool) {
|
||||
} else if (this_token.type==json_token_type::tok_str ||
|
||||
this_token.type==json_token_type::tok_bool) {
|
||||
hash.elems.insert({name, ngc->newstr(this_token.content)});
|
||||
next();
|
||||
} else if (this_token.type==token_type::tok_num) {
|
||||
} else if (this_token.type==json_token_type::tok_num) {
|
||||
hash.elems.insert({name, var::num(str_to_num(this_token.content.c_str()))});
|
||||
next();
|
||||
}
|
||||
|
@ -288,91 +286,106 @@ void json::hash_member(nas_hash& hash, gc* ngc) {
|
|||
var json::hash_object_generate(gc* ngc) {
|
||||
auto hash_object = ngc->alloc(vm_type::vm_hash);
|
||||
temp_stack.vec().elems.push_back(hash_object);
|
||||
match(token_type::tok_lbrace);
|
||||
match(json_token_type::tok_lbrace);
|
||||
hash_member(hash_object.hash(), ngc);
|
||||
while(this_token.type==token_type::tok_comma) {
|
||||
match(token_type::tok_comma);
|
||||
while(this_token.type==json_token_type::tok_comma) {
|
||||
match(json_token_type::tok_comma);
|
||||
hash_member(hash_object.hash(), ngc);
|
||||
}
|
||||
match(token_type::tok_rbrace);
|
||||
match(json_token_type::tok_rbrace);
|
||||
temp_stack.vec().elems.pop_back();
|
||||
return hash_object;
|
||||
}
|
||||
|
||||
void json::check_eof() {
|
||||
next();
|
||||
if (this_token.type==token_type::tok_eof) {
|
||||
if (this_token.type==json_token_type::tok_eof) {
|
||||
return;
|
||||
}
|
||||
while (this_token.type!=token_type::tok_eof) {
|
||||
while (this_token.type!=json_token_type::tok_eof) {
|
||||
error_info() += "json::parse: line " + std::to_string(line);
|
||||
error_info() += ": expect " + get_content(token_type::tok_eof);
|
||||
error_info() += ": expect " + get_content(json_token_type::tok_eof);
|
||||
error_info() += " but get `" + this_token.content + "`.\n";
|
||||
next();
|
||||
}
|
||||
}
|
||||
|
||||
var json::parse(const std::string& input, gc* ngc) {
|
||||
usize parse_error = 0;
|
||||
usize line = 1;
|
||||
usize ptr = 0;
|
||||
this_token = {token_type::tok_eof, ""};
|
||||
line = 1;
|
||||
ptr = 0;
|
||||
this_token = {json_token_type::tok_eof, ""};
|
||||
error_info() = "";
|
||||
|
||||
if (input.empty()) {
|
||||
error_info() += "json::parse: empty string.\n";
|
||||
++parse_error;
|
||||
return nil;
|
||||
}
|
||||
text = input;
|
||||
next();
|
||||
if (this_token.type==token_type::tok_lbrkt) {
|
||||
if (this_token.type==json_token_type::tok_lbrkt) {
|
||||
ngc->temp = temp_stack = ngc->alloc(vm_type::vm_vec);
|
||||
auto result = vector_object_generate(ngc);
|
||||
check_eof();
|
||||
ngc->temp = nil;
|
||||
temp_stack = nil;
|
||||
ngc->temp = temp_stack = nil;
|
||||
return result;
|
||||
} else {
|
||||
ngc->temp = temp_stack = ngc->alloc(vm_type::vm_vec);
|
||||
auto result = hash_object_generate(ngc);
|
||||
check_eof();
|
||||
ngc->temp = nil;
|
||||
temp_stack = nil;
|
||||
ngc->temp = temp_stack = nil;
|
||||
return result;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
var stringify(var* args, usize size, gc* ngc) {
|
||||
auto object = args[0];
|
||||
if (!object.is_vec() && !object.is_hash()) {
|
||||
return nas_err("json::stringify", "must use hashmap or vector");
|
||||
void json_destructor(void* ptr) {
|
||||
delete static_cast<json*>(ptr);
|
||||
}
|
||||
|
||||
var builtin_json_new(context* ctx, gc* ngc) {
|
||||
var res = ngc->alloc(vm_type::vm_ghost);
|
||||
res.ghost().set("nasal::json", json_destructor, nullptr, new json);
|
||||
return res;
|
||||
}
|
||||
|
||||
var builtin_json_stringify(context* ctx, gc* ngc) {
|
||||
auto json_object = ctx->localr[1];
|
||||
auto object = ctx->localr[2];
|
||||
if (!json_object.object_check("nasal::json")) {
|
||||
return nas_err("json::stringify", "expect a json object.");
|
||||
}
|
||||
return ngc->newstr(json().stringify(object));
|
||||
auto json_ptr = static_cast<json*>(json_object.ghost().pointer);
|
||||
return ngc->newstr(json_ptr->stringify(object));
|
||||
}
|
||||
|
||||
var parse(var* args, usize size, gc* ngc) {
|
||||
auto input = args[0];
|
||||
if (!input.is_str()) {
|
||||
return nas_err("json::parse", "must use string");
|
||||
var builtin_json_parse(context* ctx, gc* ngc) {
|
||||
auto json_object = ctx->localr[1];
|
||||
auto input_string = ctx->localr[2];
|
||||
if (!json_object.object_check("nasal::json")) {
|
||||
return nas_err("json::parse", "expect a json object.");
|
||||
}
|
||||
return json().parse(input.str(), ngc);
|
||||
if (!input_string.is_str()) {
|
||||
return nas_err("json::parse", "require string as the input.");
|
||||
}
|
||||
auto json_ptr = static_cast<json*>(json_object.ghost().pointer);
|
||||
return json_ptr->parse(input_string.str(), ngc);
|
||||
}
|
||||
|
||||
var get_error(var* args, usize size, gc* ngc) {
|
||||
return ngc->newstr(json::get_error());
|
||||
var builtin_json_get_error(context* ctx, gc* ngc) {
|
||||
auto json_object = ctx->localr[1];
|
||||
if (!json_object.object_check("nasal::json")) {
|
||||
return nas_err("json::get_error", "expect a json object.");
|
||||
}
|
||||
auto json_ptr = static_cast<json*>(json_object.ghost().pointer);
|
||||
return ngc->newstr(json_ptr->get_error());
|
||||
}
|
||||
|
||||
module_func_info func_tbl[] = {
|
||||
{"stringify", stringify},
|
||||
{"parse", parse},
|
||||
{"get_error", get_error},
|
||||
nasal_builtin_table json_lib_native[] = {
|
||||
{"_json_new", builtin_json_new},
|
||||
{"_json_stringify", builtin_json_stringify},
|
||||
{"_json_parse", builtin_json_parse},
|
||||
{"_json_get_error", builtin_json_get_error},
|
||||
{nullptr, nullptr}
|
||||
};
|
||||
|
||||
NASAL_EXTERN module_func_info* get() {
|
||||
return func_tbl;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
#include "nasal.h"
|
||||
#include "nasal_gc.h"
|
||||
#include "nasal_builtin.h"
|
||||
|
||||
namespace nasal {
|
||||
|
||||
var builtin_json_new(context*, gc*);
|
||||
var builtin_json_stringify(context*, gc*);
|
||||
var builtin_json_parse(context*, gc*);
|
||||
var builtin_json_get_error(context*, gc*);
|
||||
|
||||
extern nasal_builtin_table json_lib_native[];
|
||||
|
||||
}
|
|
@ -30,6 +30,7 @@ void codegen::init_native_function() {
|
|||
load_native_function_table(flight_gear_native);
|
||||
load_native_function_table(dylib_lib_native);
|
||||
load_native_function_table(unix_lib_native);
|
||||
load_native_function_table(json_lib_native);
|
||||
}
|
||||
|
||||
void codegen::check_id_exist(identifier* node) {
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "math_lib.h"
|
||||
#include "fg_props.h"
|
||||
#include "io_lib.h"
|
||||
#include "json_lib.h"
|
||||
#include "dylib_lib.h"
|
||||
#include "unix_lib.h"
|
||||
|
||||
|
|
337
std/json.nas
337
std/json.nas
|
@ -1,329 +1,30 @@
|
|||
# lib json.nas
|
||||
# 2021 ValKmjolnir
|
||||
|
||||
var (
|
||||
_j_eof,
|
||||
_j_lbrace,
|
||||
_j_rbrace,
|
||||
_j_lbrkt,
|
||||
_j_rbrkt,
|
||||
_j_comma,
|
||||
_j_colon,
|
||||
_j_str,
|
||||
_j_num,
|
||||
_j_id,
|
||||
_j_bool
|
||||
) = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
|
||||
|
||||
var _j_content = [
|
||||
"eof",
|
||||
"`{`",
|
||||
"`}`",
|
||||
"`[`",
|
||||
"`]`",
|
||||
"`,`",
|
||||
"`:`",
|
||||
"string",
|
||||
"number",
|
||||
"identifier",
|
||||
"boolean"
|
||||
];
|
||||
|
||||
var _parse_error = 0;
|
||||
|
||||
var parse = func() {
|
||||
var text = "";
|
||||
var line = 1;
|
||||
var text_size = 0;
|
||||
var ptr = 0;
|
||||
var token = {
|
||||
content: "",
|
||||
type: ""
|
||||
};
|
||||
|
||||
var init = func() {
|
||||
text = "";
|
||||
line = 1;
|
||||
text_size = 0;
|
||||
ptr = 0;
|
||||
token = {
|
||||
content: "",
|
||||
type: ""
|
||||
};
|
||||
}
|
||||
|
||||
var isnum = func(c) {
|
||||
return '0'<=c and c<='9';
|
||||
}
|
||||
|
||||
var isid = func(c) {
|
||||
var tmp = c[0];
|
||||
return ('a'[0]<=tmp and tmp<='z'[0]) or
|
||||
('A'[0]<=tmp and tmp<='Z'[0]) or
|
||||
c=='_';
|
||||
}
|
||||
|
||||
var check = func() {
|
||||
var c = char(text[ptr]);
|
||||
return (
|
||||
c=='{' or c=='}' or
|
||||
c=='[' or c==']' or
|
||||
c==',' or c==':' or
|
||||
c=='\"' or c=='\'' or
|
||||
isnum(c) or isid(c)
|
||||
);
|
||||
}
|
||||
|
||||
var get = func(str) {
|
||||
init();
|
||||
if (!size(str)) {
|
||||
println("json::parse: empty string");
|
||||
_parse_error += 1;
|
||||
str = "[]";
|
||||
}
|
||||
text = str;
|
||||
text_size = size(text);
|
||||
return;
|
||||
}
|
||||
|
||||
var next = func() {
|
||||
while(ptr<text_size and !check()) {
|
||||
if (char(text[ptr])=='\n') {
|
||||
line += 1;
|
||||
}
|
||||
ptr += 1;
|
||||
}
|
||||
if (ptr>=text_size) {
|
||||
token.content = "eof";
|
||||
token.type = _j_eof;
|
||||
return;
|
||||
}
|
||||
|
||||
var c = char(text[ptr]);
|
||||
if (c=='{') {
|
||||
token.content = '{';
|
||||
token.type = _j_lbrace;
|
||||
} elsif (c=='}') {
|
||||
token.content = '}';
|
||||
token.type = _j_rbrace;
|
||||
} elsif (c=='[') {
|
||||
token.content = '[';
|
||||
token.type = _j_lbrkt;
|
||||
} elsif (c==']') {
|
||||
token.content = ']';
|
||||
token.type = _j_rbrkt;
|
||||
} elsif (c==',') {
|
||||
token.content = ',';
|
||||
token.type = _j_comma;
|
||||
} elsif (c==':') {
|
||||
token.content = ':';
|
||||
token.type = _j_colon;
|
||||
} elsif (c=='\"' or c=='\'') {
|
||||
var strbegin = c;
|
||||
var s = "";
|
||||
ptr += 1;
|
||||
while(ptr<text_size and char(text[ptr])!=strbegin) {
|
||||
s ~= char(text[ptr]);
|
||||
ptr += 1;
|
||||
if (char(text[ptr-1])=="\\" and ptr<text_size) {
|
||||
s ~= char(text[ptr]);
|
||||
ptr += 1;
|
||||
}
|
||||
}
|
||||
token.content=s;
|
||||
token.type=_j_str;
|
||||
} elsif (isnum(c)) {
|
||||
var s = c;
|
||||
ptr += 1;
|
||||
while(ptr<text_size and ((
|
||||
isnum(char(text[ptr])) or
|
||||
char(text[ptr])=='.' or
|
||||
char(text[ptr])=='e' or
|
||||
char(text[ptr])=='-' or
|
||||
char(text[ptr])=='+'))
|
||||
) {
|
||||
s ~= char(text[ptr]);
|
||||
ptr += 1;
|
||||
}
|
||||
ptr -= 1;
|
||||
token.content = num(s);
|
||||
token.type = _j_num;
|
||||
} elsif (isid(c)) {
|
||||
var s = c;
|
||||
ptr += 1;
|
||||
while(ptr<text_size and (isid(char(text[ptr])) or isnum(char(text[ptr])))) {
|
||||
s ~= char(text[ptr]);
|
||||
ptr += 1;
|
||||
}
|
||||
ptr -= 1;
|
||||
token.content = s;
|
||||
token.type = _j_id;
|
||||
if (s=="true" or s=="false") {
|
||||
token.type = _j_bool;
|
||||
}
|
||||
}
|
||||
ptr += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
var match = func(type) {
|
||||
if (token.type!=type) {
|
||||
println("json::parse: line ",line,": expect ",_j_content[type]," but get `",token.content,"`.");
|
||||
_parse_error += 1;
|
||||
}
|
||||
next();
|
||||
return;
|
||||
}
|
||||
|
||||
var member = func(hash) {
|
||||
var name = token.content;
|
||||
if (token.type==_j_rbrace) {
|
||||
return;
|
||||
}
|
||||
if (token.type==_j_str) {
|
||||
match(_j_str);
|
||||
} else {
|
||||
match(_j_id);
|
||||
}
|
||||
match(_j_colon);
|
||||
if (token.type==_j_lbrace) {
|
||||
hash[name] = hash_gen();
|
||||
} elsif (token.type==_j_lbrkt) {
|
||||
hash[name] = vec_gen();
|
||||
} elsif (token.type==_j_str or token.type==_j_num or token.type==_j_bool) {
|
||||
hash[name] = token.content;
|
||||
next();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var hash_gen = func() {
|
||||
var hash = {};
|
||||
match(_j_lbrace);
|
||||
member(hash);
|
||||
while(token.type==_j_comma) {
|
||||
match(_j_comma);
|
||||
member(hash);
|
||||
}
|
||||
match(_j_rbrace);
|
||||
return hash;
|
||||
}
|
||||
|
||||
var vec_gen = func() {
|
||||
var vec = [];
|
||||
match(_j_lbrkt);
|
||||
if (token.type==_j_lbrace) {
|
||||
append(vec, hash_gen());
|
||||
} elsif (token.type==_j_lbrkt) {
|
||||
append(vec, vec_gen());
|
||||
} elsif (token.type==_j_str or token.type==_j_num) {
|
||||
append(vec, token.content);
|
||||
next();
|
||||
}
|
||||
while(token.type==_j_comma) {
|
||||
match(_j_comma);
|
||||
if (token.type==_j_lbrace) {
|
||||
append(vec, hash_gen());
|
||||
} elsif (token.type==_j_lbrkt) {
|
||||
append(vec, vec_gen());
|
||||
} elsif (token.type==_j_str or token.type==_j_num) {
|
||||
append(vec, token.content);
|
||||
next();
|
||||
}
|
||||
}
|
||||
match(_j_rbrkt);
|
||||
return vec;
|
||||
}
|
||||
|
||||
return func(source) {
|
||||
_parse_error = 0;
|
||||
if (typeof(source)!="str") {
|
||||
println("json::parse: must use string but get", typeof(str));
|
||||
_parse_error += 1;
|
||||
return [];
|
||||
}
|
||||
|
||||
get(source);
|
||||
next();
|
||||
|
||||
if (token.type==_j_lbrkt) {
|
||||
var res = vec_gen();
|
||||
} else {
|
||||
var res = hash_gen();
|
||||
}
|
||||
|
||||
init();
|
||||
return res;
|
||||
}
|
||||
var _json = func() {
|
||||
return _json_new();
|
||||
}();
|
||||
|
||||
var _stringify = func(json_object, object) {
|
||||
return _json_stringify(json_object, object);
|
||||
}
|
||||
|
||||
var _parse = func(json_object, input_string) {
|
||||
return _json_parse(json_object, input_string);
|
||||
}
|
||||
|
||||
var _get_error = func(json_object) {
|
||||
return _json_get_error(json_object);
|
||||
}
|
||||
|
||||
var stringify = func(object) {
|
||||
_parse_error = 0;
|
||||
var object_type = typeof(object);
|
||||
if (object_type!="hash" and object_type!="vec" and object_type!="namespace") {
|
||||
_parse_error += 1;
|
||||
println("json::stringify: must use hashmap or vector, but get ", typeof(object));
|
||||
return "[]";
|
||||
}
|
||||
return _stringify(_json, object);
|
||||
}
|
||||
|
||||
var s = "";
|
||||
var gen = func(elem) {
|
||||
var t = typeof(elem);
|
||||
if (t=="num") {
|
||||
s ~= str(elem);
|
||||
} elsif (t=="str") {
|
||||
s ~= '"'~elem~'"';
|
||||
} elsif (t=="vec") {
|
||||
vgen(elem);
|
||||
} elsif (t=="hash") {
|
||||
hgen(elem);
|
||||
} else {
|
||||
s ~= '"undefined"';
|
||||
}
|
||||
}
|
||||
|
||||
var vgen = func(v) {
|
||||
s ~= "[";
|
||||
var vsize = size(v);
|
||||
for(var i = 0; i<vsize; i += 1) {
|
||||
gen(v[i]);
|
||||
if (i!=vsize-1) {
|
||||
s~=",";
|
||||
}
|
||||
}
|
||||
s ~= "]";
|
||||
}
|
||||
|
||||
var hgen = func(h) {
|
||||
s ~= "{";
|
||||
var k = keys(h);
|
||||
var vsize = size(k);
|
||||
for(var i = 0; i<vsize; i += 1) {
|
||||
s ~= "\""~k[i]~"\":";
|
||||
gen(h[k[i]]);
|
||||
if (i!=vsize-1) {
|
||||
s ~= ",";
|
||||
}
|
||||
}
|
||||
s ~= "}";
|
||||
}
|
||||
|
||||
if (typeof(object)=="vec") {
|
||||
vgen(object);
|
||||
} else {
|
||||
hgen(object);
|
||||
}
|
||||
return s;
|
||||
var parse = func(input_string) {
|
||||
return _parse(_json, input_string);
|
||||
}
|
||||
|
||||
var get_error = func() {
|
||||
return _parse_error;
|
||||
}
|
||||
|
||||
var check_error = func() {
|
||||
if (_parse_error==0) {
|
||||
return;
|
||||
}
|
||||
println("json: encounter ", _parse_error, " error(s), stop.");
|
||||
exit(-1);
|
||||
return _get_error(_json);
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
# 2023/11/06 ValKmjolnir
|
||||
|
||||
use module.libsock;
|
||||
use module.libjson;
|
||||
use std.json;
|
||||
use std.os;
|
||||
use std.unix;
|
||||
|
||||
|
@ -87,9 +87,9 @@ var new = func(hostname, port) {
|
|||
var data = substr(total_source, begin_position, length);
|
||||
|
||||
# parse this json and return
|
||||
var props = libjson.parse(data);
|
||||
if (size(libjson.get_error())>0) {
|
||||
println("encounter error when parsing \"", path, "\":\n", libjson.get_error());
|
||||
var props = json.parse(data);
|
||||
if (size(json.get_error())>0) {
|
||||
println("encounter error when parsing \"", path, "\":\n", json.get_error());
|
||||
logprint(LOG_DEBUG, _raw_str(data));
|
||||
return {path: path};
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
# available in C++; just use node.getNode(path).whatever() instead.
|
||||
#
|
||||
use std.math;
|
||||
use std.string;
|
||||
|
||||
var _new = func {
|
||||
return {
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use std.json;
|
||||
use module.libjson;
|
||||
use std.process_bar;
|
||||
|
||||
var ss = json.stringify({
|
||||
|
@ -19,7 +18,6 @@ var ss = json.stringify({
|
|||
|
||||
println(ss, "\n");
|
||||
println(json.parse(ss), "\n");
|
||||
println(libjson.parse(ss), "\n");
|
||||
|
||||
var ss = json.stringify([{
|
||||
vec:[0,1,2,3],
|
||||
|
@ -37,11 +35,10 @@ var ss = json.stringify([{
|
|||
|
||||
println(ss, "\n");
|
||||
println(json.parse(ss), "\n");
|
||||
println(libjson.parse(ss), "\n");
|
||||
|
||||
var test_func = func(input_string) {
|
||||
var result = libjson.parse(input_string);
|
||||
var errno = libjson.get_error();
|
||||
var result = json.parse(input_string);
|
||||
var errno = json.get_error();
|
||||
if (!size(errno)) {
|
||||
println("\e[92;1msuccess\e[0m:");
|
||||
println(" ", result);
|
||||
|
@ -60,7 +57,7 @@ test_func("{\"1\":1}");
|
|||
test_func("[[[}]]]");
|
||||
test_func("=-==_+_+_+");
|
||||
test_func("123");
|
||||
test_func(libjson.stringify({
|
||||
test_func(json.stringify({
|
||||
a: 0,
|
||||
b: nil,
|
||||
c: "this is a string",
|
||||
|
@ -100,8 +97,8 @@ var test_json = func(json) {
|
|||
};
|
||||
|
||||
var stamp = maketimestamp();
|
||||
test_json(libjson);
|
||||
println("time usage: ", stamp.elapsedUSec()/1000, " ms");
|
||||
stamp.stamp();
|
||||
test_json(json);
|
||||
println("time usage: ", stamp.elapsedUSec()/1000, " ms");
|
||||
for(var i = 0; i<10; i += 1) {
|
||||
stamp.stamp();
|
||||
test_json(json);
|
||||
println("time usage: ", stamp.elapsedUSec()/1000, " ms");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue