Packages
caffeine_lang
5.4.4
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/frontend/pipeline.gleam
/// Frontend pipeline for compiling .caffeine source files.
/// Orchestrates the tokenizer, parser, validator, and lowering
/// to transform .caffeine source into Measurement and Expectation types.
import caffeine_lang/errors.{type CompilationError}
import caffeine_lang/frontend/lowering
import caffeine_lang/frontend/parser
import caffeine_lang/frontend/parser_error.{type ParserError}
import caffeine_lang/frontend/validator
import caffeine_lang/linker/expectations.{type Expectation}
import caffeine_lang/linker/measurements.{type Measurement, type Raw}
import caffeine_lang/source_file.{
type ExpectationSource, type MeasurementSource, type SourceFile,
}
import gleam/list
import gleam/result
/// Compiles a measurements .caffeine source to a list of raw (unvalidated) measurements.
@internal
pub fn compile_measurements(
source: SourceFile(MeasurementSource),
) -> Result(List(Measurement(Raw)), CompilationError) {
use ast <- result.try(
parser.parse_measurements_file(source.content)
|> result.map_error(fn(errs) {
parser_errors_to_compilation_error(errs, source.path)
}),
)
use validated <- result.try(
validator.validate_measurements_file(ast)
|> result.map_error(fn(errs) {
validator_errors_to_compilation_error(errs, source.path)
}),
)
Ok(lowering.lower_measurements(validated))
}
/// Compiles an expects .caffeine source to a list of expectations.
@internal
pub fn compile_expects(
source: SourceFile(ExpectationSource),
) -> Result(List(Expectation), CompilationError) {
use ast <- result.try(
parser.parse_expects_file(source.content)
|> result.map_error(fn(errs) {
parser_errors_to_compilation_error(errs, source.path)
}),
)
use validated <- result.try(
validator.validate_expects_file(ast)
|> result.map_error(fn(errs) {
validator_errors_to_compilation_error(errs, source.path)
}),
)
Ok(lowering.lower_expectations(validated))
}
fn parser_error_to_compilation_error(
err: parser_error.ParserError,
file_path: String,
) -> CompilationError {
errors.frontend_parse_error(
msg: file_path <> ": " <> parser_error.to_string(err),
)
}
/// Converts a list of ParserErrors to a single CompilationError.
fn parser_errors_to_compilation_error(
errs: List(ParserError),
file_path: String,
) -> CompilationError {
case errs {
[single] -> parser_error_to_compilation_error(single, file_path)
multiple -> {
let compilation_errors =
multiple
|> list.map(parser_error_to_compilation_error(_, file_path))
errors.CompilationErrors(errors: compilation_errors)
}
}
}
fn validator_error_to_compilation_error(
err: validator.ValidatorError,
file_path: String,
) -> CompilationError {
errors.frontend_validation_error(
msg: file_path <> ": " <> validator_error_to_string(err),
)
}
/// Converts a list of ValidatorErrors to a single CompilationError.
fn validator_errors_to_compilation_error(
errs: List(validator.ValidatorError),
file_path: String,
) -> CompilationError {
case errs {
[single] -> validator_error_to_compilation_error(single, file_path)
multiple -> {
let compilation_errors =
multiple
|> list.map(validator_error_to_compilation_error(_, file_path))
errors.CompilationErrors(errors: compilation_errors)
}
}
}
fn validator_error_to_string(err: validator.ValidatorError) -> String {
case err {
validator.DuplicateExtendable(name) -> "Duplicate extendable: " <> name
validator.UndefinedExtendable(name, referenced_by, _candidates) ->
"Undefined extendable '"
<> name
<> "' referenced by '"
<> referenced_by
<> "'"
validator.DuplicateExtendsReference(name, referenced_by) ->
"Duplicate extends reference '"
<> name
<> "' in '"
<> referenced_by
<> "'"
validator.InvalidExtendableKind(name, expected, got) ->
"Invalid extendable kind for '"
<> name
<> "': expected "
<> expected
<> ", got "
<> got
validator.UndefinedTypeAlias(name, referenced_by, _candidates) ->
"Undefined type alias '"
<> name
<> "' referenced by '"
<> referenced_by
<> "'"
validator.DuplicateTypeAlias(name) -> "Duplicate type alias: " <> name
validator.CircularTypeAlias(name, _cycle) ->
"Circular type alias reference detected in '" <> name <> "'"
validator.InvalidDictKeyTypeAlias(alias_name, resolved_to, referenced_by) ->
"Type alias '"
<> alias_name
<> "' used as Dict key resolves to '"
<> resolved_to
<> "' which is not String-based, in '"
<> referenced_by
<> "'"
validator.ExtendableOvershadowing(field_name, item_name, extendable_name) ->
"Field '"
<> field_name
<> "' in '"
<> item_name
<> "' overshadows field from extendable '"
<> extendable_name
<> "'"
validator.ExtendableTypeAliasNameCollision(name) ->
"Name '" <> name <> "' is used as both an extendable and a type alias"
validator.InvalidRefinementValue(value, expected_type, referenced_by) ->
"Refinement value '"
<> value
<> "' is not a valid "
<> expected_type
<> " literal, in '"
<> referenced_by
<> "'"
validator.InvalidPercentageBounds(value, referenced_by) ->
"Percentage value '"
<> value
<> "' must be between 0.0 and 100.0, in '"
<> referenced_by
<> "'"
}
}