Skip to content

Commit ef28fcc

Browse files
authored
Merge branch 'main' into progTypes
2 parents 67cd53a + f170cc8 commit ef28fcc

19 files changed

Lines changed: 249 additions & 121 deletions

NEWS.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,19 @@ ethos 0.1.2 prerelease
55

66
- Change the execution semantics when a program takes an unevalated term as an argument. In particular, we do not call user provided programs and oracles when at least argument could not be evaluated. This change was made to make errors more intuitive. Note this changes the semantics of programs that previously relied on being called on unevaluated terms.
77
- User programs, user oracles, and builtin operators that are unapplied are now considered unevaluated. This makes the type checker more strict and disallows passing them as arguments to other programs, which previously led to undefined behavior.
8+
- Changes the interface of `declare-parameterized-const`. In particular, the parameters of a parameterized constants are no longer assumed to be implicit, and are explicit by default. The `:implicit` attribute can be used on all parameters to recover the previous behavior. Other attributes such as `:opaque` and `:requires` can be used on parameters to this command.
9+
- Remove support for the explicit parameter annotation `eo::_`, which was used to provide annotations for implicit arguments to parameterized constants.
10+
- Changed the semantics of pairwise and chainable operators for a single argument, which now reduces to the neutral element of the combining operator instead of a parse error.
11+
- The operator `eo::typeof` now fails to evaluate if the type of the given term is not ground.
12+
813
- Adds support for the SMT-LIB `as` annotations for ambiguous datatype constructors, i.e. those whose return type cannot be inferred from its argument types. Following SMT-LIB convention, ambiguous datatype constructors are expected to be annotated with their *return* type using `as`, which internally is treated as a type argument to the constructor.
914
- The semantics for `eo::dt_constructors` is extended for instantiated parametric datatypes. For example calling `eo::dt_constructors` on `(List Int)` returns the list containing `cons` and `(as nil (List Int))`.
1015
- The semantics for `eo::dt_selectors` is extended for annotated constructors. For example calling `eo::dt_selectors` on `(as nil (List Int))` returns the empty list.
11-
- Changed the semantics of pairwise and chainable operators for a single argument, which now reduces to the neutral element of the combining operator instead of a parse error.
16+
1217
- Added the option `--stats-all` to track the number of times side conditions are invoked.
1318
- The option `--print-let` has been renamed to `--print-dag` and is now enabled by default. The printer is changed to use `eo::define` instead of `let`.
1419
- Ethos now explicitly forbids `:var`, `:implicit`, and `:opaque` on return types.
15-
- The operator `eo::typeof` now fails to evaluate if the type of the given term is not ground.
20+
- The option `--binder-fresh`, which specified for fresh variables to be constructed when parsing binders, has been removed.
1621

1722
ethos 0.1.1
1823
===========

src/cmd_parser.cpp

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -137,19 +137,21 @@ bool CmdParser::parseNextCommand()
137137
case Token::DECLARE_PARAMETERIZED_CONST:
138138
case Token::DECLARE_ORACLE_FUN:
139139
{
140-
//d_state.checkThatLogicIsSet();
141140
std::string name = d_eparser.parseSymbol();
142141
//d_state.checkUserSymbol(name);
143142
std::vector<Expr> sorts;
143+
// the parameters, if declare-parameterized-const
144144
std::vector<Expr> params;
145+
// attributes marked on variables
146+
std::map<ExprValue*, AttrMap> pattrMap;
145147
if (tok == Token::DECLARE_FUN || tok == Token::DECLARE_ORACLE_FUN)
146148
{
147149
sorts = d_eparser.parseTypeList();
148150
}
149151
else if (tok == Token::DECLARE_PARAMETERIZED_CONST)
150152
{
151153
d_state.pushScope();
152-
params = d_eparser.parseAndBindSortedVarList();
154+
params = d_eparser.parseAndBindSortedVarList(Kind::CONST, pattrMap);
153155
}
154156
Expr ret = d_eparser.parseType();
155157
Attr ck = Attr::NONE;
@@ -171,7 +173,7 @@ bool CmdParser::parseNextCommand()
171173
AttrMap attrs;
172174
d_eparser.parseAttributeList(Kind::CONST, t, attrs);
173175
// determine if an attribute specified a constructor kind
174-
d_eparser.processAttributeMap(attrs, ck, cons, params);
176+
d_eparser.processAttributeMap(attrs, ck, cons);
175177
}
176178
// declare-fun does not parse attribute list, as it is only in smt2
177179
t = ret;
@@ -189,6 +191,44 @@ bool CmdParser::parseNextCommand()
189191
opaqueArgs.push_back(t[0][0]);
190192
t = t[1];
191193
}
194+
// process the parameter list
195+
if (!params.empty())
196+
{
197+
// explicit parameters are quote arrows
198+
std::map<ExprValue*, AttrMap>::iterator itp;
199+
AttrMap::iterator itpa;
200+
for (size_t i = 0, nparams = params.size(); i < nparams; i++)
201+
{
202+
size_t ii = nparams - i - 1;
203+
Expr qt = d_state.mkQuoteType(params[ii]);
204+
itp = pattrMap.find(params[ii].getValue());
205+
if (itp != pattrMap.end())
206+
{
207+
itpa = itp->second.find(Attr::REQUIRES);
208+
if (itpa != itp->second.end())
209+
{
210+
// requires adds to return type
211+
t = d_state.mkRequires(itpa->second, t);
212+
itp->second.erase(itpa);
213+
}
214+
itpa = itp->second.find(Attr::OPAQUE);
215+
if (itpa != itp->second.end())
216+
{
217+
// if marked opaque, it is an opaque argument
218+
opaqueArgs.insert(opaqueArgs.begin(), qt);
219+
itp->second.erase(itpa);
220+
continue;
221+
}
222+
}
223+
if (!opaqueArgs.empty())
224+
{
225+
d_lex.parseError("Opaque arguments must be a prefix of arguments.");
226+
}
227+
t = d_state.mkFunctionType({qt}, t);
228+
}
229+
}
230+
// now process remainder of map
231+
d_eparser.processAttributeMaps(pattrMap);
192232
if (!opaqueArgs.empty())
193233
{
194234
if (ck!=Attr::NONE)
@@ -329,7 +369,7 @@ bool CmdParser::parseNextCommand()
329369
}
330370
}
331371
std::vector<Expr> vs =
332-
d_eparser.parseAndBindSortedVarList();
372+
d_eparser.parseAndBindSortedVarList(Kind::PROOF_RULE);
333373
Expr assume;
334374
Expr plCons;
335375
std::vector<Expr> premises;
@@ -489,9 +529,11 @@ bool CmdParser::parseNextCommand()
489529
std::string name = d_eparser.parseSymbol();
490530
//d_state.checkUserSymbol(name);
491531
std::vector<Expr> impls;
532+
std::vector<Expr> opaques;
533+
std::map<ExprValue*, AttrMap> pattrMap;
492534
std::vector<Expr> vars =
493-
d_eparser.parseAndBindSortedVarList(impls);
494-
if (!impls.empty())
535+
d_eparser.parseAndBindSortedVarList(Kind::LAMBDA, pattrMap);
536+
if (vars.size() < pattrMap.size())
495537
{
496538
// If there were implicit variables, we go back and refine what is
497539
// bound in the body to only include the explicit arguments. This
@@ -507,6 +549,8 @@ bool CmdParser::parseNextCommand()
507549
d_state.bind(e.getSymbol(), e);
508550
}
509551
}
552+
// now process remainder of map
553+
d_eparser.processAttributeMaps(pattrMap);
510554
Expr ret;
511555
if (tok == Token::DEFINE_FUN)
512556
{
@@ -683,7 +727,8 @@ bool CmdParser::parseNextCommand()
683727
}
684728
// push the scope
685729
d_state.pushScope();
686-
std::vector<Expr> vars = d_eparser.parseAndBindSortedVarList();
730+
std::vector<Expr> vars =
731+
d_eparser.parseAndBindSortedVarList(Kind::PROGRAM);
687732
std::vector<Expr> argTypes = d_eparser.parseTypeList();
688733
Expr retType = d_eparser.parseType();
689734
Expr progType = retType;

src/expr.cpp

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -236,8 +236,7 @@ std::string quoteSymbol(const std::string& s)
236236
std::map<const ExprValue*, size_t> Expr::computeLetBinding(
237237
const Expr& e, std::vector<Expr>& ll)
238238
{
239-
size_t idc = 0;
240-
std::map<const ExprValue*, size_t> lbind;
239+
std::map<const ExprValue*, size_t> lcount;
241240
std::unordered_set<const ExprValue*> visited;
242241
std::vector<Expr> visit;
243242
std::vector<Expr> llv;
@@ -246,35 +245,41 @@ std::map<const ExprValue*, size_t> Expr::computeLetBinding(
246245
do
247246
{
248247
cur = visit.back();
249-
visit.pop_back();
250248
if (cur.getNumChildren() == 0)
251249
{
250+
visit.pop_back();
252251
continue;
253252
}
254253
const ExprValue* cv = cur.getValue();
255254
if (visited.find(cv) == visited.end())
256255
{
257256
visited.insert(cv);
258-
llv.push_back(cur);
259257
for (size_t i = 0, nchildren = cur.getNumChildren(); i < nchildren; i++)
260258
{
261259
visit.push_back(cur[i]);
262260
}
263261
continue;
264262
}
265-
if (lbind.find(cv) == lbind.end())
263+
visit.pop_back();
264+
// add to vector, which is done after all subterms of cv are added to llv
265+
if (lcount.find(cv) == lcount.end())
266266
{
267-
lbind[cv] = idc;
268-
idc++;
267+
llv.push_back(cur);
269268
}
269+
lcount[cv]++;
270270
}while(!visit.empty());
271+
// go back and only keep the ones that were found more than once.
272+
std::map<const ExprValue*, size_t> lbind;
273+
size_t idc = 0;
271274
for (size_t i=0, lsize = llv.size(); i<lsize; i++)
272275
{
273-
const Expr& l = llv[lsize - 1 - i];
276+
const Expr& l = llv[i];
274277
const ExprValue* lv = l.getValue();
275-
if (lbind.find(lv) != lbind.end())
278+
if (lcount[lv] > 1)
276279
{
277280
ll.push_back(l);
281+
lbind[lv] = idc;
282+
idc++;
278283
}
279284
}
280285
return lbind;

src/expr.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,9 @@ class Expr
118118
explicit Expr(const ExprValue* ev);
119119
Expr(const Expr& e);
120120
~Expr();
121-
/** Get the free symbols */
121+
/** Get the free parameters in expression e */
122122
static std::vector<Expr> getVariables(const Expr& e);
123-
/** Get the free symbols in vector es */
123+
/** Get the free parameters in vector es */
124124
static std::vector<Expr> getVariables(const std::vector<Expr>& es);
125125
/** Get the free symbols */
126126
static bool hasVariable(const Expr& e,

0 commit comments

Comments
 (0)