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
@@ -0,0 +1,35 @@
1
+ module Gisele
2
+ module Language
3
+ module Syntax
4
+ module Node
5
+
6
+ def to_ast
7
+ Language::AST.node(_to_ast)
8
+ end
9
+
10
+ end # module Node
11
+ end # module Syntax
12
+ end # module Language
13
+ end # module Gisele
14
+ require_relative 'event_set'
15
+ require_relative 'fluent_def'
16
+ require_relative 'trackvar_def'
17
+ require_relative 'var_ref'
18
+ require_relative 'bool_lit'
19
+ require_relative 'bool_paren'
20
+ require_relative 'bool_not'
21
+ require_relative 'bool_and'
22
+ require_relative 'bool_or'
23
+ require_relative 'st_list'
24
+ require_relative 'implicit_seq_st'
25
+ require_relative 'task_call_st'
26
+ require_relative 'seq_st'
27
+ require_relative 'par_st'
28
+ require_relative 'while_st'
29
+ require_relative 'if_st'
30
+ require_relative 'else_clause'
31
+ require_relative 'elsif_clause'
32
+ require_relative 'task_refinement'
33
+ require_relative 'task_signature'
34
+ require_relative 'task_def'
35
+ require_relative 'unit'
@@ -0,0 +1,14 @@
1
+ module Gisele
2
+ module Language
3
+ module Syntax
4
+ module ParSt
5
+ include Node
6
+
7
+ def _to_ast
8
+ [:par_st] + captures[:st_list].first.value
9
+ end
10
+
11
+ end # module ParSt
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 SeqSt
5
+ include Node
6
+
7
+ def _to_ast
8
+ [:seq_st] + captures[:st_list].first.value
9
+ end
10
+
11
+ end # module SeqSt
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 StList
5
+ include Node
6
+
7
+ def value
8
+ captures[:explicit_statement].map{|x| x.to_ast}
9
+ end
10
+
11
+ end # module StList
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 TaskCallSt
5
+ include Node
6
+
7
+ def _to_ast
8
+ [:task_call_st, strip]
9
+ end
10
+
11
+ end # module TaskCallSt
12
+ end # module Syntax
13
+ end # module Language
14
+ end # module Gisele
@@ -0,0 +1,17 @@
1
+ module Gisele
2
+ module Language
3
+ module Syntax
4
+ module TaskDef
5
+ include Node
6
+
7
+ def _to_ast
8
+ name = captures[:task_name].first.strip
9
+ sig = captures[:task_signature].map{|x| x.to_ast}.first || [:task_signature]
10
+ ref = captures[:task_refinement].map{|x| x.to_ast}.first || [:task_refinement]
11
+ [:task_def, name, sig, ref]
12
+ end
13
+
14
+ end # module TaskDef
15
+ end # module Syntax
16
+ end # module Language
17
+ end # module Gisele
@@ -0,0 +1,15 @@
1
+ module Gisele
2
+ module Language
3
+ module Syntax
4
+ module TaskRefinement
5
+ include Node
6
+
7
+ def _to_ast
8
+ main = captures[:process_statement].first.to_ast
9
+ [:task_refinement, main]
10
+ end
11
+
12
+ end # module TaskRefinement
13
+ end # module Syntax
14
+ end # module Language
15
+ end # module Gisele
@@ -0,0 +1,15 @@
1
+ module Gisele
2
+ module Language
3
+ module Syntax
4
+ module TaskSignature
5
+ include Node
6
+
7
+ def _to_ast
8
+ list = captures[:task_signature_element].map{|x| x.to_ast}
9
+ [:task_signature] + list
10
+ end
11
+
12
+ end # module TaskSignature
13
+ end # module Syntax
14
+ end # module Language
15
+ end # module Gisele
@@ -0,0 +1,19 @@
1
+ module Gisele
2
+ module Language
3
+ module Syntax
4
+ module TrackvarDef
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
+ term = [:event_set] unless term
11
+ initval = captures[:initially_def].first
12
+ initval = (initval && !initval.empty?) ? initval.value : nil
13
+ [:trackvar, name, init, term, initval]
14
+ end
15
+
16
+ end # module TrackvarDef
17
+ end # module Syntax
18
+ end # module Language
19
+ end # module Gisele
@@ -0,0 +1,14 @@
1
+ module Gisele
2
+ module Language
3
+ module Syntax
4
+ module Unit
5
+ include Node
6
+
7
+ def _to_ast
8
+ [:unit] + captures[:task_def].map{|x| x.to_ast}
9
+ end
10
+
11
+ end # module Unit
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 VarRef
5
+ include Node
6
+
7
+ def _to_ast
8
+ [:var_ref, strip]
9
+ end
10
+
11
+ end # module VarRef
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 WhileSt
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
+ [:while_st, cond, dost]
11
+ end
12
+
13
+ end # module WhileSt
14
+ end # module Syntax
15
+ end # module Language
16
+ end # module Gisele
@@ -0,0 +1,29 @@
1
+ require_relative 'syntax/node'
2
+ module Gisele
3
+ module Language
4
+ module Syntax
5
+ Citrus.load(File.expand_path('../syntax/grammar', __FILE__))
6
+
7
+ def parse(input, options = {})
8
+ source = parsing_source(input)
9
+ Grammar.parse(source, options)
10
+ end
11
+ module_function :parse
12
+
13
+ def ast(input, parse_options = {})
14
+ parse(input, parse_options).to_ast
15
+ end
16
+ module_function :ast
17
+
18
+ private
19
+
20
+ def parsing_source(input)
21
+ input = File.read(input.to_path) if input.respond_to?(:to_path)
22
+ input = input.to_str if input.respond_to?(:to_str)
23
+ input
24
+ end
25
+ module_function :parsing_source
26
+
27
+ end # module Syntax
28
+ end # module Language
29
+ end # module Gisele
@@ -0,0 +1,38 @@
1
+ module Gisele
2
+ module Language
3
+ class Transformer
4
+ include AST::Helpers
5
+
6
+ def call(node)
7
+ node = pre_call(node)
8
+ meth = :"on_#{node.rule_name}"
9
+ meth = :"on_missing" unless respond_to?(meth)
10
+ post_call send(meth, node)
11
+ end
12
+
13
+ def on_missing(node)
14
+ raise UnexpectedNodeError, "Unexpected node: #{node.rule_name}"
15
+ end
16
+
17
+ protected
18
+
19
+ def pre_call(node)
20
+ unless looks_a_node?(node)
21
+ raise ArgumentError, "AST node expected, got #{node.inspect}", caller
22
+ end
23
+ node(node)
24
+ end
25
+
26
+ def post_call(transformed)
27
+ looks_a_node?(transformed) ? node(transformed) : transformed
28
+ end
29
+
30
+ def copy_and_applyall(node)
31
+ node.copy do |memo,child|
32
+ memo << (child.is_a?(AST::Node) ? call(child) : child)
33
+ end
34
+ end
35
+
36
+ end # class Transformer
37
+ end # module Language
38
+ end # module Gisele
@@ -1,6 +1,20 @@
1
1
  module Gisele
2
2
  module Language
3
3
 
4
+ def rule2mod(rule)
5
+ rule.to_s.gsub(/(^|_)([a-z])/){|x| $2.capitalize}.to_sym
6
+ end
7
+ module_function :rule2mod
8
+
9
+ def mod2rule(mod)
10
+ mod = mod.name.to_s.split('::').last.to_sym if mod.is_a?(Module)
11
+ mod.to_s.gsub(/[A-Z]/){|x| "_#{x.downcase}"}[1..-1].to_sym
12
+ end
13
+ module_function :mod2rule
14
+
4
15
  end # module Language
5
16
  end # module Gisele
6
- require_relative 'language/parser'
17
+ require_relative 'language/syntax'
18
+ require_relative 'language/ast'
19
+ require_relative 'language/transformer'
20
+ require_relative 'language/sugar_removal'
@@ -2,8 +2,8 @@ module Gisele
2
2
  module Version
3
3
 
4
4
  MAJOR = 0
5
- MINOR = 0
6
- TINY = 1
5
+ MINOR = 1
6
+ TINY = 0
7
7
 
8
8
  def self.to_s
9
9
  [ MAJOR, MINOR, TINY ].join('.')
data/lib/gisele.rb CHANGED
@@ -1,14 +1,20 @@
1
1
  require_relative "gisele/version"
2
2
  require_relative "gisele/loader"
3
+ require_relative 'gisele/errors'
3
4
  #
4
5
  # Gisele is a Process Analyzer Toolset
5
6
  #
6
7
  module Gisele
7
8
 
8
9
  def parse(input)
9
- Language::Parser::parse(input)
10
+ Language::Syntax::parse(input)
10
11
  end
11
12
  module_function :parse
12
13
 
14
+ def ast(input)
15
+ Language::Syntax::ast(input)
16
+ end
17
+ module_function :ast
18
+
13
19
  end # module Gisele
14
20
  require_relative 'gisele/language'
@@ -1,43 +1,53 @@
1
1
  [
2
- :task,
3
- "Simple",
2
+ :unit,
4
3
  [
5
- :signature,
4
+ :task_def,
5
+ "Simple",
6
6
  [
7
- :fluent,
8
- "diagKnown",
7
+ :task_signature,
9
8
  [
10
- :event_set,
11
- "Diagnosis:start"
12
- ],
13
- [
14
- :event_set,
15
- "Treatment:end"
16
- ],
17
- nil
18
- ]
19
- ],
20
- [
21
- :refinement,
9
+ :fluent,
10
+ "diagKnown",
11
+ [
12
+ :event_set,
13
+ "Diagnosis:start"
14
+ ],
15
+ [
16
+ :event_set,
17
+ "Treatment:end"
18
+ ],
19
+ nil
20
+ ]
21
+ ],
22
22
  [
23
- :seq,
23
+ :task_refinement,
24
24
  [
25
- :if,
25
+ :seq_st,
26
26
  [
27
- :not,
27
+ :if_st,
28
+ [
29
+ :bool_not,
30
+ [
31
+ :var_ref,
32
+ "diagKnown"
33
+ ]
34
+ ],
28
35
  [
29
- :varref,
30
- "diagKnown"
36
+ :task_call_st,
37
+ "Diagnosis"
38
+ ],
39
+ [
40
+ :else_clause,
41
+ [
42
+ :task_call_st,
43
+ "NoDiag"
44
+ ]
31
45
  ]
32
46
  ],
33
47
  [
34
- :task_call,
35
- "Diagnosis"
48
+ :task_call_st,
49
+ "Treatment"
36
50
  ]
37
- ],
38
- [
39
- :task_call,
40
- "Treatment"
41
51
  ]
42
52
  ]
43
53
  ]
@@ -7,6 +7,7 @@ SYNOPSIS
7
7
 
8
8
  OPTIONS
9
9
  --ast=[MODE] Prints the process abstract syntax tree (debug,ruby)
10
+ --no-sugar Apply syntactic sugar removal
10
11
  --help Show this help message
11
12
  --version Show version and exit
12
13
 
@@ -19,4 +20,8 @@ DESCRIPTION
19
20
  debugging, that is with colors and extra information. Use --ast=ruby to get a ruby
20
21
  array for automatic processing.
21
22
 
23
+ When --no-sugar is specified, syntactic sugar is first removed before making any other
24
+ transformation. For now, this rewrites all `if` statements as explicit `case` guarded
25
+ commands.
26
+
22
27
  SystemExit
@@ -0,0 +1 @@
1
+ gisele --no-sugar --ast=ruby tasks/simple.gis
@@ -0,0 +1,61 @@
1
+ [
2
+ :unit,
3
+ [
4
+ :task_def,
5
+ "Simple",
6
+ [
7
+ :task_signature,
8
+ [
9
+ :fluent,
10
+ "diagKnown",
11
+ [
12
+ :event_set,
13
+ "Diagnosis:start"
14
+ ],
15
+ [
16
+ :event_set,
17
+ "Treatment:end"
18
+ ],
19
+ nil
20
+ ]
21
+ ],
22
+ [
23
+ :task_refinement,
24
+ [
25
+ :seq_st,
26
+ [
27
+ :case_st,
28
+ [
29
+ :when_clause,
30
+ [
31
+ :bool_not,
32
+ [
33
+ :var_ref,
34
+ "diagKnown"
35
+ ]
36
+ ],
37
+ [
38
+ :task_call_st,
39
+ "Diagnosis"
40
+ ]
41
+ ],
42
+ [
43
+ :when_clause,
44
+ [
45
+ :var_ref,
46
+ "diagKnown"
47
+ ],
48
+ [
49
+ :task_call_st,
50
+ "NoDiag"
51
+ ]
52
+ ]
53
+ ],
54
+ [
55
+ :task_call_st,
56
+ "Treatment"
57
+ ]
58
+ ]
59
+ ]
60
+ ]
61
+ ]
@@ -1,15 +1,19 @@
1
- [:task, "Simple",
2
- [:signature,
3
- [:fluent, "diagKnown",
4
- [:event_set, "Diagnosis:start"],
5
- [:event_set, "Treatment:end"],
6
- nil ]
7
- ],
8
- [:refinement,
9
- [:seq,
10
- [:if,
11
- [:not, [:varref, "diagKnown"]],
12
- [:task_call, "Diagnosis"] ],
13
- [:task_call, "Treatment"]]
14
- ]
1
+ [:unit,
2
+ [:task_def, "Simple",
3
+ [:task_signature,
4
+ [:fluent, "diagKnown",
5
+ [:event_set, "Diagnosis:start"],
6
+ [:event_set, "Treatment:end"],
7
+ nil ]
8
+ ],
9
+ [:task_refinement,
10
+ [:seq_st,
11
+ [:if_st,
12
+ [:bool_not, [:var_ref, "diagKnown"]],
13
+ [:task_call_st, "Diagnosis"],
14
+ [:else_clause,
15
+ [:task_call_st, "NoDiag"] ]],
16
+ [:task_call_st, "Treatment"]]
17
+ ]
18
+ ]
15
19
  ]
@@ -3,6 +3,8 @@ task Simple
3
3
  refinement
4
4
  if not(diagKnown)
5
5
  Diagnosis
6
+ else
7
+ NoDiag
6
8
  end
7
9
  Treatment
8
10
  end
data/spec/spec_helper.rb CHANGED
@@ -11,7 +11,7 @@ ensure
11
11
  $stdout, $stderr = stdout, stderr
12
12
  end
13
13
 
14
- module Helpers
14
+ module SpecHelpers
15
15
 
16
16
  def fixtures_dir
17
17
  (Path.dir/:fixtures)
@@ -24,6 +24,6 @@ module Helpers
24
24
  end
25
25
 
26
26
  RSpec.configure do |c|
27
- c.extend Helpers
28
- c.include Helpers
27
+ c.extend SpecHelpers
28
+ c.include SpecHelpers
29
29
  end
@@ -1,14 +1,14 @@
1
1
  require 'spec_helper'
2
2
  describe "The examples" do
3
-
3
+
4
4
  (Path.backfind(".[examples]")/:examples).glob("**/*.gis").each do |file|
5
5
 
6
6
  describe file do
7
7
  it 'parses without any error' do
8
- Gisele::parse(file).should be_a(Array)
8
+ Gisele::ast(file).should be_a(Array)
9
9
  end
10
10
  end
11
11
 
12
12
  end
13
-
13
+
14
14
  end
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+ module Gisele::Language::AST
3
+ describe Node do
4
+ include Helpers
5
+
6
+ describe 'rule_name' do
7
+ it 'returns the first array element' do
8
+ node([:hello]).rule_name.should eq(:hello)
9
+ end
10
+ end
11
+
12
+ describe 'children' do
13
+
14
+ it 'returns all but the rule name' do
15
+ node([:hello, "world", "!"]).children.should eq(["world", "!"])
16
+ end
17
+
18
+ it 'returns an empty array when no children' do
19
+ node([:hello]).children.should eq([])
20
+ end
21
+
22
+ end # children
23
+
24
+ describe 'copy' do
25
+
26
+ it 'collects block results ala `inject`' do
27
+ source = node([:unit, "world", "gisele"])
28
+ target = source.copy do |memo,child|
29
+ memo << child.upcase
30
+ end
31
+ target.should be_a(Unit)
32
+ target.should eq([:unit, "WORLD", "GISELE"])
33
+ end
34
+
35
+ it 'returns a real equal copy when no children' do
36
+ source = node([:unit])
37
+ target = source.copy do |memo,child| end
38
+ target.should eq(source)
39
+ target.object_id.should_not eq(source.object_id)
40
+ target.should be_a(Unit)
41
+ end
42
+
43
+ end
44
+
45
+ describe 'dup' do
46
+
47
+ it 'duplicates the underlying array' do
48
+ arr = [:unit, "etc."]
49
+ node(arr).dup.should eq(arr)
50
+ end
51
+
52
+ it 'ensures duplicated array is still a node' do
53
+ arr = [:unit, "etc."]
54
+ node(arr).dup.should be_a(Unit)
55
+ node(arr).dup.should be_a(Node)
56
+ end
57
+
58
+ end # dup
59
+
60
+ end
61
+ end