summaryrefslogtreecommitdiff
path: root/src/initial_check.ml
AgeCommit message (Collapse)Author
2018-11-07Move inline forall in function definitionsAlasdair Armstrong
* Previously we allowed the following bizarre syntax for a forall quantifier on a function: val foo(arg1: int('n), arg2: typ2) -> forall 'n, 'n >= 0. unit this commit changes this to the more sane: val foo forall 'n, 'n >= 2. (arg1: int('n), arg2: typ2) -> unit Having talked about it today, we could consider adding the syntax val foo where 'n >= 2. (arg1: int('n), arg2: typ2) -> unit which would avoid the forall (by implicitly quantifying variables in the constraint), and be slightly more friendly especially for documentation purposes. Only RISC-V used this syntax, so all uses of it there have been switched to the new style. * Second, there is a new (somewhat experimental) syntax for existentials, that is hopefully more readable and closer to minisail: val foo(x: int, y: int) -> int('m) with 'm >= 2 "type('n) with constraint" is equivalent to minisail: {'n: type | constraint} the type variables in typ are implicitly quantified, so this is equivalent to {'n, constraint. typ('n)} In order to make this syntax non-ambiguous we have to use == in constraints rather than =, but this is a good thing anyway because the previous situation where = was type level equality and == term level equality was confusing. Now all the type type-level and term-level operators can be consistent. However, to avoid breaking anything = is still allowed in non-with constraints, and produces a deprecated warning when parsed.
2018-10-31Rename Reporting_basic to ReportingAlasdair Armstrong
There is no Reporting_complex, so it's not clear what the basic is intended to signify anyway. Add a GitHub issue link to any err_unreachable errors (as they are all bugs)
2018-10-24Add constraint synonymsAlasdair Armstrong
Currently not enabled by default, the flag -Xconstraint_synonyms enables them For generating constraints in ASL parser, we want to be able to give names to the constraints that we attach to certain variables. It's slightly awkward right now when constraints get long complicated because the entire constraint always has to be typed out in full whenever it appears, and there's no way to abstract away from that. This adds constraint synonyms, which work much like type synonyms except for constraints, e.g. constraint Size('n) = 'n in {1, 2, 4, 8} | 128 <= 'n <= 256 these constraints can then be used instead of the full constraint, e.g. val f : forall 'n, where Size('n). int('n) -> unit Unfortunatly we need to have a keyword to 'call' the constraint synonym otherwise the grammer stops being LR(1). This could be resolved by parsing all constraints into Parse_ast.atyp and then de-sugaring them into constraints, which is what happens for n-expressions already, but that would require quite a bit of work on the parser. To avoid this forcing changes to any other parts of Sail, the intended invariant is that all constraints appearing anywhere in a type-checked AST have no constraint synonyms, so they don't have to worry about matching on NC_app, or calling Env.expand_typquant_synonyms (which isn't even exported for this reason).
2018-10-11Change the function type in the ASTAlasdair
Changes the representation of function types in the ast from Typ_fn : typ -> typ to Typ_fn : typ list -> typ to more accurately represent their use in the various backends, where we often compile functions to either their curried representations as in Lem and Isabelle, or just multiple argument functions in C. There's still some oddity because a single pattern in a function clause can bind against multiple arguments, and maybe we want to forbid this in the future. The syntax also hasn't changed (yet), so in theory this change shouldn't break anything (but it invariably will...). In the future we would ideally require that a function with N arguments has exactly N patterns in its declaration, one for each argument so f : (x, y) -> z f _ = ... would be disallowed (as _ matches both x and y), forcing f(_, _) = z this would simply quite a few things, Also we could have a different syntax for function argument lists and tuples, because it's rather hard to define a function that actually takes a tuple with the syntax how it is now. Some issues I noticed when doing this refactoring: Line 1926 of Coq translation. untuple_args_pat is maybe no longer needed? However there's still some funnyness where a pattern can be used to bind multiple function arguments so maybe it still is. Line 2306 of monomorphisation. I simplified the logic here. I think it's equivalent now, but I could be wrong. Line 4517 of rewrites. I'm not sure what make_cstr_mappings is doing here, but hopefully the simpler version is the same.
2018-08-31mappings: Support for unidirectional mapping clausesJon French
2018-08-28add __POS__ argument to Err_unreachable for better error reportingJon French
2018-08-16Remove unused ref typeAlasdair Armstrong
2018-08-16Various cleanups to ott grammarAlasdair Armstrong
Add additional well-formedness check when calling typing rules
2018-07-26Patterns: add or and not patternsAlastair Reid
These match the new ASL pattern constructors: - !p matches if the pattern p does not match - { p1, ... pn } matches if any of the patterns p1 ... pn match We desugar the set pattern "{p1, ... pn}" into "p1 | (p2 | ... pn)". ASL does not have pattern binding but Sail does. The rules at the moment are that none of the pattern can contain patterns. This could be relaxed by allowing "p1 | p2" to bind variables provided p1 and p2 both bind the same variables.
2018-06-28Deduplicate arguments for different constructors in undefined fnsBrian Campbell
Makes the generated undefined functions smaller, easier to read, and avoids excessive memory usage in Coq (e.g., for large AST types).
2018-06-26Add configuration registers so __SetConfig ASL can be translatedAlasdair Armstrong
Registers can now be marked as configuration registers, for example: register configuration CFG_RVBAR = 0x1300000 They work like ordinary registers except they can only be set by functions with the 'configuration' effect and have no effect when read. They also have an initialiser, like a let-binding. Internally there is a new reg_dec constructor DEC_config. They are intended to represent configuration parameters for the model, which can change between runs, but don't change during execution. Currently they'll only work when compiled to C. Internally registers can now have custom effects for reads and writes rather than just rreg and wreg, so the type signatures of Env.add_register and Env.get_register have changed, as well as the Register lvar, so in the type checker we now write: Env.add_register id read_effect write_effect typ rather than Env.add_register id typ For the corresponding change to ASL parser there's a function is_config in asl_to_sail.ml which controls what becomes a configuration register for ARM. Some things we have to keep as let-bindings because Sail can't handle them changing at runtime - e.g. the length of vectors in other top-level definitions. Luckily __SetConfig doesn't (yet) try to change those options. Together these changes allow us to translate the ASL __SetConfig function, which means we should get command-line option compatibility with ArchEx for running the ARM conformance tests.
2018-06-11add 'pat as id' mapping-patternsJon French
2018-06-11Merge branch 'sail2' into mappingsJon French
(involved some manual tinkering with gitignore, type_check, riscv)
2018-06-04Fix an issue with riscv_platform involving flow typingAlasdair Armstrong
- Refactor the flow typing implementation in the type-checker. This should fix an issue involving riscv_platform. Specifically it should now work better when an if statement contains multiple conditions combined with and/or, only some of which imply constraints at the type level. This change also simplifies the implementation of flow typing, and removes some obscure features that were hardly used - specifically, flow typing could modify types, but this was fairly obscure and doesn't seem to affect any of our specifications. More testing is needed to ensure that this change hasn't inadvertantly broken anything, but it does pass all our tests and continue to typecheck arm, riscv and cheri. - Also adds a option for generating faster undefined functions for enum and variant types. Previously I tried to optimise away such functions in the C backend, because they could be slow and cause considerable uneccessary allocation, however this was error prone and it turns out a much simpler solution is to simply make the functions themselves much faster, at the cost of hard-coding certain decisions about what undefined means for these types at compile tile (which is fine for fast emulation). This almost doubles the performance of the generated C code. - Add a wrapper for right shift to avoid UB when shifting by 64 or more places.
2018-05-16Add support for inline val-spec declaration for mappingsJon French
This means that a mapping which formerly had to be pre-declared like val name : a <-> b ... mapping name { x <-> y, ... } can now be shortened to mapping name : a <-> b { x <-> y, ... }
2018-05-10Merge branch 'sail2' into mappingsJon French
2018-05-03Flow typing and l-expression changes for ASL parserAlasdair Armstrong
1. Experiment with allowing some flow typing on mutable variables for translating ASL in a more idiomatic way. I realise after updating some of the test cases that this could have some problematic side effects for lem translation, where mutable variables are translated into monadic code. We'd need to ensure that whatever flow typing happens for mutable variables also works for monadic code, including within transformed loops. If this doesn't work out some of these changes may need to be reverted. 2. Make the type inference for l-expressions a bit smarter. Splits the type checking rules for l-expressions into a inference part and a checking part like the other bi-directional rules. Should not be able to type check slightly more l-expresions, such as nested vector slices that may not have checked previously. The l-expression rules for vector patterns should be simpler now, but they are also more strict about bounds checking. Previously the bounds checks were derived from the corresponding operations that would appear on the RHS (i.e. LEXP_vector would get it's check from vector_access). This meant that the l-expression bounds checks could be weakend by weakening the checks on those operations. Now this is no longer possible, there is a -no_lexp_bounds_check option which turns of bounds checking in l-expressions. Currently this is on for the generated ARM spec, but this should only be temporary. 3. Add a LEXP_vector_concat which mirrors P_vector_concat except in l-expressions. Previously there was a hack that overloaded LEXP_tup for this to translate some ASL patterns, but that was fairly ugly. Adapt the rewriter and other parts of the code to handle this. The rewriter for lexp tuple vector assignments is now a rewriter for vector concat assignments. 4. Include a newly generated version of aarch64_no_vector 5. Update the Ocaml test suite to use builtins in lib/
2018-05-02scattered mappingsJon French
2018-05-02re-indent to_ast_defJon French
2018-05-02refactor string append pattern ast to be based on lists rather than pairsJon French
2018-05-01add type annotation patterns to mpatsJon French
2018-05-01further progressJon French
2018-05-01conversion from parse_ast to astJon French
2018-05-01re-indent Initial_check.to_ast_typJon French
2018-05-01start of string pattern matching: currently only literalsJon French
2018-04-19Fix bug with function being applied to tuplesAlasdair Armstrong
For some reason there was a desugaring rule that mapped f((x, y)) to f(x, y) in initial_check.ml, this prevented functions and constructors from being applied to tuples.
2018-04-18Rename BK_nat to BK_int to be consistent with source syntaxAlasdair Armstrong
2018-04-18Updates to latex mode for documentationAlasdair Armstrong
2018-04-10Porting some minisail changes to sail2 branchAlasdair Armstrong
This commit primarily changes how existential types are bound in letbindings. Essentially, the constraints on both numeric and existentially quantified types are lifted into the surrounding type context automatically, so in ``` val f : nat -> nat let x = f(3) ``` whereas x would have had type nat by default before, it'll now have type atom('n) with a constraint that 'n >= 0 (where 'n is some fresh type variable). This has several advantages: x can be passed to functions expecting an atom argument, such as a vector indexing operation without any clunky cast functions - ex_int, ex_nat, and ex_range are no longer required. The let 'x = something() syntax is also less needed, and is now only really required when we specifically want a name to refer to x's type. This changes slightly the nature of the type pattern syntax---whereas previously it was used to cause an existential to be destructured, it now just provides names for an automatically destructured binding. Usually however, this just works the same. Also: - Fixed an issue where the rewrite_split_fun_constr_pats rewriting pass didn't add type paramemters for newly added type variables in generated function parameters. - Updated string_of_ functions in ast_util to reflect syntax changes - Fixed a C compilation issue where elements of union type constructors were not being coerced between big integers and 64-bit integers where appropriate - Type annotations in patterns now generalise, rather than restrict the type of the pattern. This should be safer and easier to handle in the various backends. I don't think any code we had was relying on this behaviour anyway. - Add inequality operator to lib/flow.sail - Fix an issue whereby top-level let bindings with annotations were checked incorrectly
2018-04-06Fix some error msg typos.Prashanth Mundkur
2018-04-06Update sail.tex for wip latex outputAlasdair Armstrong
Fix a bug in initial check which caused X() = y to expect an additional parameter. Some tweaks to sail2 emacs mode
2018-03-14WIP Latex formattingAlasdair Armstrong
Added option -latex that outputs input to a latex document. Added doc comments that can be attached to certain AST nodes - right now just valspecs and function clauses, e.g. /*! Documentation for main */ val main : unit -> unit These comments are kept by the sail pretty printer, and used when generating latex
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-02-06Add aux constructor to type patterns for consistencyAlasdair Armstrong
2018-02-06Improve destructuring existential typesAlasdair Armstrong
Make destructuring existentials less arcane by allowing them to be destructured via type patterns (typ_pat in ast.ml). This allows the following code for example: val mk_square : unit -> {'n 'm, 'n = 'm. vector('n, dec, vector('m, dec, bit))} function test (() : unit) -> unit = { let matrix as vector('width, _, 'height) = mk_square (); _prove(constraint('width = 'height)); () } where 'width we become 'n from mk_square, and 'height becomes 'm. The old syntax let vector as 'length = ... or even let 'vector = ... still works under this new scheme in a uniform way, so this is backwards compatible The way this works is when a kind identifier in a type pattern is bound against a type, e.g. 'height being bound against vector('m, dec, bit) in the example, then we get a constraint that 'height is equal to the first and only n-expression in the type, in this case 'm. If the type has two or more n-expressions (or zero) then this is a type error.
2018-02-05Add typ patterns for destructuring existentialsAlasdair Armstrong
2018-01-30Generate functions from enums to numbers and vice versaAlasdair Armstrong
For an enumeration type T, we can create a function T_of_num and num_of_T which convert from the enum to and from a numeric type. The numeric type is range(0, n) where n is the number of constructors in the enum minus one. This makes sure the conversion is type safe, but maybe this is too much of a hassle. It would be possible to automatically overload all these functions into generic to_enum and from_enum as in Haskell's Enum typeclass, but we don't do this yet. Currently these functions affect a few lem test cases, but I think that is only because they are tested without any prelude functions and pattern rewrites require a few functions to be defined What is really broken is if one tries to generate these functions like enum x = A | B | C function f A = 0 function f B = 1 function f C = 2 the rewriter really doesn't like function clauses like this, and it seems really hard to fix properly (I tried and gave up), this is a shame as the generation code is much more succinct with definitions like above
2018-01-25Add simple conditional processing and file includeAlasdair Armstrong
Can now use C-style include declarations to include files within other sail files. This is done in such a way that all the location information is preserved in error messages. As an example: $include "aarch64/prelude.sail" $define SYM $ifndef SYM $include <../util.sail> $endif would include the file aarch64/prelude.sail relative to the file where the include is contained. It then defines a symbol SYM and includes another file if it is not defined. The <../util.sail> include will be accessed relative to $SAIL_DIR/lib, so $SAIL_DIR/lib/../util.sail in this case. This can be used with the standard C trick of $ifndef ONCE $define ONCE val f : unit -> unit $endif so no matter how many sail files include the above file, the valspec for f will only appear once. Currently we just have $include, $define, $ifdef and $ifndef (with $else and $endif). We're using $ rather than # because # is already used in internal identifiers, although this could be switched.
2018-01-16Created version of typecheck test suite for sail2 branchAlasdair Armstrong
Currently doesn't try to compile to lem or use the MIPS spec All the failing tests have been removed because I intend to handle them differently - they were very fragile before because there was no indication of why they failed, so as sail evolved they tended to start failing for the wrong reasons and not testing what they were supposed to.
2018-01-12OCaml interactive mode can now run full aarch64 examples, and ocaml test cases.Alasdair Armstrong
2018-01-11Ocaml semantics can now run aarch64 hello world example using octapodAlasdair Armstrong
New testcase for bitfield syntax Updated to work with latest lem and linksem
2018-01-05Moved parser, lexer and pretty printer to correct locations.Alasdair Armstrong
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-04Additional tests for ocaml backendAlasdair Armstrong
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-14An experimental version of sail without bitvector start indexes.Alasdair Armstrong
Works with the vector branch of asl_parser
2017-12-13Cleanup code by fixing compiler warnings, and fix ocaml compilationAlasdair Armstrong
Add the ast.sed script we need to build sail. Currently we just need this to fix up the locations in the AST but it will be removed once we can share locations between ocaml and lem.
2017-12-13Use big_nums from LemAlasdair Armstrong