Early work on an Include block.
This commit is contained in:
parent
3b7077e761
commit
d4bb08efea
1
docs/.eleventyignore
Normal file
1
docs/.eleventyignore
Normal file
@ -0,0 +1 @@
|
|||||||
|
/**/*.inc.tce
|
7
docs/src/_includes/nodes/Include.njk
Normal file
7
docs/src/_includes/nodes/Include.njk
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{% from "./Node.njk" import Node %}
|
||||||
|
|
||||||
|
{% macro render(node, page) %}
|
||||||
|
{% for child in node.children %}
|
||||||
|
{{ Node(child.type, child, page) }}
|
||||||
|
{% endfor %}
|
||||||
|
{% endmacro %}
|
@ -1,435 +0,0 @@
|
|||||||
layout layout.njk
|
|
||||||
title C Documentation - Terrace
|
|
||||||
description
|
|
||||||
C language documentation for the Terrace programming language
|
|
||||||
|
|
||||||
Section light
|
|
||||||
class flex flex-col md:flex-row gap-16
|
|
||||||
|
|
||||||
Block
|
|
||||||
class w-full lg:w-1/3
|
|
||||||
TableOfContents
|
|
||||||
|
|
||||||
Block
|
|
||||||
Heading 1 Terrace C Documentation
|
|
||||||
class -ml-2
|
|
||||||
|
|
||||||
Markdown
|
|
||||||
Documentation is available for the following languages:
|
|
||||||
- [C](/docs/c/) - 75% Complete
|
|
||||||
- [JavaScript](/docs/javascript/) - 75% Complete
|
|
||||||
- [Python](/docs/python/) - 0% Complete
|
|
||||||
|
|
||||||
Heading 2 Getting Started
|
|
||||||
class mt-12 mb-6
|
|
||||||
Markdown
|
|
||||||
The terrace parser is distributed as a set of C header files.<br/>
|
|
||||||
To use it, download and include the following files in your project tree:
|
|
||||||
- [parser.h](https://git.thederf.com/thederf/Terrace/src/branch/main/packages/c/parser.h) - Core terrace parser
|
|
||||||
- [document.h](https://git.thederf.com/thederf/Terrace/src/branch/main/packages/c/document.h) - (optional) Convenience functions for parsing of documents
|
|
||||||
|
|
||||||
A simple example program using to read each line from stdin and output parser information, looking for a "title" key:
|
|
||||||
CodeBlock c
|
|
||||||
// Provides getline() for reading from stdin
|
|
||||||
#include <stdio.h>
|
|
||||||
// Provides free() for deallocating the lines from getline()
|
|
||||||
#include <stdlib.h>
|
|
||||||
// Provides document API for interacting with Terrace files
|
|
||||||
#include "document.h"
|
|
||||||
|
|
||||||
// Custom userData struct. Stores information needed
|
|
||||||
// by read_line below.
|
|
||||||
typedef struct read_line_container_s {
|
|
||||||
size_t bufsize;
|
|
||||||
} read_line_container_t;
|
|
||||||
|
|
||||||
// A user-supplied function to read lines from stdin (or whichever data source you choose)
|
|
||||||
int read_line_from_stdin(char** line, void* userData) {
|
|
||||||
read_line_container_t* lineContainer = (read_line_container_t*) userData;
|
|
||||||
// Uses getline from the C stdlib to read the next line from stdin.
|
|
||||||
int num_chars_read = getline(line, &lineContainer->bufsize, stdin);
|
|
||||||
// Change trailing newline to null char. Terrace doesn't use trailing newlines
|
|
||||||
if (num_chars_read > 0) (*line)[num_chars_read - 1] = '\0';
|
|
||||||
// Return the number of charaters read to the document parser.
|
|
||||||
return num_chars_read;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
|
||||||
read_line_container_t read_line_information = { .bufsize = 64 };
|
|
||||||
// Initialize the terrace document with the line reader function created above.
|
|
||||||
terrace_document_t doc = terrace_create_document(' ', &read_line_from_stdin, &read_line_information);
|
|
||||||
|
|
||||||
// Loop over every line in the document.
|
|
||||||
while(terrace_next(&doc, -1)) {
|
|
||||||
// > Replace with your custom line handling code.
|
|
||||||
|
|
||||||
// Print the line and level to demonstrate the terrace_level and terrace_line functions.
|
|
||||||
printf("| level %u | line %s |", terrace_level(&doc), terrace_line(&doc, -1));
|
|
||||||
// If one of the lines starts with "title", output it.
|
|
||||||
if (terrace_match(&doc, "title")) {
|
|
||||||
printf("Title: %s |", terrace_tail(&doc));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Free allocated line memory
|
|
||||||
free(line);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Markdown
|
|
||||||
|
|
||||||
Heading 2 Core API
|
|
||||||
class mt-12
|
|
||||||
Markdown
|
|
||||||
**Note:** The Core API is designed for maximum portability and is not intended to be directly consumed.
|
|
||||||
|
|
||||||
For most projects you'll want to use the [Document API](#document-api) instead.
|
|
||||||
It provides an ergonomic wrapper around the Core API and lets you focus on parsing
|
|
||||||
your documents.
|
|
||||||
|
|
||||||
Heading 3 terrace_linedata_t
|
|
||||||
class mb-4 mt-12
|
|
||||||
Markdown
|
|
||||||
This struct holds information about each line as it is parsed. Mutated each time [terrace_parse_line()](#terrace-parse-line) is called. Not intended to be used directly.
|
|
||||||
Use the relevant `terrace_` functions from the [Document API](#document-api) instead.
|
|
||||||
CodeBlock c
|
|
||||||
// Holds the parsed information from each line.
|
|
||||||
typedef struct terrace_linedata_s {
|
|
||||||
// Which character is being used for indentation. Avoids having to specify it on each terrace_parse_line call.
|
|
||||||
char indent;
|
|
||||||
// How many indent characters are present in the current line before the first non-indent character.
|
|
||||||
unsigned int level;
|
|
||||||
// The number of characters before the start of the line's "head" section.
|
|
||||||
// (Normally the same as `level`)
|
|
||||||
unsigned int offsetHead;
|
|
||||||
// The number of characters before the start of the line's "tail" section.
|
|
||||||
unsigned int offsetTail;
|
|
||||||
} terrace_linedata_t;
|
|
||||||
|
|
||||||
Heading 3 terrace_create_linedata()
|
|
||||||
class mb-4 mt-12
|
|
||||||
Markdown
|
|
||||||
| Parameter | Type | Description
|
|
||||||
| -------------- | --------------------- | -----------------------------------------------------------------------
|
|
||||||
| indent | const char | The character used for indentation in the document. Only a single character is permitted.
|
|
||||||
| **@returns** | [terrace_linedata_t](#terrace-linedatat) | A terrace_linedata_t struct with the specified indent character and all other values initialized to 0.
|
|
||||||
|
|
||||||
Initialize a [terrace_linedata](#terrace-linedatat) struct with default values to pass to [terrace_parse_line()](#terrace-parse-line).
|
|
||||||
CodeBlock c
|
|
||||||
// Call Signature
|
|
||||||
terrace_linedata_t terrace_create_linedata(const char indent)
|
|
||||||
Heading 3 terrace_parse_line()
|
|
||||||
class mb-4 mt-12
|
|
||||||
Markdown
|
|
||||||
| Parameter | Type | Description
|
|
||||||
| -------------- | --------------------- | -----------------------------------------------------------------------
|
|
||||||
| line | char* | A pointer to the line to parse as a C-style string. Shouldn't end with a newline.
|
|
||||||
| lineData | [terrace_linedata_t](#terrace-linedatat)* | A pointer to the terrace_linedata_t struct to store information about the current line in.
|
|
||||||
|
|
||||||
Core Terrace parser function, sets `level`, `offsetHead`, and `offsetTail` in a [terrace_linedata](#terrace-linedatat) struct based on the current line.
|
|
||||||
CodeBlock c
|
|
||||||
// Call Signature
|
|
||||||
void terrace_parse_line(const char* line, terrace_linedata_t* lineData)
|
|
||||||
|
|
||||||
Heading 2 Document API
|
|
||||||
class mt-12
|
|
||||||
|
|
||||||
Heading 3 terrace_document_t
|
|
||||||
class mb-4 mt-12
|
|
||||||
Markdown
|
|
||||||
Tracks state of a document while being parsed.
|
|
||||||
Obtained from [terrace_create_document()](#terrace-create-document) below
|
|
||||||
CodeBlock c
|
|
||||||
// Type Definition
|
|
||||||
typedef struct terrace_document_s {
|
|
||||||
// == Internal State == //
|
|
||||||
unsigned int _repeatCurrentLine;
|
|
||||||
// Current line being read
|
|
||||||
char* _currentLine;
|
|
||||||
|
|
||||||
// == External Information == //
|
|
||||||
// Embedded line data struct. Holds information about the current parsed line
|
|
||||||
terrace_linedata_t lineData;
|
|
||||||
// Custom data passed to the readline function
|
|
||||||
void* userData;
|
|
||||||
/**
|
|
||||||
* Line reader function, provided by the user
|
|
||||||
* Needed to get the next line inside of `terrace_next(doc)`
|
|
||||||
* @param {char**} line First argument is a pointer to `_currentLine`, above
|
|
||||||
* @param {void*} userData Second argument is `userData`, above
|
|
||||||
* @returns {int} The number of characters read, or -1 if no characters were read.
|
|
||||||
*/
|
|
||||||
int (*reader)(char** line, void* userData);
|
|
||||||
} terrace_document_t;
|
|
||||||
|
|
||||||
Heading 3 terrace_create_document()
|
|
||||||
class mb-4 mt-12
|
|
||||||
Markdown
|
|
||||||
| Parameter | Type | Description
|
|
||||||
| -------------- | --------------------- | -----------------------------------------------------------------------
|
|
||||||
| indent | const char | The indent character to use. Generally a single space character.
|
|
||||||
| reader | int (\*reader)(char** line, void* userData) | A function pointer to a function that reads lines sequentially from a user-provided source. Receives a pointer to `lineData->_currLine`, and `userData`, supplied in the next argument.
|
|
||||||
| userData | void * | A user-supplied pointer to any state information needed by their reader function. Passed to `reader`each time it is called.
|
|
||||||
| **@returns** | [terrace_document_t](#terrace-documentt) | A state struct needed by the convenience functions below.
|
|
||||||
|
|
||||||
Initializes the state needed for the convenience functions below. Takes a user-supplied `reader` function to read each line from a user-determined source.
|
|
||||||
CodeBlock c
|
|
||||||
// Call Signature
|
|
||||||
terrace_document_t terrace_create_document(const char indent, int (*reader)(char** line, void* userData), void* userData)
|
|
||||||
|
|
||||||
Heading 3 terrace_next()
|
|
||||||
class mb-4 mt-12
|
|
||||||
|
|
||||||
Markdown
|
|
||||||
| Parameter | Type | Description
|
|
||||||
| -------------- | --------------------- | -----------------------------------------------------------------------
|
|
||||||
| doc | [terrace_document_t*](#terrace-documentt) | A pointer to the current document state struct.
|
|
||||||
| levelScope | int | If set above -1, `next()` will return `0` when it encounters a line with a level at or below `levelScope`
|
|
||||||
| **@returns** | char | Returns `1` after parsing a line, or `0` if the document has ended or a line at or below `levelScope` has been encountered.
|
|
||||||
|
|
||||||
Advances the current position in the terrace document and populates lineData
|
|
||||||
with the parsed information from that line.
|
|
||||||
|
|
||||||
Returns `1` after parsing the next line, or `0` upon reaching the end of the document.
|
|
||||||
If the `levelScope` parameter is not -1, `terrace_next()` will also return `0` when it encounters a line
|
|
||||||
with a level at or below `levelScope`. This allows you to iterate through subsections of a document.
|
|
||||||
|
|
||||||
If a lower-level line was encountered, the following call to `terrace_next()` will repeat this line again.
|
|
||||||
This allows a child loop to look forward, determine that the next line will be outside its purview,
|
|
||||||
and return control to the calling loop transparently without additional logic.
|
|
||||||
|
|
||||||
Intended to be used inside a while loop to parse a section of a Terrace document.
|
|
||||||
|
|
||||||
CodeBlock c
|
|
||||||
// Call Signature
|
|
||||||
char terrace_next(terrace_document_t* doc, int levelScope)
|
|
||||||
|
|
||||||
// Usage
|
|
||||||
while(terrace_next(doc, -1)) {
|
|
||||||
// Do something with each line.
|
|
||||||
}
|
|
||||||
|
|
||||||
Heading 3 terrace_level()
|
|
||||||
class mb-4 mt-12
|
|
||||||
Markdown
|
|
||||||
| Parameter | Type | Description
|
|
||||||
| -------------- | --------------------- | -----------------------------------------------------------------------
|
|
||||||
| doc | [terrace_document_t*](#terrace-documentt) | A pointer to the current document state struct.
|
|
||||||
| **@returns** | unsigned int | The indent level of the current line
|
|
||||||
|
|
||||||
Returns the number of indent characters of the current line.
|
|
||||||
|
|
||||||
Given the following document, `terrace_level(doc)` would return 0, 1, 2, and 5 respectively for each line.
|
|
||||||
CodeBlock terrace
|
|
||||||
block
|
|
||||||
block
|
|
||||||
block
|
|
||||||
block
|
|
||||||
|
|
||||||
CodeBlock c
|
|
||||||
// Call Signature
|
|
||||||
unsigned int terrace_level(terrace_document_t* doc)
|
|
||||||
|
|
||||||
// Usage
|
|
||||||
while(terrace_next(doc, -1)) {
|
|
||||||
printf("Indent Level: %u", terrace_level(doc));
|
|
||||||
}
|
|
||||||
|
|
||||||
Heading 3 terrace_line()
|
|
||||||
class mb-4 mt-12
|
|
||||||
Markdown
|
|
||||||
| Parameter | Type | Description
|
|
||||||
| -------------- | --------------------- | -----------------------------------------------------------------------
|
|
||||||
| doc | [terrace_document_t*](#terrace-documentt) | A pointer to the current document state struct.
|
|
||||||
| startOffset | int | How many indent characters to skip before outputting the line contents. If set to -1, uses the current indent level.
|
|
||||||
| **@returns** | char* | The line contents starting from `startOffset`
|
|
||||||
|
|
||||||
Get a string with the current line contents.
|
|
||||||
If `startOffset` is -1, skips all indent characters by default. Otherwise only skips the amount specified.
|
|
||||||
|
|
||||||
Given the following document
|
|
||||||
CodeBlock terrace
|
|
||||||
root
|
|
||||||
sub-line
|
|
||||||
Markdown
|
|
||||||
- Calling `terrace_line(doc, -1)` on the second line returns "sub-line", trimming off the leading indent characters.
|
|
||||||
- Calling `terrace_line(doc, 0)` however, returns " sub-line", with all four leading spaces.
|
|
||||||
|
|
||||||
`startOffset`s other than `-1` are primarily used for parsing blocks that have literal indented multi-line text
|
|
||||||
|
|
||||||
CodeBlock c
|
|
||||||
// Call Signature
|
|
||||||
char* terrace_line(terrace_document_t* doc, int startOffset)
|
|
||||||
|
|
||||||
// Usage
|
|
||||||
while(terrace_next(doc, -1)) {
|
|
||||||
printf("Line with indent characters: %s", terrace_line(doc, 0));
|
|
||||||
printf("Line without indent characters: %s", terrace_line(doc, -1));
|
|
||||||
}
|
|
||||||
|
|
||||||
Heading 3 terrace_head_length()
|
|
||||||
class mb-4 mt-12
|
|
||||||
Markdown
|
|
||||||
| Parameter | Type | Description
|
|
||||||
| -------------- | --------------------- | -----------------------------------------------------------------------
|
|
||||||
| doc | [terrace_document_t*](#terrace-documentt) | A pointer to the current document state struct.
|
|
||||||
| **@returns** | unsigned int | The length of the `head` portion (first word) of a line
|
|
||||||
|
|
||||||
Get the *length* of the first "word" of a line,
|
|
||||||
starting from the first non-indent character to the first space or end of the line
|
|
||||||
Often used for deciding how to parse a block.
|
|
||||||
|
|
||||||
Because C uses NULL-terminated strings, we cannot easily slice a string to return something out of the middle.
|
|
||||||
Instead, `terrace_head_length()` provides the length of the head portion.
|
|
||||||
In combination with `doc->lineData.offsetHead`, you can copy the head section into a new string,
|
|
||||||
or use any number of `strn*` C stdlib functions to work with the head section without copying it.
|
|
||||||
|
|
||||||
Terrace DSLs do not *need* to use head-tail line structure, but support for them is built into the parser
|
|
||||||
|
|
||||||
Given the following line, `terrace_head_length(doc)` returns `5`
|
|
||||||
CodeBlock terrace
|
|
||||||
title An Important Document
|
|
||||||
CodeBlock c
|
|
||||||
// Call Signature
|
|
||||||
unsigned int terrace_head_length(terrace_document_t* doc)
|
|
||||||
|
|
||||||
// Usage
|
|
||||||
while(terrace_next(doc, -1)) {
|
|
||||||
printf("Head length: %u", terrace_head_length(doc));
|
|
||||||
}
|
|
||||||
|
|
||||||
Heading 3 terrace_tail()
|
|
||||||
class mb-4 mt-12
|
|
||||||
Markdown
|
|
||||||
| Parameter | Type | Description
|
|
||||||
| -------------- | --------------------- | -----------------------------------------------------------------------
|
|
||||||
| doc | [terrace_document_t*](#terrace-documentt) | A pointer to the current document state struct.
|
|
||||||
| **@returns** | char* | The remainder of the line following the `head` portion, with no leading space.
|
|
||||||
|
|
||||||
Get a char pointer to everything following the first "word" of a line,
|
|
||||||
starting from the first character after the space at the end of `head`.
|
|
||||||
|
|
||||||
Terrace DSLs do not *need* to use head-tail line structure, but support for them is built into the parser
|
|
||||||
|
|
||||||
Given the following line, `terrace_tail(doc)` returns "An Important Document"
|
|
||||||
CodeBlock terrace
|
|
||||||
title An Important Document
|
|
||||||
CodeBlock c
|
|
||||||
// Call Signature
|
|
||||||
char* terrace_tail(terrace_document_t* doc)
|
|
||||||
|
|
||||||
// Usage
|
|
||||||
while(terrace_next(doc, -1)) {
|
|
||||||
printf("Line tail: %s", terrace_tail(doc));
|
|
||||||
}
|
|
||||||
|
|
||||||
Heading 3 terrace_match()
|
|
||||||
class mb-4 mt-12
|
|
||||||
Markdown
|
|
||||||
| Parameter | Type | Description
|
|
||||||
| -------------- | --------------------- | -----------------------------------------------------------------------
|
|
||||||
| doc | [terrace_document_t*](#terrace-documentt) | A pointer to the current document state struct.
|
|
||||||
| matchValue | const char* | A string to check against the line `head` for equality.
|
|
||||||
| **@returns** | char | A byte set to `0` if the head does not match, or `1`if it does match.
|
|
||||||
|
|
||||||
Quickly check if the current line head matches a specified value. Useful in many document-parsing situations.
|
|
||||||
|
|
||||||
Given the following line:
|
|
||||||
CodeBlock terrace
|
|
||||||
title An Important Document
|
|
||||||
Markdown
|
|
||||||
- `terrace_match(doc, "title")` returns `1`
|
|
||||||
- `terrace_match(doc, "somethingElse")` returns `0`
|
|
||||||
CodeBlock c
|
|
||||||
// Call Signature
|
|
||||||
char terrace_match(terrace_document_t* doc, const char* matchHead)
|
|
||||||
|
|
||||||
// Usage
|
|
||||||
while(terrace_next(doc, -1)) {
|
|
||||||
printf("Does the line start with 'title': %d", terrace_match(doc, "title"));
|
|
||||||
}
|
|
||||||
|
|
||||||
Heading 2 Recipes
|
|
||||||
class mt-12
|
|
||||||
|
|
||||||
Heading 3 Parse a single line
|
|
||||||
Markdown
|
|
||||||
Parses a single line into `line_data`, the prints the information from `line_data`.
|
|
||||||
CodeBlock c
|
|
||||||
#include "parser.h"
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
|
||||||
char* line = "example line";
|
|
||||||
// Create the line_data struct
|
|
||||||
terrace_linedata_t line_data;
|
|
||||||
// Set the indent character to a space
|
|
||||||
line_data.indent = ' ';
|
|
||||||
// Populates line_data level, offsetHead, and offsetTail from line
|
|
||||||
terrace_parse_line(line, &line_data);
|
|
||||||
|
|
||||||
printf(
|
|
||||||
"level %u | indent %c | offsetHead %u | offsetTail %u\n",
|
|
||||||
line_data.level,
|
|
||||||
line_data.indent,
|
|
||||||
line_data.offsetHead,
|
|
||||||
line_data.offsetTail
|
|
||||||
);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Heading 3 Parse all lines from stdin
|
|
||||||
Markdown
|
|
||||||
Reads lines from stdin one-by-one and prints each line's `line_data`.
|
|
||||||
CodeBlock c
|
|
||||||
#include "parser.h"
|
|
||||||
// Depends on several cstdlib functions
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
|
||||||
// Pointer to start of line
|
|
||||||
char *line = NULL;
|
|
||||||
// Initial size of the buffer to read into
|
|
||||||
// getline() will resize as needed
|
|
||||||
size_t bufsize = 128;
|
|
||||||
// How many characters have been read
|
|
||||||
ssize_t chars_read = 0;
|
|
||||||
|
|
||||||
// Create the line_data struct
|
|
||||||
terrace_linedata_t line_data;
|
|
||||||
// Set the indent character to a space
|
|
||||||
line_data.indent = ' ';
|
|
||||||
|
|
||||||
while (chars_read = getline(&line, &bufsize, stdin)) {
|
|
||||||
// If chars_read is -1, we've reached end of file.
|
|
||||||
if (chars_read == -1) break;
|
|
||||||
// getline returns lines with a trailing newline
|
|
||||||
// terrace_parse_line expects no trailing newline
|
|
||||||
// strip it off using strtok()
|
|
||||||
// (An odd solution, probably leaks memory)
|
|
||||||
char *terrace_line = strtok(line, "\n");
|
|
||||||
terrace_parse_line(terrace_line, &line_data);
|
|
||||||
|
|
||||||
printf(
|
|
||||||
"level %u | indent %c | offsetHead %u | offsetTail %u\n",
|
|
||||||
line_data.level,
|
|
||||||
line_data.indent,
|
|
||||||
line_data.offsetHead,
|
|
||||||
line_data.offsetTail
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Free the buffer allocated by getline().
|
|
||||||
free(line);
|
|
||||||
}
|
|
||||||
|
|
||||||
Heading 2 Contributing
|
|
||||||
class mt-12
|
|
||||||
|
|
||||||
Section dark
|
|
||||||
Footer
|
|
||||||
class w-full
|
|
52
docs/src/docs/c/core-api.inc.tce
Normal file
52
docs/src/docs/c/core-api.inc.tce
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
Heading 2 Core API
|
||||||
|
class mt-12
|
||||||
|
Markdown
|
||||||
|
**Note:** The Core API is designed for maximum portability and is not intended to be directly consumed.
|
||||||
|
|
||||||
|
For most projects you'll want to use the [Document API](#document-api) instead.
|
||||||
|
It provides an ergonomic wrapper around the Core API and lets you focus on parsing
|
||||||
|
your documents.
|
||||||
|
|
||||||
|
Heading 3 terrace_linedata_t
|
||||||
|
class mb-4 mt-12
|
||||||
|
Markdown
|
||||||
|
This struct holds information about each line as it is parsed. Mutated each time [terrace_parse_line()](#terrace-parse-line) is called. Not intended to be used directly.
|
||||||
|
Use the relevant `terrace_` functions from the [Document API](#document-api) instead.
|
||||||
|
CodeBlock c
|
||||||
|
// Holds the parsed information from each line.
|
||||||
|
typedef struct terrace_linedata_s {
|
||||||
|
// Which character is being used for indentation. Avoids having to specify it on each terrace_parse_line call.
|
||||||
|
char indent;
|
||||||
|
// How many indent characters are present in the current line before the first non-indent character.
|
||||||
|
unsigned int level;
|
||||||
|
// The number of characters before the start of the line's "head" section.
|
||||||
|
// (Normally the same as `level`)
|
||||||
|
unsigned int offsetHead;
|
||||||
|
// The number of characters before the start of the line's "tail" section.
|
||||||
|
unsigned int offsetTail;
|
||||||
|
} terrace_linedata_t;
|
||||||
|
|
||||||
|
Heading 3 terrace_create_linedata()
|
||||||
|
class mb-4 mt-12
|
||||||
|
Markdown
|
||||||
|
| Parameter | Type | Description
|
||||||
|
| -------------- | --------------------- | -----------------------------------------------------------------------
|
||||||
|
| indent | const char | The character used for indentation in the document. Only a single character is permitted.
|
||||||
|
| **@returns** | [terrace_linedata_t](#terrace-linedatat) | A terrace_linedata_t struct with the specified indent character and all other values initialized to 0.
|
||||||
|
|
||||||
|
Initialize a [terrace_linedata](#terrace-linedatat) struct with default values to pass to [terrace_parse_line()](#terrace-parse-line).
|
||||||
|
CodeBlock c
|
||||||
|
// Call Signature
|
||||||
|
terrace_linedata_t terrace_create_linedata(const char indent)
|
||||||
|
Heading 3 terrace_parse_line()
|
||||||
|
class mb-4 mt-12
|
||||||
|
Markdown
|
||||||
|
| Parameter | Type | Description
|
||||||
|
| -------------- | --------------------- | -----------------------------------------------------------------------
|
||||||
|
| line | char* | A pointer to the line to parse as a C-style string. Shouldn't end with a newline.
|
||||||
|
| lineData | [terrace_linedata_t](#terrace-linedatat)* | A pointer to the terrace_linedata_t struct to store information about the current line in.
|
||||||
|
|
||||||
|
Core Terrace parser function, sets `level`, `offsetHead`, and `offsetTail` in a [terrace_linedata](#terrace-linedatat) struct based on the current line.
|
||||||
|
CodeBlock c
|
||||||
|
// Call Signature
|
||||||
|
void terrace_parse_line(const char* line, terrace_linedata_t* lineData)
|
294
docs/src/docs/c/document-api.inc.tce
Normal file
294
docs/src/docs/c/document-api.inc.tce
Normal file
@ -0,0 +1,294 @@
|
|||||||
|
Heading 2 Document API
|
||||||
|
class mt-12
|
||||||
|
|
||||||
|
Heading 3 terrace_document_t
|
||||||
|
class mb-4 mt-12
|
||||||
|
Markdown
|
||||||
|
Tracks state of a document while being parsed.
|
||||||
|
Obtained from [terrace_create_document()](#terrace-create-document) below
|
||||||
|
CodeBlock c
|
||||||
|
// Type Definition
|
||||||
|
typedef struct terrace_document_s {
|
||||||
|
// == Internal State == //
|
||||||
|
unsigned int _repeatCurrentLine;
|
||||||
|
// Current line being read
|
||||||
|
char* _currentLine;
|
||||||
|
|
||||||
|
// == External Information == //
|
||||||
|
// Embedded line data struct. Holds information about the current parsed line
|
||||||
|
terrace_linedata_t lineData;
|
||||||
|
// Custom data passed to the readline function
|
||||||
|
void* userData;
|
||||||
|
/**
|
||||||
|
* Line reader function, provided by the user
|
||||||
|
* Needed to get the next line inside of `terrace_next(doc)`
|
||||||
|
* @param {char**} line First argument is a pointer to `_currentLine`, above
|
||||||
|
* @param {void*} userData Second argument is `userData`, above
|
||||||
|
* @returns {int} The number of characters read, or -1 if no characters were read.
|
||||||
|
*/
|
||||||
|
int (*reader)(char** line, void* userData);
|
||||||
|
} terrace_document_t;
|
||||||
|
|
||||||
|
Heading 3 terrace_create_document()
|
||||||
|
class mb-4 mt-12
|
||||||
|
Markdown
|
||||||
|
| Parameter | Type | Description
|
||||||
|
| -------------- | --------------------- | -----------------------------------------------------------------------
|
||||||
|
| indent | const char | The indent character to use. Generally a single space character.
|
||||||
|
| reader | int (\*reader)(char** line, void* userData) | A function pointer to a function that reads lines sequentially from a user-provided source. Receives a pointer to `lineData->_currLine`, and `userData`, supplied in the next argument.
|
||||||
|
| userData | void * | A user-supplied pointer to any state information needed by their reader function. Passed to `reader`each time it is called.
|
||||||
|
| **@returns** | [terrace_document_t](#terrace-documentt) | A state struct needed by the convenience functions below.
|
||||||
|
|
||||||
|
Initializes the state needed for the convenience functions below. Takes a user-supplied `reader` function to read each line from a user-determined source.
|
||||||
|
CodeBlock c
|
||||||
|
// Call Signature
|
||||||
|
terrace_document_t terrace_create_document(const char indent, int (*reader)(char** line, void* userData), void* userData)
|
||||||
|
|
||||||
|
Heading 3 terrace_next()
|
||||||
|
class mb-4 mt-12
|
||||||
|
|
||||||
|
Markdown
|
||||||
|
| Parameter | Type | Description
|
||||||
|
| -------------- | --------------------- | -----------------------------------------------------------------------
|
||||||
|
| doc | [terrace_document_t*](#terrace-documentt) | A pointer to the current document state struct.
|
||||||
|
| levelScope | int | If set above -1, `next()` will return `0` when it encounters a line with a level at or below `levelScope`
|
||||||
|
| **@returns** | char | Returns `1` after parsing a line, or `0` if the document has ended or a line at or below `levelScope` has been encountered.
|
||||||
|
|
||||||
|
Advances the current position in the terrace document and populates lineData
|
||||||
|
with the parsed information from that line.
|
||||||
|
|
||||||
|
Returns `1` after parsing the next line, or `0` upon reaching the end of the document.
|
||||||
|
If the `levelScope` parameter is not -1, `terrace_next()` will also return `0` when it encounters a line
|
||||||
|
with a level at or below `levelScope`. This allows you to iterate through subsections of a document.
|
||||||
|
|
||||||
|
If a lower-level line was encountered, the following call to `terrace_next()` will repeat this line again.
|
||||||
|
This allows a child loop to look forward, determine that the next line will be outside its purview,
|
||||||
|
and return control to the calling loop transparently without additional logic.
|
||||||
|
|
||||||
|
Intended to be used inside a while loop to parse a section of a Terrace document.
|
||||||
|
|
||||||
|
CodeBlock c
|
||||||
|
// Call Signature
|
||||||
|
char terrace_next(terrace_document_t* doc, int levelScope)
|
||||||
|
|
||||||
|
// Usage
|
||||||
|
while(terrace_next(doc, -1)) {
|
||||||
|
// Do something with each line.
|
||||||
|
}
|
||||||
|
|
||||||
|
Heading 3 terrace_level()
|
||||||
|
class mb-4 mt-12
|
||||||
|
Markdown
|
||||||
|
| Parameter | Type | Description
|
||||||
|
| -------------- | --------------------- | -----------------------------------------------------------------------
|
||||||
|
| doc | [terrace_document_t*](#terrace-documentt) | A pointer to the current document state struct.
|
||||||
|
| **@returns** | unsigned int | The indent level of the current line
|
||||||
|
|
||||||
|
Returns the number of indent characters of the current line.
|
||||||
|
|
||||||
|
Given the following document, `terrace_level(doc)` would return 0, 1, 2, and 5 respectively for each line.
|
||||||
|
CodeBlock terrace
|
||||||
|
block
|
||||||
|
block
|
||||||
|
block
|
||||||
|
block
|
||||||
|
|
||||||
|
CodeBlock c
|
||||||
|
// Call Signature
|
||||||
|
unsigned int terrace_level(terrace_document_t* doc)
|
||||||
|
|
||||||
|
// Usage
|
||||||
|
while(terrace_next(doc, -1)) {
|
||||||
|
printf("Indent Level: %u", terrace_level(doc));
|
||||||
|
}
|
||||||
|
|
||||||
|
Heading 3 terrace_line()
|
||||||
|
class mb-4 mt-12
|
||||||
|
Markdown
|
||||||
|
| Parameter | Type | Description
|
||||||
|
| -------------- | --------------------- | -----------------------------------------------------------------------
|
||||||
|
| doc | [terrace_document_t*](#terrace-documentt) | A pointer to the current document state struct.
|
||||||
|
| startOffset | int | How many indent characters to skip before outputting the line contents. If set to -1, uses the current indent level.
|
||||||
|
| **@returns** | char* | The line contents starting from `startOffset`
|
||||||
|
|
||||||
|
Get a string with the current line contents.
|
||||||
|
If `startOffset` is -1, skips all indent characters by default. Otherwise only skips the amount specified.
|
||||||
|
|
||||||
|
Given the following document
|
||||||
|
CodeBlock terrace
|
||||||
|
root
|
||||||
|
sub-line
|
||||||
|
Markdown
|
||||||
|
- Calling `terrace_line(doc, -1)` on the second line returns "sub-line", trimming off the leading indent characters.
|
||||||
|
- Calling `terrace_line(doc, 0)` however, returns " sub-line", with all four leading spaces.
|
||||||
|
|
||||||
|
`startOffset`s other than `-1` are primarily used for parsing blocks that have literal indented multi-line text
|
||||||
|
|
||||||
|
CodeBlock c
|
||||||
|
// Call Signature
|
||||||
|
char* terrace_line(terrace_document_t* doc, int startOffset)
|
||||||
|
|
||||||
|
// Usage
|
||||||
|
while(terrace_next(doc, -1)) {
|
||||||
|
printf("Line with indent characters: %s", terrace_line(doc, 0));
|
||||||
|
printf("Line without indent characters: %s", terrace_line(doc, -1));
|
||||||
|
}
|
||||||
|
|
||||||
|
Heading 3 terrace_head_length()
|
||||||
|
class mb-4 mt-12
|
||||||
|
Markdown
|
||||||
|
| Parameter | Type | Description
|
||||||
|
| -------------- | --------------------- | -----------------------------------------------------------------------
|
||||||
|
| doc | [terrace_document_t*](#terrace-documentt) | A pointer to the current document state struct.
|
||||||
|
| **@returns** | unsigned int | The length of the `head` portion (first word) of a line
|
||||||
|
|
||||||
|
Get the *length* of the first "word" of a line,
|
||||||
|
starting from the first non-indent character to the first space or end of the line
|
||||||
|
Often used for deciding how to parse a block.
|
||||||
|
|
||||||
|
Because C uses NULL-terminated strings, we cannot easily slice a string to return something out of the middle.
|
||||||
|
Instead, `terrace_head_length()` provides the length of the head portion.
|
||||||
|
In combination with `doc->lineData.offsetHead`, you can copy the head section into a new string,
|
||||||
|
or use any number of `strn*` C stdlib functions to work with the head section without copying it.
|
||||||
|
|
||||||
|
Terrace DSLs do not *need* to use head-tail line structure, but support for them is built into the parser
|
||||||
|
|
||||||
|
Given the following line, `terrace_head_length(doc)` returns `5`
|
||||||
|
CodeBlock terrace
|
||||||
|
title An Important Document
|
||||||
|
CodeBlock c
|
||||||
|
// Call Signature
|
||||||
|
unsigned int terrace_head_length(terrace_document_t* doc)
|
||||||
|
|
||||||
|
// Usage
|
||||||
|
while(terrace_next(doc, -1)) {
|
||||||
|
printf("Head length: %u", terrace_head_length(doc));
|
||||||
|
}
|
||||||
|
|
||||||
|
Heading 3 terrace_tail()
|
||||||
|
class mb-4 mt-12
|
||||||
|
Markdown
|
||||||
|
| Parameter | Type | Description
|
||||||
|
| -------------- | --------------------- | -----------------------------------------------------------------------
|
||||||
|
| doc | [terrace_document_t*](#terrace-documentt) | A pointer to the current document state struct.
|
||||||
|
| **@returns** | char* | The remainder of the line following the `head` portion, with no leading space.
|
||||||
|
|
||||||
|
Get a char pointer to everything following the first "word" of a line,
|
||||||
|
starting from the first character after the space at the end of `head`.
|
||||||
|
|
||||||
|
Terrace DSLs do not *need* to use head-tail line structure, but support for them is built into the parser
|
||||||
|
|
||||||
|
Given the following line, `terrace_tail(doc)` returns "An Important Document"
|
||||||
|
CodeBlock terrace
|
||||||
|
title An Important Document
|
||||||
|
CodeBlock c
|
||||||
|
// Call Signature
|
||||||
|
char* terrace_tail(terrace_document_t* doc)
|
||||||
|
|
||||||
|
// Usage
|
||||||
|
while(terrace_next(doc, -1)) {
|
||||||
|
printf("Line tail: %s", terrace_tail(doc));
|
||||||
|
}
|
||||||
|
|
||||||
|
Heading 3 terrace_match()
|
||||||
|
class mb-4 mt-12
|
||||||
|
Markdown
|
||||||
|
| Parameter | Type | Description
|
||||||
|
| -------------- | --------------------- | -----------------------------------------------------------------------
|
||||||
|
| doc | [terrace_document_t*](#terrace-documentt) | A pointer to the current document state struct.
|
||||||
|
| matchValue | const char* | A string to check against the line `head` for equality.
|
||||||
|
| **@returns** | char | A byte set to `0` if the head does not match, or `1`if it does match.
|
||||||
|
|
||||||
|
Quickly check if the current line head matches a specified value. Useful in many document-parsing situations.
|
||||||
|
|
||||||
|
Given the following line:
|
||||||
|
CodeBlock terrace
|
||||||
|
title An Important Document
|
||||||
|
Markdown
|
||||||
|
- `terrace_match(doc, "title")` returns `1`
|
||||||
|
- `terrace_match(doc, "somethingElse")` returns `0`
|
||||||
|
CodeBlock c
|
||||||
|
// Call Signature
|
||||||
|
char terrace_match(terrace_document_t* doc, const char* matchHead)
|
||||||
|
|
||||||
|
// Usage
|
||||||
|
while(terrace_next(doc, -1)) {
|
||||||
|
printf("Does the line start with 'title': %d", terrace_match(doc, "title"));
|
||||||
|
}
|
||||||
|
|
||||||
|
Heading 2 Recipes
|
||||||
|
class mt-12
|
||||||
|
|
||||||
|
Heading 3 Parse a single line
|
||||||
|
Markdown
|
||||||
|
Parses a single line into `line_data`, the prints the information from `line_data`.
|
||||||
|
CodeBlock c
|
||||||
|
#include "parser.h"
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
char* line = "example line";
|
||||||
|
// Create the line_data struct
|
||||||
|
terrace_linedata_t line_data;
|
||||||
|
// Set the indent character to a space
|
||||||
|
line_data.indent = ' ';
|
||||||
|
// Populates line_data level, offsetHead, and offsetTail from line
|
||||||
|
terrace_parse_line(line, &line_data);
|
||||||
|
|
||||||
|
printf(
|
||||||
|
"level %u | indent %c | offsetHead %u | offsetTail %u\n",
|
||||||
|
line_data.level,
|
||||||
|
line_data.indent,
|
||||||
|
line_data.offsetHead,
|
||||||
|
line_data.offsetTail
|
||||||
|
);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Heading 3 Parse all lines from stdin
|
||||||
|
Markdown
|
||||||
|
Reads lines from stdin one-by-one and prints each line's `line_data`.
|
||||||
|
CodeBlock c
|
||||||
|
#include "parser.h"
|
||||||
|
// Depends on several cstdlib functions
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
// Pointer to start of line
|
||||||
|
char *line = NULL;
|
||||||
|
// Initial size of the buffer to read into
|
||||||
|
// getline() will resize as needed
|
||||||
|
size_t bufsize = 128;
|
||||||
|
// How many characters have been read
|
||||||
|
ssize_t chars_read = 0;
|
||||||
|
|
||||||
|
// Create the line_data struct
|
||||||
|
terrace_linedata_t line_data;
|
||||||
|
// Set the indent character to a space
|
||||||
|
line_data.indent = ' ';
|
||||||
|
|
||||||
|
while (chars_read = getline(&line, &bufsize, stdin)) {
|
||||||
|
// If chars_read is -1, we've reached end of file.
|
||||||
|
if (chars_read == -1) break;
|
||||||
|
// getline returns lines with a trailing newline
|
||||||
|
// terrace_parse_line expects no trailing newline
|
||||||
|
// strip it off using strtok()
|
||||||
|
// (An odd solution, probably leaks memory)
|
||||||
|
char *terrace_line = strtok(line, "\n");
|
||||||
|
terrace_parse_line(terrace_line, &line_data);
|
||||||
|
|
||||||
|
printf(
|
||||||
|
"level %u | indent %c | offsetHead %u | offsetTail %u\n",
|
||||||
|
line_data.level,
|
||||||
|
line_data.indent,
|
||||||
|
line_data.offsetHead,
|
||||||
|
line_data.offsetTail
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Free the buffer allocated by getline().
|
||||||
|
free(line);
|
||||||
|
}
|
88
docs/src/docs/c/index.tce
Normal file
88
docs/src/docs/c/index.tce
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
layout layout.njk
|
||||||
|
title C Documentation - Terrace
|
||||||
|
description
|
||||||
|
C language documentation for the Terrace programming language
|
||||||
|
|
||||||
|
Section light
|
||||||
|
class flex flex-col md:flex-row gap-16
|
||||||
|
|
||||||
|
Block
|
||||||
|
class w-full lg:w-1/3
|
||||||
|
TableOfContents
|
||||||
|
|
||||||
|
Block
|
||||||
|
Heading 1 Terrace C Documentation
|
||||||
|
class -ml-2
|
||||||
|
|
||||||
|
Markdown
|
||||||
|
Documentation is available for the following languages:
|
||||||
|
- [C](/docs/c/) - 75% Complete
|
||||||
|
- [JavaScript](/docs/javascript/) - 75% Complete
|
||||||
|
- [Python](/docs/python/) - 0% Complete
|
||||||
|
|
||||||
|
Heading 2 Getting Started
|
||||||
|
class mt-12 mb-6
|
||||||
|
Markdown
|
||||||
|
The terrace parser is distributed as a set of C header files.<br/>
|
||||||
|
To use it, download and include the following files in your project tree:
|
||||||
|
- [parser.h](https://git.thederf.com/thederf/Terrace/src/branch/main/packages/c/parser.h) - Core terrace parser
|
||||||
|
- [document.h](https://git.thederf.com/thederf/Terrace/src/branch/main/packages/c/document.h) - (optional) Convenience functions for parsing of documents
|
||||||
|
|
||||||
|
A simple example program using to read each line from stdin and output parser information, looking for a "title" key:
|
||||||
|
CodeBlock c
|
||||||
|
// Provides getline() for reading from stdin
|
||||||
|
#include <stdio.h>
|
||||||
|
// Provides free() for deallocating the lines from getline()
|
||||||
|
#include <stdlib.h>
|
||||||
|
// Provides document API for interacting with Terrace files
|
||||||
|
#include "document.h"
|
||||||
|
|
||||||
|
// Custom userData struct. Stores information needed
|
||||||
|
// by read_line below.
|
||||||
|
typedef struct read_line_container_s {
|
||||||
|
size_t bufsize;
|
||||||
|
} read_line_container_t;
|
||||||
|
|
||||||
|
// A user-supplied function to read lines from stdin (or whichever data source you choose)
|
||||||
|
int read_line_from_stdin(char** line, void* userData) {
|
||||||
|
read_line_container_t* lineContainer = (read_line_container_t*) userData;
|
||||||
|
// Uses getline from the C stdlib to read the next line from stdin.
|
||||||
|
int num_chars_read = getline(line, &lineContainer->bufsize, stdin);
|
||||||
|
// Change trailing newline to null char. Terrace doesn't use trailing newlines
|
||||||
|
if (num_chars_read > 0) (*line)[num_chars_read - 1] = '\0';
|
||||||
|
// Return the number of charaters read to the document parser.
|
||||||
|
return num_chars_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
read_line_container_t read_line_information = { .bufsize = 64 };
|
||||||
|
// Initialize the terrace document with the line reader function created above.
|
||||||
|
terrace_document_t doc = terrace_create_document(' ', &read_line_from_stdin, &read_line_information);
|
||||||
|
|
||||||
|
// Loop over every line in the document.
|
||||||
|
while(terrace_next(&doc, -1)) {
|
||||||
|
// > Replace with your custom line handling code.
|
||||||
|
|
||||||
|
// Print the line and level to demonstrate the terrace_level and terrace_line functions.
|
||||||
|
printf("| level %u | line %s |", terrace_level(&doc), terrace_line(&doc, -1));
|
||||||
|
// If one of the lines starts with "title", output it.
|
||||||
|
if (terrace_match(&doc, "title")) {
|
||||||
|
printf("Title: %s |", terrace_tail(&doc));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Free allocated line memory
|
||||||
|
free(line);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Include ./src/docs/c/core-api.inc.tce
|
||||||
|
Include ./src/docs/c/document-api.inc.tce
|
||||||
|
|
||||||
|
Heading 2 Contributing
|
||||||
|
class mt-12
|
||||||
|
|
||||||
|
Section dark
|
||||||
|
Footer
|
||||||
|
class w-full
|
@ -1,579 +0,0 @@
|
|||||||
layout layout.njk
|
|
||||||
title JavaScript Documentation - Terrace
|
|
||||||
description
|
|
||||||
JavaScript language documentation for the Terrace programming language
|
|
||||||
|
|
||||||
Section light
|
|
||||||
class flex flex-col md:flex-row gap-16
|
|
||||||
|
|
||||||
Block
|
|
||||||
class w-full lg:w-1/3
|
|
||||||
TableOfContents
|
|
||||||
|
|
||||||
Block
|
|
||||||
Heading 1 Terrace JavaScript Documentation
|
|
||||||
class -ml-2
|
|
||||||
|
|
||||||
Markdown
|
|
||||||
Documentation is available for the following languages:
|
|
||||||
- [C](/docs/c/) - 75% Complete
|
|
||||||
- [JavaScript](/docs/javascript/) - 75% Complete
|
|
||||||
- [Python](/docs/python/) - 0% Complete
|
|
||||||
|
|
||||||
Heading 2 Getting Started
|
|
||||||
class mt-12 mb-6
|
|
||||||
Markdown
|
|
||||||
Install Terrace using [NPM](https://www.npmjs.com/):
|
|
||||||
|
|
||||||
CodeBlock bash
|
|
||||||
# NPM (https://npmjs.com)
|
|
||||||
$ npm install @terrace-lang/js
|
|
||||||
|
|
||||||
# PNPM (https://pnpm.io/)
|
|
||||||
$ pnpm install @terrace-lang/js
|
|
||||||
|
|
||||||
# Yarn (https://yarnpkg.com/)
|
|
||||||
$ yarn add @terrace-lang/js
|
|
||||||
|
|
||||||
Heading 2 Core API
|
|
||||||
class mt-12
|
|
||||||
Markdown
|
|
||||||
**Note:** The Core API uses C-style conventions to optimize memory management
|
|
||||||
and improve portability to other environments and languages.
|
|
||||||
It is unwieldy and does not follow JavaScript best practices.
|
|
||||||
|
|
||||||
For most projects you'll want to use the [Document API](#document-api) instead.
|
|
||||||
It provides an ergonomic wrapper around the Core API and lets you focus on parsing
|
|
||||||
your documents.
|
|
||||||
|
|
||||||
Heading 3 LineData
|
|
||||||
class mb-4 mt-12
|
|
||||||
CodeBlock typescript
|
|
||||||
// Type Definition
|
|
||||||
// Holds the parsed information from each line.
|
|
||||||
type LineData = {
|
|
||||||
// Which character is being used for indentation. Avoids having to specify it on each parseLine call.
|
|
||||||
indent: string;
|
|
||||||
// How many indent characters are present in the current line before the first non-indent character.
|
|
||||||
level: number;
|
|
||||||
// The number of characters before the start of the line's "head" section.
|
|
||||||
// (Normally the same as `level`)
|
|
||||||
offsetHead: number;
|
|
||||||
// The number of characters before the start of the line's "tail" section.
|
|
||||||
offsetTail: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
Heading 3 createLineData()
|
|
||||||
class mb-4 mt-12
|
|
||||||
Markdown
|
|
||||||
| Parameter | Type | Description
|
|
||||||
| -------------- | --------------------- | -----------------------------------------------------------------------
|
|
||||||
| indent | string | The character used for indentation in the document. Only a single character is permitted.
|
|
||||||
| **@returns** | [LineData](#line-data) | A LineData instance with the specified indent character and all other values initialized to 0.
|
|
||||||
|
|
||||||
Initialize a LineData instance with default values to pass to [parseLine()](#parse-line).
|
|
||||||
|
|
||||||
CodeBlock typescript
|
|
||||||
// Type Definition
|
|
||||||
function createLineData(indent: string = ' '): LineData
|
|
||||||
|
|
||||||
// Import Path
|
|
||||||
import { createLineData } from '@terrace-lang/js/parser'
|
|
||||||
|
|
||||||
// Usage
|
|
||||||
const lineData = createLineData(' ')
|
|
||||||
console.dir(lineData)
|
|
||||||
// { indent: ' ', level: 0, offsetHead: 0, offsetTail: 0 }
|
|
||||||
// Use the same lineData object for all calls to parseLine in the same document.
|
|
||||||
|
|
||||||
Heading 3 parseLine()
|
|
||||||
class mb-4 mt-12
|
|
||||||
Markdown
|
|
||||||
| Parameter | Type | Description
|
|
||||||
| -------------- | --------------------- | -----------------------------------------------------------------------
|
|
||||||
| line | string | A string containing a line to parse. Shouldn't end with a newline.
|
|
||||||
| lineData | [LineData](#line-data) | A LineData object to store information about the current line, from [createLineData()](#create-line-data).<br/>**Mutated in-place!**
|
|
||||||
|
|
||||||
Core Terrace parser function, sets `level`, `offsetHead`, and `offsetTail` in a [LineData](#line-data) object based on the passed line.
|
|
||||||
Note that this is a C-style function, `lineData` is treated as a reference and mutated in-place.
|
|
||||||
|
|
||||||
CodeBlock typescript
|
|
||||||
// Type Definition
|
|
||||||
function parseLine(lineData: LineData): LineData
|
|
||||||
|
|
||||||
// Import Path
|
|
||||||
import { createLineData, parseLine } from '@terrace-lang/js/parser'
|
|
||||||
|
|
||||||
// Usage
|
|
||||||
const lineData = createLineData(' ')
|
|
||||||
parseLine('title Example Title', lineData)
|
|
||||||
console.dir(lineData)
|
|
||||||
// { indent: ' ', level: 0, offsetHead: 0, offsetTail: 5 }
|
|
||||||
|
|
||||||
Heading 2 Document API
|
|
||||||
class mt-12
|
|
||||||
|
|
||||||
Heading 3 useDocument()
|
|
||||||
class mb-4 mt-12
|
|
||||||
Markdown
|
|
||||||
| Parameter | Type | Description
|
|
||||||
| -------------- | --------------------- | -----------------------------------------------------------------------
|
|
||||||
| reader | [Reader](#reader) | When called, resolves to a string containing the next line in the document.
|
|
||||||
| indent | string | The character used for indentation in the document. Only a single character is permitted.
|
|
||||||
| **@returns** | [Document](#document) | A set of convenience functions for iterating through and parsing a document line by line.
|
|
||||||
|
|
||||||
Provides a simple set of convenience functions around parseLine for more ergonomic parsing of Terrace documents.
|
|
||||||
CodeBlock typescript
|
|
||||||
// Type Definition
|
|
||||||
function useDocument (reader: Reader, indent: string = ' '): Document
|
|
||||||
|
|
||||||
// Import Path
|
|
||||||
import { useDocument } from '@terrace-lang/js/document'
|
|
||||||
|
|
||||||
Heading 3 Document
|
|
||||||
class mb-4 mt-12
|
|
||||||
Markdown
|
|
||||||
Container for a handful of convenience functions for parsing documents.
|
|
||||||
Obtained from [useDocument()](#usedocument) above
|
|
||||||
CodeBlock typescript
|
|
||||||
// Type Definition
|
|
||||||
type Document = {
|
|
||||||
next: (levelScope?: number) => Promise<boolean>
|
|
||||||
level: () => number,
|
|
||||||
line: (startOffset?: number) => string,
|
|
||||||
head: () => string,
|
|
||||||
tail: () => string,
|
|
||||||
match: (matchHead: string) => boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
Heading 3 Document.next()
|
|
||||||
class mb-4 mt-12
|
|
||||||
|
|
||||||
Markdown
|
|
||||||
| Parameter | Type | Description
|
|
||||||
| -------------- | --------------------- | -----------------------------------------------------------------------
|
|
||||||
| levelScope | number = -1 | If specified, `next()` will return `false` when it encounters a line with a level at or below `levelScope`
|
|
||||||
| **@returns** | Promise<boolean> | Returns `true` after parsing a line, or `false` if the document has ended or a line at or below `levelScope` has been encountered.
|
|
||||||
|
|
||||||
Advances the current position in the terrace document and populates lineData
|
|
||||||
with the parsed information from that line.
|
|
||||||
|
|
||||||
Returns `true` after parsing the next line, or `false` upon reaching the end of the document.
|
|
||||||
If the `levelScope` parameter is provided, `next()` will return `false` when it encounters a line
|
|
||||||
with a level at or below `levelScope`. This allows you to iterate through subsections of a document.
|
|
||||||
|
|
||||||
If a lower-level line was encountered, the following call to `next()` will repeat this line again.
|
|
||||||
This allows a child loop to look forward, determine that the next line will be outside its purview,
|
|
||||||
and return control to the calling loop transparently without additional logic.
|
|
||||||
|
|
||||||
Intended to be used inside a while loop to parse a section of a Terrace document.
|
|
||||||
|
|
||||||
CodeBlock typescript
|
|
||||||
// Type Definition
|
|
||||||
next: (levelScope?: number) => Promise<boolean>
|
|
||||||
|
|
||||||
// Import Path
|
|
||||||
import { useDocument } from '@terrace-lang/js/document'
|
|
||||||
|
|
||||||
// Usage
|
|
||||||
const { next } = useDocument(...)
|
|
||||||
while (await next()) {
|
|
||||||
// Do something with each line.
|
|
||||||
}
|
|
||||||
|
|
||||||
Heading 3 Document.level()
|
|
||||||
class mb-4 mt-12
|
|
||||||
Markdown
|
|
||||||
| Parameter | Type | Description
|
|
||||||
| -------------- | --------------------- | -----------------------------------------------------------------------
|
|
||||||
| **@returns** | number | The indent level of the current line
|
|
||||||
|
|
||||||
Returns the number of indent characters of the current line.
|
|
||||||
|
|
||||||
Given the following document, `level()` would return 0, 1, 2, and 5 respectively for each line.
|
|
||||||
CodeBlock terrace
|
|
||||||
block
|
|
||||||
block
|
|
||||||
block
|
|
||||||
block
|
|
||||||
|
|
||||||
CodeBlock typescript
|
|
||||||
// Type Definition
|
|
||||||
level: () => number
|
|
||||||
|
|
||||||
// Usage
|
|
||||||
import { useDocument } from '@terrace-lang/js/document'
|
|
||||||
const { level } = useDocument(...)
|
|
||||||
|
|
||||||
Heading 3 Document.line()
|
|
||||||
class mb-4 mt-12
|
|
||||||
Markdown
|
|
||||||
| Parameter | Type | Description
|
|
||||||
| -------------- | --------------------- | -----------------------------------------------------------------------
|
|
||||||
| levelScope | startOffset = [level()](#document-level) | How many indent characters to skip before outputting the line contents. Defaults to the current indent level
|
|
||||||
| **@returns** | string | The line contents starting from `startOffset`
|
|
||||||
|
|
||||||
Get a string with the current line contents. Skips all indent characters by default, but this can be configured with `startOffset`
|
|
||||||
|
|
||||||
Given the following document
|
|
||||||
CodeBlock terrace
|
|
||||||
root
|
|
||||||
sub-line
|
|
||||||
Markdown
|
|
||||||
- Calling `line()` on the second line returns "sub-line", trimming off the leading indent characters.
|
|
||||||
- Calling `line(0)` however, returns " sub-line", with all four leading spaces.
|
|
||||||
|
|
||||||
`startOffset` is primarily used for parsing blocks that have literal indented multi-line text, such as markdown.
|
|
||||||
|
|
||||||
CodeBlock typescript
|
|
||||||
// Type Definition
|
|
||||||
line: (startOffset?: number) => string
|
|
||||||
|
|
||||||
// Usage
|
|
||||||
import { useDocument } from '@terrace-lang/js/document'
|
|
||||||
const { line } = useDocument(...)
|
|
||||||
|
|
||||||
Heading 3 Document.head()
|
|
||||||
class mb-4 mt-12
|
|
||||||
Markdown
|
|
||||||
| Parameter | Type | Description
|
|
||||||
| -------------- | --------------------- | -----------------------------------------------------------------------
|
|
||||||
| **@returns** | string | The `head` portion (first word) of a line
|
|
||||||
|
|
||||||
Get the first "word" of a line, starting from the first non-indent character to the first space or end of the line.
|
|
||||||
Often used for deciding how to parse a block.
|
|
||||||
|
|
||||||
Terrace DSLs do not *need* to use head-tail line structure, but support for them is built into the parser
|
|
||||||
|
|
||||||
Given the following line, [head()](#document-head) returns "title"
|
|
||||||
CodeBlock terrace
|
|
||||||
title An Important Document
|
|
||||||
CodeBlock typescript
|
|
||||||
// Type Definition
|
|
||||||
head: () => string
|
|
||||||
|
|
||||||
// Usage
|
|
||||||
import { useDocument } from '@terrace-lang/js/document'
|
|
||||||
const { head } = useDocument(...)
|
|
||||||
|
|
||||||
Heading 3 Document.tail()
|
|
||||||
class mb-4 mt-12
|
|
||||||
Markdown
|
|
||||||
| Parameter | Type | Description
|
|
||||||
| -------------- | --------------------- | -----------------------------------------------------------------------
|
|
||||||
| **@returns** | string | The remainder of the line following the [head()](#document-head) portion, with no leading space
|
|
||||||
|
|
||||||
Get all text following the first "word" of a line, starting from the first character after the space at the end of [head()](#document-head)
|
|
||||||
|
|
||||||
Terrace DSLs do not *need* to use head-tail line structure, but support for them is built into the parser
|
|
||||||
|
|
||||||
Given the following line, [tail()](#document-tail) returns "An Important Document"
|
|
||||||
CodeBlock terrace
|
|
||||||
title An Important Document
|
|
||||||
CodeBlock typescript
|
|
||||||
// Type Definition
|
|
||||||
tail: () => string
|
|
||||||
|
|
||||||
// Usage
|
|
||||||
import { useDocument } from '@terrace-lang/js/document'
|
|
||||||
const { tail } = useDocument(...)
|
|
||||||
|
|
||||||
Heading 3 Document.match()
|
|
||||||
class mb-4 mt-12
|
|
||||||
Markdown
|
|
||||||
| Parameter | Type | Description
|
|
||||||
| -------------- | --------------------- | -----------------------------------------------------------------------
|
|
||||||
| matchValue | string | A string to check against [head()](#document-head) for equality
|
|
||||||
| **@returns** | boolean | Whether the current [head()](#document-head) matches the passed value
|
|
||||||
|
|
||||||
Quickly check if the current line head matches a specified value
|
|
||||||
|
|
||||||
Shorthand for `matchValue === head()`
|
|
||||||
|
|
||||||
Given the following line
|
|
||||||
CodeBlock terrace
|
|
||||||
title An Important Document
|
|
||||||
Markdown
|
|
||||||
- `match('title')` returns `true`
|
|
||||||
- `match('somethingElse`) returns `false`
|
|
||||||
CodeBlock typescript
|
|
||||||
// Type Definition
|
|
||||||
match: (matchValue: string) => boolean
|
|
||||||
|
|
||||||
// Usage
|
|
||||||
import { useDocument } from '@terrace-lang/js/document'
|
|
||||||
const { match } = useDocument(...)
|
|
||||||
|
|
||||||
Heading 2 Reader API
|
|
||||||
class mt-12
|
|
||||||
Markdown
|
|
||||||
The [Document API](#document-api) requires `Reader` functions to iterate through lines
|
|
||||||
in a document. A reader function simply returns a string (or a promise resolving to a string).
|
|
||||||
Each time it is called, it returns the next line from whichever source it is pulling them.
|
|
||||||
|
|
||||||
Terrace provides a few built-in readers, but you are welcome to build your own instead.
|
|
||||||
|
|
||||||
Heading 3 Reader
|
|
||||||
class mb-4 mt-12
|
|
||||||
Markdown
|
|
||||||
Any function (async included) that returns the next line in a document when called and null when the end of the document has been reached.
|
|
||||||
|
|
||||||
CodeBlock typescript
|
|
||||||
// Type Definition
|
|
||||||
type Reader = () => string|null|Promise<string|null>
|
|
||||||
|
|
||||||
Heading 3 createStringReader()
|
|
||||||
class mb-4 mt-12
|
|
||||||
Markdown
|
|
||||||
| Parameter | Type | Description
|
|
||||||
| -------------- | --------------------- | -----------------------------------------------------------------------
|
|
||||||
| source | string\|string[] | The lines to iterate over, as a multiline string or an array of line strings.
|
|
||||||
| index | number | Optional - which line to start from.
|
|
||||||
| **@returns** | [Reader](#reader) | A reader function that returns each line from the source document when called sequentially.
|
|
||||||
|
|
||||||
Get a simple [Reader](#reader) function that always returns the next line from a mutliline string or an array of line strings.
|
|
||||||
CodeBlock typescript
|
|
||||||
// Type Definition
|
|
||||||
function createStringReader(source: string|string[], index: number = 0): Reader
|
|
||||||
|
|
||||||
// Import Path
|
|
||||||
import { createStringReader } from '@terrace-lang/js/readers/js-string'
|
|
||||||
|
|
||||||
Markdown
|
|
||||||
**Usage**
|
|
||||||
CodeBlock typescript
|
|
||||||
import { createStringReader, useDocument } from '@terrace-lang/js'
|
|
||||||
|
|
||||||
// Create a string reader with two lines
|
|
||||||
const reader = createStringReader('title Example Title\n line2')
|
|
||||||
// Also permitted:
|
|
||||||
// const reader = createStringReader(['title Example Title', ' line 2'])
|
|
||||||
|
|
||||||
const { next, level, line } = useDocument(reader)
|
|
||||||
await next()
|
|
||||||
console.log(level(), line())
|
|
||||||
// 0 title Example Title
|
|
||||||
await next()
|
|
||||||
console.log(level(), line())
|
|
||||||
// 1 line 2
|
|
||||||
|
|
||||||
|
|
||||||
Heading 3 createFileReader()
|
|
||||||
class mb-4 mt-12
|
|
||||||
Markdown
|
|
||||||
| Parameter | Type | Description
|
|
||||||
| -------------- | --------------------- | -----------------------------------------------------------------------
|
|
||||||
| path | string | A path to the file to read.
|
|
||||||
| **@returns** | [Reader](#reader) | A reader function that returns each line from the file when called sequentially
|
|
||||||
|
|
||||||
**Note:** Only available in Node.js environments.<br/>
|
|
||||||
Get a [Reader](#reader) function that returns the next line from the specified file when called sequentially.
|
|
||||||
|
|
||||||
|
|
||||||
CodeBlock typescript
|
|
||||||
// Type Definition
|
|
||||||
function createFileReader(path: string): Reader
|
|
||||||
|
|
||||||
// Import Path
|
|
||||||
import { createFileReader } from '@terrace-lang/js/readers/node-readline'
|
|
||||||
|
|
||||||
Markdown
|
|
||||||
**Usage**
|
|
||||||
CodeExample
|
|
||||||
summary-class mb-[300px]
|
|
||||||
pre-class max-h-[300px]
|
|
||||||
javascript main.js
|
|
||||||
import { createFileReader, useDocument } from '@terrace-lang/js'
|
|
||||||
|
|
||||||
// Read the file ./example.tce
|
|
||||||
const { next, level, line } = useDocument(createFileReader('./example.tce'))
|
|
||||||
await next()
|
|
||||||
console.log(level(), line())
|
|
||||||
// 0 title Example Title
|
|
||||||
await next()
|
|
||||||
console.log(level(), line())
|
|
||||||
// 1 line 2
|
|
||||||
|
|
||||||
terrace example.tce
|
|
||||||
title Example Title
|
|
||||||
line 2
|
|
||||||
|
|
||||||
Heading 3 createStdinReader()
|
|
||||||
class mb-4 mt-12
|
|
||||||
Markdown
|
|
||||||
| Parameter | Type | Description
|
|
||||||
| -------------- | --------------------- | -----------------------------------------------------------------------
|
|
||||||
| **@returns** | [Reader](#reader) | A reader function that returns each line from `stdin` when called sequentially
|
|
||||||
|
|
||||||
**Note:** Only available in Node.js environments.<br/>
|
|
||||||
Get a [Reader](#reader) function that returns the next line from standard input when called sequentially. Does not block stdin to wait for input. If no input is present it returns null immediately.
|
|
||||||
CodeBlock typescript
|
|
||||||
// Type Definition
|
|
||||||
function createStdinReader(): Reader
|
|
||||||
|
|
||||||
// Import Path
|
|
||||||
import { createStdinReader } from '@terrace-lang/js/readers/node-readline'
|
|
||||||
Markdown
|
|
||||||
**Usage**
|
|
||||||
CodeExample
|
|
||||||
summary-class mb-[250px]
|
|
||||||
pre-class max-h-[250px]
|
|
||||||
javascript main.js
|
|
||||||
import { createStdinReader, useDocument } from '@terrace-lang/js'
|
|
||||||
|
|
||||||
// Read the contents of standard input
|
|
||||||
const { next, level, line } = useDocument(createStdinReader())
|
|
||||||
|
|
||||||
while(await next()) {
|
|
||||||
console.log(level(), line())
|
|
||||||
// See `shell` panel above for output
|
|
||||||
}
|
|
||||||
|
|
||||||
terrace example.tce
|
|
||||||
title Example Title
|
|
||||||
line 2
|
|
||||||
|
|
||||||
sh
|
|
||||||
# Run main.js with the contents of example.tce piped to stdin
|
|
||||||
$ cat example.tce > node ./main.js
|
|
||||||
0 title Example Title
|
|
||||||
1 line 2
|
|
||||||
|
|
||||||
Heading 3 createStreamReader()
|
|
||||||
class mb-4 mt-12
|
|
||||||
Markdown
|
|
||||||
| Parameter | Type | Description
|
|
||||||
| -------------- | --------------------- | -----------------------------------------------------------------------
|
|
||||||
| stream | NodeJS.ReadStream|fs.ReadStream | A ReadStream compatible with Node.js `readline` APIs
|
|
||||||
| **@returns** | [Reader](#reader) | A reader function that returns each line from `stdin` when called sequentially
|
|
||||||
|
|
||||||
**Note:** Only available in Node.js environments.<br/>
|
|
||||||
Get a [Reader](#reader) function that always returns the next line from a passed read stream when called sequentially.
|
|
||||||
CodeBlock typescript
|
|
||||||
// Type Definition
|
|
||||||
function createStreamReader(): Reader
|
|
||||||
|
|
||||||
// Import Path
|
|
||||||
import { createStreamReader } from '@terrace-lang/js/readers/node-readline'
|
|
||||||
Markdown
|
|
||||||
**Usage**
|
|
||||||
CodeExample
|
|
||||||
summary-class mb-[320px]
|
|
||||||
pre-class max-h-[320px]
|
|
||||||
javascript main.js
|
|
||||||
import fs from 'node:fs'
|
|
||||||
import { createStreamReader, useDocument } from '@terrace-lang/js'
|
|
||||||
|
|
||||||
// Read the file ./example.tce - equivalent to the `createFileReader` example above.
|
|
||||||
const reader = createStreamReader(fs.createReadStream('./example.tce'))
|
|
||||||
const { next, level, line } = useDocument(reader)
|
|
||||||
await next()
|
|
||||||
console.log(level(), line())
|
|
||||||
// 0 title Example Title
|
|
||||||
await next()
|
|
||||||
console.log(level(), line())
|
|
||||||
// 1 line 2
|
|
||||||
|
|
||||||
terrace example.tce
|
|
||||||
title Example Title
|
|
||||||
line 2
|
|
||||||
|
|
||||||
Heading 2 Recipes
|
|
||||||
class mt-12
|
|
||||||
|
|
||||||
Heading 3 Read object properties
|
|
||||||
class mb-2
|
|
||||||
Markdown
|
|
||||||
Read known properties from a Terrace block and write them to an object.
|
|
||||||
CodeBlock javascript
|
|
||||||
// Provides simple convenience functions over the core parser
|
|
||||||
// CommonJS: const { useDocument } = require('@terrace-lang/js/document')
|
|
||||||
import { useDocument } from '@terrace-lang/js/document'
|
|
||||||
// A helper for iterating over a string line-by-line
|
|
||||||
// CommonJS: const { createStringReader } = require('@terrace-lang/js/readers/js-string')
|
|
||||||
import { createStringReader } from '@terrace-lang/js/readers/js-string'
|
|
||||||
|
|
||||||
const input = `
|
|
||||||
object
|
|
||||||
string_property An example string
|
|
||||||
numeric_property 4
|
|
||||||
`
|
|
||||||
|
|
||||||
const output = {
|
|
||||||
string_property: null,
|
|
||||||
numeric_property: null
|
|
||||||
}
|
|
||||||
|
|
||||||
// useDocument returns convenience functions
|
|
||||||
const { next, level, head, tail, match } = useDocument(createStringReader(input))
|
|
||||||
|
|
||||||
// next() parses the next line in the document
|
|
||||||
while (await next()) {
|
|
||||||
// match('object') is equivalent to head() === 'object'
|
|
||||||
// Essentially: "If the current line starts with 'object'"
|
|
||||||
if (match('object')) {
|
|
||||||
const objectLevel = level()
|
|
||||||
// When we call next with a parent level it,
|
|
||||||
// only iterates over lines inside the parent block
|
|
||||||
while (await next(objectLevel)) {
|
|
||||||
// tail() returns the part of the current line after the first space
|
|
||||||
if (match('string_property')) output.string_property = tail()
|
|
||||||
// parseFloat() here the string tail() to a numeric float value
|
|
||||||
if (match('numeric_property')) output.numeric_property = parseFloat(tail())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
console.dir(output)
|
|
||||||
// { string_property: 'An example string', numeric_property: 4 }
|
|
||||||
|
|
||||||
Markdown
|
|
||||||
Read *all* properties as strings from a Terrace block and write them to an object.
|
|
||||||
CodeBlock javascript
|
|
||||||
// Provides simple convenience functions over the core parser
|
|
||||||
// CommonJS: const { useDocument } = require('@terrace-lang/js/document')
|
|
||||||
import { useDocument } from '@terrace-lang/js/document'
|
|
||||||
// A helper for iterating over a string line-by-line
|
|
||||||
// CommonJS: const { createStringReader } = require('@terrace-lang/js/readers/js-string')
|
|
||||||
import { createStringReader } from '@terrace-lang/js/readers/js-string'
|
|
||||||
|
|
||||||
const input = `
|
|
||||||
object
|
|
||||||
property1 Value 1
|
|
||||||
property2 Value 2
|
|
||||||
random_property igazi3ii4quaC5OdoB5quohnah1beeNg
|
|
||||||
`
|
|
||||||
|
|
||||||
const output = {}
|
|
||||||
|
|
||||||
// useDocument returns convenience functions
|
|
||||||
const { next, level, head, tail, match } = useDocument(createStringReader(input))
|
|
||||||
|
|
||||||
// next() parses the next line in the document
|
|
||||||
while (await next()) {
|
|
||||||
// match('object') is equivalent to head() === 'object'
|
|
||||||
// Essentially: "If the current line starts with 'object'"
|
|
||||||
if (match('object')) {
|
|
||||||
const objectLevel = level()
|
|
||||||
// When we call next with a parent level,
|
|
||||||
// it only iterates over lines inside the parent block
|
|
||||||
while (await next(objectLevel)) {
|
|
||||||
// Skip empty lines
|
|
||||||
if (!line()) continue
|
|
||||||
// Add any properties to the object as strings using the
|
|
||||||
// line head() as the key and tail() as the value
|
|
||||||
output[head()] = tail()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
console.dir(output)
|
|
||||||
// { property1: 'Value 1', property2: 'Value 2', random_property: 'igazi3ii4quaC5OdoB5quohnah1beeNg' }
|
|
||||||
|
|
||||||
|
|
||||||
Heading 2 Contributing
|
|
||||||
class mt-12
|
|
||||||
|
|
||||||
Section dark
|
|
||||||
Footer
|
|
||||||
class w-full
|
|
74
docs/src/docs/javascript/core-api.inc.tce
Normal file
74
docs/src/docs/javascript/core-api.inc.tce
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
Heading 2 Core API
|
||||||
|
class mt-12
|
||||||
|
Markdown
|
||||||
|
**Note:** The Core API uses C-style conventions to optimize memory management
|
||||||
|
and improve portability to other environments and languages.
|
||||||
|
It is unwieldy and does not follow JavaScript best practices.
|
||||||
|
|
||||||
|
For most projects you'll want to use the [Document API](#document-api) instead.
|
||||||
|
It provides an ergonomic wrapper around the Core API and lets you focus on parsing
|
||||||
|
your documents.
|
||||||
|
|
||||||
|
Heading 3 LineData
|
||||||
|
class mb-4 mt-12
|
||||||
|
CodeBlock typescript
|
||||||
|
// Type Definition
|
||||||
|
// Holds the parsed information from each line.
|
||||||
|
type LineData = {
|
||||||
|
// Which character is being used for indentation. Avoids having to specify it on each parseLine call.
|
||||||
|
indent: string;
|
||||||
|
// How many indent characters are present in the current line before the first non-indent character.
|
||||||
|
level: number;
|
||||||
|
// The number of characters before the start of the line's "head" section.
|
||||||
|
// (Normally the same as `level`)
|
||||||
|
offsetHead: number;
|
||||||
|
// The number of characters before the start of the line's "tail" section.
|
||||||
|
offsetTail: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
Heading 3 createLineData()
|
||||||
|
class mb-4 mt-12
|
||||||
|
Markdown
|
||||||
|
| Parameter | Type | Description
|
||||||
|
| -------------- | --------------------- | -----------------------------------------------------------------------
|
||||||
|
| indent | string | The character used for indentation in the document. Only a single character is permitted.
|
||||||
|
| **@returns** | [LineData](#line-data) | A LineData instance with the specified indent character and all other values initialized to 0.
|
||||||
|
|
||||||
|
Initialize a LineData instance with default values to pass to [parseLine()](#parse-line).
|
||||||
|
|
||||||
|
CodeBlock typescript
|
||||||
|
// Type Definition
|
||||||
|
function createLineData(indent: string = ' '): LineData
|
||||||
|
|
||||||
|
// Import Path
|
||||||
|
import { createLineData } from '@terrace-lang/js/parser'
|
||||||
|
|
||||||
|
// Usage
|
||||||
|
const lineData = createLineData(' ')
|
||||||
|
console.dir(lineData)
|
||||||
|
// { indent: ' ', level: 0, offsetHead: 0, offsetTail: 0 }
|
||||||
|
// Use the same lineData object for all calls to parseLine in the same document.
|
||||||
|
|
||||||
|
Heading 3 parseLine()
|
||||||
|
class mb-4 mt-12
|
||||||
|
Markdown
|
||||||
|
| Parameter | Type | Description
|
||||||
|
| -------------- | --------------------- | -----------------------------------------------------------------------
|
||||||
|
| line | string | A string containing a line to parse. Shouldn't end with a newline.
|
||||||
|
| lineData | [LineData](#line-data) | A LineData object to store information about the current line, from [createLineData()](#create-line-data).<br/>**Mutated in-place!**
|
||||||
|
|
||||||
|
Core Terrace parser function, sets `level`, `offsetHead`, and `offsetTail` in a [LineData](#line-data) object based on the passed line.
|
||||||
|
Note that this is a C-style function, `lineData` is treated as a reference and mutated in-place.
|
||||||
|
|
||||||
|
CodeBlock typescript
|
||||||
|
// Type Definition
|
||||||
|
function parseLine(lineData: LineData): LineData
|
||||||
|
|
||||||
|
// Import Path
|
||||||
|
import { createLineData, parseLine } from '@terrace-lang/js/parser'
|
||||||
|
|
||||||
|
// Usage
|
||||||
|
const lineData = createLineData(' ')
|
||||||
|
parseLine('title Example Title', lineData)
|
||||||
|
console.dir(lineData)
|
||||||
|
// { indent: ' ', level: 0, offsetHead: 0, offsetTail: 5 }
|
193
docs/src/docs/javascript/document-api.inc.tce
Normal file
193
docs/src/docs/javascript/document-api.inc.tce
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
Heading 2 Document API
|
||||||
|
class mt-12
|
||||||
|
|
||||||
|
Heading 3 useDocument()
|
||||||
|
class mb-4 mt-12
|
||||||
|
Markdown
|
||||||
|
| Parameter | Type | Description
|
||||||
|
| -------------- | --------------------- | -----------------------------------------------------------------------
|
||||||
|
| reader | [Reader](#reader) | When called, resolves to a string containing the next line in the document.
|
||||||
|
| indent | string | The character used for indentation in the document. Only a single character is permitted.
|
||||||
|
| **@returns** | [Document](#document) | A set of convenience functions for iterating through and parsing a document line by line.
|
||||||
|
|
||||||
|
Provides a simple set of convenience functions around parseLine for more ergonomic parsing of Terrace documents.
|
||||||
|
CodeBlock typescript
|
||||||
|
// Type Definition
|
||||||
|
function useDocument (reader: Reader, indent: string = ' '): Document
|
||||||
|
|
||||||
|
// Import Path
|
||||||
|
import { useDocument } from '@terrace-lang/js/document'
|
||||||
|
|
||||||
|
Heading 3 Document
|
||||||
|
class mb-4 mt-12
|
||||||
|
Markdown
|
||||||
|
Container for a handful of convenience functions for parsing documents.
|
||||||
|
Obtained from [useDocument()](#usedocument) above
|
||||||
|
CodeBlock typescript
|
||||||
|
// Type Definition
|
||||||
|
type Document = {
|
||||||
|
next: (levelScope?: number) => Promise<boolean>
|
||||||
|
level: () => number,
|
||||||
|
line: (startOffset?: number) => string,
|
||||||
|
head: () => string,
|
||||||
|
tail: () => string,
|
||||||
|
match: (matchHead: string) => boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
Heading 3 Document.next()
|
||||||
|
class mb-4 mt-12
|
||||||
|
|
||||||
|
Markdown
|
||||||
|
| Parameter | Type | Description
|
||||||
|
| -------------- | --------------------- | -----------------------------------------------------------------------
|
||||||
|
| levelScope | number = -1 | If specified, `next()` will return `false` when it encounters a line with a level at or below `levelScope`
|
||||||
|
| **@returns** | Promise<boolean> | Returns `true` after parsing a line, or `false` if the document has ended or a line at or below `levelScope` has been encountered.
|
||||||
|
|
||||||
|
Advances the current position in the terrace document and populates lineData
|
||||||
|
with the parsed information from that line.
|
||||||
|
|
||||||
|
Returns `true` after parsing the next line, or `false` upon reaching the end of the document.
|
||||||
|
If the `levelScope` parameter is provided, `next()` will return `false` when it encounters a line
|
||||||
|
with a level at or below `levelScope`. This allows you to iterate through subsections of a document.
|
||||||
|
|
||||||
|
If a lower-level line was encountered, the following call to `next()` will repeat this line again.
|
||||||
|
This allows a child loop to look forward, determine that the next line will be outside its purview,
|
||||||
|
and return control to the calling loop transparently without additional logic.
|
||||||
|
|
||||||
|
Intended to be used inside a while loop to parse a section of a Terrace document.
|
||||||
|
|
||||||
|
CodeBlock typescript
|
||||||
|
// Type Definition
|
||||||
|
next: (levelScope?: number) => Promise<boolean>
|
||||||
|
|
||||||
|
// Import Path
|
||||||
|
import { useDocument } from '@terrace-lang/js/document'
|
||||||
|
|
||||||
|
// Usage
|
||||||
|
const { next } = useDocument(...)
|
||||||
|
while (await next()) {
|
||||||
|
// Do something with each line.
|
||||||
|
}
|
||||||
|
|
||||||
|
Heading 3 Document.level()
|
||||||
|
class mb-4 mt-12
|
||||||
|
Markdown
|
||||||
|
| Parameter | Type | Description
|
||||||
|
| -------------- | --------------------- | -----------------------------------------------------------------------
|
||||||
|
| **@returns** | number | The indent level of the current line
|
||||||
|
|
||||||
|
Returns the number of indent characters of the current line.
|
||||||
|
|
||||||
|
Given the following document, `level()` would return 0, 1, 2, and 5 respectively for each line.
|
||||||
|
CodeBlock terrace
|
||||||
|
block
|
||||||
|
block
|
||||||
|
block
|
||||||
|
block
|
||||||
|
|
||||||
|
CodeBlock typescript
|
||||||
|
// Type Definition
|
||||||
|
level: () => number
|
||||||
|
|
||||||
|
// Usage
|
||||||
|
import { useDocument } from '@terrace-lang/js/document'
|
||||||
|
const { level } = useDocument(...)
|
||||||
|
|
||||||
|
Heading 3 Document.line()
|
||||||
|
class mb-4 mt-12
|
||||||
|
Markdown
|
||||||
|
| Parameter | Type | Description
|
||||||
|
| -------------- | --------------------- | -----------------------------------------------------------------------
|
||||||
|
| levelScope | startOffset = [level()](#document-level) | How many indent characters to skip before outputting the line contents. Defaults to the current indent level
|
||||||
|
| **@returns** | string | The line contents starting from `startOffset`
|
||||||
|
|
||||||
|
Get a string with the current line contents. Skips all indent characters by default, but this can be configured with `startOffset`
|
||||||
|
|
||||||
|
Given the following document
|
||||||
|
CodeBlock terrace
|
||||||
|
root
|
||||||
|
sub-line
|
||||||
|
Markdown
|
||||||
|
- Calling `line()` on the second line returns "sub-line", trimming off the leading indent characters.
|
||||||
|
- Calling `line(0)` however, returns " sub-line", with all four leading spaces.
|
||||||
|
|
||||||
|
`startOffset` is primarily used for parsing blocks that have literal indented multi-line text, such as markdown.
|
||||||
|
|
||||||
|
CodeBlock typescript
|
||||||
|
// Type Definition
|
||||||
|
line: (startOffset?: number) => string
|
||||||
|
|
||||||
|
// Usage
|
||||||
|
import { useDocument } from '@terrace-lang/js/document'
|
||||||
|
const { line } = useDocument(...)
|
||||||
|
|
||||||
|
Heading 3 Document.head()
|
||||||
|
class mb-4 mt-12
|
||||||
|
Markdown
|
||||||
|
| Parameter | Type | Description
|
||||||
|
| -------------- | --------------------- | -----------------------------------------------------------------------
|
||||||
|
| **@returns** | string | The `head` portion (first word) of a line
|
||||||
|
|
||||||
|
Get the first "word" of a line, starting from the first non-indent character to the first space or end of the line.
|
||||||
|
Often used for deciding how to parse a block.
|
||||||
|
|
||||||
|
Terrace DSLs do not *need* to use head-tail line structure, but support for them is built into the parser
|
||||||
|
|
||||||
|
Given the following line, [head()](#document-head) returns "title"
|
||||||
|
CodeBlock terrace
|
||||||
|
title An Important Document
|
||||||
|
CodeBlock typescript
|
||||||
|
// Type Definition
|
||||||
|
head: () => string
|
||||||
|
|
||||||
|
// Usage
|
||||||
|
import { useDocument } from '@terrace-lang/js/document'
|
||||||
|
const { head } = useDocument(...)
|
||||||
|
|
||||||
|
Heading 3 Document.tail()
|
||||||
|
class mb-4 mt-12
|
||||||
|
Markdown
|
||||||
|
| Parameter | Type | Description
|
||||||
|
| -------------- | --------------------- | -----------------------------------------------------------------------
|
||||||
|
| **@returns** | string | The remainder of the line following the [head()](#document-head) portion, with no leading space
|
||||||
|
|
||||||
|
Get all text following the first "word" of a line, starting from the first character after the space at the end of [head()](#document-head)
|
||||||
|
|
||||||
|
Terrace DSLs do not *need* to use head-tail line structure, but support for them is built into the parser
|
||||||
|
|
||||||
|
Given the following line, [tail()](#document-tail) returns "An Important Document"
|
||||||
|
CodeBlock terrace
|
||||||
|
title An Important Document
|
||||||
|
CodeBlock typescript
|
||||||
|
// Type Definition
|
||||||
|
tail: () => string
|
||||||
|
|
||||||
|
// Usage
|
||||||
|
import { useDocument } from '@terrace-lang/js/document'
|
||||||
|
const { tail } = useDocument(...)
|
||||||
|
|
||||||
|
Heading 3 Document.match()
|
||||||
|
class mb-4 mt-12
|
||||||
|
Markdown
|
||||||
|
| Parameter | Type | Description
|
||||||
|
| -------------- | --------------------- | -----------------------------------------------------------------------
|
||||||
|
| matchValue | string | A string to check against [head()](#document-head) for equality
|
||||||
|
| **@returns** | boolean | Whether the current [head()](#document-head) matches the passed value
|
||||||
|
|
||||||
|
Quickly check if the current line head matches a specified value
|
||||||
|
|
||||||
|
Shorthand for `matchValue === head()`
|
||||||
|
|
||||||
|
Given the following line
|
||||||
|
CodeBlock terrace
|
||||||
|
title An Important Document
|
||||||
|
Markdown
|
||||||
|
- `match('title')` returns `true`
|
||||||
|
- `match('somethingElse`) returns `false`
|
||||||
|
CodeBlock typescript
|
||||||
|
// Type Definition
|
||||||
|
match: (matchValue: string) => boolean
|
||||||
|
|
||||||
|
// Usage
|
||||||
|
import { useDocument } from '@terrace-lang/js/document'
|
||||||
|
const { match } = useDocument(...)
|
48
docs/src/docs/javascript/index.tce
Normal file
48
docs/src/docs/javascript/index.tce
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
layout layout.njk
|
||||||
|
title JavaScript Documentation - Terrace
|
||||||
|
description
|
||||||
|
JavaScript language documentation for the Terrace programming language
|
||||||
|
|
||||||
|
Section light
|
||||||
|
class flex flex-col md:flex-row gap-16
|
||||||
|
|
||||||
|
Block
|
||||||
|
class w-full lg:w-1/3
|
||||||
|
TableOfContents
|
||||||
|
|
||||||
|
Block
|
||||||
|
Heading 1 Terrace JavaScript Documentation
|
||||||
|
class -ml-2
|
||||||
|
|
||||||
|
Markdown
|
||||||
|
Documentation is available for the following languages:
|
||||||
|
- [C](/docs/c/) - 75% Complete
|
||||||
|
- [JavaScript](/docs/javascript/) - 75% Complete
|
||||||
|
- [Python](/docs/python/) - 0% Complete
|
||||||
|
|
||||||
|
Heading 2 Getting Started
|
||||||
|
class mt-12 mb-6
|
||||||
|
Markdown
|
||||||
|
Install Terrace using [NPM](https://www.npmjs.com/):
|
||||||
|
|
||||||
|
CodeBlock bash
|
||||||
|
# NPM (https://npmjs.com)
|
||||||
|
$ npm install @terrace-lang/js
|
||||||
|
|
||||||
|
# PNPM (https://pnpm.io/)
|
||||||
|
$ pnpm install @terrace-lang/js
|
||||||
|
|
||||||
|
# Yarn (https://yarnpkg.com/)
|
||||||
|
$ yarn add @terrace-lang/js
|
||||||
|
|
||||||
|
Include ./src/docs/javascript/core-api.inc.tce
|
||||||
|
Include ./src/docs/javascript/document-api.inc.tce
|
||||||
|
Include ./src/docs/javascript/reader-api.inc.tce
|
||||||
|
Include ./src/docs/javascript/recipes.inc.tce
|
||||||
|
|
||||||
|
Heading 2 Contributing
|
||||||
|
class mt-12
|
||||||
|
|
||||||
|
Section dark
|
||||||
|
Footer
|
||||||
|
class w-full
|
173
docs/src/docs/javascript/reader-api.inc.tce
Normal file
173
docs/src/docs/javascript/reader-api.inc.tce
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
Heading 2 Reader API
|
||||||
|
class mt-12
|
||||||
|
Markdown
|
||||||
|
The [Document API](#document-api) requires `Reader` functions to iterate through lines
|
||||||
|
in a document. A reader function simply returns a string (or a promise resolving to a string).
|
||||||
|
Each time it is called, it returns the next line from whichever source it is pulling them.
|
||||||
|
|
||||||
|
Terrace provides a few built-in readers, but you are welcome to build your own instead.
|
||||||
|
|
||||||
|
Heading 3 Reader
|
||||||
|
class mb-4 mt-12
|
||||||
|
Markdown
|
||||||
|
Any function (async included) that returns the next line in a document when called and null when the end of the document has been reached.
|
||||||
|
|
||||||
|
CodeBlock typescript
|
||||||
|
// Type Definition
|
||||||
|
type Reader = () => string|null|Promise<string|null>
|
||||||
|
|
||||||
|
Heading 3 createStringReader()
|
||||||
|
class mb-4 mt-12
|
||||||
|
Markdown
|
||||||
|
| Parameter | Type | Description
|
||||||
|
| -------------- | --------------------- | -----------------------------------------------------------------------
|
||||||
|
| source | string\|string[] | The lines to iterate over, as a multiline string or an array of line strings.
|
||||||
|
| index | number | Optional - which line to start from.
|
||||||
|
| **@returns** | [Reader](#reader) | A reader function that returns each line from the source document when called sequentially.
|
||||||
|
|
||||||
|
Get a simple [Reader](#reader) function that always returns the next line from a mutliline string or an array of line strings.
|
||||||
|
CodeBlock typescript
|
||||||
|
// Type Definition
|
||||||
|
function createStringReader(source: string|string[], index: number = 0): Reader
|
||||||
|
|
||||||
|
// Import Path
|
||||||
|
import { createStringReader } from '@terrace-lang/js/readers/js-string'
|
||||||
|
|
||||||
|
Markdown
|
||||||
|
**Usage**
|
||||||
|
CodeBlock typescript
|
||||||
|
import { createStringReader, useDocument } from '@terrace-lang/js'
|
||||||
|
|
||||||
|
// Create a string reader with two lines
|
||||||
|
const reader = createStringReader('title Example Title\n line2')
|
||||||
|
// Also permitted:
|
||||||
|
// const reader = createStringReader(['title Example Title', ' line 2'])
|
||||||
|
|
||||||
|
const { next, level, line } = useDocument(reader)
|
||||||
|
await next()
|
||||||
|
console.log(level(), line())
|
||||||
|
// 0 title Example Title
|
||||||
|
await next()
|
||||||
|
console.log(level(), line())
|
||||||
|
// 1 line 2
|
||||||
|
|
||||||
|
|
||||||
|
Heading 3 createFileReader()
|
||||||
|
class mb-4 mt-12
|
||||||
|
Markdown
|
||||||
|
| Parameter | Type | Description
|
||||||
|
| -------------- | --------------------- | -----------------------------------------------------------------------
|
||||||
|
| path | string | A path to the file to read.
|
||||||
|
| **@returns** | [Reader](#reader) | A reader function that returns each line from the file when called sequentially
|
||||||
|
|
||||||
|
**Note:** Only available in Node.js environments.<br/>
|
||||||
|
Get a [Reader](#reader) function that returns the next line from the specified file when called sequentially.
|
||||||
|
|
||||||
|
|
||||||
|
CodeBlock typescript
|
||||||
|
// Type Definition
|
||||||
|
function createFileReader(path: string): Reader
|
||||||
|
|
||||||
|
// Import Path
|
||||||
|
import { createFileReader } from '@terrace-lang/js/readers/node-readline'
|
||||||
|
|
||||||
|
Markdown
|
||||||
|
**Usage**
|
||||||
|
CodeExample
|
||||||
|
summary-class mb-[300px]
|
||||||
|
pre-class max-h-[300px]
|
||||||
|
javascript main.js
|
||||||
|
import { createFileReader, useDocument } from '@terrace-lang/js'
|
||||||
|
|
||||||
|
// Read the file ./example.tce
|
||||||
|
const { next, level, line } = useDocument(createFileReader('./example.tce'))
|
||||||
|
await next()
|
||||||
|
console.log(level(), line())
|
||||||
|
// 0 title Example Title
|
||||||
|
await next()
|
||||||
|
console.log(level(), line())
|
||||||
|
// 1 line 2
|
||||||
|
|
||||||
|
terrace example.tce
|
||||||
|
title Example Title
|
||||||
|
line 2
|
||||||
|
|
||||||
|
Heading 3 createStdinReader()
|
||||||
|
class mb-4 mt-12
|
||||||
|
Markdown
|
||||||
|
| Parameter | Type | Description
|
||||||
|
| -------------- | --------------------- | -----------------------------------------------------------------------
|
||||||
|
| **@returns** | [Reader](#reader) | A reader function that returns each line from `stdin` when called sequentially
|
||||||
|
|
||||||
|
**Note:** Only available in Node.js environments.<br/>
|
||||||
|
Get a [Reader](#reader) function that returns the next line from standard input when called sequentially. Does not block stdin to wait for input. If no input is present it returns null immediately.
|
||||||
|
CodeBlock typescript
|
||||||
|
// Type Definition
|
||||||
|
function createStdinReader(): Reader
|
||||||
|
|
||||||
|
// Import Path
|
||||||
|
import { createStdinReader } from '@terrace-lang/js/readers/node-readline'
|
||||||
|
Markdown
|
||||||
|
**Usage**
|
||||||
|
CodeExample
|
||||||
|
summary-class mb-[250px]
|
||||||
|
pre-class max-h-[250px]
|
||||||
|
javascript main.js
|
||||||
|
import { createStdinReader, useDocument } from '@terrace-lang/js'
|
||||||
|
|
||||||
|
// Read the contents of standard input
|
||||||
|
const { next, level, line } = useDocument(createStdinReader())
|
||||||
|
|
||||||
|
while(await next()) {
|
||||||
|
console.log(level(), line())
|
||||||
|
// See `shell` panel above for output
|
||||||
|
}
|
||||||
|
|
||||||
|
terrace example.tce
|
||||||
|
title Example Title
|
||||||
|
line 2
|
||||||
|
|
||||||
|
sh
|
||||||
|
# Run main.js with the contents of example.tce piped to stdin
|
||||||
|
$ cat example.tce > node ./main.js
|
||||||
|
0 title Example Title
|
||||||
|
1 line 2
|
||||||
|
|
||||||
|
Heading 3 createStreamReader()
|
||||||
|
class mb-4 mt-12
|
||||||
|
Markdown
|
||||||
|
| Parameter | Type | Description
|
||||||
|
| -------------- | --------------------- | -----------------------------------------------------------------------
|
||||||
|
| stream | NodeJS.ReadStream|fs.ReadStream | A ReadStream compatible with Node.js `readline` APIs
|
||||||
|
| **@returns** | [Reader](#reader) | A reader function that returns each line from `stdin` when called sequentially
|
||||||
|
|
||||||
|
**Note:** Only available in Node.js environments.<br/>
|
||||||
|
Get a [Reader](#reader) function that always returns the next line from a passed read stream when called sequentially.
|
||||||
|
CodeBlock typescript
|
||||||
|
// Type Definition
|
||||||
|
function createStreamReader(): Reader
|
||||||
|
|
||||||
|
// Import Path
|
||||||
|
import { createStreamReader } from '@terrace-lang/js/readers/node-readline'
|
||||||
|
Markdown
|
||||||
|
**Usage**
|
||||||
|
CodeExample
|
||||||
|
summary-class mb-[320px]
|
||||||
|
pre-class max-h-[320px]
|
||||||
|
javascript main.js
|
||||||
|
import fs from 'node:fs'
|
||||||
|
import { createStreamReader, useDocument } from '@terrace-lang/js'
|
||||||
|
|
||||||
|
// Read the file ./example.tce - equivalent to the `createFileReader` example above.
|
||||||
|
const reader = createStreamReader(fs.createReadStream('./example.tce'))
|
||||||
|
const { next, level, line } = useDocument(reader)
|
||||||
|
await next()
|
||||||
|
console.log(level(), line())
|
||||||
|
// 0 title Example Title
|
||||||
|
await next()
|
||||||
|
console.log(level(), line())
|
||||||
|
// 1 line 2
|
||||||
|
|
||||||
|
terrace example.tce
|
||||||
|
title Example Title
|
||||||
|
line 2
|
91
docs/src/docs/javascript/recipes.inc.tce
Normal file
91
docs/src/docs/javascript/recipes.inc.tce
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
Heading 2 Recipes
|
||||||
|
class mt-12
|
||||||
|
|
||||||
|
Heading 3 Read object properties
|
||||||
|
class mb-2
|
||||||
|
Markdown
|
||||||
|
Read known properties from a Terrace block and write them to an object.
|
||||||
|
CodeBlock javascript
|
||||||
|
// Provides simple convenience functions over the core parser
|
||||||
|
// CommonJS: const { useDocument } = require('@terrace-lang/js/document')
|
||||||
|
import { useDocument } from '@terrace-lang/js/document'
|
||||||
|
// A helper for iterating over a string line-by-line
|
||||||
|
// CommonJS: const { createStringReader } = require('@terrace-lang/js/readers/js-string')
|
||||||
|
import { createStringReader } from '@terrace-lang/js/readers/js-string'
|
||||||
|
|
||||||
|
const input = `
|
||||||
|
object
|
||||||
|
string_property An example string
|
||||||
|
numeric_property 4
|
||||||
|
`
|
||||||
|
|
||||||
|
const output = {
|
||||||
|
string_property: null,
|
||||||
|
numeric_property: null
|
||||||
|
}
|
||||||
|
|
||||||
|
// useDocument returns convenience functions
|
||||||
|
const { next, level, head, tail, match } = useDocument(createStringReader(input))
|
||||||
|
|
||||||
|
// next() parses the next line in the document
|
||||||
|
while (await next()) {
|
||||||
|
// match('object') is equivalent to head() === 'object'
|
||||||
|
// Essentially: "If the current line starts with 'object'"
|
||||||
|
if (match('object')) {
|
||||||
|
const objectLevel = level()
|
||||||
|
// When we call next with a parent level it,
|
||||||
|
// only iterates over lines inside the parent block
|
||||||
|
while (await next(objectLevel)) {
|
||||||
|
// tail() returns the part of the current line after the first space
|
||||||
|
if (match('string_property')) output.string_property = tail()
|
||||||
|
// parseFloat() here the string tail() to a numeric float value
|
||||||
|
if (match('numeric_property')) output.numeric_property = parseFloat(tail())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.dir(output)
|
||||||
|
// { string_property: 'An example string', numeric_property: 4 }
|
||||||
|
|
||||||
|
Markdown
|
||||||
|
Read *all* properties as strings from a Terrace block and write them to an object.
|
||||||
|
CodeBlock javascript
|
||||||
|
// Provides simple convenience functions over the core parser
|
||||||
|
// CommonJS: const { useDocument } = require('@terrace-lang/js/document')
|
||||||
|
import { useDocument } from '@terrace-lang/js/document'
|
||||||
|
// A helper for iterating over a string line-by-line
|
||||||
|
// CommonJS: const { createStringReader } = require('@terrace-lang/js/readers/js-string')
|
||||||
|
import { createStringReader } from '@terrace-lang/js/readers/js-string'
|
||||||
|
|
||||||
|
const input = `
|
||||||
|
object
|
||||||
|
property1 Value 1
|
||||||
|
property2 Value 2
|
||||||
|
random_property igazi3ii4quaC5OdoB5quohnah1beeNg
|
||||||
|
`
|
||||||
|
|
||||||
|
const output = {}
|
||||||
|
|
||||||
|
// useDocument returns convenience functions
|
||||||
|
const { next, level, head, tail, match } = useDocument(createStringReader(input))
|
||||||
|
|
||||||
|
// next() parses the next line in the document
|
||||||
|
while (await next()) {
|
||||||
|
// match('object') is equivalent to head() === 'object'
|
||||||
|
// Essentially: "If the current line starts with 'object'"
|
||||||
|
if (match('object')) {
|
||||||
|
const objectLevel = level()
|
||||||
|
// When we call next with a parent level,
|
||||||
|
// it only iterates over lines inside the parent block
|
||||||
|
while (await next(objectLevel)) {
|
||||||
|
// Skip empty lines
|
||||||
|
if (!line()) continue
|
||||||
|
// Add any properties to the object as strings using the
|
||||||
|
// line head() as the key and tail() as the value
|
||||||
|
output[head()] = tail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.dir(output)
|
||||||
|
// { property1: 'Value 1', property2: 'Value 2', random_property: 'igazi3ii4quaC5OdoB5quohnah1beeNg' }
|
28
docs/src/parser/nodes/Include.js
Normal file
28
docs/src/parser/nodes/Include.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
const { useDocument } = require('@terrace-lang/js/document')
|
||||||
|
const { createFileReader } = require('@terrace-lang/js/readers/node-readline')
|
||||||
|
const fs = require('fs/promises')
|
||||||
|
const path = require('path')
|
||||||
|
const knownNodes = require('./index.js')
|
||||||
|
|
||||||
|
module.exports = async function (originalDoc, rootLevel, ...args) {
|
||||||
|
const includedDoc = useDocument(createFileReader(originalDoc.tail()))
|
||||||
|
const { next, head, tail, level } = includedDoc
|
||||||
|
|
||||||
|
const node = {
|
||||||
|
type: originalDoc.head(),
|
||||||
|
class: '',
|
||||||
|
children: []
|
||||||
|
}
|
||||||
|
|
||||||
|
while (await next()) {
|
||||||
|
if (!head()) continue
|
||||||
|
const block = head()
|
||||||
|
|
||||||
|
if (!knownNodes[block]) continue
|
||||||
|
node.children.push(await knownNodes[block](includedDoc, level(), ...args))
|
||||||
|
}
|
||||||
|
|
||||||
|
console.dir(node)
|
||||||
|
|
||||||
|
return node
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
const parseNode = require('./Node.js')
|
const parseNode = require('./Node.js')
|
||||||
|
|
||||||
|
module.exports.Include = require('./Include.js')
|
||||||
module.exports.Block = parseNode
|
module.exports.Block = parseNode
|
||||||
module.exports.Section = async (doc, rootLevel, ...args) => {
|
module.exports.Section = async (doc, rootLevel, ...args) => {
|
||||||
const variant = doc.tail()
|
const variant = doc.tail()
|
||||||
|
45
pnpm-lock.yaml
generated
45
pnpm-lock.yaml
generated
@ -61,10 +61,13 @@ importers:
|
|||||||
'@terrace-lang/c': workspace:*
|
'@terrace-lang/c': workspace:*
|
||||||
'@terrace-lang/js': workspace:*
|
'@terrace-lang/js': workspace:*
|
||||||
'@terrace-lang/python': workspace:*
|
'@terrace-lang/python': workspace:*
|
||||||
|
chai: ^4.3.7
|
||||||
dependencies:
|
dependencies:
|
||||||
'@terrace-lang/c': link:../packages/c
|
'@terrace-lang/c': link:../packages/c
|
||||||
'@terrace-lang/js': link:../packages/js
|
'@terrace-lang/js': link:../packages/js
|
||||||
'@terrace-lang/python': link:../packages/python
|
'@terrace-lang/python': link:../packages/python
|
||||||
|
devDependencies:
|
||||||
|
chai: 4.3.7
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
@ -1361,6 +1364,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-TaTivMB6pYI1kXwrFlEhLeGfOqoDNdTxjCdwRfFFkEA30Eu+k48W34nlok2EYWJfFFzqaEmichdNM7th6M5HNw==}
|
resolution: {integrity: sha512-TaTivMB6pYI1kXwrFlEhLeGfOqoDNdTxjCdwRfFFkEA30Eu+k48W34nlok2EYWJfFFzqaEmichdNM7th6M5HNw==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/assertion-error/1.1.0:
|
||||||
|
resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/async-each-series/0.1.1:
|
/async-each-series/0.1.1:
|
||||||
resolution: {integrity: sha512-p4jj6Fws4Iy2m0iCmI2am2ZNZCgbdgE+P8F/8csmn2vx7ixXrO2zGcuNsD46X5uZSVecmkEy/M06X2vG8KD6dQ==}
|
resolution: {integrity: sha512-p4jj6Fws4Iy2m0iCmI2am2ZNZCgbdgE+P8F/8csmn2vx7ixXrO2zGcuNsD46X5uZSVecmkEy/M06X2vG8KD6dQ==}
|
||||||
engines: {node: '>=0.8.0'}
|
engines: {node: '>=0.8.0'}
|
||||||
@ -1673,6 +1680,19 @@ packages:
|
|||||||
resolution: {integrity: sha512-qMBmvmQmFXaSxexkjjfMvD5rnDL0+m+dUMZKoDYsGG8iZN29RuYh9eRoMvKsT6uMAWlyUUGDEQGJJYjzCIO9ew==}
|
resolution: {integrity: sha512-qMBmvmQmFXaSxexkjjfMvD5rnDL0+m+dUMZKoDYsGG8iZN29RuYh9eRoMvKsT6uMAWlyUUGDEQGJJYjzCIO9ew==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/chai/4.3.7:
|
||||||
|
resolution: {integrity: sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==}
|
||||||
|
engines: {node: '>=4'}
|
||||||
|
dependencies:
|
||||||
|
assertion-error: 1.1.0
|
||||||
|
check-error: 1.0.2
|
||||||
|
deep-eql: 4.1.3
|
||||||
|
get-func-name: 2.0.0
|
||||||
|
loupe: 2.3.6
|
||||||
|
pathval: 1.1.1
|
||||||
|
type-detect: 4.0.8
|
||||||
|
dev: true
|
||||||
|
|
||||||
/chalk/1.1.3:
|
/chalk/1.1.3:
|
||||||
resolution: {integrity: sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==}
|
resolution: {integrity: sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
@ -1712,6 +1732,10 @@ packages:
|
|||||||
is-regex: 1.1.4
|
is-regex: 1.1.4
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/check-error/1.0.2:
|
||||||
|
resolution: {integrity: sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/chokidar/3.5.3:
|
/chokidar/3.5.3:
|
||||||
resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
|
resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
|
||||||
engines: {node: '>= 8.10.0'}
|
engines: {node: '>= 8.10.0'}
|
||||||
@ -1931,6 +1955,13 @@ packages:
|
|||||||
resolution: {integrity: sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==}
|
resolution: {integrity: sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/deep-eql/4.1.3:
|
||||||
|
resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
dependencies:
|
||||||
|
type-detect: 4.0.8
|
||||||
|
dev: true
|
||||||
|
|
||||||
/deepmerge/4.3.0:
|
/deepmerge/4.3.0:
|
||||||
resolution: {integrity: sha512-z2wJZXrmeHdvYJp/Ux55wIjqo81G5Bp4c+oELTW+7ar6SogWHajt5a9gO3s3IDaGSAXjDk0vlQKN3rms8ab3og==}
|
resolution: {integrity: sha512-z2wJZXrmeHdvYJp/Ux55wIjqo81G5Bp4c+oELTW+7ar6SogWHajt5a9gO3s3IDaGSAXjDk0vlQKN3rms8ab3og==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
@ -2705,6 +2736,10 @@ packages:
|
|||||||
engines: {node: 6.* || 8.* || >= 10.*}
|
engines: {node: 6.* || 8.* || >= 10.*}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/get-func-name/2.0.0:
|
||||||
|
resolution: {integrity: sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/get-intrinsic/1.2.0:
|
/get-intrinsic/1.2.0:
|
||||||
resolution: {integrity: sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==}
|
resolution: {integrity: sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -3893,6 +3928,12 @@ packages:
|
|||||||
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
|
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/loupe/2.3.6:
|
||||||
|
resolution: {integrity: sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==}
|
||||||
|
dependencies:
|
||||||
|
get-func-name: 2.0.0
|
||||||
|
dev: true
|
||||||
|
|
||||||
/lru-cache/4.1.5:
|
/lru-cache/4.1.5:
|
||||||
resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==}
|
resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -4347,6 +4388,10 @@ packages:
|
|||||||
pify: 3.0.0
|
pify: 3.0.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/pathval/1.1.1:
|
||||||
|
resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/picocolors/1.0.0:
|
/picocolors/1.0.0:
|
||||||
resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
|
resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
|
||||||
dev: true
|
dev: true
|
||||||
|
@ -5,8 +5,11 @@
|
|||||||
"test": "NODE_OPTIONS=--experimental-vm-modules NODE_NO_WARNINGS=1 jest"
|
"test": "NODE_OPTIONS=--experimental-vm-modules NODE_NO_WARNINGS=1 jest"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@terrace-lang/js": "workspace:*",
|
|
||||||
"@terrace-lang/c": "workspace:*",
|
"@terrace-lang/c": "workspace:*",
|
||||||
|
"@terrace-lang/js": "workspace:*",
|
||||||
"@terrace-lang/python": "workspace:*"
|
"@terrace-lang/python": "workspace:*"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"chai": "^4.3.7"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user