feat: publish Dever core with project scaffolding and versioned AI skills

This commit is contained in:
Antigravity committed 2026-10-04 13:37:30 +00:00
1 parent 70fa73cdc2
commit ac458ffa7f
960 files changed
+221319 -1163

No files matched your search

+253
View File
@@ -0,0 +1,253 @@
use crate::diagnostic::Diagnostic;
use crate::hir::{
CallArgument, CallTarget, Expression, ExpressionKind, Function, HandlerTarget, Statement,
};
use crate::source::Span;
use crate::types::{Definition, Parameter};
use super::{
Symbols,
symbols::{referenced_types, shape_fields},
};
pub(super) fn check(
functions: &[Function],
types: &[Definition],
symbols: &Symbols,
errors: &mut Vec<Diagnostic>,
) {
let mut calls = vec![Vec::new(); functions.len()];
let mut dependencies = vec![Vec::new(); symbols.packages.len()];
for definition in types {
for field in shape_fields(&definition.shape) {
referenced_types(&field.ty, &mut |id| {
dependency(
&mut dependencies,
definition.owner,
types[id].owner,
definition.span,
symbols,
)
});
}
}
for (caller, function) in functions.iter().enumerate() {
for ty in function
.parameters
.iter()
.flat_map(|parameter| match parameter {
Parameter::Value(ty) => vec![ty],
Parameter::Handler(signature) => signature
.parameters
.iter()
.chain(signature.outputs.iter().map(|field| &field.ty))
.collect(),
})
.chain(function.outputs.iter().map(|field| &field.ty))
{
referenced_types(ty, &mut |id| {
dependency(
&mut dependencies,
function.owner,
types[id].owner,
function.span,
symbols,
)
});
}
visit(function, |expression| {
referenced_types(&expression.ty, &mut |id| {
dependency(
&mut dependencies,
function.owner,
types[id].owner,
expression.span,
symbols,
)
});
let callee = match expression.kind.static_call().map(|(target, _)| target) {
Some(CallTarget::Function(function))
| Some(CallTarget::Handler(HandlerTarget::Function(function))) => Some(function),
_ => match expression.kind.callback() {
Some(HandlerTarget::Function(function)) => Some(function),
_ => None,
},
};
if let Some(callee) = callee {
calls[caller].push((callee, expression.span));
dependency(
&mut dependencies,
function.owner,
functions[callee].owner,
expression.span,
symbols,
);
}
if let Some((_, arguments)) = expression.kind.static_call() {
for argument in arguments {
if let CallArgument::Handler(HandlerTarget::Function(target)) = argument {
dependency(
&mut dependencies,
function.owner,
functions[*target].owner,
expression.span,
symbols,
);
}
}
}
});
}
for (graph, message) in [
(&calls, "recursive function calls are not allowed"),
(&dependencies, "cyclic package dependencies are not allowed"),
] {
if let Some(span) = cycle(graph) {
errors.push(Diagnostic::error("C007", message, span));
}
}
let roots = functions
.iter()
.enumerate()
.filter(|(_, function)| {
function
.parameters
.iter()
.all(|parameter| matches!(parameter, Parameter::Value(_)))
})
.map(|(function, _)| crate::specialize::Specialization {
function,
handlers: Vec::new(),
});
if let Err(span) = crate::specialize::reachable(functions, roots) {
errors.push(Diagnostic::error(
"C007",
"recursive specialized handler calls are not allowed",
span,
));
}
}
// Explicit DFS frames keep long acyclic call chains off the compiler's call stack.
pub(super) fn cycle(graph: &[Vec<(usize, Span)>]) -> Option<Span> {
let mut state = vec![0_u8; graph.len()];
for root in 0..graph.len() {
if state[root] != 0 {
continue;
}
state[root] = 1;
let mut pending = vec![(root, 0)];
while let Some((node, edge)) = pending.last_mut() {
if *edge == graph[*node].len() {
state[*node] = 2;
pending.pop();
continue;
}
let (next, span) = graph[*node][*edge];
*edge += 1;
match state[next] {
1 => return Some(span),
0 => {
state[next] = 1;
pending.push((next, 0));
}
_ => {}
}
}
}
None
}
fn dependency(
graph: &mut [Vec<(usize, Span)>],
owner: usize,
target: usize,
span: Span,
symbols: &Symbols,
) {
let same_domain = symbols.packages[owner].layout.domain().is_some()
&& symbols.packages[owner].layout.domain() == symbols.packages[target].layout.domain();
if owner != target && !same_domain {
graph[owner].push((target, span));
}
}
pub(crate) fn visit(function: &Function, mut apply: impl FnMut(&Expression)) {
let mut pending = Vec::new();
for clause in &function.clauses {
for statement in &clause.body {
pending.push(match statement {
Statement::Assign { value, .. } | Statement::Call(value) => value,
});
}
}
visit_pending(pending, &mut apply);
}
pub(crate) fn visit_expression(expression: &Expression, mut apply: impl FnMut(&Expression)) {
visit_pending(vec![expression], &mut apply);
}
fn visit_pending<'a>(mut pending: Vec<&'a Expression>, apply: &mut impl FnMut(&'a Expression)) {
while let Some(expression) = pending.pop() {
apply(expression);
match &expression.kind {
ExpressionKind::Field { value, .. }
| ExpressionKind::Fail(value)
| ExpressionKind::Unary { value, .. }
| ExpressionKind::Promote(value)
| ExpressionKind::Some(value)
| ExpressionKind::AwaitTask(value)
| ExpressionKind::StopTask(value)
| ExpressionKind::Group(value)
| ExpressionKind::AwaitGroup(value)
| ExpressionKind::StopGroup(value)
| ExpressionKind::ChannelReceive(value)
| ExpressionKind::ChannelClose(value) => pending.push(value),
ExpressionKind::Call { arguments, .. }
| ExpressionKind::CaptureResult { arguments, .. }
| ExpressionKind::ParallelCall { arguments, .. }
| ExpressionKind::BlockingCall { arguments, .. } => {
pending.extend(arguments.iter().filter_map(|argument| match argument {
CallArgument::Value(value) => Some(value),
CallArgument::Handler(_) => None,
}));
}
ExpressionKind::RunCall {
group, arguments, ..
} => {
pending.extend(group.iter().map(Box::as_ref));
pending.extend(arguments.iter().filter_map(|argument| match argument {
CallArgument::Value(value) => Some(value),
CallArgument::Handler(_) => None,
}));
}
ExpressionKind::ModelOperation { operation, .. } => {
pending.extend(operation.expressions());
}
ExpressionKind::Channel { capacity, .. } => pending.push(capacity),
ExpressionKind::ChannelSend { channel, value } => {
pending.extend([channel.as_ref(), value.as_ref()]);
}
ExpressionKind::Intrinsic { arguments, .. }
| ExpressionKind::JobEnqueue { arguments, .. }
| ExpressionKind::Collection { arguments, .. }
| ExpressionKind::Variant { arguments, .. }
| ExpressionKind::List(arguments) => pending.extend(arguments),
ExpressionKind::Record { fields } => {
pending.extend(fields.iter().map(|(_, value)| value));
}
ExpressionKind::Map(entries) => {
for (key, value) in entries {
pending.extend([key, value]);
}
}
ExpressionKind::Binary { left, right, .. } => {
pending.extend([left.as_ref(), right.as_ref()]);
}
ExpressionKind::Constant(_)
| ExpressionKind::Local(_)
| ExpressionKind::ChoiceOptions { .. } => {}
}
}
}