mirror of
https://github.com/Zenithsiz/zbuild.git
synced 2026-02-03 05:57:09 +00:00
Compare commits
3 Commits
0cc2410216
...
5b0e51a127
| Author | SHA1 | Date | |
|---|---|---|---|
| 5b0e51a127 | |||
| 5176d20ab7 | |||
| 5a2c251b9b |
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
@ -21,6 +21,7 @@
|
||||
"tempdir",
|
||||
"thiserror",
|
||||
"yeet",
|
||||
"yokeable",
|
||||
"Zbuild",
|
||||
"zutil"
|
||||
],
|
||||
|
||||
65
src/ast.rs
65
src/ast.rs
@ -14,7 +14,7 @@ use {
|
||||
};
|
||||
|
||||
/// Zbuild ast
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||
pub struct Ast {
|
||||
/// Aliases
|
||||
pub aliases: Vec<AliasStmt>,
|
||||
@ -61,7 +61,7 @@ impl Parsable for Ast {
|
||||
}
|
||||
|
||||
/// Alias statement
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||
pub struct AliasStmt {
|
||||
/// Alias name
|
||||
pub name: Ident,
|
||||
@ -83,7 +83,7 @@ impl Parsable for AliasStmt {
|
||||
}
|
||||
|
||||
/// Pattern statement
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||
pub struct PatStmt {
|
||||
/// Pattern name
|
||||
pub name: Ident,
|
||||
@ -107,7 +107,7 @@ impl Parsable for PatStmt {
|
||||
}
|
||||
|
||||
/// Default statement
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||
pub struct DefaultStmt {
|
||||
/// Default
|
||||
pub default: Expr,
|
||||
@ -124,7 +124,7 @@ impl Parsable for DefaultStmt {
|
||||
}
|
||||
|
||||
/// Rule statement
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||
pub struct RuleStmt {
|
||||
/// Rule name
|
||||
pub name: Ident,
|
||||
@ -190,7 +190,7 @@ impl Parsable for RuleStmt {
|
||||
}
|
||||
|
||||
/// Dependency statement
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||
pub enum DepStmt {
|
||||
/// File
|
||||
File(Expr),
|
||||
@ -214,7 +214,7 @@ impl Parsable for DepStmt {
|
||||
}
|
||||
|
||||
/// Command
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||
pub struct Command {
|
||||
/// Working directory
|
||||
pub cwd: Option<Expr>,
|
||||
@ -274,7 +274,7 @@ impl Parsable for Command {
|
||||
}
|
||||
|
||||
/// Include statement
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||
pub struct IncludeStmt {
|
||||
/// Path
|
||||
pub path: StringLiteral,
|
||||
@ -291,7 +291,7 @@ impl Parsable for IncludeStmt {
|
||||
}
|
||||
|
||||
/// Array
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||
pub struct Array<T>(pub Vec<T>);
|
||||
|
||||
impl<T> Parsable for Array<T>
|
||||
@ -334,7 +334,7 @@ where
|
||||
}
|
||||
|
||||
/// Expression
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||
pub struct Expr {
|
||||
/// Dependencies file
|
||||
pub is_deps_file: bool,
|
||||
@ -378,7 +378,7 @@ impl Parsable for Expr {
|
||||
}
|
||||
|
||||
/// Expression component
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||
pub enum ExprCmpt {
|
||||
/// Identifier
|
||||
Ident { ident: Ident, ops: Vec<ExprOp> },
|
||||
@ -442,14 +442,14 @@ impl ExprCmpt {
|
||||
}
|
||||
|
||||
/// Expression operators
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub enum ExprOp {
|
||||
/// Directory name, `.dir_name`.
|
||||
DirName,
|
||||
}
|
||||
|
||||
/// Identifier
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||
pub struct Ident(pub ArcStr);
|
||||
|
||||
impl Parsable for Ident {
|
||||
@ -466,7 +466,7 @@ impl Parsable for Ident {
|
||||
}
|
||||
|
||||
/// String literal
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||
pub struct StringLiteral(ArcStr);
|
||||
|
||||
impl Parsable for StringLiteral {
|
||||
@ -543,7 +543,7 @@ pub trait Parsable: Sized {
|
||||
}
|
||||
|
||||
/// Parser
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||
pub struct Parser {
|
||||
/// Input
|
||||
input: ArcStr,
|
||||
@ -656,8 +656,10 @@ impl Parser {
|
||||
let end_idx = rest.find("###").context("Expected `###` after `###`")?;
|
||||
Ok(&rest[end_idx + 3..])
|
||||
} else if let Some(rest) = remaining.strip_prefix('#') {
|
||||
let end_idx = rest.find('\n').unwrap_or(rest.len());
|
||||
Ok(&rest[end_idx + 1..])
|
||||
match rest.find('\n') {
|
||||
Some(end_idx) => Ok(&rest[end_idx + 1..]),
|
||||
None => Ok(&rest[rest.len()..]),
|
||||
}
|
||||
} else {
|
||||
Ok::<_, AppError>(remaining)
|
||||
}
|
||||
@ -788,3 +790,32 @@ pub fn parse(path: &Path) -> Result<Ast, AppError> {
|
||||
|
||||
Ok(ast)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn parse_ast() {
|
||||
const EMPTY_AST: Ast = Ast {
|
||||
aliases: vec![],
|
||||
pats: vec![],
|
||||
defaults: vec![],
|
||||
rules: vec![],
|
||||
includes: vec![],
|
||||
};
|
||||
let cases = [
|
||||
("", EMPTY_AST),
|
||||
("#Comment\n", EMPTY_AST),
|
||||
("#Comment", EMPTY_AST),
|
||||
("###Comment###", EMPTY_AST),
|
||||
];
|
||||
|
||||
for (input, expected_ast) in cases {
|
||||
let mut parser = Parser::new(input.into());
|
||||
let ast = Ast::parse_from(&mut parser)
|
||||
.unwrap_or_else(|err| panic!("Unable to parse input {input:?}: {}", err.pretty()));
|
||||
assert_eq!(ast, expected_ast, "Ast differed for {input:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,16 +27,28 @@ use {
|
||||
pub struct ArcStr {
|
||||
/// Inner
|
||||
// Note: We need an `Arc<String>` for efficient conversion to/from `String`
|
||||
inner: Yoke<&'static str, Arc<String>>,
|
||||
inner: Yoke<&'static str, Option<Arc<String>>>,
|
||||
}
|
||||
|
||||
impl ArcStr {
|
||||
/// Creates a new arc string from a static string
|
||||
pub const fn from_static(s: &'static str) -> Self {
|
||||
Self {
|
||||
inner: Yoke::new_owned(s),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the range of this string compared to the base
|
||||
fn base_range(&self) -> Range<usize> {
|
||||
self.inner
|
||||
.backing_cart()
|
||||
.substr_range(self)
|
||||
.expect("String pointer should be within allocation")
|
||||
match self.inner.backing_cart() {
|
||||
// If we're backed by anything, check in relation to it
|
||||
Some(inner) => inner
|
||||
.substr_range(self)
|
||||
.expect("String pointer should be within allocation"),
|
||||
|
||||
// Otherwise, we're all of ourselves
|
||||
None => 0..self.len(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Updates this string as a `&mut String`.
|
||||
@ -50,29 +62,37 @@ impl ArcStr {
|
||||
let range = self.base_range();
|
||||
|
||||
// Get the inner string
|
||||
let mut inner = mem::take(self).inner.into_backing_cart();
|
||||
let s = match Arc::get_mut(&mut inner) {
|
||||
// If we're unique, slice the parts we don't care about and return
|
||||
Some(s) => {
|
||||
s.truncate(range.end);
|
||||
let _ = s.drain(..range.start);
|
||||
|
||||
s
|
||||
let inner = mem::take(self).inner;
|
||||
let output;
|
||||
*self = match inner.try_into_yokeable() {
|
||||
Ok(s) => {
|
||||
let mut s = s.to_owned();
|
||||
output = f(&mut s);
|
||||
Self::from(s)
|
||||
},
|
||||
Err(inner) => {
|
||||
// TODO: Get rid of this panic here?
|
||||
let mut inner = inner.into_backing_cart().expect("Should have a cart");
|
||||
let s = match Arc::get_mut(&mut inner) {
|
||||
// If we're unique, slice the parts we don't care about and return
|
||||
Some(s) => {
|
||||
s.truncate(range.end);
|
||||
let _ = s.drain(..range.start);
|
||||
|
||||
// Otherwise copy
|
||||
None => {
|
||||
inner = Arc::new(inner[range].to_owned());
|
||||
Arc::get_mut(&mut inner).expect("Should be unique")
|
||||
s
|
||||
},
|
||||
|
||||
// Otherwise copy
|
||||
None => {
|
||||
inner = Arc::new(inner[range].to_owned());
|
||||
Arc::get_mut(&mut inner).expect("Should be unique")
|
||||
},
|
||||
};
|
||||
output = f(s);
|
||||
Self::from(inner)
|
||||
},
|
||||
};
|
||||
|
||||
// Then mutate
|
||||
let output = f(s);
|
||||
|
||||
// And finally, reconstruct ourselves
|
||||
*self = Self::from(inner);
|
||||
|
||||
output
|
||||
}
|
||||
|
||||
@ -163,6 +183,12 @@ impl Borrow<str> for ArcStr {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'_ str> for ArcStr {
|
||||
fn from(s: &str) -> Self {
|
||||
Self::from(s.to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for ArcStr {
|
||||
fn from(s: String) -> Self {
|
||||
Self::from(Arc::new(s))
|
||||
@ -172,7 +198,7 @@ impl From<String> for ArcStr {
|
||||
impl From<Arc<String>> for ArcStr {
|
||||
fn from(s: Arc<String>) -> Self {
|
||||
Self {
|
||||
inner: Yoke::attach_to_cart(s, |s| &**s),
|
||||
inner: Yoke::attach_to_cart(s, |s| &**s).wrap_cart_in_option(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -182,18 +208,115 @@ impl From<ArcStr> for String {
|
||||
// Get the range of our specific string
|
||||
let range = s.base_range();
|
||||
|
||||
let inner = s.inner.into_backing_cart();
|
||||
match Arc::try_unwrap(inner) {
|
||||
// If we're unique, slice the parts we don't care about and return
|
||||
Ok(mut inner) => {
|
||||
inner.truncate(range.end);
|
||||
let _ = inner.drain(..range.start);
|
||||
match s.inner.try_into_yokeable() {
|
||||
// If we're not backed by anything, just extend the string
|
||||
Ok(s) => s.to_owned(),
|
||||
|
||||
inner
|
||||
// Otherwise, wrap it
|
||||
Err(inner) => match Arc::try_unwrap(inner.into_backing_cart().expect("Should have a cart")) {
|
||||
// If we're unique, slice the parts we don't care about and return
|
||||
Ok(mut inner) => {
|
||||
inner.truncate(range.end);
|
||||
let _ = inner.drain(..range.start);
|
||||
|
||||
inner
|
||||
},
|
||||
|
||||
// Otherwise copy
|
||||
Err(inner) => inner[range].to_owned(),
|
||||
},
|
||||
|
||||
// Otherwise copy
|
||||
Err(inner) => inner[range].to_owned(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use {super::*, std::collections::HashSet};
|
||||
|
||||
#[test]
|
||||
fn from_static() {
|
||||
let mut s = ArcStr::from_static("abc");
|
||||
assert_eq!(&*s, "abc");
|
||||
assert_eq!(&*s.slice(1..2), "b");
|
||||
assert_eq!(&*s.slice_from_str(&s[1..2]), "b");
|
||||
|
||||
s.with_mut(|s| s.push('d'));
|
||||
assert_eq!(&*s, "abcd");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mutate() {
|
||||
let mut s = ArcStr::from("abc");
|
||||
s.with_mut(|s| s.push_str("def"));
|
||||
assert_eq!(&*s, "abcdef");
|
||||
|
||||
let s2 = s.clone();
|
||||
s.with_mut(|s| s.push_str("ghi"));
|
||||
assert_eq!(&*s, "abcdefghi");
|
||||
assert_eq!(&*s2, "abcdef");
|
||||
|
||||
let output = s.with_mut(|_s| 123);
|
||||
assert_eq!(output, 123);
|
||||
|
||||
let output = ArcStr::from_static("abc").with_mut(|_s| 456);
|
||||
assert_eq!(output, 456);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn strip() {
|
||||
let s = ArcStr::from("abc");
|
||||
assert_eq!(s.strip_prefix("ab").as_deref(), Some("c"));
|
||||
assert_eq!(s.strip_prefix("ac").as_deref(), None);
|
||||
|
||||
assert_eq!(s.strip_suffix("bc").as_deref(), Some("a"));
|
||||
assert_eq!(s.strip_suffix("ac").as_deref(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eq_cmp() {
|
||||
let a = ArcStr::from("a");
|
||||
let b = ArcStr::from("b");
|
||||
assert_eq!(a, ArcStr::from("a"));
|
||||
assert_ne!(a, b);
|
||||
assert!(b > a);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hash() {
|
||||
let s = ArcStr::from("abc");
|
||||
let mut h = HashSet::new();
|
||||
assert!(h.insert(s.clone()));
|
||||
assert!(!h.insert(s));
|
||||
assert!(!h.insert(ArcStr::from("abc")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_string() {
|
||||
assert_eq!(String::from(ArcStr::from_static("abc")), "abc");
|
||||
|
||||
let mut s = ArcStr::from("abc");
|
||||
assert_eq!(String::from(s.clone()), "abc");
|
||||
|
||||
s.with_mut(|s| s.push('d'));
|
||||
assert_eq!(String::from(s), "abcd");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn borrow() {
|
||||
let s = ArcStr::from("abc");
|
||||
assert_eq!(Borrow::<str>::borrow(&s), "abc");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fmt() {
|
||||
let s = ArcStr::from("abc");
|
||||
|
||||
let mut output = String::new();
|
||||
fmt::write(&mut output, format_args!("{s}")).expect("Unable to write");
|
||||
assert_eq!(output, "abc");
|
||||
|
||||
output.clear();
|
||||
fmt::write(&mut output, format_args!("{s:?}")).expect("Unable to write");
|
||||
assert_eq!(output, r#""abc""#);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user