Skip to content

Commit eb59523

Browse files
committed
Improve JavaScript API and also support arena in lex
1 parent a932d7d commit eb59523

File tree

15 files changed

+731
-247
lines changed

15 files changed

+731
-247
lines changed

ext/herb/extension.c

Lines changed: 68 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -25,26 +25,41 @@ static VALUE Herb_lex(int argc, VALUE* argv, VALUE self) {
2525

2626
char* string = (char*) check_string(source);
2727
bool print_arena_stats = false;
28+
VALUE external_arena = Qnil;
2829

2930
if (!NIL_P(options)) {
3031
VALUE arena_stats = rb_hash_lookup(options, rb_utf8_str_new_cstr("arena_stats"));
3132
if (NIL_P(arena_stats)) { arena_stats = rb_hash_lookup(options, ID2SYM(rb_intern("arena_stats"))); }
3233
if (!NIL_P(arena_stats) && RTEST(arena_stats)) { print_arena_stats = true; }
34+
35+
external_arena = rb_hash_lookup(options, rb_utf8_str_new_cstr("arena"));
36+
if (NIL_P(external_arena)) { external_arena = rb_hash_lookup(options, ID2SYM(rb_intern("arena"))); }
3337
}
3438

35-
hb_arena_T* arena = malloc(sizeof(hb_arena_T));
36-
if (!arena) { return Qnil; }
39+
hb_arena_T* arena;
40+
bool owns_arena;
3741

38-
if (!hb_arena_init(arena, KB(512))) {
39-
free(arena);
40-
return Qnil;
42+
if (!NIL_P(external_arena)) {
43+
arena = get_arena_from_value(external_arena);
44+
owns_arena = false;
45+
} else {
46+
arena = malloc(sizeof(hb_arena_T));
47+
if (!arena) { return Qnil; }
48+
49+
if (!hb_arena_init(arena, KB(512))) {
50+
free(arena);
51+
return Qnil;
52+
}
53+
owns_arena = true;
4154
}
4255

4356
herb_lex_result_T* lex_result = herb_lex(string, arena);
4457

4558
if (!lex_result) {
46-
hb_arena_free(arena);
47-
free(arena);
59+
if (owns_arena) {
60+
hb_arena_free(arena);
61+
free(arena);
62+
}
4863
return Qnil;
4964
}
5065

@@ -63,26 +78,41 @@ static VALUE Herb_lex_file(int argc, VALUE* argv, VALUE self) {
6378

6479
char* file_path = (char*) check_string(path);
6580
bool print_arena_stats = false;
81+
VALUE external_arena = Qnil;
6682

6783
if (!NIL_P(options)) {
6884
VALUE arena_stats = rb_hash_lookup(options, rb_utf8_str_new_cstr("arena_stats"));
6985
if (NIL_P(arena_stats)) { arena_stats = rb_hash_lookup(options, ID2SYM(rb_intern("arena_stats"))); }
7086
if (!NIL_P(arena_stats) && RTEST(arena_stats)) { print_arena_stats = true; }
87+
88+
external_arena = rb_hash_lookup(options, rb_utf8_str_new_cstr("arena"));
89+
if (NIL_P(external_arena)) { external_arena = rb_hash_lookup(options, ID2SYM(rb_intern("arena"))); }
7190
}
7291

73-
hb_arena_T* arena = malloc(sizeof(hb_arena_T));
74-
if (!arena) { return Qnil; }
92+
hb_arena_T* arena;
93+
bool owns_arena;
7594

76-
if (!hb_arena_init(arena, KB(512))) {
77-
free(arena);
78-
return Qnil;
95+
if (!NIL_P(external_arena)) {
96+
arena = get_arena_from_value(external_arena);
97+
owns_arena = false;
98+
} else {
99+
arena = malloc(sizeof(hb_arena_T));
100+
if (!arena) { return Qnil; }
101+
102+
if (!hb_arena_init(arena, KB(512))) {
103+
free(arena);
104+
return Qnil;
105+
}
106+
owns_arena = true;
79107
}
80108

81109
herb_lex_result_T* lex_result = herb_lex_file(file_path, arena);
82110

83111
if (!lex_result) {
84-
hb_arena_free(arena);
85-
free(arena);
112+
if (owns_arena) {
113+
hb_arena_free(arena);
114+
free(arena);
115+
}
86116
return Qnil;
87117
}
88118

@@ -176,6 +206,7 @@ static VALUE Herb_parse_file(int argc, VALUE* argv, VALUE self) {
176206

177207
parser_options_T parser_options = HERB_DEFAULT_PARSER_OPTIONS;
178208
bool print_arena_stats = false;
209+
VALUE external_arena = Qnil;
179210

180211
if (!NIL_P(options)) {
181212
VALUE track_whitespace = rb_hash_lookup(options, rb_utf8_str_new_cstr("track_whitespace"));
@@ -193,24 +224,40 @@ static VALUE Herb_parse_file(int argc, VALUE* argv, VALUE self) {
193224
VALUE arena_stats = rb_hash_lookup(options, rb_utf8_str_new_cstr("arena_stats"));
194225
if (NIL_P(arena_stats)) { arena_stats = rb_hash_lookup(options, ID2SYM(rb_intern("arena_stats"))); }
195226
if (!NIL_P(arena_stats) && RTEST(arena_stats)) { print_arena_stats = true; }
227+
228+
external_arena = rb_hash_lookup(options, rb_utf8_str_new_cstr("arena"));
229+
if (NIL_P(external_arena)) { external_arena = rb_hash_lookup(options, ID2SYM(rb_intern("arena"))); }
196230
}
197231

198-
hb_arena_T* arena = malloc(sizeof(hb_arena_T));
199-
if (!arena) { return Qnil; }
232+
hb_arena_T* arena;
233+
bool owns_arena;
200234

201-
if (!hb_arena_init(arena, KB(512))) {
202-
free(arena);
203-
return Qnil;
235+
if (!NIL_P(external_arena)) {
236+
arena = get_arena_from_value(external_arena);
237+
owns_arena = false;
238+
} else {
239+
arena = malloc(sizeof(hb_arena_T));
240+
if (!arena) { return Qnil; }
241+
242+
if (!hb_arena_init(arena, KB(512))) {
243+
free(arena);
244+
return Qnil;
245+
}
246+
owns_arena = true;
204247
}
205248

206249
AST_DOCUMENT_NODE_T* root = herb_parse(string, &parser_options, arena);
207250

208251
if (!root) {
209-
hb_arena_free(arena);
210-
free(arena);
252+
if (owns_arena) {
253+
hb_arena_free(arena);
254+
free(arena);
255+
}
211256
return Qnil;
212257
}
213258

259+
root->owns_arena = owns_arena;
260+
214261
VALUE result = create_parse_result(root, source_value);
215262

216263
if (print_arena_stats) { hb_arena_print_stats(arena); }

javascript/packages/browser/src/wasm-backend.ts

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,37 @@
11
import { name, version } from "../package.json"
22

3-
import { HerbBackend } from "@herb-tools/core"
3+
import { HerbBackend, Arena } from "@herb-tools/core"
4+
import type { ArenaBackend, CreateArenaOptions } from "@herb-tools/core"
5+
6+
class WASMArenaBackend implements ArenaBackend {
7+
private backend: any
8+
private arenaId: number
9+
10+
constructor(backend: any, arenaId: number) {
11+
this.backend = backend
12+
this.arenaId = arenaId
13+
}
14+
15+
get position(): number {
16+
return this.backend.arenaPosition(this.arenaId)
17+
}
18+
19+
get capacity(): number {
20+
return this.backend.arenaCapacity(this.arenaId)
21+
}
22+
23+
reset(): void {
24+
this.backend.resetArena(this.arenaId)
25+
}
26+
27+
free(): void {
28+
this.backend.freeArena(this.arenaId)
29+
}
30+
31+
toBackendOption(): { arenaId: number } {
32+
return { arenaId: this.arenaId }
33+
}
34+
}
435

536
export class HerbBackendWASM extends HerbBackend {
637
lexFile(): never {
@@ -14,4 +45,10 @@ export class HerbBackendWASM extends HerbBackend {
1445
backendVersion(): string {
1546
return `${name}@${version}`
1647
}
48+
49+
createArena(options?: CreateArenaOptions): Arena {
50+
this.ensureBackend()
51+
const arenaId = (this.backend as any).createArena(options?.size ?? 0)
52+
return new Arena(new WASMArenaBackend(this.backend, arenaId))
53+
}
1754
}

0 commit comments

Comments
 (0)