Added legacy-style json api wrapper
This commit is contained in:
parent
fc9ce8b8e4
commit
d0c62157b4
@ -17,6 +17,8 @@ const AstGen = @import("stage2/AstGen.zig");
|
||||
const Zir = @import("stage2/Zir.zig");
|
||||
const InternPool = @import("analyser/InternPool.zig");
|
||||
|
||||
const legacy_json = @import("legacy_json.zig");
|
||||
|
||||
const DocumentStore = @This();
|
||||
|
||||
pub const Uri = []const u8;
|
||||
@ -43,10 +45,10 @@ const BuildFile = struct {
|
||||
|
||||
pub fn deinit(self: *BuildFile, allocator: std.mem.Allocator) void {
|
||||
allocator.free(self.uri);
|
||||
std.json.parseFree(BuildConfig, allocator, self.config);
|
||||
legacy_json.parseFree(BuildConfig, allocator, self.config);
|
||||
if (self.builtin_uri) |builtin_uri| allocator.free(builtin_uri);
|
||||
if (self.build_associated_config) |cfg| {
|
||||
std.json.parseFree(BuildAssociatedConfig, allocator, cfg);
|
||||
legacy_json.parseFree(BuildAssociatedConfig, allocator, cfg);
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -301,7 +303,7 @@ pub fn applySave(self: *DocumentStore, handle: *const Handle) !void {
|
||||
return;
|
||||
};
|
||||
|
||||
std.json.parseFree(BuildConfig, self.allocator, build_file.config);
|
||||
legacy_json.parseFree(BuildConfig, self.allocator, build_file.config);
|
||||
build_file.config = build_config;
|
||||
}
|
||||
}
|
||||
@ -326,7 +328,7 @@ pub fn invalidateBuildFiles(self: *DocumentStore) void {
|
||||
return;
|
||||
};
|
||||
|
||||
std.json.parseFree(BuildConfig, self.allocator, build_file.config);
|
||||
legacy_json.parseFree(BuildConfig, self.allocator, build_file.config);
|
||||
build_file.config = build_config;
|
||||
}
|
||||
}
|
||||
@ -457,7 +459,7 @@ pub fn isInStd(uri: Uri) bool {
|
||||
}
|
||||
|
||||
/// looks for a `zls.build.json` file in the build file directory
|
||||
/// has to be freed with `std.json.parseFree`
|
||||
/// has to be freed with `json_compat.parseFree`
|
||||
fn loadBuildAssociatedConfiguration(allocator: std.mem.Allocator, build_file: BuildFile) !BuildAssociatedConfig {
|
||||
const tracy_zone = tracy.trace(@src());
|
||||
defer tracy_zone.end();
|
||||
@ -473,7 +475,7 @@ fn loadBuildAssociatedConfiguration(allocator: std.mem.Allocator, build_file: Bu
|
||||
const file_buf = try config_file.readToEndAlloc(allocator, std.math.maxInt(usize));
|
||||
defer allocator.free(file_buf);
|
||||
|
||||
return try std.json.parseFromSlice(BuildAssociatedConfig, allocator, file_buf, .{});
|
||||
return try legacy_json.parseFromSlice(BuildAssociatedConfig, allocator, file_buf, .{});
|
||||
}
|
||||
|
||||
/// Caller owns returned memory!
|
||||
@ -510,7 +512,7 @@ pub fn executeBuildRunner(
|
||||
}
|
||||
|
||||
/// Runs the build.zig and extracts include directories and packages
|
||||
/// Has to be freed with `std.json.parseFree`
|
||||
/// Has to be freed with `json_compat.parseFree`
|
||||
pub fn loadBuildConfiguration(
|
||||
allocator: std.mem.Allocator,
|
||||
build_file: BuildFile,
|
||||
@ -564,13 +566,13 @@ pub fn loadBuildConfiguration(
|
||||
// to the BuildConfig type
|
||||
.ignore_unknown_fields = true,
|
||||
};
|
||||
const build_config = std.json.parseFromSlice(
|
||||
const build_config = legacy_json.parseFromSlice(
|
||||
BuildConfig,
|
||||
allocator,
|
||||
zig_run_result.stdout,
|
||||
parse_options,
|
||||
) catch return error.RunFailed;
|
||||
errdefer std.json.parseFree(BuildConfig, allocator, build_config);
|
||||
errdefer legacy_json.parseFree(BuildConfig, allocator, build_config);
|
||||
|
||||
for (build_config.packages) |*pkg| {
|
||||
const pkg_abs_path = try std.fs.path.resolve(allocator, &[_][]const u8{ build_file_path, "..", pkg.path });
|
||||
|
@ -1286,12 +1286,12 @@ const Message = union(enum) {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn fromJsonValueTree(tree: std.json.ValueTree) error{InvalidRequest}!Message {
|
||||
pub fn fromJsonValueTree(root: std.json.Value) error{InvalidRequest}!Message {
|
||||
const tracy_zone = tracy.trace(@src());
|
||||
defer tracy_zone.end();
|
||||
|
||||
if (tree.root != .object) return error.InvalidRequest;
|
||||
const object = tree.root.object;
|
||||
if (root != .object) return error.InvalidRequest;
|
||||
const object = root.object;
|
||||
|
||||
if (object.get("id")) |id_obj| {
|
||||
comptime std.debug.assert(!tres.isAllocatorRequired(types.RequestId));
|
||||
@ -1348,16 +1348,13 @@ pub fn processJsonRpc(
|
||||
const tracy_zone = tracy.trace(@src());
|
||||
defer tracy_zone.end();
|
||||
|
||||
var parser = std.json.Parser.init(server.arena.allocator(), .alloc_always);
|
||||
defer parser.deinit();
|
||||
|
||||
var tree = parser.parse(json) catch |err| {
|
||||
var tree = std.json.parseFromSlice(std.json.Value, server.arena.allocator(), json, .{}) catch |err| {
|
||||
log.err("failed to parse message: {}", .{err});
|
||||
return; // maybe panic?
|
||||
};
|
||||
defer tree.deinit();
|
||||
|
||||
const message = Message.fromJsonValueTree(tree) catch |err| {
|
||||
const message = Message.fromJsonValueTree(tree.value) catch |err| {
|
||||
log.err("failed to parse message: {}", .{err});
|
||||
return; // maybe panic?
|
||||
};
|
||||
|
@ -10,6 +10,8 @@ const offsets = @import("offsets.zig");
|
||||
|
||||
const logger = std.log.scoped(.zls_config);
|
||||
|
||||
const legacy_json = @import("legacy_json.zig");
|
||||
|
||||
pub fn loadFromFile(allocator: std.mem.Allocator, file_path: []const u8) ?Config {
|
||||
const tracy_zone = tracy.trace(@src());
|
||||
defer tracy_zone.end();
|
||||
@ -34,7 +36,7 @@ pub fn loadFromFile(allocator: std.mem.Allocator, file_path: []const u8) ?Config
|
||||
scanner.enableDiagnostics(&parse_diagnostics);
|
||||
|
||||
// TODO: report errors using "textDocument/publishDiagnostics"
|
||||
var config = std.json.parseFromTokenSource(Config, allocator, &scanner, parse_options) catch |err| {
|
||||
var config = legacy_json.parseFromTokenSource(Config, allocator, &scanner, parse_options) catch |err| {
|
||||
logger.warn(
|
||||
"{s}:{d}:{d}: Error while parsing configuration file {}",
|
||||
.{ file_path, parse_diagnostics.getLine(), parse_diagnostics.getColumn(), err },
|
||||
@ -82,7 +84,7 @@ pub fn configChanged(config: *Config, runtime_zig_version: *?ZigVersionWrapper,
|
||||
logger.info("Using zig executable '{s}'", .{exe_path});
|
||||
|
||||
var env = getZigEnv(allocator, exe_path) orelse break :blk;
|
||||
defer std.json.parseFree(Env, allocator, env);
|
||||
defer legacy_json.parseFree(Env, allocator, env);
|
||||
|
||||
if (config.zig_lib_path) |lib_path| allocator.free(lib_path);
|
||||
// Make sure the path is absolute
|
||||
@ -177,7 +179,7 @@ pub const Env = struct {
|
||||
target: ?[]const u8 = null,
|
||||
};
|
||||
|
||||
/// result has to be freed with `std.json.parseFree`
|
||||
/// result has to be freed with `json_compat.parseFree`
|
||||
pub fn getZigEnv(allocator: std.mem.Allocator, zig_exe_path: []const u8) ?Env {
|
||||
const zig_env_result = std.ChildProcess.exec(.{
|
||||
.allocator = allocator,
|
||||
@ -202,7 +204,7 @@ pub fn getZigEnv(allocator: std.mem.Allocator, zig_exe_path: []const u8) ?Env {
|
||||
else => logger.err("zig env invocation failed", .{}),
|
||||
}
|
||||
|
||||
return std.json.parseFromSlice(
|
||||
return legacy_json.parseFromSlice(
|
||||
Env,
|
||||
allocator,
|
||||
zig_env_result.stdout,
|
||||
|
176
src/legacy_json.zig
Normal file
176
src/legacy_json.zig
Normal file
@ -0,0 +1,176 @@
|
||||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const ParseError = std.json.ParseError;
|
||||
const Scanner = std.json.Scanner;
|
||||
const ParseOptions = std.json.ParseOptions;
|
||||
pub fn parseFromSlice(
|
||||
comptime T: type,
|
||||
allocator: Allocator,
|
||||
s: []const u8,
|
||||
options: ParseOptions,
|
||||
) (ParseError(Scanner) || std.mem.Allocator.Error)!T {
|
||||
const json = try std.json.parseFromSlice(T, allocator, s, options);
|
||||
defer json.deinit();
|
||||
return deepCopy(T, allocator, json.value);
|
||||
}
|
||||
pub fn parseFromTokenSource(
|
||||
comptime T: type,
|
||||
allocator: Allocator,
|
||||
scanner_or_reader: anytype,
|
||||
options: ParseOptions,
|
||||
) (ParseError(@TypeOf(scanner_or_reader.*)) || std.mem.Allocator.Error)!T {
|
||||
const json = try std.json.parseFromTokenSource(T, allocator, scanner_or_reader, options);
|
||||
defer json.deinit();
|
||||
return try deepCopy(T, allocator, json.value);
|
||||
}
|
||||
|
||||
/// Recursively copies a struct, reallocating pointers and slices
|
||||
fn deepCopy(comptime T: type, allocator: Allocator, value: T) !T {
|
||||
switch (@typeInfo(T)) {
|
||||
.Bool, .Float, .ComptimeFloat, .Int, .ComptimeInt, .Enum => return value,
|
||||
.Optional => {
|
||||
if (value) |v| {
|
||||
return try deepCopy(@TypeOf(v), allocator, v);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
.Union => |unionInfo| {
|
||||
if (unionInfo.tag_type) |UnionTagType| {
|
||||
inline for (unionInfo.fields) |u_field| {
|
||||
if (value == @field(UnionTagType, u_field.name)) {
|
||||
return @unionInit(T, u_field.name, deepCopy(u_field.type, allocator, @field(value, u_field.name)));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
unreachable;
|
||||
}
|
||||
},
|
||||
.Struct => |structInfo| {
|
||||
var result: T = undefined;
|
||||
inline for (structInfo.fields) |field| {
|
||||
if (field.is_comptime) @compileError("comptime fields are not supported: " ++ @typeName(T) ++ "." ++ field.name);
|
||||
const field_value = @field(value, field.name);
|
||||
@field(result, field.name) = try deepCopy(@TypeOf(field_value), allocator, field_value);
|
||||
}
|
||||
return result;
|
||||
},
|
||||
.Array, .Vector => {
|
||||
var r: T = undefined;
|
||||
for (value, 0..) |v, i| {
|
||||
r[i] = try deepCopy(@TypeOf(v), allocator, v);
|
||||
}
|
||||
return r;
|
||||
},
|
||||
.Pointer => |ptrInfo| {
|
||||
switch (ptrInfo.size) {
|
||||
.One => {
|
||||
const r: *ptrInfo.child = try allocator.create(ptrInfo.child);
|
||||
errdefer allocator.destroy(r);
|
||||
r.* = try deepCopy(ptrInfo.child, allocator, value.*);
|
||||
return r;
|
||||
},
|
||||
.Slice => {
|
||||
var result = std.ArrayList(ptrInfo.child).init(allocator);
|
||||
errdefer result.deinit();
|
||||
for (value) |v| {
|
||||
try result.append(try deepCopy(ptrInfo.child, allocator, v));
|
||||
}
|
||||
if (ptrInfo.sentinel) |some| {
|
||||
const sentinel_value = @ptrCast(*align(1) const ptrInfo.child, some).*;
|
||||
return try result.toOwnedSliceSentinel(sentinel_value);
|
||||
}
|
||||
return try result.toOwnedSlice();
|
||||
},
|
||||
|
||||
else => @compileError("Unable to deepCopy type '" ++ @typeName(T) ++ "'"),
|
||||
}
|
||||
},
|
||||
|
||||
else => @compileError("Unable to deepCopy type '" ++ @typeName(T) ++ "'"),
|
||||
}
|
||||
}
|
||||
/// Releases resources created by parseFromSlice() or parseFromTokenSource().
|
||||
pub fn parseFree(comptime T: type, allocator: Allocator, value: T) void {
|
||||
switch (@typeInfo(T)) {
|
||||
.Bool, .Float, .ComptimeFloat, .Int, .ComptimeInt, .Enum => {},
|
||||
.Optional => {
|
||||
if (value) |v| {
|
||||
return parseFree(@TypeOf(v), allocator, v);
|
||||
}
|
||||
},
|
||||
.Union => |unionInfo| {
|
||||
if (unionInfo.tag_type) |UnionTagType| {
|
||||
inline for (unionInfo.fields) |u_field| {
|
||||
if (value == @field(UnionTagType, u_field.name)) {
|
||||
parseFree(u_field.type, allocator, @field(value, u_field.name));
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
unreachable;
|
||||
}
|
||||
},
|
||||
.Struct => |structInfo| {
|
||||
inline for (structInfo.fields) |field| {
|
||||
var should_free = true;
|
||||
if (field.default_value) |default| {
|
||||
switch (@typeInfo(field.type)) {
|
||||
// We must not attempt to free pointers to struct default values
|
||||
.Pointer => |fieldPtrInfo| {
|
||||
const field_value = @field(value, field.name);
|
||||
const field_ptr = switch (fieldPtrInfo.size) {
|
||||
.One => field_value,
|
||||
.Slice => field_value.ptr,
|
||||
else => unreachable, // Other pointer types are not parseable
|
||||
};
|
||||
const field_addr = @intFromPtr(field_ptr);
|
||||
|
||||
const casted_default = @ptrCast(*const field.type, @alignCast(@alignOf(field.type), default)).*;
|
||||
const default_ptr = switch (fieldPtrInfo.size) {
|
||||
.One => casted_default,
|
||||
.Slice => casted_default.ptr,
|
||||
else => unreachable, // Other pointer types are not parseable
|
||||
};
|
||||
const default_addr = @intFromPtr(default_ptr);
|
||||
|
||||
if (field_addr == default_addr) {
|
||||
should_free = false;
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
if (should_free) {
|
||||
parseFree(field.type, allocator, @field(value, field.name));
|
||||
}
|
||||
}
|
||||
},
|
||||
.Array => |arrayInfo| {
|
||||
for (value) |v| {
|
||||
parseFree(arrayInfo.child, allocator, v);
|
||||
}
|
||||
},
|
||||
.Vector => |vecInfo| {
|
||||
var i: usize = 0;
|
||||
while (i < vecInfo.len) : (i += 1) {
|
||||
parseFree(vecInfo.child, allocator, value[i]);
|
||||
}
|
||||
},
|
||||
.Pointer => |ptrInfo| {
|
||||
switch (ptrInfo.size) {
|
||||
.One => {
|
||||
parseFree(ptrInfo.child, allocator, value.*);
|
||||
allocator.destroy(value);
|
||||
},
|
||||
.Slice => {
|
||||
for (value) |v| {
|
||||
parseFree(ptrInfo.child, allocator, v);
|
||||
}
|
||||
allocator.free(value);
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
@ -10,6 +10,7 @@ const Server = @import("Server.zig");
|
||||
const Header = @import("Header.zig");
|
||||
const debug = @import("debug.zig");
|
||||
const binned_allocator = @import("binned_allocator");
|
||||
const legacy_json = @import("legacy_json.zig");
|
||||
|
||||
const logger = std.log.scoped(.zls_main);
|
||||
const message_logger = std.log.scoped(.message);
|
||||
@ -147,8 +148,8 @@ fn updateConfig(
|
||||
defer allocator.free(json_message);
|
||||
try file.reader().readNoEof(json_message);
|
||||
|
||||
const new_config = try std.json.parseFromSlice(Config, allocator, json_message, .{});
|
||||
std.json.parseFree(Config, allocator, config.*);
|
||||
const new_config = try legacy_json.parseFromSlice(Config, allocator, json_message, .{});
|
||||
legacy_json.parseFree(Config, allocator, config.*);
|
||||
config.* = new_config;
|
||||
}
|
||||
}
|
||||
@ -334,7 +335,7 @@ fn parseArgs(allocator: std.mem.Allocator) !ParseArgsResult {
|
||||
if (specified.get(.@"show-config-path")) {
|
||||
const new_config = try getConfig(allocator, result.config_path);
|
||||
defer if (new_config.config_path) |path| allocator.free(path);
|
||||
defer std.json.parseFree(Config, allocator, new_config.config);
|
||||
defer legacy_json.parseFree(Config, allocator, new_config.config);
|
||||
|
||||
const full_path = if (new_config.config_path) |path| blk: {
|
||||
break :blk try std.fs.path.resolve(allocator, &.{ path, "zls.json" });
|
||||
@ -392,7 +393,7 @@ pub fn main() !void {
|
||||
logger.info("Starting ZLS {s} @ '{s}'", .{ build_options.version, result.zls_exe_path });
|
||||
|
||||
var config = try getConfig(allocator, result.config_path);
|
||||
defer std.json.parseFree(Config, allocator, config.config);
|
||||
defer legacy_json.parseFree(Config, allocator, config.config);
|
||||
defer if (config.config_path) |path| allocator.free(path);
|
||||
|
||||
if (result.replay_enabled and config.config.replay_session_path == null and config.config.record_session_path == null) {
|
||||
|
@ -60,7 +60,7 @@ pub const Context = struct {
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Context) void {
|
||||
std.json.parseFree(Config, allocator, self.config.*);
|
||||
@import("../src/legacy_json.zig").parseFree(Config, allocator, self.config.*);
|
||||
allocator.destroy(self.config);
|
||||
|
||||
self.request("shutdown", "{}", null) catch {};
|
||||
@ -129,14 +129,10 @@ pub const Context = struct {
|
||||
|
||||
const expected = expect orelse return;
|
||||
|
||||
// parse the response
|
||||
var parser = std.json.Parser.init(allocator, .alloc_always);
|
||||
defer parser.deinit();
|
||||
|
||||
var tree = try parser.parse(response_bytes);
|
||||
var tree = try std.json.parseFromSlice(std.json.Value, allocator, response_bytes, .{});
|
||||
defer tree.deinit();
|
||||
|
||||
const response = tree.root.object;
|
||||
const response = tree.value.object;
|
||||
|
||||
// assertions
|
||||
try std.testing.expectEqualStrings("2.0", response.get("jsonrpc").?.string);
|
||||
@ -195,11 +191,10 @@ pub const Context = struct {
|
||||
const response_bytes = try self.requestAlloc(method, buffer.items);
|
||||
defer self.server.allocator.free(response_bytes);
|
||||
|
||||
var parser = std.json.Parser.init(self.arena.allocator(), .alloc_always);
|
||||
var tree = try parser.parse(try self.arena.allocator().dupe(u8, response_bytes));
|
||||
var tree = try std.json.parseFromSlice(std.json.Value, self.arena.allocator(), try self.arena.allocator().dupe(u8, response_bytes), .{});
|
||||
|
||||
// TODO validate jsonrpc and id
|
||||
|
||||
return tres.parse(Response(Result), tree.root, self.arena.allocator());
|
||||
return tres.parse(Response(Result), tree.value, self.arena.allocator());
|
||||
}
|
||||
};
|
||||
|
@ -108,7 +108,7 @@ fn testTranslate(c_source: []const u8) !translate_c.Result {
|
||||
if (!std.process.can_spawn) return error.SkipZigTest;
|
||||
|
||||
var config: zls.Config = .{};
|
||||
defer std.json.parseFree(zls.Config, allocator, config);
|
||||
defer @import("../../src/legacy_json.zig").parseFree(zls.Config, allocator, config);
|
||||
|
||||
var runtime_zig_version: ?zls.ZigVersionWrapper = null;
|
||||
defer if (runtime_zig_version) |*v| v.free();
|
||||
|
Loading…
Reference in New Issue
Block a user