msgpack-idl 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +4 -0
- data/lib/msgpack/idl/ast.rb +164 -3
- data/lib/msgpack/idl/command/example.rb +64 -4
- data/lib/msgpack/idl/command/idl.rb +75 -42
- data/lib/msgpack/idl/command/vimcolor.rb +254 -0
- data/lib/msgpack/idl/command/vimcolor/mark.vim +67 -0
- data/lib/msgpack/idl/command/vimcolor/msgspec.vim +68 -0
- data/lib/msgpack/idl/error.rb +1 -1
- data/lib/msgpack/idl/evaluator.rb +283 -138
- data/lib/msgpack/idl/ir.rb +31 -6
- data/lib/msgpack/idl/parser/rule.rb +20 -3
- data/lib/msgpack/idl/parser/transform.rb +15 -18
- data/lib/msgpack/idl/version.rb +1 -1
- metadata +7 -4
@@ -0,0 +1,254 @@
|
|
1
|
+
#
|
2
|
+
# VimColor for Ruby
|
3
|
+
#
|
4
|
+
# Copyright (c) 2008-2011 FURUHASHI Sadayuki
|
5
|
+
#
|
6
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
+
# of this software and associated documentation files (the "Software"), to deal
|
8
|
+
# in the Software without restriction, including without limitation the rights
|
9
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
# copies of the Software, and to permit persons to whom the Software is
|
11
|
+
# furnished to do so, subject to the following conditions:
|
12
|
+
#
|
13
|
+
# The above copyright notice and this permission notice shall be included in
|
14
|
+
# all copies or substantial portions of the Software.
|
15
|
+
#
|
16
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22
|
+
# THE SOFTWARE.
|
23
|
+
#
|
24
|
+
|
25
|
+
class VimColor
|
26
|
+
VIM_COMMAND = "vim"
|
27
|
+
VIM_OPTIONS = %w[-R -X -Z -i NONE -u NONE -N]
|
28
|
+
VIM_PRESET = ["+set nomodeline", '+set expandtab'] # +set shiftwidth
|
29
|
+
VIM_POSTSET = [":let b:is_bash=1", ":filetype on"]
|
30
|
+
VIM_MARK_SCRIPT = File.join(File.dirname(__FILE__), 'vimcolor', 'mark.vim')
|
31
|
+
VIM_UNESCAPE = {'&l' => '<', '&g' => '>', '&a' => '&'}
|
32
|
+
|
33
|
+
def initialize(command=nil, options=nil, preset=nil, postset=nil)
|
34
|
+
require 'tempfile'
|
35
|
+
@command = VIM_COMMAND.dup
|
36
|
+
@options = VIM_OPTIONS + (options || [])
|
37
|
+
@preset = VIM_PRESET + (preset || [])
|
38
|
+
@postset = VIM_POSTSET + (postset || [])
|
39
|
+
end
|
40
|
+
|
41
|
+
attr_accessor :command, :options, :preset, :postset
|
42
|
+
|
43
|
+
def run_file(path, options, formatter_class, *formatter_args)
|
44
|
+
preset = @preset.dup
|
45
|
+
postset = @postset.dup
|
46
|
+
|
47
|
+
if formatter_class.class == Symbol
|
48
|
+
formatter_class = self.class.const_get("Format_#{formatter_class}")
|
49
|
+
end
|
50
|
+
|
51
|
+
if options.is_a? Hash
|
52
|
+
if options.include? :filetype
|
53
|
+
postset.unshift(":set filetype=#{options[:filetype]}")
|
54
|
+
end
|
55
|
+
if options.include? :encoding
|
56
|
+
preset.unshift("+set encoding=#{options[:encoding]}")
|
57
|
+
end
|
58
|
+
else
|
59
|
+
postset.unshift(":set filetype=#{options}")
|
60
|
+
end
|
61
|
+
|
62
|
+
vimout = nil
|
63
|
+
tmp_stream = Tempfile.new('ruby-vimcolor')
|
64
|
+
begin
|
65
|
+
tmp_path = tmp_stream.path
|
66
|
+
tmp_stream.puts <<SCRIPT
|
67
|
+
:syntax on
|
68
|
+
#{postset.join("\n")}
|
69
|
+
:source #{VIM_MARK_SCRIPT}
|
70
|
+
:write! #{tmp_path}
|
71
|
+
:qall!
|
72
|
+
|
73
|
+
SCRIPT
|
74
|
+
tmp_stream.flush
|
75
|
+
pid = Process.fork {
|
76
|
+
STDIN.reopen "/dev/null"
|
77
|
+
STDOUT.reopen "/dev/null", "a"
|
78
|
+
STDERR.reopen "/dev/null", "a"
|
79
|
+
args = []
|
80
|
+
args.concat @options
|
81
|
+
args.concat ['-s', tmp_path]
|
82
|
+
args.push path
|
83
|
+
args.concat preset
|
84
|
+
exec(@command, *args)
|
85
|
+
exit 127
|
86
|
+
}
|
87
|
+
Process.waitpid(pid)
|
88
|
+
tmp_stream.seek(0)
|
89
|
+
vimout = tmp_stream.read
|
90
|
+
ensure
|
91
|
+
tmp_stream.close
|
92
|
+
end
|
93
|
+
|
94
|
+
require 'strscan'
|
95
|
+
s = StringScanner.new(vimout)
|
96
|
+
|
97
|
+
formatter = formatter_class.new(*formatter_args)
|
98
|
+
while s.scan_until(/(.*?)>(.*?)>(.*?)<\2</m)
|
99
|
+
formatter.push('', s[1]) unless s[1].empty?
|
100
|
+
type = s[2]
|
101
|
+
text = s[3]
|
102
|
+
text.gsub!(/&[agl]/) do
|
103
|
+
VIM_UNESCAPE[$&]
|
104
|
+
end
|
105
|
+
formatter.push(type, text)
|
106
|
+
end
|
107
|
+
formatter.result
|
108
|
+
end
|
109
|
+
|
110
|
+
|
111
|
+
def run_stream(stream, options, formatter_class, *formatter_args)
|
112
|
+
tmp_in = Tempfile.new('ruby-vimcolor-input')
|
113
|
+
begin
|
114
|
+
tmp_in.write(stream.read)
|
115
|
+
tmp_in.flush
|
116
|
+
run_file(tmp_in.path, options, formatter_class, *formatter_args)
|
117
|
+
ensure
|
118
|
+
tmp_in.close
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
|
123
|
+
def run(str, options, formatter_class, *formatter_args)
|
124
|
+
tmp_in = Tempfile.new('ruby-vimcolor-input')
|
125
|
+
begin
|
126
|
+
tmp_in.write(str)
|
127
|
+
tmp_in.flush
|
128
|
+
run_file(tmp_in.path, options, formatter_class, *formatter_args)
|
129
|
+
ensure
|
130
|
+
tmp_in.close
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
|
136
|
+
|
137
|
+
class VimColor
|
138
|
+
|
139
|
+
class Format_array
|
140
|
+
def initialize
|
141
|
+
@result = []
|
142
|
+
end
|
143
|
+
def push(type, text)
|
144
|
+
@result.push [type, text]
|
145
|
+
end
|
146
|
+
attr_reader :result
|
147
|
+
end
|
148
|
+
|
149
|
+
|
150
|
+
class Format_xml
|
151
|
+
def initialize
|
152
|
+
@result = ''
|
153
|
+
end
|
154
|
+
def push(type, text)
|
155
|
+
VimColor._escape_xml!(text)
|
156
|
+
type = 'Normal' if type.empty?
|
157
|
+
@result << %[<#{type}>#{text}</#{type}>]
|
158
|
+
end
|
159
|
+
attr_reader :result
|
160
|
+
end
|
161
|
+
|
162
|
+
|
163
|
+
class Format_html
|
164
|
+
def initialize(class_prefix = 'syn')
|
165
|
+
@result = ''
|
166
|
+
@prefix = class_prefix
|
167
|
+
end
|
168
|
+
def push(type, text)
|
169
|
+
VimColor._escape_xml!(text)
|
170
|
+
if type.empty?
|
171
|
+
@result << text
|
172
|
+
else
|
173
|
+
@result << %[<span class="#{@prefix}#{type}">#{text}</span>]
|
174
|
+
end
|
175
|
+
end
|
176
|
+
attr_reader :result
|
177
|
+
end
|
178
|
+
|
179
|
+
|
180
|
+
def self._escape_xml!(text)
|
181
|
+
text.gsub!("&", "&")
|
182
|
+
text.gsub!("<", "<")
|
183
|
+
text.gsub!(">", ">")
|
184
|
+
text.gsub!("'", "'")
|
185
|
+
text.gsub!('"', """)
|
186
|
+
text
|
187
|
+
end
|
188
|
+
|
189
|
+
|
190
|
+
class Format_ansi
|
191
|
+
AnsiCodes = {
|
192
|
+
:normal => 0,
|
193
|
+
:reset => 0,
|
194
|
+
:bold => 1,
|
195
|
+
:dark => 2,
|
196
|
+
:italic => 3,
|
197
|
+
:underline => 4,
|
198
|
+
:blink => 5,
|
199
|
+
:rapid_blink => 6,
|
200
|
+
:negative => 7,
|
201
|
+
:concealed => 8,
|
202
|
+
:strikethrough => 9,
|
203
|
+
:black => 30,
|
204
|
+
:red => 31,
|
205
|
+
:green => 32,
|
206
|
+
:yellow => 33,
|
207
|
+
:blue => 34,
|
208
|
+
:magenta => 35,
|
209
|
+
:cyan => 36,
|
210
|
+
:white => 37,
|
211
|
+
:on_black => 40,
|
212
|
+
:on_red => 41,
|
213
|
+
:on_green => 42,
|
214
|
+
:on_yellow => 43,
|
215
|
+
:on_blue => 44,
|
216
|
+
:on_magenta => 45,
|
217
|
+
:on_cyan => 46,
|
218
|
+
:on_white => 47,
|
219
|
+
}
|
220
|
+
def initialize(colors = {})
|
221
|
+
@result = ''
|
222
|
+
@colors = Hash.new([])
|
223
|
+
@colors.merge!({
|
224
|
+
'Comment' => [ :cyan ],
|
225
|
+
'Constant' => [ :red ],
|
226
|
+
'Identifier' => [ :green ],
|
227
|
+
'Statement' => [ :yellow ],
|
228
|
+
'PreProc' => [ :magenta ],
|
229
|
+
'Type' => [ :green ],
|
230
|
+
'Special' => [ :magenta ],
|
231
|
+
'Underlined' => [ :underline ],
|
232
|
+
'Error' => [ :red ],
|
233
|
+
'Todo' => [ :black, :on_yellow ],
|
234
|
+
})
|
235
|
+
@colors.merge!(colors)
|
236
|
+
end
|
237
|
+
def push(type, text)
|
238
|
+
seq = ''
|
239
|
+
codes = @colors[type].dup
|
240
|
+
codes.unshift(:reset)
|
241
|
+
codes.each {|c|
|
242
|
+
num = AnsiCodes[c]
|
243
|
+
seq << "\e[#{num}m" if num
|
244
|
+
}
|
245
|
+
@result << seq << text
|
246
|
+
end
|
247
|
+
def result
|
248
|
+
@result << "\e[0m"
|
249
|
+
@result
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
end
|
254
|
+
|
@@ -0,0 +1,67 @@
|
|
1
|
+
" mark.vim - turn Vim syntax highlighting into an ad-hoc markup language that
|
2
|
+
" can be parsed by the Text::VimColor Perl module.
|
3
|
+
"
|
4
|
+
" Maintainer: Geoff Richards <qef@laxan.com>
|
5
|
+
" Based loosely on 2html.vim, by Bram Moolenaar <Bram@vim.org>,
|
6
|
+
" modified by David Ne\v{c}as (Yeti) <yeti@physics.muni.cz>.
|
7
|
+
|
8
|
+
set report=1000000
|
9
|
+
|
10
|
+
" For some reason (I'm sure it used to work) we now need to get Vim
|
11
|
+
" to make another attempt to detect the filetype if it wasn't set
|
12
|
+
" explicitly.
|
13
|
+
if !strlen(&filetype)
|
14
|
+
filetype detect
|
15
|
+
endif
|
16
|
+
"syn on
|
17
|
+
|
18
|
+
" Set up the output buffer.
|
19
|
+
new
|
20
|
+
set modifiable
|
21
|
+
set paste
|
22
|
+
|
23
|
+
" Expand tabs. Without this they come out as '^I'.
|
24
|
+
set isprint+=9
|
25
|
+
|
26
|
+
wincmd p
|
27
|
+
|
28
|
+
" Loop over all lines in the original text
|
29
|
+
let s:end = line("$")
|
30
|
+
let s:lnum = 1
|
31
|
+
while s:lnum <= s:end
|
32
|
+
|
33
|
+
" Get the current line
|
34
|
+
let s:line = getline(s:lnum)
|
35
|
+
let s:len = strlen(s:line)
|
36
|
+
let s:new = ""
|
37
|
+
|
38
|
+
" Loop over each character in the line
|
39
|
+
let s:col = 1
|
40
|
+
while s:col <= s:len
|
41
|
+
let s:startcol = s:col " The start column for processing text
|
42
|
+
let s:id = synID(s:lnum, s:col, 1)
|
43
|
+
let s:col = s:col + 1
|
44
|
+
" Speed loop (it's small - that's the trick)
|
45
|
+
" Go along till we find a change in synID
|
46
|
+
while s:col <= s:len && s:id == synID(s:lnum, s:col, 1) | let s:col = s:col + 1 | endwhile
|
47
|
+
|
48
|
+
" Output the text with the same synID, with class set to c{s:id}
|
49
|
+
let s:id = synIDtrans(s:id)
|
50
|
+
let s:name = synIDattr(s:id, 'name')
|
51
|
+
let s:new = s:new . '>' . s:name . '>' . substitute(substitute(substitute(strpart(s:line, s:startcol - 1, s:col - s:startcol), '&', '\&a', 'g'), '<', '\&l', 'g'), '>', '\&g', 'g') . '<' . s:name . '<'
|
52
|
+
|
53
|
+
if s:col > s:len
|
54
|
+
break
|
55
|
+
endif
|
56
|
+
endwhile
|
57
|
+
|
58
|
+
exe "normal \<C-W>pa" . strtrans(s:new) . "\n\e\<C-W>p"
|
59
|
+
let s:lnum = s:lnum + 1
|
60
|
+
+
|
61
|
+
endwhile
|
62
|
+
|
63
|
+
" Strip whitespace from the ends of lines
|
64
|
+
%s:\s\+$::e
|
65
|
+
|
66
|
+
wincmd p
|
67
|
+
normal dd
|
@@ -0,0 +1,68 @@
|
|
1
|
+
|
2
|
+
if version < 600
|
3
|
+
syntax clear
|
4
|
+
elseif exists("b:current_syntax")
|
5
|
+
finish
|
6
|
+
endif
|
7
|
+
|
8
|
+
syn case match
|
9
|
+
|
10
|
+
" Todo
|
11
|
+
syn keyword msgspecTodo TODO FIXME XXX contained
|
12
|
+
|
13
|
+
" Comments
|
14
|
+
syn match msgspecComment "#.*" contains=msgspecTodo
|
15
|
+
syn match msgspecComment "\/\/.*$" contains=msgspecTodo
|
16
|
+
syn region msgspecComment start="/\*" end="\*/" contains=msgspecTodo,msgspecComment
|
17
|
+
|
18
|
+
" Literal
|
19
|
+
syn match msgspecString "'\(\\.\|[^'\\]\)*'"
|
20
|
+
syn match msgspecString "\"\(\\.\|[^\"\\]\)*\""
|
21
|
+
syn match msgspecNumber "\<[0-9][0-9]*\(\.[0-9][0-9]*\)\?\>"
|
22
|
+
syn keyword msgspecBoolean true false
|
23
|
+
|
24
|
+
" Keywords
|
25
|
+
syn keyword msgspecKeyword default
|
26
|
+
syn keyword msgspecDeclareKeyword include namespace
|
27
|
+
syn keyword msgspecTypeKeyword const typedef typespec
|
28
|
+
syn keyword msgspecStructure interface service message exception enum application
|
29
|
+
"syn keyword msgspecStructureDeclaration import
|
30
|
+
syn keyword msgspecException throws
|
31
|
+
syn keyword msgspecModifier required optional
|
32
|
+
syn keyword msgspecBasicType void
|
33
|
+
syn keyword msgspecBasicType byte int short long
|
34
|
+
syn keyword msgspecBasicType ubyte uint ushort ulong
|
35
|
+
syn keyword msgspecBasicType float double bool string raw
|
36
|
+
syn keyword msgspecContainerType map list
|
37
|
+
"syn match msgspecSpecial "?"
|
38
|
+
syn keyword msgspecSpecial inherit
|
39
|
+
"syn keyword msgspecSpecial obsolete
|
40
|
+
|
41
|
+
" Special
|
42
|
+
syn match msgspecId "\<\d\+:"
|
43
|
+
syn match msgspecServiceVersion ":\d\+\>"
|
44
|
+
|
45
|
+
" Block
|
46
|
+
syn region msgspecBlock matchgroup=NONE start="{" end="}" contains=@msgspecBlockItems
|
47
|
+
syn cluster msgspecBlockItems contains=msgspecComment,msgspecString,msgspecNumber,msgspecKeyword,msgspecId,msgspecServiceVersion,msgspecStructureDeclaration,msgspecException,msgspecModifier,msgspecBasicType,msgspecContainerType,msgspecSpecial,msgspecBlock
|
48
|
+
|
49
|
+
hi link msgspecTodo Todo
|
50
|
+
hi link msgspecComment Comment
|
51
|
+
hi link msgspecString String
|
52
|
+
hi link msgspecNumber Number
|
53
|
+
hi link msgspecBoolean Boolean
|
54
|
+
hi link msgspecTypeKeyword Type
|
55
|
+
hi link msgspecStructure Structure
|
56
|
+
hi link msgspecStructureDeclaration Special
|
57
|
+
hi link msgspecException Exception
|
58
|
+
hi link msgspecModifier Special
|
59
|
+
hi link msgspecDeclareKeyword PreProc
|
60
|
+
hi link msgspecKeyword Keyword
|
61
|
+
hi link msgspecBasicType Type
|
62
|
+
hi link msgspecSpecial Special
|
63
|
+
"hi link msgspecContainerType Type
|
64
|
+
hi link msgspecId Label
|
65
|
+
hi link msgspecServiceVersion Label
|
66
|
+
|
67
|
+
let b:current_syntax = "msgspec"
|
68
|
+
|
data/lib/msgpack/idl/error.rb
CHANGED
@@ -55,16 +55,42 @@ class Evaluator
|
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
58
|
+
class InheritAllMark
|
59
|
+
def initialize(ast)
|
60
|
+
@ast = ast
|
61
|
+
end
|
62
|
+
attr_reader :ast
|
63
|
+
def name
|
64
|
+
""
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class InheritMark
|
69
|
+
def initialize(ast, name)
|
70
|
+
@ast = ast
|
71
|
+
@name = name
|
72
|
+
end
|
73
|
+
attr_reader :ast, :name
|
74
|
+
end
|
75
|
+
|
76
|
+
class InheritMarkWithCheck < InheritMark
|
77
|
+
def initialize(ast, func)
|
78
|
+
super(ast, func.name)
|
79
|
+
@func = func
|
80
|
+
end
|
81
|
+
attr_reader :func
|
82
|
+
end
|
83
|
+
|
58
84
|
def initialize
|
59
85
|
@names = {} # name:String => AST::Element
|
60
86
|
|
61
87
|
@types = {} # name:String => AST::Type
|
62
88
|
@generic_types = [] # Template
|
63
89
|
|
64
|
-
@global_namespace = "" # Namespace
|
90
|
+
@global_namespace = [""] # Namespace
|
65
91
|
@lang_namespace = {} # lang:String => scope:Namespace
|
66
92
|
|
67
|
-
@
|
93
|
+
@service_versions = {} # serviceName:String => (IR::Service, [(IR::ServiceVersion, AST::ServiceVersion)])
|
68
94
|
|
69
95
|
init_built_in
|
70
96
|
|
@@ -89,7 +115,7 @@ class Evaluator
|
|
89
115
|
if e.super_class
|
90
116
|
super_message = resolve_type(e.super_class)
|
91
117
|
if !super_message.is_a?(IR::Exception)
|
92
|
-
raise InvalidNameError, "`#{e.super_class}'
|
118
|
+
raise InvalidNameError, "Super class of the exception `#{e.super_class}' must be an exception"
|
93
119
|
end
|
94
120
|
end
|
95
121
|
new_fields = resolve_fields(e.fields, super_message)
|
@@ -100,7 +126,7 @@ class Evaluator
|
|
100
126
|
if e.super_class
|
101
127
|
super_message = resolve_type(e.super_class)
|
102
128
|
if !super_message.is_a?(IR::Message)
|
103
|
-
raise InvalidNameError, "`#{e.super_class}'
|
129
|
+
raise InvalidNameError, "Super class of the message `#{e.super_class}' must be a message"
|
104
130
|
end
|
105
131
|
end
|
106
132
|
new_fields = resolve_fields(e.fields, super_message)
|
@@ -113,9 +139,9 @@ class Evaluator
|
|
113
139
|
|
114
140
|
when AST::Service
|
115
141
|
v = e.version || 0
|
116
|
-
|
117
|
-
funcs =
|
118
|
-
add_service_version(
|
142
|
+
check_service_version(e.name, v)
|
143
|
+
funcs = resolve_service_partial(e.functions)
|
144
|
+
add_service_version(e, e.name, v, funcs)
|
119
145
|
|
120
146
|
when AST::Application
|
121
147
|
check_name(e.name, e)
|
@@ -123,34 +149,93 @@ class Evaluator
|
|
123
149
|
add_application(e.name, scopes)
|
124
150
|
|
125
151
|
else
|
126
|
-
raise SemanticsError, "Unknown toplevel AST element `#{e.class}'
|
152
|
+
raise SemanticsError, "Unknown toplevel AST element `#{e.class}'"
|
127
153
|
end
|
154
|
+
|
155
|
+
rescue => error
|
156
|
+
raise_error(error, e)
|
128
157
|
end
|
129
158
|
|
130
159
|
def evaluate_inheritance
|
131
|
-
@
|
160
|
+
@ir_services = @service_versions.values.map {|s,versions|
|
161
|
+
versions = versions.sort_by {|sv,ast| sv.version }
|
162
|
+
|
132
163
|
super_versions = []
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
164
|
+
versions.each do |sv,ast|
|
165
|
+
begin
|
166
|
+
real_functions = []
|
167
|
+
sv.functions.each {|f|
|
168
|
+
case f
|
169
|
+
when InheritAllMark
|
170
|
+
begin
|
171
|
+
if super_versions.empty?
|
172
|
+
raise InheritanceError, "Inherit on the oldest version is invalid"
|
173
|
+
end
|
174
|
+
last = super_versions.last
|
175
|
+
last.functions.each {|ifunc|
|
176
|
+
real_functions << IR::InheritedFunction.new(last.version, ifunc)
|
177
|
+
}
|
178
|
+
rescue => error
|
179
|
+
raise_error(error, f.ast)
|
144
180
|
end
|
145
|
-
|
181
|
+
|
182
|
+
when InheritMark
|
183
|
+
begin
|
184
|
+
if super_versions.empty?
|
185
|
+
raise InheritanceError, "Inherit on the oldest version is invalid"
|
186
|
+
end
|
187
|
+
inherit_func = nil
|
188
|
+
inherit_version = nil
|
189
|
+
super_versions.reverse_each do |ssv|
|
190
|
+
inherit_func = ssv.functions.find {|ifunc| f.name == ifunc.name }
|
191
|
+
if inherit_func
|
192
|
+
inherit_version = ssv.version
|
193
|
+
break
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
unless inherit_func
|
198
|
+
raise InheritanceError, "No such function: #{f.name}"
|
199
|
+
end
|
200
|
+
|
201
|
+
if f.is_a?(InheritMarkWithCheck)
|
202
|
+
if inherit_func.args != f.func.args ||
|
203
|
+
inherit_func.return_type != f.func.return_type ||
|
204
|
+
inherit_func.exceptions != f.func.exceptions
|
205
|
+
raise InheritanceError, "Function signature is mismatched with #{s.name}:#{inherit_version}.#{f.name}"
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
real_functions << IR::InheritedFunction.new(inherit_version, inherit_func)
|
210
|
+
rescue => error
|
211
|
+
raise_error(error, f.ast)
|
212
|
+
end
|
213
|
+
|
214
|
+
when IR::Function
|
215
|
+
real_functions << f
|
216
|
+
|
217
|
+
else
|
218
|
+
raise "Unknown partially evaluated function: #{f.inspect}"
|
146
219
|
end
|
220
|
+
}
|
221
|
+
|
222
|
+
if real_functions.uniq!
|
223
|
+
# may be caused by InheritAllMark
|
224
|
+
# FIXME show warning?
|
147
225
|
end
|
148
|
-
}
|
149
226
|
|
150
|
-
|
227
|
+
sv.functions = real_functions
|
228
|
+
|
229
|
+
super_versions << sv
|
230
|
+
rescue => error
|
231
|
+
raise_error(error, ast)
|
232
|
+
end
|
151
233
|
end
|
234
|
+
s.versions = super_versions
|
235
|
+
|
236
|
+
s
|
152
237
|
}
|
153
|
-
|
238
|
+
|
154
239
|
self
|
155
240
|
end
|
156
241
|
|
@@ -164,6 +249,22 @@ class Evaluator
|
|
164
249
|
end
|
165
250
|
|
166
251
|
private
|
252
|
+
def raise_error(error, ast = nil)
|
253
|
+
if ast
|
254
|
+
msg = %[#{error.message}
|
255
|
+
|
256
|
+
while processing:
|
257
|
+
#{ast.summary.split("\n").map {|l| " #{l}" }.join("\n")}]
|
258
|
+
|
259
|
+
else
|
260
|
+
msg = error.message
|
261
|
+
end
|
262
|
+
|
263
|
+
wrap = error.class.new(msg)
|
264
|
+
wrap.set_backtrace(error.backtrace)
|
265
|
+
raise wrap
|
266
|
+
end
|
267
|
+
|
167
268
|
def spec_namespace(lang)
|
168
269
|
if ns = @lang_namespace[lang]
|
169
270
|
return ns
|
@@ -186,7 +287,7 @@ class Evaluator
|
|
186
287
|
|
187
288
|
def check_name(name, e)
|
188
289
|
if ee = @names[name]
|
189
|
-
raise DuplicatedNameError, "
|
290
|
+
raise DuplicatedNameError, "Duplicated name `#{name}'"
|
190
291
|
end
|
191
292
|
@names[name] = e
|
192
293
|
end
|
@@ -195,7 +296,7 @@ class Evaluator
|
|
195
296
|
def resolve_simple_type(e)
|
196
297
|
type = @types[e.name]
|
197
298
|
unless type
|
198
|
-
raise NameNotFoundError, "
|
299
|
+
raise NameNotFoundError, "Type not found `#{e.name}'"
|
199
300
|
end
|
200
301
|
if e.nullable? && !type.is_a?(IR::NullableType)
|
201
302
|
IR::NullableType.new(type)
|
@@ -217,7 +318,7 @@ class Evaluator
|
|
217
318
|
end
|
218
319
|
}
|
219
320
|
unless resolved_types
|
220
|
-
raise NameNotFoundError, "
|
321
|
+
raise NameNotFoundError, "Generic type not matched `#{e.name}'"
|
221
322
|
end
|
222
323
|
type = IR::ParameterizedType.new(resolved_types, template.generic_type)
|
223
324
|
if template.nullable || e.nullable?
|
@@ -249,42 +350,46 @@ class Evaluator
|
|
249
350
|
end
|
250
351
|
|
251
352
|
new_fields = fields.map {|e|
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
353
|
+
begin
|
354
|
+
if e.id == 0
|
355
|
+
raise InvalidNameError, "Field id 0 is invalid"
|
356
|
+
end
|
357
|
+
if e.id < 0
|
358
|
+
raise InvalidNameError, "Field id < 0 is invalid"
|
359
|
+
end
|
360
|
+
if n = used_ids[e.id]
|
361
|
+
raise DuplicatedNameError, "Field id #{e.id} is duplicated with field `#{n}'"
|
362
|
+
end
|
363
|
+
if i = used_names[e.name]
|
364
|
+
raise DuplicatedNameError, "Field name `#{e.name}' is duplicated with id #{i}"
|
365
|
+
end
|
366
|
+
if super_used_ids[e.id]
|
367
|
+
raise InheritanceError, "Field id #{e.id} is duplicated with super class `#{e.name}'"
|
368
|
+
end
|
369
|
+
if super_used_names[e.name]
|
370
|
+
raise InheritanceError, "Field name is duplicated with super class `#{e.name}'"
|
371
|
+
end
|
270
372
|
|
271
|
-
|
272
|
-
|
373
|
+
used_ids[e.id] = e.name
|
374
|
+
used_names[e.name] = e.id
|
273
375
|
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
376
|
+
type = resolve_type(e.type)
|
377
|
+
if e.modifier == AST::FIELD_OPTIONAL
|
378
|
+
option = IR::FIELD_OPTIONAL
|
379
|
+
else
|
380
|
+
option = IR::FIELD_REQUIRED
|
381
|
+
end
|
280
382
|
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
383
|
+
if e.is_a?(AST::ValueAssignedField)
|
384
|
+
v = resolve_initial_value(type, e.value)
|
385
|
+
else
|
386
|
+
v = resolve_implicit_value(type)
|
387
|
+
end
|
286
388
|
|
287
|
-
|
389
|
+
IR::Field.new(e.id, type, e.name, option, v)
|
390
|
+
rescue => error
|
391
|
+
raise_error(error, e)
|
392
|
+
end
|
288
393
|
}.sort_by {|f|
|
289
394
|
f.id
|
290
395
|
}
|
@@ -327,21 +432,21 @@ class Evaluator
|
|
327
432
|
when AST::EnumLiteral
|
328
433
|
enum = resolve_type(e.name)
|
329
434
|
if !enum.is_a?(IR::Enum)
|
330
|
-
raise NameNotFoundError, "
|
435
|
+
raise NameNotFoundError, "Not a enum type `#{e.name}'"
|
331
436
|
end
|
332
437
|
f = enum.fields.find {|f|
|
333
438
|
f.name == e.field
|
334
439
|
}
|
335
440
|
if !f
|
336
|
-
raise NameNotFoundError, "
|
441
|
+
raise NameNotFoundError, "No such field at enum `#{e.name}': #{e.field}"
|
337
442
|
end
|
338
443
|
IR::EnumValue.new(enum, f)
|
339
444
|
|
340
445
|
when AST::ConstLiteral
|
341
|
-
raise NameNotFoundError, "
|
446
|
+
raise NameNotFoundError, "Unknown constant `#{name}'"
|
342
447
|
|
343
448
|
else
|
344
|
-
raise SemanticsError, "
|
449
|
+
raise SemanticsError, "unknown literal type: #{e.class}"
|
345
450
|
end
|
346
451
|
|
347
452
|
check_assignable(type, v)
|
@@ -350,24 +455,24 @@ class Evaluator
|
|
350
455
|
|
351
456
|
def check_assignable(type, v)
|
352
457
|
if type.nullable_type? && v != IR::NilValue.nil
|
353
|
-
raise TypeError, "
|
458
|
+
raise TypeError, "Non-null value for nullable type is not allowed"
|
354
459
|
end
|
355
460
|
|
356
461
|
case v
|
357
462
|
when IR::NilValue
|
358
463
|
unless type.nullable_type?
|
359
|
-
raise TypeError, "
|
464
|
+
raise TypeError, "Assigning null to non-nullable field"
|
360
465
|
end
|
361
466
|
|
362
467
|
when IR::IntValue
|
363
468
|
unless IR::Primitive::INT_TYPES.include?(type)
|
364
|
-
raise TypeError, "
|
469
|
+
raise TypeError, "Integer type is expected: #{type}"
|
365
470
|
end
|
366
471
|
# TODO overflow
|
367
472
|
|
368
473
|
when IR::BoolValue
|
369
474
|
if type != IR::Primitive::bool
|
370
|
-
raise TypeError, "
|
475
|
+
raise TypeError, "Bool type is expected: #{type}"
|
371
476
|
end
|
372
477
|
|
373
478
|
end
|
@@ -386,7 +491,7 @@ class Evaluator
|
|
386
491
|
|
387
492
|
elsif t.is_a?(IR::Enum)
|
388
493
|
if t.fields.empty?
|
389
|
-
raise TypeError, "
|
494
|
+
raise TypeError, "Empty enum is not allowed: enum #{t.name}"
|
390
495
|
end
|
391
496
|
IR::EnumValue.new(t, t.fields.first)
|
392
497
|
|
@@ -400,20 +505,24 @@ class Evaluator
|
|
400
505
|
used_names = {}
|
401
506
|
|
402
507
|
fields = fields.map {|e|
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
508
|
+
begin
|
509
|
+
if e.id < 0
|
510
|
+
raise InvalidNameError, "Enum id < 0 is invalid"
|
511
|
+
end
|
512
|
+
if n = used_ids[e.id]
|
513
|
+
raise DuplicatedNameError, "Enum field id #{e.id} is duplicated with `#{n}'"
|
514
|
+
end
|
515
|
+
if i = used_names[e.name]
|
516
|
+
raise DuplicatedNameError, "Enum field name `#{e.name}' is duplicated with id #{i}"
|
517
|
+
end
|
412
518
|
|
413
|
-
|
414
|
-
|
519
|
+
used_ids[e.id] = e.name
|
520
|
+
used_names[e.name] = e.id
|
415
521
|
|
416
|
-
|
522
|
+
IR::EnumField.new(e.id, e.name)
|
523
|
+
rescue => error
|
524
|
+
raise_error(error, e)
|
525
|
+
end
|
417
526
|
}.sort_by {|f|
|
418
527
|
f.id
|
419
528
|
}
|
@@ -422,39 +531,52 @@ class Evaluator
|
|
422
531
|
end
|
423
532
|
|
424
533
|
def check_service_version(name, version)
|
425
|
-
s = @
|
426
|
-
s.name == name
|
427
|
-
}
|
534
|
+
s, versions = @service_versions[name]
|
428
535
|
if s
|
429
|
-
|
536
|
+
versions.each {|sv,ast|
|
430
537
|
if sv.version == version
|
431
|
-
raise DuplicatedNameError, "
|
538
|
+
raise DuplicatedNameError, "Duplicated version #{version}"
|
432
539
|
end
|
433
540
|
}
|
434
541
|
else
|
435
542
|
check_name(name, nil)
|
436
543
|
end
|
437
|
-
|
544
|
+
nil
|
438
545
|
end
|
439
546
|
|
440
|
-
def
|
547
|
+
def resolve_service_partial(funcs)
|
441
548
|
used_names = {}
|
442
549
|
|
443
550
|
funcs = funcs.map {|e|
|
444
|
-
|
445
|
-
|
446
|
-
|
551
|
+
case e
|
552
|
+
when AST::InheritAll
|
553
|
+
InheritAllMark.new(e)
|
447
554
|
|
448
|
-
|
555
|
+
when AST::InheritName, AST::InheritFunc
|
556
|
+
if used_names[e.name]
|
557
|
+
raise DuplicatedNameError, "Duplicated function name `#{e.name}'"
|
558
|
+
end
|
559
|
+
used_names[e.name] = true
|
560
|
+
|
561
|
+
if e.is_a?(AST::InheritFunc)
|
562
|
+
func = resolve_func(e)
|
563
|
+
InheritMarkWithCheck.new(e, func)
|
564
|
+
else
|
565
|
+
InheritMark.new(e, e.name)
|
566
|
+
end
|
567
|
+
|
568
|
+
when AST::Func
|
569
|
+
if used_names[e.name]
|
570
|
+
raise DuplicatedNameError, "Duplicated function name `#{e.name}'"
|
571
|
+
end
|
572
|
+
used_names[e.name] = true
|
573
|
+
|
574
|
+
resolve_func(e)
|
449
575
|
|
450
|
-
args = resolve_args(e.args)
|
451
|
-
if e.return_type.name == "void"
|
452
|
-
return_type = IR::Primitive.void
|
453
576
|
else
|
454
|
-
|
577
|
+
raise SemanticsError, "Unknown service body AST element `#{e.class}': #{e.inspect}"
|
455
578
|
end
|
456
579
|
|
457
|
-
IR::Function.new(e.name, return_type, args, nil, nil)
|
458
580
|
}.sort_by {|f|
|
459
581
|
f.name
|
460
582
|
}
|
@@ -462,41 +584,62 @@ class Evaluator
|
|
462
584
|
return funcs
|
463
585
|
end
|
464
586
|
|
587
|
+
def resolve_func(e)
|
588
|
+
args = resolve_args(e.args)
|
589
|
+
|
590
|
+
if e.return_type.name == "void"
|
591
|
+
return_type = IR::Primitive.void
|
592
|
+
else
|
593
|
+
return_type = resolve_type(e.return_type)
|
594
|
+
end
|
595
|
+
|
596
|
+
exceptions = resolve_exceptions(e.exceptions)
|
597
|
+
|
598
|
+
IR::Function.new(e.name, return_type, args, exceptions)
|
599
|
+
|
600
|
+
rescue => error
|
601
|
+
raise_error(error, e)
|
602
|
+
end
|
603
|
+
|
465
604
|
def resolve_args(args)
|
466
605
|
used_ids = []
|
467
606
|
used_names = {}
|
468
607
|
|
469
608
|
args = args.map {|e|
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
609
|
+
begin
|
610
|
+
if e.id == 0
|
611
|
+
raise InvalidNameError, "Argument id 0 is invalid"
|
612
|
+
end
|
613
|
+
if e.id < 0
|
614
|
+
raise InvalidNameError, "Argument id < 0 is invalid"
|
615
|
+
end
|
616
|
+
if n = used_ids[e.id]
|
617
|
+
raise DuplicatedNameError, "Argument id #{e.id} is duplicated with `#{n}'"
|
618
|
+
end
|
619
|
+
if i = used_names[e.name]
|
620
|
+
raise DuplicatedNameError, "Argument name `#{e.name}' is duplicated with id #{i}"
|
621
|
+
end
|
482
622
|
|
483
|
-
|
484
|
-
|
623
|
+
used_ids[e.id] = e.name
|
624
|
+
used_names[e.name] = e.id
|
485
625
|
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
626
|
+
type = resolve_type(e.type)
|
627
|
+
if e.modifier == AST::FIELD_OPTIONAL
|
628
|
+
option = IR::FIELD_OPTIONAL
|
629
|
+
else
|
630
|
+
option = IR::FIELD_REQUIRED
|
631
|
+
end
|
492
632
|
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
633
|
+
if e.is_a?(AST::ValueAssignedField)
|
634
|
+
v = resolve_initial_value(type, e.value)
|
635
|
+
else
|
636
|
+
v = resolve_implicit_value(type)
|
637
|
+
end
|
498
638
|
|
499
|
-
|
639
|
+
IR::Argument.new(e.id, type, e.name, option, v)
|
640
|
+
rescue => error
|
641
|
+
raise_error(error, e)
|
642
|
+
end
|
500
643
|
}.sort_by {|a|
|
501
644
|
a.id
|
502
645
|
}
|
@@ -504,12 +647,17 @@ class Evaluator
|
|
504
647
|
return args
|
505
648
|
end
|
506
649
|
|
650
|
+
def resolve_exceptions(exceptions)
|
651
|
+
# TODO
|
652
|
+
[]
|
653
|
+
end
|
654
|
+
|
507
655
|
def resolve_scopes(scopes)
|
508
656
|
ds = scopes.find_all {|e|
|
509
657
|
e.default?
|
510
658
|
}
|
511
659
|
if ds.size > 1
|
512
|
-
raise DuplicatedNameError, "
|
660
|
+
raise DuplicatedNameError, "Multiple default scope: #{ds.map {|e| e.name}.join(', ')}"
|
513
661
|
end
|
514
662
|
|
515
663
|
if ds.empty?
|
@@ -522,21 +670,17 @@ class Evaluator
|
|
522
670
|
|
523
671
|
scopes = scopes.map {|e|
|
524
672
|
if used_names[e.name]
|
525
|
-
raise DuplicatedNameError, "
|
673
|
+
raise DuplicatedNameError, "Duplicated scope name: #{e.name}"
|
526
674
|
end
|
527
675
|
|
528
|
-
s = @
|
529
|
-
s.name == e.service
|
530
|
-
}
|
676
|
+
s, versions = @service_versions[e.service]
|
531
677
|
unless s
|
532
|
-
raise NameNotFoundError, "
|
678
|
+
raise NameNotFoundError, "No such service: #{e.name}"
|
533
679
|
end
|
534
680
|
|
535
|
-
sv =
|
536
|
-
sv.version == e.version
|
537
|
-
}
|
681
|
+
sv = versions.find {|sv,ast| sv.version == e.version }
|
538
682
|
unless sv
|
539
|
-
raise NameNotFoundError, "
|
683
|
+
raise NameNotFoundError, "No such service version: #{e.service}:#{s.version}"
|
540
684
|
end
|
541
685
|
|
542
686
|
used_names[e.name] = true
|
@@ -579,14 +723,15 @@ class Evaluator
|
|
579
723
|
e
|
580
724
|
end
|
581
725
|
|
582
|
-
def add_service_version(
|
726
|
+
def add_service_version(e, name, version, funcs)
|
583
727
|
sv = IR::ServiceVersion.new(version, funcs)
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
@
|
728
|
+
s, versions = @service_versions[name]
|
729
|
+
unless s
|
730
|
+
s = IR::Service.new(name, nil)
|
731
|
+
versions = []
|
732
|
+
@service_versions[name] = [s, versions]
|
589
733
|
end
|
734
|
+
versions << [sv, e]
|
590
735
|
sv
|
591
736
|
end
|
592
737
|
|