All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opendaylight.yangtools.yang.ir.StatementInputV1 Maven / Gradle / Ivy

There is a newer version: 14.0.5
Show newest version
/*
 * Copyright (c) 2022 PANTHEON.tech, s.r.o. and others.  All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 */
package org.opendaylight.yangtools.yang.ir;

import com.google.common.collect.ImmutableList;
import java.io.DataInput;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.opendaylight.yangtools.yang.ir.IRArgument.Single;
import org.opendaylight.yangtools.yang.ir.IRKeyword.Qualified;
import org.opendaylight.yangtools.yang.ir.IRKeyword.Unqualified;

final class StatementInputV1 extends StatementInput {
    private final List<@NonNull IRKeyword> keywords = new ArrayList<>();
    private final List<@NonNull String> strings = new ArrayList<>();

    StatementInputV1(final DataInput in) {
        super(in);
    }

    @Override
    IRStatement readStatement() throws IOException {
        final int header = in.readUnsignedByte();
        final int locationBits = header & IOConstantsV1.HDR_LOCATION_MASK;
        return switch (locationBits) {
            case IOConstantsV1.HDR_LOCATION_22 -> {
                final int startLine = in.readUnsignedShort();
                final int startColumn = in.readUnsignedShort();
                yield new IRStatement.Z22(readKeyword(header), readArgument(header), startLine, startColumn);
            }
            case IOConstantsV1.HDR_LOCATION_31 -> {
                final int value = in.readInt();
                yield new IRStatement.Z31(readKeyword(header), readArgument(header), value);
            }
            case IOConstantsV1.HDR_LOCATION_44 -> readStatement(header);
            default -> throw new IOException("Unhandled location " + Integer.toHexString(locationBits));
        };
    }

    private @NonNull IRStatement readStatement(final int header) throws IOException {
        final int startLine = in.readInt();
        final int startColumn = in.readInt();
        final var keyword = readKeyword(header);
        final var argument = readArgument(header);
        final var statements = readSubstatements(header);

        return switch (statements.size()) {
            case 0 -> new IRStatement.Z44(keyword, argument, startLine, startColumn);
            case 1 -> new IRStatement.O44(keyword, argument, statements.get(0), startLine, startColumn);
            default -> new IRStatement.L44(keyword, argument, statements, startLine, startColumn);
        };
    }

    private @NonNull IRKeyword readKeyword(final int header) throws IOException {
        final int keyBits = header & IOConstantsV1.HDR_KEY_MASK;
        return switch (keyBits) {
            case IOConstantsV1.HDR_KEY_REF_U8 -> lookupKeyword(in.readUnsignedByte());
            case IOConstantsV1.HDR_KEY_REF_U16 -> lookupKeyword(in.readUnsignedShort());
            case IOConstantsV1.HDR_KEY_REF_S32 -> lookupKeyword(in.readInt());
            case IOConstantsV1.HDR_KEY_DEF_QUAL -> defineKeyword(Qualified.of(readString(), readString()));
            case IOConstantsV1.HDR_KEY_DEF_UQUAL -> defineKeyword(Unqualified.of(readString()));
            default -> throw new IllegalStateException("Unhandled key " + Integer.toHexString(keyBits));
        };
    }

    private @NonNull IRKeyword lookupKeyword(final int code) throws IOException {
        try {
            return keywords.get(code);
        } catch (IndexOutOfBoundsException e) {
            throw new IOException("Failed to look up keyword", e);
        }
    }

    private @NonNull IRKeyword defineKeyword(final @NonNull IRKeyword keyword) {
        keywords.add(keyword);
        return keyword;
    }

    private ImmutableList readSubstatements(final int header) throws IOException {
        final int sizeBits = header & IOConstantsV1.HDR_SIZE_MASK;
        return switch (sizeBits) {
            case IOConstantsV1.HDR_SIZE_0 -> ImmutableList.of();
            case IOConstantsV1.HDR_SIZE_U8 -> readSubstatementList(in.readUnsignedByte());
            case IOConstantsV1.HDR_SIZE_U16 -> readSubstatementList(in.readUnsignedShort());
            case IOConstantsV1.HDR_SIZE_S32 -> readSubstatementList(in.readInt());
            default -> throw new IOException("Unhandled size " + Integer.toHexString(sizeBits));
        };
    }

    private ImmutableList readSubstatementList(final int size) throws IOException {
        final var builder = ImmutableList.builderWithExpectedSize(size);
        for (int i = 0; i < size; ++i) {
            builder.add(readStatement());
        }
        return builder.build();
    }

    private @Nullable IRArgument readArgument(final int header) throws IOException {
        if ((header & IOConstantsV1.HDR_ARGUMENT_MASK) == IOConstantsV1.HDR_ARGUMENT_ABSENT) {
            return null;
        }

        final int argHeader = in.readUnsignedByte();
        final int type = argHeader & IOConstantsV1.ARG_TYPE_MASK;
        return switch (type) {
            case IOConstantsV1.ARG_TYPE_IDENTIFIER -> IRArgument.identifier(readString(argHeader));
            case IOConstantsV1.ARG_TYPE_DQUOT -> IRArgument.doubleQuoted(readString(argHeader));
            case IOConstantsV1.ARG_TYPE_SQUOT -> IRArgument.singleQuoted(readString(argHeader));
            case IOConstantsV1.ARG_TYPE_UQUOT -> IRArgument.unquoted(readString(argHeader));
            case IOConstantsV1.ARG_TYPE_CONCAT_U8 -> readConcatenation(in.readUnsignedByte());
            case IOConstantsV1.ARG_TYPE_CONCAT_U16 -> readConcatenation(in.readUnsignedShort());
            case IOConstantsV1.ARG_TYPE_CONCAT_S32 -> readConcatenation(in.readInt());
            default -> throw new IOException("Unhandled argument " + Integer.toHexString(type));
        };
    }

    private @NonNull Single readSingleArgument() throws IOException {
        final int argHeader = in.readUnsignedByte();
        final int type = argHeader & IOConstantsV1.ARG_TYPE_MASK;
        return switch (type) {
            case IOConstantsV1.ARG_TYPE_IDENTIFIER -> IRArgument.identifier(readString(argHeader));
            case IOConstantsV1.ARG_TYPE_DQUOT -> IRArgument.doubleQuoted(readString(argHeader));
            case IOConstantsV1.ARG_TYPE_SQUOT -> IRArgument.singleQuoted(readString(argHeader));
            case IOConstantsV1.ARG_TYPE_UQUOT -> IRArgument.unquoted(readString(argHeader));
            default -> throw new IOException("Unhandled single argument " + Integer.toHexString(type));
        };
    }

    private @NonNull IRArgument readConcatenation(final int count) throws IOException {
        final var builder = ImmutableList.builderWithExpectedSize(count);
        for (int i = 0; i < count; ++i) {
            builder.add(readSingleArgument());
        }
        return IRArgument.of(builder.build());
    }

    private @NonNull String readString() throws IOException {
        return readString(in.readUnsignedByte());
    }

    private @NonNull String readString(final int header) throws IOException {
        final int type = header & IOConstantsV1.STR_MASK;
        return switch (type) {
            case IOConstantsV1.STR_DEF_UTF -> defineString(in.readUTF());
            case IOConstantsV1.STR_DEF_U8 -> defineString(readStringBytes(in.readUnsignedByte()));
            case IOConstantsV1.STR_DEF_U16 -> defineString(readStringBytes(in.readUnsignedShort()));
            case IOConstantsV1.STR_DEF_S32 -> defineString(readStringBytes(in.readInt()));
            case IOConstantsV1.STR_DEF_CHARS -> defineString(readStringChars());
            case IOConstantsV1.STR_REF_U8 -> lookupString(in.readUnsignedByte());
            case IOConstantsV1.STR_REF_U16 -> lookupString(in.readUnsignedShort());
            case IOConstantsV1.STR_REF_S32 -> lookupString(in.readInt());
            default -> throw new IOException("Unhandled string " + Integer.toHexString(type));
        };
    }

    private @NonNull String lookupString(final int offset) throws IOException {
        try {
            return strings.get(offset);
        } catch (IndexOutOfBoundsException e) {
            throw new IOException("Invalid String reference " + offset, e);
        }
    }

    private @NonNull String defineString(final @NonNull String string) {
        strings.add(string);
        return string;
    }

    private @NonNull String readStringBytes(final int size) throws IOException {
        if (size > 0) {
            final byte[] bytes = new byte[size];
            in.readFully(bytes);
            return new String(bytes, StandardCharsets.UTF_8);
        } else if (size == 0) {
            return "";
        } else {
            throw new IOException("Invalid String bytes length " + size);
        }
    }

    private @NonNull String readStringChars() throws IOException {
        final int size = in.readInt();
        if (size > 0) {
            final char[] chars = new char[size];
            for (int i = 0; i < size; ++i) {
                chars[i] = in.readChar();
            }
            return String.valueOf(chars);
        } else if (size == 0) {
            return "";
        } else {
            throw new IOException("Invalid String chars length " + size);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy