Packages
caffeine_lang
0.0.17
6.3.1
6.3.0
6.2.2
6.2.1
6.2.0
6.1.2
6.1.1
6.1.0
6.0.0
5.6.0
5.5.0
5.4.4
5.4.3
5.4.2
5.4.1
5.4.0
5.3.0
5.2.0
5.1.1
5.1.0
5.0.12
5.0.11
5.0.10
5.0.8
5.0.7
5.0.6
5.0.5
5.0.4
5.0.1
5.0.0
4.10.0
4.9.0
4.8.3
4.8.2
4.8.1
4.8.0
4.7.9
4.7.8
4.7.7
4.7.6
4.7.5
4.6.7
4.6.6
4.6.5
4.6.4
4.6.3
4.6.2
4.6.0
4.5.1
4.5.0
4.4.4
4.4.3
4.4.1
4.4.0
4.3.7
4.3.6
3.0.6
3.0.5
3.0.4
3.0.3
3.0.2
3.0.1
3.0.0
2.0.5
2.0.4
2.0.3
2.0.2
2.0.1
2.0.0
1.0.2
1.0.1
0.1.0
0.0.24
0.0.23
0.0.22
0.0.21
0.0.20
0.0.19
0.0.18
0.0.17
0.0.16
0.0.15
0.0.14
0.0.13
0.0.12
0.0.11
0.0.10
0.0.9
0.0.8
0.0.7
0.0.6
0.0.5
0.0.4
0.0.2
0.0.1
A compiler for generating reliability artifacts from service expectation definitions.
Current section
Files
Jump to
Current section
Files
src/caffeine_lang/cql/generator.gleam
import caffeine_lang/cql/parser.{
type Exp, type Operator, type Primary, Add, Div, Mul, PrimaryExp, PrimaryWord,
Sub,
}
import caffeine_lang/cql/resolver.{type Primitives, GoodOverTotal}
import gleam/option.{type Option, None, Some}
// Datadog
pub fn generate_datadog_query(primitive: Primitives) -> String {
case primitive {
GoodOverTotal(numerator, denominator) -> {
"query {\n"
<> " numerator = \""
<> numerator_exp_to_datadog_query(numerator)
<> "\"\n"
<> " denominator = \""
<> denominator_exp_to_datadog_query(denominator)
<> "\"\n"
<> " }\n"
}
}
}
fn numerator_exp_to_datadog_query(exp: Exp) -> String {
// Unwrap outer PrimaryExp at top level only
case exp {
parser.Primary(PrimaryExp(exp:)) -> exp_to_string(exp)
_ -> exp_to_string(exp)
}
}
fn denominator_exp_to_datadog_query(exp: Exp) -> String {
// Unwrap outer PrimaryExp at top level only
case exp {
parser.Primary(PrimaryExp(exp:)) -> exp_to_string(exp)
_ -> exp_to_string(exp)
}
}
fn exp_to_string(exp: Exp) -> String {
case exp {
parser.Primary(primary:) -> primary_to_string(primary, None)
parser.OperatorExpr(numerator:, denominator:, operator:) ->
exp_to_string_with_context(numerator, Some(operator), True)
<> " "
<> operator_to_datadog_query(operator)
<> " "
<> exp_to_string_with_context(denominator, Some(operator), False)
}
}
fn exp_to_string_with_context(
exp: Exp,
parent_op: Option(Operator),
_is_left: Bool,
) -> String {
case exp {
parser.Primary(primary:) -> primary_to_string(primary, parent_op)
parser.OperatorExpr(numerator:, denominator:, operator:) ->
exp_to_string_with_context(numerator, Some(operator), True)
<> " "
<> operator_to_datadog_query(operator)
<> " "
<> exp_to_string_with_context(denominator, Some(operator), False)
}
}
fn primary_to_string(primary: Primary, parent_op: Option(Operator)) -> String {
case primary {
PrimaryWord(word:) -> word.value
PrimaryExp(exp:) -> {
// Check if parentheses are needed
let needs_parens = case exp, parent_op {
// If there's no parent operator, we don't need parens
_, None -> False
// If the inner expression is just a primary, check if it needs parens
parser.Primary(_), _ -> False
// If inner is an operator expression, check precedence
parser.OperatorExpr(operator: inner_op, ..), Some(parent) ->
needs_parentheses(inner_op, parent)
}
case needs_parens {
True -> "(" <> exp_to_string(exp) <> ")"
False -> exp_to_string(exp)
}
}
}
}
fn needs_parentheses(inner_op: Operator, parent_op: Operator) -> Bool {
let inner_prec = operator_precedence(inner_op)
let parent_prec = operator_precedence(parent_op)
inner_prec < parent_prec
}
fn operator_precedence(op: Operator) -> Int {
case op {
Add | Sub -> 1
Mul | Div -> 2
}
}
pub fn operator_to_datadog_query(operator: parser.Operator) -> String {
case operator {
parser.Add -> "+"
parser.Sub -> "-"
parser.Mul -> "*"
parser.Div -> "/"
}
}