Ruby 4.1.0dev (2026-08-07 revision 3acc47d282230b3999b808578b8159c989953940)
dump_ast.c
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <inttypes.h>
5#include "revision.h"
6
7/*
8 * When prism is compiled as part of CRuby, the xmalloc/xfree/etc. macros are
9 * redirected to ruby_xmalloc/ruby_xfree/etc. Since this is a standalone
10 * program that links against those same object files, we need to provide
11 * implementations of these functions.
12 */
13void *ruby_xmalloc(size_t size) { return malloc(size); }
14void *ruby_xcalloc(size_t nelems, size_t elemsiz) { return calloc(nelems, elemsiz); }
15void *ruby_xrealloc(void *ptr, size_t newsiz) { return realloc(ptr, newsiz); }
16void ruby_xfree(void *ptr) { free(ptr); }
17void ruby_xfree_sized(void *ptr, size_t _oldsize) { free(ptr); }
18void *ruby_xrealloc_sized(void *ptr, size_t newsiz, size_t _oldsiz) { return realloc(ptr, newsiz); }
19
20#include "prism.h"
21
22static void
23print_error(const pm_diagnostic_t *diagnostic, void *data)
24{
25 const pm_parser_t *parser = (const pm_parser_t *) data;
26 pm_location_t loc = pm_diagnostic_location(diagnostic);
27 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));
28 fprintf(stderr, "%" PRIi32 ":%" PRIu32 ":%s\n", line_column.line, line_column.column, pm_diagnostic_message(diagnostic));
29}
30
31#if defined(RUBY_RELEASE_DATETIME) && defined(RUBY_RELEASE_DATETIME)
32# define SHOW_PROGRAM_VERSION 2
33#elif defined(RUBY_RELEASE_DATETIME) || defined(RUBY_RELEASE_DATETIME)
34# define SHOW_PROGRAM_VERSION 1
35#else
36# define SHOW_PROGRAM_VERSION 0
37#endif
38#if SHOW_PROGRAM_VERSION
39# define usage_versions "and program versions"
40#else
41# define usage_versions "version"
42#endif
43
44static void
45usage(const char *prog)
46{
47 fprintf(stderr, "Usage: %s [options]... <filename>\n"
48 "Options:\n"
49 " -v, --version: show Prism " usage_versions "\n"
50 " -h, --help: show this message\n"
51 "", prog);
52}
53
54int
55main(int argc, const char *argv[])
56{
57 const char *filepath = 0;
58
59 for (int i = 1; i < argc; ++i) {
60 const char *arg = argv[i];
61 if (arg[0] != '-') {
62 if (filepath) {
63 fprintf(stderr, "too many filename\n");
64 goto usage;
65 }
66 filepath = arg;
67 }
68 else if (arg[1] == '-') {
69 if (!arg[2]) break;
70 if (strcmp(arg + 2, "version") == 0) {
71 version:
72 fputs("Prism " PRISM_VERSION
73#if SHOW_PROGRAM_VERSION
74 " ["
75# ifdef RUBY_RELEASE_DATETIME
76 RUBY_RELEASE_DATETIME
77# endif
78# if SHOW_PROGRAM_VERSION > 1
79 " "
80# endif
81# ifdef RUBY_REVISION
82 RUBY_REVISION
83# endif
84 "]"
85#endif
86 "\n", stdout);
87 return EXIT_SUCCESS;
88 }
89 if (strcmp(arg + 2, "help") == 0) {
90 help:
91 usage(argv[0]);
92 return EXIT_SUCCESS;
93 }
94 fprintf(stderr, "unknown option %s\n", arg);
95 goto usage;
96 }
97 else {
98 while (*++arg) {
99 switch (*arg) {
100 case 'v':
101 goto version;
102 case 'h':
103 goto help;
104 default:
105 fprintf(stderr, "unknown option -%c\n", *arg);
106 goto usage;
107 }
108 }
109 }
110 }
111
112 if (!filepath) {
113 usage:
114 usage(argv[0]);
115 return EXIT_FAILURE;
116 }
117
118 pm_source_init_result_t init_result;
119 pm_source_t *source = pm_source_mapped_new(filepath, 0, &init_result);
120
121 if (init_result != PM_SOURCE_INIT_SUCCESS) {
122 fprintf(stderr, "unable to map file: %s\n", filepath);
123 return EXIT_FAILURE;
124 }
125
126 pm_options_t *options = pm_options_new();
127 pm_options_line_set(options, 1);
128 pm_options_filepath_set(options, filepath);
129
130 pm_arena_t *arena = pm_arena_new();
131 pm_parser_t *parser = pm_parser_new(arena, pm_source_source(source), pm_source_length(source), options);
132
133 pm_node_t *node = pm_parse(parser);
134 int exit_status;
135
136 if (pm_parser_errors_size(parser) > 0)
137 {
138 fprintf(stderr, "error parsing %s\n", filepath);
139 pm_parser_errors_each(parser, print_error, parser);
140 exit_status = EXIT_FAILURE;
141 }
142 else {
143 pm_buffer_t *json = pm_buffer_new();
144 pm_dump_json(json, parser, node);
145 printf("%.*s\n", (int) pm_buffer_length(json), pm_buffer_value(json));
146 pm_buffer_free(json);
147 exit_status = EXIT_SUCCESS;
148 }
149
150 pm_parser_free(parser);
151 pm_arena_free(arena);
152 pm_source_free(source);
153 pm_options_free(options);
154
155 return exit_status;
156}
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)
Allocate and initialize a parser with the given start and end pointers.
Definition prism.c:23133
PRISM_EXPORTED_FUNCTION void pm_parser_free(pm_parser_t *parser) PRISM_NONNULL(1)
Free both the memory held by the given parser and the parser itself.
Definition prism.c:23166
PRISM_EXPORTED_FUNCTION pm_node_t * pm_parse(pm_parser_t *parser) PRISM_NONNULL(1)
Initiate the parser with the given parser.
Definition prism.c:23337
#define PRISM_VERSION
The version of the Prism library as a constant string.
Definition version.h:29
The main header file for the prism parser.
pm_source_init_result_t
Represents the result of initializing a source from a file.
Definition source.h:46
@ PM_SOURCE_INIT_SUCCESS
Indicates that the source was successfully initialized.
Definition source.h:48
A line and column in a string.
uint32_t column
The column in bytes.
int32_t line
The line number.
This struct represents a slice in the source code, defined by an offset and a length.
Definition ast.h:569
uint32_t start
The offset of the location from the start of the source.
Definition ast.h:571
This is the base structure that represents a node in the syntax tree.
Definition ast.h:1080