tree-sitter-sed 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CMakeLists.txt ADDED
@@ -0,0 +1,121 @@
1
+ cmake_minimum_required(VERSION 3.13)
2
+
3
+ project(
4
+ tree-sitter-sed
5
+ VERSION 0.4.0
6
+ DESCRIPTION "Tree-sitter grammars for POSIX sed."
7
+ HOMEPAGE_URL "https://github.com/konomanoasa/tree-sitter-sed"
8
+ LANGUAGES C
9
+ )
10
+
11
+ option(BUILD_SHARED_LIBS "Build using shared libraries" ON)
12
+ option(TREE_SITTER_REUSE_ALLOCATOR "Reuse the Tree-sitter allocator" OFF)
13
+
14
+ file(
15
+ STRINGS src/parser.c
16
+ TREE_SITTER_ABI_DEFINITION
17
+ REGEX "^#define LANGUAGE_VERSION [0-9]+$"
18
+ )
19
+ file(
20
+ STRINGS sed_ere/src/parser.c
21
+ TREE_SITTER_ERE_ABI_DEFINITION
22
+ REGEX "^#define LANGUAGE_VERSION [0-9]+$"
23
+ )
24
+ if(
25
+ NOT TREE_SITTER_ABI_DEFINITION MATCHES "^#define LANGUAGE_VERSION [0-9]+$"
26
+ OR NOT TREE_SITTER_ERE_ABI_DEFINITION MATCHES
27
+ "^#define LANGUAGE_VERSION [0-9]+$"
28
+ )
29
+ message(FATAL_ERROR "Both parsers must define one LANGUAGE_VERSION")
30
+ endif()
31
+ if(NOT TREE_SITTER_ABI_DEFINITION STREQUAL TREE_SITTER_ERE_ABI_DEFINITION)
32
+ message(FATAL_ERROR "The sed and sed_ere parsers must use the same ABI")
33
+ endif()
34
+ string(
35
+ REGEX REPLACE "^#define LANGUAGE_VERSION " ""
36
+ TREE_SITTER_ABI_VERSION
37
+ "${TREE_SITTER_ABI_DEFINITION}"
38
+ )
39
+
40
+ include(GNUInstallDirs)
41
+ if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
42
+ include(CTest)
43
+ endif()
44
+
45
+ add_library(
46
+ tree-sitter-sed
47
+ src/parser.c
48
+ src/scanner.c
49
+ sed_ere/src/parser.c
50
+ sed_ere/src/scanner.c
51
+ )
52
+ set_source_files_properties(
53
+ src/scanner.c
54
+ PROPERTIES INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/src"
55
+ )
56
+ set_source_files_properties(
57
+ sed_ere/src/scanner.c
58
+ PROPERTIES INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/sed_ere/src"
59
+ )
60
+ target_include_directories(
61
+ tree-sitter-sed
62
+ INTERFACE
63
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/bindings/c>
64
+ $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
65
+ )
66
+ target_compile_definitions(
67
+ tree-sitter-sed
68
+ PRIVATE
69
+ $<$<BOOL:${TREE_SITTER_REUSE_ALLOCATOR}>:TREE_SITTER_REUSE_ALLOCATOR>
70
+ $<$<CONFIG:Debug>:TREE_SITTER_DEBUG>
71
+ )
72
+ set_target_properties(
73
+ tree-sitter-sed
74
+ PROPERTIES
75
+ C_STANDARD 11
76
+ C_STANDARD_REQUIRED ON
77
+ DEFINE_SYMBOL ""
78
+ POSITION_INDEPENDENT_CODE ON
79
+ SOVERSION "${TREE_SITTER_ABI_VERSION}.${PROJECT_VERSION_MAJOR}"
80
+ )
81
+
82
+ if(BUILD_TESTING AND CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
83
+ add_executable(tree-sitter-sed-binding-test test/binding.test.c)
84
+ target_link_libraries(tree-sitter-sed-binding-test PRIVATE tree-sitter-sed)
85
+ add_test(
86
+ NAME tree-sitter-sed-binding
87
+ COMMAND tree-sitter-sed-binding-test
88
+ )
89
+ endif()
90
+
91
+ configure_file(
92
+ bindings/c/tree-sitter-sed.pc.in
93
+ "${CMAKE_CURRENT_BINARY_DIR}/tree-sitter-sed.pc"
94
+ @ONLY
95
+ )
96
+
97
+ install(
98
+ TARGETS tree-sitter-sed
99
+ ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
100
+ LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
101
+ RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
102
+ )
103
+ install(
104
+ DIRECTORY bindings/c/tree_sitter
105
+ DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
106
+ FILES_MATCHING PATTERN "*.h"
107
+ )
108
+ install(
109
+ FILES "${CMAKE_CURRENT_BINARY_DIR}/tree-sitter-sed.pc"
110
+ DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig"
111
+ )
112
+ install(
113
+ DIRECTORY queries/
114
+ DESTINATION "${CMAKE_INSTALL_DATADIR}/tree-sitter/queries/sed"
115
+ FILES_MATCHING PATTERN "*.scm"
116
+ )
117
+ install(
118
+ DIRECTORY sed_ere/queries/
119
+ DESTINATION "${CMAKE_INSTALL_DATADIR}/tree-sitter/queries/sed_ere"
120
+ FILES_MATCHING PATTERN "*.scm"
121
+ )
package/Makefile ADDED
@@ -0,0 +1,145 @@
1
+ LANGUAGE_NAME := tree-sitter-sed
2
+ HOMEPAGE_URL := https://github.com/konomanoasa/tree-sitter-sed
3
+ VERSION := 0.4.0
4
+ DESCRIPTION := Tree-sitter grammars for POSIX sed.
5
+
6
+ PREFIX ?= /usr/local
7
+ DATADIR ?= $(PREFIX)/share
8
+ INCLUDEDIR ?= $(PREFIX)/include
9
+ LIBDIR ?= $(PREFIX)/lib
10
+ BINDIR ?= $(PREFIX)/bin
11
+ PCLIBDIR ?= $(LIBDIR)/pkgconfig
12
+
13
+ SOURCES := src/parser.c src/scanner.c \
14
+ sed_ere/src/parser.c sed_ere/src/scanner.c
15
+ OBJECTS := $(SOURCES:.c=.o)
16
+ MAKE_BUILD_DIR := build/make
17
+ STATIC_LIBRARY := lib$(LANGUAGE_NAME).a
18
+ PKG_CONFIG := $(LANGUAGE_NAME).pc
19
+ TEST := $(MAKE_BUILD_DIR)/binding.test
20
+
21
+ ARFLAGS := rcs
22
+ override CFLAGS += -std=c11 -fPIC
23
+
24
+ SONAME_MAJOR := $(shell sed -n 's/\#define LANGUAGE_VERSION //p' src/parser.c)
25
+ SED_ERE_SONAME_MAJOR := $(shell sed -n 's/\#define LANGUAGE_VERSION //p' sed_ere/src/parser.c)
26
+ SONAME_MINOR := $(word 1,$(subst ., ,$(VERSION)))
27
+
28
+ ifeq ($(SONAME_MAJOR),)
29
+ $(error Both parsers must define LANGUAGE_VERSION)
30
+ endif
31
+ ifneq ($(SONAME_MAJOR),$(SED_ERE_SONAME_MAJOR))
32
+ $(error The sed and sed_ere parsers must use the same ABI)
33
+ endif
34
+
35
+ MACHINE := $(shell $(CC) -dumpmachine)
36
+
37
+ ifneq ($(findstring darwin,$(MACHINE)),)
38
+ SOEXT := dylib
39
+ SOEXTVER_MAJOR := $(SONAME_MAJOR).$(SOEXT)
40
+ SOEXTVER := $(SONAME_MAJOR).$(SONAME_MINOR).$(SOEXT)
41
+ LINKSHARED := -dynamiclib -Wl,-install_name,$(LIBDIR)/lib$(LANGUAGE_NAME).$(SOEXTVER)
42
+ else ifneq ($(findstring mingw32,$(MACHINE)),)
43
+ SOEXT := dll
44
+ LINKSHARED := -s -shared -Wl,--out-implib,lib$(LANGUAGE_NAME).dll.a
45
+ TEST := $(MAKE_BUILD_DIR)/binding.test.exe
46
+ else
47
+ SOEXT := so
48
+ SOEXTVER_MAJOR := $(SOEXT).$(SONAME_MAJOR)
49
+ SOEXTVER := $(SOEXT).$(SONAME_MAJOR).$(SONAME_MINOR)
50
+ LINKSHARED := -shared -Wl,-soname,lib$(LANGUAGE_NAME).$(SOEXTVER)
51
+ ifneq ($(filter $(shell uname),FreeBSD NetBSD DragonFly),)
52
+ PCLIBDIR := $(PREFIX)/libdata/pkgconfig
53
+ endif
54
+ endif
55
+
56
+ SHARED_LIBRARY := lib$(LANGUAGE_NAME).$(SOEXT)
57
+
58
+ all: $(STATIC_LIBRARY) $(SHARED_LIBRARY) $(PKG_CONFIG)
59
+
60
+ $(STATIC_LIBRARY): $(OBJECTS)
61
+ $(AR) $(ARFLAGS) $@ $^
62
+
63
+ $(SHARED_LIBRARY): $(OBJECTS)
64
+ $(CC) $(LDFLAGS) $(LINKSHARED) $^ $(LDLIBS) -o $@
65
+ ifneq ($(STRIP),)
66
+ $(STRIP) $@
67
+ endif
68
+
69
+ $(PKG_CONFIG): bindings/c/$(LANGUAGE_NAME).pc.in FORCE
70
+ sed -e 's|@PROJECT_VERSION@|$(VERSION)|' \
71
+ -e 's|@CMAKE_INSTALL_LIBDIR@|$(LIBDIR:$(PREFIX)/%=%)|' \
72
+ -e 's|@CMAKE_INSTALL_INCLUDEDIR@|$(INCLUDEDIR:$(PREFIX)/%=%)|' \
73
+ -e 's|@PROJECT_DESCRIPTION@|$(DESCRIPTION)|' \
74
+ -e 's|@PROJECT_HOMEPAGE_URL@|$(HOMEPAGE_URL)|' \
75
+ -e 's|@CMAKE_INSTALL_PREFIX@|$(PREFIX)|' $< > $@
76
+
77
+ src/parser.o: src/tree_sitter/parser.h
78
+ src/scanner.o: common/scanner.h src/tree_sitter/alloc.h src/tree_sitter/parser.h
79
+ src/scanner.o: CPPFLAGS += -Isrc
80
+ sed_ere/src/parser.o: sed_ere/src/tree_sitter/parser.h
81
+ sed_ere/src/scanner.o: common/scanner.h sed_ere/src/tree_sitter/alloc.h \
82
+ sed_ere/src/tree_sitter/parser.h
83
+ sed_ere/src/scanner.o: CPPFLAGS += -Ised_ere/src
84
+
85
+ $(MAKE_BUILD_DIR):
86
+ mkdir -p $@
87
+
88
+ $(TEST): test/binding.test.c $(STATIC_LIBRARY) | $(MAKE_BUILD_DIR)
89
+ $(CC) $(CPPFLAGS) $(CFLAGS) -Ibindings/c $< $(STATIC_LIBRARY) $(LDFLAGS) $(LDLIBS) -o $@
90
+
91
+ test: $(TEST)
92
+ ./$(TEST)
93
+
94
+ install: all
95
+ install -d '$(DESTDIR)$(DATADIR)'/tree-sitter/queries/sed \
96
+ '$(DESTDIR)$(DATADIR)'/tree-sitter/queries/sed_ere \
97
+ '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter \
98
+ '$(DESTDIR)$(PCLIBDIR)' \
99
+ '$(DESTDIR)$(LIBDIR)'
100
+ install -m644 bindings/c/tree_sitter/$(LANGUAGE_NAME).h \
101
+ '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter/$(LANGUAGE_NAME).h
102
+ install -m644 $(PKG_CONFIG) '$(DESTDIR)$(PCLIBDIR)'/$(PKG_CONFIG)
103
+ install -m644 $(STATIC_LIBRARY) '$(DESTDIR)$(LIBDIR)'/$(STATIC_LIBRARY)
104
+ ifneq ($(findstring mingw32,$(MACHINE)),)
105
+ install -d '$(DESTDIR)$(BINDIR)'
106
+ install -m755 $(SHARED_LIBRARY) '$(DESTDIR)$(BINDIR)'/$(SHARED_LIBRARY)
107
+ install -m644 lib$(LANGUAGE_NAME).dll.a \
108
+ '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).dll.a
109
+ else
110
+ install -m755 $(SHARED_LIBRARY) \
111
+ '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXTVER)
112
+ cd '$(DESTDIR)$(LIBDIR)' && \
113
+ ln -sf lib$(LANGUAGE_NAME).$(SOEXTVER) \
114
+ lib$(LANGUAGE_NAME).$(SOEXTVER_MAJOR)
115
+ cd '$(DESTDIR)$(LIBDIR)' && \
116
+ ln -sf lib$(LANGUAGE_NAME).$(SOEXTVER_MAJOR) $(SHARED_LIBRARY)
117
+ endif
118
+ install -m644 queries/*.scm \
119
+ '$(DESTDIR)$(DATADIR)'/tree-sitter/queries/sed
120
+ install -m644 sed_ere/queries/*.scm \
121
+ '$(DESTDIR)$(DATADIR)'/tree-sitter/queries/sed_ere
122
+
123
+ uninstall:
124
+ $(RM) '$(DESTDIR)$(LIBDIR)'/$(STATIC_LIBRARY) \
125
+ '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter/$(LANGUAGE_NAME).h \
126
+ '$(DESTDIR)$(PCLIBDIR)'/$(PKG_CONFIG)
127
+ ifneq ($(findstring mingw32,$(MACHINE)),)
128
+ $(RM) '$(DESTDIR)$(BINDIR)'/$(SHARED_LIBRARY) \
129
+ '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).dll.a
130
+ else
131
+ $(RM) '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXTVER) \
132
+ '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXTVER_MAJOR) \
133
+ '$(DESTDIR)$(LIBDIR)'/$(SHARED_LIBRARY)
134
+ endif
135
+ $(RM) -r '$(DESTDIR)$(DATADIR)'/tree-sitter/queries/sed \
136
+ '$(DESTDIR)$(DATADIR)'/tree-sitter/queries/sed_ere
137
+
138
+ clean:
139
+ $(RM) $(OBJECTS) $(STATIC_LIBRARY) $(SHARED_LIBRARY) \
140
+ lib$(LANGUAGE_NAME).dll.a $(PKG_CONFIG)
141
+ $(RM) -r $(MAKE_BUILD_DIR)
142
+
143
+ FORCE:
144
+
145
+ .PHONY: all clean FORCE install test uninstall
package/README.md CHANGED
@@ -14,7 +14,12 @@ npm install tree-sitter-sed
14
14
 
15
15
  ## Grammars
16
16
 
17
- This repository contains two grammars. You can find [`sed_ere`](sed_ere) here.
17
+ This repository contains the following two grammars.
18
+
19
+ | Grammar | Regexp | C function |
20
+ | --------- | ------ | ----------------------- |
21
+ | `sed` | BRE | `tree_sitter_sed()` |
22
+ | `sed_ere` | ERE | `tree_sitter_sed_ere()` |
18
23
 
19
24
  ## Specifications
20
25
 
@@ -0,0 +1,10 @@
1
+ prefix=@CMAKE_INSTALL_PREFIX@
2
+ libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@
3
+ includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
4
+
5
+ Name: tree-sitter-sed
6
+ Description: @PROJECT_DESCRIPTION@
7
+ URL: @PROJECT_HOMEPAGE_URL@
8
+ Version: @PROJECT_VERSION@
9
+ Libs: -L${libdir} -ltree-sitter-sed
10
+ Cflags: -I${includedir}
@@ -0,0 +1,17 @@
1
+ #ifndef TREE_SITTER_SED_H_
2
+ #define TREE_SITTER_SED_H_
3
+
4
+ typedef struct TSLanguage TSLanguage;
5
+
6
+ #ifdef __cplusplus
7
+ extern "C" {
8
+ #endif
9
+
10
+ const TSLanguage *tree_sitter_sed(void);
11
+ const TSLanguage *tree_sitter_sed_ere(void);
12
+
13
+ #ifdef __cplusplus
14
+ }
15
+ #endif
16
+
17
+ #endif
package/common/dsl.js CHANGED
@@ -2,6 +2,28 @@ function issueRuleName(id) {
2
2
  return `_${id}_issue`;
3
3
  }
4
4
 
5
+ function outcomeRuleName(id) {
6
+ return `_${id}_outcome`;
7
+ }
8
+
9
+ function reasonRuleName(id) {
10
+ return `_${id}_reason`;
11
+ }
12
+
13
+ function defineIssueRules(definitions) {
14
+ const rules = {};
15
+
16
+ for (const definition of definitions) {
17
+ const { outcome, reason, rule } = definition;
18
+ const id = definition.id ?? reason;
19
+ rules[reasonRuleName(id)] = rule;
20
+ rules[outcomeRuleName(id)] = ($) => alias($[reasonRuleName(id)], $[reason]);
21
+ rules[issueRuleName(id)] = ($) => alias($[outcomeRuleName(id)], $[outcome]);
22
+ }
23
+
24
+ return rules;
25
+ }
26
+
5
27
  function namedExternal($, external, name) {
6
28
  return alias(external, $[name]);
7
29
  }
@@ -14,4 +36,4 @@ function issueNode($, id) {
14
36
  return alias($[issueRuleName(id)], $.syntax_issue);
15
37
  }
16
38
 
17
- module.exports = { issueField, issueNode, issueRuleName, namedExternal };
39
+ module.exports = { defineIssueRules, issueField, issueNode, namedExternal };
package/common/grammar.js CHANGED
@@ -1,33 +1,11 @@
1
1
  const {
2
+ defineIssueRules,
2
3
  issueField,
3
4
  issueNode,
4
- issueRuleName,
5
5
  namedExternal,
6
6
  } = require("./dsl");
7
7
  const regularExpressionRules = require("./regex");
8
8
 
9
- function outcomeRuleName(id) {
10
- return `_${id}_outcome`;
11
- }
12
-
13
- function reasonRuleName(id) {
14
- return `_${id}_reason`;
15
- }
16
-
17
- function defineIssueRules(definitions) {
18
- const rules = {};
19
-
20
- for (const definition of definitions) {
21
- const { outcome, reason, rule } = definition;
22
- const id = definition.id ?? reason;
23
- rules[reasonRuleName(id)] = rule;
24
- rules[outcomeRuleName(id)] = ($) => alias($[reasonRuleName(id)], $[reason]);
25
- rules[issueRuleName(id)] = ($) => alias($[outcomeRuleName(id)], $[outcome]);
26
- }
27
-
28
- return rules;
29
- }
30
-
31
9
  function missingAtEndOrBoundary($, reason) {
32
10
  return choice(
33
11
  issueField($, reason),
package/common/scanner.h CHANGED
@@ -1,5 +1,5 @@
1
- #ifndef TREE_SITTER_POSIX_SED_COMMON_SCANNER_H_
2
- #define TREE_SITTER_POSIX_SED_COMMON_SCANNER_H_
1
+ #ifndef TREE_SITTER_SED_COMMON_SCANNER_H_
2
+ #define TREE_SITTER_SED_COMMON_SCANNER_H_
3
3
 
4
4
  #ifndef SED_REGEX_EXTENDED
5
5
  #error "SED_REGEX_EXTENDED must be defined before including scanner.h"
@@ -246,6 +246,17 @@ enum {
246
246
  SCANNER_SERIALIZED_STATE_SIZE = 17,
247
247
  };
248
248
 
249
+ enum {
250
+ SERIALIZED_AT_BRANCH_START_FLAG = 1 << 0,
251
+ SERIALIZED_AFTER_ALTERNATION_FLAG = 1 << 1,
252
+ SERIALIZED_AFTER_ANCHOR_FLAG = 1 << 2,
253
+ SERIALIZED_TEXT_STATE_SHIFT = 3,
254
+ SERIALIZED_MODE_FLAGS_MAXIMUM = 31,
255
+ SERIALIZED_RANGE_PENDING_FLAG = 1 << 0,
256
+ SERIALIZED_DUPLICATION_STATE_SHIFT = 1,
257
+ SERIALIZED_BRACKET_FLAGS_MAXIMUM = 7,
258
+ };
259
+
249
260
  static void reset_bracket_tracking(ScannerState *state) {
250
261
  state->regex_bracket_term_state = REGEX_BRACKET_TERM_NONE;
251
262
  state->regex_bracket_pending_element = REGEX_BRACKET_PENDING_NONE;
@@ -315,10 +326,11 @@ static unsigned sed_scanner_serialize(void *payload, char *buffer) {
315
326
  buffer[0] = SCANNER_SERIALIZATION_VERSION;
316
327
  buffer[1] = (char)state->mode;
317
328
  buffer[2] = (char)state->regex_state;
318
- buffer[3] = (state->regex_at_branch_start ? 1 : 0) |
319
- (state->regex_after_alternation ? 2 : 0) |
320
- (state->regex_after_anchor ? 4 : 0) |
321
- ((unsigned char)state->text_state << 3);
329
+ buffer[3] =
330
+ (state->regex_at_branch_start ? SERIALIZED_AT_BRANCH_START_FLAG : 0) |
331
+ (state->regex_after_alternation ? SERIALIZED_AFTER_ALTERNATION_FLAG : 0) |
332
+ (state->regex_after_anchor ? SERIALIZED_AFTER_ANCHOR_FLAG : 0) |
333
+ ((unsigned char)state->text_state << SERIALIZED_TEXT_STATE_SHIFT);
322
334
  buffer[4] = (char)(delimiter & UINT32_C(0xff));
323
335
  buffer[5] = (char)((delimiter >> 8) & UINT32_C(0xff));
324
336
  buffer[6] = (char)((delimiter >> 16) & UINT32_C(0xff));
@@ -330,8 +342,10 @@ static unsigned sed_scanner_serialize(void *payload, char *buffer) {
330
342
  buffer[13] = (char)state->regex_bracket_first_element;
331
343
  buffer[14] = (char)state->regex_bracket_last_element;
332
344
  buffer[15] = (char)state->regex_bracket_element_count;
333
- buffer[16] = (state->regex_bracket_range_pending ? 1 : 0) |
334
- ((unsigned char)state->regex_duplication_state << 1);
345
+ buffer[16] =
346
+ (state->regex_bracket_range_pending ? SERIALIZED_RANGE_PENDING_FLAG : 0) |
347
+ ((unsigned char)state->regex_duplication_state
348
+ << SERIALIZED_DUPLICATION_STATE_SHIFT);
335
349
  return SCANNER_SERIALIZED_STATE_SIZE;
336
350
  }
337
351
 
@@ -447,12 +461,16 @@ sed_scanner_deserialize(void *payload, const char *buffer, unsigned length) {
447
461
  ((uint32_t)(unsigned char)buffer[7] << 24)),
448
462
  .mode = (enum ScannerMode)(unsigned char)buffer[1],
449
463
  .regex_state = (enum RegexState)(unsigned char)buffer[2],
450
- .regex_at_branch_start = (mode_flags & 1U) != 0,
451
- .regex_duplication_state =
452
- (enum RegexDuplicationState)((regex_bracket_flags >> 1) & 3U),
453
- .regex_after_alternation = (mode_flags & 2U) != 0,
454
- .regex_after_anchor = (mode_flags & 4U) != 0,
455
- .text_state = (enum TextState)((mode_flags >> 3) & 3U),
464
+ .regex_at_branch_start =
465
+ (mode_flags & SERIALIZED_AT_BRANCH_START_FLAG) != 0,
466
+ .regex_duplication_state = (enum RegexDuplicationState)(
467
+ (regex_bracket_flags >> SERIALIZED_DUPLICATION_STATE_SHIFT) & 3U
468
+ ),
469
+ .regex_after_alternation =
470
+ (mode_flags & SERIALIZED_AFTER_ALTERNATION_FLAG) != 0,
471
+ .regex_after_anchor = (mode_flags & SERIALIZED_AFTER_ANCHOR_FLAG) != 0,
472
+ .text_state =
473
+ (enum TextState)((mode_flags >> SERIALIZED_TEXT_STATE_SHIFT) & 3U),
456
474
  .regex_interval_state = (enum RegexIntervalState)(unsigned char)buffer[10],
457
475
  .regex_bracket_term_state =
458
476
  (enum RegexBracketTermState)(unsigned char)buffer[11],
@@ -463,7 +481,8 @@ sed_scanner_deserialize(void *payload, const char *buffer, unsigned length) {
463
481
  .regex_bracket_last_element =
464
482
  (enum RegexBracketPendingElement)(unsigned char)buffer[14],
465
483
  .regex_bracket_element_count = (uint8_t)(unsigned char)buffer[15],
466
- .regex_bracket_range_pending = (regex_bracket_flags & 1U) != 0,
484
+ .regex_bracket_range_pending =
485
+ (regex_bracket_flags & SERIALIZED_RANGE_PENDING_FLAG) != 0,
467
486
  .regex_group_depth = deserialize_uint16(buffer, 8),
468
487
  };
469
488
 
@@ -475,7 +494,7 @@ sed_scanner_deserialize(void *payload, const char *buffer, unsigned length) {
475
494
  return;
476
495
  }
477
496
 
478
- if ((mode_flags & (unsigned char)~31U) != 0) {
497
+ if ((mode_flags & (unsigned char)~SERIALIZED_MODE_FLAGS_MAXIMUM) != 0) {
479
498
  return;
480
499
  }
481
500
  if (candidate.text_state > TEXT_AFTER_ESCAPED_NEWLINE) {
@@ -502,7 +521,7 @@ sed_scanner_deserialize(void *payload, const char *buffer, unsigned length) {
502
521
  REGEX_BRACKET_PENDING_COLON ||
503
522
  candidate.regex_bracket_element_count >
504
523
  3U ||
505
- (regex_bracket_flags & (unsigned char)~7U) !=
524
+ (regex_bracket_flags & (unsigned char)~SERIALIZED_BRACKET_FLAGS_MAXIMUM) !=
506
525
  0 ||
507
526
  #if SED_REGEX_EXTENDED
508
527
  candidate.regex_duplication_state > REGEX_AFTER_REPETITION_MODIFIER
@@ -1095,44 +1114,36 @@ update_bracket_state_after_literal(ScannerState *state, int32_t character) {
1095
1114
  static bool
1096
1115
  regex_literal_boundary(const ScannerState *state, int32_t character) {
1097
1116
  if (state->regex_state == REGEX_OUTSIDE_BRACKET) {
1098
- return character ==
1099
- state->delimiter ||
1100
- character ==
1101
- '\\' ||
1102
- character ==
1103
- '(' ||
1104
- character ==
1105
- ')' ||
1106
- character ==
1107
- '[' ||
1108
- character ==
1109
- '*' ||
1110
- character ==
1111
- '+' ||
1112
- character ==
1113
- '?' ||
1114
- character ==
1115
- '|' ||
1116
- character ==
1117
- '{' ||
1118
- character ==
1119
- '.' ||
1120
- character ==
1121
- '^' ||
1122
- character == '$';
1117
+ switch (character) {
1118
+ case '\\':
1119
+ case '(':
1120
+ case ')':
1121
+ case '[':
1122
+ case '*':
1123
+ case '+':
1124
+ case '?':
1125
+ case '|':
1126
+ case '{':
1127
+ case '.':
1128
+ case '^':
1129
+ case '$':
1130
+ return true;
1131
+ default:
1132
+ return character == state->delimiter;
1133
+ }
1123
1134
  }
1124
1135
 
1125
- if (
1126
- character ==
1127
- '[' ||
1128
- (state->regex_state == REGEX_BRACKET_FIRST && character == '^') ||
1129
- (state->regex_state == REGEX_BRACKET_BODY && character == '-') ||
1130
- (state->regex_state == REGEX_BRACKET_BODY && character == ']')
1131
- ) {
1136
+ switch (character) {
1137
+ case '[':
1132
1138
  return true;
1139
+ case '^':
1140
+ return state->regex_state == REGEX_BRACKET_FIRST;
1141
+ case '-':
1142
+ case ']':
1143
+ return state->regex_state == REGEX_BRACKET_BODY;
1144
+ default:
1145
+ return false;
1133
1146
  }
1134
-
1135
- return false;
1136
1147
  }
1137
1148
 
1138
1149
  static enum LiteralScanResult
@@ -1200,15 +1211,19 @@ static bool scan_regex_bracket_opener(
1200
1211
  lexer->mark_end(lexer);
1201
1212
 
1202
1213
  TSSymbol candidate;
1214
+ enum RegexBracketTermState term_state;
1203
1215
  switch (lexer->lookahead) {
1204
1216
  case ':':
1205
1217
  candidate = REGEX_OPEN_COLON;
1218
+ term_state = REGEX_BRACKET_TERM_COLON;
1206
1219
  break;
1207
1220
  case '.':
1208
1221
  candidate = REGEX_OPEN_DOT;
1222
+ term_state = REGEX_BRACKET_TERM_DOT;
1209
1223
  break;
1210
1224
  case '=':
1211
1225
  candidate = REGEX_OPEN_EQUAL;
1226
+ term_state = REGEX_BRACKET_TERM_EQUAL;
1212
1227
  break;
1213
1228
  default:
1214
1229
  begin_single_bracket_element(state, '[');
@@ -1222,10 +1237,7 @@ static bool scan_regex_bracket_opener(
1222
1237
  consume(lexer);
1223
1238
  begin_compound_bracket_element(state);
1224
1239
  finish_first_bracket_element(state);
1225
- state->regex_bracket_term_state = candidate == REGEX_OPEN_COLON
1226
- ? REGEX_BRACKET_TERM_COLON
1227
- : candidate == REGEX_OPEN_DOT ? REGEX_BRACKET_TERM_DOT
1228
- : REGEX_BRACKET_TERM_EQUAL;
1240
+ state->regex_bracket_term_state = term_state;
1229
1241
  *symbol = candidate;
1230
1242
  return true;
1231
1243
  }
@@ -1247,6 +1259,18 @@ static bool bracket_meta_character(int32_t character) {
1247
1259
  return character == '^' || character == '-' || character == ']';
1248
1260
  }
1249
1261
 
1262
+ static int32_t
1263
+ bracket_term_close_marker(enum RegexBracketTermState term_state) {
1264
+ switch (term_state) {
1265
+ case REGEX_BRACKET_TERM_COLON:
1266
+ return ':';
1267
+ case REGEX_BRACKET_TERM_DOT:
1268
+ return '.';
1269
+ default:
1270
+ return '=';
1271
+ }
1272
+ }
1273
+
1250
1274
  static TSSymbol regex_bracket_term_content_symbol(
1251
1275
  const ScannerState *state,
1252
1276
  uint8_t character_count,
@@ -1599,6 +1623,21 @@ static enum DuplicationContextScan scan_regex_duplication_context_marker(
1599
1623
  return DUPLICATION_CONTEXT_TOKEN;
1600
1624
  }
1601
1625
 
1626
+ static bool raw_regex_operator_character(int32_t character) {
1627
+ switch (character) {
1628
+ case '(':
1629
+ case ')':
1630
+ case '*':
1631
+ case '+':
1632
+ case '?':
1633
+ case '|':
1634
+ case '{':
1635
+ return true;
1636
+ default:
1637
+ return false;
1638
+ }
1639
+ }
1640
+
1602
1641
  static bool scan_raw_regex_operator(
1603
1642
  TSLexer *lexer,
1604
1643
  ScannerState *state,
@@ -1667,39 +1706,42 @@ static bool scan_raw_regex_operator(
1667
1706
  }
1668
1707
 
1669
1708
  static bool regex_delimiter_is_special(int32_t character) {
1709
+ switch (character) {
1670
1710
  #if SED_REGEX_EXTENDED
1671
- return character ==
1672
- '.' ||
1673
- character ==
1674
- '[' ||
1675
- character ==
1676
- '(' ||
1677
- character ==
1678
- ')' ||
1679
- character ==
1680
- '*' ||
1681
- character ==
1682
- '+' ||
1683
- character ==
1684
- '?' ||
1685
- character ==
1686
- '{' ||
1687
- character ==
1688
- '|' ||
1689
- character ==
1690
- '^' ||
1691
- character == '$';
1692
- #else
1693
- return character ==
1694
- '.' ||
1695
- character ==
1696
- '[' ||
1697
- character ==
1698
- '*' ||
1699
- character ==
1700
- '^' ||
1701
- character == '$';
1711
+ case '(':
1712
+ case ')':
1713
+ case '+':
1714
+ case '?':
1715
+ case '{':
1716
+ case '|':
1717
+ #endif
1718
+ case '.':
1719
+ case '[':
1720
+ case '*':
1721
+ case '^':
1722
+ case '$':
1723
+ return true;
1724
+ default:
1725
+ return false;
1726
+ }
1727
+ }
1728
+
1729
+ static bool escape_quotes_regex_syntax(int32_t character) {
1730
+ switch (character) {
1731
+ #if SED_REGEX_EXTENDED
1732
+ case '}':
1702
1733
  #endif
1734
+ case '.':
1735
+ case '*':
1736
+ case '^':
1737
+ case '$':
1738
+ case '[':
1739
+ case '\\':
1740
+ case ']':
1741
+ return true;
1742
+ default:
1743
+ return false;
1744
+ }
1703
1745
  }
1704
1746
 
1705
1747
  static bool scan_regex_escaped_delimiter(
@@ -1815,29 +1857,11 @@ static bool scan_regex_escape_after_backslash(
1815
1857
  return emit_symbol(valid_symbols, REGEX_NEWLINE_ESCAPE, symbol);
1816
1858
  }
1817
1859
 
1818
- const int32_t character = lexer->lookahead;
1819
- const bool quotes_regex_syntax = character ==
1820
- '.' ||
1821
- character ==
1822
- '*' ||
1823
- character ==
1824
- '^' ||
1825
- character ==
1826
- '$' ||
1827
- character ==
1828
- '[' ||
1829
- character ==
1830
- '\\' ||
1831
- character ==
1832
- ']' ||
1833
- (SED_REGEX_EXTENDED && character == '}');
1834
- if (!quotes_regex_syntax) {
1835
- consume(lexer);
1836
- return emit_symbol(valid_symbols, REGEX_NONPORTABLE_ESCAPE, symbol);
1837
- }
1838
-
1860
+ const TSSymbol candidate = escape_quotes_regex_syntax(lexer->lookahead)
1861
+ ? REGEX_QUOTED_ESCAPE
1862
+ : REGEX_NONPORTABLE_ESCAPE;
1839
1863
  consume(lexer);
1840
- return emit_symbol(valid_symbols, REGEX_QUOTED_ESCAPE, symbol);
1864
+ return emit_symbol(valid_symbols, candidate, symbol);
1841
1865
  }
1842
1866
 
1843
1867
  #if !SED_REGEX_EXTENDED
@@ -2069,14 +2093,10 @@ static bool scan_regex_token(
2069
2093
  valid_symbols[REGEX_COLL_ELEM_MULTI] ||
2070
2094
  valid_symbols[REGEX_META_CHAR]
2071
2095
  ) {
2072
- const int32_t close_marker =
2073
- state->regex_bracket_term_state == REGEX_BRACKET_TERM_COLON ? ':'
2074
- : state->regex_bracket_term_state == REGEX_BRACKET_TERM_DOT ? '.'
2075
- : '=';
2076
2096
  return scan_regex_bracket_term_content(
2077
2097
  lexer,
2078
2098
  state,
2079
- close_marker,
2099
+ bracket_term_close_marker(state->regex_bracket_term_state),
2080
2100
  valid_symbols,
2081
2101
  symbol
2082
2102
  );
@@ -2211,21 +2231,7 @@ static bool scan_regex_token(
2211
2231
  );
2212
2232
  }
2213
2233
 
2214
- if (
2215
- lexer->lookahead ==
2216
- '(' ||
2217
- lexer->lookahead ==
2218
- ')' ||
2219
- lexer->lookahead ==
2220
- '*' ||
2221
- lexer->lookahead ==
2222
- '+' ||
2223
- lexer->lookahead ==
2224
- '?' ||
2225
- lexer->lookahead ==
2226
- '|' ||
2227
- lexer->lookahead == '{'
2228
- ) {
2234
+ if (raw_regex_operator_character(lexer->lookahead)) {
2229
2235
  return scan_raw_regex_operator(lexer, state, valid_symbols, symbol);
2230
2236
  }
2231
2237
 
@@ -2646,6 +2652,11 @@ static bool scan_regex_recovery_marker(
2646
2652
  return false;
2647
2653
  }
2648
2654
 
2655
+ static TSSymbol missing_text_introducer_symbol(const TSLexer *lexer) {
2656
+ return lexer->eof(lexer) ? MISSING_TEXT_INTRODUCER_MARKER
2657
+ : NONCONFORMING_MISSING_TEXT_INTRODUCER_MARKER;
2658
+ }
2659
+
2649
2660
  static bool scan_command_token(
2650
2661
  TSLexer *lexer,
2651
2662
  ScannerState *state,
@@ -2711,10 +2722,11 @@ static bool scan_command_token(
2711
2722
  *symbol = TEXT_COMMAND_START;
2712
2723
  return true;
2713
2724
  }
2714
- const TSSymbol introducer_marker = lexer->eof(lexer)
2715
- ? MISSING_TEXT_INTRODUCER_MARKER
2716
- : NONCONFORMING_MISSING_TEXT_INTRODUCER_MARKER;
2717
- return emit_symbol(valid_symbols, introducer_marker, symbol);
2725
+ return emit_symbol(
2726
+ valid_symbols,
2727
+ missing_text_introducer_symbol(lexer),
2728
+ symbol
2729
+ );
2718
2730
  }
2719
2731
 
2720
2732
  if (valid_symbols[DEFAULT_OUTPUT_SUPPRESSION] && lexer->lookahead == 'n') {
@@ -2854,11 +2866,13 @@ static bool scan_command_token(
2854
2866
  }
2855
2867
  }
2856
2868
 
2857
- const TSSymbol missing_text_introducer = lexer->eof(lexer)
2858
- ? MISSING_TEXT_INTRODUCER_MARKER
2859
- : NONCONFORMING_MISSING_TEXT_INTRODUCER_MARKER;
2860
2869
  if (
2861
- emit_missing_marker(lexer, valid_symbols, missing_text_introducer, symbol)
2870
+ emit_missing_marker(
2871
+ lexer,
2872
+ valid_symbols,
2873
+ missing_text_introducer_symbol(lexer),
2874
+ symbol
2875
+ )
2862
2876
  ) {
2863
2877
  return true;
2864
2878
  }
package/package.json CHANGED
@@ -1,13 +1,16 @@
1
1
  {
2
2
  "name": "tree-sitter-sed",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Tree-sitter grammars for POSIX sed.",
5
5
  "license": "MIT",
6
6
  "repository": "git+https://github.com/konomanoasa/tree-sitter-sed.git",
7
7
  "files": [
8
+ "bindings/c",
9
+ "CMakeLists.txt",
8
10
  "common/*.js",
9
11
  "common/scanner.h",
10
12
  "grammar.js",
13
+ "Makefile",
11
14
  "queries/*.scm",
12
15
  "src/*.c",
13
16
  "src/*.json",
@@ -17,11 +20,12 @@
17
20
  "sed_ere/src/*.c",
18
21
  "sed_ere/src/*.json",
19
22
  "sed_ere/src/tree_sitter/*.h",
23
+ "test/binding.test.c",
20
24
  "tree-sitter.json"
21
25
  ],
22
26
  "scripts": {
23
- "check": "biome check . && node scripts/check-scanner.js && node scripts/check-generated.js && npm test",
24
- "format": "biome check --write . && node scripts/check-scanner.js --write",
27
+ "check": "biome check . && node scripts/check-c.js && node scripts/check-generated.js && npm test",
28
+ "format": "biome check --write . && node scripts/check-c.js --write",
25
29
  "generate": "npm run tree-sitter -- generate-all",
26
30
  "test": "npm run tree-sitter -- test-corpus --rebuild && node --test",
27
31
  "test:fuzz": "npm run tree-sitter -- fuzz-all --iterations 100 --edits 5",
@@ -56422,7 +56422,7 @@ TS_PUBLIC const TSLanguage *tree_sitter_sed_ere(void) {
56422
56422
  .max_reserved_word_set_size = 0,
56423
56423
  .metadata = {
56424
56424
  .major_version = 0,
56425
- .minor_version = 3,
56425
+ .minor_version = 4,
56426
56426
  .patch_version = 0,
56427
56427
  },
56428
56428
  };
package/src/parser.c CHANGED
@@ -58390,7 +58390,7 @@ TS_PUBLIC const TSLanguage *tree_sitter_sed(void) {
58390
58390
  .max_reserved_word_set_size = 0,
58391
58391
  .metadata = {
58392
58392
  .major_version = 0,
58393
- .minor_version = 3,
58393
+ .minor_version = 4,
58394
58394
  .patch_version = 0,
58395
58395
  },
58396
58396
  };
@@ -0,0 +1,9 @@
1
+ #include <stddef.h>
2
+ #include <tree_sitter/tree-sitter-sed.h>
3
+
4
+ int main(void) {
5
+ const TSLanguage *sed = tree_sitter_sed();
6
+ const TSLanguage *sed_ere = tree_sitter_sed_ere();
7
+
8
+ return sed == NULL || sed_ere == NULL || sed == sed_ere;
9
+ }
package/tree-sitter.json CHANGED
@@ -21,7 +21,7 @@
21
21
  }
22
22
  ],
23
23
  "metadata": {
24
- "version": "0.3.0",
24
+ "version": "0.4.0",
25
25
  "license": "MIT",
26
26
  "description": "Tree-sitter grammars for POSIX sed.",
27
27
  "authors": [
@@ -34,7 +34,7 @@
34
34
  }
35
35
  },
36
36
  "bindings": {
37
- "c": false,
37
+ "c": true,
38
38
  "go": false,
39
39
  "node": false,
40
40
  "python": false,