Initial Dever 0.0.1

This commit is contained in:
Codex committed 2026-11-03 03:32:07 +00:00
commit 81233d098c
1479 files changed
+163782

No files matched your search

+370
View File
@@ -0,0 +1,370 @@
//! 由已检查表达式计算事实,同时验证每个构造和调用边界。
//! 不支持推导的数值操作只失去精度,不允许绕过合同。
use super::{Fact, Proof, number, require};
use crate::compiler::model::{
numeric::{Number, Range},
*,
};
use crate::syntax::{ast::Literal, diagnostic::Diagnostic, source::Span};
use std::{collections::BTreeMap, rc::Rc};
impl Proof<'_> {
pub(super) fn expression(&mut self, value: &Expression) -> Result<Rc<Fact>, Diagnostic> {
self.remaining = self.remaining.checked_sub(1).ok_or_else(|| {
Diagnostic::new("C015", "range proof exceeds its work limit", value.span)
})?;
let unknown = || Fact::unknown(&value.value_type);
Ok(match &value.kind {
Node::Literal(Literal::Number(text))
if matches!(value.value_type, Type::Int | Type::Decimal) =>
{
Fact::scalar(Some(Range::point(
Number::parse(text, &value.value_type).expect("checked literal"),
)))
}
Node::Literal(_) => unknown(),
Node::TestSecret(inner)
| Node::TestClock(inner)
| Node::TestDrain { limit: inner, .. } => {
self.expression(inner)?;
unknown()
}
Node::Variable(index) => self.variables[*index].clone(),
Node::Field(base, index) => {
self.expression(base)?
.field(*index, &base.value_type, self.definitions)
}
Node::Call(index, arguments) => {
self.arguments(*index, arguments)?;
self.outputs(*index)
}
Node::Record(index, values) => {
let mut fields = BTreeMap::new();
for (position, value) in values {
let fact = self.expression(value)?;
self.require_value(value, &fact, self.definitions[*index].ranges[*position])?;
fields.insert(*position, fact);
}
Rc::new(Fact {
fields,
..Fact::default()
})
}
Node::Variant(index, variant, values) => {
let Shape::Choice(variants) = &self.definitions[*index].shape else {
unreachable!()
};
for (value, &expected) in values.iter().zip(&variants[*variant].ranges) {
let fact = self.expression(value)?;
self.require_value(value, &fact, expected)?;
}
unknown()
}
Node::Capture(capture) => {
let fact = self.expression(&capture.call)?;
let Shape::Choice(variants) = &self.definitions[capture.definition].shape else {
unreachable!()
};
if let Node::Call(function, _) = capture.call.kind {
let signature = &self.signatures[function];
if signature.returns.is_some() {
for (((_, kind), &actual), &expected) in signature
.outputs
.iter()
.zip(&signature.output_ranges)
.zip(&variants[capture.success].ranges)
{
require(
actual.or_else(|| super::numeric_range(kind)),
expected,
value.span,
)?;
}
}
} else {
require(
fact.range
.or_else(|| super::numeric_range(&capture.call.value_type)),
variants[capture.success].ranges[0],
value.span,
)?;
}
unknown()
}
Node::Unary(operator, base) => {
let fact = self.expression(base)?;
if operator == "-" {
fact.range
.and_then(number::negate)
.map_or_else(unknown, |range| Fact::scalar(Some(range)))
} else {
unknown()
}
}
Node::Binary(operator, left, right) => {
let left = self.expression(left)?;
let right = self.expression(right)?;
if matches!(value.value_type, Type::Int | Type::Decimal) {
let range = left
.range
.zip(right.range)
.and_then(|(left, right)| number::binary(operator, left, right));
if value.value_type == Type::Int
&& matches!(operator.as_str(), "+" | "-" | "*")
&& range.is_some()
{
let span = value.span;
self.arithmetic.insert((span.source, span.start, span.end));
}
range.map_or_else(unknown, |range| Fact::scalar(Some(range)))
} else {
unknown()
}
}
Node::Decimal(base) => {
let fact = self.expression(base)?;
Fact::scalar(fact.range.map(number::decimal))
}
Node::Some(base) => self.expression(base)?,
Node::Length(base) => {
self.expression(base)?;
Fact::scalar(Some(Range {
minimum: Number::Int(0),
maximum: Number::Int(i64::MAX),
}))
}
Node::List(values) => {
let mut range = None;
let mut numeric = true;
for value in values {
let fact = self.expression(value)?;
numeric &= fact.range.is_some();
if let Some(actual) = fact.range {
range = Some(range.map_or(actual, |previous: Range| previous.hull(actual)));
}
}
Rc::new(Fact {
item: numeric.then(|| Fact::scalar(range)),
..Fact::default()
})
}
Node::Map(entries) => {
for (key, value) in entries {
self.expression(key)?;
self.expression(value)?;
}
unknown()
}
Node::Collection(collection) => self.collection(collection, value.span)?,
Node::Access(operation, values) => {
let facts = values
.iter()
.map(|value| self.expression(value))
.collect::<Result<Vec<_>, _>>()?;
match operation {
Access::First => facts[0].item.clone().unwrap_or_else(unknown),
_ => unknown(),
}
}
Node::Crypto(_, values)
| Node::Assert(values)
| Node::Calendar(_, values)
| Node::Standard(_, values)
| Node::Bytes(_, values)
| Node::Net(_, values)
| Node::Http(_, values)
| Node::Tls(_, values)
| Node::Database(_, values)
| Node::Auth(_, values)
| Node::Authorization(_, values)
| Node::Enqueue(_, values)
| Node::Io(_, values)
| Node::Upload(_, values)
| Node::Json(_, values) => {
for value in values {
self.expression(value)?;
}
unknown()
}
Node::Schedule(operation, target, values) => {
self.arguments(*target, values)?;
if *operation == Schedule::Run {
unknown()
} else {
self.outputs(*target)
}
}
Node::Join { task, .. } => {
self.expression(task)?;
if let Type::Task(target) = task.value_type {
self.outputs(target)
} else {
unknown()
}
}
Node::Timeout {
task,
millis,
fallback,
} => {
self.expression(task)?;
self.expression(millis)?;
let Type::Task(target) = task.value_type else {
unreachable!("checked Task");
};
self.alternatives([target, *fallback], value)?
}
Node::Race(tasks) => {
let mut targets = Vec::new();
for task in tasks {
self.expression(task)?;
let Type::Task(target) = task.value_type else {
unreachable!("checked Task");
};
targets.push(target);
}
self.alternatives(targets, value)?
}
Node::Stream(base) => self.expression(base)?,
Node::Channel(limit)
| Node::Receive(limit)
| Node::Group(limit)
| Node::Ticks(limit) => {
self.expression(limit)?;
unknown()
}
Node::Send(channel, sent) => {
self.expression(channel)?;
self.expression(sent)?;
unknown()
}
Node::GroupRun {
group,
target,
arguments,
} => {
self.expression(group)?;
self.arguments(*target, arguments)?;
unknown()
}
Node::Timer(_, base) => {
self.expression(base)?;
unknown()
}
Node::Id(base) | Node::IdText(base) | Node::Sum(base) | Node::Close(base) => {
self.expression(base)?;
unknown()
}
})
}
fn arguments(&mut self, function: usize, arguments: &[Expression]) -> Result<(), Diagnostic> {
for (argument, &expected) in arguments
.iter()
.zip(&self.signatures[function].input_ranges)
{
let fact = self.expression(argument)?;
self.require_value(argument, &fact, expected)?;
}
Ok(())
}
fn alternatives(
&mut self,
targets: impl IntoIterator<Item = usize>,
source: &Expression,
) -> Result<Rc<Fact>, Diagnostic> {
let mut fact: Option<Rc<Fact>> = None;
for target in targets {
if self.signatures[target].returns.is_none() {
continue;
}
self.remaining = self
.remaining
.checked_sub(self.signatures[target].outputs.len().max(1))
.ok_or_else(|| {
Diagnostic::new("C015", "range proof exceeds its work limit", source.span)
})?;
let value = self.outputs(target);
fact = Some(match fact {
Some(previous) => Fact::union(&previous, &value),
None => value,
});
}
Ok(fact.unwrap_or_else(|| Fact::unknown(&source.value_type)))
}
fn outputs(&self, function: usize) -> Rc<Fact> {
let ranges = &self.signatures[function].output_ranges;
let outputs = &self.signatures[function].outputs;
if let [range] = ranges.as_slice() {
return Fact::scalar(range.or_else(|| super::numeric_range(&outputs[0].1)));
}
Rc::new(Fact {
fields: ranges
.iter()
.enumerate()
.map(|(index, range)| {
(
index,
Fact::scalar(range.or_else(|| super::numeric_range(&outputs[index].1))),
)
})
.collect(),
..Fact::default()
})
}
fn collection(&mut self, collection: &Collection, span: Span) -> Result<Rc<Fact>, Diagnostic> {
let sequence = self.expression(&collection.sequence)?;
if let Some(limit) = &collection.limit {
self.expression(limit)?;
}
let extra = collection
.extra
.as_ref()
.map(|value| self.expression(value))
.transpose()?;
let signature = &self.signatures[collection.handler];
let item = if collection.sequence.value_type == Type::Bytes {
Fact::scalar(Some(Range {
minimum: Number::Int(0),
maximum: Number::Int(255),
}))
} else {
sequence
.item
.clone()
.unwrap_or_else(|| Fact::unknown(&signature.inputs[0].1))
};
self.require_value(&collection.sequence, &item, signature.input_ranges[0])?;
if let (Some(extra), Some(value)) = (&extra, &collection.extra) {
self.require_value(value, extra, signature.input_ranges[1])?;
if collection.operation.reduction() && signature.returns.is_some() {
require(signature.output_ranges[0], signature.input_ranges[1], span)?;
}
}
Ok(match collection.operation {
Operation::ParallelEach => Fact::unknown(&Type::Unit),
Operation::Each => Rc::new(Fact {
item: Some(self.outputs(collection.handler)),
..Fact::default()
}),
Operation::Filter => sequence,
Operation::Find => item,
Operation::Reduce | Operation::ReduceUntil => {
let initial = extra.expect("reduction state").range;
let range = if signature.returns.is_none() {
initial
} else {
initial
.zip(signature.output_ranges[0])
.map(|(initial, next)| initial.hull(next))
};
Fact::scalar(range)
}
Operation::Sum => Fact::unknown(&signature.outputs[0].1),
})
}
}