Skip to content

Commit

Permalink
Start better documenting C API
Browse files Browse the repository at this point in the history
  • Loading branch information
kddnewton committed Nov 1, 2023
1 parent dfdcc98 commit 2b6e661
Show file tree
Hide file tree
Showing 8 changed files with 339 additions and 106 deletions.
39 changes: 39 additions & 0 deletions Doxyfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Doxyfile 1.9.5

# This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project.
#
# All text after a double hash (##) is considered a comment and is placed in
# front of the TAG it is preceding.
#
# All text after a single hash (#) is considered a comment and will be ignored.
# The format is:
# TAG = value [value, ...]
# For lists, items can also be appended using:
# TAG += value [value, ...]
# Values that contain spaces should be placed between quotes (\" \").
#
# Note:
#
# Use doxygen to compare the used configuration file with the template
# configuration file:
# doxygen -x [configFile]

# Non-default options
PROJECT_NAME = "Prism"
OUTPUT_DIRECTORY = doc
JAVADOC_AUTOBRIEF = YES
OPTIMIZE_OUTPUT_FOR_C = YES
EXTRACT_ALL = YES
INPUT = src src/enc src/util include include/prism include/prism/enc include/prism/util
HTML_OUTPUT = c

# Default options we might want to edit in the future
HTML_STYLESHEET =
HTML_COLORSTYLE = AUTO_LIGHT
GENERATE_LATEX = NO

# Default options we definitely want to edit in the future
WARN_IF_UNDOCUMENTED = NO
WARN_NO_PARAMDOC = NO
WARN_AS_ERROR = NO
6 changes: 5 additions & 1 deletion include/prism/diagnostic.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@
#include <stdlib.h>
#include <assert.h>

// This struct represents a diagnostic found during parsing.
/**
* This struct represents a diagnostic found during parsing.
*
* @extends pm_list_node_t
*/
typedef struct {
pm_list_node_t node;
const uint8_t *start;
Expand Down
14 changes: 11 additions & 3 deletions include/prism/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -243,16 +243,24 @@ typedef enum {
PM_COMMENT___END__
} pm_comment_type_t;

// This is a node in the linked list of comments that we've found while parsing.
/**
* This is a node in the linked list of comments that we've found while parsing.
*
* @extends pm_list_node_t
*/
typedef struct pm_comment {
pm_list_node_t node;
const uint8_t *start;
const uint8_t *end;
pm_comment_type_t type;
} pm_comment_t;

// This is a node in the linked list of magic comments that we've found while
// parsing.
/**
* This is a node in the linked list of magic comments that we've found while
* parsing.
*
* @extends pm_list_node_t
*/
typedef struct {
pm_list_node_t node;
const uint8_t *key_start;
Expand Down
78 changes: 58 additions & 20 deletions include/prism/util/pm_string.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,44 +19,82 @@ typedef struct {

#define PM_EMPTY_STRING ((pm_string_t) { .type = PM_STRING_CONSTANT, .source = NULL, .length = 0 })

// Initialize a shared string that is based on initial input.
/**
* Initialize a shared string that is based on initial input.
*
* @memberof pm_string_t
*/
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.
/**
* Initialize an owned string that is responsible for freeing allocated memory.
*
* @memberof pm_string_t
*/
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.
/**
* Initialize a constant string that doesn't own its memory source.
*
* @memberof pm_string_t
*/
void pm_string_constant_init(pm_string_t *string, const char *source, size_t length);

// 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`.
/**
* 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`.
*
* @memberof pm_string_t
*/
PRISM_EXPORTED_FUNCTION bool pm_string_mapped_init(pm_string_t *string, const char *filepath);

// Returns the memory size associated with the string.
/**
* Returns the memory size associated with the string.
*
* @memberof pm_string_t
*/
size_t pm_string_memsize(const pm_string_t *string);

// Ensure the string is owned. If it is not, then reinitialize it as owned and
// copy over the previous source.
/**
* Ensure the string is owned. If it is not, then reinitialize it as owned and
* copy over the previous source.
*
* @memberof pm_string_t
*/
void pm_string_ensure_owned(pm_string_t *string);

// Returns the length associated with the string.
/**
* Returns the length associated with the string.
*
* @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.
/**
* Returns the start pointer associated with the string.
*
* @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.
/**
* Free the associated memory of the given string.
*
* @memberof pm_string_t
*/
PRISM_EXPORTED_FUNCTION void pm_string_free(pm_string_t *string);

// Returns the size of the pm_string_t struct. This is necessary to allocate the
// correct amount of memory in the FFI backend.
/**
* 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);

#endif // PRISM_STRING_H
2 changes: 1 addition & 1 deletion rakelib/rdoc.rake
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ require "rdoc/task"
RDoc::Task.new do |rdoc|
rdoc.main = "README.md"
rdoc.markup = "markdown"
rdoc.rdoc_dir = "doc"
rdoc.rdoc_dir = "doc/ruby"

rdoc.options << "--all"
rdoc.options << "--coverage-report"
Expand Down
103 changes: 102 additions & 1 deletion src/prism.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,104 @@
#include "prism.h"

/**
* @mainpage
*
* Prism is a parser for the Ruby programming language. It is designed to be
* portable, error tolerant, and maintainable. It is written in C99 and has no
* dependencies. It is currently being integrated into
* [CRuby](https://github.com/ruby/ruby),
* [JRuby](https://github.com/jruby/jruby),
* [TruffleRuby](https://github.com/oracle/truffleruby),
* [Sorbet](https://github.com/sorbet/sorbet), and
* [Syntax Tree](https://github.com/ruby-syntax-tree/syntax_tree).
*
* @section getting-started Getting started
*
* If you're vendoring this project and compiling it statically then as long as
* you have a C99 compiler you will be fine. If you're linking against it as
* shared library, then you should compile with `-fvisibility=hidden` and
* `-DPRISM_EXPORT_SYMBOLS` to tell prism to make only its public interface
* visible.
*
* @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:
*
* * @ref pm_parser_t - the main parser structure
* * @ref pm_parser_init - initialize a parser
* * @ref pm_parse - parse and return the root node
* * @ref pm_node_destroy - deallocate the root node returned by `pm_parse`
* * @ref pm_parser_free - free the internal memory of the parser
*
* Putting all of this together would look something like:
*
* ```c
* void parse(const uint8_t *source, size_t length) {
* pm_parser_t parser;
* pm_parser_init(&parser, source, length, NULL);
*
* pm_node_t *root = pm_parse(&parser);
* printf("PARSED!\n");
*
* pm_node_destroy(root);
* pm_parser_free(&parser);
* }
* ```
*
* All of the nodes "inherit" from `pm_node_t` by embedding those structures as
* their first member. This means you can downcast and upcast any node in the
* tree to a `pm_node_t`.
*
* @section serializing Serializing
*
* 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:
*
* * @ref pm_buffer_t - a small buffer object that will hold the serialized AST
* * @ref pm_buffer_free - free the memory associated with the buffer
* * @ref pm_serialize - serialize the AST into a buffer
* * @ref pm_parse_serialize - 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_parse_serialize(source, length, &buffer, NULL);
* printf("SERIALIZED!\n");
*
* pm_buffer_free(&buffer);
* }
* ```
*
* @section inspecting Inspecting
*
* Prism provides the ability to inspect the AST by pretty-printing nodes. You
* can do this with the `pm_prettyprint` function, which you would use like:
*
* ```c
* void prettyprint(const uint8_t *source, size_t length) {
* pm_parser_t parser;
* pm_parser_init(&parser, source, length, NULL);
*
* pm_node_t *root = pm_parse(&parser);
* pm_buffer_t buffer = { 0 };
*
* pm_prettyprint(&buffer, &parser, root);
* printf("*.s%\n", (int) buffer.length, buffer.value);
*
* pm_buffer_free(&buffer);
* pm_node_destroy(root);
* pm_parser_free(&parser);
* }
* ```
*/

// The prism version and the serialization format.
const char *
pm_version(void) {
Expand Down Expand Up @@ -15716,7 +15815,9 @@ pm_parser_free(pm_parser_t *parser) {
}
}

// Parse the Ruby source associated with the given parser and return the tree.
/**
* Parse the Ruby source associated with the given parser and return the tree.
*/
PRISM_EXPORTED_FUNCTION pm_node_t *
pm_parse(pm_parser_t *parser) {
return parse_program(parser);
Expand Down
Loading

0 comments on commit 2b6e661

Please sign in to comment.