brotorift 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,191 @@
1
+
2
+ class CompilerError
3
+ def initialize position
4
+ @position = position
5
+ end
6
+
7
+ def to_s
8
+ "#{@position}: #{info}"
9
+ end
10
+ end
11
+
12
+
13
+ class InitialCaseError < CompilerError
14
+ def initialize type, initial_case, ast
15
+ super ast.position
16
+ @type = type
17
+ @initial_case = initial_case
18
+ @ast = ast
19
+ end
20
+
21
+ def info
22
+ if @type == 'node_nick' then
23
+ return "'#{@ast.nickname}' : nickname of nodes should be #{@initial_case} case"
24
+ else
25
+ return "'#{@ast.name}' : name of #{@type}s should be #{@initial_case} case"
26
+ end
27
+ end
28
+ end
29
+
30
+
31
+ class BuiltinNameConflictError < CompilerError
32
+ def initialize ast
33
+ super ast.position
34
+ @name = ast.name
35
+ end
36
+
37
+ def info
38
+ "'#{@name}' : type name conflict with built-in type"
39
+ end
40
+ end
41
+
42
+
43
+ class DuplicateDefError < CompilerError
44
+ def initialize type, name, old_ast, new_ast
45
+ super new_ast.position
46
+ @type = type
47
+ @name = name
48
+ @old_pos = old_ast.position
49
+ @new_pos = new_ast.position
50
+ end
51
+
52
+ def info
53
+ "'#{@name}' : #{@type} redefinition\n #{@old_pos} : see previous #{@type} definition of '#{@name}'"
54
+ end
55
+ end
56
+
57
+
58
+ class IncludeFileNotFoundError < CompilerError
59
+ def initialize filename, position
60
+ super position
61
+ @filename = filename
62
+ end
63
+
64
+ def info
65
+ "'#{@filename}' : include file not found: "
66
+ end
67
+ end
68
+
69
+
70
+ class TypeParamCountMismatchError < CompilerError
71
+ def initialize ast, expected_count
72
+ super ast.position
73
+ @expected_count = expected_count
74
+ @actual_count = ast.params.length
75
+ end
76
+
77
+ def info
78
+ "generic parameter count mismatch: expected #{@expected_count}, provided #{@actual_count}"
79
+ end
80
+ end
81
+
82
+
83
+ class TypeNotFoundError < CompilerError
84
+ def initialize ast, name
85
+ super ast.position
86
+ @name = name
87
+ end
88
+
89
+ def info
90
+ "'#{@name}' : undefined type"
91
+ end
92
+ end
93
+
94
+
95
+ class NodeNotFoundError < CompilerError
96
+ def initialize ast, name
97
+ super ast.position
98
+ @name = name
99
+ end
100
+
101
+ def info
102
+ "'#{@name}' : undefined node"
103
+ end
104
+ end
105
+
106
+
107
+ class CorrespondingNodeNotFoundError < CompilerError
108
+ def initialize member_type_def, node_name
109
+ super member_type_def.ast.position
110
+ @type = member_type_def.type
111
+ @node_name = node_name
112
+ end
113
+
114
+ def info
115
+ "'#{@type.name}' : cannot find corresponding node '#{@node_name}'\n #{@type.ast.position} : see type definition of '#{@type.name}'"
116
+ end
117
+ end
118
+
119
+
120
+ class NodeLanguageMismatchError < CompilerError
121
+ def initialize member_type_def, node_def, external_node_def
122
+ super member_type_def.ast.position
123
+ @type = member_type_def.type
124
+ @node_name = node_def.name
125
+ @node_position = node_def.ast.position
126
+ @external_node_position = external_node_def.ast.position
127
+ end
128
+
129
+ def info
130
+ "'#{@type.name}' : node language mismatch\n" +
131
+ " #{@node_position} : see node definition of '#{@node_name}'\n" +
132
+ " #{@external_node_position} : see external node definition of '#{@node_name}'\n" +
133
+ " #{@type.ast.position} : see type definition of '#{@type.name}'\n"
134
+ end
135
+ end
136
+
137
+
138
+ class DirectionNotFoundError < CompilerError
139
+ def initialize ast, client, direction, server
140
+ super ast.position
141
+ @client = client
142
+ @direction = direction
143
+ @server = server
144
+ end
145
+
146
+ def info
147
+ case @direction
148
+ when :left
149
+ "'#{@client.name} -> #{@server.name}' : undefined direction"
150
+ when :right
151
+ "'#{@client.name} <- #{@server.name}' : undefined direction"
152
+ end
153
+ end
154
+ end
155
+
156
+
157
+ class MessageNotFoundError < CompilerError
158
+ def initialize ast, direction
159
+ super ast.position
160
+ @name = ast.message
161
+ @direction = direction
162
+ end
163
+
164
+ def info
165
+ "'#{@name}' undefined message in direction '#{@direction.name}'\n #{@direction.ast.position} : see previous direction definition of '#{@direction.name}'"
166
+ end
167
+ end
168
+
169
+
170
+ class ClientServerSameError < CompilerError
171
+ def initialize ast
172
+ super ast.position
173
+ end
174
+
175
+ def info
176
+ "client and server of a direction should not be the same"
177
+ end
178
+ end
179
+
180
+
181
+ class UnexpectedTokenError < CompilerError
182
+ def initialize token
183
+ super token.position
184
+ @type = token.type
185
+ @value = token.value
186
+ end
187
+
188
+ def info
189
+ "unexpected #{@type.to_s.downcase} : '#{@value}'"
190
+ end
191
+ end
@@ -0,0 +1,162 @@
1
+ defmodule <%= node.namespace %>.Enums do<% for e in runtime.enums.values %>
2
+ def <%= e.elixir_read_name %>(data) do
3
+ <<value::32-little, data::binary>> = data
4
+ case value do<% for v in e.elements.values %>
5
+ <%= v.value %> -> {data, <%= v.elixir_name %>}<% end %>
6
+ _ -> :error
7
+ end
8
+ end
9
+
10
+ def <%= e.elixir_write_name %>(data, value) do
11
+ case value do<% for v in e.elements.values %>
12
+ <%= v.elixir_name %> -> <<data::binary, <%= v.value %>::32-little>><% end %>
13
+ _ -> :error
14
+ end
15
+ end
16
+ <% end %>end
17
+
18
+ <% for s in runtime.structs.values %>
19
+ defmodule <%= node.namespace %>.<%= s.name %> do
20
+ defstruct [<%= s.elixir_members %>]
21
+
22
+ @typedoc """
23
+ <%= s.doc %><% for m in s.members %>
24
+ `:<%= m.elixir_name %>`: <%= m.doc %><% end %>
25
+ """
26
+ @type t :: %<%= node.namespace %>.<%= s.name %>{<%= s.elixir_members_with_types node %>}
27
+
28
+ def read(data) do<% for m in s.members %>
29
+ {data, <%= m.elixir_name %>} = <%= m.type.elixir_read node %><% end %>
30
+ {data, %{<%= s.elixir_members_with_values %>}}
31
+ end
32
+
33
+ def write(data, value) do<% for m in s.members %>
34
+ data = <%= m.type.elixir_write node, 'value.' + m.elixir_name %><% end %>
35
+ data
36
+ end
37
+ end
38
+ <% end %>
39
+ <% for n in runtime.get_node_directions node, :server %>
40
+ defmodule <%= node.namespace %>.<%= node.elixir_connection %> do
41
+ use GenServer, restart: :temporary
42
+
43
+ import <%= node.namespace %>.Enums
44
+
45
+ @behaviour Brotorift.ConnectionBehaviour
46
+ <% for m in n.in_direction.messages.values %>
47
+ <%= m.elixir_header_name %> <%= m.id %><% end %>
48
+ <% for m in n.out_direction.messages.values %>
49
+ <%= m.elixir_header_name %> <%= m.id %><% end %>
50
+ <% for m in n.out_direction.messages.values %>
51
+ @doc """
52
+ <%= m.doc %>
53
+
54
+ ## Parameters
55
+
56
+ - `connection`: <%= node.elixir_connection %> Pid<% for p in m.members %>
57
+ - `<%= p.elixir_name %>`: <%= p.doc %>
58
+ <% end %>
59
+ """
60
+ @spec <%= m.elixir_name %>(connection :: pid()<%= m.elixir_params_with_types node %>) :: :ok
61
+ def <%= m.elixir_name %>(connection<%= m.elixir_params %>) do
62
+ GenServer.cast(connection, {:<%= m.elixir_name %><%= m.elixir_params %>})
63
+ end
64
+ <% end %>
65
+ def start_link(args) do
66
+ GenServer.start_link(__MODULE__, args)
67
+ end
68
+
69
+ def handle_data(pid, data) do
70
+ GenServer.cast(pid, {:handle_data, data})
71
+ end
72
+
73
+ def stop(pid) do
74
+ GenServer.stop(pid)
75
+ end
76
+
77
+ def init({socket, transport, handler}) do
78
+ {:ok, state} = handler.open_connection(self(), socket)
79
+ {:ok, {socket, transport, handler, state}}
80
+ end
81
+
82
+ def handle_cast({:handle_data, data}, {socket, transport, handler, state}) do
83
+ {:ok, new_state} = process_packet(data, handler, state)
84
+ {:noreply, {socket, transport, handler, new_state}}
85
+ end
86
+ <% for m in n.out_direction.messages.values %>
87
+ def handle_cast({:<%= m.elixir_name %><%= m.elixir_params %>}, {socket, transport, handler, state}) do
88
+ data = <<<%= m.elixir_header_name %>::32-little>><% for p in m.members %>
89
+ data = <%= p.type.elixir_write node, p.elixir_name %><% end %>
90
+ data = <<byte_size(data)::32-little, data::binary>>
91
+ transport.send(socket, data)
92
+ {:noreply, {socket, transport, handler, state}}
93
+ end
94
+ <% end %>
95
+ def terminate(_reason, {_socket, _transport, handler, state}) do
96
+ handler.close_connection(self(), state)
97
+ end
98
+
99
+ defp process_packet(<<>>, _handler, state) do
100
+ {:ok, state}
101
+ end
102
+ defp process_packet(data, handler, state) do
103
+ <<_size::32-little, header::32-little, data::binary>> = data
104
+ case header do<% for m in n.in_direction.messages.values %>
105
+ <%= m.elixir_header_name %> -><% for p in m.members %>
106
+ {data, <%= p.elixir_name %>} = <%= p.type.elixir_read node %><% end %>
107
+ {:ok, state} = handler.<%= m.elixir_name %>(self(), state<%= m.elixir_params %>)
108
+ process_packet(data, handler, state)<% end %>
109
+ end
110
+ end
111
+ end
112
+
113
+
114
+ defmodule <%= node.namespace %>.<%= node.elixir_behaviour %> do
115
+
116
+ @doc """
117
+ Calls when the server started
118
+ """
119
+ @callback start() :: :ok
120
+
121
+ @doc """
122
+ Calls when a new client connects
123
+
124
+ ## Parameters
125
+
126
+ - `connection`: The <%= node.elixir_connection %> Pid for the client
127
+ - `socket`: The socket for the client
128
+
129
+ ## Returns
130
+
131
+ {:ok, state}
132
+
133
+ """
134
+ @callback open_connection(connection :: pid(), socket :: :gen_tcp.socket()) :: {:ok, any()}
135
+
136
+ @doc """
137
+ Calls when a client disconnects
138
+
139
+ ## Parameters
140
+
141
+ - `connection`: The <%= node.elixir_connection %> Pid for the client
142
+ - `state`: The state for the connection
143
+
144
+ """
145
+ @callback close_connection(connection :: pid(), state :: any()) :: :ok
146
+
147
+ <% for m in n.in_direction.messages.values %>
148
+ @doc """
149
+ <%= m.doc %>
150
+
151
+ ## Parameters
152
+
153
+ - `connection`: The <%= node.elixir_connection %> Pid for the client
154
+ - `state`: The state for the connection<% for p in m.members %>
155
+ - `<%= p.elixir_name %>`: <%= p.doc %>
156
+ <% end %>
157
+ """
158
+ @callback <%= m.elixir_name %>(connection :: pid(), state :: any()<%= m.elixir_params_with_types node %>) :: {:ok, any()}
159
+ <% end %>
160
+ end
161
+
162
+ <% end %>