brotorift 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/bin/brotorift +12 -0
- data/lib/ast.rb +169 -0
- data/lib/brotorift.rb +102 -0
- data/lib/case_helper.rb +13 -0
- data/lib/compiler.rb +288 -0
- data/lib/compiler_error.rb +191 -0
- data/lib/generators/elixir_server_generator.ex.erb +162 -0
- data/lib/generators/elixir_server_generator.rb +435 -0
- data/lib/generators/scala_server_generator.rb +137 -0
- data/lib/generators/scala_server_generator.scala.erb +92 -0
- data/lib/generators/unity_client_generator.cs.erb +103 -0
- data/lib/generators/unity_client_generator.rb +188 -0
- data/lib/lexer.rb +42 -0
- data/lib/parser.rb +105 -0
- data/lib/runtime.rb +345 -0
- data/lib/sequence_diagram_generator.rb +47 -0
- metadata +88 -0
@@ -0,0 +1,103 @@
|
|
1
|
+
using Brotorift;
|
2
|
+
using UnityEngine;
|
3
|
+
using System;
|
4
|
+
using System.Collections.Generic;
|
5
|
+
using System.Text;
|
6
|
+
|
7
|
+
namespace <%= node.namespace %>
|
8
|
+
{
|
9
|
+
#region Enums
|
10
|
+
<% for e in runtime.enums.values %>
|
11
|
+
/// <summary>
|
12
|
+
/// <%= e.doc %>
|
13
|
+
/// </summary>
|
14
|
+
public enum <%= e.name %>
|
15
|
+
{<% for v in e.elements.values %>
|
16
|
+
/// <summary>
|
17
|
+
/// <%= v.doc %>
|
18
|
+
/// </summary>
|
19
|
+
<%= v.name %> = <%= v.value %>,
|
20
|
+
<% end %>}
|
21
|
+
<% end %>
|
22
|
+
#endregion
|
23
|
+
|
24
|
+
#region Structs
|
25
|
+
<% for s in runtime.structs.values %>
|
26
|
+
/// <summary>
|
27
|
+
/// <%= s.doc %>
|
28
|
+
/// </summary>
|
29
|
+
public struct <%= s.name %> : IStruct
|
30
|
+
{<% for m in s.members %>
|
31
|
+
/// <summary>
|
32
|
+
/// <%= m.doc %>
|
33
|
+
/// </summary>
|
34
|
+
<%= m.unity_def %>
|
35
|
+
<% end %>
|
36
|
+
public <%= s.name %>( <%= s.members.map { |m| m.unity_param } .join ', ' %> )
|
37
|
+
{<% for m in s.members %>
|
38
|
+
this.<%= m.name %> = <%= m.name %>;<% end %>
|
39
|
+
}
|
40
|
+
|
41
|
+
public void ReadFromPacket( InPacket packet )
|
42
|
+
{<% for m in s.members %>
|
43
|
+
this.<%= m.unity_read %><% end %>
|
44
|
+
}
|
45
|
+
|
46
|
+
public void WriteToPacket( OutPacket packet )
|
47
|
+
{<% for m in s.members %>
|
48
|
+
<%= m.unity_write %><% end %>
|
49
|
+
}
|
50
|
+
}
|
51
|
+
<% end %>
|
52
|
+
#endregion
|
53
|
+
<% for node_direction in runtime.get_node_directions node, :client %>
|
54
|
+
public abstract class <%= node_direction.class_name %> : Client
|
55
|
+
{<% for m in node_direction.in_direction.messages.values %>
|
56
|
+
/// <summary>
|
57
|
+
/// <%= m.doc %>
|
58
|
+
/// </summary><% for p in m.members %>
|
59
|
+
/// <param name="<%= p.name %>"><%= p.doc %></param><% end %>
|
60
|
+
protected abstract <%= m.unity %>;<% end %>
|
61
|
+
|
62
|
+
public <%= node_direction.class_name %>()
|
63
|
+
{
|
64
|
+
}
|
65
|
+
|
66
|
+
private enum InMessage
|
67
|
+
{<% for m in node_direction.in_direction.messages.values %>
|
68
|
+
<%= m.name %> = <%= m.id %>,<% end %>
|
69
|
+
}
|
70
|
+
|
71
|
+
private enum OutMessage
|
72
|
+
{<% for m in node_direction.out_direction.messages.values %>
|
73
|
+
<%= m.name %> = <%= m.id %>,<% end %>
|
74
|
+
}
|
75
|
+
<% for m in node_direction.out_direction.messages.values %>
|
76
|
+
/// <summary>
|
77
|
+
/// <%= m.doc %>
|
78
|
+
/// </summary><% for p in m.members %>
|
79
|
+
/// <param name="<%= p.name %>"><%= p.doc %></param><% end %>
|
80
|
+
public <%= m.unity %>
|
81
|
+
{
|
82
|
+
var packet = new OutPacket( (int)OutMessage.<%= m.name %> );
|
83
|
+
<% for p in m.members %><%= p.unity_write %>
|
84
|
+
<% end %>this.SendPacket( packet );
|
85
|
+
}<% end %>
|
86
|
+
|
87
|
+
protected override void ProcessPacket( InPacket packet )
|
88
|
+
{
|
89
|
+
switch( (InMessage)packet.Header )
|
90
|
+
{<% for m in node_direction.in_direction.messages.values %>
|
91
|
+
case InMessage.<%= m.name %>:
|
92
|
+
{<% for p in m.members %>
|
93
|
+
var <%= p.unity_read %><% end %>
|
94
|
+
this.<%= m.name %>( <%= m.unity_param %> );
|
95
|
+
}
|
96
|
+
break;<% end %>
|
97
|
+
default:
|
98
|
+
break;
|
99
|
+
}
|
100
|
+
}
|
101
|
+
}
|
102
|
+
<% end %>
|
103
|
+
}
|
@@ -0,0 +1,188 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require_relative '../case_helper'
|
3
|
+
|
4
|
+
|
5
|
+
class BuiltinTypeDef
|
6
|
+
def unity
|
7
|
+
case @name
|
8
|
+
when 'UShort'
|
9
|
+
return 'ushort'
|
10
|
+
when 'UInt'
|
11
|
+
return 'uint'
|
12
|
+
when 'ULong'
|
13
|
+
return 'ulong'
|
14
|
+
when 'DateTime'
|
15
|
+
return 'DateTime'
|
16
|
+
when 'ByteBuffer'
|
17
|
+
return 'byte[]'
|
18
|
+
when 'List'
|
19
|
+
return 'List'
|
20
|
+
when 'Set'
|
21
|
+
return 'HashSet'
|
22
|
+
when 'Map'
|
23
|
+
return 'Dictionary'
|
24
|
+
when 'Vector2', 'Vector3', 'Color'
|
25
|
+
return @name
|
26
|
+
when 'Matrix4'
|
27
|
+
return 'Matrix4x4'
|
28
|
+
else
|
29
|
+
return @name.decapitalize
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
class EnumTypeDef
|
36
|
+
def unity
|
37
|
+
@name
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
class StructTypeDef
|
43
|
+
def unity
|
44
|
+
@name
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
class TypeInstanceDef
|
50
|
+
@@lambda_index = 0
|
51
|
+
|
52
|
+
def unity
|
53
|
+
if @params.empty?
|
54
|
+
return @type.unity
|
55
|
+
else
|
56
|
+
return "#{@type.unity}#{unity_type_param}"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def unity_read is_top_scope
|
61
|
+
str = ''
|
62
|
+
if @type.is_a? StructTypeDef
|
63
|
+
str = "packet.ReadStruct( new #{@type.name}() )"
|
64
|
+
elsif @type.is_a? EnumTypeDef
|
65
|
+
str = "(#{@type.name})packet.ReadInt()"
|
66
|
+
else
|
67
|
+
str = "packet.Read#{unity_read_write}"
|
68
|
+
if @params.empty?
|
69
|
+
str += '()'
|
70
|
+
else
|
71
|
+
param_str = @params.map { |p| p.unity_read false } .join ', '
|
72
|
+
str += '( ' + param_str + ' )'
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
if is_top_scope == false
|
77
|
+
str = '() => ' + str
|
78
|
+
end
|
79
|
+
|
80
|
+
str
|
81
|
+
end
|
82
|
+
|
83
|
+
def unity_write member_name, is_top_scope
|
84
|
+
str = ''
|
85
|
+
if @type.is_a? StructTypeDef
|
86
|
+
str = "packet.WriteStruct( #{member_name} )"
|
87
|
+
elsif @type.is_a? EnumTypeDef
|
88
|
+
str = "packet.WriteInt( (int)#{member_name} )"
|
89
|
+
else
|
90
|
+
str = "packet.Write#{unity_read_write}"
|
91
|
+
if @params.empty?
|
92
|
+
str += "( #{member_name} )"
|
93
|
+
else
|
94
|
+
params_str = @params.map do |p|
|
95
|
+
@@lambda_index += 1
|
96
|
+
arg_name = '_' + @@lambda_index.to_s
|
97
|
+
p.unity_write arg_name, false
|
98
|
+
end
|
99
|
+
param_str = params_str.join ', '
|
100
|
+
str += "( #{member_name}, #{param_str} )"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
if is_top_scope == false
|
105
|
+
str = "( #{member_name} ) => " + str
|
106
|
+
end
|
107
|
+
|
108
|
+
str
|
109
|
+
end
|
110
|
+
|
111
|
+
def unity_read_write
|
112
|
+
if @params.empty?
|
113
|
+
return @type.name
|
114
|
+
else
|
115
|
+
return "#{@type.name}#{unity_type_param}"
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def unity_type_param
|
120
|
+
return '' if @params.empty?
|
121
|
+
param_str = @params.map { |p| p.unity } .join ', '
|
122
|
+
'<' + param_str + '>'
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
|
127
|
+
class MemberDef
|
128
|
+
def unity_def
|
129
|
+
"public #{unity_param};"
|
130
|
+
end
|
131
|
+
|
132
|
+
def unity_param
|
133
|
+
"#{@type.unity} #{@name}"
|
134
|
+
end
|
135
|
+
|
136
|
+
def unity_read
|
137
|
+
"#{@name} = #{@type.unity_read true};"
|
138
|
+
end
|
139
|
+
|
140
|
+
def unity_write
|
141
|
+
"#{@type.unity_write @name, true};"
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
|
146
|
+
class DirectionDef
|
147
|
+
def unity_name
|
148
|
+
"#{@client}#{@server}Connector"
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
|
153
|
+
class MessageDef
|
154
|
+
def unity
|
155
|
+
param_str = members.map { |m| m.unity_param } .join ', '
|
156
|
+
"void #{@name}( #{param_str} )"
|
157
|
+
end
|
158
|
+
|
159
|
+
def unity_param
|
160
|
+
members.map { |m| m.name } .join ', '
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
|
165
|
+
class NodeDirection
|
166
|
+
def class_name
|
167
|
+
"#{@remote.name}ConnectorBase"
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
|
172
|
+
class UnityClientGenerator < Generator
|
173
|
+
def initialize
|
174
|
+
super 'unity', :client
|
175
|
+
end
|
176
|
+
|
177
|
+
def generate node, runtime
|
178
|
+
folder = File.expand_path File.dirname __FILE__
|
179
|
+
erb_file = folder + '/unity_client_generator.cs.erb'
|
180
|
+
template = File.read erb_file
|
181
|
+
erb = ERB.new template
|
182
|
+
content = erb.result binding
|
183
|
+
File.write "#{node.name}.cs", content
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
|
188
|
+
Generator.add UnityClientGenerator.new
|
data/lib/lexer.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'rltk'
|
2
|
+
|
3
|
+
|
4
|
+
class Lexer < RLTK::Lexer
|
5
|
+
# Whitespace
|
6
|
+
rule(/\s/)
|
7
|
+
|
8
|
+
# Keyword
|
9
|
+
rule(/namespace/) { :NAMESPACE }
|
10
|
+
rule(/include/) { :INCLUDE }
|
11
|
+
rule(/node/) { :NODE }
|
12
|
+
rule(/as/) { :AS }
|
13
|
+
rule(/struct/) { :STRUCT }
|
14
|
+
rule(/enum/) { :ENUM }
|
15
|
+
rule(/direction/) { :DIRECTION }
|
16
|
+
rule(/message/) { :MESSAGE }
|
17
|
+
rule(/sequence/) { :SEQUENCE }
|
18
|
+
rule(/end/) { :END }
|
19
|
+
|
20
|
+
# Operator
|
21
|
+
rule(/\./) { :DOT }
|
22
|
+
rule(/\=/) { :ASSIGN }
|
23
|
+
rule(/<-/) { :LARROW }
|
24
|
+
rule(/->/) { :RARROW }
|
25
|
+
rule(/:/) { :COLON }
|
26
|
+
rule(/</) { :LANGLE }
|
27
|
+
rule(/>/) { :RANGLE }
|
28
|
+
rule(/,/) { :COMMA }
|
29
|
+
|
30
|
+
# Number
|
31
|
+
rule(/(\+|-)?\d+/) { |t| [:NUMBER, t.to_i] }
|
32
|
+
rule(/0[xX][0-9a-fA-F]+/) { |t| [:NUMBER, t.hex] }
|
33
|
+
|
34
|
+
# String
|
35
|
+
rule(/'.+'/) { |t| [:STRING, t[1..-2]] }
|
36
|
+
|
37
|
+
# Identifier
|
38
|
+
rule(/[A-Za-z_][A-Za-z0-9_]*/) { |t| [:IDENT, t] }
|
39
|
+
|
40
|
+
# Document
|
41
|
+
rule(/#.*/) { |t| [:DOCUMENT, t[1..-1].strip] }
|
42
|
+
end
|
data/lib/parser.rb
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'rltk'
|
2
|
+
require_relative 'ast'
|
3
|
+
|
4
|
+
|
5
|
+
module RLTK
|
6
|
+
class Parser
|
7
|
+
class Environment
|
8
|
+
def position
|
9
|
+
Position.new @positions.first, @positions.last
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
class Parser < RLTK::Parser
|
17
|
+
@@enum_value = 0
|
18
|
+
|
19
|
+
list(:decl_list, :decl)
|
20
|
+
|
21
|
+
production(:decl) do
|
22
|
+
clause('include_decl') { |d| d }
|
23
|
+
clause('node_decl') { |d| d }
|
24
|
+
clause('struct_decl') { |d| d }
|
25
|
+
clause('enum_decl') { |d| d }
|
26
|
+
clause('direction_decl') { |d| d }
|
27
|
+
clause('sequence_decl') { |d| d }
|
28
|
+
end
|
29
|
+
|
30
|
+
production(:include_decl) do
|
31
|
+
clause('INCLUDE STRING') { |_, filename| IncludeDecl.new self.position, filename }
|
32
|
+
end
|
33
|
+
|
34
|
+
production(:node_decl) do
|
35
|
+
clause('NODE IDENT IDENT doc') { |_, language, name, doc| NodeDecl.new self.position, name, language, name, '', doc }
|
36
|
+
clause('NODE IDENT IDENT AS IDENT doc') { |_, language, name, _, nickname, doc| NodeDecl.new self.position, name, language, nickname, '', doc }
|
37
|
+
clause('NODE IDENT IDENT NAMESPACE namespace doc') { |_, language, name, _, namespace, doc| NodeDecl.new self.position, name, language, name, namespace, doc }
|
38
|
+
clause('NODE IDENT IDENT AS IDENT NAMESPACE namespace doc') { |_, language, name, _, nickname, _, namespace, doc| NodeDecl.new self.position, name, language, nickname, namespace, doc }
|
39
|
+
end
|
40
|
+
|
41
|
+
production(:namespace) do
|
42
|
+
clause('IDENT') { |name| name }
|
43
|
+
clause('IDENT DOT namespace') { |name, _, rest| name + '.' + rest }
|
44
|
+
end
|
45
|
+
|
46
|
+
production(:doc) do
|
47
|
+
clause('') { || '' }
|
48
|
+
clause('DOCUMENT') { |doc| doc }
|
49
|
+
end
|
50
|
+
|
51
|
+
production(:struct_decl) do
|
52
|
+
clause('STRUCT IDENT doc member_list END') { |_, name, doc, members, _| StructDecl.new self.position, name, doc, members }
|
53
|
+
end
|
54
|
+
|
55
|
+
list(:member_list, :member)
|
56
|
+
|
57
|
+
production(:member) do
|
58
|
+
clause('type IDENT doc') { |type, name, doc| MemberDecl.new self.position, type, name, doc }
|
59
|
+
end
|
60
|
+
|
61
|
+
production(:type) do
|
62
|
+
clause('IDENT') { |name| TypeDecl.new self.position, name, [] }
|
63
|
+
clause('IDENT LANGLE type_param_list RANGLE') { |name, _, params, _| TypeDecl.new self.position, name, params }
|
64
|
+
end
|
65
|
+
|
66
|
+
nonempty_list(:type_param_list, :type, :COMMA)
|
67
|
+
|
68
|
+
production(:enum_decl) do
|
69
|
+
clause('ENUM IDENT doc element_list END') { |_, name, doc, elements, _| @@enum_value = 0; EnumDecl.new self.position, name, doc, elements }
|
70
|
+
end
|
71
|
+
|
72
|
+
list(:element_list, :element)
|
73
|
+
|
74
|
+
production(:element) do
|
75
|
+
clause('IDENT doc') { |name, doc| @@enum_value += 1; EnumElementDecl.new self.position, name, @@enum_value - 1, doc }
|
76
|
+
clause('IDENT ASSIGN NUMBER doc') { |name, _, value, doc| @@enum_value = value + 1; EnumElementDecl.new self.position, name, @@enum_value - 1, doc }
|
77
|
+
end
|
78
|
+
|
79
|
+
production(:direction_decl) do
|
80
|
+
clause('DIRECTION IDENT arrow IDENT doc message_list END') { |_, client, direction, server, doc, messages, _| DirectionDecl.new self.position, client, direction, server, doc, messages }
|
81
|
+
end
|
82
|
+
|
83
|
+
production(:arrow) do
|
84
|
+
clause('LARROW') { |_| :left }
|
85
|
+
clause('RARROW') { |_| :right }
|
86
|
+
end
|
87
|
+
|
88
|
+
list(:message_list, :message)
|
89
|
+
|
90
|
+
production(:message) do
|
91
|
+
clause('MESSAGE IDENT doc member_list END') { |_, name, doc, members, _| MessageDecl.new self.position, name, doc, members }
|
92
|
+
end
|
93
|
+
|
94
|
+
production(:sequence_decl) do
|
95
|
+
clause('SEQUENCE IDENT doc step_list END') { |_, name, doc, steps, _| SequenceDecl.new self.position, name, doc, steps }
|
96
|
+
end
|
97
|
+
|
98
|
+
list(:step_list, :step)
|
99
|
+
|
100
|
+
production(:step) do
|
101
|
+
clause('IDENT arrow IDENT COLON IDENT doc') { |client, direction, server, _, message, doc| StepDecl.new self.position, client, direction, server, message, doc }
|
102
|
+
end
|
103
|
+
|
104
|
+
finalize
|
105
|
+
end
|