Beispiel #1
0
def read_line(
    name: str, type_: Type, input_data: Input, iterator: IteratorName
) -> List[str]:
    """Generate the Lua code to read a line of given type"""
    assert type_.fits_in_one_line(input_data.structs)
    if type_.main == TypeEnum.LIST:
        assert type_.encapsulated is not None
        inner = iterator.new_it()
        iterator.pop_it()
        if type_.encapsulated.main == TypeEnum.CHAR:
            return [
                "{} = {{}}".format(name),
                'io.read():gsub(".",function({0}) table.insert({1}, {0}) end)'.format(
                    inner, name
                ),
            ]
        assert type_.encapsulated.main == TypeEnum.INT
        return [
            "{} = {{}}".format(name),
            'for {} in string.gmatch(io.read(), "-?%d+") do'.format(inner),
            INDENTATION + "table.insert({}, tonumber({}))".format(name, inner),
            "end",
        ]
    if type_.main == TypeEnum.STRUCT:
        struct = input_data.get_struct(type_.struct_name)
        words = iterator.new_it()
        iterator.pop_it()
        pattern = " ".join(
            "(-?%d+)" if i.type.main == TypeEnum.INT else "(%S)" for i in struct.fields
        )
        keys = (
            '["{}"]'.format(i.name) if " " in i.name else i.name for i in struct.fields
        )
        values = (
            "tonumber({}[{}])".format(words, i + 1)
            if f.type.main == TypeEnum.INT
            else "{}[{}]".format(words, i + 1)
            for (i, f) in enumerate(struct.fields)
        )
        return [
            'local {} = {{string.match(io.read(), "{}")}}'.format(words, pattern),
            "{} = {{{}}}".format(
                name, ", ".join(i + " = " + j for (i, j) in zip(keys, values))
            ),
        ]
    return [
        name
        + " = "
        + {
            TypeEnum.INT: "tonumber(io.read())",
            TypeEnum.CHAR: "io.read()",
            TypeEnum.STR: "io.read()",
        }[type_.main]
    ]
Beispiel #2
0
def read_lines(
    type_: Type,
    size: str,
    input_data: Input,
    iterator: IteratorName,
    style: FormatStyle = FormatStyle.DEFAULT,
) -> List[str]:
    """Generate the Ruby code to read the lines for a given type"""
    if type_.fits_in_one_line(input_data.structs, style):
        return [read_line(type_, input_data)]
    if type_.main == TypeEnum.LIST:
        assert type_.encapsulated is not None
        lines = read_lines(type_.encapsulated,
                           var_name(type_.encapsulated.size), input_data,
                           iterator)
        if len(lines) == 1:
            candidate = "Array.new({}) {{ {} }}".format(size, lines[0])
            if len(candidate) <= 75:
                return [candidate]
        if lines[0][0] == "{":
            lines[0] = "Array.new({}) {{ {}".format(size, lines[0])
        else:
            lines = ["Array.new({}) {{".format(size)
                     ] + [INDENTATION + i for i in lines]
        if lines[-1][-1] == "}":
            lines[-1] += " }"
        else:
            lines.append("}")
        return lines
    assert type_.main == TypeEnum.STRUCT
    struct = input_data.get_struct(type_.struct_name)
    if struct.is_sized_struct():
        inner = iterator.new_it()
        lines = read_lines(struct.fields[1].type, inner, input_data, iterator)
        iterator.pop_it()
        lines[0] = '"{}" => {}'.format(struct.fields[1].name, lines[0])
        return ([
            "(lambda {{ |{}| {{".format(inner),
            INDENTATION + '"{}" => {},'.format(struct.fields[0].name, inner),
        ] + [INDENTATION + i for i in lines] + ["} }).call(STDIN.gets.to_i)"])
    fields = []
    for i, field in enumerate(struct.fields):
        lines = read_lines(field.type, var_name(field.type.size), input_data,
                           iterator)
        lines[0] = '{}"{}" => {}'.format(INDENTATION, field.name, lines[0])
        if i != len(struct.fields) - 1:
            lines[-1] += ","
        fields.append(lines[0])
        fields.extend([INDENTATION + i for i in lines[1:]])
    return ["{"] + fields + ["}"]
Beispiel #3
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
Beispiel #4
0
class ParserC:
    """Create the C code to parse an input"""
    def __init__(self, input_data: Input) -> None:
        self.input = input_data

        self.includes = set()  # type: Set[str]
        self.main = []  # type: List[str]
        self.method = []  # type: List[str]
        self.iterator = IteratorName([var.name for var in input_data.input])
        self.endlines = [
            (True, [], IntegerOrString.UNKNOWN)
        ]  # type: List[Tuple[bool, List[int], IntegerOrString]]

        self.indentation = 4

    def decl_new_scope(self, always_executed: bool) -> None:
        """Declare a new loop scope"""
        self.endlines.append((always_executed, [], IntegerOrString.UNKNOWN))

    def decl_end_scope(self) -> None:
        """Declare the end of a loop scope, or the end of the program"""
        assert self.endlines
        if len(self.endlines) == 1:
            for line in reversed(self.endlines[0][1]):
                del self.main[line]
            self.endlines = []
        else:
            if self.endlines[-1][2] == IntegerOrString.STRING:
                if self.endlines[-1][1]:
                    self.endlines[-1][1].pop()  # Need to keep this one
            self.endlines[-2][1].extend(self.endlines[-1][1])
            self.endlines.pop()

    def decl_new_read_line(self, integer: IntegerOrString,
                           indent: str) -> None:
        """Declare reading a new line, this will handle the line handling and
        the necessity to explicitly scan them"""
        if integer == IntegerOrString.INTEGER:
            index = len(self.endlines) - 1
            if self.endlines[index][2] == IntegerOrString.UNKNOWN:
                self.endlines[index] = (
                    self.endlines[index][0],
                    self.endlines[index][1],
                    IntegerOrString.INTEGER,
                )
            while index >= 0:
                for line in reversed(self.endlines[index][1]):
                    del self.main[line]
                del self.endlines[index][1][:]
                if not self.endlines[index][0]:
                    break
                index -= 1
        elif integer == IntegerOrString.STRING:
            if self.endlines[-1][2] == IntegerOrString.UNKNOWN:
                self.endlines[-1] = (
                    self.endlines[-1][0],
                    self.endlines[-1][1],
                    IntegerOrString.STRING,
                )
            for scope in self.endlines:
                del scope[1][:]
        self.endlines[-1][1].append(len(self.main))
        self.main.append(indent + "getchar(); // \\n")

    def type_str(self, type_: Type) -> str:
        """Return the C name for a type"""
        if type_.main == TypeEnum.INT:
            return "int"
        if type_.main == TypeEnum.STR:
            return "char*"
        if type_.main == TypeEnum.CHAR:
            return "char"
        if type_.main == TypeEnum.STRUCT:
            return "struct " + struct_name(type_.struct_name)
        assert type_.main == TypeEnum.LIST
        assert type_.encapsulated
        return self.type_str(type_.encapsulated) + "*"

    def read_line(self, name: str, type_: Type, size: str,
                  indent_lvl: int) -> None:
        """Read an entire line and store it into the right place(s)"""
        assert type_.fits_in_one_line(self.input.structs)
        indent = " " * (self.indentation * indent_lvl)
        self.includes.add("stdio.h")
        if type_.main == TypeEnum.INT:
            self.main.append(indent + 'scanf("%d", &{});'.format(name))
            self.decl_new_read_line(IntegerOrString.INTEGER, indent)
        elif type_.main == TypeEnum.CHAR:
            if "." in name or "[" in name:
                self.main.append(indent + "{} = getchar();".format(name))
            self.decl_new_read_line(IntegerOrString.STRING, indent)
        elif type_.main == TypeEnum.STR:
            self.main.append(indent + 'scanf("%[^\\n]", {});'.format(name))
            self.decl_new_read_line(IntegerOrString.STRING, indent)
        elif type_.main == TypeEnum.LIST:
            assert type_.encapsulated is not None
            if type_.encapsulated.main == TypeEnum.CHAR:
                self.main.append(
                    indent + "fgets({}, {} + 1, stdin);".format(name, size))
                self.decl_new_read_line(IntegerOrString.STRING, indent)
            else:
                assert type_.encapsulated.main == TypeEnum.INT
                index = self.iterator.new_it()
                self.main.append(
                    indent +
                    "for (int {0} = 0; {0} < {1}; ++{0})".format(index, size))
                self.main.append(" " * self.indentation + indent +
                                 'scanf("%d", &{}[{}]);'.format(name, index))
                self.decl_new_read_line(
                    IntegerOrString.UNKNOWN
                    if type_.can_be_empty else IntegerOrString.INTEGER,
                    indent,
                )
                self.iterator.pop_it()
        else:
            assert type_.main == TypeEnum.STRUCT
            struct = self.input.get_struct(type_.struct_name)
            self.main.append(indent + 'scanf("{}", {});'.format(
                " ".join("%c" if i.type.main == TypeEnum.CHAR else "%d"
                         for i in struct.fields),
                ", ".join("&" + name + "." + var_name(i.name)
                          for i in struct.fields),
            ))
            self.decl_new_read_line(
                IntegerOrString.STRING if struct.fields[0].type.main
                == TypeEnum.CHAR else IntegerOrString.INTEGER,
                indent,
            )

    def read_lines(self,
                   name: str,
                   type_: Type,
                   size: str,
                   indent_lvl: int = 0) -> None:
        """Read one or several lines and store them into the right place(s)"""
        not_initialized = "." in name or "[" in name
        if type_.main == TypeEnum.LIST and not_initialized:
            assert type_.encapsulated is not None
            self.includes.add("stdlib.h")
            array_size = ("({} + 1)".format(size)
                          if type_.main == TypeEnum.CHAR else size)
            self.main.append(
                "{0}{1} = ({3}*)malloc({2} * sizeof({3}));".format(
                    " " * self.indentation * indent_lvl,
                    name,
                    array_size,
                    self.type_str(type_.encapsulated),
                ))
        elif type_.main == TypeEnum.STR and not_initialized:
            self.includes.add("stdlib.h")
            self.main.append(
                "{}{} = (char*)malloc(({} + 1) * sizeof(char));".format(
                    " " * self.indentation * indent_lvl, name, size))
        if type_.fits_in_one_line(self.input.structs):
            self.read_line(name, type_, size, indent_lvl)
        else:
            if type_.main == TypeEnum.STRUCT:
                struct = self.input.get_struct(type_.struct_name)
                for f_name, f_type, f_size in struct.fields_name_type_size(
                        "{}.{{}}".format(name), var_name):
                    self.read_lines(f_name, f_type, f_size, indent_lvl)
            else:
                assert type_.main == TypeEnum.LIST
                assert type_.encapsulated is not None
                index = self.iterator.new_it()
                self.decl_new_scope(not type_.can_be_empty)
                self.main.append(
                    "{0}for (int {1} = 0; {1} < {2}; ++{1}) {{".format(
                        " " * self.indentation * indent_lvl, index, size))
                self.read_lines(
                    "{}[{}]".format(name, index),
                    type_.encapsulated,
                    var_name(type_.encapsulated.size),
                    indent_lvl + 1,
                )
                self.main.append(" " * self.indentation * indent_lvl + "}")
                self.iterator.pop_it()
                self.decl_end_scope()

    def read_var(self, var: Variable) -> None:
        """Read a variable"""
        init = ""
        if var.type.main == TypeEnum.CHAR:
            self.includes.add("stdio.h")
            init = " = getchar()"
        elif var.type.main == TypeEnum.STR:
            self.includes.add("stdlib.h")
            init = " = (char*)malloc(({} + 1) * sizeof(char))".format(
                var_name(var.type.size))
        elif var.type.main == TypeEnum.LIST:
            assert var.type.encapsulated is not None
            self.includes.add("stdlib.h")
            array_size = ("({} + 1)".format(var_name(var.type.size))
                          if var.type.encapsulated.main == TypeEnum.CHAR else
                          var_name(var.type.size))
            init = " = ({1}*)malloc({0} * sizeof({1}))".format(
                array_size, self.type_str(var.type.encapsulated))
        self.main.append("{} {}{};".format(
            self.type_str(var.type),
            var_name(var.name),
            init,
        ))
        self.read_lines(var_name(var.name), var.type, var_name(var.type.size))

    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("}")

    def print_line(self, var: Variable, size: str, indent_lvl: int) -> None:
        """Print the content of a var that holds in one line"""
        assert var.type.fits_in_one_line(self.input.structs)
        indent = " " * (self.indentation * indent_lvl)
        newline = " " if var.format_style == FormatStyle.NO_ENDLINE else r"\n"
        if var.type.main == TypeEnum.INT:
            self.method.append(indent + f'printf("%d{newline}", {var.name});')
        elif var.type.main == TypeEnum.CHAR:
            self.method.append(indent + f'printf("%c{newline}", {var.name});')
        elif var.type.main == TypeEnum.STR:
            self.method.append(indent + f'printf("%s{newline}", {var.name});')
        elif var.type.main == TypeEnum.LIST:
            assert var.type.encapsulated is not None
            if var.type.encapsulated.main == TypeEnum.CHAR:
                self.method.append(indent +
                                   f'printf("%s{newline}", {var.name});')
            else:
                index = self.iterator.new_it()
                self.method.append(
                    indent +
                    "for (int {0} = 0; {0} < {1}; ++{0})".format(index, size))
                self.method.append(
                    " " * self.indentation + indent +
                    "printf(\"%d%c\", {0}[{1}], {1} < {2} - 1 ? ' ' : '\\n');".
                    format(var.name, index, size))
                self.method.append(indent +
                                   "if ({} == 0) putchar('\\n');".format(size))
                self.iterator.pop_it()
        else:
            assert var.type.main == TypeEnum.STRUCT
            struct = self.input.get_struct(var.type.struct_name)
            self.method.append(indent + 'printf("{}\\n", {});'.format(
                " ".join("%c" if i.type.main == TypeEnum.CHAR else "%d"
                         for i in struct.fields),
                ", ".join(var.name + "." + var_name(i.name)
                          for i in struct.fields),
            ))

    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()

    def content(self) -> str:
        """Return the parser content"""
        output = ""
        for include in sorted(self.includes):
            output += "#include <{}>\n".format(include)
        if self.includes:
            output += "\n"
        for struct in self.input.structs:
            output += "/// {}\n".format(struct.comment)
            output += "struct {} {{\n".format(struct_name(struct.name))
            for field in struct.fields:
                output += " " * self.indentation + "{} {}; ///< {}\n".format(
                    self.type_str(field.type), var_name(field.name),
                    field.comment)
            output += "};\n\n"
        for line in self.method:
            output += line + "\n"
        if self.method:
            output += "\n"
        output += "int main() {\n"
        for line in self.main:
            output += " " * self.indentation + line + "\n"
        output += " " * self.indentation + "{}({});\n".format(
            var_name(self.input.name),
            ", ".join([var_name(i.name) for i in self.input.input]),
        )
        output += "\n" + " " * self.indentation + "return 0;\n}\n"
        return output
Beispiel #5
0
class ParserCS:
    """Create the C# code to parse an input"""
    def __init__(self, input_data: Input) -> None:
        self.input = input_data

        existing_names = [var.name for var in input_data.input]
        self.iterator = IteratorName(existing_names)
        self.words = WordsName(existing_names, cs_mode=True)

    def read_line(self, decl: bool, name: str, type_: Type,
                  indent_lvl: int) -> List[str]:
        """Read an entire line and store it into the right place(s)"""
        assert type_.fits_in_one_line(self.input.structs)
        indent = INDENTATION * indent_lvl
        if type_.main == TypeEnum.STRUCT:
            struct = self.input.get_struct(type_.struct_name)
            s_name = pascal_name(struct.name) + " "
            words = self.words.next_name()
            lines = [
                indent +
                "string[] {} = Console.ReadLine().Split(' ');".format(words)
            ]
            return lines + [
                "{}{}{} = new {}{{{}}};".format(
                    indent,
                    s_name if decl else "",
                    name,
                    s_name,
                    ", ".join("{} = {}".format(
                        var_name(f.name),
                        "int.Parse({}[{}])".format(words, i) if f.type.main ==
                        TypeEnum.INT else "{}[{}][0]".format(words, i),
                    ) for i, f in enumerate(struct.fields)),
                )
            ]
        type_decl = (type_str(type_) + " ") if decl else ""
        command = ""
        if type_.main == TypeEnum.INT:
            command = "int.Parse(Console.ReadLine())"
        elif type_.main == TypeEnum.CHAR:
            command = "Console.ReadLine()[0]"
        elif type_.main == TypeEnum.STR:
            command = "Console.ReadLine()"
        else:
            assert type_.main == TypeEnum.LIST
            assert type_.encapsulated is not None
            if type_.encapsulated.main == TypeEnum.CHAR:
                command = "Console.ReadLine().ToCharArray()"
            else:
                assert type_.encapsulated.main == TypeEnum.INT
                command = (
                    "Array.ConvertAll(Console.ReadLine().Split({}), "
                    "int.Parse)"
                ).format(
                    "new char[] {' '}, StringSplitOptions.RemoveEmptyEntries"
                    if type_.can_be_empty else "' '")

        assert command
        return ["{}{}{} = {};".format(indent, type_decl, name, command)]

    def read_lines(
        self,
        decl: bool,
        name: str,
        type_: Type,
        size: str,
        indent_lvl: int,
        style: FormatStyle = FormatStyle.DEFAULT,
    ) -> 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 type_.fits_in_one_line(self.input.structs, style):
            return self.read_line(decl, name, type_, indent_lvl)
        indent = INDENTATION * indent_lvl
        if type_.main == TypeEnum.STRUCT:
            lines = []
            if decl:
                lines.append("{}{} {};".format(indent,
                                               pascal_name(type_.struct_name),
                                               name))
            struct = self.input.get_struct(type_.struct_name)
            for f_name, f_type, f_size in struct.fields_name_type_size(
                    "{}.{{}}".format(name), var_name):
                lines.extend(
                    self.read_lines(False, f_name, f_type, f_size, indent_lvl))
            return lines
        assert type_.main == TypeEnum.LIST
        assert type_.encapsulated is not None
        far_inner_type = 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(type_) + " ") if decl else "",
                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.append(indent + "{")
        lines.extend(
            self.read_lines(
                False,
                "{}[{}]".format(name, index),
                type_.encapsulated,
                var_name(type_.encapsulated.size),
                indent_lvl + 1,
            ))
        self.words.pop_scope()
        self.iterator.pop_it()
        return lines + [indent + "}"]

    def call(self, reprint: bool) -> List[str]:
        """Declare and call the function take all inputs in arguments"""
        lines = []
        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("{0}static void {1}({2})\n{0}{{".format(
            INDENTATION, pascal_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(var_name(var.name), var.type, 2,
                                         var.format_style))
                else:
                    fmt = " ".join(f"{{{i}}}" for i in range(len(variables)))
                    lines.append(
                        INDENTATION * 2 + f'Console.WriteLine("{fmt}", ' +
                        f"{', '.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 + "}"]

    def print_line(self, name: str, type_: Type) -> str:
        """Print the content of a var that holds in one line"""
        assert type_.fits_in_one_line(self.input.structs)
        if type_.main in (TypeEnum.INT, TypeEnum.CHAR, TypeEnum.STR):
            return "Console.WriteLine({});".format(name)
        if type_.main == TypeEnum.LIST:
            assert type_.encapsulated is not None
            if type_.encapsulated.main == TypeEnum.CHAR:
                return "Console.WriteLine(new string({}));".format(name)
            assert type_.encapsulated.main == TypeEnum.INT
            return 'Console.WriteLine(String.Join(" ", {}));'.format(name)
        assert type_.main == TypeEnum.STRUCT
        fields = self.input.get_struct(type_.struct_name).fields
        return 'Console.WriteLine("{}", {});'.format(
            " ".join("{{{}}}".format(i) for i in range(len(fields))),
            ", ".join("{}.{}".format(name, var_name(f.name)) for f in fields),
        )

    def print_lines(
        self,
        name: str,
        type_: Type,
        indent_lvl: int,
        style: FormatStyle = FormatStyle.DEFAULT,
    ) -> List[str]:
        """Print the content of a var that holds in one or more lines"""
        if type_.fits_in_one_line(self.input.structs, style):
            return [INDENTATION * indent_lvl + self.print_line(name, type_)]
        if type_.main == TypeEnum.STRUCT:
            struct = self.input.get_struct(type_.struct_name)
            lines = []
            for field in struct.fields:
                lines.extend(
                    self.print_lines(
                        "{}.{}".format(name, var_name(field.name)),
                        field.type,
                        indent_lvl,
                    ))
            return lines
        assert type_.main == TypeEnum.LIST
        assert type_.encapsulated is not None
        index = self.iterator.new_it()
        self.words.push_scope()
        lines = [
            "{}foreach ({} {} in {})".format(INDENTATION * indent_lvl,
                                             type_str(type_.encapsulated),
                                             index, name)
        ]
        lines.append(INDENTATION * indent_lvl + "{")
        lines.extend(
            self.print_lines(index, type_.encapsulated, indent_lvl + 1))
        lines.append(INDENTATION * indent_lvl + "}")
        self.words.pop_scope()
        self.iterator.pop_it()
        return lines

    def content(self, reprint: bool) -> str:
        """Return the parser content"""
        output = "using System;\n\n"
        for struct in self.input.structs:
            output += "/// {}\n".format(struct.comment)
            output += "struct {}\n{{\n".format(pascal_name(struct.name))
            for field in struct.fields:
                output += INDENTATION + "public {} {}; //!< {}\n".format(
                    type_str(field.type), var_name(field.name), field.comment)
            output += "}\n\n"
        output += "class Program\n{\n"
        output += "\n".join(self.call(reprint)) + "\n"
        output += "\n{0}static void Main()\n{0}{{\n".format(INDENTATION)
        for variables in self.input.get_all_vars():
            if len(variables) == 1:
                var = variables[0]
                for line in self.read_lines(
                        True,
                        var_name(var.name),
                        var.type,
                        var_name(var.type.size),
                        2,
                        var.format_style,
                ):
                    output += line + "\n"
            else:
                words = self.words.next_name()
                output += (f"{INDENTATION * 2}string[] {words}"
                           " = Console.ReadLine().Split(' ');\n")
                for i, var in enumerate(variables):
                    assert var.type.main == TypeEnum.INT
                    output += (
                        INDENTATION * 2 +
                        f"int {var_name(var.name)} = int.Parse({words}[{i}]);\n"
                    )
        args = (var_name(var.name) for var in self.input.input)
        output += "\n{}{}({});\n".format(INDENTATION * 2,
                                         pascal_name(self.input.name),
                                         ", ".join(args))
        output += INDENTATION + "}\n}\n"
        return output
Beispiel #6
0
class ParserCpp:
    """Create the C++ code to parse an input"""

    def __init__(self, input_data: Input) -> None:
        self.input = input_data

        self.includes = set()  # type: Set[str]
        self.main = []  # type: List[str]
        self.method = []  # type: List[str]
        self.iterator = IteratorName([var.name for var in input_data.input])
        self.indent_lvl = 0

        self.indentation = 4

    def type_str(self, type_: Type) -> str:
        """Return the C++ name for a type"""
        if type_.main == TypeEnum.INT:
            return "int"
        if type_.main == TypeEnum.STR:
            self.includes.add("string")
            return "std::string"
        if type_.main == TypeEnum.CHAR:
            return "char"
        if type_.main == TypeEnum.STRUCT:
            return struct_name(type_.struct_name)
        assert type_.encapsulated
        assert type_.main == TypeEnum.LIST
        self.includes.add("vector")
        return "std::vector<{}>".format(self.type_str(type_.encapsulated))

    def read_line(self, name: str, type_: Type, size: str) -> None:
        """Read an entire line and store it into the right place(s)"""
        assert type_.fits_in_one_line(self.input.structs)
        indent = " " * (self.indentation * self.indent_lvl)
        self.includes.add("iostream")
        if type_.main in (TypeEnum.INT, TypeEnum.CHAR):
            self.main.append(indent + "std::cin >> {};".format(name))
        elif type_.main == TypeEnum.STR:
            self.includes.add("string")
            self.includes.add("istream")
            if type_.can_be_empty:
                self.main.append(indent + "if ({} > 0)".format(size))
            self.main.append(
                indent
                + " " * (self.indentation if type_.can_be_empty else 0)
                + "std::getline(std::cin >> std::ws, {});".format(name)
            )
        elif type_.main == TypeEnum.LIST:
            assert type_.encapsulated is not None
            inner_name = self.iterator.new_it()
            self.main.append(
                indent
                + "for ({}& {} : {})".format(
                    self.type_str(type_.encapsulated), inner_name, name
                )
            )
            self.main.append(
                " " * self.indentation + indent + "std::cin >> {};".format(inner_name)
            )
            self.iterator.pop_it()
        else:
            assert type_.main == TypeEnum.STRUCT
            struct = self.input.get_struct(type_.struct_name)
            self.main.append(
                indent
                + "std::cin >> {};".format(
                    " >> ".join(
                        "{}.{}".format(name, var_name(x.name)) for x in struct.fields
                    )
                )
            )

    def read_lines(
        self,
        name: str,
        type_: Type,
        size: str,
        already_resized: bool = False,
    ) -> None:
        """Read one or several lines and store them into the right place(s)"""
        if type_.main == TypeEnum.LIST and not already_resized:
            self.main.append(
                "{}{}.resize({});".format(
                    " " * self.indentation * self.indent_lvl, name, size
                )
            )
        if type_.fits_in_one_line(self.input.structs):
            self.read_line(name, type_, size)
        else:
            if type_.main == TypeEnum.STRUCT:
                struct = self.input.get_struct(type_.struct_name)
                for f_name, f_type, f_size in struct.fields_name_type_size(
                    "{}.{{}}".format(name), var_name
                ):
                    self.read_lines(f_name, f_type, f_size)
            else:
                assert type_.main == TypeEnum.LIST
                assert type_.encapsulated is not None
                inner_name = self.iterator.new_it()
                self.main.append(
                    "{}for ({}& {} : {}) {{".format(
                        " " * self.indentation * self.indent_lvl,
                        self.type_str(type_.encapsulated),
                        inner_name,
                        name,
                    )
                )
                self.indent_lvl += 1
                self.read_lines(
                    inner_name,
                    type_.encapsulated,
                    var_name(type_.encapsulated.size),
                )
                self.indent_lvl -= 1
                self.main.append(" " * self.indentation * self.indent_lvl + "}")
                self.iterator.pop_it()

    def read_var(self, var: Variable) -> None:
        """Read a variable"""
        size = ""
        if var.type.main == TypeEnum.LIST:
            try:
                size = "({})".format(int(var.type.size))
            except ValueError:
                size = "({})".format(var_name(var.type.size))
        self.main.append(
            "{} {}{}; ///< {}".format(
                self.type_str(var.type), var_name(var.name), size, var.comment
            )
        )
        self.read_lines(
            var_name(var.name), var.type, var_name(var.type.size), already_resized=True
        )

    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))
            if arg.type.main in (TypeEnum.STR, TypeEnum.LIST, TypeEnum.STRUCT):
                arguments.append(
                    "const {}& {}".format(self.type_str(arg.type), arg_name)
                )
            else:
                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(var_name(var.name), var.type, 1, var.format_style)
        else:
            self.method.extend(
                [
                    " " * self.indentation + i
                    for i in textwrap.wrap(
                        "/* TODO " + self.input.output + " */", 79 - self.indentation
                    )
                ]
            )
        self.method.append("}")

    def print_line(
        self, name: str, type_: Type, indent_lvl: int, style: FormatStyle
    ) -> None:
        """Print the content of a var that holds in one line"""
        assert type_.fits_in_one_line(self.input.structs, style)
        indent = " " * (self.indentation * indent_lvl)
        endl = '" "' if style == FormatStyle.NO_ENDLINE else "std::endl"
        if type_.main in (TypeEnum.INT, TypeEnum.CHAR, TypeEnum.STR):
            self.method.append(f"{indent}std::cout << {name} << {endl};")
        elif type_.main == TypeEnum.LIST:
            assert type_.encapsulated is not None
            inner_name = self.iterator.new_it()
            self.method.append(
                indent
                + "for (size_t {0} = 0; {0} < {1}.size(); ++{0})".format(
                    inner_name, name
                )
            )
            self.method.append(
                " " * self.indentation
                + indent
                + "std::cout << "
                + '{0}[{1}] << ({1} < {0}.size() - 1 ? "{2}" : "\\n");'.format(
                    name,
                    inner_name,
                    "" if type_.encapsulated.main == TypeEnum.CHAR else " ",
                )
            )
            self.method.append(
                indent + "if ({}.size() == 0) std::cout << std::endl;".format(name)
            )
            self.iterator.pop_it()
        else:
            assert type_.main == TypeEnum.STRUCT
            struct = self.input.get_struct(type_.struct_name)
            self.method.append(
                indent
                + "std::cout << {} << std::endl;".format(
                    " << ' ' << ".join(
                        "{}.{}".format(name, var_name(x.name)) for x in struct.fields
                    )
                )
            )

    def print_lines(
        self,
        name: str,
        type_: Type,
        indent_lvl: int,
        style: FormatStyle = FormatStyle.DEFAULT,
    ) -> None:
        """Print the content of a var that holds in one or more lines"""
        if type_.fits_in_one_line(self.input.structs, style):
            self.print_line(name, type_, indent_lvl, style)
        else:
            if type_.main == TypeEnum.STRUCT:
                for field in self.input.get_struct(type_.struct_name).fields:
                    self.print_lines(
                        "{}.{}".format(name, var_name(field.name)),
                        field.type,
                        indent_lvl,
                    )
            else:
                assert type_.main == TypeEnum.LIST
                assert type_.encapsulated is not None
                inner_name = self.iterator.new_it()
                self.method.append(
                    "{}for (const {}& {} : {}) {{".format(
                        " " * self.indentation * indent_lvl,
                        self.type_str(type_.encapsulated),
                        inner_name,
                        name,
                    )
                )
                self.print_lines(inner_name, type_.encapsulated, indent_lvl + 1)
                self.method.append(" " * self.indentation * indent_lvl + "}")
                self.iterator.pop_it()

    def content(self) -> str:
        """Return the parser content"""
        output = ""
        for include in sorted(self.includes):
            output += "#include <{}>\n".format(include)
        if self.includes:
            output += "\n"
        for struct in self.input.structs:
            output += "/// {}\n".format(struct.comment)
            output += "struct {} {{\n".format(struct_name(struct.name))
            for field in struct.fields:
                output += " " * self.indentation + "{} {}; ///< {}\n".format(
                    self.type_str(field.type), var_name(field.name), field.comment
                )
            output += "};\n\n"
        for line in self.method:
            output += line + "\n"
        if self.method:
            output += "\n"
        output += "int main() {\n"
        for line in self.main:
            output += " " * self.indentation + line + "\n"
        output += " " * self.indentation + "{}({});\n".format(
            var_name(self.input.name),
            ", ".join([var_name(i.name) for i in self.input.input]),
        )
        output += "}\n"
        return output
Beispiel #7
0
class ParserGo:
    """Create the Go code to parse an input"""

    def __init__(self, input_data: Input) -> None:
        self.input = input_data
        self.imports = set(["bufio", "os"])

        self.iterator = IteratorName([var.name for var in input_data.input])

    def read_line(self, name: str, size: str, type_: Type) -> List[str]:
        """Read an entire line and store it into the right place(s)"""

        # pylint: disable=too-many-return-statements

        assert type_.fits_in_one_line(self.input.structs)
        if type_.main == TypeEnum.INT:
            self.imports.add("strconv")
            return [
                "scanner.Scan()",
                f"{name}, _ = strconv.Atoi(scanner.Text())",
            ]
        if type_.main == TypeEnum.CHAR:
            return ["scanner.Scan()", f"{name} = scanner.Text()[0]"]
        if type_.main == TypeEnum.STR:
            return [
                "scanner.Scan()",
                f"{name} = scanner.Text()",
            ]
        if type_.main == TypeEnum.LIST:
            assert type_.encapsulated is not None
            if type_.encapsulated.main == TypeEnum.CHAR:
                return [
                    "scanner.Scan()",
                    f"{name} = scanner.Bytes()",
                ]
            inner_name = self.iterator.new_it()
            self.imports.add("strings")
            self.imports.add("strconv")
            lines = [
                "scanner.Scan()",
                f"for {inner_name}, {inner_name}Value "
                + f':= range strings.SplitN(scanner.Text(), " ", {size}) {{',
            ]
            lines.append(
                INDENTATION
                + f"{name}[{inner_name}], _ = strconv.Atoi({inner_name}Value)"
            )
            self.iterator.pop_it()
            return lines + ["}"]
        assert type_.main == TypeEnum.STRUCT
        struct = self.input.get_struct(type_.struct_name)
        self.imports.add("fmt")
        return [
            "scanner.Scan()",
            'fmt.Sscanf(scanner.Text(), "{}", {})'.format(
                " ".join(
                    "%d" if f.type.main == TypeEnum.INT else "%c" for f in struct.fields
                ),
                ", ".join(
                    "&{}.{}".format(name, var_name(f.name)) for f in struct.fields
                ),
            ),
        ]

    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

    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

    def call(self, reprint: bool) -> List[str]:
        """Declare and call the function take all inputs in arguments"""
        lines = []
        name = var_name(self.input.name)
        arguments = []
        for arg in self.input.input:
            arg_name = var_name(arg.name)
            lines.append("// {}: {}".format(arg_name, arg.comment))
            arguments.append("{} {}".format(arg_name, type_str(arg.type)))
        lines.append("func {}({}) {{".format(name, ", ".join(arguments)))
        if reprint:
            for var in self.input.input:
                lines.extend(
                    self.print_lines(var_name(var.name), var.type, 1, var.format_style)
                )
        else:
            lines.extend(
                [
                    INDENTATION + i
                    for i in textwrap.wrap(
                        "/* TODO " + self.input.output + " */", 79 - len(INDENTATION)
                    )
                ]
            )
        return lines + ["}"]

    def print_line(
        self, name: str, type_: Type, indent_lvl: int, style: FormatStyle
    ) -> List[str]:
        """Print the content of a var that holds in one line"""
        assert type_.fits_in_one_line(self.input.structs, style)
        indent = INDENTATION * indent_lvl
        self.imports.add("fmt")
        if type_.main in (TypeEnum.INT, TypeEnum.STR):
            return [
                indent
                + (
                    f'fmt.Print({name}, " ");'
                    if style == FormatStyle.NO_ENDLINE
                    else f"fmt.Println({name});"
                )
            ]
        if type_.main == TypeEnum.CHAR:
            return [indent + 'fmt.Printf("%c\\n", {});'.format(name)]
        if type_.main == TypeEnum.LIST:
            assert type_.encapsulated is not None
            if type_.encapsulated.main == TypeEnum.CHAR:
                return [indent + "fmt.Println(string({}));".format(name)]
            index = self.iterator.new_it()
            lines = [
                indent + "for {} := range {} {{".format(index, name),
                indent + INDENTATION + "fmt.Print({}[{}])".format(name, index),
            ]
            lines.extend(
                [
                    indent + INDENTATION + "if {} < len({}) - 1 {{".format(index, name),
                    indent + 2 * INDENTATION + 'fmt.Print(" ")',
                    indent + INDENTATION + "}",
                ]
            )
            self.iterator.pop_it()
            return lines + [indent + "}", indent + "fmt.Println()"]
        assert type_.main == TypeEnum.STRUCT
        struct = self.input.get_struct(type_.struct_name)
        return [
            indent
            + 'fmt.Printf("{}\\n", {})'.format(
                " ".join(
                    "%d" if x.type.main == TypeEnum.INT else "%c" for x in struct.fields
                ),
                ", ".join(
                    "{}.{}".format(name, var_name(x.name)) for x in struct.fields
                ),
            )
        ]

    def print_lines(
        self,
        name: str,
        type_: Type,
        indent_lvl: int,
        style: FormatStyle = FormatStyle.DEFAULT,
    ) -> List[str]:
        """Print the content of a var that holds in one or more lines"""
        if type_.fits_in_one_line(self.input.structs, style):
            return self.print_line(name, type_, indent_lvl, style)
        if type_.main == TypeEnum.STRUCT:
            lines = []
            for field in self.input.get_struct(type_.struct_name).fields:
                lines.extend(
                    self.print_lines(
                        "{}.{}".format(name, var_name(field.name)),
                        field.type,
                        indent_lvl,
                    )
                )
            return lines
        assert type_.main == TypeEnum.LIST
        assert type_.encapsulated is not None
        inner_name = self.iterator.new_it()
        lines = [
            "{}for _, {} := range {} {{".format(
                INDENTATION * indent_lvl, inner_name, name
            )
        ]
        lines.extend(self.print_lines(inner_name, type_.encapsulated, indent_lvl + 1))
        lines.append(INDENTATION * indent_lvl + "}")
        self.iterator.pop_it()
        return lines

    def content(self, reprint: bool) -> str:
        """Return the parser content"""
        output = ""
        for struct in self.input.structs:
            output += "// {}\n".format(struct.comment)
            output += "type {} struct {{\n".format(struct_name(struct.name))
            for field in struct.fields:
                output += INDENTATION + "{} {} // {}\n".format(
                    var_name(field.name), type_str(field.type), field.comment
                )
            output += "}\n\n"
        output += "\n".join(self.call(reprint)) + "\n\n"
        output += "func main() {\n"
        output += INDENTATION + "scanner := bufio.NewScanner(os.Stdin)\n"
        max_line_length = max(
            max_size(i.type, i.constraints, self.input, i.format_style)
            for i in self.input.input
        )
        if max_line_length > 64 * 1024:  # bufio.MaxScanTokenSize
            output += INDENTATION + (
                "scanner.Buffer(make([]byte, 0, " "64 * 1024), {})\n"
            ).format(max_line_length + 1)
        for variables in self.input.get_all_vars():
            if len(variables) == 1:
                for line in self.read_var(variables[0]):
                    output += INDENTATION + line + "\n"
            else:
                assert all(var.type.main == TypeEnum.INT for var in variables)
                output += (
                    INDENTATION
                    + f"var {', '.join(var_name(i.name) for i in variables)} int\n"
                )
                self.imports.add("fmt")
                output += INDENTATION + "scanner.Scan()\n"
                output += (
                    INDENTATION
                    + 'fmt.Sscanf(scanner.Text(), "{}", {});\n'.format(
                        " ".join(["%d"] * len(variables)),
                        ", ".join("&" + var_name(i.name) for i in variables),
                    )
                )
        output += INDENTATION + "{}({});\n".format(
            var_name(self.input.name),
            ", ".join([var_name(i.name) for i in self.input.input]),
        )
        output += "}\n"
        return (
            "package main\n\n"
            + "\n".join('import "{}"'.format(i) for i in sorted(self.imports))
            + "\n\n"
            + output
        )
Beispiel #8
0
class ParserJava:
    """Create the Java code to parse an input"""
    def __init__(self, input_data: Input) -> None:
        self.input = input_data

        self.imports = set(
            ["java.io.BufferedReader", "java.io.InputStreamReader"])
        existing_names = [var.name for var in input_data.input
                          ] + [var_name(input_data.name)]
        self.iterator = IteratorName(existing_names)
        self.words = WordsName(existing_names)

    def read_line(self, decl: bool, name: str, type_: Type,
                  indent_lvl: int) -> List[str]:
        """Read an entire line and store it into the right place(s)"""
        assert type_.fits_in_one_line(self.input.structs)
        indent = INDENTATION * indent_lvl
        if type_.main == TypeEnum.STRUCT:
            struct = self.input.get_struct(type_.struct_name)
            words = self.words.next_name()
            lines = [
                indent + f'String[] {words} = reader.readLine().split(" ");'
            ]
            lines.append(indent + "{}{} = new {}();".format(
                class_name(type_.struct_name) + " " if decl else "",
                name,
                class_name(type_.struct_name),
            ))
            lines.extend("{}{}.{} = {};".format(
                indent,
                name,
                var_name(f.name),
                f"Integer.parseInt({words}[{i}])" if f.type.main ==
                TypeEnum.INT else f"{words}[{i}].charAt(0)",
            ) for i, f in enumerate(struct.fields))
            return lines
        type_decl = (type_str(type_) + " ") if decl else ""
        command = ""
        if type_.main == TypeEnum.INT:
            command = "Integer.parseInt(reader.readLine())"
        elif type_.main == TypeEnum.CHAR:
            command = "reader.readLine().charAt(0)"
        elif type_.main == TypeEnum.STR:
            command = "reader.readLine()"
        else:
            assert type_.main == TypeEnum.LIST
            assert type_.encapsulated is not None
            if type_.encapsulated.main == TypeEnum.CHAR:
                command = "reader.readLine().toCharArray()"
            else:
                assert type_.encapsulated.main == TypeEnum.INT
                self.imports.add("java.util.Arrays")
                command = ('Arrays.stream(reader.readLine().split(" ")).{}'
                           "mapToInt(Integer::parseInt).toArray()"
                           ).format("filter(x -> !x.isEmpty())." if type_.
                                    can_be_empty else "")
        assert command
        return ["{}{}{} = {};".format(indent, type_decl, name, command)]

    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 + "}"]

    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 + "}"]

    def print_line(self, name: str, type_: Type) -> str:
        """Print the content of a var that holds in one line"""
        assert type_.fits_in_one_line(self.input.structs)
        if type_.main in (TypeEnum.INT, TypeEnum.CHAR, TypeEnum.STR):
            return f"System.out.println({name});"
        if type_.main == TypeEnum.LIST:
            assert type_.encapsulated is not None
            if type_.encapsulated.main == TypeEnum.CHAR:
                return f"System.out.println(new String({name}));"
            assert type_.encapsulated.main == TypeEnum.INT
            self.imports.add("java.util.Arrays")
            self.imports.add("java.util.stream.Collectors")
            return "System.out.println(Arrays.stream({}).mapToObj({}".format(
                name, 'String::valueOf).collect(Collectors.joining(" ")));')
        assert type_.main == TypeEnum.STRUCT
        fields = self.input.get_struct(type_.struct_name).fields
        return 'System.out.printf("{}\\n", {});'.format(
            " ".join("%d" if f.type.main == TypeEnum.INT else "%c"
                     for f in fields),
            ", ".join("{}.{}".format(name, var_name(f.name)) for f in fields),
        )

    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

    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
Beispiel #9
0
class ParserPascal:
    """Create the Pascal code to parse an input"""

    def __init__(self, input_data: Input) -> None:
        self.input = input_data

        self.includes = set()  # type: Set[str]
        self.main = []  # type: List[str]
        self.iterator = IteratorName([var.name for var in input_data.input])
        self.local_integers = set()  # type: Set[str]
        self.local_char = False
        self.indent_lvl = 0

    def read_line(self, name: str, type_: Type, size: str) -> None:
        """Read an entire line and store it into the right place(s)"""
        assert type_.fits_in_one_line(self.input.structs)
        indent = INDENTATION * self.indent_lvl
        if type_.main == TypeEnum.INT:
            self.main.append(indent + "readln({});".format(name))
        elif type_.main == TypeEnum.CHAR:
            self.main.append(indent + "readln({});".format(name))
        elif type_.main == TypeEnum.STR:
            self.main.append(indent + "readln({});".format(name))
        elif type_.main == TypeEnum.LIST:
            assert type_.encapsulated is not None
            if type_.encapsulated.main == TypeEnum.CHAR:
                self.main.append(indent + "readln({});".format(name))
            else:
                assert type_.encapsulated.main == TypeEnum.INT
                index = self.iterator.new_it()
                self.local_integers.add(index)
                self.main.append(
                    indent + "for {} := 0 to {} - 1 do".format(index, size)
                )
                self.main.append(
                    INDENTATION + indent + "read({}[{}]);".format(name, index)
                )
                self.main.append(indent + "readln();")
                self.iterator.pop_it()
        else:
            assert type_.main == TypeEnum.STRUCT
            struct = self.input.get_struct(type_.struct_name)
            args = []
            for i, field in enumerate(struct.fields):
                if i != 0 and field.type.main == TypeEnum.CHAR:
                    args.append("_")
                    self.local_char = True
                args.append(name + "." + var_name(field.name))
            self.main.append(indent + "readln({});".format(", ".join(args)))

    def read_lines(
        self,
        name: str,
        type_: Type,
        size: str,
        style: FormatStyle = FormatStyle.DEFAULT,
    ) -> None:
        """Read one or several lines and store them into the right place(s)"""
        if type_.fits_in_one_line(self.input.structs, style):
            self.read_line(name, type_, size)
        else:
            if type_.main == TypeEnum.STRUCT:
                struct = self.input.get_struct(type_.struct_name)
                for f_name, f_type, f_size in struct.fields_name_type_size(
                    "{}.{{}}".format(name), var_name
                ):
                    self.main.extend(
                        [
                            INDENTATION * self.indent_lvl + i
                            for i in init_list(f_name, f_type, f_size)
                        ]
                    )
                    self.read_lines(f_name, f_type, f_size)
            else:
                assert type_.main == TypeEnum.LIST
                assert type_.encapsulated is not None
                index = self.iterator.new_it()
                self.local_integers.add(index)
                self.main.append(
                    f"{INDENTATION * self.indent_lvl}for {index} := 0 to {size} - 1 do"
                )
                self.main.append(INDENTATION * self.indent_lvl + "begin")
                self.indent_lvl += 1
                self.read_lines(
                    f"{name}[{index}]",
                    type_.encapsulated,
                    var_name(type_.encapsulated.size),
                )
                self.indent_lvl -= 1
                self.main.append(INDENTATION * self.indent_lvl + "end;")
                self.iterator.pop_it()

    def call(self, reprint: bool) -> List[str]:
        """Declare and call the function take all inputs in arguments"""
        name = var_name(self.input.name)
        arguments = []
        method = []
        for arg in self.input.input:
            arg_name = var_name(arg.name)
            method.append("{{ @param {} {} }}".format(arg_name, arg.comment))
            const = "" if arg.type.main in (TypeEnum.INT, TypeEnum.CHAR) else "const "
            arguments.append("{}{}: {}".format(const, arg_name, type_str(arg)))
        method.append("procedure {}({});".format(name, "; ".join(arguments)))
        if reprint and self.local_integers:
            method.append("var")
            method.append(
                INDENTATION
                + "{}: longint;".format(", ".join(sorted(self.local_integers)))
            )
        method.append("begin")
        if reprint:
            self.indent_lvl += 1
            for var in self.input.input:
                method.extend(
                    self.print_lines(
                        var_name(var.name),
                        var.type,
                        var_name(var.type.size),
                        var.format_style,
                    )
                )
            self.indent_lvl -= 1
        else:
            method.extend(
                textwrap.wrap(
                    self.input.output + " *}",
                    79,
                    initial_indent=INDENTATION + "{* " + "TODO ",
                    subsequent_indent=INDENTATION,
                )
            )
        method.append("end;")
        return method

    def print_line(
        self, name: str, type_: Type, size: str, style: FormatStyle
    ) -> List[str]:
        """Print the content of a var that holds in one line"""
        assert type_.fits_in_one_line(self.input.structs, style)
        indent = INDENTATION * self.indent_lvl
        if type_.main in (TypeEnum.INT, TypeEnum.CHAR, TypeEnum.STR):
            return [
                indent
                + (
                    f"write({name}, ' ');"
                    if style == FormatStyle.NO_ENDLINE
                    else f"writeln({name});"
                )
            ]
        if type_.main == TypeEnum.LIST:
            assert type_.encapsulated is not None
            if type_.encapsulated.main == TypeEnum.CHAR:
                return [indent + f"writeln({name});"]
            lines = []
            index = self.iterator.new_it()
            lines.append(indent + f"for {index} := 0 to {size} - 2 do")
            lines.append(indent + INDENTATION + f"write({name}[{index}], ' ');")
            try:
                size_int = int(size)
                if size_int > 0:
                    lines.append(indent + f"write({name}[{size_int - 1}]);")
            except ValueError:
                lines.append(
                    indent + f"if ({size} > 0) then write({name}[{size} - 1]);"
                )
            lines.append(indent + "writeln();")
            self.iterator.pop_it()
            return lines
        assert type_.main == TypeEnum.STRUCT
        struct = self.input.get_struct(type_.struct_name)
        args = ["' '"] * (2 * len(struct.fields) - 1)
        args[::2] = [name + "." + var_name(i.name) for i in struct.fields]
        return [indent + f"writeln({', '.join(args)});"]

    def print_lines(
        self,
        name: str,
        type_: Type,
        size: str,
        style: FormatStyle = FormatStyle.DEFAULT,
    ) -> List[str]:
        """Print the content of a var that holds in one or more lines"""
        if type_.fits_in_one_line(self.input.structs, style):
            return self.print_line(name, type_, size, style)
        lines = []
        if type_.main == TypeEnum.STRUCT:
            struct = self.input.get_struct(type_.struct_name)
            struct = self.input.get_struct(type_.struct_name)
            for f_name, f_type, f_size in struct.fields_name_type_size(
                f"{name}.{{}}", var_name
            ):
                lines.extend(self.print_lines(f_name, f_type, f_size))
        else:
            assert type_.main == TypeEnum.LIST
            assert type_.encapsulated is not None
            index = self.iterator.new_it()
            lines = [
                f"{INDENTATION * self.indent_lvl}for {index} := 0 to {size} - 1 do",
                INDENTATION * self.indent_lvl + "begin",
            ]
            self.indent_lvl += 1
            lines.extend(
                self.print_lines(
                    f"{name}[{index}]",
                    type_.encapsulated,
                    var_name(type_.encapsulated.size),
                )
            )
            self.indent_lvl -= 1
            lines.append(INDENTATION * self.indent_lvl + "end;")
            self.iterator.pop_it()
        return lines

    def content(self, reprint: bool) -> str:
        """Return the parser content"""
        for variables in self.input.get_all_vars():
            if len(variables) == 1:
                var = variables[0]
                self.main.extend(init_list(var_name(var.name), var.type))
                self.read_lines(
                    var_name(var.name),
                    var.type,
                    var_name(var.type.size),
                    var.format_style,
                )
            else:
                assert all(var.type.main == TypeEnum.INT for var in variables)
                self.main.append(
                    f"readln({', '.join(var_name(i.name) for i in variables)});"
                )
        method = self.call(reprint)
        output = "program {};\n\n".format(var_name(self.input.name))
        types = decl_types(self.input.input)
        if self.input.structs or types:
            output += "type\n"
        for struct in self.input.structs:
            output += INDENTATION + "{{ {} }}\n".format(struct.comment)
            output += INDENTATION + "{} = record\n".format(var_name(struct.name))
            for field in struct.fields:
                output += 2 * INDENTATION + "{}: {}; {{ {} }}\n".format(
                    var_name(field.name), type_str(field, True), field.comment
                )
            output += INDENTATION + "end;\n\n"
        if types:
            output += "\n".join(types) + "\n\n"
        for line in method:
            output += line + "\n"
        output += "\nvar\n"
        for var in self.input.input:
            output += INDENTATION + "{}: {}; {{ {} }}\n".format(
                var_name(var.name), type_str(var), var.comment
            )
        if self.local_integers:
            output += INDENTATION + "{}: longint;\n".format(
                ", ".join(sorted(self.local_integers))
            )
        if self.local_char:
            output += INDENTATION + "_: char;\n"

        output += "begin\n"
        for line in self.main:
            output += INDENTATION + line + "\n"
        output += INDENTATION + "{}({});\n".format(
            var_name(self.input.name),
            ", ".join([var_name(i.name) for i in self.input.input]),
        )
        output += "end.\n"
        return output
Beispiel #10
0
class ParserD:
    """Create the D code to parse an input"""
    def __init__(self, input_data: Input) -> None:
        self.input = input_data
        self.imports = {"std.stdio": {"stdin"}}
        self.iterator = IteratorName([var.name for var in input_data.input])

    def add_import(self, module: str, symbol: str) -> None:
        """Add a new import statement"""
        if module in self.imports:
            self.imports[module].add(symbol)
        else:
            self.imports[module] = {symbol}

    def read_line(self, name: str, type_: Type) -> str:
        """Read a variable in one line of stdin"""
        assert type_.fits_in_one_line(self.input.structs)
        if type_.main == TypeEnum.INT:
            return 'stdin.readf("%d\\n", &{});'.format(name)
        if type_.main == TypeEnum.STR:
            return 'stdin.readf("%s\\n", &{});'.format(name)
        if type_.main == TypeEnum.CHAR:
            return 'stdin.readf("%c\\n", &{});'.format(name)
        if type_.main == TypeEnum.LIST:
            assert type_.encapsulated
            self.add_import("std.array", "split")
            self.add_import("std.conv", "to")
            if type_.encapsulated.main == TypeEnum.INT:
                self.add_import("std.array", "array")
                self.add_import("std.algorithm.iteration", "map")
                return name + " = stdin.readln.split.map!(to!int).array;"
            assert type_.encapsulated.main == TypeEnum.CHAR
            self.add_import("std.string", "chop")
            return name + " = stdin.readln.chop.to!(char[]);"
        assert type_.main == TypeEnum.STRUCT
        struct = self.input.get_struct(type_.struct_name)
        return 'stdin.readf("{}\\n", {});'.format(
            " ".join("%c" if i.type.main == TypeEnum.CHAR else "%d"
                     for i in struct.fields),
            ", ".join("&" + name + "." + var_name(i.name)
                      for i in struct.fields),
        )

    def read_lines(
        self,
        name: str,
        type_: Type,
        size: str,
        style: FormatStyle = FormatStyle.DEFAULT,
    ) -> List[str]:
        """Read a variable in one line or several lines of stdin"""
        if type_.fits_in_one_line(self.input.structs, style):
            return [self.read_line(name, type_)]
        if type_.main == TypeEnum.LIST:
            assert type_.encapsulated
            index = self.iterator.new_it()
            lines = [
                "{}.length = {};".format(name, size),
                "for (size_t {0} = 0; {0} < {1}.length; {0}++)".format(
                    index, name),
                "{",
            ]
            lines.extend([
                INDENTATION + i for i in self.read_lines(
                    "{}[{}]".format(name, index),
                    type_.encapsulated,
                    var_name(type_.encapsulated.size),
                )
            ])
            self.iterator.pop_it()
            return lines + ["}"]
        assert type_.main == TypeEnum.STRUCT
        struct = self.input.get_struct(type_.struct_name)
        lines = []
        for f_name, f_type, f_size in struct.fields_name_type_size(
                "{}.{{}}".format(name), var_name):
            lines.extend(self.read_lines(f_name, f_type, f_size))
        return lines

    def read_var(self, var: Variable) -> List[str]:
        """Read a variable from stdin"""
        return ["{} {};".format(type_str(var.type), var_name(var.name))
                ] + self.read_lines(var_name(var.name), var.type,
                                    var_name(var.type.size), var.format_style)

    def print_lines(self,
                    name: str,
                    type_: Type,
                    style: FormatStyle = FormatStyle.DEFAULT) -> List[str]:
        """Print a D variable"""
        if type_.main in (TypeEnum.INT, TypeEnum.STR, TypeEnum.CHAR):
            self.add_import("std.stdio", "writeln")
            return ["writeln({});".format(name)]
        if type_.main == TypeEnum.LIST:
            assert type_.encapsulated
            if (type_.encapsulated.main == TypeEnum.INT
                    and style != FormatStyle.FORCE_NEWLINES):
                self.add_import("std.array", "join")
                self.add_import("std.algorithm.iteration", "map")
                self.add_import("std.conv", "to")
                return ['writeln(join({}.map!(to!string), " "));'.format(name)]
            if type_.encapsulated.main == TypeEnum.CHAR:
                return ["writeln({});".format(name)]
            index = self.iterator.new_it()
            lines = [
                "for (size_t {0} = 0; {0} < {1}.length; {0}++)".format(
                    index, name),
                "{",
            ]
            lines.extend([
                INDENTATION + i for i in self.print_lines(
                    "{}[{}]".format(name, index), type_.encapsulated)
            ])
            self.iterator.pop_it()
            return lines + ["}"]
        assert type_.main == TypeEnum.STRUCT
        struct = self.input.get_struct(type_.struct_name)
        if type_.fits_in_one_line(self.input.structs, style):
            self.add_import("std.stdio", "writefln")
            return [
                'writefln("{}", {});'.format(
                    " ".join("%c" if i.type.main == TypeEnum.CHAR else "%d"
                             for i in struct.fields),
                    ", ".join(name + "." + var_name(i.name)
                              for i in struct.fields),
                )
            ]
        lines = []
        for field in struct.fields:
            lines.extend(
                self.print_lines("{}.{}".format(name, var_name(field.name)),
                                 field.type))
        return lines

    def function(self, reprint: bool) -> List[str]:
        """Return the code of the function to complete by the end user"""
        lines = ["/**", "Params:"]
        lines.extend(
            "{}{} = {}".format(INDENTATION, var_name(i.name), i.comment)
            for i in self.input.input)
        lines.append("*/")
        lines.extend([
            "void {}({})".format(
                var_name(self.input.name),
                ", ".join(
                    type_str(i.type) + " " + var_name(i.name)
                    for i in self.input.input),
            ),
            "{",
        ])
        if reprint:
            for variables in self.input.get_all_vars():
                if len(variables) == 1:
                    var = variables[0]
                    lines.extend(INDENTATION + i for i in self.print_lines(
                        var_name(var.name), var.type, var.format_style))
                else:
                    self.add_import("std.stdio", "writeln")
                    lines.append(INDENTATION + "writeln(" + ', " ", '.join(
                        var_name(i.name) for i in variables) + ");")
        else:
            lines.extend(
                textwrap.wrap(
                    self.input.output,
                    79,
                    initial_indent=INDENTATION + "// TODO ",
                    subsequent_indent=INDENTATION + "// ",
                ))
        return lines + ["}"]

    def content(self, reprint: bool) -> str:
        """Return content of the D file for parsing the input"""
        output = ""
        for struct in self.input.structs:
            output += "/// {}\n".format(struct.comment)
            output += "struct {}\n{{\n".format(struct_name(struct.name))
            for field in struct.fields:
                output += INDENTATION + "{} {}; /// {}\n".format(
                    type_str(field.type), var_name(field.name), field.comment)
            output += "}\n\n"
        output += "\n".join(self.function(reprint)) + "\n\n"
        output += "void main()\n{\n"
        for variables in self.input.get_all_vars():
            if len(variables) == 1:
                var = variables[0]
                for line in self.read_var(var):
                    output += INDENTATION + line + "\n"
            else:
                assert all(var.type.main == TypeEnum.INT for var in variables)
                output += (
                    INDENTATION +
                    f"int {', '.join(var_name(i.name) for i in variables)};\n")
                output += (
                    INDENTATION +
                    f'stdin.readf("{" ".join(["%d"] * len(variables))}\\n", ' +
                    f"{', '.join('&' + var_name(i.name) for i in variables)});\n"
                )
        args = (var_name(i.name) for i in self.input.input)
        output += "\n{}{}({});\n".format(INDENTATION,
                                         var_name(self.input.name),
                                         ", ".join(args))
        output += "}\n"

        imports = ""
        for module in sorted(self.imports.keys()):
            imports += "import {} : {};\n".format(
                module, ", ".join(sorted(self.imports[module])))
        return f"module {var_name(self.input.name)};\n\n{imports}\n{output}"
Beispiel #11
0
class ParserPHP:
    """Create the PHP code to parse an input"""
    def __init__(self, input_data: Input):
        self.input = input_data
        self.iterator = IteratorName([var.name for var in input_data.input] +
                                     [input_data.name])

    def read_lines(self, name: str, type_: Type, size: str,
                   style: FormatStyle) -> List[str]:
        """Generate the PHP code to read the lines for a given type"""
        if type_.fits_in_one_line(self.input.structs, style):
            return [read_line(type_, self.input)]
        if type_.main == TypeEnum.LIST:
            assert type_.encapsulated is not None
            iterator = "$" + self.iterator.new_it()
            lines = []
            if type_.encapsulated.fits_in_one_line(self.input.structs):
                # Here we don't really care if the encapsulated type really fits on
                # on line. What we are interested in, is that the fact that the code
                # generated to read it will fit on one line, and will need to be
                # directly assigned to a variable
                lines = [
                    f"{name}[{iterator}] = {read_line(type_.encapsulated, self.input)};"
                ]
            else:
                tmp_name = "$" + self.iterator.new_it()
                lines = self.read_lines(
                    tmp_name,
                    type_.encapsulated,
                    var_name(type_.encapsulated.size),
                    FormatStyle.DEFAULT,
                )
                lines.append(f"{name}[{iterator}] = {tmp_name};")
                self.iterator.pop_it()
            self.iterator.pop_it()
            prefix = [
                f"{name} = new SplFixedArray({size});",
                f"for ({iterator} = 0; {iterator} < {size}; {iterator}++) {{",
            ]
            return prefix + [INDENTATION + i for i in lines] + ["}"]
        assert type_.main == TypeEnum.STRUCT
        struct = self.input.get_struct(type_.struct_name)
        lines = []
        for f_name, f_type, f_size in struct.fields_name_type_size(
                '{}["{{}}"]'.format(name), lambda x: x):
            read = self.read_lines(f_name, f_type, f_size, FormatStyle.DEFAULT)
            if len(read) == 1:
                read[0] = "{} = {};".format(f_name, read[0])
            lines.extend(read)
        return ["{} = [];".format(name)] + lines

    def read_vars(self) -> List[str]:
        """Generate the PHP code to read all input variables"""
        lines = []
        for variables in self.input.get_all_vars():
            name = ", ".join(var_name(i.name) for i in variables)
            type_ = variables[0].type
            style = variables[0].format_style
            if len(variables) != 1:
                name = f"list({name})"
                assert all(var.type.main == TypeEnum.INT for var in variables)
                type_ = Type(TypeEnum.LIST, str(len(variables)),
                             Type(TypeEnum.INT))
                style = FormatStyle.DEFAULT
            size = var_name(type_.size)
            read = self.read_lines(name, type_, size, style)
            if len(read) == 1:
                read[0] = f"{name} = {read[0]};"
            lines.extend(read)
        return lines
Beispiel #12
0
class ParserJS:
    """Create the Javascript code to parse an input"""
    def __init__(self, input_data: Input) -> None:
        self.input = input_data
        existing_names = [var_name(var.name) for var in input_data.input
                          ] + [var_name(input_data.name)]
        self.iterator = IteratorName(existing_names)
        self.words = WordsName(existing_names)

    def read_line(self, decl: bool, name: str, type_: Type, size: str,
                  indent_lvl: int) -> List[str]:
        # pylint: disable = too-many-arguments
        """Generate the Javascript code to read a line of given type"""
        assert type_.fits_in_one_line(self.input.structs)
        indent = INDENTATION * indent_lvl
        start = indent + ("const " if decl else "") + name + " = "
        if type_.main == TypeEnum.LIST:
            assert type_.encapsulated is not None
            if type_.encapsulated.main == TypeEnum.CHAR:
                return [start + 'stdin[line++].split("");']
            assert type_.encapsulated.main == TypeEnum.INT
            return [
                start +
                'stdin[line++].split(" ", {}).map(Number);'.format(size)
            ]
        if type_.main == TypeEnum.STRUCT:
            struct = self.input.get_struct(type_.struct_name)
            words = self.words.next_name()
            lines = [
                indent + 'const {} = stdin[line++].split(" ");'.format(words),
                start + "{",
            ]
            lines.extend(indent + INDENTATION + "{}: {}{}".format(
                var_name(field.name),
                "{}[{}]".format(words, i) if field.type.main ==
                TypeEnum.CHAR else "Number({}[{}])".format(words, i),
                "," if i != len(struct.fields) - 1 else "",
            ) for i, field in enumerate(struct.fields))
            return lines + [indent + "};"]
        return [
            start + {
                TypeEnum.INT: "Number(stdin[line++]);",
                TypeEnum.CHAR: "stdin[line++];",
                TypeEnum.STR: "stdin[line++];",
            }[type_.main]
        ]

    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

    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