diff --git a/.gitignore b/.gitignore index 0671971dbc0217..c8319fc9e2bbd2 100644 --- a/.gitignore +++ b/.gitignore @@ -264,14 +264,14 @@ lcov*.info /lib/prism/reflection.rb /lib/prism/serialize.rb /lib/prism/visitor.rb +/prism/internal/diagnostic.h /prism/api_node.c /prism/ast.h /prism/diagnostic.c -/prism/diagnostic.h /prism/node.c /prism/prettyprint.c /prism/serialize.c -/prism/token_type.c +/prism/tokens.c /prism/srcs.mk /dump_ast diff --git a/box.c b/box.c index 4213f635601ce8..fba494f7ad2e1c 100644 --- a/box.c +++ b/box.c @@ -22,6 +22,9 @@ #include +#ifdef HAVE_FCNTL_H +#include +#endif #ifdef HAVE_SYS_SENDFILE_H # include #endif diff --git a/common.mk b/common.mk index d8c4166714f450..1c3ad312e587b7 100644 --- a/common.mk +++ b/common.mk @@ -90,27 +90,32 @@ MAKE_ENC = -f $(ENC_MK) V="$(V)" UNICODE_HDR_DIR="$(UNICODE_HDR_DIR)" \ PRISM_BUILD_DIR = prism -LIBPRISM_OBJS = prism/diagnostic.$(OBJEXT) \ +LIBPRISM_OBJS = \ + prism/arena.$(OBJEXT) \ + prism/buffer.$(OBJEXT) \ + prism/char.$(OBJEXT) \ + prism/constant_pool.$(OBJEXT) \ + prism/diagnostic.$(OBJEXT) \ prism/encoding.$(OBJEXT) \ + prism/integer.$(OBJEXT) \ + prism/json.$(OBJEXT) \ + prism/line_offset_list.$(OBJEXT) \ + prism/list.$(OBJEXT) \ + prism/memchr.$(OBJEXT) \ prism/node.$(OBJEXT) \ prism/options.$(OBJEXT) \ + prism/parser.$(OBJEXT) \ prism/prettyprint.$(OBJEXT) \ + prism/prism.$(OBJEXT) \ prism/regexp.$(OBJEXT) \ prism/serialize.$(OBJEXT) \ + prism/source.$(OBJEXT) \ prism/static_literals.$(OBJEXT) \ - prism/token_type.$(OBJEXT) \ - prism/util/pm_arena.$(OBJEXT) \ - prism/util/pm_buffer.$(OBJEXT) \ - prism/util/pm_char.$(OBJEXT) \ - prism/util/pm_constant_pool.$(OBJEXT) \ - prism/util/pm_integer.$(OBJEXT) \ - prism/util/pm_line_offset_list.$(OBJEXT) \ - prism/util/pm_list.$(OBJEXT) \ - prism/util/pm_memchr.$(OBJEXT) \ - prism/util/pm_string.$(OBJEXT) \ - prism/util/pm_strncasecmp.$(OBJEXT) \ - prism/util/pm_strpbrk.$(OBJEXT) \ - prism/prism.$(OBJEXT) + prism/string_query.$(OBJEXT) \ + prism/stringy.$(OBJEXT) \ + prism/strncasecmp.$(OBJEXT) \ + prism/strpbrk.$(OBJEXT) \ + prism/tokens.$(OBJEXT) EXTPRISM_OBJS = prism/api_node.$(OBJEXT) \ prism/extension.$(OBJEXT) \ @@ -118,6 +123,11 @@ EXTPRISM_OBJS = prism/api_node.$(OBJEXT) \ PRISM_OBJS = $(LIBPRISM_OBJS) $(EXTPRISM_OBJS) +# Prism objects depend on generated headers that are created from templates. +# This must be declared here to ensure parallel builds don't compile prism +# sources before the generated headers exist. +$(LIBPRISM_OBJS): $(srcdir)/prism/ast.h $(srcdir)/prism/internal/diagnostic.h + COMMONOBJS = \ array.$(OBJEXT) \ ast.$(OBJEXT) \ diff --git a/depend b/depend index 9f281861b91621..8481ad8222873c 100644 --- a/depend +++ b/depend @@ -306,28 +306,40 @@ ast.$(OBJEXT): $(top_srcdir)/internal/symbol.h ast.$(OBJEXT): $(top_srcdir)/internal/variable.h ast.$(OBJEXT): $(top_srcdir)/internal/vm.h ast.$(OBJEXT): $(top_srcdir)/internal/warnings.h +ast.$(OBJEXT): $(top_srcdir)/prism/arena.h ast.$(OBJEXT): $(top_srcdir)/prism/ast.h -ast.$(OBJEXT): $(top_srcdir)/prism/defines.h +ast.$(OBJEXT): $(top_srcdir)/prism/buffer.h +ast.$(OBJEXT): $(top_srcdir)/prism/comments.h +ast.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h +ast.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +ast.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h +ast.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +ast.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +ast.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h ast.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h -ast.$(OBJEXT): $(top_srcdir)/prism/encoding.h +ast.$(OBJEXT): $(top_srcdir)/prism/excludes.h +ast.$(OBJEXT): $(top_srcdir)/prism/integer.h +ast.$(OBJEXT): $(top_srcdir)/prism/internal/char.h +ast.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h +ast.$(OBJEXT): $(top_srcdir)/prism/internal/list.h +ast.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h +ast.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h +ast.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h +ast.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h +ast.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h +ast.$(OBJEXT): $(top_srcdir)/prism/json.h +ast.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h +ast.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h ast.$(OBJEXT): $(top_srcdir)/prism/node.h ast.$(OBJEXT): $(top_srcdir)/prism/options.h ast.$(OBJEXT): $(top_srcdir)/prism/parser.h ast.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h ast.$(OBJEXT): $(top_srcdir)/prism/prism.h -ast.$(OBJEXT): $(top_srcdir)/prism/regexp.h -ast.$(OBJEXT): $(top_srcdir)/prism/static_literals.h -ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_arena.h -ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h -ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h -ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h -ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h -ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_line_offset_list.h -ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h -ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h -ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h -ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h -ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +ast.$(OBJEXT): $(top_srcdir)/prism/serialize.h +ast.$(OBJEXT): $(top_srcdir)/prism/source.h +ast.$(OBJEXT): $(top_srcdir)/prism/stream.h +ast.$(OBJEXT): $(top_srcdir)/prism/string_query.h +ast.$(OBJEXT): $(top_srcdir)/prism/stringy.h ast.$(OBJEXT): $(top_srcdir)/prism/version.h ast.$(OBJEXT): {$(VPATH)}assert.h ast.$(OBJEXT): {$(VPATH)}ast.c @@ -762,28 +774,40 @@ box.$(OBJEXT): $(top_srcdir)/internal/struct.h box.$(OBJEXT): $(top_srcdir)/internal/variable.h box.$(OBJEXT): $(top_srcdir)/internal/vm.h box.$(OBJEXT): $(top_srcdir)/internal/warnings.h +box.$(OBJEXT): $(top_srcdir)/prism/arena.h box.$(OBJEXT): $(top_srcdir)/prism/ast.h -box.$(OBJEXT): $(top_srcdir)/prism/defines.h +box.$(OBJEXT): $(top_srcdir)/prism/buffer.h +box.$(OBJEXT): $(top_srcdir)/prism/comments.h +box.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h +box.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +box.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h +box.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +box.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +box.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h box.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h -box.$(OBJEXT): $(top_srcdir)/prism/encoding.h +box.$(OBJEXT): $(top_srcdir)/prism/excludes.h +box.$(OBJEXT): $(top_srcdir)/prism/integer.h +box.$(OBJEXT): $(top_srcdir)/prism/internal/char.h +box.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h +box.$(OBJEXT): $(top_srcdir)/prism/internal/list.h +box.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h +box.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h +box.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h +box.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h +box.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h +box.$(OBJEXT): $(top_srcdir)/prism/json.h +box.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h +box.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h box.$(OBJEXT): $(top_srcdir)/prism/node.h box.$(OBJEXT): $(top_srcdir)/prism/options.h box.$(OBJEXT): $(top_srcdir)/prism/parser.h box.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h box.$(OBJEXT): $(top_srcdir)/prism/prism.h -box.$(OBJEXT): $(top_srcdir)/prism/regexp.h -box.$(OBJEXT): $(top_srcdir)/prism/static_literals.h -box.$(OBJEXT): $(top_srcdir)/prism/util/pm_arena.h -box.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h -box.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h -box.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h -box.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h -box.$(OBJEXT): $(top_srcdir)/prism/util/pm_line_offset_list.h -box.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h -box.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h -box.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h -box.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h -box.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +box.$(OBJEXT): $(top_srcdir)/prism/serialize.h +box.$(OBJEXT): $(top_srcdir)/prism/source.h +box.$(OBJEXT): $(top_srcdir)/prism/stream.h +box.$(OBJEXT): $(top_srcdir)/prism/string_query.h +box.$(OBJEXT): $(top_srcdir)/prism/stringy.h box.$(OBJEXT): $(top_srcdir)/prism/version.h box.$(OBJEXT): {$(VPATH)}assert.h box.$(OBJEXT): {$(VPATH)}atomic.h @@ -1004,28 +1028,40 @@ builtin.$(OBJEXT): $(top_srcdir)/internal/struct.h builtin.$(OBJEXT): $(top_srcdir)/internal/variable.h builtin.$(OBJEXT): $(top_srcdir)/internal/vm.h builtin.$(OBJEXT): $(top_srcdir)/internal/warnings.h +builtin.$(OBJEXT): $(top_srcdir)/prism/arena.h builtin.$(OBJEXT): $(top_srcdir)/prism/ast.h -builtin.$(OBJEXT): $(top_srcdir)/prism/defines.h +builtin.$(OBJEXT): $(top_srcdir)/prism/buffer.h +builtin.$(OBJEXT): $(top_srcdir)/prism/comments.h +builtin.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h +builtin.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +builtin.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h +builtin.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +builtin.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +builtin.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h builtin.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h -builtin.$(OBJEXT): $(top_srcdir)/prism/encoding.h +builtin.$(OBJEXT): $(top_srcdir)/prism/excludes.h +builtin.$(OBJEXT): $(top_srcdir)/prism/integer.h +builtin.$(OBJEXT): $(top_srcdir)/prism/internal/char.h +builtin.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h +builtin.$(OBJEXT): $(top_srcdir)/prism/internal/list.h +builtin.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h +builtin.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h +builtin.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h +builtin.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h +builtin.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h +builtin.$(OBJEXT): $(top_srcdir)/prism/json.h +builtin.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h +builtin.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h builtin.$(OBJEXT): $(top_srcdir)/prism/node.h builtin.$(OBJEXT): $(top_srcdir)/prism/options.h builtin.$(OBJEXT): $(top_srcdir)/prism/parser.h builtin.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h builtin.$(OBJEXT): $(top_srcdir)/prism/prism.h -builtin.$(OBJEXT): $(top_srcdir)/prism/regexp.h -builtin.$(OBJEXT): $(top_srcdir)/prism/static_literals.h -builtin.$(OBJEXT): $(top_srcdir)/prism/util/pm_arena.h -builtin.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h -builtin.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h -builtin.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h -builtin.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h -builtin.$(OBJEXT): $(top_srcdir)/prism/util/pm_line_offset_list.h -builtin.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h -builtin.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h -builtin.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h -builtin.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h -builtin.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +builtin.$(OBJEXT): $(top_srcdir)/prism/serialize.h +builtin.$(OBJEXT): $(top_srcdir)/prism/source.h +builtin.$(OBJEXT): $(top_srcdir)/prism/stream.h +builtin.$(OBJEXT): $(top_srcdir)/prism/string_query.h +builtin.$(OBJEXT): $(top_srcdir)/prism/stringy.h builtin.$(OBJEXT): $(top_srcdir)/prism/version.h builtin.$(OBJEXT): {$(VPATH)}assert.h builtin.$(OBJEXT): {$(VPATH)}atomic.h @@ -1657,28 +1693,40 @@ compile.$(OBJEXT): $(top_srcdir)/internal/thread.h compile.$(OBJEXT): $(top_srcdir)/internal/variable.h compile.$(OBJEXT): $(top_srcdir)/internal/vm.h compile.$(OBJEXT): $(top_srcdir)/internal/warnings.h +compile.$(OBJEXT): $(top_srcdir)/prism/arena.h compile.$(OBJEXT): $(top_srcdir)/prism/ast.h -compile.$(OBJEXT): $(top_srcdir)/prism/defines.h +compile.$(OBJEXT): $(top_srcdir)/prism/buffer.h +compile.$(OBJEXT): $(top_srcdir)/prism/comments.h +compile.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h +compile.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +compile.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h +compile.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +compile.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +compile.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h compile.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h -compile.$(OBJEXT): $(top_srcdir)/prism/encoding.h +compile.$(OBJEXT): $(top_srcdir)/prism/excludes.h +compile.$(OBJEXT): $(top_srcdir)/prism/integer.h +compile.$(OBJEXT): $(top_srcdir)/prism/internal/char.h +compile.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h +compile.$(OBJEXT): $(top_srcdir)/prism/internal/list.h +compile.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h +compile.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h +compile.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h +compile.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h +compile.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h +compile.$(OBJEXT): $(top_srcdir)/prism/json.h +compile.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h +compile.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h compile.$(OBJEXT): $(top_srcdir)/prism/node.h compile.$(OBJEXT): $(top_srcdir)/prism/options.h compile.$(OBJEXT): $(top_srcdir)/prism/parser.h compile.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h compile.$(OBJEXT): $(top_srcdir)/prism/prism.h -compile.$(OBJEXT): $(top_srcdir)/prism/regexp.h -compile.$(OBJEXT): $(top_srcdir)/prism/static_literals.h -compile.$(OBJEXT): $(top_srcdir)/prism/util/pm_arena.h -compile.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h -compile.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h -compile.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h -compile.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h -compile.$(OBJEXT): $(top_srcdir)/prism/util/pm_line_offset_list.h -compile.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h -compile.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h -compile.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h -compile.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h -compile.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +compile.$(OBJEXT): $(top_srcdir)/prism/serialize.h +compile.$(OBJEXT): $(top_srcdir)/prism/source.h +compile.$(OBJEXT): $(top_srcdir)/prism/stream.h +compile.$(OBJEXT): $(top_srcdir)/prism/string_query.h +compile.$(OBJEXT): $(top_srcdir)/prism/stringy.h compile.$(OBJEXT): $(top_srcdir)/prism/version.h compile.$(OBJEXT): $(top_srcdir)/prism_compile.c compile.$(OBJEXT): {$(VPATH)}assert.h @@ -2339,28 +2387,40 @@ cont.$(OBJEXT): $(top_srcdir)/internal/thread.h cont.$(OBJEXT): $(top_srcdir)/internal/variable.h cont.$(OBJEXT): $(top_srcdir)/internal/vm.h cont.$(OBJEXT): $(top_srcdir)/internal/warnings.h +cont.$(OBJEXT): $(top_srcdir)/prism/arena.h cont.$(OBJEXT): $(top_srcdir)/prism/ast.h -cont.$(OBJEXT): $(top_srcdir)/prism/defines.h +cont.$(OBJEXT): $(top_srcdir)/prism/buffer.h +cont.$(OBJEXT): $(top_srcdir)/prism/comments.h +cont.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h +cont.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +cont.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h +cont.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +cont.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +cont.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h cont.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h -cont.$(OBJEXT): $(top_srcdir)/prism/encoding.h +cont.$(OBJEXT): $(top_srcdir)/prism/excludes.h +cont.$(OBJEXT): $(top_srcdir)/prism/integer.h +cont.$(OBJEXT): $(top_srcdir)/prism/internal/char.h +cont.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h +cont.$(OBJEXT): $(top_srcdir)/prism/internal/list.h +cont.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h +cont.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h +cont.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h +cont.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h +cont.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h +cont.$(OBJEXT): $(top_srcdir)/prism/json.h +cont.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h +cont.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h cont.$(OBJEXT): $(top_srcdir)/prism/node.h cont.$(OBJEXT): $(top_srcdir)/prism/options.h cont.$(OBJEXT): $(top_srcdir)/prism/parser.h cont.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h cont.$(OBJEXT): $(top_srcdir)/prism/prism.h -cont.$(OBJEXT): $(top_srcdir)/prism/regexp.h -cont.$(OBJEXT): $(top_srcdir)/prism/static_literals.h -cont.$(OBJEXT): $(top_srcdir)/prism/util/pm_arena.h -cont.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h -cont.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h -cont.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h -cont.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h -cont.$(OBJEXT): $(top_srcdir)/prism/util/pm_line_offset_list.h -cont.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h -cont.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h -cont.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h -cont.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h -cont.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +cont.$(OBJEXT): $(top_srcdir)/prism/serialize.h +cont.$(OBJEXT): $(top_srcdir)/prism/source.h +cont.$(OBJEXT): $(top_srcdir)/prism/stream.h +cont.$(OBJEXT): $(top_srcdir)/prism/string_query.h +cont.$(OBJEXT): $(top_srcdir)/prism/stringy.h cont.$(OBJEXT): $(top_srcdir)/prism/version.h cont.$(OBJEXT): {$(VPATH)}$(COROUTINE_H) cont.$(OBJEXT): {$(VPATH)}assert.h @@ -3639,28 +3699,40 @@ dmydln.$(OBJEXT): {$(VPATH)}st.h dmydln.$(OBJEXT): {$(VPATH)}subst.h dmyenc.$(OBJEXT): {$(VPATH)}dmyenc.c dmyext.$(OBJEXT): {$(VPATH)}dmyext.c +dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/arena.h dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/ast.h -dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/defines.h +dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/buffer.h +dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/comments.h +dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h +dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h +dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h -dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/encoding.h +dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/excludes.h +dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/integer.h +dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/internal/char.h +dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h +dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/internal/list.h +dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h +dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h +dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h +dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h +dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h +dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/json.h +dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h +dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/node.h dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/options.h dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/parser.h dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/prism.h -dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/regexp.h -dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/static_literals.h -dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_arena.h -dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h -dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h -dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h -dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h -dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_line_offset_list.h -dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h -dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h -dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h -dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h -dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/serialize.h +dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/source.h +dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/stream.h +dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/string_query.h +dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/stringy.h dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/version.h dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/tool/dump_ast.c enc/ascii.$(OBJEXT): $(hdrdir)/ruby/ruby.h @@ -5379,28 +5451,40 @@ eval.$(OBJEXT): $(top_srcdir)/internal/thread.h eval.$(OBJEXT): $(top_srcdir)/internal/variable.h eval.$(OBJEXT): $(top_srcdir)/internal/vm.h eval.$(OBJEXT): $(top_srcdir)/internal/warnings.h +eval.$(OBJEXT): $(top_srcdir)/prism/arena.h eval.$(OBJEXT): $(top_srcdir)/prism/ast.h -eval.$(OBJEXT): $(top_srcdir)/prism/defines.h +eval.$(OBJEXT): $(top_srcdir)/prism/buffer.h +eval.$(OBJEXT): $(top_srcdir)/prism/comments.h +eval.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h +eval.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +eval.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h +eval.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +eval.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +eval.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h eval.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h -eval.$(OBJEXT): $(top_srcdir)/prism/encoding.h +eval.$(OBJEXT): $(top_srcdir)/prism/excludes.h +eval.$(OBJEXT): $(top_srcdir)/prism/integer.h +eval.$(OBJEXT): $(top_srcdir)/prism/internal/char.h +eval.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h +eval.$(OBJEXT): $(top_srcdir)/prism/internal/list.h +eval.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h +eval.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h +eval.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h +eval.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h +eval.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h +eval.$(OBJEXT): $(top_srcdir)/prism/json.h +eval.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h +eval.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h eval.$(OBJEXT): $(top_srcdir)/prism/node.h eval.$(OBJEXT): $(top_srcdir)/prism/options.h eval.$(OBJEXT): $(top_srcdir)/prism/parser.h eval.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h eval.$(OBJEXT): $(top_srcdir)/prism/prism.h -eval.$(OBJEXT): $(top_srcdir)/prism/regexp.h -eval.$(OBJEXT): $(top_srcdir)/prism/static_literals.h -eval.$(OBJEXT): $(top_srcdir)/prism/util/pm_arena.h -eval.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h -eval.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h -eval.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h -eval.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h -eval.$(OBJEXT): $(top_srcdir)/prism/util/pm_line_offset_list.h -eval.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h -eval.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h -eval.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h -eval.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h -eval.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +eval.$(OBJEXT): $(top_srcdir)/prism/serialize.h +eval.$(OBJEXT): $(top_srcdir)/prism/source.h +eval.$(OBJEXT): $(top_srcdir)/prism/stream.h +eval.$(OBJEXT): $(top_srcdir)/prism/string_query.h +eval.$(OBJEXT): $(top_srcdir)/prism/stringy.h eval.$(OBJEXT): $(top_srcdir)/prism/version.h eval.$(OBJEXT): {$(VPATH)}assert.h eval.$(OBJEXT): {$(VPATH)}atomic.h @@ -5872,28 +5956,40 @@ gc.$(OBJEXT): $(top_srcdir)/internal/thread.h gc.$(OBJEXT): $(top_srcdir)/internal/variable.h gc.$(OBJEXT): $(top_srcdir)/internal/vm.h gc.$(OBJEXT): $(top_srcdir)/internal/warnings.h +gc.$(OBJEXT): $(top_srcdir)/prism/arena.h gc.$(OBJEXT): $(top_srcdir)/prism/ast.h -gc.$(OBJEXT): $(top_srcdir)/prism/defines.h +gc.$(OBJEXT): $(top_srcdir)/prism/buffer.h +gc.$(OBJEXT): $(top_srcdir)/prism/comments.h +gc.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h +gc.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +gc.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h +gc.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +gc.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +gc.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h gc.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h -gc.$(OBJEXT): $(top_srcdir)/prism/encoding.h +gc.$(OBJEXT): $(top_srcdir)/prism/excludes.h +gc.$(OBJEXT): $(top_srcdir)/prism/integer.h +gc.$(OBJEXT): $(top_srcdir)/prism/internal/char.h +gc.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h +gc.$(OBJEXT): $(top_srcdir)/prism/internal/list.h +gc.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h +gc.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h +gc.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h +gc.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h +gc.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h +gc.$(OBJEXT): $(top_srcdir)/prism/json.h +gc.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h +gc.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h gc.$(OBJEXT): $(top_srcdir)/prism/node.h gc.$(OBJEXT): $(top_srcdir)/prism/options.h gc.$(OBJEXT): $(top_srcdir)/prism/parser.h gc.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h gc.$(OBJEXT): $(top_srcdir)/prism/prism.h -gc.$(OBJEXT): $(top_srcdir)/prism/regexp.h -gc.$(OBJEXT): $(top_srcdir)/prism/static_literals.h -gc.$(OBJEXT): $(top_srcdir)/prism/util/pm_arena.h -gc.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h -gc.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h -gc.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h -gc.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h -gc.$(OBJEXT): $(top_srcdir)/prism/util/pm_line_offset_list.h -gc.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h -gc.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h -gc.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h -gc.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h -gc.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +gc.$(OBJEXT): $(top_srcdir)/prism/serialize.h +gc.$(OBJEXT): $(top_srcdir)/prism/source.h +gc.$(OBJEXT): $(top_srcdir)/prism/stream.h +gc.$(OBJEXT): $(top_srcdir)/prism/string_query.h +gc.$(OBJEXT): $(top_srcdir)/prism/stringy.h gc.$(OBJEXT): $(top_srcdir)/prism/version.h gc.$(OBJEXT): {$(VPATH)}assert.h gc.$(OBJEXT): {$(VPATH)}atomic.h @@ -6137,28 +6233,27 @@ goruby.$(OBJEXT): $(top_srcdir)/internal/static_assert.h goruby.$(OBJEXT): $(top_srcdir)/internal/variable.h goruby.$(OBJEXT): $(top_srcdir)/internal/vm.h goruby.$(OBJEXT): $(top_srcdir)/internal/warnings.h +goruby.$(OBJEXT): $(top_srcdir)/prism/arena.h goruby.$(OBJEXT): $(top_srcdir)/prism/ast.h -goruby.$(OBJEXT): $(top_srcdir)/prism/defines.h +goruby.$(OBJEXT): $(top_srcdir)/prism/buffer.h +goruby.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h goruby.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h -goruby.$(OBJEXT): $(top_srcdir)/prism/encoding.h +goruby.$(OBJEXT): $(top_srcdir)/prism/integer.h +goruby.$(OBJEXT): $(top_srcdir)/prism/internal/char.h +goruby.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h +goruby.$(OBJEXT): $(top_srcdir)/prism/internal/list.h +goruby.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h +goruby.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h +goruby.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h +goruby.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h +goruby.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h +goruby.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h goruby.$(OBJEXT): $(top_srcdir)/prism/node.h goruby.$(OBJEXT): $(top_srcdir)/prism/options.h goruby.$(OBJEXT): $(top_srcdir)/prism/parser.h goruby.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h goruby.$(OBJEXT): $(top_srcdir)/prism/prism.h -goruby.$(OBJEXT): $(top_srcdir)/prism/regexp.h -goruby.$(OBJEXT): $(top_srcdir)/prism/static_literals.h -goruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_arena.h -goruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h -goruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h -goruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h -goruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h -goruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_line_offset_list.h -goruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h -goruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h -goruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h -goruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h -goruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +goruby.$(OBJEXT): $(top_srcdir)/prism/stringy.h goruby.$(OBJEXT): $(top_srcdir)/prism/version.h goruby.$(OBJEXT): {$(VPATH)}assert.h goruby.$(OBJEXT): {$(VPATH)}atomic.h @@ -6384,28 +6479,40 @@ hash.$(OBJEXT): $(top_srcdir)/internal/time.h hash.$(OBJEXT): $(top_srcdir)/internal/variable.h hash.$(OBJEXT): $(top_srcdir)/internal/vm.h hash.$(OBJEXT): $(top_srcdir)/internal/warnings.h +hash.$(OBJEXT): $(top_srcdir)/prism/arena.h hash.$(OBJEXT): $(top_srcdir)/prism/ast.h -hash.$(OBJEXT): $(top_srcdir)/prism/defines.h +hash.$(OBJEXT): $(top_srcdir)/prism/buffer.h +hash.$(OBJEXT): $(top_srcdir)/prism/comments.h +hash.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h +hash.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +hash.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h +hash.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +hash.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +hash.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h hash.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h -hash.$(OBJEXT): $(top_srcdir)/prism/encoding.h +hash.$(OBJEXT): $(top_srcdir)/prism/excludes.h +hash.$(OBJEXT): $(top_srcdir)/prism/integer.h +hash.$(OBJEXT): $(top_srcdir)/prism/internal/char.h +hash.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h +hash.$(OBJEXT): $(top_srcdir)/prism/internal/list.h +hash.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h +hash.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h +hash.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h +hash.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h +hash.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h +hash.$(OBJEXT): $(top_srcdir)/prism/json.h +hash.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h +hash.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h hash.$(OBJEXT): $(top_srcdir)/prism/node.h hash.$(OBJEXT): $(top_srcdir)/prism/options.h hash.$(OBJEXT): $(top_srcdir)/prism/parser.h hash.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h hash.$(OBJEXT): $(top_srcdir)/prism/prism.h -hash.$(OBJEXT): $(top_srcdir)/prism/regexp.h -hash.$(OBJEXT): $(top_srcdir)/prism/static_literals.h -hash.$(OBJEXT): $(top_srcdir)/prism/util/pm_arena.h -hash.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h -hash.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h -hash.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h -hash.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h -hash.$(OBJEXT): $(top_srcdir)/prism/util/pm_line_offset_list.h -hash.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h -hash.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h -hash.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h -hash.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h -hash.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +hash.$(OBJEXT): $(top_srcdir)/prism/serialize.h +hash.$(OBJEXT): $(top_srcdir)/prism/source.h +hash.$(OBJEXT): $(top_srcdir)/prism/stream.h +hash.$(OBJEXT): $(top_srcdir)/prism/string_query.h +hash.$(OBJEXT): $(top_srcdir)/prism/stringy.h hash.$(OBJEXT): $(top_srcdir)/prism/version.h hash.$(OBJEXT): {$(VPATH)}assert.h hash.$(OBJEXT): {$(VPATH)}atomic.h @@ -7471,28 +7578,40 @@ iseq.$(OBJEXT): $(top_srcdir)/internal/thread.h iseq.$(OBJEXT): $(top_srcdir)/internal/variable.h iseq.$(OBJEXT): $(top_srcdir)/internal/vm.h iseq.$(OBJEXT): $(top_srcdir)/internal/warnings.h +iseq.$(OBJEXT): $(top_srcdir)/prism/arena.h iseq.$(OBJEXT): $(top_srcdir)/prism/ast.h -iseq.$(OBJEXT): $(top_srcdir)/prism/defines.h +iseq.$(OBJEXT): $(top_srcdir)/prism/buffer.h +iseq.$(OBJEXT): $(top_srcdir)/prism/comments.h +iseq.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h +iseq.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +iseq.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h +iseq.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +iseq.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +iseq.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h iseq.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h -iseq.$(OBJEXT): $(top_srcdir)/prism/encoding.h +iseq.$(OBJEXT): $(top_srcdir)/prism/excludes.h +iseq.$(OBJEXT): $(top_srcdir)/prism/integer.h +iseq.$(OBJEXT): $(top_srcdir)/prism/internal/char.h +iseq.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h +iseq.$(OBJEXT): $(top_srcdir)/prism/internal/list.h +iseq.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h +iseq.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h +iseq.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h +iseq.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h +iseq.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h +iseq.$(OBJEXT): $(top_srcdir)/prism/json.h +iseq.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h +iseq.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h iseq.$(OBJEXT): $(top_srcdir)/prism/node.h iseq.$(OBJEXT): $(top_srcdir)/prism/options.h iseq.$(OBJEXT): $(top_srcdir)/prism/parser.h iseq.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h iseq.$(OBJEXT): $(top_srcdir)/prism/prism.h -iseq.$(OBJEXT): $(top_srcdir)/prism/regexp.h -iseq.$(OBJEXT): $(top_srcdir)/prism/static_literals.h -iseq.$(OBJEXT): $(top_srcdir)/prism/util/pm_arena.h -iseq.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h -iseq.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h -iseq.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h -iseq.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h -iseq.$(OBJEXT): $(top_srcdir)/prism/util/pm_line_offset_list.h -iseq.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h -iseq.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h -iseq.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h -iseq.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h -iseq.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +iseq.$(OBJEXT): $(top_srcdir)/prism/serialize.h +iseq.$(OBJEXT): $(top_srcdir)/prism/source.h +iseq.$(OBJEXT): $(top_srcdir)/prism/stream.h +iseq.$(OBJEXT): $(top_srcdir)/prism/string_query.h +iseq.$(OBJEXT): $(top_srcdir)/prism/stringy.h iseq.$(OBJEXT): $(top_srcdir)/prism/version.h iseq.$(OBJEXT): {$(VPATH)}assert.h iseq.$(OBJEXT): {$(VPATH)}atomic.h @@ -7721,28 +7840,40 @@ jit.$(OBJEXT): $(top_srcdir)/internal/struct.h jit.$(OBJEXT): $(top_srcdir)/internal/variable.h jit.$(OBJEXT): $(top_srcdir)/internal/vm.h jit.$(OBJEXT): $(top_srcdir)/internal/warnings.h +jit.$(OBJEXT): $(top_srcdir)/prism/arena.h jit.$(OBJEXT): $(top_srcdir)/prism/ast.h -jit.$(OBJEXT): $(top_srcdir)/prism/defines.h +jit.$(OBJEXT): $(top_srcdir)/prism/buffer.h +jit.$(OBJEXT): $(top_srcdir)/prism/comments.h +jit.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h +jit.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +jit.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h +jit.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +jit.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +jit.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h jit.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h -jit.$(OBJEXT): $(top_srcdir)/prism/encoding.h +jit.$(OBJEXT): $(top_srcdir)/prism/excludes.h +jit.$(OBJEXT): $(top_srcdir)/prism/integer.h +jit.$(OBJEXT): $(top_srcdir)/prism/internal/char.h +jit.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h +jit.$(OBJEXT): $(top_srcdir)/prism/internal/list.h +jit.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h +jit.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h +jit.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h +jit.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h +jit.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h +jit.$(OBJEXT): $(top_srcdir)/prism/json.h +jit.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h +jit.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h jit.$(OBJEXT): $(top_srcdir)/prism/node.h jit.$(OBJEXT): $(top_srcdir)/prism/options.h jit.$(OBJEXT): $(top_srcdir)/prism/parser.h jit.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h jit.$(OBJEXT): $(top_srcdir)/prism/prism.h -jit.$(OBJEXT): $(top_srcdir)/prism/regexp.h -jit.$(OBJEXT): $(top_srcdir)/prism/static_literals.h -jit.$(OBJEXT): $(top_srcdir)/prism/util/pm_arena.h -jit.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h -jit.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h -jit.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h -jit.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h -jit.$(OBJEXT): $(top_srcdir)/prism/util/pm_line_offset_list.h -jit.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h -jit.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h -jit.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h -jit.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h -jit.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +jit.$(OBJEXT): $(top_srcdir)/prism/serialize.h +jit.$(OBJEXT): $(top_srcdir)/prism/source.h +jit.$(OBJEXT): $(top_srcdir)/prism/stream.h +jit.$(OBJEXT): $(top_srcdir)/prism/string_query.h +jit.$(OBJEXT): $(top_srcdir)/prism/stringy.h jit.$(OBJEXT): $(top_srcdir)/prism/version.h jit.$(OBJEXT): {$(VPATH)}assert.h jit.$(OBJEXT): {$(VPATH)}atomic.h @@ -7978,28 +8109,40 @@ load.$(OBJEXT): $(top_srcdir)/internal/thread.h load.$(OBJEXT): $(top_srcdir)/internal/variable.h load.$(OBJEXT): $(top_srcdir)/internal/vm.h load.$(OBJEXT): $(top_srcdir)/internal/warnings.h +load.$(OBJEXT): $(top_srcdir)/prism/arena.h load.$(OBJEXT): $(top_srcdir)/prism/ast.h -load.$(OBJEXT): $(top_srcdir)/prism/defines.h +load.$(OBJEXT): $(top_srcdir)/prism/buffer.h +load.$(OBJEXT): $(top_srcdir)/prism/comments.h +load.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h +load.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +load.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h +load.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +load.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +load.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h load.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h -load.$(OBJEXT): $(top_srcdir)/prism/encoding.h +load.$(OBJEXT): $(top_srcdir)/prism/excludes.h +load.$(OBJEXT): $(top_srcdir)/prism/integer.h +load.$(OBJEXT): $(top_srcdir)/prism/internal/char.h +load.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h +load.$(OBJEXT): $(top_srcdir)/prism/internal/list.h +load.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h +load.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h +load.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h +load.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h +load.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h +load.$(OBJEXT): $(top_srcdir)/prism/json.h +load.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h +load.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h load.$(OBJEXT): $(top_srcdir)/prism/node.h load.$(OBJEXT): $(top_srcdir)/prism/options.h load.$(OBJEXT): $(top_srcdir)/prism/parser.h load.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h load.$(OBJEXT): $(top_srcdir)/prism/prism.h -load.$(OBJEXT): $(top_srcdir)/prism/regexp.h -load.$(OBJEXT): $(top_srcdir)/prism/static_literals.h -load.$(OBJEXT): $(top_srcdir)/prism/util/pm_arena.h -load.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h -load.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h -load.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h -load.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h -load.$(OBJEXT): $(top_srcdir)/prism/util/pm_line_offset_list.h -load.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h -load.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h -load.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h -load.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h -load.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +load.$(OBJEXT): $(top_srcdir)/prism/serialize.h +load.$(OBJEXT): $(top_srcdir)/prism/source.h +load.$(OBJEXT): $(top_srcdir)/prism/stream.h +load.$(OBJEXT): $(top_srcdir)/prism/string_query.h +load.$(OBJEXT): $(top_srcdir)/prism/stringy.h load.$(OBJEXT): $(top_srcdir)/prism/version.h load.$(OBJEXT): {$(VPATH)}assert.h load.$(OBJEXT): {$(VPATH)}atomic.h @@ -9338,28 +9481,40 @@ miniinit.$(OBJEXT): $(top_srcdir)/internal/struct.h miniinit.$(OBJEXT): $(top_srcdir)/internal/variable.h miniinit.$(OBJEXT): $(top_srcdir)/internal/vm.h miniinit.$(OBJEXT): $(top_srcdir)/internal/warnings.h +miniinit.$(OBJEXT): $(top_srcdir)/prism/arena.h miniinit.$(OBJEXT): $(top_srcdir)/prism/ast.h -miniinit.$(OBJEXT): $(top_srcdir)/prism/defines.h +miniinit.$(OBJEXT): $(top_srcdir)/prism/buffer.h +miniinit.$(OBJEXT): $(top_srcdir)/prism/comments.h +miniinit.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h +miniinit.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +miniinit.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h +miniinit.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +miniinit.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +miniinit.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h miniinit.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h -miniinit.$(OBJEXT): $(top_srcdir)/prism/encoding.h +miniinit.$(OBJEXT): $(top_srcdir)/prism/excludes.h +miniinit.$(OBJEXT): $(top_srcdir)/prism/integer.h +miniinit.$(OBJEXT): $(top_srcdir)/prism/internal/char.h +miniinit.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h +miniinit.$(OBJEXT): $(top_srcdir)/prism/internal/list.h +miniinit.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h +miniinit.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h +miniinit.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h +miniinit.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h +miniinit.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h +miniinit.$(OBJEXT): $(top_srcdir)/prism/json.h +miniinit.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h +miniinit.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h miniinit.$(OBJEXT): $(top_srcdir)/prism/node.h miniinit.$(OBJEXT): $(top_srcdir)/prism/options.h miniinit.$(OBJEXT): $(top_srcdir)/prism/parser.h miniinit.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h miniinit.$(OBJEXT): $(top_srcdir)/prism/prism.h -miniinit.$(OBJEXT): $(top_srcdir)/prism/regexp.h -miniinit.$(OBJEXT): $(top_srcdir)/prism/static_literals.h -miniinit.$(OBJEXT): $(top_srcdir)/prism/util/pm_arena.h -miniinit.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h -miniinit.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h -miniinit.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h -miniinit.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h -miniinit.$(OBJEXT): $(top_srcdir)/prism/util/pm_line_offset_list.h -miniinit.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h -miniinit.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h -miniinit.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h -miniinit.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h -miniinit.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +miniinit.$(OBJEXT): $(top_srcdir)/prism/serialize.h +miniinit.$(OBJEXT): $(top_srcdir)/prism/source.h +miniinit.$(OBJEXT): $(top_srcdir)/prism/stream.h +miniinit.$(OBJEXT): $(top_srcdir)/prism/string_query.h +miniinit.$(OBJEXT): $(top_srcdir)/prism/stringy.h miniinit.$(OBJEXT): $(top_srcdir)/prism/version.h miniinit.$(OBJEXT): {$(VPATH)}array.rb miniinit.$(OBJEXT): {$(VPATH)}assert.h @@ -11152,29 +11307,46 @@ prism/api_node.$(OBJEXT): $(hdrdir)/ruby.h prism/api_node.$(OBJEXT): $(hdrdir)/ruby/ruby.h prism/api_node.$(OBJEXT): $(hdrdir)/ruby/version.h prism/api_node.$(OBJEXT): $(top_srcdir)/prism/api_node.c +prism/api_node.$(OBJEXT): $(top_srcdir)/prism/arena.h prism/api_node.$(OBJEXT): $(top_srcdir)/prism/ast.h -prism/api_node.$(OBJEXT): $(top_srcdir)/prism/defines.h +prism/api_node.$(OBJEXT): $(top_srcdir)/prism/buffer.h +prism/api_node.$(OBJEXT): $(top_srcdir)/prism/comments.h +prism/api_node.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h +prism/api_node.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +prism/api_node.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h +prism/api_node.$(OBJEXT): $(top_srcdir)/prism/compiler/flex_array.h +prism/api_node.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h +prism/api_node.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h +prism/api_node.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +prism/api_node.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +prism/api_node.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h prism/api_node.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h -prism/api_node.$(OBJEXT): $(top_srcdir)/prism/encoding.h +prism/api_node.$(OBJEXT): $(top_srcdir)/prism/excludes.h prism/api_node.$(OBJEXT): $(top_srcdir)/prism/extension.h +prism/api_node.$(OBJEXT): $(top_srcdir)/prism/integer.h +prism/api_node.$(OBJEXT): $(top_srcdir)/prism/internal/allocator.h +prism/api_node.$(OBJEXT): $(top_srcdir)/prism/internal/arena.h +prism/api_node.$(OBJEXT): $(top_srcdir)/prism/internal/char.h +prism/api_node.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h +prism/api_node.$(OBJEXT): $(top_srcdir)/prism/internal/list.h +prism/api_node.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h +prism/api_node.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h +prism/api_node.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h +prism/api_node.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h +prism/api_node.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h +prism/api_node.$(OBJEXT): $(top_srcdir)/prism/json.h +prism/api_node.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h +prism/api_node.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h prism/api_node.$(OBJEXT): $(top_srcdir)/prism/node.h prism/api_node.$(OBJEXT): $(top_srcdir)/prism/options.h prism/api_node.$(OBJEXT): $(top_srcdir)/prism/parser.h prism/api_node.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h prism/api_node.$(OBJEXT): $(top_srcdir)/prism/prism.h -prism/api_node.$(OBJEXT): $(top_srcdir)/prism/regexp.h -prism/api_node.$(OBJEXT): $(top_srcdir)/prism/static_literals.h -prism/api_node.$(OBJEXT): $(top_srcdir)/prism/util/pm_arena.h -prism/api_node.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h -prism/api_node.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h -prism/api_node.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h -prism/api_node.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h -prism/api_node.$(OBJEXT): $(top_srcdir)/prism/util/pm_line_offset_list.h -prism/api_node.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h -prism/api_node.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h -prism/api_node.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h -prism/api_node.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h -prism/api_node.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +prism/api_node.$(OBJEXT): $(top_srcdir)/prism/serialize.h +prism/api_node.$(OBJEXT): $(top_srcdir)/prism/source.h +prism/api_node.$(OBJEXT): $(top_srcdir)/prism/stream.h +prism/api_node.$(OBJEXT): $(top_srcdir)/prism/string_query.h +prism/api_node.$(OBJEXT): $(top_srcdir)/prism/stringy.h prism/api_node.$(OBJEXT): $(top_srcdir)/prism/version.h prism/api_node.$(OBJEXT): {$(VPATH)}assert.h prism/api_node.$(OBJEXT): {$(VPATH)}backward/2/assume.h @@ -11345,18 +11517,168 @@ prism/api_node.$(OBJEXT): {$(VPATH)}oniguruma.h prism/api_node.$(OBJEXT): {$(VPATH)}prism_xallocator.h prism/api_node.$(OBJEXT): {$(VPATH)}st.h prism/api_node.$(OBJEXT): {$(VPATH)}subst.h +prism/arena.$(OBJEXT): $(top_srcdir)/prism/arena.c +prism/arena.$(OBJEXT): $(top_srcdir)/prism/arena.h +prism/arena.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +prism/arena.$(OBJEXT): $(top_srcdir)/prism/compiler/flex_array.h +prism/arena.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h +prism/arena.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h +prism/arena.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +prism/arena.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +prism/arena.$(OBJEXT): $(top_srcdir)/prism/internal/allocator.h +prism/arena.$(OBJEXT): $(top_srcdir)/prism/internal/arena.h +prism/arena.$(OBJEXT): {$(VPATH)}config.h +prism/arena.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h +prism/arena.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h +prism/arena.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h +prism/arena.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h +prism/arena.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h +prism/arena.$(OBJEXT): {$(VPATH)}internal/compiler_is.h +prism/arena.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h +prism/arena.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h +prism/arena.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h +prism/arena.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h +prism/arena.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h +prism/arena.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h +prism/arena.$(OBJEXT): {$(VPATH)}internal/compiler_since.h +prism/arena.$(OBJEXT): {$(VPATH)}internal/config.h +prism/arena.$(OBJEXT): {$(VPATH)}internal/dllexport.h +prism/arena.$(OBJEXT): {$(VPATH)}internal/has/attribute.h +prism/arena.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h +prism/arena.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h +prism/arena.$(OBJEXT): {$(VPATH)}internal/has/extension.h +prism/arena.$(OBJEXT): {$(VPATH)}internal/has/feature.h +prism/arena.$(OBJEXT): {$(VPATH)}internal/has/warning.h +prism/arena.$(OBJEXT): {$(VPATH)}internal/xmalloc.h +prism/arena.$(OBJEXT): {$(VPATH)}prism_xallocator.h +prism/buffer.$(OBJEXT): $(top_srcdir)/prism/arena.h +prism/buffer.$(OBJEXT): $(top_srcdir)/prism/buffer.c +prism/buffer.$(OBJEXT): $(top_srcdir)/prism/buffer.h +prism/buffer.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +prism/buffer.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h +prism/buffer.$(OBJEXT): $(top_srcdir)/prism/compiler/format.h +prism/buffer.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h +prism/buffer.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +prism/buffer.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +prism/buffer.$(OBJEXT): $(top_srcdir)/prism/internal/allocator.h +prism/buffer.$(OBJEXT): $(top_srcdir)/prism/internal/buffer.h +prism/buffer.$(OBJEXT): $(top_srcdir)/prism/internal/char.h +prism/buffer.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h +prism/buffer.$(OBJEXT): {$(VPATH)}config.h +prism/buffer.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h +prism/buffer.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h +prism/buffer.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h +prism/buffer.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h +prism/buffer.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h +prism/buffer.$(OBJEXT): {$(VPATH)}internal/compiler_is.h +prism/buffer.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h +prism/buffer.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h +prism/buffer.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h +prism/buffer.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h +prism/buffer.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h +prism/buffer.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h +prism/buffer.$(OBJEXT): {$(VPATH)}internal/compiler_since.h +prism/buffer.$(OBJEXT): {$(VPATH)}internal/config.h +prism/buffer.$(OBJEXT): {$(VPATH)}internal/dllexport.h +prism/buffer.$(OBJEXT): {$(VPATH)}internal/has/attribute.h +prism/buffer.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h +prism/buffer.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h +prism/buffer.$(OBJEXT): {$(VPATH)}internal/has/extension.h +prism/buffer.$(OBJEXT): {$(VPATH)}internal/has/feature.h +prism/buffer.$(OBJEXT): {$(VPATH)}internal/has/warning.h +prism/buffer.$(OBJEXT): {$(VPATH)}internal/xmalloc.h +prism/buffer.$(OBJEXT): {$(VPATH)}prism_xallocator.h +prism/char.$(OBJEXT): $(top_srcdir)/prism/arena.h +prism/char.$(OBJEXT): $(top_srcdir)/prism/char.c +prism/char.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +prism/char.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h +prism/char.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h +prism/char.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +prism/char.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +prism/char.$(OBJEXT): $(top_srcdir)/prism/internal/char.h +prism/char.$(OBJEXT): $(top_srcdir)/prism/internal/line_offset_list.h +prism/char.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h +prism/char.$(OBJEXT): {$(VPATH)}config.h +prism/char.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h +prism/char.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h +prism/char.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h +prism/char.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h +prism/char.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h +prism/char.$(OBJEXT): {$(VPATH)}internal/compiler_is.h +prism/char.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h +prism/char.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h +prism/char.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h +prism/char.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h +prism/char.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h +prism/char.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h +prism/char.$(OBJEXT): {$(VPATH)}internal/compiler_since.h +prism/char.$(OBJEXT): {$(VPATH)}internal/config.h +prism/char.$(OBJEXT): {$(VPATH)}internal/dllexport.h +prism/char.$(OBJEXT): {$(VPATH)}internal/has/attribute.h +prism/char.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h +prism/char.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h +prism/char.$(OBJEXT): {$(VPATH)}internal/has/extension.h +prism/char.$(OBJEXT): {$(VPATH)}internal/has/feature.h +prism/char.$(OBJEXT): {$(VPATH)}internal/has/warning.h +prism/char.$(OBJEXT): {$(VPATH)}internal/xmalloc.h +prism/char.$(OBJEXT): {$(VPATH)}prism_xallocator.h +prism/constant_pool.$(OBJEXT): $(top_srcdir)/prism/arena.h +prism/constant_pool.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h +prism/constant_pool.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +prism/constant_pool.$(OBJEXT): $(top_srcdir)/prism/compiler/flex_array.h +prism/constant_pool.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h +prism/constant_pool.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h +prism/constant_pool.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +prism/constant_pool.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +prism/constant_pool.$(OBJEXT): $(top_srcdir)/prism/constant_pool.c +prism/constant_pool.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h +prism/constant_pool.$(OBJEXT): $(top_srcdir)/prism/internal/arena.h +prism/constant_pool.$(OBJEXT): $(top_srcdir)/prism/internal/constant_pool.h +prism/constant_pool.$(OBJEXT): {$(VPATH)}config.h +prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h +prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h +prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h +prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h +prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h +prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/compiler_is.h +prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h +prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h +prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h +prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h +prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h +prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h +prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/compiler_since.h +prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/config.h +prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/dllexport.h +prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/has/attribute.h +prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h +prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h +prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/has/extension.h +prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/has/feature.h +prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/has/warning.h +prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/xmalloc.h +prism/constant_pool.$(OBJEXT): {$(VPATH)}prism_xallocator.h +prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/arena.h prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/ast.h -prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/defines.h +prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/buffer.h +prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h +prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/compiler/flex_array.h +prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h +prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h +prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/diagnostic.c prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h -prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/util/pm_arena.h -prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h -prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h -prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h -prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h -prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/util/pm_line_offset_list.h -prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h -prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h +prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/integer.h +prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/internal/allocator.h +prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/internal/arena.h +prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/internal/char.h +prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/internal/diagnostic.h +prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/internal/list.h +prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h +prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/stringy.h prism/diagnostic.$(OBJEXT): {$(VPATH)}config.h prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h @@ -11381,10 +11703,10 @@ prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/has/feature.h prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/has/warning.h prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/xmalloc.h prism/diagnostic.$(OBJEXT): {$(VPATH)}prism_xallocator.h -prism/encoding.$(OBJEXT): $(top_srcdir)/prism/defines.h +prism/encoding.$(OBJEXT): $(top_srcdir)/prism/compiler/unused.h prism/encoding.$(OBJEXT): $(top_srcdir)/prism/encoding.c -prism/encoding.$(OBJEXT): $(top_srcdir)/prism/encoding.h -prism/encoding.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h +prism/encoding.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h +prism/encoding.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h prism/encoding.$(OBJEXT): {$(VPATH)}config.h prism/encoding.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h prism/encoding.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h @@ -11412,30 +11734,42 @@ prism/encoding.$(OBJEXT): {$(VPATH)}prism_xallocator.h prism/extension.$(OBJEXT): $(hdrdir)/ruby.h prism/extension.$(OBJEXT): $(hdrdir)/ruby/ruby.h prism/extension.$(OBJEXT): $(hdrdir)/ruby/version.h +prism/extension.$(OBJEXT): $(top_srcdir)/prism/arena.h prism/extension.$(OBJEXT): $(top_srcdir)/prism/ast.h -prism/extension.$(OBJEXT): $(top_srcdir)/prism/defines.h +prism/extension.$(OBJEXT): $(top_srcdir)/prism/buffer.h +prism/extension.$(OBJEXT): $(top_srcdir)/prism/comments.h +prism/extension.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h +prism/extension.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +prism/extension.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h +prism/extension.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +prism/extension.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +prism/extension.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h prism/extension.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h -prism/extension.$(OBJEXT): $(top_srcdir)/prism/encoding.h +prism/extension.$(OBJEXT): $(top_srcdir)/prism/excludes.h prism/extension.$(OBJEXT): $(top_srcdir)/prism/extension.c prism/extension.$(OBJEXT): $(top_srcdir)/prism/extension.h +prism/extension.$(OBJEXT): $(top_srcdir)/prism/integer.h +prism/extension.$(OBJEXT): $(top_srcdir)/prism/internal/char.h +prism/extension.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h +prism/extension.$(OBJEXT): $(top_srcdir)/prism/internal/list.h +prism/extension.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h +prism/extension.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h +prism/extension.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h +prism/extension.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h +prism/extension.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h +prism/extension.$(OBJEXT): $(top_srcdir)/prism/json.h +prism/extension.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h +prism/extension.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h prism/extension.$(OBJEXT): $(top_srcdir)/prism/node.h prism/extension.$(OBJEXT): $(top_srcdir)/prism/options.h prism/extension.$(OBJEXT): $(top_srcdir)/prism/parser.h prism/extension.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h prism/extension.$(OBJEXT): $(top_srcdir)/prism/prism.h -prism/extension.$(OBJEXT): $(top_srcdir)/prism/regexp.h -prism/extension.$(OBJEXT): $(top_srcdir)/prism/static_literals.h -prism/extension.$(OBJEXT): $(top_srcdir)/prism/util/pm_arena.h -prism/extension.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h -prism/extension.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h -prism/extension.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h -prism/extension.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h -prism/extension.$(OBJEXT): $(top_srcdir)/prism/util/pm_line_offset_list.h -prism/extension.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h -prism/extension.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h -prism/extension.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h -prism/extension.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h -prism/extension.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +prism/extension.$(OBJEXT): $(top_srcdir)/prism/serialize.h +prism/extension.$(OBJEXT): $(top_srcdir)/prism/source.h +prism/extension.$(OBJEXT): $(top_srcdir)/prism/stream.h +prism/extension.$(OBJEXT): $(top_srcdir)/prism/string_query.h +prism/extension.$(OBJEXT): $(top_srcdir)/prism/stringy.h prism/extension.$(OBJEXT): $(top_srcdir)/prism/version.h prism/extension.$(OBJEXT): {$(VPATH)}assert.h prism/extension.$(OBJEXT): {$(VPATH)}backward/2/assume.h @@ -11606,27 +11940,201 @@ prism/extension.$(OBJEXT): {$(VPATH)}oniguruma.h prism/extension.$(OBJEXT): {$(VPATH)}prism_xallocator.h prism/extension.$(OBJEXT): {$(VPATH)}st.h prism/extension.$(OBJEXT): {$(VPATH)}subst.h +prism/integer.$(OBJEXT): $(top_srcdir)/prism/arena.h +prism/integer.$(OBJEXT): $(top_srcdir)/prism/buffer.h +prism/integer.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +prism/integer.$(OBJEXT): $(top_srcdir)/prism/compiler/format.h +prism/integer.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +prism/integer.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +prism/integer.$(OBJEXT): $(top_srcdir)/prism/integer.c +prism/integer.$(OBJEXT): $(top_srcdir)/prism/integer.h +prism/integer.$(OBJEXT): $(top_srcdir)/prism/internal/allocator.h +prism/integer.$(OBJEXT): $(top_srcdir)/prism/internal/buffer.h +prism/integer.$(OBJEXT): $(top_srcdir)/prism/internal/char.h +prism/integer.$(OBJEXT): $(top_srcdir)/prism/internal/integer.h +prism/integer.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h +prism/integer.$(OBJEXT): {$(VPATH)}config.h +prism/integer.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h +prism/integer.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h +prism/integer.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h +prism/integer.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h +prism/integer.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h +prism/integer.$(OBJEXT): {$(VPATH)}internal/compiler_is.h +prism/integer.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h +prism/integer.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h +prism/integer.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h +prism/integer.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h +prism/integer.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h +prism/integer.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h +prism/integer.$(OBJEXT): {$(VPATH)}internal/compiler_since.h +prism/integer.$(OBJEXT): {$(VPATH)}internal/config.h +prism/integer.$(OBJEXT): {$(VPATH)}internal/dllexport.h +prism/integer.$(OBJEXT): {$(VPATH)}internal/has/attribute.h +prism/integer.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h +prism/integer.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h +prism/integer.$(OBJEXT): {$(VPATH)}internal/has/extension.h +prism/integer.$(OBJEXT): {$(VPATH)}internal/has/feature.h +prism/integer.$(OBJEXT): {$(VPATH)}internal/has/warning.h +prism/integer.$(OBJEXT): {$(VPATH)}internal/xmalloc.h +prism/integer.$(OBJEXT): {$(VPATH)}prism_xallocator.h +prism/json.$(OBJEXT): $(top_srcdir)/prism/arena.h +prism/json.$(OBJEXT): $(top_srcdir)/prism/ast.h +prism/json.$(OBJEXT): $(top_srcdir)/prism/buffer.h +prism/json.$(OBJEXT): $(top_srcdir)/prism/comments.h +prism/json.$(OBJEXT): $(top_srcdir)/prism/compiler/accel.h +prism/json.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h +prism/json.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +prism/json.$(OBJEXT): $(top_srcdir)/prism/compiler/flex_array.h +prism/json.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h +prism/json.$(OBJEXT): $(top_srcdir)/prism/compiler/format.h +prism/json.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h +prism/json.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +prism/json.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +prism/json.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h +prism/json.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h +prism/json.$(OBJEXT): $(top_srcdir)/prism/excludes.h +prism/json.$(OBJEXT): $(top_srcdir)/prism/integer.h +prism/json.$(OBJEXT): $(top_srcdir)/prism/internal/arena.h +prism/json.$(OBJEXT): $(top_srcdir)/prism/internal/buffer.h +prism/json.$(OBJEXT): $(top_srcdir)/prism/internal/constant_pool.h +prism/json.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h +prism/json.$(OBJEXT): $(top_srcdir)/prism/internal/integer.h +prism/json.$(OBJEXT): $(top_srcdir)/prism/internal/list.h +prism/json.$(OBJEXT): $(top_srcdir)/prism/internal/options.h +prism/json.$(OBJEXT): $(top_srcdir)/prism/internal/parser.h +prism/json.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h +prism/json.$(OBJEXT): $(top_srcdir)/prism/json.c +prism/json.$(OBJEXT): $(top_srcdir)/prism/json.h +prism/json.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h +prism/json.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h +prism/json.$(OBJEXT): $(top_srcdir)/prism/options.h +prism/json.$(OBJEXT): $(top_srcdir)/prism/parser.h +prism/json.$(OBJEXT): $(top_srcdir)/prism/stringy.h +prism/line_offset_list.$(OBJEXT): $(top_srcdir)/prism/arena.h +prism/line_offset_list.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h +prism/line_offset_list.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +prism/line_offset_list.$(OBJEXT): $(top_srcdir)/prism/compiler/flex_array.h +prism/line_offset_list.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h +prism/line_offset_list.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h +prism/line_offset_list.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +prism/line_offset_list.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +prism/line_offset_list.$(OBJEXT): $(top_srcdir)/prism/internal/arena.h +prism/line_offset_list.$(OBJEXT): $(top_srcdir)/prism/internal/line_offset_list.h +prism/line_offset_list.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.c +prism/line_offset_list.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h +prism/line_offset_list.$(OBJEXT): {$(VPATH)}config.h +prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h +prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h +prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h +prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h +prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h +prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/compiler_is.h +prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h +prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h +prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h +prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h +prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h +prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h +prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/compiler_since.h +prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/config.h +prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/dllexport.h +prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/has/attribute.h +prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h +prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h +prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/has/extension.h +prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/has/feature.h +prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/has/warning.h +prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/xmalloc.h +prism/line_offset_list.$(OBJEXT): {$(VPATH)}prism_xallocator.h +prism/list.$(OBJEXT): $(top_srcdir)/prism/internal/list.h +prism/list.$(OBJEXT): $(top_srcdir)/prism/list.c +prism/list.$(OBJEXT): {$(VPATH)}config.h +prism/list.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h +prism/list.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h +prism/list.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h +prism/list.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h +prism/list.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h +prism/list.$(OBJEXT): {$(VPATH)}internal/compiler_is.h +prism/list.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h +prism/list.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h +prism/list.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h +prism/list.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h +prism/list.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h +prism/list.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h +prism/list.$(OBJEXT): {$(VPATH)}internal/compiler_since.h +prism/list.$(OBJEXT): {$(VPATH)}internal/config.h +prism/list.$(OBJEXT): {$(VPATH)}internal/dllexport.h +prism/list.$(OBJEXT): {$(VPATH)}internal/has/attribute.h +prism/list.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h +prism/list.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h +prism/list.$(OBJEXT): {$(VPATH)}internal/has/extension.h +prism/list.$(OBJEXT): {$(VPATH)}internal/has/feature.h +prism/list.$(OBJEXT): {$(VPATH)}internal/has/warning.h +prism/list.$(OBJEXT): {$(VPATH)}internal/xmalloc.h +prism/list.$(OBJEXT): {$(VPATH)}prism_xallocator.h +prism/memchr.$(OBJEXT): $(top_srcdir)/prism/ast.h +prism/memchr.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h +prism/memchr.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h +prism/memchr.$(OBJEXT): $(top_srcdir)/prism/internal/list.h +prism/memchr.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h +prism/memchr.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h +prism/memchr.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h +prism/memchr.$(OBJEXT): $(top_srcdir)/prism/memchr.c +prism/memchr.$(OBJEXT): $(top_srcdir)/prism/parser.h +prism/memchr.$(OBJEXT): $(top_srcdir)/prism/stringy.h +prism/memchr.$(OBJEXT): {$(VPATH)}config.h +prism/memchr.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h +prism/memchr.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h +prism/memchr.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h +prism/memchr.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h +prism/memchr.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h +prism/memchr.$(OBJEXT): {$(VPATH)}internal/compiler_is.h +prism/memchr.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h +prism/memchr.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h +prism/memchr.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h +prism/memchr.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h +prism/memchr.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h +prism/memchr.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h +prism/memchr.$(OBJEXT): {$(VPATH)}internal/compiler_since.h +prism/memchr.$(OBJEXT): {$(VPATH)}internal/config.h +prism/memchr.$(OBJEXT): {$(VPATH)}internal/dllexport.h +prism/memchr.$(OBJEXT): {$(VPATH)}internal/has/attribute.h +prism/memchr.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h +prism/memchr.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h +prism/memchr.$(OBJEXT): {$(VPATH)}internal/has/extension.h +prism/memchr.$(OBJEXT): {$(VPATH)}internal/has/feature.h +prism/memchr.$(OBJEXT): {$(VPATH)}internal/has/warning.h +prism/memchr.$(OBJEXT): {$(VPATH)}internal/xmalloc.h +prism/memchr.$(OBJEXT): {$(VPATH)}prism_xallocator.h +prism/node.$(OBJEXT): $(top_srcdir)/prism/arena.h prism/node.$(OBJEXT): $(top_srcdir)/prism/ast.h -prism/node.$(OBJEXT): $(top_srcdir)/prism/defines.h +prism/node.$(OBJEXT): $(top_srcdir)/prism/buffer.h +prism/node.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h +prism/node.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +prism/node.$(OBJEXT): $(top_srcdir)/prism/compiler/flex_array.h +prism/node.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h +prism/node.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h +prism/node.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +prism/node.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +prism/node.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h prism/node.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h -prism/node.$(OBJEXT): $(top_srcdir)/prism/encoding.h +prism/node.$(OBJEXT): $(top_srcdir)/prism/integer.h +prism/node.$(OBJEXT): $(top_srcdir)/prism/internal/arena.h +prism/node.$(OBJEXT): $(top_srcdir)/prism/internal/char.h +prism/node.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h +prism/node.$(OBJEXT): $(top_srcdir)/prism/internal/list.h +prism/node.$(OBJEXT): $(top_srcdir)/prism/internal/node.h +prism/node.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h +prism/node.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h +prism/node.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h +prism/node.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h +prism/node.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h prism/node.$(OBJEXT): $(top_srcdir)/prism/node.c prism/node.$(OBJEXT): $(top_srcdir)/prism/node.h prism/node.$(OBJEXT): $(top_srcdir)/prism/options.h prism/node.$(OBJEXT): $(top_srcdir)/prism/parser.h prism/node.$(OBJEXT): $(top_srcdir)/prism/prism.h -prism/node.$(OBJEXT): $(top_srcdir)/prism/regexp.h -prism/node.$(OBJEXT): $(top_srcdir)/prism/static_literals.h -prism/node.$(OBJEXT): $(top_srcdir)/prism/util/pm_arena.h -prism/node.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h -prism/node.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h -prism/node.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h -prism/node.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h -prism/node.$(OBJEXT): $(top_srcdir)/prism/util/pm_line_offset_list.h -prism/node.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h -prism/node.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h -prism/node.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h -prism/node.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +prism/node.$(OBJEXT): $(top_srcdir)/prism/stringy.h prism/node.$(OBJEXT): {$(VPATH)}config.h prism/node.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h prism/node.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h @@ -11651,13 +12159,20 @@ prism/node.$(OBJEXT): {$(VPATH)}internal/has/feature.h prism/node.$(OBJEXT): {$(VPATH)}internal/has/warning.h prism/node.$(OBJEXT): {$(VPATH)}internal/xmalloc.h prism/node.$(OBJEXT): {$(VPATH)}prism_xallocator.h -prism/options.$(OBJEXT): $(top_srcdir)/prism/defines.h +prism/options.$(OBJEXT): $(top_srcdir)/prism/arena.h +prism/options.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +prism/options.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h +prism/options.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h +prism/options.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +prism/options.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +prism/options.$(OBJEXT): $(top_srcdir)/prism/internal/allocator.h +prism/options.$(OBJEXT): $(top_srcdir)/prism/internal/char.h +prism/options.$(OBJEXT): $(top_srcdir)/prism/internal/options.h +prism/options.$(OBJEXT): $(top_srcdir)/prism/internal/stringy.h +prism/options.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h prism/options.$(OBJEXT): $(top_srcdir)/prism/options.c prism/options.$(OBJEXT): $(top_srcdir)/prism/options.h -prism/options.$(OBJEXT): $(top_srcdir)/prism/util/pm_arena.h -prism/options.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h -prism/options.$(OBJEXT): $(top_srcdir)/prism/util/pm_line_offset_list.h -prism/options.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h +prism/options.$(OBJEXT): $(top_srcdir)/prism/stringy.h prism/options.$(OBJEXT): {$(VPATH)}config.h prism/options.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h prism/options.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h @@ -11682,23 +12197,97 @@ prism/options.$(OBJEXT): {$(VPATH)}internal/has/feature.h prism/options.$(OBJEXT): {$(VPATH)}internal/has/warning.h prism/options.$(OBJEXT): {$(VPATH)}internal/xmalloc.h prism/options.$(OBJEXT): {$(VPATH)}prism_xallocator.h +prism/parser.$(OBJEXT): $(top_srcdir)/prism/arena.h +prism/parser.$(OBJEXT): $(top_srcdir)/prism/ast.h +prism/parser.$(OBJEXT): $(top_srcdir)/prism/buffer.h +prism/parser.$(OBJEXT): $(top_srcdir)/prism/comments.h +prism/parser.$(OBJEXT): $(top_srcdir)/prism/compiler/accel.h +prism/parser.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h +prism/parser.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +prism/parser.$(OBJEXT): $(top_srcdir)/prism/compiler/flex_array.h +prism/parser.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h +prism/parser.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h +prism/parser.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +prism/parser.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +prism/parser.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h +prism/parser.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h +prism/parser.$(OBJEXT): $(top_srcdir)/prism/integer.h +prism/parser.$(OBJEXT): $(top_srcdir)/prism/internal/allocator.h +prism/parser.$(OBJEXT): $(top_srcdir)/prism/internal/arena.h +prism/parser.$(OBJEXT): $(top_srcdir)/prism/internal/comments.h +prism/parser.$(OBJEXT): $(top_srcdir)/prism/internal/constant_pool.h +prism/parser.$(OBJEXT): $(top_srcdir)/prism/internal/diagnostic.h +prism/parser.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h +prism/parser.$(OBJEXT): $(top_srcdir)/prism/internal/list.h +prism/parser.$(OBJEXT): $(top_srcdir)/prism/internal/magic_comments.h +prism/parser.$(OBJEXT): $(top_srcdir)/prism/internal/options.h +prism/parser.$(OBJEXT): $(top_srcdir)/prism/internal/parser.h +prism/parser.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h +prism/parser.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h +prism/parser.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h +prism/parser.$(OBJEXT): $(top_srcdir)/prism/options.h +prism/parser.$(OBJEXT): $(top_srcdir)/prism/parser.c +prism/parser.$(OBJEXT): $(top_srcdir)/prism/parser.h +prism/parser.$(OBJEXT): $(top_srcdir)/prism/stringy.h +prism/parser.$(OBJEXT): {$(VPATH)}config.h +prism/parser.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h +prism/parser.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h +prism/parser.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h +prism/parser.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h +prism/parser.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h +prism/parser.$(OBJEXT): {$(VPATH)}internal/compiler_is.h +prism/parser.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h +prism/parser.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h +prism/parser.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h +prism/parser.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h +prism/parser.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h +prism/parser.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h +prism/parser.$(OBJEXT): {$(VPATH)}internal/compiler_since.h +prism/parser.$(OBJEXT): {$(VPATH)}internal/config.h +prism/parser.$(OBJEXT): {$(VPATH)}internal/dllexport.h +prism/parser.$(OBJEXT): {$(VPATH)}internal/has/attribute.h +prism/parser.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h +prism/parser.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h +prism/parser.$(OBJEXT): {$(VPATH)}internal/has/extension.h +prism/parser.$(OBJEXT): {$(VPATH)}internal/has/feature.h +prism/parser.$(OBJEXT): {$(VPATH)}internal/has/warning.h +prism/parser.$(OBJEXT): {$(VPATH)}internal/xmalloc.h +prism/parser.$(OBJEXT): {$(VPATH)}prism_xallocator.h +prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/arena.h prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/ast.h -prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/defines.h -prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/encoding.h +prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/buffer.h +prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/comments.h +prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/compiler/accel.h +prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h +prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/compiler/flex_array.h +prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h +prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/compiler/format.h +prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h +prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h +prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h +prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/excludes.h +prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/integer.h +prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/internal/arena.h +prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/internal/buffer.h +prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/internal/char.h +prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/internal/constant_pool.h +prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h +prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/internal/integer.h +prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/internal/list.h +prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/internal/options.h +prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/internal/parser.h +prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h +prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h +prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h +prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/options.h prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/parser.h prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/prettyprint.c prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h -prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/static_literals.h -prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/util/pm_arena.h -prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h -prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h -prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h -prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h -prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/util/pm_line_offset_list.h -prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h -prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h -prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h +prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/stringy.h prism/prettyprint.$(OBJEXT): {$(VPATH)}config.h prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h @@ -11723,30 +12312,64 @@ prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/has/feature.h prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/has/warning.h prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/xmalloc.h prism/prettyprint.$(OBJEXT): {$(VPATH)}prism_xallocator.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/arena.h prism/prism.$(OBJEXT): $(top_srcdir)/prism/ast.h -prism/prism.$(OBJEXT): $(top_srcdir)/prism/defines.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/buffer.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/comments.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/compiler/accel.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/compiler/fallthrough.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/compiler/flex_array.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/compiler/format.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/compiler/unused.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h prism/prism.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h -prism/prism.$(OBJEXT): $(top_srcdir)/prism/encoding.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/excludes.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/integer.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/allocator.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/arena.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/bit.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/buffer.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/char.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/comments.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/constant_pool.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/diagnostic.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/integer.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/isinf.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/line_offset_list.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/list.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/magic_comments.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/node.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/options.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/parser.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/serialize.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/source.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/stringy.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/tokens.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h prism/prism.$(OBJEXT): $(top_srcdir)/prism/node.h -prism/prism.$(OBJEXT): $(top_srcdir)/prism/node_new.h prism/prism.$(OBJEXT): $(top_srcdir)/prism/options.h prism/prism.$(OBJEXT): $(top_srcdir)/prism/parser.h prism/prism.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h prism/prism.$(OBJEXT): $(top_srcdir)/prism/prism.c prism/prism.$(OBJEXT): $(top_srcdir)/prism/prism.h -prism/prism.$(OBJEXT): $(top_srcdir)/prism/regexp.h -prism/prism.$(OBJEXT): $(top_srcdir)/prism/static_literals.h -prism/prism.$(OBJEXT): $(top_srcdir)/prism/util/pm_arena.h -prism/prism.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h -prism/prism.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h -prism/prism.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h -prism/prism.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h -prism/prism.$(OBJEXT): $(top_srcdir)/prism/util/pm_line_offset_list.h -prism/prism.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h -prism/prism.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h -prism/prism.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h -prism/prism.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h -prism/prism.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/serialize.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/source.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/stream.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/stringy.h prism/prism.$(OBJEXT): $(top_srcdir)/prism/version.h prism/prism.$(OBJEXT): {$(VPATH)}config.h prism/prism.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h @@ -11772,25 +12395,43 @@ prism/prism.$(OBJEXT): {$(VPATH)}internal/has/feature.h prism/prism.$(OBJEXT): {$(VPATH)}internal/has/warning.h prism/prism.$(OBJEXT): {$(VPATH)}internal/xmalloc.h prism/prism.$(OBJEXT): {$(VPATH)}prism_xallocator.h +prism/regexp.$(OBJEXT): $(top_srcdir)/prism/arena.h prism/regexp.$(OBJEXT): $(top_srcdir)/prism/ast.h -prism/regexp.$(OBJEXT): $(top_srcdir)/prism/defines.h +prism/regexp.$(OBJEXT): $(top_srcdir)/prism/buffer.h +prism/regexp.$(OBJEXT): $(top_srcdir)/prism/comments.h +prism/regexp.$(OBJEXT): $(top_srcdir)/prism/compiler/accel.h +prism/regexp.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h +prism/regexp.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +prism/regexp.$(OBJEXT): $(top_srcdir)/prism/compiler/fallthrough.h +prism/regexp.$(OBJEXT): $(top_srcdir)/prism/compiler/flex_array.h +prism/regexp.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h +prism/regexp.$(OBJEXT): $(top_srcdir)/prism/compiler/format.h +prism/regexp.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h +prism/regexp.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +prism/regexp.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +prism/regexp.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h prism/regexp.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h -prism/regexp.$(OBJEXT): $(top_srcdir)/prism/encoding.h +prism/regexp.$(OBJEXT): $(top_srcdir)/prism/integer.h +prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/arena.h +prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/buffer.h +prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/char.h +prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/constant_pool.h +prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/diagnostic.h +prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h +prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/list.h +prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h +prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/options.h +prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/parser.h +prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h +prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h +prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/stringy.h +prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h +prism/regexp.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h +prism/regexp.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h prism/regexp.$(OBJEXT): $(top_srcdir)/prism/options.h prism/regexp.$(OBJEXT): $(top_srcdir)/prism/parser.h prism/regexp.$(OBJEXT): $(top_srcdir)/prism/regexp.c -prism/regexp.$(OBJEXT): $(top_srcdir)/prism/regexp.h -prism/regexp.$(OBJEXT): $(top_srcdir)/prism/static_literals.h -prism/regexp.$(OBJEXT): $(top_srcdir)/prism/util/pm_arena.h -prism/regexp.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h -prism/regexp.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h -prism/regexp.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h -prism/regexp.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h -prism/regexp.$(OBJEXT): $(top_srcdir)/prism/util/pm_line_offset_list.h -prism/regexp.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h -prism/regexp.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h -prism/regexp.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h -prism/regexp.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h +prism/regexp.$(OBJEXT): $(top_srcdir)/prism/stringy.h prism/regexp.$(OBJEXT): {$(VPATH)}config.h prism/regexp.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h prism/regexp.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h @@ -11815,29 +12456,54 @@ prism/regexp.$(OBJEXT): {$(VPATH)}internal/has/feature.h prism/regexp.$(OBJEXT): {$(VPATH)}internal/has/warning.h prism/regexp.$(OBJEXT): {$(VPATH)}internal/xmalloc.h prism/regexp.$(OBJEXT): {$(VPATH)}prism_xallocator.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/arena.h prism/serialize.$(OBJEXT): $(top_srcdir)/prism/ast.h -prism/serialize.$(OBJEXT): $(top_srcdir)/prism/defines.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/buffer.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/comments.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/compiler/accel.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/compiler/flex_array.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/compiler/format.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h prism/serialize.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h -prism/serialize.$(OBJEXT): $(top_srcdir)/prism/encoding.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/excludes.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/integer.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/arena.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/buffer.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/char.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/comments.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/constant_pool.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/diagnostic.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/list.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/magic_comments.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/options.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/parser.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/json.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h prism/serialize.$(OBJEXT): $(top_srcdir)/prism/node.h prism/serialize.$(OBJEXT): $(top_srcdir)/prism/options.h prism/serialize.$(OBJEXT): $(top_srcdir)/prism/parser.h prism/serialize.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h prism/serialize.$(OBJEXT): $(top_srcdir)/prism/prism.h -prism/serialize.$(OBJEXT): $(top_srcdir)/prism/regexp.h prism/serialize.$(OBJEXT): $(top_srcdir)/prism/serialize.c -prism/serialize.$(OBJEXT): $(top_srcdir)/prism/static_literals.h -prism/serialize.$(OBJEXT): $(top_srcdir)/prism/util/pm_arena.h -prism/serialize.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h -prism/serialize.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h -prism/serialize.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h -prism/serialize.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h -prism/serialize.$(OBJEXT): $(top_srcdir)/prism/util/pm_line_offset_list.h -prism/serialize.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h -prism/serialize.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h -prism/serialize.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h -prism/serialize.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h -prism/serialize.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/serialize.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/source.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/stream.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/string_query.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/stringy.h prism/serialize.$(OBJEXT): $(top_srcdir)/prism/version.h prism/serialize.$(OBJEXT): {$(VPATH)}config.h prism/serialize.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h @@ -11863,23 +12529,69 @@ prism/serialize.$(OBJEXT): {$(VPATH)}internal/has/feature.h prism/serialize.$(OBJEXT): {$(VPATH)}internal/has/warning.h prism/serialize.$(OBJEXT): {$(VPATH)}internal/xmalloc.h prism/serialize.$(OBJEXT): {$(VPATH)}prism_xallocator.h +prism/source.$(OBJEXT): $(top_srcdir)/prism/buffer.h +prism/source.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +prism/source.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h +prism/source.$(OBJEXT): $(top_srcdir)/prism/compiler/format.h +prism/source.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +prism/source.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +prism/source.$(OBJEXT): $(top_srcdir)/prism/internal/allocator.h +prism/source.$(OBJEXT): $(top_srcdir)/prism/internal/buffer.h +prism/source.$(OBJEXT): $(top_srcdir)/prism/internal/source.h +prism/source.$(OBJEXT): $(top_srcdir)/prism/source.c +prism/source.$(OBJEXT): $(top_srcdir)/prism/source.h +prism/source.$(OBJEXT): {$(VPATH)}config.h +prism/source.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h +prism/source.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h +prism/source.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h +prism/source.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h +prism/source.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h +prism/source.$(OBJEXT): {$(VPATH)}internal/compiler_is.h +prism/source.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h +prism/source.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h +prism/source.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h +prism/source.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h +prism/source.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h +prism/source.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h +prism/source.$(OBJEXT): {$(VPATH)}internal/compiler_since.h +prism/source.$(OBJEXT): {$(VPATH)}internal/config.h +prism/source.$(OBJEXT): {$(VPATH)}internal/dllexport.h +prism/source.$(OBJEXT): {$(VPATH)}internal/has/attribute.h +prism/source.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h +prism/source.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h +prism/source.$(OBJEXT): {$(VPATH)}internal/has/extension.h +prism/source.$(OBJEXT): {$(VPATH)}internal/has/feature.h +prism/source.$(OBJEXT): {$(VPATH)}internal/has/warning.h +prism/source.$(OBJEXT): {$(VPATH)}internal/xmalloc.h +prism/source.$(OBJEXT): {$(VPATH)}prism_xallocator.h +prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/arena.h prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/ast.h -prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/defines.h -prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/encoding.h +prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/buffer.h +prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h +prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/compiler/format.h +prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h +prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/compiler/unused.h +prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h +prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/integer.h +prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/internal/allocator.h +prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/internal/buffer.h +prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/internal/char.h +prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h +prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/internal/integer.h +prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/internal/isinf.h +prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/internal/list.h +prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h +prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/internal/stringy.h +prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h +prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/node.h prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/options.h prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/parser.h prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/static_literals.c -prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/static_literals.h -prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/util/pm_arena.h -prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h -prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h -prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h -prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h -prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/util/pm_line_offset_list.h -prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h -prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h -prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h +prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/stringy.h prism/static_literals.$(OBJEXT): {$(VPATH)}config.h prism/static_literals.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h prism/static_literals.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h @@ -11904,397 +12616,207 @@ prism/static_literals.$(OBJEXT): {$(VPATH)}internal/has/feature.h prism/static_literals.$(OBJEXT): {$(VPATH)}internal/has/warning.h prism/static_literals.$(OBJEXT): {$(VPATH)}internal/xmalloc.h prism/static_literals.$(OBJEXT): {$(VPATH)}prism_xallocator.h -prism/token_type.$(OBJEXT): $(top_srcdir)/prism/ast.h -prism/token_type.$(OBJEXT): $(top_srcdir)/prism/defines.h -prism/token_type.$(OBJEXT): $(top_srcdir)/prism/token_type.c -prism/token_type.$(OBJEXT): $(top_srcdir)/prism/util/pm_arena.h -prism/token_type.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h -prism/token_type.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h -prism/token_type.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h -prism/token_type.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h -prism/token_type.$(OBJEXT): $(top_srcdir)/prism/util/pm_line_offset_list.h -prism/token_type.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h -prism/token_type.$(OBJEXT): {$(VPATH)}config.h -prism/token_type.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h -prism/token_type.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h -prism/token_type.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h -prism/token_type.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h -prism/token_type.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h -prism/token_type.$(OBJEXT): {$(VPATH)}internal/compiler_is.h -prism/token_type.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h -prism/token_type.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h -prism/token_type.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h -prism/token_type.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h -prism/token_type.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h -prism/token_type.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h -prism/token_type.$(OBJEXT): {$(VPATH)}internal/compiler_since.h -prism/token_type.$(OBJEXT): {$(VPATH)}internal/config.h -prism/token_type.$(OBJEXT): {$(VPATH)}internal/dllexport.h -prism/token_type.$(OBJEXT): {$(VPATH)}internal/has/attribute.h -prism/token_type.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h -prism/token_type.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h -prism/token_type.$(OBJEXT): {$(VPATH)}internal/has/extension.h -prism/token_type.$(OBJEXT): {$(VPATH)}internal/has/feature.h -prism/token_type.$(OBJEXT): {$(VPATH)}internal/has/warning.h -prism/token_type.$(OBJEXT): {$(VPATH)}internal/xmalloc.h -prism/token_type.$(OBJEXT): {$(VPATH)}prism_xallocator.h -prism/util/pm_arena.$(OBJEXT): $(top_srcdir)/prism/defines.h -prism/util/pm_arena.$(OBJEXT): $(top_srcdir)/prism/util/pm_arena.c -prism/util/pm_arena.$(OBJEXT): $(top_srcdir)/prism/util/pm_arena.h -prism/util/pm_arena.$(OBJEXT): {$(VPATH)}config.h -prism/util/pm_arena.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h -prism/util/pm_arena.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h -prism/util/pm_arena.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h -prism/util/pm_arena.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h -prism/util/pm_arena.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h -prism/util/pm_arena.$(OBJEXT): {$(VPATH)}internal/compiler_is.h -prism/util/pm_arena.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h -prism/util/pm_arena.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h -prism/util/pm_arena.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h -prism/util/pm_arena.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h -prism/util/pm_arena.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h -prism/util/pm_arena.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h -prism/util/pm_arena.$(OBJEXT): {$(VPATH)}internal/compiler_since.h -prism/util/pm_arena.$(OBJEXT): {$(VPATH)}internal/config.h -prism/util/pm_arena.$(OBJEXT): {$(VPATH)}internal/dllexport.h -prism/util/pm_arena.$(OBJEXT): {$(VPATH)}internal/has/attribute.h -prism/util/pm_arena.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h -prism/util/pm_arena.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h -prism/util/pm_arena.$(OBJEXT): {$(VPATH)}internal/has/extension.h -prism/util/pm_arena.$(OBJEXT): {$(VPATH)}internal/has/feature.h -prism/util/pm_arena.$(OBJEXT): {$(VPATH)}internal/has/warning.h -prism/util/pm_arena.$(OBJEXT): {$(VPATH)}internal/xmalloc.h -prism/util/pm_arena.$(OBJEXT): {$(VPATH)}prism_xallocator.h -prism/util/pm_buffer.$(OBJEXT): $(top_srcdir)/prism/defines.h -prism/util/pm_buffer.$(OBJEXT): $(top_srcdir)/prism/util/pm_arena.h -prism/util/pm_buffer.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.c -prism/util/pm_buffer.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h -prism/util/pm_buffer.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h -prism/util/pm_buffer.$(OBJEXT): $(top_srcdir)/prism/util/pm_line_offset_list.h -prism/util/pm_buffer.$(OBJEXT): {$(VPATH)}config.h -prism/util/pm_buffer.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h -prism/util/pm_buffer.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h -prism/util/pm_buffer.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h -prism/util/pm_buffer.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h -prism/util/pm_buffer.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h -prism/util/pm_buffer.$(OBJEXT): {$(VPATH)}internal/compiler_is.h -prism/util/pm_buffer.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h -prism/util/pm_buffer.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h -prism/util/pm_buffer.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h -prism/util/pm_buffer.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h -prism/util/pm_buffer.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h -prism/util/pm_buffer.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h -prism/util/pm_buffer.$(OBJEXT): {$(VPATH)}internal/compiler_since.h -prism/util/pm_buffer.$(OBJEXT): {$(VPATH)}internal/config.h -prism/util/pm_buffer.$(OBJEXT): {$(VPATH)}internal/dllexport.h -prism/util/pm_buffer.$(OBJEXT): {$(VPATH)}internal/has/attribute.h -prism/util/pm_buffer.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h -prism/util/pm_buffer.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h -prism/util/pm_buffer.$(OBJEXT): {$(VPATH)}internal/has/extension.h -prism/util/pm_buffer.$(OBJEXT): {$(VPATH)}internal/has/feature.h -prism/util/pm_buffer.$(OBJEXT): {$(VPATH)}internal/has/warning.h -prism/util/pm_buffer.$(OBJEXT): {$(VPATH)}internal/xmalloc.h -prism/util/pm_buffer.$(OBJEXT): {$(VPATH)}prism_xallocator.h -prism/util/pm_char.$(OBJEXT): $(top_srcdir)/prism/defines.h -prism/util/pm_char.$(OBJEXT): $(top_srcdir)/prism/util/pm_arena.h -prism/util/pm_char.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.c -prism/util/pm_char.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h -prism/util/pm_char.$(OBJEXT): $(top_srcdir)/prism/util/pm_line_offset_list.h -prism/util/pm_char.$(OBJEXT): {$(VPATH)}config.h -prism/util/pm_char.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h -prism/util/pm_char.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h -prism/util/pm_char.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h -prism/util/pm_char.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h -prism/util/pm_char.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h -prism/util/pm_char.$(OBJEXT): {$(VPATH)}internal/compiler_is.h -prism/util/pm_char.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h -prism/util/pm_char.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h -prism/util/pm_char.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h -prism/util/pm_char.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h -prism/util/pm_char.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h -prism/util/pm_char.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h -prism/util/pm_char.$(OBJEXT): {$(VPATH)}internal/compiler_since.h -prism/util/pm_char.$(OBJEXT): {$(VPATH)}internal/config.h -prism/util/pm_char.$(OBJEXT): {$(VPATH)}internal/dllexport.h -prism/util/pm_char.$(OBJEXT): {$(VPATH)}internal/has/attribute.h -prism/util/pm_char.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h -prism/util/pm_char.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h -prism/util/pm_char.$(OBJEXT): {$(VPATH)}internal/has/extension.h -prism/util/pm_char.$(OBJEXT): {$(VPATH)}internal/has/feature.h -prism/util/pm_char.$(OBJEXT): {$(VPATH)}internal/has/warning.h -prism/util/pm_char.$(OBJEXT): {$(VPATH)}internal/xmalloc.h -prism/util/pm_char.$(OBJEXT): {$(VPATH)}prism_xallocator.h -prism/util/pm_constant_pool.$(OBJEXT): $(top_srcdir)/prism/defines.h -prism/util/pm_constant_pool.$(OBJEXT): $(top_srcdir)/prism/util/pm_arena.h -prism/util/pm_constant_pool.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.c -prism/util/pm_constant_pool.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h -prism/util/pm_constant_pool.$(OBJEXT): {$(VPATH)}config.h -prism/util/pm_constant_pool.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h -prism/util/pm_constant_pool.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h -prism/util/pm_constant_pool.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h -prism/util/pm_constant_pool.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h -prism/util/pm_constant_pool.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h -prism/util/pm_constant_pool.$(OBJEXT): {$(VPATH)}internal/compiler_is.h -prism/util/pm_constant_pool.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h -prism/util/pm_constant_pool.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h -prism/util/pm_constant_pool.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h -prism/util/pm_constant_pool.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h -prism/util/pm_constant_pool.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h -prism/util/pm_constant_pool.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h -prism/util/pm_constant_pool.$(OBJEXT): {$(VPATH)}internal/compiler_since.h -prism/util/pm_constant_pool.$(OBJEXT): {$(VPATH)}internal/config.h -prism/util/pm_constant_pool.$(OBJEXT): {$(VPATH)}internal/dllexport.h -prism/util/pm_constant_pool.$(OBJEXT): {$(VPATH)}internal/has/attribute.h -prism/util/pm_constant_pool.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h -prism/util/pm_constant_pool.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h -prism/util/pm_constant_pool.$(OBJEXT): {$(VPATH)}internal/has/extension.h -prism/util/pm_constant_pool.$(OBJEXT): {$(VPATH)}internal/has/feature.h -prism/util/pm_constant_pool.$(OBJEXT): {$(VPATH)}internal/has/warning.h -prism/util/pm_constant_pool.$(OBJEXT): {$(VPATH)}internal/xmalloc.h -prism/util/pm_constant_pool.$(OBJEXT): {$(VPATH)}prism_xallocator.h -prism/util/pm_integer.$(OBJEXT): $(top_srcdir)/prism/defines.h -prism/util/pm_integer.$(OBJEXT): $(top_srcdir)/prism/util/pm_arena.h -prism/util/pm_integer.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h -prism/util/pm_integer.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h -prism/util/pm_integer.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.c -prism/util/pm_integer.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h -prism/util/pm_integer.$(OBJEXT): $(top_srcdir)/prism/util/pm_line_offset_list.h -prism/util/pm_integer.$(OBJEXT): {$(VPATH)}config.h -prism/util/pm_integer.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h -prism/util/pm_integer.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h -prism/util/pm_integer.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h -prism/util/pm_integer.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h -prism/util/pm_integer.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h -prism/util/pm_integer.$(OBJEXT): {$(VPATH)}internal/compiler_is.h -prism/util/pm_integer.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h -prism/util/pm_integer.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h -prism/util/pm_integer.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h -prism/util/pm_integer.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h -prism/util/pm_integer.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h -prism/util/pm_integer.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h -prism/util/pm_integer.$(OBJEXT): {$(VPATH)}internal/compiler_since.h -prism/util/pm_integer.$(OBJEXT): {$(VPATH)}internal/config.h -prism/util/pm_integer.$(OBJEXT): {$(VPATH)}internal/dllexport.h -prism/util/pm_integer.$(OBJEXT): {$(VPATH)}internal/has/attribute.h -prism/util/pm_integer.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h -prism/util/pm_integer.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h -prism/util/pm_integer.$(OBJEXT): {$(VPATH)}internal/has/extension.h -prism/util/pm_integer.$(OBJEXT): {$(VPATH)}internal/has/feature.h -prism/util/pm_integer.$(OBJEXT): {$(VPATH)}internal/has/warning.h -prism/util/pm_integer.$(OBJEXT): {$(VPATH)}internal/xmalloc.h -prism/util/pm_integer.$(OBJEXT): {$(VPATH)}prism_xallocator.h -prism/util/pm_line_offset_list.$(OBJEXT): $(top_srcdir)/prism/defines.h -prism/util/pm_line_offset_list.$(OBJEXT): $(top_srcdir)/prism/util/pm_arena.h -prism/util/pm_line_offset_list.$(OBJEXT): $(top_srcdir)/prism/util/pm_line_offset_list.c -prism/util/pm_line_offset_list.$(OBJEXT): $(top_srcdir)/prism/util/pm_line_offset_list.h -prism/util/pm_line_offset_list.$(OBJEXT): {$(VPATH)}config.h -prism/util/pm_line_offset_list.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h -prism/util/pm_line_offset_list.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h -prism/util/pm_line_offset_list.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h -prism/util/pm_line_offset_list.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h -prism/util/pm_line_offset_list.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h -prism/util/pm_line_offset_list.$(OBJEXT): {$(VPATH)}internal/compiler_is.h -prism/util/pm_line_offset_list.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h -prism/util/pm_line_offset_list.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h -prism/util/pm_line_offset_list.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h -prism/util/pm_line_offset_list.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h -prism/util/pm_line_offset_list.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h -prism/util/pm_line_offset_list.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h -prism/util/pm_line_offset_list.$(OBJEXT): {$(VPATH)}internal/compiler_since.h -prism/util/pm_line_offset_list.$(OBJEXT): {$(VPATH)}internal/config.h -prism/util/pm_line_offset_list.$(OBJEXT): {$(VPATH)}internal/dllexport.h -prism/util/pm_line_offset_list.$(OBJEXT): {$(VPATH)}internal/has/attribute.h -prism/util/pm_line_offset_list.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h -prism/util/pm_line_offset_list.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h -prism/util/pm_line_offset_list.$(OBJEXT): {$(VPATH)}internal/has/extension.h -prism/util/pm_line_offset_list.$(OBJEXT): {$(VPATH)}internal/has/feature.h -prism/util/pm_line_offset_list.$(OBJEXT): {$(VPATH)}internal/has/warning.h -prism/util/pm_line_offset_list.$(OBJEXT): {$(VPATH)}internal/xmalloc.h -prism/util/pm_line_offset_list.$(OBJEXT): {$(VPATH)}prism_xallocator.h -prism/util/pm_list.$(OBJEXT): $(top_srcdir)/prism/defines.h -prism/util/pm_list.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.c -prism/util/pm_list.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h -prism/util/pm_list.$(OBJEXT): {$(VPATH)}config.h -prism/util/pm_list.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h -prism/util/pm_list.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h -prism/util/pm_list.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h -prism/util/pm_list.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h -prism/util/pm_list.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h -prism/util/pm_list.$(OBJEXT): {$(VPATH)}internal/compiler_is.h -prism/util/pm_list.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h -prism/util/pm_list.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h -prism/util/pm_list.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h -prism/util/pm_list.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h -prism/util/pm_list.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h -prism/util/pm_list.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h -prism/util/pm_list.$(OBJEXT): {$(VPATH)}internal/compiler_since.h -prism/util/pm_list.$(OBJEXT): {$(VPATH)}internal/config.h -prism/util/pm_list.$(OBJEXT): {$(VPATH)}internal/dllexport.h -prism/util/pm_list.$(OBJEXT): {$(VPATH)}internal/has/attribute.h -prism/util/pm_list.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h -prism/util/pm_list.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h -prism/util/pm_list.$(OBJEXT): {$(VPATH)}internal/has/extension.h -prism/util/pm_list.$(OBJEXT): {$(VPATH)}internal/has/feature.h -prism/util/pm_list.$(OBJEXT): {$(VPATH)}internal/has/warning.h -prism/util/pm_list.$(OBJEXT): {$(VPATH)}internal/xmalloc.h -prism/util/pm_list.$(OBJEXT): {$(VPATH)}prism_xallocator.h -prism/util/pm_memchr.$(OBJEXT): $(top_srcdir)/prism/ast.h -prism/util/pm_memchr.$(OBJEXT): $(top_srcdir)/prism/defines.h -prism/util/pm_memchr.$(OBJEXT): $(top_srcdir)/prism/encoding.h -prism/util/pm_memchr.$(OBJEXT): $(top_srcdir)/prism/parser.h -prism/util/pm_memchr.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h -prism/util/pm_memchr.$(OBJEXT): $(top_srcdir)/prism/util/pm_line_offset_list.h -prism/util/pm_memchr.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h -prism/util/pm_memchr.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.c -prism/util/pm_memchr.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h -prism/util/pm_memchr.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h -prism/util/pm_memchr.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h -prism/util/pm_memchr.$(OBJEXT): {$(VPATH)}config.h -prism/util/pm_memchr.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h -prism/util/pm_memchr.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h -prism/util/pm_memchr.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h -prism/util/pm_memchr.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h -prism/util/pm_memchr.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h -prism/util/pm_memchr.$(OBJEXT): {$(VPATH)}internal/compiler_is.h -prism/util/pm_memchr.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h -prism/util/pm_memchr.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h -prism/util/pm_memchr.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h -prism/util/pm_memchr.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h -prism/util/pm_memchr.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h -prism/util/pm_memchr.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h -prism/util/pm_memchr.$(OBJEXT): {$(VPATH)}internal/compiler_since.h -prism/util/pm_memchr.$(OBJEXT): {$(VPATH)}internal/config.h -prism/util/pm_memchr.$(OBJEXT): {$(VPATH)}internal/dllexport.h -prism/util/pm_memchr.$(OBJEXT): {$(VPATH)}internal/has/attribute.h -prism/util/pm_memchr.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h -prism/util/pm_memchr.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h -prism/util/pm_memchr.$(OBJEXT): {$(VPATH)}internal/has/extension.h -prism/util/pm_memchr.$(OBJEXT): {$(VPATH)}internal/has/feature.h -prism/util/pm_memchr.$(OBJEXT): {$(VPATH)}internal/has/warning.h -prism/util/pm_memchr.$(OBJEXT): {$(VPATH)}internal/xmalloc.h -prism/util/pm_memchr.$(OBJEXT): {$(VPATH)}prism_xallocator.h -prism/util/pm_string.$(OBJEXT): $(top_srcdir)/prism/defines.h -prism/util/pm_string.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.c -prism/util/pm_string.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h -prism/util/pm_string.$(OBJEXT): {$(VPATH)}config.h -prism/util/pm_string.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h -prism/util/pm_string.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h -prism/util/pm_string.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h -prism/util/pm_string.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h -prism/util/pm_string.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h -prism/util/pm_string.$(OBJEXT): {$(VPATH)}internal/compiler_is.h -prism/util/pm_string.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h -prism/util/pm_string.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h -prism/util/pm_string.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h -prism/util/pm_string.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h -prism/util/pm_string.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h -prism/util/pm_string.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h -prism/util/pm_string.$(OBJEXT): {$(VPATH)}internal/compiler_since.h -prism/util/pm_string.$(OBJEXT): {$(VPATH)}internal/config.h -prism/util/pm_string.$(OBJEXT): {$(VPATH)}internal/dllexport.h -prism/util/pm_string.$(OBJEXT): {$(VPATH)}internal/has/attribute.h -prism/util/pm_string.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h -prism/util/pm_string.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h -prism/util/pm_string.$(OBJEXT): {$(VPATH)}internal/has/extension.h -prism/util/pm_string.$(OBJEXT): {$(VPATH)}internal/has/feature.h -prism/util/pm_string.$(OBJEXT): {$(VPATH)}internal/has/warning.h -prism/util/pm_string.$(OBJEXT): {$(VPATH)}internal/xmalloc.h -prism/util/pm_string.$(OBJEXT): {$(VPATH)}prism_xallocator.h -prism/util/pm_strncasecmp.$(OBJEXT): $(top_srcdir)/prism/defines.h -prism/util/pm_strncasecmp.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.c -prism/util/pm_strncasecmp.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h -prism/util/pm_strncasecmp.$(OBJEXT): {$(VPATH)}config.h -prism/util/pm_strncasecmp.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h -prism/util/pm_strncasecmp.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h -prism/util/pm_strncasecmp.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h -prism/util/pm_strncasecmp.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h -prism/util/pm_strncasecmp.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h -prism/util/pm_strncasecmp.$(OBJEXT): {$(VPATH)}internal/compiler_is.h -prism/util/pm_strncasecmp.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h -prism/util/pm_strncasecmp.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h -prism/util/pm_strncasecmp.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h -prism/util/pm_strncasecmp.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h -prism/util/pm_strncasecmp.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h -prism/util/pm_strncasecmp.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h -prism/util/pm_strncasecmp.$(OBJEXT): {$(VPATH)}internal/compiler_since.h -prism/util/pm_strncasecmp.$(OBJEXT): {$(VPATH)}internal/config.h -prism/util/pm_strncasecmp.$(OBJEXT): {$(VPATH)}internal/dllexport.h -prism/util/pm_strncasecmp.$(OBJEXT): {$(VPATH)}internal/has/attribute.h -prism/util/pm_strncasecmp.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h -prism/util/pm_strncasecmp.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h -prism/util/pm_strncasecmp.$(OBJEXT): {$(VPATH)}internal/has/extension.h -prism/util/pm_strncasecmp.$(OBJEXT): {$(VPATH)}internal/has/feature.h -prism/util/pm_strncasecmp.$(OBJEXT): {$(VPATH)}internal/has/warning.h -prism/util/pm_strncasecmp.$(OBJEXT): {$(VPATH)}internal/xmalloc.h -prism/util/pm_strncasecmp.$(OBJEXT): {$(VPATH)}prism_xallocator.h -prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/ast.h -prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/defines.h -prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h -prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/encoding.h -prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/options.h -prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/parser.h -prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/static_literals.h -prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/util/pm_arena.h -prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h -prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h -prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h -prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h -prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/util/pm_line_offset_list.h -prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h -prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h -prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h -prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.c -prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h -prism/util/pm_strpbrk.$(OBJEXT): {$(VPATH)}config.h -prism/util/pm_strpbrk.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h -prism/util/pm_strpbrk.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h -prism/util/pm_strpbrk.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h -prism/util/pm_strpbrk.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h -prism/util/pm_strpbrk.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h -prism/util/pm_strpbrk.$(OBJEXT): {$(VPATH)}internal/compiler_is.h -prism/util/pm_strpbrk.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h -prism/util/pm_strpbrk.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h -prism/util/pm_strpbrk.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h -prism/util/pm_strpbrk.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h -prism/util/pm_strpbrk.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h -prism/util/pm_strpbrk.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h -prism/util/pm_strpbrk.$(OBJEXT): {$(VPATH)}internal/compiler_since.h -prism/util/pm_strpbrk.$(OBJEXT): {$(VPATH)}internal/config.h -prism/util/pm_strpbrk.$(OBJEXT): {$(VPATH)}internal/dllexport.h -prism/util/pm_strpbrk.$(OBJEXT): {$(VPATH)}internal/has/attribute.h -prism/util/pm_strpbrk.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h -prism/util/pm_strpbrk.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h -prism/util/pm_strpbrk.$(OBJEXT): {$(VPATH)}internal/has/extension.h -prism/util/pm_strpbrk.$(OBJEXT): {$(VPATH)}internal/has/feature.h -prism/util/pm_strpbrk.$(OBJEXT): {$(VPATH)}internal/has/warning.h -prism/util/pm_strpbrk.$(OBJEXT): {$(VPATH)}internal/xmalloc.h -prism/util/pm_strpbrk.$(OBJEXT): {$(VPATH)}prism_xallocator.h +prism/string_query.$(OBJEXT): $(top_srcdir)/prism/arena.h +prism/string_query.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +prism/string_query.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h +prism/string_query.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h +prism/string_query.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +prism/string_query.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +prism/string_query.$(OBJEXT): $(top_srcdir)/prism/internal/char.h +prism/string_query.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h +prism/string_query.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h +prism/string_query.$(OBJEXT): $(top_srcdir)/prism/string_query.c +prism/string_query.$(OBJEXT): $(top_srcdir)/prism/string_query.h +prism/stringy.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +prism/stringy.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +prism/stringy.$(OBJEXT): $(top_srcdir)/prism/internal/allocator.h +prism/stringy.$(OBJEXT): $(top_srcdir)/prism/internal/stringy.h +prism/stringy.$(OBJEXT): $(top_srcdir)/prism/stringy.c +prism/stringy.$(OBJEXT): $(top_srcdir)/prism/stringy.h +prism/stringy.$(OBJEXT): {$(VPATH)}config.h +prism/stringy.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h +prism/stringy.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h +prism/stringy.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h +prism/stringy.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h +prism/stringy.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h +prism/stringy.$(OBJEXT): {$(VPATH)}internal/compiler_is.h +prism/stringy.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h +prism/stringy.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h +prism/stringy.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h +prism/stringy.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h +prism/stringy.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h +prism/stringy.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h +prism/stringy.$(OBJEXT): {$(VPATH)}internal/compiler_since.h +prism/stringy.$(OBJEXT): {$(VPATH)}internal/config.h +prism/stringy.$(OBJEXT): {$(VPATH)}internal/dllexport.h +prism/stringy.$(OBJEXT): {$(VPATH)}internal/has/attribute.h +prism/stringy.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h +prism/stringy.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h +prism/stringy.$(OBJEXT): {$(VPATH)}internal/has/extension.h +prism/stringy.$(OBJEXT): {$(VPATH)}internal/has/feature.h +prism/stringy.$(OBJEXT): {$(VPATH)}internal/has/warning.h +prism/stringy.$(OBJEXT): {$(VPATH)}internal/xmalloc.h +prism/stringy.$(OBJEXT): {$(VPATH)}prism_xallocator.h +prism/strncasecmp.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h +prism/strncasecmp.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h +prism/strncasecmp.$(OBJEXT): $(top_srcdir)/prism/strncasecmp.c +prism/strncasecmp.$(OBJEXT): {$(VPATH)}config.h +prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h +prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h +prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h +prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h +prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h +prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/compiler_is.h +prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h +prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h +prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h +prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h +prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h +prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h +prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/compiler_since.h +prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/config.h +prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/dllexport.h +prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/has/attribute.h +prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h +prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h +prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/has/extension.h +prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/has/feature.h +prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/has/warning.h +prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/xmalloc.h +prism/strncasecmp.$(OBJEXT): {$(VPATH)}prism_xallocator.h +prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/arena.h +prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/ast.h +prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/buffer.h +prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/comments.h +prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/compiler/accel.h +prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h +prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/compiler/flex_array.h +prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h +prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h +prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/compiler/unused.h +prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h +prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h +prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/integer.h +prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/internal/arena.h +prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/internal/bit.h +prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/internal/char.h +prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/internal/constant_pool.h +prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/internal/diagnostic.h +prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h +prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/internal/list.h +prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/internal/options.h +prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/internal/parser.h +prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h +prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h +prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h +prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h +prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h +prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/options.h +prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/parser.h +prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/stringy.h +prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/strpbrk.c +prism/strpbrk.$(OBJEXT): {$(VPATH)}config.h +prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h +prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h +prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h +prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h +prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h +prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/compiler_is.h +prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h +prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h +prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h +prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h +prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h +prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h +prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/compiler_since.h +prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/config.h +prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/dllexport.h +prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/has/attribute.h +prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h +prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h +prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/has/extension.h +prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/has/feature.h +prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/has/warning.h +prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/xmalloc.h +prism/strpbrk.$(OBJEXT): {$(VPATH)}prism_xallocator.h +prism/tokens.$(OBJEXT): $(top_srcdir)/prism/arena.h +prism/tokens.$(OBJEXT): $(top_srcdir)/prism/ast.h +prism/tokens.$(OBJEXT): $(top_srcdir)/prism/buffer.h +prism/tokens.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h +prism/tokens.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +prism/tokens.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +prism/tokens.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +prism/tokens.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h +prism/tokens.$(OBJEXT): $(top_srcdir)/prism/integer.h +prism/tokens.$(OBJEXT): $(top_srcdir)/prism/internal/char.h +prism/tokens.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h +prism/tokens.$(OBJEXT): $(top_srcdir)/prism/stringy.h +prism/tokens.$(OBJEXT): $(top_srcdir)/prism/tokens.c +prism/tokens.$(OBJEXT): {$(VPATH)}config.h +prism/tokens.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h +prism/tokens.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h +prism/tokens.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h +prism/tokens.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h +prism/tokens.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h +prism/tokens.$(OBJEXT): {$(VPATH)}internal/compiler_is.h +prism/tokens.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h +prism/tokens.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h +prism/tokens.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h +prism/tokens.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h +prism/tokens.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h +prism/tokens.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h +prism/tokens.$(OBJEXT): {$(VPATH)}internal/compiler_since.h +prism/tokens.$(OBJEXT): {$(VPATH)}internal/config.h +prism/tokens.$(OBJEXT): {$(VPATH)}internal/dllexport.h +prism/tokens.$(OBJEXT): {$(VPATH)}internal/has/attribute.h +prism/tokens.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h +prism/tokens.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h +prism/tokens.$(OBJEXT): {$(VPATH)}internal/has/extension.h +prism/tokens.$(OBJEXT): {$(VPATH)}internal/has/feature.h +prism/tokens.$(OBJEXT): {$(VPATH)}internal/has/warning.h +prism/tokens.$(OBJEXT): {$(VPATH)}internal/xmalloc.h +prism/tokens.$(OBJEXT): {$(VPATH)}prism_xallocator.h prism_init.$(OBJEXT): $(hdrdir)/ruby.h prism_init.$(OBJEXT): $(hdrdir)/ruby/ruby.h prism_init.$(OBJEXT): $(hdrdir)/ruby/version.h +prism_init.$(OBJEXT): $(top_srcdir)/prism/arena.h prism_init.$(OBJEXT): $(top_srcdir)/prism/ast.h -prism_init.$(OBJEXT): $(top_srcdir)/prism/defines.h +prism_init.$(OBJEXT): $(top_srcdir)/prism/buffer.h +prism_init.$(OBJEXT): $(top_srcdir)/prism/comments.h +prism_init.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h +prism_init.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +prism_init.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h +prism_init.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +prism_init.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +prism_init.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h prism_init.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h -prism_init.$(OBJEXT): $(top_srcdir)/prism/encoding.h +prism_init.$(OBJEXT): $(top_srcdir)/prism/excludes.h prism_init.$(OBJEXT): $(top_srcdir)/prism/extension.h +prism_init.$(OBJEXT): $(top_srcdir)/prism/integer.h +prism_init.$(OBJEXT): $(top_srcdir)/prism/internal/char.h +prism_init.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h +prism_init.$(OBJEXT): $(top_srcdir)/prism/internal/list.h +prism_init.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h +prism_init.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h +prism_init.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h +prism_init.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h +prism_init.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h +prism_init.$(OBJEXT): $(top_srcdir)/prism/json.h +prism_init.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h +prism_init.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h prism_init.$(OBJEXT): $(top_srcdir)/prism/node.h prism_init.$(OBJEXT): $(top_srcdir)/prism/options.h prism_init.$(OBJEXT): $(top_srcdir)/prism/parser.h prism_init.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h prism_init.$(OBJEXT): $(top_srcdir)/prism/prism.h -prism_init.$(OBJEXT): $(top_srcdir)/prism/regexp.h -prism_init.$(OBJEXT): $(top_srcdir)/prism/static_literals.h -prism_init.$(OBJEXT): $(top_srcdir)/prism/util/pm_arena.h -prism_init.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h -prism_init.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h -prism_init.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h -prism_init.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h -prism_init.$(OBJEXT): $(top_srcdir)/prism/util/pm_line_offset_list.h -prism_init.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h -prism_init.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h -prism_init.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h -prism_init.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h -prism_init.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +prism_init.$(OBJEXT): $(top_srcdir)/prism/serialize.h +prism_init.$(OBJEXT): $(top_srcdir)/prism/source.h +prism_init.$(OBJEXT): $(top_srcdir)/prism/stream.h +prism_init.$(OBJEXT): $(top_srcdir)/prism/string_query.h +prism_init.$(OBJEXT): $(top_srcdir)/prism/stringy.h prism_init.$(OBJEXT): $(top_srcdir)/prism/version.h prism_init.$(OBJEXT): $(top_srcdir)/prism_init.c prism_init.$(OBJEXT): {$(VPATH)}assert.h @@ -12495,28 +13017,40 @@ proc.$(OBJEXT): $(top_srcdir)/internal/symbol.h proc.$(OBJEXT): $(top_srcdir)/internal/variable.h proc.$(OBJEXT): $(top_srcdir)/internal/vm.h proc.$(OBJEXT): $(top_srcdir)/internal/warnings.h +proc.$(OBJEXT): $(top_srcdir)/prism/arena.h proc.$(OBJEXT): $(top_srcdir)/prism/ast.h -proc.$(OBJEXT): $(top_srcdir)/prism/defines.h +proc.$(OBJEXT): $(top_srcdir)/prism/buffer.h +proc.$(OBJEXT): $(top_srcdir)/prism/comments.h +proc.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h +proc.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +proc.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h +proc.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +proc.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +proc.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h proc.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h -proc.$(OBJEXT): $(top_srcdir)/prism/encoding.h +proc.$(OBJEXT): $(top_srcdir)/prism/excludes.h +proc.$(OBJEXT): $(top_srcdir)/prism/integer.h +proc.$(OBJEXT): $(top_srcdir)/prism/internal/char.h +proc.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h +proc.$(OBJEXT): $(top_srcdir)/prism/internal/list.h +proc.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h +proc.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h +proc.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h +proc.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h +proc.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h +proc.$(OBJEXT): $(top_srcdir)/prism/json.h +proc.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h +proc.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h proc.$(OBJEXT): $(top_srcdir)/prism/node.h proc.$(OBJEXT): $(top_srcdir)/prism/options.h proc.$(OBJEXT): $(top_srcdir)/prism/parser.h proc.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h proc.$(OBJEXT): $(top_srcdir)/prism/prism.h -proc.$(OBJEXT): $(top_srcdir)/prism/regexp.h -proc.$(OBJEXT): $(top_srcdir)/prism/static_literals.h -proc.$(OBJEXT): $(top_srcdir)/prism/util/pm_arena.h -proc.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h -proc.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h -proc.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h -proc.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h -proc.$(OBJEXT): $(top_srcdir)/prism/util/pm_line_offset_list.h -proc.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h -proc.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h -proc.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h -proc.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h -proc.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +proc.$(OBJEXT): $(top_srcdir)/prism/serialize.h +proc.$(OBJEXT): $(top_srcdir)/prism/source.h +proc.$(OBJEXT): $(top_srcdir)/prism/stream.h +proc.$(OBJEXT): $(top_srcdir)/prism/string_query.h +proc.$(OBJEXT): $(top_srcdir)/prism/stringy.h proc.$(OBJEXT): $(top_srcdir)/prism/version.h proc.$(OBJEXT): {$(VPATH)}assert.h proc.$(OBJEXT): {$(VPATH)}atomic.h @@ -15071,28 +15605,40 @@ ruby.$(OBJEXT): $(top_srcdir)/internal/thread.h ruby.$(OBJEXT): $(top_srcdir)/internal/variable.h ruby.$(OBJEXT): $(top_srcdir)/internal/vm.h ruby.$(OBJEXT): $(top_srcdir)/internal/warnings.h +ruby.$(OBJEXT): $(top_srcdir)/prism/arena.h ruby.$(OBJEXT): $(top_srcdir)/prism/ast.h -ruby.$(OBJEXT): $(top_srcdir)/prism/defines.h +ruby.$(OBJEXT): $(top_srcdir)/prism/buffer.h +ruby.$(OBJEXT): $(top_srcdir)/prism/comments.h +ruby.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h +ruby.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +ruby.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h +ruby.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +ruby.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +ruby.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h ruby.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h -ruby.$(OBJEXT): $(top_srcdir)/prism/encoding.h +ruby.$(OBJEXT): $(top_srcdir)/prism/excludes.h +ruby.$(OBJEXT): $(top_srcdir)/prism/integer.h +ruby.$(OBJEXT): $(top_srcdir)/prism/internal/char.h +ruby.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h +ruby.$(OBJEXT): $(top_srcdir)/prism/internal/list.h +ruby.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h +ruby.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h +ruby.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h +ruby.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h +ruby.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h +ruby.$(OBJEXT): $(top_srcdir)/prism/json.h +ruby.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h +ruby.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h ruby.$(OBJEXT): $(top_srcdir)/prism/node.h ruby.$(OBJEXT): $(top_srcdir)/prism/options.h ruby.$(OBJEXT): $(top_srcdir)/prism/parser.h ruby.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h ruby.$(OBJEXT): $(top_srcdir)/prism/prism.h -ruby.$(OBJEXT): $(top_srcdir)/prism/regexp.h -ruby.$(OBJEXT): $(top_srcdir)/prism/static_literals.h -ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_arena.h -ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h -ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h -ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h -ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h -ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_line_offset_list.h -ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h -ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h -ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h -ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h -ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +ruby.$(OBJEXT): $(top_srcdir)/prism/serialize.h +ruby.$(OBJEXT): $(top_srcdir)/prism/source.h +ruby.$(OBJEXT): $(top_srcdir)/prism/stream.h +ruby.$(OBJEXT): $(top_srcdir)/prism/string_query.h +ruby.$(OBJEXT): $(top_srcdir)/prism/stringy.h ruby.$(OBJEXT): $(top_srcdir)/prism/version.h ruby.$(OBJEXT): {$(VPATH)}assert.h ruby.$(OBJEXT): {$(VPATH)}atomic.h @@ -17827,28 +18373,40 @@ thread.$(OBJEXT): $(top_srcdir)/internal/time.h thread.$(OBJEXT): $(top_srcdir)/internal/variable.h thread.$(OBJEXT): $(top_srcdir)/internal/vm.h thread.$(OBJEXT): $(top_srcdir)/internal/warnings.h +thread.$(OBJEXT): $(top_srcdir)/prism/arena.h thread.$(OBJEXT): $(top_srcdir)/prism/ast.h -thread.$(OBJEXT): $(top_srcdir)/prism/defines.h +thread.$(OBJEXT): $(top_srcdir)/prism/buffer.h +thread.$(OBJEXT): $(top_srcdir)/prism/comments.h +thread.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h +thread.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +thread.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h +thread.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +thread.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +thread.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h thread.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h -thread.$(OBJEXT): $(top_srcdir)/prism/encoding.h +thread.$(OBJEXT): $(top_srcdir)/prism/excludes.h +thread.$(OBJEXT): $(top_srcdir)/prism/integer.h +thread.$(OBJEXT): $(top_srcdir)/prism/internal/char.h +thread.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h +thread.$(OBJEXT): $(top_srcdir)/prism/internal/list.h +thread.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h +thread.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h +thread.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h +thread.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h +thread.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h +thread.$(OBJEXT): $(top_srcdir)/prism/json.h +thread.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h +thread.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h thread.$(OBJEXT): $(top_srcdir)/prism/node.h thread.$(OBJEXT): $(top_srcdir)/prism/options.h thread.$(OBJEXT): $(top_srcdir)/prism/parser.h thread.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h thread.$(OBJEXT): $(top_srcdir)/prism/prism.h -thread.$(OBJEXT): $(top_srcdir)/prism/regexp.h -thread.$(OBJEXT): $(top_srcdir)/prism/static_literals.h -thread.$(OBJEXT): $(top_srcdir)/prism/util/pm_arena.h -thread.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h -thread.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h -thread.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h -thread.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h -thread.$(OBJEXT): $(top_srcdir)/prism/util/pm_line_offset_list.h -thread.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h -thread.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h -thread.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h -thread.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h -thread.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +thread.$(OBJEXT): $(top_srcdir)/prism/serialize.h +thread.$(OBJEXT): $(top_srcdir)/prism/source.h +thread.$(OBJEXT): $(top_srcdir)/prism/stream.h +thread.$(OBJEXT): $(top_srcdir)/prism/string_query.h +thread.$(OBJEXT): $(top_srcdir)/prism/stringy.h thread.$(OBJEXT): $(top_srcdir)/prism/version.h thread.$(OBJEXT): {$(VPATH)}$(COROUTINE_H) thread.$(OBJEXT): {$(VPATH)}assert.h @@ -19144,28 +19702,40 @@ vm.$(OBJEXT): $(top_srcdir)/internal/transcode.h vm.$(OBJEXT): $(top_srcdir)/internal/variable.h vm.$(OBJEXT): $(top_srcdir)/internal/vm.h vm.$(OBJEXT): $(top_srcdir)/internal/warnings.h +vm.$(OBJEXT): $(top_srcdir)/prism/arena.h vm.$(OBJEXT): $(top_srcdir)/prism/ast.h -vm.$(OBJEXT): $(top_srcdir)/prism/defines.h +vm.$(OBJEXT): $(top_srcdir)/prism/buffer.h +vm.$(OBJEXT): $(top_srcdir)/prism/comments.h +vm.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h +vm.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +vm.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h +vm.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +vm.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +vm.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h vm.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h -vm.$(OBJEXT): $(top_srcdir)/prism/encoding.h +vm.$(OBJEXT): $(top_srcdir)/prism/excludes.h +vm.$(OBJEXT): $(top_srcdir)/prism/integer.h +vm.$(OBJEXT): $(top_srcdir)/prism/internal/char.h +vm.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h +vm.$(OBJEXT): $(top_srcdir)/prism/internal/list.h +vm.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h +vm.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h +vm.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h +vm.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h +vm.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h +vm.$(OBJEXT): $(top_srcdir)/prism/json.h +vm.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h +vm.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h vm.$(OBJEXT): $(top_srcdir)/prism/node.h vm.$(OBJEXT): $(top_srcdir)/prism/options.h vm.$(OBJEXT): $(top_srcdir)/prism/parser.h vm.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h vm.$(OBJEXT): $(top_srcdir)/prism/prism.h -vm.$(OBJEXT): $(top_srcdir)/prism/regexp.h -vm.$(OBJEXT): $(top_srcdir)/prism/static_literals.h -vm.$(OBJEXT): $(top_srcdir)/prism/util/pm_arena.h -vm.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h -vm.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h -vm.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h -vm.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h -vm.$(OBJEXT): $(top_srcdir)/prism/util/pm_line_offset_list.h -vm.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h -vm.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h -vm.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h -vm.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h -vm.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +vm.$(OBJEXT): $(top_srcdir)/prism/serialize.h +vm.$(OBJEXT): $(top_srcdir)/prism/source.h +vm.$(OBJEXT): $(top_srcdir)/prism/stream.h +vm.$(OBJEXT): $(top_srcdir)/prism/string_query.h +vm.$(OBJEXT): $(top_srcdir)/prism/stringy.h vm.$(OBJEXT): $(top_srcdir)/prism/version.h vm.$(OBJEXT): {$(VPATH)}assert.h vm.$(OBJEXT): {$(VPATH)}atomic.h @@ -19411,28 +19981,40 @@ vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/struct.h vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/variable.h vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/vm.h vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/warnings.h +vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/arena.h vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/ast.h -vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/defines.h +vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/buffer.h +vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/comments.h +vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h +vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h +vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h -vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/encoding.h +vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/excludes.h +vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/integer.h +vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/internal/char.h +vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h +vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/internal/list.h +vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h +vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h +vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h +vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h +vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h +vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/json.h +vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h +vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/node.h vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/options.h vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/parser.h vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/prism.h -vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/regexp.h -vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/static_literals.h -vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/util/pm_arena.h -vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h -vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h -vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h -vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h -vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/util/pm_line_offset_list.h -vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h -vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h -vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h -vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h -vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/serialize.h +vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/source.h +vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/stream.h +vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/string_query.h +vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/stringy.h vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/version.h vm_backtrace.$(OBJEXT): {$(VPATH)}assert.h vm_backtrace.$(OBJEXT): {$(VPATH)}atomic.h @@ -19647,28 +20229,40 @@ vm_dump.$(OBJEXT): $(top_srcdir)/internal/struct.h vm_dump.$(OBJEXT): $(top_srcdir)/internal/variable.h vm_dump.$(OBJEXT): $(top_srcdir)/internal/vm.h vm_dump.$(OBJEXT): $(top_srcdir)/internal/warnings.h +vm_dump.$(OBJEXT): $(top_srcdir)/prism/arena.h vm_dump.$(OBJEXT): $(top_srcdir)/prism/ast.h -vm_dump.$(OBJEXT): $(top_srcdir)/prism/defines.h +vm_dump.$(OBJEXT): $(top_srcdir)/prism/buffer.h +vm_dump.$(OBJEXT): $(top_srcdir)/prism/comments.h +vm_dump.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h +vm_dump.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +vm_dump.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h +vm_dump.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +vm_dump.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +vm_dump.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h vm_dump.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h -vm_dump.$(OBJEXT): $(top_srcdir)/prism/encoding.h +vm_dump.$(OBJEXT): $(top_srcdir)/prism/excludes.h +vm_dump.$(OBJEXT): $(top_srcdir)/prism/integer.h +vm_dump.$(OBJEXT): $(top_srcdir)/prism/internal/char.h +vm_dump.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h +vm_dump.$(OBJEXT): $(top_srcdir)/prism/internal/list.h +vm_dump.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h +vm_dump.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h +vm_dump.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h +vm_dump.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h +vm_dump.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h +vm_dump.$(OBJEXT): $(top_srcdir)/prism/json.h +vm_dump.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h +vm_dump.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h vm_dump.$(OBJEXT): $(top_srcdir)/prism/node.h vm_dump.$(OBJEXT): $(top_srcdir)/prism/options.h vm_dump.$(OBJEXT): $(top_srcdir)/prism/parser.h vm_dump.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h vm_dump.$(OBJEXT): $(top_srcdir)/prism/prism.h -vm_dump.$(OBJEXT): $(top_srcdir)/prism/regexp.h -vm_dump.$(OBJEXT): $(top_srcdir)/prism/static_literals.h -vm_dump.$(OBJEXT): $(top_srcdir)/prism/util/pm_arena.h -vm_dump.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h -vm_dump.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h -vm_dump.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h -vm_dump.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h -vm_dump.$(OBJEXT): $(top_srcdir)/prism/util/pm_line_offset_list.h -vm_dump.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h -vm_dump.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h -vm_dump.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h -vm_dump.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h -vm_dump.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +vm_dump.$(OBJEXT): $(top_srcdir)/prism/serialize.h +vm_dump.$(OBJEXT): $(top_srcdir)/prism/source.h +vm_dump.$(OBJEXT): $(top_srcdir)/prism/stream.h +vm_dump.$(OBJEXT): $(top_srcdir)/prism/string_query.h +vm_dump.$(OBJEXT): $(top_srcdir)/prism/stringy.h vm_dump.$(OBJEXT): $(top_srcdir)/prism/version.h vm_dump.$(OBJEXT): {$(VPATH)}addr2line.h vm_dump.$(OBJEXT): {$(VPATH)}assert.h @@ -20098,28 +20692,40 @@ vm_trace.$(OBJEXT): $(top_srcdir)/internal/thread.h vm_trace.$(OBJEXT): $(top_srcdir)/internal/variable.h vm_trace.$(OBJEXT): $(top_srcdir)/internal/vm.h vm_trace.$(OBJEXT): $(top_srcdir)/internal/warnings.h +vm_trace.$(OBJEXT): $(top_srcdir)/prism/arena.h vm_trace.$(OBJEXT): $(top_srcdir)/prism/ast.h -vm_trace.$(OBJEXT): $(top_srcdir)/prism/defines.h +vm_trace.$(OBJEXT): $(top_srcdir)/prism/buffer.h +vm_trace.$(OBJEXT): $(top_srcdir)/prism/comments.h +vm_trace.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h +vm_trace.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +vm_trace.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h +vm_trace.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +vm_trace.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +vm_trace.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h vm_trace.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h -vm_trace.$(OBJEXT): $(top_srcdir)/prism/encoding.h +vm_trace.$(OBJEXT): $(top_srcdir)/prism/excludes.h +vm_trace.$(OBJEXT): $(top_srcdir)/prism/integer.h +vm_trace.$(OBJEXT): $(top_srcdir)/prism/internal/char.h +vm_trace.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h +vm_trace.$(OBJEXT): $(top_srcdir)/prism/internal/list.h +vm_trace.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h +vm_trace.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h +vm_trace.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h +vm_trace.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h +vm_trace.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h +vm_trace.$(OBJEXT): $(top_srcdir)/prism/json.h +vm_trace.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h +vm_trace.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h vm_trace.$(OBJEXT): $(top_srcdir)/prism/node.h vm_trace.$(OBJEXT): $(top_srcdir)/prism/options.h vm_trace.$(OBJEXT): $(top_srcdir)/prism/parser.h vm_trace.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h vm_trace.$(OBJEXT): $(top_srcdir)/prism/prism.h -vm_trace.$(OBJEXT): $(top_srcdir)/prism/regexp.h -vm_trace.$(OBJEXT): $(top_srcdir)/prism/static_literals.h -vm_trace.$(OBJEXT): $(top_srcdir)/prism/util/pm_arena.h -vm_trace.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h -vm_trace.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h -vm_trace.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h -vm_trace.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h -vm_trace.$(OBJEXT): $(top_srcdir)/prism/util/pm_line_offset_list.h -vm_trace.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h -vm_trace.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h -vm_trace.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h -vm_trace.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h -vm_trace.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +vm_trace.$(OBJEXT): $(top_srcdir)/prism/serialize.h +vm_trace.$(OBJEXT): $(top_srcdir)/prism/source.h +vm_trace.$(OBJEXT): $(top_srcdir)/prism/stream.h +vm_trace.$(OBJEXT): $(top_srcdir)/prism/string_query.h +vm_trace.$(OBJEXT): $(top_srcdir)/prism/stringy.h vm_trace.$(OBJEXT): $(top_srcdir)/prism/version.h vm_trace.$(OBJEXT): {$(VPATH)}assert.h vm_trace.$(OBJEXT): {$(VPATH)}atomic.h @@ -20551,28 +21157,40 @@ yjit.$(OBJEXT): $(top_srcdir)/internal/struct.h yjit.$(OBJEXT): $(top_srcdir)/internal/variable.h yjit.$(OBJEXT): $(top_srcdir)/internal/vm.h yjit.$(OBJEXT): $(top_srcdir)/internal/warnings.h +yjit.$(OBJEXT): $(top_srcdir)/prism/arena.h yjit.$(OBJEXT): $(top_srcdir)/prism/ast.h -yjit.$(OBJEXT): $(top_srcdir)/prism/defines.h +yjit.$(OBJEXT): $(top_srcdir)/prism/buffer.h +yjit.$(OBJEXT): $(top_srcdir)/prism/comments.h +yjit.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h +yjit.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +yjit.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h +yjit.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +yjit.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +yjit.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h yjit.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h -yjit.$(OBJEXT): $(top_srcdir)/prism/encoding.h +yjit.$(OBJEXT): $(top_srcdir)/prism/excludes.h +yjit.$(OBJEXT): $(top_srcdir)/prism/integer.h +yjit.$(OBJEXT): $(top_srcdir)/prism/internal/char.h +yjit.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h +yjit.$(OBJEXT): $(top_srcdir)/prism/internal/list.h +yjit.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h +yjit.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h +yjit.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h +yjit.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h +yjit.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h +yjit.$(OBJEXT): $(top_srcdir)/prism/json.h +yjit.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h +yjit.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h yjit.$(OBJEXT): $(top_srcdir)/prism/node.h yjit.$(OBJEXT): $(top_srcdir)/prism/options.h yjit.$(OBJEXT): $(top_srcdir)/prism/parser.h yjit.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h yjit.$(OBJEXT): $(top_srcdir)/prism/prism.h -yjit.$(OBJEXT): $(top_srcdir)/prism/regexp.h -yjit.$(OBJEXT): $(top_srcdir)/prism/static_literals.h -yjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_arena.h -yjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h -yjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h -yjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h -yjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h -yjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_line_offset_list.h -yjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h -yjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h -yjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h -yjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h -yjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +yjit.$(OBJEXT): $(top_srcdir)/prism/serialize.h +yjit.$(OBJEXT): $(top_srcdir)/prism/source.h +yjit.$(OBJEXT): $(top_srcdir)/prism/stream.h +yjit.$(OBJEXT): $(top_srcdir)/prism/string_query.h +yjit.$(OBJEXT): $(top_srcdir)/prism/stringy.h yjit.$(OBJEXT): $(top_srcdir)/prism/version.h yjit.$(OBJEXT): {$(VPATH)}assert.h yjit.$(OBJEXT): {$(VPATH)}atomic.h @@ -20809,28 +21427,40 @@ zjit.$(OBJEXT): $(top_srcdir)/internal/struct.h zjit.$(OBJEXT): $(top_srcdir)/internal/variable.h zjit.$(OBJEXT): $(top_srcdir)/internal/vm.h zjit.$(OBJEXT): $(top_srcdir)/internal/warnings.h +zjit.$(OBJEXT): $(top_srcdir)/prism/arena.h zjit.$(OBJEXT): $(top_srcdir)/prism/ast.h -zjit.$(OBJEXT): $(top_srcdir)/prism/defines.h +zjit.$(OBJEXT): $(top_srcdir)/prism/buffer.h +zjit.$(OBJEXT): $(top_srcdir)/prism/comments.h +zjit.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h +zjit.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h +zjit.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h +zjit.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h +zjit.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h +zjit.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h zjit.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h -zjit.$(OBJEXT): $(top_srcdir)/prism/encoding.h +zjit.$(OBJEXT): $(top_srcdir)/prism/excludes.h +zjit.$(OBJEXT): $(top_srcdir)/prism/integer.h +zjit.$(OBJEXT): $(top_srcdir)/prism/internal/char.h +zjit.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h +zjit.$(OBJEXT): $(top_srcdir)/prism/internal/list.h +zjit.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h +zjit.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h +zjit.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h +zjit.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h +zjit.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h +zjit.$(OBJEXT): $(top_srcdir)/prism/json.h +zjit.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h +zjit.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h zjit.$(OBJEXT): $(top_srcdir)/prism/node.h zjit.$(OBJEXT): $(top_srcdir)/prism/options.h zjit.$(OBJEXT): $(top_srcdir)/prism/parser.h zjit.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h zjit.$(OBJEXT): $(top_srcdir)/prism/prism.h -zjit.$(OBJEXT): $(top_srcdir)/prism/regexp.h -zjit.$(OBJEXT): $(top_srcdir)/prism/static_literals.h -zjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_arena.h -zjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h -zjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h -zjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h -zjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h -zjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_line_offset_list.h -zjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h -zjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h -zjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h -zjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h -zjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +zjit.$(OBJEXT): $(top_srcdir)/prism/serialize.h +zjit.$(OBJEXT): $(top_srcdir)/prism/source.h +zjit.$(OBJEXT): $(top_srcdir)/prism/stream.h +zjit.$(OBJEXT): $(top_srcdir)/prism/string_query.h +zjit.$(OBJEXT): $(top_srcdir)/prism/stringy.h zjit.$(OBJEXT): $(top_srcdir)/prism/version.h zjit.$(OBJEXT): {$(VPATH)}assert.h zjit.$(OBJEXT): {$(VPATH)}atomic.h diff --git a/gems/bundled_gems b/gems/bundled_gems index 33364337bff4c5..4164ff4d405904 100644 --- a/gems/bundled_gems +++ b/gems/bundled_gems @@ -16,7 +16,7 @@ net-imap 0.6.3 https://github.com/ruby/net-imap net-smtp 0.5.1 https://github.com/ruby/net-smtp matrix 0.4.3 https://github.com/ruby/matrix prime 0.1.4 https://github.com/ruby/prime -rbs 4.0.0 https://github.com/ruby/rbs +rbs 3.10.3 https://github.com/ruby/rbs typeprof 0.31.1 https://github.com/ruby/typeprof debug 1.11.1 https://github.com/ruby/debug racc 1.8.1 https://github.com/ruby/racc diff --git a/iseq.c b/iseq.c index 3529e3aaca5300..9a0c66490d2221 100644 --- a/iseq.c +++ b/iseq.c @@ -982,7 +982,7 @@ rb_iseq_new_top(const VALUE ast_value, VALUE name, VALUE path, VALUE realpath, c rb_iseq_t * pm_iseq_new_top(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpath, const rb_iseq_t *parent, int *error_state) { - iseq_new_setup_coverage(path, (int) (node->parser->line_offsets.size - 1)); + iseq_new_setup_coverage(path, (int) (pm_parser_line_offsets(node->parser)->size - 1)); return pm_iseq_new_with_opt(node, name, path, realpath, 0, parent, 0, ISEQ_TYPE_TOP, &COMPILE_OPTION_DEFAULT, error_state); @@ -1006,7 +1006,7 @@ rb_iseq_new_main(const VALUE ast_value, VALUE path, VALUE realpath, const rb_ise rb_iseq_t * pm_iseq_new_main(pm_scope_node_t *node, VALUE path, VALUE realpath, const rb_iseq_t *parent, int opt, int *error_state) { - iseq_new_setup_coverage(path, (int) (node->parser->line_offsets.size - 1)); + iseq_new_setup_coverage(path, (int) (pm_parser_line_offsets(node->parser)->size - 1)); return pm_iseq_new_with_opt(node, rb_fstring_lit("
"), path, realpath, 0, @@ -1035,7 +1035,7 @@ pm_iseq_new_eval(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpath, if (rb_get_coverage_mode() & COVERAGE_TARGET_EVAL) { VALUE coverages = rb_get_coverages(); if (RTEST(coverages) && RTEST(path) && !RTEST(rb_hash_has_key(coverages, path))) { - iseq_setup_coverage(coverages, path, ((int) (node->parser->line_offsets.size - 1)) + first_lineno - 1); + iseq_setup_coverage(coverages, path, ((int) (pm_parser_line_offsets(node->parser)->size - 1)) + first_lineno - 1); } } @@ -1143,10 +1143,11 @@ pm_iseq_new_with_opt(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpa option = &next_option; pm_location_t *location = &node->base.location; - int32_t start_line = node->parser->start_line; + int32_t start_line = pm_parser_start_line(node->parser); + const pm_line_offset_list_t *line_offsets = pm_parser_line_offsets(node->parser); - pm_line_column_t start = pm_line_offset_list_line_column(&node->parser->line_offsets, location->start, start_line); - pm_line_column_t end = pm_line_offset_list_line_column(&node->parser->line_offsets, location->start + location->length, start_line); + pm_line_column_t start = pm_line_offset_list_line_column(line_offsets, location->start, start_line); + pm_line_column_t end = pm_line_offset_list_line_column(line_offsets, location->start + location->length, start_line); rb_code_location_t code_location = (rb_code_location_t) { .beg_pos = { .lineno = (int) start.line, .column = (int) start.column }, @@ -1411,19 +1412,20 @@ pm_iseq_compile_with_option(VALUE src, VALUE file, VALUE realpath, VALUE line, V src = StringValue(src); } - pm_parse_result_t result = { 0 }; - pm_options_line_set(&result.options, NUM2INT(line)); - pm_options_scopes_init(&result.options, 1); + pm_parse_result_t result; + pm_parse_result_init(&result); + pm_options_line_set(result.options, NUM2INT(line)); + pm_options_scopes_init(result.options, 1); result.node.coverage_enabled = 1; switch (option.frozen_string_literal) { case ISEQ_FROZEN_STRING_LITERAL_UNSET: break; case ISEQ_FROZEN_STRING_LITERAL_DISABLED: - pm_options_frozen_string_literal_set(&result.options, false); + pm_options_frozen_string_literal_set(result.options, false); break; case ISEQ_FROZEN_STRING_LITERAL_ENABLED: - pm_options_frozen_string_literal_set(&result.options, true); + pm_options_frozen_string_literal_set(result.options, true); break; default: rb_bug("pm_iseq_compile_with_option: invalid frozen_string_literal=%d", option.frozen_string_literal); @@ -1783,6 +1785,8 @@ iseqw_s_compile_prism(int argc, VALUE *argv, VALUE self) return iseqw_s_compile_parser(argc, argv, self, true); } +static VALUE iseqw_s_compile_file_prism(int argc, VALUE *argv, VALUE self); + /* * call-seq: * InstructionSequence.compile_file(file[, options]) -> iseq @@ -1806,6 +1810,10 @@ iseqw_s_compile_prism(int argc, VALUE *argv, VALUE self) static VALUE iseqw_s_compile_file(int argc, VALUE *argv, VALUE self) { + if (rb_ruby_prism_p()) { + return iseqw_s_compile_file_prism(argc, argv, self); + } + VALUE file, opt = Qnil; VALUE parser, f, exc = Qnil, ret; rb_ast_t *ast; @@ -1892,8 +1900,8 @@ iseqw_s_compile_file_prism(int argc, VALUE *argv, VALUE self) rb_execution_context_t *ec = GET_EC(); VALUE v = rb_vm_push_frame_fname(ec, file); - pm_parse_result_t result = { 0 }; - result.options.line = 1; + pm_parse_result_t result; + pm_parse_result_init(&result); result.node.coverage_enabled = 1; VALUE script_lines; diff --git a/jit.c b/jit.c index caca49d39dfaec..11ff015e362c3d 100644 --- a/jit.c +++ b/jit.c @@ -20,6 +20,10 @@ #include "internal/imemo.h" #include "ruby/internal/core/rtypeddata.h" +#ifndef _WIN32 +#include +#endif + enum jit_bindgen_constants { // Field offsets for the RObject struct ROBJECT_OFFSET_AS_HEAP_FIELDS = offsetof(struct RObject, as.heap.fields), diff --git a/lib/prism/ffi.rb b/lib/prism/ffi.rb index 1bcbfc367ccc3f..6b9bde51eaca49 100644 --- a/lib/prism/ffi.rb +++ b/lib/prism/ffi.rb @@ -59,6 +59,9 @@ def self.load_exported_functions_from(header, *functions, callbacks) # We only want to load the functions that we are interested in. next unless functions.any? { |function| line.include?(function) } + # Strip trailing attributes (PRISM_NODISCARD, PRISM_NONNULL(...), etc.) + line = line.sub(/\)(\s+PRISM_\w+(?:\([^)]*\))?)+\s*;/, ");") + # Parse the function declaration. unless /^PRISM_EXPORTED_FUNCTION (?.+) (?\w+)\((?.+)\);$/ =~ line raise "Could not parse #{line}" @@ -85,30 +88,44 @@ def self.load_exported_functions_from(header, *functions, callbacks) raise "Could not find functions #{functions.inspect}" unless functions.empty? end - callback :pm_parse_stream_fgets_t, [:pointer, :int, :pointer], :pointer - callback :pm_parse_stream_feof_t, [:pointer], :int - enum :pm_string_init_result_t, %i[PM_STRING_INIT_SUCCESS PM_STRING_INIT_ERROR_GENERIC PM_STRING_INIT_ERROR_DIRECTORY] + callback :pm_source_stream_fgets_t, [:pointer, :int, :pointer], :pointer + callback :pm_source_stream_feof_t, [:pointer], :int + pm_source_init_result_values = %i[PM_SOURCE_INIT_SUCCESS PM_SOURCE_INIT_ERROR_GENERIC PM_SOURCE_INIT_ERROR_DIRECTORY PM_SOURCE_INIT_ERROR_NON_REGULAR] + enum :pm_source_init_result_t, pm_source_init_result_values enum :pm_string_query_t, [:PM_STRING_QUERY_ERROR, -1, :PM_STRING_QUERY_FALSE, :PM_STRING_QUERY_TRUE] + # Ractor-safe lookup table for pm_source_init_result_t, since FFI's + # enum_type accesses module instance variables that are not shareable. + SOURCE_INIT_RESULT = pm_source_init_result_values.freeze + load_exported_functions_from( - "prism.h", + "prism/version.h", "pm_version", + [] + ) + + load_exported_functions_from( + "prism/serialize.h", "pm_serialize_parse", "pm_serialize_parse_stream", "pm_serialize_parse_comments", "pm_serialize_lex", "pm_serialize_parse_lex", - "pm_parse_success_p", + "pm_serialize_parse_success_p", + [] + ) + + load_exported_functions_from( + "prism/string_query.h", "pm_string_query_local", "pm_string_query_constant", "pm_string_query_method_name", - [:pm_parse_stream_fgets_t, :pm_parse_stream_feof_t] + [] ) load_exported_functions_from( - "prism/util/pm_buffer.h", - "pm_buffer_sizeof", - "pm_buffer_init", + "prism/buffer.h", + "pm_buffer_new", "pm_buffer_value", "pm_buffer_length", "pm_buffer_free", @@ -116,20 +133,19 @@ def self.load_exported_functions_from(header, *functions, callbacks) ) load_exported_functions_from( - "prism/util/pm_string.h", - "pm_string_mapped_init", - "pm_string_free", - "pm_string_source", - "pm_string_length", - "pm_string_sizeof", - [] + "prism/source.h", + "pm_source_file_new", + "pm_source_mapped_new", + "pm_source_stream_new", + "pm_source_free", + "pm_source_source", + "pm_source_length", + [:pm_source_stream_fgets_t, :pm_source_stream_feof_t] ) # This object represents a pm_buffer_t. We only use it as an opaque pointer, # so it doesn't need to know the fields of pm_buffer_t. class PrismBuffer # :nodoc: - SIZEOF = LibRubyParser.pm_buffer_sizeof - attr_reader :pointer def initialize(pointer) @@ -151,20 +167,20 @@ def read # Initialize a new buffer and yield it to the block. The buffer will be # automatically freed when the block returns. def self.with - FFI::MemoryPointer.new(SIZEOF) do |pointer| - raise unless LibRubyParser.pm_buffer_init(pointer) - return yield new(pointer) + buffer = LibRubyParser.pm_buffer_new + raise unless buffer + + begin + yield new(buffer) ensure - LibRubyParser.pm_buffer_free(pointer) + LibRubyParser.pm_buffer_free(buffer) end end end - # This object represents a pm_string_t. We only use it as an opaque pointer, - # so it doesn't have to be an FFI::Struct. - class PrismString # :nodoc: - SIZEOF = LibRubyParser.pm_string_sizeof - + # This object represents source code to be parsed. For strings it wraps a + # pointer directly; for files it uses a pm_source_t under the hood. + class PrismSource # :nodoc: PLATFORM_EXPECTS_UTF8 = RbConfig::CONFIG["host_os"].match?(/bccwin|cygwin|djgpp|mingw|mswin|wince|darwin/i) @@ -181,7 +197,7 @@ def read @pointer.read_string(@length) end - # Yields a pm_string_t pointer to the given block. + # Yields a PrismSource backed by the given string to the block. def self.with_string(string) raise TypeError unless string.is_a?(String) @@ -195,32 +211,38 @@ def self.with_string(string) end end - # Yields a pm_string_t pointer to the given block. + # Yields a PrismSource to the given block, backed by a pm_source_t. def self.with_file(filepath) raise TypeError unless filepath.is_a?(String) # On Windows and Mac, it's expected that filepaths will be encoded in # UTF-8. If they are not, we need to convert them to UTF-8 before - # passing them into pm_string_mapped_init. + # passing them into pm_source_mapped_new. if PLATFORM_EXPECTS_UTF8 && (encoding = filepath.encoding) != Encoding::ASCII_8BIT && encoding != Encoding::UTF_8 filepath = filepath.encode(Encoding::UTF_8) end - FFI::MemoryPointer.new(SIZEOF) do |pm_string| - case (result = LibRubyParser.pm_string_mapped_init(pm_string, filepath)) - when :PM_STRING_INIT_SUCCESS - pointer = LibRubyParser.pm_string_source(pm_string) - length = LibRubyParser.pm_string_length(pm_string) + FFI::MemoryPointer.new(:int) do |result_ptr| + pm_source = LibRubyParser.pm_source_mapped_new(filepath, 0, result_ptr) + + case SOURCE_INIT_RESULT[result_ptr.read_int] + when :PM_SOURCE_INIT_SUCCESS + pointer = LibRubyParser.pm_source_source(pm_source) + length = LibRubyParser.pm_source_length(pm_source) return yield new(pointer, length, false) - when :PM_STRING_INIT_ERROR_GENERIC + when :PM_SOURCE_INIT_ERROR_GENERIC raise SystemCallError.new(filepath, FFI.errno) - when :PM_STRING_INIT_ERROR_DIRECTORY + when :PM_SOURCE_INIT_ERROR_DIRECTORY raise Errno::EISDIR.new(filepath) + when :PM_SOURCE_INIT_ERROR_NON_REGULAR + # Fall back to reading the file through Ruby IO for non-regular + # files (pipes, character devices, etc.) + return with_string(File.read(filepath)) { |string| yield string } else - raise "Unknown error initializing pm_string_t: #{result.inspect}" + raise "Unknown error initializing pm_source_t: #{result_ptr.read_int}" end ensure - LibRubyParser.pm_string_free(pm_string) + LibRubyParser.pm_source_free(pm_source) if pm_source && !pm_source.null? end end end @@ -236,29 +258,29 @@ def self.with_file(filepath) class << self # Mirror the Prism.dump API by using the serialization API. def dump(source, **options) - LibRubyParser::PrismString.with_string(source) { |string| dump_common(string, options) } + LibRubyParser::PrismSource.with_string(source) { |string| dump_common(string, options) } end # Mirror the Prism.dump_file API by using the serialization API. def dump_file(filepath, **options) options[:filepath] = filepath - LibRubyParser::PrismString.with_file(filepath) { |string| dump_common(string, options) } + LibRubyParser::PrismSource.with_file(filepath) { |string| dump_common(string, options) } end # Mirror the Prism.lex API by using the serialization API. def lex(code, **options) - LibRubyParser::PrismString.with_string(code) { |string| lex_common(string, code, options) } + LibRubyParser::PrismSource.with_string(code) { |string| lex_common(string, code, options) } end # Mirror the Prism.lex_file API by using the serialization API. def lex_file(filepath, **options) options[:filepath] = filepath - LibRubyParser::PrismString.with_file(filepath) { |string| lex_common(string, string.read, options) } + LibRubyParser::PrismSource.with_file(filepath) { |string| lex_common(string, string.read, options) } end # Mirror the Prism.parse API by using the serialization API. def parse(code, **options) - LibRubyParser::PrismString.with_string(code) { |string| parse_common(string, code, options) } + LibRubyParser::PrismSource.with_string(code) { |string| parse_common(string, code, options) } end # Mirror the Prism.parse_file API by using the serialization API. This uses @@ -266,7 +288,7 @@ def parse(code, **options) # when it is available. def parse_file(filepath, **options) options[:filepath] = filepath - LibRubyParser::PrismString.with_file(filepath) { |string| parse_common(string, string.read, options) } + LibRubyParser::PrismSource.with_file(filepath) { |string| parse_common(string, string.read, options) } end # Mirror the Prism.parse_stream API by using the serialization API. @@ -284,19 +306,19 @@ def parse_stream(stream, **options) eof_callback = -> (_) { stream.eof? } - # In the pm_serialize_parse_stream function it accepts a pointer to the - # IO object as a void* and then passes it through to the callback as the - # third argument, but it never touches it itself. As such, since we have - # access to the IO object already through the closure of the lambda, we - # can pass a null pointer here and not worry. - LibRubyParser.pm_serialize_parse_stream(buffer.pointer, nil, callback, eof_callback, dump_options(options)) - Prism.load(source, buffer.read, options.fetch(:freeze, false)) + pm_source = LibRubyParser.pm_source_stream_new(nil, callback, eof_callback) + begin + LibRubyParser.pm_serialize_parse_stream(buffer.pointer, pm_source, dump_options(options)) + Prism.load(source, buffer.read, options.fetch(:freeze, false)) + ensure + LibRubyParser.pm_source_free(pm_source) if pm_source && !pm_source.null? + end end end # Mirror the Prism.parse_comments API by using the serialization API. def parse_comments(code, **options) - LibRubyParser::PrismString.with_string(code) { |string| parse_comments_common(string, code, options) } + LibRubyParser::PrismSource.with_string(code) { |string| parse_comments_common(string, code, options) } end # Mirror the Prism.parse_file_comments API by using the serialization @@ -304,23 +326,23 @@ def parse_comments(code, **options) # to use mmap when it is available. def parse_file_comments(filepath, **options) options[:filepath] = filepath - LibRubyParser::PrismString.with_file(filepath) { |string| parse_comments_common(string, string.read, options) } + LibRubyParser::PrismSource.with_file(filepath) { |string| parse_comments_common(string, string.read, options) } end # Mirror the Prism.parse_lex API by using the serialization API. def parse_lex(code, **options) - LibRubyParser::PrismString.with_string(code) { |string| parse_lex_common(string, code, options) } + LibRubyParser::PrismSource.with_string(code) { |string| parse_lex_common(string, code, options) } end # Mirror the Prism.parse_lex_file API by using the serialization API. def parse_lex_file(filepath, **options) options[:filepath] = filepath - LibRubyParser::PrismString.with_file(filepath) { |string| parse_lex_common(string, string.read, options) } + LibRubyParser::PrismSource.with_file(filepath) { |string| parse_lex_common(string, string.read, options) } end # Mirror the Prism.parse_success? API by using the serialization API. def parse_success?(code, **options) - LibRubyParser::PrismString.with_string(code) { |string| parse_file_success_common(string, options) } + LibRubyParser::PrismSource.with_string(code) { |string| parse_file_success_common(string, options) } end # Mirror the Prism.parse_failure? API by using the serialization API. @@ -331,7 +353,7 @@ def parse_failure?(code, **options) # Mirror the Prism.parse_file_success? API by using the serialization API. def parse_file_success?(filepath, **options) options[:filepath] = filepath - LibRubyParser::PrismString.with_file(filepath) { |string| parse_file_success_common(string, options) } + LibRubyParser::PrismSource.with_file(filepath) { |string| parse_file_success_common(string, options) } end # Mirror the Prism.parse_file_failure? API by using the serialization API. @@ -341,7 +363,7 @@ def parse_file_failure?(filepath, **options) # Mirror the Prism.profile API by using the serialization API. def profile(source, **options) - LibRubyParser::PrismString.with_string(source) do |string| + LibRubyParser::PrismSource.with_string(source) do |string| LibRubyParser::PrismBuffer.with do |buffer| LibRubyParser.pm_serialize_parse(buffer.pointer, string.pointer, string.length, dump_options(options)) nil @@ -351,7 +373,7 @@ def profile(source, **options) # Mirror the Prism.profile_file API by using the serialization API. def profile_file(filepath, **options) - LibRubyParser::PrismString.with_file(filepath) do |string| + LibRubyParser::PrismSource.with_file(filepath) do |string| LibRubyParser::PrismBuffer.with do |buffer| options[:filepath] = filepath LibRubyParser.pm_serialize_parse(buffer.pointer, string.pointer, string.length, dump_options(options)) @@ -400,7 +422,7 @@ def parse_lex_common(string, code, options) # :nodoc: end def parse_file_success_common(string, options) # :nodoc: - LibRubyParser.pm_parse_success_p(string.pointer, string.length, dump_options(options)) + LibRubyParser.pm_serialize_parse_success_p(string.pointer, string.length, dump_options(options)) end # Return the value that should be dumped for the command_line option. diff --git a/lib/prism/node_ext.rb b/lib/prism/node_ext.rb index 4457c26fbe04cf..8a5691848f8b6a 100644 --- a/lib/prism/node_ext.rb +++ b/lib/prism/node_ext.rb @@ -176,20 +176,6 @@ class RationalNode < Node def value Rational(numerator, denominator) end - - # Returns the value of the node as an IntegerNode or a FloatNode. This - # method is deprecated in favor of #value or #numerator/#denominator. - #-- - #: () -> (IntegerNode | FloatNode) - def numeric - deprecated("value", "numerator", "denominator") - - if denominator == 1 - IntegerNode.new(source, -1, location.chop, flags, numerator) - else - FloatNode.new(source, -1, location.chop, 0, numerator.to_f / denominator) - end - end end class ConstantReadNode < Node @@ -271,21 +257,6 @@ def full_name_parts def full_name full_name_parts.join("::") end - - # Previously, we had a child node on this class that contained either a - # constant read or a missing node. To not cause a breaking change, we - # continue to supply that API. - #-- - #: () -> (ConstantReadNode | MissingNode) - def child - deprecated("name", "name_loc") - - if (name = self.name) - ConstantReadNode.new(source, -1, name_loc, 0, name) - else - MissingNode.new(source, -1, location, 0) - end - end end class ConstantPathTargetNode < Node @@ -318,21 +289,6 @@ def full_name_parts def full_name full_name_parts.join("::") end - - # Previously, we had a child node on this class that contained either a - # constant read or a missing node. To not cause a breaking change, we - # continue to supply that API. - #-- - #: () -> (ConstantReadNode | MissingNode) - def child - deprecated("name", "name_loc") - - if (name = self.name) - ConstantReadNode.new(source, -1, name_loc, 0, name) - else - MissingNode.new(source, -1, location, 0) - end - end end class ConstantTargetNode < Node @@ -432,219 +388,4 @@ def full_message_loc attribute_write? ? message_loc&.adjoin("=") : message_loc end end - - class CallOperatorWriteNode < Node - # Returns the binary operator used to modify the receiver. This method is - # deprecated in favor of #binary_operator. - #-- - #: () -> Symbol - def operator - deprecated("binary_operator") - binary_operator - end - - # Returns the location of the binary operator used to modify the receiver. - # This method is deprecated in favor of #binary_operator_loc. - #-- - #: () -> Location - def operator_loc - deprecated("binary_operator_loc") - binary_operator_loc - end - end - - class ClassVariableOperatorWriteNode < Node - # Returns the binary operator used to modify the receiver. This method is - # deprecated in favor of #binary_operator. - #-- - #: () -> Symbol - def operator - deprecated("binary_operator") - binary_operator - end - - # Returns the location of the binary operator used to modify the receiver. - # This method is deprecated in favor of #binary_operator_loc. - #-- - #: () -> Location - def operator_loc - deprecated("binary_operator_loc") - binary_operator_loc - end - end - - class ConstantOperatorWriteNode < Node - # Returns the binary operator used to modify the receiver. This method is - # deprecated in favor of #binary_operator. - #-- - #: () -> Symbol - def operator - deprecated("binary_operator") - binary_operator - end - - # Returns the location of the binary operator used to modify the receiver. - # This method is deprecated in favor of #binary_operator_loc. - #-- - #: () -> Location - def operator_loc - deprecated("binary_operator_loc") - binary_operator_loc - end - end - - class ConstantPathOperatorWriteNode < Node - # Returns the binary operator used to modify the receiver. This method is - # deprecated in favor of #binary_operator. - #-- - #: () -> Symbol - def operator - deprecated("binary_operator") - binary_operator - end - - # Returns the location of the binary operator used to modify the receiver. - # This method is deprecated in favor of #binary_operator_loc. - #-- - #: () -> Location - def operator_loc - deprecated("binary_operator_loc") - binary_operator_loc - end - end - - class GlobalVariableOperatorWriteNode < Node - # Returns the binary operator used to modify the receiver. This method is - # deprecated in favor of #binary_operator. - #-- - #: () -> Symbol - def operator - deprecated("binary_operator") - binary_operator - end - - # Returns the location of the binary operator used to modify the receiver. - # This method is deprecated in favor of #binary_operator_loc. - #-- - #: () -> Location - def operator_loc - deprecated("binary_operator_loc") - binary_operator_loc - end - end - - class IndexOperatorWriteNode < Node - # Returns the binary operator used to modify the receiver. This method is - # deprecated in favor of #binary_operator. - #-- - #: () -> Symbol - def operator - deprecated("binary_operator") - binary_operator - end - - # Returns the location of the binary operator used to modify the receiver. - # This method is deprecated in favor of #binary_operator_loc. - #-- - #: () -> Location - def operator_loc - deprecated("binary_operator_loc") - binary_operator_loc - end - end - - class InstanceVariableOperatorWriteNode < Node - # Returns the binary operator used to modify the receiver. This method is - # deprecated in favor of #binary_operator. - #-- - #: () -> Symbol - def operator - deprecated("binary_operator") - binary_operator - end - - # Returns the location of the binary operator used to modify the receiver. - # This method is deprecated in favor of #binary_operator_loc. - #-- - #: () -> Location - def operator_loc - deprecated("binary_operator_loc") - binary_operator_loc - end - end - - class LocalVariableOperatorWriteNode < Node - # Returns the binary operator used to modify the receiver. This method is - # deprecated in favor of #binary_operator. - #-- - #: () -> Symbol - def operator - deprecated("binary_operator") - binary_operator - end - - # Returns the location of the binary operator used to modify the receiver. - # This method is deprecated in favor of #binary_operator_loc. - #-- - #: () -> Location - def operator_loc - deprecated("binary_operator_loc") - binary_operator_loc - end - end - - class CaseMatchNode < Node - # Returns the else clause of the case match node. This method is deprecated - # in favor of #else_clause. - #-- - #: () -> ElseNode? - def consequent - deprecated("else_clause") - else_clause - end - end - - class CaseNode < Node - # Returns the else clause of the case node. This method is deprecated in - # favor of #else_clause. - #-- - #: () -> ElseNode? - def consequent - deprecated("else_clause") - else_clause - end - end - - class IfNode < Node - # Returns the subsequent if/elsif/else clause of the if node. This method is - # deprecated in favor of #subsequent. - #-- - #: () -> (IfNode | ElseNode)? - def consequent - deprecated("subsequent") - subsequent - end - end - - class RescueNode < Node - # Returns the subsequent rescue clause of the rescue node. This method is - # deprecated in favor of #subsequent. - #-- - #: () -> RescueNode? - def consequent - deprecated("subsequent") - subsequent - end - end - - class UnlessNode < Node - # Returns the else clause of the unless node. This method is deprecated in - # favor of #else_clause. - #-- - #: () -> ElseNode? - def consequent - deprecated("else_clause") - else_clause - end - end end diff --git a/lib/prism/parse_result.rb b/lib/prism/parse_result.rb index 5c4d4fcb8a14dc..4d1fa2c2965121 100644 --- a/lib/prism/parse_result.rb +++ b/lib/prism/parse_result.rb @@ -58,16 +58,26 @@ def self.for(source, start_line, offsets) # The line number where this source starts. attr_reader :start_line #: Integer - # The list of newline byte offsets in the source code. - attr_reader :offsets #: Array[Integer] + # The list of newline byte offsets in the source code. When initialized from + # the C extension, this may be a packed binary string of uint32_t values + # that is lazily unpacked on first access. + #-- + #: () -> Array[Integer] + def offsets + offsets = @offsets + return offsets if offsets.is_a?(Array) + @offsets = offsets.unpack("L*") + end - # Create a new source object with the given source code. + # Create a new source object with the given source code. The offsets + # parameter can be either an Array of Integer byte offsets or a packed + # binary string of uint32_t values (from the C extension). #-- - #: (String source, Integer start_line, Array[Integer] offsets) -> void + #: (String source, Integer start_line, Array[Integer] | String offsets) -> void def initialize(source, start_line, offsets) @source = source - @start_line = start_line # set after parsing is done - @offsets = offsets # set after parsing is done + @start_line = start_line + @offsets = offsets end # Replace the value of start_line with the given value. @@ -81,7 +91,7 @@ def replace_start_line(start_line) #-- #: (Array[Integer] offsets) -> void def replace_offsets(offsets) - @offsets.replace(offsets) + @offsets = offsets end # Returns the encoding of the source code, which is set by parameters to the diff --git a/lib/prism/prism.gemspec b/lib/prism/prism.gemspec index d8b86c6fbaa01c..d489a37af4798d 100644 --- a/lib/prism/prism.gemspec +++ b/lib/prism/prism.gemspec @@ -46,29 +46,65 @@ Gem::Specification.new do |spec| "ext/prism/extension.c", "ext/prism/extension.h", "include/prism.h", + "include/prism/compiler/accel.h", + "include/prism/compiler/align.h", + "include/prism/compiler/exported.h", + "include/prism/compiler/fallthrough.h", + "include/prism/compiler/filesystem.h", + "include/prism/compiler/flex_array.h", + "include/prism/compiler/force_inline.h", + "include/prism/compiler/format.h", + "include/prism/compiler/inline.h", + "include/prism/compiler/nodiscard.h", + "include/prism/compiler/nonnull.h", + "include/prism/compiler/unused.h", + "include/prism/internal/allocator.h", + "include/prism/internal/allocator_debug.h", + "include/prism/internal/arena.h", + "include/prism/internal/bit.h", + "include/prism/internal/buffer.h", + "include/prism/internal/char.h", + "include/prism/internal/comments.h", + "include/prism/internal/constant_pool.h", + "include/prism/internal/diagnostic.h", + "include/prism/internal/encoding.h", + "include/prism/internal/integer.h", + "include/prism/internal/isinf.h", + "include/prism/internal/line_offset_list.h", + "include/prism/internal/list.h", + "include/prism/internal/magic_comments.h", + "include/prism/internal/memchr.h", + "include/prism/internal/node.h", + "include/prism/internal/options.h", + "include/prism/internal/parser.h", + "include/prism/internal/regexp.h", + "include/prism/internal/serialize.h", + "include/prism/internal/source.h", + "include/prism/internal/static_literals.h", + "include/prism/internal/strncasecmp.h", + "include/prism/internal/stringy.h", + "include/prism/internal/strpbrk.h", + "include/prism/internal/tokens.h", + "include/prism/arena.h", "include/prism/ast.h", - "include/prism/debug_allocator.h", - "include/prism/defines.h", + "include/prism/buffer.h", + "include/prism/comments.h", + "include/prism/constant_pool.h", "include/prism/diagnostic.h", - "include/prism/encoding.h", + "include/prism/excludes.h", + "include/prism/integer.h", + "include/prism/json.h", + "include/prism/line_offset_list.h", + "include/prism/magic_comments.h", "include/prism/node.h", - "include/prism/node_new.h", "include/prism/options.h", "include/prism/parser.h", "include/prism/prettyprint.h", - "include/prism/regexp.h", - "include/prism/static_literals.h", - "include/prism/util/pm_arena.h", - "include/prism/util/pm_buffer.h", - "include/prism/util/pm_char.h", - "include/prism/util/pm_constant_pool.h", - "include/prism/util/pm_integer.h", - "include/prism/util/pm_list.h", - "include/prism/util/pm_memchr.h", - "include/prism/util/pm_line_offset_list.h", - "include/prism/util/pm_strncasecmp.h", - "include/prism/util/pm_string.h", - "include/prism/util/pm_strpbrk.h", + "include/prism/serialize.h", + "include/prism/source.h", + "include/prism/stream.h", + "include/prism/string_query.h", + "include/prism/stringy.h", "include/prism/version.h", "lib/prism.rb", "lib/prism/compiler.rb", @@ -158,27 +194,31 @@ Gem::Specification.new do |spec| "sig/generated/prism/parse_result/comments.rbs", "sig/generated/prism/parse_result/errors.rbs", "sig/generated/prism/parse_result/newlines.rbs", + "src/arena.c", + "src/buffer.c", + "src/char.c", + "src/constant_pool.c", "src/diagnostic.c", "src/encoding.c", + "src/integer.c", + "src/json.c", + "src/line_offset_list.c", + "src/list.c", + "src/memchr.c", "src/node.c", "src/options.c", + "src/parser.c", "src/prettyprint.c", "src/prism.c", "src/regexp.c", "src/serialize.c", + "src/source.c", "src/static_literals.c", - "src/token_type.c", - "src/util/pm_arena.c", - "src/util/pm_buffer.c", - "src/util/pm_char.c", - "src/util/pm_constant_pool.c", - "src/util/pm_integer.c", - "src/util/pm_list.c", - "src/util/pm_memchr.c", - "src/util/pm_line_offset_list.c", - "src/util/pm_string.c", - "src/util/pm_strncasecmp.c", - "src/util/pm_strpbrk.c" + "src/string_query.c", + "src/stringy.c", + "src/strncasecmp.c", + "src/strpbrk.c", + "src/tokens.c" ] spec.extensions = ["ext/prism/extconf.rb"] diff --git a/lib/rubygems/version.rb b/lib/rubygems/version.rb index 091858b7570e79..b7966c3973f757 100644 --- a/lib/rubygems/version.rb +++ b/lib/rubygems/version.rb @@ -222,6 +222,7 @@ def initialize(version) end @version = -@version @segments = nil + @sort_key = compute_sort_key end ## @@ -350,6 +351,12 @@ def <=>(other) end return unless Gem::Version === other + + # Fast path for comparison when available. + if @sort_key && other.sort_key + return @sort_key <=> other.sort_key + end + return 0 if @version == other.version || canonical_segments == other.canonical_segments lhsegments = canonical_segments @@ -415,6 +422,21 @@ def freeze protected + attr_reader :sort_key # :nodoc: + + def compute_sort_key + segments = canonical_segments + return if segments.size > 4 || prerelease? || segments.any? {|segment| segment > 65_000 } + + base = 1_000_000_000_000 + + segments.sum do |segment| + result = segment * base + base /= 10_000 + result + end + end + def _segments # segments is lazy so it can pick up version values that come from # old marshaled versions, which don't go through marshal_load. diff --git a/load.c b/load.c index 610efabef35ddf..dc0302011605d9 100644 --- a/load.c +++ b/load.c @@ -729,8 +729,8 @@ load_iseq_eval(rb_execution_context_t *ec, VALUE fname) VALUE realpath_map = box->loaded_features_realpath_map; if (rb_ruby_prism_p()) { - pm_parse_result_t result = { 0 }; - result.options.line = 1; + pm_parse_result_t result; + pm_parse_result_init(&result); result.node.coverage_enabled = 1; VALUE error = pm_load_parse_file(&result, fname, NULL); diff --git a/mini_builtin.c b/mini_builtin.c index 48f401e78aa471..1e2c32a67efa3c 100644 --- a/mini_builtin.c +++ b/mini_builtin.c @@ -23,7 +23,8 @@ prelude_ast_value(VALUE name, VALUE code, int line) static void pm_prelude_load(pm_parse_result_t *result, VALUE name, VALUE code, int line) { - pm_options_line_set(&result->options, line); + pm_parse_result_init(result); + pm_options_line_set(result->options, line); VALUE error = pm_parse_string(result, code, name, NULL); if (!NIL_P(error)) { @@ -60,7 +61,7 @@ builtin_iseq_load(const char *feature_name, const struct rb_builtin_function *ta }; if (rb_ruby_prism_p()) { - pm_parse_result_t result = { 0 }; + pm_parse_result_t result; pm_prelude_load(&result, name_str, code, start_line); vm->builtin_function_table = table; diff --git a/prism/util/pm_arena.c b/prism/arena.c similarity index 83% rename from prism/util/pm_arena.c rename to prism/arena.c index 6b07e252101429..64a731649d7bcc 100644 --- a/prism/util/pm_arena.c +++ b/prism/arena.c @@ -1,10 +1,14 @@ -#include "prism/util/pm_arena.h" +#include "prism/internal/arena.h" + +#include "prism/internal/allocator.h" #include +#include +#include /** * Compute the block allocation size using offsetof so it is correct regardless - * of PM_FLEX_ARY_LEN. + * of PM_FLEX_ARRAY_LENGTH. */ #define PM_ARENA_BLOCK_SIZE(data_size) (offsetof(pm_arena_block_t, data) + (data_size)) @@ -77,11 +81,21 @@ pm_arena_alloc_slow(pm_arena_t *arena, size_t size) { return block->data; } +/** + * Returns a newly allocated and initialized arena. + */ +pm_arena_t * +pm_arena_new(void) { + pm_arena_t *arena = (pm_arena_t *) xcalloc(1, sizeof(pm_arena_t)); + if (arena == NULL) abort(); + return arena; +} + /** * Free all blocks in the arena. */ void -pm_arena_free(pm_arena_t *arena) { +pm_arena_cleanup(pm_arena_t *arena) { pm_arena_block_t *block = arena->current; while (block != NULL) { @@ -92,3 +106,12 @@ pm_arena_free(pm_arena_t *arena) { *arena = (pm_arena_t) { 0 }; } + +/** + * Frees both the held memory and the arena itself. + */ +void +pm_arena_free(pm_arena_t *arena) { + pm_arena_cleanup(arena); + xfree_sized(arena, sizeof(pm_arena_t)); +} diff --git a/prism/arena.h b/prism/arena.h new file mode 100644 index 00000000000000..e1fa8fc6ad2c52 --- /dev/null +++ b/prism/arena.h @@ -0,0 +1,37 @@ +/** + * @file arena.h + * + * A bump allocator for the prism parser. + */ +#ifndef PRISM_ARENA_H +#define PRISM_ARENA_H + +#include "prism/compiler/exported.h" +#include "prism/compiler/nodiscard.h" +#include "prism/compiler/nonnull.h" + +#include + +/** + * An opaque pointer to an arena that is used for allocations. + */ +typedef struct pm_arena_t pm_arena_t; + +/** + * Returns a newly allocated and initialized arena. If the arena cannot be + * allocated, this function aborts the process. + * + * @returns A pointer to the newly allocated arena. It is the responsibility of + * the caller to free the arena using pm_arena_free when it is no longer + * needed. + */ +PRISM_EXPORTED_FUNCTION PRISM_NODISCARD pm_arena_t * pm_arena_new(void); + +/** + * Frees both the held memory and the arena itself. + * + * @param arena The arena to free. + */ +PRISM_EXPORTED_FUNCTION void pm_arena_free(pm_arena_t *arena) PRISM_NONNULL(1); + +#endif diff --git a/prism/util/pm_buffer.c b/prism/buffer.c similarity index 91% rename from prism/util/pm_buffer.c rename to prism/buffer.c index 9e392427c6bae5..cb3b9a4fe8e47a 100644 --- a/prism/util/pm_buffer.c +++ b/prism/buffer.c @@ -1,31 +1,38 @@ -#include "prism/util/pm_buffer.h" +#include "prism/internal/buffer.h" -/** - * Return the size of the pm_buffer_t struct. - */ -size_t -pm_buffer_sizeof(void) { - return sizeof(pm_buffer_t); -} +#include "prism/compiler/inline.h" + +#include "prism/internal/char.h" +#include "prism/internal/allocator.h" + +#include +#include +#include +#include +#include /** * Initialize a pm_buffer_t with the given capacity. */ -bool -pm_buffer_init_capacity(pm_buffer_t *buffer, size_t capacity) { +void +pm_buffer_init(pm_buffer_t *buffer, size_t capacity) { buffer->length = 0; buffer->capacity = capacity; buffer->value = (char *) xmalloc(capacity); - return buffer->value != NULL; + if (buffer->value == NULL) abort(); } /** - * Initialize a pm_buffer_t with its default values. + * Allocate and initialize a new buffer. */ -bool -pm_buffer_init(pm_buffer_t *buffer) { - return pm_buffer_init_capacity(buffer, 1024); +pm_buffer_t * +pm_buffer_new(void) { + pm_buffer_t *buffer = (pm_buffer_t *) xmalloc(sizeof(pm_buffer_t)); + if (buffer == NULL) abort(); + + pm_buffer_init(buffer, 1024); + return buffer; } /** @@ -47,7 +54,7 @@ pm_buffer_length(const pm_buffer_t *buffer) { /** * Append the given amount of space to the buffer. */ -static inline bool +static PRISM_INLINE bool pm_buffer_append_length(pm_buffer_t *buffer, size_t length) { size_t next_length = buffer->length + length; const size_t original_capacity = buffer->capacity; @@ -72,7 +79,7 @@ pm_buffer_append_length(pm_buffer_t *buffer, size_t length) { /** * Append a generic pointer to memory to the buffer. */ -static inline void +static PRISM_INLINE void pm_buffer_append(pm_buffer_t *buffer, const void *source, size_t length) { size_t cursor = buffer->length; if (pm_buffer_append_length(buffer, length)) { @@ -350,9 +357,18 @@ pm_buffer_insert(pm_buffer_t *buffer, size_t index, const char *value, size_t le } /** - * Free the memory associated with the buffer. + * Free the memory held by the buffer. */ void -pm_buffer_free(pm_buffer_t *buffer) { +pm_buffer_cleanup(pm_buffer_t *buffer) { xfree_sized(buffer->value, buffer->capacity); } + +/** + * Free both the memory held by the buffer and the buffer itself. + */ +void +pm_buffer_free(pm_buffer_t *buffer) { + pm_buffer_cleanup(buffer); + xfree_sized(buffer, sizeof(pm_buffer_t)); +} diff --git a/prism/buffer.h b/prism/buffer.h new file mode 100644 index 00000000000000..24b572d2c3f555 --- /dev/null +++ b/prism/buffer.h @@ -0,0 +1,52 @@ +/** + * @file buffer.h + * + * A wrapper around a contiguous block of allocated memory. + */ +#ifndef PRISM_BUFFER_H +#define PRISM_BUFFER_H + +#include "prism/compiler/exported.h" +#include "prism/compiler/nodiscard.h" +#include "prism/compiler/nonnull.h" + +#include + +/** + * A wrapper around a contiguous block of allocated memory. + */ +typedef struct pm_buffer_t pm_buffer_t; + +/** + * Allocate and initialize a new buffer. If the buffer cannot be allocated, this + * function will abort the process. + * + * @returns A pointer to the initialized buffer. The caller is responsible for + * freeing the buffer with pm_buffer_free. + */ +PRISM_EXPORTED_FUNCTION PRISM_NODISCARD pm_buffer_t * pm_buffer_new(void); + +/** + * Free both the memory held by the buffer and the buffer itself. + * + * @param buffer The buffer to free. + */ +PRISM_EXPORTED_FUNCTION void pm_buffer_free(pm_buffer_t *buffer) PRISM_NONNULL(1); + +/** + * Return the value of the buffer. + * + * @param buffer The buffer to get the value of. + * @returns The value of the buffer. + */ +PRISM_EXPORTED_FUNCTION char * pm_buffer_value(const pm_buffer_t *buffer) PRISM_NONNULL(1); + +/** + * Return the length of the buffer. + * + * @param buffer The buffer to get the length of. + * @returns The length of the buffer. + */ +PRISM_EXPORTED_FUNCTION size_t pm_buffer_length(const pm_buffer_t *buffer) PRISM_NONNULL(1); + +#endif diff --git a/prism/util/pm_char.c b/prism/char.c similarity index 95% rename from prism/util/pm_char.c rename to prism/char.c index ac283af356b737..08e457aa1ffde5 100644 --- a/prism/util/pm_char.c +++ b/prism/char.c @@ -1,4 +1,7 @@ -#include "prism/util/pm_char.h" +#include "prism/internal/char.h" + +#include "prism/compiler/inline.h" +#include "prism/internal/line_offset_list.h" #define PRISM_CHAR_BIT_REGEXP_OPTION (1 << 2) @@ -55,7 +58,7 @@ static const uint8_t pm_number_table[256] = { * Returns the number of characters at the start of the string that match the * given kind. Disallows searching past the given maximum number of characters. */ -static inline size_t +static PRISM_INLINE size_t pm_strspn_char_kind(const uint8_t *string, ptrdiff_t length, uint8_t kind) { if (length <= 0) return 0; @@ -113,7 +116,7 @@ pm_strspn_regexp_option(const uint8_t *string, ptrdiff_t length) { * the string that match the given kind. Disallows searching past the given * maximum number of characters. */ -static inline size_t +static PRISM_INLINE size_t pm_strspn_number_kind(const uint8_t *string, ptrdiff_t length, uint8_t kind) { if (length <= 0) return 0; @@ -132,7 +135,7 @@ pm_strspn_number_kind(const uint8_t *string, ptrdiff_t length, uint8_t kind) { * Additionally, report the location of the last invalid underscore character * found in the string through the out invalid parameter. */ -static inline size_t +static PRISM_INLINE size_t pm_strspn_number_kind_underscores(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid, uint8_t kind) { if (length <= 0) return 0; @@ -233,7 +236,7 @@ pm_strspn_hexadecimal_number(const uint8_t *string, ptrdiff_t length, const uint /** * Returns true if the given character matches the given kind. */ -static inline bool +static PRISM_INLINE bool pm_char_is_number_kind(const uint8_t b, uint8_t kind) { return (pm_number_table[b] & kind) != 0; } @@ -269,16 +272,3 @@ bool pm_char_is_hexadecimal_digit(const uint8_t b) { return pm_char_is_number_kind(b, PRISM_NUMBER_BIT_HEXADECIMAL_DIGIT); } - -#undef PRISM_CHAR_BIT_WHITESPACE -#undef PRISM_CHAR_BIT_INLINE_WHITESPACE -#undef PRISM_CHAR_BIT_REGEXP_OPTION - -#undef PRISM_NUMBER_BIT_BINARY_DIGIT -#undef PRISM_NUMBER_BIT_BINARY_NUMBER -#undef PRISM_NUMBER_BIT_OCTAL_DIGIT -#undef PRISM_NUMBER_BIT_OCTAL_NUMBER -#undef PRISM_NUMBER_BIT_DECIMAL_DIGIT -#undef PRISM_NUMBER_BIT_DECIMAL_NUMBER -#undef PRISM_NUMBER_BIT_HEXADECIMAL_NUMBER -#undef PRISM_NUMBER_BIT_HEXADECIMAL_DIGIT diff --git a/prism/comments.h b/prism/comments.h new file mode 100644 index 00000000000000..2270d538895bc6 --- /dev/null +++ b/prism/comments.h @@ -0,0 +1,43 @@ +/** + * @file comments.h + * + * Types and functions related to comments found during parsing. + */ +#ifndef PRISM_COMMENTS_H +#define PRISM_COMMENTS_H + +#include "prism/compiler/exported.h" +#include "prism/compiler/nodiscard.h" +#include "prism/compiler/nonnull.h" + +#include "prism/ast.h" + +#include + +/** This is the type of a comment that we've found while parsing. */ +typedef enum { + PM_COMMENT_INLINE, + PM_COMMENT_EMBDOC +} pm_comment_type_t; + +/** An opaque pointer to a comment found while parsing. */ +typedef struct pm_comment_t pm_comment_t; + +/** + * Returns the location associated with the given comment. + * + * @param comment the comment whose location we want to get + * @returns the location associated with the given comment + */ +PRISM_EXPORTED_FUNCTION pm_location_t pm_comment_location(const pm_comment_t *comment) PRISM_NONNULL(1); + +/** + * Returns the type associated with the given comment. + * + * @param comment the comment whose type we want to get + * @returns the type associated with the given comment. This can either be + * PM_COMMENT_INLINE or PM_COMMENT_EMBDOC. + */ +PRISM_EXPORTED_FUNCTION pm_comment_type_t pm_comment_type(const pm_comment_t *comment) PRISM_NONNULL(1); + +#endif diff --git a/prism/compiler/accel.h b/prism/compiler/accel.h new file mode 100644 index 00000000000000..be23236d1d893a --- /dev/null +++ b/prism/compiler/accel.h @@ -0,0 +1,19 @@ +/** + * @file compiler/accel.h + */ +#ifndef PRISM_COMPILER_ACCEL_H +#define PRISM_COMPILER_ACCEL_H + +/** + * Platform detection for SIMD/fast-path implementations. At most one of these + * macros is defined, selecting the best available vectorization strategy. + */ +#if (defined(__aarch64__) && defined(__ARM_NEON)) || (defined(_MSC_VER) && defined(_M_ARM64)) +# define PRISM_HAS_NEON +#elif (defined(__x86_64__) && defined(__SSSE3__)) || (defined(_MSC_VER) && defined(_M_X64)) +# define PRISM_HAS_SSSE3 +#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +# define PRISM_HAS_SWAR +#endif + +#endif diff --git a/prism/compiler/align.h b/prism/compiler/align.h new file mode 100644 index 00000000000000..22cb49a48cdf4c --- /dev/null +++ b/prism/compiler/align.h @@ -0,0 +1,36 @@ +/** + * @file compiler/align.h + */ +#ifndef PRISM_COMPILER_ALIGN_H +#define PRISM_COMPILER_ALIGN_H + +/** + * Compiler-agnostic macros for specifying alignment of types and variables. + */ +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L /* C11 or later */ + /** Specify alignment for a type or variable. */ + #define PRISM_ALIGNAS _Alignas + + /** Get the alignment requirement of a type. */ + #define PRISM_ALIGNOF _Alignof +#elif defined(__GNUC__) || defined(__clang__) + /** Specify alignment for a type or variable. */ + #define PRISM_ALIGNAS(size) __attribute__((aligned(size))) + + /** Get the alignment requirement of a type. */ + #define PRISM_ALIGNOF(type) __alignof__(type) +#elif defined(_MSC_VER) + /** Specify alignment for a type or variable. */ + #define PRISM_ALIGNAS(size) __declspec(align(size)) + + /** Get the alignment requirement of a type. */ + #define PRISM_ALIGNOF(type) __alignof(type) +#else + /** Void because this platform does not support specifying alignment. */ + #define PRISM_ALIGNAS(size) + + /** Fallback to sizeof as alignment requirement of a type. */ + #define PRISM_ALIGNOF(type) sizeof(type) +#endif + +#endif diff --git a/prism/compiler/exported.h b/prism/compiler/exported.h new file mode 100644 index 00000000000000..823773ecbb5288 --- /dev/null +++ b/prism/compiler/exported.h @@ -0,0 +1,24 @@ +/** + * @file compiler/exported.h + */ +#ifndef PRISM_COMPILER_EXPORTED_H +#define PRISM_COMPILER_EXPORTED_H + +/** + * By default, we compile with -fvisibility=hidden. When this is enabled, we + * need to mark certain functions as being publically-visible. This macro does + * that in a compiler-agnostic way. + */ +#ifndef PRISM_EXPORTED_FUNCTION +# ifdef PRISM_EXPORT_SYMBOLS +# ifdef _WIN32 +# define PRISM_EXPORTED_FUNCTION __declspec(dllexport) extern +# else +# define PRISM_EXPORTED_FUNCTION __attribute__((__visibility__("default"))) extern +# endif +# else +# define PRISM_EXPORTED_FUNCTION +# endif +#endif + +#endif diff --git a/prism/compiler/fallthrough.h b/prism/compiler/fallthrough.h new file mode 100644 index 00000000000000..ce1b450e8a14ed --- /dev/null +++ b/prism/compiler/fallthrough.h @@ -0,0 +1,22 @@ +/** + * @file compiler/fallthrough.h + */ +#ifndef PRISM_COMPILER_FALLTHROUGH_H +#define PRISM_COMPILER_FALLTHROUGH_H + +/** + * We use -Wimplicit-fallthrough to guard potentially unintended fall-through + * between cases of a switch. Use PRISM_FALLTHROUGH to explicitly annotate cases + * where the fallthrough is intentional. + */ +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L /* C23 or later */ + #define PRISM_FALLTHROUGH [[fallthrough]]; +#elif defined(__GNUC__) || defined(__clang__) + #define PRISM_FALLTHROUGH __attribute__((fallthrough)); +#elif defined(_MSC_VER) + #define PRISM_FALLTHROUGH __fallthrough; +#else + #define PRISM_FALLTHROUGH +#endif + +#endif diff --git a/prism/compiler/filesystem.h b/prism/compiler/filesystem.h new file mode 100644 index 00000000000000..f988909db85103 --- /dev/null +++ b/prism/compiler/filesystem.h @@ -0,0 +1,32 @@ +/** + * @file compiler/filesystem.h + * + * Platform detection for mmap and filesystem support. + */ +#ifndef PRISM_COMPILER_FILESYSTEM_H +#define PRISM_COMPILER_FILESYSTEM_H + +/** + * In general, libc for embedded systems does not support memory-mapped files. + * If the target platform is POSIX or Windows, we can map a file in memory and + * read it in a more efficient manner. + */ +#ifdef _WIN32 +# define PRISM_HAS_MMAP +#else +# include +# ifdef _POSIX_MAPPED_FILES +# define PRISM_HAS_MMAP +# endif +#endif + +/** + * If PRISM_HAS_NO_FILESYSTEM is defined, then we want to exclude all filesystem + * related code from the library. All filesystem related code should be guarded + * by PRISM_HAS_FILESYSTEM. + */ +#ifndef PRISM_HAS_NO_FILESYSTEM +# define PRISM_HAS_FILESYSTEM +#endif + +#endif diff --git a/prism/compiler/flex_array.h b/prism/compiler/flex_array.h new file mode 100644 index 00000000000000..7504b5fdd388b6 --- /dev/null +++ b/prism/compiler/flex_array.h @@ -0,0 +1,19 @@ +/** + * @file compiler/flex_array.h + */ +#ifndef PRISM_COMPILER_FLEX_ARRAY_H +#define PRISM_COMPILER_FLEX_ARRAY_H + +/** + * A macro for helper define a flexible array member. C99 supports `data[]`, GCC + * supports `data[0]` as an extension, and older compilers require `data[1]`. + */ +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) + #define PM_FLEX_ARRAY_LENGTH /* data[] */ +#elif defined(__GNUC__) && !defined(__STRICT_ANSI__) + #define PM_FLEX_ARRAY_LENGTH 0 /* data[0] */ +#else + #define PM_FLEX_ARRAY_LENGTH 1 /* data[1] */ +#endif + +#endif diff --git a/prism/compiler/force_inline.h b/prism/compiler/force_inline.h new file mode 100644 index 00000000000000..e189d592d61a23 --- /dev/null +++ b/prism/compiler/force_inline.h @@ -0,0 +1,21 @@ +/** + * @file compiler/force_inline.h + */ +#ifndef PRISM_COMPILER_FORCE_INLINE_H +#define PRISM_COMPILER_FORCE_INLINE_H + +#include "prism/compiler/inline.h" + +/** + * Force a function to be inlined at every call site. Use sparingly — only for + * small, hot functions where the compiler's heuristics fail to inline. + */ +#if defined(_MSC_VER) +# define PRISM_FORCE_INLINE __forceinline +#elif defined(__GNUC__) || defined(__clang__) +# define PRISM_FORCE_INLINE PRISM_INLINE __attribute__((always_inline)) +#else +# define PRISM_FORCE_INLINE PRISM_INLINE +#endif + +#endif diff --git a/prism/compiler/format.h b/prism/compiler/format.h new file mode 100644 index 00000000000000..32f4c3c6d77523 --- /dev/null +++ b/prism/compiler/format.h @@ -0,0 +1,25 @@ +/** + * @file compiler/format.h + */ +#ifndef PRISM_COMPILER_FORMAT_H +#define PRISM_COMPILER_FORMAT_H + +/** + * Certain compilers support specifying that a function accepts variadic + * parameters that look like printf format strings to provide a better developer + * experience when someone is using the function. This macro does that in a + * compiler-agnostic way. + */ +#if defined(__GNUC__) +# if defined(__MINGW_PRINTF_FORMAT) +# define PRISM_ATTRIBUTE_FORMAT(fmt_idx_, arg_idx_) __attribute__((format(__MINGW_PRINTF_FORMAT, fmt_idx_, arg_idx_))) +# else +# define PRISM_ATTRIBUTE_FORMAT(fmt_idx_, arg_idx_) __attribute__((format(printf, fmt_idx_, arg_idx_))) +# endif +#elif defined(__clang__) +# define PRISM_ATTRIBUTE_FORMAT(fmt_idx_, arg_idx_) __attribute__((__format__(__printf__, fmt_idx_, arg_idx_))) +#else +# define PRISM_ATTRIBUTE_FORMAT(fmt_idx_, arg_idx_) +#endif + +#endif diff --git a/prism/compiler/inline.h b/prism/compiler/inline.h new file mode 100644 index 00000000000000..856a3756917c00 --- /dev/null +++ b/prism/compiler/inline.h @@ -0,0 +1,17 @@ +/** + * @file compiler/inline.h + */ +#ifndef PRISM_COMPILER_INLINE_H +#define PRISM_COMPILER_INLINE_H + +/** + * Old Visual Studio versions do not support the inline keyword, so we need to + * define it to be __inline. + */ +#if defined(_MSC_VER) && !defined(inline) +# define PRISM_INLINE __inline +#else +# define PRISM_INLINE inline +#endif + +#endif diff --git a/prism/compiler/nodiscard.h b/prism/compiler/nodiscard.h new file mode 100644 index 00000000000000..ccd6c007190dc5 --- /dev/null +++ b/prism/compiler/nodiscard.h @@ -0,0 +1,22 @@ +/** + * @file compiler/nodiscard.h + */ +#ifndef PRISM_COMPILER_NODISCARD_H +#define PRISM_COMPILER_NODISCARD_H + +/** + * Mark the return value of a function as important so that the compiler warns + * if a caller ignores it. This is useful for functions that return error codes + * or allocated resources that must be freed. + */ +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L +# define PRISM_NODISCARD [[nodiscard]] +#elif defined(__GNUC__) || defined(__clang__) +# define PRISM_NODISCARD __attribute__((__warn_unused_result__)) +#elif defined(_MSC_VER) +# define PRISM_NODISCARD _Check_return_ +#else +# define PRISM_NODISCARD +#endif + +#endif diff --git a/prism/compiler/nonnull.h b/prism/compiler/nonnull.h new file mode 100644 index 00000000000000..9d193556653221 --- /dev/null +++ b/prism/compiler/nonnull.h @@ -0,0 +1,18 @@ +/** + * @file compiler/nonnull.h + */ +#ifndef PRISM_COMPILER_NONNULL_H +#define PRISM_COMPILER_NONNULL_H + +/** + * Mark the parameters of a function as non-null. This allows the compiler to + * warn if a caller passes NULL for a parameter that should never be NULL. The + * arguments are the 1-based indices of the parameters. + */ +#if defined(__GNUC__) || defined(__clang__) +# define PRISM_NONNULL(...) __attribute__((__nonnull__(__VA_ARGS__))) +#else +# define PRISM_NONNULL(...) +#endif + +#endif diff --git a/prism/compiler/unused.h b/prism/compiler/unused.h new file mode 100644 index 00000000000000..6a9e125dde944d --- /dev/null +++ b/prism/compiler/unused.h @@ -0,0 +1,18 @@ +/** + * @file compiler/unused.h + */ +#ifndef PRISM_COMPILER_UNUSED_H +#define PRISM_COMPILER_UNUSED_H + +/** + * GCC will warn if you specify a function or parameter that is unused at + * runtime. This macro allows you to mark a function or parameter as unused in a + * compiler-agnostic way. + */ +#if defined(__GNUC__) +# define PRISM_UNUSED __attribute__((unused)) +#else +# define PRISM_UNUSED +#endif + +#endif diff --git a/prism/util/pm_constant_pool.c b/prism/constant_pool.c similarity index 95% rename from prism/util/pm_constant_pool.c rename to prism/constant_pool.c index 74e2a125241d27..90201ebb8e35fc 100644 --- a/prism/util/pm_constant_pool.c +++ b/prism/constant_pool.c @@ -1,5 +1,11 @@ -#include "prism/util/pm_constant_pool.h" -#include "prism/util/pm_arena.h" +#include "prism/internal/constant_pool.h" + +#include "prism/compiler/align.h" +#include "prism/compiler/inline.h" +#include "prism/internal/arena.h" + +#include +#include /** * Initialize a list of constant ids. @@ -76,7 +82,7 @@ pm_constant_id_list_includes(pm_constant_id_list_t *list, pm_constant_id_t id) { * by XOR followed by multiplication by a large odd constant, which spreads * entropy across all bits. A final xorshift fold produces the 32-bit result. */ -static inline uint32_t +static PRISM_INLINE uint32_t pm_constant_pool_hash(const uint8_t *start, size_t length) { // This constant is borrowed from wyhash. It is a 64-bit odd integer with // roughly equal 0/1 bits, chosen for good avalanche behavior when used in @@ -162,7 +168,7 @@ is_power_of_two(uint32_t size) { /** * Resize a constant pool to a given capacity. */ -static inline void +static PRISM_INLINE void pm_constant_pool_resize(pm_arena_t *arena, pm_constant_pool_t *pool) { assert(is_power_of_two(pool->capacity)); @@ -252,7 +258,7 @@ pm_constant_pool_find(const pm_constant_pool_t *pool, const uint8_t *start, size /** * Insert a constant into a constant pool and return its index in the pool. */ -static inline pm_constant_id_t +static PRISM_INLINE pm_constant_id_t pm_constant_pool_insert(pm_arena_t *arena, pm_constant_pool_t *pool, const uint8_t *start, size_t length, pm_constant_pool_bucket_type_t type) { if (pool->size >= (pool->capacity / 4 * 3)) { pm_constant_pool_resize(arena, pool); @@ -338,3 +344,17 @@ pm_constant_pool_insert_constant(pm_arena_t *arena, pm_constant_pool_t *pool, co return pm_constant_pool_insert(arena, pool, start, length, PM_CONSTANT_POOL_BUCKET_CONSTANT); } +/** + * Return a raw pointer to the start of a constant. + */ +const uint8_t * +pm_constant_start(const pm_constant_t *constant) { + return constant->start; +} + +/** + * Return the length of a constant. + */ +size_t pm_constant_length(const pm_constant_t *constant) { + return constant->length; +} diff --git a/prism/constant_pool.h b/prism/constant_pool.h new file mode 100644 index 00000000000000..dc03235c70cb6e --- /dev/null +++ b/prism/constant_pool.h @@ -0,0 +1,81 @@ +/** + * @file constant_pool.h + * + * A data structure that stores a set of strings. + * + * Each string is assigned a unique id, which can be used to compare strings for + * equality. This comparison ends up being much faster than strcmp, since it + * only requires a single integer comparison. + */ +#ifndef PRISM_CONSTANT_POOL_H +#define PRISM_CONSTANT_POOL_H + +#include "prism/compiler/exported.h" +#include "prism/compiler/nodiscard.h" +#include "prism/compiler/nonnull.h" + +#include "prism/arena.h" + +#include +#include + +/** + * A constant id is a unique identifier for a constant in the constant pool. + */ +typedef uint32_t pm_constant_id_t; + +/** + * A list of constant IDs. Usually used to represent a set of locals. + */ +typedef struct { + /** The number of constant ids in the list. */ + size_t size; + + /** The number of constant ids that have been allocated in the list. */ + size_t capacity; + + /** The constant ids in the list. */ + pm_constant_id_t *ids; +} pm_constant_id_list_t; + +/** A constant in the pool which effectively stores a string. */ +typedef struct pm_constant_t pm_constant_t; + +/** + * The overall constant pool, which stores constants found while parsing. + */ +typedef struct pm_constant_pool_t pm_constant_pool_t; + +/** + * Return a raw pointer to the start of a constant. + * + * @param constant The constant to get the start of. + * @returns A raw pointer to the start of the constant. + */ +PRISM_EXPORTED_FUNCTION const uint8_t * pm_constant_start(const pm_constant_t *constant) PRISM_NONNULL(1); + +/** + * Return the length of a constant. + * + * @param constant The constant to get the length of. + * @returns The length of the constant. + */ +PRISM_EXPORTED_FUNCTION size_t pm_constant_length(const pm_constant_t *constant) PRISM_NONNULL(1); + +/** + * Initialize a list of constant ids. + * + * @param list The list to initialize. + */ +PRISM_EXPORTED_FUNCTION void pm_constant_id_list_init(pm_constant_id_list_t *list) PRISM_NONNULL(1); + +/** + * Append a constant id to a list of constant ids. + * + * @param arena The arena to use for allocations. + * @param list The list to append to. + * @param id The constant id to append. + */ +PRISM_EXPORTED_FUNCTION void pm_constant_id_list_append(pm_arena_t *arena, pm_constant_id_list_t *list, pm_constant_id_t id) PRISM_NONNULL(1, 2); + +#endif diff --git a/prism/defines.h b/prism/defines.h deleted file mode 100644 index d666582b178963..00000000000000 --- a/prism/defines.h +++ /dev/null @@ -1,379 +0,0 @@ -/** - * @file defines.h - * - * Macro definitions used throughout the prism library. - * - * This file should be included first by any *.h or *.c in prism for consistency - * and to ensure that the macros are defined before they are used. - */ -#ifndef PRISM_DEFINES_H -#define PRISM_DEFINES_H - -#include -#include -#include -#include -#include -#include -#include -#include - -/** - * We want to be able to use the PRI* macros for printing out integers, but on - * some platforms they aren't included unless this is already defined. - */ -#define __STDC_FORMAT_MACROS -// Include sys/types.h before inttypes.h to work around issue with -// certain versions of GCC and newlib which causes omission of PRIx64 -#include -#include - -/** - * When we are parsing using recursive descent, we want to protect against - * malicious payloads that could attempt to crash our parser. We do this by - * specifying a maximum depth to which we are allowed to recurse. - */ -#ifndef PRISM_DEPTH_MAXIMUM - #define PRISM_DEPTH_MAXIMUM 10000 -#endif - -/** - * By default, we compile with -fvisibility=hidden. When this is enabled, we - * need to mark certain functions as being publically-visible. This macro does - * that in a compiler-agnostic way. - */ -#ifndef PRISM_EXPORTED_FUNCTION -# ifdef PRISM_EXPORT_SYMBOLS -# ifdef _WIN32 -# define PRISM_EXPORTED_FUNCTION __declspec(dllexport) extern -# else -# define PRISM_EXPORTED_FUNCTION __attribute__((__visibility__("default"))) extern -# endif -# else -# define PRISM_EXPORTED_FUNCTION -# endif -#endif - -/** - * Certain compilers support specifying that a function accepts variadic - * parameters that look like printf format strings to provide a better developer - * experience when someone is using the function. This macro does that in a - * compiler-agnostic way. - */ -#if defined(__GNUC__) -# if defined(__MINGW_PRINTF_FORMAT) -# define PRISM_ATTRIBUTE_FORMAT(string_index, argument_index) __attribute__((format(__MINGW_PRINTF_FORMAT, string_index, argument_index))) -# else -# define PRISM_ATTRIBUTE_FORMAT(string_index, argument_index) __attribute__((format(printf, string_index, argument_index))) -# endif -#elif defined(__clang__) -# define PRISM_ATTRIBUTE_FORMAT(string_index, argument_index) __attribute__((__format__(__printf__, string_index, argument_index))) -#else -# define PRISM_ATTRIBUTE_FORMAT(string_index, argument_index) -#endif - -/** - * GCC will warn if you specify a function or parameter that is unused at - * runtime. This macro allows you to mark a function or parameter as unused in a - * compiler-agnostic way. - */ -#if defined(__GNUC__) -# define PRISM_ATTRIBUTE_UNUSED __attribute__((unused)) -#else -# define PRISM_ATTRIBUTE_UNUSED -#endif - -/** - * Old Visual Studio versions do not support the inline keyword, so we need to - * define it to be __inline. - */ -#if defined(_MSC_VER) && !defined(inline) -# define inline __inline -#endif - -/** - * Force a function to be inlined at every call site. Use sparingly — only for - * small, hot functions where the compiler's heuristics fail to inline. - */ -#if defined(_MSC_VER) -# define PRISM_FORCE_INLINE __forceinline -#elif defined(__GNUC__) || defined(__clang__) -# define PRISM_FORCE_INLINE inline __attribute__((always_inline)) -#else -# define PRISM_FORCE_INLINE inline -#endif - -/** - * Old Visual Studio versions before 2015 do not implement sprintf, but instead - * implement _snprintf. We standard that here. - */ -#if !defined(snprintf) && defined(_MSC_VER) && (_MSC_VER < 1900) -# define snprintf _snprintf -#endif - -/** - * A simple utility macro to concatenate two tokens together, necessary when one - * of the tokens is itself a macro. - */ -#define PM_CONCATENATE(left, right) left ## right - -/** - * We want to be able to use static assertions, but they weren't standardized - * until C11. As such, we polyfill it here by making a hacky typedef that will - * fail to compile due to a negative array size if the condition is false. - */ -#if defined(_Static_assert) -# define PM_STATIC_ASSERT(line, condition, message) _Static_assert(condition, message) -#else -# define PM_STATIC_ASSERT(line, condition, message) typedef char PM_CONCATENATE(static_assert_, line)[(condition) ? 1 : -1] -#endif - -/** - * In general, libc for embedded systems does not support memory-mapped files. - * If the target platform is POSIX or Windows, we can map a file in memory and - * read it in a more efficient manner. - */ -#ifdef _WIN32 -# define PRISM_HAS_MMAP -#else -# include -# ifdef _POSIX_MAPPED_FILES -# define PRISM_HAS_MMAP -# endif -#endif - -/** - * If PRISM_HAS_NO_FILESYSTEM is defined, then we want to exclude all filesystem - * related code from the library. All filesystem related code should be guarded - * by PRISM_HAS_FILESYSTEM. - */ -#ifndef PRISM_HAS_NO_FILESYSTEM -# define PRISM_HAS_FILESYSTEM -#endif - -/** - * isinf on POSIX systems it accepts a float, a double, or a long double. - * But mingw didn't provide an isinf macro, only an isinf function that only - * accepts floats, so we need to use _finite instead. - */ -#ifdef __MINGW64__ - #include - #define PRISM_ISINF(x) (!_finite(x)) -#else - #define PRISM_ISINF(x) isinf(x) -#endif - -/** - * If you build prism with a custom allocator, configure it with - * "-D PRISM_XALLOCATOR" to use your own allocator that defines xmalloc, - * xrealloc, xcalloc, and xfree. - * - * For example, your `prism_xallocator.h` file could look like this: - * - * ``` - * #ifndef PRISM_XALLOCATOR_H - * #define PRISM_XALLOCATOR_H - * #define xmalloc my_malloc - * #define xrealloc my_realloc - * #define xcalloc my_calloc - * #define xfree my_free - * #define xrealloc_sized my_realloc_sized // (optional) - * #define xfree_sized my_free_sized // (optional) - * #endif - * ``` - */ -#ifdef PRISM_XALLOCATOR - #include "prism_xallocator.h" -#else - #ifndef xmalloc - /** - * The malloc function that should be used. This can be overridden with - * the PRISM_XALLOCATOR define. - */ - #define xmalloc malloc - #endif - - #ifndef xrealloc - /** - * The realloc function that should be used. This can be overridden with - * the PRISM_XALLOCATOR define. - */ - #define xrealloc realloc - #endif - - #ifndef xcalloc - /** - * The calloc function that should be used. This can be overridden with - * the PRISM_XALLOCATOR define. - */ - #define xcalloc calloc - #endif - - #ifndef xfree - /** - * The free function that should be used. This can be overridden with the - * PRISM_XALLOCATOR define. - */ - #define xfree free - #endif -#endif - -#ifndef xfree_sized -/** - * The free_sized function that should be used. This can be overridden with the - * PRISM_XALLOCATOR define. - * If not defined, defaults to calling xfree. - */ - #define xfree_sized(p, s) xfree(((void)(s), (p))) -#endif - -#ifndef xrealloc_sized -/** - * The xrealloc_sized function that should be used. This can be overridden with the - * PRISM_XALLOCATOR define. - * If not defined, defaults to calling xrealloc. - */ - #define xrealloc_sized(p, ns, os) xrealloc((p), ((void)(os), (ns))) -#endif - -#ifdef PRISM_BUILD_DEBUG - #include "prism/debug_allocator.h" -#endif - -/** - * If PRISM_BUILD_MINIMAL is defined, then we're going to define every possible - * switch that will turn off certain features of prism. - */ -#ifdef PRISM_BUILD_MINIMAL - /** Exclude the serialization API. */ - #define PRISM_EXCLUDE_SERIALIZATION - - /** Exclude the JSON serialization API. */ - #define PRISM_EXCLUDE_JSON - - /** Exclude the prettyprint API. */ - #define PRISM_EXCLUDE_PRETTYPRINT - - /** Exclude the full set of encodings, using the minimal only. */ - #define PRISM_ENCODING_EXCLUDE_FULL -#endif - -/** - * Support PRISM_LIKELY and PRISM_UNLIKELY to help the compiler optimize its - * branch predication. - */ -#if defined(__GNUC__) || defined(__clang__) - /** The compiler should predicate that this branch will be taken. */ - #define PRISM_LIKELY(x) __builtin_expect(!!(x), 1) - - /** The compiler should predicate that this branch will not be taken. */ - #define PRISM_UNLIKELY(x) __builtin_expect(!!(x), 0) -#else - /** Void because this platform does not support branch prediction hints. */ - #define PRISM_LIKELY(x) (x) - - /** Void because this platform does not support branch prediction hints. */ - #define PRISM_UNLIKELY(x) (x) -#endif - -/** - * Platform detection for SIMD / fast-path implementations. At most one of - * these macros is defined, selecting the best available vectorization strategy. - */ -#if (defined(__aarch64__) && defined(__ARM_NEON)) || (defined(_MSC_VER) && defined(_M_ARM64)) - #define PRISM_HAS_NEON -#elif (defined(__x86_64__) && defined(__SSSE3__)) || (defined(_MSC_VER) && defined(_M_X64)) - #define PRISM_HAS_SSSE3 -#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - #define PRISM_HAS_SWAR -#endif - -/** - * Count trailing zero bits in a 64-bit value. Used by SWAR identifier scanning - * to find the first non-matching byte in a word. - * - * Precondition: v must be nonzero. The result is undefined when v == 0 - * (matching the behavior of __builtin_ctzll and _BitScanForward64). - */ -#if defined(__GNUC__) || defined(__clang__) - #define pm_ctzll(v) ((unsigned) __builtin_ctzll(v)) -#elif defined(_MSC_VER) - #include - static inline unsigned pm_ctzll(uint64_t v) { - unsigned long index; - _BitScanForward64(&index, v); - return (unsigned) index; - } -#else - static inline unsigned - pm_ctzll(uint64_t v) { - unsigned c = 0; - v &= (uint64_t) (-(int64_t) v); - if (v & 0x00000000FFFFFFFFULL) c += 0; else c += 32; - if (v & 0x0000FFFF0000FFFFULL) c += 0; else c += 16; - if (v & 0x00FF00FF00FF00FFULL) c += 0; else c += 8; - if (v & 0x0F0F0F0F0F0F0F0FULL) c += 0; else c += 4; - if (v & 0x3333333333333333ULL) c += 0; else c += 2; - if (v & 0x5555555555555555ULL) c += 0; else c += 1; - return c; - } -#endif - -/** - * We use -Wimplicit-fallthrough to guard potentially unintended fall-through between cases of a switch. - * Use PRISM_FALLTHROUGH to explicitly annotate cases where the fallthrough is intentional. - */ -#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L // C23 or later - #define PRISM_FALLTHROUGH [[fallthrough]]; -#elif defined(__GNUC__) || defined(__clang__) - #define PRISM_FALLTHROUGH __attribute__((fallthrough)); -#elif defined(_MSC_VER) - #define PRISM_FALLTHROUGH __fallthrough; -#else - #define PRISM_FALLTHROUGH -#endif - -/** - * A macro for defining a flexible array member. C99 supports `data[]`, GCC - * supports `data[0]` as an extension, and older compilers require `data[1]`. - */ -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) - #define PM_FLEX_ARY_LEN /* data[] */ -#elif defined(__GNUC__) && !defined(__STRICT_ANSI__) - #define PM_FLEX_ARY_LEN 0 /* data[0] */ -#else - #define PM_FLEX_ARY_LEN 1 /* data[1] */ -#endif - -/** - * We need to align nodes in the AST to a pointer boundary so that it can be - * safely cast to different node types. Use PRISM_ALIGNAS/PRISM_ALIGNOF to - * specify alignment in a compiler-agnostic way. - */ -#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L /* C11 or later */ - /** Specify alignment for a type or variable. */ - #define PRISM_ALIGNAS _Alignas - - /** Get the alignment requirement of a type. */ - #define PRISM_ALIGNOF _Alignof -#elif defined(__GNUC__) || defined(__clang__) - /** Specify alignment for a type or variable. */ - #define PRISM_ALIGNAS(size) __attribute__((aligned(size))) - - /** Get the alignment requirement of a type. */ - #define PRISM_ALIGNOF(type) __alignof__(type) -#elif defined(_MSC_VER) - /** Specify alignment for a type or variable. */ - #define PRISM_ALIGNAS(size) __declspec(align(size)) - - /** Get the alignment requirement of a type. */ - #define PRISM_ALIGNOF(type) __alignof(type) -#else - /** Void because this platform does not support specifying alignment. */ - #define PRISM_ALIGNAS(size) - - /** Fallback to sizeof as alignment requirement of a type. */ - #define PRISM_ALIGNOF(type) sizeof(type) -#endif - -#endif diff --git a/prism/diagnostic.h b/prism/diagnostic.h new file mode 100644 index 00000000000000..370061ec569135 --- /dev/null +++ b/prism/diagnostic.h @@ -0,0 +1,93 @@ +/** + * @file diagnostic.h + * + * A list of diagnostics generated during parsing. + */ +#ifndef PRISM_DIAGNOSTIC_H +#define PRISM_DIAGNOSTIC_H + +#include "prism/compiler/exported.h" +#include "prism/compiler/nodiscard.h" +#include "prism/compiler/nonnull.h" + +#include "prism/ast.h" + +/** + * An opaque pointer to a diagnostic generated during parsing. + */ +typedef struct pm_diagnostic_t pm_diagnostic_t; + +/** + * The levels of errors generated during parsing. + */ +typedef enum { + /** For errors that should raise a syntax error. */ + PM_ERROR_LEVEL_SYNTAX = 0, + + /** For errors that should raise an argument error. */ + PM_ERROR_LEVEL_ARGUMENT = 1, + + /** For errors that should raise a load error. */ + PM_ERROR_LEVEL_LOAD = 2 +} pm_error_level_t; + +/** + * The levels of warnings generated during parsing. + */ +typedef enum { + /** For warnings which should be emitted if $VERBOSE != nil. */ + PM_WARNING_LEVEL_DEFAULT = 0, + + /** For warnings which should be emitted if $VERBOSE == true. */ + PM_WARNING_LEVEL_VERBOSE = 1 +} pm_warning_level_t; + +/** + * Get the type of the given diagnostic. + * + * @param diagnostic The diagnostic to get the type of. + * @returns The type of the given diagnostic. Note that this is a string + * representation of an internal ID, and is not meant to be relied upon as a + * stable identifier for the diagnostic. We do not guarantee that these will + * not change in the future. This is meant to be used for debugging and + * error reporting purposes, and not for programmatic checks. + */ +PRISM_EXPORTED_FUNCTION const char * pm_diagnostic_type(const pm_diagnostic_t *diagnostic) PRISM_NONNULL(1); + +/** + * Get the location of the given diagnostic. + * + * @param diagnostic The diagnostic to get the location of. + * @returns The location of the given diagnostic. + */ +PRISM_EXPORTED_FUNCTION pm_location_t pm_diagnostic_location(const pm_diagnostic_t *diagnostic) PRISM_NONNULL(1); + +/** + * Get the message of the given diagnostic. + * + * @param diagnostic The diagnostic to get the message of. + * @returns The message of the given diagnostic. + */ +PRISM_EXPORTED_FUNCTION const char * pm_diagnostic_message(const pm_diagnostic_t *diagnostic) PRISM_NONNULL(1); + +/** + * Get the error level associated with the given diagnostic. + * + * @param diagnostic The diagnostic to get the error level of. + * @returns The error level of the given diagnostic. If the diagnostic was a + * warning, or is in any way not an error, then the return value is + * undefined and should not be relied upon. + */ +PRISM_EXPORTED_FUNCTION pm_error_level_t pm_diagnostic_error_level(const pm_diagnostic_t *diagnostic) PRISM_NONNULL(1); + +/** + * Get the warning level associated with the given diagnostic. + * + * @param diagnostic The diagnostic to get the warning level of. + * @returns The warning level of the given diagnostic. If the diagnostic was an + * error, or is in any way not a warning, then the return value is + * undefined and should not be relied upon. + */ +PRISM_EXPORTED_FUNCTION pm_warning_level_t pm_diagnostic_warning_level(const pm_diagnostic_t *diagnostic) PRISM_NONNULL(1); + +#endif diff --git a/prism/encoding.c b/prism/encoding.c index d7e5616840483f..c9c2e130563c3a 100644 --- a/prism/encoding.c +++ b/prism/encoding.c @@ -1,4 +1,9 @@ -#include "prism/encoding.h" +#include "prism/internal/encoding.h" + +#include "prism/compiler/unused.h" +#include "prism/internal/strncasecmp.h" + +#include typedef uint32_t pm_unicode_codepoint_t; @@ -4089,7 +4094,7 @@ pm_encoding_ascii_isupper_char(const uint8_t *b, ptrdiff_t n) { * matter what the codepoint, so this function is shared between them. */ static size_t -pm_encoding_single_char_width(PRISM_ATTRIBUTE_UNUSED const uint8_t *b, PRISM_ATTRIBUTE_UNUSED ptrdiff_t n) { +pm_encoding_single_char_width(PRISM_UNUSED const uint8_t *b, PRISM_UNUSED ptrdiff_t n) { return 1; } diff --git a/prism/excludes.h b/prism/excludes.h new file mode 100644 index 00000000000000..8600622f637dfb --- /dev/null +++ b/prism/excludes.h @@ -0,0 +1,29 @@ +/** + * @file excludes.h + * + * A header file that defines macros to exclude certain features of the prism + * library. This is useful for reducing the size of the library when certain + * features are not needed. + */ +#ifndef PRISM_EXCLUDES_H +#define PRISM_EXCLUDES_H + +/** + * If PRISM_BUILD_MINIMAL is defined, then we're going to define every possible + * switch that will turn off certain features of prism. + */ +#ifdef PRISM_BUILD_MINIMAL + /** Exclude the serialization API. */ + #define PRISM_EXCLUDE_SERIALIZATION + + /** Exclude the JSON serialization API. */ + #define PRISM_EXCLUDE_JSON + + /** Exclude the prettyprint API. */ + #define PRISM_EXCLUDE_PRETTYPRINT + + /** Exclude the full set of encodings, using the minimal only. */ + #define PRISM_ENCODING_EXCLUDE_FULL +#endif + +#endif diff --git a/prism/extension.c b/prism/extension.c index c248b0c12356d2..9f9169cfff7880 100644 --- a/prism/extension.c +++ b/prism/extension.c @@ -4,6 +4,8 @@ #include #endif +#include + // NOTE: this file should contain only bindings. All non-trivial logic should be // in libprism so it can be shared its the various callers. @@ -64,18 +66,6 @@ check_string(VALUE value) { return RSTRING_PTR(value); } -/** - * Load the contents and size of the given string into the given pm_string_t. - */ -static void -input_load_string(pm_string_t *input, VALUE string) { - // Check if the string is a string. If it's not, then raise a type error. - if (!RB_TYPE_P(string, T_STRING)) { - rb_raise(rb_eTypeError, "wrong argument type %" PRIsVALUE " (expected String)", rb_obj_class(string)); - } - - pm_string_constant_init(input, RSTRING_PTR(string), RSTRING_LEN(string)); -} /******************************************************************************/ /* Building C options from Ruby options */ @@ -148,10 +138,8 @@ build_options_scopes(pm_options_t *options, VALUE scopes) { // Initialize the scope array. size_t locals_count = RARRAY_LEN(locals); - pm_options_scope_t *options_scope = &options->scopes[scope_index]; - if (!pm_options_scope_init(options_scope, locals_count)) { - rb_raise(rb_eNoMemError, "failed to allocate memory"); - } + pm_options_scope_t *options_scope = pm_options_scope_mut(options, scope_index); + pm_options_scope_init(options_scope, locals_count); // Iterate over the locals and add them to the scope. for (size_t local_index = 0; local_index < locals_count; local_index++) { @@ -164,7 +152,7 @@ build_options_scopes(pm_options_t *options, VALUE scopes) { } // Add the local to the scope. - pm_string_t *scope_local = &options_scope->locals[local_index]; + pm_string_t *scope_local = pm_options_scope_local_mut(options_scope, local_index); const char *name = rb_id2name(SYM2ID(local)); pm_string_constant_init(scope_local, name, strlen(name)); } @@ -208,10 +196,10 @@ build_options_i(VALUE key, VALUE value, VALUE argument) { if (!pm_options_version_set(options, ruby_version, 3)) { // Prism doesn't know this specific version. Is it lower? if (ruby_version[0] < '3' || (ruby_version[0] == '3' && ruby_version[2] < '3')) { - options->version = PM_OPTIONS_VERSION_CRUBY_3_3; + pm_options_version_set_lowest(options); } else { // Must be higher. - options->version = PM_OPTIONS_VERSION_LATEST; + pm_options_version_set_highest(options); } } } else if (!pm_options_version_set(options, version, RSTRING_LEN(value))) { @@ -278,7 +266,7 @@ build_options(VALUE argument) { */ static void extract_options(pm_options_t *options, VALUE filepath, VALUE keywords) { - options->line = 1; // default + pm_options_line_set(options, 1); /* default */ if (!NIL_P(keywords)) { struct build_options_data data = { .options = options, .keywords = keywords }; @@ -306,36 +294,46 @@ extract_options(pm_options_t *options, VALUE filepath, VALUE keywords) { /** * Read options for methods that look like (source, **options). */ -static void -string_options(int argc, VALUE *argv, pm_string_t *input, pm_options_t *options) { +static VALUE +string_options(int argc, VALUE *argv, pm_options_t *options) { VALUE string; VALUE keywords; rb_scan_args(argc, argv, "1:", &string, &keywords); + if (!RB_TYPE_P(string, T_STRING)) { + pm_options_free(options); + rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (expected String)", rb_obj_class(string)); + } + extract_options(options, Qnil, keywords); - input_load_string(input, string); + return string; } /** * Read options for methods that look like (filepath, **options). */ -static void -file_options(int argc, VALUE *argv, pm_string_t *input, pm_options_t *options, VALUE *encoded_filepath) { +static pm_source_t * +file_options(int argc, VALUE *argv, pm_options_t *options, VALUE *encoded_filepath) { VALUE filepath; VALUE keywords; rb_scan_args(argc, argv, "1:", &filepath, &keywords); - Check_Type(filepath, T_STRING); + if (!RB_TYPE_P(filepath, T_STRING)) { + pm_options_free(options); + rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (expected String)", rb_obj_class(filepath)); + } + *encoded_filepath = rb_str_encode_ospath(filepath); extract_options(options, *encoded_filepath, keywords); - const char *source = (const char *) pm_string_source(&options->filepath); - pm_string_init_result_t result; + const char *source = (const char *) pm_string_source(pm_options_filepath(options)); + pm_source_init_result_t result; + pm_source_t *pm_src = pm_source_file_new(source, &result); - switch (result = pm_string_file_init(input, source)) { - case PM_STRING_INIT_SUCCESS: + switch (result) { + case PM_SOURCE_INIT_SUCCESS: break; - case PM_STRING_INIT_ERROR_GENERIC: { + case PM_SOURCE_INIT_ERROR_GENERIC: { pm_options_free(options); #ifdef _WIN32 @@ -347,7 +345,7 @@ file_options(int argc, VALUE *argv, pm_string_t *input, pm_options_t *options, V rb_syserr_fail(e, source); break; } - case PM_STRING_INIT_ERROR_DIRECTORY: + case PM_SOURCE_INIT_ERROR_DIRECTORY: pm_options_free(options); rb_syserr_fail(EISDIR, source); break; @@ -356,6 +354,8 @@ file_options(int argc, VALUE *argv, pm_string_t *input, pm_options_t *options, V rb_raise(rb_eRuntimeError, "Unknown error (%d) initializing file: %s", result, source); break; } + + return pm_src; } #ifndef PRISM_EXCLUDE_SERIALIZATION @@ -368,23 +368,22 @@ file_options(int argc, VALUE *argv, pm_string_t *input, pm_options_t *options, V * Dump the AST corresponding to the given input to a string. */ static VALUE -dump_input(pm_string_t *input, const pm_options_t *options) { - pm_buffer_t buffer; - if (!pm_buffer_init(&buffer)) { +dump_input(const uint8_t *input, size_t input_length, const pm_options_t *options) { + pm_buffer_t *buffer = pm_buffer_new(); + if (!buffer) { rb_raise(rb_eNoMemError, "failed to allocate memory"); } - pm_arena_t arena = { 0 }; - pm_parser_t parser; - pm_parser_init(&arena, &parser, pm_string_source(input), pm_string_length(input), options); + pm_arena_t *arena = pm_arena_new(); + pm_parser_t *parser = pm_parser_new(arena, input, input_length, options); - pm_node_t *node = pm_parse(&parser); - pm_serialize(&parser, node, &buffer); + pm_node_t *node = pm_parse(parser); + pm_serialize(parser, node, buffer); - VALUE result = rb_str_new(pm_buffer_value(&buffer), pm_buffer_length(&buffer)); - pm_buffer_free(&buffer); - pm_parser_free(&parser); - pm_arena_free(&arena); + VALUE result = rb_str_new(pm_buffer_value(buffer), pm_buffer_length(buffer)); + pm_buffer_free(buffer); + pm_parser_free(parser); + pm_arena_free(arena); return result; } @@ -399,26 +398,30 @@ dump_input(pm_string_t *input, const pm_options_t *options) { */ static VALUE dump(int argc, VALUE *argv, VALUE self) { - pm_string_t input; - pm_options_t options = { 0 }; - string_options(argc, argv, &input, &options); + pm_options_t *options = pm_options_new(); + VALUE string = string_options(argc, argv, options); + + const uint8_t *source = (const uint8_t *) RSTRING_PTR(string); + size_t length = RSTRING_LEN(string); #ifdef PRISM_BUILD_DEBUG - size_t length = pm_string_length(&input); char* dup = xmalloc(length); - memcpy(dup, pm_string_source(&input), length); - pm_string_constant_init(&input, dup, length); + memcpy(dup, source, length); + source = (const uint8_t *) dup; #endif - VALUE value = dump_input(&input, &options); - if (options.freeze) rb_obj_freeze(value); + VALUE value = dump_input(source, length, options); + if (pm_options_freeze(options)) rb_obj_freeze(value); #ifdef PRISM_BUILD_DEBUG +#ifdef xfree_sized xfree_sized(dup, length); +#else + xfree(dup); +#endif #endif - pm_string_free(&input); - pm_options_free(&options); + pm_options_free(options); return value; } @@ -433,15 +436,14 @@ dump(int argc, VALUE *argv, VALUE self) { */ static VALUE dump_file(int argc, VALUE *argv, VALUE self) { - pm_string_t input; - pm_options_t options = { 0 }; + pm_options_t *options = pm_options_new(); VALUE encoded_filepath; - file_options(argc, argv, &input, &options, &encoded_filepath); + pm_source_t *src = file_options(argc, argv, options, &encoded_filepath); - VALUE value = dump_input(&input, &options); - pm_string_free(&input); - pm_options_free(&options); + VALUE value = dump_input(pm_source_source(src), pm_source_length(src), options); + pm_source_free(src); + pm_options_free(options); return value; } @@ -483,26 +485,33 @@ parser_location(VALUE source, bool freeze, uint32_t start, uint32_t length) { */ static inline VALUE parser_comment(VALUE source, bool freeze, const pm_comment_t *comment) { - VALUE argv[] = { PARSER_LOCATION(source, freeze, comment->location) }; - VALUE type = (comment->type == PM_COMMENT_EMBDOC) ? rb_cPrismEmbDocComment : rb_cPrismInlineComment; + VALUE argv[] = { PARSER_LOCATION(source, freeze, pm_comment_location(comment)) }; + VALUE type = (pm_comment_type(comment) == PM_COMMENT_EMBDOC) ? rb_cPrismEmbDocComment : rb_cPrismInlineComment; return rb_class_new_instance_freeze(1, argv, type, freeze); } +typedef struct { + VALUE comments; + VALUE source; + bool freeze; +} parser_comments_each_data_t; + +static void +parser_comments_each(const pm_comment_t *comment, void *data) { + parser_comments_each_data_t *each_data = (parser_comments_each_data_t *) data; + VALUE value = parser_comment(each_data->source, each_data->freeze, comment); + rb_ary_push(each_data->comments, value); +} + /** * Extract the comments out of the parser into an array. */ static VALUE parser_comments(const pm_parser_t *parser, VALUE source, bool freeze) { - VALUE comments = rb_ary_new_capa(parser->comment_list.size); - - for ( - const pm_comment_t *comment = (const pm_comment_t *) parser->comment_list.head; - comment != NULL; - comment = (const pm_comment_t *) comment->node.next - ) { - VALUE value = parser_comment(source, freeze, comment); - rb_ary_push(comments, value); - } + VALUE comments = rb_ary_new_capa(pm_parser_comments_size(parser)); + + parser_comments_each_data_t each_data = { comments, source, freeze }; + pm_parser_comments_each(parser, parser_comments_each, &each_data); if (freeze) rb_obj_freeze(comments); return comments; @@ -513,27 +522,38 @@ parser_comments(const pm_parser_t *parser, VALUE source, bool freeze) { */ static inline VALUE parser_magic_comment(VALUE source, bool freeze, const pm_magic_comment_t *magic_comment) { - VALUE key_loc = parser_location(source, freeze, magic_comment->key.start, magic_comment->key.length); - VALUE value_loc = parser_location(source, freeze, magic_comment->value.start, magic_comment->value.length); + pm_location_t key = pm_magic_comment_key(magic_comment); + pm_location_t value = pm_magic_comment_value(magic_comment); + + VALUE key_loc = parser_location(source, freeze, key.start, key.length); + VALUE value_loc = parser_location(source, freeze, value.start, value.length); + VALUE argv[] = { key_loc, value_loc }; return rb_class_new_instance_freeze(2, argv, rb_cPrismMagicComment, freeze); } +typedef struct { + VALUE magic_comments; + VALUE source; + bool freeze; +} parser_magic_comments_each_data_t; + +static void +parser_magic_comments_each(const pm_magic_comment_t *magic_comment, void *data) { + parser_magic_comments_each_data_t *each_data = (parser_magic_comments_each_data_t *) data; + VALUE value = parser_magic_comment(each_data->source, each_data->freeze, magic_comment); + rb_ary_push(each_data->magic_comments, value); +} + /** * Extract the magic comments out of the parser into an array. */ static VALUE parser_magic_comments(const pm_parser_t *parser, VALUE source, bool freeze) { - VALUE magic_comments = rb_ary_new_capa(parser->magic_comment_list.size); - - for ( - const pm_magic_comment_t *magic_comment = (const pm_magic_comment_t *) parser->magic_comment_list.head; - magic_comment != NULL; - magic_comment = (const pm_magic_comment_t *) magic_comment->node.next - ) { - VALUE value = parser_magic_comment(source, freeze, magic_comment); - rb_ary_push(magic_comments, value); - } + VALUE magic_comments = rb_ary_new_capa(pm_parser_magic_comments_size(parser)); + + parser_magic_comments_each_data_t each_data = { magic_comments, source, freeze }; + pm_parser_magic_comments_each(parser, parser_magic_comments_each, &each_data); if (freeze) rb_obj_freeze(magic_comments); return magic_comments; @@ -545,85 +565,109 @@ parser_magic_comments(const pm_parser_t *parser, VALUE source, bool freeze) { */ static VALUE parser_data_loc(const pm_parser_t *parser, VALUE source, bool freeze) { - if (parser->data_loc.length == 0) { + const pm_location_t *data_loc = pm_parser_data_loc(parser); + + if (data_loc->length == 0) { return Qnil; } else { - return parser_location(source, freeze, parser->data_loc.start, parser->data_loc.length); + return parser_location(source, freeze, data_loc->start, data_loc->length); } } +typedef struct { + VALUE errors; + rb_encoding *encoding; + VALUE source; + bool freeze; +} parser_errors_each_data_t; + +static void +parser_errors_each(const pm_diagnostic_t *diagnostic, void *data) { + parser_errors_each_data_t *each_data = (parser_errors_each_data_t *) data; + + VALUE type = ID2SYM(rb_intern(pm_diagnostic_type(diagnostic))); + VALUE message = rb_obj_freeze(rb_enc_str_new_cstr(pm_diagnostic_message(diagnostic), each_data->encoding)); + VALUE location = PARSER_LOCATION(each_data->source, each_data->freeze, pm_diagnostic_location(diagnostic)); + + pm_error_level_t error_level = pm_diagnostic_error_level(diagnostic); + VALUE level = Qnil; + + switch (error_level) { + case PM_ERROR_LEVEL_SYNTAX: + level = ID2SYM(rb_intern("syntax")); + break; + case PM_ERROR_LEVEL_ARGUMENT: + level = ID2SYM(rb_intern("argument")); + break; + case PM_ERROR_LEVEL_LOAD: + level = ID2SYM(rb_intern("load")); + break; + default: + rb_raise(rb_eRuntimeError, "Unknown level: %" PRIu8, error_level); + } + + VALUE argv[] = { type, message, location, level }; + VALUE value = rb_class_new_instance_freeze(4, argv, rb_cPrismParseError, each_data->freeze); + rb_ary_push(each_data->errors, value); +} + /** * Extract the errors out of the parser into an array. */ static VALUE parser_errors(const pm_parser_t *parser, rb_encoding *encoding, VALUE source, bool freeze) { - VALUE errors = rb_ary_new_capa(parser->error_list.size); - - for ( - const pm_diagnostic_t *error = (const pm_diagnostic_t *) parser->error_list.head; - error != NULL; - error = (const pm_diagnostic_t *) error->node.next - ) { - VALUE type = ID2SYM(rb_intern(pm_diagnostic_id_human(error->diag_id))); - VALUE message = rb_obj_freeze(rb_enc_str_new_cstr(error->message, encoding)); - VALUE location = PARSER_LOCATION(source, freeze, error->location); - - VALUE level = Qnil; - switch (error->level) { - case PM_ERROR_LEVEL_SYNTAX: - level = ID2SYM(rb_intern("syntax")); - break; - case PM_ERROR_LEVEL_ARGUMENT: - level = ID2SYM(rb_intern("argument")); - break; - case PM_ERROR_LEVEL_LOAD: - level = ID2SYM(rb_intern("load")); - break; - default: - rb_raise(rb_eRuntimeError, "Unknown level: %" PRIu8, error->level); - } + VALUE errors = rb_ary_new_capa(pm_parser_errors_size(parser)); - VALUE argv[] = { type, message, location, level }; - VALUE value = rb_class_new_instance_freeze(4, argv, rb_cPrismParseError, freeze); - rb_ary_push(errors, value); - } + parser_errors_each_data_t each_data = { errors, encoding, source, freeze }; + pm_parser_errors_each(parser, parser_errors_each, &each_data); if (freeze) rb_obj_freeze(errors); return errors; } +typedef struct { + VALUE warnings; + rb_encoding *encoding; + VALUE source; + bool freeze; +} parser_warnings_each_data_t; + +static void +parser_warnings_each(const pm_diagnostic_t *diagnostic, void *data) { + parser_warnings_each_data_t *each_data = (parser_warnings_each_data_t *) data; + + VALUE type = ID2SYM(rb_intern(pm_diagnostic_type(diagnostic))); + VALUE message = rb_obj_freeze(rb_enc_str_new_cstr(pm_diagnostic_message(diagnostic), each_data->encoding)); + VALUE location = PARSER_LOCATION(each_data->source, each_data->freeze, pm_diagnostic_location(diagnostic)); + + pm_warning_level_t warning_level = pm_diagnostic_warning_level(diagnostic); + VALUE level = Qnil; + + switch (warning_level) { + case PM_WARNING_LEVEL_DEFAULT: + level = ID2SYM(rb_intern("default")); + break; + case PM_WARNING_LEVEL_VERBOSE: + level = ID2SYM(rb_intern("verbose")); + break; + default: + rb_raise(rb_eRuntimeError, "Unknown level: %" PRIu8, warning_level); + } + + VALUE argv[] = { type, message, location, level }; + VALUE value = rb_class_new_instance_freeze(4, argv, rb_cPrismParseWarning, each_data->freeze); + rb_ary_push(each_data->warnings, value); +} + /** * Extract the warnings out of the parser into an array. */ static VALUE parser_warnings(const pm_parser_t *parser, rb_encoding *encoding, VALUE source, bool freeze) { - VALUE warnings = rb_ary_new_capa(parser->warning_list.size); - - for ( - const pm_diagnostic_t *warning = (const pm_diagnostic_t *) parser->warning_list.head; - warning != NULL; - warning = (const pm_diagnostic_t *) warning->node.next - ) { - VALUE type = ID2SYM(rb_intern(pm_diagnostic_id_human(warning->diag_id))); - VALUE message = rb_obj_freeze(rb_enc_str_new_cstr(warning->message, encoding)); - VALUE location = PARSER_LOCATION(source, freeze, warning->location); - - VALUE level = Qnil; - switch (warning->level) { - case PM_WARNING_LEVEL_DEFAULT: - level = ID2SYM(rb_intern("default")); - break; - case PM_WARNING_LEVEL_VERBOSE: - level = ID2SYM(rb_intern("verbose")); - break; - default: - rb_raise(rb_eRuntimeError, "Unknown level: %" PRIu8, warning->level); - } + VALUE warnings = rb_ary_new_capa(pm_parser_warnings_size(parser)); - VALUE argv[] = { type, message, location, level }; - VALUE value = rb_class_new_instance_freeze(4, argv, rb_cPrismParseWarning, freeze); - rb_ary_push(warnings, value); - } + parser_warnings_each_data_t each_data = { warnings, encoding, source, freeze }; + pm_parser_warnings_each(parser, parser_warnings_each, &each_data); if (freeze) rb_obj_freeze(warnings); return warnings; @@ -641,7 +685,7 @@ parse_result_create(VALUE class, const pm_parser_t *parser, VALUE value, rb_enco parser_data_loc(parser, source, freeze), parser_errors(parser, encoding, source, freeze), parser_warnings(parser, encoding, source, freeze), - parser->continuable ? Qtrue : Qfalse, + pm_parser_continuable(parser) ? Qtrue : Qfalse, source }; @@ -670,11 +714,11 @@ typedef struct { * onto the tokens array. */ static void -parse_lex_token(void *data, pm_parser_t *parser, pm_token_t *token) { - parse_lex_data_t *parse_lex_data = (parse_lex_data_t *) parser->lex_callback->data; +parse_lex_token(pm_parser_t *parser, pm_token_t *token, void *data) { + parse_lex_data_t *parse_lex_data = (parse_lex_data_t *) data; VALUE value = pm_token_new(parser, token, parse_lex_data->encoding, parse_lex_data->source, parse_lex_data->freeze); - VALUE yields = rb_assoc_new(value, INT2FIX(parser->lex_state)); + VALUE yields = rb_assoc_new(value, INT2FIX(pm_parser_lex_state(parser))); if (parse_lex_data->freeze) { rb_obj_freeze(value); @@ -691,8 +735,8 @@ parse_lex_token(void *data, pm_parser_t *parser, pm_token_t *token) { */ static void parse_lex_encoding_changed_callback(pm_parser_t *parser) { - parse_lex_data_t *parse_lex_data = (parse_lex_data_t *) parser->lex_callback->data; - parse_lex_data->encoding = rb_enc_find(parser->encoding->name); + parse_lex_data_t *parse_lex_data = (parse_lex_data_t *) pm_parser_lex_callback_data(parser); + parse_lex_data->encoding = rb_enc_find(pm_parser_encoding_name(parser)); // Since the encoding changed, we need to go back and change the encoding of // the tokens that were already lexed. This is only going to end up being @@ -737,44 +781,38 @@ parse_lex_encoding_changed_callback(pm_parser_t *parser) { * the nodes and tokens. */ static VALUE -parse_lex_input(pm_string_t *input, const pm_options_t *options, bool return_nodes) { - pm_arena_t arena = { 0 }; - pm_parser_t parser; - pm_parser_init(&arena, &parser, pm_string_source(input), pm_string_length(input), options); - pm_parser_register_encoding_changed_callback(&parser, parse_lex_encoding_changed_callback); +parse_lex_input(const uint8_t *input, size_t input_length, const pm_options_t *options, bool return_nodes) { + pm_arena_t *arena = pm_arena_new(); + pm_parser_t *parser = pm_parser_new(arena, input, input_length, options); + pm_parser_encoding_changed_callback_set(parser, parse_lex_encoding_changed_callback); - VALUE source_string = rb_str_new((const char *) pm_string_source(input), pm_string_length(input)); - VALUE offsets = rb_ary_new_capa(parser.line_offsets.size); - VALUE source = rb_funcall(rb_cPrismSource, rb_id_source_for, 3, source_string, LONG2NUM(parser.start_line), offsets); + VALUE source_string = rb_str_new((const char *) input, input_length); + VALUE offsets = rb_ary_new_capa(pm_parser_line_offsets(parser)->size); + VALUE source = rb_funcall(rb_cPrismSource, rb_id_source_for, 3, source_string, LONG2NUM(pm_parser_start_line(parser)), offsets); parse_lex_data_t parse_lex_data = { .source = source, .tokens = rb_ary_new(), .encoding = rb_utf8_encoding(), - .freeze = options->freeze, + .freeze = pm_options_freeze(options), }; parse_lex_data_t *data = &parse_lex_data; - pm_lex_callback_t lex_callback = (pm_lex_callback_t) { - .data = (void *) data, - .callback = parse_lex_token, - }; + pm_parser_lex_callback_set(parser, parse_lex_token, data); - parser.lex_callback = &lex_callback; - pm_node_t *node = pm_parse(&parser); + pm_node_t *node = pm_parse(parser); - // Here we need to update the Source object to have the correct - // encoding for the source string and the correct newline offsets. - // We do it here because we've already created the Source object and given - // it over to all of the tokens, and both of these are only set after pm_parse(). - rb_encoding *encoding = rb_enc_find(parser.encoding->name); + /* Update the Source object with the correct encoding and line offsets, + * which are only available after pm_parse() completes. */ + rb_encoding *encoding = rb_enc_find(pm_parser_encoding_name(parser)); rb_enc_associate(source_string, encoding); - for (size_t index = 0; index < parser.line_offsets.size; index++) { - rb_ary_push(offsets, ULONG2NUM(parser.line_offsets.offsets[index])); + const pm_line_offset_list_t *line_offsets = pm_parser_line_offsets(parser); + for (size_t index = 0; index < line_offsets->size; index++) { + rb_ary_store(offsets, (long) index, ULONG2NUM(line_offsets->offsets[index])); } - if (options->freeze) { + if (pm_options_freeze(options)) { rb_obj_freeze(source_string); rb_obj_freeze(offsets); rb_obj_freeze(source); @@ -784,16 +822,16 @@ parse_lex_input(pm_string_t *input, const pm_options_t *options, bool return_nod VALUE result; if (return_nodes) { VALUE value = rb_ary_new_capa(2); - rb_ary_push(value, pm_ast_new(&parser, node, parse_lex_data.encoding, source, options->freeze)); + rb_ary_push(value, pm_ast_new(parser, node, parse_lex_data.encoding, source, pm_options_freeze(options))); rb_ary_push(value, parse_lex_data.tokens); - if (options->freeze) rb_obj_freeze(value); - result = parse_result_create(rb_cPrismParseLexResult, &parser, value, parse_lex_data.encoding, source, options->freeze); + if (pm_options_freeze(options)) rb_obj_freeze(value); + result = parse_result_create(rb_cPrismParseLexResult, parser, value, parse_lex_data.encoding, source, pm_options_freeze(options)); } else { - result = parse_result_create(rb_cPrismLexResult, &parser, parse_lex_data.tokens, parse_lex_data.encoding, source, options->freeze); + result = parse_result_create(rb_cPrismLexResult, parser, parse_lex_data.tokens, parse_lex_data.encoding, source, pm_options_freeze(options)); } - pm_parser_free(&parser); - pm_arena_free(&arena); + pm_parser_free(parser); + pm_arena_free(arena); return result; } @@ -808,13 +846,11 @@ parse_lex_input(pm_string_t *input, const pm_options_t *options, bool return_nod */ static VALUE lex(int argc, VALUE *argv, VALUE self) { - pm_string_t input; - pm_options_t options = { 0 }; - string_options(argc, argv, &input, &options); + pm_options_t *options = pm_options_new(); + VALUE string = string_options(argc, argv, options); - VALUE result = parse_lex_input(&input, &options, false); - pm_string_free(&input); - pm_options_free(&options); + VALUE result = parse_lex_input((const uint8_t *) RSTRING_PTR(string), RSTRING_LEN(string), options, false); + pm_options_free(options); return result; } @@ -829,15 +865,14 @@ lex(int argc, VALUE *argv, VALUE self) { */ static VALUE lex_file(int argc, VALUE *argv, VALUE self) { - pm_string_t input; - pm_options_t options = { 0 }; + pm_options_t *options = pm_options_new(); VALUE encoded_filepath; - file_options(argc, argv, &input, &options, &encoded_filepath); + pm_source_t *src = file_options(argc, argv, options, &encoded_filepath); - VALUE value = parse_lex_input(&input, &options, false); - pm_string_free(&input); - pm_options_free(&options); + VALUE value = parse_lex_input(pm_source_source(src), pm_source_length(src), options, false); + pm_source_free(src); + pm_options_free(options); return value; } @@ -850,24 +885,24 @@ lex_file(int argc, VALUE *argv, VALUE self) { * Parse the given input and return a ParseResult instance. */ static VALUE -parse_input(pm_string_t *input, const pm_options_t *options) { - pm_arena_t arena = { 0 }; - pm_parser_t parser; - pm_parser_init(&arena, &parser, pm_string_source(input), pm_string_length(input), options); +parse_input(const uint8_t *input, size_t input_length, const pm_options_t *options) { + pm_arena_t *arena = pm_arena_new(); + pm_parser_t *parser = pm_parser_new(arena, input, input_length, options); - pm_node_t *node = pm_parse(&parser); - rb_encoding *encoding = rb_enc_find(parser.encoding->name); + pm_node_t *node = pm_parse(parser); + rb_encoding *encoding = rb_enc_find(pm_parser_encoding_name(parser)); - VALUE source = pm_source_new(&parser, encoding, options->freeze); - VALUE value = pm_ast_new(&parser, node, encoding, source, options->freeze); - VALUE result = parse_result_create(rb_cPrismParseResult, &parser, value, encoding, source, options->freeze); + bool freeze = pm_options_freeze(options); + VALUE source = pm_source_new(parser, encoding, freeze); + VALUE value = pm_ast_new(parser, node, encoding, source, freeze); + VALUE result = parse_result_create(rb_cPrismParseResult, parser, value, encoding, source, freeze); - if (options->freeze) { + if (freeze) { rb_obj_freeze(source); } - pm_parser_free(&parser); - pm_arena_free(&arena); + pm_parser_free(parser); + pm_arena_free(arena); return result; } @@ -919,25 +954,29 @@ parse_input(pm_string_t *input, const pm_options_t *options) { */ static VALUE parse(int argc, VALUE *argv, VALUE self) { - pm_string_t input; - pm_options_t options = { 0 }; - string_options(argc, argv, &input, &options); + pm_options_t *options = pm_options_new(); + VALUE string = string_options(argc, argv, options); + + const uint8_t *source = (const uint8_t *) RSTRING_PTR(string); + size_t length = RSTRING_LEN(string); #ifdef PRISM_BUILD_DEBUG - size_t length = pm_string_length(&input); char* dup = xmalloc(length); - memcpy(dup, pm_string_source(&input), length); - pm_string_constant_init(&input, dup, length); + memcpy(dup, source, length); + source = (const uint8_t *) dup; #endif - VALUE value = parse_input(&input, &options); + VALUE value = parse_input(source, length, options); #ifdef PRISM_BUILD_DEBUG +#ifdef xfree_sized xfree_sized(dup, length); +#else + xfree(dup); +#endif #endif - pm_string_free(&input); - pm_options_free(&options); + pm_options_free(options); return value; } @@ -951,15 +990,14 @@ parse(int argc, VALUE *argv, VALUE self) { */ static VALUE parse_file(int argc, VALUE *argv, VALUE self) { - pm_string_t input; - pm_options_t options = { 0 }; + pm_options_t *options = pm_options_new(); VALUE encoded_filepath; - file_options(argc, argv, &input, &options, &encoded_filepath); + pm_source_t *src = file_options(argc, argv, options, &encoded_filepath); - VALUE value = parse_input(&input, &options); - pm_string_free(&input); - pm_options_free(&options); + VALUE value = parse_input(pm_source_source(src), pm_source_length(src), options); + pm_source_free(src); + pm_options_free(options); return value; } @@ -968,14 +1006,13 @@ parse_file(int argc, VALUE *argv, VALUE self) { * Parse the given input and return nothing. */ static void -profile_input(pm_string_t *input, const pm_options_t *options) { - pm_arena_t arena = { 0 }; - pm_parser_t parser; - pm_parser_init(&arena, &parser, pm_string_source(input), pm_string_length(input), options); - - pm_parse(&parser); - pm_parser_free(&parser); - pm_arena_free(&arena); +profile_input(const uint8_t *input, size_t input_length, const pm_options_t *options) { + pm_arena_t *arena = pm_arena_new(); + pm_parser_t *parser = pm_parser_new(arena, input, input_length, options); + + pm_parse(parser); + pm_parser_free(parser); + pm_arena_free(arena); } /** @@ -989,13 +1026,11 @@ profile_input(pm_string_t *input, const pm_options_t *options) { */ static VALUE profile(int argc, VALUE *argv, VALUE self) { - pm_string_t input; - pm_options_t options = { 0 }; + pm_options_t *options = pm_options_new(); + VALUE string = string_options(argc, argv, options); - string_options(argc, argv, &input, &options); - profile_input(&input, &options); - pm_string_free(&input); - pm_options_free(&options); + profile_input((const uint8_t *) RSTRING_PTR(string), RSTRING_LEN(string), options); + pm_options_free(options); return Qnil; } @@ -1011,15 +1046,14 @@ profile(int argc, VALUE *argv, VALUE self) { */ static VALUE profile_file(int argc, VALUE *argv, VALUE self) { - pm_string_t input; - pm_options_t options = { 0 }; + pm_options_t *options = pm_options_new(); VALUE encoded_filepath; - file_options(argc, argv, &input, &options, &encoded_filepath); + pm_source_t *src = file_options(argc, argv, options, &encoded_filepath); - profile_input(&input, &options); - pm_string_free(&input); - pm_options_free(&options); + profile_input(pm_source_source(src), pm_source_length(src), options); + pm_source_free(src); + pm_options_free(options); return Qnil; } @@ -1067,23 +1101,24 @@ parse_stream(int argc, VALUE *argv, VALUE self) { VALUE keywords; rb_scan_args(argc, argv, "1:", &stream, &keywords); - pm_options_t options = { 0 }; - extract_options(&options, Qnil, keywords); + pm_options_t *options = pm_options_new(); + extract_options(options, Qnil, keywords); - pm_arena_t arena = { 0 }; - pm_parser_t parser; - pm_buffer_t buffer; + pm_source_t *src = pm_source_stream_new((void *) stream, parse_stream_fgets, parse_stream_eof); + pm_arena_t *arena = pm_arena_new(); + pm_parser_t *parser; - pm_node_t *node = pm_parse_stream(&arena, &parser, &buffer, (void *) stream, parse_stream_fgets, parse_stream_eof, &options); - rb_encoding *encoding = rb_enc_find(parser.encoding->name); + pm_node_t *node = pm_parse_stream(&parser, arena, src, options); + rb_encoding *encoding = rb_enc_find(pm_parser_encoding_name(parser)); - VALUE source = pm_source_new(&parser, encoding, options.freeze); - VALUE value = pm_ast_new(&parser, node, encoding, source, options.freeze); - VALUE result = parse_result_create(rb_cPrismParseResult, &parser, value, encoding, source, options.freeze); + VALUE source = pm_source_new(parser, encoding, pm_options_freeze(options)); + VALUE value = pm_ast_new(parser, node, encoding, source, pm_options_freeze(options)); + VALUE result = parse_result_create(rb_cPrismParseResult, parser, value, encoding, source, pm_options_freeze(options)); - pm_buffer_free(&buffer); - pm_parser_free(&parser); - pm_arena_free(&arena); + pm_source_free(src); + pm_parser_free(parser); + pm_arena_free(arena); + pm_options_free(options); return result; } @@ -1092,19 +1127,18 @@ parse_stream(int argc, VALUE *argv, VALUE self) { * Parse the given input and return an array of Comment objects. */ static VALUE -parse_input_comments(pm_string_t *input, const pm_options_t *options) { - pm_arena_t arena = { 0 }; - pm_parser_t parser; - pm_parser_init(&arena, &parser, pm_string_source(input), pm_string_length(input), options); +parse_input_comments(const uint8_t *input, size_t input_length, const pm_options_t *options) { + pm_arena_t *arena = pm_arena_new(); + pm_parser_t *parser = pm_parser_new(arena, input, input_length, options); - pm_parse(&parser); - rb_encoding *encoding = rb_enc_find(parser.encoding->name); + pm_parse(parser); + rb_encoding *encoding = rb_enc_find(pm_parser_encoding_name(parser)); - VALUE source = pm_source_new(&parser, encoding, options->freeze); - VALUE comments = parser_comments(&parser, source, options->freeze); + VALUE source = pm_source_new(parser, encoding, pm_options_freeze(options)); + VALUE comments = parser_comments(parser, source, pm_options_freeze(options)); - pm_parser_free(&parser); - pm_arena_free(&arena); + pm_parser_free(parser); + pm_arena_free(arena); return comments; } @@ -1119,13 +1153,11 @@ parse_input_comments(pm_string_t *input, const pm_options_t *options) { */ static VALUE parse_comments(int argc, VALUE *argv, VALUE self) { - pm_string_t input; - pm_options_t options = { 0 }; - string_options(argc, argv, &input, &options); + pm_options_t *options = pm_options_new(); + VALUE string = string_options(argc, argv, options); - VALUE result = parse_input_comments(&input, &options); - pm_string_free(&input); - pm_options_free(&options); + VALUE result = parse_input_comments((const uint8_t *) RSTRING_PTR(string), RSTRING_LEN(string), options); + pm_options_free(options); return result; } @@ -1140,15 +1172,14 @@ parse_comments(int argc, VALUE *argv, VALUE self) { */ static VALUE parse_file_comments(int argc, VALUE *argv, VALUE self) { - pm_string_t input; - pm_options_t options = { 0 }; + pm_options_t *options = pm_options_new(); VALUE encoded_filepath; - file_options(argc, argv, &input, &options, &encoded_filepath); + pm_source_t *src = file_options(argc, argv, options, &encoded_filepath); - VALUE value = parse_input_comments(&input, &options); - pm_string_free(&input); - pm_options_free(&options); + VALUE value = parse_input_comments(pm_source_source(src), pm_source_length(src), options); + pm_source_free(src); + pm_options_free(options); return value; } @@ -1170,13 +1201,11 @@ parse_file_comments(int argc, VALUE *argv, VALUE self) { */ static VALUE parse_lex(int argc, VALUE *argv, VALUE self) { - pm_string_t input; - pm_options_t options = { 0 }; - string_options(argc, argv, &input, &options); + pm_options_t *options = pm_options_new(); + VALUE string = string_options(argc, argv, options); - VALUE value = parse_lex_input(&input, &options, true); - pm_string_free(&input); - pm_options_free(&options); + VALUE value = parse_lex_input((const uint8_t *) RSTRING_PTR(string), RSTRING_LEN(string), options, true); + pm_options_free(options); return value; } @@ -1198,15 +1227,14 @@ parse_lex(int argc, VALUE *argv, VALUE self) { */ static VALUE parse_lex_file(int argc, VALUE *argv, VALUE self) { - pm_string_t input; - pm_options_t options = { 0 }; + pm_options_t *options = pm_options_new(); VALUE encoded_filepath; - file_options(argc, argv, &input, &options, &encoded_filepath); + pm_source_t *src = file_options(argc, argv, options, &encoded_filepath); - VALUE value = parse_lex_input(&input, &options, true); - pm_string_free(&input); - pm_options_free(&options); + VALUE value = parse_lex_input(pm_source_source(src), pm_source_length(src), options, true); + pm_source_free(src); + pm_options_free(options); return value; } @@ -1215,16 +1243,15 @@ parse_lex_file(int argc, VALUE *argv, VALUE self) { * Parse the given input and return true if it parses without errors. */ static VALUE -parse_input_success_p(pm_string_t *input, const pm_options_t *options) { - pm_arena_t arena = { 0 }; - pm_parser_t parser; - pm_parser_init(&arena, &parser, pm_string_source(input), pm_string_length(input), options); +parse_input_success_p(const uint8_t *input, size_t input_length, const pm_options_t *options) { + pm_arena_t *arena = pm_arena_new(); + pm_parser_t *parser = pm_parser_new(arena, input, input_length, options); - pm_parse(&parser); + pm_parse(parser); - VALUE result = parser.error_list.size == 0 ? Qtrue : Qfalse; - pm_parser_free(&parser); - pm_arena_free(&arena); + VALUE result = pm_parser_errors_size(parser) == 0 ? Qtrue : Qfalse; + pm_parser_free(parser); + pm_arena_free(arena); return result; } @@ -1239,13 +1266,11 @@ parse_input_success_p(pm_string_t *input, const pm_options_t *options) { */ static VALUE parse_success_p(int argc, VALUE *argv, VALUE self) { - pm_string_t input; - pm_options_t options = { 0 }; - string_options(argc, argv, &input, &options); + pm_options_t *options = pm_options_new(); + VALUE string = string_options(argc, argv, options); - VALUE result = parse_input_success_p(&input, &options); - pm_string_free(&input); - pm_options_free(&options); + VALUE result = parse_input_success_p((const uint8_t *) RSTRING_PTR(string), RSTRING_LEN(string), options); + pm_options_free(options); return result; } @@ -1273,15 +1298,14 @@ parse_failure_p(int argc, VALUE *argv, VALUE self) { */ static VALUE parse_file_success_p(int argc, VALUE *argv, VALUE self) { - pm_string_t input; - pm_options_t options = { 0 }; + pm_options_t *options = pm_options_new(); VALUE encoded_filepath; - file_options(argc, argv, &input, &options, &encoded_filepath); + pm_source_t *src = file_options(argc, argv, options, &encoded_filepath); - VALUE result = parse_input_success_p(&input, &options); - pm_string_free(&input); - pm_options_free(&options); + VALUE result = parse_input_success_p(pm_source_source(src), pm_source_length(src), options); + pm_source_free(src); + pm_options_free(options); return result; } diff --git a/prism/util/pm_integer.c b/prism/integer.c similarity index 98% rename from prism/util/pm_integer.c rename to prism/integer.c index 2b77a4b5d2f9d4..1b69dbdcebd291 100644 --- a/prism/util/pm_integer.c +++ b/prism/integer.c @@ -1,4 +1,25 @@ -#include "prism/util/pm_integer.h" +#include "prism/internal/integer.h" + +#include "prism/internal/allocator.h" +#include "prism/internal/buffer.h" + +#include +#include +#include +#include +#include +#include + +/** + * Free the internal memory of an integer. This memory will only be allocated if + * the integer exceeds the size of a single uint32_t. + */ +static void +pm_integer_free(pm_integer_t *integer) { + if (integer->values) { + xfree(integer->values); + } +} /** * Pull out the length and values from the integer, regardless of the form in @@ -604,7 +625,7 @@ void pm_integers_reduce(pm_integer_t *numerator, pm_integer_t *denominator) { /** * Convert an integer to a decimal string. */ -PRISM_EXPORTED_FUNCTION void +void pm_integer_string(pm_buffer_t *buffer, const pm_integer_t *integer) { if (integer->negative) { pm_buffer_append_byte(buffer, '-'); @@ -658,14 +679,3 @@ pm_integer_string(pm_buffer_t *buffer, const pm_integer_t *integer) { xfree_sized(digits, sizeof(char) * digits_length); pm_integer_free(&converted); } - -/** - * Free the internal memory of an integer. This memory will only be allocated if - * the integer exceeds the size of a single uint32_t. - */ -PRISM_EXPORTED_FUNCTION void -pm_integer_free(pm_integer_t *integer) { - if (integer->values) { - xfree(integer->values); - } -} diff --git a/prism/integer.h b/prism/integer.h new file mode 100644 index 00000000000000..92859868852ed7 --- /dev/null +++ b/prism/integer.h @@ -0,0 +1,41 @@ +/** + * @file integer.h + * + * This module provides functions for working with arbitrary-sized integers. + */ +#ifndef PRISM_INTEGER_H +#define PRISM_INTEGER_H + +#include +#include +#include + +/** + * A structure represents an arbitrary-sized integer. + */ +typedef struct { + /** + * The number of allocated values. length is set to 0 if the integer fits + * into uint32_t. + */ + size_t length; + + /** + * List of 32-bit integers. Set to NULL if the integer fits into uint32_t. + */ + uint32_t *values; + + /** + * Embedded value for small integer. This value is set to 0 if the value + * does not fit into uint32_t. + */ + uint32_t value; + + /** + * Whether or not the integer is negative. It is stored this way so that a + * zeroed pm_integer_t is always positive zero. + */ + bool negative; +} pm_integer_t; + +#endif diff --git a/prism/internal/allocator.h b/prism/internal/allocator.h new file mode 100644 index 00000000000000..6c54010dbf5042 --- /dev/null +++ b/prism/internal/allocator.h @@ -0,0 +1,68 @@ +#ifndef PRISM_INTERNAL_ALLOCATOR_H +#define PRISM_INTERNAL_ALLOCATOR_H + +/* If you build Prism with a custom allocator, configure it with + * "-D PRISM_XALLOCATOR" to use your own allocator that defines xmalloc, + * xrealloc, xcalloc, and xfree. + * + * For example, your `prism_xallocator.h` file could look like this: + * + * ``` + * #ifndef PRISM_XALLOCATOR_H + * #define PRISM_XALLOCATOR_H + * #define xmalloc my_malloc + * #define xrealloc my_realloc + * #define xcalloc my_calloc + * #define xfree my_free + * #define xrealloc_sized my_realloc_sized // (optional) + * #define xfree_sized my_free_sized // (optional) + * #endif + * ``` + */ +#ifdef PRISM_XALLOCATOR + #include "prism_xallocator.h" +#else + #ifndef xmalloc + /* The malloc function that should be used. This can be overridden with + * the PRISM_XALLOCATOR define. */ + #define xmalloc malloc + #endif + + #ifndef xrealloc + /* The realloc function that should be used. This can be overridden with + * the PRISM_XALLOCATOR define. */ + #define xrealloc realloc + #endif + + #ifndef xcalloc + /* The calloc function that should be used. This can be overridden with + * the PRISM_XALLOCATOR define. */ + #define xcalloc calloc + #endif + + #ifndef xfree + /* The free function that should be used. This can be overridden with + * the PRISM_XALLOCATOR define. */ + #define xfree free + #endif +#endif + +#ifndef xfree_sized + /* The free_sized function that should be used. This can be overridden with + * the PRISM_XALLOCATOR define. If not defined, defaults to calling xfree. + */ + #define xfree_sized(p, s) xfree(((void)(s), (p))) +#endif + +#ifndef xrealloc_sized + /* The xrealloc_sized function that should be used. This can be overridden + * with the PRISM_XALLOCATOR define. If not defined, defaults to calling + * xrealloc. */ + #define xrealloc_sized(p, ns, os) xrealloc((p), ((void)(os), (ns))) +#endif + +#ifdef PRISM_BUILD_DEBUG + #include "prism/internal/allocator_debug.h" +#endif + +#endif diff --git a/prism/debug_allocator.h b/prism/internal/allocator_debug.h similarity index 62% rename from prism/debug_allocator.h rename to prism/internal/allocator_debug.h index 3e28a95efbcae7..846e96ba2da5ee 100644 --- a/prism/debug_allocator.h +++ b/prism/internal/allocator_debug.h @@ -1,37 +1,29 @@ -/** - * @file debug_allocator.h - * - * Decorate allocation function to ensure sizes are correct. - */ -#ifndef PRISM_DEBUG_ALLOCATOR_H -#define PRISM_DEBUG_ALLOCATOR_H +#ifndef PRISM_INTERNAL_ALLOCATOR_DEBUG_H +#define PRISM_INTERNAL_ALLOCATOR_DEBUG_H #include #include #include static inline void * -pm_debug_malloc(size_t size) -{ +pm_allocator_debug_malloc(size_t size) { size_t *memory = xmalloc(size + sizeof(size_t)); memory[0] = size; return memory + 1; } static inline void * -pm_debug_calloc(size_t nmemb, size_t size) -{ +pm_allocator_debug_calloc(size_t nmemb, size_t size) { size_t total_size = nmemb * size; - void *ptr = pm_debug_malloc(total_size); + void *ptr = pm_allocator_debug_malloc(total_size); memset(ptr, 0, total_size); return ptr; } static inline void * -pm_debug_realloc(void *ptr, size_t size) -{ +pm_allocator_debug_realloc(void *ptr, size_t size) { if (ptr == NULL) { - return pm_debug_malloc(size); + return pm_allocator_debug_malloc(size); } size_t *memory = (size_t *)ptr; @@ -42,8 +34,7 @@ pm_debug_realloc(void *ptr, size_t size) } static inline void -pm_debug_free(void *ptr) -{ +pm_allocator_debug_free(void *ptr) { if (ptr != NULL) { size_t *memory = (size_t *)ptr; xfree(memory - 1); @@ -51,8 +42,7 @@ pm_debug_free(void *ptr) } static inline void -pm_debug_free_sized(void *ptr, size_t old_size) -{ +pm_allocator_debug_free_sized(void *ptr, size_t old_size) { if (ptr != NULL) { size_t *memory = (size_t *)ptr; if (old_size != memory[-1]) { @@ -64,14 +54,13 @@ pm_debug_free_sized(void *ptr, size_t old_size) } static inline void * -pm_debug_realloc_sized(void *ptr, size_t size, size_t old_size) -{ +pm_allocator_debug_realloc_sized(void *ptr, size_t size, size_t old_size) { if (ptr == NULL) { if (old_size != 0) { fprintf(stderr, "[BUG] realloc_sized called with NULL pointer and old size %lu\n", old_size); abort(); } - return pm_debug_malloc(size); + return pm_allocator_debug_malloc(size); } size_t *memory = (size_t *)ptr; @@ -79,7 +68,7 @@ pm_debug_realloc_sized(void *ptr, size_t size, size_t old_size) fprintf(stderr, "[BUG] buffer %p was allocated with size %lu but realloced with size %lu\n", ptr, memory[-1], old_size); abort(); } - return pm_debug_realloc(ptr, size); + return pm_allocator_debug_realloc(ptr, size); } #undef xmalloc @@ -89,11 +78,11 @@ pm_debug_realloc_sized(void *ptr, size_t size, size_t old_size) #undef xrealloc_sized #undef xfree_sized -#define xmalloc pm_debug_malloc -#define xrealloc pm_debug_realloc -#define xcalloc pm_debug_calloc -#define xfree pm_debug_free -#define xrealloc_sized pm_debug_realloc_sized -#define xfree_sized pm_debug_free_sized +#define xmalloc pm_allocator_debug_malloc +#define xrealloc pm_allocator_debug_realloc +#define xcalloc pm_allocator_debug_calloc +#define xfree pm_allocator_debug_free +#define xrealloc_sized pm_allocator_debug_realloc_sized +#define xfree_sized pm_allocator_debug_free_sized #endif diff --git a/prism/util/pm_arena.h b/prism/internal/arena.h similarity index 61% rename from prism/util/pm_arena.h rename to prism/internal/arena.h index 175b39c6df650a..2e413b42bffaf0 100644 --- a/prism/util/pm_arena.h +++ b/prism/internal/arena.h @@ -1,80 +1,72 @@ -/** - * @file pm_arena.h - * - * A bump allocator for the prism parser. - */ -#ifndef PRISM_ARENA_H -#define PRISM_ARENA_H +#ifndef PRISM_INTERNAL_ARENA_H +#define PRISM_INTERNAL_ARENA_H + +#include "prism/compiler/exported.h" +#include "prism/compiler/flex_array.h" +#include "prism/compiler/force_inline.h" +#include "prism/compiler/inline.h" -#include "prism/defines.h" +#include "prism/arena.h" #include -#include -#include #include -/** +/* * A single block of memory in the arena. Blocks are linked via prev pointers so * they can be freed by walking the chain. */ typedef struct pm_arena_block { - /** The previous block in the chain (for freeing). */ + /* The previous block in the chain (for freeing). */ struct pm_arena_block *prev; - /** The total usable bytes in data[]. */ + /* The total usable bytes in data[]. */ size_t capacity; - /** The number of bytes consumed so far. */ + /* The number of bytes consumed so far. */ size_t used; - /** The block's data. */ - char data[PM_FLEX_ARY_LEN]; + /* The block's data. */ + char data[PM_FLEX_ARRAY_LENGTH]; } pm_arena_block_t; -/** +/* * A bump allocator. Allocations are made by bumping a pointer within the * current block. When a block is full, a new block is allocated and linked to * the previous one. All blocks are freed at once by walking the chain. */ -typedef struct { - /** The active block (allocate from here). */ +struct pm_arena_t { + /* The active block (allocate from here). */ pm_arena_block_t *current; - /** The number of blocks allocated. */ + /* The number of blocks allocated. */ size_t block_count; -} pm_arena_t; +}; -/** +/* + * Free all blocks in the arena. After this call, all pointers returned by + * pm_arena_alloc and pm_arena_zalloc are invalid. + */ +void pm_arena_cleanup(pm_arena_t *arena); + +/* * Ensure the arena has at least `capacity` bytes available in its current * block, allocating a new block if necessary. This allows callers to * pre-size the arena to avoid repeated small block allocations. - * - * @param arena The arena to pre-size. - * @param capacity The minimum number of bytes to ensure are available. */ void pm_arena_reserve(pm_arena_t *arena, size_t capacity); -/** +/* * Slow path for pm_arena_alloc: allocate a new block and return a pointer to * the first `size` bytes. Do not call directly — use pm_arena_alloc instead. - * - * @param arena The arena to allocate from. - * @param size The number of bytes to allocate. - * @returns A pointer to the allocated memory. */ void * pm_arena_alloc_slow(pm_arena_t *arena, size_t size); -/** +/* * Allocate memory from the arena. The returned memory is NOT zeroed. This * function is infallible — it aborts on allocation failure. * * The fast path (bump pointer within the current block) is inlined at each * call site. The slow path (new block allocation) is out-of-line. - * - * @param arena The arena to allocate from. - * @param size The number of bytes to allocate. - * @param alignment The required alignment (must be a power of 2). - * @returns A pointer to the allocated memory. */ static PRISM_FORCE_INLINE void * pm_arena_alloc(pm_arena_t *arena, size_t size, size_t alignment) { @@ -91,45 +83,26 @@ pm_arena_alloc(pm_arena_t *arena, size_t size, size_t alignment) { return pm_arena_alloc_slow(arena, size); } -/** +/* * Allocate zero-initialized memory from the arena. This function is infallible * — it aborts on allocation failure. - * - * @param arena The arena to allocate from. - * @param size The number of bytes to allocate. - * @param alignment The required alignment (must be a power of 2). - * @returns A pointer to the allocated, zero-initialized memory. */ -static inline void * +static PRISM_INLINE void * pm_arena_zalloc(pm_arena_t *arena, size_t size, size_t alignment) { void *ptr = pm_arena_alloc(arena, size, alignment); memset(ptr, 0, size); return ptr; } -/** +/* * Allocate memory from the arena and copy the given data into it. This is a * convenience wrapper around pm_arena_alloc + memcpy. - * - * @param arena The arena to allocate from. - * @param src The source data to copy. - * @param size The number of bytes to allocate and copy. - * @param alignment The required alignment (must be a power of 2). - * @returns A pointer to the allocated copy. */ -static inline void * +static PRISM_INLINE void * pm_arena_memdup(pm_arena_t *arena, const void *src, size_t size, size_t alignment) { void *dst = pm_arena_alloc(arena, size, alignment); memcpy(dst, src, size); return dst; } -/** - * Free all blocks in the arena. After this call, all pointers returned by - * pm_arena_alloc and pm_arena_zalloc are invalid. - * - * @param arena The arena to free. - */ -PRISM_EXPORTED_FUNCTION void pm_arena_free(pm_arena_t *arena); - #endif diff --git a/prism/internal/bit.h b/prism/internal/bit.h new file mode 100644 index 00000000000000..b0111a4c2c0d59 --- /dev/null +++ b/prism/internal/bit.h @@ -0,0 +1,42 @@ +#ifndef PRISM_INTERNAL_BIT_H +#define PRISM_INTERNAL_BIT_H + +#include "prism/compiler/inline.h" + +/* + * Count trailing zero bits in a 64-bit value. Used by SWAR identifier scanning + * to find the first non-matching byte in a word. + * + * Precondition: v must be nonzero. The result is undefined when v == 0 + * (matching the behavior of __builtin_ctzll and _BitScanForward64). + */ +#if defined(__GNUC__) || defined(__clang__) +#define pm_ctzll(v) ((unsigned) __builtin_ctzll(v)) +#elif defined(_MSC_VER) +#include +#include + +static PRISM_INLINE unsigned +pm_ctzll(uint64_t v) { + unsigned long index; + _BitScanForward64(&index, v); + return (unsigned) index; +} +#else +#include + +static PRISM_INLINE unsigned +pm_ctzll(uint64_t v) { + unsigned c = 0; + v &= (uint64_t) (-(int64_t) v); + if (v & 0x00000000FFFFFFFFULL) c += 0; else c += 32; + if (v & 0x0000FFFF0000FFFFULL) c += 0; else c += 16; + if (v & 0x00FF00FF00FF00FFULL) c += 0; else c += 8; + if (v & 0x0F0F0F0F0F0F0F0FULL) c += 0; else c += 4; + if (v & 0x3333333333333333ULL) c += 0; else c += 2; + if (v & 0x5555555555555555ULL) c += 0; else c += 1; + return c; +} +#endif + +#endif diff --git a/prism/internal/buffer.h b/prism/internal/buffer.h new file mode 100644 index 00000000000000..a849bbf8e65256 --- /dev/null +++ b/prism/internal/buffer.h @@ -0,0 +1,91 @@ +#ifndef PRISM_INTERNAL_BUFFER_H +#define PRISM_INTERNAL_BUFFER_H + +#include "prism/compiler/format.h" + +#include "prism/buffer.h" + +#include +#include + +/* + * A simple memory buffer that stores data in a contiguous block of memory. + */ +struct pm_buffer_t { + /* The length of the buffer in bytes. */ + size_t length; + + /* The capacity of the buffer in bytes that has been allocated. */ + size_t capacity; + + /* A pointer to the start of the buffer. */ + char *value; +}; + +/* Initialize a pm_buffer_t with the given capacity. */ +void pm_buffer_init(pm_buffer_t *buffer, size_t capacity); + +/* Free the memory held by the buffer. */ +void pm_buffer_cleanup(pm_buffer_t *buffer); + +/* Append the given amount of space as zeroes to the buffer. */ +void pm_buffer_append_zeroes(pm_buffer_t *buffer, size_t length); + +/* Append a formatted string to the buffer. */ +void pm_buffer_append_format(pm_buffer_t *buffer, const char *format, ...) PRISM_ATTRIBUTE_FORMAT(2, 3); + +/* Append a string to the buffer. */ +void pm_buffer_append_string(pm_buffer_t *buffer, const char *value, size_t length); + +/* Append a list of bytes to the buffer. */ +void pm_buffer_append_bytes(pm_buffer_t *buffer, const uint8_t *value, size_t length); + +/* Append a single byte to the buffer. */ +void pm_buffer_append_byte(pm_buffer_t *buffer, uint8_t value); + +/* Append a 32-bit unsigned integer to the buffer as a variable-length integer. */ +void pm_buffer_append_varuint(pm_buffer_t *buffer, uint32_t value); + +/* Append a 32-bit signed integer to the buffer as a variable-length integer. */ +void pm_buffer_append_varsint(pm_buffer_t *buffer, int32_t value); + +/* Append a double to the buffer. */ +void pm_buffer_append_double(pm_buffer_t *buffer, double value); + +/* Append a unicode codepoint to the buffer. */ +bool pm_buffer_append_unicode_codepoint(pm_buffer_t *buffer, uint32_t value); + +/* + * The different types of escaping that can be performed by the buffer when + * appending a slice of Ruby source code. + */ +typedef enum { + PM_BUFFER_ESCAPING_RUBY, + PM_BUFFER_ESCAPING_JSON +} pm_buffer_escaping_t; + +/* Append a slice of source code to the buffer. */ +void pm_buffer_append_source(pm_buffer_t *buffer, const uint8_t *source, size_t length, pm_buffer_escaping_t escaping); + +/* Prepend the given string to the buffer. */ +void pm_buffer_prepend_string(pm_buffer_t *buffer, const char *value, size_t length); + +/* Concatenate one buffer onto another. */ +void pm_buffer_concat(pm_buffer_t *destination, const pm_buffer_t *source); + +/* + * Clear the buffer by reducing its size to 0. This does not free the allocated + * memory, but it does allow the buffer to be reused. + */ +void pm_buffer_clear(pm_buffer_t *buffer); + +/* Strip the whitespace from the end of the buffer. */ +void pm_buffer_rstrip(pm_buffer_t *buffer); + +/* Checks if the buffer includes the given value. */ +size_t pm_buffer_index(const pm_buffer_t *buffer, char value); + +/* Insert the given string into the buffer at the given index. */ +void pm_buffer_insert(pm_buffer_t *buffer, size_t index, const char *value, size_t length); + +#endif diff --git a/prism/util/pm_char.h b/prism/internal/char.h similarity index 51% rename from prism/util/pm_char.h rename to prism/internal/char.h index 516390b21c03d4..9a58fba8c5b7e7 100644 --- a/prism/util/pm_char.h +++ b/prism/internal/char.h @@ -1,59 +1,42 @@ -/** - * @file pm_char.h - * - * Functions for working with characters and strings. - */ -#ifndef PRISM_CHAR_H -#define PRISM_CHAR_H +#ifndef PRISM_INTERNAL_CHAR_H +#define PRISM_INTERNAL_CHAR_H -#include "prism/defines.h" -#include "prism/util/pm_line_offset_list.h" +#include "prism/compiler/force_inline.h" + +#include "prism/arena.h" +#include "prism/line_offset_list.h" #include #include +#include -/** Bit flag for whitespace characters in pm_byte_table. */ +/* Bit flag for whitespace characters in pm_byte_table. */ #define PRISM_CHAR_BIT_WHITESPACE (1 << 0) -/** Bit flag for inline whitespace characters in pm_byte_table. */ +/* Bit flag for inline whitespace characters in pm_byte_table. */ #define PRISM_CHAR_BIT_INLINE_WHITESPACE (1 << 1) -/** +/* * A lookup table for classifying bytes. Each entry is a bitfield of - * PRISM_CHAR_BIT_* flags. Defined in pm_char.c. + * PRISM_CHAR_BIT_* flags. Defined in char.c. */ extern const uint8_t pm_byte_table[256]; -/** - * Returns true if the given character is a whitespace character. - * - * @param b The character to check. - * @return True if the given character is a whitespace character. - */ +/* Returns true if the given character is a whitespace character. */ static PRISM_FORCE_INLINE bool pm_char_is_whitespace(const uint8_t b) { return (pm_byte_table[b] & PRISM_CHAR_BIT_WHITESPACE) != 0; } -/** - * Returns true if the given character is an inline whitespace character. - * - * @param b The character to check. - * @return True if the given character is an inline whitespace character. - */ +/* Returns true if the given character is an inline whitespace character. */ static PRISM_FORCE_INLINE bool pm_char_is_inline_whitespace(const uint8_t b) { return (pm_byte_table[b] & PRISM_CHAR_BIT_INLINE_WHITESPACE) != 0; } -/** +/* * Returns the number of characters at the start of the string that are inline * whitespace (space/tab). Scans the byte table directly for use in hot paths. - * - * @param string The string to search. - * @param length The maximum number of characters to search. - * @return The number of characters at the start of the string that are inline - * whitespace. */ static PRISM_FORCE_INLINE size_t pm_strspn_inline_whitespace(const uint8_t *string, ptrdiff_t length) { @@ -64,57 +47,33 @@ pm_strspn_inline_whitespace(const uint8_t *string, ptrdiff_t length) { return size; } -/** +/* * Returns the number of characters at the start of the string that are * whitespace. Disallows searching past the given maximum number of characters. - * - * @param string The string to search. - * @param length The maximum number of characters to search. - * @return The number of characters at the start of the string that are - * whitespace. */ size_t pm_strspn_whitespace(const uint8_t *string, ptrdiff_t length); -/** +/* * Returns the number of characters at the start of the string that are * whitespace while also tracking the location of each newline. Disallows * searching past the given maximum number of characters. - * - * @param string The string to search. - * @param length The maximum number of characters to search. - * @param arena The arena to allocate from when appending to line_offsets. - * @param line_offsets The list of newlines to populate. - * @param start_offset The offset at which the string occurs in the source, for - * the purpose of tracking newlines. - * @return The number of characters at the start of the string that are - * whitespace. */ size_t pm_strspn_whitespace_newlines(const uint8_t *string, ptrdiff_t length, pm_arena_t *arena, pm_line_offset_list_t *line_offsets, uint32_t start_offset); -/** +/* * Returns the number of characters at the start of the string that are decimal * digits. Disallows searching past the given maximum number of characters. - * - * @param string The string to search. - * @param length The maximum number of characters to search. - * @return The number of characters at the start of the string that are decimal - * digits. */ size_t pm_strspn_decimal_digit(const uint8_t *string, ptrdiff_t length); -/** +/* * Returns the number of characters at the start of the string that are * hexadecimal digits. Disallows searching past the given maximum number of * characters. - * - * @param string The string to search. - * @param length The maximum number of characters to search. - * @return The number of characters at the start of the string that are - * hexadecimal digits. */ size_t pm_strspn_hexadecimal_digit(const uint8_t *string, ptrdiff_t length); -/** +/* * Returns the number of characters at the start of the string that are octal * digits or underscores. Disallows searching past the given maximum number of * characters. @@ -122,17 +81,10 @@ size_t pm_strspn_hexadecimal_digit(const uint8_t *string, ptrdiff_t length); * If multiple underscores are found in a row or if an underscore is * found at the end of the number, then the invalid pointer is set to the index * of the first invalid underscore. - * - * @param string The string to search. - * @param length The maximum number of characters to search. - * @param invalid The pointer to set to the index of the first invalid - * underscore. - * @return The number of characters at the start of the string that are octal - * digits or underscores. */ size_t pm_strspn_octal_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid); -/** +/* * Returns the number of characters at the start of the string that are decimal * digits or underscores. Disallows searching past the given maximum number of * characters. @@ -140,17 +92,10 @@ size_t pm_strspn_octal_number(const uint8_t *string, ptrdiff_t length, const uin * If multiple underscores are found in a row or if an underscore is * found at the end of the number, then the invalid pointer is set to the index * of the first invalid underscore. - * - * @param string The string to search. - * @param length The maximum number of characters to search. - * @param invalid The pointer to set to the index of the first invalid - * underscore. - * @return The number of characters at the start of the string that are decimal - * digits or underscores. */ size_t pm_strspn_decimal_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid); -/** +/* * Returns the number of characters at the start of the string that are * hexadecimal digits or underscores. Disallows searching past the given maximum * number of characters. @@ -158,28 +103,16 @@ size_t pm_strspn_decimal_number(const uint8_t *string, ptrdiff_t length, const u * If multiple underscores are found in a row or if an underscore is * found at the end of the number, then the invalid pointer is set to the index * of the first invalid underscore. - * - * @param string The string to search. - * @param length The maximum number of characters to search. - * @param invalid The pointer to set to the index of the first invalid - * underscore. - * @return The number of characters at the start of the string that are - * hexadecimal digits or underscores. */ size_t pm_strspn_hexadecimal_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid); -/** +/* * Returns the number of characters at the start of the string that are regexp * options. Disallows searching past the given maximum number of characters. - * - * @param string The string to search. - * @param length The maximum number of characters to search. - * @return The number of characters at the start of the string that are regexp - * options. */ size_t pm_strspn_regexp_option(const uint8_t *string, ptrdiff_t length); -/** +/* * Returns the number of characters at the start of the string that are binary * digits or underscores. Disallows searching past the given maximum number of * characters. @@ -187,47 +120,20 @@ size_t pm_strspn_regexp_option(const uint8_t *string, ptrdiff_t length); * If multiple underscores are found in a row or if an underscore is * found at the end of the number, then the invalid pointer is set to the index * of the first invalid underscore. - * - * @param string The string to search. - * @param length The maximum number of characters to search. - * @param invalid The pointer to set to the index of the first invalid - * underscore. - * @return The number of characters at the start of the string that are binary - * digits or underscores. */ size_t pm_strspn_binary_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid); -/** - * Returns true if the given character is a binary digit. - * - * @param b The character to check. - * @return True if the given character is a binary digit. - */ +/* Returns true if the given character is a binary digit. */ bool pm_char_is_binary_digit(const uint8_t b); -/** - * Returns true if the given character is an octal digit. - * - * @param b The character to check. - * @return True if the given character is an octal digit. - */ +/* Returns true if the given character is an octal digit. */ bool pm_char_is_octal_digit(const uint8_t b); -/** - * Returns true if the given character is a decimal digit. - * - * @param b The character to check. - * @return True if the given character is a decimal digit. - */ +/* Returns true if the given character is a decimal digit. */ bool pm_char_is_decimal_digit(const uint8_t b); -/** - * Returns true if the given character is a hexadecimal digit. - * - * @param b The character to check. - * @return True if the given character is a hexadecimal digit. - */ +/* Returns true if the given character is a hexadecimal digit. */ bool pm_char_is_hexadecimal_digit(const uint8_t b); #endif diff --git a/prism/internal/comments.h b/prism/internal/comments.h new file mode 100644 index 00000000000000..bb3039a6583e75 --- /dev/null +++ b/prism/internal/comments.h @@ -0,0 +1,20 @@ +#ifndef PRISM_INTERNAL_COMMENTS_H +#define PRISM_INTERNAL_COMMENTS_H + +#include "prism/comments.h" + +#include "prism/internal/list.h" + +/* A comment found while parsing. */ +struct pm_comment_t { + /* The embedded base node. */ + pm_list_node_t node; + + /* The location of the comment in the source. */ + pm_location_t location; + + /* The type of the comment. */ + pm_comment_type_t type; +}; + +#endif diff --git a/prism/internal/constant_pool.h b/prism/internal/constant_pool.h new file mode 100644 index 00000000000000..fa2be783f56390 --- /dev/null +++ b/prism/internal/constant_pool.h @@ -0,0 +1,117 @@ +#ifndef PRISM_INTERNAL_CONSTANT_POOL_H +#define PRISM_INTERNAL_CONSTANT_POOL_H + +#include "prism/constant_pool.h" + +#include "prism/arena.h" + +#include + +/* A constant in the pool which effectively stores a string. */ +struct pm_constant_t { + /* A pointer to the start of the string. */ + const uint8_t *start; + + /* The length of the string. */ + size_t length; +}; + +/* + * The type of bucket in the constant pool hash map. This determines how the + * bucket should be freed. + */ +typedef unsigned int pm_constant_pool_bucket_type_t; + +/* By default, each constant is a slice of the source. */ +static const pm_constant_pool_bucket_type_t PM_CONSTANT_POOL_BUCKET_DEFAULT = 0; + +/* An owned constant is one for which memory has been allocated. */ +static const pm_constant_pool_bucket_type_t PM_CONSTANT_POOL_BUCKET_OWNED = 1; + +/* A constant constant is known at compile time. */ +static const pm_constant_pool_bucket_type_t PM_CONSTANT_POOL_BUCKET_CONSTANT = 2; + +/* A bucket in the hash map. */ +typedef struct { + /* The incremental ID used for indexing back into the pool. */ + unsigned int id: 30; + + /* The type of the bucket, which determines how to free it. */ + pm_constant_pool_bucket_type_t type: 2; + + /* The hash of the bucket. */ + uint32_t hash; + + /* + * A pointer to the start of the string, stored directly in the bucket to + * avoid a pointer chase to the constants array during probing. + */ + const uint8_t *start; + + /* The length of the string. */ + size_t length; +} pm_constant_pool_bucket_t; + +/* The overall constant pool, which stores constants found while parsing. */ +struct pm_constant_pool_t { + /* The buckets in the hash map. */ + pm_constant_pool_bucket_t *buckets; + + /* The constants that are stored in the buckets. */ + pm_constant_t *constants; + + /* The number of buckets in the hash map. */ + uint32_t size; + + /* The number of buckets that have been allocated in the hash map. */ + uint32_t capacity; +}; + +/* + * When we allocate constants into the pool, we reserve 0 to mean that the slot + * is not yet filled. This constant is reused in other places to indicate the + * lack of a constant id. + */ +#define PM_CONSTANT_ID_UNSET 0 + +/* Initialize a list of constant ids with a given capacity. */ +void pm_constant_id_list_init_capacity(pm_arena_t *arena, pm_constant_id_list_t *list, size_t capacity); + +/* Insert a constant id into a list of constant ids at the specified index. */ +void pm_constant_id_list_insert(pm_constant_id_list_t *list, size_t index, pm_constant_id_t id); + +/* Checks if the current constant id list includes the given constant id. */ +bool pm_constant_id_list_includes(pm_constant_id_list_t *list, pm_constant_id_t id); + +/* Initialize a new constant pool with a given capacity. */ +void pm_constant_pool_init(pm_arena_t *arena, pm_constant_pool_t *pool, uint32_t capacity); + +/* Return a pointer to the constant indicated by the given constant id. */ +pm_constant_t * pm_constant_pool_id_to_constant(const pm_constant_pool_t *pool, pm_constant_id_t constant_id); + +/* + * Find a constant in a constant pool. Returns the id of the constant, or 0 if + * the constant is not found. + */ +pm_constant_id_t pm_constant_pool_find(const pm_constant_pool_t *pool, const uint8_t *start, size_t length); + +/* + * Insert a constant into a constant pool that is a slice of a source string. + * Returns the id of the constant, or 0 if any potential calls to resize fail. + */ +pm_constant_id_t pm_constant_pool_insert_shared(pm_arena_t *arena, pm_constant_pool_t *pool, const uint8_t *start, size_t length); + +/* + * Insert a constant into a constant pool from memory that is now owned by the + * constant pool. Returns the id of the constant, or 0 if any potential calls to + * resize fail. + */ +pm_constant_id_t pm_constant_pool_insert_owned(pm_arena_t *arena, pm_constant_pool_t *pool, uint8_t *start, size_t length); + +/* + * Insert a constant into a constant pool from memory that is constant. Returns + * the id of the constant, or 0 if any potential calls to resize fail. + */ +pm_constant_id_t pm_constant_pool_insert_constant(pm_arena_t *arena, pm_constant_pool_t *pool, const uint8_t *start, size_t length); + +#endif diff --git a/prism/encoding.h b/prism/internal/encoding.h similarity index 79% rename from prism/encoding.h rename to prism/internal/encoding.h index 5f7724821f5b31..62392ef970eab1 100644 --- a/prism/encoding.h +++ b/prism/internal/encoding.h @@ -1,128 +1,95 @@ -/** - * @file encoding.h - * - * The encoding interface and implementations used by the parser. - */ -#ifndef PRISM_ENCODING_H -#define PRISM_ENCODING_H - -#include "prism/defines.h" -#include "prism/util/pm_strncasecmp.h" +#ifndef PRISM_INTERNAL_ENCODING_H +#define PRISM_INTERNAL_ENCODING_H -#include #include #include #include -/** +/* * This struct defines the functions necessary to implement the encoding * interface so we can determine how many bytes the subsequent character takes. * Each callback should return the number of bytes, or 0 if the next bytes are * invalid for the encoding and type. */ typedef struct { - /** + /* * Return the number of bytes that the next character takes if it is valid * in the encoding. Does not read more than n bytes. It is assumed that n is * at least 1. */ size_t (*char_width)(const uint8_t *b, ptrdiff_t n); - /** + /* * Return the number of bytes that the next character takes if it is valid * in the encoding and is alphabetical. Does not read more than n bytes. It * is assumed that n is at least 1. */ size_t (*alpha_char)(const uint8_t *b, ptrdiff_t n); - /** + /* * Return the number of bytes that the next character takes if it is valid * in the encoding and is alphanumeric. Does not read more than n bytes. It * is assumed that n is at least 1. */ size_t (*alnum_char)(const uint8_t *b, ptrdiff_t n); - /** + /* * Return true if the next character is valid in the encoding and is an * uppercase character. Does not read more than n bytes. It is assumed that * n is at least 1. */ bool (*isupper_char)(const uint8_t *b, ptrdiff_t n); - /** + /* * The name of the encoding. This should correspond to a value that can be * passed to Encoding.find in Ruby. */ const char *name; - /** - * Return true if the encoding is a multibyte encoding. - */ + /* Return true if the encoding is a multibyte encoding. */ bool multibyte; } pm_encoding_t; -/** +/* * All of the lookup tables use the first bit of each embedded byte to indicate * whether the codepoint is alphabetical. */ #define PRISM_ENCODING_ALPHABETIC_BIT 1 << 0 -/** +/* * All of the lookup tables use the second bit of each embedded byte to indicate * whether the codepoint is alphanumeric. */ #define PRISM_ENCODING_ALPHANUMERIC_BIT 1 << 1 -/** +/* * All of the lookup tables use the third bit of each embedded byte to indicate * whether the codepoint is uppercase. */ #define PRISM_ENCODING_UPPERCASE_BIT 1 << 2 -/** - * Return the size of the next character in the UTF-8 encoding. - * - * @param b The bytes to read. - * @param n The number of bytes that can be read. - * @returns The number of bytes that the next character takes if it is valid in - * the encoding, or 0 if it is not. - */ +/* Return the size of the next character in the UTF-8 encoding. */ size_t pm_encoding_utf_8_char_width(const uint8_t *b, ptrdiff_t n); -/** +/* * Return the size of the next character in the UTF-8 encoding if it is an * alphabetical character. - * - * @param b The bytes to read. - * @param n The number of bytes that can be read. - * @returns The number of bytes that the next character takes if it is valid in - * the encoding, or 0 if it is not. */ size_t pm_encoding_utf_8_alpha_char(const uint8_t *b, ptrdiff_t n); -/** +/* * Return the size of the next character in the UTF-8 encoding if it is an * alphanumeric character. - * - * @param b The bytes to read. - * @param n The number of bytes that can be read. - * @returns The number of bytes that the next character takes if it is valid in - * the encoding, or 0 if it is not. */ size_t pm_encoding_utf_8_alnum_char(const uint8_t *b, ptrdiff_t n); -/** +/* * Return true if the next character in the UTF-8 encoding if it is an uppercase * character. - * - * @param b The bytes to read. - * @param n The number of bytes that can be read. - * @returns True if the next character is valid in the encoding and is an - * uppercase character, or false if it is not. */ bool pm_encoding_utf_8_isupper_char(const uint8_t *b, ptrdiff_t n); -/** +/* * This lookup table is referenced in both the UTF-8 encoding file and the * parser directly in order to speed up the default encoding processing. It is * used to indicate whether a character is alphabetical, alphanumeric, or @@ -130,9 +97,7 @@ bool pm_encoding_utf_8_isupper_char(const uint8_t *b, ptrdiff_t n); */ extern const uint8_t pm_encoding_unicode_table[256]; -/** - * These are all of the encodings that prism supports. - */ +/* These are all of the encodings that prism supports. */ typedef enum { PM_ENCODING_UTF_8 = 0, PM_ENCODING_US_ASCII, @@ -140,8 +105,8 @@ typedef enum { PM_ENCODING_EUC_JP, PM_ENCODING_WINDOWS_31J, -// We optionally support excluding the full set of encodings to only support the -// minimum necessary to process Ruby code without encoding comments. +/* We optionally support excluding the full set of encodings to only support the + * minimum necessary to process Ruby code without encoding comments. */ #ifndef PRISM_ENCODING_EXCLUDE_FULL PM_ENCODING_BIG5, PM_ENCODING_BIG5_HKSCS, @@ -233,50 +198,44 @@ typedef enum { PM_ENCODING_MAXIMUM } pm_encoding_type_t; -/** - * This is the table of all of the encodings that prism supports. - */ +/* This is the table of all of the encodings that prism supports. */ extern const pm_encoding_t pm_encodings[PM_ENCODING_MAXIMUM]; -/** +/* * This is the default UTF-8 encoding. We need a reference to it to quickly * create parsers. */ #define PM_ENCODING_UTF_8_ENTRY (&pm_encodings[PM_ENCODING_UTF_8]) -/** +/* * This is the US-ASCII encoding. We need a reference to it to be able to * compare against it when a string is being created because it could possibly * need to fall back to ASCII-8BIT. */ #define PM_ENCODING_US_ASCII_ENTRY (&pm_encodings[PM_ENCODING_US_ASCII]) -/** +/* * This is the ASCII-8BIT encoding. We need a reference to it so that pm_strpbrk * can compare against it because invalid multibyte characters are not a thing * in this encoding. It is also needed for handling Regexp encoding flags. */ #define PM_ENCODING_ASCII_8BIT_ENTRY (&pm_encodings[PM_ENCODING_ASCII_8BIT]) -/** +/* * This is the EUC-JP encoding. We need a reference to it to quickly process * regular expression modifiers. */ #define PM_ENCODING_EUC_JP_ENTRY (&pm_encodings[PM_ENCODING_EUC_JP]) -/** +/* * This is the Windows-31J encoding. We need a reference to it to quickly * process regular expression modifiers. */ #define PM_ENCODING_WINDOWS_31J_ENTRY (&pm_encodings[PM_ENCODING_WINDOWS_31J]) -/** +/* * Parse the given name of an encoding and return a pointer to the corresponding * encoding struct if one can be found, otherwise return NULL. - * - * @param start A pointer to the first byte of the name. - * @param end A pointer to the last byte of the name. - * @returns A pointer to the encoding struct if one is found, otherwise NULL. */ const pm_encoding_t * pm_encoding_find(const uint8_t *start, const uint8_t *end); diff --git a/prism/internal/integer.h b/prism/internal/integer.h new file mode 100644 index 00000000000000..7c9767e323bd8a --- /dev/null +++ b/prism/internal/integer.h @@ -0,0 +1,68 @@ +/* + * This module provides functions for working with arbitrary-sized integers. + */ +#ifndef PRISM_INTERNAL_INTEGER_H +#define PRISM_INTERNAL_INTEGER_H + +#include "prism/buffer.h" +#include "prism/integer.h" + +#include + +/* + * An enum controlling the base of an integer. It is expected that the base is + * already known before parsing the integer, even though it could be derived + * from the string itself. + */ +typedef enum { + /* The default decimal base, with no prefix. Leading 0s will be ignored. */ + PM_INTEGER_BASE_DEFAULT, + + /* The binary base, indicated by a 0b or 0B prefix. */ + PM_INTEGER_BASE_BINARY, + + /* The octal base, indicated by a 0, 0o, or 0O prefix. */ + PM_INTEGER_BASE_OCTAL, + + /* The decimal base, indicated by a 0d, 0D, or empty prefix. */ + PM_INTEGER_BASE_DECIMAL, + + /* The hexadecimal base, indicated by a 0x or 0X prefix. */ + PM_INTEGER_BASE_HEXADECIMAL, + + /* + * An unknown base, in which case pm_integer_parse will derive it based on + * the content of the string. This is less efficient and does more + * comparisons, so if callers know the base ahead of time, they should use + * that instead. + */ + PM_INTEGER_BASE_UNKNOWN +} pm_integer_base_t; + +/* + * Parse an integer from a string. This assumes that the format of the integer + * has already been validated, as internal validation checks are not performed + * here. + */ +void pm_integer_parse(pm_integer_t *integer, pm_integer_base_t base, const uint8_t *start, const uint8_t *end); + +/* + * Compare two integers. This function returns -1 if the left integer is less + * than the right integer, 0 if they are equal, and 1 if the left integer is + * greater than the right integer. + */ +int pm_integer_compare(const pm_integer_t *left, const pm_integer_t *right); + +/* + * Reduce a ratio of integers to its simplest form. + * + * If either the numerator or denominator do not fit into a 32-bit integer, then + * this function is a no-op. In the future, we may consider reducing even the + * larger numbers, but for now we're going to keep it simple. + */ +void pm_integers_reduce(pm_integer_t *numerator, pm_integer_t *denominator); + +/* Convert an integer to a decimal string. */ +void pm_integer_string(pm_buffer_t *buffer, const pm_integer_t *integer); + +#endif diff --git a/prism/internal/isinf.h b/prism/internal/isinf.h new file mode 100644 index 00000000000000..41c160f56d10ee --- /dev/null +++ b/prism/internal/isinf.h @@ -0,0 +1,16 @@ +#ifndef PRISM_INTERNAL_ISINF_H +#define PRISM_INTERNAL_ISINF_H + +/* + * isinf on POSIX systems accepts a float, a double, or a long double. But mingw + * didn't provide an isinf macro, only an isinf function that only accepts + * floats, so we need to use _finite instead. + */ +#ifdef __MINGW64__ + #include + #define PRISM_ISINF(x) (!_finite(x)) +#else + #define PRISM_ISINF(x) isinf(x) +#endif + +#endif diff --git a/prism/internal/line_offset_list.h b/prism/internal/line_offset_list.h new file mode 100644 index 00000000000000..dac9f7052e340c --- /dev/null +++ b/prism/internal/line_offset_list.h @@ -0,0 +1,34 @@ +#ifndef PRISM_INTERNAL_LINE_OFFSET_LIST_H +#define PRISM_INTERNAL_LINE_OFFSET_LIST_H + +#include "prism/compiler/force_inline.h" + +#include "prism/arena.h" +#include "prism/line_offset_list.h" + +/* Initialize a new line offset list with the given capacity. */ +void pm_line_offset_list_init(pm_arena_t *arena, pm_line_offset_list_t *list, size_t capacity); + +/* Clear out the offsets that have been appended to the list. */ +void pm_line_offset_list_clear(pm_line_offset_list_t *list); + +/* Append a new offset to the list (slow path with resize). */ +void pm_line_offset_list_append_slow(pm_arena_t *arena, pm_line_offset_list_t *list, uint32_t cursor); + +/* Append a new offset to the list. */ +static PRISM_FORCE_INLINE void +pm_line_offset_list_append(pm_arena_t *arena, pm_line_offset_list_t *list, uint32_t cursor) { + if (list->size < list->capacity) { + list->offsets[list->size++] = cursor; + } else { + pm_line_offset_list_append_slow(arena, list, cursor); + } +} + +/* + * Returns the line of the given offset. If the offset is not in the list, the + * line of the closest offset less than the given offset is returned. + */ +int32_t pm_line_offset_list_line(const pm_line_offset_list_t *list, uint32_t cursor, int32_t start_line); + +#endif diff --git a/prism/util/pm_list.h b/prism/internal/list.h similarity index 56% rename from prism/util/pm_list.h rename to prism/internal/list.h index f544bb2943d3ff..0ab59ef32afedb 100644 --- a/prism/util/pm_list.h +++ b/prism/internal/list.h @@ -1,19 +1,9 @@ -/** - * @file pm_list.h - * - * An abstract linked list. - */ -#ifndef PRISM_LIST_H -#define PRISM_LIST_H +#ifndef PRISM_INTERNAL_LIST_H +#define PRISM_INTERNAL_LIST_H -#include "prism/defines.h" - -#include #include -#include -#include -/** +/* * This struct represents an abstract linked list that provides common * functionality. It is meant to be used any time a linked list is necessary to * store data. @@ -44,60 +34,29 @@ * iteration and appending of new nodes. */ typedef struct pm_list_node { - /** A pointer to the next node in the list. */ + /* A pointer to the next node in the list. */ struct pm_list_node *next; } pm_list_node_t; -/** +/* * This represents the overall linked list. It keeps a pointer to the head and * tail so that iteration is easy and pushing new nodes is easy. */ typedef struct { - /** The size of the list. */ + /* The size of the list. */ size_t size; - /** A pointer to the head of the list. */ + /* A pointer to the head of the list. */ pm_list_node_t *head; - /** A pointer to the tail of the list. */ + /* A pointer to the tail of the list. */ pm_list_node_t *tail; } pm_list_t; -/** - * Returns true if the given list is empty. - * - * @param list The list to check. - * @return True if the given list is empty, otherwise false. - * - * \public \memberof pm_list_t - */ -PRISM_EXPORTED_FUNCTION bool pm_list_empty_p(pm_list_t *list); - -/** - * Returns the size of the list. - * - * @param list The list to check. - * @return The size of the list. - * - * \public \memberof pm_list_t - */ -PRISM_EXPORTED_FUNCTION size_t pm_list_size(pm_list_t *list); +/* Returns the size of the list. */ +size_t pm_list_size(pm_list_t *list); -/** - * Append a node to the given list. - * - * @param list The list to append to. - * @param node The node to append. - */ +/* Append a node to the given list. */ void pm_list_append(pm_list_t *list, pm_list_node_t *node); -/** - * Deallocate the internal state of the given list. - * - * @param list The list to free. - * - * \public \memberof pm_list_t - */ -PRISM_EXPORTED_FUNCTION void pm_list_free(pm_list_t *list); - #endif diff --git a/prism/internal/magic_comments.h b/prism/internal/magic_comments.h new file mode 100644 index 00000000000000..72a581c5d7b1c7 --- /dev/null +++ b/prism/internal/magic_comments.h @@ -0,0 +1,23 @@ +#ifndef PRISM_INTERNAL_MAGIC_COMMENTS_H +#define PRISM_INTERNAL_MAGIC_COMMENTS_H + +#include "prism/magic_comments.h" + +#include "prism/internal/list.h" + +/* + * This is a node in the linked list of magic comments that we've found while + * parsing. + */ +struct pm_magic_comment_t { + /* The embedded base node. */ + pm_list_node_t node; + + /* The key of the magic comment. */ + pm_location_t key; + + /* The value of the magic comment. */ + pm_location_t value; +}; + +#endif diff --git a/prism/internal/memchr.h b/prism/internal/memchr.h new file mode 100644 index 00000000000000..63c738387d65d7 --- /dev/null +++ b/prism/internal/memchr.h @@ -0,0 +1,15 @@ +#ifndef PRISM_INTERNAL_MEMCHR_H +#define PRISM_INTERNAL_MEMCHR_H + +#include "prism/internal/encoding.h" + +#include + +/* + * We need to roll our own memchr to handle cases where the encoding changes and + * we need to search for a character in a buffer that could be the trailing byte + * of a multibyte character. + */ +void * pm_memchr(const void *source, int character, size_t number, bool encoding_changed, const pm_encoding_t *encoding); + +#endif diff --git a/prism/internal/node.h b/prism/internal/node.h new file mode 100644 index 00000000000000..ca6d5616d76ee5 --- /dev/null +++ b/prism/internal/node.h @@ -0,0 +1,32 @@ +#ifndef PRISM_INTERNAL_NODE_H +#define PRISM_INTERNAL_NODE_H + +#include "prism/node.h" + +#include "prism/compiler/force_inline.h" + +#include "prism/arena.h" + +/* + * Slow path for pm_node_list_append: grow the list and append the node. + * Do not call directly — use pm_node_list_append instead. + */ +void pm_node_list_append_slow(pm_arena_t *arena, pm_node_list_t *list, pm_node_t *node); + +/* Append a new node onto the end of the node list. */ +static PRISM_FORCE_INLINE void +pm_node_list_append(pm_arena_t *arena, pm_node_list_t *list, pm_node_t *node) { + if (list->size < list->capacity) { + list->nodes[list->size++] = node; + } else { + pm_node_list_append_slow(arena, list, node); + } +} + +/* Prepend a new node onto the beginning of the node list. */ +void pm_node_list_prepend(pm_arena_t *arena, pm_node_list_t *list, pm_node_t *node); + +/* Concatenate the given node list onto the end of the other node list. */ +void pm_node_list_concat(pm_arena_t *arena, pm_node_list_t *list, pm_node_list_t *other); + +#endif diff --git a/prism/internal/options.h b/prism/internal/options.h new file mode 100644 index 00000000000000..7e37742a8bef1f --- /dev/null +++ b/prism/internal/options.h @@ -0,0 +1,212 @@ +#ifndef PRISM_INTERNAL_OPTIONS_H +#define PRISM_INTERNAL_OPTIONS_H + +#include "prism/options.h" + +/* A scope of locals surrounding the code that is being parsed. */ +struct pm_options_scope_t { + /* The number of locals in the scope. */ + size_t locals_count; + + /* The names of the locals in the scope. */ + pm_string_t *locals; + + /* Flags for the set of forwarding parameters in this scope. */ + uint8_t forwarding; +}; + +/* + * The version of Ruby syntax that we should be parsing with. This is used to + * allow consumers to specify which behavior they want in case they need to + * parse in the same way as a specific version of CRuby would have. + */ +typedef enum { + /* + * If an explicit version is not provided, the current version of prism will + * be used. + */ + PM_OPTIONS_VERSION_UNSET = 0, + + /* The vendored version of prism in CRuby 3.3.x. */ + PM_OPTIONS_VERSION_CRUBY_3_3 = 1, + + /* The vendored version of prism in CRuby 3.4.x. */ + PM_OPTIONS_VERSION_CRUBY_3_4 = 2, + + /* The vendored version of prism in CRuby 4.0.x. */ + PM_OPTIONS_VERSION_CRUBY_3_5 = 3, + + /* The vendored version of prism in CRuby 4.0.x. */ + PM_OPTIONS_VERSION_CRUBY_4_0 = 3, + + /* The vendored version of prism in CRuby 4.1.x. */ + PM_OPTIONS_VERSION_CRUBY_4_1 = 4, + + /* The current version of prism. */ + PM_OPTIONS_VERSION_LATEST = PM_OPTIONS_VERSION_CRUBY_4_1 +} pm_options_version_t; + +/* The options that can be passed to the parser. */ +struct pm_options_t { + /* + * The callback to call when additional switches are found in a shebang + * comment. + */ + pm_options_shebang_callback_t shebang_callback; + + /* + * Any additional data that should be passed along to the shebang callback + * if one was set. + */ + void *shebang_callback_data; + + /* The name of the file that is currently being parsed. */ + pm_string_t filepath; + + /* + * The line within the file that the parse starts on. This value is + * 1-indexed. + */ + int32_t line; + + /* + * The name of the encoding that the source file is in. Note that this must + * correspond to a name that can be found with Encoding.find in Ruby. + */ + pm_string_t encoding; + + /* The number of scopes surrounding the code that is being parsed. */ + size_t scopes_count; + + /* + * The scopes surrounding the code that is being parsed. For most parses + * this will be NULL, but for evals it will be the locals that are in scope + * surrounding the eval. Scopes are ordered from the outermost scope to the + * innermost one. + */ + pm_options_scope_t *scopes; + + /* + * The version of prism that we should be parsing with. This is used to + * allow consumers to specify which behavior they want in case they need to + * parse exactly as a specific version of CRuby. + */ + pm_options_version_t version; + + /* A bitset of the various options that were set on the command line. */ + uint8_t command_line; + + /* + * Whether or not the frozen string literal option has been set. + * May be: + * - PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED + * - PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED + * - PM_OPTIONS_FROZEN_STRING_LITERAL_UNSET + */ + int8_t frozen_string_literal; + + /* + * Whether or not the encoding magic comments should be respected. This is a + * niche use-case where you want to parse a file with a specific encoding + * but ignore any encoding magic comments at the top of the file. + */ + bool encoding_locked; + + /* + * When the file being parsed is the main script, the shebang will be + * considered for command-line flags (or for implicit -x). The caller needs + * to pass this information to the parser so that it can behave correctly. + */ + bool main_script; + + /* + * When the file being parsed is considered a "partial" script, jumps will + * not be marked as errors if they are not contained within loops/blocks. + * This is used in the case that you're parsing a script that you know will + * be embedded inside another script later, but you do not have that context + * yet. For example, when parsing an ERB template that will be evaluated + * inside another script. + */ + bool partial_script; + + /* + * Whether or not the parser should freeze the nodes that it creates. This + * makes it possible to have a deeply frozen AST that is safe to share + * between concurrency primitives. + */ + bool freeze; +}; + +/* Free the internal memory associated with the options. */ +void pm_options_cleanup(pm_options_t *options); + +/* + * Deserialize an options struct from the given binary string. This is used to + * pass options to the parser from an FFI call so that consumers of the library + * from an FFI perspective don't have to worry about the structure of our + * options structs. Since the source of these calls will be from Ruby + * implementation internals we assume it is from a trusted source. + * + * `data` is assumed to be a valid pointer pointing to well-formed data. The + * layout of this data should be the same every time, and is described below: + * + * | # bytes | field | + * | ------- | -------------------------- | + * | `4` | the length of the filepath | + * | ... | the filepath bytes | + * | `4` | the line number | + * | `4` | the length the encoding | + * | ... | the encoding bytes | + * | `1` | frozen string literal | + * | `1` | -p command line option | + * | `1` | -n command line option | + * | `1` | -l command line option | + * | `1` | -a command line option | + * | `1` | the version | + * | `1` | encoding locked | + * | `1` | main script | + * | `1` | partial script | + * | `1` | freeze | + * | `4` | the number of scopes | + * | ... | the scopes | + * + * The version field is an enum, so it should be one of the following values: + * + * | value | version | + * | ----- | ------------------------- | + * | `0` | use the latest version of prism | + * | `1` | use the version of prism that is vendored in CRuby 3.3.0 | + * | `2` | use the version of prism that is vendored in CRuby 3.4.0 | + * | `3` | use the version of prism that is vendored in CRuby 4.0.0 | + * | `4` | use the version of prism that is vendored in CRuby 4.1.0 | + * + * Each scope is laid out as follows: + * + * | # bytes | field | + * | ------- | -------------------------- | + * | `4` | the number of locals | + * | `1` | the forwarding flags | + * | ... | the locals | + * + * Each local is laid out as follows: + * + * | # bytes | field | + * | ------- | -------------------------- | + * | `4` | the length of the local | + * | ... | the local bytes | + * + * Some additional things to note about this layout: + * + * * The filepath can have a length of 0, in which case we'll consider it an + * empty string. + * * The line number should be 0-indexed. + * * The encoding can have a length of 0, in which case we'll use the default + * encoding (UTF-8). If it's not 0, it should correspond to a name of an + * encoding that can be passed to `Encoding.find` in Ruby. + * * The frozen string literal, encoding locked, main script, and partial script + * fields are booleans, so their values should be either 0 or 1. + * * The number of scopes can be 0. + */ +void pm_options_read(pm_options_t *options, const char *data); + +#endif diff --git a/prism/internal/parser.h b/prism/internal/parser.h new file mode 100644 index 00000000000000..3afe226757d2d0 --- /dev/null +++ b/prism/internal/parser.h @@ -0,0 +1,957 @@ +#ifndef PRISM_INTERNAL_PARSER_H +#define PRISM_INTERNAL_PARSER_H + +#include "prism/compiler/accel.h" + +#include "prism/internal/arena.h" +#include "prism/internal/constant_pool.h" +#include "prism/internal/encoding.h" +#include "prism/internal/list.h" +#include "prism/internal/options.h" +#include "prism/internal/static_literals.h" + +#include "prism/ast.h" +#include "prism/line_offset_list.h" +#include "prism/parser.h" + +#include +#include +#include + +/* + * This enum provides various bits that represent different kinds of states that + * the lexer can track. This is used to determine which kind of token to return + * based on the context of the parser. + */ +typedef enum { + PM_LEX_STATE_BIT_BEG, + PM_LEX_STATE_BIT_END, + PM_LEX_STATE_BIT_ENDARG, + PM_LEX_STATE_BIT_ENDFN, + PM_LEX_STATE_BIT_ARG, + PM_LEX_STATE_BIT_CMDARG, + PM_LEX_STATE_BIT_MID, + PM_LEX_STATE_BIT_FNAME, + PM_LEX_STATE_BIT_DOT, + PM_LEX_STATE_BIT_CLASS, + PM_LEX_STATE_BIT_LABEL, + PM_LEX_STATE_BIT_LABELED, + PM_LEX_STATE_BIT_FITEM +} pm_lex_state_bit_t; + +/* + * This enum combines the various bits from the above enum into individual + * values that represent the various states of the lexer. + */ +typedef enum { + PM_LEX_STATE_NONE = 0, + PM_LEX_STATE_BEG = (1 << PM_LEX_STATE_BIT_BEG), + PM_LEX_STATE_END = (1 << PM_LEX_STATE_BIT_END), + PM_LEX_STATE_ENDARG = (1 << PM_LEX_STATE_BIT_ENDARG), + PM_LEX_STATE_ENDFN = (1 << PM_LEX_STATE_BIT_ENDFN), + PM_LEX_STATE_ARG = (1 << PM_LEX_STATE_BIT_ARG), + PM_LEX_STATE_CMDARG = (1 << PM_LEX_STATE_BIT_CMDARG), + PM_LEX_STATE_MID = (1 << PM_LEX_STATE_BIT_MID), + PM_LEX_STATE_FNAME = (1 << PM_LEX_STATE_BIT_FNAME), + PM_LEX_STATE_DOT = (1 << PM_LEX_STATE_BIT_DOT), + PM_LEX_STATE_CLASS = (1 << PM_LEX_STATE_BIT_CLASS), + PM_LEX_STATE_LABEL = (1 << PM_LEX_STATE_BIT_LABEL), + PM_LEX_STATE_LABELED = (1 << PM_LEX_STATE_BIT_LABELED), + PM_LEX_STATE_FITEM = (1 << PM_LEX_STATE_BIT_FITEM), + PM_LEX_STATE_BEG_ANY = PM_LEX_STATE_BEG | PM_LEX_STATE_MID | PM_LEX_STATE_CLASS, + PM_LEX_STATE_ARG_ANY = PM_LEX_STATE_ARG | PM_LEX_STATE_CMDARG, + PM_LEX_STATE_END_ANY = PM_LEX_STATE_END | PM_LEX_STATE_ENDARG | PM_LEX_STATE_ENDFN +} pm_lex_state_t; + +/* + * The type of quote that a heredoc uses. + */ +typedef enum { + PM_HEREDOC_QUOTE_NONE, + PM_HEREDOC_QUOTE_SINGLE = '\'', + PM_HEREDOC_QUOTE_DOUBLE = '"', + PM_HEREDOC_QUOTE_BACKTICK = '`', +} pm_heredoc_quote_t; + +/* + * The type of indentation that a heredoc uses. + */ +typedef enum { + PM_HEREDOC_INDENT_NONE, + PM_HEREDOC_INDENT_DASH, + PM_HEREDOC_INDENT_TILDE, +} pm_heredoc_indent_t; + +/* + * All of the information necessary to store to lexing a heredoc. + */ +typedef struct { + /* A pointer to the start of the heredoc identifier. */ + const uint8_t *ident_start; + + /* The length of the heredoc identifier. */ + size_t ident_length; + + /* The type of quote that the heredoc uses. */ + pm_heredoc_quote_t quote; + + /* The type of indentation that the heredoc uses. */ + pm_heredoc_indent_t indent; +} pm_heredoc_lex_mode_t; + +/* + * When lexing Ruby source, the lexer has a small amount of state to tell which + * kind of token it is currently lexing. For example, when we find the start of + * a string, the first token that we return is a TOKEN_STRING_BEGIN token. After + * that the lexer is now in the PM_LEX_STRING mode, and will return tokens that + * are found as part of a string. + */ +typedef struct pm_lex_mode { + /* The type of this lex mode. */ + enum { + /* This state is used when any given token is being lexed. */ + PM_LEX_DEFAULT, + + /* + * This state is used when we're lexing as normal but inside an embedded + * expression of a string. + */ + PM_LEX_EMBEXPR, + + /* + * This state is used when we're lexing a variable that is embedded + * directly inside of a string with the # shorthand. + */ + PM_LEX_EMBVAR, + + /* This state is used when you are inside the content of a heredoc. */ + PM_LEX_HEREDOC, + + /* + * This state is used when we are lexing a list of tokens, as in a %w + * word list literal or a %i symbol list literal. + */ + PM_LEX_LIST, + + /* + * This state is used when a regular expression has been begun and we + * are looking for the terminator. + */ + PM_LEX_REGEXP, + + /* + * This state is used when we are lexing a string or a string-like + * token, as in string content with either quote or an xstring. + */ + PM_LEX_STRING + } mode; + + /* The data associated with this type of lex mode. */ + union { + struct { + /* This keeps track of the nesting level of the list. */ + size_t nesting; + + /* Whether or not interpolation is allowed in this list. */ + bool interpolation; + + /* + * When lexing a list, it takes into account balancing the + * terminator if the terminator is one of (), [], {}, or <>. + */ + uint8_t incrementor; + + /* This is the terminator of the list literal. */ + uint8_t terminator; + + /* + * This is the character set that should be used to delimit the + * tokens within the list. + */ + uint8_t breakpoints[11]; + } list; + + struct { + /* + * This keeps track of the nesting level of the regular expression. + */ + size_t nesting; + + /* + * When lexing a regular expression, it takes into account balancing + * the terminator if the terminator is one of (), [], {}, or <>. + */ + uint8_t incrementor; + + /* This is the terminator of the regular expression. */ + uint8_t terminator; + + /* + * This is the character set that should be used to delimit the + * tokens within the regular expression. + */ + uint8_t breakpoints[7]; + } regexp; + + struct { + /* This keeps track of the nesting level of the string. */ + size_t nesting; + + /* Whether or not interpolation is allowed in this string. */ + bool interpolation; + + /* + * Whether or not at the end of the string we should allow a :, + * which would indicate this was a dynamic symbol instead of a + * string. + */ + bool label_allowed; + + /* + * When lexing a string, it takes into account balancing the + * terminator if the terminator is one of (), [], {}, or <>. + */ + uint8_t incrementor; + + /* + * This is the terminator of the string. It is typically either a + * single or double quote. + */ + uint8_t terminator; + + /* + * This is the character set that should be used to delimit the + * tokens within the string. + */ + uint8_t breakpoints[7]; + } string; + + struct { + /* + * All of the data necessary to lex a heredoc. + */ + pm_heredoc_lex_mode_t base; + + /* + * This is the pointer to the character where lexing should resume + * once the heredoc has been completely processed. + */ + const uint8_t *next_start; + + /* + * This is used to track the amount of common whitespace on each + * line so that we know how much to dedent each line in the case of + * a tilde heredoc. + */ + size_t *common_whitespace; + + /* True if the previous token ended with a line continuation. */ + bool line_continuation; + } heredoc; + } as; + + /* The previous lex state so that it knows how to pop. */ + struct pm_lex_mode *prev; +} pm_lex_mode_t; + +/* + * We pre-allocate a certain number of lex states in order to avoid having to + * call malloc too many times while parsing. You really shouldn't need more than + * this because you only really nest deeply when doing string interpolation. + */ +#define PM_LEX_STACK_SIZE 4 + +/* + * While parsing, we keep track of a stack of contexts. This is helpful for + * error recovery so that we can pop back to a previous context when we hit a + * token that is understood by a parent context but not by the current context. + */ +typedef enum { + /* a null context, used for returning a value from a function */ + PM_CONTEXT_NONE = 0, + + /* a begin statement */ + PM_CONTEXT_BEGIN, + + /* an ensure statement with an explicit begin */ + PM_CONTEXT_BEGIN_ENSURE, + + /* a rescue else statement with an explicit begin */ + PM_CONTEXT_BEGIN_ELSE, + + /* a rescue statement with an explicit begin */ + PM_CONTEXT_BEGIN_RESCUE, + + /* expressions in block arguments using braces */ + PM_CONTEXT_BLOCK_BRACES, + + /* expressions in block arguments using do..end */ + PM_CONTEXT_BLOCK_KEYWORDS, + + /* an ensure statement within a do..end block */ + PM_CONTEXT_BLOCK_ENSURE, + + /* a rescue else statement within a do..end block */ + PM_CONTEXT_BLOCK_ELSE, + + /* expressions in block parameters `foo do |...| end ` */ + PM_CONTEXT_BLOCK_PARAMETERS, + + /* a rescue statement within a do..end block */ + PM_CONTEXT_BLOCK_RESCUE, + + /* a case when statements */ + PM_CONTEXT_CASE_WHEN, + + /* a case in statements */ + PM_CONTEXT_CASE_IN, + + /* a class declaration */ + PM_CONTEXT_CLASS, + + /* an ensure statement within a class statement */ + PM_CONTEXT_CLASS_ENSURE, + + /* a rescue else statement within a class statement */ + PM_CONTEXT_CLASS_ELSE, + + /* a rescue statement within a class statement */ + PM_CONTEXT_CLASS_RESCUE, + + /* a method definition */ + PM_CONTEXT_DEF, + + /* an ensure statement within a method definition */ + PM_CONTEXT_DEF_ENSURE, + + /* a rescue else statement within a method definition */ + PM_CONTEXT_DEF_ELSE, + + /* a rescue statement within a method definition */ + PM_CONTEXT_DEF_RESCUE, + + /* a method definition's parameters */ + PM_CONTEXT_DEF_PARAMS, + + /* a defined? expression */ + PM_CONTEXT_DEFINED, + + /* a method definition's default parameter */ + PM_CONTEXT_DEFAULT_PARAMS, + + /* an else clause */ + PM_CONTEXT_ELSE, + + /* an elsif clause */ + PM_CONTEXT_ELSIF, + + /* an interpolated expression */ + PM_CONTEXT_EMBEXPR, + + /* a for loop */ + PM_CONTEXT_FOR, + + /* a for loop's index */ + PM_CONTEXT_FOR_INDEX, + + /* an if statement */ + PM_CONTEXT_IF, + + /* a lambda expression with braces */ + PM_CONTEXT_LAMBDA_BRACES, + + /* a lambda expression with do..end */ + PM_CONTEXT_LAMBDA_DO_END, + + /* an ensure statement within a lambda expression */ + PM_CONTEXT_LAMBDA_ENSURE, + + /* a rescue else statement within a lambda expression */ + PM_CONTEXT_LAMBDA_ELSE, + + /* a rescue statement within a lambda expression */ + PM_CONTEXT_LAMBDA_RESCUE, + + /* the predicate clause of a loop statement */ + PM_CONTEXT_LOOP_PREDICATE, + + /* the top level context */ + PM_CONTEXT_MAIN, + + /* a module declaration */ + PM_CONTEXT_MODULE, + + /* an ensure statement within a module statement */ + PM_CONTEXT_MODULE_ENSURE, + + /* a rescue else statement within a module statement */ + PM_CONTEXT_MODULE_ELSE, + + /* a rescue statement within a module statement */ + PM_CONTEXT_MODULE_RESCUE, + + /* a multiple target expression */ + PM_CONTEXT_MULTI_TARGET, + + /* a parenthesized expression */ + PM_CONTEXT_PARENS, + + /* an END block */ + PM_CONTEXT_POSTEXE, + + /* a predicate inside an if/elsif/unless statement */ + PM_CONTEXT_PREDICATE, + + /* a BEGIN block */ + PM_CONTEXT_PREEXE, + + /* a modifier rescue clause */ + PM_CONTEXT_RESCUE_MODIFIER, + + /* a singleton class definition */ + PM_CONTEXT_SCLASS, + + /* an ensure statement with a singleton class */ + PM_CONTEXT_SCLASS_ENSURE, + + /* a rescue else statement with a singleton class */ + PM_CONTEXT_SCLASS_ELSE, + + /* a rescue statement with a singleton class */ + PM_CONTEXT_SCLASS_RESCUE, + + /* a ternary expression */ + PM_CONTEXT_TERNARY, + + /* an unless statement */ + PM_CONTEXT_UNLESS, + + /* an until statement */ + PM_CONTEXT_UNTIL, + + /* a while statement */ + PM_CONTEXT_WHILE, +} pm_context_t; + +/* This is a node in a linked list of contexts. */ +typedef struct pm_context_node { + /* The context that this node represents. */ + pm_context_t context; + + /* A pointer to the previous context in the linked list. */ + struct pm_context_node *prev; +} pm_context_node_t; + +/* The type of shareable constant value that can be set. */ +typedef uint8_t pm_shareable_constant_value_t; +static const pm_shareable_constant_value_t PM_SCOPE_SHAREABLE_CONSTANT_NONE = 0x0; +static const pm_shareable_constant_value_t PM_SCOPE_SHAREABLE_CONSTANT_LITERAL = PM_SHAREABLE_CONSTANT_NODE_FLAGS_LITERAL; +static const pm_shareable_constant_value_t PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_EVERYTHING = PM_SHAREABLE_CONSTANT_NODE_FLAGS_EXPERIMENTAL_EVERYTHING; +static const pm_shareable_constant_value_t PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_COPY = PM_SHAREABLE_CONSTANT_NODE_FLAGS_EXPERIMENTAL_COPY; + +/* + * This tracks an individual local variable in a certain lexical context, as + * well as the number of times is it read. + */ +typedef struct { + /* The name of the local variable. */ + pm_constant_id_t name; + + /* The location of the local variable in the source. */ + pm_location_t location; + + /* The index of the local variable in the local table. */ + uint32_t index; + + /* The number of times the local variable is read. */ + uint32_t reads; + + /* The hash of the local variable. */ + uint32_t hash; +} pm_local_t; + +/* + * This is a set of local variables in a certain lexical context (method, class, + * module, etc.). We need to track how many times these variables are read in + * order to warn if they only get written. + */ +typedef struct pm_locals { + /* The number of local variables in the set. */ + uint32_t size; + + /* The capacity of the local variables set. */ + uint32_t capacity; + + /* + * A bloom filter over constant IDs stored in this set. Used to quickly + * reject lookups for names that are definitely not present, avoiding the + * cost of a linear scan or hash probe. + */ + uint32_t bloom; + + /* The nullable allocated memory for the local variables in the set. */ + pm_local_t *locals; +} pm_locals_t; + +/* The flags about scope parameters that can be set. */ +typedef uint8_t pm_scope_parameters_t; +static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_NONE = 0x0; +static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_FORWARDING_POSITIONALS = 0x1; +static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_FORWARDING_KEYWORDS = 0x2; +static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_FORWARDING_BLOCK = 0x4; +static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_FORWARDING_ALL = 0x8; +static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED = 0x10; +static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_NUMBERED_INNER = 0x20; +static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_NUMBERED_FOUND = 0x40; + +/* + * This struct represents a node in a linked list of scopes. Some scopes can see + * into their parent scopes, while others cannot. + */ +typedef struct pm_scope { + /* A pointer to the previous scope in the linked list. */ + struct pm_scope *previous; + + /* The IDs of the locals in the given scope. */ + pm_locals_t locals; + + /* + * This is a list of the implicit parameters contained within the block. + * These will be processed after the block is parsed to determine the kind + * of parameters node that should be used and to check if any errors need to + * be added. + */ + pm_node_list_t implicit_parameters; + + /* + * This is a bitfield that indicates the parameters that are being used in + * this scope. It is a combination of the PM_SCOPE_PARAMETERS_* constants. + * There are three different kinds of parameters that can be used in a + * scope: + * + * - Ordinary parameters (e.g., def foo(bar); end) + * - Numbered parameters (e.g., def foo; _1; end) + * - The it parameter (e.g., def foo; it; end) + * + * If ordinary parameters are being used, then certain parameters can be + * forwarded to another method/structure. Those are indicated by four + * additional bits in the params field. For example, some combinations of: + * + * - def foo(*); end + * - def foo(**); end + * - def foo(&); end + * - def foo(...); end + */ + pm_scope_parameters_t parameters; + + /* + * The current state of constant shareability for this scope. This is + * changed by magic shareable_constant_value comments. + */ + pm_shareable_constant_value_t shareable_constant; + + /* + * A boolean indicating whether or not this scope can see into its parent. + * If closed is true, then the scope cannot see into its parent. + */ + bool closed; +} pm_scope_t; + +/* + * A struct that represents a stack of boolean values. + */ +typedef uint32_t pm_state_stack_t; + +/* + * This struct represents the overall parser. It contains a reference to the + * source file, as well as pointers that indicate where in the source it's + * currently parsing. It also contains the most recent and current token that + * it's considering. + */ +struct pm_parser_t { + /* The arena used for all AST-lifetime allocations. Caller-owned. */ + pm_arena_t *arena; + + /* The arena used for parser metadata (comments, diagnostics, etc.). */ + pm_arena_t metadata_arena; + + /* + * The next node identifier that will be assigned. This is a unique + * identifier used to track nodes such that the syntax tree can be dropped + * but the node can be found through another parse. + */ + uint32_t node_id; + + /* + * A single-entry cache for pm_parser_constant_id_raw. Avoids redundant + * constant pool lookups when the same token is resolved multiple times + * (e.g., once during lexing for local variable detection, and again + * during parsing for node creation). + */ + struct { + const uint8_t *start; + const uint8_t *end; + pm_constant_id_t id; + } constant_cache; + + /* The current state of the lexer. */ + pm_lex_state_t lex_state; + + /* Tracks the current nesting of (), [], and {}. */ + int enclosure_nesting; + + /* + * Used to temporarily track the nesting of enclosures to determine if a { + * is the beginning of a lambda following the parameters of a lambda. + */ + int lambda_enclosure_nesting; + + /* + * Used to track the nesting of braces to ensure we get the correct value + * when we are interpolating blocks with braces. + */ + int brace_nesting; + + /* + * The stack used to determine if a do keyword belongs to the predicate of a + * while, until, or for loop. + */ + pm_state_stack_t do_loop_stack; + + /* + * The stack used to determine if a do keyword belongs to the beginning of a + * block. + */ + pm_state_stack_t accepts_block_stack; + + /* A stack of lex modes. */ + struct { + /* The current mode of the lexer. */ + pm_lex_mode_t *current; + + /* The stack of lexer modes. */ + pm_lex_mode_t stack[PM_LEX_STACK_SIZE]; + + /* The current index into the lexer mode stack. */ + size_t index; + } lex_modes; + + /* The pointer to the start of the source. */ + const uint8_t *start; + + /* The pointer to the end of the source. */ + const uint8_t *end; + + /* The previous token we were considering. */ + pm_token_t previous; + + /* The current token we're considering. */ + pm_token_t current; + + /* + * This is a special field set on the parser when we need the parser to jump + * to a specific location when lexing the next token, as opposed to just + * using the end of the previous token. Normally this is NULL. + */ + const uint8_t *next_start; + + /* + * This field indicates the end of a heredoc whose identifier was found on + * the current line. If another heredoc is found on the same line, then this + * will be moved forward to the end of that heredoc. If no heredocs are + * found on a line then this is NULL. + */ + const uint8_t *heredoc_end; + + /* The list of comments that have been found while parsing. */ + pm_list_t comment_list; + + /* The list of magic comments that have been found while parsing. */ + pm_list_t magic_comment_list; + + /* + * An optional location that represents the location of the __END__ marker + * and the rest of the content of the file. This content is loaded into the + * DATA constant when the file being parsed is the main file being executed. + */ + pm_location_t data_loc; + + /* The list of warnings that have been found while parsing. */ + pm_list_t warning_list; + + /* The list of errors that have been found while parsing. */ + pm_list_t error_list; + + /* The current local scope. */ + pm_scope_t *current_scope; + + /* The current parsing context. */ + pm_context_node_t *current_context; + + /* + * The hash keys for the hash that is currently being parsed. This is not + * usually necessary because it can pass it down the various call chains, + * but in the event that you're parsing a hash that is being directly + * pushed into another hash with **, we need to share the hash keys so that + * we can warn for the nested hash as well. + */ + pm_static_literals_t *current_hash_keys; + + /* + * The encoding functions for the current file is attached to the parser as + * it's parsing so that it can change with a magic comment. + */ + const pm_encoding_t *encoding; + + /* + * When the encoding that is being used to parse the source is changed by + * prism, we provide the ability here to call out to a user-defined + * function. + */ + pm_encoding_changed_callback_t encoding_changed_callback; + + /* + * This pointer indicates where a comment must start if it is to be + * considered an encoding comment. + */ + const uint8_t *encoding_comment_start; + + /* + * When you are lexing through a file, the lexer needs all of the information + * that the parser additionally provides (for example, the local table). So if + * you want to properly lex Ruby, you need to actually lex it in the context of + * the parser. In order to provide this functionality, we optionally allow a + * struct to be attached to the parser that calls back out to a user-provided + * callback when each token is lexed. + */ + struct { + /* + * This is the callback that is called when a token is lexed. It is + * passed the opaque data pointer, the parser, and the token that was + * lexed. + */ + pm_lex_callback_t callback; + + /* + * This opaque pointer is used to provide whatever information the user + * deemed necessary to the callback. In our case we use it to pass the + * array that the tokens get appended into. + */ + void *data; + } lex_callback; + + /* + * This is the path of the file being parsed. We use the filepath when + * constructing SourceFileNodes. + */ + pm_string_t filepath; + + /* + * This constant pool keeps all of the constants defined throughout the file + * so that we can reference them later. + */ + pm_constant_pool_t constant_pool; + + /* This is the list of line offsets in the source file. */ + pm_line_offset_list_t line_offsets; + + /* + * State communicated from the lexer to the parser for integer tokens. + */ + struct { + /* + * A flag indicating the base of the integer (binary, octal, decimal, + * hexadecimal). Set during lexing and read during node creation. + */ + pm_node_flags_t base; + + /* + * When lexing a decimal integer that fits in a uint32_t, we compute + * the value during lexing to avoid re-scanning the digits during + * parsing. If lexed is true, this holds the result and + * pm_integer_parse can be skipped. + */ + uint32_t value; + + /* Whether value holds a valid pre-computed integer. */ + bool lexed; + } integer; + + /* + * This string is used to pass information from the lexer to the parser. It + * is particularly necessary because of escape sequences. + */ + pm_string_t current_string; + + /* + * The line number at the start of the parse. This will be used to offset + * the line numbers of all of the locations. + */ + int32_t start_line; + + /* + * When a string-like expression is being lexed, any byte or escape sequence + * that resolves to a value whose top bit is set (i.e., >= 0x80) will + * explicitly set the encoding to the same encoding as the source. + * Alternatively, if a unicode escape sequence is used (e.g., \\u{80}) that + * resolves to a value whose top bit is set, then the encoding will be + * explicitly set to UTF-8. + * + * The _next_ time this happens, if the encoding that is about to become the + * explicitly set encoding does not match the previously set explicit + * encoding, a mixed encoding error will be emitted. + * + * When the expression is finished being lexed, the explicit encoding + * controls the encoding of the expression. For the most part this means + * that the expression will either be encoded in the source encoding or + * UTF-8. This holds for all encodings except US-ASCII. If the source is + * US-ASCII and an explicit encoding was set that was _not_ UTF-8, then the + * expression will be encoded as ASCII-8BIT. + * + * Note that if the expression is a list, different elements within the same + * list can have different encodings, so this will get reset between each + * element. Furthermore all of this only applies to lists that support + * interpolation, because otherwise escapes that could change the encoding + * are ignored. + * + * At first glance, it may make more sense for this to live on the lexer + * mode, but we need it here to communicate back to the parser for character + * literals that do not push a new lexer mode. + */ + const pm_encoding_t *explicit_encoding; + + /* + * When parsing block exits (e.g., break, next, redo), we need to validate + * that they are in correct contexts. For the most part we can do this by + * looking at our parent contexts. However, modifier while and until + * expressions can change that context to make block exits valid. In these + * cases, we need to keep track of the block exits and then validate them + * after the expression has been parsed. + * + * We use a pointer here because we don't want to keep a whole list attached + * since this will only be used in the context of begin/end expressions. + */ + pm_node_list_t *current_block_exits; + + /* The version of prism that we should use to parse. */ + pm_options_version_t version; + + /* The command line flags given from the options. */ + uint8_t command_line; + + /* + * Whether or not we have found a frozen_string_literal magic comment with + * a true or false value. + * May be: + * - PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED + * - PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED + * - PM_OPTIONS_FROZEN_STRING_LITERAL_UNSET + */ + int8_t frozen_string_literal; + + /* + * Whether or not we are parsing an eval string. This impacts whether or not + * we should evaluate if block exits/yields are valid. + */ + bool parsing_eval; + + /* + * Whether or not we are parsing a "partial" script, which is a script that + * will be evaluated in the context of another script, so we should not + * check jumps (next/break/etc.) for validity. + */ + bool partial_script; + + /* Whether or not we're at the beginning of a command. */ + bool command_start; + + /* + * Whether or not we're currently parsing the body of an endless method + * definition. In this context, PM_TOKEN_KEYWORD_DO_BLOCK should not be + * consumed by commands (it should bubble up to the outer context). + */ + bool in_endless_def_body; + + /* Whether or not we're currently recovering from a syntax error. */ + bool recovering; + + /* + * Whether or not the source being parsed could become valid if more input + * were appended. This is set to false when the parser encounters a token + * that is definitively wrong (e.g., a stray `end` or `]`) as opposed to + * merely incomplete. + */ + bool continuable; + + /* + * This is very specialized behavior for when you want to parse in a context + * that does not respect encoding comments. Its main use case is translating + * into the whitequark/parser AST which re-encodes source files in UTF-8 + * before they are parsed and ignores encoding comments. + */ + bool encoding_locked; + + /* + * Whether or not the encoding has been changed by a magic comment. We use + * this to provide a fast path for the lexer instead of going through the + * function pointer. + */ + bool encoding_changed; + + /* + * This flag indicates that we are currently parsing a pattern matching + * expression and impacts that calculation of newlines. + */ + bool pattern_matching_newlines; + + /* This flag indicates that we are currently parsing a keyword argument. */ + bool in_keyword_arg; + + /* + * Whether or not the parser has seen a token that has semantic meaning + * (i.e., a token that is not a comment or whitespace). + */ + bool semantic_token_seen; + + /* + * By default, Ruby always warns about mismatched indentation. This can be + * toggled with a magic comment. + */ + bool warn_mismatched_indentation; + +#if defined(PRISM_HAS_NEON) || defined(PRISM_HAS_SSSE3) || defined(PRISM_HAS_SWAR) + /* + * Cached lookup tables for pm_strpbrk's SIMD fast path. Avoids rebuilding + * the nibble-based tables on every call when the charset hasn't changed + * (which is the common case during string/regex/list lexing). + */ + struct { + /* The cached charset (null-terminated, max 11 chars + NUL). */ + uint8_t charset[12]; + + /* Nibble-based low lookup table for SIMD matching. */ + uint8_t low_lut[16]; + + /* Nibble-based high lookup table for SIMD matching. */ + uint8_t high_lut[16]; + + /* Scalar fallback table (4 x 64-bit bitmasks covering all ASCII). */ + uint64_t table[4]; + } strpbrk_cache; +#endif +}; + +/* + * Initialize a parser with the given start and end pointers. + */ +void pm_parser_init(pm_arena_t *arena, pm_parser_t *parser, const uint8_t *source, size_t size, const pm_options_t *options); + +/* + * Free the memory held by the given parser. + * + * This does not free the `pm_options_t` object that was used to initialize the + * parser. + */ +void pm_parser_cleanup(pm_parser_t *parser); + +#endif diff --git a/prism/internal/regexp.h b/prism/internal/regexp.h new file mode 100644 index 00000000000000..3710c984fcba76 --- /dev/null +++ b/prism/internal/regexp.h @@ -0,0 +1,41 @@ +#ifndef PRISM_INTERNAL_REGEXP_H +#define PRISM_INTERNAL_REGEXP_H + +#include "prism/ast.h" +#include "prism/parser.h" + +/* + * Accumulation state for named capture groups found during regexp parsing. + * The caller initializes this with the call node and passes it to + * pm_regexp_parse. The regexp parser populates match and names as groups + * are found. + */ +typedef struct { + /* The call node wrapping the regular expression node (for =~). */ + pm_call_node_t *call; + + /* The match write node being built, or NULL if no captures found yet. */ + pm_match_write_node_t *match; + + /* The list of capture names found so far (for deduplication). */ + pm_constant_id_list_t names; +} pm_regexp_name_data_t; + +/* + * Callback invoked by pm_regexp_parse() for each named capture group found. + */ +typedef void (*pm_regexp_name_callback_t)(pm_parser_t *parser, const pm_string_t *name, bool shared, pm_regexp_name_data_t *data); + +/* + * Parse a regular expression, validate its encoding, and optionally extract + * named capture groups. Returns the encoding flags to set on the node. + */ +PRISM_EXPORTED_FUNCTION pm_node_flags_t pm_regexp_parse(pm_parser_t *parser, pm_regular_expression_node_t *node, pm_regexp_name_callback_t name_callback, pm_regexp_name_data_t *name_data); + +/* + * Parse an interpolated regular expression for named capture groups only. + * No encoding validation is performed. + */ +void pm_regexp_parse_named_captures(pm_parser_t *parser, const uint8_t *source, size_t size, bool shared, bool extended_mode, pm_regexp_name_callback_t name_callback, pm_regexp_name_data_t *name_data); + +#endif diff --git a/prism/internal/serialize.h b/prism/internal/serialize.h new file mode 100644 index 00000000000000..e611a0374bd4bf --- /dev/null +++ b/prism/internal/serialize.h @@ -0,0 +1,34 @@ +#ifndef PRISM_INTERNAL_SERIALIZE_H +#define PRISM_INTERNAL_SERIALIZE_H + +#include "prism/internal/encoding.h" +#include "prism/internal/list.h" + +#include "prism/ast.h" +#include "prism/buffer.h" +#include "prism/excludes.h" +#include "prism/parser.h" + +/* We optionally support serializing to a binary string. For systems that do not + * want or need this functionality, it can be turned off with the + * PRISM_EXCLUDE_SERIALIZATION define. */ +#ifndef PRISM_EXCLUDE_SERIALIZATION + +/* + * Serialize the given list of comments to the given buffer. + */ +void pm_serialize_comment_list(pm_list_t *list, pm_buffer_t *buffer); + +/* + * Serialize the name of the encoding to the buffer. + */ +void pm_serialize_encoding(const pm_encoding_t *encoding, pm_buffer_t *buffer); + +/* + * Serialize the encoding, metadata, nodes, and constant pool. + */ +void pm_serialize_content(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer); + +#endif + +#endif diff --git a/prism/internal/source.h b/prism/internal/source.h new file mode 100644 index 00000000000000..b3c2b55be320ec --- /dev/null +++ b/prism/internal/source.h @@ -0,0 +1,72 @@ +#ifndef PRISM_INTERNAL_SOURCE_H +#define PRISM_INTERNAL_SOURCE_H + +#include "prism/source.h" +#include "prism/buffer.h" + +#include + +/* + * The type of source, which determines cleanup behavior. + */ +typedef enum { + /* Wraps existing constant memory, no cleanup. */ + PM_SOURCE_CONSTANT, + + /* Wraps existing shared memory (non-owning slice), no cleanup. */ + PM_SOURCE_SHARED, + + /* Owns a heap-allocated buffer, freed on cleanup. */ + PM_SOURCE_OWNED, + + /* Memory-mapped file, unmapped on cleanup. */ + PM_SOURCE_MAPPED, + + /* Stream source backed by a pm_buffer_t. */ + PM_SOURCE_STREAM +} pm_source_type_t; + +/* + * The internal representation of a source. + */ +struct pm_source_t { + /* A pointer to the start of the source data. */ + const uint8_t *source; + + /* The length of the source data in bytes. */ + size_t length; + + /* The type of the source. */ + pm_source_type_t type; + + /* Stream-specific data, only used for PM_SOURCE_STREAM sources. */ + struct { + /* The buffer that holds the accumulated stream data. */ + pm_buffer_t *buffer; + + /* The stream object to read from. */ + void *stream; + + /* The function to use to read from the stream. */ + pm_source_stream_fgets_t *fgets; + + /* The function to use to check if the stream is at EOF. */ + pm_source_stream_feof_t *feof; + + /* Whether the stream has reached EOF. */ + bool eof; + } stream; +}; + +/* + * Read from a stream into the source's internal buffer. This is used by + * pm_parse_stream to incrementally read the source. + */ +bool pm_source_stream_read(pm_source_t *source); + +/* + * Returns whether the stream source has reached EOF. + */ +bool pm_source_stream_eof(const pm_source_t *source); + +#endif diff --git a/prism/static_literals.h b/prism/internal/static_literals.h similarity index 61% rename from prism/static_literals.h rename to prism/internal/static_literals.h index 6d73e5d04f79b3..d59002ac0aeda8 100644 --- a/prism/static_literals.h +++ b/prism/internal/static_literals.h @@ -1,33 +1,25 @@ -/** - * @file static_literals.h - * - * A set of static literal nodes that can be checked for duplicates. - */ -#ifndef PRISM_STATIC_LITERALS_H -#define PRISM_STATIC_LITERALS_H +#ifndef PRISM_INTERNAL_STATIC_LITERALS_H +#define PRISM_INTERNAL_STATIC_LITERALS_H -#include "prism/defines.h" #include "prism/ast.h" -#include "prism/util/pm_line_offset_list.h" - -#include -#include +#include "prism/buffer.h" +#include "prism/line_offset_list.h" -/** +/* * An internal hash table for a set of nodes. */ typedef struct { - /** The array of nodes in the hash table. */ + /* The array of nodes in the hash table. */ pm_node_t **nodes; - /** The size of the hash table. */ + /* The size of the hash table. */ uint32_t size; - /** The space that has been allocated in the hash table. */ + /* The space that has been allocated in the hash table. */ uint32_t capacity; } pm_node_hash_t; -/** +/* * Certain sets of nodes (hash keys and when clauses) check for duplicate nodes * to alert the user of potential issues. To do this, we keep a set of the nodes * that have been seen so far, and compare whenever we find a new node. @@ -36,87 +28,70 @@ typedef struct { * that need to be performed. */ typedef struct { - /** + /* * This is the set of IntegerNode and SourceLineNode instances. */ pm_node_hash_t integer_nodes; - /** + /* * This is the set of FloatNode instances. */ pm_node_hash_t float_nodes; - /** + /* * This is the set of RationalNode and ImaginaryNode instances. */ pm_node_hash_t number_nodes; - /** + /* * This is the set of StringNode and SourceFileNode instances. */ pm_node_hash_t string_nodes; - /** + /* * This is the set of RegularExpressionNode instances. */ pm_node_hash_t regexp_nodes; - /** + /* * This is the set of SymbolNode instances. */ pm_node_hash_t symbol_nodes; - /** + /* * A pointer to the last TrueNode instance that was inserted, or NULL. */ pm_node_t *true_node; - /** + /* * A pointer to the last FalseNode instance that was inserted, or NULL. */ pm_node_t *false_node; - /** + /* * A pointer to the last NilNode instance that was inserted, or NULL. */ pm_node_t *nil_node; - /** + /* * A pointer to the last SourceEncodingNode instance that was inserted, or * NULL. */ pm_node_t *source_encoding_node; } pm_static_literals_t; -/** +/* * Add a node to the set of static literals. - * - * @param line_offsets The list of newline offsets to use to calculate lines. - * @param start The start of the source being parsed. - * @param start_line The line number that the parser starts on. - * @param literals The set of static literals to add the node to. - * @param node The node to add to the set. - * @param replace Whether to replace the previous node if one already exists. - * @return A pointer to the node that is being overwritten, if there is one. */ pm_node_t * pm_static_literals_add(const pm_line_offset_list_t *line_offsets, const uint8_t *start, int32_t start_line, pm_static_literals_t *literals, pm_node_t *node, bool replace); -/** +/* * Free the internal memory associated with the given static literals set. - * - * @param literals The set of static literals to free. */ void pm_static_literals_free(pm_static_literals_t *literals); -/** +/* * Create a string-based representation of the given static literal. - * - * @param buffer The buffer to write the string to. - * @param line_offsets The list of newline offsets to use to calculate lines. - * @param start The start of the source being parsed. - * @param start_line The line number that the parser starts on. - * @param encoding_name The name of the encoding of the source being parsed. - * @param node The node to create a string representation of. */ void pm_static_literal_inspect(pm_buffer_t *buffer, const pm_line_offset_list_t *line_offsets, const uint8_t *start, int32_t start_line, const char *encoding_name, const pm_node_t *node); diff --git a/prism/internal/stringy.h b/prism/internal/stringy.h new file mode 100644 index 00000000000000..1aaa23ea75aa6f --- /dev/null +++ b/prism/internal/stringy.h @@ -0,0 +1,30 @@ +#ifndef PRISM_INTERNAL_STRINGY_H +#define PRISM_INTERNAL_STRINGY_H + +#include "prism/stringy.h" + +/* + * Defines an empty string. This is useful for initializing a string that will + * be filled in later. + */ +#define PM_STRING_EMPTY ((pm_string_t) { .type = PM_STRING_CONSTANT, .source = NULL, .length = 0 }) + +/* + * Initialize a shared string that is based on initial input. + */ +void pm_string_shared_init(pm_string_t *string, const uint8_t *start, const uint8_t *end); + +/* + * Compare the underlying lengths and bytes of two strings. Returns 0 if the + * strings are equal, a negative number if the left string is less than the + * right string, and a positive number if the left string is greater than the + * right string. + */ +int pm_string_compare(const pm_string_t *left, const pm_string_t *right); + +/* + * Free the associated memory of the given string. + */ +void pm_string_cleanup(pm_string_t *string); + +#endif diff --git a/prism/util/pm_strncasecmp.h b/prism/internal/strncasecmp.h similarity index 51% rename from prism/util/pm_strncasecmp.h rename to prism/internal/strncasecmp.h index 5cb88cb5eb5363..775f6a993e6969 100644 --- a/prism/util/pm_strncasecmp.h +++ b/prism/internal/strncasecmp.h @@ -1,18 +1,10 @@ -/** - * @file pm_strncasecmp.h - * - * A custom strncasecmp implementation. - */ -#ifndef PRISM_STRNCASECMP_H -#define PRISM_STRNCASECMP_H +#ifndef PRISM_INTERNAL_STRNCASECMP_H +#define PRISM_INTERNAL_STRNCASECMP_H -#include "prism/defines.h" - -#include #include #include -/** +/* * Compare two strings, ignoring case, up to the given length. Returns 0 if the * strings are equal, a negative number if string1 is less than string2, or a * positive number if string1 is greater than string2. @@ -20,12 +12,6 @@ * Note that this is effectively our own implementation of strncasecmp, but it's * not available on all of the platforms we want to support so we're rolling it * here. - * - * @param string1 The first string to compare. - * @param string2 The second string to compare - * @param length The maximum number of characters to compare. - * @return 0 if the strings are equal, a negative number if string1 is less than - * string2, or a positive number if string1 is greater than string2. */ int pm_strncasecmp(const uint8_t *string1, const uint8_t *string2, size_t length); diff --git a/prism/util/pm_strpbrk.h b/prism/internal/strpbrk.h similarity index 66% rename from prism/util/pm_strpbrk.h rename to prism/internal/strpbrk.h index f387bd5782f169..d64156c002224e 100644 --- a/prism/util/pm_strpbrk.h +++ b/prism/internal/strpbrk.h @@ -1,19 +1,15 @@ -/** - * @file pm_strpbrk.h - * - * A custom strpbrk implementation. - */ -#ifndef PRISM_STRPBRK_H -#define PRISM_STRPBRK_H +#ifndef PRISM_INTERNAL_STRPBRK_H +#define PRISM_INTERNAL_STRPBRK_H -#include "prism/defines.h" -#include "prism/diagnostic.h" #include "prism/parser.h" +/* The maximum number of bytes in a strpbrk charset. */ +#define PM_STRPBRK_CACHE_SIZE 16 + #include -#include +#include -/** +/* * Here we have rolled our own version of strpbrk. The standard library strpbrk * has undefined behavior when the source string is not null-terminated. We want * to support strings that are not null-terminated because pm_parse does not @@ -31,15 +27,6 @@ * characters that are trailing bytes of multi-byte characters. For example, in * Shift-JIS, the backslash character can be a trailing byte. In that case we * need to take a slower path and iterate one multi-byte character at a time. - * - * @param parser The parser. - * @param source The source to search. - * @param charset The charset to search for. - * @param length The maximum number of bytes to search. - * @param validate Whether to validate that the source string is valid in the - * current encoding of the parser. - * @return A pointer to the first character in the source string that is in the - * charset, or NULL if no such character exists. */ const uint8_t * pm_strpbrk(pm_parser_t *parser, const uint8_t *source, const uint8_t *charset, ptrdiff_t length, bool validate); diff --git a/prism/internal/tokens.h b/prism/internal/tokens.h new file mode 100644 index 00000000000000..3a983e54ae85ee --- /dev/null +++ b/prism/internal/tokens.h @@ -0,0 +1,11 @@ +#ifndef PRISM_INTERNAL_TOKENS_H +#define PRISM_INTERNAL_TOKENS_H + +#include "prism/ast.h" + +/* + * Returns the human name of the given token type. + */ +const char * pm_token_str(pm_token_type_t token_type); + +#endif diff --git a/prism/json.c b/prism/json.c new file mode 100644 index 00000000000000..72975db72480d7 --- /dev/null +++ b/prism/json.c @@ -0,0 +1,5723 @@ +/*----------------------------------------------------------------------------*/ +/* This file is generated by the templates/template.rb script and should not */ +/* be modified manually. See */ +/* templates/src/json.c.erb */ +/* if you are looking to modify the */ +/* template */ +/*----------------------------------------------------------------------------*/ + +#include "prism/json.h" + +// Ensure this translation unit is never empty, even when JSON is excluded. +typedef int pm_json_unused_t; + +#ifndef PRISM_EXCLUDE_JSON + +#include "prism/internal/buffer.h" +#include "prism/internal/constant_pool.h" +#include "prism/internal/integer.h" +#include "prism/internal/parser.h" + +#include + +static void +pm_dump_json_constant(pm_buffer_t *buffer, const pm_parser_t *parser, pm_constant_id_t constant_id) { + const pm_constant_t *constant = pm_constant_pool_id_to_constant(&parser->constant_pool, constant_id); + pm_buffer_append_byte(buffer, '"'); + pm_buffer_append_source(buffer, constant->start, constant->length, PM_BUFFER_ESCAPING_JSON); + pm_buffer_append_byte(buffer, '"'); +} + +static void +pm_dump_json_location(pm_buffer_t *buffer, const pm_location_t *location) { + pm_buffer_append_format(buffer, "{\"start\":%" PRIu32 ",\"length\":%" PRIu32 "}", location->start, location->length); +} + +/** + * Dump JSON to the given buffer. + */ +void +pm_dump_json(pm_buffer_t *buffer, const pm_parser_t *parser, const pm_node_t *node) { + switch (PM_NODE_TYPE(node)) { + case PM_ALIAS_GLOBAL_VARIABLE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"AliasGlobalVariableNode\",\"location\":", 45); + + const pm_alias_global_variable_node_t *cast = (const pm_alias_global_variable_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the new_name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"new_name\":", 11); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->new_name); + + // Dump the old_name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"old_name\":", 11); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->old_name); + + // Dump the keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"keyword_loc\":", 14); + pm_dump_json_location(buffer, &cast->keyword_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_ALIAS_METHOD_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"AliasMethodNode\",\"location\":", 37); + + const pm_alias_method_node_t *cast = (const pm_alias_method_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the new_name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"new_name\":", 11); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->new_name); + + // Dump the old_name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"old_name\":", 11); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->old_name); + + // Dump the keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"keyword_loc\":", 14); + pm_dump_json_location(buffer, &cast->keyword_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_ALTERNATION_PATTERN_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"AlternationPatternNode\",\"location\":", 44); + + const pm_alternation_pattern_node_t *cast = (const pm_alternation_pattern_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the left field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"left\":", 7); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->left); + + // Dump the right field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"right\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->right); + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_AND_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"AndNode\",\"location\":", 29); + + const pm_and_node_t *cast = (const pm_and_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the left field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"left\":", 7); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->left); + + // Dump the right field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"right\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->right); + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_ARGUMENTS_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"ArgumentsNode\",\"location\":", 35); + + const pm_arguments_node_t *cast = (const pm_arguments_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the ArgumentsNodeFlags field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"flags\":", 8); + size_t flags = 0; + pm_buffer_append_byte(buffer, '['); + if (PM_NODE_FLAG_P(cast, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_FORWARDING)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"CONTAINS_FORWARDING\"", 21); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"CONTAINS_KEYWORDS\"", 19); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"CONTAINS_KEYWORD_SPLAT\"", 24); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"CONTAINS_SPLAT\"", 16); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_MULTIPLE_SPLATS)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"CONTAINS_MULTIPLE_SPLATS\"", 26); + flags++; + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the arguments field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"arguments\":", 12); + const pm_node_list_t *arguments = &cast->arguments; + pm_buffer_append_byte(buffer, '['); + + for (size_t index = 0; index < arguments->size; index++) { + if (index != 0) pm_buffer_append_byte(buffer, ','); + pm_dump_json(buffer, parser, arguments->nodes[index]); + } + pm_buffer_append_byte(buffer, ']'); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_ARRAY_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"ArrayNode\",\"location\":", 31); + + const pm_array_node_t *cast = (const pm_array_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the ArrayNodeFlags field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"flags\":", 8); + size_t flags = 0; + pm_buffer_append_byte(buffer, '['); + if (PM_NODE_FLAG_P(cast, PM_ARRAY_NODE_FLAGS_CONTAINS_SPLAT)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"CONTAINS_SPLAT\"", 16); + flags++; + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the elements field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"elements\":", 11); + const pm_node_list_t *elements = &cast->elements; + pm_buffer_append_byte(buffer, '['); + + for (size_t index = 0; index < elements->size; index++) { + if (index != 0) pm_buffer_append_byte(buffer, ','); + pm_dump_json(buffer, parser, elements->nodes[index]); + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the opening_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"opening_loc\":", 14); + if (cast->opening_loc.length != 0) { + pm_dump_json_location(buffer, &cast->opening_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the closing_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"closing_loc\":", 14); + if (cast->closing_loc.length != 0) { + pm_dump_json_location(buffer, &cast->closing_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_ARRAY_PATTERN_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"ArrayPatternNode\",\"location\":", 38); + + const pm_array_pattern_node_t *cast = (const pm_array_pattern_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the constant field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"constant\":", 11); + if (cast->constant != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->constant); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the requireds field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"requireds\":", 12); + const pm_node_list_t *requireds = &cast->requireds; + pm_buffer_append_byte(buffer, '['); + + for (size_t index = 0; index < requireds->size; index++) { + if (index != 0) pm_buffer_append_byte(buffer, ','); + pm_dump_json(buffer, parser, requireds->nodes[index]); + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the rest field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"rest\":", 7); + if (cast->rest != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->rest); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the posts field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"posts\":", 8); + const pm_node_list_t *posts = &cast->posts; + pm_buffer_append_byte(buffer, '['); + + for (size_t index = 0; index < posts->size; index++) { + if (index != 0) pm_buffer_append_byte(buffer, ','); + pm_dump_json(buffer, parser, posts->nodes[index]); + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the opening_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"opening_loc\":", 14); + if (cast->opening_loc.length != 0) { + pm_dump_json_location(buffer, &cast->opening_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the closing_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"closing_loc\":", 14); + if (cast->closing_loc.length != 0) { + pm_dump_json_location(buffer, &cast->closing_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_ASSOC_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"AssocNode\",\"location\":", 31); + + const pm_assoc_node_t *cast = (const pm_assoc_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the key field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"key\":", 6); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->key); + + // Dump the value field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"value\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + if (cast->operator_loc.length != 0) { + pm_dump_json_location(buffer, &cast->operator_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_ASSOC_SPLAT_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"AssocSplatNode\",\"location\":", 36); + + const pm_assoc_splat_node_t *cast = (const pm_assoc_splat_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the value field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"value\":", 8); + if (cast->value != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_BACK_REFERENCE_READ_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"BackReferenceReadNode\",\"location\":", 43); + + const pm_back_reference_read_node_t *cast = (const pm_back_reference_read_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + pm_dump_json_constant(buffer, parser, cast->name); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_BEGIN_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"BeginNode\",\"location\":", 31); + + const pm_begin_node_t *cast = (const pm_begin_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the begin_keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"begin_keyword_loc\":", 20); + if (cast->begin_keyword_loc.length != 0) { + pm_dump_json_location(buffer, &cast->begin_keyword_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the statements field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"statements\":", 13); + if (cast->statements != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the rescue_clause field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"rescue_clause\":", 16); + if (cast->rescue_clause != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->rescue_clause); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the else_clause field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"else_clause\":", 14); + if (cast->else_clause != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->else_clause); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the ensure_clause field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"ensure_clause\":", 16); + if (cast->ensure_clause != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->ensure_clause); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the end_keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"end_keyword_loc\":", 18); + if (cast->end_keyword_loc.length != 0) { + pm_dump_json_location(buffer, &cast->end_keyword_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_BLOCK_ARGUMENT_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"BlockArgumentNode\",\"location\":", 39); + + const pm_block_argument_node_t *cast = (const pm_block_argument_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the expression field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"expression\":", 13); + if (cast->expression != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->expression); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_BLOCK_LOCAL_VARIABLE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"BlockLocalVariableNode\",\"location\":", 44); + + const pm_block_local_variable_node_t *cast = (const pm_block_local_variable_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the ParameterFlags field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"flags\":", 8); + size_t flags = 0; + pm_buffer_append_byte(buffer, '['); + if (PM_NODE_FLAG_P(cast, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"REPEATED_PARAMETER\"", 20); + flags++; + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + pm_dump_json_constant(buffer, parser, cast->name); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_BLOCK_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"BlockNode\",\"location\":", 31); + + const pm_block_node_t *cast = (const pm_block_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the locals field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"locals\":", 9); + const pm_constant_id_list_t *locals = &cast->locals; + pm_buffer_append_byte(buffer, '['); + + for (size_t index = 0; index < locals->size; index++) { + if (index != 0) pm_buffer_append_byte(buffer, ','); + pm_dump_json_constant(buffer, parser, locals->ids[index]); + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the parameters field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"parameters\":", 13); + if (cast->parameters != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->parameters); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the body field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"body\":", 7); + if (cast->body != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->body); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the opening_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"opening_loc\":", 14); + pm_dump_json_location(buffer, &cast->opening_loc); + + // Dump the closing_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"closing_loc\":", 14); + pm_dump_json_location(buffer, &cast->closing_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_BLOCK_PARAMETER_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"BlockParameterNode\",\"location\":", 40); + + const pm_block_parameter_node_t *cast = (const pm_block_parameter_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the ParameterFlags field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"flags\":", 8); + size_t flags = 0; + pm_buffer_append_byte(buffer, '['); + if (PM_NODE_FLAG_P(cast, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"REPEATED_PARAMETER\"", 20); + flags++; + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + if (cast->name != PM_CONSTANT_ID_UNSET) { + pm_dump_json_constant(buffer, parser, cast->name); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the name_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name_loc\":", 11); + if (cast->name_loc.length != 0) { + pm_dump_json_location(buffer, &cast->name_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_BLOCK_PARAMETERS_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"BlockParametersNode\",\"location\":", 41); + + const pm_block_parameters_node_t *cast = (const pm_block_parameters_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the parameters field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"parameters\":", 13); + if (cast->parameters != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->parameters); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the locals field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"locals\":", 9); + const pm_node_list_t *locals = &cast->locals; + pm_buffer_append_byte(buffer, '['); + + for (size_t index = 0; index < locals->size; index++) { + if (index != 0) pm_buffer_append_byte(buffer, ','); + pm_dump_json(buffer, parser, locals->nodes[index]); + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the opening_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"opening_loc\":", 14); + if (cast->opening_loc.length != 0) { + pm_dump_json_location(buffer, &cast->opening_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the closing_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"closing_loc\":", 14); + if (cast->closing_loc.length != 0) { + pm_dump_json_location(buffer, &cast->closing_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_BREAK_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"BreakNode\",\"location\":", 31); + + const pm_break_node_t *cast = (const pm_break_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the arguments field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"arguments\":", 12); + if (cast->arguments != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->arguments); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"keyword_loc\":", 14); + pm_dump_json_location(buffer, &cast->keyword_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_CALL_AND_WRITE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"CallAndWriteNode\",\"location\":", 38); + + const pm_call_and_write_node_t *cast = (const pm_call_and_write_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the CallNodeFlags field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"flags\":", 8); + size_t flags = 0; + pm_buffer_append_byte(buffer, '['); + if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"SAFE_NAVIGATION\"", 17); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"VARIABLE_CALL\"", 15); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"ATTRIBUTE_WRITE\"", 17); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"IGNORE_VISIBILITY\"", 19); + flags++; + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the receiver field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"receiver\":", 11); + if (cast->receiver != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->receiver); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the call_operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"call_operator_loc\":", 20); + if (cast->call_operator_loc.length != 0) { + pm_dump_json_location(buffer, &cast->call_operator_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the message_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"message_loc\":", 14); + if (cast->message_loc.length != 0) { + pm_dump_json_location(buffer, &cast->message_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the read_name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"read_name\":", 12); + pm_dump_json_constant(buffer, parser, cast->read_name); + + // Dump the write_name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"write_name\":", 13); + pm_dump_json_constant(buffer, parser, cast->write_name); + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + // Dump the value field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"value\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_CALL_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"CallNode\",\"location\":", 30); + + const pm_call_node_t *cast = (const pm_call_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the CallNodeFlags field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"flags\":", 8); + size_t flags = 0; + pm_buffer_append_byte(buffer, '['); + if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"SAFE_NAVIGATION\"", 17); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"VARIABLE_CALL\"", 15); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"ATTRIBUTE_WRITE\"", 17); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"IGNORE_VISIBILITY\"", 19); + flags++; + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the receiver field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"receiver\":", 11); + if (cast->receiver != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->receiver); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the call_operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"call_operator_loc\":", 20); + if (cast->call_operator_loc.length != 0) { + pm_dump_json_location(buffer, &cast->call_operator_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + pm_dump_json_constant(buffer, parser, cast->name); + + // Dump the message_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"message_loc\":", 14); + if (cast->message_loc.length != 0) { + pm_dump_json_location(buffer, &cast->message_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the opening_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"opening_loc\":", 14); + if (cast->opening_loc.length != 0) { + pm_dump_json_location(buffer, &cast->opening_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the arguments field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"arguments\":", 12); + if (cast->arguments != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->arguments); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the closing_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"closing_loc\":", 14); + if (cast->closing_loc.length != 0) { + pm_dump_json_location(buffer, &cast->closing_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the equal_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"equal_loc\":", 12); + if (cast->equal_loc.length != 0) { + pm_dump_json_location(buffer, &cast->equal_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the block field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"block\":", 8); + if (cast->block != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->block); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_CALL_OPERATOR_WRITE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"CallOperatorWriteNode\",\"location\":", 43); + + const pm_call_operator_write_node_t *cast = (const pm_call_operator_write_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the CallNodeFlags field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"flags\":", 8); + size_t flags = 0; + pm_buffer_append_byte(buffer, '['); + if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"SAFE_NAVIGATION\"", 17); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"VARIABLE_CALL\"", 15); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"ATTRIBUTE_WRITE\"", 17); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"IGNORE_VISIBILITY\"", 19); + flags++; + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the receiver field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"receiver\":", 11); + if (cast->receiver != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->receiver); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the call_operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"call_operator_loc\":", 20); + if (cast->call_operator_loc.length != 0) { + pm_dump_json_location(buffer, &cast->call_operator_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the message_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"message_loc\":", 14); + if (cast->message_loc.length != 0) { + pm_dump_json_location(buffer, &cast->message_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the read_name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"read_name\":", 12); + pm_dump_json_constant(buffer, parser, cast->read_name); + + // Dump the write_name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"write_name\":", 13); + pm_dump_json_constant(buffer, parser, cast->write_name); + + // Dump the binary_operator field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"binary_operator\":", 18); + pm_dump_json_constant(buffer, parser, cast->binary_operator); + + // Dump the binary_operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"binary_operator_loc\":", 22); + pm_dump_json_location(buffer, &cast->binary_operator_loc); + + // Dump the value field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"value\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_CALL_OR_WRITE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"CallOrWriteNode\",\"location\":", 37); + + const pm_call_or_write_node_t *cast = (const pm_call_or_write_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the CallNodeFlags field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"flags\":", 8); + size_t flags = 0; + pm_buffer_append_byte(buffer, '['); + if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"SAFE_NAVIGATION\"", 17); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"VARIABLE_CALL\"", 15); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"ATTRIBUTE_WRITE\"", 17); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"IGNORE_VISIBILITY\"", 19); + flags++; + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the receiver field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"receiver\":", 11); + if (cast->receiver != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->receiver); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the call_operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"call_operator_loc\":", 20); + if (cast->call_operator_loc.length != 0) { + pm_dump_json_location(buffer, &cast->call_operator_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the message_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"message_loc\":", 14); + if (cast->message_loc.length != 0) { + pm_dump_json_location(buffer, &cast->message_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the read_name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"read_name\":", 12); + pm_dump_json_constant(buffer, parser, cast->read_name); + + // Dump the write_name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"write_name\":", 13); + pm_dump_json_constant(buffer, parser, cast->write_name); + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + // Dump the value field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"value\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_CALL_TARGET_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"CallTargetNode\",\"location\":", 36); + + const pm_call_target_node_t *cast = (const pm_call_target_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the CallNodeFlags field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"flags\":", 8); + size_t flags = 0; + pm_buffer_append_byte(buffer, '['); + if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"SAFE_NAVIGATION\"", 17); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"VARIABLE_CALL\"", 15); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"ATTRIBUTE_WRITE\"", 17); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"IGNORE_VISIBILITY\"", 19); + flags++; + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the receiver field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"receiver\":", 11); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->receiver); + + // Dump the call_operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"call_operator_loc\":", 20); + pm_dump_json_location(buffer, &cast->call_operator_loc); + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + pm_dump_json_constant(buffer, parser, cast->name); + + // Dump the message_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"message_loc\":", 14); + pm_dump_json_location(buffer, &cast->message_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_CAPTURE_PATTERN_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"CapturePatternNode\",\"location\":", 40); + + const pm_capture_pattern_node_t *cast = (const pm_capture_pattern_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the value field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"value\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); + + // Dump the target field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"target\":", 9); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->target); + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_CASE_MATCH_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"CaseMatchNode\",\"location\":", 35); + + const pm_case_match_node_t *cast = (const pm_case_match_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the predicate field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"predicate\":", 12); + if (cast->predicate != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->predicate); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the conditions field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"conditions\":", 13); + const pm_node_list_t *conditions = &cast->conditions; + pm_buffer_append_byte(buffer, '['); + + for (size_t index = 0; index < conditions->size; index++) { + if (index != 0) pm_buffer_append_byte(buffer, ','); + pm_dump_json(buffer, parser, conditions->nodes[index]); + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the else_clause field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"else_clause\":", 14); + if (cast->else_clause != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->else_clause); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the case_keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"case_keyword_loc\":", 19); + pm_dump_json_location(buffer, &cast->case_keyword_loc); + + // Dump the end_keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"end_keyword_loc\":", 18); + pm_dump_json_location(buffer, &cast->end_keyword_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_CASE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"CaseNode\",\"location\":", 30); + + const pm_case_node_t *cast = (const pm_case_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the predicate field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"predicate\":", 12); + if (cast->predicate != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->predicate); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the conditions field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"conditions\":", 13); + const pm_node_list_t *conditions = &cast->conditions; + pm_buffer_append_byte(buffer, '['); + + for (size_t index = 0; index < conditions->size; index++) { + if (index != 0) pm_buffer_append_byte(buffer, ','); + pm_dump_json(buffer, parser, conditions->nodes[index]); + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the else_clause field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"else_clause\":", 14); + if (cast->else_clause != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->else_clause); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the case_keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"case_keyword_loc\":", 19); + pm_dump_json_location(buffer, &cast->case_keyword_loc); + + // Dump the end_keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"end_keyword_loc\":", 18); + pm_dump_json_location(buffer, &cast->end_keyword_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_CLASS_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"ClassNode\",\"location\":", 31); + + const pm_class_node_t *cast = (const pm_class_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the locals field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"locals\":", 9); + const pm_constant_id_list_t *locals = &cast->locals; + pm_buffer_append_byte(buffer, '['); + + for (size_t index = 0; index < locals->size; index++) { + if (index != 0) pm_buffer_append_byte(buffer, ','); + pm_dump_json_constant(buffer, parser, locals->ids[index]); + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the class_keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"class_keyword_loc\":", 20); + pm_dump_json_location(buffer, &cast->class_keyword_loc); + + // Dump the constant_path field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"constant_path\":", 16); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->constant_path); + + // Dump the inheritance_operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"inheritance_operator_loc\":", 27); + if (cast->inheritance_operator_loc.length != 0) { + pm_dump_json_location(buffer, &cast->inheritance_operator_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the superclass field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"superclass\":", 13); + if (cast->superclass != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->superclass); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the body field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"body\":", 7); + if (cast->body != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->body); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the end_keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"end_keyword_loc\":", 18); + pm_dump_json_location(buffer, &cast->end_keyword_loc); + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + pm_dump_json_constant(buffer, parser, cast->name); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_CLASS_VARIABLE_AND_WRITE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"ClassVariableAndWriteNode\",\"location\":", 47); + + const pm_class_variable_and_write_node_t *cast = (const pm_class_variable_and_write_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + pm_dump_json_constant(buffer, parser, cast->name); + + // Dump the name_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name_loc\":", 11); + pm_dump_json_location(buffer, &cast->name_loc); + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + // Dump the value field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"value\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_CLASS_VARIABLE_OPERATOR_WRITE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"ClassVariableOperatorWriteNode\",\"location\":", 52); + + const pm_class_variable_operator_write_node_t *cast = (const pm_class_variable_operator_write_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + pm_dump_json_constant(buffer, parser, cast->name); + + // Dump the name_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name_loc\":", 11); + pm_dump_json_location(buffer, &cast->name_loc); + + // Dump the binary_operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"binary_operator_loc\":", 22); + pm_dump_json_location(buffer, &cast->binary_operator_loc); + + // Dump the value field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"value\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); + + // Dump the binary_operator field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"binary_operator\":", 18); + pm_dump_json_constant(buffer, parser, cast->binary_operator); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_CLASS_VARIABLE_OR_WRITE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"ClassVariableOrWriteNode\",\"location\":", 46); + + const pm_class_variable_or_write_node_t *cast = (const pm_class_variable_or_write_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + pm_dump_json_constant(buffer, parser, cast->name); + + // Dump the name_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name_loc\":", 11); + pm_dump_json_location(buffer, &cast->name_loc); + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + // Dump the value field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"value\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_CLASS_VARIABLE_READ_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"ClassVariableReadNode\",\"location\":", 43); + + const pm_class_variable_read_node_t *cast = (const pm_class_variable_read_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + pm_dump_json_constant(buffer, parser, cast->name); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_CLASS_VARIABLE_TARGET_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"ClassVariableTargetNode\",\"location\":", 45); + + const pm_class_variable_target_node_t *cast = (const pm_class_variable_target_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + pm_dump_json_constant(buffer, parser, cast->name); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_CLASS_VARIABLE_WRITE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"ClassVariableWriteNode\",\"location\":", 44); + + const pm_class_variable_write_node_t *cast = (const pm_class_variable_write_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + pm_dump_json_constant(buffer, parser, cast->name); + + // Dump the name_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name_loc\":", 11); + pm_dump_json_location(buffer, &cast->name_loc); + + // Dump the value field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"value\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_CONSTANT_AND_WRITE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"ConstantAndWriteNode\",\"location\":", 42); + + const pm_constant_and_write_node_t *cast = (const pm_constant_and_write_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + pm_dump_json_constant(buffer, parser, cast->name); + + // Dump the name_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name_loc\":", 11); + pm_dump_json_location(buffer, &cast->name_loc); + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + // Dump the value field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"value\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_CONSTANT_OPERATOR_WRITE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"ConstantOperatorWriteNode\",\"location\":", 47); + + const pm_constant_operator_write_node_t *cast = (const pm_constant_operator_write_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + pm_dump_json_constant(buffer, parser, cast->name); + + // Dump the name_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name_loc\":", 11); + pm_dump_json_location(buffer, &cast->name_loc); + + // Dump the binary_operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"binary_operator_loc\":", 22); + pm_dump_json_location(buffer, &cast->binary_operator_loc); + + // Dump the value field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"value\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); + + // Dump the binary_operator field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"binary_operator\":", 18); + pm_dump_json_constant(buffer, parser, cast->binary_operator); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_CONSTANT_OR_WRITE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"ConstantOrWriteNode\",\"location\":", 41); + + const pm_constant_or_write_node_t *cast = (const pm_constant_or_write_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + pm_dump_json_constant(buffer, parser, cast->name); + + // Dump the name_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name_loc\":", 11); + pm_dump_json_location(buffer, &cast->name_loc); + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + // Dump the value field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"value\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_CONSTANT_PATH_AND_WRITE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"ConstantPathAndWriteNode\",\"location\":", 46); + + const pm_constant_path_and_write_node_t *cast = (const pm_constant_path_and_write_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the target field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"target\":", 9); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->target); + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + // Dump the value field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"value\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_CONSTANT_PATH_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"ConstantPathNode\",\"location\":", 38); + + const pm_constant_path_node_t *cast = (const pm_constant_path_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the parent field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"parent\":", 9); + if (cast->parent != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->parent); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + if (cast->name != PM_CONSTANT_ID_UNSET) { + pm_dump_json_constant(buffer, parser, cast->name); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the delimiter_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"delimiter_loc\":", 16); + pm_dump_json_location(buffer, &cast->delimiter_loc); + + // Dump the name_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name_loc\":", 11); + pm_dump_json_location(buffer, &cast->name_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_CONSTANT_PATH_OPERATOR_WRITE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"ConstantPathOperatorWriteNode\",\"location\":", 51); + + const pm_constant_path_operator_write_node_t *cast = (const pm_constant_path_operator_write_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the target field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"target\":", 9); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->target); + + // Dump the binary_operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"binary_operator_loc\":", 22); + pm_dump_json_location(buffer, &cast->binary_operator_loc); + + // Dump the value field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"value\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); + + // Dump the binary_operator field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"binary_operator\":", 18); + pm_dump_json_constant(buffer, parser, cast->binary_operator); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_CONSTANT_PATH_OR_WRITE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"ConstantPathOrWriteNode\",\"location\":", 45); + + const pm_constant_path_or_write_node_t *cast = (const pm_constant_path_or_write_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the target field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"target\":", 9); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->target); + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + // Dump the value field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"value\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_CONSTANT_PATH_TARGET_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"ConstantPathTargetNode\",\"location\":", 44); + + const pm_constant_path_target_node_t *cast = (const pm_constant_path_target_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the parent field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"parent\":", 9); + if (cast->parent != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->parent); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + if (cast->name != PM_CONSTANT_ID_UNSET) { + pm_dump_json_constant(buffer, parser, cast->name); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the delimiter_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"delimiter_loc\":", 16); + pm_dump_json_location(buffer, &cast->delimiter_loc); + + // Dump the name_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name_loc\":", 11); + pm_dump_json_location(buffer, &cast->name_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_CONSTANT_PATH_WRITE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"ConstantPathWriteNode\",\"location\":", 43); + + const pm_constant_path_write_node_t *cast = (const pm_constant_path_write_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the target field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"target\":", 9); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->target); + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + // Dump the value field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"value\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_CONSTANT_READ_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"ConstantReadNode\",\"location\":", 38); + + const pm_constant_read_node_t *cast = (const pm_constant_read_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + pm_dump_json_constant(buffer, parser, cast->name); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_CONSTANT_TARGET_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"ConstantTargetNode\",\"location\":", 40); + + const pm_constant_target_node_t *cast = (const pm_constant_target_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + pm_dump_json_constant(buffer, parser, cast->name); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_CONSTANT_WRITE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"ConstantWriteNode\",\"location\":", 39); + + const pm_constant_write_node_t *cast = (const pm_constant_write_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + pm_dump_json_constant(buffer, parser, cast->name); + + // Dump the name_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name_loc\":", 11); + pm_dump_json_location(buffer, &cast->name_loc); + + // Dump the value field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"value\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_DEF_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"DefNode\",\"location\":", 29); + + const pm_def_node_t *cast = (const pm_def_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + pm_dump_json_constant(buffer, parser, cast->name); + + // Dump the name_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name_loc\":", 11); + pm_dump_json_location(buffer, &cast->name_loc); + + // Dump the receiver field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"receiver\":", 11); + if (cast->receiver != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->receiver); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the parameters field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"parameters\":", 13); + if (cast->parameters != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->parameters); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the body field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"body\":", 7); + if (cast->body != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->body); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the locals field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"locals\":", 9); + const pm_constant_id_list_t *locals = &cast->locals; + pm_buffer_append_byte(buffer, '['); + + for (size_t index = 0; index < locals->size; index++) { + if (index != 0) pm_buffer_append_byte(buffer, ','); + pm_dump_json_constant(buffer, parser, locals->ids[index]); + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the def_keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"def_keyword_loc\":", 18); + pm_dump_json_location(buffer, &cast->def_keyword_loc); + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + if (cast->operator_loc.length != 0) { + pm_dump_json_location(buffer, &cast->operator_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the lparen_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"lparen_loc\":", 13); + if (cast->lparen_loc.length != 0) { + pm_dump_json_location(buffer, &cast->lparen_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the rparen_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"rparen_loc\":", 13); + if (cast->rparen_loc.length != 0) { + pm_dump_json_location(buffer, &cast->rparen_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the equal_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"equal_loc\":", 12); + if (cast->equal_loc.length != 0) { + pm_dump_json_location(buffer, &cast->equal_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the end_keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"end_keyword_loc\":", 18); + if (cast->end_keyword_loc.length != 0) { + pm_dump_json_location(buffer, &cast->end_keyword_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_DEFINED_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"DefinedNode\",\"location\":", 33); + + const pm_defined_node_t *cast = (const pm_defined_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the lparen_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"lparen_loc\":", 13); + if (cast->lparen_loc.length != 0) { + pm_dump_json_location(buffer, &cast->lparen_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the value field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"value\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); + + // Dump the rparen_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"rparen_loc\":", 13); + if (cast->rparen_loc.length != 0) { + pm_dump_json_location(buffer, &cast->rparen_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"keyword_loc\":", 14); + pm_dump_json_location(buffer, &cast->keyword_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_ELSE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"ElseNode\",\"location\":", 30); + + const pm_else_node_t *cast = (const pm_else_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the else_keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"else_keyword_loc\":", 19); + pm_dump_json_location(buffer, &cast->else_keyword_loc); + + // Dump the statements field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"statements\":", 13); + if (cast->statements != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the end_keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"end_keyword_loc\":", 18); + if (cast->end_keyword_loc.length != 0) { + pm_dump_json_location(buffer, &cast->end_keyword_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_EMBEDDED_STATEMENTS_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"EmbeddedStatementsNode\",\"location\":", 44); + + const pm_embedded_statements_node_t *cast = (const pm_embedded_statements_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the opening_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"opening_loc\":", 14); + pm_dump_json_location(buffer, &cast->opening_loc); + + // Dump the statements field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"statements\":", 13); + if (cast->statements != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the closing_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"closing_loc\":", 14); + pm_dump_json_location(buffer, &cast->closing_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_EMBEDDED_VARIABLE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"EmbeddedVariableNode\",\"location\":", 42); + + const pm_embedded_variable_node_t *cast = (const pm_embedded_variable_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + // Dump the variable field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"variable\":", 11); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->variable); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_ENSURE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"EnsureNode\",\"location\":", 32); + + const pm_ensure_node_t *cast = (const pm_ensure_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the ensure_keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"ensure_keyword_loc\":", 21); + pm_dump_json_location(buffer, &cast->ensure_keyword_loc); + + // Dump the statements field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"statements\":", 13); + if (cast->statements != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the end_keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"end_keyword_loc\":", 18); + pm_dump_json_location(buffer, &cast->end_keyword_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_FALSE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"FalseNode\",\"location\":", 31); + + const pm_false_node_t *cast = (const pm_false_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_FIND_PATTERN_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"FindPatternNode\",\"location\":", 37); + + const pm_find_pattern_node_t *cast = (const pm_find_pattern_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the constant field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"constant\":", 11); + if (cast->constant != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->constant); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the left field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"left\":", 7); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->left); + + // Dump the requireds field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"requireds\":", 12); + const pm_node_list_t *requireds = &cast->requireds; + pm_buffer_append_byte(buffer, '['); + + for (size_t index = 0; index < requireds->size; index++) { + if (index != 0) pm_buffer_append_byte(buffer, ','); + pm_dump_json(buffer, parser, requireds->nodes[index]); + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the right field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"right\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->right); + + // Dump the opening_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"opening_loc\":", 14); + if (cast->opening_loc.length != 0) { + pm_dump_json_location(buffer, &cast->opening_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the closing_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"closing_loc\":", 14); + if (cast->closing_loc.length != 0) { + pm_dump_json_location(buffer, &cast->closing_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_FLIP_FLOP_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"FlipFlopNode\",\"location\":", 34); + + const pm_flip_flop_node_t *cast = (const pm_flip_flop_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the RangeFlags field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"flags\":", 8); + size_t flags = 0; + pm_buffer_append_byte(buffer, '['); + if (PM_NODE_FLAG_P(cast, PM_RANGE_FLAGS_EXCLUDE_END)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"EXCLUDE_END\"", 13); + flags++; + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the left field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"left\":", 7); + if (cast->left != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->left); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the right field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"right\":", 8); + if (cast->right != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->right); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_FLOAT_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"FloatNode\",\"location\":", 31); + + const pm_float_node_t *cast = (const pm_float_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the value field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"value\":", 8); + pm_buffer_append_format(buffer, "%f", cast->value); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_FOR_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"ForNode\",\"location\":", 29); + + const pm_for_node_t *cast = (const pm_for_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the index field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"index\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->index); + + // Dump the collection field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"collection\":", 13); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->collection); + + // Dump the statements field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"statements\":", 13); + if (cast->statements != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the for_keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"for_keyword_loc\":", 18); + pm_dump_json_location(buffer, &cast->for_keyword_loc); + + // Dump the in_keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"in_keyword_loc\":", 17); + pm_dump_json_location(buffer, &cast->in_keyword_loc); + + // Dump the do_keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"do_keyword_loc\":", 17); + if (cast->do_keyword_loc.length != 0) { + pm_dump_json_location(buffer, &cast->do_keyword_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the end_keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"end_keyword_loc\":", 18); + pm_dump_json_location(buffer, &cast->end_keyword_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_FORWARDING_ARGUMENTS_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"ForwardingArgumentsNode\",\"location\":", 45); + + const pm_forwarding_arguments_node_t *cast = (const pm_forwarding_arguments_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_FORWARDING_PARAMETER_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"ForwardingParameterNode\",\"location\":", 45); + + const pm_forwarding_parameter_node_t *cast = (const pm_forwarding_parameter_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_FORWARDING_SUPER_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"ForwardingSuperNode\",\"location\":", 41); + + const pm_forwarding_super_node_t *cast = (const pm_forwarding_super_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the block field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"block\":", 8); + if (cast->block != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->block); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_GLOBAL_VARIABLE_AND_WRITE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"GlobalVariableAndWriteNode\",\"location\":", 48); + + const pm_global_variable_and_write_node_t *cast = (const pm_global_variable_and_write_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + pm_dump_json_constant(buffer, parser, cast->name); + + // Dump the name_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name_loc\":", 11); + pm_dump_json_location(buffer, &cast->name_loc); + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + // Dump the value field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"value\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"GlobalVariableOperatorWriteNode\",\"location\":", 53); + + const pm_global_variable_operator_write_node_t *cast = (const pm_global_variable_operator_write_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + pm_dump_json_constant(buffer, parser, cast->name); + + // Dump the name_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name_loc\":", 11); + pm_dump_json_location(buffer, &cast->name_loc); + + // Dump the binary_operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"binary_operator_loc\":", 22); + pm_dump_json_location(buffer, &cast->binary_operator_loc); + + // Dump the value field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"value\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); + + // Dump the binary_operator field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"binary_operator\":", 18); + pm_dump_json_constant(buffer, parser, cast->binary_operator); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_GLOBAL_VARIABLE_OR_WRITE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"GlobalVariableOrWriteNode\",\"location\":", 47); + + const pm_global_variable_or_write_node_t *cast = (const pm_global_variable_or_write_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + pm_dump_json_constant(buffer, parser, cast->name); + + // Dump the name_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name_loc\":", 11); + pm_dump_json_location(buffer, &cast->name_loc); + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + // Dump the value field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"value\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_GLOBAL_VARIABLE_READ_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"GlobalVariableReadNode\",\"location\":", 44); + + const pm_global_variable_read_node_t *cast = (const pm_global_variable_read_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + pm_dump_json_constant(buffer, parser, cast->name); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_GLOBAL_VARIABLE_TARGET_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"GlobalVariableTargetNode\",\"location\":", 46); + + const pm_global_variable_target_node_t *cast = (const pm_global_variable_target_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + pm_dump_json_constant(buffer, parser, cast->name); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_GLOBAL_VARIABLE_WRITE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"GlobalVariableWriteNode\",\"location\":", 45); + + const pm_global_variable_write_node_t *cast = (const pm_global_variable_write_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + pm_dump_json_constant(buffer, parser, cast->name); + + // Dump the name_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name_loc\":", 11); + pm_dump_json_location(buffer, &cast->name_loc); + + // Dump the value field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"value\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_HASH_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"HashNode\",\"location\":", 30); + + const pm_hash_node_t *cast = (const pm_hash_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the opening_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"opening_loc\":", 14); + pm_dump_json_location(buffer, &cast->opening_loc); + + // Dump the elements field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"elements\":", 11); + const pm_node_list_t *elements = &cast->elements; + pm_buffer_append_byte(buffer, '['); + + for (size_t index = 0; index < elements->size; index++) { + if (index != 0) pm_buffer_append_byte(buffer, ','); + pm_dump_json(buffer, parser, elements->nodes[index]); + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the closing_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"closing_loc\":", 14); + pm_dump_json_location(buffer, &cast->closing_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_HASH_PATTERN_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"HashPatternNode\",\"location\":", 37); + + const pm_hash_pattern_node_t *cast = (const pm_hash_pattern_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the constant field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"constant\":", 11); + if (cast->constant != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->constant); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the elements field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"elements\":", 11); + const pm_node_list_t *elements = &cast->elements; + pm_buffer_append_byte(buffer, '['); + + for (size_t index = 0; index < elements->size; index++) { + if (index != 0) pm_buffer_append_byte(buffer, ','); + pm_dump_json(buffer, parser, elements->nodes[index]); + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the rest field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"rest\":", 7); + if (cast->rest != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->rest); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the opening_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"opening_loc\":", 14); + if (cast->opening_loc.length != 0) { + pm_dump_json_location(buffer, &cast->opening_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the closing_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"closing_loc\":", 14); + if (cast->closing_loc.length != 0) { + pm_dump_json_location(buffer, &cast->closing_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_IF_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"IfNode\",\"location\":", 28); + + const pm_if_node_t *cast = (const pm_if_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the if_keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"if_keyword_loc\":", 17); + if (cast->if_keyword_loc.length != 0) { + pm_dump_json_location(buffer, &cast->if_keyword_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the predicate field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"predicate\":", 12); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->predicate); + + // Dump the then_keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"then_keyword_loc\":", 19); + if (cast->then_keyword_loc.length != 0) { + pm_dump_json_location(buffer, &cast->then_keyword_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the statements field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"statements\":", 13); + if (cast->statements != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the subsequent field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"subsequent\":", 13); + if (cast->subsequent != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->subsequent); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the end_keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"end_keyword_loc\":", 18); + if (cast->end_keyword_loc.length != 0) { + pm_dump_json_location(buffer, &cast->end_keyword_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_IMAGINARY_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"ImaginaryNode\",\"location\":", 35); + + const pm_imaginary_node_t *cast = (const pm_imaginary_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the numeric field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"numeric\":", 10); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->numeric); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_IMPLICIT_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"ImplicitNode\",\"location\":", 34); + + const pm_implicit_node_t *cast = (const pm_implicit_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the value field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"value\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_IMPLICIT_REST_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"ImplicitRestNode\",\"location\":", 38); + + const pm_implicit_rest_node_t *cast = (const pm_implicit_rest_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_IN_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"InNode\",\"location\":", 28); + + const pm_in_node_t *cast = (const pm_in_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the pattern field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"pattern\":", 10); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->pattern); + + // Dump the statements field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"statements\":", 13); + if (cast->statements != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the in_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"in_loc\":", 9); + pm_dump_json_location(buffer, &cast->in_loc); + + // Dump the then_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"then_loc\":", 11); + if (cast->then_loc.length != 0) { + pm_dump_json_location(buffer, &cast->then_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_INDEX_AND_WRITE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"IndexAndWriteNode\",\"location\":", 39); + + const pm_index_and_write_node_t *cast = (const pm_index_and_write_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the CallNodeFlags field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"flags\":", 8); + size_t flags = 0; + pm_buffer_append_byte(buffer, '['); + if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"SAFE_NAVIGATION\"", 17); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"VARIABLE_CALL\"", 15); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"ATTRIBUTE_WRITE\"", 17); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"IGNORE_VISIBILITY\"", 19); + flags++; + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the receiver field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"receiver\":", 11); + if (cast->receiver != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->receiver); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the call_operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"call_operator_loc\":", 20); + if (cast->call_operator_loc.length != 0) { + pm_dump_json_location(buffer, &cast->call_operator_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the opening_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"opening_loc\":", 14); + pm_dump_json_location(buffer, &cast->opening_loc); + + // Dump the arguments field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"arguments\":", 12); + if (cast->arguments != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->arguments); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the closing_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"closing_loc\":", 14); + pm_dump_json_location(buffer, &cast->closing_loc); + + // Dump the block field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"block\":", 8); + if (cast->block != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->block); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + // Dump the value field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"value\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_INDEX_OPERATOR_WRITE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"IndexOperatorWriteNode\",\"location\":", 44); + + const pm_index_operator_write_node_t *cast = (const pm_index_operator_write_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the CallNodeFlags field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"flags\":", 8); + size_t flags = 0; + pm_buffer_append_byte(buffer, '['); + if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"SAFE_NAVIGATION\"", 17); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"VARIABLE_CALL\"", 15); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"ATTRIBUTE_WRITE\"", 17); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"IGNORE_VISIBILITY\"", 19); + flags++; + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the receiver field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"receiver\":", 11); + if (cast->receiver != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->receiver); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the call_operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"call_operator_loc\":", 20); + if (cast->call_operator_loc.length != 0) { + pm_dump_json_location(buffer, &cast->call_operator_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the opening_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"opening_loc\":", 14); + pm_dump_json_location(buffer, &cast->opening_loc); + + // Dump the arguments field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"arguments\":", 12); + if (cast->arguments != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->arguments); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the closing_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"closing_loc\":", 14); + pm_dump_json_location(buffer, &cast->closing_loc); + + // Dump the block field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"block\":", 8); + if (cast->block != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->block); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the binary_operator field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"binary_operator\":", 18); + pm_dump_json_constant(buffer, parser, cast->binary_operator); + + // Dump the binary_operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"binary_operator_loc\":", 22); + pm_dump_json_location(buffer, &cast->binary_operator_loc); + + // Dump the value field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"value\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_INDEX_OR_WRITE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"IndexOrWriteNode\",\"location\":", 38); + + const pm_index_or_write_node_t *cast = (const pm_index_or_write_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the CallNodeFlags field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"flags\":", 8); + size_t flags = 0; + pm_buffer_append_byte(buffer, '['); + if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"SAFE_NAVIGATION\"", 17); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"VARIABLE_CALL\"", 15); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"ATTRIBUTE_WRITE\"", 17); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"IGNORE_VISIBILITY\"", 19); + flags++; + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the receiver field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"receiver\":", 11); + if (cast->receiver != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->receiver); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the call_operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"call_operator_loc\":", 20); + if (cast->call_operator_loc.length != 0) { + pm_dump_json_location(buffer, &cast->call_operator_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the opening_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"opening_loc\":", 14); + pm_dump_json_location(buffer, &cast->opening_loc); + + // Dump the arguments field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"arguments\":", 12); + if (cast->arguments != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->arguments); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the closing_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"closing_loc\":", 14); + pm_dump_json_location(buffer, &cast->closing_loc); + + // Dump the block field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"block\":", 8); + if (cast->block != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->block); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + // Dump the value field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"value\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_INDEX_TARGET_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"IndexTargetNode\",\"location\":", 37); + + const pm_index_target_node_t *cast = (const pm_index_target_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the CallNodeFlags field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"flags\":", 8); + size_t flags = 0; + pm_buffer_append_byte(buffer, '['); + if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"SAFE_NAVIGATION\"", 17); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"VARIABLE_CALL\"", 15); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"ATTRIBUTE_WRITE\"", 17); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"IGNORE_VISIBILITY\"", 19); + flags++; + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the receiver field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"receiver\":", 11); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->receiver); + + // Dump the opening_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"opening_loc\":", 14); + pm_dump_json_location(buffer, &cast->opening_loc); + + // Dump the arguments field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"arguments\":", 12); + if (cast->arguments != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->arguments); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the closing_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"closing_loc\":", 14); + pm_dump_json_location(buffer, &cast->closing_loc); + + // Dump the block field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"block\":", 8); + if (cast->block != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->block); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_INSTANCE_VARIABLE_AND_WRITE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"InstanceVariableAndWriteNode\",\"location\":", 50); + + const pm_instance_variable_and_write_node_t *cast = (const pm_instance_variable_and_write_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + pm_dump_json_constant(buffer, parser, cast->name); + + // Dump the name_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name_loc\":", 11); + pm_dump_json_location(buffer, &cast->name_loc); + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + // Dump the value field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"value\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"InstanceVariableOperatorWriteNode\",\"location\":", 55); + + const pm_instance_variable_operator_write_node_t *cast = (const pm_instance_variable_operator_write_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + pm_dump_json_constant(buffer, parser, cast->name); + + // Dump the name_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name_loc\":", 11); + pm_dump_json_location(buffer, &cast->name_loc); + + // Dump the binary_operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"binary_operator_loc\":", 22); + pm_dump_json_location(buffer, &cast->binary_operator_loc); + + // Dump the value field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"value\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); + + // Dump the binary_operator field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"binary_operator\":", 18); + pm_dump_json_constant(buffer, parser, cast->binary_operator); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_INSTANCE_VARIABLE_OR_WRITE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"InstanceVariableOrWriteNode\",\"location\":", 49); + + const pm_instance_variable_or_write_node_t *cast = (const pm_instance_variable_or_write_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + pm_dump_json_constant(buffer, parser, cast->name); + + // Dump the name_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name_loc\":", 11); + pm_dump_json_location(buffer, &cast->name_loc); + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + // Dump the value field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"value\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_INSTANCE_VARIABLE_READ_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"InstanceVariableReadNode\",\"location\":", 46); + + const pm_instance_variable_read_node_t *cast = (const pm_instance_variable_read_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + pm_dump_json_constant(buffer, parser, cast->name); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_INSTANCE_VARIABLE_TARGET_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"InstanceVariableTargetNode\",\"location\":", 48); + + const pm_instance_variable_target_node_t *cast = (const pm_instance_variable_target_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + pm_dump_json_constant(buffer, parser, cast->name); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_INSTANCE_VARIABLE_WRITE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"InstanceVariableWriteNode\",\"location\":", 47); + + const pm_instance_variable_write_node_t *cast = (const pm_instance_variable_write_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + pm_dump_json_constant(buffer, parser, cast->name); + + // Dump the name_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name_loc\":", 11); + pm_dump_json_location(buffer, &cast->name_loc); + + // Dump the value field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"value\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_INTEGER_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"IntegerNode\",\"location\":", 33); + + const pm_integer_node_t *cast = (const pm_integer_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the IntegerBaseFlags field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"flags\":", 8); + size_t flags = 0; + pm_buffer_append_byte(buffer, '['); + if (PM_NODE_FLAG_P(cast, PM_INTEGER_BASE_FLAGS_BINARY)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"BINARY\"", 8); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_INTEGER_BASE_FLAGS_DECIMAL)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"DECIMAL\"", 9); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_INTEGER_BASE_FLAGS_OCTAL)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"OCTAL\"", 7); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_INTEGER_BASE_FLAGS_HEXADECIMAL)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"HEXADECIMAL\"", 13); + flags++; + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the value field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"value\":", 8); + pm_integer_string(buffer, &cast->value); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_INTERPOLATED_MATCH_LAST_LINE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"InterpolatedMatchLastLineNode\",\"location\":", 51); + + const pm_interpolated_match_last_line_node_t *cast = (const pm_interpolated_match_last_line_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the RegularExpressionFlags field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"flags\":", 8); + size_t flags = 0; + pm_buffer_append_byte(buffer, '['); + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"IGNORE_CASE\"", 13); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"EXTENDED\"", 10); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"MULTI_LINE\"", 12); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_ONCE)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"ONCE\"", 6); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_EUC_JP)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"EUC_JP\"", 8); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"ASCII_8BIT\"", 12); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"WINDOWS_31J\"", 13); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_UTF_8)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"UTF_8\"", 7); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"FORCED_UTF8_ENCODING\"", 22); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"FORCED_BINARY_ENCODING\"", 24); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"FORCED_US_ASCII_ENCODING\"", 26); + flags++; + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the opening_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"opening_loc\":", 14); + pm_dump_json_location(buffer, &cast->opening_loc); + + // Dump the parts field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"parts\":", 8); + const pm_node_list_t *parts = &cast->parts; + pm_buffer_append_byte(buffer, '['); + + for (size_t index = 0; index < parts->size; index++) { + if (index != 0) pm_buffer_append_byte(buffer, ','); + pm_dump_json(buffer, parser, parts->nodes[index]); + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the closing_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"closing_loc\":", 14); + pm_dump_json_location(buffer, &cast->closing_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"InterpolatedRegularExpressionNode\",\"location\":", 55); + + const pm_interpolated_regular_expression_node_t *cast = (const pm_interpolated_regular_expression_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the RegularExpressionFlags field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"flags\":", 8); + size_t flags = 0; + pm_buffer_append_byte(buffer, '['); + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"IGNORE_CASE\"", 13); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"EXTENDED\"", 10); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"MULTI_LINE\"", 12); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_ONCE)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"ONCE\"", 6); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_EUC_JP)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"EUC_JP\"", 8); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"ASCII_8BIT\"", 12); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"WINDOWS_31J\"", 13); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_UTF_8)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"UTF_8\"", 7); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"FORCED_UTF8_ENCODING\"", 22); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"FORCED_BINARY_ENCODING\"", 24); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"FORCED_US_ASCII_ENCODING\"", 26); + flags++; + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the opening_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"opening_loc\":", 14); + pm_dump_json_location(buffer, &cast->opening_loc); + + // Dump the parts field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"parts\":", 8); + const pm_node_list_t *parts = &cast->parts; + pm_buffer_append_byte(buffer, '['); + + for (size_t index = 0; index < parts->size; index++) { + if (index != 0) pm_buffer_append_byte(buffer, ','); + pm_dump_json(buffer, parser, parts->nodes[index]); + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the closing_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"closing_loc\":", 14); + pm_dump_json_location(buffer, &cast->closing_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_INTERPOLATED_STRING_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"InterpolatedStringNode\",\"location\":", 44); + + const pm_interpolated_string_node_t *cast = (const pm_interpolated_string_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the InterpolatedStringNodeFlags field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"flags\":", 8); + size_t flags = 0; + pm_buffer_append_byte(buffer, '['); + if (PM_NODE_FLAG_P(cast, PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"FROZEN\"", 8); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"MUTABLE\"", 9); + flags++; + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the opening_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"opening_loc\":", 14); + if (cast->opening_loc.length != 0) { + pm_dump_json_location(buffer, &cast->opening_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the parts field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"parts\":", 8); + const pm_node_list_t *parts = &cast->parts; + pm_buffer_append_byte(buffer, '['); + + for (size_t index = 0; index < parts->size; index++) { + if (index != 0) pm_buffer_append_byte(buffer, ','); + pm_dump_json(buffer, parser, parts->nodes[index]); + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the closing_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"closing_loc\":", 14); + if (cast->closing_loc.length != 0) { + pm_dump_json_location(buffer, &cast->closing_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_INTERPOLATED_SYMBOL_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"InterpolatedSymbolNode\",\"location\":", 44); + + const pm_interpolated_symbol_node_t *cast = (const pm_interpolated_symbol_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the opening_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"opening_loc\":", 14); + if (cast->opening_loc.length != 0) { + pm_dump_json_location(buffer, &cast->opening_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the parts field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"parts\":", 8); + const pm_node_list_t *parts = &cast->parts; + pm_buffer_append_byte(buffer, '['); + + for (size_t index = 0; index < parts->size; index++) { + if (index != 0) pm_buffer_append_byte(buffer, ','); + pm_dump_json(buffer, parser, parts->nodes[index]); + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the closing_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"closing_loc\":", 14); + if (cast->closing_loc.length != 0) { + pm_dump_json_location(buffer, &cast->closing_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_INTERPOLATED_X_STRING_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"InterpolatedXStringNode\",\"location\":", 45); + + const pm_interpolated_x_string_node_t *cast = (const pm_interpolated_x_string_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the opening_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"opening_loc\":", 14); + pm_dump_json_location(buffer, &cast->opening_loc); + + // Dump the parts field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"parts\":", 8); + const pm_node_list_t *parts = &cast->parts; + pm_buffer_append_byte(buffer, '['); + + for (size_t index = 0; index < parts->size; index++) { + if (index != 0) pm_buffer_append_byte(buffer, ','); + pm_dump_json(buffer, parser, parts->nodes[index]); + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the closing_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"closing_loc\":", 14); + pm_dump_json_location(buffer, &cast->closing_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_IT_LOCAL_VARIABLE_READ_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"ItLocalVariableReadNode\",\"location\":", 45); + + const pm_it_local_variable_read_node_t *cast = (const pm_it_local_variable_read_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_IT_PARAMETERS_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"ItParametersNode\",\"location\":", 38); + + const pm_it_parameters_node_t *cast = (const pm_it_parameters_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_KEYWORD_HASH_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"KeywordHashNode\",\"location\":", 37); + + const pm_keyword_hash_node_t *cast = (const pm_keyword_hash_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the KeywordHashNodeFlags field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"flags\":", 8); + size_t flags = 0; + pm_buffer_append_byte(buffer, '['); + if (PM_NODE_FLAG_P(cast, PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"SYMBOL_KEYS\"", 13); + flags++; + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the elements field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"elements\":", 11); + const pm_node_list_t *elements = &cast->elements; + pm_buffer_append_byte(buffer, '['); + + for (size_t index = 0; index < elements->size; index++) { + if (index != 0) pm_buffer_append_byte(buffer, ','); + pm_dump_json(buffer, parser, elements->nodes[index]); + } + pm_buffer_append_byte(buffer, ']'); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_KEYWORD_REST_PARAMETER_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"KeywordRestParameterNode\",\"location\":", 46); + + const pm_keyword_rest_parameter_node_t *cast = (const pm_keyword_rest_parameter_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the ParameterFlags field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"flags\":", 8); + size_t flags = 0; + pm_buffer_append_byte(buffer, '['); + if (PM_NODE_FLAG_P(cast, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"REPEATED_PARAMETER\"", 20); + flags++; + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + if (cast->name != PM_CONSTANT_ID_UNSET) { + pm_dump_json_constant(buffer, parser, cast->name); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the name_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name_loc\":", 11); + if (cast->name_loc.length != 0) { + pm_dump_json_location(buffer, &cast->name_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_LAMBDA_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"LambdaNode\",\"location\":", 32); + + const pm_lambda_node_t *cast = (const pm_lambda_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the locals field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"locals\":", 9); + const pm_constant_id_list_t *locals = &cast->locals; + pm_buffer_append_byte(buffer, '['); + + for (size_t index = 0; index < locals->size; index++) { + if (index != 0) pm_buffer_append_byte(buffer, ','); + pm_dump_json_constant(buffer, parser, locals->ids[index]); + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + // Dump the opening_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"opening_loc\":", 14); + pm_dump_json_location(buffer, &cast->opening_loc); + + // Dump the closing_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"closing_loc\":", 14); + pm_dump_json_location(buffer, &cast->closing_loc); + + // Dump the parameters field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"parameters\":", 13); + if (cast->parameters != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->parameters); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the body field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"body\":", 7); + if (cast->body != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->body); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_LOCAL_VARIABLE_AND_WRITE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"LocalVariableAndWriteNode\",\"location\":", 47); + + const pm_local_variable_and_write_node_t *cast = (const pm_local_variable_and_write_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the name_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name_loc\":", 11); + pm_dump_json_location(buffer, &cast->name_loc); + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + // Dump the value field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"value\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + pm_dump_json_constant(buffer, parser, cast->name); + + // Dump the depth field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"depth\":", 8); + pm_buffer_append_format(buffer, "%" PRIu32, cast->depth); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_LOCAL_VARIABLE_OPERATOR_WRITE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"LocalVariableOperatorWriteNode\",\"location\":", 52); + + const pm_local_variable_operator_write_node_t *cast = (const pm_local_variable_operator_write_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the name_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name_loc\":", 11); + pm_dump_json_location(buffer, &cast->name_loc); + + // Dump the binary_operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"binary_operator_loc\":", 22); + pm_dump_json_location(buffer, &cast->binary_operator_loc); + + // Dump the value field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"value\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + pm_dump_json_constant(buffer, parser, cast->name); + + // Dump the binary_operator field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"binary_operator\":", 18); + pm_dump_json_constant(buffer, parser, cast->binary_operator); + + // Dump the depth field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"depth\":", 8); + pm_buffer_append_format(buffer, "%" PRIu32, cast->depth); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_LOCAL_VARIABLE_OR_WRITE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"LocalVariableOrWriteNode\",\"location\":", 46); + + const pm_local_variable_or_write_node_t *cast = (const pm_local_variable_or_write_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the name_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name_loc\":", 11); + pm_dump_json_location(buffer, &cast->name_loc); + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + // Dump the value field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"value\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + pm_dump_json_constant(buffer, parser, cast->name); + + // Dump the depth field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"depth\":", 8); + pm_buffer_append_format(buffer, "%" PRIu32, cast->depth); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_LOCAL_VARIABLE_READ_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"LocalVariableReadNode\",\"location\":", 43); + + const pm_local_variable_read_node_t *cast = (const pm_local_variable_read_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + pm_dump_json_constant(buffer, parser, cast->name); + + // Dump the depth field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"depth\":", 8); + pm_buffer_append_format(buffer, "%" PRIu32, cast->depth); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_LOCAL_VARIABLE_TARGET_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"LocalVariableTargetNode\",\"location\":", 45); + + const pm_local_variable_target_node_t *cast = (const pm_local_variable_target_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + pm_dump_json_constant(buffer, parser, cast->name); + + // Dump the depth field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"depth\":", 8); + pm_buffer_append_format(buffer, "%" PRIu32, cast->depth); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_LOCAL_VARIABLE_WRITE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"LocalVariableWriteNode\",\"location\":", 44); + + const pm_local_variable_write_node_t *cast = (const pm_local_variable_write_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + pm_dump_json_constant(buffer, parser, cast->name); + + // Dump the depth field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"depth\":", 8); + pm_buffer_append_format(buffer, "%" PRIu32, cast->depth); + + // Dump the name_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name_loc\":", 11); + pm_dump_json_location(buffer, &cast->name_loc); + + // Dump the value field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"value\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_MATCH_LAST_LINE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"MatchLastLineNode\",\"location\":", 39); + + const pm_match_last_line_node_t *cast = (const pm_match_last_line_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the RegularExpressionFlags field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"flags\":", 8); + size_t flags = 0; + pm_buffer_append_byte(buffer, '['); + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"IGNORE_CASE\"", 13); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"EXTENDED\"", 10); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"MULTI_LINE\"", 12); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_ONCE)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"ONCE\"", 6); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_EUC_JP)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"EUC_JP\"", 8); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"ASCII_8BIT\"", 12); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"WINDOWS_31J\"", 13); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_UTF_8)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"UTF_8\"", 7); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"FORCED_UTF8_ENCODING\"", 22); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"FORCED_BINARY_ENCODING\"", 24); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"FORCED_US_ASCII_ENCODING\"", 26); + flags++; + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the opening_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"opening_loc\":", 14); + pm_dump_json_location(buffer, &cast->opening_loc); + + // Dump the content_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"content_loc\":", 14); + pm_dump_json_location(buffer, &cast->content_loc); + + // Dump the closing_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"closing_loc\":", 14); + pm_dump_json_location(buffer, &cast->closing_loc); + + // Dump the unescaped field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"unescaped\":", 12); + const pm_string_t *unescaped = &cast->unescaped; + pm_buffer_append_byte(buffer, '"'); + pm_buffer_append_source(buffer, pm_string_source(unescaped), pm_string_length(unescaped), PM_BUFFER_ESCAPING_JSON); + pm_buffer_append_byte(buffer, '"'); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_MATCH_PREDICATE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"MatchPredicateNode\",\"location\":", 40); + + const pm_match_predicate_node_t *cast = (const pm_match_predicate_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the value field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"value\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); + + // Dump the pattern field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"pattern\":", 10); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->pattern); + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_MATCH_REQUIRED_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"MatchRequiredNode\",\"location\":", 39); + + const pm_match_required_node_t *cast = (const pm_match_required_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the value field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"value\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); + + // Dump the pattern field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"pattern\":", 10); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->pattern); + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_MATCH_WRITE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"MatchWriteNode\",\"location\":", 36); + + const pm_match_write_node_t *cast = (const pm_match_write_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the call field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"call\":", 7); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->call); + + // Dump the targets field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"targets\":", 10); + const pm_node_list_t *targets = &cast->targets; + pm_buffer_append_byte(buffer, '['); + + for (size_t index = 0; index < targets->size; index++) { + if (index != 0) pm_buffer_append_byte(buffer, ','); + pm_dump_json(buffer, parser, targets->nodes[index]); + } + pm_buffer_append_byte(buffer, ']'); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_MISSING_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"MissingNode\",\"location\":", 33); + + const pm_missing_node_t *cast = (const pm_missing_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_MODULE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"ModuleNode\",\"location\":", 32); + + const pm_module_node_t *cast = (const pm_module_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the locals field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"locals\":", 9); + const pm_constant_id_list_t *locals = &cast->locals; + pm_buffer_append_byte(buffer, '['); + + for (size_t index = 0; index < locals->size; index++) { + if (index != 0) pm_buffer_append_byte(buffer, ','); + pm_dump_json_constant(buffer, parser, locals->ids[index]); + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the module_keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"module_keyword_loc\":", 21); + pm_dump_json_location(buffer, &cast->module_keyword_loc); + + // Dump the constant_path field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"constant_path\":", 16); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->constant_path); + + // Dump the body field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"body\":", 7); + if (cast->body != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->body); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the end_keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"end_keyword_loc\":", 18); + pm_dump_json_location(buffer, &cast->end_keyword_loc); + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + pm_dump_json_constant(buffer, parser, cast->name); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_MULTI_TARGET_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"MultiTargetNode\",\"location\":", 37); + + const pm_multi_target_node_t *cast = (const pm_multi_target_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the lefts field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"lefts\":", 8); + const pm_node_list_t *lefts = &cast->lefts; + pm_buffer_append_byte(buffer, '['); + + for (size_t index = 0; index < lefts->size; index++) { + if (index != 0) pm_buffer_append_byte(buffer, ','); + pm_dump_json(buffer, parser, lefts->nodes[index]); + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the rest field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"rest\":", 7); + if (cast->rest != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->rest); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the rights field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"rights\":", 9); + const pm_node_list_t *rights = &cast->rights; + pm_buffer_append_byte(buffer, '['); + + for (size_t index = 0; index < rights->size; index++) { + if (index != 0) pm_buffer_append_byte(buffer, ','); + pm_dump_json(buffer, parser, rights->nodes[index]); + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the lparen_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"lparen_loc\":", 13); + if (cast->lparen_loc.length != 0) { + pm_dump_json_location(buffer, &cast->lparen_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the rparen_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"rparen_loc\":", 13); + if (cast->rparen_loc.length != 0) { + pm_dump_json_location(buffer, &cast->rparen_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_MULTI_WRITE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"MultiWriteNode\",\"location\":", 36); + + const pm_multi_write_node_t *cast = (const pm_multi_write_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the lefts field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"lefts\":", 8); + const pm_node_list_t *lefts = &cast->lefts; + pm_buffer_append_byte(buffer, '['); + + for (size_t index = 0; index < lefts->size; index++) { + if (index != 0) pm_buffer_append_byte(buffer, ','); + pm_dump_json(buffer, parser, lefts->nodes[index]); + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the rest field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"rest\":", 7); + if (cast->rest != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->rest); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the rights field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"rights\":", 9); + const pm_node_list_t *rights = &cast->rights; + pm_buffer_append_byte(buffer, '['); + + for (size_t index = 0; index < rights->size; index++) { + if (index != 0) pm_buffer_append_byte(buffer, ','); + pm_dump_json(buffer, parser, rights->nodes[index]); + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the lparen_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"lparen_loc\":", 13); + if (cast->lparen_loc.length != 0) { + pm_dump_json_location(buffer, &cast->lparen_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the rparen_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"rparen_loc\":", 13); + if (cast->rparen_loc.length != 0) { + pm_dump_json_location(buffer, &cast->rparen_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + // Dump the value field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"value\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_NEXT_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"NextNode\",\"location\":", 30); + + const pm_next_node_t *cast = (const pm_next_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the arguments field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"arguments\":", 12); + if (cast->arguments != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->arguments); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"keyword_loc\":", 14); + pm_dump_json_location(buffer, &cast->keyword_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_NIL_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"NilNode\",\"location\":", 29); + + const pm_nil_node_t *cast = (const pm_nil_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_NO_BLOCK_PARAMETER_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"NoBlockParameterNode\",\"location\":", 42); + + const pm_no_block_parameter_node_t *cast = (const pm_no_block_parameter_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + // Dump the keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"keyword_loc\":", 14); + pm_dump_json_location(buffer, &cast->keyword_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_NO_KEYWORDS_PARAMETER_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"NoKeywordsParameterNode\",\"location\":", 45); + + const pm_no_keywords_parameter_node_t *cast = (const pm_no_keywords_parameter_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + // Dump the keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"keyword_loc\":", 14); + pm_dump_json_location(buffer, &cast->keyword_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_NUMBERED_PARAMETERS_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"NumberedParametersNode\",\"location\":", 44); + + const pm_numbered_parameters_node_t *cast = (const pm_numbered_parameters_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the maximum field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"maximum\":", 10); + pm_buffer_append_format(buffer, "%" PRIu8, cast->maximum); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_NUMBERED_REFERENCE_READ_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"NumberedReferenceReadNode\",\"location\":", 47); + + const pm_numbered_reference_read_node_t *cast = (const pm_numbered_reference_read_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the number field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"number\":", 9); + pm_buffer_append_format(buffer, "%" PRIu32, cast->number); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_OPTIONAL_KEYWORD_PARAMETER_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"OptionalKeywordParameterNode\",\"location\":", 50); + + const pm_optional_keyword_parameter_node_t *cast = (const pm_optional_keyword_parameter_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the ParameterFlags field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"flags\":", 8); + size_t flags = 0; + pm_buffer_append_byte(buffer, '['); + if (PM_NODE_FLAG_P(cast, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"REPEATED_PARAMETER\"", 20); + flags++; + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + pm_dump_json_constant(buffer, parser, cast->name); + + // Dump the name_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name_loc\":", 11); + pm_dump_json_location(buffer, &cast->name_loc); + + // Dump the value field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"value\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_OPTIONAL_PARAMETER_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"OptionalParameterNode\",\"location\":", 43); + + const pm_optional_parameter_node_t *cast = (const pm_optional_parameter_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the ParameterFlags field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"flags\":", 8); + size_t flags = 0; + pm_buffer_append_byte(buffer, '['); + if (PM_NODE_FLAG_P(cast, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"REPEATED_PARAMETER\"", 20); + flags++; + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + pm_dump_json_constant(buffer, parser, cast->name); + + // Dump the name_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name_loc\":", 11); + pm_dump_json_location(buffer, &cast->name_loc); + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + // Dump the value field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"value\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_OR_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"OrNode\",\"location\":", 28); + + const pm_or_node_t *cast = (const pm_or_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the left field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"left\":", 7); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->left); + + // Dump the right field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"right\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->right); + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_PARAMETERS_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"ParametersNode\",\"location\":", 36); + + const pm_parameters_node_t *cast = (const pm_parameters_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the requireds field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"requireds\":", 12); + const pm_node_list_t *requireds = &cast->requireds; + pm_buffer_append_byte(buffer, '['); + + for (size_t index = 0; index < requireds->size; index++) { + if (index != 0) pm_buffer_append_byte(buffer, ','); + pm_dump_json(buffer, parser, requireds->nodes[index]); + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the optionals field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"optionals\":", 12); + const pm_node_list_t *optionals = &cast->optionals; + pm_buffer_append_byte(buffer, '['); + + for (size_t index = 0; index < optionals->size; index++) { + if (index != 0) pm_buffer_append_byte(buffer, ','); + pm_dump_json(buffer, parser, optionals->nodes[index]); + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the rest field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"rest\":", 7); + if (cast->rest != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->rest); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the posts field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"posts\":", 8); + const pm_node_list_t *posts = &cast->posts; + pm_buffer_append_byte(buffer, '['); + + for (size_t index = 0; index < posts->size; index++) { + if (index != 0) pm_buffer_append_byte(buffer, ','); + pm_dump_json(buffer, parser, posts->nodes[index]); + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the keywords field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"keywords\":", 11); + const pm_node_list_t *keywords = &cast->keywords; + pm_buffer_append_byte(buffer, '['); + + for (size_t index = 0; index < keywords->size; index++) { + if (index != 0) pm_buffer_append_byte(buffer, ','); + pm_dump_json(buffer, parser, keywords->nodes[index]); + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the keyword_rest field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"keyword_rest\":", 15); + if (cast->keyword_rest != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->keyword_rest); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the block field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"block\":", 8); + if (cast->block != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->block); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_PARENTHESES_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"ParenthesesNode\",\"location\":", 37); + + const pm_parentheses_node_t *cast = (const pm_parentheses_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the ParenthesesNodeFlags field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"flags\":", 8); + size_t flags = 0; + pm_buffer_append_byte(buffer, '['); + if (PM_NODE_FLAG_P(cast, PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"MULTIPLE_STATEMENTS\"", 21); + flags++; + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the body field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"body\":", 7); + if (cast->body != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->body); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the opening_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"opening_loc\":", 14); + pm_dump_json_location(buffer, &cast->opening_loc); + + // Dump the closing_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"closing_loc\":", 14); + pm_dump_json_location(buffer, &cast->closing_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_PINNED_EXPRESSION_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"PinnedExpressionNode\",\"location\":", 42); + + const pm_pinned_expression_node_t *cast = (const pm_pinned_expression_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the expression field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"expression\":", 13); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->expression); + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + // Dump the lparen_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"lparen_loc\":", 13); + pm_dump_json_location(buffer, &cast->lparen_loc); + + // Dump the rparen_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"rparen_loc\":", 13); + pm_dump_json_location(buffer, &cast->rparen_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_PINNED_VARIABLE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"PinnedVariableNode\",\"location\":", 40); + + const pm_pinned_variable_node_t *cast = (const pm_pinned_variable_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the variable field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"variable\":", 11); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->variable); + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_POST_EXECUTION_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"PostExecutionNode\",\"location\":", 39); + + const pm_post_execution_node_t *cast = (const pm_post_execution_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the statements field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"statements\":", 13); + if (cast->statements != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"keyword_loc\":", 14); + pm_dump_json_location(buffer, &cast->keyword_loc); + + // Dump the opening_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"opening_loc\":", 14); + pm_dump_json_location(buffer, &cast->opening_loc); + + // Dump the closing_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"closing_loc\":", 14); + pm_dump_json_location(buffer, &cast->closing_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_PRE_EXECUTION_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"PreExecutionNode\",\"location\":", 38); + + const pm_pre_execution_node_t *cast = (const pm_pre_execution_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the statements field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"statements\":", 13); + if (cast->statements != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"keyword_loc\":", 14); + pm_dump_json_location(buffer, &cast->keyword_loc); + + // Dump the opening_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"opening_loc\":", 14); + pm_dump_json_location(buffer, &cast->opening_loc); + + // Dump the closing_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"closing_loc\":", 14); + pm_dump_json_location(buffer, &cast->closing_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_PROGRAM_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"ProgramNode\",\"location\":", 33); + + const pm_program_node_t *cast = (const pm_program_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the locals field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"locals\":", 9); + const pm_constant_id_list_t *locals = &cast->locals; + pm_buffer_append_byte(buffer, '['); + + for (size_t index = 0; index < locals->size; index++) { + if (index != 0) pm_buffer_append_byte(buffer, ','); + pm_dump_json_constant(buffer, parser, locals->ids[index]); + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the statements field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"statements\":", 13); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_RANGE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"RangeNode\",\"location\":", 31); + + const pm_range_node_t *cast = (const pm_range_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the RangeFlags field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"flags\":", 8); + size_t flags = 0; + pm_buffer_append_byte(buffer, '['); + if (PM_NODE_FLAG_P(cast, PM_RANGE_FLAGS_EXCLUDE_END)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"EXCLUDE_END\"", 13); + flags++; + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the left field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"left\":", 7); + if (cast->left != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->left); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the right field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"right\":", 8); + if (cast->right != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->right); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_RATIONAL_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"RationalNode\",\"location\":", 34); + + const pm_rational_node_t *cast = (const pm_rational_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the IntegerBaseFlags field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"flags\":", 8); + size_t flags = 0; + pm_buffer_append_byte(buffer, '['); + if (PM_NODE_FLAG_P(cast, PM_INTEGER_BASE_FLAGS_BINARY)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"BINARY\"", 8); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_INTEGER_BASE_FLAGS_DECIMAL)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"DECIMAL\"", 9); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_INTEGER_BASE_FLAGS_OCTAL)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"OCTAL\"", 7); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_INTEGER_BASE_FLAGS_HEXADECIMAL)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"HEXADECIMAL\"", 13); + flags++; + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the numerator field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"numerator\":", 12); + pm_integer_string(buffer, &cast->numerator); + + // Dump the denominator field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"denominator\":", 14); + pm_integer_string(buffer, &cast->denominator); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_REDO_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"RedoNode\",\"location\":", 30); + + const pm_redo_node_t *cast = (const pm_redo_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_REGULAR_EXPRESSION_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"RegularExpressionNode\",\"location\":", 43); + + const pm_regular_expression_node_t *cast = (const pm_regular_expression_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the RegularExpressionFlags field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"flags\":", 8); + size_t flags = 0; + pm_buffer_append_byte(buffer, '['); + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"IGNORE_CASE\"", 13); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"EXTENDED\"", 10); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"MULTI_LINE\"", 12); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_ONCE)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"ONCE\"", 6); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_EUC_JP)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"EUC_JP\"", 8); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"ASCII_8BIT\"", 12); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"WINDOWS_31J\"", 13); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_UTF_8)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"UTF_8\"", 7); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"FORCED_UTF8_ENCODING\"", 22); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"FORCED_BINARY_ENCODING\"", 24); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"FORCED_US_ASCII_ENCODING\"", 26); + flags++; + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the opening_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"opening_loc\":", 14); + pm_dump_json_location(buffer, &cast->opening_loc); + + // Dump the content_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"content_loc\":", 14); + pm_dump_json_location(buffer, &cast->content_loc); + + // Dump the closing_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"closing_loc\":", 14); + pm_dump_json_location(buffer, &cast->closing_loc); + + // Dump the unescaped field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"unescaped\":", 12); + const pm_string_t *unescaped = &cast->unescaped; + pm_buffer_append_byte(buffer, '"'); + pm_buffer_append_source(buffer, pm_string_source(unescaped), pm_string_length(unescaped), PM_BUFFER_ESCAPING_JSON); + pm_buffer_append_byte(buffer, '"'); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_REQUIRED_KEYWORD_PARAMETER_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"RequiredKeywordParameterNode\",\"location\":", 50); + + const pm_required_keyword_parameter_node_t *cast = (const pm_required_keyword_parameter_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the ParameterFlags field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"flags\":", 8); + size_t flags = 0; + pm_buffer_append_byte(buffer, '['); + if (PM_NODE_FLAG_P(cast, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"REPEATED_PARAMETER\"", 20); + flags++; + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + pm_dump_json_constant(buffer, parser, cast->name); + + // Dump the name_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name_loc\":", 11); + pm_dump_json_location(buffer, &cast->name_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_REQUIRED_PARAMETER_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"RequiredParameterNode\",\"location\":", 43); + + const pm_required_parameter_node_t *cast = (const pm_required_parameter_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the ParameterFlags field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"flags\":", 8); + size_t flags = 0; + pm_buffer_append_byte(buffer, '['); + if (PM_NODE_FLAG_P(cast, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"REPEATED_PARAMETER\"", 20); + flags++; + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + pm_dump_json_constant(buffer, parser, cast->name); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_RESCUE_MODIFIER_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"RescueModifierNode\",\"location\":", 40); + + const pm_rescue_modifier_node_t *cast = (const pm_rescue_modifier_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the expression field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"expression\":", 13); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->expression); + + // Dump the keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"keyword_loc\":", 14); + pm_dump_json_location(buffer, &cast->keyword_loc); + + // Dump the rescue_expression field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"rescue_expression\":", 20); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->rescue_expression); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_RESCUE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"RescueNode\",\"location\":", 32); + + const pm_rescue_node_t *cast = (const pm_rescue_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"keyword_loc\":", 14); + pm_dump_json_location(buffer, &cast->keyword_loc); + + // Dump the exceptions field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"exceptions\":", 13); + const pm_node_list_t *exceptions = &cast->exceptions; + pm_buffer_append_byte(buffer, '['); + + for (size_t index = 0; index < exceptions->size; index++) { + if (index != 0) pm_buffer_append_byte(buffer, ','); + pm_dump_json(buffer, parser, exceptions->nodes[index]); + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + if (cast->operator_loc.length != 0) { + pm_dump_json_location(buffer, &cast->operator_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the reference field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"reference\":", 12); + if (cast->reference != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->reference); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the then_keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"then_keyword_loc\":", 19); + if (cast->then_keyword_loc.length != 0) { + pm_dump_json_location(buffer, &cast->then_keyword_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the statements field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"statements\":", 13); + if (cast->statements != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the subsequent field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"subsequent\":", 13); + if (cast->subsequent != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->subsequent); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_REST_PARAMETER_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"RestParameterNode\",\"location\":", 39); + + const pm_rest_parameter_node_t *cast = (const pm_rest_parameter_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the ParameterFlags field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"flags\":", 8); + size_t flags = 0; + pm_buffer_append_byte(buffer, '['); + if (PM_NODE_FLAG_P(cast, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"REPEATED_PARAMETER\"", 20); + flags++; + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the name field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name\":", 7); + if (cast->name != PM_CONSTANT_ID_UNSET) { + pm_dump_json_constant(buffer, parser, cast->name); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the name_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"name_loc\":", 11); + if (cast->name_loc.length != 0) { + pm_dump_json_location(buffer, &cast->name_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_RETRY_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"RetryNode\",\"location\":", 31); + + const pm_retry_node_t *cast = (const pm_retry_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_RETURN_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"ReturnNode\",\"location\":", 32); + + const pm_return_node_t *cast = (const pm_return_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"keyword_loc\":", 14); + pm_dump_json_location(buffer, &cast->keyword_loc); + + // Dump the arguments field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"arguments\":", 12); + if (cast->arguments != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->arguments); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_SELF_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"SelfNode\",\"location\":", 30); + + const pm_self_node_t *cast = (const pm_self_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_SHAREABLE_CONSTANT_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"ShareableConstantNode\",\"location\":", 43); + + const pm_shareable_constant_node_t *cast = (const pm_shareable_constant_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the ShareableConstantNodeFlags field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"flags\":", 8); + size_t flags = 0; + pm_buffer_append_byte(buffer, '['); + if (PM_NODE_FLAG_P(cast, PM_SHAREABLE_CONSTANT_NODE_FLAGS_LITERAL)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"LITERAL\"", 9); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_SHAREABLE_CONSTANT_NODE_FLAGS_EXPERIMENTAL_EVERYTHING)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"EXPERIMENTAL_EVERYTHING\"", 25); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_SHAREABLE_CONSTANT_NODE_FLAGS_EXPERIMENTAL_COPY)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"EXPERIMENTAL_COPY\"", 19); + flags++; + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the write field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"write\":", 8); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->write); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_SINGLETON_CLASS_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"SingletonClassNode\",\"location\":", 40); + + const pm_singleton_class_node_t *cast = (const pm_singleton_class_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the locals field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"locals\":", 9); + const pm_constant_id_list_t *locals = &cast->locals; + pm_buffer_append_byte(buffer, '['); + + for (size_t index = 0; index < locals->size; index++) { + if (index != 0) pm_buffer_append_byte(buffer, ','); + pm_dump_json_constant(buffer, parser, locals->ids[index]); + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the class_keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"class_keyword_loc\":", 20); + pm_dump_json_location(buffer, &cast->class_keyword_loc); + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + // Dump the expression field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"expression\":", 13); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->expression); + + // Dump the body field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"body\":", 7); + if (cast->body != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->body); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the end_keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"end_keyword_loc\":", 18); + pm_dump_json_location(buffer, &cast->end_keyword_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_SOURCE_ENCODING_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"SourceEncodingNode\",\"location\":", 40); + + const pm_source_encoding_node_t *cast = (const pm_source_encoding_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_SOURCE_FILE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"SourceFileNode\",\"location\":", 36); + + const pm_source_file_node_t *cast = (const pm_source_file_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the StringFlags field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"flags\":", 8); + size_t flags = 0; + pm_buffer_append_byte(buffer, '['); + if (PM_NODE_FLAG_P(cast, PM_STRING_FLAGS_FORCED_UTF8_ENCODING)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"FORCED_UTF8_ENCODING\"", 22); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_STRING_FLAGS_FORCED_BINARY_ENCODING)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"FORCED_BINARY_ENCODING\"", 24); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_STRING_FLAGS_FROZEN)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"FROZEN\"", 8); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_STRING_FLAGS_MUTABLE)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"MUTABLE\"", 9); + flags++; + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the filepath field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"filepath\":", 11); + const pm_string_t *filepath = &cast->filepath; + pm_buffer_append_byte(buffer, '"'); + pm_buffer_append_source(buffer, pm_string_source(filepath), pm_string_length(filepath), PM_BUFFER_ESCAPING_JSON); + pm_buffer_append_byte(buffer, '"'); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_SOURCE_LINE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"SourceLineNode\",\"location\":", 36); + + const pm_source_line_node_t *cast = (const pm_source_line_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_SPLAT_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"SplatNode\",\"location\":", 31); + + const pm_splat_node_t *cast = (const pm_splat_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the operator_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"operator_loc\":", 15); + pm_dump_json_location(buffer, &cast->operator_loc); + + // Dump the expression field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"expression\":", 13); + if (cast->expression != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->expression); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_STATEMENTS_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"StatementsNode\",\"location\":", 36); + + const pm_statements_node_t *cast = (const pm_statements_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the body field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"body\":", 7); + const pm_node_list_t *body = &cast->body; + pm_buffer_append_byte(buffer, '['); + + for (size_t index = 0; index < body->size; index++) { + if (index != 0) pm_buffer_append_byte(buffer, ','); + pm_dump_json(buffer, parser, body->nodes[index]); + } + pm_buffer_append_byte(buffer, ']'); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_STRING_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"StringNode\",\"location\":", 32); + + const pm_string_node_t *cast = (const pm_string_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the StringFlags field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"flags\":", 8); + size_t flags = 0; + pm_buffer_append_byte(buffer, '['); + if (PM_NODE_FLAG_P(cast, PM_STRING_FLAGS_FORCED_UTF8_ENCODING)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"FORCED_UTF8_ENCODING\"", 22); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_STRING_FLAGS_FORCED_BINARY_ENCODING)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"FORCED_BINARY_ENCODING\"", 24); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_STRING_FLAGS_FROZEN)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"FROZEN\"", 8); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_STRING_FLAGS_MUTABLE)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"MUTABLE\"", 9); + flags++; + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the opening_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"opening_loc\":", 14); + if (cast->opening_loc.length != 0) { + pm_dump_json_location(buffer, &cast->opening_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the content_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"content_loc\":", 14); + pm_dump_json_location(buffer, &cast->content_loc); + + // Dump the closing_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"closing_loc\":", 14); + if (cast->closing_loc.length != 0) { + pm_dump_json_location(buffer, &cast->closing_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the unescaped field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"unescaped\":", 12); + const pm_string_t *unescaped = &cast->unescaped; + pm_buffer_append_byte(buffer, '"'); + pm_buffer_append_source(buffer, pm_string_source(unescaped), pm_string_length(unescaped), PM_BUFFER_ESCAPING_JSON); + pm_buffer_append_byte(buffer, '"'); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_SUPER_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"SuperNode\",\"location\":", 31); + + const pm_super_node_t *cast = (const pm_super_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"keyword_loc\":", 14); + pm_dump_json_location(buffer, &cast->keyword_loc); + + // Dump the lparen_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"lparen_loc\":", 13); + if (cast->lparen_loc.length != 0) { + pm_dump_json_location(buffer, &cast->lparen_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the arguments field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"arguments\":", 12); + if (cast->arguments != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->arguments); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the rparen_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"rparen_loc\":", 13); + if (cast->rparen_loc.length != 0) { + pm_dump_json_location(buffer, &cast->rparen_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the block field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"block\":", 8); + if (cast->block != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->block); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_SYMBOL_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"SymbolNode\",\"location\":", 32); + + const pm_symbol_node_t *cast = (const pm_symbol_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the SymbolFlags field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"flags\":", 8); + size_t flags = 0; + pm_buffer_append_byte(buffer, '['); + if (PM_NODE_FLAG_P(cast, PM_SYMBOL_FLAGS_FORCED_UTF8_ENCODING)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"FORCED_UTF8_ENCODING\"", 22); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_SYMBOL_FLAGS_FORCED_BINARY_ENCODING)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"FORCED_BINARY_ENCODING\"", 24); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"FORCED_US_ASCII_ENCODING\"", 26); + flags++; + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the opening_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"opening_loc\":", 14); + if (cast->opening_loc.length != 0) { + pm_dump_json_location(buffer, &cast->opening_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the value_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"value_loc\":", 12); + if (cast->value_loc.length != 0) { + pm_dump_json_location(buffer, &cast->value_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the closing_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"closing_loc\":", 14); + if (cast->closing_loc.length != 0) { + pm_dump_json_location(buffer, &cast->closing_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the unescaped field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"unescaped\":", 12); + const pm_string_t *unescaped = &cast->unescaped; + pm_buffer_append_byte(buffer, '"'); + pm_buffer_append_source(buffer, pm_string_source(unescaped), pm_string_length(unescaped), PM_BUFFER_ESCAPING_JSON); + pm_buffer_append_byte(buffer, '"'); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_TRUE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"TrueNode\",\"location\":", 30); + + const pm_true_node_t *cast = (const pm_true_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_UNDEF_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"UndefNode\",\"location\":", 31); + + const pm_undef_node_t *cast = (const pm_undef_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the names field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"names\":", 8); + const pm_node_list_t *names = &cast->names; + pm_buffer_append_byte(buffer, '['); + + for (size_t index = 0; index < names->size; index++) { + if (index != 0) pm_buffer_append_byte(buffer, ','); + pm_dump_json(buffer, parser, names->nodes[index]); + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"keyword_loc\":", 14); + pm_dump_json_location(buffer, &cast->keyword_loc); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_UNLESS_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"UnlessNode\",\"location\":", 32); + + const pm_unless_node_t *cast = (const pm_unless_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"keyword_loc\":", 14); + pm_dump_json_location(buffer, &cast->keyword_loc); + + // Dump the predicate field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"predicate\":", 12); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->predicate); + + // Dump the then_keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"then_keyword_loc\":", 19); + if (cast->then_keyword_loc.length != 0) { + pm_dump_json_location(buffer, &cast->then_keyword_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the statements field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"statements\":", 13); + if (cast->statements != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the else_clause field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"else_clause\":", 14); + if (cast->else_clause != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->else_clause); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the end_keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"end_keyword_loc\":", 18); + if (cast->end_keyword_loc.length != 0) { + pm_dump_json_location(buffer, &cast->end_keyword_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_UNTIL_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"UntilNode\",\"location\":", 31); + + const pm_until_node_t *cast = (const pm_until_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the LoopFlags field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"flags\":", 8); + size_t flags = 0; + pm_buffer_append_byte(buffer, '['); + if (PM_NODE_FLAG_P(cast, PM_LOOP_FLAGS_BEGIN_MODIFIER)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"BEGIN_MODIFIER\"", 16); + flags++; + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"keyword_loc\":", 14); + pm_dump_json_location(buffer, &cast->keyword_loc); + + // Dump the do_keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"do_keyword_loc\":", 17); + if (cast->do_keyword_loc.length != 0) { + pm_dump_json_location(buffer, &cast->do_keyword_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the closing_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"closing_loc\":", 14); + if (cast->closing_loc.length != 0) { + pm_dump_json_location(buffer, &cast->closing_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the predicate field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"predicate\":", 12); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->predicate); + + // Dump the statements field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"statements\":", 13); + if (cast->statements != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_WHEN_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"WhenNode\",\"location\":", 30); + + const pm_when_node_t *cast = (const pm_when_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"keyword_loc\":", 14); + pm_dump_json_location(buffer, &cast->keyword_loc); + + // Dump the conditions field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"conditions\":", 13); + const pm_node_list_t *conditions = &cast->conditions; + pm_buffer_append_byte(buffer, '['); + + for (size_t index = 0; index < conditions->size; index++) { + if (index != 0) pm_buffer_append_byte(buffer, ','); + pm_dump_json(buffer, parser, conditions->nodes[index]); + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the then_keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"then_keyword_loc\":", 19); + if (cast->then_keyword_loc.length != 0) { + pm_dump_json_location(buffer, &cast->then_keyword_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the statements field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"statements\":", 13); + if (cast->statements != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_WHILE_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"WhileNode\",\"location\":", 31); + + const pm_while_node_t *cast = (const pm_while_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the LoopFlags field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"flags\":", 8); + size_t flags = 0; + pm_buffer_append_byte(buffer, '['); + if (PM_NODE_FLAG_P(cast, PM_LOOP_FLAGS_BEGIN_MODIFIER)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"BEGIN_MODIFIER\"", 16); + flags++; + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"keyword_loc\":", 14); + pm_dump_json_location(buffer, &cast->keyword_loc); + + // Dump the do_keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"do_keyword_loc\":", 17); + if (cast->do_keyword_loc.length != 0) { + pm_dump_json_location(buffer, &cast->do_keyword_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the closing_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"closing_loc\":", 14); + if (cast->closing_loc.length != 0) { + pm_dump_json_location(buffer, &cast->closing_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the predicate field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"predicate\":", 12); + pm_dump_json(buffer, parser, (const pm_node_t *) cast->predicate); + + // Dump the statements field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"statements\":", 13); + if (cast->statements != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_X_STRING_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"XStringNode\",\"location\":", 33); + + const pm_x_string_node_t *cast = (const pm_x_string_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the EncodingFlags field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"flags\":", 8); + size_t flags = 0; + pm_buffer_append_byte(buffer, '['); + if (PM_NODE_FLAG_P(cast, PM_ENCODING_FLAGS_FORCED_UTF8_ENCODING)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"FORCED_UTF8_ENCODING\"", 22); + flags++; + } + if (PM_NODE_FLAG_P(cast, PM_ENCODING_FLAGS_FORCED_BINARY_ENCODING)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"FORCED_BINARY_ENCODING\"", 24); + flags++; + } + pm_buffer_append_byte(buffer, ']'); + + // Dump the opening_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"opening_loc\":", 14); + pm_dump_json_location(buffer, &cast->opening_loc); + + // Dump the content_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"content_loc\":", 14); + pm_dump_json_location(buffer, &cast->content_loc); + + // Dump the closing_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"closing_loc\":", 14); + pm_dump_json_location(buffer, &cast->closing_loc); + + // Dump the unescaped field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"unescaped\":", 12); + const pm_string_t *unescaped = &cast->unescaped; + pm_buffer_append_byte(buffer, '"'); + pm_buffer_append_source(buffer, pm_string_source(unescaped), pm_string_length(unescaped), PM_BUFFER_ESCAPING_JSON); + pm_buffer_append_byte(buffer, '"'); + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_YIELD_NODE: { + pm_buffer_append_string(buffer, "{\"type\":\"YieldNode\",\"location\":", 31); + + const pm_yield_node_t *cast = (const pm_yield_node_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + + // Dump the keyword_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"keyword_loc\":", 14); + pm_dump_json_location(buffer, &cast->keyword_loc); + + // Dump the lparen_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"lparen_loc\":", 13); + if (cast->lparen_loc.length != 0) { + pm_dump_json_location(buffer, &cast->lparen_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the arguments field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"arguments\":", 12); + if (cast->arguments != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast->arguments); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + // Dump the rparen_loc field + pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"rparen_loc\":", 13); + if (cast->rparen_loc.length != 0) { + pm_dump_json_location(buffer, &cast->rparen_loc); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + + pm_buffer_append_byte(buffer, '}'); + break; + } + case PM_SCOPE_NODE: + break; + } +} + +#endif diff --git a/prism/json.h b/prism/json.h new file mode 100644 index 00000000000000..11039e7796cb43 --- /dev/null +++ b/prism/json.h @@ -0,0 +1,32 @@ +/** + * @file json.h + */ +#ifndef PRISM_JSON_H +#define PRISM_JSON_H + +#include "prism/excludes.h" + +/* We optionally support dumping to JSON. For systems that don't want or need + * this functionality, it can be turned off with the PRISM_EXCLUDE_JSON define. + */ +#ifndef PRISM_EXCLUDE_JSON + +#include "prism/compiler/exported.h" +#include "prism/compiler/nonnull.h" + +#include "prism/ast.h" +#include "prism/buffer.h" +#include "prism/parser.h" + +/** + * Dump JSON to the given buffer. + * + * @param buffer The buffer to serialize to. + * @param parser The parser that parsed the node. + * @param node The node to serialize. + */ +PRISM_EXPORTED_FUNCTION void pm_dump_json(pm_buffer_t *buffer, const pm_parser_t *parser, const pm_node_t *node) PRISM_NONNULL(1, 2, 3); + +#endif + +#endif diff --git a/prism/util/pm_line_offset_list.c b/prism/line_offset_list.c similarity index 94% rename from prism/util/pm_line_offset_list.c rename to prism/line_offset_list.c index 0648901e297a7a..ce217ebd3f19f4 100644 --- a/prism/util/pm_line_offset_list.c +++ b/prism/line_offset_list.c @@ -1,4 +1,9 @@ -#include "prism/util/pm_line_offset_list.h" +#include "prism/compiler/align.h" +#include "prism/internal/line_offset_list.h" +#include "prism/internal/arena.h" + +#include +#include /** * Initialize a new line offset list with the given capacity. diff --git a/prism/line_offset_list.h b/prism/line_offset_list.h new file mode 100644 index 00000000000000..848bc491397772 --- /dev/null +++ b/prism/line_offset_list.h @@ -0,0 +1,61 @@ +/** + * @file line_offset_list.h + * + * A list of byte offsets of newlines in a string. + * + * When compiling the syntax tree, it's necessary to know the line and column + * of many nodes. This is necessary to support things like error messages, + * tracepoints, etc. + * + * It's possible that we could store the start line, start column, end line, and + * end column on every node in addition to the offsets that we already store, + * but that would be quite a lot of memory overhead. + */ +#ifndef PRISM_LINE_OFFSET_LIST_H +#define PRISM_LINE_OFFSET_LIST_H + +#include "prism/compiler/exported.h" +#include "prism/compiler/nonnull.h" + +#include +#include + +/** + * A list of offsets of the start of lines in a string. The offsets are assumed + * to be sorted/inserted in ascending order. + */ +typedef struct { + /** The number of offsets in the list. */ + size_t size; + + /** The capacity of the list that has been allocated. */ + size_t capacity; + + /** The list of offsets. */ + uint32_t *offsets; +} pm_line_offset_list_t; + +/** + * A line and column in a string. + */ +typedef struct { + /** The line number. */ + int32_t line; + + /** The column in bytes. */ + uint32_t column; +} pm_line_column_t; + +/** + * Returns the line and column of the given offset. If the offset is not in the + * list, the line and column of the closest offset less than the given offset + * are returned. + * + * @param list The list to search. + * @param cursor The offset to search for. + * @param start_line The line to start counting from. + * @returns The line and column of the given offset. + */ +PRISM_EXPORTED_FUNCTION pm_line_column_t pm_line_offset_list_line_column(const pm_line_offset_list_t *list, uint32_t cursor, int32_t start_line) PRISM_NONNULL(1); + +#endif diff --git a/prism/list.c b/prism/list.c new file mode 100644 index 00000000000000..8d4cd1be946df2 --- /dev/null +++ b/prism/list.c @@ -0,0 +1,24 @@ +#include "prism/internal/list.h" + +/** + * Returns the size of the list. + */ +size_t +pm_list_size(pm_list_t *list) { + return list->size; +} + +/** + * Append a node to the given list. + */ +void +pm_list_append(pm_list_t *list, pm_list_node_t *node) { + if (list->head == NULL) { + list->head = node; + } else { + list->tail->next = node; + } + + list->tail = node; + list->size++; +} diff --git a/prism/magic_comments.h b/prism/magic_comments.h new file mode 100644 index 00000000000000..c9d6b600e87de6 --- /dev/null +++ b/prism/magic_comments.h @@ -0,0 +1,35 @@ +/** + * @file magic_comments.h + * + * Types and functions related to magic comments found during parsing. + */ +#ifndef PRISM_MAGIC_COMMENTS_H +#define PRISM_MAGIC_COMMENTS_H + +#include "prism/compiler/exported.h" +#include "prism/compiler/nonnull.h" + +#include "prism/ast.h" + +#include + +/** An opaque pointer to a magic comment found while parsing. */ +typedef struct pm_magic_comment_t pm_magic_comment_t; + +/** + * Returns the location of the key associated with the given magic comment. + * + * @param magic_comment the magic comment whose key location we want to get + * @returns the location of the key associated with the given magic comment + */ +PRISM_EXPORTED_FUNCTION pm_location_t pm_magic_comment_key(const pm_magic_comment_t *magic_comment) PRISM_NONNULL(1); + +/** + * Returns the location of the value associated with the given magic comment. + * + * @param magic_comment the magic comment whose value location we want to get + * @returns the location of the value associated with the given magic comment + */ +PRISM_EXPORTED_FUNCTION pm_location_t pm_magic_comment_value(const pm_magic_comment_t *magic_comment) PRISM_NONNULL(1); + +#endif diff --git a/prism/util/pm_memchr.c b/prism/memchr.c similarity index 85% rename from prism/util/pm_memchr.c rename to prism/memchr.c index 7ea20ace6d5290..6266d4ca7a5192 100644 --- a/prism/util/pm_memchr.c +++ b/prism/memchr.c @@ -1,6 +1,10 @@ -#include "prism/util/pm_memchr.h" +#include "prism/internal/memchr.h" -#define PRISM_MEMCHR_TRAILING_BYTE_MINIMUM 0x40 +#include +#include +#include + +#define TRAILING_BYTE_MINIMUM 0x40 /** * We need to roll our own memchr to handle cases where the encoding changes and @@ -9,7 +13,7 @@ */ void * pm_memchr(const void *memory, int character, size_t number, bool encoding_changed, const pm_encoding_t *encoding) { - if (encoding_changed && encoding->multibyte && character >= PRISM_MEMCHR_TRAILING_BYTE_MINIMUM) { + if (encoding_changed && encoding->multibyte && character >= TRAILING_BYTE_MINIMUM) { const uint8_t *source = (const uint8_t *) memory; size_t index = 0; @@ -31,5 +35,3 @@ pm_memchr(const void *memory, int character, size_t number, bool encoding_change return memchr(memory, character, number); } } - -#undef PRISM_MEMCHR_TRAILING_BYTE_MINIMUM diff --git a/prism/node.h b/prism/node.h index f02f8ba892b935..75bc3c9b2dcb85 100644 --- a/prism/node.h +++ b/prism/node.h @@ -6,9 +6,10 @@ #ifndef PRISM_NODE_H #define PRISM_NODE_H -#include "prism/defines.h" -#include "prism/parser.h" -#include "prism/util/pm_buffer.h" +#include "prism/compiler/exported.h" +#include "prism/compiler/nonnull.h" + +#include "prism/ast.h" /** * Loop through each node in the node list, writing each node to the given @@ -17,57 +18,13 @@ #define PM_NODE_LIST_FOREACH(list, index, node) \ for (size_t index = 0; index < (list)->size && ((node) = (list)->nodes[index]); index++) -/** - * Slow path for pm_node_list_append: grow the list and append the node. - * Do not call directly — use pm_node_list_append instead. - * - * @param arena The arena to allocate from. - * @param list The list to append to. - * @param node The node to append. - */ -void pm_node_list_append_slow(pm_arena_t *arena, pm_node_list_t *list, pm_node_t *node); - -/** - * Append a new node onto the end of the node list. - * - * @param arena The arena to allocate from. - * @param list The list to append to. - * @param node The node to append. - */ -static PRISM_FORCE_INLINE void -pm_node_list_append(pm_arena_t *arena, pm_node_list_t *list, pm_node_t *node) { - if (list->size < list->capacity) { - list->nodes[list->size++] = node; - } else { - pm_node_list_append_slow(arena, list, node); - } -} - -/** - * Prepend a new node onto the beginning of the node list. - * - * @param arena The arena to allocate from. - * @param list The list to prepend to. - * @param node The node to prepend. - */ -void pm_node_list_prepend(pm_arena_t *arena, pm_node_list_t *list, pm_node_t *node); - -/** - * Concatenate the given node list onto the end of the other node list. - * - * @param arena The arena to allocate from. - * @param list The list to concatenate onto. - * @param other The list to concatenate. - */ -void pm_node_list_concat(pm_arena_t *arena, pm_node_list_t *list, pm_node_list_t *other); - /** * Returns a string representation of the given node type. * * @param node_type The node type to convert to a string. - * @return A string representation of the given node type. + * @returns A string representation of the given node type. */ -PRISM_EXPORTED_FUNCTION const char * pm_node_type_to_str(pm_node_type_t node_type); +PRISM_EXPORTED_FUNCTION const char * pm_node_type(pm_node_type_t node_type); /** * Visit each of the nodes in this subtree using the given visitor callback. The @@ -85,7 +42,7 @@ PRISM_EXPORTED_FUNCTION const char * pm_node_type_to_str(pm_node_type_t node_typ * bool visit(const pm_node_t *node, void *data) { * size_t *indent = (size_t *) data; * for (size_t i = 0; i < *indent * 2; i++) putc(' ', stdout); - * printf("%s\n", pm_node_type_to_str(node->type)); + * printf("%s\n", pm_node_type(node->type)); * * size_t next_indent = *indent + 1; * size_t *next_data = &next_indent; @@ -98,19 +55,21 @@ PRISM_EXPORTED_FUNCTION const char * pm_node_type_to_str(pm_node_type_t node_typ * const char *source = "1 + 2; 3 + 4"; * size_t size = strlen(source); * - * pm_arena_t arena = { 0 }; - * pm_parser_t parser; - * pm_options_t options = { 0 }; - * pm_parser_init(&arena, &parser, (const uint8_t *) source, size, &options); + * pm_arena_t *arena = pm_arena_new(); + * pm_options_t *options = pm_options_new(); + * + * pm_parser_t *parser = pm_parser_new(arena, (const uint8_t *) source, size, options); * * size_t indent = 0; - * pm_node_t *node = pm_parse(&parser); + * pm_node_t *node = pm_parse(parser); * * size_t *data = &indent; * pm_visit_node(node, visit, data); * - * pm_parser_free(&parser); - * pm_arena_free(&arena); + * pm_parser_free(parser); + * pm_options_free(options); + * pm_arena_free(arena); + * * return EXIT_SUCCESS; * } * ``` @@ -119,7 +78,7 @@ PRISM_EXPORTED_FUNCTION const char * pm_node_type_to_str(pm_node_type_t node_typ * @param visitor The callback to call for each node in the subtree. * @param data An opaque pointer that is passed to the visitor callback. */ -PRISM_EXPORTED_FUNCTION void pm_visit_node(const pm_node_t *node, bool (*visitor)(const pm_node_t *node, void *data), void *data); +PRISM_EXPORTED_FUNCTION void pm_visit_node(const pm_node_t *node, bool (*visitor)(const pm_node_t *node, void *data), void *data) PRISM_NONNULL(1); /** * Visit the children of the given node with the given callback. This is the @@ -130,6 +89,6 @@ PRISM_EXPORTED_FUNCTION void pm_visit_node(const pm_node_t *node, bool (*visitor * @param visitor The callback to call for each child node. * @param data An opaque pointer that is passed to the visitor callback. */ -PRISM_EXPORTED_FUNCTION void pm_visit_child_nodes(const pm_node_t *node, bool (*visitor)(const pm_node_t *node, void *data), void *data); +PRISM_EXPORTED_FUNCTION void pm_visit_child_nodes(const pm_node_t *node, bool (*visitor)(const pm_node_t *node, void *data), void *data) PRISM_NONNULL(1); #endif diff --git a/prism/node_new.h b/prism/node_new.h deleted file mode 100644 index 09bfc1a9dc065b..00000000000000 --- a/prism/node_new.h +++ /dev/null @@ -1,4071 +0,0 @@ -/*----------------------------------------------------------------------------*/ -/* This file is generated by the templates/template.rb script and should not */ -/* be modified manually. See */ -/* templates/include/prism/node_new.h.erb */ -/* if you are looking to modify the */ -/* template */ -/*----------------------------------------------------------------------------*/ - -/** - * @file node_new.h - * - * Static inline functions for allocating and initializing AST nodes. - * - * -- - */ -#ifndef PRISM_NODE_NEW_H -#define PRISM_NODE_NEW_H - -#include "prism/node.h" - -/** - * Allocate and initialize a new AliasGlobalVariableNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param new_name Represents the new name of the global variable that can be used after aliasing\. - * @param old_name Represents the old name of the global variable that can be used before aliasing\. - * @param keyword_loc The Location of the \`alias\` keyword\. - * @return The newly allocated and initialized node. - */ -static inline pm_alias_global_variable_node_t * -pm_alias_global_variable_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_node *new_name, struct pm_node *old_name, pm_location_t keyword_loc) { - pm_alias_global_variable_node_t *node = (pm_alias_global_variable_node_t *) pm_arena_alloc(arena, sizeof(pm_alias_global_variable_node_t), PRISM_ALIGNOF(pm_alias_global_variable_node_t)); - - *node = (pm_alias_global_variable_node_t) { - .base = { .type = PM_ALIAS_GLOBAL_VARIABLE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .new_name = new_name, - .old_name = old_name, - .keyword_loc = keyword_loc - }; - - return node; -} - -/** - * Allocate and initialize a new AliasMethodNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param new_name Represents the new name of the method that will be aliased\. - * @param old_name Represents the old name of the method that will be aliased\. - * @param keyword_loc Represents the Location of the \`alias\` keyword\. - * @return The newly allocated and initialized node. - */ -static inline pm_alias_method_node_t * -pm_alias_method_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_node *new_name, struct pm_node *old_name, pm_location_t keyword_loc) { - pm_alias_method_node_t *node = (pm_alias_method_node_t *) pm_arena_alloc(arena, sizeof(pm_alias_method_node_t), PRISM_ALIGNOF(pm_alias_method_node_t)); - - *node = (pm_alias_method_node_t) { - .base = { .type = PM_ALIAS_METHOD_NODE, .flags = flags, .node_id = node_id, .location = location }, - .new_name = new_name, - .old_name = old_name, - .keyword_loc = keyword_loc - }; - - return node; -} - -/** - * Allocate and initialize a new AlternationPatternNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param left Represents the left side of the expression\. - * @param right Represents the right side of the expression\. - * @param operator_loc Represents the alternation operator Location\. - * @return The newly allocated and initialized node. - */ -static inline pm_alternation_pattern_node_t * -pm_alternation_pattern_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_node *left, struct pm_node *right, pm_location_t operator_loc) { - pm_alternation_pattern_node_t *node = (pm_alternation_pattern_node_t *) pm_arena_alloc(arena, sizeof(pm_alternation_pattern_node_t), PRISM_ALIGNOF(pm_alternation_pattern_node_t)); - - *node = (pm_alternation_pattern_node_t) { - .base = { .type = PM_ALTERNATION_PATTERN_NODE, .flags = flags, .node_id = node_id, .location = location }, - .left = left, - .right = right, - .operator_loc = operator_loc - }; - - return node; -} - -/** - * Allocate and initialize a new AndNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param left Represents the left side of the expression\. It can be any [non\-void expression](https://github\.com/ruby/prism/blob/main/docs/parsing\_rules\.md\#non\-void\-expression)\. - * @param right Represents the right side of the expression\. - * @param operator_loc The Location of the \`and\` keyword or the \`&&\` operator\. - * @return The newly allocated and initialized node. - */ -static inline pm_and_node_t * -pm_and_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_node *left, struct pm_node *right, pm_location_t operator_loc) { - pm_and_node_t *node = (pm_and_node_t *) pm_arena_alloc(arena, sizeof(pm_and_node_t), PRISM_ALIGNOF(pm_and_node_t)); - - *node = (pm_and_node_t) { - .base = { .type = PM_AND_NODE, .flags = flags, .node_id = node_id, .location = location }, - .left = left, - .right = right, - .operator_loc = operator_loc - }; - - return node; -} - -/** - * Allocate and initialize a new ArgumentsNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param arguments The list of arguments, if present\. These can be any [non\-void expressions](https://github\.com/ruby/prism/blob/main/docs/parsing\_rules\.md\#non\-void\-expression)\. - * @return The newly allocated and initialized node. - */ -static inline pm_arguments_node_t * -pm_arguments_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_node_list_t arguments) { - pm_arguments_node_t *node = (pm_arguments_node_t *) pm_arena_alloc(arena, sizeof(pm_arguments_node_t), PRISM_ALIGNOF(pm_arguments_node_t)); - - *node = (pm_arguments_node_t) { - .base = { .type = PM_ARGUMENTS_NODE, .flags = flags, .node_id = node_id, .location = location }, - .arguments = arguments - }; - - return node; -} - -/** - * Allocate and initialize a new ArrayNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param elements Represent the list of zero or more [non\-void expressions](https://github\.com/ruby/prism/blob/main/docs/parsing\_rules\.md\#non\-void\-expression) within the array\. - * @param opening_loc Represents the optional source Location for the opening token\. - * @param closing_loc Represents the optional source Location for the closing token\. - * @return The newly allocated and initialized node. - */ -static inline pm_array_node_t * -pm_array_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_node_list_t elements, pm_location_t opening_loc, pm_location_t closing_loc) { - pm_array_node_t *node = (pm_array_node_t *) pm_arena_alloc(arena, sizeof(pm_array_node_t), PRISM_ALIGNOF(pm_array_node_t)); - - *node = (pm_array_node_t) { - .base = { .type = PM_ARRAY_NODE, .flags = flags, .node_id = node_id, .location = location }, - .elements = elements, - .opening_loc = opening_loc, - .closing_loc = closing_loc - }; - - return node; -} - -/** - * Allocate and initialize a new ArrayPatternNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param constant Represents the optional constant preceding the Array - * @param requireds Represents the required elements of the array pattern\. - * @param rest Represents the rest element of the array pattern\. - * @param posts Represents the elements after the rest element of the array pattern\. - * @param opening_loc Represents the opening Location of the array pattern\. - * @param closing_loc Represents the closing Location of the array pattern\. - * @return The newly allocated and initialized node. - */ -static inline pm_array_pattern_node_t * -pm_array_pattern_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_node *constant, pm_node_list_t requireds, struct pm_node *rest, pm_node_list_t posts, pm_location_t opening_loc, pm_location_t closing_loc) { - pm_array_pattern_node_t *node = (pm_array_pattern_node_t *) pm_arena_alloc(arena, sizeof(pm_array_pattern_node_t), PRISM_ALIGNOF(pm_array_pattern_node_t)); - - *node = (pm_array_pattern_node_t) { - .base = { .type = PM_ARRAY_PATTERN_NODE, .flags = flags, .node_id = node_id, .location = location }, - .constant = constant, - .requireds = requireds, - .rest = rest, - .posts = posts, - .opening_loc = opening_loc, - .closing_loc = closing_loc - }; - - return node; -} - -/** - * Allocate and initialize a new AssocNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param key The key of the association\. This can be any [non\-void expression](https://github\.com/ruby/prism/blob/main/docs/parsing\_rules\.md\#non\-void\-expression)\. - * @param value The value of the association, if present\. This can be any [non\-void expression](https://github\.com/ruby/prism/blob/main/docs/parsing\_rules\.md\#non\-void\-expression)\. - * @param operator_loc The Location of the \`=\>\` operator, if present\. - * @return The newly allocated and initialized node. - */ -static inline pm_assoc_node_t * -pm_assoc_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_node *key, struct pm_node *value, pm_location_t operator_loc) { - pm_assoc_node_t *node = (pm_assoc_node_t *) pm_arena_alloc(arena, sizeof(pm_assoc_node_t), PRISM_ALIGNOF(pm_assoc_node_t)); - - *node = (pm_assoc_node_t) { - .base = { .type = PM_ASSOC_NODE, .flags = flags, .node_id = node_id, .location = location }, - .key = key, - .value = value, - .operator_loc = operator_loc - }; - - return node; -} - -/** - * Allocate and initialize a new AssocSplatNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param value The value to be splatted, if present\. Will be missing when keyword rest argument forwarding is used\. - * @param operator_loc The Location of the \`\*\*\` operator\. - * @return The newly allocated and initialized node. - */ -static inline pm_assoc_splat_node_t * -pm_assoc_splat_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_node *value, pm_location_t operator_loc) { - pm_assoc_splat_node_t *node = (pm_assoc_splat_node_t *) pm_arena_alloc(arena, sizeof(pm_assoc_splat_node_t), PRISM_ALIGNOF(pm_assoc_splat_node_t)); - - *node = (pm_assoc_splat_node_t) { - .base = { .type = PM_ASSOC_SPLAT_NODE, .flags = flags, .node_id = node_id, .location = location }, - .value = value, - .operator_loc = operator_loc - }; - - return node; -} - -/** - * Allocate and initialize a new BackReferenceReadNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param name The name of the back\-reference variable, including the leading \`$\`\. - * @return The newly allocated and initialized node. - */ -static inline pm_back_reference_read_node_t * -pm_back_reference_read_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_constant_id_t name) { - pm_back_reference_read_node_t *node = (pm_back_reference_read_node_t *) pm_arena_alloc(arena, sizeof(pm_back_reference_read_node_t), PRISM_ALIGNOF(pm_back_reference_read_node_t)); - - *node = (pm_back_reference_read_node_t) { - .base = { .type = PM_BACK_REFERENCE_READ_NODE, .flags = flags, .node_id = node_id, .location = location }, - .name = name - }; - - return node; -} - -/** - * Allocate and initialize a new BeginNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param begin_keyword_loc Represents the Location of the \`begin\` keyword\. - * @param statements Represents the statements within the begin block\. - * @param rescue_clause Represents the rescue clause within the begin block\. - * @param else_clause Represents the else clause within the begin block\. - * @param ensure_clause Represents the ensure clause within the begin block\. - * @param end_keyword_loc Represents the Location of the \`end\` keyword\. - * @return The newly allocated and initialized node. - */ -static inline pm_begin_node_t * -pm_begin_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_location_t begin_keyword_loc, struct pm_statements_node *statements, struct pm_rescue_node *rescue_clause, struct pm_else_node *else_clause, struct pm_ensure_node *ensure_clause, pm_location_t end_keyword_loc) { - pm_begin_node_t *node = (pm_begin_node_t *) pm_arena_alloc(arena, sizeof(pm_begin_node_t), PRISM_ALIGNOF(pm_begin_node_t)); - - *node = (pm_begin_node_t) { - .base = { .type = PM_BEGIN_NODE, .flags = flags, .node_id = node_id, .location = location }, - .begin_keyword_loc = begin_keyword_loc, - .statements = statements, - .rescue_clause = rescue_clause, - .else_clause = else_clause, - .ensure_clause = ensure_clause, - .end_keyword_loc = end_keyword_loc - }; - - return node; -} - -/** - * Allocate and initialize a new BlockArgumentNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param expression The expression that is being passed as a block argument\. This can be any [non\-void expression](https://github\.com/ruby/prism/blob/main/docs/parsing\_rules\.md\#non\-void\-expression)\. - * @param operator_loc Represents the Location of the \`&\` operator\. - * @return The newly allocated and initialized node. - */ -static inline pm_block_argument_node_t * -pm_block_argument_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_node *expression, pm_location_t operator_loc) { - pm_block_argument_node_t *node = (pm_block_argument_node_t *) pm_arena_alloc(arena, sizeof(pm_block_argument_node_t), PRISM_ALIGNOF(pm_block_argument_node_t)); - - *node = (pm_block_argument_node_t) { - .base = { .type = PM_BLOCK_ARGUMENT_NODE, .flags = flags, .node_id = node_id, .location = location }, - .expression = expression, - .operator_loc = operator_loc - }; - - return node; -} - -/** - * Allocate and initialize a new BlockLocalVariableNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param name The name of the block local variable\. - * @return The newly allocated and initialized node. - */ -static inline pm_block_local_variable_node_t * -pm_block_local_variable_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_constant_id_t name) { - pm_block_local_variable_node_t *node = (pm_block_local_variable_node_t *) pm_arena_alloc(arena, sizeof(pm_block_local_variable_node_t), PRISM_ALIGNOF(pm_block_local_variable_node_t)); - - *node = (pm_block_local_variable_node_t) { - .base = { .type = PM_BLOCK_LOCAL_VARIABLE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .name = name - }; - - return node; -} - -/** - * Allocate and initialize a new BlockNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param locals The local variables declared in the block\. - * @param parameters The parameters of the block\. - * @param body The body of the block\. - * @param opening_loc Represents the Location of the opening \`{\` or \`do\`\. - * @param closing_loc Represents the Location of the closing \`}\` or \`end\`\. - * @return The newly allocated and initialized node. - */ -static inline pm_block_node_t * -pm_block_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_constant_id_list_t locals, struct pm_node *parameters, struct pm_node *body, pm_location_t opening_loc, pm_location_t closing_loc) { - pm_block_node_t *node = (pm_block_node_t *) pm_arena_alloc(arena, sizeof(pm_block_node_t), PRISM_ALIGNOF(pm_block_node_t)); - - *node = (pm_block_node_t) { - .base = { .type = PM_BLOCK_NODE, .flags = flags, .node_id = node_id, .location = location }, - .locals = locals, - .parameters = parameters, - .body = body, - .opening_loc = opening_loc, - .closing_loc = closing_loc - }; - - return node; -} - -/** - * Allocate and initialize a new BlockParameterNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param name The name of the block parameter\. - * @param name_loc Represents the Location of the block parameter name\. - * @param operator_loc Represents the Location of the \`&\` operator\. - * @return The newly allocated and initialized node. - */ -static inline pm_block_parameter_node_t * -pm_block_parameter_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_constant_id_t name, pm_location_t name_loc, pm_location_t operator_loc) { - pm_block_parameter_node_t *node = (pm_block_parameter_node_t *) pm_arena_alloc(arena, sizeof(pm_block_parameter_node_t), PRISM_ALIGNOF(pm_block_parameter_node_t)); - - *node = (pm_block_parameter_node_t) { - .base = { .type = PM_BLOCK_PARAMETER_NODE, .flags = flags, .node_id = node_id, .location = location }, - .name = name, - .name_loc = name_loc, - .operator_loc = operator_loc - }; - - return node; -} - -/** - * Allocate and initialize a new BlockParametersNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param parameters Represents the parameters of the block\. - * @param locals Represents the local variables of the block\. - * @param opening_loc Represents the opening Location of the block parameters\. - * @param closing_loc Represents the closing Location of the block parameters\. - * @return The newly allocated and initialized node. - */ -static inline pm_block_parameters_node_t * -pm_block_parameters_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_parameters_node *parameters, pm_node_list_t locals, pm_location_t opening_loc, pm_location_t closing_loc) { - pm_block_parameters_node_t *node = (pm_block_parameters_node_t *) pm_arena_alloc(arena, sizeof(pm_block_parameters_node_t), PRISM_ALIGNOF(pm_block_parameters_node_t)); - - *node = (pm_block_parameters_node_t) { - .base = { .type = PM_BLOCK_PARAMETERS_NODE, .flags = flags, .node_id = node_id, .location = location }, - .parameters = parameters, - .locals = locals, - .opening_loc = opening_loc, - .closing_loc = closing_loc - }; - - return node; -} - -/** - * Allocate and initialize a new BreakNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param arguments The arguments to the break statement, if present\. These can be any [non\-void expressions](https://github\.com/ruby/prism/blob/main/docs/parsing\_rules\.md\#non\-void\-expression)\. - * @param keyword_loc The Location of the \`break\` keyword\. - * @return The newly allocated and initialized node. - */ -static inline pm_break_node_t * -pm_break_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_arguments_node *arguments, pm_location_t keyword_loc) { - pm_break_node_t *node = (pm_break_node_t *) pm_arena_alloc(arena, sizeof(pm_break_node_t), PRISM_ALIGNOF(pm_break_node_t)); - - *node = (pm_break_node_t) { - .base = { .type = PM_BREAK_NODE, .flags = flags, .node_id = node_id, .location = location }, - .arguments = arguments, - .keyword_loc = keyword_loc - }; - - return node; -} - -/** - * Allocate and initialize a new CallAndWriteNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param receiver The object that the method is being called on\. This can be either \`nil\` or any [non\-void expression](https://github\.com/ruby/prism/blob/main/docs/parsing\_rules\.md\#non\-void\-expression)\. - * @param call_operator_loc Represents the Location of the call operator\. - * @param message_loc Represents the Location of the message\. - * @param read_name Represents the name of the method being called\. - * @param write_name Represents the name of the method being written to\. - * @param operator_loc Represents the Location of the operator\. - * @param value Represents the value being assigned\. - * @return The newly allocated and initialized node. - */ -static inline pm_call_and_write_node_t * -pm_call_and_write_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_node *receiver, pm_location_t call_operator_loc, pm_location_t message_loc, pm_constant_id_t read_name, pm_constant_id_t write_name, pm_location_t operator_loc, struct pm_node *value) { - pm_call_and_write_node_t *node = (pm_call_and_write_node_t *) pm_arena_alloc(arena, sizeof(pm_call_and_write_node_t), PRISM_ALIGNOF(pm_call_and_write_node_t)); - - *node = (pm_call_and_write_node_t) { - .base = { .type = PM_CALL_AND_WRITE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .receiver = receiver, - .call_operator_loc = call_operator_loc, - .message_loc = message_loc, - .read_name = read_name, - .write_name = write_name, - .operator_loc = operator_loc, - .value = value - }; - - return node; -} - -/** - * Allocate and initialize a new CallNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param receiver The object that the method is being called on\. This can be either \`nil\` or any [non\-void expression](https://github\.com/ruby/prism/blob/main/docs/parsing\_rules\.md\#non\-void\-expression)\. - * @param call_operator_loc Represents the Location of the call operator\. - * @param name Represents the name of the method being called\. - * @param message_loc Represents the Location of the message\. - * @param opening_loc Represents the Location of the left parenthesis\. - * @param arguments Represents the arguments to the method call\. These can be any [non\-void expressions](https://github\.com/ruby/prism/blob/main/docs/parsing\_rules\.md\#non\-void\-expression)\. - * @param closing_loc Represents the Location of the right parenthesis\. - * @param equal_loc Represents the Location of the equal sign, in the case that this is an attribute write\. - * @param block Represents the block that is being passed to the method\. - * @return The newly allocated and initialized node. - */ -static inline pm_call_node_t * -pm_call_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_node *receiver, pm_location_t call_operator_loc, pm_constant_id_t name, pm_location_t message_loc, pm_location_t opening_loc, struct pm_arguments_node *arguments, pm_location_t closing_loc, pm_location_t equal_loc, struct pm_node *block) { - pm_call_node_t *node = (pm_call_node_t *) pm_arena_alloc(arena, sizeof(pm_call_node_t), PRISM_ALIGNOF(pm_call_node_t)); - - *node = (pm_call_node_t) { - .base = { .type = PM_CALL_NODE, .flags = flags, .node_id = node_id, .location = location }, - .receiver = receiver, - .call_operator_loc = call_operator_loc, - .name = name, - .message_loc = message_loc, - .opening_loc = opening_loc, - .arguments = arguments, - .closing_loc = closing_loc, - .equal_loc = equal_loc, - .block = block - }; - - return node; -} - -/** - * Allocate and initialize a new CallOperatorWriteNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param receiver The object that the method is being called on\. This can be either \`nil\` or any [non\-void expressions](https://github\.com/ruby/prism/blob/main/docs/parsing\_rules\.md\#non\-void\-expression)\. - * @param call_operator_loc Represents the Location of the call operator\. - * @param message_loc Represents the Location of the message\. - * @param read_name Represents the name of the method being called\. - * @param write_name Represents the name of the method being written to\. - * @param binary_operator Represents the binary operator being used\. - * @param binary_operator_loc Represents the Location of the binary operator\. - * @param value Represents the value being assigned\. - * @return The newly allocated and initialized node. - */ -static inline pm_call_operator_write_node_t * -pm_call_operator_write_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_node *receiver, pm_location_t call_operator_loc, pm_location_t message_loc, pm_constant_id_t read_name, pm_constant_id_t write_name, pm_constant_id_t binary_operator, pm_location_t binary_operator_loc, struct pm_node *value) { - pm_call_operator_write_node_t *node = (pm_call_operator_write_node_t *) pm_arena_alloc(arena, sizeof(pm_call_operator_write_node_t), PRISM_ALIGNOF(pm_call_operator_write_node_t)); - - *node = (pm_call_operator_write_node_t) { - .base = { .type = PM_CALL_OPERATOR_WRITE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .receiver = receiver, - .call_operator_loc = call_operator_loc, - .message_loc = message_loc, - .read_name = read_name, - .write_name = write_name, - .binary_operator = binary_operator, - .binary_operator_loc = binary_operator_loc, - .value = value - }; - - return node; -} - -/** - * Allocate and initialize a new CallOrWriteNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param receiver The object that the method is being called on\. This can be either \`nil\` or any [non\-void expressions](https://github\.com/ruby/prism/blob/main/docs/parsing\_rules\.md\#non\-void\-expression)\. - * @param call_operator_loc Represents the Location of the call operator\. - * @param message_loc Represents the Location of the message\. - * @param read_name Represents the name of the method being called\. - * @param write_name Represents the name of the method being written to\. - * @param operator_loc Represents the Location of the operator\. - * @param value Represents the value being assigned\. - * @return The newly allocated and initialized node. - */ -static inline pm_call_or_write_node_t * -pm_call_or_write_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_node *receiver, pm_location_t call_operator_loc, pm_location_t message_loc, pm_constant_id_t read_name, pm_constant_id_t write_name, pm_location_t operator_loc, struct pm_node *value) { - pm_call_or_write_node_t *node = (pm_call_or_write_node_t *) pm_arena_alloc(arena, sizeof(pm_call_or_write_node_t), PRISM_ALIGNOF(pm_call_or_write_node_t)); - - *node = (pm_call_or_write_node_t) { - .base = { .type = PM_CALL_OR_WRITE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .receiver = receiver, - .call_operator_loc = call_operator_loc, - .message_loc = message_loc, - .read_name = read_name, - .write_name = write_name, - .operator_loc = operator_loc, - .value = value - }; - - return node; -} - -/** - * Allocate and initialize a new CallTargetNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param receiver The object that the method is being called on\. This can be any [non\-void expression](https://github\.com/ruby/prism/blob/main/docs/parsing\_rules\.md\#non\-void\-expression)\. - * @param call_operator_loc Represents the Location of the call operator\. - * @param name Represents the name of the method being called\. - * @param message_loc Represents the Location of the message\. - * @return The newly allocated and initialized node. - */ -static inline pm_call_target_node_t * -pm_call_target_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_node *receiver, pm_location_t call_operator_loc, pm_constant_id_t name, pm_location_t message_loc) { - pm_call_target_node_t *node = (pm_call_target_node_t *) pm_arena_alloc(arena, sizeof(pm_call_target_node_t), PRISM_ALIGNOF(pm_call_target_node_t)); - - *node = (pm_call_target_node_t) { - .base = { .type = PM_CALL_TARGET_NODE, .flags = flags, .node_id = node_id, .location = location }, - .receiver = receiver, - .call_operator_loc = call_operator_loc, - .name = name, - .message_loc = message_loc - }; - - return node; -} - -/** - * Allocate and initialize a new CapturePatternNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param value Represents the value to capture\. - * @param target Represents the target of the capture\. - * @param operator_loc Represents the Location of the \`=\>\` operator\. - * @return The newly allocated and initialized node. - */ -static inline pm_capture_pattern_node_t * -pm_capture_pattern_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_node *value, struct pm_local_variable_target_node *target, pm_location_t operator_loc) { - pm_capture_pattern_node_t *node = (pm_capture_pattern_node_t *) pm_arena_alloc(arena, sizeof(pm_capture_pattern_node_t), PRISM_ALIGNOF(pm_capture_pattern_node_t)); - - *node = (pm_capture_pattern_node_t) { - .base = { .type = PM_CAPTURE_PATTERN_NODE, .flags = flags, .node_id = node_id, .location = location }, - .value = value, - .target = target, - .operator_loc = operator_loc - }; - - return node; -} - -/** - * Allocate and initialize a new CaseMatchNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param predicate Represents the predicate of the case match\. This can be either \`nil\` or any [non\-void expressions](https://github\.com/ruby/prism/blob/main/docs/parsing\_rules\.md\#non\-void\-expression)\. - * @param conditions Represents the conditions of the case match\. - * @param else_clause Represents the else clause of the case match\. - * @param case_keyword_loc Represents the Location of the \`case\` keyword\. - * @param end_keyword_loc Represents the Location of the \`end\` keyword\. - * @return The newly allocated and initialized node. - */ -static inline pm_case_match_node_t * -pm_case_match_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_node *predicate, pm_node_list_t conditions, struct pm_else_node *else_clause, pm_location_t case_keyword_loc, pm_location_t end_keyword_loc) { - pm_case_match_node_t *node = (pm_case_match_node_t *) pm_arena_alloc(arena, sizeof(pm_case_match_node_t), PRISM_ALIGNOF(pm_case_match_node_t)); - - *node = (pm_case_match_node_t) { - .base = { .type = PM_CASE_MATCH_NODE, .flags = flags, .node_id = node_id, .location = location }, - .predicate = predicate, - .conditions = conditions, - .else_clause = else_clause, - .case_keyword_loc = case_keyword_loc, - .end_keyword_loc = end_keyword_loc - }; - - return node; -} - -/** - * Allocate and initialize a new CaseNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param predicate Represents the predicate of the case statement\. This can be either \`nil\` or any [non\-void expressions](https://github\.com/ruby/prism/blob/main/docs/parsing\_rules\.md\#non\-void\-expression)\. - * @param conditions Represents the conditions of the case statement\. - * @param else_clause Represents the else clause of the case statement\. - * @param case_keyword_loc Represents the Location of the \`case\` keyword\. - * @param end_keyword_loc Represents the Location of the \`end\` keyword\. - * @return The newly allocated and initialized node. - */ -static inline pm_case_node_t * -pm_case_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_node *predicate, pm_node_list_t conditions, struct pm_else_node *else_clause, pm_location_t case_keyword_loc, pm_location_t end_keyword_loc) { - pm_case_node_t *node = (pm_case_node_t *) pm_arena_alloc(arena, sizeof(pm_case_node_t), PRISM_ALIGNOF(pm_case_node_t)); - - *node = (pm_case_node_t) { - .base = { .type = PM_CASE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .predicate = predicate, - .conditions = conditions, - .else_clause = else_clause, - .case_keyword_loc = case_keyword_loc, - .end_keyword_loc = end_keyword_loc - }; - - return node; -} - -/** - * Allocate and initialize a new ClassNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param locals The locals field. - * @param class_keyword_loc Represents the Location of the \`class\` keyword\. - * @param constant_path The constant_path field. - * @param inheritance_operator_loc Represents the Location of the \`\<\` operator\. - * @param superclass Represents the superclass of the class\. - * @param body Represents the body of the class\. - * @param end_keyword_loc Represents the Location of the \`end\` keyword\. - * @param name The name of the class\. - * @return The newly allocated and initialized node. - */ -static inline pm_class_node_t * -pm_class_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_constant_id_list_t locals, pm_location_t class_keyword_loc, struct pm_node *constant_path, pm_location_t inheritance_operator_loc, struct pm_node *superclass, struct pm_node *body, pm_location_t end_keyword_loc, pm_constant_id_t name) { - pm_class_node_t *node = (pm_class_node_t *) pm_arena_alloc(arena, sizeof(pm_class_node_t), PRISM_ALIGNOF(pm_class_node_t)); - - *node = (pm_class_node_t) { - .base = { .type = PM_CLASS_NODE, .flags = flags, .node_id = node_id, .location = location }, - .locals = locals, - .class_keyword_loc = class_keyword_loc, - .constant_path = constant_path, - .inheritance_operator_loc = inheritance_operator_loc, - .superclass = superclass, - .body = body, - .end_keyword_loc = end_keyword_loc, - .name = name - }; - - return node; -} - -/** - * Allocate and initialize a new ClassVariableAndWriteNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param name The name of the class variable, which is a \`@@\` followed by an [identifier](https://github\.com/ruby/prism/blob/main/docs/parsing\_rules\.md\#identifiers)\. - * @param name_loc Represents the Location of the variable name\. - * @param operator_loc Represents the Location of the \`&&=\` operator\. - * @param value Represents the value being assigned\. This can be any [non\-void expression](https://github\.com/ruby/prism/blob/main/docs/parsing\_rules\.md\#non\-void\-expression)\. - * @return The newly allocated and initialized node. - */ -static inline pm_class_variable_and_write_node_t * -pm_class_variable_and_write_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_constant_id_t name, pm_location_t name_loc, pm_location_t operator_loc, struct pm_node *value) { - pm_class_variable_and_write_node_t *node = (pm_class_variable_and_write_node_t *) pm_arena_alloc(arena, sizeof(pm_class_variable_and_write_node_t), PRISM_ALIGNOF(pm_class_variable_and_write_node_t)); - - *node = (pm_class_variable_and_write_node_t) { - .base = { .type = PM_CLASS_VARIABLE_AND_WRITE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .name = name, - .name_loc = name_loc, - .operator_loc = operator_loc, - .value = value - }; - - return node; -} - -/** - * Allocate and initialize a new ClassVariableOperatorWriteNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param name The name field. - * @param name_loc The name_loc field. - * @param binary_operator_loc The binary_operator_loc field. - * @param value The value field. - * @param binary_operator The binary_operator field. - * @return The newly allocated and initialized node. - */ -static inline pm_class_variable_operator_write_node_t * -pm_class_variable_operator_write_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_constant_id_t name, pm_location_t name_loc, pm_location_t binary_operator_loc, struct pm_node *value, pm_constant_id_t binary_operator) { - pm_class_variable_operator_write_node_t *node = (pm_class_variable_operator_write_node_t *) pm_arena_alloc(arena, sizeof(pm_class_variable_operator_write_node_t), PRISM_ALIGNOF(pm_class_variable_operator_write_node_t)); - - *node = (pm_class_variable_operator_write_node_t) { - .base = { .type = PM_CLASS_VARIABLE_OPERATOR_WRITE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .name = name, - .name_loc = name_loc, - .binary_operator_loc = binary_operator_loc, - .value = value, - .binary_operator = binary_operator - }; - - return node; -} - -/** - * Allocate and initialize a new ClassVariableOrWriteNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param name The name field. - * @param name_loc The name_loc field. - * @param operator_loc The operator_loc field. - * @param value The value field. - * @return The newly allocated and initialized node. - */ -static inline pm_class_variable_or_write_node_t * -pm_class_variable_or_write_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_constant_id_t name, pm_location_t name_loc, pm_location_t operator_loc, struct pm_node *value) { - pm_class_variable_or_write_node_t *node = (pm_class_variable_or_write_node_t *) pm_arena_alloc(arena, sizeof(pm_class_variable_or_write_node_t), PRISM_ALIGNOF(pm_class_variable_or_write_node_t)); - - *node = (pm_class_variable_or_write_node_t) { - .base = { .type = PM_CLASS_VARIABLE_OR_WRITE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .name = name, - .name_loc = name_loc, - .operator_loc = operator_loc, - .value = value - }; - - return node; -} - -/** - * Allocate and initialize a new ClassVariableReadNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param name The name of the class variable, which is a \`@@\` followed by an [identifier](https://github\.com/ruby/prism/blob/main/docs/parsing\_rules\.md\#identifiers)\. - * @return The newly allocated and initialized node. - */ -static inline pm_class_variable_read_node_t * -pm_class_variable_read_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_constant_id_t name) { - pm_class_variable_read_node_t *node = (pm_class_variable_read_node_t *) pm_arena_alloc(arena, sizeof(pm_class_variable_read_node_t), PRISM_ALIGNOF(pm_class_variable_read_node_t)); - - *node = (pm_class_variable_read_node_t) { - .base = { .type = PM_CLASS_VARIABLE_READ_NODE, .flags = flags, .node_id = node_id, .location = location }, - .name = name - }; - - return node; -} - -/** - * Allocate and initialize a new ClassVariableTargetNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param name The name field. - * @return The newly allocated and initialized node. - */ -static inline pm_class_variable_target_node_t * -pm_class_variable_target_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_constant_id_t name) { - pm_class_variable_target_node_t *node = (pm_class_variable_target_node_t *) pm_arena_alloc(arena, sizeof(pm_class_variable_target_node_t), PRISM_ALIGNOF(pm_class_variable_target_node_t)); - - *node = (pm_class_variable_target_node_t) { - .base = { .type = PM_CLASS_VARIABLE_TARGET_NODE, .flags = flags, .node_id = node_id, .location = location }, - .name = name - }; - - return node; -} - -/** - * Allocate and initialize a new ClassVariableWriteNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param name The name of the class variable, which is a \`@@\` followed by an [identifier](https://github\.com/ruby/prism/blob/main/docs/parsing\_rules\.md\#identifiers)\. - * @param name_loc The Location of the variable name\. - * @param value The value to write to the class variable\. This can be any [non\-void expression](https://github\.com/ruby/prism/blob/main/docs/parsing\_rules\.md\#non\-void\-expression)\. - * @param operator_loc The Location of the \`=\` operator\. - * @return The newly allocated and initialized node. - */ -static inline pm_class_variable_write_node_t * -pm_class_variable_write_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_constant_id_t name, pm_location_t name_loc, struct pm_node *value, pm_location_t operator_loc) { - pm_class_variable_write_node_t *node = (pm_class_variable_write_node_t *) pm_arena_alloc(arena, sizeof(pm_class_variable_write_node_t), PRISM_ALIGNOF(pm_class_variable_write_node_t)); - - *node = (pm_class_variable_write_node_t) { - .base = { .type = PM_CLASS_VARIABLE_WRITE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .name = name, - .name_loc = name_loc, - .value = value, - .operator_loc = operator_loc - }; - - return node; -} - -/** - * Allocate and initialize a new ConstantAndWriteNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param name The name field. - * @param name_loc The name_loc field. - * @param operator_loc The operator_loc field. - * @param value The value field. - * @return The newly allocated and initialized node. - */ -static inline pm_constant_and_write_node_t * -pm_constant_and_write_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_constant_id_t name, pm_location_t name_loc, pm_location_t operator_loc, struct pm_node *value) { - pm_constant_and_write_node_t *node = (pm_constant_and_write_node_t *) pm_arena_alloc(arena, sizeof(pm_constant_and_write_node_t), PRISM_ALIGNOF(pm_constant_and_write_node_t)); - - *node = (pm_constant_and_write_node_t) { - .base = { .type = PM_CONSTANT_AND_WRITE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .name = name, - .name_loc = name_loc, - .operator_loc = operator_loc, - .value = value - }; - - return node; -} - -/** - * Allocate and initialize a new ConstantOperatorWriteNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param name The name field. - * @param name_loc The name_loc field. - * @param binary_operator_loc The binary_operator_loc field. - * @param value The value field. - * @param binary_operator The binary_operator field. - * @return The newly allocated and initialized node. - */ -static inline pm_constant_operator_write_node_t * -pm_constant_operator_write_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_constant_id_t name, pm_location_t name_loc, pm_location_t binary_operator_loc, struct pm_node *value, pm_constant_id_t binary_operator) { - pm_constant_operator_write_node_t *node = (pm_constant_operator_write_node_t *) pm_arena_alloc(arena, sizeof(pm_constant_operator_write_node_t), PRISM_ALIGNOF(pm_constant_operator_write_node_t)); - - *node = (pm_constant_operator_write_node_t) { - .base = { .type = PM_CONSTANT_OPERATOR_WRITE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .name = name, - .name_loc = name_loc, - .binary_operator_loc = binary_operator_loc, - .value = value, - .binary_operator = binary_operator - }; - - return node; -} - -/** - * Allocate and initialize a new ConstantOrWriteNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param name The name field. - * @param name_loc The name_loc field. - * @param operator_loc The operator_loc field. - * @param value The value field. - * @return The newly allocated and initialized node. - */ -static inline pm_constant_or_write_node_t * -pm_constant_or_write_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_constant_id_t name, pm_location_t name_loc, pm_location_t operator_loc, struct pm_node *value) { - pm_constant_or_write_node_t *node = (pm_constant_or_write_node_t *) pm_arena_alloc(arena, sizeof(pm_constant_or_write_node_t), PRISM_ALIGNOF(pm_constant_or_write_node_t)); - - *node = (pm_constant_or_write_node_t) { - .base = { .type = PM_CONSTANT_OR_WRITE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .name = name, - .name_loc = name_loc, - .operator_loc = operator_loc, - .value = value - }; - - return node; -} - -/** - * Allocate and initialize a new ConstantPathAndWriteNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param target The target field. - * @param operator_loc The operator_loc field. - * @param value The value field. - * @return The newly allocated and initialized node. - */ -static inline pm_constant_path_and_write_node_t * -pm_constant_path_and_write_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_constant_path_node *target, pm_location_t operator_loc, struct pm_node *value) { - pm_constant_path_and_write_node_t *node = (pm_constant_path_and_write_node_t *) pm_arena_alloc(arena, sizeof(pm_constant_path_and_write_node_t), PRISM_ALIGNOF(pm_constant_path_and_write_node_t)); - - *node = (pm_constant_path_and_write_node_t) { - .base = { .type = PM_CONSTANT_PATH_AND_WRITE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .target = target, - .operator_loc = operator_loc, - .value = value - }; - - return node; -} - -/** - * Allocate and initialize a new ConstantPathNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param parent The left\-hand node of the path, if present\. It can be \`nil\` or any [non\-void expression](https://github\.com/ruby/prism/blob/main/docs/parsing\_rules\.md\#non\-void\-expression)\. It will be \`nil\` when the constant lookup is at the root of the module tree\. - * @param name The name of the constant being accessed\. This could be \`nil\` in the event of a syntax error\. - * @param delimiter_loc The Location of the \`::\` delimiter\. - * @param name_loc The Location of the name of the constant\. - * @return The newly allocated and initialized node. - */ -static inline pm_constant_path_node_t * -pm_constant_path_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_node *parent, pm_constant_id_t name, pm_location_t delimiter_loc, pm_location_t name_loc) { - pm_constant_path_node_t *node = (pm_constant_path_node_t *) pm_arena_alloc(arena, sizeof(pm_constant_path_node_t), PRISM_ALIGNOF(pm_constant_path_node_t)); - - *node = (pm_constant_path_node_t) { - .base = { .type = PM_CONSTANT_PATH_NODE, .flags = flags, .node_id = node_id, .location = location }, - .parent = parent, - .name = name, - .delimiter_loc = delimiter_loc, - .name_loc = name_loc - }; - - return node; -} - -/** - * Allocate and initialize a new ConstantPathOperatorWriteNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param target The target field. - * @param binary_operator_loc The binary_operator_loc field. - * @param value The value field. - * @param binary_operator The binary_operator field. - * @return The newly allocated and initialized node. - */ -static inline pm_constant_path_operator_write_node_t * -pm_constant_path_operator_write_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_constant_path_node *target, pm_location_t binary_operator_loc, struct pm_node *value, pm_constant_id_t binary_operator) { - pm_constant_path_operator_write_node_t *node = (pm_constant_path_operator_write_node_t *) pm_arena_alloc(arena, sizeof(pm_constant_path_operator_write_node_t), PRISM_ALIGNOF(pm_constant_path_operator_write_node_t)); - - *node = (pm_constant_path_operator_write_node_t) { - .base = { .type = PM_CONSTANT_PATH_OPERATOR_WRITE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .target = target, - .binary_operator_loc = binary_operator_loc, - .value = value, - .binary_operator = binary_operator - }; - - return node; -} - -/** - * Allocate and initialize a new ConstantPathOrWriteNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param target The target field. - * @param operator_loc The operator_loc field. - * @param value The value field. - * @return The newly allocated and initialized node. - */ -static inline pm_constant_path_or_write_node_t * -pm_constant_path_or_write_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_constant_path_node *target, pm_location_t operator_loc, struct pm_node *value) { - pm_constant_path_or_write_node_t *node = (pm_constant_path_or_write_node_t *) pm_arena_alloc(arena, sizeof(pm_constant_path_or_write_node_t), PRISM_ALIGNOF(pm_constant_path_or_write_node_t)); - - *node = (pm_constant_path_or_write_node_t) { - .base = { .type = PM_CONSTANT_PATH_OR_WRITE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .target = target, - .operator_loc = operator_loc, - .value = value - }; - - return node; -} - -/** - * Allocate and initialize a new ConstantPathTargetNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param parent The parent field. - * @param name The name field. - * @param delimiter_loc The delimiter_loc field. - * @param name_loc The name_loc field. - * @return The newly allocated and initialized node. - */ -static inline pm_constant_path_target_node_t * -pm_constant_path_target_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_node *parent, pm_constant_id_t name, pm_location_t delimiter_loc, pm_location_t name_loc) { - pm_constant_path_target_node_t *node = (pm_constant_path_target_node_t *) pm_arena_alloc(arena, sizeof(pm_constant_path_target_node_t), PRISM_ALIGNOF(pm_constant_path_target_node_t)); - - *node = (pm_constant_path_target_node_t) { - .base = { .type = PM_CONSTANT_PATH_TARGET_NODE, .flags = flags, .node_id = node_id, .location = location }, - .parent = parent, - .name = name, - .delimiter_loc = delimiter_loc, - .name_loc = name_loc - }; - - return node; -} - -/** - * Allocate and initialize a new ConstantPathWriteNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param target A node representing the constant path being written to\. - * @param operator_loc The Location of the \`=\` operator\. - * @param value The value to write to the constant path\. It can be any [non\-void expression](https://github\.com/ruby/prism/blob/main/docs/parsing\_rules\.md\#non\-void\-expression)\. - * @return The newly allocated and initialized node. - */ -static inline pm_constant_path_write_node_t * -pm_constant_path_write_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_constant_path_node *target, pm_location_t operator_loc, struct pm_node *value) { - pm_constant_path_write_node_t *node = (pm_constant_path_write_node_t *) pm_arena_alloc(arena, sizeof(pm_constant_path_write_node_t), PRISM_ALIGNOF(pm_constant_path_write_node_t)); - - *node = (pm_constant_path_write_node_t) { - .base = { .type = PM_CONSTANT_PATH_WRITE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .target = target, - .operator_loc = operator_loc, - .value = value - }; - - return node; -} - -/** - * Allocate and initialize a new ConstantReadNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param name The name of the [constant](https://github\.com/ruby/prism/blob/main/docs/parsing\_rules\.md\#constants)\. - * @return The newly allocated and initialized node. - */ -static inline pm_constant_read_node_t * -pm_constant_read_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_constant_id_t name) { - pm_constant_read_node_t *node = (pm_constant_read_node_t *) pm_arena_alloc(arena, sizeof(pm_constant_read_node_t), PRISM_ALIGNOF(pm_constant_read_node_t)); - - *node = (pm_constant_read_node_t) { - .base = { .type = PM_CONSTANT_READ_NODE, .flags = flags, .node_id = node_id, .location = location }, - .name = name - }; - - return node; -} - -/** - * Allocate and initialize a new ConstantTargetNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param name The name field. - * @return The newly allocated and initialized node. - */ -static inline pm_constant_target_node_t * -pm_constant_target_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_constant_id_t name) { - pm_constant_target_node_t *node = (pm_constant_target_node_t *) pm_arena_alloc(arena, sizeof(pm_constant_target_node_t), PRISM_ALIGNOF(pm_constant_target_node_t)); - - *node = (pm_constant_target_node_t) { - .base = { .type = PM_CONSTANT_TARGET_NODE, .flags = flags, .node_id = node_id, .location = location }, - .name = name - }; - - return node; -} - -/** - * Allocate and initialize a new ConstantWriteNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param name The name of the [constant](https://github\.com/ruby/prism/blob/main/docs/parsing\_rules\.md\#constants)\. - * @param name_loc The Location of the constant name\. - * @param value The value to write to the constant\. It can be any [non\-void expression](https://github\.com/ruby/prism/blob/main/docs/parsing\_rules\.md\#non\-void\-expression)\. - * @param operator_loc The Location of the \`=\` operator\. - * @return The newly allocated and initialized node. - */ -static inline pm_constant_write_node_t * -pm_constant_write_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_constant_id_t name, pm_location_t name_loc, struct pm_node *value, pm_location_t operator_loc) { - pm_constant_write_node_t *node = (pm_constant_write_node_t *) pm_arena_alloc(arena, sizeof(pm_constant_write_node_t), PRISM_ALIGNOF(pm_constant_write_node_t)); - - *node = (pm_constant_write_node_t) { - .base = { .type = PM_CONSTANT_WRITE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .name = name, - .name_loc = name_loc, - .value = value, - .operator_loc = operator_loc - }; - - return node; -} - -/** - * Allocate and initialize a new DefNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param name The name field. - * @param name_loc The name_loc field. - * @param receiver The receiver field. - * @param parameters The parameters field. - * @param body The body field. - * @param locals The locals field. - * @param def_keyword_loc The def_keyword_loc field. - * @param operator_loc The operator_loc field. - * @param lparen_loc The lparen_loc field. - * @param rparen_loc The rparen_loc field. - * @param equal_loc The equal_loc field. - * @param end_keyword_loc The end_keyword_loc field. - * @return The newly allocated and initialized node. - */ -static inline pm_def_node_t * -pm_def_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_constant_id_t name, pm_location_t name_loc, struct pm_node *receiver, struct pm_parameters_node *parameters, struct pm_node *body, pm_constant_id_list_t locals, pm_location_t def_keyword_loc, pm_location_t operator_loc, pm_location_t lparen_loc, pm_location_t rparen_loc, pm_location_t equal_loc, pm_location_t end_keyword_loc) { - pm_def_node_t *node = (pm_def_node_t *) pm_arena_alloc(arena, sizeof(pm_def_node_t), PRISM_ALIGNOF(pm_def_node_t)); - - *node = (pm_def_node_t) { - .base = { .type = PM_DEF_NODE, .flags = flags, .node_id = node_id, .location = location }, - .name = name, - .name_loc = name_loc, - .receiver = receiver, - .parameters = parameters, - .body = body, - .locals = locals, - .def_keyword_loc = def_keyword_loc, - .operator_loc = operator_loc, - .lparen_loc = lparen_loc, - .rparen_loc = rparen_loc, - .equal_loc = equal_loc, - .end_keyword_loc = end_keyword_loc - }; - - return node; -} - -/** - * Allocate and initialize a new DefinedNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param lparen_loc The lparen_loc field. - * @param value The value field. - * @param rparen_loc The rparen_loc field. - * @param keyword_loc The keyword_loc field. - * @return The newly allocated and initialized node. - */ -static inline pm_defined_node_t * -pm_defined_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_location_t lparen_loc, struct pm_node *value, pm_location_t rparen_loc, pm_location_t keyword_loc) { - pm_defined_node_t *node = (pm_defined_node_t *) pm_arena_alloc(arena, sizeof(pm_defined_node_t), PRISM_ALIGNOF(pm_defined_node_t)); - - *node = (pm_defined_node_t) { - .base = { .type = PM_DEFINED_NODE, .flags = flags, .node_id = node_id, .location = location }, - .lparen_loc = lparen_loc, - .value = value, - .rparen_loc = rparen_loc, - .keyword_loc = keyword_loc - }; - - return node; -} - -/** - * Allocate and initialize a new ElseNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param else_keyword_loc The else_keyword_loc field. - * @param statements The statements field. - * @param end_keyword_loc The end_keyword_loc field. - * @return The newly allocated and initialized node. - */ -static inline pm_else_node_t * -pm_else_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_location_t else_keyword_loc, struct pm_statements_node *statements, pm_location_t end_keyword_loc) { - pm_else_node_t *node = (pm_else_node_t *) pm_arena_alloc(arena, sizeof(pm_else_node_t), PRISM_ALIGNOF(pm_else_node_t)); - - *node = (pm_else_node_t) { - .base = { .type = PM_ELSE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .else_keyword_loc = else_keyword_loc, - .statements = statements, - .end_keyword_loc = end_keyword_loc - }; - - return node; -} - -/** - * Allocate and initialize a new EmbeddedStatementsNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param opening_loc The opening_loc field. - * @param statements The statements field. - * @param closing_loc The closing_loc field. - * @return The newly allocated and initialized node. - */ -static inline pm_embedded_statements_node_t * -pm_embedded_statements_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_location_t opening_loc, struct pm_statements_node *statements, pm_location_t closing_loc) { - pm_embedded_statements_node_t *node = (pm_embedded_statements_node_t *) pm_arena_alloc(arena, sizeof(pm_embedded_statements_node_t), PRISM_ALIGNOF(pm_embedded_statements_node_t)); - - *node = (pm_embedded_statements_node_t) { - .base = { .type = PM_EMBEDDED_STATEMENTS_NODE, .flags = flags, .node_id = node_id, .location = location }, - .opening_loc = opening_loc, - .statements = statements, - .closing_loc = closing_loc - }; - - return node; -} - -/** - * Allocate and initialize a new EmbeddedVariableNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param operator_loc The operator_loc field. - * @param variable The variable field. - * @return The newly allocated and initialized node. - */ -static inline pm_embedded_variable_node_t * -pm_embedded_variable_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_location_t operator_loc, struct pm_node *variable) { - pm_embedded_variable_node_t *node = (pm_embedded_variable_node_t *) pm_arena_alloc(arena, sizeof(pm_embedded_variable_node_t), PRISM_ALIGNOF(pm_embedded_variable_node_t)); - - *node = (pm_embedded_variable_node_t) { - .base = { .type = PM_EMBEDDED_VARIABLE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .operator_loc = operator_loc, - .variable = variable - }; - - return node; -} - -/** - * Allocate and initialize a new EnsureNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param ensure_keyword_loc The ensure_keyword_loc field. - * @param statements The statements field. - * @param end_keyword_loc The end_keyword_loc field. - * @return The newly allocated and initialized node. - */ -static inline pm_ensure_node_t * -pm_ensure_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_location_t ensure_keyword_loc, struct pm_statements_node *statements, pm_location_t end_keyword_loc) { - pm_ensure_node_t *node = (pm_ensure_node_t *) pm_arena_alloc(arena, sizeof(pm_ensure_node_t), PRISM_ALIGNOF(pm_ensure_node_t)); - - *node = (pm_ensure_node_t) { - .base = { .type = PM_ENSURE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .ensure_keyword_loc = ensure_keyword_loc, - .statements = statements, - .end_keyword_loc = end_keyword_loc - }; - - return node; -} - -/** - * Allocate and initialize a new FalseNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @return The newly allocated and initialized node. - */ -static inline pm_false_node_t * -pm_false_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location) { - pm_false_node_t *node = (pm_false_node_t *) pm_arena_alloc(arena, sizeof(pm_false_node_t), PRISM_ALIGNOF(pm_false_node_t)); - - *node = (pm_false_node_t) { - .base = { .type = PM_FALSE_NODE, .flags = flags, .node_id = node_id, .location = location } - }; - - return node; -} - -/** - * Allocate and initialize a new FindPatternNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param constant Represents the optional constant preceding the pattern - * @param left Represents the first wildcard node in the pattern\. - * @param requireds Represents the nodes in between the wildcards\. - * @param right Represents the second wildcard node in the pattern\. - * @param opening_loc The Location of the opening brace\. - * @param closing_loc The Location of the closing brace\. - * @return The newly allocated and initialized node. - */ -static inline pm_find_pattern_node_t * -pm_find_pattern_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_node *constant, struct pm_splat_node *left, pm_node_list_t requireds, struct pm_node *right, pm_location_t opening_loc, pm_location_t closing_loc) { - pm_find_pattern_node_t *node = (pm_find_pattern_node_t *) pm_arena_alloc(arena, sizeof(pm_find_pattern_node_t), PRISM_ALIGNOF(pm_find_pattern_node_t)); - - *node = (pm_find_pattern_node_t) { - .base = { .type = PM_FIND_PATTERN_NODE, .flags = flags, .node_id = node_id, .location = location }, - .constant = constant, - .left = left, - .requireds = requireds, - .right = right, - .opening_loc = opening_loc, - .closing_loc = closing_loc - }; - - return node; -} - -/** - * Allocate and initialize a new FlipFlopNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param left The left field. - * @param right The right field. - * @param operator_loc The operator_loc field. - * @return The newly allocated and initialized node. - */ -static inline pm_flip_flop_node_t * -pm_flip_flop_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_node *left, struct pm_node *right, pm_location_t operator_loc) { - pm_flip_flop_node_t *node = (pm_flip_flop_node_t *) pm_arena_alloc(arena, sizeof(pm_flip_flop_node_t), PRISM_ALIGNOF(pm_flip_flop_node_t)); - - *node = (pm_flip_flop_node_t) { - .base = { .type = PM_FLIP_FLOP_NODE, .flags = flags, .node_id = node_id, .location = location }, - .left = left, - .right = right, - .operator_loc = operator_loc - }; - - return node; -} - -/** - * Allocate and initialize a new FloatNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param value The value of the floating point number as a Float\. - * @return The newly allocated and initialized node. - */ -static inline pm_float_node_t * -pm_float_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, double value) { - pm_float_node_t *node = (pm_float_node_t *) pm_arena_alloc(arena, sizeof(pm_float_node_t), PRISM_ALIGNOF(pm_float_node_t)); - - *node = (pm_float_node_t) { - .base = { .type = PM_FLOAT_NODE, .flags = flags, .node_id = node_id, .location = location }, - .value = value - }; - - return node; -} - -/** - * Allocate and initialize a new ForNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param index The index expression for \`for\` loops\. - * @param collection The collection to iterate over\. - * @param statements Represents the body of statements to execute for each iteration of the loop\. - * @param for_keyword_loc The Location of the \`for\` keyword\. - * @param in_keyword_loc The Location of the \`in\` keyword\. - * @param do_keyword_loc The Location of the \`do\` keyword, if present\. - * @param end_keyword_loc The Location of the \`end\` keyword\. - * @return The newly allocated and initialized node. - */ -static inline pm_for_node_t * -pm_for_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_node *index, struct pm_node *collection, struct pm_statements_node *statements, pm_location_t for_keyword_loc, pm_location_t in_keyword_loc, pm_location_t do_keyword_loc, pm_location_t end_keyword_loc) { - pm_for_node_t *node = (pm_for_node_t *) pm_arena_alloc(arena, sizeof(pm_for_node_t), PRISM_ALIGNOF(pm_for_node_t)); - - *node = (pm_for_node_t) { - .base = { .type = PM_FOR_NODE, .flags = flags, .node_id = node_id, .location = location }, - .index = index, - .collection = collection, - .statements = statements, - .for_keyword_loc = for_keyword_loc, - .in_keyword_loc = in_keyword_loc, - .do_keyword_loc = do_keyword_loc, - .end_keyword_loc = end_keyword_loc - }; - - return node; -} - -/** - * Allocate and initialize a new ForwardingArgumentsNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @return The newly allocated and initialized node. - */ -static inline pm_forwarding_arguments_node_t * -pm_forwarding_arguments_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location) { - pm_forwarding_arguments_node_t *node = (pm_forwarding_arguments_node_t *) pm_arena_alloc(arena, sizeof(pm_forwarding_arguments_node_t), PRISM_ALIGNOF(pm_forwarding_arguments_node_t)); - - *node = (pm_forwarding_arguments_node_t) { - .base = { .type = PM_FORWARDING_ARGUMENTS_NODE, .flags = flags, .node_id = node_id, .location = location } - }; - - return node; -} - -/** - * Allocate and initialize a new ForwardingParameterNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @return The newly allocated and initialized node. - */ -static inline pm_forwarding_parameter_node_t * -pm_forwarding_parameter_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location) { - pm_forwarding_parameter_node_t *node = (pm_forwarding_parameter_node_t *) pm_arena_alloc(arena, sizeof(pm_forwarding_parameter_node_t), PRISM_ALIGNOF(pm_forwarding_parameter_node_t)); - - *node = (pm_forwarding_parameter_node_t) { - .base = { .type = PM_FORWARDING_PARAMETER_NODE, .flags = flags, .node_id = node_id, .location = location } - }; - - return node; -} - -/** - * Allocate and initialize a new ForwardingSuperNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param block All other arguments are forwarded as normal, except the original block is replaced with the new block\. - * @return The newly allocated and initialized node. - */ -static inline pm_forwarding_super_node_t * -pm_forwarding_super_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_block_node *block) { - pm_forwarding_super_node_t *node = (pm_forwarding_super_node_t *) pm_arena_alloc(arena, sizeof(pm_forwarding_super_node_t), PRISM_ALIGNOF(pm_forwarding_super_node_t)); - - *node = (pm_forwarding_super_node_t) { - .base = { .type = PM_FORWARDING_SUPER_NODE, .flags = flags, .node_id = node_id, .location = location }, - .block = block - }; - - return node; -} - -/** - * Allocate and initialize a new GlobalVariableAndWriteNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param name The name field. - * @param name_loc The name_loc field. - * @param operator_loc The operator_loc field. - * @param value The value field. - * @return The newly allocated and initialized node. - */ -static inline pm_global_variable_and_write_node_t * -pm_global_variable_and_write_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_constant_id_t name, pm_location_t name_loc, pm_location_t operator_loc, struct pm_node *value) { - pm_global_variable_and_write_node_t *node = (pm_global_variable_and_write_node_t *) pm_arena_alloc(arena, sizeof(pm_global_variable_and_write_node_t), PRISM_ALIGNOF(pm_global_variable_and_write_node_t)); - - *node = (pm_global_variable_and_write_node_t) { - .base = { .type = PM_GLOBAL_VARIABLE_AND_WRITE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .name = name, - .name_loc = name_loc, - .operator_loc = operator_loc, - .value = value - }; - - return node; -} - -/** - * Allocate and initialize a new GlobalVariableOperatorWriteNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param name The name field. - * @param name_loc The name_loc field. - * @param binary_operator_loc The binary_operator_loc field. - * @param value The value field. - * @param binary_operator The binary_operator field. - * @return The newly allocated and initialized node. - */ -static inline pm_global_variable_operator_write_node_t * -pm_global_variable_operator_write_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_constant_id_t name, pm_location_t name_loc, pm_location_t binary_operator_loc, struct pm_node *value, pm_constant_id_t binary_operator) { - pm_global_variable_operator_write_node_t *node = (pm_global_variable_operator_write_node_t *) pm_arena_alloc(arena, sizeof(pm_global_variable_operator_write_node_t), PRISM_ALIGNOF(pm_global_variable_operator_write_node_t)); - - *node = (pm_global_variable_operator_write_node_t) { - .base = { .type = PM_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .name = name, - .name_loc = name_loc, - .binary_operator_loc = binary_operator_loc, - .value = value, - .binary_operator = binary_operator - }; - - return node; -} - -/** - * Allocate and initialize a new GlobalVariableOrWriteNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param name The name field. - * @param name_loc The name_loc field. - * @param operator_loc The operator_loc field. - * @param value The value field. - * @return The newly allocated and initialized node. - */ -static inline pm_global_variable_or_write_node_t * -pm_global_variable_or_write_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_constant_id_t name, pm_location_t name_loc, pm_location_t operator_loc, struct pm_node *value) { - pm_global_variable_or_write_node_t *node = (pm_global_variable_or_write_node_t *) pm_arena_alloc(arena, sizeof(pm_global_variable_or_write_node_t), PRISM_ALIGNOF(pm_global_variable_or_write_node_t)); - - *node = (pm_global_variable_or_write_node_t) { - .base = { .type = PM_GLOBAL_VARIABLE_OR_WRITE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .name = name, - .name_loc = name_loc, - .operator_loc = operator_loc, - .value = value - }; - - return node; -} - -/** - * Allocate and initialize a new GlobalVariableReadNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param name The name of the global variable, which is a \`$\` followed by an [identifier](https://github\.com/ruby/prism/blob/main/docs/parsing\_rules\.md\#identifier)\. Alternatively, it can be one of the special global variables designated by a symbol\. - * @return The newly allocated and initialized node. - */ -static inline pm_global_variable_read_node_t * -pm_global_variable_read_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_constant_id_t name) { - pm_global_variable_read_node_t *node = (pm_global_variable_read_node_t *) pm_arena_alloc(arena, sizeof(pm_global_variable_read_node_t), PRISM_ALIGNOF(pm_global_variable_read_node_t)); - - *node = (pm_global_variable_read_node_t) { - .base = { .type = PM_GLOBAL_VARIABLE_READ_NODE, .flags = flags, .node_id = node_id, .location = location }, - .name = name - }; - - return node; -} - -/** - * Allocate and initialize a new GlobalVariableTargetNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param name The name field. - * @return The newly allocated and initialized node. - */ -static inline pm_global_variable_target_node_t * -pm_global_variable_target_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_constant_id_t name) { - pm_global_variable_target_node_t *node = (pm_global_variable_target_node_t *) pm_arena_alloc(arena, sizeof(pm_global_variable_target_node_t), PRISM_ALIGNOF(pm_global_variable_target_node_t)); - - *node = (pm_global_variable_target_node_t) { - .base = { .type = PM_GLOBAL_VARIABLE_TARGET_NODE, .flags = flags, .node_id = node_id, .location = location }, - .name = name - }; - - return node; -} - -/** - * Allocate and initialize a new GlobalVariableWriteNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param name The name of the global variable, which is a \`$\` followed by an [identifier](https://github\.com/ruby/prism/blob/main/docs/parsing\_rules\.md\#identifier)\. Alternatively, it can be one of the special global variables designated by a symbol\. - * @param name_loc The Location of the global variable's name\. - * @param value The value to write to the global variable\. It can be any [non\-void expression](https://github\.com/ruby/prism/blob/main/docs/parsing\_rules\.md\#non\-void\-expression)\. - * @param operator_loc The Location of the \`=\` operator\. - * @return The newly allocated and initialized node. - */ -static inline pm_global_variable_write_node_t * -pm_global_variable_write_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_constant_id_t name, pm_location_t name_loc, struct pm_node *value, pm_location_t operator_loc) { - pm_global_variable_write_node_t *node = (pm_global_variable_write_node_t *) pm_arena_alloc(arena, sizeof(pm_global_variable_write_node_t), PRISM_ALIGNOF(pm_global_variable_write_node_t)); - - *node = (pm_global_variable_write_node_t) { - .base = { .type = PM_GLOBAL_VARIABLE_WRITE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .name = name, - .name_loc = name_loc, - .value = value, - .operator_loc = operator_loc - }; - - return node; -} - -/** - * Allocate and initialize a new HashNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param opening_loc The Location of the opening brace\. - * @param elements The elements of the hash\. These can be either \`AssocNode\`s or \`AssocSplatNode\`s\. - * @param closing_loc The Location of the closing brace\. - * @return The newly allocated and initialized node. - */ -static inline pm_hash_node_t * -pm_hash_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_location_t opening_loc, pm_node_list_t elements, pm_location_t closing_loc) { - pm_hash_node_t *node = (pm_hash_node_t *) pm_arena_alloc(arena, sizeof(pm_hash_node_t), PRISM_ALIGNOF(pm_hash_node_t)); - - *node = (pm_hash_node_t) { - .base = { .type = PM_HASH_NODE, .flags = flags, .node_id = node_id, .location = location }, - .opening_loc = opening_loc, - .elements = elements, - .closing_loc = closing_loc - }; - - return node; -} - -/** - * Allocate and initialize a new HashPatternNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param constant Represents the optional constant preceding the Hash\. - * @param elements Represents the explicit named hash keys and values\. - * @param rest Represents the rest of the Hash keys and values\. This can be named, unnamed, or explicitly forbidden via \`\*\*nil\`, this last one results in a \`NoKeywordsParameterNode\`\. - * @param opening_loc The Location of the opening brace\. - * @param closing_loc The Location of the closing brace\. - * @return The newly allocated and initialized node. - */ -static inline pm_hash_pattern_node_t * -pm_hash_pattern_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_node *constant, pm_node_list_t elements, struct pm_node *rest, pm_location_t opening_loc, pm_location_t closing_loc) { - pm_hash_pattern_node_t *node = (pm_hash_pattern_node_t *) pm_arena_alloc(arena, sizeof(pm_hash_pattern_node_t), PRISM_ALIGNOF(pm_hash_pattern_node_t)); - - *node = (pm_hash_pattern_node_t) { - .base = { .type = PM_HASH_PATTERN_NODE, .flags = flags, .node_id = node_id, .location = location }, - .constant = constant, - .elements = elements, - .rest = rest, - .opening_loc = opening_loc, - .closing_loc = closing_loc - }; - - return node; -} - -/** - * Allocate and initialize a new IfNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param if_keyword_loc The Location of the \`if\` keyword if present\. - * @param predicate The node for the condition the \`IfNode\` is testing\. - * @param then_keyword_loc The Location of the \`then\` keyword (if present) or the \`?\` in a ternary expression, \`nil\` otherwise\. - * @param statements Represents the body of statements that will be executed when the predicate is evaluated as truthy\. Will be \`nil\` when no body is provided\. - * @param subsequent Represents an \`ElseNode\` or an \`IfNode\` when there is an \`else\` or an \`elsif\` in the \`if\` statement\. - * @param end_keyword_loc The Location of the \`end\` keyword if present, \`nil\` otherwise\. - * @return The newly allocated and initialized node. - */ -static inline pm_if_node_t * -pm_if_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_location_t if_keyword_loc, struct pm_node *predicate, pm_location_t then_keyword_loc, struct pm_statements_node *statements, struct pm_node *subsequent, pm_location_t end_keyword_loc) { - pm_if_node_t *node = (pm_if_node_t *) pm_arena_alloc(arena, sizeof(pm_if_node_t), PRISM_ALIGNOF(pm_if_node_t)); - - *node = (pm_if_node_t) { - .base = { .type = PM_IF_NODE, .flags = flags, .node_id = node_id, .location = location }, - .if_keyword_loc = if_keyword_loc, - .predicate = predicate, - .then_keyword_loc = then_keyword_loc, - .statements = statements, - .subsequent = subsequent, - .end_keyword_loc = end_keyword_loc - }; - - return node; -} - -/** - * Allocate and initialize a new ImaginaryNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param numeric The numeric field. - * @return The newly allocated and initialized node. - */ -static inline pm_imaginary_node_t * -pm_imaginary_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_node *numeric) { - pm_imaginary_node_t *node = (pm_imaginary_node_t *) pm_arena_alloc(arena, sizeof(pm_imaginary_node_t), PRISM_ALIGNOF(pm_imaginary_node_t)); - - *node = (pm_imaginary_node_t) { - .base = { .type = PM_IMAGINARY_NODE, .flags = flags, .node_id = node_id, .location = location }, - .numeric = numeric - }; - - return node; -} - -/** - * Allocate and initialize a new ImplicitNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param value The value field. - * @return The newly allocated and initialized node. - */ -static inline pm_implicit_node_t * -pm_implicit_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_node *value) { - pm_implicit_node_t *node = (pm_implicit_node_t *) pm_arena_alloc(arena, sizeof(pm_implicit_node_t), PRISM_ALIGNOF(pm_implicit_node_t)); - - *node = (pm_implicit_node_t) { - .base = { .type = PM_IMPLICIT_NODE, .flags = flags, .node_id = node_id, .location = location }, - .value = value - }; - - return node; -} - -/** - * Allocate and initialize a new ImplicitRestNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @return The newly allocated and initialized node. - */ -static inline pm_implicit_rest_node_t * -pm_implicit_rest_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location) { - pm_implicit_rest_node_t *node = (pm_implicit_rest_node_t *) pm_arena_alloc(arena, sizeof(pm_implicit_rest_node_t), PRISM_ALIGNOF(pm_implicit_rest_node_t)); - - *node = (pm_implicit_rest_node_t) { - .base = { .type = PM_IMPLICIT_REST_NODE, .flags = flags, .node_id = node_id, .location = location } - }; - - return node; -} - -/** - * Allocate and initialize a new InNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param pattern The pattern field. - * @param statements The statements field. - * @param in_loc The in_loc field. - * @param then_loc The then_loc field. - * @return The newly allocated and initialized node. - */ -static inline pm_in_node_t * -pm_in_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_node *pattern, struct pm_statements_node *statements, pm_location_t in_loc, pm_location_t then_loc) { - pm_in_node_t *node = (pm_in_node_t *) pm_arena_alloc(arena, sizeof(pm_in_node_t), PRISM_ALIGNOF(pm_in_node_t)); - - *node = (pm_in_node_t) { - .base = { .type = PM_IN_NODE, .flags = flags, .node_id = node_id, .location = location }, - .pattern = pattern, - .statements = statements, - .in_loc = in_loc, - .then_loc = then_loc - }; - - return node; -} - -/** - * Allocate and initialize a new IndexAndWriteNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param receiver The receiver field. - * @param call_operator_loc The call_operator_loc field. - * @param opening_loc The opening_loc field. - * @param arguments The arguments field. - * @param closing_loc The closing_loc field. - * @param block The block field. - * @param operator_loc The operator_loc field. - * @param value The value field. - * @return The newly allocated and initialized node. - */ -static inline pm_index_and_write_node_t * -pm_index_and_write_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_node *receiver, pm_location_t call_operator_loc, pm_location_t opening_loc, struct pm_arguments_node *arguments, pm_location_t closing_loc, struct pm_block_argument_node *block, pm_location_t operator_loc, struct pm_node *value) { - pm_index_and_write_node_t *node = (pm_index_and_write_node_t *) pm_arena_alloc(arena, sizeof(pm_index_and_write_node_t), PRISM_ALIGNOF(pm_index_and_write_node_t)); - - *node = (pm_index_and_write_node_t) { - .base = { .type = PM_INDEX_AND_WRITE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .receiver = receiver, - .call_operator_loc = call_operator_loc, - .opening_loc = opening_loc, - .arguments = arguments, - .closing_loc = closing_loc, - .block = block, - .operator_loc = operator_loc, - .value = value - }; - - return node; -} - -/** - * Allocate and initialize a new IndexOperatorWriteNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param receiver The receiver field. - * @param call_operator_loc The call_operator_loc field. - * @param opening_loc The opening_loc field. - * @param arguments The arguments field. - * @param closing_loc The closing_loc field. - * @param block The block field. - * @param binary_operator The binary_operator field. - * @param binary_operator_loc The binary_operator_loc field. - * @param value The value field. - * @return The newly allocated and initialized node. - */ -static inline pm_index_operator_write_node_t * -pm_index_operator_write_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_node *receiver, pm_location_t call_operator_loc, pm_location_t opening_loc, struct pm_arguments_node *arguments, pm_location_t closing_loc, struct pm_block_argument_node *block, pm_constant_id_t binary_operator, pm_location_t binary_operator_loc, struct pm_node *value) { - pm_index_operator_write_node_t *node = (pm_index_operator_write_node_t *) pm_arena_alloc(arena, sizeof(pm_index_operator_write_node_t), PRISM_ALIGNOF(pm_index_operator_write_node_t)); - - *node = (pm_index_operator_write_node_t) { - .base = { .type = PM_INDEX_OPERATOR_WRITE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .receiver = receiver, - .call_operator_loc = call_operator_loc, - .opening_loc = opening_loc, - .arguments = arguments, - .closing_loc = closing_loc, - .block = block, - .binary_operator = binary_operator, - .binary_operator_loc = binary_operator_loc, - .value = value - }; - - return node; -} - -/** - * Allocate and initialize a new IndexOrWriteNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param receiver The receiver field. - * @param call_operator_loc The call_operator_loc field. - * @param opening_loc The opening_loc field. - * @param arguments The arguments field. - * @param closing_loc The closing_loc field. - * @param block The block field. - * @param operator_loc The operator_loc field. - * @param value The value field. - * @return The newly allocated and initialized node. - */ -static inline pm_index_or_write_node_t * -pm_index_or_write_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_node *receiver, pm_location_t call_operator_loc, pm_location_t opening_loc, struct pm_arguments_node *arguments, pm_location_t closing_loc, struct pm_block_argument_node *block, pm_location_t operator_loc, struct pm_node *value) { - pm_index_or_write_node_t *node = (pm_index_or_write_node_t *) pm_arena_alloc(arena, sizeof(pm_index_or_write_node_t), PRISM_ALIGNOF(pm_index_or_write_node_t)); - - *node = (pm_index_or_write_node_t) { - .base = { .type = PM_INDEX_OR_WRITE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .receiver = receiver, - .call_operator_loc = call_operator_loc, - .opening_loc = opening_loc, - .arguments = arguments, - .closing_loc = closing_loc, - .block = block, - .operator_loc = operator_loc, - .value = value - }; - - return node; -} - -/** - * Allocate and initialize a new IndexTargetNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param receiver The receiver field. - * @param opening_loc The opening_loc field. - * @param arguments The arguments field. - * @param closing_loc The closing_loc field. - * @param block The block field. - * @return The newly allocated and initialized node. - */ -static inline pm_index_target_node_t * -pm_index_target_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_node *receiver, pm_location_t opening_loc, struct pm_arguments_node *arguments, pm_location_t closing_loc, struct pm_block_argument_node *block) { - pm_index_target_node_t *node = (pm_index_target_node_t *) pm_arena_alloc(arena, sizeof(pm_index_target_node_t), PRISM_ALIGNOF(pm_index_target_node_t)); - - *node = (pm_index_target_node_t) { - .base = { .type = PM_INDEX_TARGET_NODE, .flags = flags, .node_id = node_id, .location = location }, - .receiver = receiver, - .opening_loc = opening_loc, - .arguments = arguments, - .closing_loc = closing_loc, - .block = block - }; - - return node; -} - -/** - * Allocate and initialize a new InstanceVariableAndWriteNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param name The name field. - * @param name_loc The name_loc field. - * @param operator_loc The operator_loc field. - * @param value The value field. - * @return The newly allocated and initialized node. - */ -static inline pm_instance_variable_and_write_node_t * -pm_instance_variable_and_write_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_constant_id_t name, pm_location_t name_loc, pm_location_t operator_loc, struct pm_node *value) { - pm_instance_variable_and_write_node_t *node = (pm_instance_variable_and_write_node_t *) pm_arena_alloc(arena, sizeof(pm_instance_variable_and_write_node_t), PRISM_ALIGNOF(pm_instance_variable_and_write_node_t)); - - *node = (pm_instance_variable_and_write_node_t) { - .base = { .type = PM_INSTANCE_VARIABLE_AND_WRITE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .name = name, - .name_loc = name_loc, - .operator_loc = operator_loc, - .value = value - }; - - return node; -} - -/** - * Allocate and initialize a new InstanceVariableOperatorWriteNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param name The name field. - * @param name_loc The name_loc field. - * @param binary_operator_loc The binary_operator_loc field. - * @param value The value field. - * @param binary_operator The binary_operator field. - * @return The newly allocated and initialized node. - */ -static inline pm_instance_variable_operator_write_node_t * -pm_instance_variable_operator_write_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_constant_id_t name, pm_location_t name_loc, pm_location_t binary_operator_loc, struct pm_node *value, pm_constant_id_t binary_operator) { - pm_instance_variable_operator_write_node_t *node = (pm_instance_variable_operator_write_node_t *) pm_arena_alloc(arena, sizeof(pm_instance_variable_operator_write_node_t), PRISM_ALIGNOF(pm_instance_variable_operator_write_node_t)); - - *node = (pm_instance_variable_operator_write_node_t) { - .base = { .type = PM_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .name = name, - .name_loc = name_loc, - .binary_operator_loc = binary_operator_loc, - .value = value, - .binary_operator = binary_operator - }; - - return node; -} - -/** - * Allocate and initialize a new InstanceVariableOrWriteNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param name The name field. - * @param name_loc The name_loc field. - * @param operator_loc The operator_loc field. - * @param value The value field. - * @return The newly allocated and initialized node. - */ -static inline pm_instance_variable_or_write_node_t * -pm_instance_variable_or_write_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_constant_id_t name, pm_location_t name_loc, pm_location_t operator_loc, struct pm_node *value) { - pm_instance_variable_or_write_node_t *node = (pm_instance_variable_or_write_node_t *) pm_arena_alloc(arena, sizeof(pm_instance_variable_or_write_node_t), PRISM_ALIGNOF(pm_instance_variable_or_write_node_t)); - - *node = (pm_instance_variable_or_write_node_t) { - .base = { .type = PM_INSTANCE_VARIABLE_OR_WRITE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .name = name, - .name_loc = name_loc, - .operator_loc = operator_loc, - .value = value - }; - - return node; -} - -/** - * Allocate and initialize a new InstanceVariableReadNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param name The name of the instance variable, which is a \`@\` followed by an [identifier](https://github\.com/ruby/prism/blob/main/docs/parsing\_rules\.md\#identifiers)\. - * @return The newly allocated and initialized node. - */ -static inline pm_instance_variable_read_node_t * -pm_instance_variable_read_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_constant_id_t name) { - pm_instance_variable_read_node_t *node = (pm_instance_variable_read_node_t *) pm_arena_alloc(arena, sizeof(pm_instance_variable_read_node_t), PRISM_ALIGNOF(pm_instance_variable_read_node_t)); - - *node = (pm_instance_variable_read_node_t) { - .base = { .type = PM_INSTANCE_VARIABLE_READ_NODE, .flags = flags, .node_id = node_id, .location = location }, - .name = name - }; - - return node; -} - -/** - * Allocate and initialize a new InstanceVariableTargetNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param name The name field. - * @return The newly allocated and initialized node. - */ -static inline pm_instance_variable_target_node_t * -pm_instance_variable_target_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_constant_id_t name) { - pm_instance_variable_target_node_t *node = (pm_instance_variable_target_node_t *) pm_arena_alloc(arena, sizeof(pm_instance_variable_target_node_t), PRISM_ALIGNOF(pm_instance_variable_target_node_t)); - - *node = (pm_instance_variable_target_node_t) { - .base = { .type = PM_INSTANCE_VARIABLE_TARGET_NODE, .flags = flags, .node_id = node_id, .location = location }, - .name = name - }; - - return node; -} - -/** - * Allocate and initialize a new InstanceVariableWriteNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param name The name of the instance variable, which is a \`@\` followed by an [identifier](https://github\.com/ruby/prism/blob/main/docs/parsing\_rules\.md\#identifiers)\. - * @param name_loc The Location of the variable name\. - * @param value The value to write to the instance variable\. It can be any [non\-void expression](https://github\.com/ruby/prism/blob/main/docs/parsing\_rules\.md\#non\-void\-expression)\. - * @param operator_loc The Location of the \`=\` operator\. - * @return The newly allocated and initialized node. - */ -static inline pm_instance_variable_write_node_t * -pm_instance_variable_write_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_constant_id_t name, pm_location_t name_loc, struct pm_node *value, pm_location_t operator_loc) { - pm_instance_variable_write_node_t *node = (pm_instance_variable_write_node_t *) pm_arena_alloc(arena, sizeof(pm_instance_variable_write_node_t), PRISM_ALIGNOF(pm_instance_variable_write_node_t)); - - *node = (pm_instance_variable_write_node_t) { - .base = { .type = PM_INSTANCE_VARIABLE_WRITE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .name = name, - .name_loc = name_loc, - .value = value, - .operator_loc = operator_loc - }; - - return node; -} - -/** - * Allocate and initialize a new IntegerNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param value The value of the integer literal as a number\. - * @return The newly allocated and initialized node. - */ -static inline pm_integer_node_t * -pm_integer_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_integer_t value) { - pm_integer_node_t *node = (pm_integer_node_t *) pm_arena_alloc(arena, sizeof(pm_integer_node_t), PRISM_ALIGNOF(pm_integer_node_t)); - - *node = (pm_integer_node_t) { - .base = { .type = PM_INTEGER_NODE, .flags = flags, .node_id = node_id, .location = location }, - .value = value - }; - - return node; -} - -/** - * Allocate and initialize a new InterpolatedMatchLastLineNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param opening_loc The opening_loc field. - * @param parts The parts field. - * @param closing_loc The closing_loc field. - * @return The newly allocated and initialized node. - */ -static inline pm_interpolated_match_last_line_node_t * -pm_interpolated_match_last_line_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_location_t opening_loc, pm_node_list_t parts, pm_location_t closing_loc) { - pm_interpolated_match_last_line_node_t *node = (pm_interpolated_match_last_line_node_t *) pm_arena_alloc(arena, sizeof(pm_interpolated_match_last_line_node_t), PRISM_ALIGNOF(pm_interpolated_match_last_line_node_t)); - - *node = (pm_interpolated_match_last_line_node_t) { - .base = { .type = PM_INTERPOLATED_MATCH_LAST_LINE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .opening_loc = opening_loc, - .parts = parts, - .closing_loc = closing_loc - }; - - return node; -} - -/** - * Allocate and initialize a new InterpolatedRegularExpressionNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param opening_loc The opening_loc field. - * @param parts The parts field. - * @param closing_loc The closing_loc field. - * @return The newly allocated and initialized node. - */ -static inline pm_interpolated_regular_expression_node_t * -pm_interpolated_regular_expression_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_location_t opening_loc, pm_node_list_t parts, pm_location_t closing_loc) { - pm_interpolated_regular_expression_node_t *node = (pm_interpolated_regular_expression_node_t *) pm_arena_alloc(arena, sizeof(pm_interpolated_regular_expression_node_t), PRISM_ALIGNOF(pm_interpolated_regular_expression_node_t)); - - *node = (pm_interpolated_regular_expression_node_t) { - .base = { .type = PM_INTERPOLATED_REGULAR_EXPRESSION_NODE, .flags = flags, .node_id = node_id, .location = location }, - .opening_loc = opening_loc, - .parts = parts, - .closing_loc = closing_loc - }; - - return node; -} - -/** - * Allocate and initialize a new InterpolatedStringNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param opening_loc The opening_loc field. - * @param parts The parts field. - * @param closing_loc The closing_loc field. - * @return The newly allocated and initialized node. - */ -static inline pm_interpolated_string_node_t * -pm_interpolated_string_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_location_t opening_loc, pm_node_list_t parts, pm_location_t closing_loc) { - pm_interpolated_string_node_t *node = (pm_interpolated_string_node_t *) pm_arena_alloc(arena, sizeof(pm_interpolated_string_node_t), PRISM_ALIGNOF(pm_interpolated_string_node_t)); - - *node = (pm_interpolated_string_node_t) { - .base = { .type = PM_INTERPOLATED_STRING_NODE, .flags = flags, .node_id = node_id, .location = location }, - .opening_loc = opening_loc, - .parts = parts, - .closing_loc = closing_loc - }; - - return node; -} - -/** - * Allocate and initialize a new InterpolatedSymbolNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param opening_loc The opening_loc field. - * @param parts The parts field. - * @param closing_loc The closing_loc field. - * @return The newly allocated and initialized node. - */ -static inline pm_interpolated_symbol_node_t * -pm_interpolated_symbol_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_location_t opening_loc, pm_node_list_t parts, pm_location_t closing_loc) { - pm_interpolated_symbol_node_t *node = (pm_interpolated_symbol_node_t *) pm_arena_alloc(arena, sizeof(pm_interpolated_symbol_node_t), PRISM_ALIGNOF(pm_interpolated_symbol_node_t)); - - *node = (pm_interpolated_symbol_node_t) { - .base = { .type = PM_INTERPOLATED_SYMBOL_NODE, .flags = flags, .node_id = node_id, .location = location }, - .opening_loc = opening_loc, - .parts = parts, - .closing_loc = closing_loc - }; - - return node; -} - -/** - * Allocate and initialize a new InterpolatedXStringNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param opening_loc The opening_loc field. - * @param parts The parts field. - * @param closing_loc The closing_loc field. - * @return The newly allocated and initialized node. - */ -static inline pm_interpolated_x_string_node_t * -pm_interpolated_x_string_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_location_t opening_loc, pm_node_list_t parts, pm_location_t closing_loc) { - pm_interpolated_x_string_node_t *node = (pm_interpolated_x_string_node_t *) pm_arena_alloc(arena, sizeof(pm_interpolated_x_string_node_t), PRISM_ALIGNOF(pm_interpolated_x_string_node_t)); - - *node = (pm_interpolated_x_string_node_t) { - .base = { .type = PM_INTERPOLATED_X_STRING_NODE, .flags = flags, .node_id = node_id, .location = location }, - .opening_loc = opening_loc, - .parts = parts, - .closing_loc = closing_loc - }; - - return node; -} - -/** - * Allocate and initialize a new ItLocalVariableReadNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @return The newly allocated and initialized node. - */ -static inline pm_it_local_variable_read_node_t * -pm_it_local_variable_read_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location) { - pm_it_local_variable_read_node_t *node = (pm_it_local_variable_read_node_t *) pm_arena_alloc(arena, sizeof(pm_it_local_variable_read_node_t), PRISM_ALIGNOF(pm_it_local_variable_read_node_t)); - - *node = (pm_it_local_variable_read_node_t) { - .base = { .type = PM_IT_LOCAL_VARIABLE_READ_NODE, .flags = flags, .node_id = node_id, .location = location } - }; - - return node; -} - -/** - * Allocate and initialize a new ItParametersNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @return The newly allocated and initialized node. - */ -static inline pm_it_parameters_node_t * -pm_it_parameters_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location) { - pm_it_parameters_node_t *node = (pm_it_parameters_node_t *) pm_arena_alloc(arena, sizeof(pm_it_parameters_node_t), PRISM_ALIGNOF(pm_it_parameters_node_t)); - - *node = (pm_it_parameters_node_t) { - .base = { .type = PM_IT_PARAMETERS_NODE, .flags = flags, .node_id = node_id, .location = location } - }; - - return node; -} - -/** - * Allocate and initialize a new KeywordHashNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param elements The elements field. - * @return The newly allocated and initialized node. - */ -static inline pm_keyword_hash_node_t * -pm_keyword_hash_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_node_list_t elements) { - pm_keyword_hash_node_t *node = (pm_keyword_hash_node_t *) pm_arena_alloc(arena, sizeof(pm_keyword_hash_node_t), PRISM_ALIGNOF(pm_keyword_hash_node_t)); - - *node = (pm_keyword_hash_node_t) { - .base = { .type = PM_KEYWORD_HASH_NODE, .flags = flags, .node_id = node_id, .location = location }, - .elements = elements - }; - - return node; -} - -/** - * Allocate and initialize a new KeywordRestParameterNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param name The name field. - * @param name_loc The name_loc field. - * @param operator_loc The operator_loc field. - * @return The newly allocated and initialized node. - */ -static inline pm_keyword_rest_parameter_node_t * -pm_keyword_rest_parameter_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_constant_id_t name, pm_location_t name_loc, pm_location_t operator_loc) { - pm_keyword_rest_parameter_node_t *node = (pm_keyword_rest_parameter_node_t *) pm_arena_alloc(arena, sizeof(pm_keyword_rest_parameter_node_t), PRISM_ALIGNOF(pm_keyword_rest_parameter_node_t)); - - *node = (pm_keyword_rest_parameter_node_t) { - .base = { .type = PM_KEYWORD_REST_PARAMETER_NODE, .flags = flags, .node_id = node_id, .location = location }, - .name = name, - .name_loc = name_loc, - .operator_loc = operator_loc - }; - - return node; -} - -/** - * Allocate and initialize a new LambdaNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param locals The locals field. - * @param operator_loc The operator_loc field. - * @param opening_loc The opening_loc field. - * @param closing_loc The closing_loc field. - * @param parameters The parameters field. - * @param body The body field. - * @return The newly allocated and initialized node. - */ -static inline pm_lambda_node_t * -pm_lambda_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_constant_id_list_t locals, pm_location_t operator_loc, pm_location_t opening_loc, pm_location_t closing_loc, struct pm_node *parameters, struct pm_node *body) { - pm_lambda_node_t *node = (pm_lambda_node_t *) pm_arena_alloc(arena, sizeof(pm_lambda_node_t), PRISM_ALIGNOF(pm_lambda_node_t)); - - *node = (pm_lambda_node_t) { - .base = { .type = PM_LAMBDA_NODE, .flags = flags, .node_id = node_id, .location = location }, - .locals = locals, - .operator_loc = operator_loc, - .opening_loc = opening_loc, - .closing_loc = closing_loc, - .parameters = parameters, - .body = body - }; - - return node; -} - -/** - * Allocate and initialize a new LocalVariableAndWriteNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param name_loc The name_loc field. - * @param operator_loc The operator_loc field. - * @param value The value field. - * @param name The name field. - * @param depth The depth field. - * @return The newly allocated and initialized node. - */ -static inline pm_local_variable_and_write_node_t * -pm_local_variable_and_write_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_location_t name_loc, pm_location_t operator_loc, struct pm_node *value, pm_constant_id_t name, uint32_t depth) { - pm_local_variable_and_write_node_t *node = (pm_local_variable_and_write_node_t *) pm_arena_alloc(arena, sizeof(pm_local_variable_and_write_node_t), PRISM_ALIGNOF(pm_local_variable_and_write_node_t)); - - *node = (pm_local_variable_and_write_node_t) { - .base = { .type = PM_LOCAL_VARIABLE_AND_WRITE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .name_loc = name_loc, - .operator_loc = operator_loc, - .value = value, - .name = name, - .depth = depth - }; - - return node; -} - -/** - * Allocate and initialize a new LocalVariableOperatorWriteNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param name_loc The name_loc field. - * @param binary_operator_loc The binary_operator_loc field. - * @param value The value field. - * @param name The name field. - * @param binary_operator The binary_operator field. - * @param depth The depth field. - * @return The newly allocated and initialized node. - */ -static inline pm_local_variable_operator_write_node_t * -pm_local_variable_operator_write_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_location_t name_loc, pm_location_t binary_operator_loc, struct pm_node *value, pm_constant_id_t name, pm_constant_id_t binary_operator, uint32_t depth) { - pm_local_variable_operator_write_node_t *node = (pm_local_variable_operator_write_node_t *) pm_arena_alloc(arena, sizeof(pm_local_variable_operator_write_node_t), PRISM_ALIGNOF(pm_local_variable_operator_write_node_t)); - - *node = (pm_local_variable_operator_write_node_t) { - .base = { .type = PM_LOCAL_VARIABLE_OPERATOR_WRITE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .name_loc = name_loc, - .binary_operator_loc = binary_operator_loc, - .value = value, - .name = name, - .binary_operator = binary_operator, - .depth = depth - }; - - return node; -} - -/** - * Allocate and initialize a new LocalVariableOrWriteNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param name_loc The name_loc field. - * @param operator_loc The operator_loc field. - * @param value The value field. - * @param name The name field. - * @param depth The depth field. - * @return The newly allocated and initialized node. - */ -static inline pm_local_variable_or_write_node_t * -pm_local_variable_or_write_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_location_t name_loc, pm_location_t operator_loc, struct pm_node *value, pm_constant_id_t name, uint32_t depth) { - pm_local_variable_or_write_node_t *node = (pm_local_variable_or_write_node_t *) pm_arena_alloc(arena, sizeof(pm_local_variable_or_write_node_t), PRISM_ALIGNOF(pm_local_variable_or_write_node_t)); - - *node = (pm_local_variable_or_write_node_t) { - .base = { .type = PM_LOCAL_VARIABLE_OR_WRITE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .name_loc = name_loc, - .operator_loc = operator_loc, - .value = value, - .name = name, - .depth = depth - }; - - return node; -} - -/** - * Allocate and initialize a new LocalVariableReadNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param name The name of the local variable, which is an [identifier](https://github\.com/ruby/prism/blob/main/docs/parsing\_rules\.md\#identifiers)\. - * @param depth The number of visible scopes that should be searched to find the origin of this local variable\. - * @return The newly allocated and initialized node. - */ -static inline pm_local_variable_read_node_t * -pm_local_variable_read_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_constant_id_t name, uint32_t depth) { - pm_local_variable_read_node_t *node = (pm_local_variable_read_node_t *) pm_arena_alloc(arena, sizeof(pm_local_variable_read_node_t), PRISM_ALIGNOF(pm_local_variable_read_node_t)); - - *node = (pm_local_variable_read_node_t) { - .base = { .type = PM_LOCAL_VARIABLE_READ_NODE, .flags = flags, .node_id = node_id, .location = location }, - .name = name, - .depth = depth - }; - - return node; -} - -/** - * Allocate and initialize a new LocalVariableTargetNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param name The name field. - * @param depth The depth field. - * @return The newly allocated and initialized node. - */ -static inline pm_local_variable_target_node_t * -pm_local_variable_target_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_constant_id_t name, uint32_t depth) { - pm_local_variable_target_node_t *node = (pm_local_variable_target_node_t *) pm_arena_alloc(arena, sizeof(pm_local_variable_target_node_t), PRISM_ALIGNOF(pm_local_variable_target_node_t)); - - *node = (pm_local_variable_target_node_t) { - .base = { .type = PM_LOCAL_VARIABLE_TARGET_NODE, .flags = flags, .node_id = node_id, .location = location }, - .name = name, - .depth = depth - }; - - return node; -} - -/** - * Allocate and initialize a new LocalVariableWriteNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param name The name of the local variable, which is an [identifier](https://github\.com/ruby/prism/blob/main/docs/parsing\_rules\.md\#identifiers)\. - * @param depth The number of semantic scopes we have to traverse to find the declaration of this variable\. - * @param name_loc The Location of the variable name\. - * @param value The value to write to the local variable\. It can be any [non\-void expression](https://github\.com/ruby/prism/blob/main/docs/parsing\_rules\.md\#non\-void\-expression)\. - * @param operator_loc The Location of the \`=\` operator\. - * @return The newly allocated and initialized node. - */ -static inline pm_local_variable_write_node_t * -pm_local_variable_write_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_constant_id_t name, uint32_t depth, pm_location_t name_loc, struct pm_node *value, pm_location_t operator_loc) { - pm_local_variable_write_node_t *node = (pm_local_variable_write_node_t *) pm_arena_alloc(arena, sizeof(pm_local_variable_write_node_t), PRISM_ALIGNOF(pm_local_variable_write_node_t)); - - *node = (pm_local_variable_write_node_t) { - .base = { .type = PM_LOCAL_VARIABLE_WRITE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .name = name, - .depth = depth, - .name_loc = name_loc, - .value = value, - .operator_loc = operator_loc - }; - - return node; -} - -/** - * Allocate and initialize a new MatchLastLineNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param opening_loc The opening_loc field. - * @param content_loc The content_loc field. - * @param closing_loc The closing_loc field. - * @param unescaped The unescaped field. - * @return The newly allocated and initialized node. - */ -static inline pm_match_last_line_node_t * -pm_match_last_line_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_location_t opening_loc, pm_location_t content_loc, pm_location_t closing_loc, pm_string_t unescaped) { - pm_match_last_line_node_t *node = (pm_match_last_line_node_t *) pm_arena_alloc(arena, sizeof(pm_match_last_line_node_t), PRISM_ALIGNOF(pm_match_last_line_node_t)); - - *node = (pm_match_last_line_node_t) { - .base = { .type = PM_MATCH_LAST_LINE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .opening_loc = opening_loc, - .content_loc = content_loc, - .closing_loc = closing_loc, - .unescaped = unescaped - }; - - return node; -} - -/** - * Allocate and initialize a new MatchPredicateNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param value The value field. - * @param pattern The pattern field. - * @param operator_loc The operator_loc field. - * @return The newly allocated and initialized node. - */ -static inline pm_match_predicate_node_t * -pm_match_predicate_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_node *value, struct pm_node *pattern, pm_location_t operator_loc) { - pm_match_predicate_node_t *node = (pm_match_predicate_node_t *) pm_arena_alloc(arena, sizeof(pm_match_predicate_node_t), PRISM_ALIGNOF(pm_match_predicate_node_t)); - - *node = (pm_match_predicate_node_t) { - .base = { .type = PM_MATCH_PREDICATE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .value = value, - .pattern = pattern, - .operator_loc = operator_loc - }; - - return node; -} - -/** - * Allocate and initialize a new MatchRequiredNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param value Represents the left\-hand side of the operator\. - * @param pattern Represents the right\-hand side of the operator\. The type of the node depends on the expression\. - * @param operator_loc The Location of the operator\. - * @return The newly allocated and initialized node. - */ -static inline pm_match_required_node_t * -pm_match_required_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_node *value, struct pm_node *pattern, pm_location_t operator_loc) { - pm_match_required_node_t *node = (pm_match_required_node_t *) pm_arena_alloc(arena, sizeof(pm_match_required_node_t), PRISM_ALIGNOF(pm_match_required_node_t)); - - *node = (pm_match_required_node_t) { - .base = { .type = PM_MATCH_REQUIRED_NODE, .flags = flags, .node_id = node_id, .location = location }, - .value = value, - .pattern = pattern, - .operator_loc = operator_loc - }; - - return node; -} - -/** - * Allocate and initialize a new MatchWriteNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param call The call field. - * @param targets The targets field. - * @return The newly allocated and initialized node. - */ -static inline pm_match_write_node_t * -pm_match_write_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_call_node *call, pm_node_list_t targets) { - pm_match_write_node_t *node = (pm_match_write_node_t *) pm_arena_alloc(arena, sizeof(pm_match_write_node_t), PRISM_ALIGNOF(pm_match_write_node_t)); - - *node = (pm_match_write_node_t) { - .base = { .type = PM_MATCH_WRITE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .call = call, - .targets = targets - }; - - return node; -} - -/** - * Allocate and initialize a new MissingNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @return The newly allocated and initialized node. - */ -static inline pm_missing_node_t * -pm_missing_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location) { - pm_missing_node_t *node = (pm_missing_node_t *) pm_arena_alloc(arena, sizeof(pm_missing_node_t), PRISM_ALIGNOF(pm_missing_node_t)); - - *node = (pm_missing_node_t) { - .base = { .type = PM_MISSING_NODE, .flags = flags, .node_id = node_id, .location = location } - }; - - return node; -} - -/** - * Allocate and initialize a new ModuleNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param locals The locals field. - * @param module_keyword_loc The module_keyword_loc field. - * @param constant_path The constant_path field. - * @param body The body field. - * @param end_keyword_loc The end_keyword_loc field. - * @param name The name field. - * @return The newly allocated and initialized node. - */ -static inline pm_module_node_t * -pm_module_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_constant_id_list_t locals, pm_location_t module_keyword_loc, struct pm_node *constant_path, struct pm_node *body, pm_location_t end_keyword_loc, pm_constant_id_t name) { - pm_module_node_t *node = (pm_module_node_t *) pm_arena_alloc(arena, sizeof(pm_module_node_t), PRISM_ALIGNOF(pm_module_node_t)); - - *node = (pm_module_node_t) { - .base = { .type = PM_MODULE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .locals = locals, - .module_keyword_loc = module_keyword_loc, - .constant_path = constant_path, - .body = body, - .end_keyword_loc = end_keyword_loc, - .name = name - }; - - return node; -} - -/** - * Allocate and initialize a new MultiTargetNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param lefts Represents the targets expressions before a splat node\. - * @param rest Represents a splat node in the target expression\. - * @param rights Represents the targets expressions after a splat node\. - * @param lparen_loc The Location of the opening parenthesis\. - * @param rparen_loc The Location of the closing parenthesis\. - * @return The newly allocated and initialized node. - */ -static inline pm_multi_target_node_t * -pm_multi_target_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_node_list_t lefts, struct pm_node *rest, pm_node_list_t rights, pm_location_t lparen_loc, pm_location_t rparen_loc) { - pm_multi_target_node_t *node = (pm_multi_target_node_t *) pm_arena_alloc(arena, sizeof(pm_multi_target_node_t), PRISM_ALIGNOF(pm_multi_target_node_t)); - - *node = (pm_multi_target_node_t) { - .base = { .type = PM_MULTI_TARGET_NODE, .flags = flags, .node_id = node_id, .location = location }, - .lefts = lefts, - .rest = rest, - .rights = rights, - .lparen_loc = lparen_loc, - .rparen_loc = rparen_loc - }; - - return node; -} - -/** - * Allocate and initialize a new MultiWriteNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param lefts Represents the targets expressions before a splat node\. - * @param rest Represents a splat node in the target expression\. - * @param rights Represents the targets expressions after a splat node\. - * @param lparen_loc The Location of the opening parenthesis\. - * @param rparen_loc The Location of the closing parenthesis\. - * @param operator_loc The Location of the operator\. - * @param value The value to write to the targets\. It can be any [non\-void expression](https://github\.com/ruby/prism/blob/main/docs/parsing\_rules\.md\#non\-void\-expression)\. - * @return The newly allocated and initialized node. - */ -static inline pm_multi_write_node_t * -pm_multi_write_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_node_list_t lefts, struct pm_node *rest, pm_node_list_t rights, pm_location_t lparen_loc, pm_location_t rparen_loc, pm_location_t operator_loc, struct pm_node *value) { - pm_multi_write_node_t *node = (pm_multi_write_node_t *) pm_arena_alloc(arena, sizeof(pm_multi_write_node_t), PRISM_ALIGNOF(pm_multi_write_node_t)); - - *node = (pm_multi_write_node_t) { - .base = { .type = PM_MULTI_WRITE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .lefts = lefts, - .rest = rest, - .rights = rights, - .lparen_loc = lparen_loc, - .rparen_loc = rparen_loc, - .operator_loc = operator_loc, - .value = value - }; - - return node; -} - -/** - * Allocate and initialize a new NextNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param arguments The arguments field. - * @param keyword_loc The keyword_loc field. - * @return The newly allocated and initialized node. - */ -static inline pm_next_node_t * -pm_next_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_arguments_node *arguments, pm_location_t keyword_loc) { - pm_next_node_t *node = (pm_next_node_t *) pm_arena_alloc(arena, sizeof(pm_next_node_t), PRISM_ALIGNOF(pm_next_node_t)); - - *node = (pm_next_node_t) { - .base = { .type = PM_NEXT_NODE, .flags = flags, .node_id = node_id, .location = location }, - .arguments = arguments, - .keyword_loc = keyword_loc - }; - - return node; -} - -/** - * Allocate and initialize a new NilNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @return The newly allocated and initialized node. - */ -static inline pm_nil_node_t * -pm_nil_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location) { - pm_nil_node_t *node = (pm_nil_node_t *) pm_arena_alloc(arena, sizeof(pm_nil_node_t), PRISM_ALIGNOF(pm_nil_node_t)); - - *node = (pm_nil_node_t) { - .base = { .type = PM_NIL_NODE, .flags = flags, .node_id = node_id, .location = location } - }; - - return node; -} - -/** - * Allocate and initialize a new NoBlockParameterNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param operator_loc The operator_loc field. - * @param keyword_loc The keyword_loc field. - * @return The newly allocated and initialized node. - */ -static inline pm_no_block_parameter_node_t * -pm_no_block_parameter_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_location_t operator_loc, pm_location_t keyword_loc) { - pm_no_block_parameter_node_t *node = (pm_no_block_parameter_node_t *) pm_arena_alloc(arena, sizeof(pm_no_block_parameter_node_t), PRISM_ALIGNOF(pm_no_block_parameter_node_t)); - - *node = (pm_no_block_parameter_node_t) { - .base = { .type = PM_NO_BLOCK_PARAMETER_NODE, .flags = flags, .node_id = node_id, .location = location }, - .operator_loc = operator_loc, - .keyword_loc = keyword_loc - }; - - return node; -} - -/** - * Allocate and initialize a new NoKeywordsParameterNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param operator_loc The operator_loc field. - * @param keyword_loc The keyword_loc field. - * @return The newly allocated and initialized node. - */ -static inline pm_no_keywords_parameter_node_t * -pm_no_keywords_parameter_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_location_t operator_loc, pm_location_t keyword_loc) { - pm_no_keywords_parameter_node_t *node = (pm_no_keywords_parameter_node_t *) pm_arena_alloc(arena, sizeof(pm_no_keywords_parameter_node_t), PRISM_ALIGNOF(pm_no_keywords_parameter_node_t)); - - *node = (pm_no_keywords_parameter_node_t) { - .base = { .type = PM_NO_KEYWORDS_PARAMETER_NODE, .flags = flags, .node_id = node_id, .location = location }, - .operator_loc = operator_loc, - .keyword_loc = keyword_loc - }; - - return node; -} - -/** - * Allocate and initialize a new NumberedParametersNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param maximum The maximum field. - * @return The newly allocated and initialized node. - */ -static inline pm_numbered_parameters_node_t * -pm_numbered_parameters_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, uint8_t maximum) { - pm_numbered_parameters_node_t *node = (pm_numbered_parameters_node_t *) pm_arena_alloc(arena, sizeof(pm_numbered_parameters_node_t), PRISM_ALIGNOF(pm_numbered_parameters_node_t)); - - *node = (pm_numbered_parameters_node_t) { - .base = { .type = PM_NUMBERED_PARAMETERS_NODE, .flags = flags, .node_id = node_id, .location = location }, - .maximum = maximum - }; - - return node; -} - -/** - * Allocate and initialize a new NumberedReferenceReadNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param number The (1\-indexed, from the left) number of the capture group\. Numbered references that are too large result in this value being \`0\`\. - * @return The newly allocated and initialized node. - */ -static inline pm_numbered_reference_read_node_t * -pm_numbered_reference_read_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, uint32_t number) { - pm_numbered_reference_read_node_t *node = (pm_numbered_reference_read_node_t *) pm_arena_alloc(arena, sizeof(pm_numbered_reference_read_node_t), PRISM_ALIGNOF(pm_numbered_reference_read_node_t)); - - *node = (pm_numbered_reference_read_node_t) { - .base = { .type = PM_NUMBERED_REFERENCE_READ_NODE, .flags = flags, .node_id = node_id, .location = location }, - .number = number - }; - - return node; -} - -/** - * Allocate and initialize a new OptionalKeywordParameterNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param name The name field. - * @param name_loc The name_loc field. - * @param value The value field. - * @return The newly allocated and initialized node. - */ -static inline pm_optional_keyword_parameter_node_t * -pm_optional_keyword_parameter_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_constant_id_t name, pm_location_t name_loc, struct pm_node *value) { - pm_optional_keyword_parameter_node_t *node = (pm_optional_keyword_parameter_node_t *) pm_arena_alloc(arena, sizeof(pm_optional_keyword_parameter_node_t), PRISM_ALIGNOF(pm_optional_keyword_parameter_node_t)); - - *node = (pm_optional_keyword_parameter_node_t) { - .base = { .type = PM_OPTIONAL_KEYWORD_PARAMETER_NODE, .flags = flags, .node_id = node_id, .location = location }, - .name = name, - .name_loc = name_loc, - .value = value - }; - - return node; -} - -/** - * Allocate and initialize a new OptionalParameterNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param name The name field. - * @param name_loc The name_loc field. - * @param operator_loc The operator_loc field. - * @param value The value field. - * @return The newly allocated and initialized node. - */ -static inline pm_optional_parameter_node_t * -pm_optional_parameter_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_constant_id_t name, pm_location_t name_loc, pm_location_t operator_loc, struct pm_node *value) { - pm_optional_parameter_node_t *node = (pm_optional_parameter_node_t *) pm_arena_alloc(arena, sizeof(pm_optional_parameter_node_t), PRISM_ALIGNOF(pm_optional_parameter_node_t)); - - *node = (pm_optional_parameter_node_t) { - .base = { .type = PM_OPTIONAL_PARAMETER_NODE, .flags = flags, .node_id = node_id, .location = location }, - .name = name, - .name_loc = name_loc, - .operator_loc = operator_loc, - .value = value - }; - - return node; -} - -/** - * Allocate and initialize a new OrNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param left Represents the left side of the expression\. It can be any [non\-void expression](https://github\.com/ruby/prism/blob/main/docs/parsing\_rules\.md\#non\-void\-expression)\. - * @param right Represents the right side of the expression\. - * @param operator_loc The Location of the \`or\` keyword or the \`||\` operator\. - * @return The newly allocated and initialized node. - */ -static inline pm_or_node_t * -pm_or_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_node *left, struct pm_node *right, pm_location_t operator_loc) { - pm_or_node_t *node = (pm_or_node_t *) pm_arena_alloc(arena, sizeof(pm_or_node_t), PRISM_ALIGNOF(pm_or_node_t)); - - *node = (pm_or_node_t) { - .base = { .type = PM_OR_NODE, .flags = flags, .node_id = node_id, .location = location }, - .left = left, - .right = right, - .operator_loc = operator_loc - }; - - return node; -} - -/** - * Allocate and initialize a new ParametersNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param requireds The requireds field. - * @param optionals The optionals field. - * @param rest The rest field. - * @param posts The posts field. - * @param keywords The keywords field. - * @param keyword_rest The keyword_rest field. - * @param block The block field. - * @return The newly allocated and initialized node. - */ -static inline pm_parameters_node_t * -pm_parameters_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_node_list_t requireds, pm_node_list_t optionals, struct pm_node *rest, pm_node_list_t posts, pm_node_list_t keywords, struct pm_node *keyword_rest, struct pm_node *block) { - pm_parameters_node_t *node = (pm_parameters_node_t *) pm_arena_alloc(arena, sizeof(pm_parameters_node_t), PRISM_ALIGNOF(pm_parameters_node_t)); - - *node = (pm_parameters_node_t) { - .base = { .type = PM_PARAMETERS_NODE, .flags = flags, .node_id = node_id, .location = location }, - .requireds = requireds, - .optionals = optionals, - .rest = rest, - .posts = posts, - .keywords = keywords, - .keyword_rest = keyword_rest, - .block = block - }; - - return node; -} - -/** - * Allocate and initialize a new ParenthesesNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param body The body field. - * @param opening_loc The opening_loc field. - * @param closing_loc The closing_loc field. - * @return The newly allocated and initialized node. - */ -static inline pm_parentheses_node_t * -pm_parentheses_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_node *body, pm_location_t opening_loc, pm_location_t closing_loc) { - pm_parentheses_node_t *node = (pm_parentheses_node_t *) pm_arena_alloc(arena, sizeof(pm_parentheses_node_t), PRISM_ALIGNOF(pm_parentheses_node_t)); - - *node = (pm_parentheses_node_t) { - .base = { .type = PM_PARENTHESES_NODE, .flags = flags, .node_id = node_id, .location = location }, - .body = body, - .opening_loc = opening_loc, - .closing_loc = closing_loc - }; - - return node; -} - -/** - * Allocate and initialize a new PinnedExpressionNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param expression The expression used in the pinned expression - * @param operator_loc The Location of the \`^\` operator - * @param lparen_loc The Location of the opening parenthesis\. - * @param rparen_loc The Location of the closing parenthesis\. - * @return The newly allocated and initialized node. - */ -static inline pm_pinned_expression_node_t * -pm_pinned_expression_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_node *expression, pm_location_t operator_loc, pm_location_t lparen_loc, pm_location_t rparen_loc) { - pm_pinned_expression_node_t *node = (pm_pinned_expression_node_t *) pm_arena_alloc(arena, sizeof(pm_pinned_expression_node_t), PRISM_ALIGNOF(pm_pinned_expression_node_t)); - - *node = (pm_pinned_expression_node_t) { - .base = { .type = PM_PINNED_EXPRESSION_NODE, .flags = flags, .node_id = node_id, .location = location }, - .expression = expression, - .operator_loc = operator_loc, - .lparen_loc = lparen_loc, - .rparen_loc = rparen_loc - }; - - return node; -} - -/** - * Allocate and initialize a new PinnedVariableNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param variable The variable used in the pinned expression - * @param operator_loc The Location of the \`^\` operator - * @return The newly allocated and initialized node. - */ -static inline pm_pinned_variable_node_t * -pm_pinned_variable_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_node *variable, pm_location_t operator_loc) { - pm_pinned_variable_node_t *node = (pm_pinned_variable_node_t *) pm_arena_alloc(arena, sizeof(pm_pinned_variable_node_t), PRISM_ALIGNOF(pm_pinned_variable_node_t)); - - *node = (pm_pinned_variable_node_t) { - .base = { .type = PM_PINNED_VARIABLE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .variable = variable, - .operator_loc = operator_loc - }; - - return node; -} - -/** - * Allocate and initialize a new PostExecutionNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param statements The statements field. - * @param keyword_loc The keyword_loc field. - * @param opening_loc The opening_loc field. - * @param closing_loc The closing_loc field. - * @return The newly allocated and initialized node. - */ -static inline pm_post_execution_node_t * -pm_post_execution_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_statements_node *statements, pm_location_t keyword_loc, pm_location_t opening_loc, pm_location_t closing_loc) { - pm_post_execution_node_t *node = (pm_post_execution_node_t *) pm_arena_alloc(arena, sizeof(pm_post_execution_node_t), PRISM_ALIGNOF(pm_post_execution_node_t)); - - *node = (pm_post_execution_node_t) { - .base = { .type = PM_POST_EXECUTION_NODE, .flags = flags, .node_id = node_id, .location = location }, - .statements = statements, - .keyword_loc = keyword_loc, - .opening_loc = opening_loc, - .closing_loc = closing_loc - }; - - return node; -} - -/** - * Allocate and initialize a new PreExecutionNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param statements The statements field. - * @param keyword_loc The keyword_loc field. - * @param opening_loc The opening_loc field. - * @param closing_loc The closing_loc field. - * @return The newly allocated and initialized node. - */ -static inline pm_pre_execution_node_t * -pm_pre_execution_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_statements_node *statements, pm_location_t keyword_loc, pm_location_t opening_loc, pm_location_t closing_loc) { - pm_pre_execution_node_t *node = (pm_pre_execution_node_t *) pm_arena_alloc(arena, sizeof(pm_pre_execution_node_t), PRISM_ALIGNOF(pm_pre_execution_node_t)); - - *node = (pm_pre_execution_node_t) { - .base = { .type = PM_PRE_EXECUTION_NODE, .flags = flags, .node_id = node_id, .location = location }, - .statements = statements, - .keyword_loc = keyword_loc, - .opening_loc = opening_loc, - .closing_loc = closing_loc - }; - - return node; -} - -/** - * Allocate and initialize a new ProgramNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param locals The locals field. - * @param statements The statements field. - * @return The newly allocated and initialized node. - */ -static inline pm_program_node_t * -pm_program_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_constant_id_list_t locals, struct pm_statements_node *statements) { - pm_program_node_t *node = (pm_program_node_t *) pm_arena_alloc(arena, sizeof(pm_program_node_t), PRISM_ALIGNOF(pm_program_node_t)); - - *node = (pm_program_node_t) { - .base = { .type = PM_PROGRAM_NODE, .flags = flags, .node_id = node_id, .location = location }, - .locals = locals, - .statements = statements - }; - - return node; -} - -/** - * Allocate and initialize a new RangeNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param left The left\-hand side of the range, if present\. It can be either \`nil\` or any [non\-void expression](https://github\.com/ruby/prism/blob/main/docs/parsing\_rules\.md\#non\-void\-expression)\. - * @param right The right\-hand side of the range, if present\. It can be either \`nil\` or any [non\-void expression](https://github\.com/ruby/prism/blob/main/docs/parsing\_rules\.md\#non\-void\-expression)\. - * @param operator_loc The Location of the \`\.\.\` or \`\.\.\.\` operator\. - * @return The newly allocated and initialized node. - */ -static inline pm_range_node_t * -pm_range_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_node *left, struct pm_node *right, pm_location_t operator_loc) { - pm_range_node_t *node = (pm_range_node_t *) pm_arena_alloc(arena, sizeof(pm_range_node_t), PRISM_ALIGNOF(pm_range_node_t)); - - *node = (pm_range_node_t) { - .base = { .type = PM_RANGE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .left = left, - .right = right, - .operator_loc = operator_loc - }; - - return node; -} - -/** - * Allocate and initialize a new RationalNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param numerator The numerator of the rational number\. - * @param denominator The denominator of the rational number\. - * @return The newly allocated and initialized node. - */ -static inline pm_rational_node_t * -pm_rational_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_integer_t numerator, pm_integer_t denominator) { - pm_rational_node_t *node = (pm_rational_node_t *) pm_arena_alloc(arena, sizeof(pm_rational_node_t), PRISM_ALIGNOF(pm_rational_node_t)); - - *node = (pm_rational_node_t) { - .base = { .type = PM_RATIONAL_NODE, .flags = flags, .node_id = node_id, .location = location }, - .numerator = numerator, - .denominator = denominator - }; - - return node; -} - -/** - * Allocate and initialize a new RedoNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @return The newly allocated and initialized node. - */ -static inline pm_redo_node_t * -pm_redo_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location) { - pm_redo_node_t *node = (pm_redo_node_t *) pm_arena_alloc(arena, sizeof(pm_redo_node_t), PRISM_ALIGNOF(pm_redo_node_t)); - - *node = (pm_redo_node_t) { - .base = { .type = PM_REDO_NODE, .flags = flags, .node_id = node_id, .location = location } - }; - - return node; -} - -/** - * Allocate and initialize a new RegularExpressionNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param opening_loc The opening_loc field. - * @param content_loc The content_loc field. - * @param closing_loc The closing_loc field. - * @param unescaped The unescaped field. - * @return The newly allocated and initialized node. - */ -static inline pm_regular_expression_node_t * -pm_regular_expression_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_location_t opening_loc, pm_location_t content_loc, pm_location_t closing_loc, pm_string_t unescaped) { - pm_regular_expression_node_t *node = (pm_regular_expression_node_t *) pm_arena_alloc(arena, sizeof(pm_regular_expression_node_t), PRISM_ALIGNOF(pm_regular_expression_node_t)); - - *node = (pm_regular_expression_node_t) { - .base = { .type = PM_REGULAR_EXPRESSION_NODE, .flags = flags, .node_id = node_id, .location = location }, - .opening_loc = opening_loc, - .content_loc = content_loc, - .closing_loc = closing_loc, - .unescaped = unescaped - }; - - return node; -} - -/** - * Allocate and initialize a new RequiredKeywordParameterNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param name The name field. - * @param name_loc The name_loc field. - * @return The newly allocated and initialized node. - */ -static inline pm_required_keyword_parameter_node_t * -pm_required_keyword_parameter_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_constant_id_t name, pm_location_t name_loc) { - pm_required_keyword_parameter_node_t *node = (pm_required_keyword_parameter_node_t *) pm_arena_alloc(arena, sizeof(pm_required_keyword_parameter_node_t), PRISM_ALIGNOF(pm_required_keyword_parameter_node_t)); - - *node = (pm_required_keyword_parameter_node_t) { - .base = { .type = PM_REQUIRED_KEYWORD_PARAMETER_NODE, .flags = flags, .node_id = node_id, .location = location }, - .name = name, - .name_loc = name_loc - }; - - return node; -} - -/** - * Allocate and initialize a new RequiredParameterNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param name The name field. - * @return The newly allocated and initialized node. - */ -static inline pm_required_parameter_node_t * -pm_required_parameter_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_constant_id_t name) { - pm_required_parameter_node_t *node = (pm_required_parameter_node_t *) pm_arena_alloc(arena, sizeof(pm_required_parameter_node_t), PRISM_ALIGNOF(pm_required_parameter_node_t)); - - *node = (pm_required_parameter_node_t) { - .base = { .type = PM_REQUIRED_PARAMETER_NODE, .flags = flags, .node_id = node_id, .location = location }, - .name = name - }; - - return node; -} - -/** - * Allocate and initialize a new RescueModifierNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param expression The expression field. - * @param keyword_loc The keyword_loc field. - * @param rescue_expression The rescue_expression field. - * @return The newly allocated and initialized node. - */ -static inline pm_rescue_modifier_node_t * -pm_rescue_modifier_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_node *expression, pm_location_t keyword_loc, struct pm_node *rescue_expression) { - pm_rescue_modifier_node_t *node = (pm_rescue_modifier_node_t *) pm_arena_alloc(arena, sizeof(pm_rescue_modifier_node_t), PRISM_ALIGNOF(pm_rescue_modifier_node_t)); - - *node = (pm_rescue_modifier_node_t) { - .base = { .type = PM_RESCUE_MODIFIER_NODE, .flags = flags, .node_id = node_id, .location = location }, - .expression = expression, - .keyword_loc = keyword_loc, - .rescue_expression = rescue_expression - }; - - return node; -} - -/** - * Allocate and initialize a new RescueNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param keyword_loc The keyword_loc field. - * @param exceptions The exceptions field. - * @param operator_loc The operator_loc field. - * @param reference The reference field. - * @param then_keyword_loc The then_keyword_loc field. - * @param statements The statements field. - * @param subsequent The subsequent field. - * @return The newly allocated and initialized node. - */ -static inline pm_rescue_node_t * -pm_rescue_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_location_t keyword_loc, pm_node_list_t exceptions, pm_location_t operator_loc, struct pm_node *reference, pm_location_t then_keyword_loc, struct pm_statements_node *statements, struct pm_rescue_node *subsequent) { - pm_rescue_node_t *node = (pm_rescue_node_t *) pm_arena_alloc(arena, sizeof(pm_rescue_node_t), PRISM_ALIGNOF(pm_rescue_node_t)); - - *node = (pm_rescue_node_t) { - .base = { .type = PM_RESCUE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .keyword_loc = keyword_loc, - .exceptions = exceptions, - .operator_loc = operator_loc, - .reference = reference, - .then_keyword_loc = then_keyword_loc, - .statements = statements, - .subsequent = subsequent - }; - - return node; -} - -/** - * Allocate and initialize a new RestParameterNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param name The name field. - * @param name_loc The name_loc field. - * @param operator_loc The operator_loc field. - * @return The newly allocated and initialized node. - */ -static inline pm_rest_parameter_node_t * -pm_rest_parameter_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_constant_id_t name, pm_location_t name_loc, pm_location_t operator_loc) { - pm_rest_parameter_node_t *node = (pm_rest_parameter_node_t *) pm_arena_alloc(arena, sizeof(pm_rest_parameter_node_t), PRISM_ALIGNOF(pm_rest_parameter_node_t)); - - *node = (pm_rest_parameter_node_t) { - .base = { .type = PM_REST_PARAMETER_NODE, .flags = flags, .node_id = node_id, .location = location }, - .name = name, - .name_loc = name_loc, - .operator_loc = operator_loc - }; - - return node; -} - -/** - * Allocate and initialize a new RetryNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @return The newly allocated and initialized node. - */ -static inline pm_retry_node_t * -pm_retry_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location) { - pm_retry_node_t *node = (pm_retry_node_t *) pm_arena_alloc(arena, sizeof(pm_retry_node_t), PRISM_ALIGNOF(pm_retry_node_t)); - - *node = (pm_retry_node_t) { - .base = { .type = PM_RETRY_NODE, .flags = flags, .node_id = node_id, .location = location } - }; - - return node; -} - -/** - * Allocate and initialize a new ReturnNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param keyword_loc The keyword_loc field. - * @param arguments The arguments field. - * @return The newly allocated and initialized node. - */ -static inline pm_return_node_t * -pm_return_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_location_t keyword_loc, struct pm_arguments_node *arguments) { - pm_return_node_t *node = (pm_return_node_t *) pm_arena_alloc(arena, sizeof(pm_return_node_t), PRISM_ALIGNOF(pm_return_node_t)); - - *node = (pm_return_node_t) { - .base = { .type = PM_RETURN_NODE, .flags = flags, .node_id = node_id, .location = location }, - .keyword_loc = keyword_loc, - .arguments = arguments - }; - - return node; -} - -/** - * Allocate and initialize a new SelfNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @return The newly allocated and initialized node. - */ -static inline pm_self_node_t * -pm_self_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location) { - pm_self_node_t *node = (pm_self_node_t *) pm_arena_alloc(arena, sizeof(pm_self_node_t), PRISM_ALIGNOF(pm_self_node_t)); - - *node = (pm_self_node_t) { - .base = { .type = PM_SELF_NODE, .flags = flags, .node_id = node_id, .location = location } - }; - - return node; -} - -/** - * Allocate and initialize a new ShareableConstantNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param write The constant write that should be modified with the shareability state\. - * @return The newly allocated and initialized node. - */ -static inline pm_shareable_constant_node_t * -pm_shareable_constant_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, struct pm_node *write) { - pm_shareable_constant_node_t *node = (pm_shareable_constant_node_t *) pm_arena_alloc(arena, sizeof(pm_shareable_constant_node_t), PRISM_ALIGNOF(pm_shareable_constant_node_t)); - - *node = (pm_shareable_constant_node_t) { - .base = { .type = PM_SHAREABLE_CONSTANT_NODE, .flags = flags, .node_id = node_id, .location = location }, - .write = write - }; - - return node; -} - -/** - * Allocate and initialize a new SingletonClassNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param locals The locals field. - * @param class_keyword_loc The class_keyword_loc field. - * @param operator_loc The operator_loc field. - * @param expression The expression field. - * @param body The body field. - * @param end_keyword_loc The end_keyword_loc field. - * @return The newly allocated and initialized node. - */ -static inline pm_singleton_class_node_t * -pm_singleton_class_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_constant_id_list_t locals, pm_location_t class_keyword_loc, pm_location_t operator_loc, struct pm_node *expression, struct pm_node *body, pm_location_t end_keyword_loc) { - pm_singleton_class_node_t *node = (pm_singleton_class_node_t *) pm_arena_alloc(arena, sizeof(pm_singleton_class_node_t), PRISM_ALIGNOF(pm_singleton_class_node_t)); - - *node = (pm_singleton_class_node_t) { - .base = { .type = PM_SINGLETON_CLASS_NODE, .flags = flags, .node_id = node_id, .location = location }, - .locals = locals, - .class_keyword_loc = class_keyword_loc, - .operator_loc = operator_loc, - .expression = expression, - .body = body, - .end_keyword_loc = end_keyword_loc - }; - - return node; -} - -/** - * Allocate and initialize a new SourceEncodingNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @return The newly allocated and initialized node. - */ -static inline pm_source_encoding_node_t * -pm_source_encoding_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location) { - pm_source_encoding_node_t *node = (pm_source_encoding_node_t *) pm_arena_alloc(arena, sizeof(pm_source_encoding_node_t), PRISM_ALIGNOF(pm_source_encoding_node_t)); - - *node = (pm_source_encoding_node_t) { - .base = { .type = PM_SOURCE_ENCODING_NODE, .flags = flags, .node_id = node_id, .location = location } - }; - - return node; -} - -/** - * Allocate and initialize a new SourceFileNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param filepath Represents the file path being parsed\. This corresponds directly to the \`filepath\` option given to the various \`Prism\.parse\*\` APIs\. - * @return The newly allocated and initialized node. - */ -static inline pm_source_file_node_t * -pm_source_file_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_string_t filepath) { - pm_source_file_node_t *node = (pm_source_file_node_t *) pm_arena_alloc(arena, sizeof(pm_source_file_node_t), PRISM_ALIGNOF(pm_source_file_node_t)); - - *node = (pm_source_file_node_t) { - .base = { .type = PM_SOURCE_FILE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .filepath = filepath - }; - - return node; -} - -/** - * Allocate and initialize a new SourceLineNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @return The newly allocated and initialized node. - */ -static inline pm_source_line_node_t * -pm_source_line_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location) { - pm_source_line_node_t *node = (pm_source_line_node_t *) pm_arena_alloc(arena, sizeof(pm_source_line_node_t), PRISM_ALIGNOF(pm_source_line_node_t)); - - *node = (pm_source_line_node_t) { - .base = { .type = PM_SOURCE_LINE_NODE, .flags = flags, .node_id = node_id, .location = location } - }; - - return node; -} - -/** - * Allocate and initialize a new SplatNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param operator_loc The operator_loc field. - * @param expression The expression field. - * @return The newly allocated and initialized node. - */ -static inline pm_splat_node_t * -pm_splat_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_location_t operator_loc, struct pm_node *expression) { - pm_splat_node_t *node = (pm_splat_node_t *) pm_arena_alloc(arena, sizeof(pm_splat_node_t), PRISM_ALIGNOF(pm_splat_node_t)); - - *node = (pm_splat_node_t) { - .base = { .type = PM_SPLAT_NODE, .flags = flags, .node_id = node_id, .location = location }, - .operator_loc = operator_loc, - .expression = expression - }; - - return node; -} - -/** - * Allocate and initialize a new StatementsNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param body The body field. - * @return The newly allocated and initialized node. - */ -static inline pm_statements_node_t * -pm_statements_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_node_list_t body) { - pm_statements_node_t *node = (pm_statements_node_t *) pm_arena_alloc(arena, sizeof(pm_statements_node_t), PRISM_ALIGNOF(pm_statements_node_t)); - - *node = (pm_statements_node_t) { - .base = { .type = PM_STATEMENTS_NODE, .flags = flags, .node_id = node_id, .location = location }, - .body = body - }; - - return node; -} - -/** - * Allocate and initialize a new StringNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param opening_loc The opening_loc field. - * @param content_loc The content_loc field. - * @param closing_loc The closing_loc field. - * @param unescaped The unescaped field. - * @return The newly allocated and initialized node. - */ -static inline pm_string_node_t * -pm_string_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_location_t opening_loc, pm_location_t content_loc, pm_location_t closing_loc, pm_string_t unescaped) { - pm_string_node_t *node = (pm_string_node_t *) pm_arena_alloc(arena, sizeof(pm_string_node_t), PRISM_ALIGNOF(pm_string_node_t)); - - *node = (pm_string_node_t) { - .base = { .type = PM_STRING_NODE, .flags = flags, .node_id = node_id, .location = location }, - .opening_loc = opening_loc, - .content_loc = content_loc, - .closing_loc = closing_loc, - .unescaped = unescaped - }; - - return node; -} - -/** - * Allocate and initialize a new SuperNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param keyword_loc The keyword_loc field. - * @param lparen_loc The lparen_loc field. - * @param arguments Can be only \`nil\` when there are empty parentheses, like \`super()\`\. - * @param rparen_loc The rparen_loc field. - * @param block The block field. - * @return The newly allocated and initialized node. - */ -static inline pm_super_node_t * -pm_super_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_location_t keyword_loc, pm_location_t lparen_loc, struct pm_arguments_node *arguments, pm_location_t rparen_loc, struct pm_node *block) { - pm_super_node_t *node = (pm_super_node_t *) pm_arena_alloc(arena, sizeof(pm_super_node_t), PRISM_ALIGNOF(pm_super_node_t)); - - *node = (pm_super_node_t) { - .base = { .type = PM_SUPER_NODE, .flags = flags, .node_id = node_id, .location = location }, - .keyword_loc = keyword_loc, - .lparen_loc = lparen_loc, - .arguments = arguments, - .rparen_loc = rparen_loc, - .block = block - }; - - return node; -} - -/** - * Allocate and initialize a new SymbolNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param opening_loc The opening_loc field. - * @param value_loc The value_loc field. - * @param closing_loc The closing_loc field. - * @param unescaped The unescaped field. - * @return The newly allocated and initialized node. - */ -static inline pm_symbol_node_t * -pm_symbol_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_location_t opening_loc, pm_location_t value_loc, pm_location_t closing_loc, pm_string_t unescaped) { - pm_symbol_node_t *node = (pm_symbol_node_t *) pm_arena_alloc(arena, sizeof(pm_symbol_node_t), PRISM_ALIGNOF(pm_symbol_node_t)); - - *node = (pm_symbol_node_t) { - .base = { .type = PM_SYMBOL_NODE, .flags = flags, .node_id = node_id, .location = location }, - .opening_loc = opening_loc, - .value_loc = value_loc, - .closing_loc = closing_loc, - .unescaped = unescaped - }; - - return node; -} - -/** - * Allocate and initialize a new TrueNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @return The newly allocated and initialized node. - */ -static inline pm_true_node_t * -pm_true_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location) { - pm_true_node_t *node = (pm_true_node_t *) pm_arena_alloc(arena, sizeof(pm_true_node_t), PRISM_ALIGNOF(pm_true_node_t)); - - *node = (pm_true_node_t) { - .base = { .type = PM_TRUE_NODE, .flags = flags, .node_id = node_id, .location = location } - }; - - return node; -} - -/** - * Allocate and initialize a new UndefNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param names The names field. - * @param keyword_loc The keyword_loc field. - * @return The newly allocated and initialized node. - */ -static inline pm_undef_node_t * -pm_undef_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_node_list_t names, pm_location_t keyword_loc) { - pm_undef_node_t *node = (pm_undef_node_t *) pm_arena_alloc(arena, sizeof(pm_undef_node_t), PRISM_ALIGNOF(pm_undef_node_t)); - - *node = (pm_undef_node_t) { - .base = { .type = PM_UNDEF_NODE, .flags = flags, .node_id = node_id, .location = location }, - .names = names, - .keyword_loc = keyword_loc - }; - - return node; -} - -/** - * Allocate and initialize a new UnlessNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param keyword_loc The Location of the \`unless\` keyword\. - * @param predicate The condition to be evaluated for the unless expression\. It can be any [non\-void expression](https://github\.com/ruby/prism/blob/main/docs/parsing\_rules\.md\#non\-void\-expression)\. - * @param then_keyword_loc The Location of the \`then\` keyword, if present\. - * @param statements The body of statements that will executed if the unless condition is - * @param else_clause The else clause of the unless expression, if present\. - * @param end_keyword_loc The Location of the \`end\` keyword, if present\. - * @return The newly allocated and initialized node. - */ -static inline pm_unless_node_t * -pm_unless_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_location_t keyword_loc, struct pm_node *predicate, pm_location_t then_keyword_loc, struct pm_statements_node *statements, struct pm_else_node *else_clause, pm_location_t end_keyword_loc) { - pm_unless_node_t *node = (pm_unless_node_t *) pm_arena_alloc(arena, sizeof(pm_unless_node_t), PRISM_ALIGNOF(pm_unless_node_t)); - - *node = (pm_unless_node_t) { - .base = { .type = PM_UNLESS_NODE, .flags = flags, .node_id = node_id, .location = location }, - .keyword_loc = keyword_loc, - .predicate = predicate, - .then_keyword_loc = then_keyword_loc, - .statements = statements, - .else_clause = else_clause, - .end_keyword_loc = end_keyword_loc - }; - - return node; -} - -/** - * Allocate and initialize a new UntilNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param keyword_loc The keyword_loc field. - * @param do_keyword_loc The do_keyword_loc field. - * @param closing_loc The closing_loc field. - * @param predicate The predicate field. - * @param statements The statements field. - * @return The newly allocated and initialized node. - */ -static inline pm_until_node_t * -pm_until_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_location_t keyword_loc, pm_location_t do_keyword_loc, pm_location_t closing_loc, struct pm_node *predicate, struct pm_statements_node *statements) { - pm_until_node_t *node = (pm_until_node_t *) pm_arena_alloc(arena, sizeof(pm_until_node_t), PRISM_ALIGNOF(pm_until_node_t)); - - *node = (pm_until_node_t) { - .base = { .type = PM_UNTIL_NODE, .flags = flags, .node_id = node_id, .location = location }, - .keyword_loc = keyword_loc, - .do_keyword_loc = do_keyword_loc, - .closing_loc = closing_loc, - .predicate = predicate, - .statements = statements - }; - - return node; -} - -/** - * Allocate and initialize a new WhenNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param keyword_loc The keyword_loc field. - * @param conditions The conditions field. - * @param then_keyword_loc The then_keyword_loc field. - * @param statements The statements field. - * @return The newly allocated and initialized node. - */ -static inline pm_when_node_t * -pm_when_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_location_t keyword_loc, pm_node_list_t conditions, pm_location_t then_keyword_loc, struct pm_statements_node *statements) { - pm_when_node_t *node = (pm_when_node_t *) pm_arena_alloc(arena, sizeof(pm_when_node_t), PRISM_ALIGNOF(pm_when_node_t)); - - *node = (pm_when_node_t) { - .base = { .type = PM_WHEN_NODE, .flags = flags, .node_id = node_id, .location = location }, - .keyword_loc = keyword_loc, - .conditions = conditions, - .then_keyword_loc = then_keyword_loc, - .statements = statements - }; - - return node; -} - -/** - * Allocate and initialize a new WhileNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param keyword_loc The keyword_loc field. - * @param do_keyword_loc The do_keyword_loc field. - * @param closing_loc The closing_loc field. - * @param predicate The predicate field. - * @param statements The statements field. - * @return The newly allocated and initialized node. - */ -static inline pm_while_node_t * -pm_while_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_location_t keyword_loc, pm_location_t do_keyword_loc, pm_location_t closing_loc, struct pm_node *predicate, struct pm_statements_node *statements) { - pm_while_node_t *node = (pm_while_node_t *) pm_arena_alloc(arena, sizeof(pm_while_node_t), PRISM_ALIGNOF(pm_while_node_t)); - - *node = (pm_while_node_t) { - .base = { .type = PM_WHILE_NODE, .flags = flags, .node_id = node_id, .location = location }, - .keyword_loc = keyword_loc, - .do_keyword_loc = do_keyword_loc, - .closing_loc = closing_loc, - .predicate = predicate, - .statements = statements - }; - - return node; -} - -/** - * Allocate and initialize a new XStringNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param opening_loc The opening_loc field. - * @param content_loc The content_loc field. - * @param closing_loc The closing_loc field. - * @param unescaped The unescaped field. - * @return The newly allocated and initialized node. - */ -static inline pm_x_string_node_t * -pm_x_string_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_location_t opening_loc, pm_location_t content_loc, pm_location_t closing_loc, pm_string_t unescaped) { - pm_x_string_node_t *node = (pm_x_string_node_t *) pm_arena_alloc(arena, sizeof(pm_x_string_node_t), PRISM_ALIGNOF(pm_x_string_node_t)); - - *node = (pm_x_string_node_t) { - .base = { .type = PM_X_STRING_NODE, .flags = flags, .node_id = node_id, .location = location }, - .opening_loc = opening_loc, - .content_loc = content_loc, - .closing_loc = closing_loc, - .unescaped = unescaped - }; - - return node; -} - -/** - * Allocate and initialize a new YieldNode node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. - * @param keyword_loc The keyword_loc field. - * @param lparen_loc The lparen_loc field. - * @param arguments The arguments field. - * @param rparen_loc The rparen_loc field. - * @return The newly allocated and initialized node. - */ -static inline pm_yield_node_t * -pm_yield_node_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location, pm_location_t keyword_loc, pm_location_t lparen_loc, struct pm_arguments_node *arguments, pm_location_t rparen_loc) { - pm_yield_node_t *node = (pm_yield_node_t *) pm_arena_alloc(arena, sizeof(pm_yield_node_t), PRISM_ALIGNOF(pm_yield_node_t)); - - *node = (pm_yield_node_t) { - .base = { .type = PM_YIELD_NODE, .flags = flags, .node_id = node_id, .location = location }, - .keyword_loc = keyword_loc, - .lparen_loc = lparen_loc, - .arguments = arguments, - .rparen_loc = rparen_loc - }; - - return node; -} - -#endif diff --git a/prism/options.c b/prism/options.c index 961d52330f8e35..b589865a2aa253 100644 --- a/prism/options.c +++ b/prism/options.c @@ -1,18 +1,78 @@ -#include "prism/options.h" +#include "prism/internal/options.h" + +#include "prism/compiler/inline.h" + +#include "prism/internal/allocator.h" +#include "prism/internal/char.h" +#include "prism/internal/stringy.h" + +#include +#include + +/** + * Allocate a new options struct. If the options struct cannot be allocated, + * this function aborts the process. + */ +pm_options_t * +pm_options_new(void) { + pm_options_t *options = xcalloc(1, sizeof(pm_options_t)); + if (options == NULL) abort(); + return options; +} + +/** + * Free the internal memory associated with the options. + */ +void +pm_options_cleanup(pm_options_t *options) { + pm_string_cleanup(&options->filepath); + pm_string_cleanup(&options->encoding); + + for (size_t scope_index = 0; scope_index < options->scopes_count; scope_index++) { + pm_options_scope_t *scope = &options->scopes[scope_index]; + + for (size_t local_index = 0; local_index < scope->locals_count; local_index++) { + pm_string_cleanup(&scope->locals[local_index]); + } + + xfree_sized(scope->locals, scope->locals_count * sizeof(pm_string_t)); + } + + xfree_sized(options->scopes, options->scopes_count * sizeof(pm_options_scope_t)); +} + +/** + * Free both the held memory of the given options struct and the struct itself. + * + * @param options The options struct to free. + */ +void +pm_options_free(pm_options_t *options) { + pm_options_cleanup(options); + xfree_sized(options, sizeof(pm_options_t)); +} /** * Set the shebang callback option on the given options struct. */ -PRISM_EXPORTED_FUNCTION void +void pm_options_shebang_callback_set(pm_options_t *options, pm_options_shebang_callback_t shebang_callback, void *shebang_callback_data) { options->shebang_callback = shebang_callback; options->shebang_callback_data = shebang_callback_data; } +/** + * Get the filepath option on the given options struct. + */ +const pm_string_t * +pm_options_filepath(const pm_options_t *options) { + return &options->filepath; +} + /** * Set the filepath option on the given options struct. */ -PRISM_EXPORTED_FUNCTION void +void pm_options_filepath_set(pm_options_t *options, const char *filepath) { pm_string_constant_init(&options->filepath, filepath, strlen(filepath)); } @@ -20,7 +80,7 @@ pm_options_filepath_set(pm_options_t *options, const char *filepath) { /** * Set the encoding option on the given options struct. */ -PRISM_EXPORTED_FUNCTION void +void pm_options_encoding_set(pm_options_t *options, const char *encoding) { pm_string_constant_init(&options->encoding, encoding, strlen(encoding)); } @@ -28,7 +88,7 @@ pm_options_encoding_set(pm_options_t *options, const char *encoding) { /** * Set the encoding_locked option on the given options struct. */ -PRISM_EXPORTED_FUNCTION void +void pm_options_encoding_locked_set(pm_options_t *options, bool encoding_locked) { options->encoding_locked = encoding_locked; } @@ -36,7 +96,7 @@ pm_options_encoding_locked_set(pm_options_t *options, bool encoding_locked) { /** * Set the line option on the given options struct. */ -PRISM_EXPORTED_FUNCTION void +void pm_options_line_set(pm_options_t *options, int32_t line) { options->line = line; } @@ -44,7 +104,7 @@ pm_options_line_set(pm_options_t *options, int32_t line) { /** * Set the frozen string literal option on the given options struct. */ -PRISM_EXPORTED_FUNCTION void +void pm_options_frozen_string_literal_set(pm_options_t *options, bool frozen_string_literal) { options->frozen_string_literal = frozen_string_literal ? PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED : PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED; } @@ -52,7 +112,7 @@ pm_options_frozen_string_literal_set(pm_options_t *options, bool frozen_string_l /** * Sets the command line option on the given options struct. */ -PRISM_EXPORTED_FUNCTION void +void pm_options_command_line_set(pm_options_t *options, uint8_t command_line) { options->command_line = command_line; } @@ -60,7 +120,7 @@ pm_options_command_line_set(pm_options_t *options, uint8_t command_line) { /** * Checks if the given slice represents a number. */ -static inline bool +static PRISM_INLINE bool is_number(const char *string, size_t length) { return pm_strspn_decimal_digit((const uint8_t *) string, (ptrdiff_t) length) == length; } @@ -70,7 +130,7 @@ is_number(const char *string, size_t length) { * string. If the string contains an invalid option, this returns false. * Otherwise, it returns true. */ -PRISM_EXPORTED_FUNCTION bool +bool pm_options_version_set(pm_options_t *options, const char *version, size_t length) { if (version == NULL) { options->version = PM_OPTIONS_VERSION_LATEST; @@ -123,8 +183,8 @@ pm_options_version_set(pm_options_t *options, const char *version, size_t length } } - if (length >= 6) { - if (strncmp(version, "latest", 7) == 0) { // 7 to compare the \0 as well + if (length == 6) { + if (strncmp(version, "latest", 6) == 0) { options->version = PM_OPTIONS_VERSION_LATEST; return true; } @@ -133,10 +193,28 @@ pm_options_version_set(pm_options_t *options, const char *version, size_t length return false; } +/** + * Set the version option on the given options struct to the lowest version of + * Ruby that prism supports. + */ +void +pm_options_version_set_lowest(pm_options_t *options) { + options->version = PM_OPTIONS_VERSION_CRUBY_3_3; +} + +/** + * Set the version option on the given options struct to the highest version of + * Ruby that prism supports. + */ +void +pm_options_version_set_highest(pm_options_t *options) { + options->version = PM_OPTIONS_VERSION_LATEST; +} + /** * Set the main script option on the given options struct. */ -PRISM_EXPORTED_FUNCTION void +void pm_options_main_script_set(pm_options_t *options, bool main_script) { options->main_script = main_script; } @@ -144,15 +222,23 @@ pm_options_main_script_set(pm_options_t *options, bool main_script) { /** * Set the partial script option on the given options struct. */ -PRISM_EXPORTED_FUNCTION void +void pm_options_partial_script_set(pm_options_t *options, bool partial_script) { options->partial_script = partial_script; } +/** + * Get the freeze option on the given options struct. + */ +bool +pm_options_freeze(const pm_options_t *options) { + return options->freeze; +} + /** * Set the freeze option on the given options struct. */ -PRISM_EXPORTED_FUNCTION void +void pm_options_freeze_set(pm_options_t *options, bool freeze) { options->freeze = freeze; } @@ -168,7 +254,7 @@ pm_options_freeze_set(pm_options_t *options, bool freeze) { /** * Allocate and zero out the scopes array on the given options struct. */ -PRISM_EXPORTED_FUNCTION bool +bool pm_options_scopes_init(pm_options_t *options, size_t scopes_count) { options->scopes_count = scopes_count; options->scopes = xcalloc(scopes_count, sizeof(pm_options_scope_t)); @@ -176,10 +262,20 @@ pm_options_scopes_init(pm_options_t *options, size_t scopes_count) { } /** - * Return a pointer to the scope at the given index within the given options. + * Return a constant pointer to the scope at the given index within the given + * options. */ -PRISM_EXPORTED_FUNCTION const pm_options_scope_t * -pm_options_scope_get(const pm_options_t *options, size_t index) { +const pm_options_scope_t * +pm_options_scope(const pm_options_t *options, size_t index) { + return &options->scopes[index]; +} + +/** + * Return a mutable pointer to the scope at the given index within the given + * options. + */ +pm_options_scope_t * +pm_options_scope_mut(pm_options_t *options, size_t index) { return &options->scopes[index]; } @@ -187,49 +283,38 @@ pm_options_scope_get(const pm_options_t *options, size_t index) { * Create a new options scope struct. This will hold a set of locals that are in * scope surrounding the code that is being parsed. */ -PRISM_EXPORTED_FUNCTION bool +void pm_options_scope_init(pm_options_scope_t *scope, size_t locals_count) { scope->locals_count = locals_count; scope->locals = xcalloc(locals_count, sizeof(pm_string_t)); scope->forwarding = PM_OPTIONS_SCOPE_FORWARDING_NONE; - return scope->locals != NULL; + if (scope->locals == NULL) abort(); } /** - * Return a pointer to the local at the given index within the given scope. + * Return a constant pointer to the local at the given index within the given + * scope. */ -PRISM_EXPORTED_FUNCTION const pm_string_t * -pm_options_scope_local_get(const pm_options_scope_t *scope, size_t index) { +const pm_string_t * +pm_options_scope_local(const pm_options_scope_t *scope, size_t index) { return &scope->locals[index]; } /** - * Set the forwarding option on the given scope struct. + * Return a mutable pointer to the local at the given index within the given + * scope. */ -PRISM_EXPORTED_FUNCTION void -pm_options_scope_forwarding_set(pm_options_scope_t *scope, uint8_t forwarding) { - scope->forwarding = forwarding; +pm_string_t * +pm_options_scope_local_mut(pm_options_scope_t *scope, size_t index) { + return &scope->locals[index]; } /** - * Free the internal memory associated with the options. + * Set the forwarding option on the given scope struct. */ -PRISM_EXPORTED_FUNCTION void -pm_options_free(pm_options_t *options) { - pm_string_free(&options->filepath); - pm_string_free(&options->encoding); - - for (size_t scope_index = 0; scope_index < options->scopes_count; scope_index++) { - pm_options_scope_t *scope = &options->scopes[scope_index]; - - for (size_t local_index = 0; local_index < scope->locals_count; local_index++) { - pm_string_free(&scope->locals[local_index]); - } - - xfree_sized(scope->locals, scope->locals_count * sizeof(pm_string_t)); - } - - xfree_sized(options->scopes, options->scopes_count * sizeof(pm_options_scope_t)); +void +pm_options_scope_forwarding_set(pm_options_scope_t *scope, uint8_t forwarding) { + scope->forwarding = forwarding; } /** @@ -314,10 +399,7 @@ pm_options_read(pm_options_t *options, const char *data) { data += 4; pm_options_scope_t *scope = &options->scopes[scope_index]; - if (!pm_options_scope_init(scope, locals_count)) { - pm_options_free(options); - return; - } + pm_options_scope_init(scope, locals_count); uint8_t forwarding = (uint8_t) *data++; pm_options_scope_forwarding_set(&options->scopes[scope_index], forwarding); diff --git a/prism/options.h b/prism/options.h index 9a19a2aeadf31a..1b6ff4af1fe2d9 100644 --- a/prism/options.h +++ b/prism/options.h @@ -6,16 +6,27 @@ #ifndef PRISM_OPTIONS_H #define PRISM_OPTIONS_H -#include "prism/defines.h" -#include "prism/util/pm_char.h" -#include "prism/util/pm_string.h" +#include "prism/compiler/exported.h" +#include "prism/compiler/nodiscard.h" +#include "prism/compiler/nonnull.h" + +#include "prism/stringy.h" #include #include -#include /** - * String literals should be made frozen. + * A scope of locals surrounding the code that is being parsed. + */ +typedef struct pm_options_scope_t pm_options_scope_t; + +/** + * The options that can be passed to the parser. + */ +typedef struct pm_options_t pm_options_t; + +/** + * String literals should not be frozen. */ #define PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED ((int8_t) -1) @@ -26,42 +37,25 @@ #define PM_OPTIONS_FROZEN_STRING_LITERAL_UNSET ((int8_t) 0) /** - * String literals should be made mutable. + * String literals should be made frozen. */ #define PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED ((int8_t) 1) -/** - * A scope of locals surrounding the code that is being parsed. - */ -typedef struct pm_options_scope { - /** The number of locals in the scope. */ - size_t locals_count; - - /** The names of the locals in the scope. */ - pm_string_t *locals; - - /** Flags for the set of forwarding parameters in this scope. */ - uint8_t forwarding; -} pm_options_scope_t; - /** The default value for parameters. */ static const uint8_t PM_OPTIONS_SCOPE_FORWARDING_NONE = 0x0; -/** When the scope is fowarding with the * parameter. */ +/** When the scope is forwarding with the * parameter. */ static const uint8_t PM_OPTIONS_SCOPE_FORWARDING_POSITIONALS = 0x1; -/** When the scope is fowarding with the ** parameter. */ +/** When the scope is forwarding with the ** parameter. */ static const uint8_t PM_OPTIONS_SCOPE_FORWARDING_KEYWORDS = 0x2; -/** When the scope is fowarding with the & parameter. */ +/** When the scope is forwarding with the & parameter. */ static const uint8_t PM_OPTIONS_SCOPE_FORWARDING_BLOCK = 0x4; -/** When the scope is fowarding with the ... parameter. */ +/** When the scope is forwarding with the ... parameter. */ static const uint8_t PM_OPTIONS_SCOPE_FORWARDING_ALL = 0x8; -// Forward declaration needed by the callback typedef. -struct pm_options; - /** * The callback called when additional switches are found in a shebang comment * that need to be processed by the runtime. @@ -74,133 +68,7 @@ struct pm_options; * @param shebang_callback_data Any additional data that should be passed along * to the callback. */ -typedef void (*pm_options_shebang_callback_t)(struct pm_options *options, const uint8_t *source, size_t length, void *shebang_callback_data); - -/** - * The version of Ruby syntax that we should be parsing with. This is used to - * allow consumers to specify which behavior they want in case they need to - * parse in the same way as a specific version of CRuby would have. - */ -typedef enum { - /** - * If an explicit version is not provided, the current version of prism will - * be used. - */ - PM_OPTIONS_VERSION_UNSET = 0, - - /** The vendored version of prism in CRuby 3.3.x. */ - PM_OPTIONS_VERSION_CRUBY_3_3 = 1, - - /** The vendored version of prism in CRuby 3.4.x. */ - PM_OPTIONS_VERSION_CRUBY_3_4 = 2, - - /** The vendored version of prism in CRuby 4.0.x. */ - PM_OPTIONS_VERSION_CRUBY_3_5 = 3, - - /** The vendored version of prism in CRuby 4.0.x. */ - PM_OPTIONS_VERSION_CRUBY_4_0 = 3, - - /** The vendored version of prism in CRuby 4.1.x. */ - PM_OPTIONS_VERSION_CRUBY_4_1 = 4, - - /** The current version of prism. */ - PM_OPTIONS_VERSION_LATEST = PM_OPTIONS_VERSION_CRUBY_4_1 -} pm_options_version_t; - -/** - * The options that can be passed to the parser. - */ -typedef struct pm_options { - /** - * The callback to call when additional switches are found in a shebang - * comment. - */ - pm_options_shebang_callback_t shebang_callback; - - /** - * Any additional data that should be passed along to the shebang callback - * if one was set. - */ - void *shebang_callback_data; - - /** The name of the file that is currently being parsed. */ - pm_string_t filepath; - - /** - * The line within the file that the parse starts on. This value is - * 1-indexed. - */ - int32_t line; - - /** - * The name of the encoding that the source file is in. Note that this must - * correspond to a name that can be found with Encoding.find in Ruby. - */ - pm_string_t encoding; - - /** - * The number of scopes surrounding the code that is being parsed. - */ - size_t scopes_count; - - /** - * The scopes surrounding the code that is being parsed. For most parses - * this will be NULL, but for evals it will be the locals that are in scope - * surrounding the eval. Scopes are ordered from the outermost scope to the - * innermost one. - */ - pm_options_scope_t *scopes; - - /** - * The version of prism that we should be parsing with. This is used to - * allow consumers to specify which behavior they want in case they need to - * parse exactly as a specific version of CRuby. - */ - pm_options_version_t version; - - /** A bitset of the various options that were set on the command line. */ - uint8_t command_line; - - /** - * Whether or not the frozen string literal option has been set. - * May be: - * - PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED - * - PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED - * - PM_OPTIONS_FROZEN_STRING_LITERAL_UNSET - */ - int8_t frozen_string_literal; - - /** - * Whether or not the encoding magic comments should be respected. This is a - * niche use-case where you want to parse a file with a specific encoding - * but ignore any encoding magic comments at the top of the file. - */ - bool encoding_locked; - - /** - * When the file being parsed is the main script, the shebang will be - * considered for command-line flags (or for implicit -x). The caller needs - * to pass this information to the parser so that it can behave correctly. - */ - bool main_script; - - /** - * When the file being parsed is considered a "partial" script, jumps will - * not be marked as errors if they are not contained within loops/blocks. - * This is used in the case that you're parsing a script that you know will - * be embedded inside another script later, but you do not have that context - * yet. For example, when parsing an ERB template that will be evaluated - * inside another script. - */ - bool partial_script; - - /** - * Whether or not the parser should freeze the nodes that it creates. This - * makes it possible to have a deeply frozen AST that is safe to share - * between concurrency primitives. - */ - bool freeze; -} pm_options_t; +typedef void (*pm_options_shebang_callback_t)(pm_options_t *options, const uint8_t *source, size_t length, void *shebang_callback_data); /** * A bit representing whether or not the command line -a option was set. -a @@ -239,6 +107,22 @@ static const uint8_t PM_OPTIONS_COMMAND_LINE_P = 0x10; */ static const uint8_t PM_OPTIONS_COMMAND_LINE_X = 0x20; +/** + * Allocate a new options struct. If the options struct cannot be allocated, + * this function aborts the process. + * + * @returns A new options struct with default values. It is the responsibility + * of the caller to free this struct using pm_options_free(). + */ +PRISM_EXPORTED_FUNCTION PRISM_NODISCARD pm_options_t * pm_options_new(void); + +/** + * Free both the held memory of the given options struct and the struct itself. + * + * @param options The options struct to free. + */ +PRISM_EXPORTED_FUNCTION void pm_options_free(pm_options_t *options) PRISM_NONNULL(1); + /** * Set the shebang callback option on the given options struct. * @@ -246,70 +130,64 @@ static const uint8_t PM_OPTIONS_COMMAND_LINE_X = 0x20; * @param shebang_callback The shebang callback to set. * @param shebang_callback_data Any additional data that should be passed along * to the callback. + */ +PRISM_EXPORTED_FUNCTION void pm_options_shebang_callback_set(pm_options_t *options, pm_options_shebang_callback_t shebang_callback, void *shebang_callback_data) PRISM_NONNULL(1); + +/** + * Get the filepath option on the given options struct. * - * \public \memberof pm_options + * @param options The options struct to get the filepath from. + * @returns The filepath. */ -PRISM_EXPORTED_FUNCTION void pm_options_shebang_callback_set(pm_options_t *options, pm_options_shebang_callback_t shebang_callback, void *shebang_callback_data); +PRISM_EXPORTED_FUNCTION const pm_string_t * pm_options_filepath(const pm_options_t *options) PRISM_NONNULL(1); /** * Set the filepath option on the given options struct. * * @param options The options struct to set the filepath on. * @param filepath The filepath to set. - * - * \public \memberof pm_options */ -PRISM_EXPORTED_FUNCTION void pm_options_filepath_set(pm_options_t *options, const char *filepath); +PRISM_EXPORTED_FUNCTION void pm_options_filepath_set(pm_options_t *options, const char *filepath) PRISM_NONNULL(1); /** * Set the line option on the given options struct. * * @param options The options struct to set the line on. * @param line The line to set. - * - * \public \memberof pm_options */ -PRISM_EXPORTED_FUNCTION void pm_options_line_set(pm_options_t *options, int32_t line); +PRISM_EXPORTED_FUNCTION void pm_options_line_set(pm_options_t *options, int32_t line) PRISM_NONNULL(1); /** * Set the encoding option on the given options struct. * * @param options The options struct to set the encoding on. * @param encoding The encoding to set. - * - * \public \memberof pm_options */ -PRISM_EXPORTED_FUNCTION void pm_options_encoding_set(pm_options_t *options, const char *encoding); +PRISM_EXPORTED_FUNCTION void pm_options_encoding_set(pm_options_t *options, const char *encoding) PRISM_NONNULL(1); /** * Set the encoding_locked option on the given options struct. * * @param options The options struct to set the encoding_locked value on. * @param encoding_locked The encoding_locked value to set. - * - * \public \memberof pm_options */ -PRISM_EXPORTED_FUNCTION void pm_options_encoding_locked_set(pm_options_t *options, bool encoding_locked); +PRISM_EXPORTED_FUNCTION void pm_options_encoding_locked_set(pm_options_t *options, bool encoding_locked) PRISM_NONNULL(1); /** * Set the frozen string literal option on the given options struct. * * @param options The options struct to set the frozen string literal value on. * @param frozen_string_literal The frozen string literal value to set. - * - * \public \memberof pm_options */ -PRISM_EXPORTED_FUNCTION void pm_options_frozen_string_literal_set(pm_options_t *options, bool frozen_string_literal); +PRISM_EXPORTED_FUNCTION void pm_options_frozen_string_literal_set(pm_options_t *options, bool frozen_string_literal) PRISM_NONNULL(1); /** * Sets the command line option on the given options struct. * * @param options The options struct to set the command line option on. * @param command_line The command_line value to set. - * - * \public \memberof pm_options */ -PRISM_EXPORTED_FUNCTION void pm_options_command_line_set(pm_options_t *options, uint8_t command_line); +PRISM_EXPORTED_FUNCTION void pm_options_command_line_set(pm_options_t *options, uint8_t command_line) PRISM_NONNULL(1); /** * Set the version option on the given options struct by parsing the given @@ -319,176 +197,123 @@ PRISM_EXPORTED_FUNCTION void pm_options_command_line_set(pm_options_t *options, * @param options The options struct to set the version on. * @param version The version to set. * @param length The length of the version string. - * @return Whether or not the version was parsed successfully. + * @returns Whether or not the version was parsed successfully. + */ +PRISM_EXPORTED_FUNCTION bool pm_options_version_set(pm_options_t *options, const char *version, size_t length) PRISM_NONNULL(1); + +/** + * Set the version option on the given options struct to the lowest version of + * Ruby that prism supports. + * + * @param options The options struct to set the version on. + */ +PRISM_EXPORTED_FUNCTION void pm_options_version_set_lowest(pm_options_t *options) PRISM_NONNULL(1); + +/** + * Set the version option on the given options struct to the highest version of + * Ruby that prism supports. * - * \public \memberof pm_options + * @param options The options struct to set the version on. */ -PRISM_EXPORTED_FUNCTION bool pm_options_version_set(pm_options_t *options, const char *version, size_t length); +PRISM_EXPORTED_FUNCTION void pm_options_version_set_highest(pm_options_t *options) PRISM_NONNULL(1); /** * Set the main script option on the given options struct. * * @param options The options struct to set the main script value on. * @param main_script The main script value to set. - * - * \public \memberof pm_options */ -PRISM_EXPORTED_FUNCTION void pm_options_main_script_set(pm_options_t *options, bool main_script); +PRISM_EXPORTED_FUNCTION void pm_options_main_script_set(pm_options_t *options, bool main_script) PRISM_NONNULL(1); /** * Set the partial script option on the given options struct. * * @param options The options struct to set the partial script value on. * @param partial_script The partial script value to set. + */ +PRISM_EXPORTED_FUNCTION void pm_options_partial_script_set(pm_options_t *options, bool partial_script) PRISM_NONNULL(1); + +/** + * Get the freeze option on the given options struct. * - * \public \memberof pm_options + * @param options The options struct to get the freeze value from. + * @returns The freeze value. */ -PRISM_EXPORTED_FUNCTION void pm_options_partial_script_set(pm_options_t *options, bool partial_script); +PRISM_EXPORTED_FUNCTION bool pm_options_freeze(const pm_options_t *options) PRISM_NONNULL(1); /** * Set the freeze option on the given options struct. * * @param options The options struct to set the freeze value on. * @param freeze The freeze value to set. - * - * \public \memberof pm_options */ -PRISM_EXPORTED_FUNCTION void pm_options_freeze_set(pm_options_t *options, bool freeze); +PRISM_EXPORTED_FUNCTION void pm_options_freeze_set(pm_options_t *options, bool freeze) PRISM_NONNULL(1); /** * Allocate and zero out the scopes array on the given options struct. * * @param options The options struct to initialize the scopes array on. * @param scopes_count The number of scopes to allocate. - * @return Whether or not the scopes array was initialized successfully. - * - * \public \memberof pm_options + * @returns Whether or not the scopes array was initialized successfully. */ -PRISM_EXPORTED_FUNCTION bool pm_options_scopes_init(pm_options_t *options, size_t scopes_count); +PRISM_EXPORTED_FUNCTION bool pm_options_scopes_init(pm_options_t *options, size_t scopes_count) PRISM_NONNULL(1); /** - * Return a pointer to the scope at the given index within the given options. + * Return a constant pointer to the scope at the given index within the given + * options. * * @param options The options struct to get the scope from. * @param index The index of the scope to get. - * @return A pointer to the scope at the given index. + * @returns A constant pointer to the scope at the given index. + */ +PRISM_EXPORTED_FUNCTION const pm_options_scope_t * pm_options_scope(const pm_options_t *options, size_t index) PRISM_NONNULL(1); + +/** + * Return a mutable pointer to the scope at the given index within the given + * options. * - * \public \memberof pm_options + * @param options The options struct to get the scope from. + * @param index The index of the scope to get. + * @returns A mutable pointer to the scope at the given index. */ -PRISM_EXPORTED_FUNCTION const pm_options_scope_t * pm_options_scope_get(const pm_options_t *options, size_t index); +PRISM_EXPORTED_FUNCTION pm_options_scope_t * pm_options_scope_mut(pm_options_t *options, size_t index) PRISM_NONNULL(1); /** * Create a new options scope struct. This will hold a set of locals that are in - * scope surrounding the code that is being parsed. + * scope surrounding the code that is being parsed. If the scope was unable to + * allocate its locals, this function will abort the process. * * @param scope The scope struct to initialize. * @param locals_count The number of locals to allocate. - * @return Whether or not the scope was initialized successfully. - * - * \public \memberof pm_options */ -PRISM_EXPORTED_FUNCTION bool pm_options_scope_init(pm_options_scope_t *scope, size_t locals_count); +PRISM_EXPORTED_FUNCTION void pm_options_scope_init(pm_options_scope_t *scope, size_t locals_count) PRISM_NONNULL(1); /** - * Return a pointer to the local at the given index within the given scope. + * Return a constant pointer to the local at the given index within the given + * scope. * * @param scope The scope struct to get the local from. * @param index The index of the local to get. - * @return A pointer to the local at the given index. - * - * \public \memberof pm_options + * @returns A constant pointer to the local at the given index. */ -PRISM_EXPORTED_FUNCTION const pm_string_t * pm_options_scope_local_get(const pm_options_scope_t *scope, size_t index); +PRISM_EXPORTED_FUNCTION const pm_string_t * pm_options_scope_local(const pm_options_scope_t *scope, size_t index) PRISM_NONNULL(1); /** - * Set the forwarding option on the given scope struct. + * Return a mutable pointer to the local at the given index within the given + * scope. * - * @param scope The scope struct to set the forwarding on. - * @param forwarding The forwarding value to set. - * - * \public \memberof pm_options - */ -PRISM_EXPORTED_FUNCTION void pm_options_scope_forwarding_set(pm_options_scope_t *scope, uint8_t forwarding); - -/** - * Free the internal memory associated with the options. - * - * @param options The options struct whose internal memory should be freed. - * - * \public \memberof pm_options + * @param scope The scope struct to get the local from. + * @param index The index of the local to get. + * @returns A mutable pointer to the local at the given index. */ -PRISM_EXPORTED_FUNCTION void pm_options_free(pm_options_t *options); +PRISM_EXPORTED_FUNCTION pm_string_t * pm_options_scope_local_mut(pm_options_scope_t *scope, size_t index) PRISM_NONNULL(1); /** - * Deserialize an options struct from the given binary string. This is used to - * pass options to the parser from an FFI call so that consumers of the library - * from an FFI perspective don't have to worry about the structure of our - * options structs. Since the source of these calls will be from Ruby - * implementation internals we assume it is from a trusted source. - * - * `data` is assumed to be a valid pointer pointing to well-formed data. The - * layout of this data should be the same every time, and is described below: - * - * | # bytes | field | - * | ------- | -------------------------- | - * | `4` | the length of the filepath | - * | ... | the filepath bytes | - * | `4` | the line number | - * | `4` | the length the encoding | - * | ... | the encoding bytes | - * | `1` | frozen string literal | - * | `1` | -p command line option | - * | `1` | -n command line option | - * | `1` | -l command line option | - * | `1` | -a command line option | - * | `1` | the version | - * | `1` | encoding locked | - * | `1` | main script | - * | `1` | partial script | - * | `1` | freeze | - * | `4` | the number of scopes | - * | ... | the scopes | - * - * The version field is an enum, so it should be one of the following values: - * - * | value | version | - * | ----- | ------------------------- | - * | `0` | use the latest version of prism | - * | `1` | use the version of prism that is vendored in CRuby 3.3.0 | - * | `2` | use the version of prism that is vendored in CRuby 3.4.0 | - * | `3` | use the version of prism that is vendored in CRuby 4.0.0 | - * | `4` | use the version of prism that is vendored in CRuby 4.1.0 | - * - * Each scope is laid out as follows: - * - * | # bytes | field | - * | ------- | -------------------------- | - * | `4` | the number of locals | - * | `1` | the forwarding flags | - * | ... | the locals | - * - * Each local is laid out as follows: - * - * | # bytes | field | - * | ------- | -------------------------- | - * | `4` | the length of the local | - * | ... | the local bytes | - * - * Some additional things to note about this layout: - * - * * The filepath can have a length of 0, in which case we'll consider it an - * empty string. - * * The line number should be 0-indexed. - * * The encoding can have a length of 0, in which case we'll use the default - * encoding (UTF-8). If it's not 0, it should correspond to a name of an - * encoding that can be passed to `Encoding.find` in Ruby. - * * The frozen string literal, encoding locked, main script, and partial script - * fields are booleans, so their values should be either 0 or 1. - * * The number of scopes can be 0. + * Set the forwarding option on the given scope struct. * - * @param options The options struct to deserialize into. - * @param data The binary string to deserialize from. + * @param scope The scope struct to set the forwarding on. + * @param forwarding The forwarding value to set. */ -void pm_options_read(pm_options_t *options, const char *data); +PRISM_EXPORTED_FUNCTION void pm_options_scope_forwarding_set(pm_options_scope_t *scope, uint8_t forwarding) PRISM_NONNULL(1); #endif diff --git a/prism/parser.c b/prism/parser.c new file mode 100644 index 00000000000000..415cd3198499f4 --- /dev/null +++ b/prism/parser.c @@ -0,0 +1,302 @@ +#include "prism/internal/parser.h" + +#include "prism/internal/allocator.h" +#include "prism/internal/comments.h" +#include "prism/internal/diagnostic.h" +#include "prism/internal/encoding.h" +#include "prism/internal/magic_comments.h" + +#include + +/** + * Register a callback that will be called whenever prism changes the encoding + * it is using to parse based on the magic comment. + */ +void +pm_parser_encoding_changed_callback_set(pm_parser_t *parser, pm_encoding_changed_callback_t callback) { + parser->encoding_changed_callback = callback; +} + +/** + * Register a callback that will be called whenever a token is lexed. + */ +void +pm_parser_lex_callback_set(pm_parser_t *parser, pm_lex_callback_t callback, void *data) { + parser->lex_callback.callback = callback; + parser->lex_callback.data = data; +} + +/** + * Returns the opaque data that is passed to the lex callback when it is called. + */ +void * +pm_parser_lex_callback_data(const pm_parser_t *parser) { + return parser->lex_callback.data; +} + +/** + * Returns the raw pointer to the start of the source that is being parsed. + */ +const uint8_t * +pm_parser_start(const pm_parser_t *parser) { + return parser->start; +} + +/** + * Returns the raw pointer to the end of the source that is being parsed. + */ +const uint8_t * +pm_parser_end(const pm_parser_t *parser) { + return parser->end; +} + +/** + * Returns the line that the parser was considered to have started on. + * + * @param parser the parser whose start line we want to get + * @return the line that the parser was considered to have started on + */ +int32_t +pm_parser_start_line(const pm_parser_t *parser) { + return parser->start_line; +} + +/** + * Returns the name of the encoding that is being used to parse the source. + */ +const char * +pm_parser_encoding_name(const pm_parser_t *parser) { + return parser->encoding->name; +} + +/** + * Returns the width of the character at the given pointer in the encoding that + * is being used to parse the source. + */ +size_t +pm_parser_encoding_char_width(const pm_parser_t *parser, const uint8_t *start, ptrdiff_t remaining) { + return parser->encoding->char_width(start, remaining); +} + +/** + * Returns whether or not the parser is using the US-ASCII encoding. + */ +bool +pm_parser_encoding_us_ascii(const pm_parser_t *parser) { + return parser->encoding == PM_ENCODING_US_ASCII_ENTRY; +} + +/** + * Returns the filepath that is being used to parse the source. + */ +const pm_string_t * +pm_parser_filepath(const pm_parser_t *parser) { + return &parser->filepath; +} + +/** + * Find a constant in the parser's constant pool. Returns the id of the + * constant, or 0 if the constant is not found. + */ +pm_constant_id_t +pm_parser_constant_find(const pm_parser_t *parser, const uint8_t *start, size_t length) { + return pm_constant_pool_find(&parser->constant_pool, start, length); +} + +/** + * Returns the frozen string literal value of the parser. + */ +int8_t +pm_parser_frozen_string_literal(const pm_parser_t *parser) { + return parser->frozen_string_literal; +} + +/** + * Returns the line offsets that are associated with the given parser. + * + * @param parser the parser whose line offsets we want to get + * @return the line offsets that are associated with the given parser + */ +const pm_line_offset_list_t * +pm_parser_line_offsets(const pm_parser_t *parser) { + return &parser->line_offsets; +} + +/** + * Returns the location of the __DATA__ section that is associated with the + * given parser, if it exists. + */ +const pm_location_t * +pm_parser_data_loc(const pm_parser_t *parser) { + return &parser->data_loc; +} + +/** + * Returns whether the given parser is continuable, meaning that it could become + * valid if more input were appended, as opposed to being definitively invalid. + */ +bool +pm_parser_continuable(const pm_parser_t *parser) { + return parser->continuable; +} + +/** + * Returns the lex state of the parser. Note that this is an internal detail, + * and we are purposefully not returning an instance of the internal enum that + * we use to track this. This is only exposed because we need it for some very + * niche use cases. Most consumers should avoid this function. + */ +int +pm_parser_lex_state(const pm_parser_t *parser) { + return (int) parser->lex_state; +} + +/** + * Returns the location associated with the given comment. + */ +pm_location_t +pm_comment_location(const pm_comment_t *comment) { + return comment->location; +} + +/** + * Returns the type associated with the given comment. + */ +pm_comment_type_t +pm_comment_type(const pm_comment_t *comment) { + return comment->type; +} + +/** + * Returns the number of comments associated with the given parser. + */ +size_t +pm_parser_comments_size(const pm_parser_t *parser) { + return parser->comment_list.size; +} + +/** + * Iterates over the comments associated with the given parser and calls the + * given callback for each comment. + */ +void +pm_parser_comments_each(const pm_parser_t *parser, pm_comment_callback_t callback, void *data) { + const pm_list_node_t *current = parser->comment_list.head; + while (current != NULL) { + const pm_comment_t *comment = (const pm_comment_t *) current; + callback(comment, data); + current = current->next; + } +} + +/** + * Returns the location associated with the given magic comment key. + */ +pm_location_t +pm_magic_comment_key(const pm_magic_comment_t *magic_comment) { + return magic_comment->key; +} + +/** + * Returns the location associated with the given magic comment value. + */ +pm_location_t +pm_magic_comment_value(const pm_magic_comment_t *magic_comment) { + return magic_comment->value; +} + +/** + * Returns the number of magic comments associated with the given parser. + */ +size_t +pm_parser_magic_comments_size(const pm_parser_t *parser) { + return parser->magic_comment_list.size; +} + +/** + * Iterates over the magic comments associated with the given parser and calls + * the given callback for each magic comment. + */ +void +pm_parser_magic_comments_each(const pm_parser_t *parser, pm_magic_comment_callback_t callback, void *data) { + const pm_list_node_t *current = parser->magic_comment_list.head; + while (current != NULL) { + const pm_magic_comment_t *magic_comment = (const pm_magic_comment_t *) current; + callback(magic_comment, data); + current = current->next; + } +} + +/** + * Returns the number of errors associated with the given parser. + */ +size_t +pm_parser_errors_size(const pm_parser_t *parser) { + return parser->error_list.size; +} + +/** + * Returns the number of warnings associated with the given parser. + */ +size_t +pm_parser_warnings_size(const pm_parser_t *parser) { + return parser->warning_list.size; +} + +static inline void +pm_parser_diagnostics_each(const pm_list_t *list, pm_diagnostic_callback_t callback, void *data) { + const pm_list_node_t *current = list->head; + while (current != NULL) { + const pm_diagnostic_t *diagnostic = (const pm_diagnostic_t *) current; + callback(diagnostic, data); + current = current->next; + } +} + +/** + * Iterates over the errors associated with the given parser and calls the + * given callback for each error. + */ +void +pm_parser_errors_each(const pm_parser_t *parser, pm_diagnostic_callback_t callback, void *data) { + pm_parser_diagnostics_each(&parser->error_list, callback, data); +} + +/** + * Iterates over the warnings associated with the given parser and calls the + * given callback for each warning. + */ +void +pm_parser_warnings_each(const pm_parser_t *parser, pm_diagnostic_callback_t callback, void *data) { + pm_parser_diagnostics_each(&parser->warning_list, callback, data); +} + +/** + * Returns the number of constants in the constant pool associated with the + * given parser. + */ +size_t +pm_parser_constants_size(const pm_parser_t *parser) { + return parser->constant_pool.size; +} + +/** + * Iterates over the constants in the constant pool associated with the given + * parser and calls the given callback for each constant. + */ +void +pm_parser_constants_each(const pm_parser_t *parser, pm_constant_callback_t callback, void *data) { + for (uint32_t index = 0; index < parser->constant_pool.size; index++) { + const pm_constant_t *constant = &parser->constant_pool.constants[index]; + callback(constant, data); + } +} + +/** + * Returns a pointer to the constant at the given id in the constant pool + * associated with the given parser. + */ +const pm_constant_t * +pm_parser_constant(const pm_parser_t *parser, pm_constant_id_t constant_id) { + return pm_constant_pool_id_to_constant(&parser->constant_pool, constant_id); +} diff --git a/prism/parser.h b/prism/parser.h index 66df791244bcb4..2c8c4b3a7acdc0 100644 --- a/prism/parser.h +++ b/prism/parser.h @@ -6,990 +6,343 @@ #ifndef PRISM_PARSER_H #define PRISM_PARSER_H -#include "prism/defines.h" +#include "prism/compiler/nodiscard.h" +#include "prism/compiler/nonnull.h" + #include "prism/ast.h" -#include "prism/encoding.h" +#include "prism/comments.h" +#include "prism/diagnostic.h" +#include "prism/line_offset_list.h" +#include "prism/magic_comments.h" #include "prism/options.h" -#include "prism/static_literals.h" -#include "prism/util/pm_arena.h" -#include "prism/util/pm_constant_pool.h" -#include "prism/util/pm_list.h" -#include "prism/util/pm_line_offset_list.h" -#include "prism/util/pm_string.h" - -#include - -/** - * This enum provides various bits that represent different kinds of states that - * the lexer can track. This is used to determine which kind of token to return - * based on the context of the parser. - */ -typedef enum { - PM_LEX_STATE_BIT_BEG, - PM_LEX_STATE_BIT_END, - PM_LEX_STATE_BIT_ENDARG, - PM_LEX_STATE_BIT_ENDFN, - PM_LEX_STATE_BIT_ARG, - PM_LEX_STATE_BIT_CMDARG, - PM_LEX_STATE_BIT_MID, - PM_LEX_STATE_BIT_FNAME, - PM_LEX_STATE_BIT_DOT, - PM_LEX_STATE_BIT_CLASS, - PM_LEX_STATE_BIT_LABEL, - PM_LEX_STATE_BIT_LABELED, - PM_LEX_STATE_BIT_FITEM -} pm_lex_state_bit_t; - -/** - * This enum combines the various bits from the above enum into individual - * values that represent the various states of the lexer. - */ -typedef enum { - PM_LEX_STATE_NONE = 0, - PM_LEX_STATE_BEG = (1 << PM_LEX_STATE_BIT_BEG), - PM_LEX_STATE_END = (1 << PM_LEX_STATE_BIT_END), - PM_LEX_STATE_ENDARG = (1 << PM_LEX_STATE_BIT_ENDARG), - PM_LEX_STATE_ENDFN = (1 << PM_LEX_STATE_BIT_ENDFN), - PM_LEX_STATE_ARG = (1 << PM_LEX_STATE_BIT_ARG), - PM_LEX_STATE_CMDARG = (1 << PM_LEX_STATE_BIT_CMDARG), - PM_LEX_STATE_MID = (1 << PM_LEX_STATE_BIT_MID), - PM_LEX_STATE_FNAME = (1 << PM_LEX_STATE_BIT_FNAME), - PM_LEX_STATE_DOT = (1 << PM_LEX_STATE_BIT_DOT), - PM_LEX_STATE_CLASS = (1 << PM_LEX_STATE_BIT_CLASS), - PM_LEX_STATE_LABEL = (1 << PM_LEX_STATE_BIT_LABEL), - PM_LEX_STATE_LABELED = (1 << PM_LEX_STATE_BIT_LABELED), - PM_LEX_STATE_FITEM = (1 << PM_LEX_STATE_BIT_FITEM), - PM_LEX_STATE_BEG_ANY = PM_LEX_STATE_BEG | PM_LEX_STATE_MID | PM_LEX_STATE_CLASS, - PM_LEX_STATE_ARG_ANY = PM_LEX_STATE_ARG | PM_LEX_STATE_CMDARG, - PM_LEX_STATE_END_ANY = PM_LEX_STATE_END | PM_LEX_STATE_ENDARG | PM_LEX_STATE_ENDFN -} pm_lex_state_t; - -/** - * The type of quote that a heredoc uses. - */ -typedef enum { - PM_HEREDOC_QUOTE_NONE, - PM_HEREDOC_QUOTE_SINGLE = '\'', - PM_HEREDOC_QUOTE_DOUBLE = '"', - PM_HEREDOC_QUOTE_BACKTICK = '`', -} pm_heredoc_quote_t; - -/** - * The type of indentation that a heredoc uses. - */ -typedef enum { - PM_HEREDOC_INDENT_NONE, - PM_HEREDOC_INDENT_DASH, - PM_HEREDOC_INDENT_TILDE, -} pm_heredoc_indent_t; - -/** - * All of the information necessary to store to lexing a heredoc. - */ -typedef struct { - /** A pointer to the start of the heredoc identifier. */ - const uint8_t *ident_start; - - /** The length of the heredoc identifier. */ - size_t ident_length; - - /** The type of quote that the heredoc uses. */ - pm_heredoc_quote_t quote; - - /** The type of indentation that the heredoc uses. */ - pm_heredoc_indent_t indent; -} pm_heredoc_lex_mode_t; - -/** - * The size of the breakpoints and strpbrk cache charset buffers. All - * breakpoint arrays and the strpbrk cache charset must share this size so - * that memcmp can safely compare the full buffer without overreading. - */ -#define PM_STRPBRK_CACHE_SIZE 16 - -/** - * When lexing Ruby source, the lexer has a small amount of state to tell which - * kind of token it is currently lexing. For example, when we find the start of - * a string, the first token that we return is a TOKEN_STRING_BEGIN token. After - * that the lexer is now in the PM_LEX_STRING mode, and will return tokens that - * are found as part of a string. - */ -typedef struct pm_lex_mode { - /** The type of this lex mode. */ - enum { - /** This state is used when any given token is being lexed. */ - PM_LEX_DEFAULT, - - /** - * This state is used when we're lexing as normal but inside an embedded - * expression of a string. - */ - PM_LEX_EMBEXPR, - - /** - * This state is used when we're lexing a variable that is embedded - * directly inside of a string with the # shorthand. - */ - PM_LEX_EMBVAR, - - /** This state is used when you are inside the content of a heredoc. */ - PM_LEX_HEREDOC, - - /** - * This state is used when we are lexing a list of tokens, as in a %w - * word list literal or a %i symbol list literal. - */ - PM_LEX_LIST, - - /** - * This state is used when a regular expression has been begun and we - * are looking for the terminator. - */ - PM_LEX_REGEXP, - - /** - * This state is used when we are lexing a string or a string-like - * token, as in string content with either quote or an xstring. - */ - PM_LEX_STRING - } mode; - - /** The data associated with this type of lex mode. */ - union { - struct { - /** This keeps track of the nesting level of the list. */ - size_t nesting; - - /** Whether or not interpolation is allowed in this list. */ - bool interpolation; - - /** - * When lexing a list, it takes into account balancing the - * terminator if the terminator is one of (), [], {}, or <>. - */ - uint8_t incrementor; - - /** This is the terminator of the list literal. */ - uint8_t terminator; - - /** - * This is the character set that should be used to delimit the - * tokens within the list. - */ - uint8_t breakpoints[PM_STRPBRK_CACHE_SIZE]; - } list; - - struct { - /** - * This keeps track of the nesting level of the regular expression. - */ - size_t nesting; - - /** - * When lexing a regular expression, it takes into account balancing - * the terminator if the terminator is one of (), [], {}, or <>. - */ - uint8_t incrementor; - - /** This is the terminator of the regular expression. */ - uint8_t terminator; - - /** - * This is the character set that should be used to delimit the - * tokens within the regular expression. - */ - uint8_t breakpoints[PM_STRPBRK_CACHE_SIZE]; - } regexp; - - struct { - /** This keeps track of the nesting level of the string. */ - size_t nesting; - - /** Whether or not interpolation is allowed in this string. */ - bool interpolation; - - /** - * Whether or not at the end of the string we should allow a :, - * which would indicate this was a dynamic symbol instead of a - * string. - */ - bool label_allowed; - - /** - * When lexing a string, it takes into account balancing the - * terminator if the terminator is one of (), [], {}, or <>. - */ - uint8_t incrementor; - - /** - * This is the terminator of the string. It is typically either a - * single or double quote. - */ - uint8_t terminator; - - /** - * This is the character set that should be used to delimit the - * tokens within the string. - */ - uint8_t breakpoints[PM_STRPBRK_CACHE_SIZE]; - } string; - - struct { - /** - * All of the data necessary to lex a heredoc. - */ - pm_heredoc_lex_mode_t base; - - /** - * This is the pointer to the character where lexing should resume - * once the heredoc has been completely processed. - */ - const uint8_t *next_start; - - /** - * This is used to track the amount of common whitespace on each - * line so that we know how much to dedent each line in the case of - * a tilde heredoc. - */ - size_t *common_whitespace; - - /** True if the previous token ended with a line continuation. */ - bool line_continuation; - } heredoc; - } as; - - /** The previous lex state so that it knows how to pop. */ - struct pm_lex_mode *prev; -} pm_lex_mode_t; - -/** - * We pre-allocate a certain number of lex states in order to avoid having to - * call malloc too many times while parsing. You really shouldn't need more than - * this because you only really nest deeply when doing string interpolation. - */ -#define PM_LEX_STACK_SIZE 4 /** * The parser used to parse Ruby source. */ -typedef struct pm_parser pm_parser_t; +typedef struct pm_parser_t pm_parser_t; /** - * While parsing, we keep track of a stack of contexts. This is helpful for - * error recovery so that we can pop back to a previous context when we hit a - * token that is understood by a parent context but not by the current context. + * Allocate and initialize a parser with the given start and end pointers. + * + * @param arena The arena to use for all AST-lifetime allocations. It is caller- + * owned and must outlive the parser. + * @param source The source to parse. + * @param size The size of the source. + * @param options The optional options to use when parsing. These options must + * live for the whole lifetime of this parser. + * @returns The initialized parser. It is the responsibility of the caller to + * free the parser with `pm_parser_free()`. */ -typedef enum { - /** a null context, used for returning a value from a function */ - PM_CONTEXT_NONE = 0, - - /** a begin statement */ - PM_CONTEXT_BEGIN, - - /** an ensure statement with an explicit begin */ - PM_CONTEXT_BEGIN_ENSURE, - - /** a rescue else statement with an explicit begin */ - PM_CONTEXT_BEGIN_ELSE, - - /** a rescue statement with an explicit begin */ - PM_CONTEXT_BEGIN_RESCUE, - - /** expressions in block arguments using braces */ - PM_CONTEXT_BLOCK_BRACES, - - /** expressions in block arguments using do..end */ - PM_CONTEXT_BLOCK_KEYWORDS, - - /** an ensure statement within a do..end block */ - PM_CONTEXT_BLOCK_ENSURE, - - /** a rescue else statement within a do..end block */ - PM_CONTEXT_BLOCK_ELSE, - - /** expressions in block parameters `foo do |...| end ` */ - PM_CONTEXT_BLOCK_PARAMETERS, - - /** a rescue statement within a do..end block */ - PM_CONTEXT_BLOCK_RESCUE, - - /** a case when statements */ - PM_CONTEXT_CASE_WHEN, - - /** a case in statements */ - PM_CONTEXT_CASE_IN, - - /** a class declaration */ - PM_CONTEXT_CLASS, - - /** an ensure statement within a class statement */ - PM_CONTEXT_CLASS_ENSURE, - - /** a rescue else statement within a class statement */ - PM_CONTEXT_CLASS_ELSE, +PRISM_EXPORTED_FUNCTION PRISM_NODISCARD pm_parser_t * pm_parser_new(pm_arena_t *arena, const uint8_t *source, size_t size, const pm_options_t *options) PRISM_NONNULL(1); - /** a rescue statement within a class statement */ - PM_CONTEXT_CLASS_RESCUE, - - /** a method definition */ - PM_CONTEXT_DEF, - - /** an ensure statement within a method definition */ - PM_CONTEXT_DEF_ENSURE, - - /** a rescue else statement within a method definition */ - PM_CONTEXT_DEF_ELSE, - - /** a rescue statement within a method definition */ - PM_CONTEXT_DEF_RESCUE, - - /** a method definition's parameters */ - PM_CONTEXT_DEF_PARAMS, - - /** a defined? expression */ - PM_CONTEXT_DEFINED, - - /** a method definition's default parameter */ - PM_CONTEXT_DEFAULT_PARAMS, - - /** an else clause */ - PM_CONTEXT_ELSE, - - /** an elsif clause */ - PM_CONTEXT_ELSIF, - - /** an interpolated expression */ - PM_CONTEXT_EMBEXPR, - - /** a for loop */ - PM_CONTEXT_FOR, - - /** a for loop's index */ - PM_CONTEXT_FOR_INDEX, - - /** an if statement */ - PM_CONTEXT_IF, - - /** a lambda expression with braces */ - PM_CONTEXT_LAMBDA_BRACES, +/** + * Free both the memory held by the given parser and the parser itself. + * + * @param parser The parser to free. + */ +PRISM_EXPORTED_FUNCTION void pm_parser_free(pm_parser_t *parser) PRISM_NONNULL(1); - /** a lambda expression with do..end */ - PM_CONTEXT_LAMBDA_DO_END, +/** + * When the encoding that is being used to parse the source is changed by prism, + * we provide the ability here to call out to a user-defined function. + */ +typedef void (*pm_encoding_changed_callback_t)(pm_parser_t *parser); - /** an ensure statement within a lambda expression */ - PM_CONTEXT_LAMBDA_ENSURE, +/** + * This is the callback that is called when a token is lexed. It is passed + * the opaque data pointer, the parser, and the token that was lexed. + */ +typedef void (*pm_lex_callback_t)(pm_parser_t *parser, pm_token_t *token, void *data); - /** a rescue else statement within a lambda expression */ - PM_CONTEXT_LAMBDA_ELSE, +/** + * Register a callback that will be called whenever prism changes the encoding + * it is using to parse based on the magic comment. + * + * @param parser The parser to register the callback with. + * @param callback The callback to register. + */ +PRISM_EXPORTED_FUNCTION void pm_parser_encoding_changed_callback_set(pm_parser_t *parser, pm_encoding_changed_callback_t callback) PRISM_NONNULL(1); - /** a rescue statement within a lambda expression */ - PM_CONTEXT_LAMBDA_RESCUE, +/** + * Register a callback that will be called whenever a token is lexed. + * + * @param parser The parser to register the callback with. + * @param data The opaque data to pass to the callback when it is called. + * @param callback The callback to register. + */ +PRISM_EXPORTED_FUNCTION void pm_parser_lex_callback_set(pm_parser_t *parser, pm_lex_callback_t callback, void *data) PRISM_NONNULL(1); - /** the predicate clause of a loop statement */ - PM_CONTEXT_LOOP_PREDICATE, +/** + * Returns the opaque data that is passed to the lex callback when it is called. + * + * @param parser The parser whose lex callback data we want to get. + * @returns The opaque data that is passed to the lex callback when it is called. + */ +PRISM_EXPORTED_FUNCTION void * pm_parser_lex_callback_data(const pm_parser_t *parser) PRISM_NONNULL(1); - /** the top level context */ - PM_CONTEXT_MAIN, +/** + * Returns the raw pointer to the start of the source that is being parsed. + * + * @param parser the parser whose start pointer we want to get + * @returns the raw pointer to the start of the source that is being parsed + */ +PRISM_EXPORTED_FUNCTION const uint8_t * pm_parser_start(const pm_parser_t *parser) PRISM_NONNULL(1); - /** a module declaration */ - PM_CONTEXT_MODULE, +/** + * Returns the raw pointer to the end of the source that is being parsed. + * + * @param parser the parser whose end pointer we want to get + * @returns the raw pointer to the end of the source that is being parsed + */ +PRISM_EXPORTED_FUNCTION const uint8_t * pm_parser_end(const pm_parser_t *parser) PRISM_NONNULL(1); - /** an ensure statement within a module statement */ - PM_CONTEXT_MODULE_ENSURE, +/** + * Returns the line that the parser was considered to have started on. + * + * @param parser the parser whose start line we want to get + * @returns the line that the parser was considered to have started on + */ +PRISM_EXPORTED_FUNCTION int32_t pm_parser_start_line(const pm_parser_t *parser) PRISM_NONNULL(1); - /** a rescue else statement within a module statement */ - PM_CONTEXT_MODULE_ELSE, +/** + * Returns the name of the encoding that is being used to parse the source. + * + * @param parser the parser whose encoding name we want to get + * @returns the name of the encoding that is being used to parse the source + */ +PRISM_EXPORTED_FUNCTION const char * pm_parser_encoding_name(const pm_parser_t *parser) PRISM_NONNULL(1); - /** a rescue statement within a module statement */ - PM_CONTEXT_MODULE_RESCUE, +/** + * Returns the width of the character at the given pointer in the encoding that + * is being used to parse the source. + * + * @param parser the parser whose encoding we want to use + * @param start a pointer to the start of the character + * @param remaining the number of bytes remaining in the source + * @returns the width of the character in bytes + */ +PRISM_EXPORTED_FUNCTION size_t pm_parser_encoding_char_width(const pm_parser_t *parser, const uint8_t *start, ptrdiff_t remaining) PRISM_NONNULL(1, 2); - /** a multiple target expression */ - PM_CONTEXT_MULTI_TARGET, +/** + * Returns whether or not the parser is using the US-ASCII encoding. + * + * @param parser the parser to check + * @returns true if the parser is using US-ASCII encoding, false otherwise + */ +PRISM_EXPORTED_FUNCTION bool pm_parser_encoding_us_ascii(const pm_parser_t *parser) PRISM_NONNULL(1); - /** a parenthesized expression */ - PM_CONTEXT_PARENS, +/** + * Returns the filepath that is being used to parse the source. + * + * @param parser the parser whose filepath we want to get + * @returns a pointer to the filepath string + */ +PRISM_EXPORTED_FUNCTION const pm_string_t * pm_parser_filepath(const pm_parser_t *parser) PRISM_NONNULL(1); - /** an END block */ - PM_CONTEXT_POSTEXE, +/** + * Find a constant in the parser's constant pool. Returns the id of the + * constant, or 0 if the constant is not found. + * + * @param parser the parser whose constant pool we want to search + * @param start a pointer to the start of the string to search for + * @param length the length of the string to search for + * @returns the id of the constant, or 0 if the constant is not found + */ +PRISM_EXPORTED_FUNCTION pm_constant_id_t pm_parser_constant_find(const pm_parser_t *parser, const uint8_t *start, size_t length) PRISM_NONNULL(1, 2); - /** a predicate inside an if/elsif/unless statement */ - PM_CONTEXT_PREDICATE, +/** + * Returns the frozen string literal value of the parser, as determined by the + * frozen_string_literal magic comment or the option set on the parser. + * + * @param parser the parser whose frozen string literal value we want to get + * @returns -1 if disabled, 0 if unset, 1 if enabled + */ +PRISM_EXPORTED_FUNCTION int8_t pm_parser_frozen_string_literal(const pm_parser_t *parser) PRISM_NONNULL(1); - /** a BEGIN block */ - PM_CONTEXT_PREEXE, +/** + * Returns the line offsets that are associated with the given parser. + * + * @param parser the parser whose line offsets we want to get + * @returns the line offsets that are associated with the given parser + */ +PRISM_EXPORTED_FUNCTION const pm_line_offset_list_t * pm_parser_line_offsets(const pm_parser_t *parser) PRISM_NONNULL(1); - /** a modifier rescue clause */ - PM_CONTEXT_RESCUE_MODIFIER, +/** + * Returns the location of the __DATA__ section that is associated with the + * given parser. + * + * @param parser the parser whose data location we want to get + * @returns the location of the __DATA__ section that is associated with the + * given parser. If it is unset, then the length will be set to 0. + */ +PRISM_EXPORTED_FUNCTION const pm_location_t * pm_parser_data_loc(const pm_parser_t *parser) PRISM_NONNULL(1); - /** a singleton class definition */ - PM_CONTEXT_SCLASS, +/** + * Returns whether the given parser is continuable, meaning that it could become + * valid if more input were appended, as opposed to being definitively invalid. + * + * @param parser the parser whose continuable status we want to get + * @returns whether the given parser is continuable + */ +PRISM_EXPORTED_FUNCTION bool pm_parser_continuable(const pm_parser_t *parser) PRISM_NONNULL(1); - /** an ensure statement with a singleton class */ - PM_CONTEXT_SCLASS_ENSURE, +/** + * Returns the lex state of the parser. Note that this is an internal detail, + * and we are purposefully not returning an instance of the internal enum that + * we use to track this. This is only exposed because we need it for some very + * niche use cases. Most consumers should avoid this function. + * + * @param parser the parser whose lex state we want to get + * @returns the lex state of the parser + */ +PRISM_EXPORTED_FUNCTION int pm_parser_lex_state(const pm_parser_t *parser) PRISM_NONNULL(1); - /** a rescue else statement with a singleton class */ - PM_CONTEXT_SCLASS_ELSE, +/** + * Returns the number of comments associated with the given parser. + * + * @param parser the parser whose comments we want to get the size of + * @returns the number of comments associated with the given parser + */ +PRISM_EXPORTED_FUNCTION size_t pm_parser_comments_size(const pm_parser_t *parser) PRISM_NONNULL(1); - /** a rescue statement with a singleton class */ - PM_CONTEXT_SCLASS_RESCUE, +/** + * A callback function that can be used to process comments found while parsing. + */ +typedef void (*pm_comment_callback_t)(const pm_comment_t *comment, void *data); - /** a ternary expression */ - PM_CONTEXT_TERNARY, +/** + * Iterates over the comments associated with the given parser and calls the + * given callback for each comment. + * + * @param parser the parser whose comments we want to iterate over + * @param callback the callback function to call for each comment. This function + * will be passed a pointer to the comment and the data parameter passed to + * this function. + * @param data the data to pass to the callback function for each comment. This + * can be NULL if no data needs to be passed to the callback function. + */ +PRISM_EXPORTED_FUNCTION void pm_parser_comments_each(const pm_parser_t *parser, pm_comment_callback_t callback, void *data) PRISM_NONNULL(1); - /** an unless statement */ - PM_CONTEXT_UNLESS, +/** + * Returns the number of magic comments associated with the given parser. + * + * @param parser the parser whose magic comments we want to get the size of + * @returns the number of magic comments associated with the given parser + */ +PRISM_EXPORTED_FUNCTION size_t pm_parser_magic_comments_size(const pm_parser_t *parser) PRISM_NONNULL(1); - /** an until statement */ - PM_CONTEXT_UNTIL, +/** + * A callback function that can be used to process magic comments found while parsing. + */ +typedef void (*pm_magic_comment_callback_t)(const pm_magic_comment_t *magic_comment, void *data); - /** a while statement */ - PM_CONTEXT_WHILE, -} pm_context_t; +/** + * Iterates over the magic comments associated with the given parser and calls the + * given callback for each magic comment. + * + * @param parser the parser whose magic comments we want to iterate over + * @param callback the callback function to call for each magic comment. This + * function will be passed a pointer to the magic comment and the data + * parameter passed to this function. + * @param data the data to pass to the callback function for each magic comment. + * This can be NULL if no data needs to be passed to the callback function. + */ +PRISM_EXPORTED_FUNCTION void pm_parser_magic_comments_each(const pm_parser_t *parser, pm_magic_comment_callback_t callback, void *data) PRISM_NONNULL(1); -/** This is a node in a linked list of contexts. */ -typedef struct pm_context_node { - /** The context that this node represents. */ - pm_context_t context; +/** + * Returns the number of errors associated with the given parser. + * + * @param parser the parser whose errors we want to get the size of + * @returns the number of errors associated with the given parser + */ +PRISM_EXPORTED_FUNCTION size_t pm_parser_errors_size(const pm_parser_t *parser) PRISM_NONNULL(1); - /** A pointer to the previous context in the linked list. */ - struct pm_context_node *prev; -} pm_context_node_t; +/** + * Returns the number of warnings associated with the given parser. + * + * @param parser the parser whose warnings we want to get the size of + * @returns the number of warnings associated with the given parser + */ +PRISM_EXPORTED_FUNCTION size_t pm_parser_warnings_size(const pm_parser_t *parser) PRISM_NONNULL(1); -/** This is the type of a comment that we've found while parsing. */ -typedef enum { - PM_COMMENT_INLINE, - PM_COMMENT_EMBDOC -} pm_comment_type_t; +/** + * A callback function that can be used to process diagnostics found while + * parsing. + */ +typedef void (*pm_diagnostic_callback_t)(const pm_diagnostic_t *diagnostic, void *data); /** - * This is a node in the linked list of comments that we've found while parsing. + * Iterates over the errors associated with the given parser and calls the + * given callback for each error. * - * @extends pm_list_node_t + * @param parser the parser whose errors we want to iterate over + * @param callback the callback function to call for each error. This function + * will be passed a pointer to the error and the data parameter passed to + * this function. + * @param data the data to pass to the callback function for each error. This + * can be NULL if no data needs to be passed to the callback function. */ -typedef struct pm_comment { - /** The embedded base node. */ - pm_list_node_t node; +PRISM_EXPORTED_FUNCTION void pm_parser_errors_each(const pm_parser_t *parser, pm_diagnostic_callback_t callback, void *data) PRISM_NONNULL(1); - /** The location of the comment in the source. */ - pm_location_t location; - - /** The type of comment that we've found. */ - pm_comment_type_t type; -} pm_comment_t; +/** + * Iterates over the warnings associated with the given parser and calls the + * given callback for each warning. + * + * @param parser the parser whose warnings we want to iterate over + * @param callback the callback function to call for each warning. This function + * will be passed a pointer to the warning and the data parameter passed to + * this function. + * @param data the data to pass to the callback function for each warning. This + * can be NULL if no data needs to be passed to the callback function. + */ +PRISM_EXPORTED_FUNCTION void pm_parser_warnings_each(const pm_parser_t *parser, pm_diagnostic_callback_t callback, void *data) PRISM_NONNULL(1); /** - * This is a node in the linked list of magic comments that we've found while - * parsing. + * Returns the number of constants in the constant pool associated with the + * given parser. * - * @extends pm_list_node_t + * @param parser the parser whose constant pool constants we want to get the + * size of + * @returns the number of constants in the constant pool associated with the + * given parser */ -typedef struct { - /** The embedded base node. */ - pm_list_node_t node; +PRISM_EXPORTED_FUNCTION size_t pm_parser_constants_size(const pm_parser_t *parser) PRISM_NONNULL(1); - /** The key of the magic comment. */ - pm_location_t key; +/** + * A callback function that can be used to process constants found while + * parsing. + */ +typedef void (*pm_constant_callback_t)(const pm_constant_t *constant, void *data); - /** The value of the magic comment. */ - pm_location_t value; -} pm_magic_comment_t; +/** + * Iterates over the constants in the constant pool associated with the given + * parser and calls the given callback for each constant. + * + * @param parser the parser whose constants we want to iterate over + * @param callback the callback function to call for each constant. This function + * will be passed a pointer to the constant and the data parameter passed to + * this function. + * @param data the data to pass to the callback function for each constant. This + * can be NULL if no data needs to be passed to the callback function. + */ +PRISM_EXPORTED_FUNCTION void pm_parser_constants_each(const pm_parser_t *parser, pm_constant_callback_t callback, void *data) PRISM_NONNULL(1); /** - * When the encoding that is being used to parse the source is changed by prism, - * we provide the ability here to call out to a user-defined function. + * Returns a pointer to the constant at the given id in the constant pool + * associated with the given parser. + * + * @param parser the parser whose constant pool we want to look up from + * @param constant_id the id of the constant to look up (1-based) + * @returns a pointer to the constant at the given id */ -typedef void (*pm_encoding_changed_callback_t)(pm_parser_t *parser); +PRISM_EXPORTED_FUNCTION const pm_constant_t * pm_parser_constant(const pm_parser_t *parser, pm_constant_id_t constant_id) PRISM_NONNULL(1); /** - * When you are lexing through a file, the lexer needs all of the information - * that the parser additionally provides (for example, the local table). So if - * you want to properly lex Ruby, you need to actually lex it in the context of - * the parser. In order to provide this functionality, we optionally allow a - * struct to be attached to the parser that calls back out to a user-provided - * callback when each token is lexed. - */ -typedef struct { - /** - * This opaque pointer is used to provide whatever information the user - * deemed necessary to the callback. In our case we use it to pass the array - * that the tokens get appended into. - */ - void *data; - - /** - * This is the callback that is called when a token is lexed. It is passed - * the opaque data pointer, the parser, and the token that was lexed. - */ - void (*callback)(void *data, pm_parser_t *parser, pm_token_t *token); -} pm_lex_callback_t; - -/** The type of shareable constant value that can be set. */ -typedef uint8_t pm_shareable_constant_value_t; -static const pm_shareable_constant_value_t PM_SCOPE_SHAREABLE_CONSTANT_NONE = 0x0; -static const pm_shareable_constant_value_t PM_SCOPE_SHAREABLE_CONSTANT_LITERAL = PM_SHAREABLE_CONSTANT_NODE_FLAGS_LITERAL; -static const pm_shareable_constant_value_t PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_EVERYTHING = PM_SHAREABLE_CONSTANT_NODE_FLAGS_EXPERIMENTAL_EVERYTHING; -static const pm_shareable_constant_value_t PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_COPY = PM_SHAREABLE_CONSTANT_NODE_FLAGS_EXPERIMENTAL_COPY; - -/** - * This tracks an individual local variable in a certain lexical context, as - * well as the number of times is it read. - */ -typedef struct { - /** The name of the local variable. */ - pm_constant_id_t name; - - /** The location of the local variable in the source. */ - pm_location_t location; - - /** The index of the local variable in the local table. */ - uint32_t index; - - /** The number of times the local variable is read. */ - uint32_t reads; - - /** The hash of the local variable. */ - uint32_t hash; -} pm_local_t; - -/** - * This is a set of local variables in a certain lexical context (method, class, - * module, etc.). We need to track how many times these variables are read in - * order to warn if they only get written. - */ -typedef struct pm_locals { - /** The number of local variables in the set. */ - uint32_t size; - - /** The capacity of the local variables set. */ - uint32_t capacity; - - /** - * A bloom filter over constant IDs stored in this set. Used to quickly - * reject lookups for names that are definitely not present, avoiding the - * cost of a linear scan or hash probe. - */ - uint32_t bloom; - - /** The nullable allocated memory for the local variables in the set. */ - pm_local_t *locals; -} pm_locals_t; - -/** The flags about scope parameters that can be set. */ -typedef uint8_t pm_scope_parameters_t; -static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_NONE = 0x0; -static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_FORWARDING_POSITIONALS = 0x1; -static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_FORWARDING_KEYWORDS = 0x2; -static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_FORWARDING_BLOCK = 0x4; -static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_FORWARDING_ALL = 0x8; -static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED = 0x10; -static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_NUMBERED_INNER = 0x20; -static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_NUMBERED_FOUND = 0x40; - -/** - * This struct represents a node in a linked list of scopes. Some scopes can see - * into their parent scopes, while others cannot. - */ -typedef struct pm_scope { - /** A pointer to the previous scope in the linked list. */ - struct pm_scope *previous; - - /** The IDs of the locals in the given scope. */ - pm_locals_t locals; - - /** - * This is a list of the implicit parameters contained within the block. - * These will be processed after the block is parsed to determine the kind - * of parameters node that should be used and to check if any errors need to - * be added. - */ - pm_node_list_t implicit_parameters; - - /** - * This is a bitfield that indicates the parameters that are being used in - * this scope. It is a combination of the PM_SCOPE_PARAMETERS_* constants. - * There are three different kinds of parameters that can be used in a - * scope: - * - * - Ordinary parameters (e.g., def foo(bar); end) - * - Numbered parameters (e.g., def foo; _1; end) - * - The it parameter (e.g., def foo; it; end) - * - * If ordinary parameters are being used, then certain parameters can be - * forwarded to another method/structure. Those are indicated by four - * additional bits in the params field. For example, some combinations of: - * - * - def foo(*); end - * - def foo(**); end - * - def foo(&); end - * - def foo(...); end - */ - pm_scope_parameters_t parameters; - - /** - * The current state of constant shareability for this scope. This is - * changed by magic shareable_constant_value comments. - */ - pm_shareable_constant_value_t shareable_constant; - - /** - * A boolean indicating whether or not this scope can see into its parent. - * If closed is true, then the scope cannot see into its parent. - */ - bool closed; -} pm_scope_t; - -/** - * A struct that represents a stack of boolean values. - */ -typedef uint32_t pm_state_stack_t; - -/** - * This struct represents the overall parser. It contains a reference to the - * source file, as well as pointers that indicate where in the source it's - * currently parsing. It also contains the most recent and current token that - * it's considering. - */ -struct pm_parser { - /** The arena used for all AST-lifetime allocations. Caller-owned. */ - pm_arena_t *arena; - - /** The arena used for parser metadata (comments, diagnostics, etc.). */ - pm_arena_t metadata_arena; - - /** - * The next node identifier that will be assigned. This is a unique - * identifier used to track nodes such that the syntax tree can be dropped - * but the node can be found through another parse. - */ - uint32_t node_id; - - /** The current state of the lexer. */ - pm_lex_state_t lex_state; - - /** Tracks the current nesting of (), [], and {}. */ - int enclosure_nesting; - - /** - * Used to temporarily track the nesting of enclosures to determine if a { - * is the beginning of a lambda following the parameters of a lambda. - */ - int lambda_enclosure_nesting; - - /** - * Used to track the nesting of braces to ensure we get the correct value - * when we are interpolating blocks with braces. - */ - int brace_nesting; - - /** - * The stack used to determine if a do keyword belongs to the predicate of a - * while, until, or for loop. - */ - pm_state_stack_t do_loop_stack; - - /** - * The stack used to determine if a do keyword belongs to the beginning of a - * block. - */ - pm_state_stack_t accepts_block_stack; - - /** A stack of lex modes. */ - struct { - /** The current mode of the lexer. */ - pm_lex_mode_t *current; - - /** The stack of lexer modes. */ - pm_lex_mode_t stack[PM_LEX_STACK_SIZE]; - - /** The current index into the lexer mode stack. */ - size_t index; - } lex_modes; - - /** The pointer to the start of the source. */ - const uint8_t *start; - - /** The pointer to the end of the source. */ - const uint8_t *end; - - /** The previous token we were considering. */ - pm_token_t previous; - - /** The current token we're considering. */ - pm_token_t current; - - /** - * This is a special field set on the parser when we need the parser to jump - * to a specific location when lexing the next token, as opposed to just - * using the end of the previous token. Normally this is NULL. - */ - const uint8_t *next_start; - - /** - * This field indicates the end of a heredoc whose identifier was found on - * the current line. If another heredoc is found on the same line, then this - * will be moved forward to the end of that heredoc. If no heredocs are - * found on a line then this is NULL. - */ - const uint8_t *heredoc_end; - - /** The list of comments that have been found while parsing. */ - pm_list_t comment_list; - - /** The list of magic comments that have been found while parsing. */ - pm_list_t magic_comment_list; - - /** - * An optional location that represents the location of the __END__ marker - * and the rest of the content of the file. This content is loaded into the - * DATA constant when the file being parsed is the main file being executed. - */ - pm_location_t data_loc; - - /** The list of warnings that have been found while parsing. */ - pm_list_t warning_list; - - /** The list of errors that have been found while parsing. */ - pm_list_t error_list; - - /** The current local scope. */ - pm_scope_t *current_scope; - - /** The current parsing context. */ - pm_context_node_t *current_context; - - /** - * The hash keys for the hash that is currently being parsed. This is not - * usually necessary because it can pass it down the various call chains, - * but in the event that you're parsing a hash that is being directly - * pushed into another hash with **, we need to share the hash keys so that - * we can warn for the nested hash as well. - */ - pm_static_literals_t *current_hash_keys; - - /** - * The encoding functions for the current file is attached to the parser as - * it's parsing so that it can change with a magic comment. - */ - const pm_encoding_t *encoding; - - /** - * When the encoding that is being used to parse the source is changed by - * prism, we provide the ability here to call out to a user-defined - * function. - */ - pm_encoding_changed_callback_t encoding_changed_callback; - - /** - * This pointer indicates where a comment must start if it is to be - * considered an encoding comment. - */ - const uint8_t *encoding_comment_start; - - /** - * This is an optional callback that can be attached to the parser that will - * be called whenever a new token is lexed by the parser. - */ - pm_lex_callback_t *lex_callback; - - /** - * This is the path of the file being parsed. We use the filepath when - * constructing SourceFileNodes. - */ - pm_string_t filepath; - - /** - * This constant pool keeps all of the constants defined throughout the file - * so that we can reference them later. - */ - pm_constant_pool_t constant_pool; - - /** This is the list of line offsets in the source file. */ - pm_line_offset_list_t line_offsets; - - /** - * State communicated from the lexer to the parser for integer tokens. - */ - struct { - /** - * A flag indicating the base of the integer (binary, octal, decimal, - * hexadecimal). Set during lexing and read during node creation. - */ - pm_node_flags_t base; - - /** - * When lexing a decimal integer that fits in a uint32_t, we compute - * the value during lexing to avoid re-scanning the digits during - * parsing. If lexed is true, this holds the result and - * pm_integer_parse can be skipped. - */ - uint32_t value; - - /** Whether value holds a valid pre-computed integer. */ - bool lexed; - } integer; - - /** - * This string is used to pass information from the lexer to the parser. It - * is particularly necessary because of escape sequences. - */ - pm_string_t current_string; - - /** - * The line number at the start of the parse. This will be used to offset - * the line numbers of all of the locations. - */ - int32_t start_line; - - /** - * When a string-like expression is being lexed, any byte or escape sequence - * that resolves to a value whose top bit is set (i.e., >= 0x80) will - * explicitly set the encoding to the same encoding as the source. - * Alternatively, if a unicode escape sequence is used (e.g., \\u{80}) that - * resolves to a value whose top bit is set, then the encoding will be - * explicitly set to UTF-8. - * - * The _next_ time this happens, if the encoding that is about to become the - * explicitly set encoding does not match the previously set explicit - * encoding, a mixed encoding error will be emitted. - * - * When the expression is finished being lexed, the explicit encoding - * controls the encoding of the expression. For the most part this means - * that the expression will either be encoded in the source encoding or - * UTF-8. This holds for all encodings except US-ASCII. If the source is - * US-ASCII and an explicit encoding was set that was _not_ UTF-8, then the - * expression will be encoded as ASCII-8BIT. - * - * Note that if the expression is a list, different elements within the same - * list can have different encodings, so this will get reset between each - * element. Furthermore all of this only applies to lists that support - * interpolation, because otherwise escapes that could change the encoding - * are ignored. - * - * At first glance, it may make more sense for this to live on the lexer - * mode, but we need it here to communicate back to the parser for character - * literals that do not push a new lexer mode. - */ - const pm_encoding_t *explicit_encoding; - - /** - * When parsing block exits (e.g., break, next, redo), we need to validate - * that they are in correct contexts. For the most part we can do this by - * looking at our parent contexts. However, modifier while and until - * expressions can change that context to make block exits valid. In these - * cases, we need to keep track of the block exits and then validate them - * after the expression has been parsed. - * - * We use a pointer here because we don't want to keep a whole list attached - * since this will only be used in the context of begin/end expressions. - */ - pm_node_list_t *current_block_exits; - - /** The version of prism that we should use to parse. */ - pm_options_version_t version; - - /** The command line flags given from the options. */ - uint8_t command_line; - - /** - * Whether or not we have found a frozen_string_literal magic comment with - * a true or false value. - * May be: - * - PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED - * - PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED - * - PM_OPTIONS_FROZEN_STRING_LITERAL_UNSET - */ - int8_t frozen_string_literal; - - /** - * Whether or not we are parsing an eval string. This impacts whether or not - * we should evaluate if block exits/yields are valid. - */ - bool parsing_eval; - - /** - * Whether or not we are parsing a "partial" script, which is a script that - * will be evaluated in the context of another script, so we should not - * check jumps (next/break/etc.) for validity. - */ - bool partial_script; - - /** Whether or not we're at the beginning of a command. */ - bool command_start; - - /** - * Whether or not we're currently parsing the body of an endless method - * definition. In this context, PM_TOKEN_KEYWORD_DO_BLOCK should not be - * consumed by commands (it should bubble up to the outer context). - */ - bool in_endless_def_body; - - /** Whether or not we're currently recovering from a syntax error. */ - bool recovering; - - /** - * Whether or not the source being parsed could become valid if more input - * were appended. This is set to false when the parser encounters a token - * that is definitively wrong (e.g., a stray `end` or `]`) as opposed to - * merely incomplete. - */ - bool continuable; - - /** - * This is very specialized behavior for when you want to parse in a context - * that does not respect encoding comments. Its main use case is translating - * into the whitequark/parser AST which re-encodes source files in UTF-8 - * before they are parsed and ignores encoding comments. - */ - bool encoding_locked; - - /** - * Whether or not the encoding has been changed by a magic comment. We use - * this to provide a fast path for the lexer instead of going through the - * function pointer. - */ - bool encoding_changed; - - /** - * This flag indicates that we are currently parsing a pattern matching - * expression and impacts that calculation of newlines. - */ - bool pattern_matching_newlines; - - /** This flag indicates that we are currently parsing a keyword argument. */ - bool in_keyword_arg; - - /** - * Whether or not the parser has seen a token that has semantic meaning - * (i.e., a token that is not a comment or whitespace). - */ - bool semantic_token_seen; - - /** - * By default, Ruby always warns about mismatched indentation. This can be - * toggled with a magic comment. - */ - bool warn_mismatched_indentation; - -#if defined(PRISM_HAS_NEON) || defined(PRISM_HAS_SSSE3) || defined(PRISM_HAS_SWAR) - /** - * Cached lookup tables for pm_strpbrk's SIMD fast path. Avoids rebuilding - * the nibble-based tables on every call when the charset hasn't changed - * (which is the common case during string/regex/list lexing). - */ - struct { - /** The cached charset (null-terminated, NUL-padded). */ - uint8_t charset[PM_STRPBRK_CACHE_SIZE]; - - /** Nibble-based low lookup table for SIMD matching. */ - uint8_t low_lut[16]; - - /** Nibble-based high lookup table for SIMD matching. */ - uint8_t high_lut[16]; - - /** Scalar fallback table (4 x 64-bit bitmasks covering all ASCII). */ - uint64_t table[4]; - } strpbrk_cache; -#endif -}; + * Initiate the parser with the given parser. + * + * @param parser The parser to use. + * @returns The AST representing the source. + */ +PRISM_EXPORTED_FUNCTION pm_node_t * pm_parse(pm_parser_t *parser) PRISM_NONNULL(1); #endif diff --git a/prism/prettyprint.h b/prism/prettyprint.h index 5a52b2b6b8eb43..0d8e416341e18b 100644 --- a/prism/prettyprint.h +++ b/prism/prettyprint.h @@ -6,19 +6,16 @@ #ifndef PRISM_PRETTYPRINT_H #define PRISM_PRETTYPRINT_H -#include "prism/defines.h" +#include "prism/excludes.h" -#ifdef PRISM_EXCLUDE_PRETTYPRINT +#ifndef PRISM_EXCLUDE_PRETTYPRINT -void pm_prettyprint(void); - -#else - -#include +#include "prism/compiler/exported.h" +#include "prism/compiler/nonnull.h" #include "prism/ast.h" +#include "prism/buffer.h" #include "prism/parser.h" -#include "prism/util/pm_buffer.h" /** * Pretty-prints the AST represented by the given node to the given buffer. @@ -27,7 +24,7 @@ void pm_prettyprint(void); * @param parser The parser that parsed the AST. * @param node The root node of the AST to pretty-print. */ -PRISM_EXPORTED_FUNCTION void pm_prettyprint(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm_node_t *node); +PRISM_EXPORTED_FUNCTION void pm_prettyprint(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm_node_t *node) PRISM_NONNULL(1, 2, 3); #endif diff --git a/prism/prism.c b/prism/prism.c index dc7cbef2d4b9fd..1fa4a46ed825a0 100644 --- a/prism/prism.c +++ b/prism/prism.c @@ -1,5 +1,90 @@ -#include "prism.h" -#include "prism/node_new.h" +#include "prism/compiler/accel.h" +#include "prism/compiler/fallthrough.h" +#include "prism/compiler/unused.h" + +#include "prism/internal/allocator.h" +#include "prism/internal/arena.h" +#include "prism/internal/bit.h" +#include "prism/internal/buffer.h" +#include "prism/internal/char.h" +#include "prism/internal/comments.h" +#include "prism/internal/constant_pool.h" +#include "prism/internal/diagnostic.h" +#include "prism/internal/encoding.h" +#include "prism/internal/integer.h" +#include "prism/internal/isinf.h" +#include "prism/internal/line_offset_list.h" +#include "prism/internal/list.h" +#include "prism/internal/magic_comments.h" +#include "prism/internal/memchr.h" +#include "prism/internal/node.h" +#include "prism/internal/options.h" +#include "prism/internal/parser.h" +#include "prism/internal/regexp.h" +#include "prism/internal/serialize.h" +#include "prism/internal/source.h" +#include "prism/internal/static_literals.h" +#include "prism/internal/stringy.h" +#include "prism/internal/strncasecmp.h" +#include "prism/internal/strpbrk.h" +#include "prism/internal/tokens.h" + +#include "prism/excludes.h" +#include "prism/serialize.h" +#include "prism/stream.h" +#include "prism/version.h" + +#include +#include +#include +#include +#include +#include +#include + +/** + * When we are parsing using recursive descent, we want to protect against + * malicious payloads that could attempt to crash our parser. We do this by + * specifying a maximum depth to which we are allowed to recurse. + */ +#ifndef PRISM_DEPTH_MAXIMUM + #define PRISM_DEPTH_MAXIMUM 10000 +#endif + +/** + * A simple utility macro to concatenate two tokens together, necessary when one + * of the tokens is itself a macro. + */ +#define PM_CONCATENATE(left, right) left ## right + +/** + * We want to be able to use static assertions, but they weren't standardized + * until C11. As such, we polyfill it here by making a hacky typedef that will + * fail to compile due to a negative array size if the condition is false. + */ +#if defined(_Static_assert) +# define PM_STATIC_ASSERT(line, condition, message) _Static_assert(condition, message) +#else +# define PM_STATIC_ASSERT(line, condition, message) typedef char PM_CONCATENATE(static_assert_, line)[(condition) ? 1 : -1] +#endif + +/** + * Support PRISM_LIKELY and PRISM_UNLIKELY to help the compiler optimize its + * branch predication. + */ +#if defined(__GNUC__) || defined(__clang__) + /** The compiler should predicate that this branch will be taken. */ + #define PRISM_LIKELY(x) __builtin_expect(!!(x), 1) + + /** The compiler should predicate that this branch will not be taken. */ + #define PRISM_UNLIKELY(x) __builtin_expect(!!(x), 0) +#else + /** Void because this platform does not support branch prediction hints. */ + #define PRISM_LIKELY(x) (x) + + /** Void because this platform does not support branch prediction hints. */ + #define PRISM_UNLIKELY(x) (x) +#endif /** * The prism version and the serialization format. @@ -72,7 +157,7 @@ pm_version(void) { * Returns the incrementor character that should be used to increment the * nesting count if one is possible. */ -static inline uint8_t +static PRISM_INLINE uint8_t lex_mode_incrementor(const uint8_t start) { switch (start) { case '(': @@ -89,7 +174,7 @@ lex_mode_incrementor(const uint8_t start) { * Returns the matching character that should be used to terminate a list * beginning with the given character. */ -static inline uint8_t +static PRISM_INLINE uint8_t lex_mode_terminator(const uint8_t start) { switch (start) { case '(': @@ -131,7 +216,7 @@ lex_mode_push(pm_parser_t *parser, pm_lex_mode_t lex_mode) { /** * Push on a new list lex mode. */ -static inline bool +static PRISM_INLINE bool lex_mode_push_list(pm_parser_t *parser, bool interpolation, uint8_t delimiter) { uint8_t incrementor = lex_mode_incrementor(delimiter); uint8_t terminator = lex_mode_terminator(delimiter); @@ -179,7 +264,7 @@ lex_mode_push_list(pm_parser_t *parser, bool interpolation, uint8_t delimiter) { * called when we're at the end of the file. We want the parser to be able to * perform its normal error tolerance. */ -static inline bool +static PRISM_INLINE bool lex_mode_push_list_eof(pm_parser_t *parser) { return lex_mode_push_list(parser, false, '\0'); } @@ -187,7 +272,7 @@ lex_mode_push_list_eof(pm_parser_t *parser) { /** * Push on a new regexp lex mode. */ -static inline bool +static PRISM_INLINE bool lex_mode_push_regexp(pm_parser_t *parser, uint8_t incrementor, uint8_t terminator) { pm_lex_mode_t lex_mode = { .mode = PM_LEX_REGEXP, @@ -223,7 +308,7 @@ lex_mode_push_regexp(pm_parser_t *parser, uint8_t incrementor, uint8_t terminato /** * Push on a new string lex mode. */ -static inline bool +static PRISM_INLINE bool lex_mode_push_string(pm_parser_t *parser, bool interpolation, bool label_allowed, uint8_t incrementor, uint8_t terminator) { pm_lex_mode_t lex_mode = { .mode = PM_LEX_STRING, @@ -270,7 +355,7 @@ lex_mode_push_string(pm_parser_t *parser, bool interpolation, bool label_allowed * called when we're at the end of the file. We want the parser to be able to * perform its normal error tolerance. */ -static inline bool +static PRISM_INLINE bool lex_mode_push_string_eof(pm_parser_t *parser) { return lex_mode_push_string(parser, false, false, '\0', '\0'); } @@ -298,7 +383,7 @@ lex_mode_pop(pm_parser_t *parser) { /** * This is the equivalent of IS_lex_state is CRuby. */ -static inline bool +static PRISM_INLINE bool lex_state_p(const pm_parser_t *parser, pm_lex_state_t state) { return parser->lex_state & state; } @@ -309,7 +394,7 @@ typedef enum { PM_IGNORED_NEWLINE_PATTERN } pm_ignored_newline_type_t; -static inline pm_ignored_newline_type_t +static PRISM_INLINE pm_ignored_newline_type_t lex_state_ignored_p(pm_parser_t *parser) { bool ignored = lex_state_p(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_CLASS | PM_LEX_STATE_FNAME | PM_LEX_STATE_DOT) && !lex_state_p(parser, PM_LEX_STATE_LABELED); @@ -322,17 +407,17 @@ lex_state_ignored_p(pm_parser_t *parser) { } } -static inline bool +static PRISM_INLINE bool lex_state_beg_p(pm_parser_t *parser) { return lex_state_p(parser, PM_LEX_STATE_BEG_ANY) || ((parser->lex_state & (PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED)) == (PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED)); } -static inline bool +static PRISM_INLINE bool lex_state_arg_p(pm_parser_t *parser) { return lex_state_p(parser, PM_LEX_STATE_ARG_ANY); } -static inline bool +static PRISM_INLINE bool lex_state_spcarg_p(pm_parser_t *parser, bool space_seen) { if (parser->current.end >= parser->end) { return false; @@ -340,7 +425,7 @@ lex_state_spcarg_p(pm_parser_t *parser, bool space_seen) { return lex_state_arg_p(parser) && space_seen && !pm_char_is_whitespace(*parser->current.end); } -static inline bool +static PRISM_INLINE bool lex_state_end_p(pm_parser_t *parser) { return lex_state_p(parser, PM_LEX_STATE_END_ANY); } @@ -348,7 +433,7 @@ lex_state_end_p(pm_parser_t *parser) { /** * This is the equivalent of IS_AFTER_OPERATOR in CRuby. */ -static inline bool +static PRISM_INLINE bool lex_state_operator_p(pm_parser_t *parser) { return lex_state_p(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_DOT); } @@ -357,7 +442,7 @@ lex_state_operator_p(pm_parser_t *parser) { * Set the state of the lexer. This is defined as a function to be able to put a * breakpoint in it. */ -static inline void +static PRISM_INLINE void lex_state_set(pm_parser_t *parser, pm_lex_state_t state) { parser->lex_state = state; } @@ -371,7 +456,7 @@ lex_state_set(pm_parser_t *parser, pm_lex_state_t state) { #endif #if PM_DEBUG_LOGGING -PRISM_ATTRIBUTE_UNUSED static void +PRISM_UNUSED static void debug_state(pm_parser_t *parser) { fprintf(stderr, "STATE: "); bool first = true; @@ -452,7 +537,7 @@ debug_lex_state_set(pm_parser_t *parser, pm_lex_state_t state, char const * call /** * Append an error to the list of errors on the parser. */ -static inline void +static PRISM_INLINE void pm_parser_err(pm_parser_t *parser, uint32_t start, uint32_t length, pm_diagnostic_id_t diag_id) { pm_diagnostic_list_append(&parser->metadata_arena, &parser->error_list, start, length, diag_id); } @@ -461,7 +546,7 @@ pm_parser_err(pm_parser_t *parser, uint32_t start, uint32_t length, pm_diagnosti * Append an error to the list of errors on the parser using the location of the * given token. */ -static inline void +static PRISM_INLINE void pm_parser_err_token(pm_parser_t *parser, const pm_token_t *token, pm_diagnostic_id_t diag_id) { pm_parser_err(parser, PM_TOKEN_START(parser, token), PM_TOKEN_LENGTH(token), diag_id); } @@ -470,7 +555,7 @@ pm_parser_err_token(pm_parser_t *parser, const pm_token_t *token, pm_diagnostic_ * Append an error to the list of errors on the parser using the location of the * current token. */ -static inline void +static PRISM_INLINE void pm_parser_err_current(pm_parser_t *parser, pm_diagnostic_id_t diag_id) { pm_parser_err_token(parser, &parser->current, diag_id); } @@ -479,7 +564,7 @@ pm_parser_err_current(pm_parser_t *parser, pm_diagnostic_id_t diag_id) { * Append an error to the list of errors on the parser using the location of the * previous token. */ -static inline void +static PRISM_INLINE void pm_parser_err_previous(pm_parser_t *parser, pm_diagnostic_id_t diag_id) { pm_parser_err_token(parser, &parser->previous, diag_id); } @@ -488,7 +573,7 @@ pm_parser_err_previous(pm_parser_t *parser, pm_diagnostic_id_t diag_id) { * Append an error to the list of errors on the parser using the location of the * given node. */ -static inline void +static PRISM_INLINE void pm_parser_err_node(pm_parser_t *parser, const pm_node_t *node, pm_diagnostic_id_t diag_id) { pm_parser_err(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), diag_id); } @@ -530,7 +615,7 @@ pm_parser_err_node(pm_parser_t *parser, const pm_node_t *node, pm_diagnostic_id_ /** * Append a warning to the list of warnings on the parser. */ -static inline void +static PRISM_INLINE void pm_parser_warn(pm_parser_t *parser, uint32_t start, uint32_t length, pm_diagnostic_id_t diag_id) { pm_diagnostic_list_append(&parser->metadata_arena, &parser->warning_list, start, length, diag_id); } @@ -539,7 +624,7 @@ pm_parser_warn(pm_parser_t *parser, uint32_t start, uint32_t length, pm_diagnost * Append a warning to the list of warnings on the parser using the location of * the given token. */ -static inline void +static PRISM_INLINE void pm_parser_warn_token(pm_parser_t *parser, const pm_token_t *token, pm_diagnostic_id_t diag_id) { pm_parser_warn(parser, PM_TOKEN_START(parser, token), PM_TOKEN_LENGTH(token), diag_id); } @@ -548,7 +633,7 @@ pm_parser_warn_token(pm_parser_t *parser, const pm_token_t *token, pm_diagnostic * Append a warning to the list of warnings on the parser using the location of * the given node. */ -static inline void +static PRISM_INLINE void pm_parser_warn_node(pm_parser_t *parser, const pm_node_t *node, pm_diagnostic_id_t diag_id) { pm_parser_warn(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), diag_id); } @@ -751,7 +836,7 @@ pm_parser_scope_forwarding_keywords_check(pm_parser_t *parser, const pm_token_t /** * Get the current state of constant shareability. */ -static inline pm_shareable_constant_value_t +static PRISM_INLINE pm_shareable_constant_value_t pm_parser_scope_shareable_constant_get(pm_parser_t *parser) { return parser->current_scope->shareable_constant; } @@ -990,7 +1075,7 @@ pm_locals_reads(pm_locals_t *locals, pm_constant_id_t name) { * written but not read in certain contexts. */ static void -pm_locals_order(PRISM_ATTRIBUTE_UNUSED pm_parser_t *parser, pm_locals_t *locals, pm_constant_id_list_t *list, bool toplevel) { +pm_locals_order(pm_parser_t *parser, pm_locals_t *locals, pm_constant_id_list_t *list, bool toplevel) { pm_constant_id_list_init_capacity(parser->arena, list, locals->size); // If we're still below the threshold for switching to a hash, then we only @@ -1033,15 +1118,27 @@ pm_locals_order(PRISM_ATTRIBUTE_UNUSED pm_parser_t *parser, pm_locals_t *locals, /** * Retrieve the constant pool id for the given location. */ -static inline pm_constant_id_t +static PRISM_INLINE pm_constant_id_t pm_parser_constant_id_raw(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) { - return pm_constant_pool_insert_shared(&parser->metadata_arena, &parser->constant_pool, start, (size_t) (end - start)); + /* Fast path: if this is the same token as the last lookup (same pointer + * range), return the cached result. */ + if (start == parser->constant_cache.start && end == parser->constant_cache.end) { + return parser->constant_cache.id; + } + + pm_constant_id_t id = pm_constant_pool_insert_shared(&parser->metadata_arena, &parser->constant_pool, start, (size_t) (end - start)); + + parser->constant_cache.start = start; + parser->constant_cache.end = end; + parser->constant_cache.id = id; + + return id; } /** * Retrieve the constant pool id for the given string. */ -static inline pm_constant_id_t +static PRISM_INLINE pm_constant_id_t pm_parser_constant_id_owned(pm_parser_t *parser, uint8_t *start, size_t length) { return pm_constant_pool_insert_owned(&parser->metadata_arena, &parser->constant_pool, start, length); } @@ -1049,7 +1146,7 @@ pm_parser_constant_id_owned(pm_parser_t *parser, uint8_t *start, size_t length) /** * Retrieve the constant pool id for the given static literal C string. */ -static inline pm_constant_id_t +static PRISM_INLINE pm_constant_id_t pm_parser_constant_id_constant(pm_parser_t *parser, const char *start, size_t length) { return pm_constant_pool_insert_constant(&parser->metadata_arena, &parser->constant_pool, (const uint8_t *) start, length); } @@ -1057,7 +1154,7 @@ pm_parser_constant_id_constant(pm_parser_t *parser, const char *start, size_t le /** * Retrieve the constant pool id for the given token. */ -static inline pm_constant_id_t +static PRISM_INLINE pm_constant_id_t pm_parser_constant_id_token(pm_parser_t *parser, const pm_token_t *token) { return pm_parser_constant_id_raw(parser, token->start, token->end); } @@ -1276,7 +1373,7 @@ pm_check_value_expression(pm_parser_t *parser, pm_node_t *node) { return NULL; } -static inline void +static PRISM_INLINE void pm_assert_value_expression(pm_parser_t *parser, pm_node_t *node) { pm_node_t *void_node = pm_check_value_expression(parser, node); if (void_node != NULL) { @@ -1517,7 +1614,7 @@ pm_conditional_predicate_warn_write_literal_p(const pm_node_t *node) { * Add a warning to the parser if the value that is being written inside of a * predicate to a conditional is a literal. */ -static inline void +static PRISM_INLINE void pm_conditional_predicate_warn_write_literal(pm_parser_t *parser, const pm_node_t *node) { if (pm_conditional_predicate_warn_write_literal_p(node)) { pm_parser_warn_node(parser, node, parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 ? PM_WARN_EQUAL_IN_CONDITIONAL_3_3 : PM_WARN_EQUAL_IN_CONDITIONAL); @@ -1683,7 +1780,7 @@ typedef struct { /** * Retrieve the end location of a `pm_arguments_t` object. */ -static inline const pm_location_t * +static PRISM_INLINE const pm_location_t * pm_arguments_end(pm_arguments_t *arguments) { if (arguments->block != NULL) { uint32_t end = PM_NODE_END(arguments->block); @@ -1746,7 +1843,7 @@ pm_arguments_validate_block(pm_parser_t *parser, pm_arguments_t *arguments, pm_b * reason we have the encoding_changed boolean to check if we need to go through * the function pointer or can just directly use the UTF-8 functions. */ -static inline size_t +static PRISM_INLINE size_t char_is_identifier_start(const pm_parser_t *parser, const uint8_t *b, ptrdiff_t n) { if (n <= 0) return 0; @@ -1773,7 +1870,7 @@ char_is_identifier_start(const pm_parser_t *parser, const uint8_t *b, ptrdiff_t * Similar to char_is_identifier but this function assumes that the encoding * has not been changed. */ -static inline size_t +static PRISM_INLINE size_t char_is_identifier_utf8(const uint8_t *b, ptrdiff_t n) { if (n <= 0) { return 0; @@ -1800,7 +1897,7 @@ char_is_identifier_utf8(const uint8_t *b, ptrdiff_t n) { #if defined(PRISM_HAS_NEON) #include -static inline size_t +static PRISM_INLINE size_t scan_identifier_ascii(const uint8_t *start, const uint8_t *end) { const uint8_t *cursor = start; @@ -1854,7 +1951,7 @@ scan_identifier_ascii(const uint8_t *start, const uint8_t *end) { #elif defined(PRISM_HAS_SSSE3) #include -static inline size_t +static PRISM_INLINE size_t scan_identifier_ascii(const uint8_t *start, const uint8_t *end) { const uint8_t *cursor = start; @@ -1908,7 +2005,7 @@ scan_identifier_ascii(const uint8_t *start, const uint8_t *end) { * impossible. The result has bit 7 set if and only if byte >= lo. The same * reasoning applies to the upper-bound direction. */ -static inline size_t +static PRISM_INLINE size_t scan_identifier_ascii(const uint8_t *start, const uint8_t *end) { static const uint64_t ones = 0x0101010101010101ULL; static const uint64_t highs = 0x8080808080808080ULL; @@ -1967,7 +2064,7 @@ scan_identifier_ascii(const uint8_t *start, const uint8_t *end) { * the identifiers in a source file once the first character has been found. So * it's important that it be as fast as possible. */ -static inline size_t +static PRISM_INLINE size_t char_is_identifier(const pm_parser_t *parser, const uint8_t *b, ptrdiff_t n) { if (n <= 0) { return 0; @@ -2005,7 +2102,7 @@ const unsigned int pm_global_name_punctuation_hash[(0x7e - 0x20 + 31) / 32] = { #undef BIT #undef PUNCT -static inline bool +static PRISM_INLINE bool char_is_global_name_punctuation(const uint8_t b) { const unsigned int i = (const unsigned int) b; if (i <= 0x20 || 0x7e < i) return false; @@ -2013,7 +2110,7 @@ char_is_global_name_punctuation(const uint8_t b) { return (pm_global_name_punctuation_hash[(i - 0x20) / 32] >> (i % 32)) & 1; } -static inline bool +static PRISM_INLINE bool token_is_setter_name(pm_token_t *token) { return ( (token->type == PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL) || @@ -2101,7 +2198,7 @@ pm_local_is_keyword(const char *source, size_t length) { /** * Set the given flag on the given node. */ -static inline void +static PRISM_INLINE void pm_node_flag_set(pm_node_t *node, pm_node_flags_t flag) { node->flags |= flag; } @@ -2109,7 +2206,7 @@ pm_node_flag_set(pm_node_t *node, pm_node_flags_t flag) { /** * Remove the given flag from the given node. */ -static inline void +static PRISM_INLINE void pm_node_flag_unset(pm_node_t *node, pm_node_flags_t flag) { node->flags &= (pm_node_flags_t) ~flag; } @@ -2117,7 +2214,7 @@ pm_node_flag_unset(pm_node_t *node, pm_node_flags_t flag) { /** * Set the repeated parameter flag on the given node. */ -static inline void +static PRISM_INLINE void pm_node_flag_set_repeated_parameter(pm_node_t *node) { assert(PM_NODE_TYPE(node) == PM_BLOCK_LOCAL_VARIABLE_NODE || PM_NODE_TYPE(node) == PM_BLOCK_PARAMETER_NODE || @@ -2145,7 +2242,7 @@ pm_node_flag_set_repeated_parameter(pm_node_t *node) { /** * Parse out the options for a regular expression. */ -static inline pm_node_flags_t +static PRISM_INLINE pm_node_flags_t pm_regular_expression_flags_create(pm_parser_t *parser, const pm_token_t *closing) { pm_node_flags_t flags = 0; @@ -2173,7 +2270,7 @@ pm_regular_expression_flags_create(pm_parser_t *parser, const pm_token_t *closin const char *word = unknown_flags_length >= 2 ? "options" : "option"; PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_REGEXP_UNKNOWN_OPTIONS, word, unknown_flags_length, pm_buffer_value(&unknown_flags)); } - pm_buffer_free(&unknown_flags); + pm_buffer_cleanup(&unknown_flags); } return flags; @@ -2194,7 +2291,7 @@ pm_statements_node_body_length(pm_statements_node_t *node); * Move an integer's values array into the arena. If the integer has heap- * allocated values, copy them to the arena and free the original. */ -static inline void +static PRISM_INLINE void pm_integer_arena_move(pm_arena_t *arena, pm_integer_t *integer) { if (integer->values != NULL) { size_t byte_size = integer->length * sizeof(uint32_t); @@ -2364,7 +2461,7 @@ pm_array_node_create(pm_parser_t *parser, const pm_token_t *opening) { /** * Append an argument to an array node. */ -static inline void +static PRISM_INLINE void pm_array_node_elements_append(pm_arena_t *arena, pm_array_node_t *node, pm_node_t *element) { if (!node->elements.size && !node->opening_loc.length) { PM_NODE_START_SET_NODE(node, element); @@ -2491,7 +2588,7 @@ pm_array_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *openin ); } -static inline void +static PRISM_INLINE void pm_array_pattern_node_requireds_append(pm_arena_t *arena, pm_array_pattern_node_t *node, pm_node_t *inner) { pm_node_list_append(arena, &node->requireds, inner); } @@ -2820,7 +2917,7 @@ pm_call_node_create(pm_parser_t *parser, pm_node_flags_t flags) { * Returns the value that the ignore visibility flag should be set to for the * given receiver. */ -static inline pm_node_flags_t +static PRISM_INLINE pm_node_flags_t pm_call_node_ignore_visibility_flag(const pm_node_t *receiver) { return PM_NODE_TYPE_P(receiver, PM_SELF_NODE) ? PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY : 0; } @@ -3070,7 +3167,7 @@ pm_call_node_variable_call_create(pm_parser_t *parser, pm_token_t *message) { * Returns whether or not this call can be used on the left-hand side of an * operator assignment. */ -static inline bool +static PRISM_INLINE bool pm_call_node_writable_p(const pm_parser_t *parser, const pm_call_node_t *node) { return ( (node->message_loc.length > 0) && @@ -3578,7 +3675,7 @@ pm_class_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) * a = *b * a = 1, 2, 3 */ -static inline pm_node_flags_t +static PRISM_INLINE pm_node_flags_t pm_implicit_array_write_flags(const pm_node_t *node, pm_node_flags_t flags) { if (PM_NODE_TYPE_P(node, PM_ARRAY_NODE) && ((const pm_array_node_t *) node)->opening_loc.length == 0) { return flags; @@ -4501,7 +4598,7 @@ pm_hash_node_create(pm_parser_t *parser, const pm_token_t *opening) { /** * Append a new element to a hash node. */ -static inline void +static PRISM_INLINE void pm_hash_node_elements_append(pm_arena_t *arena, pm_hash_node_t *hash, pm_node_t *element) { pm_node_list_append(arena, &hash->elements, element); @@ -4518,7 +4615,7 @@ pm_hash_node_elements_append(pm_arena_t *arena, pm_hash_node_t *hash, pm_node_t } } -static inline void +static PRISM_INLINE void pm_hash_node_closing_loc_set(const pm_parser_t *parser, pm_hash_node_t *hash, pm_token_t *token) { PM_NODE_LENGTH_SET_TOKEN(parser, hash, token); hash->closing_loc = TOK2LOC(parser, token); @@ -4618,13 +4715,13 @@ pm_if_node_ternary_create(pm_parser_t *parser, pm_node_t *predicate, const pm_to ); } -static inline void +static PRISM_INLINE void pm_if_node_end_keyword_loc_set(const pm_parser_t *parser, pm_if_node_t *node, const pm_token_t *keyword) { PM_NODE_LENGTH_SET_TOKEN(parser, node, keyword); node->end_keyword_loc = TOK2LOC(parser, keyword); } -static inline void +static PRISM_INLINE void pm_else_node_end_keyword_loc_set(const pm_parser_t *parser, pm_else_node_t *node, const pm_token_t *keyword) { PM_NODE_LENGTH_SET_TOKEN(parser, node, keyword); node->end_keyword_loc = TOK2LOC(parser, keyword); @@ -4947,7 +5044,7 @@ pm_interpolated_regular_expression_node_create(pm_parser_t *parser, const pm_tok ); } -static inline void +static PRISM_INLINE void pm_interpolated_regular_expression_node_append(pm_arena_t *arena, pm_interpolated_regular_expression_node_t *node, pm_node_t *part) { if (PM_NODE_START(node) > PM_NODE_START(part)) { PM_NODE_START_SET_NODE(node, part); @@ -4959,7 +5056,7 @@ pm_interpolated_regular_expression_node_append(pm_arena_t *arena, pm_interpolate pm_interpolated_node_append(arena, UP(node), &node->parts, part); } -static inline void +static PRISM_INLINE void pm_interpolated_regular_expression_node_closing_set(pm_parser_t *parser, pm_interpolated_regular_expression_node_t *node, const pm_token_t *closing) { node->closing_loc = TOK2LOC(parser, closing); PM_NODE_LENGTH_SET_TOKEN(parser, node, closing); @@ -4989,7 +5086,7 @@ pm_interpolated_regular_expression_node_closing_set(pm_parser_t *parser, pm_inte * is necessary to indicate that the string should be left up to the runtime, * which could potentially use a chilled string otherwise. */ -static inline void +static PRISM_INLINE void pm_interpolated_string_node_append(pm_arena_t *arena, pm_interpolated_string_node_t *node, pm_node_t *part) { #define CLEAR_FLAGS(node) \ node->base.flags = (pm_node_flags_t) (FL(node) & ~(PM_NODE_FLAG_STATIC_LITERAL | PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN | PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE)) @@ -5192,13 +5289,13 @@ pm_interpolated_xstring_node_create(pm_parser_t *parser, const pm_token_t *openi ); } -static inline void +static PRISM_INLINE void pm_interpolated_xstring_node_append(pm_arena_t *arena, pm_interpolated_x_string_node_t *node, pm_node_t *part) { pm_interpolated_node_append(arena, UP(node), &node->parts, part); PM_NODE_LENGTH_SET_NODE(node, part); } -static inline void +static PRISM_INLINE void pm_interpolated_xstring_node_closing_set(const pm_parser_t *parser, pm_interpolated_x_string_node_t *node, const pm_token_t *closing) { node->closing_loc = TOK2LOC(parser, closing); PM_NODE_LENGTH_SET_TOKEN(parser, node, closing); @@ -5454,7 +5551,7 @@ pm_local_variable_write_node_create(pm_parser_t *parser, pm_constant_id_t name, /** * Returns true if the given bounds comprise `it`. */ -static inline bool +static PRISM_INLINE bool pm_token_is_it(const uint8_t *start, const uint8_t *end) { return (end - start == 2) && (start[0] == 'i') && (start[1] == 't'); } @@ -5463,7 +5560,7 @@ pm_token_is_it(const uint8_t *start, const uint8_t *end) { * Returns true if the given bounds comprise a numbered parameter (i.e., they * are of the form /^_\d$/). */ -static inline bool +static PRISM_INLINE bool pm_token_is_numbered_parameter(const pm_parser_t *parser, uint32_t start, uint32_t length) { return ( (length == 2) && @@ -5477,7 +5574,7 @@ pm_token_is_numbered_parameter(const pm_parser_t *parser, uint32_t start, uint32 * Ensure the given bounds do not comprise a numbered parameter. If they do, add * an appropriate error message to the parser. */ -static inline void +static PRISM_INLINE void pm_refute_numbered_parameter(pm_parser_t *parser, uint32_t start, uint32_t length) { if (pm_token_is_numbered_parameter(parser, start, length)) { PM_PARSER_ERR_FORMAT(parser, start, length, PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->start + start); @@ -6117,7 +6214,7 @@ pm_regular_expression_node_create_unescaped(pm_parser_t *parser, const pm_token_ /** * Allocate a new initialize a new RegularExpressionNode node. */ -static inline pm_regular_expression_node_t * +static PRISM_INLINE pm_regular_expression_node_t * pm_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) { return pm_regular_expression_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY); } @@ -6172,7 +6269,7 @@ pm_rescue_node_create(pm_parser_t *parser, const pm_token_t *keyword) { ); } -static inline void +static PRISM_INLINE void pm_rescue_node_operator_set(const pm_parser_t *parser, pm_rescue_node_t *node, const pm_token_t *operator) { node->operator_loc = TOK2LOC(parser, operator); } @@ -6407,7 +6504,7 @@ pm_statements_node_body_length(pm_statements_node_t *node) { * Update the location of the statements node based on the statement that is * being added to the list. */ -static inline void +static PRISM_INLINE void pm_statements_node_body_update(pm_statements_node_t *node, pm_node_t *statement) { if (pm_statements_node_body_length(node) == 0 || PM_NODE_START(statement) < PM_NODE_START(node)) { PM_NODE_START_SET_NODE(node, statement); @@ -6458,7 +6555,7 @@ pm_statements_node_body_prepend(pm_arena_t *arena, pm_statements_node_t *node, p /** * Allocate a new StringNode node with the current string on the parser. */ -static inline pm_string_node_t * +static PRISM_INLINE pm_string_node_t * pm_string_node_create_unescaped(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing, const pm_string_t *string) { pm_node_flags_t flags = 0; @@ -6590,7 +6687,7 @@ parse_symbol_encoding_validate_other(pm_parser_t *parser, const pm_token_t *loca * If the validate flag is set, then it will check the contents of the symbol * to ensure that all characters are valid in the encoding. */ -static inline pm_node_flags_t +static PRISM_INLINE pm_node_flags_t parse_symbol_encoding(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents, bool validate) { if (parser->explicit_encoding != NULL) { // A Symbol may optionally have its encoding explicitly set. This will @@ -6639,7 +6736,7 @@ pm_symbol_node_create_unescaped(pm_parser_t *parser, const pm_token_t *opening, /** * Allocate and initialize a new SymbolNode node. */ -static inline pm_symbol_node_t * +static PRISM_INLINE pm_symbol_node_t * pm_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) { return pm_symbol_node_create_unescaped(parser, opening, value, closing, &PM_STRING_EMPTY, 0); } @@ -6880,7 +6977,7 @@ pm_unless_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const ); } -static inline void +static PRISM_INLINE void pm_unless_node_end_keyword_loc_set(const pm_parser_t *parser, pm_unless_node_t *node, const pm_token_t *end_keyword) { node->end_keyword_loc = TOK2LOC(parser, end_keyword); PM_NODE_LENGTH_SET_TOKEN(parser, node, end_keyword); @@ -6979,7 +7076,7 @@ pm_when_node_conditions_append(pm_arena_t *arena, pm_when_node_t *node, pm_node_ /** * Set the location of the then keyword of a when node. */ -static inline void +static PRISM_INLINE void pm_when_node_then_keyword_loc_set(const pm_parser_t *parser, pm_when_node_t *node, const pm_token_t *then_keyword) { PM_NODE_LENGTH_SET_TOKEN(parser, node, then_keyword); node->then_keyword_loc = TOK2LOC(parser, then_keyword); @@ -7077,7 +7174,7 @@ pm_xstring_node_create_unescaped(pm_parser_t *parser, const pm_token_t *opening, /** * Allocate and initialize a new XStringNode node. */ -static inline pm_x_string_node_t * +static PRISM_INLINE pm_x_string_node_t * pm_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) { return pm_xstring_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY); } @@ -7137,7 +7234,7 @@ pm_parser_local_depth_constant_id(pm_parser_t *parser, pm_constant_id_t constant * described by the given token. This function implicitly inserts a constant * into the constant pool. */ -static inline int +static PRISM_INLINE int pm_parser_local_depth(pm_parser_t *parser, pm_token_t *token) { return pm_parser_local_depth_constant_id(parser, pm_parser_constant_id_token(parser, token)); } @@ -7145,7 +7242,7 @@ pm_parser_local_depth(pm_parser_t *parser, pm_token_t *token) { /** * Add a constant id to the local table of the current scope. */ -static inline void +static PRISM_INLINE void pm_parser_local_add(pm_parser_t *parser, pm_constant_id_t constant_id, const uint8_t *start, const uint8_t *end, uint32_t reads) { pm_locals_write(&parser->current_scope->locals, constant_id, U32(start - parser->start), U32(end - start), reads); } @@ -7163,7 +7260,7 @@ pm_parser_local_add_raw(pm_parser_t *parser, const uint8_t *start, const uint8_t /** * Add a local variable from a location to the current scope. */ -static inline pm_constant_id_t +static PRISM_INLINE pm_constant_id_t pm_parser_local_add_location(pm_parser_t *parser, pm_location_t *location, uint32_t reads) { return pm_parser_local_add_raw(parser, parser->start + location->start, parser->start + location->start + location->length, reads); } @@ -7171,7 +7268,7 @@ pm_parser_local_add_location(pm_parser_t *parser, pm_location_t *location, uint3 /** * Add a local variable from a token to the current scope. */ -static inline pm_constant_id_t +static PRISM_INLINE pm_constant_id_t pm_parser_local_add_token(pm_parser_t *parser, pm_token_t *token, uint32_t reads) { return pm_parser_local_add_raw(parser, token->start, token->end, reads); } @@ -7241,7 +7338,7 @@ pm_parser_scope_pop(pm_parser_t *parser) { /** * Pushes a value onto the stack. */ -static inline void +static PRISM_INLINE void pm_state_stack_push(pm_state_stack_t *stack, bool value) { *stack = (*stack << 1) | (value & 1); } @@ -7249,7 +7346,7 @@ pm_state_stack_push(pm_state_stack_t *stack, bool value) { /** * Pops a value off the stack. */ -static inline void +static PRISM_INLINE void pm_state_stack_pop(pm_state_stack_t *stack) { *stack >>= 1; } @@ -7257,38 +7354,38 @@ pm_state_stack_pop(pm_state_stack_t *stack) { /** * Returns the value at the top of the stack. */ -static inline bool +static PRISM_INLINE bool pm_state_stack_p(const pm_state_stack_t *stack) { return *stack & 1; } -static inline void +static PRISM_INLINE void pm_accepts_block_stack_push(pm_parser_t *parser, bool value) { // Use the negation of the value to prevent stack overflow. pm_state_stack_push(&parser->accepts_block_stack, !value); } -static inline void +static PRISM_INLINE void pm_accepts_block_stack_pop(pm_parser_t *parser) { pm_state_stack_pop(&parser->accepts_block_stack); } -static inline bool +static PRISM_INLINE bool pm_accepts_block_stack_p(pm_parser_t *parser) { return !pm_state_stack_p(&parser->accepts_block_stack); } -static inline void +static PRISM_INLINE void pm_do_loop_stack_push(pm_parser_t *parser, bool value) { pm_state_stack_push(&parser->do_loop_stack, value); } -static inline void +static PRISM_INLINE void pm_do_loop_stack_pop(pm_parser_t *parser) { pm_state_stack_pop(&parser->do_loop_stack); } -static inline bool +static PRISM_INLINE bool pm_do_loop_stack_p(pm_parser_t *parser) { return pm_state_stack_p(&parser->do_loop_stack); } @@ -7301,7 +7398,7 @@ pm_do_loop_stack_p(pm_parser_t *parser) { * Get the next character in the source starting from +cursor+. If that position * is beyond the end of the source then return '\0'. */ -static inline uint8_t +static PRISM_INLINE uint8_t peek_at(const pm_parser_t *parser, const uint8_t *cursor) { if (cursor < parser->end) { return *cursor; @@ -7315,7 +7412,7 @@ peek_at(const pm_parser_t *parser, const uint8_t *cursor) { * adding the given offset. If that position is beyond the end of the source * then return '\0'. */ -static inline uint8_t +static PRISM_INLINE uint8_t peek_offset(pm_parser_t *parser, ptrdiff_t offset) { return peek_at(parser, parser->current.end + offset); } @@ -7324,7 +7421,7 @@ peek_offset(pm_parser_t *parser, ptrdiff_t offset) { * Get the next character in the source starting from parser->current.end. If * that position is beyond the end of the source then return '\0'. */ -static inline uint8_t +static PRISM_INLINE uint8_t peek(const pm_parser_t *parser) { return peek_at(parser, parser->current.end); } @@ -7333,7 +7430,7 @@ peek(const pm_parser_t *parser) { * If the character to be read matches the given value, then returns true and * advances the current pointer. */ -static inline bool +static PRISM_INLINE bool match(pm_parser_t *parser, uint8_t value) { if (peek(parser) == value) { parser->current.end++; @@ -7346,7 +7443,7 @@ match(pm_parser_t *parser, uint8_t value) { * Return the length of the line ending string starting at +cursor+, or 0 if it * is not a line ending. This function is intended to be CRLF/LF agnostic. */ -static inline size_t +static PRISM_INLINE size_t match_eol_at(pm_parser_t *parser, const uint8_t *cursor) { if (peek_at(parser, cursor) == '\n') { return 1; @@ -7362,7 +7459,7 @@ match_eol_at(pm_parser_t *parser, const uint8_t *cursor) { * `parser->current.end + offset`, or 0 if it is not a line ending. This * function is intended to be CRLF/LF agnostic. */ -static inline size_t +static PRISM_INLINE size_t match_eol_offset(pm_parser_t *parser, ptrdiff_t offset) { return match_eol_at(parser, parser->current.end + offset); } @@ -7372,7 +7469,7 @@ match_eol_offset(pm_parser_t *parser, ptrdiff_t offset) { * or 0 if it is not a line ending. This function is intended to be CRLF/LF * agnostic. */ -static inline size_t +static PRISM_INLINE size_t match_eol(pm_parser_t *parser) { return match_eol_at(parser, parser->current.end); } @@ -7380,7 +7477,7 @@ match_eol(pm_parser_t *parser) { /** * Skip to the next newline character or NUL byte. */ -static inline const uint8_t * +static PRISM_INLINE const uint8_t * next_newline(const uint8_t *cursor, ptrdiff_t length) { assert(length >= 0); @@ -7393,7 +7490,7 @@ next_newline(const uint8_t *cursor, ptrdiff_t length) { /** * This is equivalent to the predicate of warn_balanced in CRuby. */ -static inline bool +static PRISM_INLINE bool ambiguous_operator_p(const pm_parser_t *parser, bool space_seen) { return !lex_state_p(parser, PM_LEX_STATE_CLASS | PM_LEX_STATE_DOT | PM_LEX_STATE_FNAME | PM_LEX_STATE_ENDFN) && space_seen && !pm_char_is_whitespace(peek(parser)); } @@ -7496,7 +7593,7 @@ parser_lex_magic_comment_boolean_value(const uint8_t *value_start, uint32_t valu } } -static inline bool +static PRISM_INLINE bool pm_char_is_magic_comment_key_delimiter(const uint8_t b) { return b == '\'' || b == '"' || b == ':' || b == ';'; } @@ -7506,7 +7603,7 @@ pm_char_is_magic_comment_key_delimiter(const uint8_t b) { * found, it returns a pointer to the start of the marker. Otherwise it returns * NULL. */ -static inline const uint8_t * +static PRISM_INLINE const uint8_t * parser_lex_magic_comment_emacs_marker(pm_parser_t *parser, const uint8_t *cursor, const uint8_t *end) { // Scan for '*' as the middle character, since it is rarer than '-' in // typical comments and avoids repeated memchr calls for '-' that hit @@ -7529,7 +7626,7 @@ parser_lex_magic_comment_emacs_marker(pm_parser_t *parser, const uint8_t *cursor * It returns true if it consumes the entire comment. Otherwise it returns * false. */ -static inline bool +static PRISM_INLINE bool parser_lex_magic_comment(pm_parser_t *parser, bool semantic_token_seen) { bool result = true; @@ -7729,7 +7826,7 @@ parser_lex_magic_comment(pm_parser_t *parser, bool semantic_token_seen) { // When we're done, we want to free the string in case we had to // allocate memory for it. - pm_string_free(&key); + pm_string_cleanup(&key); // Allocate a new magic comment node to append to the parser's list. pm_magic_comment_t *magic_comment = (pm_magic_comment_t *) pm_arena_alloc(&parser->metadata_arena, sizeof(pm_magic_comment_t), PRISM_ALIGNOF(pm_magic_comment_t)); @@ -7804,7 +7901,7 @@ static const uint32_t context_terminators[] = { [PM_CONTEXT_WHILE] = (1U << PM_TOKEN_KEYWORD_END), }; -static inline bool +static PRISM_INLINE bool context_terminator(pm_context_t context, pm_token_t *token) { return token->type < 32 && (context_terminators[context] & (1U << token->type)); } @@ -7968,7 +8065,7 @@ context_human(pm_context_t context) { /* Specific token lexers */ /******************************************************************************/ -static inline void +static PRISM_INLINE void pm_strspn_number_validate(pm_parser_t *parser, const uint8_t *string, size_t length, const uint8_t *invalid) { if (invalid != NULL) { pm_diagnostic_id_t diag_id = (invalid == (string + length - 1)) ? PM_ERR_INVALID_NUMBER_UNDERSCORE_TRAILING : PM_ERR_INVALID_NUMBER_UNDERSCORE_INNER; @@ -8367,7 +8464,7 @@ lex_global_variable(pm_parser_t *parser) { * * `type` - the expected token type * * `modifier_type` - the expected modifier token type */ -static inline pm_token_type_t +static PRISM_INLINE pm_token_type_t lex_keyword(pm_parser_t *parser, const uint8_t *current_start, const char *value, size_t vlen, pm_lex_state_t state, pm_token_type_t type, pm_token_type_t modifier_type) { if (memcmp(current_start, value, vlen) == 0) { pm_lex_state_t last_state = parser->lex_state; @@ -8708,7 +8805,7 @@ static const bool ascii_printable_chars[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 }; -static inline bool +static PRISM_INLINE bool char_is_ascii_printable(const uint8_t b) { return (b < 0x80) && ascii_printable_chars[b]; } @@ -8717,7 +8814,7 @@ char_is_ascii_printable(const uint8_t b) { * Return the value that a hexadecimal digit character represents. For example, * transform 'a' into 10, 'b' into 11, etc. */ -static inline uint8_t +static PRISM_INLINE uint8_t escape_hexadecimal_digit(const uint8_t value) { return (uint8_t) ((value <= '9') ? (value - '0') : (value & 0x7) + 9); } @@ -8727,7 +8824,7 @@ escape_hexadecimal_digit(const uint8_t value) { * digits scanned. This function assumes that the characters have already been * validated. */ -static inline uint32_t +static PRISM_INLINE uint32_t escape_unicode(pm_parser_t *parser, const uint8_t *string, size_t length, const pm_location_t *error_location, const uint8_t flags) { uint32_t value = 0; for (size_t index = 0; index < length; index++) { @@ -8755,7 +8852,7 @@ escape_unicode(pm_parser_t *parser, const uint8_t *string, size_t length, const /** * Escape a single character value based on the given flags. */ -static inline uint8_t +static PRISM_INLINE uint8_t escape_byte(uint8_t value, const uint8_t flags) { if (flags & PM_ESCAPE_FLAG_CONTROL) value &= 0x9f; if (flags & PM_ESCAPE_FLAG_META) value |= 0x80; @@ -8765,7 +8862,7 @@ escape_byte(uint8_t value, const uint8_t flags) { /** * Write a unicode codepoint to the given buffer. */ -static inline void +static PRISM_INLINE void escape_write_unicode(pm_parser_t *parser, pm_buffer_t *buffer, const uint8_t flags, const uint8_t *start, const uint8_t *end, uint32_t value) { // \u escape sequences in string-like structures implicitly change the // encoding to UTF-8 if they are >= 0x80 or if they are used in a character @@ -8801,7 +8898,7 @@ escape_write_unicode(pm_parser_t *parser, pm_buffer_t *buffer, const uint8_t fla * When you're writing a byte to the unescape buffer, if the byte is non-ASCII * (i.e., the top bit is set) then it locks in the encoding. */ -static inline void +static PRISM_INLINE void escape_write_byte_encoded(pm_parser_t *parser, pm_buffer_t *buffer, const uint8_t flags, uint8_t byte) { if (byte >= 0x80) { if (parser->explicit_encoding != NULL && parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY && parser->encoding != PM_ENCODING_UTF_8_ENTRY) { @@ -8834,7 +8931,7 @@ escape_write_byte_encoded(pm_parser_t *parser, pm_buffer_t *buffer, const uint8_ * Note that in this case there is a literal \ byte in the regular expression * source so that the regular expression engine will perform its own unescaping. */ -static inline void +static PRISM_INLINE void escape_write_byte(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expression_buffer, uint8_t flags, uint8_t byte) { if (flags & PM_ESCAPE_FLAG_REGEXP) { pm_buffer_append_format(regular_expression_buffer, "\\x%02X", byte); @@ -8846,7 +8943,7 @@ escape_write_byte(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular /** * Write each byte of the given escaped character into the buffer. */ -static inline void +static PRISM_INLINE void escape_write_escape_encoded(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expression_buffer, uint8_t flags) { size_t width; if (parser->encoding_changed) { @@ -9366,14 +9463,14 @@ lex_question_mark(pm_parser_t *parser) { lex_state_set(parser, PM_LEX_STATE_END); pm_buffer_t buffer; - pm_buffer_init_capacity(&buffer, 3); + pm_buffer_init(&buffer, 3); escape_read(parser, &buffer, NULL, PM_ESCAPE_FLAG_SINGLE); // Copy buffer data into the arena and free the heap buffer. void *arena_data = pm_arena_memdup(parser->arena, buffer.value, buffer.length, PRISM_ALIGNOF(uint8_t)); pm_string_constant_init(&parser->current_string, (const char *) arena_data, buffer.length); - pm_buffer_free(&buffer); + pm_buffer_cleanup(&buffer); return PM_TOKEN_CHARACTER_LITERAL; } else { @@ -9439,17 +9536,17 @@ lex_at_variable(pm_parser_t *parser) { /** * Optionally call out to the lex callback if one is provided. */ -static inline void +static PRISM_INLINE void parser_lex_callback(pm_parser_t *parser) { - if (parser->lex_callback) { - parser->lex_callback->callback(parser->lex_callback->data, parser, &parser->current); + if (parser->lex_callback.callback) { + parser->lex_callback.callback(parser, &parser->current, parser->lex_callback.data); } } /** * Return a new comment node of the specified type. */ -static inline pm_comment_t * +static PRISM_INLINE pm_comment_t * parser_comment(pm_parser_t *parser, pm_comment_type_t type) { pm_comment_t *comment = (pm_comment_t *) pm_arena_alloc(&parser->metadata_arena, sizeof(pm_comment_t), PRISM_ALIGNOF(pm_comment_t)); @@ -9548,7 +9645,7 @@ lex_embdoc(pm_parser_t *parser) { * This happens in a couple places depending on whether or not we have already * lexed a comment. */ -static inline void +static PRISM_INLINE void parser_lex_ignored_newline(pm_parser_t *parser) { parser->current.type = PM_TOKEN_IGNORED_NEWLINE; parser_lex_callback(parser); @@ -9563,7 +9660,7 @@ parser_lex_ignored_newline(pm_parser_t *parser) { * If it is set, then we need to skip past the heredoc body and then clear the * heredoc_end field. */ -static inline void +static PRISM_INLINE void parser_flush_heredoc_end(pm_parser_t *parser) { assert(parser->heredoc_end <= parser->end); parser->next_start = parser->heredoc_end; @@ -9639,12 +9736,12 @@ typedef struct { /** * Push the given byte into the token buffer. */ -static inline void +static PRISM_INLINE void pm_token_buffer_push_byte(pm_token_buffer_t *token_buffer, uint8_t byte) { pm_buffer_append_byte(&token_buffer->buffer, byte); } -static inline void +static PRISM_INLINE void pm_regexp_token_buffer_push_byte(pm_regexp_token_buffer_t *token_buffer, uint8_t byte) { pm_buffer_append_byte(&token_buffer->regexp_buffer, byte); } @@ -9652,7 +9749,7 @@ pm_regexp_token_buffer_push_byte(pm_regexp_token_buffer_t *token_buffer, uint8_t /** * Return the width of the character at the end of the current token. */ -static inline size_t +static PRISM_INLINE size_t parser_char_width(const pm_parser_t *parser) { size_t width; if (parser->encoding_changed) { @@ -9691,19 +9788,19 @@ pm_regexp_token_buffer_push_escaped(pm_regexp_token_buffer_t *token_buffer, pm_p * contents of the token buffer into the current string on the parser so that it * can be attached to the correct node. */ -static inline void +static PRISM_INLINE void pm_token_buffer_copy(pm_parser_t *parser, pm_token_buffer_t *token_buffer) { // Copy buffer data into the arena and free the heap buffer. size_t len = pm_buffer_length(&token_buffer->buffer); void *arena_data = pm_arena_memdup(parser->arena, pm_buffer_value(&token_buffer->buffer), len, PRISM_ALIGNOF(uint8_t)); pm_string_constant_init(&parser->current_string, (const char *) arena_data, len); - pm_buffer_free(&token_buffer->buffer); + pm_buffer_cleanup(&token_buffer->buffer); } -static inline void +static PRISM_INLINE void pm_regexp_token_buffer_copy(pm_parser_t *parser, pm_regexp_token_buffer_t *token_buffer) { pm_token_buffer_copy(parser, &token_buffer->base); - pm_buffer_free(&token_buffer->regexp_buffer); + pm_buffer_cleanup(&token_buffer->regexp_buffer); } /** @@ -9752,7 +9849,7 @@ static void pm_token_buffer_escape(pm_parser_t *parser, pm_token_buffer_t *token_buffer) { const uint8_t *start; if (token_buffer->cursor == NULL) { - pm_buffer_init_capacity(&token_buffer->buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE); + pm_buffer_init(&token_buffer->buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE); start = parser->current.start; } else { start = token_buffer->cursor; @@ -9769,8 +9866,8 @@ static void pm_regexp_token_buffer_escape(pm_parser_t *parser, pm_regexp_token_buffer_t *token_buffer) { const uint8_t *start; if (token_buffer->base.cursor == NULL) { - pm_buffer_init_capacity(&token_buffer->base.buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE); - pm_buffer_init_capacity(&token_buffer->regexp_buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE); + pm_buffer_init(&token_buffer->base.buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE); + pm_buffer_init(&token_buffer->regexp_buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE); start = parser->current.start; } else { start = token_buffer->base.cursor; @@ -9789,7 +9886,7 @@ pm_regexp_token_buffer_escape(pm_parser_t *parser, pm_regexp_token_buffer_t *tok * Effectively the same thing as pm_strspn_inline_whitespace, but in the case of * a tilde heredoc expands out tab characters to the nearest tab boundaries. */ -static inline size_t +static PRISM_INLINE size_t pm_heredoc_strspn_inline_whitespace(pm_parser_t *parser, const uint8_t **cursor, pm_heredoc_indent_t indent) { size_t whitespace = 0; @@ -10266,7 +10363,7 @@ parser_lex(pm_parser_t *parser) { // , case ',': if ((parser->previous.type == PM_TOKEN_COMMA) && (parser->enclosure_nesting > 0)) { - PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_ARRAY_TERM, pm_token_type_human(parser->current.type)); + PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_ARRAY_TERM, pm_token_str(parser->current.type)); } lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL); @@ -12475,7 +12572,7 @@ pm_binding_powers_t pm_binding_powers[PM_TOKEN_MAXIMUM] = { /** * Returns true if the current token is of the given type. */ -static inline bool +static PRISM_INLINE bool match1(const pm_parser_t *parser, pm_token_type_t type) { return parser->current.type == type; } @@ -12483,7 +12580,7 @@ match1(const pm_parser_t *parser, pm_token_type_t type) { /** * Returns true if the current token is of either of the given types. */ -static inline bool +static PRISM_INLINE bool match2(const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) { return match1(parser, type1) || match1(parser, type2); } @@ -12491,7 +12588,7 @@ match2(const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) /** * Returns true if the current token is any of the three given types. */ -static inline bool +static PRISM_INLINE bool match3(const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3) { return match1(parser, type1) || match1(parser, type2) || match1(parser, type3); } @@ -12499,15 +12596,23 @@ match3(const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, /** * Returns true if the current token is any of the four given types. */ -static inline bool +static PRISM_INLINE bool match4(const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3, pm_token_type_t type4) { return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4); } +/** + * Returns true if the current token is any of the six given types. + */ +static PRISM_INLINE bool +match6(const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3, pm_token_type_t type4, pm_token_type_t type5, pm_token_type_t type6) { + return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6); +} + /** * Returns true if the current token is any of the seven given types. */ -static inline bool +static PRISM_INLINE bool match7(const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3, pm_token_type_t type4, pm_token_type_t type5, pm_token_type_t type6, pm_token_type_t type7) { return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6) || match1(parser, type7); } @@ -12515,7 +12620,7 @@ match7(const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, /** * Returns true if the current token is any of the eight given types. */ -static inline bool +static PRISM_INLINE bool match8(const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3, pm_token_type_t type4, pm_token_type_t type5, pm_token_type_t type6, pm_token_type_t type7, pm_token_type_t type8) { return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6) || match1(parser, type7) || match1(parser, type8); } @@ -12539,7 +12644,7 @@ accept1(pm_parser_t *parser, pm_token_type_t type) { * If the current token is either of the two given types, lex forward by one * token and return true. Otherwise return false. */ -static inline bool +static PRISM_INLINE bool accept2(pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) { if (match2(parser, type1, type2)) { parser_lex(parser); @@ -12655,7 +12760,7 @@ parse_value_expression(pm_parser_t *parser, pm_binding_power_t binding_power, ui * work in all cases, it may need to be refactored later. But it appears to work * for now. */ -static inline bool +static PRISM_INLINE bool token_begins_expression_p(pm_token_type_t type) { switch (type) { case PM_TOKEN_EQUAL_GREATER: @@ -13405,7 +13510,7 @@ parse_statements(pm_parser_t *parser, pm_context_t context, uint16_t depth) { // This is an inlined version of accept1 because the error that we // want to add has varargs. If this happens again, we should // probably extract a helper function. - PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_type_human(parser->current.type)); + PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type)); parser->previous.start = parser->previous.end; parser->previous.type = 0; } @@ -13450,7 +13555,7 @@ pm_hash_key_static_literals_add(pm_parser_t *parser, pm_static_literals_t *liter pm_line_offset_list_line_column(&parser->line_offsets, PM_NODE_START(node), parser->start_line).line ); - pm_buffer_free(&buffer); + pm_buffer_cleanup(&buffer); } } @@ -13595,7 +13700,7 @@ parse_assocs(pm_parser_t *parser, pm_static_literals_t *literals, pm_node_t *nod return contains_keyword_splat; } -static inline bool +static PRISM_INLINE bool argument_allowed_for_bare_hash(pm_parser_t *parser, pm_node_t *argument) { if (pm_symbol_node_label_p(parser, argument)) { return true; @@ -13622,7 +13727,7 @@ argument_allowed_for_bare_hash(pm_parser_t *parser, pm_node_t *argument) { /** * Append an argument to a list of arguments. */ -static inline void +static PRISM_INLINE void parse_arguments_append(pm_parser_t *parser, pm_arguments_t *arguments, pm_node_t *argument) { if (arguments->arguments == NULL) { arguments->arguments = pm_arguments_node_create(parser); @@ -14008,7 +14113,7 @@ update_parameter_state(pm_parser_t *parser, pm_token_t *token, pm_parameters_ord return true; } -static inline void +static PRISM_INLINE void parse_parameters_handle_trailing_comma( pm_parser_t *parser, pm_parameters_node_t *params, @@ -14548,7 +14653,7 @@ typedef enum { * Parse any number of rescue clauses. This will form a linked list of if * nodes pointing to each other from the top. */ -static inline void +static PRISM_INLINE void parse_rescues(pm_parser_t *parser, size_t opening_newline_index, const pm_token_t *opening, pm_begin_node_t *parent_node, pm_rescues_type_t type, uint16_t depth) { pm_rescue_node_t *current = NULL; @@ -15006,6 +15111,16 @@ parse_block(pm_parser_t *parser, uint16_t depth) { */ static bool parse_arguments_list(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_block, uint8_t flags, uint16_t depth) { + /* Fast path: if the current token can't begin an expression and isn't + * a parenthesis, block opener, or splat/block-pass operator, there are + * no arguments to parse. */ + if ( + !token_begins_expression_p(parser->current.type) && + !match6(parser, PM_TOKEN_PARENTHESIS_LEFT, PM_TOKEN_KEYWORD_DO, PM_TOKEN_KEYWORD_DO_BLOCK, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR, PM_TOKEN_UAMPERSAND) + ) { + return false; + } + bool found = false; bool parsed_command_args = false; @@ -15020,7 +15135,7 @@ parse_arguments_list(pm_parser_t *parser, pm_arguments_t *arguments, bool accept parse_arguments(parser, arguments, accepts_block, PM_TOKEN_PARENTHESIS_RIGHT, (uint8_t) (flags & ~PM_PARSE_ACCEPTS_DO_BLOCK), (uint16_t) (depth + 1)); if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) { - PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_ARGUMENT_TERM_PAREN, pm_token_type_human(parser->current.type)); + PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_ARGUMENT_TERM_PAREN, pm_token_str(parser->current.type)); parser->previous.start = parser->previous.end; parser->previous.type = 0; } @@ -15042,7 +15157,7 @@ parse_arguments_list(pm_parser_t *parser, pm_arguments_t *arguments, bool accept // then we have a trailing comma where we need to check whether it is // allowed or not. if (parser->previous.type == PM_TOKEN_COMMA && !match1(parser, PM_TOKEN_SEMICOLON)) { - PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_EXPECT_ARGUMENT, pm_token_type_human(parser->current.type)); + PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_EXPECT_ARGUMENT, pm_token_str(parser->current.type)); } pm_accepts_block_stack_pop(parser); @@ -15321,7 +15436,7 @@ pop_block_exits(pm_parser_t *parser, pm_node_list_t *previous_block_exits) { } } -static inline pm_node_t * +static PRISM_INLINE pm_node_t * parse_predicate(pm_parser_t *parser, pm_binding_power_t binding_power, pm_context_t context, pm_token_t *then_keyword, uint16_t depth) { context_push(parser, PM_CONTEXT_PREDICATE); pm_diagnostic_id_t error_id = context == PM_CONTEXT_IF ? PM_ERR_CONDITIONAL_IF_PREDICATE : PM_ERR_CONDITIONAL_UNLESS_PREDICATE; @@ -15343,7 +15458,7 @@ parse_predicate(pm_parser_t *parser, pm_binding_power_t binding_power, pm_contex return predicate; } -static inline pm_node_t * +static PRISM_INLINE pm_node_t * parse_conditional(pm_parser_t *parser, pm_context_t context, size_t opening_newline_index, bool if_after_else, uint16_t depth) { pm_node_list_t current_block_exits = { 0 }; pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits); @@ -15542,7 +15657,7 @@ PM_STATIC_ASSERT(__LINE__, ((int) PM_STRING_FLAGS_FORCED_UTF8_ENCODING) == ((int * If the encoding was explicitly set through the lexing process, then we need * to potentially mark the string's flags to indicate how to encode it. */ -static inline pm_node_flags_t +static PRISM_INLINE pm_node_flags_t parse_unescaped_encoding(const pm_parser_t *parser) { if (parser->explicit_encoding != NULL) { if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) { @@ -15859,7 +15974,7 @@ parse_symbol(pm_parser_t *parser, pm_lex_mode_t *lex_mode, pm_lex_state_t next_s * Parse an argument to undef which can either be a bare word, a symbol, a * constant, or an interpolated symbol. */ -static inline pm_node_t * +static PRISM_INLINE pm_node_t * parse_undef_argument(pm_parser_t *parser, uint16_t depth) { switch (parser->current.type) { case PM_CASE_OPERATOR: @@ -15894,7 +16009,7 @@ parse_undef_argument(pm_parser_t *parser, uint16_t depth) { * we need to set the lex state to PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM * between the first and second arguments. */ -static inline pm_node_t * +static PRISM_INLINE pm_node_t * parse_alias_argument(pm_parser_t *parser, bool first, uint16_t depth) { switch (parser->current.type) { case PM_CASE_OPERATOR: @@ -16002,7 +16117,7 @@ parse_variable_call(pm_parser_t *parser) { * parser. If it does not match a valid method definition name, then a missing * token is returned. */ -static inline pm_token_t +static PRISM_INLINE pm_token_t parse_method_definition_name(pm_parser_t *parser) { switch (parser->current.type) { case PM_CASE_KEYWORD: @@ -16019,7 +16134,7 @@ parse_method_definition_name(pm_parser_t *parser) { parser_lex(parser); return parser->previous; default: - PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_DEF_NAME, pm_token_type_human(parser->current.type)); + PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_DEF_NAME, pm_token_str(parser->current.type)); return (pm_token_t) { .type = 0, .start = parser->current.start, .end = parser->current.end }; } } @@ -16075,7 +16190,7 @@ parse_heredoc_dedent_string(pm_arena_t *arena, pm_string_t *string, size_t commo * If we end up trimming all of the whitespace from a node and it isn't * part of a line continuation, then we'll drop it from the list entirely. */ -static inline bool +static PRISM_INLINE bool heredoc_dedent_discard_string_node(pm_parser_t *parser, pm_string_node_t *string_node) { if (string_node->unescaped.length == 0) { const uint8_t *cursor = parser->start + PM_LOCATION_START(&string_node->content_loc); @@ -16136,7 +16251,7 @@ parse_strings_empty_content(const uint8_t *location) { /** * Parse a set of strings that could be concatenated together. */ -static inline pm_node_t * +static PRISM_INLINE pm_node_t * parse_strings(pm_parser_t *parser, pm_node_t *current, bool accepts_label, uint16_t depth) { assert(parser->current.type == PM_TOKEN_STRING_BEGIN); bool concating = false; @@ -16221,7 +16336,7 @@ parse_strings(pm_parser_t *parser, pm_node_t *current, bool accepts_label, uint1 } else if (accept1(parser, PM_TOKEN_STRING_END)) { node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped)); } else { - PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_STRING_LITERAL_TERM, pm_token_type_human(parser->previous.type)); + PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_STRING_LITERAL_TERM, pm_token_str(parser->previous.type)); parser->previous.start = parser->previous.end; parser->previous.type = 0; node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped)); @@ -16858,7 +16973,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm first_node = parse_expression(parser, PM_BINDING_POWER_MAX, PM_PARSE_ACCEPTS_DO_BLOCK | PM_PARSE_ACCEPTS_LABEL, PM_ERR_PATTERN_HASH_KEY_LABEL, (uint16_t) (depth + 1)); break; default: { - PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_PATTERN_HASH_KEY, pm_token_type_human(parser->current.type)); + PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_PATTERN_HASH_KEY, pm_token_str(parser->current.type)); parser_lex(parser); first_node = UP(pm_missing_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous))); @@ -17287,7 +17402,7 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag * from its start bounds. If it's a compound node, then we will recursively * apply this function to its value. */ -static inline void +static PRISM_INLINE void parse_negative_numeric(pm_node_t *node) { switch (PM_NODE_TYPE(node)) { case PM_INTEGER_NODE: { @@ -17331,22 +17446,22 @@ static void pm_parser_err_prefix(pm_parser_t *parser, pm_diagnostic_id_t diag_id) { switch (diag_id) { case PM_ERR_HASH_KEY: { - PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, diag_id, pm_token_type_human(parser->previous.type)); + PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, diag_id, pm_token_str(parser->previous.type)); break; } case PM_ERR_HASH_VALUE: case PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR: { - PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, diag_id, pm_token_type_human(parser->current.type)); + PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, diag_id, pm_token_str(parser->current.type)); break; } case PM_ERR_UNARY_RECEIVER: { - const char *human = (parser->current.type == PM_TOKEN_EOF ? "end-of-input" : pm_token_type_human(parser->current.type)); + const char *human = (parser->current.type == PM_TOKEN_EOF ? "end-of-input" : pm_token_str(parser->current.type)); PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, diag_id, human, parser->previous.start[0]); break; } case PM_ERR_UNARY_DISALLOWED: case PM_ERR_EXPECT_ARGUMENT: { - PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, diag_id, pm_token_type_human(parser->current.type)); + PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, diag_id, pm_token_str(parser->current.type)); break; } default: @@ -17547,7 +17662,7 @@ parse_yield(pm_parser_t *parser, const pm_node_t *node) { * Determine if a given call node looks like a "command", which means it has * arguments but does not have parentheses. */ -static inline bool +static PRISM_INLINE bool pm_call_node_command_p(const pm_call_node_t *node) { return ( (node->opening_loc.length == 0) && @@ -17639,7 +17754,7 @@ pm_block_call_p(const pm_node_t *node) { /** * Parse an expression that begins with the previous node that we just lexed. */ -static inline pm_node_t * +static PRISM_INLINE pm_node_t * parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) { switch (parser->current.type) { case PM_TOKEN_BRACKET_LEFT_ARRAY: { @@ -17669,7 +17784,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, u } else { // If there was no comma, then we need to add a syntax // error. - PM_PARSER_ERR_FORMAT(parser, PM_TOKEN_END(parser, &parser->previous), 0, PM_ERR_ARRAY_SEPARATOR, pm_token_type_human(parser->current.type)); + PM_PARSER_ERR_FORMAT(parser, PM_TOKEN_END(parser, &parser->previous), 0, PM_ERR_ARRAY_SEPARATOR, pm_token_str(parser->current.type)); parser->previous.start = parser->previous.end; parser->previous.type = 0; } @@ -17745,7 +17860,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, u accept1(parser, PM_TOKEN_NEWLINE); if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) { - PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_ARRAY_TERM, pm_token_type_human(parser->current.type)); + PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_ARRAY_TERM, pm_token_str(parser->current.type)); parser->previous.start = parser->previous.end; parser->previous.type = 0; } @@ -17888,7 +18003,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, u // If we didn't find a terminator and we didn't find a right // parenthesis, then this is a syntax error. if (!terminator_found && !match1(parser, PM_TOKEN_EOF)) { - PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_type_human(parser->current.type)); + PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type)); } // Parse each statement within the parentheses. @@ -17919,7 +18034,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, u } else if (!match1(parser, PM_TOKEN_EOF)) { // If we're at the end of the file, then we're going to add // an error after this for the ) anyway. - PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_type_human(parser->current.type)); + PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type)); } } @@ -18678,7 +18793,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, u // Reject `foo && return bar`. if (!(flags & PM_PARSE_ACCEPTS_COMMAND_CALL) && arguments.arguments != NULL) { - PM_PARSER_ERR_TOKEN_FORMAT(parser, &next, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_type_human(next.type)); + PM_PARSER_ERR_TOKEN_FORMAT(parser, &next, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(next.type)); } } } @@ -18759,7 +18874,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, u pm_parser_scope_push(parser, true); if (!match2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) { - PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_SINGLETON_CLASS_DELIMITER, pm_token_type_human(parser->current.type)); + PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_SINGLETON_CLASS_DELIMITER, pm_token_str(parser->current.type)); } pm_node_t *statements = NULL; @@ -18964,7 +19079,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, u name = parse_method_definition_name(parser); } else { if (!valid_name) { - PM_PARSER_ERR_TOKEN_FORMAT(parser, &identifier, PM_ERR_DEF_NAME, pm_token_type_human(identifier.type)); + PM_PARSER_ERR_TOKEN_FORMAT(parser, &identifier, PM_ERR_DEF_NAME, pm_token_str(identifier.type)); } name = identifier; @@ -19038,7 +19153,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, u context_pop(parser); if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) { - PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_DEF_PARAMS_TERM_PAREN, pm_token_type_human(parser->current.type)); + PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_DEF_PARAMS_TERM_PAREN, pm_token_str(parser->current.type)); parser->previous.start = parser->previous.end; parser->previous.type = 0; } @@ -19150,7 +19265,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, u // `def f = def g = foo bar`) is a command assignment and // cannot appear as a def body. if (PM_NODE_TYPE_P(statement, PM_DEF_NODE) && pm_command_call_value_p(statement)) { - PM_PARSER_ERR_NODE_FORMAT(parser, statement, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_type_human(parser->current.type)); + PM_PARSER_ERR_NODE_FORMAT(parser, statement, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type)); } pm_statements_node_body_append(parser, (pm_statements_node_t *) statements, statement, false); @@ -19325,7 +19440,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, u do_keyword = parser->previous; } else { if (!match2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE)) { - PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_FOR_DELIMITER, pm_token_type_human(parser->current.type)); + PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_FOR_DELIMITER, pm_token_str(parser->current.type)); } } @@ -20357,12 +20472,12 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, u // If we get here, then we are assuming this token is closing a // parent context, so we'll indicate that to the user so that // they know how we behaved. - PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT, pm_token_type_human(parser->current.type), context_human(recoverable)); + PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT, pm_token_str(parser->current.type), context_human(recoverable)); } else if (diag_id == PM_ERR_CANNOT_PARSE_EXPRESSION) { // We're going to make a special case here, because "cannot // parse expression" is pretty generic, and we know here that we // have an unexpected token. - PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE, pm_token_type_human(parser->current.type)); + PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE, pm_token_str(parser->current.type)); } else { pm_parser_err_prefix(parser, diag_id); } @@ -20390,7 +20505,7 @@ parse_assignment_value(pm_parser_t *parser, pm_binding_power_t previous_binding_ // operators with higher binding power. If we find one, emit an error // and skip the operator and its right-hand side. if (pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_MODIFIER && (pm_command_call_value_p(value) || pm_block_call_p(value))) { - PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_type_human(parser->current.type)); + PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type)); parser_lex(parser); parse_expression(parser, pm_binding_powers[parser->previous.type].right, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1)); } @@ -20496,7 +20611,7 @@ parse_assignment_values(pm_parser_t *parser, pm_binding_power_t previous_binding // operators with higher binding power. If we find one, emit an error // and skip the operator and its right-hand side. if (single_value && pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_MODIFIER && (pm_command_call_value_p(value) || pm_block_call_p(value))) { - PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_type_human(parser->current.type)); + PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type)); parser_lex(parser); parse_expression(parser, pm_binding_powers[parser->previous.type].right, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1)); } @@ -20551,7 +20666,7 @@ parse_call_operator_write(pm_parser_t *parser, pm_call_node_t *call_node, const } } -static inline const uint8_t * +static PRISM_INLINE const uint8_t * pm_named_capture_escape_hex(pm_buffer_t *unescaped, const uint8_t *cursor, const uint8_t *end) { cursor++; @@ -20572,7 +20687,7 @@ pm_named_capture_escape_hex(pm_buffer_t *unescaped, const uint8_t *cursor, const return cursor; } -static inline const uint8_t * +static PRISM_INLINE const uint8_t * pm_named_capture_escape_octal(pm_buffer_t *unescaped, const uint8_t *cursor, const uint8_t *end) { uint8_t value = (uint8_t) (*cursor - '0'); cursor++; @@ -20591,7 +20706,7 @@ pm_named_capture_escape_octal(pm_buffer_t *unescaped, const uint8_t *cursor, con return cursor; } -static inline const uint8_t * +static PRISM_INLINE const uint8_t * pm_named_capture_escape_unicode(pm_parser_t *parser, pm_buffer_t *unescaped, const uint8_t *cursor, const uint8_t *end, const pm_location_t *error_location) { const uint8_t *start = cursor - 1; cursor++; @@ -20706,7 +20821,7 @@ parse_regular_expression_named_capture(pm_parser_t *parser, const pm_string_t *c // If the name of the capture group isn't a valid identifier, we do // not add it to the local table. if (!pm_slice_is_valid_local(parser, source, source + length)) { - pm_buffer_free(&unescaped); + pm_buffer_cleanup(&unescaped); return; } @@ -20737,7 +20852,7 @@ parse_regular_expression_named_capture(pm_parser_t *parser, const pm_string_t *c // If the local is not already a local but it is a keyword, then we // do not want to add a capture for this. if (pm_local_is_keyword((const char *) source, length)) { - pm_buffer_free(&unescaped); + pm_buffer_cleanup(&unescaped); return; } @@ -20758,7 +20873,7 @@ parse_regular_expression_named_capture(pm_parser_t *parser, const pm_string_t *c pm_node_list_append(parser->arena, &callback_data->match->targets, target); } - pm_buffer_free(&unescaped); + pm_buffer_cleanup(&unescaped); } /** @@ -20783,7 +20898,7 @@ parse_interpolated_regular_expression_named_captures(pm_parser_t *parser, const } } -static inline pm_node_t * +static PRISM_INLINE pm_node_t * parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) { pm_token_t token = parser->current; @@ -21224,7 +21339,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t // In this case we have an operator but we don't know what it's for. // We need to treat it as an error. For now, we'll mark it as an error // and just skip right past it. - PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, pm_token_type_human(parser->current.type)); + PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, pm_token_str(parser->current.type)); return node; } } @@ -21297,7 +21412,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t pm_string_owned_init(&owned, (uint8_t *) memory, total_length); result = parse_interpolated_regular_expression_named_captures(parser, &owned, call, PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED)); - pm_string_free(&owned); + pm_string_cleanup(&owned); } } else if (PM_NODE_TYPE_P(node, PM_REGULAR_EXPRESSION_NODE)) { // If we have a regular expression node, then we can parse @@ -21346,21 +21461,21 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t case PM_RESCUE_MODIFIER_NODE: { pm_rescue_modifier_node_t *cast = (pm_rescue_modifier_node_t *) node; if (PM_NODE_TYPE_P(cast->rescue_expression, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->rescue_expression, PM_MATCH_REQUIRED_NODE)) { - PM_PARSER_ERR_TOKEN_FORMAT(parser, &operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_type_human(operator.type)); + PM_PARSER_ERR_TOKEN_FORMAT(parser, &operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(operator.type)); } break; } case PM_AND_NODE: { pm_and_node_t *cast = (pm_and_node_t *) node; if (PM_NODE_TYPE_P(cast->right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->right, PM_MATCH_REQUIRED_NODE)) { - PM_PARSER_ERR_TOKEN_FORMAT(parser, &operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_type_human(operator.type)); + PM_PARSER_ERR_TOKEN_FORMAT(parser, &operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(operator.type)); } break; } case PM_OR_NODE: { pm_or_node_t *cast = (pm_or_node_t *) node; if (PM_NODE_TYPE_P(cast->right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->right, PM_MATCH_REQUIRED_NODE)) { - PM_PARSER_ERR_TOKEN_FORMAT(parser, &operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_type_human(operator.type)); + PM_PARSER_ERR_TOKEN_FORMAT(parser, &operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(operator.type)); } break; } @@ -21399,21 +21514,21 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t case PM_RESCUE_MODIFIER_NODE: { pm_rescue_modifier_node_t *cast = (pm_rescue_modifier_node_t *) node; if (PM_NODE_TYPE_P(cast->rescue_expression, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->rescue_expression, PM_MATCH_REQUIRED_NODE)) { - PM_PARSER_ERR_TOKEN_FORMAT(parser, &operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_type_human(operator.type)); + PM_PARSER_ERR_TOKEN_FORMAT(parser, &operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(operator.type)); } break; } case PM_AND_NODE: { pm_and_node_t *cast = (pm_and_node_t *) node; if (PM_NODE_TYPE_P(cast->right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->right, PM_MATCH_REQUIRED_NODE)) { - PM_PARSER_ERR_TOKEN_FORMAT(parser, &operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_type_human(operator.type)); + PM_PARSER_ERR_TOKEN_FORMAT(parser, &operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(operator.type)); } break; } case PM_OR_NODE: { pm_or_node_t *cast = (pm_or_node_t *) node; if (PM_NODE_TYPE_P(cast->right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->right, PM_MATCH_REQUIRED_NODE)) { - PM_PARSER_ERR_TOKEN_FORMAT(parser, &operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_type_human(operator.type)); + PM_PARSER_ERR_TOKEN_FORMAT(parser, &operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(operator.type)); } break; } @@ -21434,7 +21549,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t break; } default: { - PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_MESSAGE, pm_token_type_human(parser->current.type)); + PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_MESSAGE, pm_token_str(parser->current.type)); message = (pm_token_t) { .type = 0, .start = parser->previous.end, .end = parser->previous.end }; } } @@ -21848,7 +21963,7 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t // If this is a non-assoc operator and we are about to parse the // exact same operator, then we need to add an error. if (match1(parser, current_token_type)) { - PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_NON_ASSOCIATIVE_OPERATOR, pm_token_type_human(parser->current.type), pm_token_type_human(current_token_type)); + PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_NON_ASSOCIATIVE_OPERATOR, pm_token_str(parser->current.type), pm_token_str(current_token_type)); break; } @@ -21861,7 +21976,7 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t // if (PM_NODE_TYPE_P(node, PM_RANGE_NODE) && ((pm_range_node_t *) node)->right == NULL) { if (match4(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_DOT, PM_TOKEN_AMPERSAND_DOT)) { - PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_NON_ASSOCIATIVE_OPERATOR, pm_token_type_human(parser->current.type), pm_token_type_human(current_token_type)); + PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_NON_ASSOCIATIVE_OPERATOR, pm_token_str(parser->current.type), pm_token_str(current_token_type)); break; } @@ -22140,7 +22255,7 @@ pm_parser_init_shebang(pm_parser_t *parser, const pm_options_t *options, const c /** * Initialize a parser with the given start and end pointers. */ -PRISM_EXPORTED_FUNCTION void +void pm_parser_init(pm_arena_t *arena, pm_parser_t *parser, const uint8_t *source, size_t size, const pm_options_t *options) { assert(arena != NULL); assert(source != NULL); @@ -22176,7 +22291,7 @@ pm_parser_init(pm_arena_t *arena, pm_parser_t *parser, const uint8_t *source, si .encoding = PM_ENCODING_UTF_8_ENTRY, .encoding_changed_callback = NULL, .encoding_comment_start = source, - .lex_callback = NULL, + .lex_callback = { 0 }, .filepath = { 0 }, .constant_pool = { 0 }, .line_offsets = { 0 }, @@ -22257,7 +22372,7 @@ pm_parser_init(pm_arena_t *arena, pm_parser_t *parser, const uint8_t *source, si if (parser->parsing_eval) parser->warn_mismatched_indentation = false; for (size_t scope_index = 0; scope_index < options->scopes_count; scope_index++) { - const pm_options_scope_t *scope = pm_options_scope_get(options, scope_index); + const pm_options_scope_t *scope = pm_options_scope(options, scope_index); pm_parser_scope_push(parser, scope_index == 0); // Scopes given from the outside are not allowed to have numbered @@ -22265,7 +22380,7 @@ pm_parser_init(pm_arena_t *arena, pm_parser_t *parser, const uint8_t *source, si parser->current_scope->parameters = ((pm_scope_parameters_t) scope->forwarding) | PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED; for (size_t local_index = 0; local_index < scope->locals_count; local_index++) { - const pm_string_t *local = pm_options_scope_local_get(scope, local_index); + const pm_string_t *local = pm_options_scope_local(scope, local_index); const uint8_t *source = pm_string_source(local); size_t length = pm_string_length(local); @@ -22398,21 +22513,28 @@ pm_parser_init(pm_arena_t *arena, pm_parser_t *parser, const uint8_t *source, si } /** - * Register a callback that will be called whenever prism changes the encoding - * it is using to parse based on the magic comment. + * Allocate and initialize a parser with the given start and end pointers. + * + * The resulting parser must eventually be freed with `pm_parser_free()`. The + * arena is caller-owned and must outlive the parser — `pm_parser_cleanup()` + * does not free the arena. */ -PRISM_EXPORTED_FUNCTION void -pm_parser_register_encoding_changed_callback(pm_parser_t *parser, pm_encoding_changed_callback_t callback) { - parser->encoding_changed_callback = callback; +pm_parser_t * +pm_parser_new(pm_arena_t *arena, const uint8_t *source, size_t size, const pm_options_t *options) { + pm_parser_t *parser = (pm_parser_t *) xmalloc(sizeof(pm_parser_t)); + if (parser == NULL) abort(); + + pm_parser_init(arena, parser, source, size, options); + return parser; } /** * Free any memory associated with the given parser. */ -PRISM_EXPORTED_FUNCTION void -pm_parser_free(pm_parser_t *parser) { - pm_string_free(&parser->filepath); - pm_arena_free(&parser->metadata_arena); +void +pm_parser_cleanup(pm_parser_t *parser) { + pm_string_cleanup(&parser->filepath); + pm_arena_cleanup(&parser->metadata_arena); while (parser->current_scope != NULL) { // Normally, popping the scope doesn't free the locals since it is @@ -22427,6 +22549,15 @@ pm_parser_free(pm_parser_t *parser) { } } +/** + * Free both the memory held by the given parser and the parser itself. + */ +void +pm_parser_free(pm_parser_t *parser) { + pm_parser_cleanup(parser); + xfree_sized(parser, sizeof(pm_parser_t)); +} + /** * Returns true if the given diagnostic ID represents an error that cannot be * fixed by appending more input. These are errors where the existing source @@ -22592,116 +22723,40 @@ pm_parse_continuable(pm_parser_t *parser) { /** * Parse the Ruby source associated with the given parser and return the tree. */ -PRISM_EXPORTED_FUNCTION pm_node_t * +pm_node_t * pm_parse(pm_parser_t *parser) { pm_node_t *node = parse_program(parser); pm_parse_continuable(parser); return node; } -/** - * Read into the stream until the gets callback returns false. If the last read - * line from the stream matches an __END__ marker, then halt and return false, - * otherwise return true. - */ -static bool -pm_parse_stream_read(pm_buffer_t *buffer, void *stream, pm_parse_stream_fgets_t *stream_fgets, pm_parse_stream_feof_t *stream_feof) { -#define LINE_SIZE 4096 - char line[LINE_SIZE]; - - while (memset(line, '\n', LINE_SIZE), stream_fgets(line, LINE_SIZE, stream) != NULL) { - size_t length = LINE_SIZE; - while (length > 0 && line[length - 1] == '\n') length--; - - if (length == LINE_SIZE) { - // If we read a line that is the maximum size and it doesn't end - // with a newline, then we'll just append it to the buffer and - // continue reading. - length--; - pm_buffer_append_string(buffer, line, length); - continue; - } - - // Append the line to the buffer. - length--; - pm_buffer_append_string(buffer, line, length); - - // Check if the line matches the __END__ marker. If it does, then stop - // reading and return false. In most circumstances, this means we should - // stop reading from the stream so that the DATA constant can pick it - // up. - switch (length) { - case 7: - if (strncmp(line, "__END__", 7) == 0) return false; - break; - case 8: - if (strncmp(line, "__END__\n", 8) == 0) return false; - break; - case 9: - if (strncmp(line, "__END__\r\n", 9) == 0) return false; - break; - } - - // All data should be read via gets. If the string returned by gets - // _doesn't_ end with a newline, then we assume we hit EOF condition. - if (stream_feof(stream)) { - break; - } - } - - return true; -#undef LINE_SIZE -} - /** * Parse a stream of Ruby source and return the tree. * * Prism is designed around having the entire source in memory at once, but you * can stream stdin in to Ruby so we need to support a streaming API. */ -PRISM_EXPORTED_FUNCTION pm_node_t * -pm_parse_stream(pm_arena_t *arena, pm_parser_t *parser, pm_buffer_t *buffer, void *stream, pm_parse_stream_fgets_t *stream_fgets, pm_parse_stream_feof_t *stream_feof, const pm_options_t *options) { - pm_buffer_init(buffer); +pm_node_t * +pm_parse_stream(pm_parser_t **parser, pm_arena_t *arena, pm_source_t *source, const pm_options_t *options) { + bool eof = pm_source_stream_read(source); - bool eof = pm_parse_stream_read(buffer, stream, stream_fgets, stream_feof); + pm_parser_t *tmp = pm_parser_new(arena, pm_source_source(source), pm_source_length(source), options); + pm_node_t *node = pm_parse(tmp); - pm_parser_init(arena, parser, (const uint8_t *) pm_buffer_value(buffer), pm_buffer_length(buffer), options); - pm_node_t *node = pm_parse(parser); + while (!eof && tmp->error_list.size > 0) { + eof = pm_source_stream_read(source); - while (!eof && parser->error_list.size > 0) { - eof = pm_parse_stream_read(buffer, stream, stream_fgets, stream_feof); + pm_parser_free(tmp); + pm_arena_cleanup(arena); - pm_parser_free(parser); - pm_arena_free(arena); - pm_parser_init(arena, parser, (const uint8_t *) pm_buffer_value(buffer), pm_buffer_length(buffer), options); - node = pm_parse(parser); + tmp = pm_parser_new(arena, pm_source_source(source), pm_source_length(source), options); + node = pm_parse(tmp); } + *parser = tmp; return node; } -/** - * Parse the source and return true if it parses without errors or warnings. - */ -PRISM_EXPORTED_FUNCTION bool -pm_parse_success_p(const uint8_t *source, size_t size, const char *data) { - pm_options_t options = { 0 }; - pm_options_read(&options, data); - - pm_arena_t arena = { 0 }; - pm_parser_t parser; - pm_parser_init(&arena, &parser, source, size, &options); - - pm_parse(&parser); - - bool result = parser.error_list.size == 0; - pm_parser_free(&parser); - pm_arena_free(&arena); - pm_options_free(&options); - - return result; -} - #undef PM_CASE_KEYWORD #undef PM_CASE_OPERATOR #undef PM_CASE_WRITABLE @@ -22712,7 +22767,7 @@ pm_parse_success_p(const uint8_t *source, size_t size, const char *data) { // PRISM_EXCLUDE_SERIALIZATION define. #ifndef PRISM_EXCLUDE_SERIALIZATION -static inline void +static PRISM_INLINE void pm_serialize_header(pm_buffer_t *buffer) { pm_buffer_append_string(buffer, "PRISM", 5); pm_buffer_append_byte(buffer, PRISM_VERSION_MAJOR); @@ -22724,7 +22779,7 @@ pm_serialize_header(pm_buffer_t *buffer) { /** * Serialize the AST represented by the given node to the given buffer. */ -PRISM_EXPORTED_FUNCTION void +void pm_serialize(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) { pm_serialize_header(buffer); pm_serialize_content(parser, node, buffer); @@ -22735,7 +22790,7 @@ pm_serialize(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) { * Parse and serialize the AST represented by the given source to the given * buffer. */ -PRISM_EXPORTED_FUNCTION void +void pm_serialize_parse(pm_buffer_t *buffer, const uint8_t *source, size_t size, const char *data) { pm_options_t options = { 0 }; pm_options_read(&options, data); @@ -22750,38 +22805,36 @@ pm_serialize_parse(pm_buffer_t *buffer, const uint8_t *source, size_t size, cons pm_serialize_content(&parser, node, buffer); pm_buffer_append_byte(buffer, '\0'); - pm_parser_free(&parser); - pm_arena_free(&arena); - pm_options_free(&options); + pm_parser_cleanup(&parser); + pm_arena_cleanup(&arena); + pm_options_cleanup(&options); } /** * Parse and serialize the AST represented by the source that is read out of the * given stream into to the given buffer. */ -PRISM_EXPORTED_FUNCTION void -pm_serialize_parse_stream(pm_buffer_t *buffer, void *stream, pm_parse_stream_fgets_t *stream_fgets, pm_parse_stream_feof_t *stream_feof, const char *data) { +void +pm_serialize_parse_stream(pm_buffer_t *buffer, pm_source_t *source, const char *data) { pm_arena_t arena = { 0 }; - pm_parser_t parser; + pm_parser_t *parser; pm_options_t options = { 0 }; pm_options_read(&options, data); - pm_buffer_t parser_buffer; - pm_node_t *node = pm_parse_stream(&arena, &parser, &parser_buffer, stream, stream_fgets, stream_feof, &options); + pm_node_t *node = pm_parse_stream(&parser, &arena, source, &options); pm_serialize_header(buffer); - pm_serialize_content(&parser, node, buffer); + pm_serialize_content(parser, node, buffer); pm_buffer_append_byte(buffer, '\0'); - pm_buffer_free(&parser_buffer); - pm_parser_free(&parser); - pm_arena_free(&arena); - pm_options_free(&options); + pm_parser_free(parser); + pm_arena_cleanup(&arena); + pm_options_cleanup(&options); } /** * Parse and serialize the comments in the given source to the given buffer. */ -PRISM_EXPORTED_FUNCTION void +void pm_serialize_parse_comments(pm_buffer_t *buffer, const uint8_t *source, size_t size, const char *data) { pm_options_t options = { 0 }; pm_options_read(&options, data); @@ -22796,172 +22849,9 @@ pm_serialize_parse_comments(pm_buffer_t *buffer, const uint8_t *source, size_t s pm_buffer_append_varsint(buffer, parser.start_line); pm_serialize_comment_list(&parser.comment_list, buffer); - pm_parser_free(&parser); - pm_arena_free(&arena); - pm_options_free(&options); + pm_parser_cleanup(&parser); + pm_arena_cleanup(&arena); + pm_options_cleanup(&options); } #endif - -/******************************************************************************/ -/* Slice queries for the Ruby API */ -/******************************************************************************/ - -/** The category of slice returned from pm_slice_type. */ -typedef enum { - /** Returned when the given encoding name is invalid. */ - PM_SLICE_TYPE_ERROR = -1, - - /** Returned when no other types apply to the slice. */ - PM_SLICE_TYPE_NONE, - - /** Returned when the slice is a valid local variable name. */ - PM_SLICE_TYPE_LOCAL, - - /** Returned when the slice is a valid constant name. */ - PM_SLICE_TYPE_CONSTANT, - - /** Returned when the slice is a valid method name. */ - PM_SLICE_TYPE_METHOD_NAME -} pm_slice_type_t; - -/** - * Check that the slice is a valid local variable name or constant. - */ -pm_slice_type_t -pm_slice_type(const uint8_t *source, size_t length, const char *encoding_name) { - // first, get the right encoding object - const pm_encoding_t *encoding = pm_encoding_find((const uint8_t *) encoding_name, (const uint8_t *) (encoding_name + strlen(encoding_name))); - if (encoding == NULL) return PM_SLICE_TYPE_ERROR; - - // check that there is at least one character - if (length == 0) return PM_SLICE_TYPE_NONE; - - size_t width; - if ((width = encoding->alpha_char(source, (ptrdiff_t) length)) != 0) { - // valid because alphabetical - } else if (*source == '_') { - // valid because underscore - width = 1; - } else if ((*source >= 0x80) && ((width = encoding->char_width(source, (ptrdiff_t) length)) > 0)) { - // valid because multibyte - } else { - // invalid because no match - return PM_SLICE_TYPE_NONE; - } - - // determine the type of the slice based on the first character - const uint8_t *end = source + length; - pm_slice_type_t result = encoding->isupper_char(source, end - source) ? PM_SLICE_TYPE_CONSTANT : PM_SLICE_TYPE_LOCAL; - - // next, iterate through all of the bytes of the string to ensure that they - // are all valid identifier characters - source += width; - - while (source < end) { - if ((width = encoding->alnum_char(source, end - source)) != 0) { - // valid because alphanumeric - source += width; - } else if (*source == '_') { - // valid because underscore - source++; - } else if ((*source >= 0x80) && ((width = encoding->char_width(source, end - source)) > 0)) { - // valid because multibyte - source += width; - } else { - // invalid because no match - break; - } - } - - // accept a ! or ? at the end of the slice as a method name - if (*source == '!' || *source == '?' || *source == '=') { - source++; - result = PM_SLICE_TYPE_METHOD_NAME; - } - - // valid if we are at the end of the slice - return source == end ? result : PM_SLICE_TYPE_NONE; -} - -/** - * Check that the slice is a valid local variable name. - */ -PRISM_EXPORTED_FUNCTION pm_string_query_t -pm_string_query_local(const uint8_t *source, size_t length, const char *encoding_name) { - switch (pm_slice_type(source, length, encoding_name)) { - case PM_SLICE_TYPE_ERROR: - return PM_STRING_QUERY_ERROR; - case PM_SLICE_TYPE_NONE: - case PM_SLICE_TYPE_CONSTANT: - case PM_SLICE_TYPE_METHOD_NAME: - return PM_STRING_QUERY_FALSE; - case PM_SLICE_TYPE_LOCAL: - return PM_STRING_QUERY_TRUE; - } - - assert(false && "unreachable"); - return PM_STRING_QUERY_FALSE; -} - -/** - * Check that the slice is a valid constant name. - */ -PRISM_EXPORTED_FUNCTION pm_string_query_t -pm_string_query_constant(const uint8_t *source, size_t length, const char *encoding_name) { - switch (pm_slice_type(source, length, encoding_name)) { - case PM_SLICE_TYPE_ERROR: - return PM_STRING_QUERY_ERROR; - case PM_SLICE_TYPE_NONE: - case PM_SLICE_TYPE_LOCAL: - case PM_SLICE_TYPE_METHOD_NAME: - return PM_STRING_QUERY_FALSE; - case PM_SLICE_TYPE_CONSTANT: - return PM_STRING_QUERY_TRUE; - } - - assert(false && "unreachable"); - return PM_STRING_QUERY_FALSE; -} - -/** - * Check that the slice is a valid method name. - */ -PRISM_EXPORTED_FUNCTION pm_string_query_t -pm_string_query_method_name(const uint8_t *source, size_t length, const char *encoding_name) { -#define B(p) ((p) ? PM_STRING_QUERY_TRUE : PM_STRING_QUERY_FALSE) -#define C1(c) (*source == c) -#define C2(s) (memcmp(source, s, 2) == 0) -#define C3(s) (memcmp(source, s, 3) == 0) - - switch (pm_slice_type(source, length, encoding_name)) { - case PM_SLICE_TYPE_ERROR: - return PM_STRING_QUERY_ERROR; - case PM_SLICE_TYPE_NONE: - break; - case PM_SLICE_TYPE_LOCAL: - // numbered parameters are not valid method names - return B((length != 2) || (source[0] != '_') || (source[1] == '0') || !pm_char_is_decimal_digit(source[1])); - case PM_SLICE_TYPE_CONSTANT: - // all constants are valid method names - case PM_SLICE_TYPE_METHOD_NAME: - // all method names are valid method names - return PM_STRING_QUERY_TRUE; - } - - switch (length) { - case 1: - return B(C1('&') || C1('`') || C1('!') || C1('^') || C1('>') || C1('<') || C1('-') || C1('%') || C1('|') || C1('+') || C1('/') || C1('*') || C1('~')); - case 2: - return B(C2("!=") || C2("!~") || C2("[]") || C2("==") || C2("=~") || C2(">=") || C2(">>") || C2("<=") || C2("<<") || C2("**")); - case 3: - return B(C3("===") || C3("<=>") || C3("[]=")); - default: - return PM_STRING_QUERY_FALSE; - } - -#undef B -#undef C1 -#undef C2 -#undef C3 -} diff --git a/prism/prism.h b/prism/prism.h index 76733b8aaf9f35..b342bb32c671d7 100644 --- a/prism/prism.h +++ b/prism/prism.h @@ -10,309 +10,21 @@ extern "C" { #endif -#include "prism/defines.h" -#include "prism/util/pm_arena.h" -#include "prism/util/pm_buffer.h" -#include "prism/util/pm_char.h" -#include "prism/util/pm_integer.h" -#include "prism/util/pm_memchr.h" -#include "prism/util/pm_strncasecmp.h" -#include "prism/util/pm_strpbrk.h" +#include "prism/arena.h" #include "prism/ast.h" +#include "prism/buffer.h" #include "prism/diagnostic.h" +#include "prism/json.h" #include "prism/node.h" #include "prism/options.h" #include "prism/parser.h" #include "prism/prettyprint.h" -#include "prism/regexp.h" -#include "prism/static_literals.h" +#include "prism/serialize.h" +#include "prism/source.h" +#include "prism/stream.h" +#include "prism/string_query.h" #include "prism/version.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef _WIN32 -#include -#endif - -/** - * The prism version and the serialization format. - * - * @returns The prism version as a constant string. - */ -PRISM_EXPORTED_FUNCTION const char * pm_version(void); - -/** - * Initialize a parser with the given start and end pointers. - * - * The resulting parser must eventually be freed with `pm_parser_free()`. The - * arena is caller-owned and must outlive the parser — `pm_parser_free()` does - * not free the arena. - * - * @param arena The arena to use for all AST-lifetime allocations. - * @param parser The parser to initialize. - * @param source The source to parse. - * @param size The size of the source. - * @param options The optional options to use when parsing. These options must - * live for the whole lifetime of this parser. - * - * \public \memberof pm_parser - */ -PRISM_EXPORTED_FUNCTION void pm_parser_init(pm_arena_t *arena, pm_parser_t *parser, const uint8_t *source, size_t size, const pm_options_t *options); - -/** - * Register a callback that will be called whenever prism changes the encoding - * it is using to parse based on the magic comment. - * - * @param parser The parser to register the callback with. - * @param callback The callback to register. - * - * \public \memberof pm_parser - */ -PRISM_EXPORTED_FUNCTION void pm_parser_register_encoding_changed_callback(pm_parser_t *parser, pm_encoding_changed_callback_t callback); - -/** - * Free any memory associated with the given parser. - * - * This does not free the `pm_options_t` object that was used to initialize the - * parser. - * - * @param parser The parser to free. - * - * \public \memberof pm_parser - */ -PRISM_EXPORTED_FUNCTION void pm_parser_free(pm_parser_t *parser); - -/** - * Initiate the parser with the given parser. - * - * @param parser The parser to use. - * @return The AST representing the source. - * - * \public \memberof pm_parser - */ -PRISM_EXPORTED_FUNCTION pm_node_t * pm_parse(pm_parser_t *parser); - -/** - * This function is used in pm_parse_stream() to retrieve a line of input from a - * stream. It closely mirrors that of fgets so that fgets can be used as the - * default implementation. - */ -typedef char * (pm_parse_stream_fgets_t)(char *string, int size, void *stream); - -/** - * This function is used in pm_parse_stream to check whether a stream is EOF. - * It closely mirrors that of feof so that feof can be used as the - * default implementation. - */ -typedef int (pm_parse_stream_feof_t)(void *stream); - -/** - * Parse a stream of Ruby source and return the tree. - * - * @param arena The arena to use for all AST-lifetime allocations. - * @param parser The parser to use. - * @param buffer The buffer to use. - * @param stream The stream to parse. - * @param stream_fgets The function to use to read from the stream. - * @param stream_feof The function to use to determine if the stream has hit eof. - * @param options The optional options to use when parsing. - * @return The AST representing the source. - * - * \public \memberof pm_parser - */ -PRISM_EXPORTED_FUNCTION pm_node_t * pm_parse_stream(pm_arena_t *arena, pm_parser_t *parser, pm_buffer_t *buffer, void *stream, pm_parse_stream_fgets_t *stream_fgets, pm_parse_stream_feof_t *stream_feof, const pm_options_t *options); - -// We optionally support serializing to a binary string. For systems that don't -// want or need this functionality, it can be turned off with the -// PRISM_EXCLUDE_SERIALIZATION define. -#ifndef PRISM_EXCLUDE_SERIALIZATION - -/** - * Parse and serialize the AST represented by the source that is read out of the - * given stream into to the given buffer. - * - * @param buffer The buffer to serialize to. - * @param stream The stream to parse. - * @param stream_fgets The function to use to read from the stream. - * @param stream_feof The function to use to tell if the stream has hit eof. - * @param data The optional data to pass to the parser. - */ -PRISM_EXPORTED_FUNCTION void pm_serialize_parse_stream(pm_buffer_t *buffer, void *stream, pm_parse_stream_fgets_t *stream_fgets, pm_parse_stream_feof_t *stream_feof, const char *data); - -/** - * Serialize the given list of comments to the given buffer. - * - * @param list The list of comments to serialize. - * @param buffer The buffer to serialize to. - */ -void pm_serialize_comment_list(pm_list_t *list, pm_buffer_t *buffer); - -/** - * Serialize the name of the encoding to the buffer. - * - * @param encoding The encoding to serialize. - * @param buffer The buffer to serialize to. - */ -void pm_serialize_encoding(const pm_encoding_t *encoding, pm_buffer_t *buffer); - -/** - * Serialize the encoding, metadata, nodes, and constant pool. - * - * @param parser The parser to serialize. - * @param node The node to serialize. - * @param buffer The buffer to serialize to. - */ -void pm_serialize_content(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer); - -/** - * Serialize the AST represented by the given node to the given buffer. - * - * @param parser The parser to serialize. - * @param node The node to serialize. - * @param buffer The buffer to serialize to. - */ -PRISM_EXPORTED_FUNCTION void pm_serialize(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer); - -/** - * Parse the given source to the AST and dump the AST to the given buffer. - * - * @param buffer The buffer to serialize to. - * @param source The source to parse. - * @param size The size of the source. - * @param data The optional data to pass to the parser. - */ -PRISM_EXPORTED_FUNCTION void pm_serialize_parse(pm_buffer_t *buffer, const uint8_t *source, size_t size, const char *data); - -/** - * Parse and serialize the comments in the given source to the given buffer. - * - * @param buffer The buffer to serialize to. - * @param source The source to parse. - * @param size The size of the source. - * @param data The optional data to pass to the parser. - */ -PRISM_EXPORTED_FUNCTION void pm_serialize_parse_comments(pm_buffer_t *buffer, const uint8_t *source, size_t size, const char *data); - -/** - * Lex the given source and serialize to the given buffer. - * - * @param source The source to lex. - * @param size The size of the source. - * @param buffer The buffer to serialize to. - * @param data The optional data to pass to the lexer. - */ -PRISM_EXPORTED_FUNCTION void pm_serialize_lex(pm_buffer_t *buffer, const uint8_t *source, size_t size, const char *data); - -/** - * Parse and serialize both the AST and the tokens represented by the given - * source to the given buffer. - * - * @param buffer The buffer to serialize to. - * @param source The source to parse. - * @param size The size of the source. - * @param data The optional data to pass to the parser. - */ -PRISM_EXPORTED_FUNCTION void pm_serialize_parse_lex(pm_buffer_t *buffer, const uint8_t *source, size_t size, const char *data); - -#endif - -/** - * Parse the source and return true if it parses without errors or warnings. - * - * @param source The source to parse. - * @param size The size of the source. - * @param data The optional data to pass to the parser. - * @return True if the source parses without errors or warnings. - */ -PRISM_EXPORTED_FUNCTION bool pm_parse_success_p(const uint8_t *source, size_t size, const char *data); - -/** - * Returns a string representation of the given token type. - * - * @param token_type The token type to convert to a string. - * @return A string representation of the given token type. - */ -PRISM_EXPORTED_FUNCTION const char * pm_token_type_name(pm_token_type_t token_type); - -/** - * Returns the human name of the given token type. - * - * @param token_type The token type to convert to a human name. - * @return The human name of the given token type. - */ -const char * pm_token_type_human(pm_token_type_t token_type); - -// We optionally support dumping to JSON. For systems that don't want or need -// this functionality, it can be turned off with the PRISM_EXCLUDE_JSON define. -#ifndef PRISM_EXCLUDE_JSON - -/** - * Dump JSON to the given buffer. - * - * @param buffer The buffer to serialize to. - * @param parser The parser that parsed the node. - * @param node The node to serialize. - */ -PRISM_EXPORTED_FUNCTION void pm_dump_json(pm_buffer_t *buffer, const pm_parser_t *parser, const pm_node_t *node); - -#endif - -/** - * Represents the results of a slice query. - */ -typedef enum { - /** Returned if the encoding given to a slice query was invalid. */ - PM_STRING_QUERY_ERROR = -1, - - /** Returned if the result of the slice query is false. */ - PM_STRING_QUERY_FALSE, - - /** Returned if the result of the slice query is true. */ - PM_STRING_QUERY_TRUE -} pm_string_query_t; - -/** - * Check that the slice is a valid local variable name. - * - * @param source The source to check. - * @param length The length of the source. - * @param encoding_name The name of the encoding of the source. - * @return PM_STRING_QUERY_TRUE if the query is true, PM_STRING_QUERY_FALSE if - * the query is false, and PM_STRING_QUERY_ERROR if the encoding was invalid. - */ -PRISM_EXPORTED_FUNCTION pm_string_query_t pm_string_query_local(const uint8_t *source, size_t length, const char *encoding_name); - -/** - * Check that the slice is a valid constant name. - * - * @param source The source to check. - * @param length The length of the source. - * @param encoding_name The name of the encoding of the source. - * @return PM_STRING_QUERY_TRUE if the query is true, PM_STRING_QUERY_FALSE if - * the query is false, and PM_STRING_QUERY_ERROR if the encoding was invalid. - */ -PRISM_EXPORTED_FUNCTION pm_string_query_t pm_string_query_constant(const uint8_t *source, size_t length, const char *encoding_name); - -/** - * Check that the slice is a valid method name. - * - * @param source The source to check. - * @param length The length of the source. - * @param encoding_name The name of the encoding of the source. - * @return PM_STRING_QUERY_TRUE if the query is true, PM_STRING_QUERY_FALSE if - * the query is false, and PM_STRING_QUERY_ERROR if the encoding was invalid. - */ -PRISM_EXPORTED_FUNCTION pm_string_query_t pm_string_query_method_name(const uint8_t *source, size_t length, const char *encoding_name); - /** * @mainpage * @@ -335,29 +47,27 @@ PRISM_EXPORTED_FUNCTION pm_string_query_t pm_string_query_method_name(const uint * * @section parsing Parsing * - * In order to parse Ruby code, the structures and functions that you're going - * to want to use and be aware of are: + * In order to parse Ruby code, the functions that you are going to want to use + * and be aware of are: * - * * `pm_arena_t` - the arena allocator for AST-lifetime memory - * * `pm_parser_t` - the main parser structure - * * `pm_parser_init()` - initialize a parser + * * `pm_arena_new()` - create a new arena to hold all AST-lifetime allocations + * * `pm_parser_new()` - allocate and initialize a new parser * * `pm_parse()` - parse and return the root node - * * `pm_parser_free()` - free the internal memory of the parser + * * `pm_parser_free()` - free the parser and its internal memory * * `pm_arena_free()` - free all AST-lifetime memory * * Putting all of this together would look something like: * * ```c * void parse(const uint8_t *source, size_t length) { - * pm_arena_t arena = { 0 }; - * pm_parser_t parser; - * pm_parser_init(&arena, &parser, source, length, NULL); + * pm_arena_t *arena = pm_arena_new(); + * pm_parser_t *parser = pm_parser_new(arena, source, length, NULL); * - * pm_node_t *root = pm_parse(&parser); + * pm_node_t *root = pm_parse(parser); * printf("PARSED!\n"); * - * pm_parser_free(&parser); - * pm_arena_free(&arena); + * pm_parser_free(parser); + * pm_arena_free(arena); * } * ``` * @@ -370,24 +80,23 @@ PRISM_EXPORTED_FUNCTION pm_string_query_t pm_string_query_method_name(const uint * Prism provides the ability to serialize the AST and its related metadata into * a binary format. This format is designed to be portable to different * languages and runtimes so that you only need to make one FFI call in order to - * parse Ruby code. The structures and functions that you're going to want to - * use and be aware of are: + * parse Ruby code. The functions that you are going to want to use and be + * aware of are: * - * * `pm_buffer_t` - a small buffer object that will hold the serialized AST - * * `pm_buffer_free()` - free the memory associated with the buffer - * * `pm_serialize()` - serialize the AST into a buffer + * * `pm_buffer_new()` - create a new buffer + * * `pm_buffer_free()` - free the buffer and its internal memory * * `pm_serialize_parse()` - parse and serialize the AST into a buffer * * Putting all of this together would look something like: * * ```c * void serialize(const uint8_t *source, size_t length) { - * pm_buffer_t buffer = { 0 }; + * pm_buffer_t *buffer = pm_buffer_new(); * - * pm_serialize_parse(&buffer, source, length, NULL); + * pm_serialize_parse(buffer, source, length, NULL); * printf("SERIALIZED!\n"); * - * pm_buffer_free(&buffer); + * pm_buffer_free(buffer); * } * ``` * @@ -398,19 +107,18 @@ PRISM_EXPORTED_FUNCTION pm_string_query_t pm_string_query_method_name(const uint * * ```c * void prettyprint(const uint8_t *source, size_t length) { - * pm_arena_t arena = { 0 }; - * pm_parser_t parser; - * pm_parser_init(&arena, &parser, source, length, NULL); + * pm_arena_t *arena = pm_arena_new(); + * pm_parser_t *parser = pm_parser_new(arena, source, length, NULL); * - * pm_node_t *root = pm_parse(&parser); - * pm_buffer_t buffer = { 0 }; + * pm_node_t *root = pm_parse(parser); + * pm_buffer_t *buffer = pm_buffer_new(); * - * pm_prettyprint(&buffer, &parser, root); - * printf("%*.s\n", (int) buffer.length, buffer.value); + * pm_prettyprint(buffer, parser, root); + * printf("%*.s\n", (int) pm_buffer_length(buffer), pm_buffer_value(buffer)); * - * pm_buffer_free(&buffer); - * pm_parser_free(&parser); - * pm_arena_free(&arena); + * pm_buffer_free(buffer); + * pm_parser_free(parser); + * pm_arena_free(arena); * } * ``` */ diff --git a/prism/regexp.c b/prism/regexp.c index df8bb69b21b783..cc17aa4d09e5b5 100644 --- a/prism/regexp.c +++ b/prism/regexp.c @@ -1,7 +1,18 @@ -#include "prism/regexp.h" -#include "prism/diagnostic.h" -#include "prism/util/pm_buffer.h" -#include "prism/util/pm_strncasecmp.h" +#include "prism/internal/regexp.h" + +#include "prism/compiler/inline.h" +#include "prism/compiler/fallthrough.h" +#include "prism/internal/buffer.h" +#include "prism/internal/char.h" +#include "prism/internal/diagnostic.h" +#include "prism/internal/encoding.h" +#include "prism/internal/memchr.h" +#include "prism/internal/parser.h" +#include "prism/internal/stringy.h" +#include "prism/internal/strncasecmp.h" + +#include +#include /** The maximum depth of nested groups allowed in a regular expression. */ #define PM_REGEXP_PARSE_DEPTH_MAX 4096 @@ -115,7 +126,7 @@ typedef struct { * (points into the original source), we can point to the exact error location. * Otherwise, we point to the whole regexp node. */ -static inline void +static PRISM_INLINE void pm_regexp_parse_error(pm_regexp_parser_t *parser, const uint8_t *start, const uint8_t *end, const char *message) { pm_parser_t *pm = parser->parser; uint32_t loc_start, loc_length; @@ -158,13 +169,13 @@ pm_regexp_parser_named_capture(pm_regexp_parser_t *parser, const uint8_t *start, pm_string_t string; pm_string_shared_init(&string, start, end); parser->name_callback(parser->parser, &string, parser->shared, parser->name_data); - pm_string_free(&string); + pm_string_cleanup(&string); } /** * Returns true if the next character is the end of the source. */ -static inline bool +static PRISM_INLINE bool pm_regexp_char_is_eof(pm_regexp_parser_t *parser) { return parser->cursor >= parser->end; } @@ -172,7 +183,7 @@ pm_regexp_char_is_eof(pm_regexp_parser_t *parser) { /** * Optionally accept a char and consume it if it exists. */ -static inline bool +static PRISM_INLINE bool pm_regexp_char_accept(pm_regexp_parser_t *parser, uint8_t value) { if (!pm_regexp_char_is_eof(parser) && *parser->cursor == value) { parser->cursor++; @@ -184,7 +195,7 @@ pm_regexp_char_accept(pm_regexp_parser_t *parser, uint8_t value) { /** * Expect a character to be present and consume it. */ -static inline bool +static PRISM_INLINE bool pm_regexp_char_expect(pm_regexp_parser_t *parser, uint8_t value) { if (!pm_regexp_char_is_eof(parser) && *parser->cursor == value) { parser->cursor++; @@ -216,7 +227,7 @@ pm_regexp_char_find(pm_regexp_parser_t *parser, uint8_t value) { * escape bytes >= 0x80 are followed by a non-hex-escape, this appends a 0x00 * sentinel to separate the groups for later multibyte validation. */ -static inline void +static PRISM_INLINE void pm_regexp_hex_group_boundary(pm_regexp_parser_t *parser) { if (parser->hex_group_active) { pm_buffer_append_byte(&parser->hex_escape_buffer, 0x00); @@ -227,7 +238,7 @@ pm_regexp_hex_group_boundary(pm_regexp_parser_t *parser) { /** * Track a hex escape byte value >= 0x80 for multibyte validation. */ -static inline void +static PRISM_INLINE void pm_regexp_track_hex_escape(pm_regexp_parser_t *parser, uint8_t byte) { if (byte >= 0x80) { pm_buffer_append_byte(&parser->hex_escape_buffer, byte); @@ -244,7 +255,7 @@ pm_regexp_track_hex_escape(pm_regexp_parser_t *parser, uint8_t byte) { /** * Parse a hex digit character and return its value, or -1 if not a hex digit. */ -static inline int +static PRISM_INLINE int pm_regexp_hex_digit_value(uint8_t byte) { if (byte >= '0' && byte <= '9') return byte - '0'; if (byte >= 'a' && byte <= 'f') return byte - 'a' + 10; @@ -1454,7 +1465,7 @@ pm_regexp_validate_encoding_modifier(pm_regexp_parser_t *parser, bool ascii_only pm_buffer_t formatted = { 0 }; pm_regexp_format_for_error(&formatted, parser->encoding, (const uint8_t *) source_start, (size_t) source_length); PM_REGEXP_ENCODING_ERROR(parser, PM_ERR_REGEXP_NON_ESCAPED_MBC, (int) formatted.length, (const char *) formatted.value); - pm_buffer_free(&formatted); + pm_buffer_cleanup(&formatted); } } @@ -1595,7 +1606,7 @@ pm_regexp_validate_encoding(pm_regexp_parser_t *parser, bool ascii_only, pm_node * extraction walks the unescaped content since escape sequences in group names * (e.g., line continuations) have already been processed by the lexer. */ -PRISM_EXPORTED_FUNCTION pm_node_flags_t +pm_node_flags_t pm_regexp_parse(pm_parser_t *parser, pm_regular_expression_node_t *node, pm_regexp_name_callback_t name_callback, pm_regexp_name_data_t *name_data) { const uint8_t *source = parser->start + node->content_loc.start; size_t size = node->content_loc.length; @@ -1648,7 +1659,7 @@ pm_regexp_parse(pm_parser_t *parser, pm_regular_expression_node_t *node, pm_rege const char *error_source = (const char *) pm_string_source(&node->unescaped); int error_source_length = (int) pm_string_length(&node->unescaped); pm_node_flags_t encoding_flags = pm_regexp_validate_encoding(®exp_parser, ascii_only, flags, error_source, error_source_length); - pm_buffer_free(®exp_parser.hex_escape_buffer); + pm_buffer_cleanup(®exp_parser.hex_escape_buffer); // Second pass: walk unescaped content for named capture extraction. if (name_callback != NULL) { @@ -1702,5 +1713,5 @@ pm_regexp_parse_named_captures(pm_parser_t *parser, const uint8_t *source, size_ }; pm_regexp_parse_pattern(®exp_parser); - pm_buffer_free(®exp_parser.hex_escape_buffer); + pm_buffer_cleanup(®exp_parser.hex_escape_buffer); } diff --git a/prism/regexp.h b/prism/regexp.h deleted file mode 100644 index b3e739b457ec4f..00000000000000 --- a/prism/regexp.h +++ /dev/null @@ -1,72 +0,0 @@ -/** - * @file regexp.h - * - * A regular expression parser. - */ -#ifndef PRISM_REGEXP_H -#define PRISM_REGEXP_H - -#include "prism/defines.h" -#include "prism/parser.h" -#include "prism/encoding.h" -#include "prism/util/pm_memchr.h" -#include "prism/util/pm_string.h" - -#include -#include -#include - -/** - * Accumulation state for named capture groups found during regexp parsing. - * The caller initializes this with the call node and passes it to - * pm_regexp_parse. The regexp parser populates match and names as groups - * are found. - */ -typedef struct { - /** The call node wrapping the regular expression node (for =~). */ - pm_call_node_t *call; - - /** The match write node being built, or NULL if no captures found yet. */ - pm_match_write_node_t *match; - - /** The list of capture names found so far (for deduplication). */ - pm_constant_id_list_t names; -} pm_regexp_name_data_t; - -/** - * Callback invoked by pm_regexp_parse() for each named capture group found. - * - * @param parser The main parser. - * @param name The name of the capture group. - * @param shared Whether the source content is shared (impacts constant storage). - * @param data The accumulation state for named captures. - */ -typedef void (*pm_regexp_name_callback_t)(pm_parser_t *parser, const pm_string_t *name, bool shared, pm_regexp_name_data_t *data); - -/** - * Parse a regular expression, validate its encoding, and optionally extract - * named capture groups. Returns the encoding flags to set on the node. - * - * @param parser The parser that is currently being used. - * @param node The regular expression node to parse and validate. - * @param name_callback The optional callback to call when a named capture group is found. - * @param name_data The optional accumulation state for named captures. - * @return The encoding flags to set on the node (e.g., FORCED_UTF8_ENCODING). - */ -PRISM_EXPORTED_FUNCTION pm_node_flags_t pm_regexp_parse(pm_parser_t *parser, pm_regular_expression_node_t *node, pm_regexp_name_callback_t name_callback, pm_regexp_name_data_t *name_data); - -/** - * Parse an interpolated regular expression for named capture groups only. - * No encoding validation is performed. - * - * @param parser The parser that is currently being used. - * @param source The source content to parse. - * @param size The length of the source content. - * @param shared Whether the source points into the parser's source buffer. - * @param extended_mode Whether or not the regular expression is in extended mode. - * @param name_callback The callback to call when a named capture group is found. - * @param name_data The accumulation state for named captures. - */ -void pm_regexp_parse_named_captures(pm_parser_t *parser, const uint8_t *source, size_t size, bool shared, bool extended_mode, pm_regexp_name_callback_t name_callback, pm_regexp_name_data_t *name_data); - -#endif diff --git a/prism/serialize.h b/prism/serialize.h new file mode 100644 index 00000000000000..786a1514bcadf4 --- /dev/null +++ b/prism/serialize.h @@ -0,0 +1,96 @@ +/** + * @file serialize.h + * + * The functions related to serializing the AST to a binary format. + */ +#ifndef PRISM_SERIALIZE_H +#define PRISM_SERIALIZE_H + +#include "prism/excludes.h" + +/* We optionally support serializing to a binary string. For systems that do not + * want or need this functionality, it can be turned off with the + * PRISM_EXCLUDE_SERIALIZATION define. */ +#ifndef PRISM_EXCLUDE_SERIALIZATION + +#include "prism/compiler/exported.h" +#include "prism/compiler/nonnull.h" + +#include "prism/buffer.h" +#include "prism/parser.h" +#include "prism/source.h" +#include "prism/stream.h" + +/** + * Serialize the AST represented by the given node to the given buffer. + * + * @param parser The parser to serialize. + * @param node The node to serialize. + * @param buffer The buffer to serialize to. + */ +PRISM_EXPORTED_FUNCTION void pm_serialize(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) PRISM_NONNULL(1, 2, 3); + +/** + * Parse the given source to the AST and dump the AST to the given buffer. + * + * @param buffer The buffer to serialize to. + * @param source The source to parse. + * @param size The size of the source. + * @param data The optional data to pass to the parser. + */ +PRISM_EXPORTED_FUNCTION void pm_serialize_parse(pm_buffer_t *buffer, const uint8_t *source, size_t size, const char *data) PRISM_NONNULL(1, 2); + +/** + * Parse and serialize the AST represented by the given source into the given + * buffer. + * + * @param buffer The buffer to serialize to. + * @param source The source to parse. + * @param data The optional data to pass to the parser. + */ +PRISM_EXPORTED_FUNCTION void pm_serialize_parse_stream(pm_buffer_t *buffer, pm_source_t *source, const char *data) PRISM_NONNULL(1, 2); + +/** + * Parse and serialize the comments in the given source to the given buffer. + * + * @param buffer The buffer to serialize to. + * @param source The source to parse. + * @param size The size of the source. + * @param data The optional data to pass to the parser. + */ +PRISM_EXPORTED_FUNCTION void pm_serialize_parse_comments(pm_buffer_t *buffer, const uint8_t *source, size_t size, const char *data) PRISM_NONNULL(1, 2); + +/** + * Lex the given source and serialize to the given buffer. + * + * @param source The source to lex. + * @param size The size of the source. + * @param buffer The buffer to serialize to. + * @param data The optional data to pass to the lexer. + */ +PRISM_EXPORTED_FUNCTION void pm_serialize_lex(pm_buffer_t *buffer, const uint8_t *source, size_t size, const char *data) PRISM_NONNULL(1, 2); + +/** + * Parse and serialize both the AST and the tokens represented by the given + * source to the given buffer. + * + * @param buffer The buffer to serialize to. + * @param source The source to parse. + * @param size The size of the source. + * @param data The optional data to pass to the parser. + */ +PRISM_EXPORTED_FUNCTION void pm_serialize_parse_lex(pm_buffer_t *buffer, const uint8_t *source, size_t size, const char *data) PRISM_NONNULL(1, 2); + +/** + * Parse the source and return true if it parses without errors or warnings. + * + * @param source The source to parse. + * @param size The size of the source. + * @param data The optional data to pass to the parser. + * @returns True if the source parses without errors or warnings. + */ +PRISM_EXPORTED_FUNCTION bool pm_serialize_parse_success_p(const uint8_t *source, size_t size, const char *data) PRISM_NONNULL(1); + +#endif + +#endif diff --git a/prism/source.c b/prism/source.c new file mode 100644 index 00000000000000..f61cb19c1bca2b --- /dev/null +++ b/prism/source.c @@ -0,0 +1,491 @@ +#include "prism/internal/source.h" + +#include "prism/internal/allocator.h" +#include "prism/internal/buffer.h" + +#include +#include + +/* The following headers are necessary to read files using demand paging. */ +#ifdef _WIN32 +#include +#elif defined(_POSIX_MAPPED_FILES) +#include +#include +#include +#elif defined(PRISM_HAS_FILESYSTEM) +#include +#include +#endif + +static const uint8_t empty_source[] = ""; + +/** + * Allocate and initialize a pm_source_t with the given fields. + */ +static pm_source_t * +pm_source_alloc(const uint8_t *source, size_t length, pm_source_type_t type) { + pm_source_t *result = xmalloc(sizeof(pm_source_t)); + if (result == NULL) abort(); + + *result = (struct pm_source_t) { + .source = source, + .length = length, + .type = type + }; + + return result; +} + +/** + * Create a new source that wraps existing constant memory. + */ +pm_source_t * +pm_source_constant_new(const uint8_t *data, size_t length) { + return pm_source_alloc(data, length, PM_SOURCE_CONSTANT); +} + +/** + * Create a new source that wraps existing shared memory. + */ +pm_source_t * +pm_source_shared_new(const uint8_t *data, size_t length) { + return pm_source_alloc(data, length, PM_SOURCE_SHARED); +} + +/** + * Create a new source that owns its memory. + */ +pm_source_t * +pm_source_owned_new(uint8_t *data, size_t length) { + return pm_source_alloc(data, length, PM_SOURCE_OWNED); +} + +#ifdef _WIN32 +/** + * Represents a file handle on Windows, where the path will need to be freed + * when the file is closed. + */ +typedef struct { + /** The path to the file, which will become allocated memory. */ + WCHAR *path; + + /** The size of the allocated path in bytes. */ + size_t path_size; + + /** The handle to the file, which will start as uninitialized memory. */ + HANDLE file; +} pm_source_file_handle_t; + +/** + * Open the file indicated by the filepath parameter for reading on Windows. + */ +static pm_source_init_result_t +pm_source_file_handle_open(pm_source_file_handle_t *handle, const char *filepath) { + int length = MultiByteToWideChar(CP_UTF8, 0, filepath, -1, NULL, 0); + if (length == 0) return PM_SOURCE_INIT_ERROR_GENERIC; + + handle->path_size = sizeof(WCHAR) * ((size_t) length); + handle->path = xmalloc(handle->path_size); + if ((handle->path == NULL) || (MultiByteToWideChar(CP_UTF8, 0, filepath, -1, handle->path, length) == 0)) { + xfree_sized(handle->path, handle->path_size); + return PM_SOURCE_INIT_ERROR_GENERIC; + } + + handle->file = CreateFileW(handle->path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL); + if (handle->file == INVALID_HANDLE_VALUE) { + pm_source_init_result_t result = PM_SOURCE_INIT_ERROR_GENERIC; + + if (GetLastError() == ERROR_ACCESS_DENIED) { + DWORD attributes = GetFileAttributesW(handle->path); + if ((attributes != INVALID_FILE_ATTRIBUTES) && (attributes & FILE_ATTRIBUTE_DIRECTORY)) { + result = PM_SOURCE_INIT_ERROR_DIRECTORY; + } + } + + xfree_sized(handle->path, handle->path_size); + return result; + } + + return PM_SOURCE_INIT_SUCCESS; +} + +/** + * Close the file handle and free the path. + */ +static void +pm_source_file_handle_close(pm_source_file_handle_t *handle) { + xfree_sized(handle->path, handle->path_size); + CloseHandle(handle->file); +} +#endif + +/** + * Create a new source by memory-mapping a file. + */ +pm_source_t * +pm_source_mapped_new(const char *filepath, int open_flags, pm_source_init_result_t *result) { +#ifdef _WIN32 + (void) open_flags; + + /* Open the file for reading. */ + pm_source_file_handle_t handle; + *result = pm_source_file_handle_open(&handle, filepath); + if (*result != PM_SOURCE_INIT_SUCCESS) return NULL; + + /* Get the file size. */ + DWORD file_size = GetFileSize(handle.file, NULL); + if (file_size == INVALID_FILE_SIZE) { + pm_source_file_handle_close(&handle); + *result = PM_SOURCE_INIT_ERROR_GENERIC; + return NULL; + } + + /* If the file is empty, then return a constant source. */ + if (file_size == 0) { + pm_source_file_handle_close(&handle); + *result = PM_SOURCE_INIT_SUCCESS; + return pm_source_alloc(empty_source, 0, PM_SOURCE_CONSTANT); + } + + /* Create a mapping of the file. */ + HANDLE mapping = CreateFileMapping(handle.file, NULL, PAGE_READONLY, 0, 0, NULL); + if (mapping == NULL) { + pm_source_file_handle_close(&handle); + *result = PM_SOURCE_INIT_ERROR_GENERIC; + return NULL; + } + + /* Map the file into memory. */ + uint8_t *source = (uint8_t *) MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0); + CloseHandle(mapping); + pm_source_file_handle_close(&handle); + + if (source == NULL) { + *result = PM_SOURCE_INIT_ERROR_GENERIC; + return NULL; + } + + *result = PM_SOURCE_INIT_SUCCESS; + return pm_source_alloc(source, (size_t) file_size, PM_SOURCE_MAPPED); +#elif defined(_POSIX_MAPPED_FILES) + /* Open the file for reading. */ + int fd = open(filepath, O_RDONLY | open_flags); + if (fd == -1) { + *result = PM_SOURCE_INIT_ERROR_GENERIC; + return NULL; + } + + /* Stat the file to get the file size. */ + struct stat sb; + if (fstat(fd, &sb) == -1) { + close(fd); + *result = PM_SOURCE_INIT_ERROR_GENERIC; + return NULL; + } + + /* Ensure it is a file and not a directory. */ + if (S_ISDIR(sb.st_mode)) { + close(fd); + *result = PM_SOURCE_INIT_ERROR_DIRECTORY; + return NULL; + } + + /* + * For non-regular files (pipes, character devices), return a specific + * error so the caller can handle reading through their own I/O layer. + */ + if (!S_ISREG(sb.st_mode)) { + close(fd); + *result = PM_SOURCE_INIT_ERROR_NON_REGULAR; + return NULL; + } + + /* mmap the file descriptor to virtually get the contents. */ + size_t size = (size_t) sb.st_size; + + if (size == 0) { + close(fd); + *result = PM_SOURCE_INIT_SUCCESS; + return pm_source_alloc(empty_source, 0, PM_SOURCE_CONSTANT); + } + + uint8_t *source = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); + if (source == MAP_FAILED) { + close(fd); + *result = PM_SOURCE_INIT_ERROR_GENERIC; + return NULL; + } + + close(fd); + *result = PM_SOURCE_INIT_SUCCESS; + return pm_source_alloc(source, size, PM_SOURCE_MAPPED); +#else + (void) open_flags; + return pm_source_file_new(filepath, result); +#endif +} + +/** + * Create a new source by reading a file into a heap-allocated buffer. + */ +pm_source_t * +pm_source_file_new(const char *filepath, pm_source_init_result_t *result) { +#ifdef _WIN32 + /* Open the file for reading. */ + pm_source_file_handle_t handle; + *result = pm_source_file_handle_open(&handle, filepath); + if (*result != PM_SOURCE_INIT_SUCCESS) return NULL; + + /* Get the file size. */ + const DWORD file_size = GetFileSize(handle.file, NULL); + if (file_size == INVALID_FILE_SIZE) { + pm_source_file_handle_close(&handle); + *result = PM_SOURCE_INIT_ERROR_GENERIC; + return NULL; + } + + /* If the file is empty, return a constant source. */ + if (file_size == 0) { + pm_source_file_handle_close(&handle); + *result = PM_SOURCE_INIT_SUCCESS; + return pm_source_alloc(empty_source, 0, PM_SOURCE_CONSTANT); + } + + /* Create a buffer to read the file into. */ + uint8_t *source = xmalloc(file_size); + if (source == NULL) { + pm_source_file_handle_close(&handle); + *result = PM_SOURCE_INIT_ERROR_GENERIC; + return NULL; + } + + /* Read the contents of the file. */ + DWORD bytes_read; + if (!ReadFile(handle.file, source, file_size, &bytes_read, NULL)) { + xfree_sized(source, file_size); + pm_source_file_handle_close(&handle); + *result = PM_SOURCE_INIT_ERROR_GENERIC; + return NULL; + } + + /* Check the number of bytes read. */ + if (bytes_read != file_size) { + xfree_sized(source, file_size); + pm_source_file_handle_close(&handle); + *result = PM_SOURCE_INIT_ERROR_GENERIC; + return NULL; + } + + pm_source_file_handle_close(&handle); + *result = PM_SOURCE_INIT_SUCCESS; + return pm_source_alloc(source, (size_t) file_size, PM_SOURCE_OWNED); +#elif defined(PRISM_HAS_FILESYSTEM) + /* Open the file for reading. */ + int fd = open(filepath, O_RDONLY); + if (fd == -1) { + *result = PM_SOURCE_INIT_ERROR_GENERIC; + return NULL; + } + + /* Stat the file to get the file size. */ + struct stat sb; + if (fstat(fd, &sb) == -1) { + close(fd); + *result = PM_SOURCE_INIT_ERROR_GENERIC; + return NULL; + } + + /* Ensure it is a file and not a directory. */ + if (S_ISDIR(sb.st_mode)) { + close(fd); + *result = PM_SOURCE_INIT_ERROR_DIRECTORY; + return NULL; + } + + /* Check the size to see if it's empty. */ + size_t size = (size_t) sb.st_size; + if (size == 0) { + close(fd); + *result = PM_SOURCE_INIT_SUCCESS; + return pm_source_alloc(empty_source, 0, PM_SOURCE_CONSTANT); + } + + const size_t length = (size_t) size; + uint8_t *source = xmalloc(length); + if (source == NULL) { + close(fd); + *result = PM_SOURCE_INIT_ERROR_GENERIC; + return NULL; + } + + ssize_t bytes_read = read(fd, source, length); + close(fd); + + if (bytes_read == -1 || (size_t) bytes_read != length) { + xfree_sized(source, length); + *result = PM_SOURCE_INIT_ERROR_GENERIC; + return NULL; + } + + *result = PM_SOURCE_INIT_SUCCESS; + return pm_source_alloc(source, length, PM_SOURCE_OWNED); +#else + (void) filepath; + *result = PM_SOURCE_INIT_ERROR_GENERIC; + perror("pm_source_file_new is not implemented for this platform"); + return NULL; +#endif +} + +/** + * Create a new source by reading from a stream. This allocates the source + * but does not read from the stream yet. Use pm_source_stream_read to read + * data. + */ +pm_source_t * +pm_source_stream_new(void *stream, pm_source_stream_fgets_t *fgets, pm_source_stream_feof_t *feof) { + pm_source_t *source = pm_source_alloc(NULL, 0, PM_SOURCE_STREAM); + source->stream.buffer = pm_buffer_new(); + source->stream.stream = stream; + source->stream.fgets = fgets; + source->stream.feof = feof; + source->stream.eof = false; + + return source; +} + +/** + * Read from the stream into the source's internal buffer until __END__ is + * encountered or EOF is reached. Updates the source pointer and length. + * + * Returns true if EOF was reached, false if __END__ was encountered. + */ +bool +pm_source_stream_read(pm_source_t *source) { + pm_buffer_t *buffer = source->stream.buffer; + +#define LINE_SIZE 4096 + char line[LINE_SIZE]; + + while (memset(line, '\n', LINE_SIZE), source->stream.fgets(line, LINE_SIZE, source->stream.stream) != NULL) { + size_t length = LINE_SIZE; + while (length > 0 && line[length - 1] == '\n') length--; + + if (length == LINE_SIZE) { + /* + * If we read a line that is the maximum size and it doesn't end + * with a newline, then we'll just append it to the buffer and + * continue reading. + */ + length--; + pm_buffer_append_string(buffer, line, length); + continue; + } + + /* Append the line to the buffer. */ + length--; + pm_buffer_append_string(buffer, line, length); + + /* + * Check if the line matches the __END__ marker. If it does, then stop + * reading and return false. In most circumstances, this means we should + * stop reading from the stream so that the DATA constant can pick it + * up. + */ + switch (length) { + case 7: + if (strncmp(line, "__END__", 7) == 0) { + source->source = (const uint8_t *) pm_buffer_value(buffer); + source->length = pm_buffer_length(buffer); + return false; + } + break; + case 8: + if (strncmp(line, "__END__\n", 8) == 0) { + source->source = (const uint8_t *) pm_buffer_value(buffer); + source->length = pm_buffer_length(buffer); + return false; + } + break; + case 9: + if (strncmp(line, "__END__\r\n", 9) == 0) { + source->source = (const uint8_t *) pm_buffer_value(buffer); + source->length = pm_buffer_length(buffer); + return false; + } + break; + } + + /* + * All data should be read via gets. If the string returned by gets + * _doesn't_ end with a newline, then we assume we hit EOF condition. + */ + if (source->stream.feof(source->stream.stream)) { + break; + } + } + +#undef LINE_SIZE + + source->stream.eof = true; + source->source = (const uint8_t *) pm_buffer_value(buffer); + source->length = pm_buffer_length(buffer); + return true; +} + +/** + * Returns whether the stream source has reached EOF. + */ +bool +pm_source_stream_eof(const pm_source_t *source) { + return source->stream.eof; +} + +/** + * Free the given source and any memory it owns. + */ +void +pm_source_free(pm_source_t *source) { + switch (source->type) { + case PM_SOURCE_CONSTANT: + case PM_SOURCE_SHARED: + /* No cleanup needed for the data. */ + break; + case PM_SOURCE_OWNED: + xfree_sized((void *) source->source, source->length); + break; + case PM_SOURCE_MAPPED: +#if defined(_WIN32) + if (source->length > 0) { + UnmapViewOfFile((void *) source->source); + } +#elif defined(_POSIX_MAPPED_FILES) + if (source->length > 0) { + munmap((void *) source->source, source->length); + } +#endif + break; + case PM_SOURCE_STREAM: + pm_buffer_free(source->stream.buffer); + break; + } + + xfree_sized(source, sizeof(pm_source_t)); +} + +/** + * Returns the length of the source data in bytes. + */ +size_t +pm_source_length(const pm_source_t *source) { + return source->length; +} + +/** + * Returns a pointer to the source data. + */ +const uint8_t * +pm_source_source(const pm_source_t *source) { + return source->source; +} diff --git a/prism/source.h b/prism/source.h new file mode 100644 index 00000000000000..c79987d3fb9c34 --- /dev/null +++ b/prism/source.h @@ -0,0 +1,148 @@ +/** + * @file source.h + * + * An opaque type representing the source code being parsed, regardless of + * origin (constant memory, file, memory-mapped file, or stream). + */ +#ifndef PRISM_SOURCE_H +#define PRISM_SOURCE_H + +#include "prism/compiler/exported.h" +#include "prism/compiler/filesystem.h" +#include "prism/compiler/nodiscard.h" +#include "prism/compiler/nonnull.h" + +#include +#include + +/** + * An opaque type representing source code being parsed. + */ +typedef struct pm_source_t pm_source_t; + +/** + * This function is used to retrieve a line of input from a stream. It closely + * mirrors that of fgets so that fgets can be used as the default + * implementation. + */ +typedef char * (pm_source_stream_fgets_t)(char *string, int size, void *stream); + +/** + * This function is used to check whether a stream is at EOF. It closely mirrors + * that of feof so that feof can be used as the default implementation. + */ +typedef int (pm_source_stream_feof_t)(void *stream); + +/** + * Represents the result of initializing a source from a file. + */ +typedef enum { + /** Indicates that the source was successfully initialized. */ + PM_SOURCE_INIT_SUCCESS = 0, + + /** + * Indicates a generic error from a source init function, where the type + * of error should be read from `errno` or `GetLastError()`. + */ + PM_SOURCE_INIT_ERROR_GENERIC = 1, + + /** + * Indicates that the file that was attempted to be opened was a directory. + */ + PM_SOURCE_INIT_ERROR_DIRECTORY = 2, + + /** + * Indicates that the file is not a regular file (e.g. a pipe or character + * device) and the caller should handle reading it. + */ + PM_SOURCE_INIT_ERROR_NON_REGULAR = 3 +} pm_source_init_result_t; + +/** + * Create a new source that wraps existing constant memory. The memory is not + * owned and will not be freed. + * + * @param data The pointer to the source data. + * @param length The length of the source data in bytes. + * @returns A new source. Aborts on allocation failure. + */ +PRISM_EXPORTED_FUNCTION PRISM_NODISCARD pm_source_t * pm_source_constant_new(const uint8_t *data, size_t length); + +/** + * Create a new source that wraps existing shared memory. The memory is not + * owned and will not be freed. Semantically a "slice" of another source. + * + * @param data The pointer to the source data. + * @param length The length of the source data in bytes. + * @returns A new source. Aborts on allocation failure. + */ +PRISM_EXPORTED_FUNCTION PRISM_NODISCARD pm_source_t * pm_source_shared_new(const uint8_t *data, size_t length); + +/** + * Create a new source that owns its memory. The memory will be freed with + * xfree when the source is freed. + * + * @param data The pointer to the heap-allocated source data. + * @param length The length of the source data in bytes. + * @returns A new source. Aborts on allocation failure. + */ +PRISM_EXPORTED_FUNCTION PRISM_NODISCARD pm_source_t * pm_source_owned_new(uint8_t *data, size_t length); + +/** + * Create a new source by reading a file into a heap-allocated buffer. + * + * @param filepath The path to the file to read. + * @param result Out parameter for the result of the initialization. + * @returns A new source, or NULL on error (with result written to out param). + */ +PRISM_EXPORTED_FUNCTION PRISM_NODISCARD pm_source_t * pm_source_file_new(const char *filepath, pm_source_init_result_t *result) PRISM_NONNULL(1, 2); + +/** + * Create a new source by memory-mapping a file. Falls back to file reading on + * platforms without mmap support. + * + * If the file is a non-regular file (e.g. a pipe or character device), + * PM_SOURCE_INIT_ERROR_NON_REGULAR is returned, allowing the caller to handle + * it appropriately (e.g. by reading it through their own I/O layer). + * + * @param filepath The path to the file to read. + * @param open_flags Additional flags to pass to open(2) (e.g. O_NONBLOCK). + * @param result Out parameter for the result of the initialization. + * @returns A new source, or NULL on error (with result written to out param). + */ +PRISM_EXPORTED_FUNCTION PRISM_NODISCARD pm_source_t * pm_source_mapped_new(const char *filepath, int open_flags, pm_source_init_result_t *result) PRISM_NONNULL(1, 3); + +/** + * Create a new source by reading from a stream using the provided callbacks. + * + * @param stream The stream to read from. + * @param fgets The function to use to read from the stream. + * @param feof The function to use to check if the stream is at EOF. + * @returns A new source. Aborts on allocation failure. + */ +PRISM_EXPORTED_FUNCTION PRISM_NODISCARD pm_source_t * pm_source_stream_new(void *stream, pm_source_stream_fgets_t *fgets, pm_source_stream_feof_t *feof); + +/** + * Free the given source and any memory it owns. + * + * @param source The source to free. + */ +PRISM_EXPORTED_FUNCTION void pm_source_free(pm_source_t *source) PRISM_NONNULL(1); + +/** + * Returns the length of the source data in bytes. + * + * @param source The source to get the length of. + * @returns The length of the source data. + */ +PRISM_EXPORTED_FUNCTION size_t pm_source_length(const pm_source_t *source) PRISM_NONNULL(1); + +/** + * Returns a pointer to the source data. + * + * @param source The source to get the data of. + * @returns A pointer to the source data. + */ +PRISM_EXPORTED_FUNCTION const uint8_t * pm_source_source(const pm_source_t *source) PRISM_NONNULL(1); + +#endif diff --git a/prism/srcs.mk b/prism/srcs.mk index ca3f86d3162621..9d158ea8ec1ff4 100644 --- a/prism/srcs.mk +++ b/prism/srcs.mk @@ -37,19 +37,12 @@ $(srcdir)/prism/ast.h: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/ realclean-prism-srcs:: $(RM) $(srcdir)/prism/ast.h -main incs: $(srcdir)/prism/diagnostic.h -$(srcdir)/prism/diagnostic.h: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/include/prism/diagnostic.h.erb - $(Q) $(BASERUBY) $(PRISM_TEMPLATE) include/prism/diagnostic.h $@ +main incs: $(srcdir)/prism/internal/diagnostic.h +$(srcdir)/prism/internal/diagnostic.h: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/include/prism/internal/diagnostic.h.erb + $(Q) $(BASERUBY) $(PRISM_TEMPLATE) include/prism/internal/diagnostic.h $@ realclean-prism-srcs:: - $(RM) $(srcdir)/prism/diagnostic.h - -main incs: $(srcdir)/prism/node_new.h -$(srcdir)/prism/node_new.h: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/include/prism/node_new.h.erb - $(Q) $(BASERUBY) $(PRISM_TEMPLATE) include/prism/node_new.h $@ - -realclean-prism-srcs:: - $(RM) $(srcdir)/prism/node_new.h + $(RM) $(srcdir)/prism/internal/diagnostic.h main srcs: $(srcdir)/lib/prism/compiler.rb $(srcdir)/lib/prism/compiler.rb: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/lib/prism/compiler.rb.erb @@ -128,6 +121,13 @@ $(srcdir)/prism/diagnostic.c: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATE realclean-prism-srcs:: $(RM) $(srcdir)/prism/diagnostic.c +main srcs: $(srcdir)/prism/json.c +$(srcdir)/prism/json.c: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/src/json.c.erb + $(Q) $(BASERUBY) $(PRISM_TEMPLATE) src/json.c $@ + +realclean-prism-srcs:: + $(RM) $(srcdir)/prism/json.c + main srcs: $(srcdir)/prism/node.c $(srcdir)/prism/node.c: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/src/node.c.erb $(Q) $(BASERUBY) $(PRISM_TEMPLATE) src/node.c $@ @@ -149,9 +149,9 @@ $(srcdir)/prism/serialize.c: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES realclean-prism-srcs:: $(RM) $(srcdir)/prism/serialize.c -main srcs: $(srcdir)/prism/token_type.c -$(srcdir)/prism/token_type.c: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/src/token_type.c.erb - $(Q) $(BASERUBY) $(PRISM_TEMPLATE) src/token_type.c $@ +main srcs: $(srcdir)/prism/tokens.c +$(srcdir)/prism/tokens.c: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/src/tokens.c.erb + $(Q) $(BASERUBY) $(PRISM_TEMPLATE) src/tokens.c $@ realclean-prism-srcs:: - $(RM) $(srcdir)/prism/token_type.c + $(RM) $(srcdir)/prism/tokens.c diff --git a/prism/static_literals.c b/prism/static_literals.c index f3a5650d314d83..9af1eadf5d36b2 100644 --- a/prism/static_literals.c +++ b/prism/static_literals.c @@ -1,4 +1,18 @@ -#include "prism/static_literals.h" +#include "prism/internal/static_literals.h" + +#include "prism/compiler/inline.h" +#include "prism/compiler/unused.h" + +#include "prism/internal/allocator.h" +#include "prism/internal/buffer.h" +#include "prism/internal/integer.h" +#include "prism/internal/isinf.h" +#include "prism/internal/stringy.h" + +#include +#include +#include +#include /** * A small struct used for passing around a subset of the information that is @@ -19,7 +33,7 @@ typedef struct { const char *encoding_name; } pm_static_literals_metadata_t; -static inline uint32_t +static PRISM_INLINE uint32_t murmur_scramble(uint32_t value) { value *= 0xcc9e2d51; value = (value << 15) | (value >> 17); @@ -271,7 +285,7 @@ pm_compare_integer_nodes(const pm_static_literals_metadata_t *metadata, const pm * A comparison function for comparing two FloatNode instances. */ static int -pm_compare_float_nodes(PRISM_ATTRIBUTE_UNUSED const pm_static_literals_metadata_t *metadata, const pm_node_t *left, const pm_node_t *right) { +pm_compare_float_nodes(PRISM_UNUSED const pm_static_literals_metadata_t *metadata, const pm_node_t *left, const pm_node_t *right) { const double left_value = ((const pm_float_node_t *) left)->value; const double right_value = ((const pm_float_node_t *) right)->value; return PM_NUMERIC_COMPARISON(left_value, right_value); @@ -330,7 +344,7 @@ pm_string_value(const pm_node_t *node) { * A comparison function for comparing two nodes that have attached strings. */ static int -pm_compare_string_nodes(PRISM_ATTRIBUTE_UNUSED const pm_static_literals_metadata_t *metadata, const pm_node_t *left, const pm_node_t *right) { +pm_compare_string_nodes(PRISM_UNUSED const pm_static_literals_metadata_t *metadata, const pm_node_t *left, const pm_node_t *right) { const pm_string_t *left_string = pm_string_value(left); const pm_string_t *right_string = pm_string_value(right); return pm_string_compare(left_string, right_string); @@ -340,7 +354,7 @@ pm_compare_string_nodes(PRISM_ATTRIBUTE_UNUSED const pm_static_literals_metadata * A comparison function for comparing two RegularExpressionNode instances. */ static int -pm_compare_regular_expression_nodes(PRISM_ATTRIBUTE_UNUSED const pm_static_literals_metadata_t *metadata, const pm_node_t *left, const pm_node_t *right) { +pm_compare_regular_expression_nodes(PRISM_UNUSED const pm_static_literals_metadata_t *metadata, const pm_node_t *left, const pm_node_t *right) { const pm_regular_expression_node_t *left_regexp = (const pm_regular_expression_node_t *) left; const pm_regular_expression_node_t *right_regexp = (const pm_regular_expression_node_t *) right; @@ -501,7 +515,7 @@ pm_static_literal_positive_p(const pm_node_t *node) { /** * Create a string-based representation of the given static literal. */ -static inline void +static PRISM_INLINE void pm_static_literal_inspect_node(pm_buffer_t *buffer, const pm_static_literals_metadata_t *metadata, const pm_node_t *node) { switch (PM_NODE_TYPE(node)) { case PM_FALSE_NODE: diff --git a/prism/stream.h b/prism/stream.h new file mode 100644 index 00000000000000..678322b442d84a --- /dev/null +++ b/prism/stream.h @@ -0,0 +1,28 @@ +/** + * @file stream.h + * + * Functions for parsing streams. + */ +#ifndef PRISM_STREAM_H +#define PRISM_STREAM_H + +#include "prism/compiler/exported.h" +#include "prism/compiler/nonnull.h" + +#include "prism/arena.h" +#include "prism/options.h" +#include "prism/parser.h" +#include "prism/source.h" + +/** + * Parse a stream of Ruby source and return the tree. + * + * @param parser The out parameter to write the parser to. + * @param arena The arena to use for all AST-lifetime allocations. + * @param source The source to use, created via pm_source_stream_new. + * @param options The optional options to use when parsing. + * @returns The AST representing the source. + */ +PRISM_EXPORTED_FUNCTION pm_node_t * pm_parse_stream(pm_parser_t **parser, pm_arena_t *arena, pm_source_t *source, const pm_options_t *options) PRISM_NONNULL(1, 2, 3); + +#endif diff --git a/prism/string_query.c b/prism/string_query.c new file mode 100644 index 00000000000000..ccedaf9c000769 --- /dev/null +++ b/prism/string_query.c @@ -0,0 +1,166 @@ +#include "prism/string_query.h" + +#include "prism/internal/char.h" +#include "prism/internal/encoding.h" + +#include +#include + +/** The category of slice returned from pm_slice_type. */ +typedef enum { + /** Returned when the given encoding name is invalid. */ + PM_SLICE_TYPE_ERROR = -1, + + /** Returned when no other types apply to the slice. */ + PM_SLICE_TYPE_NONE, + + /** Returned when the slice is a valid local variable name. */ + PM_SLICE_TYPE_LOCAL, + + /** Returned when the slice is a valid constant name. */ + PM_SLICE_TYPE_CONSTANT, + + /** Returned when the slice is a valid method name. */ + PM_SLICE_TYPE_METHOD_NAME +} pm_slice_type_t; + +/** + * Check that the slice is a valid local variable name or constant. + */ +static pm_slice_type_t +pm_slice_type(const uint8_t *source, size_t length, const char *encoding_name) { + // first, get the right encoding object + const pm_encoding_t *encoding = pm_encoding_find((const uint8_t *) encoding_name, (const uint8_t *) (encoding_name + strlen(encoding_name))); + if (encoding == NULL) return PM_SLICE_TYPE_ERROR; + + // check that there is at least one character + if (length == 0) return PM_SLICE_TYPE_NONE; + + size_t width; + if ((width = encoding->alpha_char(source, (ptrdiff_t) length)) != 0) { + // valid because alphabetical + } else if (*source == '_') { + // valid because underscore + width = 1; + } else if ((*source >= 0x80) && ((width = encoding->char_width(source, (ptrdiff_t) length)) > 0)) { + // valid because multibyte + } else { + // invalid because no match + return PM_SLICE_TYPE_NONE; + } + + // determine the type of the slice based on the first character + const uint8_t *end = source + length; + pm_slice_type_t result = encoding->isupper_char(source, end - source) ? PM_SLICE_TYPE_CONSTANT : PM_SLICE_TYPE_LOCAL; + + // next, iterate through all of the bytes of the string to ensure that they + // are all valid identifier characters + source += width; + + while (source < end) { + if ((width = encoding->alnum_char(source, end - source)) != 0) { + // valid because alphanumeric + source += width; + } else if (*source == '_') { + // valid because underscore + source++; + } else if ((*source >= 0x80) && ((width = encoding->char_width(source, end - source)) > 0)) { + // valid because multibyte + source += width; + } else { + // invalid because no match + break; + } + } + + // accept a ! or ? at the end of the slice as a method name + if (*source == '!' || *source == '?' || *source == '=') { + source++; + result = PM_SLICE_TYPE_METHOD_NAME; + } + + // valid if we are at the end of the slice + return source == end ? result : PM_SLICE_TYPE_NONE; +} + +/** + * Check that the slice is a valid local variable name. + */ +pm_string_query_t +pm_string_query_local(const uint8_t *source, size_t length, const char *encoding_name) { + switch (pm_slice_type(source, length, encoding_name)) { + case PM_SLICE_TYPE_ERROR: + return PM_STRING_QUERY_ERROR; + case PM_SLICE_TYPE_NONE: + case PM_SLICE_TYPE_CONSTANT: + case PM_SLICE_TYPE_METHOD_NAME: + return PM_STRING_QUERY_FALSE; + case PM_SLICE_TYPE_LOCAL: + return PM_STRING_QUERY_TRUE; + } + + assert(false && "unreachable"); + return PM_STRING_QUERY_FALSE; +} + +/** + * Check that the slice is a valid constant name. + */ +pm_string_query_t +pm_string_query_constant(const uint8_t *source, size_t length, const char *encoding_name) { + switch (pm_slice_type(source, length, encoding_name)) { + case PM_SLICE_TYPE_ERROR: + return PM_STRING_QUERY_ERROR; + case PM_SLICE_TYPE_NONE: + case PM_SLICE_TYPE_LOCAL: + case PM_SLICE_TYPE_METHOD_NAME: + return PM_STRING_QUERY_FALSE; + case PM_SLICE_TYPE_CONSTANT: + return PM_STRING_QUERY_TRUE; + } + + assert(false && "unreachable"); + return PM_STRING_QUERY_FALSE; +} + +/** + * Check that the slice is a valid method name. + */ +pm_string_query_t +pm_string_query_method_name(const uint8_t *source, size_t length, const char *encoding_name) { +#define B(p) ((p) ? PM_STRING_QUERY_TRUE : PM_STRING_QUERY_FALSE) +#define C1(c) (*source == c) +#define C2(s) (memcmp(source, s, 2) == 0) +#define C3(s) (memcmp(source, s, 3) == 0) + + switch (pm_slice_type(source, length, encoding_name)) { + case PM_SLICE_TYPE_ERROR: + return PM_STRING_QUERY_ERROR; + case PM_SLICE_TYPE_NONE: + break; + case PM_SLICE_TYPE_LOCAL: + // numbered parameters are not valid method names + return B((length != 2) || (source[0] != '_') || (source[1] == '0') || !pm_char_is_decimal_digit(source[1])); + case PM_SLICE_TYPE_CONSTANT: + // all constants are valid method names + case PM_SLICE_TYPE_METHOD_NAME: + // all method names are valid method names + return PM_STRING_QUERY_TRUE; + } + + switch (length) { + case 1: + return B(C1('&') || C1('`') || C1('!') || C1('^') || C1('>') || C1('<') || C1('-') || C1('%') || C1('|') || C1('+') || C1('/') || C1('*') || C1('~')); + case 2: + return B(C2("!=") || C2("!~") || C2("[]") || C2("==") || C2("=~") || C2(">=") || C2(">>") || C2("<=") || C2("<<") || C2("**")); + case 3: + return B(C3("===") || C3("<=>") || C3("[]=")); + default: + return PM_STRING_QUERY_FALSE; + } + +#undef B +#undef C1 +#undef C2 +#undef C3 +} diff --git a/prism/string_query.h b/prism/string_query.h new file mode 100644 index 00000000000000..6ee1a9d9b68992 --- /dev/null +++ b/prism/string_query.h @@ -0,0 +1,63 @@ +/** + * @file string_query.h + * + * Functions for querying properties of strings, such as whether they are valid + * local variable names, constant names, or method names. + */ +#ifndef PRISM_STRING_QUERY_H +#define PRISM_STRING_QUERY_H + +#include "prism/compiler/exported.h" +#include "prism/compiler/nonnull.h" + +#include +#include + +/** + * Represents the results of a slice query. + */ +typedef enum { + /** Returned if the encoding given to a slice query was invalid. */ + PM_STRING_QUERY_ERROR = -1, + + /** Returned if the result of the slice query is false. */ + PM_STRING_QUERY_FALSE, + + /** Returned if the result of the slice query is true. */ + PM_STRING_QUERY_TRUE +} pm_string_query_t; + +/** + * Check that the slice is a valid local variable name. + * + * @param source The source to check. + * @param length The length of the source. + * @param encoding_name The name of the encoding of the source. + * @returns PM_STRING_QUERY_TRUE if the query is true, PM_STRING_QUERY_FALSE if + * the query is false, and PM_STRING_QUERY_ERROR if the encoding was invalid. + */ +PRISM_EXPORTED_FUNCTION pm_string_query_t pm_string_query_local(const uint8_t *source, size_t length, const char *encoding_name) PRISM_NONNULL(1, 3); + +/** + * Check that the slice is a valid constant name. + * + * @param source The source to check. + * @param length The length of the source. + * @param encoding_name The name of the encoding of the source. + * @returns PM_STRING_QUERY_TRUE if the query is true, PM_STRING_QUERY_FALSE if + * the query is false, and PM_STRING_QUERY_ERROR if the encoding was invalid. + */ +PRISM_EXPORTED_FUNCTION pm_string_query_t pm_string_query_constant(const uint8_t *source, size_t length, const char *encoding_name) PRISM_NONNULL(1, 3); + +/** + * Check that the slice is a valid method name. + * + * @param source The source to check. + * @param length The length of the source. + * @param encoding_name The name of the encoding of the source. + * @returns PM_STRING_QUERY_TRUE if the query is true, PM_STRING_QUERY_FALSE if + * the query is false, and PM_STRING_QUERY_ERROR if the encoding was invalid. + */ +PRISM_EXPORTED_FUNCTION pm_string_query_t pm_string_query_method_name(const uint8_t *source, size_t length, const char *encoding_name) PRISM_NONNULL(1, 3); + +#endif diff --git a/prism/stringy.c b/prism/stringy.c new file mode 100644 index 00000000000000..d6f4c4a777ace7 --- /dev/null +++ b/prism/stringy.c @@ -0,0 +1,91 @@ +#include "prism/internal/stringy.h" + +#include "prism/internal/allocator.h" + +#include +#include +#include + +/** + * Initialize a shared string that is based on initial input. + */ +void +pm_string_shared_init(pm_string_t *string, const uint8_t *start, const uint8_t *end) { + assert(start <= end); + + *string = (pm_string_t) { + .type = PM_STRING_SHARED, + .source = start, + .length = (size_t) (end - start) + }; +} + +/** + * Initialize an owned string that is responsible for freeing allocated memory. + */ +void +pm_string_owned_init(pm_string_t *string, uint8_t *source, size_t length) { + *string = (pm_string_t) { + .type = PM_STRING_OWNED, + .source = source, + .length = length + }; +} + +/** + * Initialize a constant string that doesn't own its memory source. + */ +void +pm_string_constant_init(pm_string_t *string, const char *source, size_t length) { + *string = (pm_string_t) { + .type = PM_STRING_CONSTANT, + .source = (const uint8_t *) source, + .length = length + }; +} + +/** + * Compare the underlying lengths and bytes of two strings. Returns 0 if the + * strings are equal, a negative number if the left string is less than the + * right string, and a positive number if the left string is greater than the + * right string. + */ +int +pm_string_compare(const pm_string_t *left, const pm_string_t *right) { + size_t left_length = pm_string_length(left); + size_t right_length = pm_string_length(right); + + if (left_length < right_length) { + return -1; + } else if (left_length > right_length) { + return 1; + } + + return memcmp(pm_string_source(left), pm_string_source(right), left_length); +} + +/** + * Returns the length associated with the string. + */ +size_t +pm_string_length(const pm_string_t *string) { + return string->length; +} + +/** + * Returns the start pointer associated with the string. + */ +const uint8_t * +pm_string_source(const pm_string_t *string) { + return string->source; +} + +/** + * Free the associated memory of the given string. + */ +void +pm_string_cleanup(pm_string_t *string) { + if (string->type == PM_STRING_OWNED) { + xfree_sized((void *) string->source, string->length); + } +} diff --git a/prism/stringy.h b/prism/stringy.h new file mode 100644 index 00000000000000..0d64387ac3e81e --- /dev/null +++ b/prism/stringy.h @@ -0,0 +1,72 @@ +/** + * @file stringy.h + * + * A generic string type that can have various ownership semantics. + */ +#ifndef PRISM_STRINGY_H +#define PRISM_STRINGY_H + +#include "prism/compiler/exported.h" +#include "prism/compiler/nonnull.h" + +#include +#include + +/** + * A generic string type that can have various ownership semantics. + */ +typedef struct { + /** A pointer to the start of the string. */ + const uint8_t *source; + + /** The length of the string in bytes of memory. */ + size_t length; + + /** The type of the string. This field determines how the string should be freed. */ + enum { + /** This string is a constant string, and should not be freed. */ + PM_STRING_CONSTANT, + + /** This is a slice of another string, and should not be freed. */ + PM_STRING_SHARED, + + /** This string owns its memory, and should be freed internally. */ + PM_STRING_OWNED + } type; +} pm_string_t; + +/** + * Initialize a constant string that doesn't own its memory source. + * + * @param string The string to initialize. + * @param source The source of the string. + * @param length The length of the string. + */ +PRISM_EXPORTED_FUNCTION void pm_string_constant_init(pm_string_t *string, const char *source, size_t length) PRISM_NONNULL(1); + +/** + * Initialize an owned string that is responsible for freeing allocated memory. + * + * @param string The string to initialize. + * @param source The source of the string. + * @param length The length of the string. + */ +PRISM_EXPORTED_FUNCTION void pm_string_owned_init(pm_string_t *string, uint8_t *source, size_t length) PRISM_NONNULL(1, 2); + +/** + * Returns the length associated with the string. + * + * @param string The string to get the length of. + * @returns The length of the string. + */ +PRISM_EXPORTED_FUNCTION size_t pm_string_length(const pm_string_t *string) PRISM_NONNULL(1); + +/** + * Returns the start pointer associated with the string. + * + * @param string The string to get the start pointer of. + * @returns The start pointer of the string. + */ +PRISM_EXPORTED_FUNCTION const uint8_t * pm_string_source(const pm_string_t *string) PRISM_NONNULL(1); + +#endif diff --git a/prism/util/pm_strncasecmp.c b/prism/strncasecmp.c similarity index 88% rename from prism/util/pm_strncasecmp.c rename to prism/strncasecmp.c index 3f584215540c02..a373cad6d78055 100644 --- a/prism/util/pm_strncasecmp.c +++ b/prism/strncasecmp.c @@ -1,11 +1,12 @@ -#include "prism/util/pm_strncasecmp.h" +#include "prism/internal/strncasecmp.h" + +#include "prism/compiler/inline.h" /** * A locale-insensitive version of `tolower(3)` */ -static inline int -pm_tolower(int c) -{ +static PRISM_INLINE int +pm_tolower(int c) { if ('A' <= c && c <= 'Z') { return c | 0x20; } diff --git a/prism/util/pm_strpbrk.c b/prism/strpbrk.c similarity index 94% rename from prism/util/pm_strpbrk.c rename to prism/strpbrk.c index fdd2ab4567580f..383707eb72d570 100644 --- a/prism/util/pm_strpbrk.c +++ b/prism/strpbrk.c @@ -1,9 +1,22 @@ -#include "prism/util/pm_strpbrk.h" +#include "prism/internal/strpbrk.h" + +#include "prism/compiler/accel.h" +#include "prism/compiler/inline.h" +#include "prism/compiler/unused.h" + +#include "prism/internal/bit.h" +#include "prism/internal/diagnostic.h" +#include "prism/internal/encoding.h" +#include "prism/internal/parser.h" + +#include +#include +#include /** * Add an invalid multibyte character error to the parser. */ -static inline void +static PRISM_INLINE void pm_strpbrk_invalid_multibyte_character(pm_parser_t *parser, uint32_t start, uint32_t length) { pm_diagnostic_list_append_format(&parser->metadata_arena, &parser->error_list, start, length, PM_ERR_INVALID_MULTIBYTE_CHARACTER, parser->start[start]); } @@ -11,7 +24,7 @@ pm_strpbrk_invalid_multibyte_character(pm_parser_t *parser, uint32_t start, uint /** * Set the explicit encoding for the parser to the current encoding. */ -static inline void +static PRISM_INLINE void pm_strpbrk_explicit_encoding_set(pm_parser_t *parser, uint32_t start, uint32_t length) { if (parser->explicit_encoding != NULL) { if (parser->explicit_encoding == parser->encoding) { @@ -57,7 +70,7 @@ pm_strpbrk_explicit_encoding_set(pm_parser_t *parser, uint32_t start, uint32_t l * - low_lut/high_lut: nibble-based lookup tables for SIMD matching (NEON/SSSE3) * - table: 256-bit bitmap for scalar fallback matching (all platforms) */ -static inline void +static PRISM_INLINE void pm_strpbrk_cache_update(pm_parser_t *parser, const uint8_t *charset) { // The cache key is the full charset buffer (PM_STRPBRK_CACHE_SIZE bytes). // Since it is always NUL-padded, a fixed-size comparison covers both @@ -94,7 +107,7 @@ pm_strpbrk_cache_update(pm_parser_t *parser, const uint8_t *charset) { #if defined(PRISM_HAS_NEON) #include -static inline bool +static PRISM_INLINE bool scan_strpbrk_ascii(pm_parser_t *parser, const uint8_t *source, size_t maximum, const uint8_t *charset, size_t *index) { pm_strpbrk_cache_update(parser, charset); @@ -149,7 +162,7 @@ scan_strpbrk_ascii(pm_parser_t *parser, const uint8_t *source, size_t maximum, c #elif defined(PRISM_HAS_SSSE3) #include -static inline bool +static PRISM_INLINE bool scan_strpbrk_ascii(pm_parser_t *parser, const uint8_t *source, size_t maximum, const uint8_t *charset, size_t *index) { pm_strpbrk_cache_update(parser, charset); @@ -201,7 +214,7 @@ scan_strpbrk_ascii(pm_parser_t *parser, const uint8_t *source, size_t maximum, c #elif defined(PRISM_HAS_SWAR) -static inline bool +static PRISM_INLINE bool scan_strpbrk_ascii(pm_parser_t *parser, const uint8_t *source, size_t maximum, const uint8_t *charset, size_t *index) { pm_strpbrk_cache_update(parser, charset); @@ -243,8 +256,8 @@ scan_strpbrk_ascii(pm_parser_t *parser, const uint8_t *source, size_t maximum, c #else -static inline bool -scan_strpbrk_ascii(PRISM_ATTRIBUTE_UNUSED pm_parser_t *parser, PRISM_ATTRIBUTE_UNUSED const uint8_t *source, PRISM_ATTRIBUTE_UNUSED size_t maximum, PRISM_ATTRIBUTE_UNUSED const uint8_t *charset, size_t *index) { +static PRISM_INLINE bool +scan_strpbrk_ascii(PRISM_UNUSED pm_parser_t *parser, PRISM_UNUSED const uint8_t *source, PRISM_UNUSED size_t maximum, PRISM_UNUSED const uint8_t *charset, size_t *index) { *index = 0; return false; } @@ -254,7 +267,7 @@ scan_strpbrk_ascii(PRISM_ATTRIBUTE_UNUSED pm_parser_t *parser, PRISM_ATTRIBUTE_U /** * This is the default path. */ -static inline const uint8_t * +static PRISM_INLINE const uint8_t * pm_strpbrk_utf8(pm_parser_t *parser, const uint8_t *source, const uint8_t *charset, size_t index, size_t maximum, bool validate) { while (index < maximum) { if (strchr((const char *) charset, source[index]) != NULL) { @@ -292,7 +305,7 @@ pm_strpbrk_utf8(pm_parser_t *parser, const uint8_t *source, const uint8_t *chars /** * This is the path when the encoding is ASCII-8BIT. */ -static inline const uint8_t * +static PRISM_INLINE const uint8_t * pm_strpbrk_ascii_8bit(pm_parser_t *parser, const uint8_t *source, const uint8_t *charset, size_t index, size_t maximum, bool validate) { while (index < maximum) { if (strchr((const char *) charset, source[index]) != NULL) { @@ -309,7 +322,7 @@ pm_strpbrk_ascii_8bit(pm_parser_t *parser, const uint8_t *source, const uint8_t /** * This is the slow path that does care about the encoding. */ -static inline const uint8_t * +static PRISM_INLINE const uint8_t * pm_strpbrk_multi_byte(pm_parser_t *parser, const uint8_t *source, const uint8_t *charset, size_t index, size_t maximum, bool validate) { const pm_encoding_t *encoding = parser->encoding; @@ -351,7 +364,7 @@ pm_strpbrk_multi_byte(pm_parser_t *parser, const uint8_t *source, const uint8_t * This is the fast path that does not care about the encoding because we know * the encoding only supports single-byte characters. */ -static inline const uint8_t * +static PRISM_INLINE const uint8_t * pm_strpbrk_single_byte(pm_parser_t *parser, const uint8_t *source, const uint8_t *charset, size_t index, size_t maximum, bool validate) { const pm_encoding_t *encoding = parser->encoding; diff --git a/prism/templates/ext/prism/api_node.c.erb b/prism/templates/ext/prism/api_node.c.erb index e3bcf116cc900a..71f7fe273e2ab2 100644 --- a/prism/templates/ext/prism/api_node.c.erb +++ b/prism/templates/ext/prism/api_node.c.erb @@ -1,5 +1,9 @@ #line <%= __LINE__ + 1 %> "prism/templates/ext/prism/<%= File.basename(__FILE__) %>" #include "prism/extension.h" +#include "prism/internal/allocator.h" +#include "prism/internal/arena.h" + +#include extern VALUE rb_cPrism; extern VALUE rb_cPrismNode; @@ -24,8 +28,8 @@ pm_location_new(const uint32_t start, const uint32_t length, VALUE source, bool VALUE pm_token_new(const pm_parser_t *parser, const pm_token_t *token, rb_encoding *encoding, VALUE source, bool freeze) { - ID type = rb_intern(pm_token_type_name(token->type)); - VALUE location = pm_location_new((uint32_t) (token->start - parser->start), (uint32_t) (token->end - token->start), source, freeze); + ID type = rb_intern(pm_token_type(token->type)); + VALUE location = pm_location_new((uint32_t) (token->start - pm_parser_start(parser)), (uint32_t) (token->end - token->start), source, freeze); VALUE slice = rb_enc_str_new((const char *) token->start, token->end - token->start, encoding); if (freeze) rb_obj_freeze(slice); @@ -74,19 +78,18 @@ pm_integer_new(const pm_integer_t *integer) { // Create a Prism::Source object from the given parser, after pm_parse() was called. VALUE pm_source_new(const pm_parser_t *parser, rb_encoding *encoding, bool freeze) { - VALUE source_string = rb_enc_str_new((const char *) parser->start, parser->end - parser->start, encoding); + const uint8_t *start = pm_parser_start(parser); + VALUE source_string = rb_enc_str_new((const char *) start, pm_parser_end(parser) - start, encoding); - VALUE offsets = rb_ary_new_capa(parser->line_offsets.size); - for (size_t index = 0; index < parser->line_offsets.size; index++) { - rb_ary_push(offsets, ULONG2NUM(parser->line_offsets.offsets[index])); - } + const pm_line_offset_list_t *line_offsets = pm_parser_line_offsets(parser); + VALUE offsets = rb_str_new((const char *) line_offsets->offsets, line_offsets->size * sizeof(uint32_t)); if (freeze) { rb_obj_freeze(source_string); rb_obj_freeze(offsets); } - VALUE source = rb_funcall(rb_cPrismSource, rb_intern("for"), 3, source_string, LONG2NUM(parser->start_line), offsets); + VALUE source = rb_funcall(rb_cPrismSource, rb_intern("for"), 3, source_string, LONG2NUM(pm_parser_start_line(parser)), offsets); if (freeze) rb_obj_freeze(source); return source; @@ -99,8 +102,8 @@ typedef struct pm_node_stack_node { } pm_node_stack_node_t; static void -pm_node_stack_push(pm_node_stack_node_t **stack, const pm_node_t *visit) { - pm_node_stack_node_t *node = xmalloc(sizeof(pm_node_stack_node_t)); +pm_node_stack_push(pm_arena_t *arena, pm_node_stack_node_t **stack, const pm_node_t *visit) { + pm_node_stack_node_t *node = (pm_node_stack_node_t *) pm_arena_alloc(arena, sizeof(pm_node_stack_node_t), PRISM_ALIGNOF(pm_node_stack_node_t)); node->prev = *stack; node->visit = visit; node->visited = false; @@ -113,32 +116,40 @@ pm_node_stack_pop(pm_node_stack_node_t **stack) { const pm_node_t *visit = current->visit; *stack = current->prev; - xfree_sized(current, sizeof(pm_node_stack_node_t)); return visit; } -VALUE -pm_ast_new(const pm_parser_t *parser, const pm_node_t *node, rb_encoding *encoding, VALUE source, bool freeze) { - VALUE constants = rb_ary_new_capa(parser->constant_pool.size); - - for (uint32_t index = 0; index < parser->constant_pool.size; index++) { - pm_constant_t *constant = &parser->constant_pool.constants[index]; - int state = 0; +typedef struct { + VALUE constants; + rb_encoding *encoding; +} pm_ast_constants_each_data_t; - VALUE string = rb_enc_str_new((const char *) constant->start, constant->length, encoding); - VALUE value = rb_protect(rb_str_intern, string, &state); +static void +pm_ast_constants_each(const pm_constant_t *constant, void *data) { + pm_ast_constants_each_data_t *constants_data = (pm_ast_constants_each_data_t *) data; + int state = 0; - if (state != 0) { - value = ID2SYM(rb_intern_const("?")); - rb_set_errinfo(Qnil); - } + VALUE string = rb_enc_str_new((const char *) pm_constant_start(constant), pm_constant_length(constant), constants_data->encoding); + VALUE value = rb_protect(rb_str_intern, string, &state); - rb_ary_push(constants, value); + if (state != 0) { + value = ID2SYM(rb_intern_const("?")); + rb_set_errinfo(Qnil); } + rb_ary_push(constants_data->constants, value); +} + +VALUE +pm_ast_new(const pm_parser_t *parser, const pm_node_t *node, rb_encoding *encoding, VALUE source, bool freeze) { + VALUE constants = rb_ary_new_capa(pm_parser_constants_size(parser)); + pm_ast_constants_each_data_t constants_data = { .constants = constants, .encoding = encoding }; + pm_parser_constants_each(parser, pm_ast_constants_each, &constants_data); + + pm_arena_t *node_arena = pm_arena_new(); pm_node_stack_node_t *node_stack = NULL; - pm_node_stack_push(&node_stack, node); + pm_node_stack_push(node_arena, &node_stack, node); VALUE value_stack = rb_ary_new(); while (node_stack != NULL) { @@ -161,10 +172,10 @@ pm_ast_new(const pm_parser_t *parser, const pm_node_t *node, rb_encoding *encodi <%- node.fields.each do |field| -%> <%- case field -%> <%- when Prism::Template::NodeField, Prism::Template::OptionalNodeField -%> - pm_node_stack_push(&node_stack, (pm_node_t *) cast-><%= field.name %>); + pm_node_stack_push(node_arena, &node_stack, (pm_node_t *) cast-><%= field.name %>); <%- when Prism::Template::NodeListField -%> for (size_t index = 0; index < cast-><%= field.name %>.size; index++) { - pm_node_stack_push(&node_stack, (pm_node_t *) cast-><%= field.name %>.nodes[index]); + pm_node_stack_push(node_arena, &node_stack, (pm_node_t *) cast-><%= field.name %>.nodes[index]); } <%- end -%> <%- end -%> @@ -266,6 +277,7 @@ pm_ast_new(const pm_parser_t *parser, const pm_node_t *node, rb_encoding *encodi } } + pm_arena_free(node_arena); return rb_ary_pop(value_stack); } diff --git a/prism/templates/include/prism/ast.h.erb b/prism/templates/include/prism/ast.h.erb index 06123417727fcb..3b3be25e76ffce 100644 --- a/prism/templates/include/prism/ast.h.erb +++ b/prism/templates/include/prism/ast.h.erb @@ -8,12 +8,14 @@ #ifndef PRISM_AST_H #define PRISM_AST_H -#include "prism/defines.h" -#include "prism/util/pm_constant_pool.h" -#include "prism/util/pm_integer.h" -#include "prism/util/pm_string.h" +#include "prism/compiler/align.h" +#include "prism/compiler/exported.h" + +#include "prism/arena.h" +#include "prism/constant_pool.h" +#include "prism/integer.h" +#include "prism/stringy.h" -#include #include #include @@ -45,6 +47,15 @@ typedef struct { const uint8_t *end; } pm_token_t; +/** + * Returns a string representation of the given token type. + * + * @param token_type The type of the token to get the string representation of. + * @returns A string representation of the given token type. This is meant for + * debugging purposes and is not guaranteed to be stable across versions. + */ +PRISM_EXPORTED_FUNCTION const char * pm_token_type(pm_token_type_t token_type); + /** * This struct represents a slice in the source code, defined by an offset and * a length. Note that we have confirmation that we can represent all locations @@ -238,6 +249,23 @@ typedef enum pm_<%= flag.human %> { PM_<%= flag.human.upcase %>_LAST, } pm_<%= flag.human %>_t; <%- end -%> +<%- nodes.each do |node| -%> + +<%- params = node.fields.map(&:c_param) -%> +/** + * Allocate and initialize a new <%= node.name %> node. + * + * @param arena The arena to allocate from. + * @param node_id The unique identifier for this node. + * @param flags The flags for this node. + * @param location The location of this node in the source. +<%- node.fields.each do |field| -%> + * @param <%= field.name %> <%= field.comment ? Prism::Template::Doxygen.verbatim(field.comment.lines.first.strip) : "The #{field.name} field." %> +<%- end -%> + * @returns The newly allocated and initialized node. + */ +PRISM_EXPORTED_FUNCTION pm_<%= node.human %>_t * pm_<%= node.human %>_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location<%= params.empty? ? "" : ", #{params.join(", ")}" %>); +<%- end -%> /** * When we're serializing to Java, we want to skip serializing the location diff --git a/prism/templates/include/prism/diagnostic.h.erb b/prism/templates/include/prism/diagnostic.h.erb deleted file mode 100644 index 935fb663ea325d..00000000000000 --- a/prism/templates/include/prism/diagnostic.h.erb +++ /dev/null @@ -1,117 +0,0 @@ -/** - * @file diagnostic.h - * - * A list of diagnostics generated during parsing. - */ -#ifndef PRISM_DIAGNOSTIC_H -#define PRISM_DIAGNOSTIC_H - -#include "prism/ast.h" -#include "prism/defines.h" -#include "prism/util/pm_arena.h" -#include "prism/util/pm_list.h" - -#include -#include -#include - -/** - * The diagnostic IDs of all of the diagnostics, used to communicate the types - * of errors between the parser and the user. - */ -typedef enum { - // These are the error diagnostics. - <%- errors.each do |error| -%> - PM_ERR_<%= error.name %>, - <%- end -%> - - // These are the warning diagnostics. - <%- warnings.each do |warning| -%> - PM_WARN_<%= warning.name %>, - <%- end -%> -} pm_diagnostic_id_t; - -/** - * This struct represents a diagnostic generated during parsing. - * - * @extends pm_list_node_t - */ -typedef struct { - /** The embedded base node. */ - pm_list_node_t node; - - /** The location of the diagnostic in the source. */ - pm_location_t location; - - /** The ID of the diagnostic. */ - pm_diagnostic_id_t diag_id; - - /** The message associated with the diagnostic. */ - const char *message; - - /** - * The level of the diagnostic, see `pm_error_level_t` and - * `pm_warning_level_t` for possible values. - */ - uint8_t level; -} pm_diagnostic_t; - -/** - * The levels of errors generated during parsing. - */ -typedef enum { - /** For errors that should raise a syntax error. */ - PM_ERROR_LEVEL_SYNTAX = 0, - - /** For errors that should raise an argument error. */ - PM_ERROR_LEVEL_ARGUMENT = 1, - - /** For errors that should raise a load error. */ - PM_ERROR_LEVEL_LOAD = 2 -} pm_error_level_t; - -/** - * The levels of warnings generated during parsing. - */ -typedef enum { - /** For warnings which should be emitted if $VERBOSE != nil. */ - PM_WARNING_LEVEL_DEFAULT = 0, - - /** For warnings which should be emitted if $VERBOSE == true. */ - PM_WARNING_LEVEL_VERBOSE = 1 -} pm_warning_level_t; - -/** - * Get the human-readable name of the given diagnostic ID. - * - * @param diag_id The diagnostic ID. - * @return The human-readable name of the diagnostic ID. - */ -const char * pm_diagnostic_id_human(pm_diagnostic_id_t diag_id); - -/** - * Append a diagnostic to the given list of diagnostics that is using shared - * memory for its message. - * - * @param arena The arena to allocate from. - * @param list The list to append to. - * @param start The source offset of the start of the diagnostic. - * @param length The length of the diagnostic. - * @param diag_id The diagnostic ID. - */ -void pm_diagnostic_list_append(pm_arena_t *arena, pm_list_t *list, uint32_t start, uint32_t length, pm_diagnostic_id_t diag_id); - -/** - * Append a diagnostic to the given list of diagnostics that is using a format - * string for its message. - * - * @param arena The arena to allocate from. - * @param list The list to append to. - * @param start The source offset of the start of the diagnostic. - * @param length The length of the diagnostic. - * @param diag_id The diagnostic ID. - * @param ... The arguments to the format string for the message. - */ -void pm_diagnostic_list_append_format(pm_arena_t *arena, pm_list_t *list, uint32_t start, uint32_t length, pm_diagnostic_id_t diag_id, ...); - -#endif diff --git a/prism/templates/include/prism/internal/diagnostic.h.erb b/prism/templates/include/prism/internal/diagnostic.h.erb new file mode 100644 index 00000000000000..ee44ff5382f457 --- /dev/null +++ b/prism/templates/include/prism/internal/diagnostic.h.erb @@ -0,0 +1,60 @@ +#ifndef PRISM_INTERNAL_DIAGNOSTIC_H +#define PRISM_INTERNAL_DIAGNOSTIC_H + +#include "prism/internal/list.h" + +#include "prism/arena.h" +#include "prism/diagnostic.h" + +/* + * The diagnostic IDs of all of the diagnostics, used to communicate the types + * of errors between the parser and the user. + */ +typedef enum { + /* These are the error diagnostics. */ + <%- errors.each do |error| -%> + PM_ERR_<%= error.name %>, + <%- end -%> + + /* These are the warning diagnostics. */ + <%- warnings.each do |warning| -%> + PM_WARN_<%= warning.name %>, + <%- end -%> +} pm_diagnostic_id_t; + +/* + * This struct represents a diagnostic generated during parsing. + */ +struct pm_diagnostic_t { + /* The embedded base node. */ + pm_list_node_t node; + + /* The location of the diagnostic in the source. */ + pm_location_t location; + + /* The ID of the diagnostic. */ + pm_diagnostic_id_t diag_id; + + /* The message associated with the diagnostic. */ + const char *message; + + /* + * The level of the diagnostic, see `pm_error_level_t` and + * `pm_warning_level_t` for possible values. + */ + uint8_t level; +}; + +/* + * Append a diagnostic to the given list of diagnostics that is using shared + * memory for its message. + */ +void pm_diagnostic_list_append(pm_arena_t *arena, pm_list_t *list, uint32_t start, uint32_t length, pm_diagnostic_id_t diag_id); + +/* + * Append a diagnostic to the given list of diagnostics that is using a format + * string for its message. + */ +void pm_diagnostic_list_append_format(pm_arena_t *arena, pm_list_t *list, uint32_t start, uint32_t length, pm_diagnostic_id_t diag_id, ...); + +#endif diff --git a/prism/templates/include/prism/node_new.h.erb b/prism/templates/include/prism/node_new.h.erb deleted file mode 100644 index 56c214e00634b1..00000000000000 --- a/prism/templates/include/prism/node_new.h.erb +++ /dev/null @@ -1,42 +0,0 @@ -/** - * @file node_new.h - * - * Static inline functions for allocating and initializing AST nodes. - * - * -- - */ -#ifndef PRISM_NODE_NEW_H -#define PRISM_NODE_NEW_H - -#include "prism/node.h" - -<%- nodes.each do |node| -%> -<%- params = node.fields.map(&:c_param) -%> -/** - * Allocate and initialize a new <%= node.name %> node. - * - * @param arena The arena to allocate from. - * @param node_id The unique identifier for this node. - * @param flags The flags for this node. - * @param location The location of this node in the source. -<%- node.fields.each do |field| -%> - * @param <%= field.name %> <%= field.comment ? Prism::Template::Doxygen.verbatim(field.comment.lines.first.strip) : "The #{field.name} field." %> -<%- end -%> - * @return The newly allocated and initialized node. - */ -static inline pm_<%= node.human %>_t * -pm_<%= node.human %>_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location<%= params.empty? ? "" : ", #{params.join(", ")}" %>) { - pm_<%= node.human %>_t *node = (pm_<%= node.human %>_t *) pm_arena_alloc(arena, sizeof(pm_<%= node.human %>_t), PRISM_ALIGNOF(pm_<%= node.human %>_t)); - - *node = (pm_<%= node.human %>_t) { - .base = { .type = <%= node.type %>, .flags = flags, .node_id = node_id, .location = location }<%= node.fields.empty? ? "" : "," %> -<%- node.fields.each_with_index do |field, index| -%> - .<%= field.name %> = <%= field.name %><%= index < node.fields.size - 1 ? "," : "" %> -<%- end -%> - }; - - return node; -} - -<%- end -%> -#endif diff --git a/prism/templates/lib/prism/serialize.rb.erb b/prism/templates/lib/prism/serialize.rb.erb index c272d84bb4f889..a676f957af96df 100644 --- a/prism/templates/lib/prism/serialize.rb.erb +++ b/prism/templates/lib/prism/serialize.rb.erb @@ -437,11 +437,10 @@ module Prism tokens = [] #: Array[[Token, Integer]] while (type = TOKEN_TYPES.fetch(load_varuint)) - start = load_varuint - length = load_varuint + location = load_location_object(false) + lex_state = load_varuint - location = Location.new(@source, start, length) token = Token.new(@source, type, location.slice, location) tokens << [token, lex_state] diff --git a/prism/templates/src/diagnostic.c.erb b/prism/templates/src/diagnostic.c.erb index b02714637dea07..0dea7328694cf3 100644 --- a/prism/templates/src/diagnostic.c.erb +++ b/prism/templates/src/diagnostic.c.erb @@ -1,5 +1,16 @@ -#include "prism/diagnostic.h" -#include "prism/util/pm_arena.h" +#include "prism/internal/diagnostic.h" + +#include "prism/compiler/inline.h" + +#include "prism/internal/allocator.h" +#include "prism/internal/arena.h" +#include "prism/internal/list.h" + +#include +#include +#include +#include +#include #define PM_DIAGNOSTIC_ID_MAX <%= errors.length + warnings.length %> @@ -76,16 +87,16 @@ typedef struct { * * `PM_WARNING_LEVEL_VERBOSE` - Warnings that appear with `-w`, as in `ruby -w -c -e 'code'`. */ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = { - // Special error that can be replaced + /* Special error that can be replaced */ [PM_ERR_CANNOT_PARSE_EXPRESSION] = { "cannot parse the expression", PM_ERROR_LEVEL_SYNTAX }, - // Errors that should raise argument errors + /* Errors that should raise argument errors */ [PM_ERR_INVALID_ENCODING_MAGIC_COMMENT] = { "unknown or invalid encoding in the magic comment", PM_ERROR_LEVEL_ARGUMENT }, - // Errors that should raise load errors + /* Errors that should raise load errors */ [PM_ERR_SCRIPT_NOT_FOUND] = { "no Ruby script found in input", PM_ERROR_LEVEL_LOAD }, - // Errors that should raise syntax errors + /* Errors that should raise syntax errors */ [PM_ERR_ALIAS_ARGUMENT] = { "invalid argument being passed to `alias`; expected a bare word, symbol, constant, or global variable", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_ALIAS_ARGUMENT_NUMBERED_REFERENCE] = { "invalid argument being passed to `alias`; can't make alias for the number variables", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_AMPAMPEQ_MULTI_ASSIGN] = { "unexpected `&&=` in a multiple assignment", PM_ERROR_LEVEL_SYNTAX }, @@ -354,7 +365,7 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = { [PM_ERR_STRING_INTERPOLATED_TERM] = { "unterminated string; expected a closing delimiter for the interpolated string", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_STRING_LITERAL_EOF] = { "unterminated string meets end of file", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_STRING_LITERAL_TERM] = { "unexpected %s, expected a string literal terminator", PM_ERROR_LEVEL_SYNTAX }, - [PM_ERR_SYMBOL_INVALID] = { "invalid symbol", PM_ERROR_LEVEL_SYNTAX }, // TODO expected symbol? prism.c ~9719 + [PM_ERR_SYMBOL_INVALID] = { "invalid symbol", PM_ERROR_LEVEL_SYNTAX }, /* TODO expected symbol? prism.c ~9719 */ [PM_ERR_SYMBOL_TERM_DYNAMIC] = { "unterminated quoted string; expected a closing delimiter for the dynamic symbol", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_SYMBOL_TERM_INTERPOLATED] = { "unterminated symbol; expected a closing delimiter for the interpolated symbol", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_TERNARY_COLON] = { "expected a `:` after the true expression of a ternary operator", PM_ERROR_LEVEL_SYNTAX }, @@ -381,7 +392,7 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = { [PM_ERR_WRITE_TARGET_UNEXPECTED] = { "unexpected write target", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_XSTRING_TERM] = { "expected a closing delimiter for the `%x` or backtick string", PM_ERROR_LEVEL_SYNTAX }, - // Warnings + /* Warnings */ [PM_WARN_AMBIGUOUS_BINARY_OPERATOR] = { "'%s' after local variable or literal is interpreted as binary operator even though it seems like %s", PM_WARNING_LEVEL_VERBOSE }, [PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_MINUS] = { "ambiguous first argument; put parentheses or a space even after `-` operator", PM_WARNING_LEVEL_VERBOSE }, [PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_PLUS] = { "ambiguous first argument; put parentheses or a space even after `+` operator", PM_WARNING_LEVEL_VERBOSE }, @@ -417,8 +428,8 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = { /** * Get the human-readable name of the given diagnostic ID. */ -const char * -pm_diagnostic_id_human(pm_diagnostic_id_t diag_id) { +static const char * +pm_diagnostic_id_name(pm_diagnostic_id_t diag_id) { switch (diag_id) { <%- errors.each do |error| -%> case PM_ERR_<%= error.name %>: return "<%= error.name.downcase %>"; @@ -432,8 +443,8 @@ pm_diagnostic_id_human(pm_diagnostic_id_t diag_id) { return ""; } -static inline const char * -pm_diagnostic_message(pm_diagnostic_id_t diag_id) { +static PRISM_INLINE const char * +pm_diagnostic_id_message(pm_diagnostic_id_t diag_id) { assert(diag_id < PM_DIAGNOSTIC_ID_MAX); const char *message = diagnostic_messages[diag_id].message; @@ -442,13 +453,53 @@ pm_diagnostic_message(pm_diagnostic_id_t diag_id) { return message; } -static inline uint8_t -pm_diagnostic_level(pm_diagnostic_id_t diag_id) { +static PRISM_INLINE uint8_t +pm_diagnostic_id_level(pm_diagnostic_id_t diag_id) { assert(diag_id < PM_DIAGNOSTIC_ID_MAX); return (uint8_t) diagnostic_messages[diag_id].level; } +/** + * Get the type of the given diagnostic. + */ +const char * +pm_diagnostic_type(const pm_diagnostic_t *diagnostic) { + return pm_diagnostic_id_name(diagnostic->diag_id); +} + +/** + * Get the location of the given diagnostic. + */ +pm_location_t +pm_diagnostic_location(const pm_diagnostic_t *diagnostic) { + return diagnostic->location; +} + +/** + * Get the message of the given diagnostic. + */ +const char * +pm_diagnostic_message(const pm_diagnostic_t *diagnostic) { + return diagnostic->message; +} + +/** + * Get the error level associated with the given diagnostic. + */ +pm_error_level_t +pm_diagnostic_error_level(const pm_diagnostic_t *diagnostic) { + return (pm_error_level_t) pm_diagnostic_id_level(diagnostic->diag_id); +} + +/** + * Get the warning level associated with the given diagnostic. + */ +pm_warning_level_t +pm_diagnostic_warning_level(const pm_diagnostic_t *diagnostic) { + return (pm_warning_level_t) pm_diagnostic_id_level(diagnostic->diag_id); +} + /** * Append an error to the given list of diagnostic. */ @@ -459,8 +510,8 @@ pm_diagnostic_list_append(pm_arena_t *arena, pm_list_t *list, uint32_t start, ui *diagnostic = (pm_diagnostic_t) { .location = { .start = start, .length = length }, .diag_id = diag_id, - .message = pm_diagnostic_message(diag_id), - .level = pm_diagnostic_level(diag_id) + .message = pm_diagnostic_id_message(diag_id), + .level = pm_diagnostic_id_level(diag_id) }; pm_list_append(list, (pm_list_node_t *) diagnostic); @@ -475,7 +526,7 @@ pm_diagnostic_list_append_format(pm_arena_t *arena, pm_list_t *list, uint32_t st va_list arguments; va_start(arguments, diag_id); - const char *format = pm_diagnostic_message(diag_id); + const char *format = pm_diagnostic_id_message(diag_id); int result = vsnprintf(NULL, 0, format, arguments); va_end(arguments); @@ -496,9 +547,8 @@ pm_diagnostic_list_append_format(pm_arena_t *arena, pm_list_t *list, uint32_t st .location = { .start = start, .length = length }, .diag_id = diag_id, .message = message, - .level = pm_diagnostic_level(diag_id) + .level = pm_diagnostic_id_level(diag_id) }; pm_list_append(list, (pm_list_node_t *) diagnostic); } - diff --git a/prism/templates/src/json.c.erb b/prism/templates/src/json.c.erb new file mode 100644 index 00000000000000..5c4ab8d92a8e72 --- /dev/null +++ b/prism/templates/src/json.c.erb @@ -0,0 +1,130 @@ +#include "prism/json.h" + +// Ensure this translation unit is never empty, even when JSON is excluded. +typedef int pm_json_unused_t; + +#ifndef PRISM_EXCLUDE_JSON + +#include "prism/internal/buffer.h" +#include "prism/internal/constant_pool.h" +#include "prism/internal/integer.h" +#include "prism/internal/parser.h" + +#include + +static void +pm_dump_json_constant(pm_buffer_t *buffer, const pm_parser_t *parser, pm_constant_id_t constant_id) { + const pm_constant_t *constant = pm_constant_pool_id_to_constant(&parser->constant_pool, constant_id); + pm_buffer_append_byte(buffer, '"'); + pm_buffer_append_source(buffer, constant->start, constant->length, PM_BUFFER_ESCAPING_JSON); + pm_buffer_append_byte(buffer, '"'); +} + +static void +pm_dump_json_location(pm_buffer_t *buffer, const pm_location_t *location) { + pm_buffer_append_format(buffer, "{\"start\":%" PRIu32 ",\"length\":%" PRIu32 "}", location->start, location->length); +} + +/** + * Dump JSON to the given buffer. + */ +void +pm_dump_json(pm_buffer_t *buffer, const pm_parser_t *parser, const pm_node_t *node) { + switch (PM_NODE_TYPE(node)) { + <%- nodes.each do |node| -%> + case <%= node.type %>: { + pm_buffer_append_string(buffer, "{\"type\":\"<%= node.name %>\",\"location\":", <%= node.name.bytesize + 22 %>); + + const pm_<%= node.human %>_t *cast = (const pm_<%= node.human %>_t *) node; + pm_dump_json_location(buffer, &cast->base.location); + <%- [*node.flags, *node.fields].each_with_index do |field, index| -%> + + // Dump the <%= field.name %> field + pm_buffer_append_byte(buffer, ','); + <%- if field.is_a?(Prism::Template::Flags) -%> + pm_buffer_append_string(buffer, "\"flags\":", 8); + <%- else -%> + pm_buffer_append_string(buffer, "\"<%= field.name %>\":", <%= field.name.bytesize + 3 %>); + <%- end -%> + <%- case field -%> + <%- when Prism::Template::NodeField -%> + pm_dump_json(buffer, parser, (const pm_node_t *) cast-><%= field.name %>); + <%- when Prism::Template::OptionalNodeField -%> + if (cast-><%= field.name %> != NULL) { + pm_dump_json(buffer, parser, (const pm_node_t *) cast-><%= field.name %>); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + <%- when Prism::Template::NodeListField -%> + const pm_node_list_t *<%= field.name %> = &cast-><%= field.name %>; + pm_buffer_append_byte(buffer, '['); + + for (size_t index = 0; index < <%= field.name %>->size; index++) { + if (index != 0) pm_buffer_append_byte(buffer, ','); + pm_dump_json(buffer, parser, <%= field.name %>->nodes[index]); + } + pm_buffer_append_byte(buffer, ']'); + <%- when Prism::Template::StringField -%> + const pm_string_t *<%= field.name %> = &cast-><%= field.name %>; + pm_buffer_append_byte(buffer, '"'); + pm_buffer_append_source(buffer, pm_string_source(<%= field.name %>), pm_string_length(<%= field.name %>), PM_BUFFER_ESCAPING_JSON); + pm_buffer_append_byte(buffer, '"'); + <%- when Prism::Template::ConstantField -%> + pm_dump_json_constant(buffer, parser, cast-><%= field.name %>); + <%- when Prism::Template::OptionalConstantField -%> + if (cast-><%= field.name %> != PM_CONSTANT_ID_UNSET) { + pm_dump_json_constant(buffer, parser, cast-><%= field.name %>); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + <%- when Prism::Template::ConstantListField -%> + const pm_constant_id_list_t *<%= field.name %> = &cast-><%= field.name %>; + pm_buffer_append_byte(buffer, '['); + + for (size_t index = 0; index < <%= field.name %>->size; index++) { + if (index != 0) pm_buffer_append_byte(buffer, ','); + pm_dump_json_constant(buffer, parser, <%= field.name %>->ids[index]); + } + pm_buffer_append_byte(buffer, ']'); + <%- when Prism::Template::LocationField -%> + pm_dump_json_location(buffer, &cast-><%= field.name %>); + <%- when Prism::Template::OptionalLocationField -%> + if (cast-><%= field.name %>.length != 0) { + pm_dump_json_location(buffer, &cast-><%= field.name %>); + } else { + pm_buffer_append_string(buffer, "null", 4); + } + <%- when Prism::Template::UInt8Field -%> + pm_buffer_append_format(buffer, "%" PRIu8, cast-><%= field.name %>); + <%- when Prism::Template::UInt32Field -%> + pm_buffer_append_format(buffer, "%" PRIu32, cast-><%= field.name %>); + <%- when Prism::Template::Flags -%> + size_t flags = 0; + pm_buffer_append_byte(buffer, '['); + <%- node.flags.values.each_with_index do |value, index| -%> + if (PM_NODE_FLAG_P(cast, PM_<%= node.flags.human.upcase %>_<%= value.name %>)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"<%= value.name %>\"", <%= value.name.bytesize + 2 %>); + flags++; + } + <%- end -%> + pm_buffer_append_byte(buffer, ']'); + <%- when Prism::Template::IntegerField -%> + pm_integer_string(buffer, &cast-><%= field.name %>); + <%- when Prism::Template::DoubleField -%> + pm_buffer_append_format(buffer, "%f", cast-><%= field.name %>); + <%- else -%> + <%- raise %> + <%- end -%> + <%- end -%> + + pm_buffer_append_byte(buffer, '}'); + break; + } + <%- end -%> + case PM_SCOPE_NODE: + break; + } +} + +#endif diff --git a/prism/templates/src/node.c.erb b/prism/templates/src/node.c.erb index 93ea275a545bf6..f51aff6e53157f 100644 --- a/prism/templates/src/node.c.erb +++ b/prism/templates/src/node.c.erb @@ -1,5 +1,9 @@ #line <%= __LINE__ + 1 %> "prism/templates/src/<%= File.basename(__FILE__) %>" -#include "prism/node.h" +#include "prism/internal/node.h" + +#include "prism/internal/arena.h" + +#include /** * Attempts to grow the node list to the next size. If there is already @@ -74,8 +78,8 @@ pm_node_list_concat(pm_arena_t *arena, pm_node_list_t *list, pm_node_list_t *oth /** * Returns a string representation of the given node type. */ -PRISM_EXPORTED_FUNCTION const char * -pm_node_type_to_str(pm_node_type_t node_type) +const char * +pm_node_type(pm_node_type_t node_type) { switch (node_type) { <%- nodes.each do |node| -%> @@ -94,7 +98,7 @@ pm_node_type_to_str(pm_node_type_t node_type) * pointer and is passed to the visitor callback for consumers to use as they * see fit. */ -PRISM_EXPORTED_FUNCTION void +void pm_visit_node(const pm_node_t *node, bool (*visitor)(const pm_node_t *node, void *data), void *data) { if (visitor(node, data)) pm_visit_child_nodes(node, visitor, data); } @@ -104,7 +108,7 @@ pm_visit_node(const pm_node_t *node, bool (*visitor)(const pm_node_t *node, void * default behavior for walking the tree that is called from pm_visit_node if * the callback returns true. */ -PRISM_EXPORTED_FUNCTION void +void pm_visit_child_nodes(const pm_node_t *node, bool (*visitor)(const pm_node_t *node, void *data), void *data) { switch (PM_NODE_TYPE(node)) { <%- nodes.each do |node| -%> @@ -140,124 +144,23 @@ pm_visit_child_nodes(const pm_node_t *node, bool (*visitor)(const pm_node_t *nod break; } } +<%- nodes.each do |node| -%> -// We optionally support dumping to JSON. For systems that don't want or need -// this functionality, it can be turned off with the PRISM_EXCLUDE_JSON define. -#ifndef PRISM_EXCLUDE_JSON - -static void -pm_dump_json_constant(pm_buffer_t *buffer, const pm_parser_t *parser, pm_constant_id_t constant_id) { - const pm_constant_t *constant = pm_constant_pool_id_to_constant(&parser->constant_pool, constant_id); - pm_buffer_append_byte(buffer, '"'); - pm_buffer_append_source(buffer, constant->start, constant->length, PM_BUFFER_ESCAPING_JSON); - pm_buffer_append_byte(buffer, '"'); -} - -static void -pm_dump_json_location(pm_buffer_t *buffer, const pm_location_t *location) { - pm_buffer_append_format(buffer, "{\"start\":%" PRIu32 ",\"length\":%" PRIu32 "}", location->start, location->length); -} - +<%- params = node.fields.map(&:c_param) -%> /** - * Dump JSON to the given buffer. + * Allocate and initialize a new <%= node.name %> node. */ -PRISM_EXPORTED_FUNCTION void -pm_dump_json(pm_buffer_t *buffer, const pm_parser_t *parser, const pm_node_t *node) { - switch (PM_NODE_TYPE(node)) { - <%- nodes.each do |node| -%> - case <%= node.type %>: { - pm_buffer_append_string(buffer, "{\"type\":\"<%= node.name %>\",\"location\":", <%= node.name.bytesize + 22 %>); - - const pm_<%= node.human %>_t *cast = (const pm_<%= node.human %>_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - <%- [*node.flags, *node.fields].each_with_index do |field, index| -%> - - // Dump the <%= field.name %> field - pm_buffer_append_byte(buffer, ','); - <%- if field.is_a?(Prism::Template::Flags) -%> - pm_buffer_append_string(buffer, "\"flags\":", 8); - <%- else -%> - pm_buffer_append_string(buffer, "\"<%= field.name %>\":", <%= field.name.bytesize + 3 %>); - <%- end -%> - <%- case field -%> - <%- when Prism::Template::NodeField -%> - pm_dump_json(buffer, parser, (const pm_node_t *) cast-><%= field.name %>); - <%- when Prism::Template::OptionalNodeField -%> - if (cast-><%= field.name %> != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast-><%= field.name %>); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - <%- when Prism::Template::NodeListField -%> - const pm_node_list_t *<%= field.name %> = &cast-><%= field.name %>; - pm_buffer_append_byte(buffer, '['); - - for (size_t index = 0; index < <%= field.name %>->size; index++) { - if (index != 0) pm_buffer_append_byte(buffer, ','); - pm_dump_json(buffer, parser, <%= field.name %>->nodes[index]); - } - pm_buffer_append_byte(buffer, ']'); - <%- when Prism::Template::StringField -%> - const pm_string_t *<%= field.name %> = &cast-><%= field.name %>; - pm_buffer_append_byte(buffer, '"'); - pm_buffer_append_source(buffer, pm_string_source(<%= field.name %>), pm_string_length(<%= field.name %>), PM_BUFFER_ESCAPING_JSON); - pm_buffer_append_byte(buffer, '"'); - <%- when Prism::Template::ConstantField -%> - pm_dump_json_constant(buffer, parser, cast-><%= field.name %>); - <%- when Prism::Template::OptionalConstantField -%> - if (cast-><%= field.name %> != PM_CONSTANT_ID_UNSET) { - pm_dump_json_constant(buffer, parser, cast-><%= field.name %>); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - <%- when Prism::Template::ConstantListField -%> - const pm_constant_id_list_t *<%= field.name %> = &cast-><%= field.name %>; - pm_buffer_append_byte(buffer, '['); - - for (size_t index = 0; index < <%= field.name %>->size; index++) { - if (index != 0) pm_buffer_append_byte(buffer, ','); - pm_dump_json_constant(buffer, parser, <%= field.name %>->ids[index]); - } - pm_buffer_append_byte(buffer, ']'); - <%- when Prism::Template::LocationField -%> - pm_dump_json_location(buffer, &cast-><%= field.name %>); - <%- when Prism::Template::OptionalLocationField -%> - if (cast-><%= field.name %>.length != 0) { - pm_dump_json_location(buffer, &cast-><%= field.name %>); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - <%- when Prism::Template::UInt8Field -%> - pm_buffer_append_format(buffer, "%" PRIu8, cast-><%= field.name %>); - <%- when Prism::Template::UInt32Field -%> - pm_buffer_append_format(buffer, "%" PRIu32, cast-><%= field.name %>); - <%- when Prism::Template::Flags -%> - size_t flags = 0; - pm_buffer_append_byte(buffer, '['); - <%- node.flags.values.each_with_index do |value, index| -%> - if (PM_NODE_FLAG_P(cast, PM_<%= node.flags.human.upcase %>_<%= value.name %>)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"<%= value.name %>\"", <%= value.name.bytesize + 2 %>); - flags++; - } - <%- end -%> - pm_buffer_append_byte(buffer, ']'); - <%- when Prism::Template::IntegerField -%> - pm_integer_string(buffer, &cast-><%= field.name %>); - <%- when Prism::Template::DoubleField -%> - pm_buffer_append_format(buffer, "%f", cast-><%= field.name %>); - <%- else -%> - <%- raise %> - <%- end -%> - <%- end -%> +pm_<%= node.human %>_t * +pm_<%= node.human %>_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location<%= params.empty? ? "" : ", #{params.join(", ")}" %>) { + pm_<%= node.human %>_t *node = (pm_<%= node.human %>_t *) pm_arena_alloc(arena, sizeof(pm_<%= node.human %>_t), PRISM_ALIGNOF(pm_<%= node.human %>_t)); + + *node = (pm_<%= node.human %>_t) { + .base = { .type = <%= node.type %>, .flags = flags, .node_id = node_id, .location = location }<%= node.fields.empty? ? "" : "," %> +<%- node.fields.each_with_index do |field, index| -%> + .<%= field.name %> = <%= field.name %><%= index < node.fields.size - 1 ? "," : "" %> +<%- end -%> + }; - pm_buffer_append_byte(buffer, '}'); - break; - } - <%- end -%> - case PM_SCOPE_NODE: - break; - } + return node; } - -#endif +<%- end -%> diff --git a/prism/templates/src/prettyprint.c.erb b/prism/templates/src/prettyprint.c.erb index 44423ca42b2b06..f12531d9342a8c 100644 --- a/prism/templates/src/prettyprint.c.erb +++ b/prism/templates/src/prettyprint.c.erb @@ -1,23 +1,34 @@ <%# encoding: ASCII -%> #include "prism/prettyprint.h" -// We optionally support pretty printing nodes. For systems that don't want or -// need this functionality, it can be turned off with the -// PRISM_EXCLUDE_PRETTYPRINT define. +/* We optionally support pretty printing nodes. For systems that don't want or + * need this functionality, it can be turned off with the + * PRISM_EXCLUDE_PRETTYPRINT define. */ #ifdef PRISM_EXCLUDE_PRETTYPRINT -void pm_prettyprint(void) {} +/* Ensure this translation unit is never empty, even when prettyprint is + * excluded. */ +typedef int pm_prettyprint_unused_t; #else -static inline void +#include "prism/compiler/inline.h" +#include "prism/internal/buffer.h" +#include "prism/internal/constant_pool.h" +#include "prism/internal/integer.h" +#include "prism/internal/parser.h" +#include "prism/line_offset_list.h" + +#include + +static PRISM_INLINE void prettyprint_location(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm_location_t *location) { pm_line_column_t start = pm_line_offset_list_line_column(&parser->line_offsets, location->start, parser->start_line); pm_line_column_t end = pm_line_offset_list_line_column(&parser->line_offsets, location->start + location->length, parser->start_line); pm_buffer_append_format(output_buffer, "(%" PRIi32 ",%" PRIu32 ")-(%" PRIi32 ",%" PRIu32 ")", start.line, start.column, end.line, end.column); } -static inline void +static PRISM_INLINE void prettyprint_constant(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm_constant_id_t constant_id) { pm_constant_t *constant = pm_constant_pool_id_to_constant(&parser->constant_pool, constant_id); pm_buffer_append_format(output_buffer, ":%.*s", (int) constant->length, constant->start); @@ -156,11 +167,11 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm /** * Pretty-prints the AST represented by the given node to the given buffer. */ -PRISM_EXPORTED_FUNCTION void +void pm_prettyprint(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm_node_t *node) { pm_buffer_t prefix_buffer = { 0 }; prettyprint_node(output_buffer, parser, node, &prefix_buffer); - pm_buffer_free(&prefix_buffer); + pm_buffer_cleanup(&prefix_buffer); } #endif diff --git a/prism/templates/src/serialize.c.erb b/prism/templates/src/serialize.c.erb index 78e4f348932f45..3d9811e5db686b 100644 --- a/prism/templates/src/serialize.c.erb +++ b/prism/templates/src/serialize.c.erb @@ -1,19 +1,42 @@ -#include "prism.h" +#include "prism/excludes.h" + +/* We optionally support serializing to a binary string. For systems that do not + * want or need this functionality, it can be turned off with the + * PRISM_EXCLUDE_SERIALIZATION define. */ +#ifdef PRISM_EXCLUDE_SERIALIZATION + +/* Ensure this translation unit is never empty, even when serialization is + * excluded. */ +typedef int pm_serialize_unused_t; + +#else -// We optionally support serializing to a binary string. For systems that don't -// want or need this functionality, it can be turned off with the -// PRISM_EXCLUDE_SERIALIZATION define. -#ifndef PRISM_EXCLUDE_SERIALIZATION +#include "prism/compiler/inline.h" + +#include "prism/internal/buffer.h" +#include "prism/internal/comments.h" +#include "prism/internal/diagnostic.h" +#include "prism/internal/encoding.h" +#include "prism/internal/list.h" +#include "prism/internal/magic_comments.h" +#include "prism/internal/options.h" +#include "prism/internal/parser.h" + +#include "prism.h" +#include "prism/ast.h" +#include "prism/line_offset_list.h" +#include #include +#include -static inline uint32_t +static PRISM_INLINE uint32_t pm_ptrdifft_to_u32(ptrdiff_t value) { assert(value >= 0 && ((unsigned long) value) < UINT32_MAX); return (uint32_t) value; } -static inline uint32_t +static PRISM_INLINE uint32_t pm_sizet_to_u32(size_t value) { assert(value < UINT32_MAX); return (uint32_t) value; @@ -298,7 +321,7 @@ pm_serialize_content(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) } static void -serialize_token(void *data, pm_parser_t *parser, pm_token_t *token) { +serialize_token(pm_parser_t *parser, pm_token_t *token, void *data) { pm_buffer_t *buffer = (pm_buffer_t *) data; pm_buffer_append_varuint(buffer, token->type); @@ -310,7 +333,7 @@ serialize_token(void *data, pm_parser_t *parser, pm_token_t *token) { /** * Lex the given source and serialize to the given buffer. */ -PRISM_EXPORTED_FUNCTION void +void pm_serialize_lex(pm_buffer_t *buffer, const uint8_t *source, size_t size, const char *data) { pm_options_t options = { 0 }; pm_options_read(&options, data); @@ -319,12 +342,7 @@ pm_serialize_lex(pm_buffer_t *buffer, const uint8_t *source, size_t size, const pm_parser_t parser; pm_parser_init(&arena, &parser, source, size, &options); - pm_lex_callback_t lex_callback = (pm_lex_callback_t) { - .data = (void *) buffer, - .callback = serialize_token, - }; - - parser.lex_callback = &lex_callback; + pm_parser_lex_callback_set(&parser, serialize_token, buffer); pm_parse(&parser); // Append 0 to mark end of tokens. @@ -332,16 +350,16 @@ pm_serialize_lex(pm_buffer_t *buffer, const uint8_t *source, size_t size, const pm_serialize_metadata(&parser, buffer); - pm_parser_free(&parser); - pm_arena_free(&arena); - pm_options_free(&options); + pm_parser_cleanup(&parser); + pm_arena_cleanup(&arena); + pm_options_cleanup(&options); } /** * Parse and serialize both the AST and the tokens represented by the given * source to the given buffer. */ -PRISM_EXPORTED_FUNCTION void +void pm_serialize_parse_lex(pm_buffer_t *buffer, const uint8_t *source, size_t size, const char *data) { pm_options_t options = { 0 }; pm_options_read(&options, data); @@ -350,20 +368,37 @@ pm_serialize_parse_lex(pm_buffer_t *buffer, const uint8_t *source, size_t size, pm_parser_t parser; pm_parser_init(&arena, &parser, source, size, &options); - pm_lex_callback_t lex_callback = (pm_lex_callback_t) { - .data = (void *) buffer, - .callback = serialize_token, - }; - - parser.lex_callback = &lex_callback; + pm_parser_lex_callback_set(&parser, serialize_token, buffer); pm_node_t *node = pm_parse(&parser); pm_buffer_append_byte(buffer, 0); pm_serialize(&parser, node, buffer); - pm_parser_free(&parser); - pm_arena_free(&arena); - pm_options_free(&options); + pm_parser_cleanup(&parser); + pm_arena_cleanup(&arena); + pm_options_cleanup(&options); +} + +/** + * Parse the source and return true if it parses without errors or warnings. + */ +bool +pm_serialize_parse_success_p(const uint8_t *source, size_t size, const char *data) { + pm_options_t options = { 0 }; + pm_options_read(&options, data); + + pm_arena_t arena = { 0 }; + pm_parser_t parser; + pm_parser_init(&arena, &parser, source, size, &options); + + pm_parse(&parser); + + bool result = parser.error_list.size == 0; + pm_parser_cleanup(&parser); + pm_arena_cleanup(&arena); + pm_options_cleanup(&options); + + return result; } #endif diff --git a/prism/templates/src/token_type.c.erb b/prism/templates/src/tokens.c.erb similarity index 97% rename from prism/templates/src/token_type.c.erb rename to prism/templates/src/tokens.c.erb index 94e41ec4ba1a2b..1e829547382526 100644 --- a/prism/templates/src/token_type.c.erb +++ b/prism/templates/src/tokens.c.erb @@ -1,12 +1,12 @@ -#include - #include "prism/ast.h" +#include + /** * Returns a string representation of the given token type. */ -PRISM_EXPORTED_FUNCTION const char * -pm_token_type_name(pm_token_type_t token_type) { +const char * +pm_token_type(pm_token_type_t token_type) { switch (token_type) { <%- tokens.each do |token| -%> case PM_TOKEN_<%= token.name %>: @@ -27,7 +27,7 @@ pm_token_type_name(pm_token_type_t token_type) { * Returns the human name of the given token type. */ const char * -pm_token_type_human(pm_token_type_t token_type) { +pm_token_str(pm_token_type_t token_type) { switch (token_type) { case PM_TOKEN_EOF: return "end-of-input"; @@ -360,8 +360,8 @@ pm_token_type_human(pm_token_type_t token_type) { return ""; } - // Provide a default, because some compilers can't determine that the above - // switch is exhaustive. + /* Provide a default, because some compilers cannot determine that the above + * switch is exhaustive. */ assert(false && "unreachable"); return ""; } diff --git a/prism/templates/template.rb b/prism/templates/template.rb index 70fa17c83d59b9..8f7734dd43f001 100755 --- a/prism/templates/template.rb +++ b/prism/templates/template.rb @@ -53,7 +53,7 @@ def self.escape(value) module Doxygen # Similar to /verbatim ... /endverbatim but doesn't wrap the result in a code block. def self.verbatim(value) - value.gsub(/[\.*%!`#<>_+-]/, '\\\\\0') + value.gsub(/[*%!`#<>_+@-]/, '\\\\\0') end end @@ -684,8 +684,7 @@ def locals TEMPLATES = [ "ext/prism/api_node.c", "include/prism/ast.h", - "include/prism/diagnostic.h", - "include/prism/node_new.h", + "include/prism/internal/diagnostic.h", "javascript/src/deserialize.js", "javascript/src/nodes.js", "javascript/src/visitor.js", @@ -703,10 +702,11 @@ def locals "lib/prism/serialize.rb", "lib/prism/visitor.rb", "src/diagnostic.c", + "src/json.c", "src/node.c", "src/prettyprint.c", "src/serialize.c", - "src/token_type.c" + "src/tokens.c" ] end end diff --git a/prism/util/pm_buffer.h b/prism/util/pm_buffer.h deleted file mode 100644 index cb80f8b3ce7d01..00000000000000 --- a/prism/util/pm_buffer.h +++ /dev/null @@ -1,236 +0,0 @@ -/** - * @file pm_buffer.h - * - * A wrapper around a contiguous block of allocated memory. - */ -#ifndef PRISM_BUFFER_H -#define PRISM_BUFFER_H - -#include "prism/defines.h" -#include "prism/util/pm_char.h" - -#include -#include -#include -#include -#include - -/** - * A pm_buffer_t is a simple memory buffer that stores data in a contiguous - * block of memory. - */ -typedef struct { - /** The length of the buffer in bytes. */ - size_t length; - - /** The capacity of the buffer in bytes that has been allocated. */ - size_t capacity; - - /** A pointer to the start of the buffer. */ - char *value; -} pm_buffer_t; - -/** - * Return the size of the pm_buffer_t struct. - * - * @returns The size of the pm_buffer_t struct. - */ -PRISM_EXPORTED_FUNCTION size_t pm_buffer_sizeof(void); - -/** - * Initialize a pm_buffer_t with the given capacity. - * - * @param buffer The buffer to initialize. - * @param capacity The capacity of the buffer. - * @returns True if the buffer was initialized successfully, false otherwise. - */ -bool pm_buffer_init_capacity(pm_buffer_t *buffer, size_t capacity); - -/** - * Initialize a pm_buffer_t with its default values. - * - * @param buffer The buffer to initialize. - * @returns True if the buffer was initialized successfully, false otherwise. - * - * \public \memberof pm_buffer_t - */ -PRISM_EXPORTED_FUNCTION bool pm_buffer_init(pm_buffer_t *buffer); - -/** - * Return the value of the buffer. - * - * @param buffer The buffer to get the value of. - * @returns The value of the buffer. - * - * \public \memberof pm_buffer_t - */ -PRISM_EXPORTED_FUNCTION char * pm_buffer_value(const pm_buffer_t *buffer); - -/** - * Return the length of the buffer. - * - * @param buffer The buffer to get the length of. - * @returns The length of the buffer. - * - * \public \memberof pm_buffer_t - */ -PRISM_EXPORTED_FUNCTION size_t pm_buffer_length(const pm_buffer_t *buffer); - -/** - * Append the given amount of space as zeroes to the buffer. - * - * @param buffer The buffer to append to. - * @param length The amount of space to append and zero. - */ -void pm_buffer_append_zeroes(pm_buffer_t *buffer, size_t length); - -/** - * Append a formatted string to the buffer. - * - * @param buffer The buffer to append to. - * @param format The format string to append. - * @param ... The arguments to the format string. - */ -void pm_buffer_append_format(pm_buffer_t *buffer, const char *format, ...) PRISM_ATTRIBUTE_FORMAT(2, 3); - -/** - * Append a string to the buffer. - * - * @param buffer The buffer to append to. - * @param value The string to append. - * @param length The length of the string to append. - */ -void pm_buffer_append_string(pm_buffer_t *buffer, const char *value, size_t length); - -/** - * Append a list of bytes to the buffer. - * - * @param buffer The buffer to append to. - * @param value The bytes to append. - * @param length The length of the bytes to append. - */ -void pm_buffer_append_bytes(pm_buffer_t *buffer, const uint8_t *value, size_t length); - -/** - * Append a single byte to the buffer. - * - * @param buffer The buffer to append to. - * @param value The byte to append. - */ -void pm_buffer_append_byte(pm_buffer_t *buffer, uint8_t value); - -/** - * Append a 32-bit unsigned integer to the buffer as a variable-length integer. - * - * @param buffer The buffer to append to. - * @param value The integer to append. - */ -void pm_buffer_append_varuint(pm_buffer_t *buffer, uint32_t value); - -/** - * Append a 32-bit signed integer to the buffer as a variable-length integer. - * - * @param buffer The buffer to append to. - * @param value The integer to append. - */ -void pm_buffer_append_varsint(pm_buffer_t *buffer, int32_t value); - -/** - * Append a double to the buffer. - * - * @param buffer The buffer to append to. - * @param value The double to append. - */ -void pm_buffer_append_double(pm_buffer_t *buffer, double value); - -/** - * Append a unicode codepoint to the buffer. - * - * @param buffer The buffer to append to. - * @param value The character to append. - * @returns True if the codepoint was valid and appended successfully, false - * otherwise. - */ -bool pm_buffer_append_unicode_codepoint(pm_buffer_t *buffer, uint32_t value); - -/** - * The different types of escaping that can be performed by the buffer when - * appending a slice of Ruby source code. - */ -typedef enum { - PM_BUFFER_ESCAPING_RUBY, - PM_BUFFER_ESCAPING_JSON -} pm_buffer_escaping_t; - -/** - * Append a slice of source code to the buffer. - * - * @param buffer The buffer to append to. - * @param source The source code to append. - * @param length The length of the source code to append. - * @param escaping The type of escaping to perform. - */ -void pm_buffer_append_source(pm_buffer_t *buffer, const uint8_t *source, size_t length, pm_buffer_escaping_t escaping); - -/** - * Prepend the given string to the buffer. - * - * @param buffer The buffer to prepend to. - * @param value The string to prepend. - * @param length The length of the string to prepend. - */ -void pm_buffer_prepend_string(pm_buffer_t *buffer, const char *value, size_t length); - -/** - * Concatenate one buffer onto another. - * - * @param destination The buffer to concatenate onto. - * @param source The buffer to concatenate. - */ -void pm_buffer_concat(pm_buffer_t *destination, const pm_buffer_t *source); - -/** - * Clear the buffer by reducing its size to 0. This does not free the allocated - * memory, but it does allow the buffer to be reused. - * - * @param buffer The buffer to clear. - */ -void pm_buffer_clear(pm_buffer_t *buffer); - -/** - * Strip the whitespace from the end of the buffer. - * - * @param buffer The buffer to strip. - */ -void pm_buffer_rstrip(pm_buffer_t *buffer); - -/** - * Checks if the buffer includes the given value. - * - * @param buffer The buffer to check. - * @param value The value to check for. - * @returns The index of the first occurrence of the value in the buffer, or - * SIZE_MAX if the value is not found. - */ -size_t pm_buffer_index(const pm_buffer_t *buffer, char value); - -/** - * Insert the given string into the buffer at the given index. - * - * @param buffer The buffer to insert into. - * @param index The index to insert at. - * @param value The string to insert. - * @param length The length of the string to insert. - */ -void pm_buffer_insert(pm_buffer_t *buffer, size_t index, const char *value, size_t length); - -/** - * Free the memory associated with the buffer. - * - * @param buffer The buffer to free. - * - * \public \memberof pm_buffer_t - */ -PRISM_EXPORTED_FUNCTION void pm_buffer_free(pm_buffer_t *buffer); - -#endif diff --git a/prism/util/pm_constant_pool.h b/prism/util/pm_constant_pool.h deleted file mode 100644 index c527343273f297..00000000000000 --- a/prism/util/pm_constant_pool.h +++ /dev/null @@ -1,217 +0,0 @@ -/** - * @file pm_constant_pool.h - * - * A data structure that stores a set of strings. - * - * Each string is assigned a unique id, which can be used to compare strings for - * equality. This comparison ends up being much faster than strcmp, since it - * only requires a single integer comparison. - */ -#ifndef PRISM_CONSTANT_POOL_H -#define PRISM_CONSTANT_POOL_H - -#include "prism/defines.h" -#include "prism/util/pm_arena.h" - -#include -#include -#include -#include -#include - -/** - * When we allocate constants into the pool, we reserve 0 to mean that the slot - * is not yet filled. This constant is reused in other places to indicate the - * lack of a constant id. - */ -#define PM_CONSTANT_ID_UNSET 0 - -/** - * A constant id is a unique identifier for a constant in the constant pool. - */ -typedef uint32_t pm_constant_id_t; - -/** - * A list of constant IDs. Usually used to represent a set of locals. - */ -typedef struct { - /** The number of constant ids in the list. */ - size_t size; - - /** The number of constant ids that have been allocated in the list. */ - size_t capacity; - - /** The constant ids in the list. */ - pm_constant_id_t *ids; -} pm_constant_id_list_t; - -/** - * Initialize a list of constant ids. - * - * @param list The list to initialize. - */ -void pm_constant_id_list_init(pm_constant_id_list_t *list); - -/** - * Initialize a list of constant ids with a given capacity. - * - * @param arena The arena to allocate from. - * @param list The list to initialize. - * @param capacity The initial capacity of the list. - */ -void pm_constant_id_list_init_capacity(pm_arena_t *arena, pm_constant_id_list_t *list, size_t capacity); - -/** - * Append a constant id to a list of constant ids. - * - * @param arena The arena to allocate from. - * @param list The list to append to. - * @param id The id to append. - */ -void pm_constant_id_list_append(pm_arena_t *arena, pm_constant_id_list_t *list, pm_constant_id_t id); - -/** - * Insert a constant id into a list of constant ids at the specified index. - * - * @param list The list to insert into. - * @param index The index at which to insert. - * @param id The id to insert. - */ -void pm_constant_id_list_insert(pm_constant_id_list_t *list, size_t index, pm_constant_id_t id); - -/** - * Checks if the current constant id list includes the given constant id. - * - * @param list The list to check. - * @param id The id to check for. - * @return Whether the list includes the given id. - */ -bool pm_constant_id_list_includes(pm_constant_id_list_t *list, pm_constant_id_t id); - -/** - * The type of bucket in the constant pool hash map. This determines how the - * bucket should be freed. - */ -typedef unsigned int pm_constant_pool_bucket_type_t; - -/** By default, each constant is a slice of the source. */ -static const pm_constant_pool_bucket_type_t PM_CONSTANT_POOL_BUCKET_DEFAULT = 0; - -/** An owned constant is one for which memory has been allocated. */ -static const pm_constant_pool_bucket_type_t PM_CONSTANT_POOL_BUCKET_OWNED = 1; - -/** A constant constant is known at compile time. */ -static const pm_constant_pool_bucket_type_t PM_CONSTANT_POOL_BUCKET_CONSTANT = 2; - -/** A bucket in the hash map. */ -typedef struct { - /** The incremental ID used for indexing back into the pool. */ - unsigned int id: 30; - - /** The type of the bucket, which determines how to free it. */ - pm_constant_pool_bucket_type_t type: 2; - - /** The hash of the bucket. */ - uint32_t hash; - - /** - * A pointer to the start of the string, stored directly in the bucket to - * avoid a pointer chase to the constants array during probing. - */ - const uint8_t *start; - - /** The length of the string. */ - size_t length; -} pm_constant_pool_bucket_t; - -/** A constant in the pool which effectively stores a string. */ -typedef struct { - /** A pointer to the start of the string. */ - const uint8_t *start; - - /** The length of the string. */ - size_t length; -} pm_constant_t; - -/** The overall constant pool, which stores constants found while parsing. */ -typedef struct { - /** The buckets in the hash map. */ - pm_constant_pool_bucket_t *buckets; - - /** The constants that are stored in the buckets. */ - pm_constant_t *constants; - - /** The number of buckets in the hash map. */ - uint32_t size; - - /** The number of buckets that have been allocated in the hash map. */ - uint32_t capacity; -} pm_constant_pool_t; - -/** - * Initialize a new constant pool with a given capacity. - * - * @param arena The arena to allocate from. - * @param pool The pool to initialize. - * @param capacity The initial capacity of the pool. - */ -void pm_constant_pool_init(pm_arena_t *arena, pm_constant_pool_t *pool, uint32_t capacity); - -/** - * Return a pointer to the constant indicated by the given constant id. - * - * @param pool The pool to get the constant from. - * @param constant_id The id of the constant to get. - * @return A pointer to the constant. - */ -pm_constant_t * pm_constant_pool_id_to_constant(const pm_constant_pool_t *pool, pm_constant_id_t constant_id); - -/** - * Find a constant in a constant pool. Returns the id of the constant, or 0 if - * the constant is not found. - * - * @param pool The pool to find the constant in. - * @param start A pointer to the start of the constant. - * @param length The length of the constant. - * @return The id of the constant. - */ -pm_constant_id_t pm_constant_pool_find(const pm_constant_pool_t *pool, const uint8_t *start, size_t length); - -/** - * Insert a constant into a constant pool that is a slice of a source string. - * Returns the id of the constant, or 0 if any potential calls to resize fail. - * - * @param arena The arena to allocate from. - * @param pool The pool to insert the constant into. - * @param start A pointer to the start of the constant. - * @param length The length of the constant. - * @return The id of the constant. - */ -pm_constant_id_t pm_constant_pool_insert_shared(pm_arena_t *arena, pm_constant_pool_t *pool, const uint8_t *start, size_t length); - -/** - * Insert a constant into a constant pool from memory that is now owned by the - * constant pool. Returns the id of the constant, or 0 if any potential calls to - * resize fail. - * - * @param arena The arena to allocate from. - * @param pool The pool to insert the constant into. - * @param start A pointer to the start of the constant. - * @param length The length of the constant. - * @return The id of the constant. - */ -pm_constant_id_t pm_constant_pool_insert_owned(pm_arena_t *arena, pm_constant_pool_t *pool, uint8_t *start, size_t length); - -/** - * Insert a constant into a constant pool from memory that is constant. Returns - * the id of the constant, or 0 if any potential calls to resize fail. - * - * @param arena The arena to allocate from. - * @param pool The pool to insert the constant into. - * @param start A pointer to the start of the constant. - * @param length The length of the constant. - * @return The id of the constant. - */ -pm_constant_id_t pm_constant_pool_insert_constant(pm_arena_t *arena, pm_constant_pool_t *pool, const uint8_t *start, size_t length); - -#endif diff --git a/prism/util/pm_integer.h b/prism/util/pm_integer.h deleted file mode 100644 index 304665e6205dea..00000000000000 --- a/prism/util/pm_integer.h +++ /dev/null @@ -1,130 +0,0 @@ -/** - * @file pm_integer.h - * - * This module provides functions for working with arbitrary-sized integers. - */ -#ifndef PRISM_NUMBER_H -#define PRISM_NUMBER_H - -#include "prism/defines.h" -#include "prism/util/pm_buffer.h" - -#include -#include -#include -#include - -/** - * A structure represents an arbitrary-sized integer. - */ -typedef struct { - /** - * The number of allocated values. length is set to 0 if the integer fits - * into uint32_t. - */ - size_t length; - - /** - * List of 32-bit integers. Set to NULL if the integer fits into uint32_t. - */ - uint32_t *values; - - /** - * Embedded value for small integer. This value is set to 0 if the value - * does not fit into uint32_t. - */ - uint32_t value; - - /** - * Whether or not the integer is negative. It is stored this way so that a - * zeroed pm_integer_t is always positive zero. - */ - bool negative; -} pm_integer_t; - -/** - * An enum controlling the base of an integer. It is expected that the base is - * already known before parsing the integer, even though it could be derived - * from the string itself. - */ -typedef enum { - /** The default decimal base, with no prefix. Leading 0s will be ignored. */ - PM_INTEGER_BASE_DEFAULT, - - /** The binary base, indicated by a 0b or 0B prefix. */ - PM_INTEGER_BASE_BINARY, - - /** The octal base, indicated by a 0, 0o, or 0O prefix. */ - PM_INTEGER_BASE_OCTAL, - - /** The decimal base, indicated by a 0d, 0D, or empty prefix. */ - PM_INTEGER_BASE_DECIMAL, - - /** The hexadecimal base, indicated by a 0x or 0X prefix. */ - PM_INTEGER_BASE_HEXADECIMAL, - - /** - * An unknown base, in which case pm_integer_parse will derive it based on - * the content of the string. This is less efficient and does more - * comparisons, so if callers know the base ahead of time, they should use - * that instead. - */ - PM_INTEGER_BASE_UNKNOWN -} pm_integer_base_t; - -/** - * Parse an integer from a string. This assumes that the format of the integer - * has already been validated, as internal validation checks are not performed - * here. - * - * @param integer The integer to parse into. - * @param base The base of the integer. - * @param start The start of the string. - * @param end The end of the string. - */ -void pm_integer_parse(pm_integer_t *integer, pm_integer_base_t base, const uint8_t *start, const uint8_t *end); - -/** - * Compare two integers. This function returns -1 if the left integer is less - * than the right integer, 0 if they are equal, and 1 if the left integer is - * greater than the right integer. - * - * @param left The left integer to compare. - * @param right The right integer to compare. - * @return The result of the comparison. - */ -int pm_integer_compare(const pm_integer_t *left, const pm_integer_t *right); - -/** - * Reduce a ratio of integers to its simplest form. - * - * If either the numerator or denominator do not fit into a 32-bit integer, then - * this function is a no-op. In the future, we may consider reducing even the - * larger numbers, but for now we're going to keep it simple. - * - * @param numerator The numerator of the ratio. - * @param denominator The denominator of the ratio. - */ -void pm_integers_reduce(pm_integer_t *numerator, pm_integer_t *denominator); - -/** - * Convert an integer to a decimal string. - * - * @param buffer The buffer to append the string to. - * @param integer The integer to convert to a string. - * - * \public \memberof pm_integer_t - */ -PRISM_EXPORTED_FUNCTION void pm_integer_string(pm_buffer_t *buffer, const pm_integer_t *integer); - -/** - * Free the internal memory of an integer. This memory will only be allocated if - * the integer exceeds the size of a single node in the linked list. - * - * @param integer The integer to free. - * - * \public \memberof pm_integer_t - */ -PRISM_EXPORTED_FUNCTION void pm_integer_free(pm_integer_t *integer); - -#endif diff --git a/prism/util/pm_line_offset_list.h b/prism/util/pm_line_offset_list.h deleted file mode 100644 index 62a52da4ece7e8..00000000000000 --- a/prism/util/pm_line_offset_list.h +++ /dev/null @@ -1,115 +0,0 @@ -/** - * @file pm_line_offset_list.h - * - * A list of byte offsets of newlines in a string. - * - * When compiling the syntax tree, it's necessary to know the line and column - * of many nodes. This is necessary to support things like error messages, - * tracepoints, etc. - * - * It's possible that we could store the start line, start column, end line, and - * end column on every node in addition to the offsets that we already store, - * but that would be quite a lot of memory overhead. - */ -#ifndef PRISM_LINE_OFFSET_LIST_H -#define PRISM_LINE_OFFSET_LIST_H - -#include "prism/defines.h" -#include "prism/util/pm_arena.h" - -#include -#include -#include -#include - -/** - * A list of offsets of the start of lines in a string. The offsets are assumed - * to be sorted/inserted in ascending order. - */ -typedef struct { - /** The number of offsets in the list. */ - size_t size; - - /** The capacity of the list that has been allocated. */ - size_t capacity; - - /** The list of offsets. */ - uint32_t *offsets; -} pm_line_offset_list_t; - -/** - * A line and column in a string. - */ -typedef struct { - /** The line number. */ - int32_t line; - - /** The column in bytes. */ - uint32_t column; -} pm_line_column_t; - -/** - * Initialize a new line offset list with the given capacity. - * - * @param arena The arena to allocate from. - * @param list The list to initialize. - * @param capacity The initial capacity of the list. - */ -void pm_line_offset_list_init(pm_arena_t *arena, pm_line_offset_list_t *list, size_t capacity); - -/** - * Clear out the offsets that have been appended to the list. - * - * @param list The list to clear. - */ -void pm_line_offset_list_clear(pm_line_offset_list_t *list); - -/** - * Append a new offset to the list (slow path with resize). - * - * @param arena The arena to allocate from. - * @param list The list to append to. - * @param cursor The offset to append. - */ -void pm_line_offset_list_append_slow(pm_arena_t *arena, pm_line_offset_list_t *list, uint32_t cursor); - -/** - * Append a new offset to the list. - * - * @param arena The arena to allocate from. - * @param list The list to append to. - * @param cursor The offset to append. - */ -static PRISM_FORCE_INLINE void -pm_line_offset_list_append(pm_arena_t *arena, pm_line_offset_list_t *list, uint32_t cursor) { - if (list->size < list->capacity) { - list->offsets[list->size++] = cursor; - } else { - pm_line_offset_list_append_slow(arena, list, cursor); - } -} - -/** - * Returns the line of the given offset. If the offset is not in the list, the - * line of the closest offset less than the given offset is returned. - * - * @param list The list to search. - * @param cursor The offset to search for. - * @param start_line The line to start counting from. - * @return The line of the given offset. - */ -int32_t pm_line_offset_list_line(const pm_line_offset_list_t *list, uint32_t cursor, int32_t start_line); - -/** - * Returns the line and column of the given offset. If the offset is not in the - * list, the line and column of the closest offset less than the given offset - * are returned. - * - * @param list The list to search. - * @param cursor The offset to search for. - * @param start_line The line to start counting from. - * @return The line and column of the given offset. - */ -PRISM_EXPORTED_FUNCTION pm_line_column_t pm_line_offset_list_line_column(const pm_line_offset_list_t *list, uint32_t cursor, int32_t start_line); - -#endif diff --git a/prism/util/pm_list.c b/prism/util/pm_list.c deleted file mode 100644 index 940baffb64da35..00000000000000 --- a/prism/util/pm_list.c +++ /dev/null @@ -1,49 +0,0 @@ -#include "prism/util/pm_list.h" - -/** - * Returns true if the given list is empty. - */ -PRISM_EXPORTED_FUNCTION bool -pm_list_empty_p(pm_list_t *list) { - return list->head == NULL; -} - -/** - * Returns the size of the list. - */ -PRISM_EXPORTED_FUNCTION size_t -pm_list_size(pm_list_t *list) { - return list->size; -} - -/** - * Append a node to the given list. - */ -void -pm_list_append(pm_list_t *list, pm_list_node_t *node) { - if (list->head == NULL) { - list->head = node; - } else { - list->tail->next = node; - } - - list->tail = node; - list->size++; -} - -/** - * Deallocate the internal state of the given list. - */ -PRISM_EXPORTED_FUNCTION void -pm_list_free(pm_list_t *list) { - pm_list_node_t *node = list->head; - pm_list_node_t *next; - - while (node != NULL) { - next = node->next; - xfree_sized(node, sizeof(pm_list_node_t)); - node = next; - } - - list->size = 0; -} diff --git a/prism/util/pm_memchr.h b/prism/util/pm_memchr.h deleted file mode 100644 index e0671eaed3b9a6..00000000000000 --- a/prism/util/pm_memchr.h +++ /dev/null @@ -1,29 +0,0 @@ -/** - * @file pm_memchr.h - * - * A custom memchr implementation. - */ -#ifndef PRISM_MEMCHR_H -#define PRISM_MEMCHR_H - -#include "prism/defines.h" -#include "prism/encoding.h" - -#include - -/** - * We need to roll our own memchr to handle cases where the encoding changes and - * we need to search for a character in a buffer that could be the trailing byte - * of a multibyte character. - * - * @param source The source string. - * @param character The character to search for. - * @param number The maximum number of bytes to search. - * @param encoding_changed Whether the encoding changed. - * @param encoding A pointer to the encoding. - * @return A pointer to the first occurrence of the character in the source - * string, or NULL if no such character exists. - */ -void * pm_memchr(const void *source, int character, size_t number, bool encoding_changed, const pm_encoding_t *encoding); - -#endif diff --git a/prism/util/pm_string.c b/prism/util/pm_string.c deleted file mode 100644 index 5ba8c78ec17d9c..00000000000000 --- a/prism/util/pm_string.c +++ /dev/null @@ -1,382 +0,0 @@ -#include "prism/util/pm_string.h" - -static const uint8_t empty_source[] = ""; - -/** - * Returns the size of the pm_string_t struct. This is necessary to allocate the - * correct amount of memory in the FFI backend. - */ -PRISM_EXPORTED_FUNCTION size_t -pm_string_sizeof(void) { - return sizeof(pm_string_t); -} - -/** - * Initialize a shared string that is based on initial input. - */ -void -pm_string_shared_init(pm_string_t *string, const uint8_t *start, const uint8_t *end) { - assert(start <= end); - - *string = (pm_string_t) { - .type = PM_STRING_SHARED, - .source = start, - .length = (size_t) (end - start) - }; -} - -/** - * Initialize an owned string that is responsible for freeing allocated memory. - */ -void -pm_string_owned_init(pm_string_t *string, uint8_t *source, size_t length) { - *string = (pm_string_t) { - .type = PM_STRING_OWNED, - .source = source, - .length = length - }; -} - -/** - * Initialize a constant string that doesn't own its memory source. - */ -void -pm_string_constant_init(pm_string_t *string, const char *source, size_t length) { - *string = (pm_string_t) { - .type = PM_STRING_CONSTANT, - .source = (const uint8_t *) source, - .length = length - }; -} - -#ifdef _WIN32 -/** - * Represents a file handle on Windows, where the path will need to be freed - * when the file is closed. - */ -typedef struct { - /** The path to the file, which will become allocated memory. */ - WCHAR *path; - - /** The handle to the file, which will start as uninitialized memory. */ - HANDLE file; -} pm_string_file_handle_t; - -/** - * Open the file indicated by the filepath parameter for reading on Windows. - * Perform any kind of normalization that needs to happen on the filepath. - */ -static pm_string_init_result_t -pm_string_file_handle_open(pm_string_file_handle_t *handle, const char *filepath) { - int length = MultiByteToWideChar(CP_UTF8, 0, filepath, -1, NULL, 0); - if (length == 0) return PM_STRING_INIT_ERROR_GENERIC; - - const size_t path_size = sizeof(WCHAR) * ((size_t) length); - handle->path = xmalloc(path_size); - if ((handle->path == NULL) || (MultiByteToWideChar(CP_UTF8, 0, filepath, -1, handle->path, length) == 0)) { - xfree_sized(handle->path, path_size); - return PM_STRING_INIT_ERROR_GENERIC; - } - - handle->file = CreateFileW(handle->path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL); - if (handle->file == INVALID_HANDLE_VALUE) { - pm_string_init_result_t result = PM_STRING_INIT_ERROR_GENERIC; - - if (GetLastError() == ERROR_ACCESS_DENIED) { - DWORD attributes = GetFileAttributesW(handle->path); - if ((attributes != INVALID_FILE_ATTRIBUTES) && (attributes & FILE_ATTRIBUTE_DIRECTORY)) { - result = PM_STRING_INIT_ERROR_DIRECTORY; - } - } - - xfree_sized(handle->path, path_size); - return result; - } - - return PM_STRING_INIT_SUCCESS; -} - -/** - * Close the file handle and free the path. - */ -static void -pm_string_file_handle_close(pm_string_file_handle_t *handle) { - xfree(handle->path); - CloseHandle(handle->file); -} -#endif - -/** - * Read the file indicated by the filepath parameter into source and load its - * contents and size into the given `pm_string_t`. The given `pm_string_t` - * should be freed using `pm_string_free` when it is no longer used. - * - * We want to use demand paging as much as possible in order to avoid having to - * read the entire file into memory (which could be detrimental to performance - * for large files). This means that if we're on windows we'll use - * `MapViewOfFile`, on POSIX systems that have access to `mmap` we'll use - * `mmap`, and on other POSIX systems we'll use `read`. - */ -PRISM_EXPORTED_FUNCTION pm_string_init_result_t -pm_string_mapped_init(pm_string_t *string, const char *filepath) { -#ifdef _WIN32 - // Open the file for reading. - pm_string_file_handle_t handle; - pm_string_init_result_t result = pm_string_file_handle_open(&handle, filepath); - if (result != PM_STRING_INIT_SUCCESS) return result; - - // Get the file size. - DWORD file_size = GetFileSize(handle.file, NULL); - if (file_size == INVALID_FILE_SIZE) { - pm_string_file_handle_close(&handle); - return PM_STRING_INIT_ERROR_GENERIC; - } - - // If the file is empty, then we don't need to do anything else, we'll set - // the source to a constant empty string and return. - if (file_size == 0) { - pm_string_file_handle_close(&handle); - *string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = empty_source, .length = 0 }; - return PM_STRING_INIT_SUCCESS; - } - - // Create a mapping of the file. - HANDLE mapping = CreateFileMapping(handle.file, NULL, PAGE_READONLY, 0, 0, NULL); - if (mapping == NULL) { - pm_string_file_handle_close(&handle); - return PM_STRING_INIT_ERROR_GENERIC; - } - - // Map the file into memory. - uint8_t *source = (uint8_t *) MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0); - CloseHandle(mapping); - pm_string_file_handle_close(&handle); - - if (source == NULL) { - return PM_STRING_INIT_ERROR_GENERIC; - } - - *string = (pm_string_t) { .type = PM_STRING_MAPPED, .source = source, .length = (size_t) file_size }; - return PM_STRING_INIT_SUCCESS; -#elif defined(_POSIX_MAPPED_FILES) - // Open the file for reading - int fd = open(filepath, O_RDONLY); - if (fd == -1) { - return PM_STRING_INIT_ERROR_GENERIC; - } - - // Stat the file to get the file size - struct stat sb; - if (fstat(fd, &sb) == -1) { - close(fd); - return PM_STRING_INIT_ERROR_GENERIC; - } - - // Ensure it is a file and not a directory - if (S_ISDIR(sb.st_mode)) { - close(fd); - return PM_STRING_INIT_ERROR_DIRECTORY; - } - - // mmap the file descriptor to virtually get the contents - size_t size = (size_t) sb.st_size; - uint8_t *source = NULL; - - if (size == 0) { - close(fd); - *string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = empty_source, .length = 0 }; - return PM_STRING_INIT_SUCCESS; - } - - source = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); - if (source == MAP_FAILED) { - close(fd); - return PM_STRING_INIT_ERROR_GENERIC; - } - - close(fd); - *string = (pm_string_t) { .type = PM_STRING_MAPPED, .source = source, .length = size }; - return PM_STRING_INIT_SUCCESS; -#else - return pm_string_file_init(string, filepath); -#endif -} - -/** - * Read the file indicated by the filepath parameter into source and load its - * contents and size into the given `pm_string_t`. The given `pm_string_t` - * should be freed using `pm_string_free` when it is no longer used. - */ -PRISM_EXPORTED_FUNCTION pm_string_init_result_t -pm_string_file_init(pm_string_t *string, const char *filepath) { -#ifdef _WIN32 - // Open the file for reading. - pm_string_file_handle_t handle; - pm_string_init_result_t result = pm_string_file_handle_open(&handle, filepath); - if (result != PM_STRING_INIT_SUCCESS) return result; - - // Get the file size. - const DWORD file_size = GetFileSize(handle.file, NULL); - if (file_size == INVALID_FILE_SIZE) { - pm_string_file_handle_close(&handle); - return PM_STRING_INIT_ERROR_GENERIC; - } - - // If the file is empty, then we don't need to do anything else, we'll set - // the source to a constant empty string and return. - if (file_size == 0) { - pm_string_file_handle_close(&handle); - *string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = empty_source, .length = 0 }; - return PM_STRING_INIT_SUCCESS; - } - - // Create a buffer to read the file into. - uint8_t *source = xmalloc(file_size); - if (source == NULL) { - pm_string_file_handle_close(&handle); - return PM_STRING_INIT_ERROR_GENERIC; - } - - // Read the contents of the file - DWORD bytes_read; - if (!ReadFile(handle.file, source, file_size, &bytes_read, NULL)) { - pm_string_file_handle_close(&handle); - return PM_STRING_INIT_ERROR_GENERIC; - } - - // Check the number of bytes read - if (bytes_read != file_size) { - xfree_sized(source, file_size); - pm_string_file_handle_close(&handle); - return PM_STRING_INIT_ERROR_GENERIC; - } - - pm_string_file_handle_close(&handle); - *string = (pm_string_t) { .type = PM_STRING_OWNED, .source = source, .length = (size_t) file_size }; - return PM_STRING_INIT_SUCCESS; -#elif defined(PRISM_HAS_FILESYSTEM) - // Open the file for reading - int fd = open(filepath, O_RDONLY); - if (fd == -1) { - return PM_STRING_INIT_ERROR_GENERIC; - } - - // Stat the file to get the file size - struct stat sb; - if (fstat(fd, &sb) == -1) { - close(fd); - return PM_STRING_INIT_ERROR_GENERIC; - } - - // Ensure it is a file and not a directory - if (S_ISDIR(sb.st_mode)) { - close(fd); - return PM_STRING_INIT_ERROR_DIRECTORY; - } - - // Check the size to see if it's empty - size_t size = (size_t) sb.st_size; - if (size == 0) { - close(fd); - *string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = empty_source, .length = 0 }; - return PM_STRING_INIT_SUCCESS; - } - - const size_t length = (size_t) size; - uint8_t *source = xmalloc(length); - if (source == NULL) { - close(fd); - return PM_STRING_INIT_ERROR_GENERIC; - } - - long bytes_read = (long) read(fd, source, length); - close(fd); - - if (bytes_read == -1) { - xfree_sized(source, length); - return PM_STRING_INIT_ERROR_GENERIC; - } - - *string = (pm_string_t) { .type = PM_STRING_OWNED, .source = source, .length = length }; - return PM_STRING_INIT_SUCCESS; -#else - (void) string; - (void) filepath; - perror("pm_string_file_init is not implemented for this platform"); - return PM_STRING_INIT_ERROR_GENERIC; -#endif -} - -/** - * Ensure the string is owned. If it is not, then reinitialize it as owned and - * copy over the previous source. - */ -void -pm_string_ensure_owned(pm_string_t *string) { - if (string->type == PM_STRING_OWNED) return; - - size_t length = pm_string_length(string); - const uint8_t *source = pm_string_source(string); - - uint8_t *memory = xmalloc(length); - if (!memory) return; - - pm_string_owned_init(string, memory, length); - memcpy((void *) string->source, source, length); -} - -/** - * Compare the underlying lengths and bytes of two strings. Returns 0 if the - * strings are equal, a negative number if the left string is less than the - * right string, and a positive number if the left string is greater than the - * right string. - */ -int -pm_string_compare(const pm_string_t *left, const pm_string_t *right) { - size_t left_length = pm_string_length(left); - size_t right_length = pm_string_length(right); - - if (left_length < right_length) { - return -1; - } else if (left_length > right_length) { - return 1; - } - - return memcmp(pm_string_source(left), pm_string_source(right), left_length); -} - -/** - * Returns the length associated with the string. - */ -PRISM_EXPORTED_FUNCTION size_t -pm_string_length(const pm_string_t *string) { - return string->length; -} - -/** - * Returns the start pointer associated with the string. - */ -PRISM_EXPORTED_FUNCTION const uint8_t * -pm_string_source(const pm_string_t *string) { - return string->source; -} - -/** - * Free the associated memory of the given string. - */ -PRISM_EXPORTED_FUNCTION void -pm_string_free(pm_string_t *string) { - void *memory = (void *) string->source; - - if (string->type == PM_STRING_OWNED) { - xfree(memory); -#ifdef PRISM_HAS_MMAP - } else if (string->type == PM_STRING_MAPPED && string->length) { -#if defined(_WIN32) - UnmapViewOfFile(memory); -#elif defined(_POSIX_MAPPED_FILES) - munmap(memory, string->length); -#endif -#endif /* PRISM_HAS_MMAP */ - } -} diff --git a/prism/util/pm_string.h b/prism/util/pm_string.h deleted file mode 100644 index 76942180b6eecb..00000000000000 --- a/prism/util/pm_string.h +++ /dev/null @@ -1,200 +0,0 @@ -/** - * @file pm_string.h - * - * A generic string type that can have various ownership semantics. - */ -#ifndef PRISM_STRING_H -#define PRISM_STRING_H - -#include "prism/defines.h" - -#include -#include -#include -#include -#include -#include - -// The following headers are necessary to read files using demand paging. -#ifdef _WIN32 -#include -#elif defined(_POSIX_MAPPED_FILES) -#include -#include -#include -#elif defined(PRISM_HAS_FILESYSTEM) -#include -#include -#endif - -/** - * A generic string type that can have various ownership semantics. - */ -typedef struct { - /** A pointer to the start of the string. */ - const uint8_t *source; - - /** The length of the string in bytes of memory. */ - size_t length; - - /** The type of the string. This field determines how the string should be freed. */ - enum { - /** This string is a constant string, and should not be freed. */ - PM_STRING_CONSTANT, - - /** This is a slice of another string, and should not be freed. */ - PM_STRING_SHARED, - - /** This string owns its memory, and should be freed using `pm_string_free()`. */ - PM_STRING_OWNED, - -#ifdef PRISM_HAS_MMAP - /** This string is a memory-mapped file, and should be freed using `pm_string_free()`. */ - PM_STRING_MAPPED -#endif - } type; -} pm_string_t; - -/** - * Returns the size of the pm_string_t struct. This is necessary to allocate the - * correct amount of memory in the FFI backend. - * - * @return The size of the pm_string_t struct. - */ -PRISM_EXPORTED_FUNCTION size_t pm_string_sizeof(void); - -/** - * Defines an empty string. This is useful for initializing a string that will - * be filled in later. - */ -#define PM_STRING_EMPTY ((pm_string_t) { .type = PM_STRING_CONSTANT, .source = NULL, .length = 0 }) - -/** - * Initialize a shared string that is based on initial input. - * - * @param string The string to initialize. - * @param start The start of the string. - * @param end The end of the string. - */ -void pm_string_shared_init(pm_string_t *string, const uint8_t *start, const uint8_t *end); - -/** - * Initialize an owned string that is responsible for freeing allocated memory. - * - * @param string The string to initialize. - * @param source The source of the string. - * @param length The length of the string. - */ -void pm_string_owned_init(pm_string_t *string, uint8_t *source, size_t length); - -/** - * Initialize a constant string that doesn't own its memory source. - * - * @param string The string to initialize. - * @param source The source of the string. - * @param length The length of the string. - */ -PRISM_EXPORTED_FUNCTION void pm_string_constant_init(pm_string_t *string, const char *source, size_t length); - -/** - * Represents the result of calling pm_string_mapped_init or - * pm_string_file_init. We need this additional information because there is - * not a platform-agnostic way to indicate that the file that was attempted to - * be opened was a directory. - */ -typedef enum { - /** Indicates that the string was successfully initialized. */ - PM_STRING_INIT_SUCCESS = 0, - /** - * Indicates a generic error from a string_*_init function, where the type - * of error should be read from `errno` or `GetLastError()`. - */ - PM_STRING_INIT_ERROR_GENERIC = 1, - /** - * Indicates that the file that was attempted to be opened was a directory. - */ - PM_STRING_INIT_ERROR_DIRECTORY = 2 -} pm_string_init_result_t; - -/** - * Read the file indicated by the filepath parameter into source and load its - * contents and size into the given `pm_string_t`. The given `pm_string_t` - * should be freed using `pm_string_free` when it is no longer used. - * - * We want to use demand paging as much as possible in order to avoid having to - * read the entire file into memory (which could be detrimental to performance - * for large files). This means that if we're on windows we'll use - * `MapViewOfFile`, on POSIX systems that have access to `mmap` we'll use - * `mmap`, and on other POSIX systems we'll use `read`. - * - * @param string The string to initialize. - * @param filepath The filepath to read. - * @return The success of the read, indicated by the value of the enum. - * - * \public \memberof pm_string_t - */ -PRISM_EXPORTED_FUNCTION pm_string_init_result_t pm_string_mapped_init(pm_string_t *string, const char *filepath); - -/** - * Read the file indicated by the filepath parameter into source and load its - * contents and size into the given `pm_string_t`. The given `pm_string_t` - * should be freed using `pm_string_free` when it is no longer used. - * - * @param string The string to initialize. - * @param filepath The filepath to read. - * @return The success of the read, indicated by the value of the enum. - * - * \public \memberof pm_string_t - */ -PRISM_EXPORTED_FUNCTION pm_string_init_result_t pm_string_file_init(pm_string_t *string, const char *filepath); - -/** - * Ensure the string is owned. If it is not, then reinitialize it as owned and - * copy over the previous source. - * - * @param string The string to ensure is owned. - */ -void pm_string_ensure_owned(pm_string_t *string); - -/** - * Compare the underlying lengths and bytes of two strings. Returns 0 if the - * strings are equal, a negative number if the left string is less than the - * right string, and a positive number if the left string is greater than the - * right string. - * - * @param left The left string to compare. - * @param right The right string to compare. - * @return The comparison result. - */ -int pm_string_compare(const pm_string_t *left, const pm_string_t *right); - -/** - * Returns the length associated with the string. - * - * @param string The string to get the length of. - * @return The length of the string. - * - * \public \memberof pm_string_t - */ -PRISM_EXPORTED_FUNCTION size_t pm_string_length(const pm_string_t *string); - -/** - * Returns the start pointer associated with the string. - * - * @param string The string to get the start pointer of. - * @return The start pointer of the string. - * - * \public \memberof pm_string_t - */ -PRISM_EXPORTED_FUNCTION const uint8_t * pm_string_source(const pm_string_t *string); - -/** - * Free the associated memory of the given string. - * - * @param string The string to free. - * - * \public \memberof pm_string_t - */ -PRISM_EXPORTED_FUNCTION void pm_string_free(pm_string_t *string); - -#endif diff --git a/prism/version.h b/prism/version.h index b95611f96c78e8..181b3984622062 100644 --- a/prism/version.h +++ b/prism/version.h @@ -6,6 +6,8 @@ #ifndef PRISM_VERSION_H #define PRISM_VERSION_H +#include "prism/compiler/exported.h" + /** * The major version of the Prism library as an int. */ @@ -26,4 +28,11 @@ */ #define PRISM_VERSION "1.9.0" +/** + * The prism version and the serialization format. + * + * @returns The prism version as a constant string. + */ +PRISM_EXPORTED_FUNCTION const char * pm_version(void); + #endif diff --git a/prism_compile.c b/prism_compile.c index 3fa24029412308..66f7d6f2fa32f7 100644 --- a/prism_compile.c +++ b/prism_compile.c @@ -1,6 +1,8 @@ #include "prism.h" #include "ruby/version.h" +#include + /** * This compiler defines its own concept of the location of a node. We do this * because we want to pair line information with node identifier so that we can @@ -212,27 +214,27 @@ pm_line_offset_list_line_cached(const pm_line_offset_list_t *list, uint32_t curs return pm_line_offset_list_line_column_cached(list, cursor, start_line, last_line).line; } -#define PM_NODE_START_LOCATION(parser, node) \ - ((pm_node_location_t) { .line = pm_line_offset_list_line_cached(&(parser)->line_offsets, ((const pm_node_t *) (node))->location.start, (parser)->start_line, &scope_node->last_line), .node_id = ((const pm_node_t *) (node))->node_id }) +#define PM_NODE_START_LOCATION(node) \ + ((pm_node_location_t) { .line = pm_line_offset_list_line_cached(scope_node->line_offsets, ((const pm_node_t *) (node))->location.start, scope_node->start_line, &scope_node->last_line), .node_id = ((const pm_node_t *) (node))->node_id }) -#define PM_NODE_END_LOCATION(parser, node) \ - ((pm_node_location_t) { .line = pm_line_offset_list_line_cached(&(parser)->line_offsets, ((const pm_node_t *) (node))->location.start + ((const pm_node_t *) (node))->location.length, (parser)->start_line, &scope_node->last_line), .node_id = ((const pm_node_t *) (node))->node_id }) +#define PM_NODE_END_LOCATION(node) \ + ((pm_node_location_t) { .line = pm_line_offset_list_line_cached(scope_node->line_offsets, ((const pm_node_t *) (node))->location.start + ((const pm_node_t *) (node))->location.length, scope_node->start_line, &scope_node->last_line), .node_id = ((const pm_node_t *) (node))->node_id }) -#define PM_LOCATION_START_LOCATION(parser, location, id) \ - ((pm_node_location_t) { .line = pm_line_offset_list_line_cached(&(parser)->line_offsets, (location)->start, (parser)->start_line, &scope_node->last_line), .node_id = id }) +#define PM_LOCATION_START_LOCATION(location, id) \ + ((pm_node_location_t) { .line = pm_line_offset_list_line_cached(scope_node->line_offsets, (location)->start, scope_node->start_line, &scope_node->last_line), .node_id = id }) -#define PM_NODE_START_LINE_COLUMN(parser, node) \ - pm_line_offset_list_line_column_cached(&(parser)->line_offsets, ((const pm_node_t *) (node))->location.start, (parser)->start_line, &scope_node->last_line) +#define PM_NODE_START_LINE_COLUMN(node) \ + pm_line_offset_list_line_column_cached(scope_node->line_offsets, ((const pm_node_t *) (node))->location.start, scope_node->start_line, &scope_node->last_line) -#define PM_NODE_END_LINE_COLUMN(parser, node) \ - pm_line_offset_list_line_column_cached(&(parser)->line_offsets, ((const pm_node_t *) (node))->location.start + ((const pm_node_t *) (node))->location.length, (parser)->start_line, &scope_node->last_line) +#define PM_NODE_END_LINE_COLUMN(node) \ + pm_line_offset_list_line_column_cached(scope_node->line_offsets, ((const pm_node_t *) (node))->location.start + ((const pm_node_t *) (node))->location.length, scope_node->start_line, &scope_node->last_line) -#define PM_LOCATION_START_LINE_COLUMN(parser, location) \ - pm_line_offset_list_line_column_cached(&(parser)->line_offsets, (location)->start, (parser)->start_line, &scope_node->last_line) +#define PM_LOCATION_START_LINE_COLUMN(location) \ + pm_line_offset_list_line_column_cached(scope_node->line_offsets, (location)->start, scope_node->start_line, &scope_node->last_line) static int pm_location_line_number(const pm_parser_t *parser, const pm_location_t *location) { - return (int) pm_line_offset_list_line(&parser->line_offsets, location->start, parser->start_line); + return (int) pm_line_offset_list_line_column(pm_parser_line_offsets(parser), location->start, pm_parser_start_line(parser)).line; } /** @@ -240,14 +242,14 @@ pm_location_line_number(const pm_parser_t *parser, const pm_location_t *location * compilation (where access patterns are roughly sequential). */ static inline int -pm_node_line_number_cached(const pm_parser_t *parser, const pm_node_t *node, pm_scope_node_t *scope_node) +pm_node_line_number_cached(const pm_node_t *node, pm_scope_node_t *scope_node) { - return (int) pm_line_offset_list_line_cached(&parser->line_offsets, node->location.start, parser->start_line, &scope_node->last_line); + return (int) pm_line_offset_list_line_cached(scope_node->line_offsets, node->location.start, scope_node->start_line, &scope_node->last_line); } static inline int -pm_location_line_number_cached(const pm_parser_t *parser, const pm_location_t *location, pm_scope_node_t *scope_node) { - return (int) pm_line_offset_list_line_cached(&parser->line_offsets, location->start, parser->start_line, &scope_node->last_line); +pm_location_line_number_cached(const pm_location_t *location, pm_scope_node_t *scope_node) { + return (int) pm_line_offset_list_line_cached(scope_node->line_offsets, location->start, scope_node->start_line, &scope_node->last_line); } /** @@ -347,7 +349,7 @@ parse_imaginary(const pm_imaginary_node_t *node) break; } default: - rb_bug("Unexpected numeric type on imaginary number %s\n", pm_node_type_to_str(PM_NODE_TYPE(node->numeric))); + rb_bug("Unexpected numeric type on imaginary number %s\n", pm_node_type(PM_NODE_TYPE(node->numeric))); } return RB_OBJ_SET_SHAREABLE(rb_complex_raw(INT2FIX(0), imaginary_part)); @@ -401,7 +403,7 @@ parse_static_literal_string(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const rb_enc_str_coderange(value); if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) { - int line_number = pm_node_line_number_cached(scope_node->parser, node, scope_node); + int line_number = pm_node_line_number_cached(node, scope_node); value = rb_ractor_make_shareable(rb_str_with_debug_created_info(value, rb_iseq_path(iseq), line_number)); } @@ -468,7 +470,7 @@ parse_regexp_string_part(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_ VALUE string = rb_enc_str_new((const char *) pm_string_source(unescaped), pm_string_length(unescaped), encoding); VALUE error = rb_reg_check_preprocess(string); - if (error != Qnil) parse_regexp_error(iseq, pm_node_line_number_cached(scope_node->parser, node, scope_node), "%" PRIsVALUE, rb_obj_as_string(error)); + if (error != Qnil) parse_regexp_error(iseq, pm_node_line_number_cached(node, scope_node), "%" PRIsVALUE, rb_obj_as_string(error)); return string; } @@ -490,7 +492,7 @@ pm_static_literal_concat(rb_iseq_t *iseq, const pm_node_list_t *nodes, pm_scope_ else { string = parse_string_encoded(part, &((const pm_string_node_t *) part)->unescaped, scope_node->encoding); VALUE error = rb_reg_check_preprocess(string); - if (error != Qnil) parse_regexp_error(iseq, pm_node_line_number_cached(scope_node->parser, part, scope_node), "%" PRIsVALUE, rb_obj_as_string(error)); + if (error != Qnil) parse_regexp_error(iseq, pm_node_line_number_cached(part, scope_node), "%" PRIsVALUE, rb_obj_as_string(error)); } } else { @@ -607,8 +609,8 @@ parse_regexp(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node { VALUE errinfo = rb_errinfo(); - int32_t line_number = pm_node_line_number_cached(scope_node->parser, node, scope_node); - VALUE regexp = rb_reg_compile(string, parse_regexp_flags(node), (const char *) pm_string_source(&scope_node->parser->filepath), line_number); + int32_t line_number = pm_node_line_number_cached(node, scope_node); + VALUE regexp = rb_reg_compile(string, parse_regexp_flags(node), (const char *) pm_string_source(pm_parser_filepath(scope_node->parser)), line_number); if (NIL_P(regexp)) { VALUE message = rb_attr_get(rb_errinfo(), idMesg); @@ -674,7 +676,7 @@ pm_interpolated_node_compile(rb_iseq_t *iseq, const pm_node_list_t *parts, const } else { current_string = string_value; - if (index != 0) current_location = PM_NODE_END_LOCATION(scope_node->parser, part); + if (index != 0) current_location = PM_NODE_END_LOCATION(part); } } else { @@ -701,7 +703,7 @@ pm_interpolated_node_compile(rb_iseq_t *iseq, const pm_node_list_t *parts, const } else { current_string = string_value; - current_location = PM_NODE_START_LOCATION(scope_node->parser, part); + current_location = PM_NODE_START_LOCATION(part); } } else { @@ -712,7 +714,7 @@ pm_interpolated_node_compile(rb_iseq_t *iseq, const pm_node_list_t *parts, const if (explicit_regexp_encoding != NULL) { encoding = explicit_regexp_encoding; } - else if (scope_node->parser->encoding == PM_ENCODING_US_ASCII_ENTRY) { + else if (pm_parser_encoding_us_ascii(scope_node->parser)) { encoding = rb_ascii8bit_encoding(); } else { @@ -736,7 +738,7 @@ pm_interpolated_node_compile(rb_iseq_t *iseq, const pm_node_list_t *parts, const PM_COMPILE_NOT_POPPED(part); - const pm_node_location_t current_location = PM_NODE_START_LOCATION(scope_node->parser, part); + const pm_node_location_t current_location = PM_NODE_START_LOCATION(part); PUSH_INSN(ret, current_location, dup); { @@ -883,7 +885,7 @@ pm_static_literal_value(rb_iseq_t *iseq, const pm_node_t *node, pm_scope_node_t } case PM_INTERPOLATED_STRING_NODE: { VALUE string = pm_static_literal_concat(iseq, &((const pm_interpolated_string_node_t *) node)->parts, scope_node, NULL, NULL, false); - int line_number = pm_node_line_number_cached(scope_node->parser, node, scope_node); + int line_number = pm_node_line_number_cached(node, scope_node); return pm_static_literal_string(iseq, string, line_number); } case PM_INTERPOLATED_SYMBOL_NODE: { @@ -911,7 +913,7 @@ pm_static_literal_value(rb_iseq_t *iseq, const pm_node_t *node, pm_scope_node_t return pm_source_file_value(cast, scope_node); } case PM_SOURCE_LINE_NODE: - return INT2FIX(pm_node_line_number_cached(scope_node->parser, node, scope_node)); + return INT2FIX(pm_node_line_number_cached(node, scope_node)); case PM_STRING_NODE: { const pm_string_node_t *cast = (const pm_string_node_t *) node; return parse_static_literal_string(iseq, scope_node, node, &cast->unescaped); @@ -921,7 +923,7 @@ pm_static_literal_value(rb_iseq_t *iseq, const pm_node_t *node, pm_scope_node_t case PM_TRUE_NODE: return Qtrue; default: - rb_bug("Don't have a literal value for node type %s", pm_node_type_to_str(PM_NODE_TYPE(node))); + rb_bug("Don't have a literal value for node type %s", pm_node_type(PM_NODE_TYPE(node))); return Qfalse; } } @@ -932,8 +934,8 @@ pm_static_literal_value(rb_iseq_t *iseq, const pm_node_t *node, pm_scope_node_t static rb_code_location_t pm_code_location(pm_scope_node_t *scope_node, const pm_node_t *node) { - const pm_line_column_t start_location = PM_NODE_START_LINE_COLUMN(scope_node->parser, node); - const pm_line_column_t end_location = PM_NODE_END_LINE_COLUMN(scope_node->parser, node); + const pm_line_column_t start_location = PM_NODE_START_LINE_COLUMN(node); + const pm_line_column_t end_location = PM_NODE_END_LINE_COLUMN(node); return (rb_code_location_t) { .beg_pos = { .lineno = start_location.line, .column = start_location.column }, @@ -955,7 +957,7 @@ pm_compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const pm_no static void pm_compile_logical(rb_iseq_t *iseq, LINK_ANCHOR *const ret, pm_node_t *cond, LABEL *then_label, LABEL *else_label, bool popped, pm_scope_node_t *scope_node) { - const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, cond); + const pm_node_location_t location = PM_NODE_START_LOCATION(cond); DECL_ANCHOR(seq); @@ -984,7 +986,7 @@ pm_compile_logical(rb_iseq_t *iseq, LINK_ANCHOR *const ret, pm_node_t *cond, LAB static void pm_compile_flip_flop_bound(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) { - const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node); + const pm_node_location_t location = PM_NODE_START_LOCATION(node); if (PM_NODE_TYPE_P(node, PM_INTEGER_NODE)) { PM_COMPILE_NOT_POPPED(node); @@ -1047,7 +1049,7 @@ static void pm_compile_defined_expr(rb_iseq_t *iseq, const pm_node_t *node, cons static void pm_compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const pm_node_t *cond, LABEL *then_label, LABEL *else_label, bool popped, pm_scope_node_t *scope_node) { - const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, cond); + const pm_node_location_t location = PM_NODE_START_LOCATION(cond); again: switch (PM_NODE_TYPE(cond)) { @@ -1160,7 +1162,7 @@ pm_compile_conditional(rb_iseq_t *iseq, const pm_node_location_t *node_location, if (statements != NULL) { branch_location = pm_code_location(scope_node, (const pm_node_t *) statements); } else if (type == PM_IF_NODE) { - pm_line_column_t predicate_end = PM_NODE_END_LINE_COLUMN(scope_node->parser, predicate); + pm_line_column_t predicate_end = PM_NODE_END_LINE_COLUMN(predicate); branch_location = (rb_code_location_t) { .beg_pos = { .lineno = predicate_end.line, .column = predicate_end.column }, .end_pos = { .lineno = predicate_end.line, .column = predicate_end.column } @@ -1343,7 +1345,7 @@ pm_lookup_local_index(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, pm_con static ID pm_constant_id_lookup(const pm_scope_node_t *scope_node, pm_constant_id_t constant_id) { - if (constant_id < 1 || constant_id > scope_node->parser->constant_pool.size) { + if (constant_id < 1 || constant_id > pm_parser_constants_size(scope_node->parser)) { rb_bug("constant_id out of range: %u", (unsigned int)constant_id); } return scope_node->constants[constant_id - 1]; @@ -1459,7 +1461,7 @@ static void pm_compile_shareable_constant_value(rb_iseq_t *iseq, const pm_node_t static void pm_compile_hash_elements(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_list_t *elements, const pm_node_flags_t shareability, VALUE path, bool argument, LINK_ANCHOR *const ret, pm_scope_node_t *scope_node) { - const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node); + const pm_node_location_t location = PM_NODE_START_LOCATION(node); // If this element is not popped, then we need to create the hash on the // stack. Neighboring plain assoc nodes should be grouped together (either @@ -2385,7 +2387,7 @@ static int pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, cons static int pm_compile_pattern_generic_error(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, VALUE message, unsigned int base_index) { - const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node); + const pm_node_location_t location = PM_NODE_START_LOCATION(node); LABEL *match_succeeded_label = NEW_LABEL(location.line); PUSH_INSN(ret, location, dup); @@ -2415,7 +2417,7 @@ pm_compile_pattern_generic_error(rb_iseq_t *iseq, pm_scope_node_t *scope_node, c static int pm_compile_pattern_length_error(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, VALUE message, VALUE length, unsigned int base_index) { - const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node); + const pm_node_location_t location = PM_NODE_START_LOCATION(node); LABEL *match_succeeded_label = NEW_LABEL(location.line); PUSH_INSN(ret, location, dup); @@ -2448,7 +2450,7 @@ pm_compile_pattern_length_error(rb_iseq_t *iseq, pm_scope_node_t *scope_node, co static int pm_compile_pattern_eqq_error(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, unsigned int base_index) { - const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node); + const pm_node_location_t location = PM_NODE_START_LOCATION(node); LABEL *match_succeeded_label = NEW_LABEL(location.line); PUSH_INSN(ret, location, dup); @@ -2484,7 +2486,7 @@ pm_compile_pattern_eqq_error(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const static int pm_compile_pattern_match(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, LABEL *unmatched_label, bool in_single_pattern, bool use_deconstructed_cache, unsigned int base_index) { - LABEL *matched_label = NEW_LABEL(pm_node_line_number_cached(scope_node->parser, node, scope_node)); + LABEL *matched_label = NEW_LABEL(pm_node_line_number_cached(node, scope_node)); CHECK(pm_compile_pattern(iseq, scope_node, node, ret, matched_label, unmatched_label, in_single_pattern, use_deconstructed_cache, base_index)); PUSH_LABEL(ret, matched_label); return COMPILE_OK; @@ -2498,7 +2500,7 @@ pm_compile_pattern_match(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_ static int pm_compile_pattern_deconstruct(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, LABEL *deconstruct_label, LABEL *match_failed_label, LABEL *deconstructed_label, LABEL *type_error_label, bool in_single_pattern, bool use_deconstructed_cache, unsigned int base_index) { - const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node); + const pm_node_location_t location = PM_NODE_START_LOCATION(node); if (use_deconstructed_cache) { PUSH_INSN1(ret, location, topn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_DECONSTRUCTED_CACHE)); @@ -2552,7 +2554,7 @@ pm_compile_pattern_deconstruct(rb_iseq_t *iseq, pm_scope_node_t *scope_node, con static int pm_compile_pattern_constant(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, LABEL *match_failed_label, bool in_single_pattern, unsigned int base_index) { - const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node); + const pm_node_location_t location = PM_NODE_START_LOCATION(node); PUSH_INSN(ret, location, dup); PM_COMPILE_NOT_POPPED(node); @@ -2575,7 +2577,7 @@ pm_compile_pattern_constant(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const static void pm_compile_pattern_error_handler(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, LABEL *done_label, bool popped) { - const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node); + const pm_node_location_t location = PM_NODE_START_LOCATION(node); LABEL *key_error_label = NEW_LABEL(location.line); LABEL *cleanup_label = NEW_LABEL(location.line); @@ -2634,7 +2636,7 @@ pm_compile_pattern_error_handler(rb_iseq_t *iseq, pm_scope_node_t *scope_node, c static int pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, LABEL *matched_label, LABEL *unmatched_label, bool in_single_pattern, bool use_deconstructed_cache, unsigned int base_index) { - const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node); + const pm_node_location_t location = PM_NODE_START_LOCATION(node); switch (PM_NODE_TYPE(node)) { case PM_ARRAY_PATTERN_NODE: { @@ -3288,7 +3290,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t // If we get here, then we have a node type that should not be in this // position. This would be a bug in the parser, because a different node // type should never have been created in this position in the tree. - rb_bug("Unexpected node type in pattern matching expression: %s", pm_node_type_to_str(PM_NODE_TYPE(node))); + rb_bug("Unexpected node type in pattern matching expression: %s", pm_node_type(PM_NODE_TYPE(node))); break; } @@ -3318,6 +3320,9 @@ pm_scope_node_init(const pm_node_t *node, pm_scope_node_t *scope, pm_scope_node_ if (previous) { scope->parser = previous->parser; + scope->options = previous->options; + scope->line_offsets = previous->line_offsets; + scope->start_line = previous->start_line; scope->encoding = previous->encoding; scope->filepath_encoding = previous->filepath_encoding; scope->constants = previous->constants; @@ -3502,7 +3507,7 @@ pm_compile_builtin_attr(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_a const pm_node_t *argument; PM_NODE_LIST_FOREACH(&arguments->arguments, index, argument) { if (!PM_NODE_TYPE_P(argument, PM_SYMBOL_NODE)) { - COMPILE_ERROR(iseq, node_location->line, "non symbol argument to attr!: %s", pm_node_type_to_str(PM_NODE_TYPE(argument))); + COMPILE_ERROR(iseq, node_location->line, "non symbol argument to attr!: %s", pm_node_type(PM_NODE_TYPE(argument))); return COMPILE_NG; } @@ -3549,7 +3554,7 @@ pm_compile_builtin_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const pm_scope_n const pm_node_t *argument = arguments->arguments.nodes[0]; if (!PM_NODE_TYPE_P(argument, PM_SYMBOL_NODE)) { - COMPILE_ERROR(iseq, node_location->line, "non symbol argument to arg!: %s", pm_node_type_to_str(PM_NODE_TYPE(argument))); + COMPILE_ERROR(iseq, node_location->line, "non symbol argument to arg!: %s", pm_node_type(PM_NODE_TYPE(argument))); return COMPILE_NG; } @@ -3738,7 +3743,7 @@ pm_compile_call(rb_iseq_t *iseq, const pm_call_node_t *call_node, LINK_ANCHOR *c const pm_location_t *message_loc = &call_node->message_loc; if (message_loc->length == 0) message_loc = &call_node->base.location; - const pm_node_location_t location = PM_LOCATION_START_LOCATION(scope_node->parser, message_loc, call_node->base.node_id); + const pm_node_location_t location = PM_LOCATION_START_LOCATION(message_loc, call_node->base.node_id); LABEL *else_label = NEW_LABEL(location.line); LABEL *end_label = NEW_LABEL(location.line); @@ -3779,8 +3784,8 @@ pm_compile_call(rb_iseq_t *iseq, const pm_call_node_t *call_node, LINK_ANCHOR *c end_cursor = call_node->closing_loc.start + call_node->closing_loc.length; } - const pm_line_column_t start_location = PM_NODE_START_LINE_COLUMN(scope_node->parser, call_node); - const pm_line_column_t end_location = pm_line_offset_list_line_column_cached(&scope_node->parser->line_offsets, end_cursor, scope_node->parser->start_line, &scope_node->last_line); + const pm_line_column_t start_location = PM_NODE_START_LINE_COLUMN(call_node); + const pm_line_column_t end_location = pm_line_offset_list_line_column_cached(scope_node->line_offsets, end_cursor, scope_node->start_line, &scope_node->last_line); code_location = (rb_code_location_t) { .beg_pos = { .lineno = start_location.line, .column = start_location.column }, @@ -3810,7 +3815,7 @@ pm_compile_call(rb_iseq_t *iseq, const pm_call_node_t *call_node, LINK_ANCHOR *c pm_scope_node_t next_scope_node; pm_scope_node_init(call_node->block, &next_scope_node, scope_node); - block_iseq = NEW_CHILD_ISEQ(&next_scope_node, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, pm_node_line_number_cached(scope_node->parser, call_node->block, scope_node)); + block_iseq = NEW_CHILD_ISEQ(&next_scope_node, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, pm_node_line_number_cached(call_node->block, scope_node)); pm_scope_node_destroy(&next_scope_node); ISEQ_COMPILE_DATA(iseq)->current_block = block_iseq; } @@ -3926,7 +3931,7 @@ pm_compile_call(rb_iseq_t *iseq, const pm_call_node_t *call_node, LINK_ANCHOR *c static inline VALUE pm_compile_back_reference_ref(const pm_scope_node_t *scope_node, const pm_back_reference_read_node_t *node) { - const char *type = (const char *) (scope_node->parser->start + node->base.location.start + 1); + const char *type = (const char *) (pm_parser_start(scope_node->parser) + node->base.location.start + 1); // Since a back reference is `$`, Ruby represents the ID as an // rb_intern on the value after the `$`. @@ -4645,7 +4650,7 @@ pm_compile_defined_expr0(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_l case PM_PROGRAM_NODE: case PM_SCOPE_NODE: case PM_STATEMENTS_NODE: - rb_bug("Unreachable node in defined?: %s", pm_node_type_to_str(PM_NODE_TYPE(node))); + rb_bug("Unreachable node in defined?: %s", pm_node_type(PM_NODE_TYPE(node))); } RUBY_ASSERT(dtype != DEFINED_NOT_DEFINED); @@ -4866,7 +4871,7 @@ pm_compile_destructured_param_locals(const pm_multi_target_node_t *node, st_tabl static inline void pm_compile_destructured_param_write(rb_iseq_t *iseq, const pm_required_parameter_node_t *node, LINK_ANCHOR *const ret, pm_scope_node_t *scope_node) { - const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node); + const pm_node_location_t location = PM_NODE_START_LOCATION(node); pm_local_index_t index = pm_lookup_local_index(iseq, scope_node, node->name, 0); PUSH_SETLOCAL(ret, location, index.index, index.level); } @@ -4882,7 +4887,7 @@ pm_compile_destructured_param_write(rb_iseq_t *iseq, const pm_required_parameter static void pm_compile_destructured_param_writes(rb_iseq_t *iseq, const pm_multi_target_node_t *node, LINK_ANCHOR *const ret, pm_scope_node_t *scope_node) { - const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node); + const pm_node_location_t location = PM_NODE_START_LOCATION(node); bool has_rest = (node->rest && PM_NODE_TYPE_P(node->rest, PM_SPLAT_NODE) && (((const pm_splat_node_t *) node->rest)->expression) != NULL); bool has_rights = node->rights.size > 0; @@ -5079,7 +5084,7 @@ pm_compile_multi_target_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR static void pm_compile_target_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const parents, LINK_ANCHOR *const writes, LINK_ANCHOR *const cleanup, pm_scope_node_t *scope_node, pm_multi_target_state_t *state) { - const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node); + const pm_node_location_t location = PM_NODE_START_LOCATION(node); switch (PM_NODE_TYPE(node)) { case PM_LOCAL_VARIABLE_TARGET_NODE: { @@ -5316,7 +5321,7 @@ pm_compile_target_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *cons break; } default: - rb_bug("Unexpected node type: %s", pm_node_type_to_str(PM_NODE_TYPE(node))); + rb_bug("Unexpected node type: %s", pm_node_type(PM_NODE_TYPE(node))); break; } } @@ -5329,7 +5334,7 @@ pm_compile_target_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *cons static void pm_compile_multi_target_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const parents, LINK_ANCHOR *const writes, LINK_ANCHOR *const cleanup, pm_scope_node_t *scope_node, pm_multi_target_state_t *state) { - const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node); + const pm_node_location_t location = PM_NODE_START_LOCATION(node); const pm_node_list_t *lefts; const pm_node_t *rest; const pm_node_list_t *rights; @@ -5350,7 +5355,7 @@ pm_compile_multi_target_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR break; } default: - rb_bug("Unsupported node %s", pm_node_type_to_str(PM_NODE_TYPE(node))); + rb_bug("Unsupported node %s", pm_node_type(PM_NODE_TYPE(node))); break; } @@ -5412,7 +5417,7 @@ pm_compile_multi_target_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR static void pm_compile_for_node_index(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, pm_scope_node_t *scope_node) { - const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node); + const pm_node_location_t location = PM_NODE_START_LOCATION(node); switch (PM_NODE_TYPE(node)) { case PM_LOCAL_VARIABLE_TARGET_NODE: { @@ -5495,7 +5500,7 @@ pm_compile_for_node_index(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *c break; } default: - rb_bug("Unexpected node type for index in for node: %s", pm_node_type_to_str(PM_NODE_TYPE(node))); + rb_bug("Unexpected node type for index in for node: %s", pm_node_type(PM_NODE_TYPE(node))); break; } } @@ -5503,8 +5508,6 @@ pm_compile_for_node_index(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *c static void pm_compile_rescue(rb_iseq_t *iseq, const pm_begin_node_t *cast, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) { - const pm_parser_t *parser = scope_node->parser; - LABEL *lstart = NEW_LABEL(node_location->line); LABEL *lend = NEW_LABEL(node_location->line); LABEL *lcont = NEW_LABEL(node_location->line); @@ -5516,7 +5519,7 @@ pm_compile_rescue(rb_iseq_t *iseq, const pm_begin_node_t *cast, const pm_node_lo &rescue_scope_node, rb_str_concat(rb_str_new2("rescue in "), ISEQ_BODY(iseq)->location.label), ISEQ_TYPE_RESCUE, - pm_node_line_number_cached(parser, (const pm_node_t *) cast->rescue_clause, scope_node) + pm_node_line_number_cached((const pm_node_t *) cast->rescue_clause, scope_node) ); pm_scope_node_destroy(&rescue_scope_node); @@ -5532,7 +5535,7 @@ pm_compile_rescue(rb_iseq_t *iseq, const pm_begin_node_t *cast, const pm_node_lo PM_COMPILE_NOT_POPPED((const pm_node_t *) cast->statements); } else { - const pm_node_location_t location = PM_NODE_START_LOCATION(parser, cast->rescue_clause); + const pm_node_location_t location = PM_NODE_START_LOCATION(cast->rescue_clause); PUSH_INSN(ret, location, putnil); } @@ -5555,12 +5558,11 @@ pm_compile_rescue(rb_iseq_t *iseq, const pm_begin_node_t *cast, const pm_node_lo static void pm_compile_ensure(rb_iseq_t *iseq, const pm_begin_node_t *cast, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) { - const pm_parser_t *parser = scope_node->parser; const pm_statements_node_t *statements = cast->ensure_clause->statements; pm_node_location_t location; if (statements != NULL) { - location = PM_NODE_START_LOCATION(parser, statements); + location = PM_NODE_START_LOCATION(statements); } else { location = *node_location; @@ -5650,7 +5652,7 @@ pm_opt_str_freeze_p(const rb_iseq_t *iseq, const pm_call_node_t *node) static void pm_compile_constant_read(rb_iseq_t *iseq, VALUE name, const pm_location_t *name_loc, uint32_t node_id, LINK_ANCHOR *const ret, pm_scope_node_t *scope_node) { - const pm_node_location_t location = PM_LOCATION_START_LOCATION(scope_node->parser, name_loc, node_id); + const pm_node_location_t location = PM_LOCATION_START_LOCATION(name_loc, node_id); if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) { ISEQ_BODY(iseq)->ic_size++; @@ -5710,7 +5712,7 @@ pm_constant_path_parts(const pm_node_t *node, const pm_scope_node_t *scope_node) static void pm_compile_constant_path(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const prefix, LINK_ANCHOR *const body, bool popped, pm_scope_node_t *scope_node) { - const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node); + const pm_node_location_t location = PM_NODE_START_LOCATION(node); switch (PM_NODE_TYPE(node)) { case PM_CONSTANT_READ_NODE: { @@ -5815,12 +5817,12 @@ pm_compile_shareable_constant_value(rb_iseq_t *iseq, const pm_node_t *node, cons { VALUE literal = pm_compile_shareable_constant_literal(iseq, node, scope_node); if (literal != Qundef) { - const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node); + const pm_node_location_t location = PM_NODE_START_LOCATION(node); PUSH_INSN1(ret, location, putobject, literal); return; } - const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node); + const pm_node_location_t location = PM_NODE_START_LOCATION(node); switch (PM_NODE_TYPE(node)) { case PM_ARRAY_NODE: { const pm_array_node_t *cast = (const pm_array_node_t *) node; @@ -6285,7 +6287,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod body->param.flags.ambiguous_param0 = true; break; default: - rb_bug("Unexpected node type for parameters: %s", pm_node_type_to_str(PM_NODE_TYPE(scope_node->parameters))); + rb_bug("Unexpected node type for parameters: %s", pm_node_type(PM_NODE_TYPE(scope_node->parameters))); } } @@ -6493,7 +6495,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod break; } default: - rb_bug("Unsupported node in requireds in parameters %s", pm_node_type_to_str(PM_NODE_TYPE(required))); + rb_bug("Unsupported node in requireds in parameters %s", pm_node_type(PM_NODE_TYPE(required))); } } @@ -6598,7 +6600,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod break; } default: - rb_bug("Unsupported node in posts in parameters %s", pm_node_type_to_str(PM_NODE_TYPE(post_node))); + rb_bug("Unsupported node in posts in parameters %s", pm_node_type(PM_NODE_TYPE(post_node))); } } } @@ -6761,7 +6763,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod break; } default: - rb_bug("node type %s not expected as keyword_rest", pm_node_type_to_str(PM_NODE_TYPE(parameters_node->keyword_rest))); + rb_bug("node type %s not expected as keyword_rest", pm_node_type(PM_NODE_TYPE(parameters_node->keyword_rest))); } } @@ -6798,7 +6800,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod break; } default: - rb_bug("node type %s not expected as block parameter", pm_node_type_to_str(PM_NODE_TYPE(parameters_node->block))); + rb_bug("node type %s not expected as block parameter", pm_node_type(PM_NODE_TYPE(parameters_node->block))); } } } @@ -6863,7 +6865,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod RUBY_ASSERT(0 < maximum && maximum <= 9); for (int i = 0; i < maximum; i++, local_index++) { const uint8_t param_name[] = { '_', '1' + i }; - pm_constant_id_t constant_id = pm_constant_pool_find(&scope_node->parser->constant_pool, param_name, 2); + pm_constant_id_t constant_id = pm_parser_constant_find(scope_node->parser, param_name, 2); RUBY_ASSERT(constant_id && "parser should fill in any gaps in numbered parameters"); pm_insert_local_index(constant_id, local_index, index_lookup_table, local_table_for_iseq, scope_node); } @@ -6996,7 +6998,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod // ^^ break; default: - rb_bug("Unexpected keyword parameter node type %s", pm_node_type_to_str(PM_NODE_TYPE(keyword_parameter_node))); + rb_bug("Unexpected keyword parameter node type %s", pm_node_type(PM_NODE_TYPE(keyword_parameter_node))); } } } @@ -7098,7 +7100,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod break; } case ISEQ_TYPE_ENSURE: { - const pm_node_location_t statements_location = (scope_node->body != NULL ? PM_NODE_START_LOCATION(scope_node->parser, scope_node->body) : location); + const pm_node_location_t statements_location = (scope_node->body != NULL ? PM_NODE_START_LOCATION(scope_node->body) : location); iseq_set_exception_local_table(iseq); if (scope_node->body != NULL) { @@ -7161,7 +7163,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod } if (PM_NODE_TYPE_P(scope_node->ast_node, PM_CLASS_NODE) || PM_NODE_TYPE_P(scope_node->ast_node, PM_MODULE_NODE)) { - const pm_node_location_t end_location = PM_NODE_END_LOCATION(scope_node->parser, scope_node->ast_node); + const pm_node_location_t end_location = PM_NODE_END_LOCATION(scope_node->ast_node); PUSH_TRACE(ret, RUBY_EVENT_END); ISEQ_COMPILE_DATA(iseq)->last_line = end_location.line; } @@ -7181,13 +7183,13 @@ pm_compile_alias_global_variable_node(rb_iseq_t *iseq, const pm_alias_global_var { const pm_location_t *name_loc = &node->new_name->location; - VALUE operand = ID2SYM(rb_intern3((const char *) (scope_node->parser->start + name_loc->start), name_loc->length, scope_node->encoding)); + VALUE operand = ID2SYM(rb_intern3((const char *) (pm_parser_start(scope_node->parser) + name_loc->start), name_loc->length, scope_node->encoding)); PUSH_INSN1(ret, *location, putobject, operand); } { const pm_location_t *name_loc = &node->old_name->location; - VALUE operand = ID2SYM(rb_intern3((const char *) (scope_node->parser->start + name_loc->start), name_loc->length, scope_node->encoding)); + VALUE operand = ID2SYM(rb_intern3((const char *) (pm_parser_start(scope_node->parser) + name_loc->start), name_loc->length, scope_node->encoding)); PUSH_INSN1(ret, *location, putobject, operand); } @@ -7468,7 +7470,7 @@ pm_compile_call_node(rb_iseq_t *iseq, const pm_call_node_t *node, LINK_ANCHOR *c const pm_location_t *message_loc = &node->message_loc; if (message_loc->length == 0) message_loc = &node->base.location; - const pm_node_location_t location = PM_LOCATION_START_LOCATION(scope_node->parser, message_loc, node->base.node_id); + const pm_node_location_t location = PM_LOCATION_START_LOCATION(message_loc, node->base.node_id); const char *builtin_func; if (UNLIKELY(iseq_has_builtin_function_table(iseq)) && (builtin_func = pm_iseq_builtin_function_name(scope_node, node->receiver, method_id)) != NULL) { @@ -7632,7 +7634,6 @@ pm_compile_case_node_dispatch(rb_iseq_t *iseq, VALUE dispatch, const pm_node_t * static inline void pm_compile_case_node(rb_iseq_t *iseq, const pm_case_node_t *cast, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) { - const pm_parser_t *parser = scope_node->parser; const pm_node_location_t location = *node_location; const pm_node_list_t *conditions = &cast->conditions; @@ -7671,7 +7672,7 @@ pm_compile_case_node(rb_iseq_t *iseq, const pm_case_node_t *cast, const pm_node_ const pm_when_node_t *clause = (const pm_when_node_t *) conditions->nodes[clause_index]; const pm_node_list_t *conditions = &clause->conditions; - int clause_lineno = pm_node_line_number_cached(parser, (const pm_node_t *) clause, scope_node); + int clause_lineno = pm_node_line_number_cached((const pm_node_t *) clause, scope_node); LABEL *label = NEW_LABEL(clause_lineno); PUSH_LABEL(body_seq, label); @@ -7697,14 +7698,14 @@ pm_compile_case_node(rb_iseq_t *iseq, const pm_case_node_t *cast, const pm_node_ const pm_node_t *condition = conditions->nodes[condition_index]; if (PM_NODE_TYPE_P(condition, PM_SPLAT_NODE)) { - pm_node_location_t cond_location = PM_NODE_START_LOCATION(parser, condition); + pm_node_location_t cond_location = PM_NODE_START_LOCATION(condition); PUSH_INSN(cond_seq, cond_location, putnil); pm_compile_node(iseq, condition, cond_seq, false, scope_node); PUSH_INSN1(cond_seq, cond_location, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_WHEN | VM_CHECKMATCH_ARRAY)); PUSH_INSNL(cond_seq, cond_location, branchif, label); } else { - LABEL *next_label = NEW_LABEL(pm_node_line_number_cached(parser, condition, scope_node)); + LABEL *next_label = NEW_LABEL(pm_node_line_number_cached(condition, scope_node)); pm_compile_branch_condition(iseq, cond_seq, condition, label, next_label, false, scope_node); PUSH_LABEL(cond_seq, next_label); } @@ -7776,7 +7777,7 @@ pm_compile_case_node(rb_iseq_t *iseq, const pm_case_node_t *cast, const pm_node_ // node instructions later. for (size_t clause_index = 0; clause_index < conditions->size; clause_index++) { const pm_when_node_t *clause = (const pm_when_node_t *) conditions->nodes[clause_index]; - pm_node_location_t clause_location = PM_NODE_START_LOCATION(parser, (const pm_node_t *) clause); + pm_node_location_t clause_location = PM_NODE_START_LOCATION((const pm_node_t *) clause); const pm_node_list_t *conditions = &clause->conditions; LABEL *label = NEW_LABEL(clause_location.line); @@ -7786,7 +7787,7 @@ pm_compile_case_node(rb_iseq_t *iseq, const pm_case_node_t *cast, const pm_node_ // jumps into the body if it matches. for (size_t condition_index = 0; condition_index < conditions->size; condition_index++) { const pm_node_t *condition = conditions->nodes[condition_index]; - const pm_node_location_t condition_location = PM_NODE_START_LOCATION(parser, condition); + const pm_node_location_t condition_location = PM_NODE_START_LOCATION(condition); // If we haven't already abandoned the optimization, then // we're going to try to compile the condition into the @@ -7862,7 +7863,7 @@ pm_compile_case_node(rb_iseq_t *iseq, const pm_case_node_t *cast, const pm_node_ PUSH_LABEL(ret, else_label); if (cast->else_clause != NULL) { - pm_node_location_t else_location = PM_NODE_START_LOCATION(parser, cast->else_clause->statements != NULL ? ((const pm_node_t *) cast->else_clause->statements) : ((const pm_node_t *) cast->else_clause)); + pm_node_location_t else_location = PM_NODE_START_LOCATION(cast->else_clause->statements != NULL ? ((const pm_node_t *) cast->else_clause->statements) : ((const pm_node_t *) cast->else_clause)); PUSH_INSN(ret, else_location, pop); // Establish branch coverage for the else clause. @@ -7951,8 +7952,8 @@ pm_compile_case_match_node(rb_iseq_t *iseq, const pm_case_match_node_t *node, co RUBY_ASSERT(PM_NODE_TYPE_P(condition, PM_IN_NODE)); const pm_in_node_t *in_node = (const pm_in_node_t *) condition; - const pm_node_location_t in_location = PM_NODE_START_LOCATION(scope_node->parser, in_node); - const pm_node_location_t pattern_location = PM_NODE_START_LOCATION(scope_node->parser, in_node->pattern); + const pm_node_location_t in_location = PM_NODE_START_LOCATION(in_node); + const pm_node_location_t pattern_location = PM_NODE_START_LOCATION(in_node->pattern); if (branch_id) { PUSH_INSN(body_seq, in_location, putnil); @@ -8730,8 +8731,7 @@ pm_compile_yield_node(rb_iseq_t *iseq, const pm_yield_node_t *node, const pm_nod static void pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) { - const pm_parser_t *parser = scope_node->parser; - const pm_node_location_t location = PM_NODE_START_LOCATION(parser, node); + const pm_node_location_t location = PM_NODE_START_LOCATION(node); int lineno = (int) location.line; if (PM_NODE_TYPE_P(node, PM_BEGIN_NODE) && (((const pm_begin_node_t *) node)->statements == NULL) && (((const pm_begin_node_t *) node)->rescue_clause != NULL)) { @@ -8739,7 +8739,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, // has a rescue clause, then the other parser considers it as // starting on the same line as the rescue, as opposed to the // location of the begin keyword. We replicate that behavior here. - lineno = (int) PM_NODE_START_LINE_COLUMN(parser, ((const pm_begin_node_t *) node)->rescue_clause).line; + lineno = (int) PM_NODE_START_LINE_COLUMN(((const pm_begin_node_t *) node)->rescue_clause).line; } if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_NEWLINE) && ISEQ_COMPILE_DATA(iseq)->last_line != lineno) { @@ -9786,7 +9786,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, pm_scope_node_t next_scope_node; pm_scope_node_init(node, &next_scope_node, scope_node); - int opening_lineno = pm_location_line_number_cached(parser, &cast->opening_loc, scope_node); + int opening_lineno = pm_location_line_number_cached(&cast->opening_loc, scope_node); const rb_iseq_t *block = NEW_CHILD_ISEQ(&next_scope_node, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, opening_lineno); pm_scope_node_destroy(&next_scope_node); @@ -10264,7 +10264,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, &rescue_scope_node, rb_str_concat(rb_str_new2("rescue in "), ISEQ_BODY(iseq)->location.label), ISEQ_TYPE_RESCUE, - pm_node_line_number_cached(parser, cast->rescue_expression, scope_node) + pm_node_line_number_cached(cast->rescue_expression, scope_node) ); pm_scope_node_destroy(&rescue_scope_node); @@ -10353,7 +10353,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, pm_compile_constant_path_operator_write_node(iseq, (const pm_constant_path_operator_write_node_t *) cast->write, shareability, &location, ret, popped, scope_node); break; default: - rb_bug("Unexpected node type for shareable constant write: %s", pm_node_type_to_str(PM_NODE_TYPE(cast->write))); + rb_bug("Unexpected node type for shareable constant write: %s", pm_node_type(PM_NODE_TYPE(cast->write))); break; } @@ -10567,7 +10567,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, pm_compile_yield_node(iseq, (const pm_yield_node_t *) node, &location, ret, popped, scope_node); return; default: - rb_raise(rb_eNotImpError, "node type %s not implemented", pm_node_type_to_str(PM_NODE_TYPE(node))); + rb_raise(rb_eNotImpError, "node type %s not implemented", pm_node_type(PM_NODE_TYPE(node))); return; } } @@ -10629,6 +10629,15 @@ pm_iseq_compile_node(rb_iseq_t *iseq, pm_scope_node_t *node) return iseq_setup(iseq, ret); } +void +pm_parse_result_init(pm_parse_result_t *result) +{ + memset(result, 0, sizeof(pm_parse_result_t)); + result->arena = pm_arena_new(); + result->options = pm_options_new(); + pm_options_line_set(result->options, 1); +} + /** * Free the internal memory associated with a pm_parse_result_t struct. * Importantly this does not free the struct itself. @@ -10637,20 +10646,20 @@ void pm_parse_result_free(pm_parse_result_t *result) { if (result->parsed) { - SIZED_FREE_N(result->node.constants, result->node.parser->constant_pool.size); + SIZED_FREE_N(result->node.constants, pm_parser_constants_size(result->node.parser)); pm_scope_node_destroy(&result->node); } - pm_parser_free(&result->parser); - pm_arena_free(&result->arena); - pm_string_free(&result->input); - pm_options_free(&result->options); + if (result->parser) pm_parser_free(result->parser); + pm_arena_free(result->arena); + if (result->source) pm_source_free(result->source); + pm_options_free(result->options); } /** An error that is going to be formatted into the output. */ typedef struct { /** A pointer to the diagnostic that was generated during parsing. */ - pm_diagnostic_t *error; + const pm_diagnostic_t *error; /** The start line of the diagnostic message. */ int32_t line; @@ -10686,81 +10695,93 @@ typedef struct { #define PM_COLOR_RESET "\033[m" #define PM_ERROR_TRUNCATE 30 -static inline pm_parse_error_t * -pm_parse_errors_format_sort(const pm_parser_t *parser, const pm_list_t *error_list, const pm_line_offset_list_t *line_offsets) { - pm_parse_error_t *errors = xcalloc(error_list->size, sizeof(pm_parse_error_t)); - if (errors == NULL) return NULL; +/** Context struct for collecting errors via callback. */ +typedef struct { + pm_parse_error_t *errors; + size_t count; + size_t capacity; + const pm_line_offset_list_t *line_offsets; + int32_t start_line; +} pm_error_collect_t; - int32_t start_line = parser->start_line; - pm_diagnostic_t *finish = (pm_diagnostic_t * )error_list->tail->next; - - for (pm_diagnostic_t *error = (pm_diagnostic_t *) error_list->head; error != finish; error = (pm_diagnostic_t *) error->node.next) { - pm_line_column_t start = pm_line_offset_list_line_column(line_offsets, error->location.start, start_line); - pm_line_column_t end = pm_line_offset_list_line_column(line_offsets, error->location.start + error->location.length, start_line); - - // We're going to insert this error into the array in sorted order. We - // do this by finding the first error that has a line number greater - // than the current error and then inserting the current error before - // that one. - size_t index = 0; - while ( - (index < error_list->size) && - (errors[index].error != NULL) && - ( - (errors[index].line < start.line) || - ((errors[index].line == start.line) && (errors[index].column_start < start.column)) - ) - ) index++; - - // Now we're going to shift all of the errors after this one down one - // index to make room for the new error. - if (index + 1 < error_list->size) { - memmove(&errors[index + 1], &errors[index], sizeof(pm_parse_error_t) * (error_list->size - index - 1)); - } - - // Finally, we'll insert the error into the array. - uint32_t column_end; - if (start.line == end.line) { - column_end = end.column; - } else { - column_end = (uint32_t) (line_offsets->offsets[start.line - start_line + 1] - line_offsets->offsets[start.line - start_line] - 1); - } +static void +pm_error_collect_callback(const pm_diagnostic_t *diagnostic, void *data) +{ + pm_error_collect_t *ctx = (pm_error_collect_t *) data; + pm_location_t loc = pm_diagnostic_location(diagnostic); - // Ensure we have at least one column of error. - if (start.column == column_end) column_end++; + pm_line_column_t start = pm_line_offset_list_line_column(ctx->line_offsets, loc.start, ctx->start_line); + pm_line_column_t end = pm_line_offset_list_line_column(ctx->line_offsets, loc.start + loc.length, ctx->start_line); - errors[index] = (pm_parse_error_t) { - .error = error, - .line = start.line, - .column_start = start.column, - .column_end = column_end - }; + uint32_t column_end; + if (start.line == end.line) { + column_end = end.column; + } else { + column_end = (uint32_t) (ctx->line_offsets->offsets[start.line - ctx->start_line + 1] - ctx->line_offsets->offsets[start.line - ctx->start_line] - 1); } - return errors; + // Ensure we have at least one column of error. + if (start.column == column_end) column_end++; + + // Insert into sorted position (insertion sort). + size_t index = 0; + while ( + (index < ctx->count) && + ( + (ctx->errors[index].line < start.line) || + ((ctx->errors[index].line == start.line) && (ctx->errors[index].column_start < start.column)) + ) + ) index++; + + if (index < ctx->count) { + memmove(&ctx->errors[index + 1], &ctx->errors[index], sizeof(pm_parse_error_t) * (ctx->count - index)); + } + + ctx->errors[index] = (pm_parse_error_t) { + .error = diagnostic, + .line = start.line, + .column_start = start.column, + .column_end = column_end + }; + ctx->count++; } -/* Append a literal string to the buffer. */ -#define pm_buffer_append_literal(buffer, str) pm_buffer_append_string(buffer, str, rb_strlen_lit(str)) +static inline pm_parse_error_t * +pm_parse_errors_format_sort(const pm_parser_t *parser, size_t error_count, const pm_line_offset_list_t *line_offsets) { + pm_parse_error_t *errors = xcalloc(error_count, sizeof(pm_parse_error_t)); + if (errors == NULL) return NULL; + + pm_error_collect_t ctx = { + .errors = errors, + .count = 0, + .capacity = error_count, + .line_offsets = line_offsets, + .start_line = pm_parser_start_line(parser) + }; + + pm_parser_errors_each(parser, pm_error_collect_callback, &ctx); + + return errors; +} static inline void -pm_parse_errors_format_line(const pm_parser_t *parser, const pm_line_offset_list_t *line_offsets, const char *number_prefix, int32_t line, uint32_t column_start, uint32_t column_end, pm_buffer_t *buffer) { - int32_t line_delta = line - parser->start_line; +pm_parse_errors_format_line(const pm_parser_t *parser, const pm_line_offset_list_t *line_offsets, const char *number_prefix, int32_t line, uint32_t column_start, uint32_t column_end, VALUE buffer) { + int32_t line_delta = line - pm_parser_start_line(parser); assert(line_delta >= 0); size_t index = (size_t) line_delta; assert(index < line_offsets->size); - const uint8_t *start = &parser->start[line_offsets->offsets[index]]; + const uint8_t *start = &pm_parser_start(parser)[line_offsets->offsets[index]]; const uint8_t *end; if (index >= line_offsets->size - 1) { - end = parser->end; + end = pm_parser_end(parser); } else { - end = &parser->start[line_offsets->offsets[index + 1]]; + end = &pm_parser_start(parser)[line_offsets->offsets[index + 1]]; } - pm_buffer_append_format(buffer, number_prefix, line); + rb_str_catf(buffer, number_prefix, line); // Here we determine if we should truncate the end of the line. bool truncate_end = false; @@ -10768,7 +10789,7 @@ pm_parse_errors_format_line(const pm_parser_t *parser, const pm_line_offset_list const uint8_t *end_candidate = start + column_end + PM_ERROR_TRUNCATE; for (const uint8_t *ptr = start; ptr < end_candidate;) { - size_t char_width = parser->encoding->char_width(ptr, parser->end - ptr); + size_t char_width = pm_parser_encoding_char_width(parser, ptr, pm_parser_end(parser) - ptr); // If we failed to decode a character, then just bail out and // truncate at the fixed width. @@ -10790,40 +10811,35 @@ pm_parse_errors_format_line(const pm_parser_t *parser, const pm_line_offset_list // Here we determine if we should truncate the start of the line. if (column_start >= PM_ERROR_TRUNCATE) { - pm_buffer_append_string(buffer, "... ", 4); + rb_str_cat(buffer, "... ", 4); start += column_start; } - pm_buffer_append_string(buffer, (const char *) start, (size_t) (end - start)); + rb_str_cat(buffer, (const char *) start, (size_t) (end - start)); if (truncate_end) { - pm_buffer_append_string(buffer, " ...\n", 5); - } else if (end == parser->end && end[-1] != '\n') { - pm_buffer_append_string(buffer, "\n", 1); + rb_str_cat(buffer, " ...\n", 5); + } else if (end == pm_parser_end(parser) && end[-1] != '\n') { + rb_str_cat(buffer, "\n", 1); } } /** - * Format the errors on the parser into the given buffer. + * Format a pre-sorted array of errors into the given buffer. */ static void -pm_parse_errors_format(const pm_parser_t *parser, const pm_list_t *error_list, pm_buffer_t *buffer, int highlight, bool inline_messages) { - assert(error_list->size != 0); +pm_parse_errors_format_with(const pm_parser_t *parser, pm_parse_error_t *errors, size_t error_count, VALUE buffer, int highlight, bool inline_messages) { + assert(error_count != 0); - // First, we're going to sort all of the errors by line number using an - // insertion sort into a newly allocated array. - const int32_t start_line = parser->start_line; - const pm_line_offset_list_t *line_offsets = &parser->line_offsets; - - pm_parse_error_t *errors = pm_parse_errors_format_sort(parser, error_list, line_offsets); - if (errors == NULL) return; + const int32_t start_line = pm_parser_start_line(parser); + const pm_line_offset_list_t *line_offsets = pm_parser_line_offsets(parser); // Now we're going to determine how we're going to format line numbers and // blank lines based on the maximum number of digits in the line numbers // that are going to be displaid. pm_parse_error_format_t error_format; int32_t first_line_number = errors[0].line; - int32_t last_line_number = errors[error_list->size - 1].line; + int32_t last_line_number = errors[error_count - 1].line; // If we have a maximum line number that is negative, then we're going to // use the absolute value for comparison but multiple by 10 to additionally @@ -10912,11 +10928,10 @@ pm_parse_errors_format(const pm_parser_t *parser, const pm_list_t *error_list, p // the source before the error to give some context. We'll be careful not to // display the same line twice in case the errors are close enough in the // source. - int32_t last_line = parser->start_line - 1; + int32_t last_line = pm_parser_start_line(parser) - 1; uint32_t last_column_start = 0; - const pm_encoding_t *encoding = parser->encoding; - for (size_t index = 0; index < error_list->size; index++) { + for (size_t index = 0; index < error_count; index++) { pm_parse_error_t *error = &errors[index]; // Here we determine how many lines of padding of the source to display, @@ -10924,14 +10939,14 @@ pm_parse_errors_format(const pm_parser_t *parser, const pm_list_t *error_list, p if (error->line - last_line > 1) { if (error->line - last_line > 2) { if ((index != 0) && (error->line - last_line > 3)) { - pm_buffer_append_string(buffer, error_format.divider, error_format.divider_length); + rb_str_cat(buffer, error_format.divider, error_format.divider_length); } - pm_buffer_append_string(buffer, " ", 2); + rb_str_cat(buffer, " ", 2); pm_parse_errors_format_line(parser, line_offsets, error_format.number_prefix, error->line - 2, 0, 0, buffer); } - pm_buffer_append_string(buffer, " ", 2); + rb_str_cat(buffer, " ", 2); pm_parse_errors_format_line(parser, line_offsets, error_format.number_prefix, error->line - 1, 0, 0, buffer); } @@ -10939,18 +10954,18 @@ pm_parse_errors_format(const pm_parser_t *parser, const pm_list_t *error_list, p // the line that has the error in it. if ((index == 0) || (error->line != last_line)) { if (highlight > 1) { - pm_buffer_append_literal(buffer, PM_COLOR_RED "> " PM_COLOR_RESET); + rb_str_cat_cstr(buffer, PM_COLOR_RED "> " PM_COLOR_RESET); } else if (highlight > 0) { - pm_buffer_append_literal(buffer, PM_COLOR_BOLD "> " PM_COLOR_RESET); + rb_str_cat_cstr(buffer, PM_COLOR_BOLD "> " PM_COLOR_RESET); } else { - pm_buffer_append_literal(buffer, "> "); + rb_str_cat_cstr(buffer, "> "); } last_column_start = error->column_start; // Find the maximum column end of all the errors on this line. uint32_t column_end = error->column_end; - for (size_t next_index = index + 1; next_index < error_list->size; next_index++) { + for (size_t next_index = index + 1; next_index < error_count; next_index++) { if (errors[next_index].line != error->line) break; if (errors[next_index].column_end > column_end) column_end = errors[next_index].column_end; } @@ -10958,8 +10973,8 @@ pm_parse_errors_format(const pm_parser_t *parser, const pm_list_t *error_list, p pm_parse_errors_format_line(parser, line_offsets, error_format.number_prefix, error->line, error->column_start, column_end, buffer); } - const uint8_t *start = &parser->start[line_offsets->offsets[error->line - start_line]]; - if (start == parser->end) pm_buffer_append_byte(buffer, '\n'); + const uint8_t *start = &pm_parser_start(parser)[line_offsets->offsets[error->line - start_line]]; + if (start == pm_parser_end(parser)) rb_str_cat(buffer, "\n", 1); // Now we'll display the actual error message. We'll do this by first // putting the prefix to the line, then a bunch of blank spaces @@ -10970,59 +10985,59 @@ pm_parse_errors_format(const pm_parser_t *parser, const pm_list_t *error_list, p // character when displaid in the terminal. For some east-asian // languages or emoji, this means it can be thrown off pretty badly. We // will need to solve this eventually. - pm_buffer_append_string(buffer, " ", 2); - pm_buffer_append_string(buffer, error_format.blank_prefix, error_format.blank_prefix_length); + rb_str_cat(buffer, " ", 2); + rb_str_cat(buffer, error_format.blank_prefix, error_format.blank_prefix_length); size_t column = 0; if (last_column_start >= PM_ERROR_TRUNCATE) { - pm_buffer_append_string(buffer, " ", 4); + rb_str_cat(buffer, " ", 4); column = last_column_start; } while (column < error->column_start) { - pm_buffer_append_byte(buffer, ' '); + rb_str_cat(buffer, " ", 1); - size_t char_width = encoding->char_width(start + column, parser->end - (start + column)); + size_t char_width = pm_parser_encoding_char_width(parser, start + column, pm_parser_end(parser) - (start + column)); column += (char_width == 0 ? 1 : char_width); } - if (highlight > 1) pm_buffer_append_literal(buffer, PM_COLOR_RED); - else if (highlight > 0) pm_buffer_append_literal(buffer, PM_COLOR_BOLD); - pm_buffer_append_byte(buffer, '^'); + if (highlight > 1) rb_str_cat_cstr(buffer, PM_COLOR_RED); + else if (highlight > 0) rb_str_cat_cstr(buffer, PM_COLOR_BOLD); + rb_str_cat(buffer, "^", 1); - size_t char_width = encoding->char_width(start + column, parser->end - (start + column)); + size_t char_width = pm_parser_encoding_char_width(parser, start + column, pm_parser_end(parser) - (start + column)); column += (char_width == 0 ? 1 : char_width); while (column < error->column_end) { - pm_buffer_append_byte(buffer, '~'); + rb_str_cat(buffer, "~", 1); - size_t char_width = encoding->char_width(start + column, parser->end - (start + column)); + size_t char_width = pm_parser_encoding_char_width(parser, start + column, pm_parser_end(parser) - (start + column)); column += (char_width == 0 ? 1 : char_width); } - if (highlight > 0) pm_buffer_append_literal(buffer, PM_COLOR_RESET); + if (highlight > 0) rb_str_cat_cstr(buffer, PM_COLOR_RESET); if (inline_messages) { - pm_buffer_append_byte(buffer, ' '); + rb_str_cat(buffer, " ", 1); assert(error->error != NULL); - const char *message = error->error->message; - pm_buffer_append_string(buffer, message, strlen(message)); + const char *message = pm_diagnostic_message(error->error); + rb_str_cat(buffer, message, strlen(message)); } - pm_buffer_append_byte(buffer, '\n'); + rb_str_cat(buffer, "\n", 1); // Here we determine how many lines of padding to display after the // error, depending on where the next error is in source. last_line = error->line; int32_t next_line; - if (index == error_list->size - 1) { - next_line = (((int32_t) line_offsets->size) + parser->start_line); + if (index == error_count - 1) { + next_line = (((int32_t) line_offsets->size) + pm_parser_start_line(parser)); // If the file ends with a newline, subtract one from our "next_line" // so that we don't output an extra line at the end of the file - if ((parser->start + line_offsets->offsets[line_offsets->size - 1]) == parser->end) { + if ((pm_parser_start(parser) + line_offsets->offsets[line_offsets->size - 1]) == pm_parser_end(parser)) { next_line--; } } @@ -11031,18 +11046,30 @@ pm_parse_errors_format(const pm_parser_t *parser, const pm_list_t *error_list, p } if (next_line - last_line > 1) { - pm_buffer_append_string(buffer, " ", 2); + rb_str_cat(buffer, " ", 2); pm_parse_errors_format_line(parser, line_offsets, error_format.number_prefix, ++last_line, 0, 0, buffer); } if (next_line - last_line > 1) { - pm_buffer_append_string(buffer, " ", 2); + rb_str_cat(buffer, " ", 2); pm_parse_errors_format_line(parser, line_offsets, error_format.number_prefix, ++last_line, 0, 0, buffer); } } - // Finally, we'll free the array of errors that we allocated. - SIZED_FREE_N(errors, error_list->size); +} + +/** + * Format the errors on the parser into the given buffer. + */ +static void +pm_parse_errors_format(const pm_parser_t *parser, size_t error_count, VALUE buffer, int highlight, bool inline_messages) { + const pm_line_offset_list_t *line_offsets = pm_parser_line_offsets(parser); + + pm_parse_error_t *errors = pm_parse_errors_format_sort(parser, error_count, line_offsets); + if (errors == NULL) return; + + pm_parse_errors_format_with(parser, errors, error_count, buffer, highlight, inline_messages); + SIZED_FREE_N(errors, error_count); } #undef PM_ERROR_TRUNCATE @@ -11057,23 +11084,136 @@ pm_parse_errors_format(const pm_parser_t *parser, const pm_list_t *error_list, p * as well. */ static bool -pm_parse_process_error_utf8_p(const pm_parser_t *parser, const pm_location_t *location) +pm_parse_process_error_utf8_p(const pm_parser_t *parser, pm_location_t location) { - const size_t start_line = pm_line_offset_list_line_column(&parser->line_offsets, location->start, 1).line; - const size_t end_line = pm_line_offset_list_line_column(&parser->line_offsets, location->start + location->length, 1).line; + const size_t start_line = pm_line_offset_list_line_column(pm_parser_line_offsets(parser), location.start, 1).line; + const size_t end_line = pm_line_offset_list_line_column(pm_parser_line_offsets(parser), location.start + location.length, 1).line; - const uint8_t *start = parser->start + parser->line_offsets.offsets[start_line - 1]; - const uint8_t *end = ((end_line == parser->line_offsets.size) ? parser->end : (parser->start + parser->line_offsets.offsets[end_line])); - size_t width; + const pm_line_offset_list_t *line_offsets = pm_parser_line_offsets(parser); + const uint8_t *start = pm_parser_start(parser) + line_offsets->offsets[start_line - 1]; + const uint8_t *end = ((end_line == line_offsets->size) ? pm_parser_end(parser) : (pm_parser_start(parser) + line_offsets->offsets[end_line])); + rb_encoding *utf8 = rb_utf8_encoding(); while (start < end) { - if ((width = pm_encoding_utf_8_char_width(start, end - start)) == 0) return false; - start += width; + int width = rb_enc_precise_mbclen((const char *) start, (const char *) end, utf8); + if (!MBCLEN_CHARFOUND_P(width)) return false; + start += MBCLEN_CHARFOUND_LEN(width); } return true; } +/** Context for the error processing callback used in pm_parse_process_error. */ +typedef struct { + const pm_parse_result_t *result; + const pm_parser_t *parser; + const pm_string_t *filepath; + VALUE buffer; + int highlight; + bool valid_utf8; + bool found_argument_error; + bool found_load_error; + VALUE early_return; + const pm_diagnostic_t *first_error; + size_t error_count; +} pm_process_error_ctx_t; + +static void +pm_process_error_check_callback(const pm_diagnostic_t *diagnostic, void *data) +{ + pm_process_error_ctx_t *ctx = (pm_process_error_ctx_t *) data; + pm_location_t loc = pm_diagnostic_location(diagnostic); + + if (ctx->first_error == NULL) ctx->first_error = diagnostic; + ctx->error_count++; + + switch (pm_diagnostic_error_level(diagnostic)) { + case PM_ERROR_LEVEL_SYNTAX: + if (ctx->valid_utf8 && !pm_parse_process_error_utf8_p(ctx->parser, loc)) { + ctx->valid_utf8 = false; + } + break; + case PM_ERROR_LEVEL_ARGUMENT: { + if (ctx->found_argument_error || ctx->found_load_error) break; + ctx->found_argument_error = true; + + int32_t line_number = (int32_t) pm_location_line_number(ctx->parser, &loc); + + rb_str_catf( + ctx->buffer, + "%.*s:%" PRIi32 ": %s", + (int) pm_string_length(ctx->filepath), + pm_string_source(ctx->filepath), + line_number, + pm_diagnostic_message(diagnostic) + ); + + if (pm_parse_process_error_utf8_p(ctx->parser, loc)) { + rb_str_cat(ctx->buffer, "\n", 1); + // Format just this one error. We construct a single-element sorted + // array manually and call the format function with count=1. + const pm_line_offset_list_t *line_offsets = pm_parser_line_offsets(ctx->parser); + int32_t start_line = pm_parser_start_line(ctx->parser); + pm_line_column_t start_lc = pm_line_offset_list_line_column(line_offsets, loc.start, start_line); + pm_line_column_t end_lc = pm_line_offset_list_line_column(line_offsets, loc.start + loc.length, start_line); + + uint32_t col_end; + if (start_lc.line == end_lc.line) { + col_end = end_lc.column; + } else { + col_end = (uint32_t) (line_offsets->offsets[start_lc.line - start_line + 1] - line_offsets->offsets[start_lc.line - start_line] - 1); + } + if (start_lc.column == col_end) col_end++; + + pm_parse_error_t single_error = { + .error = diagnostic, + .line = start_lc.line, + .column_start = start_lc.column, + .column_end = col_end + }; + pm_parse_errors_format_with(ctx->parser, &single_error, 1, ctx->buffer, ctx->highlight, false); + } + + ctx->early_return = rb_exc_new_str(rb_eArgError, ctx->buffer); + break; + } + case PM_ERROR_LEVEL_LOAD: { + if (ctx->found_argument_error || ctx->found_load_error) break; + ctx->found_load_error = true; + + VALUE message = rb_enc_str_new_cstr(pm_diagnostic_message(diagnostic), rb_locale_encoding()); + VALUE value = rb_exc_new3(rb_eLoadError, message); + rb_ivar_set(value, rb_intern_const("@path"), Qnil); + ctx->early_return = value; + break; + } + } +} + +/** Callback for formatting non-UTF8 errors. */ +typedef struct { + const pm_parser_t *parser; + const pm_string_t *filepath; + VALUE buffer; + bool first; +} pm_error_simple_format_ctx_t; + +static void +pm_error_simple_format_callback(const pm_diagnostic_t *diagnostic, void *data) +{ + pm_error_simple_format_ctx_t *ctx = (pm_error_simple_format_ctx_t *) data; + pm_location_t loc = pm_diagnostic_location(diagnostic); + + if (!ctx->first) rb_str_cat(ctx->buffer, "\n", 1); + ctx->first = false; + + rb_str_catf(ctx->buffer, "%.*s:%" PRIi32 ": %s", + (int) pm_string_length(ctx->filepath), + pm_string_source(ctx->filepath), + (int32_t) pm_location_line_number(ctx->parser, &loc), + pm_diagnostic_message(diagnostic)); +} + /** * Generate an error object from the given parser that contains as much * information as possible about the errors that were encountered. @@ -11081,12 +11221,11 @@ pm_parse_process_error_utf8_p(const pm_parser_t *parser, const pm_location_t *lo static VALUE pm_parse_process_error(const pm_parse_result_t *result) { - const pm_parser_t *parser = &result->parser; - const pm_diagnostic_t *head = (const pm_diagnostic_t *) parser->error_list.head; - bool valid_utf8 = true; + const pm_parser_t *parser = result->parser; + size_t error_count = pm_parser_errors_size(parser); - pm_buffer_t buffer = { 0 }; - const pm_string_t *filepath = &parser->filepath; + VALUE buffer = rb_str_buf_new(0); + const pm_string_t *filepath = pm_parser_filepath(parser); int highlight = rb_stderr_tty_p(); if (highlight) { @@ -11094,90 +11233,98 @@ pm_parse_process_error(const pm_parse_result_t *result) highlight = (no_color == NULL || no_color[0] == '\0') ? 2 : 1; } - for (const pm_diagnostic_t *error = head; error != NULL; error = (const pm_diagnostic_t *) error->node.next) { - switch (error->level) { - case PM_ERROR_LEVEL_SYNTAX: - // It is implicitly assumed that the error messages will be - // encodeable as UTF-8. Because of this, we can't include source - // examples that contain invalid byte sequences. So if any source - // examples include invalid UTF-8 byte sequences, we will skip - // showing source examples entirely. - if (valid_utf8 && !pm_parse_process_error_utf8_p(parser, &error->location)) { - valid_utf8 = false; - } - break; - case PM_ERROR_LEVEL_ARGUMENT: { - // Any errors with the level PM_ERROR_LEVEL_ARGUMENT take over as - // the only argument that gets raised. This is to allow priority - // messages that should be handled before anything else. - int32_t line_number = (int32_t) pm_location_line_number(parser, &error->location); - - pm_buffer_append_format( - &buffer, - "%.*s:%" PRIi32 ": %s", - (int) pm_string_length(filepath), - pm_string_source(filepath), - line_number, - error->message - ); - - if (pm_parse_process_error_utf8_p(parser, &error->location)) { - pm_buffer_append_byte(&buffer, '\n'); - - pm_list_node_t *list_node = (pm_list_node_t *) error; - pm_list_t error_list = { .size = 1, .head = list_node, .tail = list_node }; - - pm_parse_errors_format(parser, &error_list, &buffer, highlight, false); - } + // First pass: check for argument/load errors and UTF-8 validity. + pm_process_error_ctx_t ctx = { + .result = result, + .parser = parser, + .filepath = filepath, + .buffer = buffer, + .highlight = highlight, + .valid_utf8 = true, + .found_argument_error = false, + .found_load_error = false, + .early_return = Qundef, + .first_error = NULL, + .error_count = 0 + }; - VALUE value = rb_exc_new(rb_eArgError, pm_buffer_value(&buffer), pm_buffer_length(&buffer)); - pm_buffer_free(&buffer); + pm_parser_errors_each(parser, pm_process_error_check_callback, &ctx); - return value; - } - case PM_ERROR_LEVEL_LOAD: { - // Load errors are much simpler, because they don't include any of - // the source in them. We create the error directly from the - // message. - VALUE message = rb_enc_str_new_cstr(error->message, rb_locale_encoding()); - VALUE value = rb_exc_new3(rb_eLoadError, message); - rb_ivar_set(value, rb_intern_const("@path"), Qnil); - return value; - } - } + // If we found an argument or load error, return it immediately. + if (ctx.early_return != Qundef) { + return ctx.early_return; } - pm_buffer_append_format( - &buffer, + // Format the header line. + pm_location_t first_loc = pm_diagnostic_location(ctx.first_error); + rb_str_catf( + buffer, "%.*s:%" PRIi32 ": syntax error%s found\n", (int) pm_string_length(filepath), pm_string_source(filepath), - (int32_t) pm_location_line_number(parser, &head->location), - (parser->error_list.size > 1) ? "s" : "" + (int32_t) pm_location_line_number(parser, &first_loc), + (error_count > 1) ? "s" : "" ); - if (valid_utf8) { - pm_parse_errors_format(parser, &parser->error_list, &buffer, highlight, true); + if (ctx.valid_utf8) { + pm_parse_errors_format(parser, error_count, buffer, highlight, true); } else { - for (const pm_diagnostic_t *error = head; error != NULL; error = (const pm_diagnostic_t *) error->node.next) { - if (error != head) pm_buffer_append_byte(&buffer, '\n'); - pm_buffer_append_format(&buffer, "%.*s:%" PRIi32 ": %s", (int) pm_string_length(filepath), pm_string_source(filepath), (int32_t) pm_location_line_number(parser, &error->location), error->message); - } + pm_error_simple_format_ctx_t simple_ctx = { + .parser = parser, + .filepath = filepath, + .buffer = buffer, + .first = true + }; + pm_parser_errors_each(parser, pm_error_simple_format_callback, &simple_ctx); } - VALUE message = rb_enc_str_new(pm_buffer_value(&buffer), pm_buffer_length(&buffer), result->node.encoding); - VALUE error = rb_exc_new_str(rb_eSyntaxError, message); + rb_enc_associate(buffer, result->node.encoding); + VALUE error = rb_exc_new_str(rb_eSyntaxError, buffer); rb_encoding *filepath_encoding = result->node.filepath_encoding != NULL ? result->node.filepath_encoding : rb_utf8_encoding(); VALUE path = rb_enc_str_new((const char *) pm_string_source(filepath), pm_string_length(filepath), filepath_encoding); rb_ivar_set(error, rb_intern_const("@path"), path); - pm_buffer_free(&buffer); return error; } +/** Context for interning constants via callback. */ +typedef struct { + ID *constants; + rb_encoding *encoding; + size_t index; +} pm_intern_constants_ctx_t; + +static void +pm_intern_constants_callback(const pm_constant_t *constant, void *data) +{ + pm_intern_constants_ctx_t *ctx = (pm_intern_constants_ctx_t *) data; + ctx->constants[ctx->index++] = rb_intern3((const char *) pm_constant_start(constant), pm_constant_length(constant), ctx->encoding); +} + +/** Context for emitting warnings via callback. */ +typedef struct { + const pm_parser_t *parser; + rb_encoding *encoding; + const char *filepath; +} pm_warning_emit_ctx_t; + +static void +pm_warning_emit_callback(const pm_diagnostic_t *diagnostic, void *data) { + pm_warning_emit_ctx_t *ctx = (pm_warning_emit_ctx_t *) data; + pm_location_t loc = pm_diagnostic_location(diagnostic); + int line = pm_location_line_number(ctx->parser, &loc); + + if (pm_diagnostic_warning_level(diagnostic) == PM_WARNING_LEVEL_VERBOSE) { + rb_enc_compile_warning(ctx->encoding, ctx->filepath, line, "%s", pm_diagnostic_message(diagnostic)); + } + else { + rb_enc_compile_warn(ctx->encoding, ctx->filepath, line, "%s", pm_diagnostic_message(diagnostic)); + } +} + /** * Parse the parse result and raise a Ruby error if there are any syntax errors. * It returns an error if one should be raised. It is assumed that the parse @@ -11186,7 +11333,7 @@ pm_parse_process_error(const pm_parse_result_t *result) static VALUE pm_parse_process(pm_parse_result_t *result, pm_node_t *node, VALUE *script_lines) { - pm_parser_t *parser = &result->parser; + pm_parser_t *parser = result->parser; // First, set up the scope node so that the AST node is attached and can be // freed regardless of whether or we return an error. @@ -11197,42 +11344,37 @@ pm_parse_process(pm_parse_result_t *result, pm_node_t *node, VALUE *script_lines pm_scope_node_init(node, scope_node, NULL); scope_node->filepath_encoding = filepath_encoding; - scope_node->encoding = rb_enc_find(parser->encoding->name); - if (!scope_node->encoding) rb_bug("Encoding not found %s!", parser->encoding->name); + const char *encoding_name = pm_parser_encoding_name(parser); + scope_node->encoding = rb_enc_find(encoding_name); + if (!scope_node->encoding) rb_bug("Encoding not found %s!", encoding_name); scope_node->coverage_enabled = coverage_enabled; // If RubyVM.keep_script_lines is set to true, then we need to create that // array of script lines here. if (script_lines != NULL) { - *script_lines = rb_ary_new_capa(parser->line_offsets.size); + const pm_line_offset_list_t *line_offsets = pm_parser_line_offsets(parser); + *script_lines = rb_ary_new_capa(line_offsets->size); - for (size_t index = 0; index < parser->line_offsets.size; index++) { - size_t offset = parser->line_offsets.offsets[index]; - size_t length = index == parser->line_offsets.size - 1 ? ((size_t) (parser->end - (parser->start + offset))) : (parser->line_offsets.offsets[index + 1] - offset); - rb_ary_push(*script_lines, rb_enc_str_new((const char *) parser->start + offset, length, scope_node->encoding)); + for (size_t index = 0; index < line_offsets->size; index++) { + size_t offset = line_offsets->offsets[index]; + size_t length = index == line_offsets->size - 1 ? ((size_t) (pm_parser_end(parser) - (pm_parser_start(parser) + offset))) : (line_offsets->offsets[index + 1] - offset); + rb_ary_push(*script_lines, rb_enc_str_new((const char *) pm_parser_start(parser) + offset, length, scope_node->encoding)); } scope_node->script_lines = script_lines; } // Emit all of the various warnings from the parse. - const pm_diagnostic_t *warning; - const char *warning_filepath = (const char *) pm_string_source(&parser->filepath); - - for (warning = (const pm_diagnostic_t *) parser->warning_list.head; warning != NULL; warning = (const pm_diagnostic_t *) warning->node.next) { - int line = pm_location_line_number(parser, &warning->location); - - if (warning->level == PM_WARNING_LEVEL_VERBOSE) { - rb_enc_compile_warning(scope_node->encoding, warning_filepath, line, "%s", warning->message); - } - else { - rb_enc_compile_warn(scope_node->encoding, warning_filepath, line, "%s", warning->message); - } - } + pm_warning_emit_ctx_t warning_ctx = { + .parser = parser, + .encoding = scope_node->encoding, + .filepath = (const char *) pm_string_source(pm_parser_filepath(parser)) + }; + pm_parser_warnings_each(parser, pm_warning_emit_callback, &warning_ctx); // If there are errors, raise an appropriate error and free the result. - if (parser->error_list.size > 0) { + if (pm_parser_errors_size(parser) > 0) { VALUE error = pm_parse_process_error(result); // TODO: We need to set the backtrace. @@ -11243,12 +11385,14 @@ pm_parse_process(pm_parse_result_t *result, pm_node_t *node, VALUE *script_lines // Now set up the constant pool and intern all of the various constants into // their corresponding IDs. scope_node->parser = parser; - scope_node->constants = parser->constant_pool.size ? xcalloc(parser->constant_pool.size, sizeof(ID)) : NULL; + scope_node->options = result->options; + scope_node->line_offsets = pm_parser_line_offsets(parser); + scope_node->start_line = pm_parser_start_line(parser); + size_t constants_size = pm_parser_constants_size(parser); + scope_node->constants = constants_size ? xcalloc(constants_size, sizeof(ID)) : NULL; - for (uint32_t index = 0; index < parser->constant_pool.size; index++) { - pm_constant_t *constant = &parser->constant_pool.constants[index]; - scope_node->constants[index] = rb_intern3((const char *) constant->start, constant->length, scope_node->encoding); - } + pm_intern_constants_ctx_t intern_ctx = { .constants = scope_node->constants, .encoding = scope_node->encoding, .index = 0 }; + pm_parser_constants_each(parser, pm_intern_constants_callback, &intern_ctx); scope_node->index_lookup_table = st_init_numtable(); pm_constant_id_list_t *locals = &scope_node->locals; @@ -11293,9 +11437,9 @@ pm_options_frozen_string_literal_init(pm_options_t *options) static inline VALUE pm_parse_file_script_lines(const pm_scope_node_t *scope_node, const pm_parser_t *parser) { - const pm_line_offset_list_t *line_offsets = &parser->line_offsets; - const char *start = (const char *) parser->start; - const char *end = (const char *) parser->end; + const pm_line_offset_list_t *line_offsets = pm_parser_line_offsets(parser); + const char *start = (const char *) pm_parser_start(parser); + const char *end = (const char *) pm_parser_end(parser); // If we end exactly on a newline, then there's no need to push on a final // segment. If we don't, then we need to push on the last offset up to the @@ -11321,165 +11465,52 @@ pm_parse_file_script_lines(const pm_scope_node_t *scope_node, const pm_parser_t return lines; } -// This is essentially pm_string_mapped_init(), preferring to memory map the -// file, with additional handling for files that require blocking to properly -// read (e.g. pipes). -static pm_string_init_result_t -pm_read_file(pm_string_t *string, const char *filepath) +/** + * Attempt to load the file into memory. Return a Ruby error if the file cannot + * be read. + */ +VALUE +pm_load_file(pm_parse_result_t *result, VALUE filepath, bool load_error) { -#ifdef _WIN32 - // Open the file for reading. - int length = MultiByteToWideChar(CP_UTF8, 0, filepath, -1, NULL, 0); - if (length == 0) return PM_STRING_INIT_ERROR_GENERIC; - - WCHAR *wfilepath = ALLOC_N(WCHAR, length); - if ((wfilepath == NULL) || (MultiByteToWideChar(CP_UTF8, 0, filepath, -1, wfilepath, length) == 0)) { - SIZED_FREE_N(wfilepath, length); - return PM_STRING_INIT_ERROR_GENERIC; - } + pm_source_init_result_t init_result; + result->source = pm_source_mapped_new(RSTRING_PTR(filepath), O_RDONLY | O_NONBLOCK, &init_result); - HANDLE file = CreateFileW(wfilepath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL); - if (file == INVALID_HANDLE_VALUE) { - pm_string_init_result_t result = PM_STRING_INIT_ERROR_GENERIC; - - if (GetLastError() == ERROR_ACCESS_DENIED) { - DWORD attributes = GetFileAttributesW(wfilepath); - if ((attributes != INVALID_FILE_ATTRIBUTES) && (attributes & FILE_ATTRIBUTE_DIRECTORY)) { - result = PM_STRING_INIT_ERROR_DIRECTORY; - } - } - - SIZED_FREE_N(wfilepath, length); - return result; - } - - // Get the file size. - DWORD file_size = GetFileSize(file, NULL); - if (file_size == INVALID_FILE_SIZE) { - CloseHandle(file); - SIZED_FREE_N(wfilepath, length); - return PM_STRING_INIT_ERROR_GENERIC; - } - - // If the file is empty, then we don't need to do anything else, we'll set - // the source to a constant empty string and return. - if (file_size == 0) { - CloseHandle(file); - SIZED_FREE_N(wfilepath, length); - const uint8_t source[] = ""; - *string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = source, .length = 0 }; - return PM_STRING_INIT_SUCCESS; - } - - // Create a mapping of the file. - HANDLE mapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL); - if (mapping == NULL) { - CloseHandle(file); - SIZED_FREE_N(wfilepath, length); - return PM_STRING_INIT_ERROR_GENERIC; - } - - // Map the file into memory. - uint8_t *source = (uint8_t *) MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0); - CloseHandle(mapping); - CloseHandle(file); - SIZED_FREE_N(wfilepath, length); - - if (source == NULL) { - return PM_STRING_INIT_ERROR_GENERIC; - } - - *string = (pm_string_t) { .type = PM_STRING_MAPPED, .source = source, .length = (size_t) file_size }; - return PM_STRING_INIT_SUCCESS; -#elif defined(_POSIX_MAPPED_FILES) - // Open the file for reading - const int open_mode = O_RDONLY | O_NONBLOCK; - int fd = open(filepath, open_mode); - if (fd == -1) { - return PM_STRING_INIT_ERROR_GENERIC; + if (init_result == PM_SOURCE_INIT_SUCCESS) { + pm_options_frozen_string_literal_init(result->options); + return Qnil; } - // Stat the file to get the file size - struct stat sb; - if (fstat(fd, &sb) == -1) { - close(fd); - return PM_STRING_INIT_ERROR_GENERIC; - } + int err; - // Ensure it is a file and not a directory - if (S_ISDIR(sb.st_mode)) { - close(fd); - return PM_STRING_INIT_ERROR_DIRECTORY; - } + // For non-regular files (pipes, character devices), we need to read + // through Ruby IO to properly release the GVL while waiting for data. + if (init_result == PM_SOURCE_INIT_ERROR_NON_REGULAR) { + const int open_mode = O_RDONLY | O_NONBLOCK; + int fd = open(RSTRING_PTR(filepath), open_mode); + if (fd == -1) goto error_generic; - // We need to wait for data first before reading from pipes and character - // devices. To not block the entire VM, we need to release the GVL while - // reading. Use IO#read to do this and let the GC handle closing the FD. - if (S_ISFIFO(sb.st_mode) || S_ISCHR(sb.st_mode)) { - VALUE io = rb_io_fdopen((int) fd, open_mode, filepath); + VALUE io = rb_io_fdopen(fd, open_mode, RSTRING_PTR(filepath)); rb_io_wait(io, RB_INT2NUM(RUBY_IO_READABLE), Qnil); VALUE contents = rb_funcall(io, rb_intern("read"), 0); - if (!RB_TYPE_P(contents, T_STRING)) { - return PM_STRING_INIT_ERROR_GENERIC; - } + if (!RB_TYPE_P(contents, T_STRING)) goto error_generic; long len = RSTRING_LEN(contents); - if (len < 0) { - return PM_STRING_INIT_ERROR_GENERIC; - } + if (len < 0) goto error_generic; size_t length = (size_t) len; - uint8_t *source = xmalloc(length); - memcpy(source, RSTRING_PTR(contents), length); - *string = (pm_string_t) { .type = PM_STRING_OWNED, .source = source, .length = length }; - - return PM_STRING_INIT_SUCCESS; - } - - // mmap the file descriptor to virtually get the contents - size_t size = (size_t) sb.st_size; - uint8_t *source = NULL; - - if (size == 0) { - close(fd); - const uint8_t source[] = ""; - *string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = source, .length = 0 }; - return PM_STRING_INIT_SUCCESS; - } - - source = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); - if (source == MAP_FAILED) { - close(fd); - return PM_STRING_INIT_ERROR_GENERIC; - } - - close(fd); - *string = (pm_string_t) { .type = PM_STRING_MAPPED, .source = source, .length = size }; - return PM_STRING_INIT_SUCCESS; -#else - return pm_string_file_init(string, filepath); -#endif -} + uint8_t *source_data = xmalloc(length); + memcpy(source_data, RSTRING_PTR(contents), length); + result->source = pm_source_owned_new(source_data, length); -/** - * Attempt to load the file into memory. Return a Ruby error if the file cannot - * be read. - */ -VALUE -pm_load_file(pm_parse_result_t *result, VALUE filepath, bool load_error) -{ - pm_string_init_result_t init_result = pm_read_file(&result->input, RSTRING_PTR(filepath)); - - if (init_result == PM_STRING_INIT_SUCCESS) { - pm_options_frozen_string_literal_init(&result->options); + pm_options_frozen_string_literal_init(result->options); return Qnil; } - int err; - if (init_result == PM_STRING_INIT_ERROR_DIRECTORY) { + if (init_result == PM_SOURCE_INIT_ERROR_DIRECTORY) { err = EISDIR; } else { +error_generic: #ifdef _WIN32 err = rb_w32_map_errno(GetLastError()); #else @@ -11513,13 +11544,13 @@ VALUE pm_parse_file(pm_parse_result_t *result, VALUE filepath, VALUE *script_lines) { result->node.filepath_encoding = rb_enc_get(filepath); - pm_options_filepath_set(&result->options, RSTRING_PTR(filepath)); + pm_options_filepath_set(result->options, RSTRING_PTR(filepath)); RB_GC_GUARD(filepath); - pm_options_version_for_current_ruby_set(&result->options); + pm_options_version_for_current_ruby_set(result->options); - pm_parser_init(&result->arena, &result->parser, pm_string_source(&result->input), pm_string_length(&result->input), &result->options); - pm_node_t *node = pm_parse(&result->parser); + result->parser = pm_parser_new(result->arena, pm_source_source(result->source), pm_source_length(result->source), result->options); + pm_node_t *node = pm_parse(result->parser); VALUE error = pm_parse_process(result, node, script_lines); @@ -11532,7 +11563,7 @@ pm_parse_file(pm_parse_result_t *result, VALUE filepath, VALUE *script_lines) VALUE constant_script_lines = rb_const_get_at(rb_cObject, id_script_lines); if (RB_TYPE_P(constant_script_lines, T_HASH)) { - rb_hash_aset(constant_script_lines, filepath, pm_parse_file_script_lines(&result->node, &result->parser)); + rb_hash_aset(constant_script_lines, filepath, pm_parse_file_script_lines(&result->node, result->parser)); } } @@ -11568,18 +11599,18 @@ pm_parse_string(pm_parse_result_t *result, VALUE source, VALUE filepath, VALUE * return rb_exc_new_cstr(rb_eArgError, "invalid source encoding"); } - pm_options_frozen_string_literal_init(&result->options); - pm_string_constant_init(&result->input, RSTRING_PTR(source), RSTRING_LEN(source)); - pm_options_encoding_set(&result->options, rb_enc_name(encoding)); + pm_options_frozen_string_literal_init(result->options); + result->source = pm_source_constant_new((const uint8_t *) RSTRING_PTR(source), (size_t) RSTRING_LEN(source)); + pm_options_encoding_set(result->options, rb_enc_name(encoding)); result->node.filepath_encoding = rb_enc_get(filepath); - pm_options_filepath_set(&result->options, RSTRING_PTR(filepath)); + pm_options_filepath_set(result->options, RSTRING_PTR(filepath)); RB_GC_GUARD(filepath); - pm_options_version_for_current_ruby_set(&result->options); + pm_options_version_for_current_ruby_set(result->options); - pm_parser_init(&result->arena, &result->parser, pm_string_source(&result->input), pm_string_length(&result->input), &result->options); - pm_node_t *node = pm_parse(&result->parser); + result->parser = pm_parser_new(result->arena, pm_source_source(result->source), pm_source_length(result->source), result->options); + pm_node_t *node = pm_parse(result->parser); return pm_parse_process(result, node, script_lines); } @@ -11640,20 +11671,15 @@ void rb_reset_argf_lineno(long n); VALUE pm_parse_stdin(pm_parse_result_t *result) { - pm_options_frozen_string_literal_init(&result->options); + pm_options_frozen_string_literal_init(result->options); struct rb_stdin_wrapper wrapped_stdin = { rb_stdin, 0 }; - pm_buffer_t buffer; - pm_node_t *node = pm_parse_stream(&result->arena, &result->parser, &buffer, (void *) &wrapped_stdin, pm_parse_stdin_fgets, pm_parse_stdin_eof, &result->options); - - // Copy the allocated buffer contents into the input string so that it gets - // freed. At this point we've handed over ownership, so we don't need to - // free the buffer itself. - pm_string_owned_init(&result->input, (uint8_t *) pm_buffer_value(&buffer), pm_buffer_length(&buffer)); + result->source = pm_source_stream_new((void *) &wrapped_stdin, pm_parse_stdin_fgets, pm_parse_stdin_eof); + pm_node_t *node = pm_parse_stream(&result->parser, result->arena, result->source, result->options); // When we're done parsing, we reset $. because we don't want the fact that // we went through an IO object to be visible to the user. @@ -11663,10 +11689,11 @@ pm_parse_stdin(pm_parse_result_t *result) } #define PM_VERSION_FOR_RELEASE(major, minor) PM_VERSION_FOR_RELEASE_IMPL(major, minor) -#define PM_VERSION_FOR_RELEASE_IMPL(major, minor) PM_OPTIONS_VERSION_CRUBY_##major##_##minor +#define PM_VERSION_FOR_RELEASE_IMPL(major, minor) #major "." #minor void pm_options_version_for_current_ruby_set(pm_options_t *options) { - options->version = PM_VERSION_FOR_RELEASE(RUBY_API_VERSION_MAJOR, RUBY_API_VERSION_MINOR); + const char *version = PM_VERSION_FOR_RELEASE(RUBY_API_VERSION_MAJOR, RUBY_API_VERSION_MINOR); + pm_options_version_set(options, version, strlen(version)); } #undef NEW_ISEQ diff --git a/prism_compile.h b/prism_compile.h index 0b5fe685273a1e..09f611569db700 100644 --- a/prism_compile.h +++ b/prism_compile.h @@ -27,6 +27,9 @@ typedef struct pm_scope_node { pm_constant_id_list_t locals; const pm_parser_t *parser; + const pm_options_t *options; + const pm_line_offset_list_t *line_offsets; + int32_t start_line; rb_encoding *encoding; /** @@ -75,16 +78,16 @@ void pm_scope_node_destroy(pm_scope_node_t *scope_node); typedef struct { /** The arena allocator for AST-lifetime memory. */ - pm_arena_t arena; + pm_arena_t *arena; /** The parser that will do the actual parsing. */ - pm_parser_t parser; + pm_parser_t *parser; /** The options that will be passed to the parser. */ - pm_options_t options; + pm_options_t *options; - /** The input that represents the source to be parsed. */ - pm_string_t input; + /** The source backing the parse (file, string, or stream). */ + pm_source_t *source; /** The resulting scope node that will hold the generated AST. */ pm_scope_node_t node; @@ -99,6 +102,7 @@ typedef struct { #define PM_CONSTANT_MULT ((pm_constant_id_t)(idMULT | PM_SPECIAL_CONSTANT_FLAG)) #define PM_CONSTANT_POW ((pm_constant_id_t)(idPow | PM_SPECIAL_CONSTANT_FLAG)) +void pm_parse_result_init(pm_parse_result_t *result); VALUE pm_load_file(pm_parse_result_t *result, VALUE filepath, bool load_error); VALUE pm_parse_file(pm_parse_result_t *result, VALUE filepath, VALUE *script_lines); VALUE pm_load_parse_file(pm_parse_result_t *result, VALUE filepath, VALUE *script_lines); diff --git a/ruby.c b/ruby.c index 105657c2206683..f9f50e99eac889 100644 --- a/ruby.c +++ b/ruby.c @@ -2181,10 +2181,8 @@ prism_script_shebang_callback(pm_options_t *options, const uint8_t *source, size static void prism_script(ruby_cmdline_options_t *opt, pm_parse_result_t *result) { - memset(result, 0, sizeof(pm_parse_result_t)); - - pm_options_t *options = &result->options; - pm_options_line_set(options, 1); + pm_parse_result_init(result); + pm_options_t *options = result->options; pm_options_main_script_set(options, true); const bool read_stdin = (strcmp(opt->script, "-") == 0); @@ -2210,7 +2208,7 @@ prism_script(ruby_cmdline_options_t *opt, pm_parse_result_t *result) // If we found an __END__ marker, then we're going to define a global // DATA constant that is a file object that can be read to read the // contents after the marker. - if (NIL_P(error) && result->parser.data_loc.length != 0) { + if (NIL_P(error) && pm_parser_data_loc(result->parser)->length != 0) { rb_define_global_const("DATA", rb_stdin); } } @@ -2247,15 +2245,18 @@ prism_script(ruby_cmdline_options_t *opt, pm_parse_result_t *result) // If we found an __END__ marker, then we're going to define a global // DATA constant that is a file object that can be read to read the // contents after the marker. - if (NIL_P(error) && result->parser.data_loc.length != 0) { + if (NIL_P(error) && pm_parser_data_loc(result->parser)->length != 0) { int xflag = opt->xflag; VALUE file = open_load_file(script_name, &xflag); - const pm_parser_t *parser = &result->parser; - uint32_t offset = parser->data_loc.start + 7; + const pm_parser_t *parser = result->parser; + const pm_location_t *data_loc = pm_parser_data_loc(parser); + const uint8_t *start = pm_parser_start(parser); + const uint8_t *end = pm_parser_end(parser); + uint32_t offset = data_loc->start + 7; - if ((parser->start + offset < parser->end) && parser->start[offset] == '\r') offset++; - if ((parser->start + offset < parser->end) && parser->start[offset] == '\n') offset++; + if ((start + offset < end) && start[offset] == '\r') offset++; + if ((start + offset < end) && start[offset] == '\n') offset++; rb_funcall(file, rb_intern_const("seek"), 2, UINT2NUM(offset), INT2FIX(SEEK_SET)); rb_define_global_const("DATA", file); @@ -2271,11 +2272,11 @@ prism_script(ruby_cmdline_options_t *opt, pm_parse_result_t *result) static VALUE prism_dump_tree(pm_parse_result_t *result) { - pm_buffer_t output_buffer = { 0 }; + pm_buffer_t *output_buffer = pm_buffer_new(); - pm_prettyprint(&output_buffer, &result->parser, result->node.ast_node); - VALUE tree = rb_str_new(output_buffer.value, output_buffer.length); - pm_buffer_free(&output_buffer); + pm_prettyprint(output_buffer, result->parser, result->node.ast_node); + VALUE tree = rb_str_new(pm_buffer_value(output_buffer), pm_buffer_length(output_buffer)); + pm_buffer_free(output_buffer); return tree; } diff --git a/test/rubygems/test_gem_version.rb b/test/rubygems/test_gem_version.rb index 3987c620d0a74d..7ad085d480186e 100644 --- a/test/rubygems/test_gem_version.rb +++ b/test/rubygems/test_gem_version.rb @@ -200,6 +200,37 @@ def test_semver assert_less_than "1.0.0-1", "1" end + def test_sort_key_is_computed_on_regular_release + refute_nil v("9.8.7").send(:sort_key) + end + + def test_sort_key_is_computed_on_security_release + refute_nil v("9.8.7.1").send(:sort_key) + end + + def test_sort_key_is_not_computed_on_prerelease + assert_nil v("9.8.7.pre1").send(:sort_key) + end + + def test_sort_key_is_not_computed_on_version_with_more_segments + assert_nil v("1.1.1.1.1.1.1").send(:sort_key) + end + + def test_sort_key_is_not_computed_on_huge_numbers + assert_nil v("2.30.1.250000").send(:sort_key) + end + + def test_sort_key_is_used_for_comparison + a = v("18.0.1") + b = v("18.0.2") + + # Ensure the slow path isn't getting hit + a.instance_variable_set(:@version, nil) + a.instance_variable_set(:@canonical_segments, nil) + + assert_operator(a, :<, b) + end + # modifying the segments of a version should not affect the segments of the cached version object def test_segments v("9.8.7").segments[2] += 1 diff --git a/thread_pthread.c b/thread_pthread.c index 9f6707ae5d1f3c..7ccb6aca60242b 100644 --- a/thread_pthread.c +++ b/thread_pthread.c @@ -1556,6 +1556,8 @@ get_native_thread_id(void) #endif #if defined(HAVE_WORKING_FORK) +void rb_internal_thread_event_hooks_rw_lock_atfork(void); + static void thread_sched_atfork(struct rb_thread_sched *sched) { @@ -1587,6 +1589,8 @@ thread_sched_atfork(struct rb_thread_sched *sched) ccan_list_head_init(&vm->ractor.sched.timeslice_threads); ccan_list_head_init(&vm->ractor.sched.running_threads); + rb_internal_thread_event_hooks_rw_lock_atfork(); + VM_ASSERT(sched->is_running); sched->is_running_timeslice = false; @@ -3390,6 +3394,22 @@ struct rb_internal_thread_event_hook { static pthread_rwlock_t rb_internal_thread_event_hooks_rw_lock = PTHREAD_RWLOCK_INITIALIZER; +#if defined(HAVE_WORKING_FORK) +void +rb_internal_thread_event_hooks_rw_lock_atfork(void) +{ + // After fork(), this rwlock may have been held by a now-dead thread. + // + // pthread_rwlock_destroy() on a held lock is undefined behavior, and + // pthread_rwlock_init() on an already-initialized lock is also undefined + // behavior + // + // Direct assignment of PTHREAD_RWLOCK_INITIALIZER is safe and portable. + rb_internal_thread_event_hooks_rw_lock = + (pthread_rwlock_t)PTHREAD_RWLOCK_INITIALIZER; +} +#endif + rb_internal_thread_event_hook_t * rb_internal_thread_add_event_hook(rb_internal_thread_event_callback callback, rb_event_flag_t internal_event, void *user_data) { diff --git a/tool/dump_ast.c b/tool/dump_ast.c index 593ecce8c44215..cd7bcb84748739 100644 --- a/tool/dump_ast.c +++ b/tool/dump_ast.c @@ -1,5 +1,7 @@ +#include #include #include +#include /* * When prism is compiled as part of CRuby, the xmalloc/xfree/etc. macros are @@ -14,6 +16,15 @@ void ruby_xfree(void *ptr) { free(ptr); } #include "prism.h" +static void +print_error(const pm_diagnostic_t *diagnostic, void *data) +{ + const pm_parser_t *parser = (const pm_parser_t *) data; + pm_location_t loc = pm_diagnostic_location(diagnostic); + const pm_line_column_t line_column = pm_line_offset_list_line_column(pm_parser_line_offsets(parser), loc.start, pm_parser_start_line(parser)); + fprintf(stderr, "%" PRIi32 ":%" PRIu32 ":%s\n", line_column.line, line_column.column, pm_diagnostic_message(diagnostic)); +} + int main(int argc, const char *argv[]) { if (argc != 2) { @@ -22,43 +33,43 @@ main(int argc, const char *argv[]) { } const char *filepath = argv[1]; - pm_string_t input; + pm_source_init_result_t init_result; + pm_source_t *source = pm_source_mapped_new(filepath, 0, &init_result); - if (pm_string_mapped_init(&input, filepath) != PM_STRING_INIT_SUCCESS) { + if (init_result != PM_SOURCE_INIT_SUCCESS) + { fprintf(stderr, "unable to map file: %s\n", filepath); return EXIT_FAILURE; } - pm_options_t options = { 0 }; - pm_options_line_set(&options, 1); - pm_options_filepath_set(&options, filepath); + pm_options_t *options = pm_options_new(); + pm_options_line_set(options, 1); + pm_options_filepath_set(options, filepath); - pm_arena_t arena = { 0 }; - pm_parser_t parser; - pm_parser_init(&arena, &parser, pm_string_source(&input), pm_string_length(&input), &options); + pm_arena_t *arena = pm_arena_new(); + pm_parser_t *parser = pm_parser_new(arena, pm_source_source(source), pm_source_length(source), options); - pm_node_t *node = pm_parse(&parser); + pm_node_t *node = pm_parse(parser); int exit_status; - if (parser.error_list.size > 0) { + if (pm_parser_errors_size(parser) > 0) + { fprintf(stderr, "error parsing %s\n", filepath); - for (const pm_diagnostic_t *diagnostic = (const pm_diagnostic_t *) parser.error_list.head; diagnostic != NULL; diagnostic = (const pm_diagnostic_t *) diagnostic->node.next) { - const pm_line_column_t line_column = pm_line_offset_list_line_column(&parser.line_offsets, diagnostic->location.start, parser.start_line); - fprintf(stderr, "%" PRIi32 ":%" PRIu32 ":%s\n", line_column.line, line_column.column, diagnostic->message); - } + pm_parser_errors_each(parser, print_error, parser); exit_status = EXIT_FAILURE; - } else { - pm_buffer_t json = { 0 }; - pm_dump_json(&json, &parser, node); - printf("%.*s\n", (int) pm_buffer_length(&json), pm_buffer_value(&json)); - pm_buffer_free(&json); + } + else { + pm_buffer_t *json = pm_buffer_new(); + pm_dump_json(json, parser, node); + printf("%.*s\n", (int) pm_buffer_length(json), pm_buffer_value(json)); + pm_buffer_free(json); exit_status = EXIT_SUCCESS; } - pm_parser_free(&parser); - pm_arena_free(&arena); - pm_string_free(&input); - pm_options_free(&options); + pm_parser_free(parser); + pm_arena_free(arena); + pm_source_free(source); + pm_options_free(options); return exit_status; } diff --git a/tool/update-bundled_gems.rb b/tool/update-bundled_gems.rb index dec6b49ceede9b..c25ec6e08a10a0 100755 --- a/tool/update-bundled_gems.rb +++ b/tool/update-bundled_gems.rb @@ -4,12 +4,15 @@ date = nil # STDOUT is not usable in inplace edit mode output = $-i ? STDOUT : STDERR + # Gems to skip auto-updating (e.g. when a new major version breaks CI) + pinned = %w[rbs] } output = STDERR if ARGF.file == STDIN END { output.print date.strftime("latest_date=%F") if date } if gem = $F[0] + next if pinned.include?(gem) ver = Gem::Version.new($F[1]) (gem, src), = Gem::SpecFetcher.fetcher.detect(:latest) {|s| s.platform == "ruby" && s.name == gem diff --git a/vm_eval.c b/vm_eval.c index 7370af4b314ae8..4216ec56f33291 100644 --- a/vm_eval.c +++ b/vm_eval.c @@ -1717,16 +1717,17 @@ pm_eval_make_iseq(VALUE src, VALUE fname, int line, coverage_enabled = 0; } - pm_parse_result_t result = { 0 }; - pm_options_line_set(&result.options, line); + pm_parse_result_t result; + pm_parse_result_init(&result); + pm_options_line_set(result.options, line); result.node.coverage_enabled = coverage_enabled; - // Cout scopes, one for each parent iseq, plus one for our local scope + // Count scopes, one for each parent iseq, plus one for our local scope int scopes_count = 0; do { scopes_count++; } while ((iseq = ISEQ_BODY(iseq)->parent_iseq)); - pm_options_scopes_init(&result.options, scopes_count + 1); + pm_options_scopes_init(result.options, scopes_count + 1); // Walk over the scope tree, adding known locals at the correct depths. The // scope array should be deepest -> shallowest. so lower indexes in the @@ -1748,13 +1749,13 @@ pm_eval_make_iseq(VALUE src, VALUE fname, int line, VALUE iseq_value = (VALUE)iseq; int locals_count = ISEQ_BODY(iseq)->local_table_size; - pm_options_scope_t *options_scope = &result.options.scopes[scopes_count - scopes_index - 1]; + pm_options_scope_t *options_scope = pm_options_scope_mut(result.options, scopes_count - scopes_index - 1); pm_options_scope_init(options_scope, locals_count); uint8_t forwarding = PM_OPTIONS_SCOPE_FORWARDING_NONE; for (int local_index = 0; local_index < locals_count; local_index++) { - pm_string_t *scope_local = &options_scope->locals[local_index]; + pm_string_t *scope_local = pm_options_scope_local_mut(options_scope, local_index); ID local = ISEQ_BODY(iseq)->local_table[local_index]; if (rb_is_local_id(local)) { @@ -1815,7 +1816,7 @@ pm_eval_make_iseq(VALUE src, VALUE fname, int line, // Add our empty local scope at the very end of the array for our eval // scope's locals. - pm_options_scope_init(&result.options.scopes[scopes_count], 0); + pm_options_scope_init(pm_options_scope_mut(result.options, scopes_count), 0); VALUE script_lines; VALUE error = pm_parse_string(&result, src, fname, ruby_vm_keep_script_lines ? &script_lines : NULL); @@ -1836,9 +1837,9 @@ pm_eval_make_iseq(VALUE src, VALUE fname, int line, pm_scope_node_t *parent_scope = ruby_xcalloc(1, sizeof(pm_scope_node_t)); RUBY_ASSERT(parent_scope != NULL); - pm_options_scope_t *options_scope = &result.options.scopes[scopes_count - scopes_index - 1]; + const pm_options_scope_t *options_scope = pm_options_scope(result.options, scopes_count - scopes_index - 1); parent_scope->coverage_enabled = coverage_enabled; - parent_scope->parser = &result.parser; + parent_scope->parser = result.parser; parent_scope->index_lookup_table = st_init_numtable(); int locals_count = ISEQ_BODY(iseq)->local_table_size; @@ -1846,7 +1847,7 @@ pm_eval_make_iseq(VALUE src, VALUE fname, int line, pm_constant_id_list_init(&parent_scope->locals); for (int local_index = 0; local_index < locals_count; local_index++) { - const pm_string_t *scope_local = &options_scope->locals[local_index]; + const pm_string_t *scope_local = pm_options_scope_local(options_scope, local_index); pm_constant_id_t constant_id = 0; const uint8_t *source = pm_string_source(scope_local); @@ -1868,18 +1869,18 @@ pm_eval_make_iseq(VALUE src, VALUE fname, int line, constant_id = PM_CONSTANT_DOT3; break; default: - constant_id = pm_constant_pool_insert_constant(&result.parser.metadata_arena, &result.parser.constant_pool, source, length); + constant_id = pm_parser_constant_find(result.parser, source, length); break; } } else { - constant_id = pm_constant_pool_insert_constant(&result.parser.metadata_arena, &result.parser.constant_pool, source, length); + constant_id = pm_parser_constant_find(result.parser, source, length); } st_insert(parent_scope->index_lookup_table, (st_data_t) constant_id, (st_data_t) local_index); } - pm_constant_id_list_append(&result.arena, &parent_scope->locals, constant_id); + pm_constant_id_list_append(result.arena, &parent_scope->locals, constant_id); } node->previous = parent_scope;