Skip to content

Commit

Permalink
Merge branch 'ajf/formula-bools' into ajf/more-formulas-4
Browse files Browse the repository at this point in the history
  • Loading branch information
HactarCE committed Jun 22, 2023
2 parents baa12ad + 64b22de commit 0387a75
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 7 deletions.
2 changes: 2 additions & 0 deletions quadratic-core/src/formulas/functions/logic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@ fn get_functions() -> Vec<FormulaFunction> {
vec![
formula_fn!(
/// Returns `TRUE`.
#[include_args_in_completion(false)]
#[examples("TRUE()")]
fn TRUE() {
true
}
),
formula_fn!(
/// Returns `FALSE`.
#[include_args_in_completion(false)]
#[examples("FALSE()")]
fn FALSE() {
false
Expand Down
11 changes: 9 additions & 2 deletions quadratic-core/src/formulas/functions/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ macro_rules! formula_fn {
) => {
$crate::formulas::functions::FormulaFunction {
name: $fn_name,
arg_completion: "",
arg_completion: None,
usage: "",
examples: &[],
doc: "",
Expand All @@ -135,14 +135,21 @@ macro_rules! formula_fn {
(
#[doc = $doc:expr]
$(#[doc = $additional_doc:expr])*
$(#[include_args_in_completion($include_args_in_completion:expr)])?
#[examples($($example_str:expr),+ $(,)?)]
$(#[$($attr:tt)*])*
fn $fn_name:ident( $($params:tt)* ) { $($body:tt)* }
) => {{
let params_list = params_list!($($params)*);

// Default to `true`
let include_args_in_completion = [$($include_args_in_completion, )? true][0];

$crate::formulas::functions::FormulaFunction {
name: stringify!($fn_name),
arg_completion: $crate::formulas::params::arg_completion_string(&params_list),
arg_completion: include_args_in_completion.then(|| {
$crate::formulas::params::arg_completion_string(&params_list)
}),
usage: $crate::formulas::params::usage_string(&params_list),
examples: &[$($example_str),+],
doc: concat!($doc $(, "\n", $additional_doc)*),
Expand Down
38 changes: 35 additions & 3 deletions quadratic-core/src/formulas/functions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ pub type FormulaFn =
/// Formula function with associated metadata.
pub struct FormulaFunction {
pub name: &'static str,
pub arg_completion: &'static str,
pub arg_completion: Option<&'static str>,
pub usage: &'static str,
pub examples: &'static [&'static str],
pub doc: &'static str,
Expand All @@ -146,8 +146,10 @@ impl FormulaFunction {
/// Returns the autocomplete snippet for this function.
pub fn autocomplete_snippet(&self) -> String {
let name = self.name;
let arg_completion = self.arg_completion;
format!("{name}({arg_completion})")
match self.arg_completion {
Some(arg_completion) => format!("{name}({arg_completion})"),
None => name.to_string(),
}
}

/// Returns the Markdown documentation for this function that should appear
Expand All @@ -174,3 +176,33 @@ pub struct FormulaFunctionCategory {
pub docs: &'static str,
pub get_functions: fn() -> Vec<FormulaFunction>,
}

#[test]
fn test_autocomplete_snippet() {
assert_eq!(
"TRUE",
ALL_FUNCTIONS.get("TRUE").unwrap().autocomplete_snippet(),
);
assert_eq!(
"PI()",
ALL_FUNCTIONS.get("PI").unwrap().autocomplete_snippet(),
);
assert_eq!(
"NOT(${1:boolean})",
ALL_FUNCTIONS.get("NOT").unwrap().autocomplete_snippet(),
);
assert_eq!(
"IF(${1:condition}, ${2:t}, ${3:f})",
ALL_FUNCTIONS.get("IF").unwrap().autocomplete_snippet(),
);
assert_eq!(
"IF(${1:condition}, ${2:t}, ${3:f})",
ALL_FUNCTIONS.get("IF").unwrap().autocomplete_snippet(),
);

// Optional
assert_eq!(
"SUMIF(${1:eval_range}, ${2:criteria}${3:, ${4:[numbers_range]}})",
ALL_FUNCTIONS.get("SUMIF").unwrap().autocomplete_snippet(),
);
}
6 changes: 4 additions & 2 deletions quadratic-core/src/formulas/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,10 @@ const TOKEN_PATTERNS: &[&str] = &[
UNTERMINATED_STRING_LITERAL_PATTERN,
// Numeric literal.
NUMERIC_LITERAL_PATTERN,
// Boolean literal (case-insensitive).
r#"false|true"#,
// Function call.
FUNCTION_CALL_PATTERN,
// Boolean literal (case-insensitive).
r#"false|true"#,
// Reference to a cell.
A1_CELL_REFERENCE_PATTERN,
// Whitespace.
Expand Down Expand Up @@ -275,6 +275,8 @@ impl Token {
s if FUNCTION_CALL_REGEX.is_match(s) => Self::FunctionCall,
s if STRING_LITERAL_REGEX.is_match(s) => Self::StringLiteral,
s if UNTERMINATED_STRING_LITERAL_REGEX.is_match(s) => Self::UnterminatedStringLiteral,
s if s.eq_ignore_ascii_case("false") => Self::False,
s if s.eq_ignore_ascii_case("true") => Self::True,
s if NUMERIC_LITERAL_REGEX.is_match(s) => Self::NumericLiteral,
s if A1_CELL_REFERENCE_REGEX.is_match(s) => Self::CellRef,
s if s.trim().is_empty() => Self::Whitespace,
Expand Down
10 changes: 10 additions & 0 deletions quadratic-core/src/formulas/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,16 @@ fn test_array_parsing() {
assert_eq!("{; }", eval_to_string(&mut NoGrid, "{ ; }"));
}

#[test]
fn test_bool_parsing() {
let g = &mut NoGrid;

assert_eq!("1", eval_to_string(g, "IF(TRUE, 1, 2)"));
assert_eq!("1", eval_to_string(g, "IF(true(), 1, 2)"));
assert_eq!("2", eval_to_string(g, "IF(False, 1, 2)"));
assert_eq!("2", eval_to_string(g, "IF(FALSE(), 1, 2)"));
}

#[test]
fn test_leading_equals() {
assert_eq!("7", eval_to_string(&mut NoGrid, "=3+4"));
Expand Down

0 comments on commit 0387a75

Please sign in to comment.