Skip to content

Commit 427bdc6

Browse files
committed
Import B3 language definitions and pretty printing rules
1 parent e86fa03 commit 427bdc6

4 files changed

Lines changed: 938 additions & 0 deletions

File tree

Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
/-
2+
Copyright Strata Contributors
3+
4+
SPDX-License-Identifier: Apache-2.0 OR MIT
5+
-/
6+
7+
import Strata.DL.Lambda.Lambda
8+
import Strata.Languages.B3.Identifiers
9+
10+
namespace B3
11+
open Std (ToFormat Format format)
12+
13+
/--
14+
Type parameters for B3 Expression.
15+
-/
16+
structure ExprParams : Type 1 where
17+
Metadata : Type
18+
IDMeta : Type
19+
20+
abbrev ExprParams.Identifier (P : ExprParams) : Type := Lambda.Identifier P.IDMeta
21+
22+
/--
23+
B3 Binary operators
24+
-/
25+
inductive BinaryOp where
26+
| iff -- "<==>"
27+
| implies -- "==>"
28+
| impliedBy -- "<=="
29+
| and -- "&&"
30+
| or -- "||"
31+
| eq -- "=="
32+
| neq -- "!="
33+
| lt -- "<"
34+
| le -- "<="
35+
| ge -- ">="
36+
| gt -- ">"
37+
| add -- "+"
38+
| sub -- "-"
39+
| mul -- "*"
40+
| div -- "div"
41+
| mod -- "mod"
42+
deriving Repr, DecidableEq
43+
44+
def BinaryOp.toString : BinaryOp → String
45+
| .iff => "<==>"
46+
| .implies => "==>"
47+
| .impliedBy => "<=="
48+
| .and => "&&"
49+
| .or => "||"
50+
| .eq => "=="
51+
| .neq => "!="
52+
| .lt => "<"
53+
| .le => "<="
54+
| .ge => ">="
55+
| .gt => ">"
56+
| .add => "+"
57+
| .sub => "-"
58+
| .mul => "*"
59+
| .div => "div"
60+
| .mod => "mod"
61+
62+
/-- Precedence levels for binary operators (higher = tighter binding) -/
63+
def BinaryOp.precedence : BinaryOp → Nat
64+
| .iff => 1
65+
| .implies => 2
66+
| .impliedBy => 2
67+
| .or => 3
68+
| .and => 4
69+
| .eq => 5
70+
| .neq => 5
71+
| .lt => 5
72+
| .le => 5
73+
| .ge => 5
74+
| .gt => 5
75+
| .add => 6
76+
| .sub => 6
77+
| .mul => 7
78+
| .div => 7
79+
| .mod => 7
80+
81+
instance : ToString BinaryOp where
82+
toString := BinaryOp.toString
83+
84+
instance : ToFormat BinaryOp where
85+
format op := op.toString
86+
87+
/--
88+
B3 Unary operators
89+
-/
90+
inductive UnaryOp where
91+
| not -- "!"
92+
| neg -- "-"
93+
deriving Repr, DecidableEq
94+
95+
def UnaryOp.toString : UnaryOp → String
96+
| .not => "!"
97+
| .neg => "-"
98+
99+
instance : ToString UnaryOp where
100+
toString := UnaryOp.toString
101+
102+
instance : ToFormat UnaryOp where
103+
format op := op.toString
104+
105+
/--
106+
B3 Quantifier kind
107+
-/
108+
inductive QuantifierKind where
109+
| forall
110+
| exists
111+
deriving Repr, DecidableEq
112+
113+
def QuantifierKind.toString : QuantifierKind → String
114+
| .forall => "forall"
115+
| .exists => "exists"
116+
117+
instance : ToString QuantifierKind where
118+
toString := QuantifierKind.toString
119+
120+
instance : ToFormat QuantifierKind where
121+
format q := q.toString
122+
123+
-- B3 Expression and Pattern - mutually inductive types.
124+
mutual
125+
126+
/--
127+
B3 Expression type - a proper tree structure parameterized by ExprParams.
128+
-/
129+
inductive Expression (P : ExprParams) : Type where
130+
| literal (md : P.Metadata) (val : Lambda.LConst)
131+
| id (md : P.Metadata) (name : P.Identifier)
132+
| ite (md : P.Metadata) (cond : Expression P) (thenExpr : Expression P) (elseExpr : Expression P)
133+
| binaryOp (md : P.Metadata) (op : BinaryOp) (lhs : Expression P) (rhs : Expression P)
134+
| unaryOp (md : P.Metadata) (op : UnaryOp) (arg : Expression P)
135+
| functionCall (md : P.Metadata) (fn : P.Identifier) (args : List (Expression P))
136+
| labeledExpr (md : P.Metadata) (label : String) (expr : Expression P)
137+
| letExpr (md : P.Metadata) (var : P.Identifier) (value : Expression P) (body : Expression P)
138+
| quantifierExpr (md : P.Metadata) (quantifier : QuantifierKind) (var : P.Identifier) (ty : String) (patterns : List (Pattern P)) (body : Expression P)
139+
140+
/--
141+
B3 Pattern for quantifier triggers.
142+
-/
143+
inductive Pattern (P : ExprParams) : Type where
144+
| pattern (md : P.Metadata) (exprs : List (Expression P))
145+
146+
end
147+
148+
mutual
149+
def Pattern.sizeOf : Pattern P → Nat
150+
| .pattern _ exprs => 1 + Expression.sizeOfList exprs
151+
152+
def Expression.sizeOf : Expression P → Nat
153+
| .literal _ _ => 1
154+
| .id _ _ => 1
155+
| .ite _ cond thenE elseE => 1 + cond.sizeOf + thenE.sizeOf + elseE.sizeOf
156+
| .binaryOp _ _ lhs rhs => 1 + lhs.sizeOf + rhs.sizeOf
157+
| .unaryOp _ _ arg => 1 + arg.sizeOf
158+
| .functionCall _ _ args => 1 + Expression.sizeOfList args
159+
| .labeledExpr _ _ e => 1 + e.sizeOf
160+
| .letExpr _ _ value body => 1 + value.sizeOf + body.sizeOf
161+
| .quantifierExpr _ _ _ _ patterns body => 1 + Pattern.sizeOfList patterns + body.sizeOf
162+
163+
def Expression.sizeOfList : List (Expression P) → Nat
164+
| [] => 0
165+
| e :: es => e.sizeOf + Expression.sizeOfList es
166+
167+
def Pattern.sizeOfList : List (Pattern P) → Nat
168+
| [] => 0
169+
| p :: ps => p.sizeOf + Pattern.sizeOfList ps
170+
171+
end
172+
173+
instance : SizeOf (Expression P) where
174+
sizeOf := Expression.sizeOf
175+
176+
instance : SizeOf (Pattern P) where
177+
sizeOf := Pattern.sizeOf
178+
179+
mutual
180+
/-- Format with optional parentheses based on parent precedence -/
181+
partial def Expression.formatWithPrec [ToFormat P.Metadata] [ToFormat P.Identifier] (parentPrec : Nat) : Expression P → Format
182+
| .literal _ val => f!"{val}"
183+
| .id _ name => ToFormat.format name
184+
| .ite _ cond thenE elseE => f!"if {Format.nest 2 (cond.formatWithPrec 0)} then {Format.nest 2 (thenE.formatWithPrec 0)} else {Format.nest 2 (elseE.formatWithPrec 0)}"
185+
| .binaryOp _ op lhs rhs =>
186+
let prec := op.precedence
187+
let lhsStr := Format.nest 2 (lhs.formatWithPrec prec)
188+
let rhsStr := Format.nest 2 (rhs.formatWithPrec (prec + 1))
189+
let inner := f!"{lhsStr} {op} {rhsStr}"
190+
if parentPrec > prec then f!"({inner})" else inner
191+
| .unaryOp _ op arg =>
192+
let argStr := Format.nest 2 (arg.formatWithPrec 100)
193+
f!"{op}{argStr}"
194+
| .functionCall _ fn args =>
195+
let argStrs := Format.joinSep (args.map (Expression.formatWithPrec 0)) ", "
196+
f!"{ToFormat.format fn}({argStrs})"
197+
| .labeledExpr _ label expr => f!"{label}: {expr.formatWithPrec 0}"
198+
| .letExpr _ var value body =>
199+
f!"val {ToFormat.format var} := {Format.nest 2 (value.formatWithPrec 0)}{Format.line}{body.formatWithPrec 0}"
200+
| .quantifierExpr _ q var ty patterns body =>
201+
let patternsFormatted := patterns.foldl (fun acc p => f!"{acc} {Pattern.format p},") Format.nil
202+
f!"{q} {ToFormat.format var} : {ty}{Format.nest 2 $ patternsFormatted} {Format.nest 2 $ body.formatWithPrec 0}"
203+
204+
partial def Expression.format [ToFormat P.Metadata] [ToFormat P.Identifier] : Expression P → Format :=
205+
Expression.formatWithPrec 0
206+
207+
partial def Pattern.format [ToFormat P.Metadata] [ToFormat P.Identifier] : Pattern P → Format
208+
| .pattern _ exprs =>
209+
let exprStrs := Format.joinSep (exprs.map Expression.format) " "
210+
f!"pattern {exprStrs}"
211+
end
212+
213+
instance [ToFormat P.Metadata] [ToFormat P.Identifier] : ToFormat (Expression P) where
214+
format := Expression.format
215+
216+
instance [ToFormat P.Metadata] [ToFormat P.Identifier] : ToFormat (Pattern P) where
217+
format := Pattern.format
218+
219+
/-- Default ExprParams with Unit metadata and B3IdentifierMetadata -/
220+
def defaultExprParams : ExprParams := {
221+
Metadata := Unit
222+
IDMeta := B3IdentifierMetadata
223+
}
224+
225+
/-- B3 Expression with default parameters -/
226+
abbrev B3Expression := Expression defaultExprParams
227+
228+
/-- B3 Pattern with default parameters -/
229+
abbrev B3Pattern := Pattern defaultExprParams
230+
231+
-- ToFormat instances for default parameters
232+
instance : Std.ToFormat Unit where
233+
format _ := ""
234+
235+
instance : Std.ToFormat B3IdentifierMetadata where
236+
format _ := ""
237+
238+
instance : Std.ToFormat (Lambda.Identifier B3IdentifierMetadata) where
239+
format id := id.name
240+
241+
instance : Std.ToFormat defaultExprParams.Metadata := inferInstanceAs (Std.ToFormat Unit)
242+
instance : Std.ToFormat defaultExprParams.Identifier := inferInstanceAs (Std.ToFormat (Lambda.Identifier B3IdentifierMetadata))
243+
244+
end B3
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/-
2+
Copyright Strata Contributors
3+
4+
SPDX-License-Identifier: Apache-2.0 OR MIT
5+
-/
6+
7+
import Strata.DL.Lambda.LExprTypeEnv
8+
9+
namespace B3
10+
11+
open Std
12+
13+
/--
14+
Metadata for B3 identifiers.
15+
For now, we use a simple unit type since B3 doesn't have scoping.
16+
-/
17+
inductive B3IdentifierMetadata where
18+
| none
19+
deriving DecidableEq, Repr
20+
21+
instance : ToFormat B3IdentifierMetadata where
22+
format
23+
| .none => ""
24+
25+
instance : ToString B3IdentifierMetadata where
26+
toString v := toString $ ToFormat.format v
27+
28+
abbrev B3Ident := Lambda.Identifier B3IdentifierMetadata
29+
abbrev B3Label := String
30+
31+
def B3IdentDec : DecidableEq B3Ident := inferInstanceAs (DecidableEq (Lambda.Identifier B3IdentifierMetadata))
32+
33+
@[match_pattern]
34+
def B3Ident.mk (s : String) : B3Ident := ⟨s, B3IdentifierMetadata.none⟩
35+
36+
instance : Coe String B3Ident where
37+
coe | s => .mk s
38+
39+
def B3Ident.toPretty (x : B3Ident) : String :=
40+
match x with | ⟨s, _⟩ => s
41+
42+
instance : ToFormat B3Ident where
43+
format i := B3Ident.toPretty i
44+
45+
instance : ToString B3Ident where
46+
toString | ⟨s, v⟩ => (toString $ ToFormat.format v) ++ (toString $ ToFormat.format s)
47+
48+
instance : Repr B3Ident where
49+
reprPrec | ⟨s, v⟩, _ => (ToFormat.format v) ++ (ToFormat.format s)
50+
51+
instance : Inhabited B3Ident where
52+
default := ⟨"_", .none⟩
53+
54+
instance : Lambda.HasGen B3IdentifierMetadata where
55+
genVar T := let (sym, state') := (Lambda.TState.genExprSym T.genState)
56+
(B3Ident.mk sym, { T with genState := state' })
57+
58+
namespace Syntax
59+
60+
open Lean Elab Meta Lambda.LExpr.SyntaxMono
61+
62+
scoped syntax ident : lidentmono
63+
64+
def elabB3Ident : Syntax → MetaM Expr
65+
| `(lidentmono| $s:ident) => do
66+
let s := toString s.getId
67+
return ← mkAppM ``B3Ident.mk #[mkStrLit s]
68+
| _ => throwUnsupportedSyntax
69+
70+
instance : MkIdent B3IdentifierMetadata where
71+
elabIdent := elabB3Ident
72+
toExpr := .const ``B3IdentifierMetadata []
73+
74+
elab "b3[" e:lexprmono "]" : term => elabLExprMono (IDMeta:=B3IdentifierMetadata) e
75+
76+
end Syntax
77+
78+
end B3

0 commit comments

Comments
 (0)