Attempt at lifetimes and RefCell only for interpretation

This commit is contained in:
DOOM1EM8Cover 2023-08-29 05:02:43 +01:00
parent c6994ab672
commit 15468a910d
19 changed files with 147 additions and 145 deletions

View file

@ -18,3 +18,7 @@ https://docs.rs/codemap/latest/codemap/
https://www.youtube.com/watch?v=m64SWl9bfvk
https://www.youtube.com/watch?v=ApHpmA1k73k
### Optimizing AST parsing and allocation
https://cs.hofstra.edu/~cscccl/rustlr_project/chapter6.html

View file

@ -1,7 +1,4 @@
tag @?
namespace examples.full
// Standard Imports
namespace dev
import std::str::StringBounds
settings {
@ -10,7 +7,7 @@ settings {
}
@affects=struct protocol
@affects=[struct protocol]
settings MailSettings {
indexed=true
}
@ -24,16 +21,16 @@ struct Mail {
struct Article {
@validators=[StringBounds(min_chars=3 max_chars=32]
1# title: str
title: str
@validators=[StringBounds(min_chars=24 max_chars=412]
2# content: str
content: str
}
@hidden
@settings=MailSettings
protocol Mail {
1# async function send(Mail)
async function send(mail: Mail)
}
@ -44,5 +41,5 @@ protocol Feed {
// Fetches new articles since last fetch
@flexible async stream
#timeout=1000ms per_send_timeout=10s cooldown=10s
1# function fetch_articles() -> Article[SENT_ARTICLES_MAX]
function fetch_articles() -> Article[SENT_ARTICLES_MAX]
}

View file

@ -1,10 +1,9 @@
use std::cell::RefCell;
// Standard Uses
use std::path::Path;
use std::collections::HashMap;
use std::fs::File;
use std::io::Write;
use std::rc::Rc;
use std::cell::RefCell;
// Crate Uses
use crate::codegen;
@ -38,7 +37,8 @@ pub fn build(path: &Path) -> Result<()> {
let latest_frozen = frozen::loader::from_latest_frozen(&frozen_path);
let compiled_project = ProjectInterpreter::from_origin(config_path);
let (compiled_project, frozen)
= ProjectInterpreter::from_origin(config_path)?;
// TODO: Check integrity of the frozen contents, if they are valid, if something is broken, etc
@ -49,33 +49,31 @@ pub fn build(path: &Path) -> Result<()> {
);
}
let mut project_ctx = RefCell::borrow_mut(&compiled_project.0);
for relative in frozen::schema_paths(&compiled_project.1) {
let mut project_ctx = compiled_project.borrow_mut();
let schema_paths = frozen::schema_paths(&frozen);
for relative in schema_paths {
let concrete = format!("{:}/{}", path.to_str().unwrap(), relative);
let concrete_path = Path::new(&concrete);
let unit = idl::parser_new::from_path(concrete_path)?;
let context = Rc::new(RefCell::new(
ir::context::SchemaContext::with_project_and_main(
unit, compiled_project.0.clone()
)
));
let context = ir::context::SchemaContext::with_project_and_main(
unit, &compiled_project
);
project_ctx.add_schema_context(context.clone());
project_ctx.add_schema_context(RefCell::new(context));
}
compiler::interpret::interpret_context(&project_ctx)?;
compiler::interpret::interpret_context(&compiled_project)?;
// We drop here since we should not need mutability anymore
drop(project_ctx);
// generate_code_for_targets(&compiled_project).unwrap();
generate_code_for_targets(&compiled_project).unwrap();
todo!()
Ok(())
// Ok(())
}
pub fn generate_code_for_targets(compiled_project: &FrozenWhole) -> Result<()> {
pub fn generate_code_for_targets(compiled_project: &mut FrozenWhole) -> Result<()> {
for item in compiled_project.1.iter() {
match item {
FrozenUnit::CodeGeneration(details) => {
@ -101,9 +99,7 @@ pub fn generate_code_for_targets(compiled_project: &FrozenWhole) -> Result<()> {
)
}
generate_code_for_context(
&compiled_project.0.borrow(), generator, &path
)?;
generate_code_for_context(&compiled_project.0, generator, &path)?;
},
_ => {}
}
@ -131,12 +127,13 @@ pub fn resolve_path_query(query: &Option<String>, args: Args) -> Result<String,
}
}
#[allow(unused)]
pub fn generate_code_for_context(
context: &ProjectContext, generator: Option<&GeneratorFn>, target_path: &Path
) -> Result<()> {
/*
for schema_context in context.schema_contexts.iter() {
let ctx = schema_context.borrow();
let frozen_schema = ctx.frozen_schema.as_ref().unwrap();
let frozen_schema = schema_context.frozen_schema.as_ref().unwrap();
let mut code = "Generated code with Comline compiler".to_owned();
@ -146,6 +143,9 @@ pub fn generate_code_for_context(
}
Ok(())
*/
todo!()
}
pub fn build_index(frozen_path: &Path) {

View file

@ -1,18 +1,22 @@
// Standard Uses
use std::cell::RefMut;
use std::cell::RefCell;
// Crate Uses
use crate::project::ir::context::ProjectContext;
use crate::schema::ir::compiler::interpreted::interpreter;
use crate::schema::ir::compiler::interpreter::meta_stage;
// External Uses
use eyre::{anyhow, Result};
pub fn interpret_context(project_context: &RefMut<ProjectContext>) -> Result<()> {
for schema_context in project_context.schema_contexts.iter() {
meta_stage::compile_schema_metadata(schema_context, project_context)
pub fn interpret_context<'a>(project_context: &'a RefCell<ProjectContext<'a>>) -> Result<()> {
let len = project_context.borrow().schema_contexts.len();
for i in 0..len {
let project_ctx = &project_context.borrow();
let schema_ctx = &project_ctx.schema_contexts[i];
meta_stage::compile_schema_metadata(&schema_ctx)
.map_err(|e| anyhow!("{}", e))?;
}

View file

@ -6,7 +6,6 @@ use std::rc::Rc;
// Crate Uses
use crate::project::idl::ast::{SourcedWhole as ProjectSourcedWhole};
use crate::schema::ir::context::SchemaContext;
use crate::schema::idl::ast::unit::{ASTUnit, Details};
// External Uses
@ -17,18 +16,17 @@ pub enum Origin {
Disk(PathBuf)
}
#[derive(Clone)]
pub struct ProjectContext {
pub struct ProjectContext<'a> {
pub origin: Origin,
pub config: ProjectSourcedWhole,
pub schema_contexts: Vec<Rc<RefCell<SchemaContext>>>,
pub schema_contexts: Vec<RefCell<SchemaContext<'a>>>,
pub relative_projects: Vec<Rc<ProjectContext>>,
pub relative_projects: Vec<ProjectContext<'a>>,
}
#[allow(unused)]
impl ProjectContext {
impl<'a> ProjectContext<'a> {
pub fn with_config_origin(origin: Origin, config: ProjectSourcedWhole) -> Self {
Self {
origin, config,
@ -47,7 +45,7 @@ impl ProjectContext {
pub(crate) fn add_relative_project(mut self, sourced: ProjectSourcedWhole) {
self.relative_projects.push(
Rc::from(Self::with_config(sourced))
Self::with_config(sourced)
)
}
@ -55,7 +53,7 @@ impl ProjectContext {
todo!()
}
pub(crate) fn add_schema_context(&mut self, context: Rc<RefCell<SchemaContext>>) {
pub(crate) fn add_schema_context(&mut self, context: RefCell<SchemaContext<'a>>) {
self.schema_contexts.push(context);
}
@ -63,21 +61,24 @@ impl ProjectContext {
todo!()
}
pub(crate) fn find_schema_by_import(&self, import: &str) -> Option<&Rc<RefCell<SchemaContext>>> {
for schema_context in self.schema_contexts.iter() {
let ctx = schema_context.borrow();
let units = &ctx.schema.1;
if let Some(unit) = units.find_namespace() {
pub(crate) fn find_schema_by_import(&self, import: &str)
-> Option<&mut SchemaContext>
{
/*
for schema_context in self.schema_contexts {
if let Some(unit) = schema_context.schema.1.find_namespace() {
if let ASTUnit::Namespace(_, namespace) = &unit.1 {
if namespace == import {
return Some(schema_context)
return Some(*schema_context)
}
}
}
}
None
*/
todo!()
}
/*

View file

@ -4,14 +4,13 @@ pub mod versioning;
// Standard Uses
use std::fmt::Debug;
use std::cell::RefCell;
// Crate Uses
use crate::autodoc::document::Document;
use crate::project::ir::context::ProjectContext;
use crate::project::ir::frozen::{Dependency, FrozenUnit, FrozenWhole};
use crate::project::ir::diff::versioning::Versioning;
// External Uses
use semver::Version;
use downcast_rs::{Downcast, impl_downcast};
@ -23,20 +22,24 @@ pub trait Differ: Downcast + Debug {
// fn on_assignment_changed(&self, old: AssignmentUnit, new: AssignmentUnit);
#[allow(unused)]
fn differ(
&self, previous: &Vec<FrozenUnit>, next: &FrozenWhole,
document_gen: bool, auto_version: bool
) {
differ(previous, next, document_gen, auto_version)
// differ(previous, next, document_gen, auto_version)
}
}
impl_downcast!(Differ);
#[allow(unused)]
pub fn differ(
previous: &Vec<FrozenUnit>, next: &FrozenWhole,
previous: &Vec<FrozenUnit>, next: &RefCell<ProjectContext>,
document_gen: bool, auto_version: bool
) {
todo!()
/*
let mut previous_version = versioning::version_from(previous).unwrap_or(
&Version::parse("0.0.0").unwrap().to_string()
);
@ -50,6 +53,7 @@ pub fn differ(
let document = listeners[0].downcast_ref::<Document>().unwrap();
let versioning = listeners[1].downcast_ref::<Versioning>().unwrap();
*/
}
#[allow(unused)]

View file

@ -3,9 +3,6 @@ pub mod loader;
pub mod meta;
// Standard Uses
use std::rc::Rc;
use std::cell::RefCell;
use std::slice::Iter;
use std::iter::FilterMap;
@ -15,7 +12,7 @@ use crate::project::ir::context::ProjectContext;
// External Uses
pub type FrozenWhole = (Rc<RefCell<ProjectContext>>, Vec<FrozenUnit>);
pub type FrozenWhole<'a> = (ProjectContext<'a>, Vec<FrozenUnit>);
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]

View file

@ -202,8 +202,8 @@ fn interpret_assigment_publish_targets(items: &Vec<DictKeyValue>)
}
#[allow(unused)]
pub fn into_frozen_whole(
context: &ProjectContext, interpreted: Vec<FrozenUnit>
pub fn into_frozen_whole<'a>(
context: &'a ProjectContext<'a>, interpreted: Vec<FrozenUnit>
) -> Result<FrozenWhole, ReportDetails<CompileError>>
{
todo!()

View file

@ -1,10 +1,8 @@
// Standard Uses
use std::cell::RefCell;
use std::rc::Rc;
// Crate Uses
use crate::project::ir::context::ProjectContext;
use crate::project::ir::frozen::{FrozenUnit, FrozenWhole};
use crate::project::ir::frozen::FrozenUnit;
use crate::project::ir::compiler::report::CompileError;
use crate::project::ir::interpreter::freezing;
use crate::report::ReportDetails;
@ -13,10 +11,10 @@ use crate::report::ReportDetails;
#[allow(unused)]
pub fn interpret_context(context: ProjectContext)
-> Result<FrozenWhole, ReportDetails<CompileError>>
pub fn interpret_context<'a>(mut context: &ProjectContext)
-> Result<Vec<FrozenUnit>, ReportDetails<CompileError>>
{
let mut interpreted: Vec<FrozenUnit> = vec![];
let mut interpreted = vec![];
for node in &context.config.1 {
let file = context.config.0.files().first().unwrap();
@ -27,6 +25,6 @@ pub fn interpret_context(context: ProjectContext)
);
}
Ok((Rc::new(RefCell::new(context)), interpreted))
Ok(interpreted)
// freezing::into_frozen_whole(&context, interpreted)
}

View file

@ -3,28 +3,29 @@ pub mod report;
pub mod interpret;
pub mod freezing;
use std::cell::RefCell;
// Standard Uses
use std::path::Path;
// Crate Uses
use crate::project;
use crate::project::idl::parser_new;
use crate::project::idl::ast::{ASTUnit, SourcedWhole};
use crate::project::ir::context::{Origin, ProjectContext};
use crate::project::ir::frozen::FrozenWhole;
use crate::project::ir::frozen::FrozenUnit;
use crate::project::ir::compiler::Compile;
// External Uses
use eyre::{anyhow, Result};
#[allow(unused)]
pub struct Interpreter {
context: ProjectContext
pub struct Interpreter<'a> {
context: ProjectContext<'a>
}
#[allow(unused)]
impl Compile for Interpreter {
type Output = FrozenWhole;
impl<'a> Compile for Interpreter<'a> {
type Output = Result<(RefCell<ProjectContext<'a>>, Vec<FrozenUnit>)>;
fn from_ast(ast: Vec<ASTUnit>) -> Self::Output {
todo!()
@ -32,8 +33,10 @@ impl Compile for Interpreter {
fn from_sourced_whole(sourced: SourcedWhole) -> Self::Output {
let context = ProjectContext::with_config(sourced);
let frozen = interpret::interpret_context(&context)
.map_err(|e| anyhow!("{:?}", e))?;
interpret::interpret_context(context).unwrap()
Ok((RefCell::new(context), frozen))
}
fn from_source(source: &str) -> Self::Output {
@ -47,11 +50,13 @@ impl Compile for Interpreter {
}
fn from_origin(origin: &Path) -> Self::Output {
let sourced = project::idl::parser_new::from_path(&origin).unwrap();
let sourced = parser_new::from_path(&origin).unwrap();
let context = ProjectContext::with_config_origin(
Origin::Disk(origin.to_path_buf()), sourced
);
let frozen = interpret::interpret_context(&context)
.map_err(|e| anyhow!("{:?}", e))?;
interpret::interpret_context(context).unwrap()
Ok((RefCell::new(context), frozen))
}
}

View file

@ -5,10 +5,10 @@ use std::sync::Arc;
// Local Uses
use crate::utils::codemap::{CodeMap, FileMap};
use crate::schema::idl::ast::unit::{ASTUnit, SourcedWholeRc, SpannedUnit};
use crate::schema::idl::ast::unit::{ASTUnit, SourcedWhole, SourcedWholeRc, SpannedUnit};
// External Uses
use eyre::{bail, Result};
use eyre::Result;
use pest::iterators::Pair;
use pest::Parser;
@ -18,7 +18,11 @@ use pest::Parser;
pub struct SchemaParser;
pub fn from_path(path: &Path) -> Result<SourcedWholeRc> {
#[allow(unused)]
pub fn from_path(path: &Path) -> Result<SourcedWhole> {
todo!();
/*
if !path.exists() { bail!("Path doesn't exist: {:?}", path) }
let source = std::fs::read_to_string(path).unwrap();
@ -28,6 +32,7 @@ pub fn from_path(path: &Path) -> Result<SourcedWholeRc> {
);
sourced_whole
*/
}
pub fn parse_source(source: String, name: String) -> Result<SourcedWholeRc> {

View file

@ -1,6 +1,5 @@
// Standard Uses
use std::cell::{RefCell, RefMut};
use std::rc::Rc;
use std::cell::RefMut;
// Local Uses
use crate::schema::idl::ast::unit::{ASTUnit, SpannedUnit};
@ -16,14 +15,13 @@ use crate::report::ReportDetails;
#[allow(unused)]
pub fn interpret_context(
schema_context: &Rc<RefCell<SchemaContext>>, project_context: &RefMut<ProjectContext>
pub fn interpret_context<'a>(
schema_context: &'a mut SchemaContext<'a>, project_context: &RefMut<ProjectContext>
) -> Result<(), ReportDetails<CompileError>> {
let mut interpreted: Vec<FrozenUnit> = vec![];
let mut context = Some(schema_context.borrow());
for i in 0..context.as_ref().unwrap().schema.1.len() {
let spanned_unit = &context.unwrap().schema.1[i];
for i in 0..schema_context.schema.1.len() {
let spanned_unit = &schema_context.schema.1[i];
use crate::schema::idl::ast::unit::ASTUnit::*;
match &spanned_unit.1 {
@ -47,13 +45,10 @@ pub fn interpret_context(
})
};
context = None;
let mut ctx_mut = schema_context.borrow_mut();
if let Some(name) = &ctx_mut.compile_state.namespace {
if let Some(name) = &schema_context.compile_state.borrow_mut().namespace {
panic!("Namespace {} was already previously set", name)
} else {
ctx_mut.compile_state.namespace = Some(name)
schema_context.compile_state.borrow_mut().namespace = Some(name)
}
}
Docstring {..} => {
@ -92,8 +87,6 @@ pub fn interpret_context(
Validator { .. } => {}
Field { .. } => {}
}
context = Some(schema_context.borrow());
}
// Ok(context.unwrap().compile_state.to_frozen())
@ -155,11 +148,13 @@ pub fn interpret_context(
}
#[allow(unused)]
pub fn interpret_node(context: &SchemaContext, node: &ASTUnit)
pub fn interpret_node(schema_context: &SchemaContext, node: &ASTUnit)
-> Result<FrozenUnit, ReportDetails<CompileError>>
{
let schema_ctx = context.project_context.clone().unwrap();
let project_ctx = context.project_context.clone().unwrap();
let Some(project_ctx) = schema_context.project_context else {
panic!()
};
let project_ctx = project_ctx.borrow_mut();
use crate::schema::idl::ast::unit::ASTUnit::*;
match node {
@ -188,7 +183,7 @@ pub fn interpret_node(context: &SchemaContext, node: &ASTUnit)
*/
}
Import(_, i) => {
let relative_unit = project_ctx.borrow().find_schema_by_import(&i);
let relative_unit = project_ctx.find_schema_by_import(&i);
/*
if relative_unit.is_none() {

View file

@ -158,6 +158,7 @@ fn to_kind_only(kind: &(Span, String)) -> KindValue {
}
}
#[allow(unused)]
fn to_primitive(
schema_context: &Rc<RefCell<SchemaContext>>,
kind: &(Span, String), value: String

View file

@ -1,31 +1,29 @@
// Standard Uses
use std::cell::{RefCell, RefMut};
use std::rc::Rc;
use std::cell::RefCell;
// Crate Uses
use crate::report::ReportDetails;
use crate::schema::ir::compiler::report::CompileError;
use crate::schema::ir::context::SchemaContext;
use crate::project::ir::context::ProjectContext;
use crate::schema::ir::compiler::interpreter::semi_frozen::SemiFrozenUnit;
// External Uses
pub fn compile_schema_metadata(
schema_context: &Rc<RefCell<SchemaContext>>, project_context: &RefMut<ProjectContext>
pub fn compile_schema_metadata<'a>(
schema_context: &'a RefCell<SchemaContext<'a>>,
) -> Result<(), ReportDetails<CompileError>> {
let mut context = Some(RefCell::borrow(&schema_context));
let schema_ctx = schema_context.borrow();
let project_ctx = schema_ctx.project_context.unwrap().borrow();
for i in 0..context.as_ref().unwrap().schema.1.len() {
let spanned_unit = &context.as_ref().unwrap().schema.1[i];
for i in 0..schema_ctx.schema.1.len() {
let spanned_unit = &schema_ctx.schema.1[i];
use crate::schema::idl::ast::unit::ASTUnit::*;
match &spanned_unit.1 {
Namespace(_, n) => {
let name = n.clone();
let Some(_)
= project_context.find_schema_by_import(&n) else
let Some(_) = project_ctx.find_schema_by_import(&n) else
{
return Err(ReportDetails {
// kind: "Namespace".to_string(),
@ -42,15 +40,11 @@ pub fn compile_schema_metadata(
})
};
context = None;
let mut ctx_mut = schema_context.borrow_mut();
if let Some(name) = &ctx_mut.compile_state.namespace {
if let Some(name) = &schema_ctx.compile_state.borrow_mut().namespace {
panic!("Namespace {} was already previously set", name)
} else {
ctx_mut.compile_state.namespace = Some(name)
schema_ctx.compile_state.borrow_mut().namespace = Some(name)
}
drop(ctx_mut);
}
Docstring {..} => {
todo!()
@ -64,19 +58,14 @@ pub fn compile_schema_metadata(
*/
}
// Docstring { .. } => {}
#[allow(unused)]
Constant { name, ..} => {
let name = name.clone();
context = None;
let mut ctx_mut = schema_context.borrow_mut();
let spanned_unit = &schema_context.borrow().schema.1[i];
let su = Rc::clone(&spanned_unit);
ctx_mut.compile_state.consts.entry(su).or_insert(
/*
schema_ctx.compile_state.borrow_mut().consts
.entry(&spanned_unit).or_insert(
SemiFrozenUnit::Constant { name: name.clone() }
);
context = Some(RefCell::borrow(&schema_context));
*/
}
Property { .. } => {}
Parameter { .. } => {}
@ -92,8 +81,6 @@ pub fn compile_schema_metadata(
Validator { .. } => {}
Field { .. } => {}
}
context = Some(RefCell::borrow(&schema_context));
}
Ok(())

View file

@ -10,6 +10,7 @@ use crate::schema::ir::context::SchemaContext;
// External Uses
#[allow(unused)]
pub fn compile_schema_metadata(schema_context: &Rc<RefCell<SchemaContext>>
) -> Result<(), ReportDetails<CompileError>>
{

View file

@ -6,6 +6,7 @@ use crate::utils::codemap::Span;
// External Uses
#[derive(Clone)]
pub enum SemiFrozenUnit {
Constant {
name: (Span, String)

View file

@ -1,24 +1,22 @@
// Standard Uses
use std::rc::Rc;
use std::cell::RefCell;
use std::collections::HashMap;
// Local Uses
use crate::project::ir::context::ProjectContext;
use crate::schema::idl::ast::unit::{SourcedWholeRc, SpannedUnit};
use crate::schema::idl::ast::unit::{SourcedWhole, SpannedUnit};
use crate::schema::ir::compiler::interpreter::semi_frozen::SemiFrozenUnit;
use crate::schema::ir::frozen::unit::FrozenUnit;
// External Uses
#[derive(Default)]
pub struct CompileState {
#[derive(Clone, Default)]
pub struct CompileState<'a> {
pub namespace: Option<String>,
pub consts: HashMap<Rc<SpannedUnit>, SemiFrozenUnit>
pub consts: HashMap<&'a SpannedUnit, SemiFrozenUnit>
}
impl CompileState {
impl<'a> CompileState<'_> {
pub(crate) fn to_frozen(&self) -> Vec<FrozenUnit> {
let mut interpreted = vec![];
@ -28,16 +26,18 @@ impl CompileState {
}
}
pub struct SchemaContext {
pub schema: SourcedWholeRc,
pub struct SchemaContext<'a> {
pub schema: SourcedWhole,
pub frozen_schema: Option<Vec<FrozenUnit>>,
pub project_context: Option<Rc<RefCell<ProjectContext>>>,
pub compile_state: CompileState
pub project_context: Option<&'a RefCell<ProjectContext<'a>>>,
// pub project_context: Option<&'a mut ProjectContext<'a>>,
pub compile_state: RefCell<CompileState<'a>>
// pub compile_state: RefCell<CompileState>
}
#[allow(unused)]
impl SchemaContext {
pub fn with_main(schema: SourcedWholeRc) -> Self{
impl<'a> SchemaContext<'a> {
pub fn with_main(schema: SourcedWhole) -> Self{
Self {
schema,
frozen_schema: None,
@ -47,7 +47,7 @@ impl SchemaContext {
}
pub fn with_project_and_main(
schema: SourcedWholeRc, project: Rc<RefCell<ProjectContext>>
schema: SourcedWhole, project: &'a RefCell<ProjectContext<'a>>
) -> Self {
Self {
schema,
@ -57,7 +57,7 @@ impl SchemaContext {
}
}
pub fn with_main_no_std(schema: SourcedWholeRc) -> Self{
pub fn with_main_no_std(schema: SourcedWhole) -> Self{
Self {
schema,
frozen_schema: None,

View file

@ -7,9 +7,10 @@ use crate::schema::ir::compiler::interpreted::primitive::KindValue;
// External Uses
pub type FrozenWhole = (SchemaContext, Vec<FrozenUnit>);
pub type FrozenWhole<'a> = (SchemaContext<'a>, Vec<FrozenUnit>);
#[derive(Debug, Eq, PartialEq, Deserialize, Serialize)]
#[derive(Deserialize, Serialize)]
#[derive(Debug, Eq, PartialEq)]
pub enum FrozenUnit {
// TODO: Are Tags really necessary anymore since we hash Frozen Units by blob, trees and commits?
// Tag(String),

View file

@ -9,5 +9,6 @@ struct Capabilities {
@provider=Any
protocol HealthCheck {
function alive() -> bool
function capabilities() -> Capabilities
}