diff --git a/lean/Main.lean b/lean/Main.lean index ede1ffd..ba1cb83 100644 --- a/lean/Main.lean +++ b/lean/Main.lean @@ -1,26 +1,30 @@ import Spa.Analysis.Sign import Spa.Analysis.Constant +import Spa.Language.Notation namespace Spa -def testCode : Stmt := - .andThen (.basic (.assign "zero" (.num 0))) - (.andThen (.basic (.assign "pos" (.add (.var "zero") (.num 1)))) - (.andThen (.basic (.assign "neg" (.sub (.var "zero") (.num 1)))) - (.basic (.assign "unknown" (.add (.var "pos") (.var "neg")))))) +def testCode : Stmt := [obj_stmt| + zero := 0; + pos := zero + 1; + neg := zero - 1; + unknown := pos + neg +] -def testCodeCond₁ : Stmt := - .andThen (.basic (.assign "var" (.num 1))) - (.ifElse (.var "var") - (.basic (.assign "var" (.add (.var "var") (.num 1)))) - (.andThen (.basic (.assign "var" (.sub (.var "var") (.num 1)))) - (.basic (.assign "var" (.num 1))))) +def testCodeCond₁ : Stmt := [obj_stmt| + var := 1; + if var { + var := var + 1 + } else { + var := var - 1; + var := 1 + } +] -def testCodeCond₂ : Stmt := - .andThen (.basic (.assign "var" (.num 1))) - (.ifElse (.var "var") - (.basic (.assign "x" (.num 1))) - (.basic .noop)) +def testCodeCond₂ : Stmt := [obj_stmt| + var := 1; + if var { x := 1 } else { noop } +] def testProgram : Program := ⟨testCode⟩ diff --git a/lean/Spa.lean b/lean/Spa.lean index 528a9d0..7abb39e 100644 --- a/lean/Spa.lean +++ b/lean/Spa.lean @@ -7,6 +7,7 @@ import Spa.Lattice.AboveBelow import Spa.Lattice.IterProd import Spa.Lattice.FiniteMap import Spa.Language.Base +import Spa.Language.Notation import Spa.Language.Semantics import Spa.Language.Graphs import Spa.Language.Traces diff --git a/lean/Spa/Language/Notation.lean b/lean/Spa/Language/Notation.lean new file mode 100644 index 0000000..cd4c61b --- /dev/null +++ b/lean/Spa/Language/Notation.lean @@ -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