Skip to content

Commit

Permalink
More lsp work
Browse files Browse the repository at this point in the history
  • Loading branch information
abbec committed Sep 17, 2024
1 parent aaf3d24 commit f6f0be9
Show file tree
Hide file tree
Showing 4 changed files with 192 additions and 120 deletions.
5 changes: 3 additions & 2 deletions src/dged/buffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -788,8 +788,9 @@ struct location buffer_end(struct buffer *buffer) {
if (buffer->lazy_row_add) {
return (struct location){.line = nlines, .col = 0};
} else {
return (struct location){.line = nlines - 1,
.col = buffer_line_length(buffer, nlines - 1)};
nlines = nlines == 0 ? 0 : nlines - 1;
return (struct location){.line = nlines,
.col = buffer_line_length(buffer, nlines)};
}
}

Expand Down
301 changes: 186 additions & 115 deletions src/dged/json.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,31 @@ struct json_array {
VEC(struct json_value) values;
};

static void setarray(struct json_value *val) {
val->type = Json_Array;
val->value.array = calloc(1, sizeof(struct json_array));
VEC_INIT(&val->value.array->values, 10);
static struct json_value create_array() {
struct json_value val = {0};
val.type = Json_Array;
val.value.array = calloc(1, sizeof(struct json_array));
VEC_INIT(&val.value.array->values, 10);

return val;
}

static void setobject(struct json_value *val) {
val->type = Json_Object;
val->value.object = calloc(1, sizeof(struct json_object));
HASHMAP_INIT(&val->value.object->members, 10, hash_name);
static struct json_value create_object() {
struct json_value val = {0};
val.type = Json_Object;
val.value.object = calloc(1, sizeof(struct json_object));
HASHMAP_INIT(&val.value.object->members, 10, hash_name);

return val;
}

static void setstring(struct json_value *val, uint8_t *current) {
val->type = Json_String;
val->value.string.s = current;
val->value.string.l = 0;
static struct json_value create_string(const uint8_t *start, uint32_t len) {
struct json_value val = {0};
val.type = Json_String;
val.value.string.s = (uint8_t *)start;
val.value.string.l = len;

return val;
}

static bool is_number(uint8_t byte) { return byte >= '0' && byte <= '9'; }
Expand All @@ -43,133 +52,195 @@ enum object_parse_state {
ObjectParseState_Value,
};

struct json_result json_parse(uint8_t *buf, uint64_t size) {
struct json_result res = {
.ok = true,
.result.document.type = Json_Null,
struct parser_state {
const uint8_t *buf;
uint64_t pos;
uint64_t len;
uint32_t line;
uint32_t col;
};

static struct json_result parse_string(struct parser_state *state) {
uint8_t byte = state->buf[++state->pos];
uint64_t start_pos = state->pos;
while (byte != '"' && state->pos < state->len) {
++state->pos;
++state->col;
}

if (byte == '"') {
uint64_t len = state->pos - start_pos;
++state->pos;
++state->col;
return (struct json_result){
.ok = true,
.result.document = create_string(&state->buf[start_pos], len),
};
}

return (struct json_result){
.ok = false,
.result.error = "expected end of string, found EOF",
};
}

struct json_value *parent = NULL;
struct json_value *current = &res.result.document;
struct json_value tmp_key = {0};
struct json_value tmp_val = {0};
uint32_t line = 1, col = 0;

enum object_parse_state obj_parse_state = ObjectParseState_Key;
for (uint64_t bufi = 0; bufi < size; ++bufi) {
uint8_t byte = buf[bufi];

// handle appends to the current scope
if (current->type == Json_Array) {
VEC_PUSH(&current->value.array->values, tmp_val);
parent = current;

// start looking for next value
tmp_val.type = Json_Null;
current = &tmp_val;
} else if (current->type == Json_Object &&
obj_parse_state == ObjectParseState_Key) {
// key is in tmp_key, start looking for value
obj_parse_state = ObjectParseState_Value;
parent = current;

tmp_val.type = Json_Null;
current = &tmp_val;
} else if (current->type == Json_Object &&
obj_parse_state == ObjectParseState_Value) {
// value is in tmp_val
// TODO: remove this alloc, should not be needed
char *k = s8tocstr(tmp_key.value.string);
uint32_t hash = 0;
HASHMAP_INSERT(&current->value.object->members, struct json_object_member,
k, tmp_val, hash);
(void)hash;
free(k);

// start looking for next key
obj_parse_state = ObjectParseState_Key;
parent = current;

tmp_key.type = Json_Null;
current = &tmp_key;
static struct json_result parse_number(struct parser_state *state) {
uint8_t byte = state->buf[state->pos];
uint64_t start_pos = state->pos;
while ((is_number(byte) || byte == '-' || byte == '.') &&
state->pos < state->len) {
++state->pos;
++state->col;
}

if (state->pos < state->len) {
uint64_t len = state->pos - start_pos;
++state->pos;
++state->col;
char *nmbr =
s8tocstr((struct s8){.s = (uint8_t *)&state->buf[start_pos], .l = len});
struct json_result res = {
.ok = true,
.result.document.type = Json_Number,
.result.document.value.number = atof(nmbr),
};
free(nmbr);
return res;
}

return (struct json_result){
.ok = false,
.result.error = "expected end of number, found EOF",
};
}

static struct json_result parse_value(struct parser_state *state) {
while (state->pos < state->len) {
uint8_t byte = state->buf[state->pos];
switch (byte) {
case '"':
return parse_string(state);
default:
if (is_number(byte) || byte == '-' || byte == '.') {
return parse_number(state);
} else if (byte == 't') {
return (struct json_result){
.ok = true,
.result.document.type = Json_Bool,
.result.document.value.boolean = true,
};
} else if (byte == 'f') {
return (struct json_result){
.ok = true,
.result.document.type = Json_Bool,
.result.document.value.boolean = false,
};
} else if (byte == 'n') {
return (struct json_result){
.ok = true,
.result.document.type = Json_Null,
};
}
break;
}
++state->pos;
}

return (struct json_result){
.ok = false,
.result.error = "expected value, found EOF",
};
}

struct json_result json_parse(const uint8_t *buf, uint64_t size) {

struct json_value root = {0};
struct json_value *current = &root;

enum object_parse_state expected = ObjectParseState_Key;
struct parser_state state = {
.buf = buf,
.pos = 0,
.len = size,
.line = 1,
.col = 0,
};

struct json_value tmp_key = {0};

for (; state.pos < state.len; ++state.pos) {
uint8_t byte = state.buf[state.pos];

switch (byte) {
case '[':
setarray(current);
parent = current;

tmp_val.type = Json_Null;
current = &tmp_val;
struct json_value arr = create_array();
(void)arr;
break;
case ']':
current = parent;
break;
case '{':
setobject(current);
obj_parse_state = ObjectParseState_Key;
parent = current;

tmp_key.type = Json_Null;
current = &tmp_key;
struct json_value obj = create_object();
(void)obj;
expected = ObjectParseState_Key;
break;
case '}':
current = parent;
break;
case '"':
if (current->type == Json_String) {
// finish off the string
current->value.string.l = (buf + bufi) - current->value.string.s;
current = parent;
} else {
setstring(current, buf + bufi + 1 /* skip " */);
}
case ' ':
case '\r':
case '\t':
break;
case '\n':
++line;
col = 0;
++state.line;
state.col = 0;
break;
default:
if (current->type == Json_String) {
// append to string
} else if (current->type == Json_Number &&
!(is_number(byte) || byte == '-' || byte == '.')) {
// end of number
current->value.string.l = (buf + bufi) - current->value.string.s;
char *nmbr = s8tocstr(current->value.string);
current->value.number = atof(nmbr);
free(nmbr);

current = parent;

} else if (current->type == Json_Null &&
(is_number(byte) || byte == '-' || byte == '.')) {
// borrow string storage in the value for storing number
// as a string
setstring(current, buf + bufi);
current->type = Json_Number;
} else if (byte == 't') {
current->type = Json_Bool;
current->value.boolean = true;
if (expected == ObjectParseState_Key) {
struct json_result res = parse_string(&state);

current = parent;
} else if (byte == 'f') {
current->type = Json_Bool;
current->value.boolean = false;
if (!res.ok) {
return res;
}

current = parent;
} else if (byte == 'n') {
current->type = Json_Null;

current = parent;
tmp_key = res.result.document;
expected = ObjectParseState_Value;
} else {
struct json_result res = parse_value(&state);

if (!res.ok) {
return res;
}

// where to put value?
if (current->type == Json_Object) {
// TODO: remove this alloc, should not be needed
char *k = s8tocstr(tmp_key.value.string);
uint32_t hash = 0;
HASHMAP_INSERT(&current->value.object->members,
struct json_object_member, k, res.result.document,
hash);
(void)hash;
free(k);

// start looking for next key
expected = ObjectParseState_Key;

} else if (current->type == Json_Array) {
VEC_PUSH(&current->value.array->values, res.result.document);
} else {
// root (no container)
*current = res.result.document;
}
}
break;
}

// TODO: not entirely correct
++col;
++state.col;
}
return res;

return (struct json_result){
.ok = true,
.result.document = root,
};
}

void json_destroy(struct json_value *value) {
Expand Down
2 changes: 1 addition & 1 deletion src/dged/json.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ struct json_result {

struct json_writer;

struct json_result json_parse(uint8_t *buf, uint64_t size);
struct json_result json_parse(const uint8_t *buf, uint64_t size);
void json_destroy(struct json_value *value);

uint64_t json_len(struct json_object *obj);
Expand Down
4 changes: 2 additions & 2 deletions src/dged/lsp.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,9 @@ void lsp_destroy(struct lsp *lsp) {
free(lsp->process);
}
if (lsp->command != NULL) {
char *command = lsp->command[0];
char *const *command = &lsp->command[0];
while (command != NULL) {
free(command);
free(*command);
++command;
}

Expand Down

0 comments on commit f6f0be9

Please sign in to comment.