piggly 1.2.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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