cairo-lang-sierra 2.19.2

Sierra representation.
Documentation
// Simple parser for sierra.
// Currently only used for testing.

use crate::ids::*;
use crate::program::*;
use crate::labeled_statement::{StatementId, PreStatement, finalize_prestatements};
use num_bigint::BigInt;

grammar;

pub Program: Program = {
    <type_declarations:TypeDeclaration*>
    <libfunc_declarations:LibfuncDeclaration*>
    <statements:PreStatement*>
    <funcs:Function*>
    => {
        let (statements, funcs) = finalize_prestatements(statements, funcs);
        Program { type_declarations, libfunc_declarations, statements, funcs }
    },
}

TypeDeclaration: TypeDeclaration = {
    "type" <id:ConcreteTypeId> "=" 
        <long_id:ConcreteTypeLongId> <declared_type_info:DeclaredTypeInfo> ";" =>
    {
        TypeDeclaration{id, long_id, declared_type_info}
    },
}

DeclaredTypeInfo: Option<DeclaredTypeInfo> = {
    "["
        "storable:" <storable:Bool> ","
        "drop:" <droppable:Bool> ","
        "dup:" <duplicatable:Bool> ","
        "zero_sized:" <zero_sized:Bool>
    "]"
    => Some(DeclaredTypeInfo {
        storable,
        droppable,
        duplicatable,
        zero_sized,
    }),
    => None,
}

pub ConcreteTypeLongId: ConcreteTypeLongId = {
    <generic_id:GenericTypeId> "<" <generic_args:GenericArgs> ">"
    => ConcreteTypeLongId{generic_id, generic_args},
    <generic_id:GenericTypeId> => ConcreteTypeLongId{generic_id, generic_args: vec![]},
}

LibfuncDeclaration: LibfuncDeclaration = {
    "libfunc" <id:ConcreteLibfuncId> "=" <long_id:ConcreteLibfuncLongId> ";"
    => LibfuncDeclaration{id, long_id},
}

pub ConcreteLibfuncLongId: ConcreteLibfuncLongId = {
    <generic_id:GenericLibfuncId> "<" <generic_args:GenericArgs> ">"
    => ConcreteLibfuncLongId{generic_id, generic_args},
    <generic_id:GenericLibfuncId> => ConcreteLibfuncLongId{generic_id, generic_args: vec![]},
}

Function: GenFunction<StatementId> = {
    <id:FunctionId> "@" <entry:StatementId>
    "(" <params: Params> ")" "->" "(" <ret_types: ConcreteTypeIds> ")" ";"
    => GenFunction::new(id, params, ret_types, entry),
}

Param: Param = {
    <id:VarId> ":" <ty:ConcreteTypeId> => Param{id, ty},
}
Params = Comma<Param>;

GenericLibfuncId: GenericLibfuncId = {
    <id:PathLabel> => GenericLibfuncId::from_string(id),
}

ConcreteLibfuncId: ConcreteLibfuncId = {
    <id:ConcreteLabel> => ConcreteLibfuncId::from_string(id),
    "[" <id:UnsignedInt> "]" => ConcreteLibfuncId::new(id),
}

FunctionId: FunctionId = {
    <id:ConcreteLabel> => FunctionId::from_string(id),
    <id:ConcreteLabel> <extra1:BracketsTokenTree> <extra2:BracesTokenTree> =>
        FunctionId::from_string(format!("{id}{extra1}{extra2}")),
    <id:ConcreteLabel> <extra:BracketsTokenTree> => FunctionId::from_string(format!("{id}{extra}")),
    <id:ConcreteLabel> <extra:BracesTokenTree> => FunctionId::from_string(format!("{id}{extra}")),
    "[" <id:UnsignedInt> "]" => FunctionId::new(id),
}

UserTypeId: UserTypeId = {
    <id:ConcreteLabel> => UserTypeId::from_string(id),
    "[" <id:BigInt> "]" => UserTypeId { id: id.try_into().unwrap(), debug_name: None },
    <value:BracesTokenTree> => UserTypeId::from_string(value),
}

TokenTree: String = {
    <value:BracesTokenTree> => value,
    <value:BracketsTokenTree> => value,
    "(" <parts:(<TokenTree>)*> ")" => format!("({})", parts.join("")),
    <label:BasicLabel> => label,
    <num:BigInt> => num.to_string(),
    ":" => <>.to_string(),
    "," => <>.to_string(),
    "." => <>.to_string(),
    "@" => <>.to_string(),
    "/" => <>.to_string(),
    "\\" => <>.to_string(),
    "-" => <>.to_string(),
}

BracesTokenTree: String = {
    "{" <parts:(<TokenTree>)*> "}" => format!("{{{}}}", parts.join("")),
}

BracketsTokenTree: String = {
    "[" <parts:(<TokenTree>)*> "]" => format!("[{}]", parts.join("")),
}

VarId: VarId = {
    <id:BasicLabel> => VarId::from_string(id),
    "[" <id:UnsignedInt> "]" => VarId::new(id),
}
VarIds = Comma<VarId>;

GenericTypeId: GenericTypeId = {
    <id:PathLabel> => GenericTypeId::from_string(id),
}

ConcreteTypeId: ConcreteTypeId = {
    <id:ConcreteLabel> => ConcreteTypeId::from_string(id),
    "@" <ty:ConcreteTypeId> => ConcreteTypeId::from_string(format!("@{ty}")),
    "[" <id:UnsignedInt> "]" => ConcreteTypeId::new(id),
    "[" <ty:ConcreteTypeId> ";" <count:UnsignedInt> "]" =>
        ConcreteTypeId::from_string(format!("[{ty}; {count}]")),
}
ConcreteTypeIds = Comma<ConcreteTypeId>;

StatementId: StatementId = {
     <id:UnsignedInt> => StatementId::Idx(StatementIdx(id as usize)),
     <label:BasicLabel> => StatementId::Label(label),
}

GenericArg: GenericArg = {
    ConcreteTypeId => GenericArg::Type(<>),
    <v:BigInt> => GenericArg::Value(v),
    "user@" <id:FunctionId> => GenericArg::UserFunc(id),
    "ut@" <id:UserTypeId> => GenericArg::UserType(id),
    "lib@" <id:ConcreteLibfuncId> => GenericArg::Libfunc(id),
}
GenericArgs = Comma<GenericArg>;

PreStatement: PreStatement = {
    <label: BasicLabel> ":" => PreStatement::Label(label),
    <statement: Statement> => PreStatement::Statement(statement),
}

Statement: GenStatement<StatementId> = {
    <invocation:Invocation> => GenStatement::Invocation(invocation),
    "return" "(" <args:VarIds> ")" ";" => GenStatement::Return(args),
}

Invocation: GenInvocation<StatementId> = {
    <libfunc_id:ConcreteLibfuncId> "(" <args:VarIds> ")" "->" "(" <results:VarIds> ")" ";" =>
        GenInvocation {
            libfunc_id,
            args,
            branches: vec![GenBranchInfo { target: GenBranchTarget::Fallthrough , results }]
        },
    <libfunc_id:ConcreteLibfuncId> "(" <args:VarIds> ")" "{" <branches:BranchInfo*> "}" ";" =>
        GenInvocation {libfunc_id, args, branches },
}

// Generates a vector of Ts with or without a trailing comma.
Comma<T>: Vec<T> = {
    // If we have an additional element we add it to the vector, otherwise
    // returning the current vector.
    <mut v:(<T> ",")*> <e:T?> => match e {
        None => v,
        Some(e) => {
            v.push(e);
            v
        }
    }
};

BranchInfo: GenBranchInfo<StatementId> = {
    <target: BranchTarget> "(" <results:VarIds> ")" =>
        GenBranchInfo { target, results },
}

BranchTarget: GenBranchTarget<StatementId> = {
     "fallthrough" => GenBranchTarget::Fallthrough,
     <id:StatementId> => GenBranchTarget::Statement(id),
}

BasicLabel: String = {
    r"[a-zA-Z_][a-zA-Z_0-9]*" => <>.to_string(),
}

// `BasicLabel`s joined by "::".
PathLabel: String = {
    BasicLabel => <>,
    <path_label:PathLabel> "::" <basic_label:BasicLabel> => format!("{path_label}::{basic_label}"),
}

// `GenericArg`s joined by ",".
GenericArgsString: String = {
    GenericArg => <>.to_string(),
    <head:GenericArgsString> "," <tail:GenericArg> => format!("{head}, {tail}"),
    <head:GenericArgsString> "," "..." => format!("{head}, ..."),
}

// Label that can also include generic arguments.
ConcreteLabel: String = {
    BasicLabel => <>,
    "(" <generic_args:GenericArgsString> ")" => format!("({generic_args})"),
    "(" <generic_args:GenericArgsString> "," ")" => format!("({generic_args})"),
    "(" ")" => format!("()"),
    <base:ConcreteLabel> "::" <next:BasicLabel> => format!("{base}::{next}"),
    <base:ConcreteLabel> "::" "<" <generic_args:GenericArgsString> ">" => format!("{base}::<{generic_args}>"),
    <base:ConcreteLabel> "<" <generic_args:GenericArgsString> ">" => format!("{base}<{generic_args}>"),
}

BigInt: BigInt = {
    r"-?[1-9][0-9]*|0" => <>.parse().unwrap(),
}

Bool: bool = {
    "false" => false,
    "true" => true,
}

UnsignedInt: u64 = {
    BigInt => u64::try_from(<>).unwrap(),
}

SignedInt: i64 = {
    BigInt => i64::try_from(<>).unwrap(),
}

I16: i16 = {
    BigInt => i16::try_from(<>).unwrap(),
}

match {
    r"[[:space:]]*" => {},
    r"//[^\n\r]*[\n\r]" => {},
    _,
}