Squash commits for public release

This commit is contained in:
2025-02-12 09:54:05 -05:00
commit 7118adc514
1108 changed files with 80873 additions and 0 deletions

View File

@@ -0,0 +1,232 @@
class Message:
def __init__(self, name, id, reply_id, decoder_magic, params, protected=False):
self.name = name
self.id = id
self.reply_id = reply_id
self.decoder_magic = decoder_magic
self.params = params
self.protected = protected
class Generator:
def __init__(self):
self.output = None
def out(self, str, tabs=0):
for i in range(tabs):
self.output.write(" ")
self.output.write(str)
self.output.write("\n")
def params_readable(self, params):
res = ""
if len(params) > 0:
for i in params:
res += "{0} {1},".format(i[0], i[1])
res = res[:-1]
return res
def message_create_std_funcs(self, msg):
self.out("int id() const override {{ return {0}; }}".format(msg.id), 1)
self.out("int reply_id() const override {{ return {0}; }}".format(
msg.reply_id), 1)
if msg.protected:
self.out("int key() const override { return m_key; }", 1)
self.out("int decoder_magic() const override {{ return {0}; }}".format(
msg.decoder_magic), 1)
for i in msg.params:
if i[0] in ["int", "uint32_t", "bool", "int32_t"]:
self.out(
"{0} {1}() const {{ return m_{1}; }}".format(i[0], i[1]), 1)
else:
self.out(
"{0}& {1}() {{ return m_{1}; }}".format(i[0], i[1]), 1)
def message_create_vars(self, msg):
if msg.protected:
self.out("message_key_t m_key;", 1)
for i in msg.params:
self.out("{0} m_{1};".format(i[0], i[1]), 1)
def message_create_constructor(self, msg):
params = msg.params
if msg.protected:
params = [('message_key_t', 'key')] + msg.params
res = "{0}({1})".format(msg.name, self.params_readable(params))
if len(params) > 0:
self.out(res, 1)
sign = ':'
for i in params:
self.out("{0} m_{1}({1})".format(sign, i[1]), 2)
sign = ','
self.out("{", 1)
self.out("}", 1)
else:
self.out(res+" {}", 1)
def message_create_encoder(self, msg):
self.out("EncodedMessage encode() const override".format(
msg.decoder_magic), 1)
self.out("{", 1)
self.out("EncodedMessage buffer;", 2)
self.out("Encoder::append(buffer, decoder_magic());", 2)
self.out("Encoder::append(buffer, id());", 2)
if msg.protected:
self.out("Encoder::append(buffer, key());", 2)
for i in msg.params:
self.out("Encoder::append(buffer, m_{0});".format(i[1]), 2)
self.out("return buffer;", 2)
self.out("}", 1)
def generate_message(self, msg):
self.out("class {0} : public Message {{".format(msg.name))
self.out("public:")
self.message_create_constructor(msg)
self.message_create_std_funcs(msg)
self.message_create_encoder(msg)
self.out("private:")
self.message_create_vars(msg)
self.out("};")
self.out("")
def decoder_create_vars(self, messages, offset=0):
var_names = set()
for (name, params) in messages.items():
for i in params:
if 'var_{0}'.format(i[1]) not in var_names:
self.out("{0} var_{1};".format(i[0], i[1]), offset)
var_names.add('var_{0}'.format(i[1]))
def decoder_decode_message(self, msg, offset=0):
params_str = ""
if msg.protected:
params_str = "secret_key, "
for i in msg.params:
params_str += "var_{0}, ".format(i[1])
if len(params_str) > 0:
params_str = params_str[:-2]
for i in msg.params:
self.out(
"Encoder::decode(buf, decoded_msg_len, var_{0});".format(i[1]), offset)
self.out("return new {0}({1});".format(msg.name, params_str), offset)
def decoder_create_std_funcs(self, decoder):
self.out("int magic() const {{ return {0}; }}".format(
decoder.magic), 1)
def decoder_create_decode(self, decoder):
self.out(
"std::unique_ptr<Message> decode(const char* buf, size_t size, size_t& decoded_msg_len) override", 1)
self.out("{", 1)
self.out("int msg_id, decoder_magic;", 2)
self.out("size_t saved_dml = decoded_msg_len;", 2)
self.out("Encoder::decode(buf, decoded_msg_len, decoder_magic);", 2)
self.out("Encoder::decode(buf, decoded_msg_len, msg_id);", 2)
self.out("if (magic() != decoder_magic) {", 2)
self.out("decoded_msg_len = saved_dml;", 3)
self.out("return nullptr;", 3)
self.out("}", 2)
if decoder.protected:
self.out("message_key_t secret_key;", 2)
self.out("Encoder::decode(buf, decoded_msg_len, secret_key);", 2)
self.out("", 0)
self.decoder_create_vars(decoder.messages, 2)
unique_msg_id = 1
self.out("", 2)
self.out("switch(msg_id) {", 2)
for (name, params) in decoder.messages.items():
self.out("case {0}:".format(unique_msg_id), 2)
# Here it doen't need to know the real reply_id, so we can put 0 here.
self.decoder_decode_message(
Message(name, unique_msg_id, 0, decoder.magic, params, decoder.protected), 3)
unique_msg_id += 1
self.out("default:", 2)
self.out("decoded_msg_len = saved_dml;", 3)
self.out("return nullptr;", 3)
self.out("}", 2)
self.out("}", 1)
self.out("", 1)
def decoder_create_handle(self, decoder):
self.out("std::unique_ptr<Message> handle(Message& msg) override", 1)
self.out("{", 1)
self.out("if (magic() != msg.decoder_magic()) {", 2)
self.out("return nullptr;", 3)
self.out("}", 2)
unique_msg_id = 1
self.out("", 2)
self.out("switch(msg.id()) {", 2)
for (name, params) in decoder.messages.items():
if name in decoder.functions:
self.out("case {0}:".format(unique_msg_id), 2)
self.out(
"return handle(static_cast<{0}&>(msg));".format(name), 3)
unique_msg_id += 1
self.out("default:", 2)
self.out("return nullptr;", 3)
self.out("}", 2)
self.out("}", 1)
self.out("", 1)
def decoder_create_virtual_handle(self, decoder):
for (accept, ret) in decoder.functions.items():
self.out(
"virtual std::unique_ptr<Message> handle({0}& msg) {{ return nullptr; }}".format(accept), 1)
def generate_decoder(self, decoder):
self.out("class {0} : public MessageDecoder {{".format(decoder.name))
self.out("public:")
self.out("{0}() {{}}".format(decoder.name), 1)
self.decoder_create_std_funcs(decoder)
self.decoder_create_decode(decoder)
self.decoder_create_handle(decoder)
self.decoder_create_virtual_handle(decoder)
self.out("};")
self.out("")
def includes(self):
self.out("// Auto generated with utils/ConnectionCompiler")
self.out("// See .ipc file")
self.out("")
self.out("#pragma once")
self.out("#include <libipc/Encoder.h>")
self.out("#include <libipc/ClientConnection.h>")
self.out("#include <libipc/ServerConnection.h>")
self.out("#include <libipc/StringEncoder.h>")
self.out("#include <libipc/VectorEncoder.h>")
self.out("#include <new>")
self.out("#include <libg/Rect.h>")
self.out("")
def generate(self, filename, decoders):
self.output = open(filename, "w+")
self.includes()
for decoder in decoders:
msgd = {}
unique_msg_id = 1
for (name, params) in decoder.messages.items():
msgd[name] = unique_msg_id
unique_msg_id += 1
for (name, params) in decoder.messages.items():
reply_name = decoder.functions.get(name, None)
reply_id = -1
if reply_name is not None:
reply_id = msgd[reply_name]
self.generate_message(
Message(name, msgd[name], reply_id, decoder.magic, params, decoder.protected))
self.generate_decoder(decoder)
self.output.close()

View File

@@ -0,0 +1,108 @@
from token import Token
from Lexer.reserved_symbols import *
from type_file import Type
class Lexer():
MAX_OPERATION_SIZE = 2
def __init__(self, code: [str]):
self.code = code
self.current_code_part = code[0]
self.current_code_line = 0
self.code_lines = len(code)
self.current_position = 0
self.current_char = self.current_code_part[self.current_position]
def advance(self):
self.current_position += 1
if self.current_position < len(self.current_code_part):
self.current_char = self.current_code_part[self.current_position]
else:
self.current_code_line += 1
if self.current_code_line < self.code_lines:
self.current_code_part = self.code[self.current_code_line]
self.current_position = 0
self.current_char = self.current_code_part[0]
else:
self.current_char = None
def skip_rest_of_line(self):
start_with_line = self.current_code_line
while self.current_char is not None and self.current_code_line == start_with_line:
self.advance()
def lookup(self, count):
peek_pos = self.current_position + count
if peek_pos < len(self.current_code_part):
return self.current_code_part[peek_pos]
else:
return None
def skip_gaps(self):
while self.current_char is not None and self.current_char == ' ':
self.advance()
def read_number(self):
result = ""
was_dot = False
while self.current_char is not None and (self.current_char.isdigit() or self.current_char == '.'):
if self.current_char == '.':
if was_dot:
print(">2 dots in number")
exit(0)
was_dot = True
result += self.current_char
self.advance()
if was_dot:
return Token(Type.Number.Real, float(result))
else:
return Token(Type.Number.Integer, int(result))
def read_word(self):
type = Type.Word
result = ""
while self.current_char is not None and (self.current_char.isalpha() or self.current_char.isdigit() or self.current_char == '_' or self.current_char == '<' or self.current_char == '>' or (self.current_char == ':' and self.lookup(1) == ':')):
if (self.current_char == ':'):
result += self.current_char
self.advance()
result += self.current_char
self.advance()
if result.upper() in reserved_words:
return Token(reserved_words[result.upper()], result.upper())
return Token(type, result)
def read_operation(self):
token = Token()
operation = ""
for i in range(self.MAX_OPERATION_SIZE):
next_element = self.lookup(i)
if next_element is None:
break
operation += next_element
if operation in reserved_symbols.keys():
token = Token(reserved_symbols[operation], operation)
if token.value is not None:
for i in range(len(token.value)):
self.advance()
return token
def next_token(self):
self.skip_gaps()
while self.current_char == '#':
self.skip_rest_of_line()
self.skip_gaps()
if self.current_char is None:
return Token(Type.Special.EOF, None)
elif self.current_char.isdigit():
return self.read_number()
elif self.current_char.isalpha():
return self.read_word()
else:
return self.read_operation()

View File

@@ -0,0 +1,24 @@
from type_file import Type
reserved_symbols = {
'(': Type.Lang.LeftBracket,
')': Type.Lang.RightBracket,
';': Type.Lang.Semi,
'.': Type.Lang.Dot,
',': Type.Lang.Comma,
':': Type.Lang.Colon,
'=>': Type.Reserved.Return,
'{': Type.Reserved.Begin,
'}': Type.Reserved.End,
}
reserved_words = {
'NAME': Type.Reserved.Name,
'MAGIC': Type.Reserved.Magic,
'KEYPROTECTED': Type.Reserved.KeyProtected,
}
available_var_types = [Type.Number.Integer,
Type.Number.Real, Type.Number.Boolean]

View File

@@ -0,0 +1,140 @@
from Lexer.lexer import Lexer
from token import Token
from type_file import Type
from connection import Connection
class Parser:
def set_code_lines(self, code: [str]):
self.lexer = Lexer(code)
self.token = Token()
self.current_token_id = -1
self.read_tokens = 0
self.lexer_rich_the_end = 0
self.tokens = []
self.next_token()
def next_token(self):
self.current_token_id += 1
self.token = self.get_token_at(self.current_token_id)
def get_token_at(self, pos):
if pos >= self.read_tokens and not self.lexer_rich_the_end:
for i in range(pos - self.read_tokens + 1):
self.tokens.append(self.lexer.next_token())
self.read_tokens += 1
if self.tokens[-1].type == Type.Special.EOF:
self.lexer_rich_the_end = True
break
return self.tokens[min(pos, self.read_tokens - 1)]
def is_nth(self, type_of_token, n):
if isinstance(type_of_token, list):
for type_of_cur_token in type_of_token:
if self.get_token_at(self.current_token_id+n).type == type_of_cur_token:
return True
return False
return self.get_token_at(self.current_token_id+n).type == type_of_token
def is_next(self, type_of_token):
if isinstance(type_of_token, list):
for type_of_cur_token in type_of_token:
if self.token.type == type_of_cur_token:
return True
return False
return self.token.type == type_of_token
def must_next(self, type_of_token):
if not self.is_next(type_of_token):
print("{0} is not {1}".format(self.token, type_of_token))
exit(1)
def __init__(self):
pass
def eat_name(self):
self.must_next(Type.Reserved.Name)
self.next_token()
self.must_next(Type.Lang.Colon)
self.next_token()
self.must_next(Type.Word)
res = self.token.value
self.next_token()
return res
def eat_protected(self):
if (self.is_next(Type.Reserved.KeyProtected)):
self.next_token()
return True
return False
def eat_magic(self):
self.must_next(Type.Reserved.Magic)
self.next_token()
self.must_next(Type.Lang.Colon)
self.next_token()
self.must_next(Type.Number.Integer)
res = self.token.value
self.next_token()
return res
def eat_params(self):
params = []
self.must_next(Type.Lang.LeftBracket)
self.next_token()
while not self.is_next(Type.Lang.RightBracket):
self.must_next(Type.Word)
typ = self.token.value
self.next_token()
self.must_next(Type.Word)
nam = self.token.value
self.next_token()
params.append([typ, nam])
if self.is_next(Type.Lang.Comma):
self.must_next(Type.Lang.Comma)
self.next_token()
self.must_next(Type.Lang.RightBracket)
self.next_token()
return params
def eat_message(self, decoder):
self.must_next(Type.Word)
msgname = self.token.value
self.next_token()
decoder.add_message(msgname, self.eat_params())
return msgname
def eat_function(self, decoder):
ms1 = self.eat_message(decoder)
ms2 = None
if self.is_next(Type.Reserved.Return):
self.must_next(Type.Reserved.Return)
self.next_token()
ms2 = self.eat_message(decoder)
decoder.add_function(ms1, ms2)
def eat_decoder(self):
self.must_next(Type.Reserved.Begin)
self.next_token()
is_protected = self.eat_protected()
decoder = Connection(self.eat_name(), self.eat_magic(), is_protected)
while not self.is_next(Type.Reserved.End):
self.eat_function(decoder)
self.must_next(Type.Reserved.End)
self.next_token()
return decoder
def parse(self):
decoders = []
while self.is_next(Type.Reserved.Begin):
decoders.append(self.eat_decoder())
print("connc: {0} decoders parsed!".format(len(decoders)))
return decoders

View File

@@ -0,0 +1,30 @@
#!/usr/bin/env python
from Parser.parser import Parser
from Generator.generator import Generator
from type_file import Type
from token import Token
import argparse
def run(input_f, output_f):
code = []
file = open(input_f, "r")
for line in file:
line = line.replace('\n', '')
if len(line) > 0:
code.append(line)
parser = Parser()
gen = Generator()
parser.set_code_lines(code)
gen.generate(output_f, parser.parse())
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('inf', type=str, help='Input file')
parser.add_argument('outf', type=str, help='Output file')
args = parser.parse_args()
run(args.inf, args.outf)

View File

@@ -0,0 +1,30 @@
#!/usr/bin/env python3
from Parser.parser import Parser
from Generator.generator import Generator
from type_file import Type
from token import Token
import argparse
def run(input_f, output_f):
code = []
file = open(input_f, "r")
for line in file:
line = line.replace('\n', '')
if len(line) > 0:
code.append(line)
parser = Parser()
gen = Generator()
parser.set_code_lines(code)
gen.generate(output_f, parser.parse())
parser = argparse.ArgumentParser()
parser.add_argument('inf', type=str, help='Input file')
parser.add_argument('outf', type=str, help='Output file')
args = parser.parse_args()
run(args.inf, args.outf)

View File

@@ -0,0 +1,21 @@
class Connection:
def __init__(self, name, magic, protected=False):
self.name = name
self.magic = magic
self.protected = protected
self.messages = {}
self.functions = {}
def add_message(self, msg_name, params):
if msg_name in self.messages:
op = self.messages[msg_name]
if (params != op):
print("{0} has 2 different params".format(msg1_name))
exit(1)
self.messages[msg_name] = params
def add_function(self, msg1_name, msg2_name=None):
if msg1_name in self.functions:
print("{0} has 2 functions".format(msg1_name))
exit(1)
self.functions[msg1_name] = msg2_name

View File

@@ -0,0 +1,8 @@
class Token:
def __init__(self, type=None, value=None):
self.type = type
self.value = value
def __str__(self):
return "Token({0}, {1})".format(self.type, self.value)

View File

@@ -0,0 +1,39 @@
class Type:
Word = 'WORD'
class Number:
Integer = 'INTEGER'
Real = 'REAL'
Boolean = 'BOOLEAN'
class BinaryOperation:
Plus = 'PLUS'
Minus = 'MINUS'
Mul = 'MUL'
Div = 'DIV'
class UnaryOperation:
fill = 'FILL'
Plus = 'PLUS'
Minus = 'MINUS'
Not = 'NOT'
class Lang:
LeftBracket = 'LeftBracket'
RightBracket = 'RightBracket'
Semi = 'SEMI'
Dot = 'DOT'
Comma = 'COMMA'
Colon = 'COLON'
class Reserved:
Begin = 'BEGIN'
End = 'END'
Return = 'RETURN'
Name = 'NAME'
Magic = 'MAGIC'
KeyProtected = 'KEYP'
class Special:
EOF = 'EOF'