gisele 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. data/CHANGELOG.md +39 -1
  2. data/gisele.noespec +1 -1
  3. data/lib/gisele/command.rb +13 -4
  4. data/lib/gisele/errors.rb +21 -0
  5. data/lib/gisele/language/ast/helpers.rb +37 -0
  6. data/lib/gisele/language/ast/node.rb +54 -0
  7. data/lib/gisele/language/ast/unit.rb +10 -0
  8. data/lib/gisele/language/ast.rb +14 -0
  9. data/lib/gisele/language/sugar_removal.rb +53 -0
  10. data/lib/gisele/language/syntax/bool_and.rb +14 -0
  11. data/lib/gisele/language/syntax/bool_lit.rb +14 -0
  12. data/lib/gisele/language/syntax/bool_not.rb +14 -0
  13. data/lib/gisele/language/syntax/bool_or.rb +14 -0
  14. data/lib/gisele/language/syntax/bool_paren.rb +14 -0
  15. data/lib/gisele/language/syntax/else_clause.rb +14 -0
  16. data/lib/gisele/language/syntax/elsif_clause.rb +16 -0
  17. data/lib/gisele/language/syntax/event_set.rb +15 -0
  18. data/lib/gisele/language/syntax/fluent_def.rb +18 -0
  19. data/lib/gisele/language/syntax/grammar.citrus +202 -0
  20. data/lib/gisele/language/syntax/if_st.rb +18 -0
  21. data/lib/gisele/language/syntax/implicit_seq_st.rb +16 -0
  22. data/lib/gisele/language/syntax/node.rb +35 -0
  23. data/lib/gisele/language/syntax/par_st.rb +14 -0
  24. data/lib/gisele/language/syntax/seq_st.rb +14 -0
  25. data/lib/gisele/language/syntax/st_list.rb +14 -0
  26. data/lib/gisele/language/syntax/task_call_st.rb +14 -0
  27. data/lib/gisele/language/syntax/task_def.rb +17 -0
  28. data/lib/gisele/language/syntax/task_refinement.rb +15 -0
  29. data/lib/gisele/language/syntax/task_signature.rb +15 -0
  30. data/lib/gisele/language/syntax/trackvar_def.rb +19 -0
  31. data/lib/gisele/language/syntax/unit.rb +14 -0
  32. data/lib/gisele/language/syntax/var_ref.rb +14 -0
  33. data/lib/gisele/language/syntax/while_st.rb +16 -0
  34. data/lib/gisele/language/syntax.rb +29 -0
  35. data/lib/gisele/language/transformer.rb +38 -0
  36. data/lib/gisele/language.rb +15 -1
  37. data/lib/gisele/version.rb +2 -2
  38. data/lib/gisele.rb +7 -1
  39. data/spec/command/main/gisele_ast_ruby.stdout +38 -28
  40. data/spec/command/main/gisele_help.stdout +5 -0
  41. data/spec/command/main/gisele_no_sugar.cmd +1 -0
  42. data/spec/command/main/gisele_no_sugar.stdout +61 -0
  43. data/spec/fixtures/tasks/simple.ast +18 -14
  44. data/spec/fixtures/tasks/simple.gis +2 -0
  45. data/spec/spec_helper.rb +3 -3
  46. data/spec/test_examples.rb +3 -3
  47. data/spec/unit/language/ast/test_node.rb +61 -0
  48. data/spec/unit/language/sugar_removal/test_if_to_guarded_commands.rb +90 -0
  49. data/spec/unit/language/{test_grammar.rb → syntax/test_grammar.rb} +18 -30
  50. data/spec/unit/language/syntax/test_to_ast.rb +245 -0
  51. data/spec/unit/language/test_ast.rb +21 -247
  52. data/spec/unit/language/test_syntax.rb +48 -0
  53. data/spec/unit/language/test_transformer.rb +68 -0
  54. data/spec/unit/test_language.rb +35 -0
  55. metadata +69 -25
  56. data/lib/gisele/language/grammar.citrus +0 -246
  57. data/lib/gisele/language/parser.rb +0 -30
  58. data/spec/unit/language/test_parser.rb +0 -27
data/CHANGELOG.md CHANGED
@@ -1,4 +1,42 @@
1
- # 0.0.1 / FIX ME
1
+ # 0.1.0 / FIX ME
2
+
3
+ ## Enhancements
4
+
5
+ * The main `gisele` command now accepts a --no-sugar option that removes syntactic
6
+ sugar. This option is limited to the rewriting of `if` statements as guarded `case`
7
+ commands for now. Additional rewriting could be added in the future.
8
+ * All AST nodes (obtained via `Gisele.ast` or similar) now include the module
9
+ `Gisele::Language::AST::Node` which contains a few utilities.
10
+
11
+ ## Breaking changes
12
+
13
+ * The language package has been reorganized and is now considered as belonging to
14
+ the private API. Further changes there will therefore not b considered as Breaking
15
+ changes in the future (expect the structure of the AST, of course).
16
+ The `Gisele.parse` and `Gisele.ast` methods belong to the public API and are therefore
17
+ the way to (parse / get an AST) from a process file / source.
18
+
19
+ * The top AST element of a process file is always a :unit. The latter may contain
20
+ one ore more task definitions. Import/include nodes will probably be added later
21
+ and authorized at the beginning of the file.
22
+
23
+ * The following syntax nodes have been renamed:
24
+ :varref -> :var_ref
25
+ :or -> :bool_or
26
+ :and -> :bool_and
27
+ :not -> :bool_not
28
+ :if -> :if_st
29
+ :else -> :else_clause
30
+ :elsif -> :elsif_clause
31
+ :while -> :while_st
32
+ :seq -> :seq_st
33
+ :par -> :par_st
34
+ :task_call -> :task_call_st
35
+ :task -> :task_def
36
+ :signature -> :task_signature
37
+ :refinement -> :task_refinement
38
+
39
+ # 0.0.1 / 2012-02-16
2
40
 
3
41
  * Enhancements
4
42
 
data/gisele.noespec CHANGED
@@ -12,7 +12,7 @@ variables:
12
12
  upper:
13
13
  Gisele
14
14
  version:
15
- 0.0.1
15
+ 0.1.0
16
16
  summary: |-
17
17
  Gisele is a Process Analyzer Toolset
18
18
  description: |-
@@ -19,13 +19,21 @@ module Gisele
19
19
  # debugging, that is with colors and extra information. Use --ast=ruby to get a ruby
20
20
  # array for automatic processing.
21
21
  #
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.
25
+ #
22
26
  class Gisele::Command < Quickl::Command(__FILE__, __LINE__)
23
27
 
24
28
  # Install options
25
29
  options do |opt|
26
- @ast = nil
30
+ @print_ast = nil
27
31
  opt.on('--ast=[MODE]', 'Prints the process abstract syntax tree (debug,ruby)') do |value|
28
- @ast = (value || "debug").to_sym
32
+ @print_ast = (value || "debug").to_sym
33
+ end
34
+ @sugar = true
35
+ opt.on('--no-sugar', 'Apply syntactic sugar removal') do
36
+ @sugar = false
29
37
  end
30
38
  opt.on_tail('--help', "Show this help message") do
31
39
  raise Quickl::Help
@@ -42,8 +50,9 @@ module Gisele
42
50
  raise Quickl::IOAccessError, "File does not exists: #{file}"
43
51
  end
44
52
 
45
- parsed = Gisele::Language::Parser.parse(file)
46
- print_ast(parsed, @ast) if @ast
53
+ ast = Gisele.ast(file)
54
+ ast = Gisele::Language::SugarRemoval.new.call(ast) unless @sugar
55
+ print_ast(ast, @print_ast) if @print_ast
47
56
  end
48
57
 
49
58
  private
@@ -0,0 +1,21 @@
1
+ module Gisele
2
+
3
+ class Error < StandardError
4
+ attr_reader :cause
5
+ def initialize(msg, cause = $!)
6
+ super(msg)
7
+ @cause = cause
8
+ end
9
+ end
10
+
11
+ # Internal errors certainly denote bugs in the implementation.
12
+ # They are typically raised when a precondition is violated.
13
+ class InternalError < Error
14
+ end
15
+
16
+ # Raised when an unexpected node is encountered in an AST-driven
17
+ # transformation.
18
+ class UnexpectedNodeError < InternalError
19
+ end
20
+
21
+ end # module Gisele
@@ -0,0 +1,37 @@
1
+ module Gisele
2
+ module Language
3
+ module AST
4
+ module Helpers
5
+
6
+ def ast(arg)
7
+ return node(arg) if looks_a_node?(arg)
8
+ Syntax.ast(arg)
9
+ end
10
+
11
+ def node(arg)
12
+ return arg if arg.is_a?(Node)
13
+ unless looks_a_node?(arg)
14
+ raise ArgumentError, "Array expected, #{arg.inspect} found."
15
+ end
16
+ extend_node(arg).tap do |node|
17
+ node.children.each{|c| node(c) if looks_a_node?(c)}
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def looks_a_node?(arg)
24
+ arg.is_a?(Node) or (arg.is_a?(Array) and arg.first.is_a?(Symbol))
25
+ end
26
+
27
+ def extend_node(arg)
28
+ modname = Language.rule2mod(arg.first)
29
+ mod = AST.const_get(modname) rescue Node
30
+ arg.extend(mod)
31
+ end
32
+
33
+ extend(self)
34
+ end # module Helpers
35
+ end # module AST
36
+ end # module Language
37
+ end # module Gisele
@@ -0,0 +1,54 @@
1
+ module Gisele
2
+ module Language
3
+ module AST
4
+ module Node
5
+
6
+ # Returns the rule name, that is, the first Symbol element
7
+ # of the node array.
8
+ #
9
+ # Example:
10
+ # file = ... path to a .gis file ...
11
+ # Gisele.ast(file).rule_name
12
+ # # => :unit
13
+ #
14
+ def rule_name
15
+ first
16
+ end
17
+
18
+ # Returns the children of this node.
19
+ #
20
+ # Children are defined as all but the rule name in the underlying
21
+ # array.
22
+ #
23
+ def children
24
+ self[1..-1]
25
+ end
26
+
27
+ # Applies copy-and-transform to this node.
28
+ #
29
+ # Example:
30
+ # node = AST.node([:something, "world", [:subnode ...]])
31
+ # node.copy do |base,child|
32
+ # base << ... make something with child ...
33
+ # end
34
+ # # => [:something, ...]
35
+ #
36
+ def copy(&block)
37
+ base = AST.node([rule_name])
38
+ children.inject(base, &block)
39
+ end
40
+
41
+ # Duplicates this node.
42
+ #
43
+ # This method ensures that the node marking through modules
44
+ # will correctly be applied to the duplicated array.
45
+ #
46
+ def dup
47
+ AST.node(super)
48
+ end
49
+
50
+ end # module Node
51
+ end # module AST
52
+ end # module Language
53
+ end # module Gisele
54
+ require_relative 'unit'
@@ -0,0 +1,10 @@
1
+ module Gisele
2
+ module Language
3
+ module AST
4
+ module Unit
5
+ include Node
6
+
7
+ end # module Node
8
+ end # module AST
9
+ end # module Language
10
+ end # module Gisele
@@ -0,0 +1,14 @@
1
+ module Gisele
2
+ module Language
3
+ module AST
4
+
5
+ def node(arg)
6
+ AST::Helpers.node(arg)
7
+ end
8
+ module_function :node
9
+
10
+ end # module AST
11
+ end # module Language
12
+ end # module Gisele
13
+ require_relative 'ast/helpers'
14
+ require_relative 'ast/node'
@@ -0,0 +1,53 @@
1
+ module Gisele
2
+ module Language
3
+ class SugarRemoval < Transformer
4
+ alias :on_missing :copy_and_applyall
5
+
6
+ def on_if_st(node)
7
+ IfToGuardedCommands.new(self).call(node)
8
+ end
9
+
10
+ class IfToGuardedCommands < Transformer
11
+
12
+ def initialize(main)
13
+ @main = main
14
+ end
15
+
16
+ def on_if_st(node)
17
+ condition, dost, *clauses = node.children
18
+ base = [:case_st, [:when_clause, condition, @main.call(dost)] ]
19
+ @condition = negate(condition)
20
+ clauses.inject base do |memo,clause|
21
+ memo << call(clause)
22
+ end
23
+ end
24
+
25
+ def on_elsif_clause(node)
26
+ 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)]
31
+ end
32
+
33
+ def on_else_clause(node)
34
+ dost, = node.children
35
+ [:when_clause,
36
+ @condition,
37
+ @main.call(dost)]
38
+ end
39
+
40
+ private
41
+
42
+ def negate(cond)
43
+ if cond.rule_name == :bool_not
44
+ cond.last
45
+ else
46
+ [:bool_not, cond]
47
+ end
48
+ end
49
+
50
+ end # class IfToGuardedCommands
51
+ end # class SugarRemoval
52
+ end # module Language
53
+ end # module Gisele
@@ -0,0 +1,14 @@
1
+ module Gisele
2
+ module Language
3
+ module Syntax
4
+ module BoolAnd
5
+ include Node
6
+
7
+ def _to_ast
8
+ [:bool_and, left.to_ast, right.to_ast]
9
+ end
10
+
11
+ end # module BoolAnd
12
+ end # module Syntax
13
+ end # module Language
14
+ end # module Gisele
@@ -0,0 +1,14 @@
1
+ module Gisele
2
+ module Language
3
+ module Syntax
4
+ module BoolLit
5
+ include Node
6
+
7
+ def _to_ast
8
+ captures[:boolean_literal].first.value
9
+ end
10
+
11
+ end # module BoolLit
12
+ end # module Syntax
13
+ end # module Language
14
+ end # module Gisele
@@ -0,0 +1,14 @@
1
+ module Gisele
2
+ module Language
3
+ module Syntax
4
+ module BoolNot
5
+ include Node
6
+
7
+ def _to_ast
8
+ [:bool_not, captures[:expr].first.to_ast]
9
+ end
10
+
11
+ end # module BoolParen
12
+ end # module Syntax
13
+ end # module Language
14
+ end # module Gisele
@@ -0,0 +1,14 @@
1
+ module Gisele
2
+ module Language
3
+ module Syntax
4
+ module BoolOr
5
+ include Node
6
+
7
+ def _to_ast
8
+ [:bool_or, left.to_ast, right.to_ast]
9
+ end
10
+
11
+ end # module BoolOr
12
+ end # module Syntax
13
+ end # module Language
14
+ end # module Gisele
@@ -0,0 +1,14 @@
1
+ module Gisele
2
+ module Language
3
+ module Syntax
4
+ module BoolParen
5
+ include Node
6
+
7
+ def _to_ast
8
+ captures[:expr].first.to_ast
9
+ end
10
+
11
+ end # module BoolParen
12
+ end # module Syntax
13
+ end # module Language
14
+ end # module Gisele
@@ -0,0 +1,14 @@
1
+ module Gisele
2
+ module Language
3
+ module Syntax
4
+ module ElseClause
5
+ include Node
6
+
7
+ def _to_ast
8
+ [:else_clause, captures[:process_statement].first.to_ast]
9
+ end
10
+
11
+ end # module ElseClause
12
+ end # module Syntax
13
+ end # module Language
14
+ end # module Gisele
@@ -0,0 +1,16 @@
1
+ module Gisele
2
+ module Language
3
+ module Syntax
4
+ module ElsifClause
5
+ include Node
6
+
7
+ def _to_ast
8
+ cond = captures[:bool_expr].first.to_ast
9
+ dost = captures[:process_statement].first.to_ast
10
+ [:elsif_clause, cond, dost]
11
+ end
12
+
13
+ end # module ElsifClause
14
+ end # module Syntax
15
+ end # module Language
16
+ end # module Gisele
@@ -0,0 +1,15 @@
1
+ module Gisele
2
+ module Language
3
+ module Syntax
4
+ module EventSet
5
+ include Node
6
+
7
+ def _to_ast
8
+ events = (captures[:event] || []).map{|e| e.value}
9
+ [:event_set] + events
10
+ end
11
+
12
+ end # module EventSet
13
+ end # module Syntax
14
+ end # module Language
15
+ end # module Gisele
@@ -0,0 +1,18 @@
1
+ module Gisele
2
+ module Language
3
+ module Syntax
4
+ module FluentDef
5
+ include Node
6
+
7
+ def _to_ast
8
+ name = captures[:variable_name].first.strip
9
+ init, term = captures[:event_set].map{|x| x.to_ast}
10
+ initval = captures[:initially_def].first
11
+ initval = (initval && !initval.empty?) ? initval.value : nil
12
+ [:fluent, name, init, term, initval]
13
+ end
14
+
15
+ end # module FluentDef
16
+ end # module Syntax
17
+ end # module Language
18
+ end # module Gisele
@@ -0,0 +1,202 @@
1
+ grammar Gisele::Language::Syntax::Grammar
2
+
3
+ ### Units
4
+
5
+ rule unit
6
+ ((spacing task_def)* spacing)
7
+ <Gisele::Language::Syntax::Unit>
8
+ end
9
+
10
+ ### Task definitions
11
+
12
+ rule task_def
13
+ ('task' spaces task_name spaces (task_signature spaces)? (task_refinement spaces)? 'end')
14
+ <Gisele::Language::Syntax::TaskDef>
15
+ end
16
+
17
+ rule task_signature
18
+ (task_signature_element (spaces task_signature_element)*)
19
+ <Gisele::Language::Syntax::TaskSignature>
20
+ end
21
+
22
+ rule task_signature_element
23
+ fluent_def | trackvar_def
24
+ end
25
+
26
+ rule task_refinement
27
+ ('refinement' spaces process_statement spaces 'end')
28
+ <Gisele::Language::Syntax::TaskRefinement>
29
+ end
30
+
31
+ ### Process statements
32
+
33
+ rule process_statement
34
+ implicit_seq_st | explicit_statement
35
+ end
36
+
37
+ rule implicit_seq_st
38
+ (explicit_statement spaces st_list)
39
+ <Gisele::Language::Syntax::ImplicitSeqSt>
40
+ end
41
+
42
+ rule st_list
43
+ (explicit_statement (spaces explicit_statement)*)
44
+ <Gisele::Language::Syntax::StList>
45
+ end
46
+
47
+ rule explicit_statement
48
+ if_st
49
+ | while_st
50
+ | seq_st
51
+ | par_st
52
+ | task_call_st
53
+ end
54
+
55
+ rule if_st
56
+ ('if' spaces bool_expr spaces process_statement spaces elsif_clause* else_clause? 'end')
57
+ <Gisele::Language::Syntax::IfSt>
58
+ end
59
+
60
+ rule elsif_clause
61
+ ('elsif' spaces bool_expr spaces process_statement spaces)
62
+ <Gisele::Language::Syntax::ElsifClause>
63
+ end
64
+
65
+ rule else_clause
66
+ ('else' spaces process_statement spaces)
67
+ <Gisele::Language::Syntax::ElseClause>
68
+ end
69
+
70
+ rule while_st
71
+ ('while' spaces bool_expr spaces process_statement spaces 'end')
72
+ <Gisele::Language::Syntax::WhileSt>
73
+ end
74
+
75
+ rule seq_st
76
+ ('seq' spaces st_list spaces 'end')
77
+ <Gisele::Language::Syntax::SeqSt>
78
+ end
79
+
80
+ rule par_st
81
+ ('par' spaces st_list spaces 'end')
82
+ <Gisele::Language::Syntax::ParSt>
83
+ end
84
+
85
+ rule task_call_st
86
+ (task_name)
87
+ <Gisele::Language::Syntax::TaskCallSt>
88
+ end
89
+
90
+ ### Boolean expressions
91
+
92
+ rule bool_expr
93
+ bool_or
94
+ end
95
+
96
+ rule bool_or
97
+ (left:bool_and spaces 'or' spaces right:bool_or)
98
+ <Gisele::Language::Syntax::BoolOr>
99
+ | bool_and
100
+ end
101
+
102
+ rule bool_and
103
+ (left:bool_not spaces 'and' spaces right:bool_and)
104
+ <Gisele::Language::Syntax::BoolAnd>
105
+ | bool_not
106
+ end
107
+
108
+ rule bool_not
109
+ ('not' &([ \t\n] | '(') spacing expr:bool_not)
110
+ <Gisele::Language::Syntax::BoolNot>
111
+ | bool_term
112
+ end
113
+
114
+ rule bool_term
115
+ bool_paren | boolean_literal | bool_varref
116
+ end
117
+
118
+ rule bool_paren
119
+ ('(' spacing expr:bool_expr spacing ')')
120
+ <Gisele::Language::Syntax::BoolParen>
121
+ end
122
+
123
+ rule bool_lit
124
+ (boolean_literal)
125
+ <Gisele::Language::Syntax::BoolLit>
126
+ end
127
+
128
+ rule bool_varref
129
+ (variable_name)
130
+ <Gisele::Language::Syntax::VarRef>
131
+ end
132
+
133
+ ### Variables
134
+
135
+ rule variable_def
136
+ trackvar_def | fluent_def
137
+ end
138
+
139
+ rule trackvar_def
140
+ ('trackvar' spaces variable_name spacing event_set (spacing ',' spacing event_set)? initially_def?)
141
+ <Gisele::Language::Syntax::TrackvarDef>
142
+ end
143
+
144
+ rule fluent_def
145
+ ('fluent' spaces variable_name spacing event_set spacing ',' spacing event_set initially_def?)
146
+ <Gisele::Language::Syntax::FluentDef>
147
+ end
148
+
149
+ rule initially_def
150
+ (spaces 'initially' spaces lit:boolean_literal){ lit.value }
151
+ end
152
+
153
+ ### Events
154
+
155
+ rule event_set
156
+ ('{' spacing (event (spacing ',' spacing event)*)? spacing '}')
157
+ <Gisele::Language::Syntax::EventSet>
158
+ end
159
+
160
+ rule event
161
+ task_start_or_end | event_name
162
+ end
163
+
164
+ rule task_start_or_end
165
+ task_name ':' ('start' | 'end')
166
+ end
167
+
168
+ ### Names
169
+
170
+ rule task_name
171
+ [A-Z] [A-Za-z0-9_]*
172
+ end
173
+
174
+ rule variable_name
175
+ [a-z] [A-Za-z0-9_]*
176
+ end
177
+
178
+ rule event_name
179
+ [a-z] [a-z0-9_]*
180
+ end
181
+
182
+ ### Literals
183
+
184
+ rule boolean_literal
185
+ ('true' | 'false'){ strip == "true" }
186
+ end
187
+
188
+ ### Spacing
189
+
190
+ rule comment
191
+ "#" (![\n] .)*
192
+ end
193
+
194
+ rule spaces
195
+ (comment | [ \t\n])+
196
+ end
197
+
198
+ rule spacing
199
+ (comment | [ \t\n])*
200
+ end
201
+
202
+ end
@@ -0,0 +1,18 @@
1
+ module Gisele
2
+ module Language
3
+ module Syntax
4
+ module IfSt
5
+ include Node
6
+
7
+ def _to_ast
8
+ cond = captures[:bool_expr].first.to_ast
9
+ dost = captures[:process_statement].first.to_ast
10
+ elsifs = captures[:elsif_clause].map{|x| x.to_ast}
11
+ els = captures[:else_clause].map{|x| x.to_ast}
12
+ [:if_st, cond, dost] + elsifs + els
13
+ end
14
+
15
+ end # module IfSt
16
+ end # module Syntax
17
+ end # module Language
18
+ end # module Gisele
@@ -0,0 +1,16 @@
1
+ module Gisele
2
+ module Language
3
+ module Syntax
4
+ module ImplicitSeqSt
5
+ include Node
6
+
7
+ def _to_ast
8
+ front = captures[:explicit_statement].first.to_ast
9
+ tail = captures[:st_list].first.value
10
+ [:seq_st, front] + tail
11
+ end
12
+
13
+ end # module ImplicitSeqSt
14
+ end # module Syntax
15
+ end # module Language
16
+ end # module Gisele