Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
C
cpdt
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
research
cpdt
Commits
40f0d583
Commit
40f0d583
authored
Sep 03, 2008
by
Adam Chlipala
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Typed target denotation
parent
c3e0b03f
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
88 additions
and
1 deletion
+88
-1
StackMachine.v
src/StackMachine.v
+88
-1
No files found.
src/StackMachine.v
View file @
40f0d583
...
@@ -96,9 +96,17 @@ Fixpoint expDenote (e : exp) : nat :=
...
@@ -96,9 +96,17 @@ Fixpoint expDenote (e : exp) : nat :=
(
**
It
is
convenient
to
be
able
to
test
definitions
before
starting
to
prove
things
about
them
.
We
can
verify
that
our
semantics
is
sensible
by
evaluating
some
sample
uses
.
*
)
(
**
It
is
convenient
to
be
able
to
test
definitions
before
starting
to
prove
things
about
them
.
We
can
verify
that
our
semantics
is
sensible
by
evaluating
some
sample
uses
.
*
)
Eval
simpl
in
expDenote
(
Const
42
)
.
Eval
simpl
in
expDenote
(
Const
42
)
.
(
**
[[
=
42
:
nat
]]
*
)
Eval
simpl
in
expDenote
(
Binop
Plus
(
Const
2
)
(
Const
2
))
.
Eval
simpl
in
expDenote
(
Binop
Plus
(
Const
2
)
(
Const
2
))
.
(
**
[[
=
4
:
nat
]]
*
)
Eval
simpl
in
expDenote
(
Binop
Times
(
Binop
Plus
(
Const
2
)
(
Const
2
))
(
Const
7
))
.
Eval
simpl
in
expDenote
(
Binop
Times
(
Binop
Plus
(
Const
2
)
(
Const
2
))
(
Const
7
))
.
(
**
[[
=
28
:
nat
]]
*
)
(
**
**
Target
language
*
)
(
**
**
Target
language
*
)
...
@@ -154,14 +162,32 @@ Fixpoint compile (e : exp) : prog :=
...
@@ -154,14 +162,32 @@ Fixpoint compile (e : exp) : prog :=
(
**
Before
we
set
about
proving
that
this
compiler
is
correct
,
we
can
try
a
few
test
runs
,
using
our
sample
programs
from
earlier
.
*
)
(
**
Before
we
set
about
proving
that
this
compiler
is
correct
,
we
can
try
a
few
test
runs
,
using
our
sample
programs
from
earlier
.
*
)
Eval
simpl
in
compile
(
Const
42
)
.
Eval
simpl
in
compile
(
Const
42
)
.
(
**
[[
=
IConst
42
::
nil
:
prog
]]
*
)
Eval
simpl
in
compile
(
Binop
Plus
(
Const
2
)
(
Const
2
))
.
Eval
simpl
in
compile
(
Binop
Plus
(
Const
2
)
(
Const
2
))
.
(
**
[[
=
IConst
2
::
IConst
2
::
IBinop
Plus
::
nil
:
prog
]]
*
)
Eval
simpl
in
compile
(
Binop
Times
(
Binop
Plus
(
Const
2
)
(
Const
2
))
(
Const
7
))
.
Eval
simpl
in
compile
(
Binop
Times
(
Binop
Plus
(
Const
2
)
(
Const
2
))
(
Const
7
))
.
(
**
[[
=
IConst
7
::
IConst
2
::
IConst
2
::
IBinop
Plus
::
IBinop
Times
::
nil
:
prog
]]
*
)
(
**
We
can
also
run
our
compiled
programs
and
chedk
that
they
give
the
right
results
.
*
)
(
**
We
can
also
run
our
compiled
programs
and
chedk
that
they
give
the
right
results
.
*
)
Eval
simpl
in
progDenote
(
compile
(
Const
42
))
nil
.
Eval
simpl
in
progDenote
(
compile
(
Const
42
))
nil
.
(
**
[[
=
Some
(
42
::
nil
)
:
option
stack
]]
*
)
Eval
simpl
in
progDenote
(
compile
(
Binop
Plus
(
Const
2
)
(
Const
2
)))
nil
.
Eval
simpl
in
progDenote
(
compile
(
Binop
Plus
(
Const
2
)
(
Const
2
)))
nil
.
(
**
[[
=
Some
(
4
::
nil
)
:
option
stack
]]
*
)
Eval
simpl
in
progDenote
(
compile
(
Binop
Times
(
Binop
Plus
(
Const
2
)
(
Const
2
))
(
Const
7
)))
nil
.
Eval
simpl
in
progDenote
(
compile
(
Binop
Times
(
Binop
Plus
(
Const
2
)
(
Const
2
))
(
Const
7
)))
nil
.
(
**
[[
=
Some
(
28
::
nil
)
:
option
stack
]]
*
)
(
**
**
Translation
correctness
*
)
(
**
**
Translation
correctness
*
)
...
@@ -584,16 +610,41 @@ Fixpoint texpDenote t (e : texp t) {struct e} : typeDenote t :=
...
@@ -584,16 +610,41 @@ Fixpoint texpDenote t (e : texp t) {struct e} : typeDenote t :=
(
**
We
can
evaluate
a
few
example
programs
to
convince
ourselves
that
this
semantics
is
correct
.
*
)
(
**
We
can
evaluate
a
few
example
programs
to
convince
ourselves
that
this
semantics
is
correct
.
*
)
Eval
simpl
in
texpDenote
(
TNConst
42
)
.
Eval
simpl
in
texpDenote
(
TNConst
42
)
.
(
**
[[
=
42
:
typeDenote
Nat
]]
*
)
Eval
simpl
in
texpDenote
(
TBConst
true
)
.
Eval
simpl
in
texpDenote
(
TBConst
true
)
.
(
**
[[
=
true
:
typeDenote
Bool
]]
*
)
Eval
simpl
in
texpDenote
(
TBinop
TTimes
(
TBinop
TPlus
(
TNConst
2
)
(
TNConst
2
))
(
TNConst
7
))
.
Eval
simpl
in
texpDenote
(
TBinop
TTimes
(
TBinop
TPlus
(
TNConst
2
)
(
TNConst
2
))
(
TNConst
7
))
.
(
**
[[
=
28
:
typeDenote
Nat
]]
*
)
Eval
simpl
in
texpDenote
(
TBinop
(
TEq
Nat
)
(
TBinop
TPlus
(
TNConst
2
)
(
TNConst
2
))
(
TNConst
7
))
.
Eval
simpl
in
texpDenote
(
TBinop
(
TEq
Nat
)
(
TBinop
TPlus
(
TNConst
2
)
(
TNConst
2
))
(
TNConst
7
))
.
(
**
[[
=
false
:
typeDenote
Bool
]]
*
)
Eval
simpl
in
texpDenote
(
TBinop
TLt
(
TBinop
TPlus
(
TNConst
2
)
(
TNConst
2
))
(
TNConst
7
))
.
Eval
simpl
in
texpDenote
(
TBinop
TLt
(
TBinop
TPlus
(
TNConst
2
)
(
TNConst
2
))
(
TNConst
7
))
.
(
**
[[
=
true
:
typeDenote
Bool
]]
*
)
(
**
**
Target
language
*
)
(
**
**
Target
language
*
)
(
**
Now
we
want
to
define
a
suitable
stack
machine
target
for
compilation
.
In
the
example
of
the
untyped
language
,
stack
machine
programs
could
encounter
stack
underflows
and
"get stuck."
This
was
unfortunate
,
since
we
had
to
deal
with
this
complication
even
though
we
proved
that
our
compiler
never
produced
underflowing
programs
.
We
could
have
used
dependent
types
to
force
all
stack
machine
programs
to
be
underflow
-
free
.
For
our
new
languages
,
besides
underflow
,
we
also
have
the
problem
of
stack
slots
with
naturals
instead
of
bools
or
vice
versa
.
This
time
,
we
will
use
indexed
typed
families
to
avoid
the
need
to
reason
about
potential
failures
.
We
start
by
defining
stack
types
,
which
classify
sets
of
possible
stacks
.
*
)
Definition
tstack
:=
list
type
.
Definition
tstack
:=
list
type
.
(
**
Any
stack
classified
by
a
[
tstack
]
must
have
exactly
as
many
elements
,
and
each
stack
element
must
have
the
type
found
in
the
same
position
of
the
stack
type
.
We
can
define
instructions
in
terms
of
stack
types
,
where
every
instruction
'
s
type
tells
us
what
initial
stack
type
it
expects
and
what
final
stack
type
it
will
produce
.
*
)
Inductive
tinstr
:
tstack
->
tstack
->
Set
:=
Inductive
tinstr
:
tstack
->
tstack
->
Set
:=
|
TINConst
:
forall
s
,
nat
->
tinstr
s
(
Nat
::
s
)
|
TINConst
:
forall
s
,
nat
->
tinstr
s
(
Nat
::
s
)
|
TIBConst
:
forall
s
,
bool
->
tinstr
s
(
Bool
::
s
)
|
TIBConst
:
forall
s
,
bool
->
tinstr
s
(
Bool
::
s
)
...
@@ -601,6 +652,8 @@ Inductive tinstr : tstack -> tstack -> Set :=
...
@@ -601,6 +652,8 @@ Inductive tinstr : tstack -> tstack -> Set :=
tbinop
arg1
arg2
res
tbinop
arg1
arg2
res
->
tinstr
(
arg1
::
arg2
::
s
)
(
res
::
s
)
.
->
tinstr
(
arg1
::
arg2
::
s
)
(
res
::
s
)
.
(
**
Stack
machine
programs
must
be
a
similar
inductive
family
,
since
,
if
we
again
used
the
[
list
]
type
family
,
we
would
not
be
able
to
guarantee
that
intermediate
stack
types
match
within
a
program
.
*
)
Inductive
tprog
:
tstack
->
tstack
->
Set
:=
Inductive
tprog
:
tstack
->
tstack
->
Set
:=
|
TNil
:
forall
s
,
tprog
s
s
|
TNil
:
forall
s
,
tprog
s
s
|
TCons
:
forall
s1
s2
s3
,
|
TCons
:
forall
s1
s2
s3
,
...
@@ -608,12 +661,18 @@ Inductive tprog : tstack -> tstack -> Set :=
...
@@ -608,12 +661,18 @@ Inductive tprog : tstack -> tstack -> Set :=
->
tprog
s2
s3
->
tprog
s2
s3
->
tprog
s1
s3
.
->
tprog
s1
s3
.
(
**
Now
,
to
define
the
semantics
of
our
new
target
language
,
we
need
a
representation
for
stacks
at
runtime
.
We
will
again
take
advantage
of
type
information
to
define
types
of
value
stacks
that
,
by
construction
,
contain
the
right
number
and
types
of
elements
.
*
)
Fixpoint
vstack
(
ts
:
tstack
)
:
Set
:=
Fixpoint
vstack
(
ts
:
tstack
)
:
Set
:=
match
ts
with
match
ts
with
|
nil
=>
unit
|
nil
=>
unit
|
t
::
ts
'
=>
typeDenote
t
*
vstack
ts
'
|
t
::
ts
'
=>
typeDenote
t
*
vstack
ts
'
end
%
type
.
end
%
type
.
(
**
This
is
another
[
Set
]
-
valued
function
.
This
time
it
is
recursive
,
which
is
perfectly
valid
,
since
[
Set
]
is
not
treated
specially
in
determining
which
functions
may
be
written
.
We
say
that
the
value
stack
of
an
empty
stack
type
is
any
value
of
type
[
unit
]
,
which
has
just
a
single
value
,
[
tt
]
.
A
nonempty
stack
type
leads
to
a
value
stack
that
is
a
pair
,
whose
first
element
has
the
proper
type
and
whose
second
element
follows
the
representation
for
the
remainder
of
the
stack
type
.
This
idea
of
programming
with
types
can
take
a
while
to
internalize
,
but
it
enables
a
very
simple
definition
of
instruction
denotation
.
We
have
the
same
kind
of
type
annotations
for
the
dependent
[
match
]
,
but
everything
else
is
like
what
you
might
expect
from
a
Lisp
-
like
version
of
ML
that
ignored
type
information
.
Nonetheless
,
the
fact
that
[
tinstrDenote
]
passes
the
type
-
checker
guarantees
that
our
stack
machine
programs
can
never
go
wrong
.
*
)
Definition
tinstrDenote
ts
ts
'
(
i
:
tinstr
ts
ts
'
)
:
vstack
ts
->
vstack
ts
'
:=
Definition
tinstrDenote
ts
ts
'
(
i
:
tinstr
ts
ts
'
)
:
vstack
ts
->
vstack
ts
'
:=
match
i
in
(
tinstr
ts
ts
'
)
return
(
vstack
ts
->
vstack
ts
'
)
with
match
i
in
(
tinstr
ts
ts
'
)
return
(
vstack
ts
->
vstack
ts
'
)
with
|
TINConst
_
n
=>
fun
s
=>
(
n
,
s
)
|
TINConst
_
n
=>
fun
s
=>
(
n
,
s
)
...
@@ -624,6 +683,34 @@ Definition tinstrDenote ts ts' (i : tinstr ts ts') : vstack ts -> vstack ts' :=
...
@@ -624,6 +683,34 @@ Definition tinstrDenote ts ts' (i : tinstr ts ts') : vstack ts -> vstack ts' :=
end
end
end
.
end
.
(
**
Why
do
we
choose
to
use
an
anonymous
function
to
bind
the
initial
stack
in
every
case
of
the
[
match
]
?
Consider
this
well
-
intentioned
but
invalid
alternative
version
:
[[
Definition
tinstrDenote
ts
ts
'
(
i
:
tinstr
ts
ts
'
)
(
s
:
vstack
ts
)
:
vstack
ts
'
:=
match
i
in
(
tinstr
ts
ts
'
)
return
(
vstack
ts
'
)
with
|
TINConst
_
n
=>
(
n
,
s
)
|
TIBConst
_
b
=>
(
b
,
s
)
|
TIBinop
_
_
_
_
b
=>
match
s
with
(
arg1
,
(
arg2
,
s
'
))
=>
((
tbinopDenote
b
)
arg1
arg2
,
s
'
)
end
end
.
The
Coq
type
-
checker
complains
that
:
[[
The
term
"(n, s)"
has
type
"(nat * vstack ts)%type"
while
it
is
expected
to
have
type
"vstack (Nat :: t)"
]]
Recall
from
our
earlier
discussion
of
[
match
]
annotations
that
we
write
the
annotations
to
express
to
the
type
-
checker
the
relationship
between
the
type
indices
of
the
case
object
and
the
result
type
of
the
[
match
]
.
Coq
chooses
to
assign
to
the
wildcard
[
_
]
after
[
TINConst
]
the
name
[
t
]
,
and
the
type
error
is
telling
us
that
the
type
checker
cannot
prove
that
[
t
]
is
the
same
as
[
ts
]
.
By
moving
[
s
]
out
of
the
[
match
]
,
we
lose
the
ability
to
express
,
with
[
in
]
and
[
return
]
clauses
,
the
relationship
between
the
shared
index
[
ts
]
of
[
s
]
and
[
i
]
.
There
%
\
textit
{%
#
<
i
>
#
are
#
</
i
>
#
%}%
reasonably
general
ways
of
getting
around
this
problem
without
pushing
binders
inside
[
match
]
es
.
However
,
the
alternatives
are
significantly
more
involved
,
and
the
technique
we
use
here
is
almost
certainly
the
best
choice
,
whenever
it
applies
.
*
)
(
**
We
finish
the
semantics
with
a
straightforward
definition
of
program
denotation
.
*
)
Fixpoint
tprogDenote
ts
ts
'
(
p
:
tprog
ts
ts
'
)
{
struct
p
}
:
vstack
ts
->
vstack
ts
'
:=
Fixpoint
tprogDenote
ts
ts
'
(
p
:
tprog
ts
ts
'
)
{
struct
p
}
:
vstack
ts
->
vstack
ts
'
:=
match
p
in
(
tprog
ts
ts
'
)
return
(
vstack
ts
->
vstack
ts
'
)
with
match
p
in
(
tprog
ts
ts
'
)
return
(
vstack
ts
->
vstack
ts
'
)
with
|
TNil
_
=>
fun
s
=>
s
|
TNil
_
=>
fun
s
=>
s
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment