gisele 0.0.1 → 0.1.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 (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