Merge 68ec70520d into 6739742fb6
This commit is contained in:
commit
e03781198f
5 changed files with 403 additions and 209 deletions
|
|
@ -52,67 +52,91 @@ extern "C" {
|
|||
|
||||
/// Reserve `new_capacity` elements of space in the array. If `new_capacity` is
|
||||
/// less than the array's current capacity, this function has no effect.
|
||||
#define array_reserve(self, new_capacity) \
|
||||
_array__reserve((Array *)(self), array_elem_size(self), new_capacity)
|
||||
#define array_reserve(self, new_capacity) \
|
||||
((self)->contents = _array__reserve( \
|
||||
(void *)(self)->contents, &(self)->capacity, \
|
||||
array_elem_size(self), new_capacity) \
|
||||
)
|
||||
|
||||
/// Free any memory allocated for this array. Note that this does not free any
|
||||
/// memory allocated for the array's contents.
|
||||
#define array_delete(self) _array__delete((Array *)(self))
|
||||
#define array_delete(self) _array__delete((self), (void *)(self)->contents, sizeof(*self))
|
||||
|
||||
/// Push a new `element` onto the end of the array.
|
||||
#define array_push(self, element) \
|
||||
(_array__grow((Array *)(self), 1, array_elem_size(self)), \
|
||||
(self)->contents[(self)->size++] = (element))
|
||||
#define array_push(self, element) \
|
||||
do { \
|
||||
(self)->contents = _array__grow( \
|
||||
(void *)(self)->contents, (self)->size, &(self)->capacity, \
|
||||
1, array_elem_size(self) \
|
||||
); \
|
||||
(self)->contents[(self)->size++] = (element); \
|
||||
} while(0)
|
||||
|
||||
/// Increase the array's size by `count` elements.
|
||||
/// New elements are zero-initialized.
|
||||
#define array_grow_by(self, count) \
|
||||
do { \
|
||||
if ((count) == 0) break; \
|
||||
_array__grow((Array *)(self), count, array_elem_size(self)); \
|
||||
#define array_grow_by(self, count) \
|
||||
do { \
|
||||
if ((count) == 0) break; \
|
||||
(self)->contents = _array__grow( \
|
||||
(self)->contents, (self)->size, &(self)->capacity, \
|
||||
count, array_elem_size(self) \
|
||||
); \
|
||||
memset((self)->contents + (self)->size, 0, (count) * array_elem_size(self)); \
|
||||
(self)->size += (count); \
|
||||
(self)->size += (count); \
|
||||
} while (0)
|
||||
|
||||
/// Append all elements from one array to the end of another.
|
||||
#define array_push_all(self, other) \
|
||||
#define array_push_all(self, other) \
|
||||
array_extend((self), (other)->size, (other)->contents)
|
||||
|
||||
/// Append `count` elements to the end of the array, reading their values from the
|
||||
/// `contents` pointer.
|
||||
#define array_extend(self, count, contents) \
|
||||
_array__splice( \
|
||||
(Array *)(self), array_elem_size(self), (self)->size, \
|
||||
0, count, contents \
|
||||
#define array_extend(self, count, other_contents) \
|
||||
(self)->contents = _array__splice( \
|
||||
(void*)(self)->contents, &(self)->size, &(self)->capacity, \
|
||||
array_elem_size(self), (self)->size, 0, count, other_contents \
|
||||
)
|
||||
|
||||
/// Remove `old_count` elements from the array starting at the given `index`. At
|
||||
/// the same index, insert `new_count` new elements, reading their values from the
|
||||
/// `new_contents` pointer.
|
||||
#define array_splice(self, _index, old_count, new_count, new_contents) \
|
||||
_array__splice( \
|
||||
(Array *)(self), array_elem_size(self), _index, \
|
||||
old_count, new_count, new_contents \
|
||||
#define array_splice(self, _index, old_count, new_count, new_contents) \
|
||||
(self)->contents = _array__splice( \
|
||||
(void *)(self)->contents, &(self)->size, &(self)->capacity, \
|
||||
array_elem_size(self), _index, old_count, new_count, new_contents \
|
||||
)
|
||||
|
||||
/// Insert one `element` into the array at the given `index`.
|
||||
#define array_insert(self, _index, element) \
|
||||
_array__splice((Array *)(self), array_elem_size(self), _index, 0, 1, &(element))
|
||||
#define array_insert(self, _index, element) \
|
||||
(self)->contents = _array__splice( \
|
||||
(void *)(self)->contents, &(self)->size, &(self)->capacity, \
|
||||
array_elem_size(self), _index, 0, 1, &(element) \
|
||||
)
|
||||
|
||||
/// Remove one element from the array at the given `index`.
|
||||
#define array_erase(self, _index) \
|
||||
_array__erase((Array *)(self), array_elem_size(self), _index)
|
||||
_array__erase((void *)(self)->contents, &(self)->size, array_elem_size(self), _index)
|
||||
|
||||
/// Pop the last element off the array, returning the element by value.
|
||||
#define array_pop(self) ((self)->contents[--(self)->size])
|
||||
|
||||
/// Assign the contents of one array to another, reallocating if necessary.
|
||||
#define array_assign(self, other) \
|
||||
_array__assign((Array *)(self), (const Array *)(other), array_elem_size(self))
|
||||
#define array_assign(self, other) \
|
||||
(self)->contents = _array__assign( \
|
||||
(void *)(self)->contents, &(self)->size, &(self)->capacity, \
|
||||
(const void *)(other)->contents, (other)->size, array_elem_size(self) \
|
||||
)
|
||||
|
||||
/// Swap one array with another
|
||||
#define array_swap(self, other) \
|
||||
_array__swap((Array *)(self), (Array *)(other))
|
||||
#define array_swap(self, other) \
|
||||
do { \
|
||||
struct Swap swapped_contents = _array__swap( \
|
||||
(void *)(self)->contents, &(self)->size, &(self)->capacity, \
|
||||
(void *)(other)->contents, &(other)->size, &(other)->capacity \
|
||||
); \
|
||||
(self)->contents = swapped_contents.self_contents; \
|
||||
(other)->contents = swapped_contents.other_contents; \
|
||||
} while (0)
|
||||
|
||||
/// Get the size of the array contents
|
||||
#define array_elem_size(self) (sizeof *(self)->contents)
|
||||
|
|
@ -157,82 +181,112 @@ extern "C" {
|
|||
|
||||
// Private
|
||||
|
||||
typedef Array(void) Array;
|
||||
// Pointers to individual `Array` fields (rather than the entire `Array` itself)
|
||||
// are passed to the various `_array__*` functions below to address strict aliasing
|
||||
// violations that arises when the _entire_ `Array` struct is passed as `Array(void)*`.
|
||||
//
|
||||
// The `Array` type itself was not altered as a solution in order to avoid breakage
|
||||
// with existing consumers (in particular, parsers with external scanners).
|
||||
|
||||
/// This is not what you're looking for, see `array_delete`.
|
||||
static inline void _array__delete(Array *self) {
|
||||
if (self->contents) {
|
||||
ts_free(self->contents);
|
||||
self->contents = NULL;
|
||||
self->size = 0;
|
||||
self->capacity = 0;
|
||||
}
|
||||
static inline void _array__delete(void *self, void *contents, size_t self_size) {
|
||||
if (contents) ts_free(contents);
|
||||
if (self) memset(self, 0, self_size);
|
||||
}
|
||||
|
||||
/// This is not what you're looking for, see `array_erase`.
|
||||
static inline void _array__erase(Array *self, size_t element_size,
|
||||
uint32_t index) {
|
||||
assert(index < self->size);
|
||||
char *contents = (char *)self->contents;
|
||||
static inline void _array__erase(void* self_contents, uint32_t *size,
|
||||
size_t element_size, uint32_t index) {
|
||||
assert(index < *size);
|
||||
char *contents = (char *)self_contents;
|
||||
memmove(contents + index * element_size, contents + (index + 1) * element_size,
|
||||
(self->size - index - 1) * element_size);
|
||||
self->size--;
|
||||
(*size - index - 1) * element_size);
|
||||
(*size)--;
|
||||
}
|
||||
|
||||
/// This is not what you're looking for, see `array_reserve`.
|
||||
static inline void _array__reserve(Array *self, size_t element_size, uint32_t new_capacity) {
|
||||
if (new_capacity > self->capacity) {
|
||||
if (self->contents) {
|
||||
self->contents = ts_realloc(self->contents, new_capacity * element_size);
|
||||
static inline void *_array__reserve(void *contents, uint32_t *capacity,
|
||||
size_t element_size, uint32_t new_capacity) {
|
||||
void *new_contents = contents;
|
||||
if (new_capacity > *capacity) {
|
||||
if (contents) {
|
||||
new_contents = ts_realloc(contents, new_capacity * element_size);
|
||||
} else {
|
||||
self->contents = ts_malloc(new_capacity * element_size);
|
||||
new_contents = ts_malloc(new_capacity * element_size);
|
||||
}
|
||||
self->capacity = new_capacity;
|
||||
*capacity = new_capacity;
|
||||
}
|
||||
return new_contents;
|
||||
}
|
||||
|
||||
/// This is not what you're looking for, see `array_assign`.
|
||||
static inline void _array__assign(Array *self, const Array *other, size_t element_size) {
|
||||
_array__reserve(self, element_size, other->size);
|
||||
self->size = other->size;
|
||||
memcpy(self->contents, other->contents, self->size * element_size);
|
||||
static inline void *_array__assign(void* self_contents, uint32_t *self_size, uint32_t *self_capacity,
|
||||
const void *other_contents, uint32_t other_size, size_t element_size) {
|
||||
void *new_contents = _array__reserve(self_contents, self_capacity, element_size, other_size);
|
||||
*self_size = other_size;
|
||||
memcpy(new_contents, other_contents, *self_size * element_size);
|
||||
return new_contents;
|
||||
}
|
||||
|
||||
struct Swap {
|
||||
void *self_contents;
|
||||
void *other_contents;
|
||||
};
|
||||
|
||||
/// This is not what you're looking for, see `array_swap`.
|
||||
static inline void _array__swap(Array *self, Array *other) {
|
||||
Array swap = *other;
|
||||
*other = *self;
|
||||
*self = swap;
|
||||
// static inline void _array__swap(Array *self, Array *other) {
|
||||
static inline struct Swap _array__swap(void *self_contents, uint32_t *self_size, uint32_t *self_capacity,
|
||||
void *other_contents, uint32_t *other_size, uint32_t *other_capacity) {
|
||||
void *new_self_contents = other_contents;
|
||||
uint32_t new_self_size = *other_size;
|
||||
uint32_t new_self_capacity = *other_capacity;
|
||||
|
||||
void *new_other_contents = self_contents;
|
||||
*other_size = *self_size;
|
||||
*other_capacity = *self_capacity;
|
||||
|
||||
*self_size = new_self_size;
|
||||
*self_capacity = new_self_capacity;
|
||||
|
||||
struct Swap out = {
|
||||
.self_contents = new_self_contents,
|
||||
.other_contents = new_other_contents,
|
||||
};
|
||||
return out;
|
||||
}
|
||||
|
||||
/// This is not what you're looking for, see `array_push` or `array_grow_by`.
|
||||
static inline void _array__grow(Array *self, uint32_t count, size_t element_size) {
|
||||
uint32_t new_size = self->size + count;
|
||||
if (new_size > self->capacity) {
|
||||
uint32_t new_capacity = self->capacity * 2;
|
||||
static inline void *_array__grow(void *contents, uint32_t size, uint32_t *capacity,
|
||||
uint32_t count, size_t element_size) {
|
||||
void *new_contents = contents;
|
||||
uint32_t new_size = size + count;
|
||||
if (new_size > *capacity) {
|
||||
uint32_t new_capacity = *capacity * 2;
|
||||
if (new_capacity < 8) new_capacity = 8;
|
||||
if (new_capacity < new_size) new_capacity = new_size;
|
||||
_array__reserve(self, element_size, new_capacity);
|
||||
new_contents = _array__reserve(contents, capacity, element_size, new_capacity);
|
||||
}
|
||||
return new_contents;
|
||||
}
|
||||
|
||||
/// This is not what you're looking for, see `array_splice`.
|
||||
static inline void _array__splice(Array *self, size_t element_size,
|
||||
static inline void *_array__splice(void *self_contents, uint32_t *size, uint32_t *capacity,
|
||||
size_t element_size,
|
||||
uint32_t index, uint32_t old_count,
|
||||
uint32_t new_count, const void *elements) {
|
||||
uint32_t new_size = self->size + new_count - old_count;
|
||||
uint32_t new_size = *size + new_count - old_count;
|
||||
uint32_t old_end = index + old_count;
|
||||
uint32_t new_end = index + new_count;
|
||||
assert(old_end <= self->size);
|
||||
assert(old_end <= *size);
|
||||
|
||||
_array__reserve(self, element_size, new_size);
|
||||
void *new_contents = _array__reserve(self_contents, capacity, element_size, new_size);
|
||||
|
||||
char *contents = (char *)self->contents;
|
||||
if (self->size > old_end) {
|
||||
char *contents = (char *)new_contents;
|
||||
if (*size > old_end) {
|
||||
memmove(
|
||||
contents + new_end * element_size,
|
||||
contents + old_end * element_size,
|
||||
(self->size - old_end) * element_size
|
||||
(*size - old_end) * element_size
|
||||
);
|
||||
}
|
||||
if (new_count > 0) {
|
||||
|
|
@ -250,7 +304,9 @@ static inline void _array__splice(Array *self, size_t element_size,
|
|||
);
|
||||
}
|
||||
}
|
||||
self->size += new_count - old_count;
|
||||
*size += new_count - old_count;
|
||||
|
||||
return new_contents;
|
||||
}
|
||||
|
||||
/// A binary search routine, based on Rust's `std::slice::binary_search_by`.
|
||||
|
|
|
|||
|
|
@ -1,19 +1,74 @@
|
|||
use crate::{bail_on_err, root_dir, FetchFixtures, EMSCRIPTEN_VERSION};
|
||||
use crate::{bail_on_err, root_dir, EMSCRIPTEN_VERSION};
|
||||
use anyhow::Result;
|
||||
use std::{fs, process::Command};
|
||||
use std::{fs, path::Path, process::Command};
|
||||
|
||||
pub fn run_fixtures(args: &FetchFixtures) -> Result<()> {
|
||||
enum FixtureRef<'a> {
|
||||
Tag(&'a str),
|
||||
Branch(&'a str),
|
||||
}
|
||||
|
||||
impl<'a> FixtureRef<'a> {
|
||||
#[allow(clippy::use_self)]
|
||||
const fn new(tag: &'a str, branch: Option<&'a str>) -> FixtureRef<'a> {
|
||||
if let Some(b) = branch {
|
||||
Self::Branch(b)
|
||||
} else {
|
||||
Self::Tag(tag)
|
||||
}
|
||||
}
|
||||
|
||||
const fn ref_type(&self) -> &'static str {
|
||||
match self {
|
||||
FixtureRef::Tag(_) => "tag",
|
||||
FixtureRef::Branch(_) => "branch",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for FixtureRef<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
FixtureRef::Tag(tag) => write!(f, "{tag}"),
|
||||
FixtureRef::Branch(branch) => write!(f, "{branch}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn current_ref_name(grammar_dir: &Path) -> Result<(String, Option<&'static str>)> {
|
||||
let tag_args = ["describe", "--tags", "--exact-match", "HEAD"];
|
||||
let branch_args = ["rev-parse", "--abbrev-ref", "HEAD"];
|
||||
|
||||
for (args, ref_type) in [tag_args.as_ref(), branch_args.as_ref()]
|
||||
.iter()
|
||||
.zip(&["tag", "branch"])
|
||||
{
|
||||
let name_cmd = Command::new("git")
|
||||
.current_dir(grammar_dir)
|
||||
.args(*args)
|
||||
.output()?;
|
||||
let name = String::from_utf8_lossy(&name_cmd.stdout);
|
||||
let name = name.trim();
|
||||
if !name.is_empty() {
|
||||
return Ok((name.to_string(), Some(ref_type)));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(("<unknown>".to_string(), None))
|
||||
}
|
||||
|
||||
pub fn run_fixtures() -> Result<()> {
|
||||
let fixtures_dir = root_dir().join("test").join("fixtures");
|
||||
let grammars_dir = fixtures_dir.join("grammars");
|
||||
let fixtures_path = fixtures_dir.join("fixtures.json");
|
||||
|
||||
// grammar name, tag
|
||||
let mut fixtures: Vec<(String, String)> =
|
||||
// grammar name, tag, [branch]
|
||||
let fixtures: Vec<(String, String, Option<String>)> =
|
||||
serde_json::from_str(&fs::read_to_string(&fixtures_path)?)?;
|
||||
|
||||
for (grammar, tag) in &mut fixtures {
|
||||
let grammar_dir = grammars_dir.join(&grammar);
|
||||
for (grammar, tag, branch) in &fixtures {
|
||||
let grammar_dir = grammars_dir.join(grammar);
|
||||
let grammar_url = format!("https://github.com/tree-sitter/tree-sitter-{grammar}");
|
||||
let target_ref = FixtureRef::new(tag, branch.as_deref());
|
||||
|
||||
println!("Fetching the {grammar} grammar...");
|
||||
|
||||
|
|
@ -24,7 +79,7 @@ pub fn run_fixtures(args: &FetchFixtures) -> Result<()> {
|
|||
"--depth",
|
||||
"1",
|
||||
"--branch",
|
||||
tag,
|
||||
&target_ref.to_string(),
|
||||
&grammar_url,
|
||||
&grammar_dir.to_string_lossy(),
|
||||
]);
|
||||
|
|
@ -33,31 +88,71 @@ pub fn run_fixtures(args: &FetchFixtures) -> Result<()> {
|
|||
&format!("Failed to clone the {grammar} grammar"),
|
||||
)?;
|
||||
} else {
|
||||
let mut describe_command = Command::new("git");
|
||||
describe_command.current_dir(&grammar_dir).args([
|
||||
"describe",
|
||||
"--tags",
|
||||
"--exact-match",
|
||||
"HEAD",
|
||||
]);
|
||||
let (current_ref, current_ref_type) = current_ref_name(&grammar_dir)?;
|
||||
if current_ref != target_ref.to_string() {
|
||||
println!(
|
||||
"Updating {grammar} grammar from {} {current_ref} to {} {target_ref}...",
|
||||
current_ref_type.unwrap_or("<unknown>"),
|
||||
target_ref.ref_type(),
|
||||
);
|
||||
|
||||
let output = describe_command.output()?;
|
||||
let current_tag = String::from_utf8_lossy(&output.stdout);
|
||||
let current_tag = current_tag.trim();
|
||||
|
||||
if current_tag != tag {
|
||||
println!("Updating {grammar} grammar from {current_tag} to {tag}...");
|
||||
|
||||
let mut fetch_command = Command::new("git");
|
||||
fetch_command.current_dir(&grammar_dir).args([
|
||||
"fetch",
|
||||
"origin",
|
||||
&format!("refs/tags/{tag}:refs/tags/{tag}"),
|
||||
]);
|
||||
bail_on_err(
|
||||
&fetch_command.spawn()?.wait_with_output()?,
|
||||
&format!("Failed to fetch tag {tag} for {grammar} grammar"),
|
||||
)?;
|
||||
match target_ref {
|
||||
FixtureRef::Branch(branch) => {
|
||||
let mut fetch_cmd = Command::new("git");
|
||||
fetch_cmd.current_dir(&grammar_dir).args([
|
||||
"fetch",
|
||||
"--update-shallow",
|
||||
"origin",
|
||||
&format!("+refs/heads/{branch}:refs/remotes/origin/{branch}"),
|
||||
]);
|
||||
bail_on_err(
|
||||
&fetch_cmd.spawn()?.wait_with_output()?,
|
||||
&format!("Failed to fetch branch {branch}"),
|
||||
)?;
|
||||
let mut switch_cmd = Command::new("git");
|
||||
switch_cmd
|
||||
.current_dir(&grammar_dir)
|
||||
.args(["switch", branch]);
|
||||
bail_on_err(
|
||||
&switch_cmd.spawn()?.wait_with_output()?,
|
||||
&format!("Failed to checkout branch {branch}"),
|
||||
)?;
|
||||
let mut set_upstream_cmd = Command::new("git");
|
||||
set_upstream_cmd.current_dir(&grammar_dir).args([
|
||||
"branch",
|
||||
"--set-upstream-to",
|
||||
&format!("origin/{branch}"),
|
||||
branch,
|
||||
]);
|
||||
bail_on_err(
|
||||
&set_upstream_cmd.spawn()?.wait_with_output()?,
|
||||
&format!("Failed to set upstream for branch {branch}"),
|
||||
)?;
|
||||
let mut pull_cmd = Command::new("git");
|
||||
pull_cmd
|
||||
.current_dir(&grammar_dir)
|
||||
.args(["pull", "origin", branch]);
|
||||
bail_on_err(
|
||||
&pull_cmd.spawn()?.wait_with_output()?,
|
||||
&format!("Failed to pull latest from branch {branch}"),
|
||||
)?;
|
||||
}
|
||||
FixtureRef::Tag(tag) => {
|
||||
let mut fetch_command = Command::new("git");
|
||||
fetch_command.current_dir(&grammar_dir).args([
|
||||
"fetch",
|
||||
"origin",
|
||||
&format!("refs/tags/{tag}:refs/tags/{tag}"),
|
||||
]);
|
||||
bail_on_err(
|
||||
&fetch_command.spawn()?.wait_with_output()?,
|
||||
&format!(
|
||||
"Failed to fetch {} {target_ref} for {grammar} grammar",
|
||||
target_ref.ref_type()
|
||||
),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
let mut reset_command = Command::new("git");
|
||||
reset_command
|
||||
|
|
@ -71,29 +166,23 @@ pub fn run_fixtures(args: &FetchFixtures) -> Result<()> {
|
|||
let mut checkout_command = Command::new("git");
|
||||
checkout_command
|
||||
.current_dir(&grammar_dir)
|
||||
.args(["checkout", tag]);
|
||||
.args(["checkout", &target_ref.to_string()]);
|
||||
bail_on_err(
|
||||
&checkout_command.spawn()?.wait_with_output()?,
|
||||
&format!("Failed to checkout tag {tag} for {grammar} grammar"),
|
||||
&format!(
|
||||
"Failed to checkout {} {target_ref} for {grammar} grammar",
|
||||
target_ref.ref_type()
|
||||
),
|
||||
)?;
|
||||
} else {
|
||||
println!("{grammar} grammar is already at tag {tag}");
|
||||
println!(
|
||||
"{grammar} grammar is already at {} {target_ref}",
|
||||
target_ref.ref_type()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if args.update {
|
||||
println!("Updating the fixtures lock file");
|
||||
fs::write(
|
||||
&fixtures_path,
|
||||
// format the JSON without extra newlines
|
||||
serde_json::to_string(&fixtures)?
|
||||
.replace("[[", "[\n [")
|
||||
.replace("],", "],\n ")
|
||||
.replace("]]", "]\n]"),
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ enum Commands {
|
|||
/// Fetches emscripten.
|
||||
FetchEmscripten,
|
||||
/// Fetches the fixtures for testing tree-sitter.
|
||||
FetchFixtures(FetchFixtures),
|
||||
FetchFixtures,
|
||||
/// Generate the Rust bindings from the C library.
|
||||
GenerateBindings,
|
||||
/// Generates the fixtures for testing tree-sitter.
|
||||
|
|
@ -118,13 +118,6 @@ struct Clippy {
|
|||
package: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
struct FetchFixtures {
|
||||
/// Update all fixtures to the latest tag
|
||||
#[arg(long, short)]
|
||||
update: bool,
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
struct GenerateFixtures {
|
||||
/// Generates the parser to Wasm
|
||||
|
|
@ -232,8 +225,8 @@ fn run() -> Result<()> {
|
|||
Commands::CheckWasmExports(check_options) => check_wasm_exports::run(&check_options)?,
|
||||
Commands::Clippy(clippy_options) => clippy::run(&clippy_options)?,
|
||||
Commands::FetchEmscripten => fetch::run_emscripten()?,
|
||||
Commands::FetchFixtures(fetch_fixture_options) => {
|
||||
fetch::run_fixtures(&fetch_fixture_options)?;
|
||||
Commands::FetchFixtures => {
|
||||
fetch::run_fixtures()?;
|
||||
}
|
||||
Commands::GenerateBindings => generate::run_bindings()?,
|
||||
Commands::GenerateFixtures(generate_fixtures_options) => {
|
||||
|
|
|
|||
192
lib/src/array.h
192
lib/src/array.h
|
|
@ -52,67 +52,91 @@ extern "C" {
|
|||
|
||||
/// Reserve `new_capacity` elements of space in the array. If `new_capacity` is
|
||||
/// less than the array's current capacity, this function has no effect.
|
||||
#define array_reserve(self, new_capacity) \
|
||||
_array__reserve((Array *)(self), array_elem_size(self), new_capacity)
|
||||
#define array_reserve(self, new_capacity) \
|
||||
((self)->contents = _array__reserve( \
|
||||
(void *)(self)->contents, &(self)->capacity, \
|
||||
array_elem_size(self), new_capacity) \
|
||||
)
|
||||
|
||||
/// Free any memory allocated for this array. Note that this does not free any
|
||||
/// memory allocated for the array's contents.
|
||||
#define array_delete(self) _array__delete((Array *)(self))
|
||||
#define array_delete(self) _array__delete((self), (void *)(self)->contents, sizeof(*self))
|
||||
|
||||
/// Push a new `element` onto the end of the array.
|
||||
#define array_push(self, element) \
|
||||
(_array__grow((Array *)(self), 1, array_elem_size(self)), \
|
||||
(self)->contents[(self)->size++] = (element))
|
||||
#define array_push(self, element) \
|
||||
do { \
|
||||
(self)->contents = _array__grow( \
|
||||
(void *)(self)->contents, (self)->size, &(self)->capacity, \
|
||||
1, array_elem_size(self) \
|
||||
); \
|
||||
(self)->contents[(self)->size++] = (element); \
|
||||
} while(0)
|
||||
|
||||
/// Increase the array's size by `count` elements.
|
||||
/// New elements are zero-initialized.
|
||||
#define array_grow_by(self, count) \
|
||||
do { \
|
||||
if ((count) == 0) break; \
|
||||
_array__grow((Array *)(self), count, array_elem_size(self)); \
|
||||
#define array_grow_by(self, count) \
|
||||
do { \
|
||||
if ((count) == 0) break; \
|
||||
(self)->contents = _array__grow( \
|
||||
(self)->contents, (self)->size, &(self)->capacity, \
|
||||
count, array_elem_size(self) \
|
||||
); \
|
||||
memset((self)->contents + (self)->size, 0, (count) * array_elem_size(self)); \
|
||||
(self)->size += (count); \
|
||||
(self)->size += (count); \
|
||||
} while (0)
|
||||
|
||||
/// Append all elements from one array to the end of another.
|
||||
#define array_push_all(self, other) \
|
||||
#define array_push_all(self, other) \
|
||||
array_extend((self), (other)->size, (other)->contents)
|
||||
|
||||
/// Append `count` elements to the end of the array, reading their values from the
|
||||
/// `contents` pointer.
|
||||
#define array_extend(self, count, contents) \
|
||||
_array__splice( \
|
||||
(Array *)(self), array_elem_size(self), (self)->size, \
|
||||
0, count, contents \
|
||||
#define array_extend(self, count, other_contents) \
|
||||
(self)->contents = _array__splice( \
|
||||
(void*)(self)->contents, &(self)->size, &(self)->capacity, \
|
||||
array_elem_size(self), (self)->size, 0, count, other_contents \
|
||||
)
|
||||
|
||||
/// Remove `old_count` elements from the array starting at the given `index`. At
|
||||
/// the same index, insert `new_count` new elements, reading their values from the
|
||||
/// `new_contents` pointer.
|
||||
#define array_splice(self, _index, old_count, new_count, new_contents) \
|
||||
_array__splice( \
|
||||
(Array *)(self), array_elem_size(self), _index, \
|
||||
old_count, new_count, new_contents \
|
||||
#define array_splice(self, _index, old_count, new_count, new_contents) \
|
||||
(self)->contents = _array__splice( \
|
||||
(void *)(self)->contents, &(self)->size, &(self)->capacity, \
|
||||
array_elem_size(self), _index, old_count, new_count, new_contents \
|
||||
)
|
||||
|
||||
/// Insert one `element` into the array at the given `index`.
|
||||
#define array_insert(self, _index, element) \
|
||||
_array__splice((Array *)(self), array_elem_size(self), _index, 0, 1, &(element))
|
||||
#define array_insert(self, _index, element) \
|
||||
(self)->contents = _array__splice( \
|
||||
(void *)(self)->contents, &(self)->size, &(self)->capacity, \
|
||||
array_elem_size(self), _index, 0, 1, &(element) \
|
||||
)
|
||||
|
||||
/// Remove one element from the array at the given `index`.
|
||||
#define array_erase(self, _index) \
|
||||
_array__erase((Array *)(self), array_elem_size(self), _index)
|
||||
_array__erase((void *)(self)->contents, &(self)->size, array_elem_size(self), _index)
|
||||
|
||||
/// Pop the last element off the array, returning the element by value.
|
||||
#define array_pop(self) ((self)->contents[--(self)->size])
|
||||
|
||||
/// Assign the contents of one array to another, reallocating if necessary.
|
||||
#define array_assign(self, other) \
|
||||
_array__assign((Array *)(self), (const Array *)(other), array_elem_size(self))
|
||||
#define array_assign(self, other) \
|
||||
(self)->contents = _array__assign( \
|
||||
(void *)(self)->contents, &(self)->size, &(self)->capacity, \
|
||||
(const void *)(other)->contents, (other)->size, array_elem_size(self) \
|
||||
)
|
||||
|
||||
/// Swap one array with another
|
||||
#define array_swap(self, other) \
|
||||
_array__swap((Array *)(self), (Array *)(other))
|
||||
#define array_swap(self, other) \
|
||||
do { \
|
||||
struct Swap swapped_contents = _array__swap( \
|
||||
(void *)(self)->contents, &(self)->size, &(self)->capacity, \
|
||||
(void *)(other)->contents, &(other)->size, &(other)->capacity \
|
||||
); \
|
||||
(self)->contents = swapped_contents.self_contents; \
|
||||
(other)->contents = swapped_contents.other_contents; \
|
||||
} while (0)
|
||||
|
||||
/// Get the size of the array contents
|
||||
#define array_elem_size(self) (sizeof *(self)->contents)
|
||||
|
|
@ -157,82 +181,112 @@ extern "C" {
|
|||
|
||||
// Private
|
||||
|
||||
typedef Array(void) Array;
|
||||
// Pointers to individual `Array` fields (rather than the entire `Array` itself)
|
||||
// are passed to the various `_array__*` functions below to address strict aliasing
|
||||
// violations that arises when the _entire_ `Array` struct is passed as `Array(void)*`.
|
||||
//
|
||||
// The `Array` type itself was not altered as a solution in order to avoid breakage
|
||||
// with existing consumers (in particular, parsers with external scanners).
|
||||
|
||||
/// This is not what you're looking for, see `array_delete`.
|
||||
static inline void _array__delete(Array *self) {
|
||||
if (self->contents) {
|
||||
ts_free(self->contents);
|
||||
self->contents = NULL;
|
||||
self->size = 0;
|
||||
self->capacity = 0;
|
||||
}
|
||||
static inline void _array__delete(void *self, void *contents, size_t self_size) {
|
||||
if (contents) ts_free(contents);
|
||||
if (self) memset(self, 0, self_size);
|
||||
}
|
||||
|
||||
/// This is not what you're looking for, see `array_erase`.
|
||||
static inline void _array__erase(Array *self, size_t element_size,
|
||||
uint32_t index) {
|
||||
ts_assert(index < self->size);
|
||||
char *contents = (char *)self->contents;
|
||||
static inline void _array__erase(void* self_contents, uint32_t *size,
|
||||
size_t element_size, uint32_t index) {
|
||||
ts_assert(index < *size);
|
||||
char *contents = (char *)self_contents;
|
||||
memmove(contents + index * element_size, contents + (index + 1) * element_size,
|
||||
(self->size - index - 1) * element_size);
|
||||
self->size--;
|
||||
(*size - index - 1) * element_size);
|
||||
(*size)--;
|
||||
}
|
||||
|
||||
/// This is not what you're looking for, see `array_reserve`.
|
||||
static inline void _array__reserve(Array *self, size_t element_size, uint32_t new_capacity) {
|
||||
if (new_capacity > self->capacity) {
|
||||
if (self->contents) {
|
||||
self->contents = ts_realloc(self->contents, new_capacity * element_size);
|
||||
static inline void *_array__reserve(void *contents, uint32_t *capacity,
|
||||
size_t element_size, uint32_t new_capacity) {
|
||||
void *new_contents = contents;
|
||||
if (new_capacity > *capacity) {
|
||||
if (contents) {
|
||||
new_contents = ts_realloc(contents, new_capacity * element_size);
|
||||
} else {
|
||||
self->contents = ts_malloc(new_capacity * element_size);
|
||||
new_contents = ts_malloc(new_capacity * element_size);
|
||||
}
|
||||
self->capacity = new_capacity;
|
||||
*capacity = new_capacity;
|
||||
}
|
||||
return new_contents;
|
||||
}
|
||||
|
||||
/// This is not what you're looking for, see `array_assign`.
|
||||
static inline void _array__assign(Array *self, const Array *other, size_t element_size) {
|
||||
_array__reserve(self, element_size, other->size);
|
||||
self->size = other->size;
|
||||
memcpy(self->contents, other->contents, self->size * element_size);
|
||||
static inline void *_array__assign(void* self_contents, uint32_t *self_size, uint32_t *self_capacity,
|
||||
const void *other_contents, uint32_t other_size, size_t element_size) {
|
||||
void *new_contents = _array__reserve(self_contents, self_capacity, element_size, other_size);
|
||||
*self_size = other_size;
|
||||
memcpy(new_contents, other_contents, *self_size * element_size);
|
||||
return new_contents;
|
||||
}
|
||||
|
||||
struct Swap {
|
||||
void *self_contents;
|
||||
void *other_contents;
|
||||
};
|
||||
|
||||
/// This is not what you're looking for, see `array_swap`.
|
||||
static inline void _array__swap(Array *self, Array *other) {
|
||||
Array swap = *other;
|
||||
*other = *self;
|
||||
*self = swap;
|
||||
// static inline void _array__swap(Array *self, Array *other) {
|
||||
static inline struct Swap _array__swap(void *self_contents, uint32_t *self_size, uint32_t *self_capacity,
|
||||
void *other_contents, uint32_t *other_size, uint32_t *other_capacity) {
|
||||
void *new_self_contents = other_contents;
|
||||
uint32_t new_self_size = *other_size;
|
||||
uint32_t new_self_capacity = *other_capacity;
|
||||
|
||||
void *new_other_contents = self_contents;
|
||||
*other_size = *self_size;
|
||||
*other_capacity = *self_capacity;
|
||||
|
||||
*self_size = new_self_size;
|
||||
*self_capacity = new_self_capacity;
|
||||
|
||||
struct Swap out = {
|
||||
.self_contents = new_self_contents,
|
||||
.other_contents = new_other_contents,
|
||||
};
|
||||
return out;
|
||||
}
|
||||
|
||||
/// This is not what you're looking for, see `array_push` or `array_grow_by`.
|
||||
static inline void _array__grow(Array *self, uint32_t count, size_t element_size) {
|
||||
uint32_t new_size = self->size + count;
|
||||
if (new_size > self->capacity) {
|
||||
uint32_t new_capacity = self->capacity * 2;
|
||||
static inline void *_array__grow(void *contents, uint32_t size, uint32_t *capacity,
|
||||
uint32_t count, size_t element_size) {
|
||||
void *new_contents = contents;
|
||||
uint32_t new_size = size + count;
|
||||
if (new_size > *capacity) {
|
||||
uint32_t new_capacity = *capacity * 2;
|
||||
if (new_capacity < 8) new_capacity = 8;
|
||||
if (new_capacity < new_size) new_capacity = new_size;
|
||||
_array__reserve(self, element_size, new_capacity);
|
||||
new_contents = _array__reserve(contents, capacity, element_size, new_capacity);
|
||||
}
|
||||
return new_contents;
|
||||
}
|
||||
|
||||
/// This is not what you're looking for, see `array_splice`.
|
||||
static inline void _array__splice(Array *self, size_t element_size,
|
||||
static inline void *_array__splice(void *self_contents, uint32_t *size, uint32_t *capacity,
|
||||
size_t element_size,
|
||||
uint32_t index, uint32_t old_count,
|
||||
uint32_t new_count, const void *elements) {
|
||||
uint32_t new_size = self->size + new_count - old_count;
|
||||
uint32_t new_size = *size + new_count - old_count;
|
||||
uint32_t old_end = index + old_count;
|
||||
uint32_t new_end = index + new_count;
|
||||
ts_assert(old_end <= self->size);
|
||||
ts_assert(old_end <= *size);
|
||||
|
||||
_array__reserve(self, element_size, new_size);
|
||||
void *new_contents = _array__reserve(self_contents, capacity, element_size, new_size);
|
||||
|
||||
char *contents = (char *)self->contents;
|
||||
if (self->size > old_end) {
|
||||
char *contents = (char *)new_contents;
|
||||
if (*size > old_end) {
|
||||
memmove(
|
||||
contents + new_end * element_size,
|
||||
contents + old_end * element_size,
|
||||
(self->size - old_end) * element_size
|
||||
(*size - old_end) * element_size
|
||||
);
|
||||
}
|
||||
if (new_count > 0) {
|
||||
|
|
@ -250,7 +304,9 @@ static inline void _array__splice(Array *self, size_t element_size,
|
|||
);
|
||||
}
|
||||
}
|
||||
self->size += new_count - old_count;
|
||||
*size += new_count - old_count;
|
||||
|
||||
return new_contents;
|
||||
}
|
||||
|
||||
/// A binary search routine, based on Rust's `std::slice::binary_search_by`.
|
||||
|
|
|
|||
32
test/fixtures/fixtures.json
vendored
32
test/fixtures/fixtures.json
vendored
|
|
@ -1,17 +1,17 @@
|
|||
[
|
||||
["bash","v0.25.0"],
|
||||
["c","v0.24.1"],
|
||||
["cpp","v0.23.4"],
|
||||
["embedded-template","v0.25.0"],
|
||||
["go","v0.25.0"],
|
||||
["html","v0.23.2"],
|
||||
["java","v0.23.5"],
|
||||
["javascript","v0.25.0"],
|
||||
["jsdoc","v0.23.2"],
|
||||
["json","v0.24.8"],
|
||||
["php","v0.24.2"],
|
||||
["python","v0.23.6"],
|
||||
["ruby","v0.23.1"],
|
||||
["rust","v0.24.0"],
|
||||
["typescript","v0.23.2"]
|
||||
]
|
||||
["bash","v0.25.0", null],
|
||||
["c","v0.24.1", null],
|
||||
["cpp","v0.23.4", null],
|
||||
["embedded-template","v0.25.0", null],
|
||||
["go","v0.25.0", null],
|
||||
["html","v0.23.2", null],
|
||||
["java","v0.23.5", null],
|
||||
["javascript","v0.25.0", null],
|
||||
["jsdoc","v0.23.2", null],
|
||||
["json","v0.24.8", null],
|
||||
["php","v0.24.2", "upstream_test_fixture"],
|
||||
["python","v0.23.6", null],
|
||||
["ruby","v0.23.1", null],
|
||||
["rust","v0.24.0", null],
|
||||
["typescript","v0.23.2", null]
|
||||
]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue