gisele 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. data/CHANGELOG.md +16 -1
  2. data/Gemfile +1 -0
  3. data/Gemfile.lock +2 -0
  4. data/gisele.gemspec +1 -0
  5. data/gisele.noespec +2 -1
  6. data/lib/gisele/command.rb +21 -6
  7. data/lib/gisele/language/ast/bool_and.rb +14 -0
  8. data/lib/gisele/language/ast/bool_expr.rb +14 -0
  9. data/lib/gisele/language/ast/bool_not.rb +14 -0
  10. data/lib/gisele/language/ast/bool_or.rb +14 -0
  11. data/lib/gisele/language/ast/elsif_clause.rb +14 -0
  12. data/lib/gisele/language/ast/helpers.rb +15 -9
  13. data/lib/gisele/language/ast/if_st.rb +14 -0
  14. data/lib/gisele/language/ast/node.rb +39 -3
  15. data/lib/gisele/language/ast/task_call_st.rb +14 -0
  16. data/lib/gisele/language/ast/var_ref.rb +14 -0
  17. data/lib/gisele/language/ast/when_clause.rb +14 -0
  18. data/lib/gisele/language/ast/while_st.rb +14 -0
  19. data/lib/gisele/language/ast.rb +2 -2
  20. data/lib/gisele/language/dot.yml +19 -0
  21. data/lib/gisele/language/sugar_removal.rb +30 -9
  22. data/lib/gisele/language/syntax/bool_expr.rb +14 -0
  23. data/lib/gisele/language/syntax/bool_lit.rb +1 -1
  24. data/lib/gisele/language/syntax/grammar.citrus +4 -3
  25. data/lib/gisele/language/syntax/node.rb +2 -1
  26. data/lib/gisele/language/to_graph.rb +119 -0
  27. data/lib/gisele/language.rb +4 -1
  28. data/lib/gisele/loader.rb +1 -0
  29. data/lib/gisele/version.rb +1 -1
  30. data/spec/command/main/gisele_ast_ruby.stdout +6 -3
  31. data/spec/command/main/gisele_graph.cmd +1 -0
  32. data/spec/command/main/gisele_graph.stdout +30 -0
  33. data/spec/command/main/gisele_help.stdout +10 -5
  34. data/spec/command/main/gisele_no_sugar.stdout +11 -5
  35. data/spec/command/main/gisele_version.stdout +1 -1
  36. data/spec/fixtures/tasks/complete.gis +18 -0
  37. data/spec/fixtures/tasks/simple.ast +57 -19
  38. data/spec/spec_helper.rb +8 -0
  39. data/spec/unit/language/ast/test_node.rb +22 -0
  40. data/spec/unit/language/sugar_removal/test_if_to_guarded_commands.rb +32 -12
  41. data/spec/unit/language/syntax/test_to_ast.rb +23 -11
  42. data/spec/unit/language/test_syntax.rb +5 -0
  43. data/spec/unit/language/test_to_graph.rb +10 -0
  44. metadata +50 -18
data/CHANGELOG.md CHANGED
@@ -1,4 +1,19 @@
1
- # 0.1.0 / FIX ME
1
+ # 0.2.0 / 2012-02-17
2
+
3
+ ## Enhancements
4
+
5
+ * A --graph option has been added to the main `gisele` shell command. It outputs a graph in
6
+ the graphviz/dot format representing a process as a box-and-arrow workflow.
7
+
8
+ ## Breaking changes
9
+
10
+ * Boolean literals (true, false) are now explicitly represented in boolean expressions,
11
+ under a :bool_lit AST node.
12
+ * All statements and clauses relying on boolean conditions (if_st, while_st, elsif_clause,
13
+ when_clause) have now an explicit :bool_expr node as first child. Previously, a subnode
14
+ of the boolean grammar was used.
15
+
16
+ # 0.1.0 / 2012-02-17
2
17
 
3
18
  ## Enhancements
4
19
 
data/Gemfile CHANGED
@@ -5,6 +5,7 @@ group :runtime do
5
5
  gem "epath", "~> 0.0.1"
6
6
  gem "quickl", "~> 0.4.3"
7
7
  gem "awesome_print", "~> 1.0"
8
+ gem "yargi", "~> 0.2.0"
8
9
  end
9
10
 
10
11
  group :development do
data/Gemfile.lock CHANGED
@@ -16,6 +16,7 @@ GEM
16
16
  diff-lcs (~> 1.1.2)
17
17
  rspec-mocks (2.8.0)
18
18
  wlang (0.10.2)
19
+ yargi (0.2.0)
19
20
 
20
21
  PLATFORMS
21
22
  ruby
@@ -29,3 +30,4 @@ DEPENDENCIES
29
30
  rake (~> 0.9.2)
30
31
  rspec (~> 2.8.0)
31
32
  wlang (~> 0.10.2)
33
+ yargi (~> 0.2.0)
data/gisele.gemspec CHANGED
@@ -131,6 +131,7 @@ Gem::Specification.new do |s|
131
131
  s.add_dependency("epath", "~> 0.0.1")
132
132
  s.add_dependency("quickl", "~> 0.4.3")
133
133
  s.add_dependency("awesome_print", "~> 1.0")
134
+ s.add_dependency("yargi", "~> 0.2.0")
134
135
 
135
136
  # The version of ruby required by this gem
136
137
  #
data/gisele.noespec CHANGED
@@ -12,7 +12,7 @@ variables:
12
12
  upper:
13
13
  Gisele
14
14
  version:
15
- 0.1.0
15
+ 0.2.0
16
16
  summary: |-
17
17
  Gisele is a Process Analyzer Toolset
18
18
  description: |-
@@ -29,6 +29,7 @@ variables:
29
29
  - {name: epath, version: "~> 0.0.1", groups: [runtime]}
30
30
  - {name: quickl, version: "~> 0.4.3", groups: [runtime]}
31
31
  - {name: awesome_print, version: "~> 1.0", groups: [runtime]}
32
+ - {name: yargi, version: "~> 0.2.0", groups: [runtime]}
32
33
  #
33
34
  - {name: rake, version: "~> 0.9.2", groups: [development]}
34
35
  - {name: bundler, version: "~> 1.0", groups: [development]}
@@ -5,7 +5,7 @@ module Gisele
5
5
  #
6
6
  # SYNOPSIS
7
7
  # gisele [--version] [--help]
8
- # gisele [--ast] PROCESS_FILE
8
+ # gisele [--ast | --graph] PROCESS_FILE
9
9
  #
10
10
  # OPTIONS
11
11
  # #{summarized_options}
@@ -14,14 +14,18 @@ module Gisele
14
14
  # The Gisele process analyzer toolset provides tools and technique to model and analyze
15
15
  # complex process models such as care processes.
16
16
  #
17
- # When --ast is used, the command parses a process file and prints its Abstract Syntax
17
+ # When --no-sugar is specified, syntactic sugar is first removed before making any other
18
+ # transformation. For now, this rewrites all `if` statements as explicit `case` guarded
19
+ # commands.
20
+ #
21
+ # When --ast is used, the command parses the process file and prints its Abstract Syntax
18
22
  # Tree (AST) on standard output. By default, this option prints the AST for manual
19
23
  # debugging, that is with colors and extra information. Use --ast=ruby to get a ruby
20
24
  # array for automatic processing.
21
25
  #
22
- # When --no-sugar is specified, syntactic sugar is first removed before making any other
23
- # transformation. For now, this rewrites all `if` statements as explicit `case` guarded
24
- # commands.
26
+ # When --graph is used, the command parses the process file. It then converts the AST into
27
+ # a directed graph representing the process as a box-and-arrow workflow and outputs it on
28
+ # standard output. For now, the only output format available is dot (from graphviz).
25
29
  #
26
30
  class Gisele::Command < Quickl::Command(__FILE__, __LINE__)
27
31
 
@@ -35,6 +39,10 @@ module Gisele
35
39
  opt.on('--no-sugar', 'Apply syntactic sugar removal') do
36
40
  @sugar = false
37
41
  end
42
+ @print_graph = nil
43
+ opt.on('--graph=[MODE]', 'Converts and print a graph (dot)') do |value|
44
+ @print_graph = (value || "dot").to_sym
45
+ end
38
46
  opt.on_tail('--help', "Show this help message") do
39
47
  raise Quickl::Help
40
48
  end
@@ -52,7 +60,9 @@ module Gisele
52
60
 
53
61
  ast = Gisele.ast(file)
54
62
  ast = Gisele::Language::SugarRemoval.new.call(ast) unless @sugar
63
+
55
64
  print_ast(ast, @print_ast) if @print_ast
65
+ print_graph(ast, @print_graph) if @print_graph
56
66
  end
57
67
 
58
68
  private
@@ -68,5 +78,10 @@ module Gisele
68
78
  ap ast, options
69
79
  end
70
80
 
71
- end # class Command
81
+ def print_graph(ast, option)
82
+ graph = Gisele::Language::ToGraph.new.call(ast)
83
+ puts graph.to_dot
84
+ end
85
+
86
+ end # class Command
72
87
  end # module Gisele
@@ -0,0 +1,14 @@
1
+ module Gisele
2
+ module Language
3
+ module AST
4
+ module BoolAnd
5
+ include Node
6
+
7
+ def label
8
+ markers[:match] ? markers[:match].to_s : "(#{self[1].label} and #{self[2].label})"
9
+ end
10
+
11
+ end # module BoolAnd
12
+ end # module AST
13
+ end # module Language
14
+ end # module Gisele
@@ -0,0 +1,14 @@
1
+ module Gisele
2
+ module Language
3
+ module AST
4
+ module BoolExpr
5
+ include Node
6
+
7
+ def label
8
+ markers[:match] ? markers[:match].to_s : last.label
9
+ end
10
+
11
+ end # module BoolExpr
12
+ end # module AST
13
+ end # module Language
14
+ end # module Gisele
@@ -0,0 +1,14 @@
1
+ module Gisele
2
+ module Language
3
+ module AST
4
+ module BoolNot
5
+ include Node
6
+
7
+ def label
8
+ markers[:match] ? markers[:match].to_s : "not(#{last.label})"
9
+ end
10
+
11
+ end # module BoolNot
12
+ end # module AST
13
+ end # module Language
14
+ end # module Gisele
@@ -0,0 +1,14 @@
1
+ module Gisele
2
+ module Language
3
+ module AST
4
+ module BoolOr
5
+ include Node
6
+
7
+ def label
8
+ markers[:match] ? markers[:match].to_s : "(#{self[1].label} or #{self[2].label})"
9
+ end
10
+
11
+ end # module BoolOr
12
+ end # module AST
13
+ end # module Language
14
+ end # module Gisele
@@ -0,0 +1,14 @@
1
+ module Gisele
2
+ module Language
3
+ module AST
4
+ module ElsifClause
5
+ include Node
6
+
7
+ def label
8
+ self[1].label
9
+ end
10
+
11
+ end # module ElsifClause
12
+ end # module AST
13
+ end # module Language
14
+ end # module Gisele
@@ -3,17 +3,17 @@ module Gisele
3
3
  module AST
4
4
  module Helpers
5
5
 
6
- def ast(arg)
7
- return node(arg) if looks_a_node?(arg)
8
- Syntax.ast(arg)
6
+ def ast(arg, markers = {})
7
+ return node(arg, markers) if looks_a_node?(arg)
8
+ ast(Syntax.ast(arg), markers)
9
9
  end
10
10
 
11
- def node(arg)
11
+ def node(arg, markers = {})
12
12
  return arg if arg.is_a?(Node)
13
13
  unless looks_a_node?(arg)
14
14
  raise ArgumentError, "Array expected, #{arg.inspect} found."
15
15
  end
16
- extend_node(arg).tap do |node|
16
+ extend_node(arg, markers).tap do |node|
17
17
  node.children.each{|c| node(c) if looks_a_node?(c)}
18
18
  end
19
19
  end
@@ -24,10 +24,16 @@ module Gisele
24
24
  arg.is_a?(Node) or (arg.is_a?(Array) and arg.first.is_a?(Symbol))
25
25
  end
26
26
 
27
- def extend_node(arg)
28
- modname = Language.rule2mod(arg.first)
29
- mod = AST.const_get(modname) rescue Node
30
- arg.extend(mod)
27
+ def extend_node(arg, markers)
28
+ mod = ast_module(arg)
29
+ arg.extend(mod).tap do |node|
30
+ node.markers = markers
31
+ end
32
+ end
33
+
34
+ def ast_module(node)
35
+ modname = Language.rule2mod(node.first)
36
+ AST.const_get(modname) rescue Node
31
37
  end
32
38
 
33
39
  extend(self)
@@ -0,0 +1,14 @@
1
+ module Gisele
2
+ module Language
3
+ module AST
4
+ module IfSt
5
+ include Node
6
+
7
+ def label
8
+ self[1].label
9
+ end
10
+
11
+ end # module IfSt
12
+ end # module AST
13
+ end # module Language
14
+ end # module Gisele
@@ -3,6 +3,16 @@ module Gisele
3
3
  module AST
4
4
  module Node
5
5
 
6
+ # Returns the node markers
7
+ def markers
8
+ @markers ||= {}
9
+ end
10
+
11
+ # Sets node markers
12
+ def markers=(markers)
13
+ @markers = markers
14
+ end
15
+
6
16
  # Returns the rule name, that is, the first Symbol element
7
17
  # of the node array.
8
18
  #
@@ -24,6 +34,11 @@ module Gisele
24
34
  self[1..-1]
25
35
  end
26
36
 
37
+ # Returns the associated ast_module
38
+ def ast_module
39
+ AST::Helpers.send(:ast_module, self)
40
+ end
41
+
27
42
  # Applies copy-and-transform to this node.
28
43
  #
29
44
  # Example:
@@ -34,7 +49,7 @@ module Gisele
34
49
  # # => [:something, ...]
35
50
  #
36
51
  def copy(&block)
37
- base = AST.node([rule_name])
52
+ base = AST.node([rule_name], markers.dup)
38
53
  children.inject(base, &block)
39
54
  end
40
55
 
@@ -44,11 +59,32 @@ module Gisele
44
59
  # will correctly be applied to the duplicated array.
45
60
  #
46
61
  def dup
47
- AST.node(super)
62
+ AST.node(super, markers.dup)
63
+ end
64
+
65
+ # Returns a label for this AST node
66
+ def label
67
+ ""
68
+ end
69
+
70
+ # Returns attributes to use for dot printing
71
+ def dot_attributes
72
+ attrs = Language::DOT_ATTRIBUTES[rule_name.to_s] || {}
73
+ attrs.merge(:label => label)
48
74
  end
49
75
 
50
76
  end # module Node
51
77
  end # module AST
52
78
  end # module Language
53
79
  end # module Gisele
54
- require_relative 'unit'
80
+ require_relative 'unit'
81
+ require_relative 'task_call_st'
82
+ require_relative 'while_st'
83
+ require_relative 'if_st'
84
+ require_relative 'elsif_clause'
85
+ require_relative 'when_clause'
86
+ require_relative 'bool_expr'
87
+ require_relative 'bool_and'
88
+ require_relative 'bool_or'
89
+ require_relative 'bool_not'
90
+ require_relative 'var_ref'
@@ -0,0 +1,14 @@
1
+ module Gisele
2
+ module Language
3
+ module AST
4
+ module TaskCallSt
5
+ include Node
6
+
7
+ def label
8
+ last.to_s
9
+ end
10
+
11
+ end # module TaskCallSt
12
+ end # module AST
13
+ end # module Language
14
+ end # module Gisele
@@ -0,0 +1,14 @@
1
+ module Gisele
2
+ module Language
3
+ module AST
4
+ module VarRef
5
+ include Node
6
+
7
+ def label
8
+ last.to_s
9
+ end
10
+
11
+ end # module BoolNot
12
+ end # module AST
13
+ end # module Language
14
+ end # module Gisele
@@ -0,0 +1,14 @@
1
+ module Gisele
2
+ module Language
3
+ module AST
4
+ module WhenClause
5
+ include Node
6
+
7
+ def label
8
+ self[1].label
9
+ end
10
+
11
+ end # module WhenClause
12
+ end # module AST
13
+ end # module Language
14
+ end # module Gisele
@@ -0,0 +1,14 @@
1
+ module Gisele
2
+ module Language
3
+ module AST
4
+ module WhileSt
5
+ include Node
6
+
7
+ def label
8
+ self[1].label
9
+ end
10
+
11
+ end # module WhileSt
12
+ end # module AST
13
+ end # module Language
14
+ end # module Gisele
@@ -2,8 +2,8 @@ module Gisele
2
2
  module Language
3
3
  module AST
4
4
 
5
- def node(arg)
6
- AST::Helpers.node(arg)
5
+ def node(arg, markers = {})
6
+ AST::Helpers.node(arg, markers)
7
7
  end
8
8
  module_function :node
9
9
 
@@ -0,0 +1,19 @@
1
+ task_refinement:
2
+ shape: circle
3
+ style: filled
4
+ fillcolor: black
5
+ fixed: true
6
+ width: 0.1
7
+ task_call_st:
8
+ shape: box
9
+ while_st:
10
+ shape: diamond
11
+ if_st:
12
+ shape: diamond
13
+ case_st:
14
+ shape: diamond
15
+ par_st:
16
+ shape: box
17
+ height: 0.1
18
+ style: filled
19
+ fillcolor: black
@@ -15,8 +15,17 @@ module Gisele
15
15
 
16
16
  def on_if_st(node)
17
17
  condition, dost, *clauses = node.children
18
- base = [:case_st, [:when_clause, condition, @main.call(dost)] ]
19
- @condition = negate(condition)
18
+
19
+ # create case_st with same markers as the if_st
20
+ when_clause = [:when_clause, condition, @main.call(dost)]
21
+ when_clause = node(when_clause, node.markers.dup)
22
+ base = [:case_st, when_clause]
23
+ base = node(base, node.markers.dup)
24
+
25
+ # this is the condition for elsif clauses
26
+ @condition = negate(condition.last)
27
+
28
+ # make injection now
20
29
  clauses.inject base do |memo,clause|
21
30
  memo << call(clause)
22
31
  end
@@ -24,17 +33,29 @@ module Gisele
24
33
 
25
34
  def on_elsif_clause(node)
26
35
  condition, dost, = node.children
27
- prev, @condition = @condition, [:bool_and, negate(condition), @condition]
28
- [:when_clause,
29
- [:bool_and, condition, prev],
30
- @main.call(dost)]
36
+
37
+ # install new conditions for me and next elsif clauses
38
+ condition = condition.last
39
+ previous = @condition
40
+ @condition = [:bool_and, negate(condition), @condition]
41
+
42
+ # convert elsif to when and keep the markers
43
+ base = \
44
+ [:when_clause,
45
+ [:bool_expr, [:bool_and, condition, previous]],
46
+ @main.call(dost) ]
47
+ node(base, node.markers.dup)
31
48
  end
32
49
 
33
50
  def on_else_clause(node)
34
51
  dost, = node.children
35
- [:when_clause,
36
- @condition,
37
- @main.call(dost)]
52
+
53
+ # convert else to when and keep the markers
54
+ base = \
55
+ [:when_clause,
56
+ [:bool_expr, @condition],
57
+ @main.call(dost)]
58
+ node(base, node.markers.dup)
38
59
  end
39
60
 
40
61
  private
@@ -0,0 +1,14 @@
1
+ module Gisele
2
+ module Language
3
+ module Syntax
4
+ module BoolExpr
5
+ include Node
6
+
7
+ def _to_ast
8
+ [:bool_expr, captures[:theexpr].first.to_ast]
9
+ end
10
+
11
+ end # module BoolExpr
12
+ end # module Syntax
13
+ end # module Language
14
+ end # module Gisele
@@ -5,7 +5,7 @@ module Gisele
5
5
  include Node
6
6
 
7
7
  def _to_ast
8
- captures[:boolean_literal].first.value
8
+ [:bool_lit, strip == "true"]
9
9
  end
10
10
 
11
11
  end # module BoolLit
@@ -90,7 +90,8 @@ grammar Gisele::Language::Syntax::Grammar
90
90
  ### Boolean expressions
91
91
 
92
92
  rule bool_expr
93
- bool_or
93
+ (spacing theexpr:bool_or)
94
+ <Gisele::Language::Syntax::BoolExpr>
94
95
  end
95
96
 
96
97
  rule bool_or
@@ -112,11 +113,11 @@ grammar Gisele::Language::Syntax::Grammar
112
113
  end
113
114
 
114
115
  rule bool_term
115
- bool_paren | boolean_literal | bool_varref
116
+ bool_paren | bool_lit | bool_varref
116
117
  end
117
118
 
118
119
  rule bool_paren
119
- ('(' spacing expr:bool_expr spacing ')')
120
+ ('(' spacing expr:bool_or spacing ')')
120
121
  <Gisele::Language::Syntax::BoolParen>
121
122
  end
122
123
 
@@ -4,7 +4,7 @@ module Gisele
4
4
  module Node
5
5
 
6
6
  def to_ast
7
- Language::AST.node(_to_ast)
7
+ Language::AST.node(_to_ast, {:match => self})
8
8
  end
9
9
 
10
10
  end # module Node
@@ -20,6 +20,7 @@ require_relative 'bool_paren'
20
20
  require_relative 'bool_not'
21
21
  require_relative 'bool_and'
22
22
  require_relative 'bool_or'
23
+ require_relative 'bool_expr'
23
24
  require_relative 'st_list'
24
25
  require_relative 'implicit_seq_st'
25
26
  require_relative 'task_call_st'
@@ -0,0 +1,119 @@
1
+ module Gisele
2
+ module Language
3
+ class ToGraph < Transformer
4
+ module Connector; end
5
+
6
+ def recurse_on_last(node)
7
+ call(node.last)
8
+ end
9
+ alias :on_unit :recurse_on_last
10
+
11
+ def on_task_def(node)
12
+ @graph = Yargi::Digraph.new
13
+ call(SugarRemoval.new.call(node.last))
14
+ @graph.vertices(Connector).each do |vertex|
15
+ next unless vertex.out_edges.size == 1
16
+ target = vertex.out_edges.first.target
17
+ @graph.reconnect(vertex.in_edges, nil, target)
18
+ @graph.remove_vertex(vertex)
19
+ end
20
+ @graph
21
+ end
22
+
23
+ def on_task_refinement(node)
24
+ entry, exit = add_vertex(node), add_vertex(node)
25
+ c_entry, c_exit = call(node.last)
26
+ connect(entry, c_entry)
27
+ connect(c_exit, exit)
28
+ [entry, exit]
29
+ end
30
+
31
+ def on_seq_st(node)
32
+ mine = entry_and_exit(node)
33
+ current = mine.first
34
+ node.children.each do |child|
35
+ c_entry, c_exit = call(child)
36
+ connect(current, c_entry)
37
+ current = c_exit
38
+ end
39
+ connect(current, mine.last)
40
+ mine
41
+ end
42
+
43
+ def on_par_st(node)
44
+ entry, exit = add_vertex(node), add_vertex(node)
45
+ node.children.each do |child|
46
+ c_entry, c_exit = call(child)
47
+ connect(entry, c_entry)
48
+ connect(c_exit, exit)
49
+ end
50
+ [entry, exit]
51
+ end
52
+
53
+ def on_case_st(node)
54
+ entry, exit = entry_and_exit(node)
55
+
56
+ diamond = add_vertex(node)
57
+ connect(entry, diamond)
58
+
59
+ node.children.each do |when_clause|
60
+ c_entry, c_exit = call(when_clause.last)
61
+ connect(diamond, c_entry, when_clause)
62
+ connect(c_exit, exit)
63
+ end
64
+
65
+ [entry, exit]
66
+ end
67
+
68
+
69
+ def on_while_st(node)
70
+ cond, dost, = node.children
71
+
72
+ entry, exit = entry_and_exit(node)
73
+
74
+ diamond = add_vertex(node)
75
+ connect(entry, diamond)
76
+
77
+ c_entry, c_exit = call(node.last)
78
+
79
+ connect(diamond, exit, false_ast_node)
80
+ connect(diamond, c_entry, true_ast_node)
81
+ connect(c_exit, diamond)
82
+
83
+ [entry, exit]
84
+ end
85
+
86
+ def on_task_call_st(node)
87
+ entry, exit = entry_and_exit(node)
88
+ task = add_vertex(node)
89
+ connect(entry, task)
90
+ connect(task, exit)
91
+ [entry, exit]
92
+ end
93
+
94
+ private
95
+
96
+ def add_vertex(node)
97
+ @graph.add_vertex(node.dot_attributes)
98
+ end
99
+
100
+ def entry_and_exit(node, tag = Connector)
101
+ @graph.add_n_vertices(2, tag)
102
+ end
103
+
104
+ def connect(source, target, node = nil)
105
+ marks = node.nil? ? {} : node.dot_attributes
106
+ @graph.connect(source, target, marks)
107
+ end
108
+
109
+ def false_ast_node
110
+ Syntax.ast("false", :root => :bool_expr)
111
+ end
112
+
113
+ def true_ast_node
114
+ Syntax.ast("true", :root => :bool_expr)
115
+ end
116
+
117
+ end # class SugarRemoval
118
+ end # module Language
119
+ end # module Gisele