msgpack-idl 0.1.0 → 0.1.1
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.
- 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
|
|