Commit 67aa9dcd authored by Lennard Gäher's avatar Lennard Gäher
Browse files

upd frontend

parent 05e3c269
......@@ -203,11 +203,10 @@ dependencies = [
"env_logger",
"lazy_static",
"log",
"proc-macro2",
"regex",
"rustc-hash",
"serde 1.0.130",
"syn",
"unicode-xid 0.0.4",
]
[[package]]
......@@ -354,7 +353,7 @@ version = "1.0.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d"
dependencies = [
"unicode-xid",
"unicode-xid 0.2.2",
]
[[package]]
......@@ -513,7 +512,7 @@ checksum = "d010a1623fbd906d51d650a9916aaefc05ffa0e4053ff7fe601167f3e715d194"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
"unicode-xid 0.2.2",
]
[[package]]
......@@ -564,6 +563,12 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
[[package]]
name = "unicode-xid"
version = "0.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
[[package]]
name = "unicode-xid"
version = "0.2.2"
......
dump_borrowck_info=true
output_dir="./output"
| Keyword | Purpose | Properties | Example |
--------------------------------------------------------------------------------------------
| `params` | specify Coq-level parameters | multiple | `#[rr:params("n" : "Z", b : "bool")]` |
| `param` | specify Coq-level parameters | multiple | `#[rr:param("n" : "Z")]` |
| `args` | specify argument types | single | `#[rr::args("n" @ "int i32", "b" @ "boolean"]` |
| `returns` | specify return type | single | `#[rr::returns("42" @ "int i32")]` |
| `requires` | specify a precondition | multiple | `#[rr:requires("⌜i > 42⌝")]` |
| `ensures` | specify a postcondition | multiple | `#[rr::ensures("⌜x > y⌝")]` |
| `exists` | specify an existential for the postco | multiple | `#[rr::exists("x" : "Z")]` |
......@@ -14,8 +14,9 @@ serde = "1.0.130"
csv = "1.1"
config = "0.11"
lazy_static = "1.4.0"
syn = { version = "1.0.80", features = ["full", "parsing"] }
proc-macro2 = "1.0"
#syn = { version = "1.0.80", features = ["full", "parsing"] }
#proc-macro2 = "1.0"
unicode-xid = "0.0.4"
analysis = { path = "../analysis" }
......
......@@ -38,7 +38,7 @@ impl CaesiumLiteral {
format!("i2v ({}) {}", i.as_str(), it.caesium_fmt().as_str())
};
let format_bool = |i: String| {
format!("i2v (Z_of_bool {}) {}", i.as_str(), (CaesiumIntType::CaesiumU8).caesium_fmt().as_str())
format!("i2v (Z_of_bool {}) {}", i.as_str(), (BOOL_REPR).caesium_fmt().as_str())
};
match self {
Self::LitI8(i) => format_int(i.to_string(), CaesiumIntType::CaesiumI8),
......@@ -114,6 +114,12 @@ pub enum CaesiumExpr {
ly: CaesiumStructLayout,
name: String,
},
Annot {
a: CaesiumAnnotation,
e: Box<CaesiumExpr>
},
DropE(Box<CaesiumExpr>),
BoxE(CaesiumLayout),
}
impl CaesiumExpr {
......@@ -155,7 +161,6 @@ impl CaesiumExpr {
Self::Borrow{lft, bk, e} => {
let formatted_bk = bk.caesium_fmt();
let formatted_e = e.caesium_fmt();
// TODO: needs lifetime info
format!("&ref{{ {}, \"{}\" }} ({})", formatted_bk, lft, formatted_e)
},
Self::AddressOf{mt, e} => {
......@@ -175,7 +180,18 @@ impl CaesiumExpr {
let formatted_ly = ly.caesium_fmt();
format!("{} at{{ {} }} \"{}\"", formatted_e, formatted_ly, name)
},
Self::Annot{a, e} => {
let formatted_e = e.caesium_fmt();
format!("AnnotExpr {} ({}) ({})", a.needs_laters(), a, formatted_e)
},
Self::BoxE(ly) => {
let formatted_ly = ly.caesium_fmt();
format!("box{{{}}}", formatted_ly)
},
Self::DropE(e) => {
let formatted_e = e.caesium_fmt();
format!("drop ({})", formatted_e)
}
// TODO
_ => format!(""),
}
......@@ -213,8 +229,14 @@ impl CaesiumBorKind {
}
pub enum CaesiumAnnotation {
/// Start a lifetime as a sublifetime of the intersection of a few other lifetimes
StartLft(CaesiumLft, Vec<CaesiumLft>),
/// End this lifetime
EndLft(CaesiumLft),
/// Extend this lifetime by making the directly owned part static
ExtendLft(CaesiumLft),
/// Shorten the lifetime of an object to the intersection of the given lifetimes
ShortenLft(Vec<CaesiumLft>),
}
impl fmt::Display for CaesiumAnnotation {
fn fmt(&self, f : &mut fmt::Formatter<'_>) -> fmt::Result {
......@@ -234,11 +256,36 @@ impl fmt::Display for CaesiumAnnotation {
},
Self::EndLft(l) => {
write!(f, "EndLftAnnot \"{}\"", l)
},
Self::ExtendLft(l) => {
write!(f, "ExtendLftAnnot \"{}\"", l)
},
Self::ShortenLft(sup) => {
write!(f, "ShortenLftAnnot [")?;
let mut need_sep = false;
for s in sup.iter() {
if need_sep {
write!(f, ", ")?;
}
write!(f, "\"{}\"", s)?;
need_sep = true;
}
write!(f, "]")
}
}
}
}
impl CaesiumAnnotation {
pub(crate) fn needs_laters(&self) -> u32 {
match self {
Self::ShortenLft{..} => 0,
_ => 0,
}
}
}
type CaesiumBlockLabel = String;
pub enum CaesiumStmt {
......@@ -375,7 +422,7 @@ impl CaesiumBinop {
let rt = String::with_capacity(20);
let format_prim = |st:&str| format!("{}{{ {} , {} }}", st, ot1.caesium_fmt(), ot2.caesium_fmt());
let format_bool = |st:&str| format!("{}{{ {} , {} , {} }}", st, ot1.caesium_fmt(), ot2.caesium_fmt(), (CaesiumIntType::CaesiumU8).caesium_fmt());
let format_bool = |st:&str| format!("{}{{ {} , {} , {} }}", st, ot1.caesium_fmt(), ot2.caesium_fmt(), (BOOL_REPR).caesium_fmt());
match self {
......@@ -466,6 +513,8 @@ impl CaesiumIntType {
}
}
pub static BOOL_REPR: CaesiumIntType = CaesiumIntType::CaesiumI8;
// Notes on ADT representation:
// - Rust structs have a single variant with several fields. This is directly accomodated by
// Caesium structs.
......@@ -571,8 +620,9 @@ pub enum CaesiumLayout {
impl CaesiumLayout {
pub fn into_caesium_op_type(self) -> CaesiumOpType {
match self {
//Self::PtrLayout => CaesiumOpType::PtrOp,
//Self::IntLayout(it) => CaesiumOpType::IntOp(it),
Self::PtrLayout => CaesiumOpType::PtrOp,
Self::IntLayout(it) => CaesiumOpType::IntOp(it),
Self::BoolLayout => CaesiumOpType::IntOp(BOOL_REPR),
// TODO: handle structs?
layout => CaesiumOpType::UntypedOp(layout),
}
......@@ -582,11 +632,11 @@ impl CaesiumLayout {
match self {
Self::PtrLayout => "void*".to_string(),
Self::IntLayout(it) => format!("it_layout {}", it.caesium_fmt().as_str()),
Self::BoolLayout => format!("it_layout {}", (CaesiumIntType::CaesiumU8).caesium_fmt().as_str()),
Self::BoolLayout => format!("it_layout {}", BOOL_REPR.caesium_fmt().as_str()),
// TODO
Self::CharLayout => format!("char_layout"),
// TODO
Self::UnitLayout => format!("unit_layout"),
Self::UnitLayout => format!("(layout_of unit_layout)"),
//TODO
Self::StructLayout(ly) => format!("struct_layout"),
// TODO
......@@ -649,6 +699,18 @@ pub struct CaesiumFunctionCode {
required_parameters: Vec<(CoqName, CoqType)>,
}
fn make_map_string(sep0: &str, sep: &str, els: Vec<(String, String)>) -> String {
let mut out = String::with_capacity(100);
for (key, value) in els.iter() {
out.push_str(sep);
out.push_str(format!("<[\"{}\" :={}{}{}]>%E $", key, sep0, value, sep).as_str());
}
out.push_str(sep);
out.push_str("∅");
out
}
impl CaesiumFunctionCode {
const initial_bb: &'static str = "_bb0";
pub fn caesium_fmt(&self) -> String {
......@@ -679,18 +741,8 @@ impl CaesiumFunctionCode {
let mut formatted_locals = String::with_capacity(100);
formatted_locals.push_str(format!("{}f_local_vars := {}", make_indent(1), format_stack_layout(self.stack_layout.iter_locals()).as_str()).as_str());
let mut formatted_bb = String::with_capacity(1000);
formatted_bb.push_str(format!("{}f_code :=", make_indent(1).as_str()).as_str());
for (name, bb) in self.basic_blocks.iter() {
formatted_bb.push_str("\n");
formatted_bb.push_str(make_indent(2).as_str());
let printed_stmt = bb.caesium_fmt(3);
formatted_bb.push_str(format!("<[\"{}\" :=\n{}\n{}]>%E $", name, printed_stmt, make_indent(2).as_str()).as_str());
}
formatted_bb.push_str("\n");
formatted_bb.push_str(make_indent(2).as_str());
formatted_bb.push_str("∅");
let formatted_bb = make_map_string("\n", format!("\n{}", make_indent(2).as_str()).as_str(),
self.basic_blocks.iter().map(|(name, bb)| (name.to_string(), bb.caesium_fmt(3))).collect());
if self.basic_blocks.len() < 1 {
panic!("CaesiumFunction has no basic block");
......@@ -704,15 +756,20 @@ impl CaesiumFunctionCode {
formatted_params.push_str(format!("({}, : {})", name, ty).as_str());
}
format!("Definition {} {} : function := {{|\n{};\n{};\n{};\n{};\n|}}",
format!("Definition {}_def {} : function := {{|\n{};\n{};\n{}f_code := {};\n{};\n|}}.",
self.name.as_str(),
formatted_params.as_str(),
formatted_args.as_str(),
formatted_locals.as_str(),
make_indent(1).as_str(),
formatted_bb.as_str(),
formatted_init.as_str())
}
/// Get the number of arguments of the function.
pub fn get_argument_count(&self) -> usize {
self.stack_layout.iter_args().len()
}
}
......@@ -831,6 +888,92 @@ pub struct CaesiumFunction {
pub spec: CaesiumFunctionSpec,
}
impl CaesiumFunction {
/// Get the name of the function.
pub fn name(&self) -> &str {
&self.code.name
}
pub fn generate_proof(&self) -> String {
let mut out = String::with_capacity(100);
let indent0 = make_indent(2);
let indent = indent0.as_str();
out.push_str(format!("\
Lemma {}_proof {} (π : thread_id) :\n\
{}⊢ typed_function π {}_def type_of_{}.\n\
Proof.\n",
self.name(), self.spec.coq_context.join(" "), indent, self.name(), self.name()).as_str());
// generate intro pattern for params
let mut ip_params = String::with_capacity(100);
let params = &self.spec.decomposed_params;
if params.len() >0 {
// product is left-associative
for _ in 0 .. params.len() - 1 {
ip_params.push_str("[ ");
}
let mut p_count = 0;
for (n, _) in params {
if p_count > 1 {
ip_params.push_str(" ]");
}
ip_params.push_str(" ");
p_count += 1;
ip_params.push_str(format!("{}", n).as_str());
}
if p_count > 1 {
ip_params.push_str(" ]");
}
}
else {
// no params, but still need to provide something to catch the unit
// (and no empty intropatterns are allowed)
ip_params.push_str("?");
}
out.push_str(format!("{}iStartProof.\n", indent).as_str());
out.push_str(format!("{}start_function \"{}\" ( {} ).\n", indent, self.name(), ip_params.as_str()).as_str());
// intro stack locations
out.push_str(format!("{}intros", indent).as_str());
for (arg, _) in self.code.stack_layout.arg_map.iter() {
out.push_str(" arg_");
out.push_str(arg.as_str());
}
for (local, _) in self.code.stack_layout.local_map.iter() {
out.push_str(" local_");
out.push_str(local.as_str());
}
out.push_str(".\n");
// destruct function parameters
out.push_str(format!("{}prepare_parameters (", indent).as_str());
for (n, _) in params {
out.push_str(" ");
out.push_str(format!("{}", n).as_str());
}
out.push_str(" ).\n");
// initialize lifetimes
let formatted_lifetimes = make_map_string(" ", " ", self.spec.decomposed_params.iter().filter_map(|(n, t)| if t.eq(&CoqType::Lft) { Some ((n.to_string(), n.to_string())) } else { None }).collect());
out.push_str(format!("{}init_lfts ({} ).\n", indent, formatted_lifetimes.as_str()).as_str());
// TODO: split blocks
out.push_str(format!("{}repeat liRStep; liShow.\n", indent).as_str());
out.push_str(format!("{}Unshelve. all: li_unshelve_sidecond; sidecond_hook; prepare_sideconditions; normalize_and_simpl_goal; try solve_goal; unsolved_sidecond_hook.\n", indent).as_str());
// TODO custom tactics specified in annotations
out.push_str(format!("{}Unshelve. all: try done; try apply: inhabitant; print_remaining_shelved_goal \"{}\".\n", indent, self.name()).as_str());
out.push_str("Qed.\n");
out
}
}
/// A CaesiumFunctionBuilder allows to incrementally construct the functions's code and the spec
/// at the same time. It ensures that both definitions line up in the right way (for instance, by
/// ensuring that other functions are linked up in a consistent way).
......@@ -871,8 +1014,8 @@ impl CaesiumFunctionBuilder {
}
/// Adds a lifetime parameter to the function.
fn add_universal_lifetime(&mut self, lft: CaesiumLft) -> Result<(), String> {
self.spec.add_coq_param(CoqName::Named(lft), CoqType::Lft, false)
pub fn add_universal_lifetime(&mut self, lft: CaesiumLft) -> Result<(), String> {
self.spec.add_param(CoqName::Named(lft), CoqType::Lft)
}
}
......
......@@ -2,7 +2,7 @@ use std::collections::HashSet;
use std::fmt::{Formatter, Display};
use std::fmt as fmt;
#[derive(Clone)]
#[derive(Clone, Debug)]
pub enum IPropConj {
Literal(String),
}
......@@ -15,7 +15,7 @@ impl Display for IPropConj {
}
}
#[derive(Clone)]
#[derive(Clone, Debug)]
/// Encodes a RR type with an accompanying refinement.
pub enum CaesiumTypeWithRef {
/// refinement + type
......@@ -28,12 +28,12 @@ impl Display for CaesiumTypeWithRef {
match self {
Self::Literal(rfn, t) => write!(f, "{} @ {}", rfn, t),
// TODO might need fix to rename unit
Self::Unit => write!(f, ".@ unit"),
Self::Unit => write!(f, "() @ unit_t"),
}
}
}
#[derive(Clone)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum CoqType {
Literal(String),
/// Coq type `lft`
......@@ -51,7 +51,7 @@ impl Display for CoqType {
}
}
#[derive(Clone)]
#[derive(Clone, Debug)]
pub enum CoqName {
Named(String),
Unnamed,
......@@ -71,7 +71,7 @@ pub type CoqPattern = String;
pub type CaesiumLft = String;
/// A universal lifetime that is not locally owned.
#[derive(Clone)]
#[derive(Clone, Debug)]
pub enum CaesiumUniversalLft {
Function,
Static,
......@@ -94,26 +94,33 @@ type CaesiumExtLftConstr = (CaesiumUniversalLft, CaesiumUniversalLft);
/**
* A Caesium function specification.
*/
#[derive(Debug)]
pub struct CaesiumFunctionSpec {
/// Coq-level parameters the typing statement needs (bool is for implicit or not)
coq_params: Vec<(CoqName, CoqType, bool)>,
pub coq_params: Vec<(CoqName, CoqType, bool)>,
/// Function name
function_name : String,
pub function_name : String,
/// function parameters (available in the typing proof)
param: (CoqPattern, CoqType),
pub param: (CoqPattern, CoqType),
// we keep the uncooked parameters to be able to generate the proof script
pub decomposed_params: Vec<(CoqName, CoqType)>,
/// external lifetime context
elctx: Vec<CaesiumExtLftConstr>,
pub elctx: Vec<CaesiumExtLftConstr>,
/// precondition as a separating conjunction
pre: Vec<IPropConj>,
pub pre: Vec<IPropConj>,
/// argument types including refinements
args: Vec<CaesiumTypeWithRef>,
pub args: Vec<CaesiumTypeWithRef>,
/// existential quantifiers for the postcondition
existential: (CoqPattern, CoqType),
pub existential: (CoqPattern, CoqType),
/// return type
ret: CaesiumTypeWithRef,
pub ret: CaesiumTypeWithRef,
/// postcondition as a separating conjunction
post: Vec<IPropConj>
pub post: Vec<IPropConj>,
/// true iff any attributes have been provided
has_spec: bool,
/// additional things to assume in the coq context
pub coq_context: Vec<String>,
}
impl CaesiumFunctionSpec {
......@@ -141,9 +148,9 @@ impl CaesiumFunctionSpec {
let mut need_sep = false;
for conjunct in conj.iter() {
if need_sep {
out.push_str(" * ");
out.push_str(" ");
}
out.push_str(format!("{}", conjunct).as_str());
out.push_str(format!("({})", conjunct).as_str());
need_sep = true;
}
}
......@@ -188,6 +195,10 @@ impl CaesiumFunctionSpec {
}
out
}
pub fn has_spec(&self) -> bool {
self.has_spec
}
}
impl Display for CaesiumFunctionSpec {
......@@ -196,8 +207,9 @@ impl Display for CaesiumFunctionSpec {
fn(∀ [param_pat] : [param_type]; [elctx]; [args]; [pre])
→ ∃ [exist_pat] : [exist_type], [ret_type]; [post]
*/
write!(f, "Definition type_of_{} {} :\n", self.function_name, self.format_coq_params().as_str())?;
write!(f, " fn(∀ {} : {}; ({}); ", self.param.0, self.param.1, self.format_elctx().as_str())?;
let context_string = self.coq_context.join(" ");
write!(f, "Definition type_of_{} {} {} :=\n", self.function_name, context_string, self.format_coq_params().as_str())?;
write!(f, " fn(∀ {} : {}, ({}); ", self.param.0, self.param.1, self.format_elctx().as_str())?;
if self.args.len() == 0 {
write!(f, "{})\n", Self::format_iprop_conj(&self.pre).as_str())?;
}
......@@ -214,7 +226,7 @@ impl Display for CaesiumFunctionSpec {
// - this should be largely independent of the spec interface provided to the user, i.e. should be
// relatively low-level
// - should be flexible enough to be later on used for more natural specs.
#[derive(Debug)]
pub struct CaesiumFunctionSpecBuilder {
/// Coq-level parameters the typing statement needs, bool is true if implicit
coq_params: Vec<(CoqName, CoqType, bool)>,
......@@ -228,6 +240,11 @@ pub struct CaesiumFunctionSpecBuilder {
post: Vec<IPropConj>,
coq_names: HashSet<String>,
/// true iff there are any annotations
has_spec: bool,
coq_context: Vec<String>,
}
impl CaesiumFunctionSpecBuilder {
......@@ -242,6 +259,8 @@ impl CaesiumFunctionSpecBuilder {
ret: None,
post: Vec::new(),
coq_names: HashSet::new(),
has_spec: false,
coq_context: Vec::new(),
}
}
......@@ -338,6 +357,15 @@ impl CaesiumFunctionSpecBuilder {
Ok(())
}
/// Add the information that attributes have been provided for this function.
pub fn have_spec(&mut self) {
self.has_spec = true;
}
pub fn add_coq_context_item(&mut self, item: String) {
self.coq_context.push(item);
}
fn uncurry_typed_binders(v : &[(CoqName, CoqType)]) -> (CoqPattern, CoqType) {
if v.len() == 0 {
("_".to_string(), CoqType::Literal("unit".to_string()))
......@@ -346,13 +374,13 @@ impl CaesiumFunctionSpecBuilder {
let mut pattern = String::with_capacity(100);
let mut types = String::with_capacity(100);
pattern.push_str("'(");
pattern.push_str("(");
types.push_str("(");
let mut need_sep = false;
for (name, t) in v {
if need_sep {
pattern.push_str(", ");
types.push_str(", ");
types.push_str(" * ");
}
pattern.push_str(format!("{}", name).as_str());
types.push_str(format!("{}", t).as_str());
......@@ -380,12 +408,15 @@ impl CaesiumFunctionSpecBuilder {
function_name: name.to_string(),
coq_params: self.coq_params,
param: parameter,
decomposed_params: self.params,
elctx: self.elctx,
pre: self.pre,
args: self.args,
existential,
ret,
post: self.post,
has_spec: self.has_spec,
coq_context: self.coq_context,
}
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -20,11 +20,13 @@ lazy_static! {
//settings.set_default("check_overflows", true).unwrap();
//settings.set_default("check_panics", true).unwrap();
settings.set_default("log_dir", "./log/").unwrap();
settings.set_default("output_dir", "./output/").unwrap();
settings.set_default("dump_debug_info", false).unwrap();
settings.set_default("dump_borrowck_info", false).unwrap();
settings.set_default("quiet", false).unwrap();
settings.set_default("skip_unsupported_features", true).unwrap();
settings.set_default("spec_hotword", "rr").unwrap();
settings.set_default("attribute_parser", "verbose").unwrap();
// Get the list of all allowed flags.
let mut allowed_keys = get_keys(&settings);
......@@ -44,12 +46,11 @@ lazy_static! {
}
// 4. Override with env variables (`RR_QUIET`, ...)
/*
settings.merge(
Environment::with_prefix("RR").ignore_empty(true)
).unwrap();