summaryrefslogtreecommitdiff
path: root/language
AgeCommit message (Collapse)Author
2018-04-05Cleanup repository by removing old and generated filesAlasdair Armstrong
Rename l2.ott to sail.ott
2018-03-23Fix build issueAlasdair Armstrong
2018-03-19Fixes to C backend for RISCV-compilationAlasdair Armstrong
Can now compile RISCV. Requires some library tweaks before it'll pass any tests, Also adds hyperlinks to wip latex output
2018-03-14Make partiality more explicit in library functions of Lem shallow embeddingThomas Bauereiss
Some functions are partial, e.g. converting a bitvector to an integer, which might fail for the bit list representation due to undefined bits. Undefined cases can be handled in different ways: - call Lem's failwith, which maps to undefined/ARB in Isabelle and HOL (the default so far), - return an option type, - raise a failure in the monad, or - use a bitstream oracle to resolve undefined bits. This patch adds different versions of partial functions corresponding to those options. The desired behaviour can be selected by choosing a binding in the Sail prelude. The naming scheme is that the failwith version is the default, while the other versions have the suffixes _maybe, _fail, and _oracle, respectively.
2018-03-09Specialise constructors for polymorphic unionsAlasdair Armstrong
Also work on making C backend compile RISC-V
2018-03-07Make union types consistent in the ASTAlasdair Armstrong
Previously union types could have no-argument constructors, for example the option type was previously: union option ('a : Type) = { Some : 'a, None } Now every union constructor must have a type, so option becomes: union option ('a : Type) = { Some : 'a, None : unit } The reason for this is because previously these two different types of constructors where very different in the AST, constructors with arguments were used the E_app AST node, and no-argument constructors used the E_id node. This was particularly awkward, because it meant that E_id nodes could have polymorphic types, i.e. every E_id node that was also a union constructor had to be annotated with a type quantifier, in constrast with all other identifiers that have unquantified types. This became an issue when monomorphising types, because the machinery for figuring out function instantiations can't be applied to identifier nodes. The same story occurs in patterns, where previously unions were split across P_id and P_app nodes - now the P_app node alone is used solely for unions. This is a breaking change because it changes the syntax for union constructors - where as previously option was matched as: function is_none opt = match opt { Some(_) => false, None => true } it is now matched as function is_none opt = match opt { Some(_) => false, None() => true } note that constructor() is syntactic sugar for constructor(()), i.e. a one argument constructor with unit as it's value. This is exactly the same as for functions where a unit-function can be called as f() and not as f(()). (This commit also makes exit() work consistently in the same way) An attempt to pattern match a variable with the same name as a union-constructor now gives an error as a way to guard against mistakes made because of this change. There is probably an argument for supporting the old syntax via some syntactic sugar, as it is slightly prettier that way, but for now I have chosen to keep the implementation as simple as possible. The RISCV spec, ARM spec, and tests have been updated to account for this change. Furthermore the option type can now be included from $SAIL_DIR/lib/ using $include <option.sail>
2018-03-02Use sail_lib.lem values in C backendAlasdair Armstrong
Rather than just using strings to represent literals, now use value types from sail_lib.lem to represent them. This allows for expressions to be evaluated at compile time, which will be useful for future optimisations involving constant folding and propagation, and allows the intermediate bytecode to be interpreted using the same lem builtins that the shallow embedding uses. To get this to work I had to tweak the build process slightly to allow ml files to import lem files from gen_lib/. Hopefully this doesn't break anything!
2018-02-26Add some obvious optimisations to C backend.Alasdair Armstrong
With these optimisations on, now get about 10x performance over OCaml.
2018-02-21Have aarch64/no_vector compiling to CAlasdair Armstrong
Just need to implement builtins, fix-up a few re-write passes, and integrate some kind of elf-loading and it should work.
2018-02-17Merge master branch into sail2 for OCaml 4.06 compatibilityThomas Bauereiss
2018-02-15List support in C backendAlasdair Armstrong
2018-02-13Support for large bitvector literals in C backendAlasdair Armstrong
2018-02-12Add support for top-level letbindings to C backendAlasdair Armstrong
2018-02-09Improve IR pretty-printing for debuggingAlasdair Armstrong
2018-02-09Formalize C backend intermediate representation in OttAlasdair Armstrong
Describes precisely the intermediate representation used in the C backend in an ott grammar, and also removes several C-isms where raw C code was inserted into the IR, so in theory this IR could be interpreted by a small VM/interpreter or compiled to LLVM bytecode etc. Currently the I_raw constructor for inserting C code is just used for inserting GCC attributes, so it can safely be ignored. Also augment and refactor the instruction type with an aux constructor so location information can be propagated down to this level.
2018-02-06Add aux constructor to type patterns for consistencyAlasdair Armstrong
2018-02-05Add typ patterns for destructuring existentialsAlasdair Armstrong
2018-01-31changed directory structure after migration to githubShaked Flur
2018-01-05Added bitfield syntax to replicate register bits typeAlasdair Armstrong
For example: bitfield cr : vector(8, dec, bit) = { CR0 : 7 .. 4, LT : 7, CR1 : 3 .. 2, CR2 : 1, CR3 : 0, } The difference this creates a newtype wrapper around the vector type, then generates getters and setters for all the fields once, rather than having to handle this construct separately in every backend.
2018-01-03Lots of experimental changes on this branchAlasdair Armstrong
* Changed comment syntax to C-style /* */ and // * References to registers and mutable variables are never created implicitly - a reference to a register or variable R is now created via the expression "ref R". References are assigned like "(*Y) = X", with "(*ref R) = X" being equivalent to "R = X". Everything is always explicit now, which simplifies the logic in the typechecker. There's also now an invariant that every id directly in a LEXP is mutable, which is actually required for our rewriter steps to be sound. * More flexible syntax for L-expressions to better support wierd power-idioms, some syntax sugar means that: X.GET(a, b, c) ==> _mod_GET(X, a, b, c) X->GET(a, b, c) ==> _mod_GET(ref X, a, b, c) for setters, this can be combined with the (still somewhat poorly named) LEXP_memory construct, such that: X->SET(a, b, c) = Y ==> _mod_SET(ref X, a, b, c, Y) Currently I use the _mod_ prefix for these 'modifier' functions, but we could omit that a la rust. * The register bits typedef construct no longer exists in the typechecker. This construct never worked consistently between backends and inc/dec vectors, and it can be easily replaced by structs with fancy setters/getters if need be. One can also use custom type operators to mimic the syntax, i.e. type operator ... ('n : Int) ('m : Int) = slice('n, 'm) struct cr = { CR0 : 32 ... 35, /* 32 : LT; 33 : GT; 34 : EQ; 35 : SO; */ CR1 : 36 ... 39, /* 36 : FX; 37 : FEX; 38 : VX; 39 : OX; */ CR2 : 40 ... 43, CR3 : 44 ... 47, CR4 : 48 ... 51, CR5 : 52 ... 55, CR6 : 56 ... 59, CR7 : 60 ... 63, } This greatly simplifies a lot of the logic in the typechecker, as it means that E_field is no longer ambiguously overloaded between records and register bit typedefs. This also makes writing semantics for these constructs much simpler.
2018-01-03Updates to interpreterAlasdair Armstrong
Experimenting with porting riscv model to new typechecker
2018-01-02Experimenting with power specAlasdair Armstrong
2017-12-13Use big_nums from LemAlasdair Armstrong
2017-12-11Prototype interactive mode for sail.Alasdair Armstrong
Requires linenoise library (opam install linenoise) for readline support. Use 'make isail' to build sail with interactive support. Plain 'make sail' should work as before with no additional dependencies. Use 'sail -i <commands>' to run sail interactively, e.g. sail -new_parser -i test/ocaml/prelude.sail test/ocaml/trycatch/tc.sail then try some commands for typechecking and evaluation sail> :t main sail> main () Doesn't use the lem interpreter right now, instead has a small operational semantics in src/interpreter.ml, but this is not very complete and will be changed/removed.
2017-12-07Resolve function clause guard parsing ambiguity by requiring parenthesesBrian Campbell
2017-12-06Add top-level pattern match guards internallyBrian Campbell
Also fix bug in mono analysis with generated variables Breaks lots of typechecking tests because it generates unnecessary equality tests on units (and the tests don't have generic equality), which I'll fix next.
2017-11-24Use unbound precision big_ints throughout sail.Alasdair Armstrong
Alastair's test cases revealed that using regular ints causes issues throughout sail, where all kinds of things can internally overflow in edge cases. This either causes crashes (e.g. int_of_string fails for big ints) or bizarre inexplicable behaviour. This patch switches the sail AST to use big_int rather than int, and updates everything accordingly. This touches everything and there may be bugs where I mistranslated things, and also n = m will still typecheck with big_ints but fail at runtime (ocaml seems to have decided that static typing is unnecessary for equality...), as it needs to be changed to eq_big_int. I also got rid of the old unused ocaml backend while I was updating things, so as to not have to fix it.
2017-11-24Attempt to document intermediate language used by Sail in ott.Alasdair Armstrong
2017-11-17Fix interpreter to work with new typecheckerAlasdair Armstrong
Need to map sail type annotations to interpreter type annotations in lem_ast ouput. This doesn't seem too hard.
2017-11-16Made l2.ott generate an ast.lem which is is valid w.r.t. -lem_ast output.Alasdair Armstrong
This is the first step towards getting the interpreter working on this branch
2017-11-16Remove unused Typ_wild constructorAlasdair Armstrong
2017-11-15Allow user defined operations in nexps (experimental)Alasdair Armstrong
There are several key changes here: 1) This commit allows for user defined operations in n-expressions using the Nexp_app constructor. These operations are linked to operators in the SMT solver, by using the smt extern when defining operations. Notably, this allows integer division and modular arithmetic to be used in types. This is best demonstrated with an example: infixl 7 / infixl 7 % val operator / = { smt: "div", ocaml: "quotient" } : forall 'n 'm, 'm != 0. (atom('n), atom('m)) -> {'o, 'o = 'n / 'm. atom('o)} val mod_atom = { smt: "mod", ocaml: "modulus" } : forall 'n 'm. (atom('n), atom('m)) -> {'o, 'o = mod_atom('n, 'm). atom('o)} val "print_int" : (string, int) -> unit overload operator % = mod_atom val main : unit -> unit function main () = { let 'm : {'x, 'x % 3 = 1. atom('x)} = 4; let 'n = m / 3; _prove(constraint(('m - 1) % 3 = 0)); _prove(constraint('n * 3 + 1 = 'm)); (* let x = 3 / 0; (* Will fail *) *) print_int("n = ", n); () } As can be seen, these nexp ops can be arbitrary user defined operators and even operator overloading works (although there are some caveats). This feature is very experimental, and some things won't work very well once you use custom operators - notably unification. However, this not necissarily a downside, because if restrict yourself to the subset of sail types that correspond to liquid types, then there is never a need to unify n-expressions. Looking further ahead, if we switch to a liquid type system a la minisail, then we no longer need to treat + - and * specially in n-expressions. So possible future refactorings could involve collapsing the Nexp datatype. 2) The typechecker is stricter about valspecs (and other types) being well-formed. This is a breaking change because previously we allowed things like: val f : atom('n) -> atom('n) and now this must be val f : forall 'n. atom('n) -> atom('n) if we want to allow the first syntax, then initial-check should desugar it this way - but it must be well-formed by the time it hits the type-checker, otherwise it's not clear that we do the right thing. Note we can actually have top-level type variables by using top-level let bindings with P_var. There's a future line of refactoring that would make it so that type variables can shadow each other properly (we should do this) - currently they all have to have unique names. 3) atom('n) is no longer syntactic sugar for range('n, 'n). The reason why we want to do this is that if we wanted to be smart about what sail operations can be translated into SMT operations at the type level we care very much that they talk about atoms and not ranges. Why? Because atom is the term level representation of a specific type variable so it's clear how to map between term level functions and type level functions, i.e. (atom('n) -> atom('n)) can be reflected at the type level by a type level function with kind Int -> Int, but the same is not true for range. Furthermore, both are interdefinable as atom('n) -> range('n, 'n) range('n, 'm) -> {'o, 'n <= 'o <= 'm. atom('n)} and I think the second is actually slightly more elegant. This change *should* be backwards compatible, as the type-checker knows how to convert from atom to ranges and unify them with each other, but there may be bugs introduced here...
2017-11-08Allow functions to be selectively declared external only for some backendsThomas Bauereiss
For example, val test = { ocaml: "test_ocaml" } : unit -> unit will only be external for OCaml. For other backends, it will have to be defined.
2017-11-08Allow for different extern names for different backendsAlasdair Armstrong
For example: val test = { ocaml: "test_ocaml", lem: "test_lem" } : unit -> unit val main : unit -> unit function main () = { test (); } for a backend not explicitly provided, the extern name would be simply "test" in this case, i.e. the string version of the id. Also fixed some bugs in the ocaml backend.
2017-10-25Allow mutually recursive functionsThomas Bauereiss
2017-10-25Generate ast.ml from ott file and update makefile.Alasdair Armstrong
Fix until loop not being counted as sugar
2017-10-25ast.ml generated from l2.ott compiles with rest of ./srcMark Wassell
2017-10-23Aligning Ott generated AST with actual ast.ml. Almost a drop-in replacement ↵Mark Wassell
but problem with aux introduced 'a type variables
2017-10-17Start of alignment of Ott definition with new implementation of type checker ↵Mark Wassell
and syntax changes
2017-10-04Alasdair, Peter: towards new Sail ottPeter Sewell
2017-07-24move value type definitions to ott, and introduce new E_internal_value ast ↵Jon French
node for passing around encapsulated evaluated values; change Interp.to_exp to now just wrap values in this node
2017-07-21remove -merge true from ott makefile -- lem at least doesn't build with itJon French
2017-07-21l2.ott: port across additions to base_effect from rmemJon French
2017-07-21l2.ott: factor ocaml 'l' type reference into ott definition of 'l'Jon French
2017-07-21l2.ott, l2_parse.ott: remove unnecessary 'type text = string'Jon French
2017-04-06typesetting tt vs non-ttPeter Sewell
2017-04-06fix typesetting of standalone grammar documentPeter Sewell
2017-03-15rename "manual.tex" to "type_system.tex"Peter Sewell
fix Makefile clean
2017-02-25wibPeter Sewell
2017-02-13wibPeter Sewell