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