Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

some support for sequence slicing in vale #50

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
2 changes: 1 addition & 1 deletion run_scons.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

set -e

SCONS_PYTHON_MAJOR_MINOR=3.6
SCONS_PYTHON_MAJOR_MINOR=3

# Windows-only: print out the directory of the Python associated to SCons
windows_scons_python_dir () {
Expand Down
3 changes: 3 additions & 0 deletions tools/Vale/src/ast.fs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ type op =
| Bop of bop
| TupleOp of typ list option
| Subscript
| Slice
| SlicePrefix
| SliceSuffix
| Update
| Cond
| FieldOp of id
Expand Down
14 changes: 13 additions & 1 deletion tools/Vale/src/emit_common_lemmas.fs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type build_env =
proc:proc_decl;
loc:loc;
is_instruction:bool;
is_no_inline:bool;
is_quick:bool;
is_operand:bool;
is_framed:bool;
Expand Down Expand Up @@ -69,6 +70,11 @@ and build_code_stmts (env:env) (benv:build_env) (stmts:stmt list):exp =
List.fold cons empty (List.rev slist)
and build_code_block (env:env) (benv:build_env) (stmts:stmt list):exp =
vaApp "Block" [build_code_stmts env benv stmts]
and build_function (env:env) (benv:build_env) (stmts:stmt list):exp =
// printfn "this is where we emit va_Function";
match benv.proc.pname with
| Id(id) -> vaApp "Function" [EString id; build_code_stmts env benv stmts]
| _ -> internalErr "Function call unexpected ID"

(* Build codegen_success value for body of procedure Q *)
let rec build_codegen_success_stmt (q:id) (env:env) (s:stmt):exp option list =
Expand Down Expand Up @@ -255,7 +261,7 @@ let rec build_lemma_stmt (senv:stmt_env) (s:stmt):ghost * bool * stmt list =
let codeBody = vaApp "get_whileBody" [code] in
let i1 = string (gen_lemma_sym ()) in
let i2 = string (gen_lemma_sym ()) in
let (n1, s1, sw1, fw1) = (Reserved ("n" + i1), Reserved ("s" + i1), Reserved ("sW" + i1), Reserved ("fW" + i1)) in
let (n1, s1, sw1, fw1) = (Id "loop_ctr", Reserved ("s" + i1), Reserved ("sW" + i1), Reserved ("fW" + i1)) in
let (sw2, fw2) = (Reserved ("sW" + i2), Reserved ("fW" + i2)) in
let (codeCond, codeBody, sCodeVars) =
if !fstar then
Expand Down Expand Up @@ -458,6 +464,7 @@ let build_pre_code_via_transform (loc:loc) (env:env) (benv:build_env) (stmts:stm
{
fname = Reserved ("transform_" + string_of_id p.pname);
fghost = NotGhost;
// finline = benv.binline;
ftargs = [];
fargs = fParams;
fret_name = None;
Expand All @@ -482,6 +489,7 @@ function method{:opaque} va_code_Q(iii:int, dummy:va_operand_reg, dummy2:va_oper
let build_code (loc:loc) (env:env) (benv:build_env) (stmts:stmt list):(loc * decl) list =
let p = benv.proc in
let isTransform = List_mem_assoc (Id "transform") p.pattrs in
let isNoInline = benv.is_no_inline in
let precode = if isTransform then build_pre_code_via_transform loc env benv stmts else [] in
if p.pghost = Ghost then [] else
let fParams = make_fun_params p.prets p.pargs in
Expand All @@ -498,6 +506,7 @@ let build_code (loc:loc) (env:env) (benv:build_env) (stmts:stmt list):(loc * dec
fbody =
if benv.is_instruction then Some (attrs_get_exp (Id "instruction") p.pattrs)
else if isTransform then Some (eapply (Reserved "get_result") [vaApp ("transform_" + string_of_id p.pname) (List.map EVar fParams)])
else if isNoInline then Some(build_function env benv stmts)
else Some (build_code_block env benv stmts);
fattrs =
if benv.is_quick then
Expand Down Expand Up @@ -753,6 +762,8 @@ let rec build_proc (envBody:env) (env:env) (loc:loc) (p:proc_decl):decls =
else []
in
let isInstruction = List_mem_assoc (Id "instruction") p.pattrs in
let isNoInline = List_mem_assoc (Id "noInline") p.pattrs in
// printfn "setting no inline: %b" isNoInline;
let isOperand = List_mem_assoc (Id "operand") p.pattrs in
let codeName prefix = Reserved ("code_" + prefix + (string_of_id p.pname)) in
let isQuick = is_quick_body p.pattrs in
Expand Down Expand Up @@ -786,6 +797,7 @@ let rec build_proc (envBody:env) (env:env) (loc:loc) (p:proc_decl):decls =
proc = p;
loc = loc;
is_instruction = isInstruction;
is_no_inline = isNoInline;
is_quick = isQuick;
is_operand = isOperand;
is_framed = attrs_get_bool (Id "frame") (p.pghost = NotGhost) p.pattrs;
Expand Down
7 changes: 6 additions & 1 deletion tools/Vale/src/emit_dafny_text.fs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ let rec string_of_exp_prec prec e =
| EApply (e, _, es, _) when is_id e && id_of_exp e = (Id "set") -> ("{" + (String.concat ", " (List.map (r 5) es)) + "}", 90)
| EOp (Subscript, [e1; e2], _) -> ((r 90 e1) + "[" + (r 90 e2) + "]", 90)
| EOp (Update, [e1; e2; e3], _) -> ((r 90 e1) + "[" + (r 90 e2) + " := " + (r 90 e3) + "]", 90)

| EOp (Slice, [e1; e2; e3], _) -> ((r 90 e1) + "[" + (r 90 e2) + " .. " + (r 90 e3) + "]", 90)
| EOp (SlicePrefix, [e1; e2; e3], _) -> ((r 90 e1) + "[" + " .. " + (r 90 e2) + "]", 90)
| EOp (SliceSuffix, [e1; e2; e3], _) -> ((r 90 e1) + "[" + (r 90 e2) + " .. " + "]", 90)

| EOp (Cond, [e1; e2; e3], _) -> ("if " + (r 90 e1) + " then " + (r 90 e2) + " else " + (r 90 e3), 0)
| EOp (FieldOp x, [e], _) -> ((r 90 e) + "." + (sid x), 90)
| EOp (FieldUpdate x, [e1; e2], _) -> ((r 90 e1) + ".(" + (sid x) + " := " + (r 90 e2) + ")", 90)
Expand Down Expand Up @@ -149,7 +154,7 @@ let rec emit_stmt (ps:print_state) (s:stmt):unit =
ps.PrintLine ("ghost var " + (String.concat ", " (List.map string_of_lhs_formal lhss)) + " := " + (string_of_exp e) + ";")
| SAssign _ -> emit_stmts ps (eliminate_assign_lhss s)
| SLetUpdates _ -> internalErr "SLetUpdates"
| SBlock ss -> notImplemented "block"
| SBlock ss -> emit_block ps ss
| SIfElse (_, e, ss1, []) ->
ps.PrintLine ("if (" + (string_of_exp e) + ")");
emit_block ps ss1
Expand Down
5 changes: 5 additions & 0 deletions tools/Vale/src/emit_vale_text.fs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,11 @@ let rec string_of_exp_prec (prec:int) (e:exp):string =
| EOp (Bop _, ([] | [_] | (_::_::_::_)), _) -> internalErr "binary operator"
| EOp (Subscript, [e1; e2], _) -> ((r 90 e1) + "[" + (r 90 e2) + "]", 90)
| EOp (Update, [e1; e2; e3], _) -> ((r 90 e1) + "[" + (r 90 e2) + " := " + (r 90 e3) + "]", 90)

| EOp (Slice, [e1; e2; e3], _) -> ((r 90 e1) + "[" + (r 90 e2) + " .. " + (r 90 e3) + "]", 90)
| EOp (SlicePrefix, [e1; e2], _) -> ((r 90 e1) + "[" + " .. " + (r 90 e2) + "]", 90)
| EOp (SliceSuffix, [e1; e2], _) -> ((r 90 e1) + "[" + (r 90 e2) + " .. " + "]", 90)

| EOp (Cond, [e1; e2; e3], _) -> ("if " + (r 90 e1) + " then " + (r 90 e2) + " else " + (r 90 e3), 0)
| EOp (FieldOp x, [e], _) -> ((r 90 e) + "." + (sid x), 90)
| EOp (FieldUpdate x, [e1; e2], _) -> ((r 90 e1) + ".(" + (sid x) + " := " + (r 90 e2) + ")", 90)
Expand Down
3 changes: 3 additions & 0 deletions tools/Vale/src/lex.fsl
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ let operatorToken (tok:string) (isCustom:bool) (s:string):(loc -> token) option
| "=" -> Some (fun loc -> EQ (loc, (isCustom, s)))
| "|" -> Some (fun loc -> BAR (loc, (isCustom, s)))
| ":=" -> Some (fun loc -> COLONEQ (loc, (isCustom, s)))

| ".." -> Some (fun loc -> DOTDOT (loc, (isCustom, s)))

| "@=" -> Some (fun loc -> ATEQ (loc, (isCustom, s)))
| "<=" -> Some (fun loc -> LE (loc, (isCustom, s)))
| ">=" -> Some (fun loc -> GE (loc, (isCustom, s)))
Expand Down
9 changes: 9 additions & 0 deletions tools/Vale/src/parse.fsy
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ let storageAttrs (a:attrs):(var_storage * attrs) =
%token <loc * (bool * string)> PLUS MINUS STAR SLASH PERCENT
%token <loc * (bool * string)> AMPAMP BARBAR LTEQEQ EQEQGT LTEQEQGT
%token <loc * (bool * string)> ATEQ COLONEQ
%token <loc * (bool * string)> DOTDOT
%token <loc> HAVOC OLD THIS
%token <loc> IS THEN ELSE LET IN OUT INOUT REVEAL GHOST INLINE
%token <loc> TTYPE TYPE OPERAND_TYPE VAR CONST READONLY FUNCTION AXIOM EXTERN PROCEDURE STATIC MODULE IMPORT OPERATOR
Expand Down Expand Up @@ -171,6 +172,11 @@ Exp1
| Exp1 QLBRACKET Exp RBRACKET { expAt $2 (EOp (Bop BIn, [$3; $1], None)) }
| Exp1 LBRACKET Exp RBRACKET { expAt $2 (EOp (Subscript, [$1; $3], None)) }
| Exp1 LBRACKET Exp COLONEQ Exp RBRACKET { expAt $2 (EOp (Update, [$1; $3; $5], None)) }

| Exp1 LBRACKET Exp DOTDOT Exp RBRACKET { expAt $2 (EOp (Slice, [$1; $3; $5], None)) }
| Exp1 LBRACKET DOTDOT Exp RBRACKET { expAt $2 (EOp (SlicePrefix, [$1; $4], None)) }
| Exp1 LBRACKET Exp DOTDOT RBRACKET { expAt $2 (EOp (SliceSuffix, [$1; $3], None)) }

| Exp1 DOT AnyId { expAt $2 (EOp (FieldOp $3, [$1], None)) }
| Exp1 DOT AnyId LPAREN Exps RPAREN { expAt $4 (EApply (EVar (exp2id $1 $3, None), None, $5, None)) }
| Exp1 DOT LPAREN AnyId COLONEQ Exp RPAREN { expAt $2 (EOp (FieldUpdate $4, [$1; $6], None)) }
Expand Down Expand Up @@ -233,6 +239,9 @@ OpToken
| LTEQEQGT { $1 }
| LBRACKET RBRACKET { ($1, (false, "[]")) }
| LBRACKET COLONEQ RBRACKET { ($1, (false, "[:=]")) }

| LBRACKET DOTDOT RBRACKET { ($1, (false, "[..]")) }

| QLBRACKET RBRACKET { ($1, (false, "?[]")) }
| DOT ID { ($1, (false, "." + snd $2 )) }
| DOT ID COLONEQ { ($1, (false, "." + snd $2 + ":=")) }
Expand Down
47 changes: 47 additions & 0 deletions tools/Vale/src/typechecker.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1461,6 +1461,48 @@ and infer_exp (env:env) (u:unifier) (e:exp) (expected_typ:typ option):(typ * aex
| (AE_ApplyX (_, _, _, es), _, _) -> ret t (AE_Op (Update, es))
| _ -> internalErr ("EOp Update")
)
| EOp (Slice, [e1; e2; e3], _) ->
(
let (t1, ae1) = infer_exp_force env u e1 expected_typ in
let x =
match t1 with
| TName (Id x) | TApply (Id x, _) -> x
| _ -> err (sprintf "cannot find overloaded operator([..]) function for collection of type %s" (string_of_typ t1))
in
let e = eapply (Operator (x + "[..]")) [e1; e2; e3] in
let (t, ae) = infer_exp env u e expected_typ in
match ae with
| (AE_ApplyX (_, _, _, es), _, _) -> ret t (AE_Op (Slice, es))
| _ -> internalErr ("EOp Slice")
)
| EOp (SlicePrefix, [e1; e2], _) ->
(
let (t1, ae1) = infer_exp_force env u e1 expected_typ in
let x =
match t1 with
| TName (Id x) | TApply (Id x, _) -> x
| _ -> err (sprintf "cannot find overloaded operator([..]) function for collection of type %s" (string_of_typ t1))
in
let e = eapply (Operator (x + "[..]")) [e1; e2; e2] in // repeated e2, probably not the best workaround
let (t, ae) = infer_exp env u e expected_typ in
match ae with
| (AE_ApplyX (_, _, _, es), _, _) -> ret t (AE_Op (SlicePrefix, es))
| _ -> internalErr ("EOp SlicePrefix")
)
| EOp (SliceSuffix, [e1; e2], _) ->
(
let (t1, ae1) = infer_exp_force env u e1 expected_typ in
let x =
match t1 with
| TName (Id x) | TApply (Id x, _) -> x
| _ -> err (sprintf "cannot find overloaded operator([..]) function for collection of type %s" (string_of_typ t1))
in
let e = eapply (Operator (x + "[..]")) [e1; e2; e2] in // repeated e2,probably not the best workaround
let (t, ae) = infer_exp env u e expected_typ in
match ae with
| (AE_ApplyX (_, _, _, es), _, _) -> ret t (AE_Op (SliceSuffix, es))
| _ -> internalErr ("EOp SliceSuffix")
)
| EOp (Bop BIn, [e1; e2], _) ->
(
let (t2, ae2) = infer_exp_force env u e2 expected_typ in
Expand Down Expand Up @@ -1931,6 +1973,7 @@ let rec tc_stmt (env:env) (s:stmt):stmt =
SIfElse (g, e, b1, b2)
| SWhile (e, invs, ed, b) ->
let (t, e) = tc_exp env e (Some tBool) in
let env = push_id env (Id "loop_ctr") (TInt (NegInf, Inf)) in
let invs = List_mapSnd (fun e -> let (_, e) = tc_exp env e (Some tProp) in e) invs in
let ed = mapSnd (List.map (fun e -> let (_, e) = tc_exp env e None in e)) ed in
let (_, b) = tc_stmts env b in
Expand Down Expand Up @@ -2101,6 +2144,10 @@ let tc_decl (env:env) (decl:((loc * decl) * bool)):(env * ((loc * decl) * bool)
| (Operator "[]", _) -> err "operator([]) expects two arguments (the first argument must be a named type)"
| (Operator "[:=]", [(_, Some (TName (Id x) | (TApply (Id x, _)))); _; _]) -> Operator (x + "[:=]")
| (Operator "[:=]", _) -> err "operator([:=]) expects three arguments (the first argument must be a named type)"

| (Operator "[..]", [(_, Some (TName (Id x) | (TApply (Id x, _)))); _; _]) -> Operator (x + "[..]")
| (Operator "[..]", _) -> err "operator([..]) expects three arguments (the first argument must be a named type)"

| (Operator "?[]", [(_, Some (TName (Id x) | (TApply (Id x, _)))); _]) -> Operator (x + "?[]")
| (Operator "?[]", _) -> err "operator(?[]) expects two arguments (the first argument must be a named type)"
| (Operator xf, [(_, Some (TName (Id xt) | (TApply (Id xt, _)))); _])
Expand Down