piggly 1.2.1 → 2.0.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 (112) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +163 -0
  3. data/Rakefile +29 -15
  4. data/bin/piggly +4 -244
  5. data/lib/piggly.rb +19 -17
  6. data/lib/piggly/command.rb +9 -0
  7. data/lib/piggly/command/base.rb +148 -0
  8. data/lib/piggly/command/report.rb +162 -0
  9. data/lib/piggly/command/test.rb +157 -0
  10. data/lib/piggly/command/trace.rb +90 -0
  11. data/lib/piggly/command/untrace.rb +78 -0
  12. data/lib/piggly/compiler.rb +7 -5
  13. data/lib/piggly/compiler/cache_dir.rb +119 -0
  14. data/lib/piggly/compiler/coverage_report.rb +63 -0
  15. data/lib/piggly/compiler/trace_compiler.rb +105 -0
  16. data/lib/piggly/config.rb +47 -22
  17. data/lib/piggly/dumper.rb +9 -0
  18. data/lib/piggly/dumper/index.rb +121 -0
  19. data/lib/piggly/dumper/qualified_name.rb +36 -0
  20. data/lib/piggly/dumper/qualified_type.rb +81 -0
  21. data/lib/piggly/dumper/reified_procedure.rb +142 -0
  22. data/lib/piggly/dumper/skeleton_procedure.rb +102 -0
  23. data/lib/piggly/installer.rb +84 -42
  24. data/lib/piggly/parser.rb +43 -49
  25. data/lib/piggly/parser/grammar.tt +289 -313
  26. data/lib/piggly/parser/nodes.rb +270 -211
  27. data/lib/piggly/parser/traversal.rb +35 -33
  28. data/lib/piggly/parser/treetop_ruby19_patch.rb +1 -1
  29. data/lib/piggly/profile.rb +81 -60
  30. data/lib/piggly/reporter.rb +5 -18
  31. data/lib/piggly/reporter/base.rb +103 -0
  32. data/lib/piggly/reporter/html_dsl.rb +63 -0
  33. data/lib/piggly/reporter/index.rb +108 -0
  34. data/lib/piggly/reporter/procedure.rb +104 -0
  35. data/lib/piggly/reporter/resources/highlight.js +21 -0
  36. data/lib/piggly/reporter/{piggly.css → resources/piggly.css} +52 -12
  37. data/lib/piggly/reporter/{sortable.js → resources/sortable.js} +0 -0
  38. data/lib/piggly/tags.rb +280 -0
  39. data/lib/piggly/task.rb +191 -40
  40. data/lib/piggly/util.rb +8 -27
  41. data/lib/piggly/util/blankslate.rb +114 -0
  42. data/lib/piggly/util/cacheable.rb +19 -0
  43. data/lib/piggly/util/enumerable.rb +44 -0
  44. data/lib/piggly/util/file.rb +17 -0
  45. data/lib/piggly/util/process_queue.rb +96 -0
  46. data/lib/piggly/util/thunk.rb +39 -0
  47. data/lib/piggly/version.rb +8 -8
  48. data/spec/examples/compiler/cacheable_spec.rb +190 -0
  49. data/spec/examples/compiler/report_spec.rb +25 -0
  50. data/spec/{compiler → examples/compiler}/trace_spec.rb +7 -57
  51. data/spec/examples/config_spec.rb +61 -0
  52. data/spec/examples/dumper/index_spec.rb +197 -0
  53. data/spec/examples/dumper/procedure_spec.rb +116 -0
  54. data/spec/{grammar → examples/grammar}/expression_spec.rb +60 -60
  55. data/spec/{grammar → examples/grammar}/statements/assignment_spec.rb +15 -15
  56. data/spec/examples/grammar/statements/declaration_spec.rb +21 -0
  57. data/spec/{grammar → examples/grammar}/statements/exception_spec.rb +10 -10
  58. data/spec/{grammar → examples/grammar}/statements/if_spec.rb +47 -34
  59. data/spec/{grammar → examples/grammar}/statements/loop_spec.rb +5 -5
  60. data/spec/{grammar → examples/grammar}/statements/sql_spec.rb +11 -11
  61. data/spec/{grammar → examples/grammar}/tokens/comment_spec.rb +11 -11
  62. data/spec/{grammar → examples/grammar}/tokens/datatype_spec.rb +14 -8
  63. data/spec/{grammar → examples/grammar}/tokens/identifier_spec.rb +26 -10
  64. data/spec/{grammar → examples/grammar}/tokens/keyword_spec.rb +5 -5
  65. data/spec/{grammar → examples/grammar}/tokens/label_spec.rb +7 -7
  66. data/spec/{grammar → examples/grammar}/tokens/literal_spec.rb +1 -1
  67. data/spec/examples/grammar/tokens/lval_spec.rb +50 -0
  68. data/spec/{grammar → examples/grammar}/tokens/number_spec.rb +1 -1
  69. data/spec/{grammar → examples/grammar}/tokens/sqlkeywords_spec.rb +1 -1
  70. data/spec/{grammar → examples/grammar}/tokens/string_spec.rb +9 -9
  71. data/spec/{grammar → examples/grammar}/tokens/whitespace_spec.rb +1 -1
  72. data/spec/examples/installer_spec.rb +59 -0
  73. data/spec/examples/parser/nodes_spec.rb +73 -0
  74. data/spec/examples/parser/traversal_spec.rb +14 -0
  75. data/spec/examples/parser_spec.rb +115 -0
  76. data/spec/examples/profile_spec.rb +153 -0
  77. data/spec/{reporter/html_spec.rb → examples/reporter/html/dsl_spec.rb} +0 -0
  78. data/spec/examples/reporter/html/index_spec.rb +0 -0
  79. data/spec/examples/reporter/html_spec.rb +1 -0
  80. data/spec/examples/reporter_spec.rb +0 -0
  81. data/spec/{compiler → examples}/tags_spec.rb +10 -10
  82. data/spec/examples/task_spec.rb +0 -0
  83. data/spec/examples/util/cacheable_spec.rb +41 -0
  84. data/spec/examples/util/enumerable_spec.rb +64 -0
  85. data/spec/examples/util/file_spec.rb +40 -0
  86. data/spec/examples/util/process_queue_spec.rb +16 -0
  87. data/spec/examples/util/thunk_spec.rb +58 -0
  88. data/spec/examples/version_spec.rb +0 -0
  89. data/spec/issues/007_spec.rb +25 -0
  90. data/spec/issues/008_spec.rb +73 -0
  91. data/spec/issues/018_spec.rb +25 -0
  92. data/spec/spec_helper.rb +253 -9
  93. metadata +136 -93
  94. data/README.markdown +0 -116
  95. data/lib/piggly/compiler/cache.rb +0 -151
  96. data/lib/piggly/compiler/pretty.rb +0 -67
  97. data/lib/piggly/compiler/queue.rb +0 -46
  98. data/lib/piggly/compiler/tags.rb +0 -244
  99. data/lib/piggly/compiler/trace.rb +0 -91
  100. data/lib/piggly/filecache.rb +0 -40
  101. data/lib/piggly/parser/parser.rb +0 -11794
  102. data/lib/piggly/reporter/html.rb +0 -207
  103. data/spec/compiler/cache_spec.rb +0 -9
  104. data/spec/compiler/pretty_spec.rb +0 -9
  105. data/spec/compiler/queue_spec.rb +0 -3
  106. data/spec/compiler/rewrite_spec.rb +0 -3
  107. data/spec/config_spec.rb +0 -58
  108. data/spec/filecache_spec.rb +0 -70
  109. data/spec/fixtures/snippets.sql +0 -158
  110. data/spec/grammar/tokens/lval_spec.rb +0 -50
  111. data/spec/parser_spec.rb +0 -8
  112. data/spec/profile_spec.rb +0 -5
@@ -0,0 +1,102 @@
1
+ module Piggly
2
+ module Dumper
3
+
4
+ #
5
+ # Encapsulates all the information about a stored procedure, except the
6
+ # procedure's source code, which is assumed to be on disk, loaded as needed.
7
+ #
8
+ class SkeletonProcedure
9
+
10
+ attr_reader :oid, :name, :type, :arg_types, :arg_modes, :arg_names,
11
+ :strict, :type, :setof, :volatility, :secdef, :identifier
12
+
13
+ def initialize(oid, name, strict, secdef, setof, type, volatility, arg_modes, arg_names, arg_types, arg_defaults)
14
+ @oid, @name, @strict, @secdef, @type, @volatility, @setof, @arg_modes, @arg_names, @arg_types, @arg_defaults =
15
+ oid, name, strict, secdef, type, volatility, setof, arg_modes, arg_names, arg_types, arg_defaults
16
+
17
+ @identifier = Digest::MD5.hexdigest(signature)
18
+ end
19
+
20
+ # Returns source text for argument list
21
+ # @return [String]
22
+ def arguments
23
+ @arg_types.zip(@arg_names, @arg_modes, @arg_defaults).map do |type, name, mode, default|
24
+ "#{mode + " " if mode}#{name.quote + " " if name}#{type.quote}#{" DEFAULT " + default if default}"
25
+ end.join(", ")
26
+ end
27
+
28
+ # Returns source text for return type
29
+ # @return [String]
30
+ def setof
31
+ @setof ? "setof " : ""
32
+ end
33
+
34
+ # Returns source text for strictness
35
+ # @return [String]
36
+ def strictness
37
+ @strict ? "strict" : ""
38
+ end
39
+
40
+ # Returns source text for security
41
+ # @return [String]
42
+ def security
43
+ @secdef ? "security definer" : ""
44
+ end
45
+
46
+ # Returns source SQL function definition statement
47
+ # @return [String]
48
+ def definition(body)
49
+ [%[create or replace function #{name.quote} (#{arguments})],
50
+ %[ returns #{setof}#{type.quote} as $__PIGGLY__$],
51
+ body,
52
+ %[$__PIGGLY__$ language plpgsql #{strictness} #{security} #{@volatility}]].join("\n")
53
+ end
54
+
55
+ # @return [String]
56
+ def signature
57
+ "#{@name}(#{@arg_modes.zip(@arg_types).map{|m,t| "#{m} #{t}" }.join(", ")})"
58
+ end
59
+
60
+ # @return [String]
61
+ def source_path(config)
62
+ config.mkpath("#{config.cache_root}/Dumper", "#{@identifier}.plpgsql")
63
+ end
64
+
65
+ # @return [String]
66
+ def load_source(config)
67
+ File.read(source_path(config))
68
+ end
69
+
70
+ # @return [String]
71
+ alias source load_source
72
+
73
+ # @return [void]
74
+ def purge_source(config)
75
+ path = source_path(config)
76
+
77
+ FileUtils.rm_r(path) if File.exists?(path)
78
+
79
+ file = Compiler::TraceCompiler.new(config).cache_path(path)
80
+ FileUtils.rm_r(file) if File.exists?(file)
81
+
82
+ file = Reporter::Base.new(config).report_path(path, ".html")
83
+ FileUtils.rm_r(file) if File.exists?(file)
84
+ end
85
+
86
+ # @return [SkeletonProcedure]
87
+ def skeleton
88
+ self
89
+ end
90
+
91
+ def skeleton?
92
+ true
93
+ end
94
+
95
+ def ==(other)
96
+ other.is_a?(self.class) and
97
+ other.identifier == identifier
98
+ end
99
+ end
100
+
101
+ end
102
+ end
@@ -1,95 +1,137 @@
1
1
  module Piggly
2
+
2
3
  class Installer
4
+ def initialize(config, connection)
5
+ @config, @connection = config, connection
6
+ end
7
+
8
+ # @return [void]
9
+ def install(procedures, profile)
10
+ @connection.exec("begin")
11
+
12
+ install_support(profile)
3
13
 
4
- # Compiles the procedures in +file+ with instrumentation and installs them
5
- def self.trace_proc(file)
6
- # recompile with instrumentation if needed
7
- cache = Piggly::TraceCompiler.cache(file)
14
+ procedures.each do |p|
15
+ begin
16
+ trace(p, profile)
17
+ rescue Parser::Failure
18
+ $stdout.puts $!
19
+ end
20
+ end
8
21
 
9
- # install instrumented code
10
- connection.exec cache['code.sql']
22
+ @connection.exec("commit")
23
+ rescue
24
+ @connection.exec("rollback")
25
+ raise
26
+ end
27
+
28
+ # @return [void]
29
+ def uninstall(procedures)
30
+ @connection.exec("begin")
11
31
 
12
- # map tag messages to tag objects
13
- Profile.add(file, cache['tags'], cache)
32
+ procedures.each{|p| untrace(p) }
33
+ uninstall_support
34
+
35
+ @connection.exec("commit")
36
+ rescue
37
+ @connection.exec("rollback")
38
+ raise
14
39
  end
15
40
 
16
- # Reinstalls the original stored procedures in +file+
17
- def self.untrace_proc(file)
18
- connection.exec File.read(file)
41
+ # @return [void]
42
+ def trace(procedure, profile)
43
+ # recompile with instrumentation
44
+ compiler = Compiler::TraceCompiler.new(@config)
45
+ result = compiler.compile(procedure)
46
+ # result[:tree] - tagged and rewritten parse tree
47
+ # result[:tags] - collection of Tag values in the tree
48
+ # result[:code] - instrumented
49
+
50
+ @connection.exec(procedure.definition(result[:code]))
51
+
52
+ profile.add(procedure, result[:tags], result)
53
+ rescue
54
+ $!.message << "\nError installing traced procedure #{procedure.name} "
55
+ $!.message << "from #{procedure.source_path(@config)}"
56
+ raise
57
+ end
58
+
59
+ # @return [void]
60
+ def untrace(procedure)
61
+ @connection.exec(procedure.definition(procedure.source(@config)))
19
62
  end
20
63
 
21
64
  # Installs necessary instrumentation support
22
- def self.install_trace
23
- # record trace messages
24
- connection.set_notice_processor(&Profile.notice_processor)
65
+ def install_support(profile)
66
+ @connection.set_notice_processor(&profile.notice_processor(@config))
67
+
68
+ # def connection.set_notice_processor
69
+ # # do nothing: prevent the notice processor from being subverted
70
+ # end
25
71
 
26
72
  # install tracing functions
27
- connection.exec <<-SQL
28
- -- signals that a conditional expression was executed
73
+ @connection.exec <<-SQL
74
+ -- Signals that a conditional expression was executed
29
75
  CREATE OR REPLACE FUNCTION piggly_cond(message varchar, value boolean)
30
76
  RETURNS boolean AS $$
31
77
  BEGIN
32
78
  IF value THEN
33
- RAISE WARNING '#{Config.trace_prefix} % t', message;
79
+ RAISE WARNING '#{@config.trace_prefix} % t', message;
34
80
  ELSE
35
- RAISE WARNING '#{Config.trace_prefix} % f', message;
81
+ RAISE WARNING '#{@config.trace_prefix} % f', message;
36
82
  END IF;
37
83
  RETURN value;
38
84
  END $$ LANGUAGE 'plpgsql' VOLATILE;
39
85
  SQL
40
86
 
41
- connection.exec <<-SQL
42
- -- generic signal
87
+ @connection.exec <<-SQL
88
+ -- Generic signal
43
89
  CREATE OR REPLACE FUNCTION piggly_signal(message varchar, signal varchar)
44
90
  RETURNS void AS $$
45
91
  BEGIN
46
- RAISE WARNING '#{Config.trace_prefix} % %', message, signal;
92
+ RAISE WARNING '#{@config.trace_prefix} % %', message, signal;
47
93
  END $$ LANGUAGE 'plpgsql' VOLATILE;
48
94
  SQL
49
95
 
50
- connection.exec <<-SQL
51
- -- signals that a (sub)expression was executed. handles '' and NULL value
96
+ @connection.exec <<-SQL
97
+ -- Signals that a (sub)expression was executed. handles '' and NULL value
52
98
  CREATE OR REPLACE FUNCTION piggly_expr(message varchar, value varchar)
53
99
  RETURNS varchar AS $$
54
100
  BEGIN
55
- RAISE WARNING '#{Config.trace_prefix} %', message;
101
+ RAISE WARNING '#{@config.trace_prefix} %', message;
56
102
  RETURN value;
57
103
  END $$ LANGUAGE 'plpgsql' VOLATILE;
58
104
  SQL
59
105
 
60
- connection.exec <<-SQL
61
- -- signals that a (sub)expression was executed. handles all other types
106
+ @connection.exec <<-SQL
107
+ -- Signals that a (sub)expression was executed. handles all other types
62
108
  CREATE OR REPLACE FUNCTION piggly_expr(message varchar, value anyelement)
63
109
  RETURNS anyelement AS $$
64
110
  BEGIN
65
- RAISE WARNING '#{Config.trace_prefix} %', message;
111
+ RAISE WARNING '#{@config.trace_prefix} %', message;
66
112
  RETURN value;
67
113
  END $$ LANGUAGE 'plpgsql' VOLATILE;
68
114
  SQL
69
115
 
70
- connection.exec <<-SQL
71
- -- signals that a branch was taken
116
+ @connection.exec <<-SQL
117
+ -- Signals that a branch was taken
72
118
  CREATE OR REPLACE FUNCTION piggly_branch(message varchar)
73
119
  RETURNS void AS $$
74
120
  BEGIN
75
- RAISE WARNING '#{Config.trace_prefix} %', message;
121
+ RAISE WARNING '#{@config.trace_prefix} %', message;
76
122
  END $$ LANGUAGE 'plpgsql' VOLATILE;
77
123
  SQL
78
124
  end
79
125
 
80
126
  # Uninstalls instrumentation support
81
- def self.uninstall_trace
82
- connection.set_notice_processor
83
- connection.exec "DROP FUNCTION IF EXISTS piggly_cond(varchar, boolean);"
84
- connection.exec "DROP FUNCTION IF EXISTS piggly_expr(varchar, varchar);"
85
- connection.exec "DROP FUNCTION IF EXISTS piggly_expr(varchar, anyelement);"
86
- connection.exec "DROP FUNCTION IF EXISTS piggly_branch(varchar);"
127
+ def uninstall_support
128
+ @connection.set_notice_processor{|x| $stderr.puts x }
129
+ @connection.exec "DROP FUNCTION IF EXISTS piggly_cond(varchar, boolean)"
130
+ @connection.exec "DROP FUNCTION IF EXISTS piggly_expr(varchar, varchar)"
131
+ @connection.exec "DROP FUNCTION IF EXISTS piggly_expr(varchar, anyelement)"
132
+ @connection.exec "DROP FUNCTION IF EXISTS piggly_branch(varchar)"
133
+ @connection.exec "DROP FUNCTION IF EXISTS piggly_signal(varchar, varchar)"
87
134
  end
88
-
89
- # Returns the active PGConn
90
- def self.connection
91
- ActiveRecord::Base.connection.raw_connection
92
- end
93
-
94
135
  end
136
+
95
137
  end
@@ -3,64 +3,58 @@ module Piggly
3
3
  #
4
4
  # Pl/pgSQL Parser, returns a tree of NodeClass values (see nodes.rb)
5
5
  #
6
- class Parser
7
- include FileCache
6
+ module Parser
8
7
 
9
- class Failure < RuntimeError; end
10
-
11
- # Returns parse tree
12
- def self.parse(string)
13
- p = parser
14
-
15
- begin
16
- # downcase input for case-insensitive parsing,
17
- # then restore original string after parsing
18
- input = string.downcase
19
- tree = p.parse(input)
20
- tree or raise Failure, "#{p.failure_reason}"
21
- rescue Failure
22
- $!.backtrace.clear
23
- raise
24
- ensure
25
- input.replace string
26
- end
27
- end
28
-
29
- def self.parser_path; File.join(File.dirname(__FILE__), 'parser', 'parser.rb') end
30
- def self.grammar_path; File.join(File.dirname(__FILE__), 'parser', 'grammar.tt') end
31
- def self.nodes_path; File.join(File.dirname(__FILE__), 'parser', 'nodes.rb') end
8
+ autoload :Nodes, "piggly/parser/nodes"
9
+ autoload :Traversal, "piggly/parser/traversal"
32
10
 
33
- def self.stale?(source)
34
- File.stale?(cache_path(source), source, grammar_path, parser_path, nodes_path)
35
- end
36
-
37
- def self.cache(source)
38
- cache = cache_path(source)
11
+ class Failure < RuntimeError; end
39
12
 
40
- if stale?(source)
41
- tree = parse(File.read(source))
42
- File.open(cache, 'w+') do |f|
43
- Marshal.dump(tree, f)
44
- tree
13
+ class << self
14
+ # Returns lazy parse tree (only parsed when the value is needed)
15
+ def parse(string)
16
+ Util::Thunk.new do
17
+ p = parser
18
+
19
+ begin
20
+ # Downcase input for case-insensitive parsing
21
+ input = string.downcase
22
+ tree = p.parse(input)
23
+ tree or raise Failure, "#{p.failure_reason}"
24
+ ensure
25
+ # Restore the original string after parsing
26
+ input.replace(string)
27
+ end
45
28
  end
46
- else
47
- _ = parser # ensure parser libraries, like nodes.rb, are loaded
48
- Marshal.load(File.read(cache))
49
29
  end
50
- end
51
30
 
52
- # Returns treetop parser (recompiled as needed)
53
- def self.parser
54
- require 'treetop'
55
- require 'piggly/parser/treetop_ruby19_patch'
56
- require nodes_path
31
+ def parser_path; "#{File.dirname(__FILE__)}/parser/parser.rb" end
32
+ def grammar_path; "#{File.dirname(__FILE__)}/parser/grammar.tt" end
33
+ def nodes_path; "#{File.dirname(__FILE__)}/parser/nodes.rb" end
34
+
35
+ # Returns treetop parser (recompiled as needed)
36
+ def parser
37
+ load_support
38
+
39
+ # @todo: Compare with the version of treetop
40
+ if Util::File.stale?(parser_path, grammar_path)
41
+ # Regenerate the parser when the grammar is updated
42
+ Treetop::Compiler::GrammarCompiler.new.compile(grammar_path, parser_path)
43
+ load parser_path
44
+ else
45
+ require parser_path
46
+ end
57
47
 
58
- if File.stale?(parser_path, grammar_path)
59
- Treetop::Compiler::GrammarCompiler.new.compile(grammar_path, parser_path)
48
+ ::PigglyParser.new
60
49
  end
50
+
51
+ private
61
52
 
62
- require parser_path
63
- ::PigglyParser.new
53
+ def load_support
54
+ require "treetop"
55
+ require "piggly/parser/treetop_ruby19_patch"
56
+ require "piggly/parser/nodes"
57
+ end
64
58
  end
65
59
 
66
60
  end
@@ -1,44 +1,31 @@
1
1
  grammar Piggly
2
- # include Keywords
3
- # include Expressions
4
- # include Statements
5
- # include Tokens
6
2
 
7
3
  rule start
8
- procedure+
9
- end
10
-
11
- # elements[20] is procedure body
12
- rule procedure
13
- procedureHeader
14
- name:tIdentifier tSpace?
15
- parameters:parameterList tSpace
16
- procedureReturn
17
- return:tType tSpace kwAS tSpace
18
- procedureBody
19
- procedureFooter <Procedure>
20
- end
21
-
22
- rule procedureHeader
23
- tSpace? 'create' tSpace 'or' tSpace 'replace' tSpace 'function' tSpace <TextNode>
24
- end
25
-
26
- rule procedureReturn
27
- 'returns' tSpace ( 'setof' tSpace )? <TextNode>
28
- end
29
-
30
- rule procedureBody
31
- dollarQuoteMarker tSpace? body:block ';'? tSpace? dollarQuoteMarker
32
- / "'" tSpace? body:block ';'? tSpace? "'"
4
+ tSpace?
5
+ block ';'?
6
+ tSpace?
33
7
  end
34
8
 
35
- rule procedureFooter
36
- expressionUntilSemiColon ';' tSpace? <TextNode>
37
- end
38
-
39
- rule parameterList
40
- '(' ( tSpace? name:tIdentifier tSpace type:tType tSpace? ',' )*
41
- ( tSpace? name:tIdentifier tSpace type:tType )? tSpace? ')'
9
+ rule block
10
+ label_open:tLabelDefinition tSpace
11
+ blockDeclarations:stmtDeclare*
12
+ kwBEGIN
13
+ bodySpace:tSpace
14
+ bodyStub:stubNode
15
+ body:statement*
16
+ blockExceptions?
17
+ kwEND
18
+ ( tSpace label_close:tLabel )?
19
+ tSpace? <Piggly::Parser::Nodes::Block>
20
+ /
21
+ blockDeclarations:stmtDeclare*
22
+ kwBEGIN
23
+ bodySpace:tSpace
24
+ bodyStub:stubNode
25
+ body:statement*
26
+ blockExceptions?
27
+ kwEND
28
+ tSpace? <Piggly::Parser::Nodes::Block>
42
29
  end
43
30
 
44
31
  rule statement
@@ -49,60 +36,37 @@ grammar Piggly
49
36
  / stmtLoop
50
37
  / stmtWhileLoop
51
38
  / stmtForLoop
39
+ / stmtForEachLoop
52
40
  / stmtExit
53
41
  / stmtContinue
54
42
  / stmtReturn
55
43
  / stmtRaise
56
44
  / stmtExecSql
57
45
  / stmtNull
58
- / stmtPerform
59
- / stmtDynamicExecute
60
- / stmtGetDiag
61
- / stmtOpen
62
- / stmtFetch
63
- / stmtMove
64
- / stmtClose ) tail:tSpace? <Statement>
65
- end
66
-
67
- rule block
68
- label_open:tLabel tSpace
69
- blockDeclarations:stmtDeclare*
70
- kwBEGIN
71
- bodySpace:tSpace
72
- bodyStub:stubNode
73
- body:statement*
74
- blockExceptions?
75
- kwEND
76
- ( tSpace label_close:tLabel )?
77
- tSpace? <Block>
78
- /
79
- blockDeclarations:stmtDeclare*
80
- kwBEGIN
81
- bodySpace:tSpace
82
- bodyStub:stubNode
83
- body:statement*
84
- blockExceptions?
85
- kwEND
86
- tSpace? <Block>
46
+ / stmtGetDiag )
47
+ tail:tSpace? <Piggly::Parser::Nodes::Statement>
87
48
  end
88
49
 
89
50
  rule stmtAssignment
90
- lval:lValue tSpace? kwASSIGN ws? rval:expressionUntilSemiColon ';' <Assignment>
51
+ lval:lValue tSpace? kwASSIGN ws?
52
+ rval:expressionUntilSemiColon ';' <Piggly::Parser::Nodes::Assignment>
91
53
  end
92
54
 
93
55
  rule stmtCase
94
- kwCASE tSpace
56
+ kwCASE tSpace
95
57
  cases:condWhen+
96
58
  else:stmtElse?
97
- kwEND tSpace kwCASE tSpace? ';' <Cond>
59
+ kwEND tSpace kwCASE
60
+ tSpace? ';' <Piggly::Parser::Nodes::Cond>
98
61
  /
99
62
  kwCASE tSpace
100
63
  expr:expressionUntilWhen
101
64
  cases:caseWhen+
102
65
  else:stmtElse?
103
- kwEND tSpace kwCASE tSpace? ';' <Case>
66
+ kwEND tSpace kwCASE
67
+ tSpace? ';' <Piggly::Parser::Nodes::Case>
104
68
  end
105
-
69
+
106
70
  rule stmtIf
107
71
  kwIF
108
72
  condSpace:tSpace?
@@ -113,9 +77,9 @@ grammar Piggly
113
77
  bodyStub:stubNode
114
78
  body:statement*
115
79
  else:stmtElse?
116
- kwEND tSpace kwIF tSpace? ';' <If>
80
+ kwEND tSpace kwIF tSpace? ';' <Piggly::Parser::Nodes::If>
117
81
  end
118
-
82
+
119
83
  rule stmtElse
120
84
  kwELSIF
121
85
  condSpace:tSpace?
@@ -125,34 +89,36 @@ grammar Piggly
125
89
  bodySpace:tSpace
126
90
  bodyStub:stubNode
127
91
  body:statement*
128
- else:stmtElse? <If>
92
+ else:stmtElse? <Piggly::Parser::Nodes::If>
129
93
  /
130
94
  kwELSE
131
95
  bodySpace:tSpace
132
96
  bodyStub:stubNode
133
- body:statement* <Else>
97
+ body:statement* <Piggly::Parser::Nodes::Else>
134
98
  end
135
-
99
+
136
100
  rule stmtLoop
137
- label_open:tLabel tSpace
101
+ label_open:tLabelDefinition tSpace
138
102
  cond:kwLOOP
139
103
  bodySpace:tSpace
140
104
  bodyStub:stubNode
141
105
  body:statement*
106
+ doneStub:stubNode
142
107
  kwEND tSpace kwLOOP
143
- ( tSpace label_close:tIdentifier )?
144
- tSpace? ';' exitStub:stubNode <Loop>
108
+ ( tSpace label_close:tLabel <Piggly::Parser::Nodes::TLabel> )?
109
+ tSpace? ';' exitStub:stubNode <Piggly::Parser::Nodes::Loop>
145
110
  /
146
111
  cond:kwLOOP
147
112
  bodySpace:tSpace
148
113
  bodyStub:stubNode
149
114
  body:statement*
115
+ doneStub:stubNode
150
116
  kwEND tSpace kwLOOP
151
- tSpace? ';' exitStub:stubNode <Loop>
117
+ tSpace? ';' exitStub:stubNode <Piggly::Parser::Nodes::Loop>
152
118
  end
153
-
119
+
154
120
  rule stmtWhileLoop
155
- label_open:tLabel tSpace
121
+ label_open:tLabelDefinition tSpace
156
122
  kwWHILE
157
123
  condSpace:tSpace?
158
124
  condStub:stubNode
@@ -162,8 +128,8 @@ grammar Piggly
162
128
  bodyStub:stubNode
163
129
  body:statement*
164
130
  kwEND tSpace kwLOOP
165
- ( tSpace label_close:tIdentifier )?
166
- tSpace? ';' <WhileLoop>
131
+ ( tSpace label_close:tLabel <Piggly::Parser::Nodes::TLabel> )?
132
+ tSpace? ';' <Piggly::Parser::Nodes::WhileLoop>
167
133
  /
168
134
  kwWHILE
169
135
  condSpace:tSpace?
@@ -174,12 +140,39 @@ grammar Piggly
174
140
  bodyStub:stubNode
175
141
  body:statement*
176
142
  kwEND tSpace kwLOOP
177
- tSpace? ';' <WhileLoop>
143
+ tSpace? ';' <Piggly::Parser::Nodes::WhileLoop>
144
+ end
145
+
146
+ rule stmtForEachLoop
147
+ label_open:tLabelDefinition tSpace
148
+ kwFOREACH tSpace tIdentifier tSpace
149
+ kwIN tSpace kwARRAY
150
+ condSpace:tSpace
151
+ cond:expressionUntilLoop
152
+ kwLOOP
153
+ bodySpace:tSpace
154
+ bodyStub:stubNode
155
+ body:statement*
156
+ doneStub:stubNode
157
+ kwEND tSpace kwLOOP
158
+ ( tSpace label_close:tLabel <Piggly::Parser::Nodes::TLabel> )?
159
+ tSpace? ';' exitStub:stubNode <Piggly::Parser::Nodes::ForEachLoop>
160
+ /
161
+ kwFOREACH tSpace tIdentifier tSpace
162
+ kwIN tSpace kwARRAY
163
+ condSpace:tSpace
164
+ cond:expressionUntilLoop
165
+ kwLOOP
166
+ bodySpace:tSpace
167
+ bodyStub:stubNode
168
+ body:statement*
169
+ doneStub:stubNode
170
+ kwEND tSpace kwLOOP
171
+ tSpace? ';' exitStub:stubNode <Piggly::Parser::Nodes::ForEachLoop>
178
172
  end
179
-
180
- # loop coverage calculated by using exitStub
173
+
181
174
  rule stmtForLoop
182
- label_open:tLabel tSpace
175
+ label_open:tLabelDefinition tSpace
183
176
  kwFOR tSpace identifierList tSpace
184
177
  kwIN
185
178
  condSpace:tSpace
@@ -190,9 +183,8 @@ grammar Piggly
190
183
  body:statement*
191
184
  doneStub:stubNode
192
185
  kwEND tSpace kwLOOP
193
- ( tSpace label_close:tIdentifier )?
194
- tSpace? ';'
195
- exitStub:stubNode <ForLoop>
186
+ ( tSpace label_close:tLabel <Piggly::Parser::Nodes::TLabel> )?
187
+ tSpace? ';' exitStub:stubNode <Piggly::Parser::Nodes::ForLoop>
196
188
  /
197
189
  kwFOR tSpace identifierList tSpace
198
190
  kwIN
@@ -203,36 +195,40 @@ grammar Piggly
203
195
  bodyStub:stubNode
204
196
  body:statement*
205
197
  doneStub:stubNode
206
- kwEND tSpace kwLOOP tSpace? ';'
207
- exitStub:stubNode <ForLoop>
198
+ kwEND tSpace kwLOOP
199
+ tSpace? ';' exitStub:stubNode <Piggly::Parser::Nodes::ForLoop>
208
200
  end
209
-
201
+
210
202
  rule stmtForSql
211
- sqlKeyword tSpace expressionUntilLoop <Sql>
203
+ sqlKeyword tSpace expressionUntilLoop <Piggly::Parser::Nodes::Sql>
212
204
  end
213
-
205
+
214
206
  rule stmtExit
215
207
  bodyStub:stubNode
216
- body:( kwEXIT (tSpace label:tIdentifier)? ) tSpace? ';' <Exit>
208
+ body:( kwEXIT (tSpace label:tLabel <Piggly::Parser::Nodes::TLabel> )? )
209
+ tSpace? ';' <Piggly::Parser::Nodes::Exit>
217
210
  /
218
- body:( kwEXIT (tSpace label:tIdentifier)? ) tSpace
211
+ body:( kwEXIT (tSpace label:tLabel <Piggly::Parser::Nodes::TLabel> )? )
212
+ tSpace
219
213
  kwWHEN
220
214
  condSpace:tSpace
221
215
  condStub:stubNode
222
- cond:expressionUntilSemiColon ';' <ExitWhen>
216
+ cond:expressionUntilSemiColon ';' <Piggly::Parser::Nodes::ExitWhen>
223
217
  end
224
218
 
225
219
  rule stmtContinue
226
220
  bodyStub:stubNode
227
- body:( kwCONTINUE (tSpace label:tIdentifier)? ) tSpace? ';' <Continue>
221
+ body:( kwCONTINUE (tSpace label:tLabel <Piggly::Parser::Nodes::TLabel> )? )
222
+ tSpace? ';' <Piggly::Parser::Nodes::Continue>
228
223
  /
229
- body:( kwCONTINUE (tSpace label:tIdentifier)? ) tSpace
224
+ body:( kwCONTINUE (tSpace label:tLabel <Piggly::Parser::Nodes::TLabel> )? )
225
+ tSpace
230
226
  kwWHEN
231
227
  condSpace:tSpace
232
228
  condStub:stubNode
233
- cond:expressionUntilSemiColon ';' <ContinueWhen>
229
+ cond:expressionUntilSemiColon ';' <Piggly::Parser::Nodes::ContinueWhen>
234
230
  end
235
-
231
+
236
232
  rule stmtReturn
237
233
  bodyStub:stubNode
238
234
  body:(kwRETURN ( tSpace? &';'
@@ -240,10 +236,10 @@ grammar Piggly
240
236
  / tSpace kwQUERY tSpace expressionUntilSemiColon
241
237
  / expressionUntilSemiColon )) ';'
242
238
  end
243
-
239
+
244
240
  rule stmtRaise
245
241
  bodyStub:stubNode
246
- body:(kwRAISE tSpace level:kwEXCEPTION tSpace expr:expressionUntilSemiColon) ';' <Throw>
242
+ body:(kwRAISE tSpace level:kwEXCEPTION tSpace expr:expressionUntilSemiColon) ';' <Piggly::Parser::Nodes::Throw>
247
243
  /
248
244
  kwRAISE tSpace
249
245
  level:( kwWARNING
@@ -252,58 +248,33 @@ grammar Piggly
252
248
  / kwLOG
253
249
  / kwDEBUG )
254
250
  tSpace
255
- expr:expressionUntilSemiColon ';' <Raise>
251
+ expr:expressionUntilSemiColon ';' <Piggly::Parser::Nodes::Raise>
256
252
  end
257
-
253
+
258
254
  rule stmtExecSql
259
- sqlKeyword tSpace expressionUntilSemiColon ';' <Sql>
260
- end
261
-
262
- rule stmtDynamicExecute
263
- kwEXECUTE tSpace expressionUntilSemiColon ';'
264
- end
265
-
266
- rule stmtPerform
267
- kwPERFORM tSpace expressionUntilSemiColon ';'
268
- end
269
-
270
- rule stmtOpen
271
- kwOPEN notImplemented
272
- end
273
-
274
- rule stmtFetch
275
- kwFETCH notImplemented
255
+ sqlKeyword tSpace expressionUntilSemiColon ';' <Piggly::Parser::Nodes::Sql>
276
256
  end
277
-
278
- rule stmtMove
279
- kwMOVE notImplemented
280
- end
281
-
282
- rule stmtClose
283
- kwCLOSE notImplemented
284
- end
285
-
257
+
286
258
  rule stmtGetDiag
287
259
  kwGET tSpace
288
260
  kwPERFORM tSpace
289
261
  notImplemented
290
262
  end
291
-
263
+
292
264
  rule stmtNull
293
265
  kwNULL tSpace? ';'
294
266
  end
295
-
296
- ##
267
+
297
268
  #############################################################################
298
-
269
+
299
270
  rule stmtDeclare
300
271
  kwDECLARE tSpace varDeclaration*
301
272
  end
302
273
 
303
274
  rule varDeclaration
304
275
  name:tIdentifier tSpace ( kwCONSTANT tSpace )?
305
- type:tType ( tSpace kwNOT tSpace kwNULL )?
306
- ( tSpace kwASSIGN tSpace? rval:expressionUntilSemiColon )?
276
+ type:tType ( tSpace kwNOT tSpace kwNULL )?
277
+ ( tSpace? kwASSIGN tSpace? rval:expressionUntilSemiColon )?
307
278
  tSpace?
308
279
  ';' tSpace?
309
280
  end
@@ -315,7 +286,7 @@ grammar Piggly
315
286
  rule blockExceptions
316
287
  kwEXCEPTION tSpace cases:exceptionCase*
317
288
  end
318
-
289
+
319
290
  rule exceptionCase
320
291
  # cannot provide branch-coverage on cond
321
292
  kwWHEN
@@ -324,7 +295,7 @@ grammar Piggly
324
295
  kwTHEN
325
296
  bodySpace:tSpace
326
297
  bodyStub:stubNode
327
- body:statement* <Catch>
298
+ body:statement* <Piggly::Parser::Nodes::Catch>
328
299
  end
329
300
 
330
301
  rule caseWhen
@@ -335,7 +306,7 @@ grammar Piggly
335
306
  kwTHEN
336
307
  bodySpace:tSpace
337
308
  bodyStub:stubNode
338
- body:statement* <Case>
309
+ body:statement* <Piggly::Parser::Nodes::CaseWhen>
339
310
  end
340
311
 
341
312
  rule condWhen
@@ -346,97 +317,103 @@ grammar Piggly
346
317
  kwTHEN
347
318
  bodySpace:tSpace
348
319
  bodyStub:stubNode
349
- body:statement* <Cond>
320
+ body:statement* <Piggly::Parser::Nodes::CondWhen>
350
321
  end
351
-
322
+
352
323
  ## EXPRESSIONS
353
324
  #############################################################################
354
-
355
- # it would be nice to match parens and brackets here, but we again assume there
356
- # are no syntax errors in the proc and let the database worry about them
357
-
325
+
358
326
  rule expressionUntilSemiColon
359
- head:tSpace? expr:( tString / skipWords / tSpace !';' / !tSpace [^;] )* tail:tSpace? &';' <Expression>
327
+ head:tSpace? expr:( tString / skipWords / tSpace !';' / !tSpace [^;] )*
328
+ tail:tSpace? &';' <Piggly::Parser::Nodes::Expression>
360
329
  end
361
-
330
+
362
331
  rule expressionUntilClosingBracket
363
- head:tSpace? expr:( tString / skipWords / tSpace !']' / !tSpace [^\]] )+ tail:tSpace? &']' <Expression>
332
+ head:tSpace? expr:( tString / skipWords / tSpace !']' / !tSpace [^\]] )+
333
+ tail:tSpace? &']' <Piggly::Parser::Nodes::Expression>
364
334
  end
365
-
335
+
366
336
  rule expressionUntilThen
367
- head:tSpace? expr:( tString / skipWords / tSpace !kwTHEN / !tSpace !kwTHEN . )+ tail:tSpace &kwTHEN <Expression>
337
+ head:tSpace? expr:( tString / skipWords / tSpace !kwTHEN / !tSpace !kwTHEN . )+
338
+ tail:tSpace &kwTHEN <Piggly::Parser::Nodes::Expression>
368
339
  end
369
-
340
+
370
341
  rule expressionUntilWhen
371
- head:tSpace? expr:( tString / skipWords / tSpace !kwWHEN / !tSpace !kwWHEN . )+ tail:tSpace &kwWHEN <Expression>
342
+ head:tSpace? expr:( tString / skipWords / tSpace !kwWHEN / !tSpace !kwWHEN . )+
343
+ tail:tSpace &kwWHEN <Piggly::Parser::Nodes::Expression>
372
344
  end
373
-
345
+
374
346
  rule expressionUntilLoop
375
- head:tSpace? expr:( tString / skipWords / tSpace !kwLOOP / !tSpace !kwLOOP . )+ tail:tSpace &kwLOOP <Expression>
347
+ head:tSpace? expr:( tString / skipWords / tSpace !kwLOOP / !tSpace !kwLOOP . )+
348
+ tail:tSpace &kwLOOP <Piggly::Parser::Nodes::Expression>
376
349
  end
377
350
 
378
351
  rule skipWords
379
- [a-z0-9_]+ <TextNode>
352
+ [a-z0-9_]+ <Piggly::Parser::Nodes::TextNode>
380
353
  end
381
354
 
382
- ##
383
355
  #############################################################################
384
356
 
385
357
  rule ws
386
- [ \t\n\v\f\r]+ <TextNode>
358
+ [ \t\n\v\f\r]+ <Piggly::Parser::Nodes::TextNode>
387
359
  end
388
-
360
+
389
361
  rule dollarQuoteMarker
390
- '$' tag:( [a-z\200-\377_] [a-z\200-\377_0-9]* )? '$' <TDollarQuoteMarker>
362
+ '$' tag:( [a-z\200-\377_] [a-z\200-\377_0-9]* )? '$' <Piggly::Parser::Nodes::TDollarQuoteMarker>
391
363
  end
392
-
364
+
393
365
  rule stubNode
394
- '' <StubNode>
366
+ '' <Piggly::Parser::Nodes::StubNode>
395
367
  end
396
368
 
397
369
  rule notImplemented
398
- '' <NotImplemented>
370
+ '' <Piggly::Parser::Nodes::NotImplemented>
399
371
  end
400
-
372
+
401
373
  rule lValue
402
- tIdentifier sub:('[' expressionUntilClosingBracket ']')+ next:('.' lValue)+ <Assignable>
403
- / tIdentifier sub:('[' expressionUntilClosingBracket ']')+ <Assignable>
404
- / tIdentifier next:('.' lValue)+ <Assignable>
405
- / tIdentifier x:'' <Assignable>
374
+ tIdentifier
375
+ ( '[' expressionUntilClosingBracket ']' )*
376
+ ( [.] lValue )*
377
+
378
+ <Piggly::Parser::Nodes::Assignable>
406
379
  end
407
-
380
+
408
381
  ## BASIC TOKENS
409
382
  #############################################################################
410
383
 
411
384
  rule tEOF
412
385
  !.
413
386
  end
414
-
387
+
388
+ rule tLabelDefinition
389
+ '<<' tSpace? tLabel tSpace? '>>' <Piggly::Parser::Nodes::TLabel>
390
+ end
391
+
415
392
  rule tLabel
416
- '<<' tSpace? name:tIdentifier tSpace? '>>' <TLabel>
393
+ tIdentifier
417
394
  end
418
-
395
+
419
396
  rule tIdentifier
420
- ( '"' [^"]+ '"' )+ <TIdentifier>
421
- / !keyword ( [a-z\200-\377_] [a-z\200-\377_0-9$]* ) <TIdentifier>
397
+ ( '"' [^"]+ '"' )+ <Piggly::Parser::Nodes::TIdentifier>
398
+ / !keyword ( [a-z\200-\377_] [a-z\200-\377_0-9$]* ) <Piggly::Parser::Nodes::TIdentifier>
422
399
  end
423
400
 
424
401
  # not context sensitive so opening and closing tag might not match
425
402
  rule tString
426
- openTag:dollarQuoteMarker content:(!dollarQuoteMarker .)* closeTag:dollarQuoteMarker <TString> /
427
- "E'" content:("''" / [^'])* "'" <TString> /
428
- "'" content:("''" / [^'])* "'" <TString>
403
+ openTag:dollarQuoteMarker content:(!dollarQuoteMarker .)* closeTag:dollarQuoteMarker <Piggly::Parser::Nodes::TString> /
404
+ "E'" content:("''" / [^'])* "'" <Piggly::Parser::Nodes::TString> /
405
+ "'" content:("''" / [^'])* "'" <Piggly::Parser::Nodes::TString>
429
406
  end
430
-
407
+
431
408
  # beware this is quite broad and might match things it shouldn't
432
409
  rule tType
433
410
  [a-z\200-\377_]
434
411
  ( '(' rType ')' /
435
412
  '[' rType ']' /
436
- [a-z\200-\377_0-9$%]+ /
437
- ws !( kwAS / kwNOT / kwASSIGN / kwDEFAULT ) )* <TDatatype>
413
+ [a-z\200-\377_0-9$%]+ '.'? /
414
+ ws !( kwAS / kwNOT / kwASSIGN / kwDEFAULT ) )* <Piggly::Parser::Nodes::TDatatype>
438
415
  end
439
-
416
+
440
417
  rule rType
441
418
  ( '(' rType ')' /
442
419
  '[' rType ']' /
@@ -444,14 +421,14 @@ grammar Piggly
444
421
  end
445
422
 
446
423
  rule tSpace
447
- ws !tComment <TextNode>
424
+ ws !tComment <Piggly::Parser::Nodes::TextNode>
448
425
  /
449
426
  ( ws / tComment )+
450
427
  end
451
-
428
+
452
429
  rule tComment
453
- '/*' content:(!'*/' .)* '*/' <TComment> /
454
- '--' content:[^\n]* ("\n" / tEOF) <TComment>
430
+ '/*' content:(!'*/' .)* '*/' <Piggly::Parser::Nodes::TComment> /
431
+ '--' content:[^\n]* ("\n" / tEOF) <Piggly::Parser::Nodes::TComment>
455
432
  end
456
433
 
457
434
  ##
@@ -480,27 +457,34 @@ grammar Piggly
480
457
  'cast' tSpace? '(' tSpace? tString tSpace kwAS tSpace tType tSpace? ')' /
481
458
  'cast' tSpace? '(' tSpace? tNumber tSpace kwAS tSpace tType tSpace? ')'
482
459
  end
483
-
460
+
484
461
  ## KEYWORDS
485
462
  #############################################################################
486
-
463
+
487
464
  rule sqlKeyword
488
465
  ( 'insert'
489
466
  / 'select'
490
467
  / 'update'
491
468
  / 'delete'
469
+ / 'perform'
470
+ / 'execute'
471
+ / 'open'
472
+ / 'close'
473
+ / 'lock'
474
+ / 'fetch'
475
+ / 'move'
476
+ / 'truncate'
477
+ / 'create'
492
478
  / 'drop'
493
479
  / 'alter'
494
480
  / 'commit'
495
481
  / 'copy'
496
482
  / 'create'
497
- / 'begin'
498
- / 'rollback'
499
483
  / 'set'
500
484
  / 'start'
501
- / 'vacuum' ) ![a-z0-9] <TextNode>
485
+ / 'notify' ) ![a-z0-9] <Piggly::Parser::Nodes::TKeyword>
502
486
  end
503
-
487
+
504
488
  rule keyword
505
489
  # WHEN is checked first as a minor optimization to distinguish
506
490
  # CONTINUE tIdentifier WHEN cond;
@@ -509,239 +493,231 @@ grammar Piggly
509
493
  # CONTINUE WHEN cond;
510
494
  # EXIT WHEN cond;
511
495
 
512
- kwWHEN / kwAS / kwASSIGN / kwALIAS / kwBEGIN / kwBY / kwCASE / kwCLOSE
496
+ kwWHEN / kwAS / kwASSIGN / kwALIAS / kwBEGIN / kwBY / kwCASE / kwARRAY
513
497
  / kwCONSTANT / kwCONTINUE / kwCURSOR / kwDEBUG / kwDECLARE / kwDEFAULT
514
498
  / kwDIAGNOSTICS / kwELSE / kwELSIF / kwEND / kwEXCEPTION / kwEXECUTE / kwEXIT
515
- / kwFETCH / kwFOR / kwFROM / kwGET / kwIF / kwIN / kwINFO / kwINSERT / kwINTO
516
- / kwIS / kwLOG / kwLOOP / kwMOVE / kwNOT / kwNOTICE / kwNULL / kwOPEN
517
- / kwOR / kwPERFORM / kwRAISE / kwRENAME / kwRESULTOID / kwRETURN
499
+ / kwFOR / kwFROM / kwGET / kwIF / kwIN / kwINFO / kwINSERT / kwINTO
500
+ / kwIS / kwLOG / kwLOOP / kwNOT / kwNOTICE / kwNULL / kwFOREACH
501
+ / kwOR / kwRAISE / kwRENAME / kwRESULTOID / kwRETURN
518
502
  / kwREVERSE / kwROWCOUNT / kwSCROLL / kwSTRICT / kwTHEN / kwTO / kwTYPE
519
503
  / kwWARNING / kwWHILE
520
504
  end
521
-
505
+
522
506
  # this terminates keywords
523
507
  rule x
524
508
  [^a-z0-9_]
525
509
  end
526
-
510
+
527
511
  rule kwAS
528
- 'as' ![a-z0-9_] <TKeyword>
512
+ 'as' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
529
513
  end
530
-
514
+
531
515
  rule kwASSIGN
532
- ':=' <TKeyword> / '=' <TKeyword>
516
+ ':=' <Piggly::Parser::Nodes::TKeyword> / '=' <Piggly::Parser::Nodes::TKeyword>
533
517
  end
534
-
518
+
535
519
  rule kwALIAS
536
- 'alias' ![a-z0-9_] <TKeyword>
520
+ 'alias' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
521
+ end
522
+
523
+ rule kwARRAY
524
+ 'array' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
537
525
  end
538
-
526
+
539
527
  rule kwBEGIN
540
- 'begin' ![a-z0-9_] <TKeyword>
528
+ 'begin' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
541
529
  end
542
-
530
+
543
531
  rule kwBY
544
- 'by' ![a-z0-9_] <TKeyword>
532
+ 'by' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
545
533
  end
546
534
 
547
535
  rule kwCASE
548
- 'case' ![a-z0-9_] <TKeyword>
549
- end
550
-
551
- rule kwCLOSE
552
- 'close' ![a-z0-9_] <TKeyword>
536
+ 'case' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
553
537
  end
554
-
538
+
555
539
  rule kwCONSTANT
556
- 'constant' ![a-z0-9_] <TKeyword>
540
+ 'constant' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
557
541
  end
558
-
542
+
559
543
  rule kwCONTINUE
560
- 'continue' ![a-z0-9_] <TKeyword>
544
+ 'continue' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
561
545
  end
562
-
546
+
563
547
  rule kwCURSOR
564
- 'cursor' ![a-z0-9_] <TKeyword>
548
+ 'cursor' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
565
549
  end
566
-
550
+
567
551
  rule kwDEBUG
568
- 'debug' ![a-z0-9_] <TKeyword>
552
+ 'debug' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
569
553
  end
570
-
554
+
571
555
  rule kwDECLARE
572
- 'declare' ![a-z0-9_] <TKeyword>
556
+ 'declare' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
573
557
  end
574
-
558
+
575
559
  rule kwDEFAULT
576
- 'default' ![a-z0-9_] <TKeyword>
560
+ 'default' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
577
561
  end
578
-
562
+
579
563
  rule kwDIAGNOSTICS
580
- 'diagnostics' ![a-z0-9_] <TKeyword>
564
+ 'diagnostics' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
581
565
  end
582
-
566
+
583
567
  rule kwELSE
584
- 'else' ![a-z0-9_] <TKeyword>
568
+ 'else' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
585
569
  end
586
-
570
+
587
571
  rule kwELSIF
588
- ('elsif'/'elseif') ![a-z0-9_] <TKeyword>
572
+ ('elsif'/'elseif') ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
589
573
  end
590
-
574
+
591
575
  rule kwEND
592
- 'end' ![a-z0-9_] <TKeyword>
576
+ 'end' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
593
577
  end
594
-
578
+
595
579
  rule kwEXCEPTION
596
- 'exception' ![a-z0-9_] <TKeyword>
580
+ 'exception' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
597
581
  end
598
-
582
+
599
583
  rule kwEXECUTE
600
- 'execute' ![a-z0-9_] <TKeyword>
584
+ 'execute' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
601
585
  end
602
-
586
+
603
587
  rule kwEXIT
604
- 'exit' ![a-z0-9_] <TKeyword>
588
+ 'exit' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
605
589
  end
606
-
607
- rule kwFETCH
608
- 'fetch' ![a-z0-9_] <TKeyword>
609
- end
610
-
590
+
611
591
  rule kwFOR
612
- 'for' ![a-z0-9_] <TKeyword>
592
+ 'for' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
613
593
  end
614
-
594
+
595
+ rule kwFOREACH
596
+ 'foreach' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
597
+ end
598
+
615
599
  rule kwFROM
616
- 'from' ![a-z0-9_] <TKeyword>
600
+ 'from' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
617
601
  end
618
-
602
+
619
603
  rule kwGET
620
- 'get' ![a-z0-9_] <TKeyword>
604
+ 'get' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
621
605
  end
622
-
606
+
623
607
  rule kwIF
624
- 'if' ![a-z0-9_] <TKeyword>
608
+ 'if' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
625
609
  end
626
-
610
+
627
611
  rule kwIN
628
- 'in' ![a-z0-9_] <TKeyword>
612
+ 'in' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
629
613
  end
630
-
614
+
631
615
  rule kwINFO
632
- 'info' ![a-z0-9_] <TKeyword>
616
+ 'info' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
633
617
  end
634
-
618
+
635
619
  rule kwINSERT
636
- 'insert' ![a-z0-9_] <TKeyword>
620
+ 'insert' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
637
621
  end
638
-
622
+
639
623
  rule kwINTO
640
- 'into' ![a-z0-9_] <TKeyword>
624
+ 'into' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
641
625
  end
642
-
626
+
643
627
  rule kwIS
644
- 'is' ![a-z0-9_] <TKeyword>
628
+ 'is' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
645
629
  end
646
-
630
+
647
631
  rule kwLOG
648
- 'log' ![a-z0-9_] <TKeyword>
632
+ 'log' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
649
633
  end
650
-
634
+
651
635
  rule kwLOOP
652
- 'loop' ![a-z0-9_] <TKeyword>
653
- end
654
-
655
- rule kwMOVE
656
- 'move' ![a-z0-9_] <TKeyword>
636
+ 'loop' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
657
637
  end
658
-
638
+
659
639
  rule kwNEXT
660
- 'next' ![a-z0-9_] <TKeyword>
640
+ 'next' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
661
641
  end
662
-
642
+
663
643
  rule kwNOT
664
- 'not' ![a-z0-9_] <TKeyword>
644
+ 'not' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
665
645
  end
666
-
646
+
667
647
  rule kwNOTICE
668
- 'notice' ![a-z0-9_] <TKeyword>
648
+ 'notice' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
669
649
  end
670
-
650
+
671
651
  rule kwNULL
672
- 'null' ![a-z0-9_] <TKeyword>
673
- end
674
-
675
- rule kwOPEN
676
- 'open' ![a-z0-9_] <TKeyword>
652
+ 'null' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
677
653
  end
678
-
654
+
679
655
  rule kwOR
680
- 'or' ![a-z0-9_] <TKeyword>
656
+ 'or' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
681
657
  end
682
-
658
+
683
659
  rule kwPERFORM
684
- 'perform' ![a-z0-9_] <TKeyword>
660
+ 'perform' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
685
661
  end
686
662
 
687
663
  rule kwQUERY
688
- 'query' ![a-z0-9_] <TKeyword>
664
+ 'query' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
689
665
  end
690
-
666
+
691
667
  rule kwRAISE
692
- 'raise' ![a-z0-9_] <TKeyword>
668
+ 'raise' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
693
669
  end
694
-
670
+
695
671
  rule kwRENAME
696
- 'rename' ![a-z0-9_] <TKeyword>
672
+ 'rename' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
697
673
  end
698
-
674
+
699
675
  rule kwRESULTOID
700
- 'result_oid' ![a-z0-9_] <TKeyword>
676
+ 'result_oid' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
701
677
  end
702
-
678
+
703
679
  rule kwRETURN
704
- 'return' ![a-z0-9_] <TKeyword>
680
+ 'return' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
705
681
  end
706
-
682
+
707
683
  rule kwREVERSE
708
- 'reverse' ![a-z0-9_] <TKeyword>
684
+ 'reverse' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
709
685
  end
710
-
686
+
711
687
  rule kwROWCOUNT
712
- 'row_count' ![a-z0-9_] <TKeyword>
688
+ 'row_count' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
713
689
  end
714
-
690
+
715
691
  rule kwSCROLL
716
- 'scroll' ![a-z0-9_] <TKeyword>
692
+ 'scroll' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
717
693
  end
718
-
694
+
719
695
  rule kwSTRICT
720
- 'strict' ![a-z0-9_] <TKeyword>
696
+ 'strict' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
721
697
  end
722
-
698
+
723
699
  rule kwTHEN
724
- 'then' ![a-z0-9_] <TKeyword>
700
+ 'then' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
725
701
  end
726
-
702
+
727
703
  rule kwTO
728
- 'to' ![a-z0-9_] <TKeyword>
704
+ 'to' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
729
705
  end
730
-
706
+
731
707
  rule kwTYPE
732
- 'type' ![a-z0-9_] <TKeyword>
708
+ 'type' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
733
709
  end
734
-
710
+
735
711
  rule kwWARNING
736
- 'warning' ![a-z0-9_] <TKeyword>
712
+ 'warning' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
737
713
  end
738
-
714
+
739
715
  rule kwWHEN
740
- 'when' ![a-z0-9_] <TKeyword>
716
+ 'when' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
741
717
  end
742
718
 
743
719
  rule kwWHILE
744
- 'while' ![a-z0-9_] <TKeyword>
720
+ 'while' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword>
745
721
  end
746
-
722
+
747
723
  end