use std::fmt;
use std::iter::{FromIterator, once};
use std::ops::{Deref, DerefMut};
#[derive(Clone, Debug, PartialEq)]
pub struct NonEmpty<T>(pub Vec<T>);
impl<T> NonEmpty<T> {
#[allow(clippy::should_implement_trait)]
#[deprecated(since = "1.2.0", note = "Use `from_non_empty_iter` instead. Will be removed in 2.0.0")]
pub fn from_iter<I>(iter: I) -> Option<Self> where I: IntoIterator<Item = T> {
let vec: Vec<_> = iter.into_iter().collect();
if vec.is_empty() {
None
} else {
Some(NonEmpty(vec))
}
}
pub fn from_non_empty_iter<I>(iter: I) -> Option<Self> where I: IntoIterator<Item = T> {
let vec: Vec<_> = iter.into_iter().collect();
if vec.is_empty() {
None
} else {
Some(NonEmpty(vec))
}
}
pub fn push(&mut self, item: T) {
self.0.push(item);
}
pub fn pop(&mut self) -> Option<T> {
if self.0.len() == 1 {
None
} else {
self.0.pop()
}
}
}
impl<T> IntoIterator for NonEmpty<T> {
type IntoIter = <Vec<T> as IntoIterator>::IntoIter;
type Item = T;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl<'a, T> IntoIterator for &'a NonEmpty<T> {
type IntoIter = <&'a Vec<T> as IntoIterator>::IntoIter;
type Item = &'a T;
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
impl<'a, T> IntoIterator for &'a mut NonEmpty<T> {
type IntoIter = <&'a mut Vec<T> as IntoIterator>::IntoIter;
type Item = &'a mut T;
fn into_iter(self) -> Self::IntoIter {
self.0.iter_mut()
}
}
impl<T> Extend<T> for NonEmpty<T> {
fn extend<I>(&mut self, iter: I) where I: IntoIterator<Item = T> {
self.0.extend(iter);
}
}
#[derive(Debug)]
pub enum IdentifierError {
StartsWithDigit,
ContainsNonASCIIAlphaNum
}
impl fmt::Display for IdentifierError {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
IdentifierError::StartsWithDigit =>
f.write_str("starts starts with a digit"),
IdentifierError::ContainsNonASCIIAlphaNum =>
f.write_str("contains at least one non-alphanumeric ASCII character")
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Identifier(pub String);
impl Identifier {
pub fn new<N>(name: N) -> Result<Self, IdentifierError> where N: Into<String> {
let name = name.into();
if name.chars().next().map(|c| c.is_ascii_alphabetic()) == Some(false) {
Err(IdentifierError::StartsWithDigit)
} else if name.contains(|c: char| !(c.is_ascii_alphanumeric() || c == '_')) {
Err(IdentifierError::ContainsNonASCIIAlphaNum)
} else {
Ok(Identifier(name))
}
}
pub fn as_str(&self) -> &str {
&self.0
}
}
impl<'a> From<&'a str> for Identifier {
fn from(s: &str) -> Self {
Identifier(s.to_owned())
}
}
impl From<String> for Identifier {
fn from(s: String) -> Self {
Identifier(s)
}
}
impl fmt::Display for Identifier {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
self.0.fmt(f)
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct TypeName(pub String);
impl TypeName {
pub fn new<N>(name: N) -> Result<Self, IdentifierError> where N: Into<String> {
let Identifier(tn) = Identifier::new(name)?;
Ok(TypeName(tn))
}
pub fn as_str(&self) -> &str {
&self.0
}
}
impl<'a> From<&'a str> for TypeName {
fn from(s: &str) -> Self {
TypeName(s.to_owned())
}
}
impl From<String> for TypeName {
fn from(s: String) -> Self {
TypeName(s)
}
}
impl fmt::Display for TypeName {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
self.0.fmt(f)
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum TypeSpecifierNonArray {
Void,
Bool,
Int,
UInt,
Float,
Double,
Vec2,
Vec3,
Vec4,
DVec2,
DVec3,
DVec4,
BVec2,
BVec3,
BVec4,
IVec2,
IVec3,
IVec4,
UVec2,
UVec3,
UVec4,
Mat2,
Mat3,
Mat4,
Mat23,
Mat24,
Mat32,
Mat34,
Mat42,
Mat43,
DMat2,
DMat3,
DMat4,
DMat23,
DMat24,
DMat32,
DMat34,
DMat42,
DMat43,
Sampler1D,
Image1D,
Sampler2D,
Image2D,
Sampler3D,
Image3D,
SamplerCube,
ImageCube,
Sampler2DRect,
Image2DRect,
Sampler1DArray,
Image1DArray,
Sampler2DArray,
Image2DArray,
SamplerBuffer,
ImageBuffer,
Sampler2DMS,
Image2DMS,
Sampler2DMSArray,
Image2DMSArray,
SamplerCubeArray,
ImageCubeArray,
Sampler1DShadow,
Sampler2DShadow,
Sampler2DRectShadow,
Sampler1DArrayShadow,
Sampler2DArrayShadow,
SamplerCubeShadow,
SamplerCubeArrayShadow,
ISampler1D,
IImage1D,
ISampler2D,
IImage2D,
ISampler3D,
IImage3D,
ISamplerCube,
IImageCube,
ISampler2DRect,
IImage2DRect,
ISampler1DArray,
IImage1DArray,
ISampler2DArray,
IImage2DArray,
ISamplerBuffer,
IImageBuffer,
ISampler2DMS,
IImage2DMS,
ISampler2DMSArray,
IImage2DMSArray,
ISamplerCubeArray,
IImageCubeArray,
AtomicUInt,
USampler1D,
UImage1D,
USampler2D,
UImage2D,
USampler3D,
UImage3D,
USamplerCube,
UImageCube,
USampler2DRect,
UImage2DRect,
USampler1DArray,
UImage1DArray,
USampler2DArray,
UImage2DArray,
USamplerBuffer,
UImageBuffer,
USampler2DMS,
UImage2DMS,
USampler2DMSArray,
UImage2DMSArray,
USamplerCubeArray,
UImageCubeArray,
Struct(StructSpecifier),
TypeName(TypeName)
}
#[derive(Clone, Debug, PartialEq)]
pub struct TypeSpecifier {
pub ty: TypeSpecifierNonArray,
pub array_specifier: Option<ArraySpecifier>
}
impl TypeSpecifier {
pub fn new(ty: TypeSpecifierNonArray) -> Self {
TypeSpecifier {
ty,
array_specifier: None
}
}
}
impl From<TypeSpecifierNonArray> for TypeSpecifier {
fn from(ty: TypeSpecifierNonArray) -> Self {
TypeSpecifier::new(ty)
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct StructSpecifier {
pub name: Option<TypeName>,
pub fields: NonEmpty<StructFieldSpecifier>,
}
#[derive(Clone, Debug, PartialEq)]
pub struct StructFieldSpecifier {
pub qualifier: Option<TypeQualifier>,
pub ty: TypeSpecifier,
pub identifiers: NonEmpty<ArrayedIdentifier>
}
impl StructFieldSpecifier {
pub fn new<A, T>(
identifier: A,
ty: T
) -> Self
where A: Into<ArrayedIdentifier>,
T: Into<TypeSpecifier> {
StructFieldSpecifier {
qualifier: None,
ty: ty.into(),
identifiers: NonEmpty(vec![identifier.into()])
}
}
pub fn new_many<I>(
identifiers: I,
ty: TypeSpecifier
) -> Self
where I: IntoIterator<Item = ArrayedIdentifier> {
StructFieldSpecifier {
qualifier: None,
ty,
identifiers: NonEmpty(identifiers.into_iter().collect())
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct ArrayedIdentifier {
pub ident: Identifier,
pub array_spec: Option<ArraySpecifier>
}
impl ArrayedIdentifier {
pub fn new<I, AS>(
ident: I,
array_spec: AS
) -> Self
where I: Into<Identifier>,
AS: Into<Option<ArraySpecifier>> {
ArrayedIdentifier {
ident: ident.into(),
array_spec: array_spec.into()
}
}
}
impl<'a> From<&'a str> for ArrayedIdentifier {
fn from(ident: &str) -> Self {
ArrayedIdentifier {
ident: Identifier(ident.to_owned()),
array_spec: None
}
}
}
impl From<Identifier> for ArrayedIdentifier {
fn from(ident: Identifier) -> Self {
ArrayedIdentifier {
ident,
array_spec: None
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct TypeQualifier {
pub qualifiers: NonEmpty<TypeQualifierSpec>
}
#[derive(Clone, Debug, PartialEq)]
pub enum TypeQualifierSpec {
Storage(StorageQualifier),
Layout(LayoutQualifier),
Precision(PrecisionQualifier),
Interpolation(InterpolationQualifier),
Invariant,
Precise
}
#[derive(Clone, Debug, PartialEq)]
pub enum StorageQualifier {
Const,
InOut,
In,
Out,
Centroid,
Patch,
Sample,
Uniform,
Buffer,
Shared,
Coherent,
Volatile,
Restrict,
ReadOnly,
WriteOnly,
Subroutine(Vec<TypeName>),
}
#[derive(Clone, Debug, PartialEq)]
pub struct LayoutQualifier {
pub ids: NonEmpty<LayoutQualifierSpec>
}
#[derive(Clone, Debug, PartialEq)]
pub enum LayoutQualifierSpec {
Identifier(Identifier, Option<Box<Expr>>),
Shared
}
#[derive(Clone, Debug, PartialEq)]
pub enum PrecisionQualifier {
High,
Medium,
Low
}
#[derive(Clone, Debug, PartialEq)]
pub enum InterpolationQualifier {
Smooth,
Flat,
NoPerspective
}
#[derive(Clone, Debug, PartialEq)]
pub struct FullySpecifiedType {
pub qualifier: Option<TypeQualifier>,
pub ty: TypeSpecifier
}
impl FullySpecifiedType {
pub fn new(ty: TypeSpecifierNonArray) -> Self {
FullySpecifiedType {
qualifier: None,
ty: TypeSpecifier {
ty,
array_specifier: None
}
}
}
}
impl From<TypeSpecifierNonArray> for FullySpecifiedType {
fn from(ty: TypeSpecifierNonArray) -> Self {
FullySpecifiedType::new(ty)
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum ArraySpecifier {
Unsized,
ExplicitlySized(Box<Expr>)
}
#[derive(Clone, Debug, PartialEq)]
pub enum Declaration {
FunctionPrototype(FunctionPrototype),
InitDeclaratorList(InitDeclaratorList),
Precision(PrecisionQualifier, TypeSpecifier),
Block(Block),
Global(TypeQualifier, Vec<Identifier>)
}
#[derive(Clone, Debug, PartialEq)]
pub struct Block {
pub qualifier: TypeQualifier,
pub name: Identifier,
pub fields: Vec<StructFieldSpecifier>,
pub identifier: Option<ArrayedIdentifier>
}
#[derive(Clone, Debug, PartialEq)]
pub enum FunIdentifier {
Identifier(Identifier),
Expr(Box<Expr>)
}
#[derive(Clone, Debug, PartialEq)]
pub struct FunctionPrototype {
pub ty: FullySpecifiedType,
pub name: Identifier,
pub parameters: Vec<FunctionParameterDeclaration>
}
#[derive(Clone, Debug, PartialEq)]
pub enum FunctionParameterDeclaration {
Named(Option<TypeQualifier>, FunctionParameterDeclarator),
Unnamed(Option<TypeQualifier>, TypeSpecifier)
}
impl FunctionParameterDeclaration {
pub fn new_named<I, T>(
ident: I,
ty: T
) -> Self
where I: Into<ArrayedIdentifier>,
T: Into<TypeSpecifier> {
let declator = FunctionParameterDeclarator {
ty: ty.into(),
ident: ident.into()
};
FunctionParameterDeclaration::Named(None, declator)
}
pub fn new_unnamed<T>(ty: T) -> Self where T: Into<TypeSpecifier> {
FunctionParameterDeclaration::Unnamed(None, ty.into())
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct FunctionParameterDeclarator {
pub ty: TypeSpecifier,
pub ident: ArrayedIdentifier
}
#[derive(Clone, Debug, PartialEq)]
pub struct InitDeclaratorList {
pub head: SingleDeclaration,
pub tail: Vec<SingleDeclarationNoType>
}
#[derive(Clone, Debug, PartialEq)]
pub struct SingleDeclaration {
pub ty: FullySpecifiedType,
pub name: Option<Identifier>,
pub array_specifier: Option<ArraySpecifier>,
pub initializer: Option<Initializer>
}
#[derive(Clone, Debug, PartialEq)]
pub struct SingleDeclarationNoType {
pub ident: ArrayedIdentifier,
pub initializer: Option<Initializer>
}
#[derive(Clone, Debug, PartialEq)]
pub enum Initializer {
Simple(Box<Expr>),
List(NonEmpty<Initializer>)
}
impl From<Expr> for Initializer {
fn from(e: Expr) -> Self {
Initializer::Simple(Box::new(e))
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum Expr {
Variable(Identifier),
IntConst(i32),
UIntConst(u32),
BoolConst(bool),
FloatConst(f32),
DoubleConst(f64),
Unary(UnaryOp, Box<Expr>),
Binary(BinaryOp, Box<Expr>, Box<Expr>),
Ternary(Box<Expr>, Box<Expr>, Box<Expr>),
Assignment(Box<Expr>, AssignmentOp, Box<Expr>),
Bracket(Box<Expr>, ArraySpecifier),
FunCall(FunIdentifier, Vec<Expr>),
Dot(Box<Expr>, Identifier),
PostInc(Box<Expr>),
PostDec(Box<Expr>),
Comma(Box<Expr>, Box<Expr>)
}
impl From<i32> for Expr {
fn from(x: i32) -> Expr {
Expr::IntConst(x)
}
}
impl From<u32> for Expr {
fn from(x: u32) -> Expr {
Expr::UIntConst(x)
}
}
impl From<bool> for Expr {
fn from(x: bool) -> Expr {
Expr::BoolConst(x)
}
}
impl From<f32> for Expr {
fn from(x: f32) -> Expr {
Expr::FloatConst(x)
}
}
impl From<f64> for Expr {
fn from(x: f64) -> Expr {
Expr::DoubleConst(x)
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum UnaryOp {
Inc,
Dec,
Add,
Minus,
Not,
Complement
}
#[derive(Clone, Debug, PartialEq)]
pub enum BinaryOp {
Or,
Xor,
And,
BitOr,
BitXor,
BitAnd,
Equal,
NonEqual,
LT,
GT,
LTE,
GTE,
LShift,
RShift,
Add,
Sub,
Mult,
Div,
Mod
}
#[derive(Clone, Debug, PartialEq)]
pub enum AssignmentOp {
Equal,
Mult,
Div,
Mod,
Add,
Sub,
LShift,
RShift,
And,
Xor,
Or
}
#[derive(Clone, Debug, PartialEq)]
pub struct TranslationUnit(pub NonEmpty<ExternalDeclaration>);
pub type ShaderStage = TranslationUnit;
impl TranslationUnit {
#[allow(clippy::should_implement_trait)]
#[deprecated(since = "1.2.0", note = "Use `from_non_empty_iter` instead. Will be removed in 2.0.0")]
pub fn from_iter<I>(iter: I) -> Option<Self> where I: IntoIterator<Item = ExternalDeclaration> {
NonEmpty::from_non_empty_iter(iter).map(TranslationUnit)
}
pub fn from_non_empty_iter<I>(iter: I) -> Option<Self> where I: IntoIterator<Item = ExternalDeclaration> {
NonEmpty::from_non_empty_iter(iter).map(TranslationUnit)
}
}
impl Deref for TranslationUnit {
type Target = NonEmpty<ExternalDeclaration>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for TranslationUnit {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl IntoIterator for TranslationUnit {
type IntoIter = <NonEmpty<ExternalDeclaration> as IntoIterator>::IntoIter;
type Item = ExternalDeclaration;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl<'a> IntoIterator for &'a TranslationUnit {
type IntoIter = <&'a NonEmpty<ExternalDeclaration> as IntoIterator>::IntoIter;
type Item = &'a ExternalDeclaration;
fn into_iter(self) -> Self::IntoIter {
(&self.0).into_iter()
}
}
impl<'a> IntoIterator for &'a mut TranslationUnit {
type IntoIter = <&'a mut NonEmpty<ExternalDeclaration> as IntoIterator>::IntoIter;
type Item = &'a mut ExternalDeclaration;
fn into_iter(self) -> Self::IntoIter {
(&mut self.0).into_iter()
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum ExternalDeclaration {
Preprocessor(Preprocessor),
FunctionDefinition(FunctionDefinition),
Declaration(Declaration)
}
impl ExternalDeclaration {
pub fn new_fn<T, N, A, S>(
ret_ty: T,
name: N,
args: A,
body: S
) -> Self
where T: Into<FullySpecifiedType>,
N: Into<Identifier>,
A: IntoIterator<Item = FunctionParameterDeclaration>,
S: IntoIterator<Item = Statement> {
ExternalDeclaration::FunctionDefinition(
FunctionDefinition {
prototype: FunctionPrototype {
ty: ret_ty.into(),
name: name.into(),
parameters: args.into_iter().collect()
},
statement: CompoundStatement {
statement_list: body.into_iter().collect()
}
}
)
}
pub fn new_struct<N, F>(name: N, fields: F) -> Option<Self>
where N: Into<TypeName>,
F: IntoIterator<Item = StructFieldSpecifier> {
let fields: Vec<_> = fields.into_iter().collect();
if fields.is_empty() {
None
} else {
Some(ExternalDeclaration::Declaration(
Declaration::InitDeclaratorList(
InitDeclaratorList {
head: SingleDeclaration {
ty: FullySpecifiedType {
qualifier: None,
ty: TypeSpecifier {
ty: TypeSpecifierNonArray::Struct(
StructSpecifier {
name: Some(name.into()),
fields: NonEmpty(fields.into_iter().collect())
}
),
array_specifier: None
}
},
name: None,
array_specifier: None,
initializer: None
},
tail: vec![]
}
)
))
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct FunctionDefinition {
pub prototype: FunctionPrototype,
pub statement: CompoundStatement,
}
#[derive(Clone, Debug, PartialEq)]
pub struct CompoundStatement {
pub statement_list: Vec<Statement>
}
impl FromIterator<Statement> for CompoundStatement {
fn from_iter<T>(iter: T) -> Self where T: IntoIterator<Item = Statement> {
CompoundStatement {
statement_list: iter.into_iter().collect()
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum Statement {
Compound(Box<CompoundStatement>),
Simple(Box<SimpleStatement>)
}
impl Statement {
pub fn new_case<C, S>(
case: C,
statements: S
) -> Self
where C: Into<CaseLabel>,
S: IntoIterator<Item = Statement> {
let case_stmt = Statement::Simple(Box::new(SimpleStatement::CaseLabel(case.into())));
Statement::Compound(
Box::new(CompoundStatement {
statement_list: once(case_stmt).chain(statements.into_iter()).collect()
})
)
}
pub fn declare_var<T, N, A, I>(
ty: T,
name: N,
array_specifier: A,
initializer: I
) -> Self
where T: Into<FullySpecifiedType>,
N: Into<Identifier>,
A: Into<Option<ArraySpecifier>>,
I: Into<Option<Initializer>> {
Statement::Simple(
Box::new(SimpleStatement::Declaration(
Declaration::InitDeclaratorList(
InitDeclaratorList {
head: SingleDeclaration {
ty: ty.into(),
name: Some(name.into()),
array_specifier: array_specifier.into(),
initializer: initializer.into()
},
tail: Vec::new()
}
)
))
)
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum SimpleStatement {
Declaration(Declaration),
Expression(ExprStatement),
Selection(SelectionStatement),
Switch(SwitchStatement),
CaseLabel(CaseLabel),
Iteration(IterationStatement),
Jump(JumpStatement)
}
impl SimpleStatement {
pub fn new_expr<E>(expr: E) -> Self where E: Into<Expr> {
SimpleStatement::Expression(Some(expr.into()))
}
pub fn new_if_else<If, True, False>(
ife: If,
truee: True,
falsee: False
) -> Self
where If: Into<Expr>,
True: Into<Statement>,
False: Into<Statement> {
SimpleStatement::Selection(
SelectionStatement {
cond: Box::new(ife.into()),
rest: SelectionRestStatement::Else(Box::new(truee.into()), Box::new(falsee.into()))
}
)
}
pub fn new_switch<H, B>(
head: H,
body: B
) -> Self
where H: Into<Expr>,
B: IntoIterator<Item = Statement> {
SimpleStatement::Switch(
SwitchStatement {
head: Box::new(head.into()),
body: body.into_iter().collect()
}
)
}
pub fn new_while<C, S>(
cond: C,
body: S
) -> Self
where C: Into<Condition>,
S: Into<Statement> {
SimpleStatement::Iteration(
IterationStatement::While(cond.into(), Box::new(body.into()))
)
}
pub fn new_do_while<C, S>(
body: S,
cond: C
) -> Self
where S: Into<Statement>,
C: Into<Expr> {
SimpleStatement::Iteration(
IterationStatement::DoWhile(Box::new(body.into()), Box::new(cond.into()))
)
}
}
pub type ExprStatement = Option<Expr>;
#[derive(Clone, Debug, PartialEq)]
pub struct SelectionStatement {
pub cond: Box<Expr>,
pub rest: SelectionRestStatement
}
#[derive(Clone, Debug, PartialEq)]
pub enum Condition {
Expr(Box<Expr>),
Assignment(FullySpecifiedType, Identifier, Initializer)
}
impl From<Expr> for Condition {
fn from(expr: Expr) -> Self {
Condition::Expr(Box::new(expr))
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum SelectionRestStatement {
Statement(Box<Statement>),
Else(Box<Statement>, Box<Statement>)
}
#[derive(Clone, Debug, PartialEq)]
pub struct SwitchStatement {
pub head: Box<Expr>,
pub body: Vec<Statement>
}
#[derive(Clone, Debug, PartialEq)]
pub enum CaseLabel {
Case(Box<Expr>),
Def
}
#[derive(Clone, Debug, PartialEq)]
pub enum IterationStatement {
While(Condition, Box<Statement>),
DoWhile(Box<Statement>, Box<Expr>),
For(ForInitStatement, ForRestStatement, Box<Statement>)
}
#[derive(Clone, Debug, PartialEq)]
pub enum ForInitStatement {
Expression(Option<Expr>),
Declaration(Box<Declaration>)
}
#[derive(Clone, Debug, PartialEq)]
pub struct ForRestStatement {
pub condition: Option<Condition>,
pub post_expr: Option<Box<Expr>>
}
#[derive(Clone, Debug, PartialEq)]
pub enum JumpStatement {
Continue,
Break,
Return(Box<Expr>),
Discard
}
#[derive(Clone, Debug, PartialEq)]
pub enum Preprocessor {
Define(PreprocessorDefine),
Version(PreprocessorVersion),
Extension(PreprocessorExtension)
}
#[derive(Clone, Debug, PartialEq)]
pub struct PreprocessorDefine {
pub name: Identifier,
pub value: Expr,
}
#[derive(Clone, Debug, PartialEq)]
pub struct PreprocessorVersion {
pub version: u16,
pub profile: Option<PreprocessorVersionProfile>
}
#[derive(Clone, Debug, PartialEq)]
pub enum PreprocessorVersionProfile {
Core,
Compatibility,
ES
}
#[derive(Clone, Debug, PartialEq)]
pub struct PreprocessorExtension {
pub name: PreprocessorExtensionName,
pub behavior: Option<PreprocessorExtensionBehavior>
}
#[derive(Clone, Debug, PartialEq)]
pub enum PreprocessorExtensionName {
All,
Specific(String)
}
#[derive(Clone, Debug, PartialEq)]
pub enum PreprocessorExtensionBehavior {
Require,
Enable,
Warn,
Disable
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn create_new_identifier() {
assert!(Identifier::new("foo_bar").is_ok());
assert!(Identifier::new("3foo_bar").is_err());
assert!(Identifier::new("FooBar").is_ok());
assert!(Identifier::new("_FooBar").is_err());
assert!(Identifier::new("foo3").is_ok());
assert!(Identifier::new("foo3_").is_ok());
assert!(Identifier::new("fδo3_").is_err());
}
#[test]
fn create_new_type_name() {
assert!(TypeName::new("foo_bar").is_ok());
assert!(TypeName::new("FooBar").is_ok());
assert!(TypeName::new("foo3").is_ok());
assert!(TypeName::new("foo3_").is_ok());
assert!(TypeName::new("_FooBar").is_err());
assert!(TypeName::new("3foo_bar").is_err());
assert!(TypeName::new("fδo3_").is_err());
}
#[test]
fn declare_new_fn() {
let _ =
ExternalDeclaration::new_fn(TypeSpecifierNonArray::Bool,
"predicate",
vec![FunctionParameterDeclaration::new_named("x", TypeSpecifierNonArray::Float)],
vec![]
);
}
#[test]
fn declare_struct() {
let point =
ExternalDeclaration::new_struct("Point2D",
vec![
StructFieldSpecifier::new("x", TypeSpecifierNonArray::Double),
StructFieldSpecifier::new("y", TypeSpecifierNonArray::Double)
]
);
assert!(point.is_some());
}
#[test]
fn declare_bad_struct() {
let point = ExternalDeclaration::new_struct("Point2D", vec![]);
assert!(point.is_none());
}
#[test]
fn initializer_from_expr() {
let _: Initializer = Expr::from(false).into();
}
}