示例#1
0
 def print_lines(self, var: Variable, size: str, indent_lvl: int) -> None:
     """Print the content of a var that holds in one or more lines"""
     if var.fits_in_one_line(self.input.structs):
         self.print_line(var, size, indent_lvl)
     else:
         if var.type.main == TypeEnum.STRUCT:
             struct = self.input.get_struct(var.type.struct_name)
             struct = self.input.get_struct(var.type.struct_name)
             for f_name, f_type, f_size in struct.fields_name_type_size(
                     f"{var.name}.{{}}", var_name):
                 self.print_lines(Variable(f_name, "", f_type), f_size,
                                  indent_lvl)
         else:
             assert var.type.main == TypeEnum.LIST
             assert var.type.encapsulated is not None
             index = self.iterator.new_it()
             self.method.append(
                 "{0}for (int {1} = 0; {1} < {2}; ++{1}) {{".format(
                     " " * self.indentation * indent_lvl, index, size))
             self.print_lines(
                 Variable(f"{var.name}[{index}]", "",
                          var.type.encapsulated),
                 var_name(var.type.encapsulated.size),
                 indent_lvl + 1,
             )
             self.method.append(" " * self.indentation * indent_lvl + "}")
             self.iterator.pop_it()
示例#2
0
 def read_lines(
     self,
     var: Variable,
     size: str,
     already_allocated: bool = False,
 ) -> List[str]:
     """Read one or several lines and store them into the right place(s)"""
     lines = []
     if var.type.main == TypeEnum.LIST and not already_allocated:
         lines.append(f"{var.name} = make({type_str(var.type)}, {size})")
     if var.fits_in_one_line(self.input.structs):
         return lines + self.read_line(var.name, size, var.type)
     if var.type.main == TypeEnum.STRUCT:
         struct = self.input.get_struct(var.type.struct_name)
         for f_name, f_type, f_size in struct.fields_name_type_size(
             var.name + ".{}", var_name
         ):
             lines.extend(self.read_lines(Variable(f_name, "", f_type), f_size))
         return lines
     assert var.type.main == TypeEnum.LIST
     assert var.type.encapsulated is not None
     inner_name = self.iterator.new_it()
     lines.append(f"for {inner_name} := range {var.name} {{")
     lines.extend(
         INDENTATION + i
         for i in self.read_lines(
             Variable(f"{var.name}[{inner_name}]", "", var.type.encapsulated),
             var_name(var.type.encapsulated.size),
         )
     )
     lines.append("}")
     self.iterator.pop_it()
     return lines
示例#3
0
 def read_lines(self, decl: bool, var: Variable, size: str,
                indent_lvl: int) -> List[str]:
     # pylint: disable=too-many-arguments
     # pylint: disable=too-many-locals
     """Read one or several lines and store them into the right place(s)"""
     if var.fits_in_one_line(self.input.structs):
         return self.read_line(decl, var.name, var.type, indent_lvl)
     indent = INDENTATION * indent_lvl
     if var.type.main == TypeEnum.STRUCT:
         lines = [
             indent + "{}{} = new {}();".format(
                 class_name(var.type.struct_name) + " " if decl else "",
                 var.name,
                 class_name(var.type.struct_name),
             )
         ]
         struct = self.input.get_struct(var.type.struct_name)
         for f_name, f_type, f_size in struct.fields_name_type_size(
                 f"{var.name}.{{}}", var_name):
             lines.extend(
                 self.read_lines(False, Variable(f_name, "", f_type),
                                 f_size, indent_lvl))
         return lines
     assert var.type.main == TypeEnum.LIST
     assert var.type.encapsulated is not None
     far_inner_type = var.type.encapsulated
     list_suffix = ""
     while far_inner_type.main == TypeEnum.LIST:
         assert far_inner_type.encapsulated is not None
         far_inner_type = far_inner_type.encapsulated
         list_suffix += "[]"
     lines = [
         "{}{}{} = new {}[{}]{};".format(
             indent,
             (type_str(var.type) + " ") if decl else "",
             var.name,
             type_str(far_inner_type),
             size,
             list_suffix,
         )
     ]
     index = self.iterator.new_it()
     self.words.push_scope()
     lines.append("{0}for (int {1} = 0; {1} < {2}; ++{1}) {{".format(
         indent, index, size))
     lines.extend(
         self.read_lines(
             False,
             Variable(f"{var.name}[{index}]", "", var.type.encapsulated),
             var_name(var.type.encapsulated.size),
             indent_lvl + 1,
         ))
     self.words.pop_scope()
     self.iterator.pop_it()
     return lines + [indent + "}"]
示例#4
0
def read_vars(input_data: Input, iterator: IteratorName) -> List[str]:
    """Read all input variables"""
    all_lines = []
    for variables in input_data.get_all_vars():
        if len(variables) == 1:
            var = variables[0]
            lines = read_lines(
                Variable(var_name(var.name), "", var.type, var.format_style),
                var_name(var.type.size),
                input_data,
                iterator,
            )
            if lines[0].startswith("local"):  # struct
                lines[1] = "local " + lines[1]
            else:
                lines[0] = "local " + lines[0]
            all_lines.extend(lines)
        else:
            assert all(var.type.main == TypeEnum.INT for var in variables)
            all_lines.append(
                'local {} = string.match(io.read(), "{}")'.format(
                    ", ".join(var_name(i.name) for i in variables),
                    " ".join(["(-?%d+)"] * len(variables)),
                )
            )
    return all_lines
示例#5
0
 def call(self, reprint: bool) -> None:
     """Declare and call the function take all inputs in arguments"""
     name = var_name(self.input.name)
     arguments = []
     for arg in self.input.input:
         arg_name = var_name(arg.name)
         self.method.append("/// \\param {} {}".format(
             arg_name, arg.comment))
         arguments.append("{} {}".format(self.type_str(arg.type), arg_name))
     self.method.append("void {}({}) {{".format(name, ", ".join(arguments)))
     if reprint:
         for var in self.input.input:
             self.print_lines(
                 Variable(var_name(var.name), "", var.type,
                          var.format_style),
                 var_name(var.type.size),
                 1,
             )
     else:
         self.method.extend([
             " " * self.indentation + i
             for i in textwrap.wrap("/* TODO " + self.input.output +
                                    " */", 79 - self.indentation)
         ])
     self.method.append("}")
示例#6
0
def error_parse_variable(dic: Dict[str, str]) -> str:
    """Explain why we a variable fails to parse"""
    # pylint: disable=too-many-return-statements
    assert Variable.from_dict(dic) is None
    if "name" not in dic:
        return "missing name field"
    if not isinstance(dic["name"], str):
        return "name field is not a string"
    for field in ("comment", "type"):
        if field not in dic:
            return "missing {} field for {}".format(field, dic["name"])
        if not isinstance(dic[field], str):
            return "{} field for {} is not a string".format(field, dic["name"])
    type_ = Type.from_string(dic["type"])
    if type_ is None:
        return "unable to parse type {} for {}: {}".format(
            dic["type"], dic["name"], error_parse_type(dic["type"]))
    if dic.get("format", "") == "no_endline" and type_.main != TypeEnum.INT:
        return f'{dic["name"]} has format "no_endline" but is {dic["type"]}, not int'
    if dic.get("format", "") == "force_newlines" and (
            type_.main != TypeEnum.LIST or type_.encapsulated is None
            or type_.encapsulated.main != TypeEnum.INT):
        return (
            f'{dic["name"]} has format "force_newlines" but is {dic["type"]}'
            ", not List[int]")
    return "unknown error"
示例#7
0
def error_parse_input(dic: Dict[str, Any]) -> str:
    """Explain why we an input fails to parse"""
    # pylint: disable=too-many-return-statements
    # pylint: disable=too-many-branches
    assert Input.from_dict(dic) is None
    if "function_name" not in dic:
        if "name" in dic:
            dic["function_name"] = dic["name"]
        else:
            return "missing function_name field"
    if not isinstance(dic["function_name"], str):
        return "function_name is not a string"
    if "structs" in dic:  # non mandatory
        if not isinstance(dic["structs"], list):
            return "'structs' is not a list"
        for node in dic["structs"]:
            if Struct.from_dict(node) is None:
                return "failed to parse struct: " + error_parse_struct(node)
    if "input" not in dic:
        return "missing input field"
    if not isinstance(dic["input"], list):
        return "output is not a list"
    for node in dic["input"]:
        if Variable.from_dict(node) is None:
            return "failed to parse variable: " + error_parse_variable(node)
    if "output" not in dic:
        return "missing output field"
    if not isinstance(dic["output"], str):
        return "output is not a string"
    return "unknown error"
示例#8
0
def read_lines(var: Variable, decl: str, size: str, input_data: Input,
               words: WordsName) -> List[str]:
    """Generate the Ruby code to read the lines for a given type"""
    if var.fits_in_one_line(input_data.structs):
        return read_line(var.name, decl, var.type, input_data, words)
    if var.type.main == TypeEnum.LIST:
        assert var.type.encapsulated is not None
        lines = [
            decl.format("()" if var.name[0] == "@" else "[]"),
            "for (1..{}) {{".format(size),
        ]
        words.push_scope()
        array_name = var.name.replace("{", "{{").replace("}", "}}")
        if array_name[0] != "@":
            array_name = "@{{" + array_name + "}}"
        lines.extend([
            INDENTATION + i for i in read_lines(
                Variable("$" + var.name[1:] +
                         "[-1]", "", var.type.encapsulated),
                "push({}, {{}});".format(array_name),
                size_name(var.type.encapsulated.size),
                input_data,
                words,
            )
        ])
        words.pop_scope()
        return lines + ["}"]
    assert var.type.main == TypeEnum.STRUCT
    struct = input_data.get_struct(var.type.struct_name)
    sizes = [size_name(field.type.size) for field in struct.fields]
    if struct.is_sized_struct():
        sizes = ["", f"{var.name}{{'{struct.fields[0].name}'}}"]
    lines = [decl.format("()" if var.name[0] == "%" else "{}")]
    for (field, f_size) in zip(struct.fields, sizes):
        f_name = f"${var.name[1:]}{{'{field.name}'}}"
        lines.extend(
            read_lines(
                Variable(f_name, "", field.type),
                f_name.replace("{", "{{").replace("}", "}}") + " = {};",
                f_size,
                input_data,
                words,
            ))
    return lines
示例#9
0
    def read_var(self, var: Variable, in_error_context: bool = False) -> str:
        """Return a Rust command for parsing a variable"""
        name = var_name(var.name)
        unwrap_method = "?" if in_error_context else None

        if var.fits_in_one_line(self.input.structs):
            read_method = self.read_line(var.type, 1, var.name, unwrap_method)
        else:
            read_method = "\n".join(self.read_lines(name, var.type, 1, unwrap_method))

        return f"    let {name} = {read_method};"
示例#10
0
 def generate_lines(self, var: Variable) -> List[str]:
     """Generate the raw input for a type"""
     if var.fits_in_one_line(self.input.structs):
         return [self.generate_line(var.name, var.type, var.constraints)]
     if var.type.main == TypeEnum.LIST:
         assert var.type.encapsulated
         inner = Variable("", "", var.type.encapsulated)
         inner.constraints = var.constraints
         lines = []
         for _ in range(self.eval_var(var.type.size)):
             lines.extend(self.generate_lines(inner))
         return lines
     if var.type.main == TypeEnum.STRUCT:
         struct = self.input.get_struct(var.type.struct_name)
         lines = []
         for field in struct.fields:
             lines.extend(self.generate_lines(field))
         return lines
     assert False
     return []
示例#11
0
 def content(self, reprint: bool) -> str:
     """Return the parser content"""
     output = ""
     for struct in self.input.structs:
         output += f"/**\n * {struct.comment}\n */\n"
         output += "class {}\n{{\n".format(class_name(struct.name))
         for field in struct.fields:
             decl_field = "{0}/**\n{0} * {1}\n{0} */\n{0}public {2} {3};\n"
             output += decl_field.format(
                 INDENTATION,
                 field.comment,
                 type_str(field.type),
                 var_name(field.name),
             )
         output += "}\n\n"
     output += "class Main {\n"
     output += "\n".join(self.call(reprint)) + "\n\n"
     output += (
         INDENTATION +
         "public static void main(String[] args) throws java.io.IOException {\n"
     )
     output += 2 * INDENTATION + (
         "BufferedReader reader = "
         "new BufferedReader(new InputStreamReader(System.in));\n")
     for variables in self.input.get_all_vars():
         if len(variables) == 1:
             var = variables[0]
             for line in self.read_lines(
                     True,
                     Variable(var_name(var.name), "", var.type,
                              var.format_style),
                     var_name(var.type.size),
                     2,
             ):
                 output += line + "\n"
         else:
             words = self.words.next_name()
             output += (f"{INDENTATION * 2}String[] {words}"
                        ' = reader.readLine().split(" ");\n')
             for i, var in enumerate(variables):
                 assert var.type.main == TypeEnum.INT
                 output += (
                     INDENTATION * 2 +
                     f"int {var_name(var.name)} = Integer.parseInt({words}[{i}]);\n"
                 )
     args = (var_name(var.name) for var in self.input.input)
     output += "\n{}{}({});\n".format(INDENTATION * 2,
                                      var_name(self.input.name),
                                      ", ".join(args))
     output += INDENTATION + "}\n}\n"
     return "".join(f"import {i};\n"
                    for i in sorted(self.imports)) + "\n" + output
示例#12
0
 def print_lines(
     self,
     var: Variable,
     size: str,
     indent_lvl: int,
 ) -> List[str]:
     """Print the content of a var that holds in one or more lines"""
     if var.fits_in_one_line(self.input.structs):
         return [
             INDENTATION * indent_lvl + self.print_line(var.name, var.type)
         ]
     if var.type.main == TypeEnum.STRUCT:
         struct = self.input.get_struct(var.type.struct_name)
         lines = []
         for f_name, f_type, f_size in struct.fields_name_type_size(
                 f"{var.name}.{{}}", var_name):
             lines.extend(
                 self.print_lines(Variable(f_name, "", f_type), f_size,
                                  indent_lvl))
         return lines
     assert var.type.main == TypeEnum.LIST
     assert var.type.encapsulated is not None
     index = self.iterator.new_it()
     self.words.push_scope()
     lines = [
         "{0}for (int {1} = 0; {1} < {2}; ++{1}) {{".format(
             INDENTATION * indent_lvl, index, size)
     ]
     lines.extend(
         self.print_lines(
             Variable(f"{var.name}[{index}]", "", var.type.encapsulated),
             var_name(var.type.encapsulated.size),
             indent_lvl + 1,
         ))
     lines.append(INDENTATION * indent_lvl + "}")
     self.words.pop_scope()
     self.iterator.pop_it()
     return lines
示例#13
0
 def read_lines(self, decl: bool, var: Variable, size: str,
                indent_lvl: int) -> List[str]:
     # pylint: disable=too-many-arguments
     """Generate the Javascript code to read the lines for a given type"""
     if var.fits_in_one_line(self.input.structs):
         return self.read_line(decl, var.name, var.type, size, indent_lvl)
     indent = INDENTATION * indent_lvl
     if var.type.main == TypeEnum.LIST:
         assert var.type.encapsulated is not None
         lines = [indent + f"{'const ' if decl else ''}{var.name} = [];"]
         iterator = self.iterator.new_it()
         inner_name = self.iterator.new_it()
         lines.append(indent +
                      "for (let {0} = 0; {0} < {1}; {0}++) {{".format(
                          iterator, size))
         self.words.push_scope()
         lines.extend(
             self.read_lines(
                 True,
                 Variable(inner_name, "", var.type.encapsulated),
                 var_name(var.type.encapsulated.size),
                 indent_lvl + 1,
             ))
         lines.append(indent + INDENTATION +
                      f"{var.name}.push({inner_name});")
         self.words.pop_scope()
         self.iterator.pop_it()
         self.iterator.pop_it()
         return lines + [indent + "}"]
     assert var.type.main == TypeEnum.STRUCT
     struct = self.input.get_struct(var.type.struct_name)
     lines = [indent + f"{'const ' if decl else ''}{var.name} = {{}};"]
     for f_name, f_type, f_size in struct.fields_name_type_size(
             f"{var.name}.{{}}", var_name):
         lines.extend(
             self.read_lines(False, Variable(f_name, "", f_type), f_size,
                             indent_lvl))
     return lines
示例#14
0
def read_lines(
    var: Variable, size: str, input_data: Input, iterator: IteratorName
) -> List[str]:
    """Generate the Lua code to read the lines for a given type"""
    if var.fits_in_one_line(input_data.structs):
        return read_line(var.name, var.type, input_data, iterator)
    if var.type.main == TypeEnum.LIST:
        assert var.type.encapsulated is not None
        inner = iterator.new_it()
        lines = read_lines(
            Variable(f"{var.name}[{inner}]", "", var.type.encapsulated),
            var_name(var.type.encapsulated.size),
            input_data,
            iterator,
        )
        iterator.pop_it()
        return (
            [f"{var.name} = {{}}", f"for {inner} = 1, {size} do"]
            + [INDENTATION + i for i in lines]
            + ["end"]
        )
    assert var.type.main == TypeEnum.STRUCT
    struct = input_data.get_struct(var.type.struct_name)
    lines = [var.name + " = {}"]
    for i, field in enumerate(struct.fields):
        f_size = var_name(field.type.size)
        if i == 1 and struct.is_sized_struct():
            f_size = f'{var.name}["{struct.fields[0].name}"]'
        lines.extend(
            read_lines(
                Variable(f'{var.name}["{field.name}"]', "", field.type),
                f_size,
                input_data,
                iterator,
            )
        )
    return lines
示例#15
0
def type_str(var: Variable, decl: bool = False) -> str:
    """Return the Pascal name for a type"""
    # pylint: disable=too-many-return-statements
    if var.type.main == TypeEnum.INT:
        return "longint"
    if var.type.main == TypeEnum.CHAR:
        return "char"
    if var.type.main == TypeEnum.STR:
        return "AnsiString"
    if var.type.main == TypeEnum.STRUCT:
        return var_name(var.type.struct_name)
    assert var.type.main == TypeEnum.LIST
    assert var.type.encapsulated
    if var.type.encapsulated.main == TypeEnum.CHAR:
        return "AnsiString"
    if decl:
        return "array of " + type_str(Variable("", "", var.type.encapsulated), True)
    return "T_" + var_name(var.name)
示例#16
0
 def read_vars(self) -> List[str]:
     """Generate the Javascript code to read all input variables"""
     lines = []
     for variables in self.input.get_all_vars():
         if len(variables) == 1:
             var = variables[0]
             lines.extend(
                 self.read_lines(
                     True,
                     Variable(var_name(var.name), "", var.type,
                              var.format_style),
                     var_name(var.type.size),
                     1,
                 ))
         else:
             lines.append(INDENTATION + "const [" +
                          ", ".join(var_name(i.name) for i in variables) +
                          '] = stdin[line++].split(" ").map(Number);')
     return lines
示例#17
0
def read_vars(input_data: Input, words: WordsName) -> List[str]:
    """Read all input variables"""
    lines = []
    for variables in input_data.get_all_vars():
        if len(variables) == 1:
            var = variables[0]
            lines.extend(
                read_lines(
                    Variable(var_name(var), "", var.type, var.format_style),
                    "my {} = {{}};".format(var_name(var)),
                    size_name(var.type.size),
                    input_data,
                    words,
                ))
        else:
            split = words.next_name()
            lines.append(f"my @{split} = split / /, <>;")
            for i, var in enumerate(variables):
                lines.append(f"my {var_name(var)} = int(${split}[{i}]);")

    return lines
示例#18
0
 def call(self, reprint: bool) -> List[str]:
     """Declare and call the function take all inputs in arguments"""
     lines = [INDENTATION + "/**"]
     arguments = []
     for arg in self.input.input:
         arg_name = var_name(arg.name)
         lines.append(INDENTATION +
                      " * @param {} {}".format(arg_name, arg.comment))
         arguments.append("{} {}".format(type_str(arg.type), arg_name))
     lines.append(INDENTATION + " */")
     lines.append("{}static void {}({}) {{".format(
         INDENTATION, var_name(self.input.name), ", ".join(arguments)))
     if reprint:
         for variables in self.input.get_all_vars():
             if len(variables) == 1:
                 var = variables[0]
                 lines.extend(
                     self.print_lines(
                         Variable(var_name(var.name), "", var.type,
                                  var.format_style),
                         var_name(var.type.size),
                         2,
                     ))
             else:
                 lines.append(INDENTATION * 2 +
                              'System.out.printf("{}\\n", {});'.format(
                                  " ".join(["%d"] * len(variables)),
                                  ", ".join(
                                      var_name(i.name) for i in variables),
                              ))
     else:
         lines.extend([
             2 * INDENTATION + i for i in textwrap.wrap(
                 "/* TODO " + self.input.output + " */",
                 79 - 2 * len(INDENTATION),
             )
         ])
     return lines + [INDENTATION + "}"]
示例#19
0
def error_parse_struct(
        dic: Dict[str, Union[str, List[Dict[str, str]]]]) -> str:
    """Explain why we a struct fails to parse"""
    # pylint: disable=too-many-return-statements
    assert Struct.from_dict(dic) is None
    if "name" not in dic:
        return "missing name field"
    if not isinstance(dic["name"], str):
        return "name field is not a string"
    for field in ("comment", "fields"):
        if field not in dic:
            return "missing {} field for {}".format(field, dic["name"])
    if not isinstance(dic["comment"], str):
        return "{} field for {} is not a string".format(field, dic["name"])
    if not isinstance(dic["fields"], list):
        return "fields field for {} is not a list".format(dic["name"])
    for i in dic["fields"]:
        if not isinstance(i, dict):
            return "a field for {}.fields is not a map".format(dic["name"])
        if Variable.from_dict(i) is None:
            return "failed to parse field of {}: {}".format(
                dic["name"], error_parse_variable(i))
    return "unknown error"
示例#20
0
 def read_var(self, var: Variable) -> List[str]:
     """Read a variable"""
     make = False
     if var.type.main == TypeEnum.LIST:
         assert var.type.encapsulated is not None
         if var.type.encapsulated.main != TypeEnum.CHAR:
             make = True
     lines = []
     if make:
         lines.append(
             "{} := make({}, {})".format(
                 var_name(var.name), type_str(var.type), var_name(var.type.size)
             )
         )
     else:
         lines.append("var {} {}".format(var_name(var.name), type_str(var.type)))
     lines.extend(
         self.read_lines(
             Variable(var_name(var.name), "", var.type, var.format_style),
             var_name(var.type.size),
             already_allocated=True,
         )
     )
     return lines