Add scoped quotation syntax for object-language programs
Introduce [spa_e| ... ] for Expr and [spa| ... ] for Stmt, scoped to the Spa namespace via a dedicated syntax category and macro_rules. This removes the deeply nested .andThen / .basic (.assign ...) boilerplate when writing programs; Main.lean's test programs are rewritten to use it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,26 +1,30 @@
|
|||||||
import Spa.Analysis.Sign
|
import Spa.Analysis.Sign
|
||||||
import Spa.Analysis.Constant
|
import Spa.Analysis.Constant
|
||||||
|
import Spa.Language.Notation
|
||||||
|
|
||||||
namespace Spa
|
namespace Spa
|
||||||
|
|
||||||
def testCode : Stmt :=
|
def testCode : Stmt := [obj_stmt|
|
||||||
.andThen (.basic (.assign "zero" (.num 0)))
|
zero := 0;
|
||||||
(.andThen (.basic (.assign "pos" (.add (.var "zero") (.num 1))))
|
pos := zero + 1;
|
||||||
(.andThen (.basic (.assign "neg" (.sub (.var "zero") (.num 1))))
|
neg := zero - 1;
|
||||||
(.basic (.assign "unknown" (.add (.var "pos") (.var "neg"))))))
|
unknown := pos + neg
|
||||||
|
]
|
||||||
|
|
||||||
def testCodeCond₁ : Stmt :=
|
def testCodeCond₁ : Stmt := [obj_stmt|
|
||||||
.andThen (.basic (.assign "var" (.num 1)))
|
var := 1;
|
||||||
(.ifElse (.var "var")
|
if var {
|
||||||
(.basic (.assign "var" (.add (.var "var") (.num 1))))
|
var := var + 1
|
||||||
(.andThen (.basic (.assign "var" (.sub (.var "var") (.num 1))))
|
} else {
|
||||||
(.basic (.assign "var" (.num 1)))))
|
var := var - 1;
|
||||||
|
var := 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
def testCodeCond₂ : Stmt :=
|
def testCodeCond₂ : Stmt := [obj_stmt|
|
||||||
.andThen (.basic (.assign "var" (.num 1)))
|
var := 1;
|
||||||
(.ifElse (.var "var")
|
if var { x := 1 } else { noop }
|
||||||
(.basic (.assign "x" (.num 1)))
|
]
|
||||||
(.basic .noop))
|
|
||||||
|
|
||||||
def testProgram : Program := ⟨testCode⟩
|
def testProgram : Program := ⟨testCode⟩
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import Spa.Lattice.AboveBelow
|
|||||||
import Spa.Lattice.IterProd
|
import Spa.Lattice.IterProd
|
||||||
import Spa.Lattice.FiniteMap
|
import Spa.Lattice.FiniteMap
|
||||||
import Spa.Language.Base
|
import Spa.Language.Base
|
||||||
|
import Spa.Language.Notation
|
||||||
import Spa.Language.Semantics
|
import Spa.Language.Semantics
|
||||||
import Spa.Language.Graphs
|
import Spa.Language.Graphs
|
||||||
import Spa.Language.Traces
|
import Spa.Language.Traces
|
||||||
|
|||||||
60
lean/Spa/Language/Notation.lean
Normal file
60
lean/Spa/Language/Notation.lean
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
import Spa.Language.Base
|
||||||
|
|
||||||
|
namespace Spa
|
||||||
|
|
||||||
|
/-!
|
||||||
|
Scoped quotation syntax for writing object-language programs.
|
||||||
|
|
||||||
|
`[obj_expr| … ]` builds an `Expr`, `[obj_stmt| … ]` builds a `Stmt`.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
[obj_stmt|
|
||||||
|
zero := 0;
|
||||||
|
pos := zero + 1;
|
||||||
|
if pos { x := 1 } else { noop };
|
||||||
|
while x { x := x - 1 }
|
||||||
|
]
|
||||||
|
```
|
||||||
|
-/
|
||||||
|
|
||||||
|
/-- Expressions of the object language. -/
|
||||||
|
declare_syntax_cat obj_expr
|
||||||
|
|
||||||
|
syntax num : obj_expr
|
||||||
|
syntax ident : obj_expr
|
||||||
|
syntax:65 obj_expr:65 " + " obj_expr:66 : obj_expr
|
||||||
|
syntax:65 obj_expr:65 " - " obj_expr:66 : obj_expr
|
||||||
|
syntax "(" obj_expr ")" : obj_expr
|
||||||
|
|
||||||
|
/-- Statements of the object language. -/
|
||||||
|
declare_syntax_cat obj_stmt
|
||||||
|
|
||||||
|
syntax "noop" : obj_stmt
|
||||||
|
syntax ident " := " obj_expr : obj_stmt
|
||||||
|
syntax "if " obj_expr " { " obj_stmt " } " "else" " { " obj_stmt " } " : obj_stmt
|
||||||
|
syntax "while " obj_expr " { " obj_stmt " } " : obj_stmt
|
||||||
|
syntax:50 obj_stmt:51 "; " obj_stmt:50 : obj_stmt
|
||||||
|
syntax "(" obj_stmt ")" : obj_stmt
|
||||||
|
|
||||||
|
scoped syntax "[obj_expr| " obj_expr " ]" : term
|
||||||
|
scoped syntax "[obj_stmt| " obj_stmt " ]" : term
|
||||||
|
|
||||||
|
scoped macro_rules
|
||||||
|
| `([obj_expr| $n:num]) => `(Expr.num $n)
|
||||||
|
| `([obj_expr| $x:ident]) => `(Expr.var $(Lean.quote x.getId.toString))
|
||||||
|
| `([obj_expr| $a + $b]) => `(Expr.add [obj_expr| $a] [obj_expr| $b])
|
||||||
|
| `([obj_expr| $a - $b]) => `(Expr.sub [obj_expr| $a] [obj_expr| $b])
|
||||||
|
| `([obj_expr| ($e:obj_expr)]) => `([obj_expr| $e])
|
||||||
|
|
||||||
|
scoped macro_rules
|
||||||
|
| `([obj_stmt| noop]) => `(Stmt.basic .noop)
|
||||||
|
| `([obj_stmt| $x:ident := $e]) =>
|
||||||
|
`(Stmt.basic (.assign $(Lean.quote x.getId.toString) [obj_expr| $e]))
|
||||||
|
| `([obj_stmt| $s₁ ; $s₂]) => `(Stmt.andThen [obj_stmt| $s₁] [obj_stmt| $s₂])
|
||||||
|
| `([obj_stmt| if $e { $s₁ } else { $s₂ }]) =>
|
||||||
|
`(Stmt.ifElse [obj_expr| $e] [obj_stmt| $s₁] [obj_stmt| $s₂])
|
||||||
|
| `([obj_stmt| while $e { $s }]) => `(Stmt.whileLoop [obj_expr| $e] [obj_stmt| $s])
|
||||||
|
| `([obj_stmt| ($s:obj_stmt)]) => `([obj_stmt| $s])
|
||||||
|
|
||||||
|
end Spa
|
||||||
Reference in New Issue
Block a user