SlideShare a Scribd company logo
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
Model-Driven Software Development - Static Analysis & Error Checking
Model-Driven Software Development - Static Analysis & Error Checking
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

More Related Content

What's hot (20)

PDF
Introduction to Python
UC San Diego
 
PDF
Fp in scala part 2
Hang Zhao
 
PPT
JBUG 11 - Scala For Java Programmers
Tikal Knowledge
 
PDF
Hidden Gems in Swift
Netguru
 
PDF
The Ring programming language version 1.5.2 book - Part 33 of 181
Mahmoud Samir Fayed
 
PPTX
Groovy vs Boilerplate and Ceremony Code
stasimus
 
PPTX
Groovy grails types, operators, objects
Husain Dalal
 
PDF
Python 2.5 reference card (2009)
gekiaruj
 
PDF
Python Cheat Sheet
Muthu Vinayagam
 
PDF
Scalaz 8: A Whole New Game
John De Goes
 
PDF
7 Habits For a More Functional Swift
Jason Larsen
 
PDF
Hammurabi
Mario Fusco
 
DOCX
What are arrays in java script
Miguel Silva Loureiro
 
PPT
For Beginners - C#
Snehal Harawande
 
PDF
A Prelude of Purity: Scaling Back ZIO
Jorge Vásquez
 
PDF
ECMA 入门
chencheng 云谦
 
PDF
The java language cheat sheet
anand_study
 
PDF
Introduction to ad-3.4, an automatic differentiation library in Haskell
nebuta
 
PDF
From java to kotlin beyond alt+shift+cmd+k - Droidcon italy
Fabio Collini
 
PDF
The Ring programming language version 1.5.4 book - Part 34 of 185
Mahmoud Samir Fayed
 
Introduction to Python
UC San Diego
 
Fp in scala part 2
Hang Zhao
 
JBUG 11 - Scala For Java Programmers
Tikal Knowledge
 
Hidden Gems in Swift
Netguru
 
The Ring programming language version 1.5.2 book - Part 33 of 181
Mahmoud Samir Fayed
 
Groovy vs Boilerplate and Ceremony Code
stasimus
 
Groovy grails types, operators, objects
Husain Dalal
 
Python 2.5 reference card (2009)
gekiaruj
 
Python Cheat Sheet
Muthu Vinayagam
 
Scalaz 8: A Whole New Game
John De Goes
 
7 Habits For a More Functional Swift
Jason Larsen
 
Hammurabi
Mario Fusco
 
What are arrays in java script
Miguel Silva Loureiro
 
For Beginners - C#
Snehal Harawande
 
A Prelude of Purity: Scaling Back ZIO
Jorge Vásquez
 
ECMA 入门
chencheng 云谦
 
The java language cheat sheet
anand_study
 
Introduction to ad-3.4, an automatic differentiation library in Haskell
nebuta
 
From java to kotlin beyond alt+shift+cmd+k - Droidcon italy
Fabio Collini
 
The Ring programming language version 1.5.4 book - Part 34 of 185
Mahmoud Samir Fayed
 

Similar to Model-Driven Software Development - Static Analysis & Error Checking (20)

PDF
Declare Your Language: Type Checking
Eelco Visser
 
PDF
09. haskell Context
Sebastian Rettig
 
PDF
Peyton jones-2009-fun with-type_functions-slide
Takayuki Muranushi
 
PDF
08. haskell Functions
Sebastian Rettig
 
PDF
Declarative Name Binding and Scope Rules
Eelco Visser
 
PDF
Ti1220 Lecture 7: Polymorphism
Eelco Visser
 
PDF
Cascon2011_5_rules+owl
ONTORULE Project
 
PDF
Scope Graphs: A fresh look at name binding in programming languages
Eelco Visser
 
PDF
A Language Designer’s Workbench. A one-stop shop for implementation and verif...
Eelco Visser
 
PDF
Declarative Type System Specification with Statix
Eelco Visser
 
PDF
Data type a la carte
Yun-Yan Chi
 
PDF
FYP Final Presentation
Jason Yeo Jie Shun
 
PDF
Rethinking Soot for Summary-Based Whole-Program Analysis
Dacong (Tony) Yan
 
PDF
Demand-Driven Context-Sensitive Alias Analysis for Java
Dacong (Tony) Yan
 
PDF
Declare Your Language: Name Resolution
Eelco Visser
 
PDF
Software analysis and testing
NishaVatwani
 
PDF
Why async and functional programming in PHP7 suck and how to get overr it?
Lucas Witold Adamus
 
PDF
NaBL: A Meta-Language for Declarative Name Binding and Scope Rules
Eelco Visser
 
PDF
Compiler Construction | Lecture 8 | Type Constraints
Eelco Visser
 
PPTX
ACM Distinguished Program: Cooperative Testing and Analysis: Human-Tool, Tool...
Tao Xie
 
Declare Your Language: Type Checking
Eelco Visser
 
09. haskell Context
Sebastian Rettig
 
Peyton jones-2009-fun with-type_functions-slide
Takayuki Muranushi
 
08. haskell Functions
Sebastian Rettig
 
Declarative Name Binding and Scope Rules
Eelco Visser
 
Ti1220 Lecture 7: Polymorphism
Eelco Visser
 
Cascon2011_5_rules+owl
ONTORULE Project
 
Scope Graphs: A fresh look at name binding in programming languages
Eelco Visser
 
A Language Designer’s Workbench. A one-stop shop for implementation and verif...
Eelco Visser
 
Declarative Type System Specification with Statix
Eelco Visser
 
Data type a la carte
Yun-Yan Chi
 
FYP Final Presentation
Jason Yeo Jie Shun
 
Rethinking Soot for Summary-Based Whole-Program Analysis
Dacong (Tony) Yan
 
Demand-Driven Context-Sensitive Alias Analysis for Java
Dacong (Tony) Yan
 
Declare Your Language: Name Resolution
Eelco Visser
 
Software analysis and testing
NishaVatwani
 
Why async and functional programming in PHP7 suck and how to get overr it?
Lucas Witold Adamus
 
NaBL: A Meta-Language for Declarative Name Binding and Scope Rules
Eelco Visser
 
Compiler Construction | Lecture 8 | Type Constraints
Eelco Visser
 
ACM Distinguished Program: Cooperative Testing and Analysis: Human-Tool, Tool...
Tao Xie
 
Ad

More from Eelco Visser (20)

PDF
CS4200 2019 | Lecture 5 | Transformation by Term Rewriting
Eelco Visser
 
PDF
CS4200 2019 | Lecture 4 | Syntactic Services
Eelco Visser
 
PDF
CS4200 2019 | Lecture 3 | Parsing
Eelco Visser
 
PDF
CS4200 2019 | Lecture 2 | syntax-definition
Eelco Visser
 
PDF
CS4200 2019 Lecture 1: Introduction
Eelco Visser
 
PDF
A Direct Semantics of Declarative Disambiguation Rules
Eelco Visser
 
PDF
Compiler Construction | Lecture 17 | Beyond Compiler Construction
Eelco Visser
 
PDF
Domain Specific Languages for Parallel Graph AnalytiX (PGX)
Eelco Visser
 
PDF
Compiler Construction | Lecture 15 | Memory Management
Eelco Visser
 
PDF
Compiler Construction | Lecture 14 | Interpreters
Eelco Visser
 
PDF
Compiler Construction | Lecture 13 | Code Generation
Eelco Visser
 
PDF
Compiler Construction | Lecture 12 | Virtual Machines
Eelco Visser
 
PDF
Compiler Construction | Lecture 11 | Monotone Frameworks
Eelco Visser
 
PDF
Compiler Construction | Lecture 10 | Data-Flow Analysis
Eelco Visser
 
PDF
Compiler Construction | Lecture 9 | Constraint Resolution
Eelco Visser
 
PDF
Compiler Construction | Lecture 7 | Type Checking
Eelco Visser
 
PDF
Compiler Construction | Lecture 6 | Introduction to Static Analysis
Eelco Visser
 
PDF
Compiler Construction | Lecture 5 | Transformation by Term Rewriting
Eelco Visser
 
PDF
Compiler Construction | Lecture 4 | Parsing
Eelco Visser
 
PDF
Compiler Construction | Lecture 3 | Syntactic Editor Services
Eelco Visser
 
CS4200 2019 | Lecture 5 | Transformation by Term Rewriting
Eelco Visser
 
CS4200 2019 | Lecture 4 | Syntactic Services
Eelco Visser
 
CS4200 2019 | Lecture 3 | Parsing
Eelco Visser
 
CS4200 2019 | Lecture 2 | syntax-definition
Eelco Visser
 
CS4200 2019 Lecture 1: Introduction
Eelco Visser
 
A Direct Semantics of Declarative Disambiguation Rules
Eelco Visser
 
Compiler Construction | Lecture 17 | Beyond Compiler Construction
Eelco Visser
 
Domain Specific Languages for Parallel Graph AnalytiX (PGX)
Eelco Visser
 
Compiler Construction | Lecture 15 | Memory Management
Eelco Visser
 
Compiler Construction | Lecture 14 | Interpreters
Eelco Visser
 
Compiler Construction | Lecture 13 | Code Generation
Eelco Visser
 
Compiler Construction | Lecture 12 | Virtual Machines
Eelco Visser
 
Compiler Construction | Lecture 11 | Monotone Frameworks
Eelco Visser
 
Compiler Construction | Lecture 10 | Data-Flow Analysis
Eelco Visser
 
Compiler Construction | Lecture 9 | Constraint Resolution
Eelco Visser
 
Compiler Construction | Lecture 7 | Type Checking
Eelco Visser
 
Compiler Construction | Lecture 6 | Introduction to Static Analysis
Eelco Visser
 
Compiler Construction | Lecture 5 | Transformation by Term Rewriting
Eelco Visser
 
Compiler Construction | Lecture 4 | Parsing
Eelco Visser
 
Compiler Construction | Lecture 3 | Syntactic Editor Services
Eelco Visser
 
Ad

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
  • 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