SlideShare une entreprise Scribd logo
1  sur  59
Télécharger pour lire hors ligne
Static Analysis & Error Checking


                         Lecture 9



                                               Course IN4308
     Eelco Visser
                                    Master Computer Science
http://eelcovisser.org          Delft University of Technology
Coming up
Lecture 8: Context-sensitive transformation
   ★ design 2
   ★ transformation with dynamic rewrite rules

Lecture 9: Static analysis & error checking
   ★ name resolution, reference resolution
   ★ type analysis

Lecture 10: Code generation
   ★ string templates, code generation by model transformation
   ★ concrete object syntax

Lecture 11: Code generation strategies
   ★ customization of generated code
Consistency Checking
Consistency Checking


Syntax definition
   ★ what are well-formed sentences?

Static analysis
   ★ not all ‘well-formedness’ properties are context-free
   ★ consistency of compositions
   ★ consistency of expressions wrt declarations

Error reporting
   ★ indicate errors in editor
   ★ use sensible error message
Consistency Checking: Ingredients

Editor Interface
   ★ collecting and displaying errors, warnings

Error checking
   ★ checking static constraints and reporting errors

Type analysis
   ★ computing types of expressions

Name resolution
   ★ disambiguation of names

Reference resolving
   ★ linking identifiers to declarations
Consistency Checking: Generic Approach


Rename
   ★ make identifiers unique

Map
   ★ map identifiers to declarations

Project
   ★ compute properties of declarations, expressions

Check
   ★ check constraints
Editor Interface

module nwl-Builders

imports nwl-Builders.generated

builders

  provider: include/nwl.ctree

  observer: editor-analyze
editor/nwl-Builders.esv
                                                                    trans/static-analysis.str
                          module static-analysis

                          imports include/nwl
                          imports entities
                          imports utils

                          rules // static analysis

                             editor-analyze:
                               (ast, path, fullpath) -> (errors, warnings, notes)
                               with ...
Editor Interface




editor-analyze:
  (ast, path, fullpath) -> (errors, warnings, notes)
  with
    errors   := <collect-all(check, conc)> ast;
    warnings := <collect-all(constraint-warning, conc)> ast;
    notes    := <collect-all(constraint-note, conc)> ast
Error Checking Rules




                 check :
                   context -> (target, error)
                   where assumption
                   where require(constraint)

                 require(s) = not(s)




– Context: identifying points in the code to check
– Assumptions: only report an error if certain assumptions hold (validating the context and avoiding spurious errors)
– Constraints: checking for constraints at the context
– Formulating an error message
– Attribution of the error to a particular character range in the source text (usually, only part of the context
Error Checking: Binary Operators



check :
  e@BinOp(e1, op, e2) ->
    (e, $[operator [op] not defined for [<pp>t1] and [<pp>t2]])
  where t1 := <type-of> e1
  where t2 := <type-of> e2
  where require(<type-of> e)
Pretty-Printing with String Interpolation


 pp : Entity(x, prop*) ->
      $[entity [x] {
           [<map(pp)>prop*]
        }]
 pp : Property(x,t) ->
      $[[x] : [<pp>t]
       ]
 pp : SimpleType(x) -> x
 pp : SetType(t) -> $[Set<[<pp> t]>]
 pp : [] -> $[]
 pp : [t] -> <pp>t
 pp : [t1,t2|ts] -> $[[<pp>t1],[<pp>[t2|ts]]]
Origin Tracking
check :
  e@BinOp(e1, op, e2) ->
    (e, $[operator [op] not defined for [<pp>t1] and [<pp>t2]])
  where ...

                                Assign(
                                  Var("x")
                                , BinOp(
                                    IntLit("2")
                                  , "+"
                                  , BinOp(IntLit("3"), "+", StringLit("4"))
                                  )
                                )

Assign(
  Var("x")
, Plus(IntLit("2"), Times(IntLit("3"), StringLit("4")))
)
Error Checking: Control-Flow Statements

  check :
    While(e, b) -> (e, $[Expression should have type Bool])
    where t := <type-of> e
    where require(<eq>(t, SimpleType("Bool")))

  check :
    If(e, b1, b2) -> (e, $[Expression should have type Bool])
    where t := <type-of> e
    where require(<eq>(t,SimpleType("Bool")))

  check :
    For(x, t, e, elem*) -> (e, $[[<pp>SetType(t)] expected])
    where t2 := <type-of> e
    where require(<eq>(t2,SetType(t)))



check rules follow the same pattern: type analysis + local consistency check
Type Analysis




type-of : e -> t




 compute type of expression
Type Analysis: Literals




type-of :
  StringLit(x) -> SimpleType("String")

type-of :
  IntLit(x) -> SimpleType("Int")
Type Analysis: Binary Operators


type-of :
  BinOp(e1, op, e2) -> t
  where t := <function-type>(op, [<type-of>e1, <type-of>e2])

function-type :
  ("+", [SimpleType("String"), SimpleType("String")]) -> SimpleType("String")

function-type :
  ("+", [SimpleType("Int"), SimpleType("Int")]) -> SimpleType("Int")

function-type :
  ("-", [SimpleType("Int"), SimpleType("Int")]) -> SimpleType("Int")
Type Analysis



BinOp(
  IntLit("2")
, "+"
, BinOp(
    IntLit("3"),
    "+",
    IntLit("4")
  )
)
Type Analysis



BinOp(
  IntLit("2")
, "+"
, BinOp(
                        type-of
    IntLit("3"),                   SimpleType("Int")
    "+",
                        type-of
    IntLit("4")                    SimpleType("Int")
  )
)
Type Analysis



BinOp(
                       type-of
  IntLit("2")                        SimpleType("Int")
, "+"
                   type-of
, BinOp(                         SimpleType("Int")
    IntLit("3"),
    "+",
    IntLit("4")
  )
)
Type Analysis



                   type-of
BinOp(                             SimpleType("Int")
  IntLit("2")
, "+"
, BinOp(
    IntLit("3"),
    "+",
    IntLit("4")
  )
)
Type Analysis: What is Type of Variable?


define page root(x : Int) {
  action exptest() {
    for(y : Int in {1,2,x}) {
      x := x + y;
    }
  }
                                               type-of :
}
                                                 Var(x) -> t
                                                 where t := ???

       Assign(
         Var("x")
       , BinOp(Var("x"), "+", Var("y"))
       )


             type of variable not part of variable use
Variables: Map


declare-all =
  alltd(declare)

declare :
  Param(x, t) -> Param(x, t)
  with rules(
         TypeOf : x -> t
       )

type-of :
  Var(x) -> t
  where t := <TypeOf> x
Scope




                    define page root(x : Int) {
                      action exptest() {
                        for(x : Int in {1,2,x}) {
                          print(x);
                        }
                      }
                    }




multiple occurrences of same identifier corresponding to different declarations
Variables: Map + Rename
rename-all = alltd(rename)

rename :
  Param(x, t) -> Param(y, t)
  with y := <rename-var>(x, t)
                                          unique annotation
rename-var :
  (x, t) -> y
  with y := x{<new>};
                                                 map variable to type
       rules(
         TypeOf   : y -> t
         RenameId : x -> y
       )
                                      rename occurrences
rename :
  Var(x) -> Var(y) where y := <RenameId> x

type-of :
  Var(x) -> t where t := <TypeOf> x
Term Annotations




                   t{t1,...,tn}




add additional information to term without affecting signature
Variables: Check




check :
  e@Var(x) -> (e, $[Variable '[x]' not declared])
  where require(<type-of>e)
Variable Binding Constructs




 rename :
   For(x, t, e1, stat1*) -> For(y, t, e2, stat2*)
   with e2 := <rename-all> e1
   with {| RenameId
          : y := <rename-var>(x, t)
          ; stat2* := <rename-all> stat1*
          |}




For   defines local variable x in body stat1*’
Assignment

is-lvalue =
  ?Var(_) <+ ?PropertyAccess(_, _)

check :
  Assign(e1, e2) -> (e1, $[Left-hand side of assignment should
                           be variable or property access])
  where require(<is-lvalue> e1)

check :
  Assign(e1, e2) -> (<id>, $[Type of lhs ('[<pp>t1]') does not
                             match type of rhs ('[<pp>t2]')])
  where t1 := <type-of>e1
  where t2 := <type-of>e2
  where require(<eq>(t1, t2))
Editor Interface with Analysis



editor-analyze:
  (ast, path, fullpath) -> (errors, warnings, notes)
  with
    ast2     := <analyze> ast;
    errors   := <collect-all(check, conc)> ast2;
    warnings := <collect-all(constraint-warning, conc)> ast2;
    notes    := <collect-all(constraint-note, conc)> ast2

analyze = rename-all
Rename, Map, Project, Check


Rename
   ★ make local variables unique

Map
   ★ variables to their type

Project
   ★ compute type of expressions

Check
   ★ check constraints using types
Data Model Consistency
Consistency of Data Model Declarations
entity Blog {
  url    : String (id)
  name   : String (name)
  posts : Set<Post>
  author : User
}

entity Post   {
  url     :   String (id)
  title   :   String (name)
  text    :   WikiText
  blog    :   Blog (inverse:posts)
  author :    User
  blog    :   Blog
  version :   Int
}
Consistency Constraints for Data Models



Unique declarations
   ★ entity names unique in model
   ★ property names unique in entity

Valid types
   ★ type is either primitive types (e.g. String) or declared entity type

Inverse properties
   ★ should refer to existing entity with existing property
Rename; Map; Project; Check


Rename
   ★ not needed: top-level declarations have global scope

Map
   ★ map identifier to AST of declaration

Project
   ★ lookup information in declaration

Check
   ★ check consistency using map & project
Entity Declarations: Map & Project
declare-def:
  ent@Entity(x, prop*) -> Entity(x, prop*)       Map
  with rules( EntityDeclaration : x -> ent )

declaration-of :
  SimpleType(x) -> <EntityDeclaration> x


                                           carrier-type =
                                             try(?SetType(<id>))

                                           is-entity-type =
                                             where(SimpleType(EntityDeclaration))

                                           is-simple-type =
                                             is-primitive-type <+ is-entity-type

                                           name-of :
                                             Entity(x, prop*) -> x

                            Project        type-of :
                                             Entity(x, prop*) -> SimpleType(x)
Entity Declarations: Check


check :
  ent@Entity(x, prop*) -> (x, $[Entity '[x]' defined more than once])
  where require(<EntityDeclaration> x => ent)

check :
  t@SimpleType(x) -> (x, $[Type '[x]' is not defined])
  where require(<is-simple-type>t)

check :
  t@SetType(type) -> (t, $[Set should have entity type as argument])
  where <is-simple-type> type
  where require(<is-entity-type> type)
Properties: Project


lookup-property(|x) =
  lookup-property(?Property(x,_,_))

lookup-property(s) :
  Entity(x, prop*) -> <fetch-elem(s)> prop*

lookup-property(s) :
  SimpleType(x) -> <declaration-of; lookup-property(s)>

type-of :
  Property(_, type, _) -> type

inverse :
  Property(_, _, anno*) -> <fetch-elem(?Inverse(_))> anno*
Properties: Check



check:
  ent@Entity(x, prop*) -> errors
  where errors := <filter(check-property(|ent))> prop*
  where require(<not(?[])> errors)

check-property(|ent) :
  Property(name, type, annos) -> (name,
                                  $[Property '[name]' defined more than once])
  where require(<type-of><lookup-property(|name)>ent => type)
Inverse Property: Check




check-property(|ent) :
  prop@Property(f, t, annos) -> (g, $[Inverse relation requires entity type])
  where Inverse(g) := <inverse>prop
  where tc := <carrier-type> t
  where <is-simple-type> tc
  where require(<is-entity-type> tc)
Inverse Property: Check
check:
  ent@Entity(x, prop*) -> errors
  where errors := <filter(check-property(|ent)); not(?[])> prop*

check-property(|ent) :
  Property(f, t, annos) -> (g, $[Inverse relation requires entity type])
  where Inverse(g) := <inverse>
  where tc := <carrier-type> t
  where <is-simple-type> tc // non-existing type already produces error message
  where require(<is-entity-type> tc)

check-property(|ent1) :
  Property(f, t, annos) -> (g, $[Entity '[<pp>tc]' has no property '[g]'])
  where Inverse(g) := <inverse>
  where tc := <carrier-type> t
  where <is-entity-type> tc
  where require(<lookup-property(|g)> tc)

check-property(|ent) :
  Property(f, t, anno*) -> (g, $[Type of '[<pp>t1].[g]' should be [<pp>t3] or [<pp>SetType(t3)]])
  where Inverse(g) := <inverse>
  where t1 := <carrier-type> t
  where t2 := <lookup-property(|g); type-of; carrier-type> t1
  where t3 := <type-of>ent
  where require(<eq>(t2, t3))




      multiple check rules necessary to check different cases
Property References




type-of :
  PropertyAccess(e, f) -> <type-of; lookup-property(|f); type-of> e

check :
  e1@PropertyAccess(e2, f) -> (f, $[[<pp>t] has no property '[f]])
  where t := <type-of> e2
  where require(<type-of>e1)
Template Consistency
define page editpost(p : Post) {
Template Consistency                     action save() {
                                           p.version := p.version + 1;
                                           return post(p);
                                         }
                                         header{output(p.title)}
                                         form{
                                           input(p.url)
                                           input(p.title)
                                           input(p.text)
Template definitions                        submit save() { "Save" }
                                         }
  ★ should be unique                   }


Template references
  ★ to existing definition
  ★ consistent with parameter declarations
define page editpost(p : Post) {
         Template AST                                                   action save() {
                                                                          p.version := p.version + 1;
                                                                          return post(p);
                                                                        }
                                                                        header{output(p.title)}
TemplateDef(                                                            form{
  [Page()]
, "editpost"                                                              input(p.url)
, [Param("p", SimpleType("Post"))]                                        input(p.title)
, [ Action(
                                                                          input(p.text)
      "save"
    , []                                                                  submit save() { "Save" }
    , [ Assign(                                                         }
           PropertyAccess(Var("p"), "version")
                                                                      }
         , Plus(PropertyAccess(Var("p"), "version"),   IntLit("1"))
         )
      , ReturnPage(PageRef("post", [Var("p")]))
      ]
    )
  , CallElems(
      "header"
    , [CallArgs("output", [PropertyAccess(Var("p"),    "title")])]
    )
  , CallElems(
      "form"
    , [ CallArgs("input", [PropertyAccess(Var("p"),    "url")])
      , CallArgs("input", [PropertyAccess(Var("p"),    "title")])
      , CallArgs("input", [PropertyAccess(Var("p"),    "text")])
      , Submit("save", [], [String(""Save"")])
      ]
    )
  ]
)
Template Definitions: Map + Rename

declare-def :
  def@TemplateDef(mod*, x, param*, elem*) -> def
  with sig := <signature-of> def;
       rules(
         Template : x -> def
         Template : sig -> def
       )

rename :
  TemplateDef(mod*, x, param1*, elem1*) -> <declare-def>
  TemplateDef(mod*, x, param2*, elem3*)
  with {| RenameId, RenameAction
         : param2* := <rename-all> param1*
         ; elem2* := <alltd(rename-action)> elem1*
         ; elem3* := <rename-all> elem2*
         |}




     rename local variables in template definition
Template Definitions: Project
is-page-def =
  ?TemplateDef([Page()],_,_,_)

param-types =
  is-list; map(?Param(_,<id>))

param-types :
  TemplateDef(mod*, x, param*, elem*) -> <param-types> param*

signature-of :
  TemplateDef(mod*, x, param*, elem*) -> (x, <param-types>param*)

declaration-of :
  TemplateDef(mod*, x, param*, elem*) -> <signature-of; Template>

declaration-of :
  Navigate(ref, elems) -> <declaration-of> ref

declaration-of :
  PageRef(x, e*) -> <Template> x

call-of :
  PageRef(x, e*) -> (x, e*)
Template Definitions: Check Uniqueness


check :
  def@TemplateDef(mod*, x, param*, elem*) ->
                                   (x, $[Multiple definitions for page '[x]'])
  where <is-page-def> def
  where require(<Template> x => def)

check :
  def@TemplateDef(mod*, x, param*, elem*) ->
                (x, $[Multiple definitions for template with signature [sig]])
  where not(is-page-def)
  where require(<declaration-of> def => def)
  where sig := <signature-of;pp-sig> def
Checking Template/Page/Function Calls



List of expressions consistent with list of types
   ★ zip

Multiple possible error causes
   ★ call of non-existing definition
   ★ parameter arity mismatch
   ★ argument type mismatch

Argument checking reusable
Templates: Check Page References



check :
  PageRef(x, e*) -> (x, $[Navigation to non-existing page])
  where require(declaration-of)

check :
  PageRef(x, e*) -> [(x, $[Navigation to template '[x]' (not a page)])]
  where def := <declaration-of>
  where require(<is-page-def> def)

check :
  PageRef(x, e*) -> <check-args>
Template Call: Project




signature-of :
  Call(x, e*, elem*) -> (x, <map(type-of)> e*)

call-of :
  Call(x, e*, elem*) -> (x, e*)

declaration-of :
  Call(x, e*, elem*) -> <signature-of; Template>

is-primitive-template =
  ?"input" <+ ?"output" <+ ?"form"
Templates: Check Template Calls

check :
  Call(x, e*, elem*) -> (x, $[Template '[x]' is not defined])
  where not(<is-primitive-template> x)
  where require(<Template> x)

check :
  Call(x, e*, elem*) -> (x, $[No definition for template with
                              signature '[x]([<map(type-of);pp> e*])'])
  where not(<is-primitive-template> x)
  where <Template> x
  where require(declaration-of)

constraint-warning :
  Call(x, e*, elem*) -> [(x, $[Page definition is used as template])]
  where def := <declaration-of>
  where require(not(<is-page-def> def))

check :
  Call(x, e*, elem*) -> <check-args>
Checking Call Arguments


check-args =
  !(<call-of>, <declaration-of>);
  (check-arg-types <+ check-args-arity)

check-arg-types :
  ((f, e*), def) -> errors
  where errors := <zip; filter(check-arg); not(?[])> (e*, <param-types> def)

check-arg :
  (e, t) -> (e, $[Argument of type '[<pp>t]' expected (not of type '[<pp>t2]')])
  where t2 := <type-of> e
  where require(<eq>(t, t2))

check-args-arity :
  ((f, e*), def) -> [(f, $['[f]' expects [<int-to-string>l] arguments;
                            [<int-to-string>k] provided])]
  with k := <length>e*
  with l := <param-types; length> def
  where require(<eq>(k, l))
Reference Resolution
Reference Resolution




Aiding program navigation
  ★ Hover-click on identifier to jump to declaration

Reuse name resolution infrastructure
Reference Resolution

module nwl-References

imports nwl-References.generated

references

  reference _ : editor-resolve



 editor-resolve:
   (source, position, ast, path, fullpath) -> target
   where
     target := <compute-target> source
From Use to Declaration



editor-resolve:
  (SimpleType(type), position, ast, path, fullpath) -> target
  where
    Entity(target,_) := <EntityDeclaration> type

editor-resolve:
  (ref@PageRef(x,e*), position, ast, path, fullpath) -> target
  where
    TemplateDef(_,target,_,_) := <declaration-of> ref
Schedule
Case 3
  ★ Syntax definition & term rewriting
  ★ Deadline: May 4

Design 2
  ★ Make a proposal (can be submitted separately)
  ★ Deadline: May 5

Lab this week
  ★ Finish Case 3
  ★ Syntax for Design 2

Next
  ★ Lecture 10: code generation

Contenu connexe

Tendances

Groovy vs Boilerplate and Ceremony Code
Groovy vs Boilerplate and Ceremony CodeGroovy vs Boilerplate and Ceremony Code
Groovy vs Boilerplate and Ceremony Code
stasimus
 
Python 2.5 reference card (2009)
Python 2.5 reference card (2009)Python 2.5 reference card (2009)
Python 2.5 reference card (2009)
gekiaruj
 

Tendances (20)

Introduction to Python
Introduction to PythonIntroduction to Python
Introduction to Python
 
Fp in scala part 2
Fp in scala part 2Fp in scala part 2
Fp in scala part 2
 
JBUG 11 - Scala For Java Programmers
JBUG 11 - Scala For Java ProgrammersJBUG 11 - Scala For Java Programmers
JBUG 11 - Scala For Java Programmers
 
Hidden Gems in Swift
Hidden Gems in SwiftHidden Gems in Swift
Hidden Gems in Swift
 
The Ring programming language version 1.5.2 book - Part 33 of 181
The Ring programming language version 1.5.2 book - Part 33 of 181The Ring programming language version 1.5.2 book - Part 33 of 181
The Ring programming language version 1.5.2 book - Part 33 of 181
 
Groovy vs Boilerplate and Ceremony Code
Groovy vs Boilerplate and Ceremony CodeGroovy vs Boilerplate and Ceremony Code
Groovy vs Boilerplate and Ceremony Code
 
Groovy grails types, operators, objects
Groovy grails types, operators, objectsGroovy grails types, operators, objects
Groovy grails types, operators, objects
 
Python 2.5 reference card (2009)
Python 2.5 reference card (2009)Python 2.5 reference card (2009)
Python 2.5 reference card (2009)
 
Python Cheat Sheet
Python Cheat SheetPython Cheat Sheet
Python Cheat Sheet
 
Scalaz 8: A Whole New Game
Scalaz 8: A Whole New GameScalaz 8: A Whole New Game
Scalaz 8: A Whole New Game
 
7 Habits For a More Functional Swift
7 Habits For a More Functional Swift7 Habits For a More Functional Swift
7 Habits For a More Functional Swift
 
Hammurabi
HammurabiHammurabi
Hammurabi
 
What are arrays in java script
What are arrays in java scriptWhat are arrays in java script
What are arrays in java script
 
For Beginners - C#
For Beginners - C#For Beginners - C#
For Beginners - C#
 
A Prelude of Purity: Scaling Back ZIO
A Prelude of Purity: Scaling Back ZIOA Prelude of Purity: Scaling Back ZIO
A Prelude of Purity: Scaling Back ZIO
 
ECMA 入门
ECMA 入门ECMA 入门
ECMA 入门
 
The java language cheat sheet
The java language cheat sheetThe java language cheat sheet
The java language cheat sheet
 
Introduction to ad-3.4, an automatic differentiation library in Haskell
Introduction to ad-3.4, an automatic differentiation library in HaskellIntroduction to ad-3.4, an automatic differentiation library in Haskell
Introduction to ad-3.4, an automatic differentiation library in Haskell
 
From java to kotlin beyond alt+shift+cmd+k - Droidcon italy
From java to kotlin beyond alt+shift+cmd+k - Droidcon italyFrom java to kotlin beyond alt+shift+cmd+k - Droidcon italy
From java to kotlin beyond alt+shift+cmd+k - Droidcon italy
 
The Ring programming language version 1.5.4 book - Part 34 of 185
The Ring programming language version 1.5.4 book - Part 34 of 185The Ring programming language version 1.5.4 book - Part 34 of 185
The Ring programming language version 1.5.4 book - Part 34 of 185
 

Similaire à Model-Driven Software Development - Static Analysis & Error Checking

High Wizardry in the Land of Scala
High Wizardry in the Land of ScalaHigh Wizardry in the Land of Scala
High Wizardry in the Land of Scala
djspiewak
 

Similaire à Model-Driven Software Development - Static Analysis & Error Checking (20)

Declare Your Language: Type Checking
Declare Your Language: Type CheckingDeclare Your Language: Type Checking
Declare Your Language: Type Checking
 
Term Rewriting
Term RewritingTerm Rewriting
Term Rewriting
 
Meet scala
Meet scalaMeet scala
Meet scala
 
Declare Your Language: Name Resolution
Declare Your Language: Name ResolutionDeclare Your Language: Name Resolution
Declare Your Language: Name Resolution
 
High Wizardry in the Land of Scala
High Wizardry in the Land of ScalaHigh Wizardry in the Land of Scala
High Wizardry in the Land of Scala
 
Introduction to R programming
Introduction to R programmingIntroduction to R programming
Introduction to R programming
 
Introducing scala
Introducing scalaIntroducing scala
Introducing scala
 
Practical cats
Practical catsPractical cats
Practical cats
 
An introduction to scala
An introduction to scalaAn introduction to scala
An introduction to scala
 
Scala Bootcamp 1
Scala Bootcamp 1Scala Bootcamp 1
Scala Bootcamp 1
 
ANSI C REFERENCE CARD
ANSI C REFERENCE CARDANSI C REFERENCE CARD
ANSI C REFERENCE CARD
 
C# programming
C# programming C# programming
C# programming
 
A Proposition for Business Process Modeling
A Proposition for Business Process ModelingA Proposition for Business Process Modeling
A Proposition for Business Process Modeling
 
Functional programming ii
Functional programming iiFunctional programming ii
Functional programming ii
 
Functions In Scala
Functions In Scala Functions In Scala
Functions In Scala
 
Array
ArrayArray
Array
 
An introduction to functional programming with Swift
An introduction to functional programming with SwiftAn introduction to functional programming with Swift
An introduction to functional programming with Swift
 
An overview of Python 2.7
An overview of Python 2.7An overview of Python 2.7
An overview of Python 2.7
 
A tour of Python
A tour of PythonA tour of Python
A tour of Python
 
Arrays
ArraysArrays
Arrays
 

Plus de Eelco Visser

Declarative Type System Specification with Statix
Declarative Type System Specification with StatixDeclarative Type System Specification with Statix
Declarative Type System Specification with Statix
Eelco Visser
 

Plus de Eelco Visser (20)

CS4200 2019 | Lecture 5 | Transformation by Term Rewriting
CS4200 2019 | Lecture 5 | Transformation by Term RewritingCS4200 2019 | Lecture 5 | Transformation by Term Rewriting
CS4200 2019 | Lecture 5 | Transformation by Term Rewriting
 
CS4200 2019 | Lecture 4 | Syntactic Services
CS4200 2019 | Lecture 4 | Syntactic ServicesCS4200 2019 | Lecture 4 | Syntactic Services
CS4200 2019 | Lecture 4 | Syntactic Services
 
CS4200 2019 | Lecture 3 | Parsing
CS4200 2019 | Lecture 3 | ParsingCS4200 2019 | Lecture 3 | Parsing
CS4200 2019 | Lecture 3 | Parsing
 
CS4200 2019 | Lecture 2 | syntax-definition
CS4200 2019 | Lecture 2 | syntax-definitionCS4200 2019 | Lecture 2 | syntax-definition
CS4200 2019 | Lecture 2 | syntax-definition
 
CS4200 2019 Lecture 1: Introduction
CS4200 2019 Lecture 1: IntroductionCS4200 2019 Lecture 1: Introduction
CS4200 2019 Lecture 1: Introduction
 
A Direct Semantics of Declarative Disambiguation Rules
A Direct Semantics of Declarative Disambiguation RulesA Direct Semantics of Declarative Disambiguation Rules
A Direct Semantics of Declarative Disambiguation Rules
 
Declarative Type System Specification with Statix
Declarative Type System Specification with StatixDeclarative Type System Specification with Statix
Declarative Type System Specification with Statix
 
Compiler Construction | Lecture 17 | Beyond Compiler Construction
Compiler Construction | Lecture 17 | Beyond Compiler ConstructionCompiler Construction | Lecture 17 | Beyond Compiler Construction
Compiler Construction | Lecture 17 | Beyond Compiler Construction
 
Domain Specific Languages for Parallel Graph AnalytiX (PGX)
Domain Specific Languages for Parallel Graph AnalytiX (PGX)Domain Specific Languages for Parallel Graph AnalytiX (PGX)
Domain Specific Languages for Parallel Graph AnalytiX (PGX)
 
Compiler Construction | Lecture 15 | Memory Management
Compiler Construction | Lecture 15 | Memory ManagementCompiler Construction | Lecture 15 | Memory Management
Compiler Construction | Lecture 15 | Memory Management
 
Compiler Construction | Lecture 14 | Interpreters
Compiler Construction | Lecture 14 | InterpretersCompiler Construction | Lecture 14 | Interpreters
Compiler Construction | Lecture 14 | Interpreters
 
Compiler Construction | Lecture 13 | Code Generation
Compiler Construction | Lecture 13 | Code GenerationCompiler Construction | Lecture 13 | Code Generation
Compiler Construction | Lecture 13 | Code Generation
 
Compiler Construction | Lecture 12 | Virtual Machines
Compiler Construction | Lecture 12 | Virtual MachinesCompiler Construction | Lecture 12 | Virtual Machines
Compiler Construction | Lecture 12 | Virtual Machines
 
Compiler Construction | Lecture 11 | Monotone Frameworks
Compiler Construction | Lecture 11 | Monotone FrameworksCompiler Construction | Lecture 11 | Monotone Frameworks
Compiler Construction | Lecture 11 | Monotone Frameworks
 
Compiler Construction | Lecture 10 | Data-Flow Analysis
Compiler Construction | Lecture 10 | Data-Flow AnalysisCompiler Construction | Lecture 10 | Data-Flow Analysis
Compiler Construction | Lecture 10 | Data-Flow Analysis
 
Compiler Construction | Lecture 9 | Constraint Resolution
Compiler Construction | Lecture 9 | Constraint ResolutionCompiler Construction | Lecture 9 | Constraint Resolution
Compiler Construction | Lecture 9 | Constraint Resolution
 
Compiler Construction | Lecture 8 | Type Constraints
Compiler Construction | Lecture 8 | Type ConstraintsCompiler Construction | Lecture 8 | Type Constraints
Compiler Construction | Lecture 8 | Type Constraints
 
Compiler Construction | Lecture 7 | Type Checking
Compiler Construction | Lecture 7 | Type CheckingCompiler Construction | Lecture 7 | Type Checking
Compiler Construction | Lecture 7 | Type Checking
 
Compiler Construction | Lecture 6 | Introduction to Static Analysis
Compiler Construction | Lecture 6 | Introduction to Static AnalysisCompiler Construction | Lecture 6 | Introduction to Static Analysis
Compiler Construction | Lecture 6 | Introduction to Static Analysis
 
Compiler Construction | Lecture 5 | Transformation by Term Rewriting
Compiler Construction | Lecture 5 | Transformation by Term RewritingCompiler Construction | Lecture 5 | Transformation by Term Rewriting
Compiler Construction | Lecture 5 | Transformation by Term Rewriting
 

Model-Driven Software Development - Static Analysis & Error Checking

  • 1. Static Analysis & Error Checking Lecture 9 Course IN4308 Eelco Visser Master Computer Science http://eelcovisser.org Delft University of Technology
  • 2. Coming up Lecture 8: Context-sensitive transformation ★ design 2 ★ transformation with dynamic rewrite rules Lecture 9: Static analysis & error checking ★ name resolution, reference resolution ★ type analysis Lecture 10: Code generation ★ string templates, code generation by model transformation ★ concrete object syntax Lecture 11: Code generation strategies ★ customization of generated code
  • 4. Consistency Checking Syntax definition ★ what are well-formed sentences? Static analysis ★ not all ‘well-formedness’ properties are context-free ★ consistency of compositions ★ consistency of expressions wrt declarations Error reporting ★ indicate errors in editor ★ use sensible error message
  • 5.
  • 6.
  • 7. Consistency Checking: Ingredients Editor Interface ★ collecting and displaying errors, warnings Error checking ★ checking static constraints and reporting errors Type analysis ★ computing types of expressions Name resolution ★ disambiguation of names Reference resolving ★ linking identifiers to declarations
  • 8. Consistency Checking: Generic Approach Rename ★ make identifiers unique Map ★ map identifiers to declarations Project ★ compute properties of declarations, expressions Check ★ check constraints
  • 9. Editor Interface module nwl-Builders imports nwl-Builders.generated builders provider: include/nwl.ctree observer: editor-analyze editor/nwl-Builders.esv trans/static-analysis.str module static-analysis imports include/nwl imports entities imports utils rules // static analysis editor-analyze: (ast, path, fullpath) -> (errors, warnings, notes) with ...
  • 10. Editor Interface editor-analyze: (ast, path, fullpath) -> (errors, warnings, notes) with errors := <collect-all(check, conc)> ast; warnings := <collect-all(constraint-warning, conc)> ast; notes := <collect-all(constraint-note, conc)> ast
  • 11. Error Checking Rules check : context -> (target, error) where assumption where require(constraint) require(s) = not(s) – Context: identifying points in the code to check – Assumptions: only report an error if certain assumptions hold (validating the context and avoiding spurious errors) – Constraints: checking for constraints at the context – Formulating an error message – Attribution of the error to a particular character range in the source text (usually, only part of the context
  • 12. Error Checking: Binary Operators check : e@BinOp(e1, op, e2) -> (e, $[operator [op] not defined for [<pp>t1] and [<pp>t2]]) where t1 := <type-of> e1 where t2 := <type-of> e2 where require(<type-of> e)
  • 13. Pretty-Printing with String Interpolation pp : Entity(x, prop*) -> $[entity [x] { [<map(pp)>prop*] }] pp : Property(x,t) -> $[[x] : [<pp>t] ] pp : SimpleType(x) -> x pp : SetType(t) -> $[Set<[<pp> t]>] pp : [] -> $[] pp : [t] -> <pp>t pp : [t1,t2|ts] -> $[[<pp>t1],[<pp>[t2|ts]]]
  • 14. Origin Tracking check : e@BinOp(e1, op, e2) -> (e, $[operator [op] not defined for [<pp>t1] and [<pp>t2]]) where ... Assign( Var("x") , BinOp( IntLit("2") , "+" , BinOp(IntLit("3"), "+", StringLit("4")) ) ) Assign( Var("x") , Plus(IntLit("2"), Times(IntLit("3"), StringLit("4"))) )
  • 15. Error Checking: Control-Flow Statements check : While(e, b) -> (e, $[Expression should have type Bool]) where t := <type-of> e where require(<eq>(t, SimpleType("Bool"))) check : If(e, b1, b2) -> (e, $[Expression should have type Bool]) where t := <type-of> e where require(<eq>(t,SimpleType("Bool"))) check : For(x, t, e, elem*) -> (e, $[[<pp>SetType(t)] expected]) where t2 := <type-of> e where require(<eq>(t2,SetType(t))) check rules follow the same pattern: type analysis + local consistency check
  • 16. Type Analysis type-of : e -> t compute type of expression
  • 17. Type Analysis: Literals type-of : StringLit(x) -> SimpleType("String") type-of : IntLit(x) -> SimpleType("Int")
  • 18. Type Analysis: Binary Operators type-of : BinOp(e1, op, e2) -> t where t := <function-type>(op, [<type-of>e1, <type-of>e2]) function-type : ("+", [SimpleType("String"), SimpleType("String")]) -> SimpleType("String") function-type : ("+", [SimpleType("Int"), SimpleType("Int")]) -> SimpleType("Int") function-type : ("-", [SimpleType("Int"), SimpleType("Int")]) -> SimpleType("Int")
  • 19. Type Analysis BinOp( IntLit("2") , "+" , BinOp( IntLit("3"), "+", IntLit("4") ) )
  • 20. Type Analysis BinOp( IntLit("2") , "+" , BinOp( type-of IntLit("3"), SimpleType("Int") "+", type-of IntLit("4") SimpleType("Int") ) )
  • 21. Type Analysis BinOp( type-of IntLit("2") SimpleType("Int") , "+" type-of , BinOp( SimpleType("Int") IntLit("3"), "+", IntLit("4") ) )
  • 22. Type Analysis type-of BinOp( SimpleType("Int") IntLit("2") , "+" , BinOp( IntLit("3"), "+", IntLit("4") ) )
  • 23. Type Analysis: What is Type of Variable? define page root(x : Int) { action exptest() { for(y : Int in {1,2,x}) { x := x + y; } } type-of : } Var(x) -> t where t := ??? Assign( Var("x") , BinOp(Var("x"), "+", Var("y")) ) type of variable not part of variable use
  • 24. Variables: Map declare-all = alltd(declare) declare : Param(x, t) -> Param(x, t) with rules( TypeOf : x -> t ) type-of : Var(x) -> t where t := <TypeOf> x
  • 25. Scope define page root(x : Int) { action exptest() { for(x : Int in {1,2,x}) { print(x); } } } multiple occurrences of same identifier corresponding to different declarations
  • 26. Variables: Map + Rename rename-all = alltd(rename) rename : Param(x, t) -> Param(y, t) with y := <rename-var>(x, t) unique annotation rename-var : (x, t) -> y with y := x{<new>}; map variable to type rules( TypeOf : y -> t RenameId : x -> y ) rename occurrences rename : Var(x) -> Var(y) where y := <RenameId> x type-of : Var(x) -> t where t := <TypeOf> x
  • 27. Term Annotations t{t1,...,tn} add additional information to term without affecting signature
  • 28. Variables: Check check : e@Var(x) -> (e, $[Variable '[x]' not declared]) where require(<type-of>e)
  • 29. Variable Binding Constructs rename : For(x, t, e1, stat1*) -> For(y, t, e2, stat2*) with e2 := <rename-all> e1 with {| RenameId : y := <rename-var>(x, t) ; stat2* := <rename-all> stat1* |} For defines local variable x in body stat1*’
  • 30. Assignment is-lvalue = ?Var(_) <+ ?PropertyAccess(_, _) check : Assign(e1, e2) -> (e1, $[Left-hand side of assignment should be variable or property access]) where require(<is-lvalue> e1) check : Assign(e1, e2) -> (<id>, $[Type of lhs ('[<pp>t1]') does not match type of rhs ('[<pp>t2]')]) where t1 := <type-of>e1 where t2 := <type-of>e2 where require(<eq>(t1, t2))
  • 31. Editor Interface with Analysis editor-analyze: (ast, path, fullpath) -> (errors, warnings, notes) with ast2 := <analyze> ast; errors := <collect-all(check, conc)> ast2; warnings := <collect-all(constraint-warning, conc)> ast2; notes := <collect-all(constraint-note, conc)> ast2 analyze = rename-all
  • 32. Rename, Map, Project, Check Rename ★ make local variables unique Map ★ variables to their type Project ★ compute type of expressions Check ★ check constraints using types
  • 34. Consistency of Data Model Declarations entity Blog { url : String (id) name : String (name) posts : Set<Post> author : User } entity Post { url : String (id) title : String (name) text : WikiText blog : Blog (inverse:posts) author : User blog : Blog version : Int }
  • 35. Consistency Constraints for Data Models Unique declarations ★ entity names unique in model ★ property names unique in entity Valid types ★ type is either primitive types (e.g. String) or declared entity type Inverse properties ★ should refer to existing entity with existing property
  • 36. Rename; Map; Project; Check Rename ★ not needed: top-level declarations have global scope Map ★ map identifier to AST of declaration Project ★ lookup information in declaration Check ★ check consistency using map & project
  • 37. Entity Declarations: Map & Project declare-def: ent@Entity(x, prop*) -> Entity(x, prop*) Map with rules( EntityDeclaration : x -> ent ) declaration-of : SimpleType(x) -> <EntityDeclaration> x carrier-type = try(?SetType(<id>)) is-entity-type = where(SimpleType(EntityDeclaration)) is-simple-type = is-primitive-type <+ is-entity-type name-of : Entity(x, prop*) -> x Project type-of : Entity(x, prop*) -> SimpleType(x)
  • 38. Entity Declarations: Check check : ent@Entity(x, prop*) -> (x, $[Entity '[x]' defined more than once]) where require(<EntityDeclaration> x => ent) check : t@SimpleType(x) -> (x, $[Type '[x]' is not defined]) where require(<is-simple-type>t) check : t@SetType(type) -> (t, $[Set should have entity type as argument]) where <is-simple-type> type where require(<is-entity-type> type)
  • 39. Properties: Project lookup-property(|x) = lookup-property(?Property(x,_,_)) lookup-property(s) : Entity(x, prop*) -> <fetch-elem(s)> prop* lookup-property(s) : SimpleType(x) -> <declaration-of; lookup-property(s)> type-of : Property(_, type, _) -> type inverse : Property(_, _, anno*) -> <fetch-elem(?Inverse(_))> anno*
  • 40. Properties: Check check: ent@Entity(x, prop*) -> errors where errors := <filter(check-property(|ent))> prop* where require(<not(?[])> errors) check-property(|ent) : Property(name, type, annos) -> (name, $[Property '[name]' defined more than once]) where require(<type-of><lookup-property(|name)>ent => type)
  • 41. Inverse Property: Check check-property(|ent) : prop@Property(f, t, annos) -> (g, $[Inverse relation requires entity type]) where Inverse(g) := <inverse>prop where tc := <carrier-type> t where <is-simple-type> tc where require(<is-entity-type> tc)
  • 42. Inverse Property: Check check: ent@Entity(x, prop*) -> errors where errors := <filter(check-property(|ent)); not(?[])> prop* check-property(|ent) : Property(f, t, annos) -> (g, $[Inverse relation requires entity type]) where Inverse(g) := <inverse> where tc := <carrier-type> t where <is-simple-type> tc // non-existing type already produces error message where require(<is-entity-type> tc) check-property(|ent1) : Property(f, t, annos) -> (g, $[Entity '[<pp>tc]' has no property '[g]']) where Inverse(g) := <inverse> where tc := <carrier-type> t where <is-entity-type> tc where require(<lookup-property(|g)> tc) check-property(|ent) : Property(f, t, anno*) -> (g, $[Type of '[<pp>t1].[g]' should be [<pp>t3] or [<pp>SetType(t3)]]) where Inverse(g) := <inverse> where t1 := <carrier-type> t where t2 := <lookup-property(|g); type-of; carrier-type> t1 where t3 := <type-of>ent where require(<eq>(t2, t3)) multiple check rules necessary to check different cases
  • 43. Property References type-of : PropertyAccess(e, f) -> <type-of; lookup-property(|f); type-of> e check : e1@PropertyAccess(e2, f) -> (f, $[[<pp>t] has no property '[f]]) where t := <type-of> e2 where require(<type-of>e1)
  • 45. define page editpost(p : Post) { Template Consistency action save() { p.version := p.version + 1; return post(p); } header{output(p.title)} form{ input(p.url) input(p.title) input(p.text) Template definitions submit save() { "Save" } } ★ should be unique } Template references ★ to existing definition ★ consistent with parameter declarations
  • 46. define page editpost(p : Post) { Template AST action save() { p.version := p.version + 1; return post(p); } header{output(p.title)} TemplateDef( form{ [Page()] , "editpost" input(p.url) , [Param("p", SimpleType("Post"))] input(p.title) , [ Action( input(p.text) "save" , [] submit save() { "Save" } , [ Assign( } PropertyAccess(Var("p"), "version") } , Plus(PropertyAccess(Var("p"), "version"), IntLit("1")) ) , ReturnPage(PageRef("post", [Var("p")])) ] ) , CallElems( "header" , [CallArgs("output", [PropertyAccess(Var("p"), "title")])] ) , CallElems( "form" , [ CallArgs("input", [PropertyAccess(Var("p"), "url")]) , CallArgs("input", [PropertyAccess(Var("p"), "title")]) , CallArgs("input", [PropertyAccess(Var("p"), "text")]) , Submit("save", [], [String(""Save"")]) ] ) ] )
  • 47. Template Definitions: Map + Rename declare-def : def@TemplateDef(mod*, x, param*, elem*) -> def with sig := <signature-of> def; rules( Template : x -> def Template : sig -> def ) rename : TemplateDef(mod*, x, param1*, elem1*) -> <declare-def> TemplateDef(mod*, x, param2*, elem3*) with {| RenameId, RenameAction : param2* := <rename-all> param1* ; elem2* := <alltd(rename-action)> elem1* ; elem3* := <rename-all> elem2* |} rename local variables in template definition
  • 48. Template Definitions: Project is-page-def = ?TemplateDef([Page()],_,_,_) param-types = is-list; map(?Param(_,<id>)) param-types : TemplateDef(mod*, x, param*, elem*) -> <param-types> param* signature-of : TemplateDef(mod*, x, param*, elem*) -> (x, <param-types>param*) declaration-of : TemplateDef(mod*, x, param*, elem*) -> <signature-of; Template> declaration-of : Navigate(ref, elems) -> <declaration-of> ref declaration-of : PageRef(x, e*) -> <Template> x call-of : PageRef(x, e*) -> (x, e*)
  • 49. Template Definitions: Check Uniqueness check : def@TemplateDef(mod*, x, param*, elem*) -> (x, $[Multiple definitions for page '[x]']) where <is-page-def> def where require(<Template> x => def) check : def@TemplateDef(mod*, x, param*, elem*) -> (x, $[Multiple definitions for template with signature [sig]]) where not(is-page-def) where require(<declaration-of> def => def) where sig := <signature-of;pp-sig> def
  • 50. Checking Template/Page/Function Calls List of expressions consistent with list of types ★ zip Multiple possible error causes ★ call of non-existing definition ★ parameter arity mismatch ★ argument type mismatch Argument checking reusable
  • 51. Templates: Check Page References check : PageRef(x, e*) -> (x, $[Navigation to non-existing page]) where require(declaration-of) check : PageRef(x, e*) -> [(x, $[Navigation to template '[x]' (not a page)])] where def := <declaration-of> where require(<is-page-def> def) check : PageRef(x, e*) -> <check-args>
  • 52. Template Call: Project signature-of : Call(x, e*, elem*) -> (x, <map(type-of)> e*) call-of : Call(x, e*, elem*) -> (x, e*) declaration-of : Call(x, e*, elem*) -> <signature-of; Template> is-primitive-template = ?"input" <+ ?"output" <+ ?"form"
  • 53. Templates: Check Template Calls check : Call(x, e*, elem*) -> (x, $[Template '[x]' is not defined]) where not(<is-primitive-template> x) where require(<Template> x) check : Call(x, e*, elem*) -> (x, $[No definition for template with signature '[x]([<map(type-of);pp> e*])']) where not(<is-primitive-template> x) where <Template> x where require(declaration-of) constraint-warning : Call(x, e*, elem*) -> [(x, $[Page definition is used as template])] where def := <declaration-of> where require(not(<is-page-def> def)) check : Call(x, e*, elem*) -> <check-args>
  • 54. Checking Call Arguments check-args = !(<call-of>, <declaration-of>); (check-arg-types <+ check-args-arity) check-arg-types : ((f, e*), def) -> errors where errors := <zip; filter(check-arg); not(?[])> (e*, <param-types> def) check-arg : (e, t) -> (e, $[Argument of type '[<pp>t]' expected (not of type '[<pp>t2]')]) where t2 := <type-of> e where require(<eq>(t, t2)) check-args-arity : ((f, e*), def) -> [(f, $['[f]' expects [<int-to-string>l] arguments; [<int-to-string>k] provided])] with k := <length>e* with l := <param-types; length> def where require(<eq>(k, l))
  • 56. Reference Resolution Aiding program navigation ★ Hover-click on identifier to jump to declaration Reuse name resolution infrastructure
  • 57. Reference Resolution module nwl-References imports nwl-References.generated references reference _ : editor-resolve editor-resolve: (source, position, ast, path, fullpath) -> target where target := <compute-target> source
  • 58. From Use to Declaration editor-resolve: (SimpleType(type), position, ast, path, fullpath) -> target where Entity(target,_) := <EntityDeclaration> type editor-resolve: (ref@PageRef(x,e*), position, ast, path, fullpath) -> target where TemplateDef(_,target,_,_) := <declaration-of> ref
  • 59. Schedule Case 3 ★ Syntax definition & term rewriting ★ Deadline: May 4 Design 2 ★ Make a proposal (can be submitted separately) ★ Deadline: May 5 Lab this week ★ Finish Case 3 ★ Syntax for Design 2 Next ★ Lecture 10: code generation