Skip to content

Commit 55e7e4e

Browse files
Support inheritance (#459)
### Changes - Change naming scheme so the name `$heap` is always used as the heap to read/assign to in the body. For read-only procedures, `$heap` is the input parameter as well as the one to read. For read/write procedures, `$heap` is the out parameter and `$heap_in` the input one. - Add a `Map.const` function to the Core factory - Add datatypes to Laurel, to support a more incremental translation to Core - During translation, introduce a `Field` datatype that has a constructor for each user defined field. - During translation, introduce a `UserType` datatype that has a constructor for each user defined type. - Support composites that have fields with the same name but different types - Move the handling of `new` from HeapParameterization to a new pass `TypeHierarchy`, that also handles `<value> as <Type>` and `<value> is <Type>`. ### Testing - Add a test `sameFieldNameDifferentType` to the mutable fields test file - Added a test file related to inheritance
1 parent 044a90b commit 55e7e4e

17 files changed

+911
-211
lines changed

Strata/Languages/Core/Factory.lean

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,21 @@ def reNoneFunc : WFLFunc CoreLParams :=
220220
def polyOldFunc : WFLFunc CoreLParams :=
221221
polyUneval "old" ["a"] [("x", mty[%a])] mty[%a]
222222

223+
/- A constant `Map` constructor with type `∀k, v. v → Map k v`.
224+
`Map.const(d)` returns a map where every key maps to the value `d`. -/
225+
def mapConstFunc : WFLFunc CoreLParams :=
226+
polyUneval "Map.const" ["k", "v"]
227+
[("d", mty[%v])]
228+
(mapTy mty[%k] mty[%v])
229+
(axioms := [
230+
ToCoreIdent esM[∀ (%v): -- %1 d
231+
(∀ (%k): -- %0 kk
232+
{(((~select : (Map %k %v) → %k → %v)
233+
((~Map.const : %v → (Map %k %v)) %1)) %0)}
234+
(((~select : (Map %k %v) → %k → %v)
235+
((~Map.const : %v → (Map %k %v)) %1)) %0) == %1)]
236+
])
237+
223238
/- A `Map` selection function with type `∀k, v. Map k v → k → v`. -/
224239
def mapSelectFunc : WFLFunc CoreLParams :=
225240
polyUneval "select" ["k", "v"]
@@ -359,6 +374,7 @@ def WFFactory : Lambda.WFLFactory CoreLParams :=
359374

360375
polyOldFunc,
361376

377+
mapConstFunc,
362378
mapSelectFunc,
363379
mapUpdateFunc,
364380

@@ -464,6 +480,7 @@ def reInterOp : Expression.Expr := reInterFunc.opExpr
464480
def reCompOp : Expression.Expr := reCompFunc.opExpr
465481
def reNoneOp : Expression.Expr := reNoneFunc.opExpr
466482
def polyOldOp : Expression.Expr := polyOldFunc.opExpr
483+
def mapConstOp : Expression.Expr := mapConstFunc.opExpr
467484
def mapSelectOp : Expression.Expr := mapSelectFunc.opExpr
468485
def mapUpdateOp : Expression.Expr := mapUpdateFunc.opExpr
469486

Strata/Languages/Laurel/CorePrelude.lean

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,15 @@ def corePreludeDDM :=
2828
#strata
2929
program Core;
3030

31-
// Abstract types for the heap model
31+
// Field and TypeTag are declared as an opaque type for DDM resolution to pass; the Laurel translator
32+
// replaces them with datatypes that contain one constructor for each field and composite type
3233
type Field;
33-
type Composite := int;
34+
type TypeTag;
35+
36+
// Composite is a datatype with a reference (int) and a runtime type tag
37+
datatype Composite () {
38+
MkComposite(ref: int, typeTag: TypeTag)
39+
};
3440

3541
// Tagged union for field values
3642
datatype Box () {

Strata/Languages/Laurel/Grammar/ConcreteToAbstractTreeTranslator.lean

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,14 @@ partial def translateStmtExpr (arg : Arg) : TransM StmtExprMd := do
206206
| q`Laurel.new, #[nameArg] =>
207207
let name ← translateIdent nameArg
208208
return mkStmtExprMd (.New name) md
209+
| q`Laurel.isType, #[targetArg, typeNameArg] =>
210+
let target ← translateStmtExpr targetArg
211+
let typeName ← translateIdent typeNameArg
212+
return mkStmtExprMd (.IsType target (mkHighTypeMd (.UserDefined typeName) md)) md
213+
| q`Laurel.asType, #[targetArg, typeNameArg] =>
214+
let target ← translateStmtExpr targetArg
215+
let typeName ← translateIdent typeNameArg
216+
return mkStmtExprMd (.AsType target (mkHighTypeMd (.UserDefined typeName) md)) md
209217
| q`Laurel.call, #[arg0, argsSeq] =>
210218
let callee ← translateStmtExpr arg0
211219
let calleeName := match callee.val with
@@ -230,7 +238,8 @@ partial def translateStmtExpr (arg : Arg) : TransM StmtExprMd := do
230238
| q`Laurel.fieldAccess, #[objArg, fieldArg] =>
231239
let obj ← translateStmtExpr objArg
232240
let field ← translateIdent fieldArg
233-
return mkStmtExprMd (.FieldSelect obj field) md
241+
let fieldMd ← getArgMetaData fieldArg
242+
return mkStmtExprMd (.FieldSelect obj field) fieldMd
234243
| q`Laurel.while, #[condArg, invSeqArg, bodyArg] =>
235244
let cond ← translateStmtExpr condArg
236245
let invariants ← match invSeqArg with
@@ -400,12 +409,21 @@ def parseComposite (arg : Arg) : TransM TypeDefinition := do
400409
let .op op := arg
401410
| TransM.error s!"parseComposite expects operation"
402411
match op.name, op.args with
403-
| q`Laurel.composite, #[nameArg, fieldsArg] =>
412+
| q`Laurel.composite, #[nameArg, extendsArg, fieldsArg] =>
404413
let name ← translateIdent nameArg
414+
let extending ← match extendsArg with
415+
| .option _ (some (.op extendsOp)) => match extendsOp.name, extendsOp.args with
416+
| q`Laurel.optionalExtends, #[parentsArg] =>
417+
match parentsArg with
418+
| .seq _ .comma args => args.toList.mapM translateIdent
419+
| singleArg => do let parent ← translateIdent singleArg; pure [parent]
420+
| _, _ => TransM.error s!"Expected optionalExtends operation, got {repr extendsOp.name}"
421+
| .option _ none => pure []
422+
| _ => TransM.error s!"Expected optionalExtends, got {repr extendsArg}"
405423
let fields ← match fieldsArg with
406424
| .seq _ _ args => args.toList.mapM parseField
407425
| _ => pure []
408-
return .Composite { name := name, extending := [], fields := fields, instanceProcedures := [] }
426+
return .Composite { name := name, extending := extending, fields := fields, instanceProcedures := [] }
409427
| _, _ =>
410428
TransM.error s!"parseComposite expects composite, got {repr op.name}"
411429

Strata/Languages/Laurel/Grammar/LaurelGrammar.st

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,16 @@ category Field;
9494
op mutableField (name: Ident, fieldType: LaurelType): Field => "var " name ":" fieldType;
9595
op immutableField (name: Ident, fieldType: LaurelType): Field => name ":" fieldType;
9696

97+
// Type checking and casting
98+
op isType (target: StmtExpr, typeName: Ident): StmtExpr => @[prec(40)] target " is " typeName;
99+
op asType (target: StmtExpr, typeName: Ident): StmtExpr => @[prec(40)] target " as " typeName;
100+
101+
// Composite types with optional extends
102+
category OptionalExtends;
103+
op optionalExtends(parents: CommaSepBy Ident): OptionalExtends => "extends " parents;
104+
97105
category Composite;
98-
op composite (name: Ident, fields: Seq Field): Composite => "composite " name "{" fields "}";
106+
op composite (name: Ident, extending: Option OptionalExtends, fields: Seq Field): Composite => "composite " name extending "{" fields "}";
99107

100108
// Procedures
101109
category OptionalReturnType;

0 commit comments

Comments
 (0)