use crate::*;


/// The entire semantic program, ready to generate bytecode.
pub struct Program {
    pub definitions: Vec<Definition>,
    pub invocations: Vec<Invocation>,
}

/// A symbol definition.
pub struct Definition {
    pub name: String,
    pub source: SourceSpan,
    pub arguments: Vec<ArgumentDefinition>,
    pub variant: DefinitionVariant,
}

pub struct ArgumentDefinition {
    pub name: String,
    pub source: SourceSpan,
    pub variant: ArgumentDefinitionVariant,
}

pub enum ArgumentDefinitionVariant {
    Integer,
    Block,
}

pub enum DefinitionVariant {
    Integer(IntegerDefinition),
    Block(Vec<BlockToken>),
}

pub struct IntegerDefinition {
    pub source: SourceSpan,
    pub variant: IntegerDefinitionVariant,
}

pub enum IntegerDefinitionVariant {
    Literal(usize),
    Constant(ConstantExpression),
    Reference(String),
}

pub struct BlockToken {
    pub source: SourceSpan,
    pub variant: BlockTokenVariant,
}

pub enum BlockTokenVariant {
    Invocation(Invocation),
    Comment(String),
    Word(PackedBinaryLiteral),
}

pub struct Invocation {
    pub name: String,
    pub source: SourceSpan,
    pub arguments: Vec<InvocationArgument>,
}

pub struct InvocationArgument {
    pub source: SourceSpan,
    pub variant: InvocationArgumentVariant,
}

pub enum InvocationArgumentVariant {
    BlockLiteral(Vec<BlockToken>),
    IntegerLiteral(usize),
    ConstantExpression(ConstantExpression),
    Reference(String),
}