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.
- checksums.yaml +7 -0
- data/README.md +163 -0
- data/Rakefile +29 -15
- data/bin/piggly +4 -244
- data/lib/piggly.rb +19 -17
- data/lib/piggly/command.rb +9 -0
- data/lib/piggly/command/base.rb +148 -0
- data/lib/piggly/command/report.rb +162 -0
- data/lib/piggly/command/test.rb +157 -0
- data/lib/piggly/command/trace.rb +90 -0
- data/lib/piggly/command/untrace.rb +78 -0
- data/lib/piggly/compiler.rb +7 -5
- data/lib/piggly/compiler/cache_dir.rb +119 -0
- data/lib/piggly/compiler/coverage_report.rb +63 -0
- data/lib/piggly/compiler/trace_compiler.rb +105 -0
- data/lib/piggly/config.rb +47 -22
- data/lib/piggly/dumper.rb +9 -0
- data/lib/piggly/dumper/index.rb +121 -0
- data/lib/piggly/dumper/qualified_name.rb +36 -0
- data/lib/piggly/dumper/qualified_type.rb +81 -0
- data/lib/piggly/dumper/reified_procedure.rb +142 -0
- data/lib/piggly/dumper/skeleton_procedure.rb +102 -0
- data/lib/piggly/installer.rb +84 -42
- data/lib/piggly/parser.rb +43 -49
- data/lib/piggly/parser/grammar.tt +289 -313
- data/lib/piggly/parser/nodes.rb +270 -211
- data/lib/piggly/parser/traversal.rb +35 -33
- data/lib/piggly/parser/treetop_ruby19_patch.rb +1 -1
- data/lib/piggly/profile.rb +81 -60
- data/lib/piggly/reporter.rb +5 -18
- data/lib/piggly/reporter/base.rb +103 -0
- data/lib/piggly/reporter/html_dsl.rb +63 -0
- data/lib/piggly/reporter/index.rb +108 -0
- data/lib/piggly/reporter/procedure.rb +104 -0
- data/lib/piggly/reporter/resources/highlight.js +21 -0
- data/lib/piggly/reporter/{piggly.css → resources/piggly.css} +52 -12
- data/lib/piggly/reporter/{sortable.js → resources/sortable.js} +0 -0
- data/lib/piggly/tags.rb +280 -0
- data/lib/piggly/task.rb +191 -40
- data/lib/piggly/util.rb +8 -27
- data/lib/piggly/util/blankslate.rb +114 -0
- data/lib/piggly/util/cacheable.rb +19 -0
- data/lib/piggly/util/enumerable.rb +44 -0
- data/lib/piggly/util/file.rb +17 -0
- data/lib/piggly/util/process_queue.rb +96 -0
- data/lib/piggly/util/thunk.rb +39 -0
- data/lib/piggly/version.rb +8 -8
- data/spec/examples/compiler/cacheable_spec.rb +190 -0
- data/spec/examples/compiler/report_spec.rb +25 -0
- data/spec/{compiler → examples/compiler}/trace_spec.rb +7 -57
- data/spec/examples/config_spec.rb +61 -0
- data/spec/examples/dumper/index_spec.rb +197 -0
- data/spec/examples/dumper/procedure_spec.rb +116 -0
- data/spec/{grammar → examples/grammar}/expression_spec.rb +60 -60
- data/spec/{grammar → examples/grammar}/statements/assignment_spec.rb +15 -15
- data/spec/examples/grammar/statements/declaration_spec.rb +21 -0
- data/spec/{grammar → examples/grammar}/statements/exception_spec.rb +10 -10
- data/spec/{grammar → examples/grammar}/statements/if_spec.rb +47 -34
- data/spec/{grammar → examples/grammar}/statements/loop_spec.rb +5 -5
- data/spec/{grammar → examples/grammar}/statements/sql_spec.rb +11 -11
- data/spec/{grammar → examples/grammar}/tokens/comment_spec.rb +11 -11
- data/spec/{grammar → examples/grammar}/tokens/datatype_spec.rb +14 -8
- data/spec/{grammar → examples/grammar}/tokens/identifier_spec.rb +26 -10
- data/spec/{grammar → examples/grammar}/tokens/keyword_spec.rb +5 -5
- data/spec/{grammar → examples/grammar}/tokens/label_spec.rb +7 -7
- data/spec/{grammar → examples/grammar}/tokens/literal_spec.rb +1 -1
- data/spec/examples/grammar/tokens/lval_spec.rb +50 -0
- data/spec/{grammar → examples/grammar}/tokens/number_spec.rb +1 -1
- data/spec/{grammar → examples/grammar}/tokens/sqlkeywords_spec.rb +1 -1
- data/spec/{grammar → examples/grammar}/tokens/string_spec.rb +9 -9
- data/spec/{grammar → examples/grammar}/tokens/whitespace_spec.rb +1 -1
- data/spec/examples/installer_spec.rb +59 -0
- data/spec/examples/parser/nodes_spec.rb +73 -0
- data/spec/examples/parser/traversal_spec.rb +14 -0
- data/spec/examples/parser_spec.rb +115 -0
- data/spec/examples/profile_spec.rb +153 -0
- data/spec/{reporter/html_spec.rb → examples/reporter/html/dsl_spec.rb} +0 -0
- data/spec/examples/reporter/html/index_spec.rb +0 -0
- data/spec/examples/reporter/html_spec.rb +1 -0
- data/spec/examples/reporter_spec.rb +0 -0
- data/spec/{compiler → examples}/tags_spec.rb +10 -10
- data/spec/examples/task_spec.rb +0 -0
- data/spec/examples/util/cacheable_spec.rb +41 -0
- data/spec/examples/util/enumerable_spec.rb +64 -0
- data/spec/examples/util/file_spec.rb +40 -0
- data/spec/examples/util/process_queue_spec.rb +16 -0
- data/spec/examples/util/thunk_spec.rb +58 -0
- data/spec/examples/version_spec.rb +0 -0
- data/spec/issues/007_spec.rb +25 -0
- data/spec/issues/008_spec.rb +73 -0
- data/spec/issues/018_spec.rb +25 -0
- data/spec/spec_helper.rb +253 -9
- metadata +136 -93
- data/README.markdown +0 -116
- data/lib/piggly/compiler/cache.rb +0 -151
- data/lib/piggly/compiler/pretty.rb +0 -67
- data/lib/piggly/compiler/queue.rb +0 -46
- data/lib/piggly/compiler/tags.rb +0 -244
- data/lib/piggly/compiler/trace.rb +0 -91
- data/lib/piggly/filecache.rb +0 -40
- data/lib/piggly/parser/parser.rb +0 -11794
- data/lib/piggly/reporter/html.rb +0 -207
- data/spec/compiler/cache_spec.rb +0 -9
- data/spec/compiler/pretty_spec.rb +0 -9
- data/spec/compiler/queue_spec.rb +0 -3
- data/spec/compiler/rewrite_spec.rb +0 -3
- data/spec/config_spec.rb +0 -58
- data/spec/filecache_spec.rb +0 -70
- data/spec/fixtures/snippets.sql +0 -158
- data/spec/grammar/tokens/lval_spec.rb +0 -50
- data/spec/parser_spec.rb +0 -8
- 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
|
data/lib/piggly/installer.rb
CHANGED
@@ -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
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
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
|
-
|
10
|
-
|
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
|
-
|
13
|
-
|
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
|
-
#
|
17
|
-
def
|
18
|
-
|
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
|
23
|
-
|
24
|
-
|
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
|
-
--
|
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 '#{
|
79
|
+
RAISE WARNING '#{@config.trace_prefix} % t', message;
|
34
80
|
ELSE
|
35
|
-
RAISE WARNING '#{
|
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
|
-
--
|
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 '#{
|
92
|
+
RAISE WARNING '#{@config.trace_prefix} % %', message, signal;
|
47
93
|
END $$ LANGUAGE 'plpgsql' VOLATILE;
|
48
94
|
SQL
|
49
95
|
|
50
|
-
connection.exec <<-SQL
|
51
|
-
--
|
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 '#{
|
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
|
-
--
|
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 '#{
|
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
|
-
--
|
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 '#{
|
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
|
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
|
data/lib/piggly/parser.rb
CHANGED
@@ -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
|
-
|
7
|
-
include FileCache
|
6
|
+
module Parser
|
8
7
|
|
9
|
-
|
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
|
-
|
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
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
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
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
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
|
-
|
59
|
-
Treetop::Compiler::GrammarCompiler.new.compile(grammar_path, parser_path)
|
48
|
+
::PigglyParser.new
|
60
49
|
end
|
50
|
+
|
51
|
+
private
|
61
52
|
|
62
|
-
|
63
|
-
|
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
|
-
|
9
|
-
|
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
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
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
|
-
/
|
59
|
-
|
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?
|
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
|
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
|
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:
|
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
|
-
|
144
|
-
|
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
|
-
|
117
|
+
tSpace? ';' exitStub:stubNode <Piggly::Parser::Nodes::Loop>
|
152
118
|
end
|
153
|
-
|
119
|
+
|
154
120
|
rule stmtWhileLoop
|
155
|
-
label_open:
|
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
|
-
|
166
|
-
|
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
|
-
|
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:
|
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
|
-
|
194
|
-
|
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
|
207
|
-
|
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:
|
208
|
+
body:( kwEXIT (tSpace label:tLabel <Piggly::Parser::Nodes::TLabel> )? )
|
209
|
+
tSpace? ';' <Piggly::Parser::Nodes::Exit>
|
217
210
|
/
|
218
|
-
body:( kwEXIT (tSpace label:
|
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:
|
221
|
+
body:( kwCONTINUE (tSpace label:tLabel <Piggly::Parser::Nodes::TLabel> )? )
|
222
|
+
tSpace? ';' <Piggly::Parser::Nodes::Continue>
|
228
223
|
/
|
229
|
-
body:( kwCONTINUE (tSpace label:
|
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
|
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* <
|
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* <
|
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 [^;] )*
|
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 [^\]] )+
|
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 . )+
|
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 . )+
|
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 . )+
|
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
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
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
|
-
|
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
|
-
/ '
|
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 /
|
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
|
-
/
|
516
|
-
/ kwIS / kwLOG / kwLOOP /
|
517
|
-
/ kwOR /
|
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
|