use std::fmt;
use std::iter::{once, FromIterator};
use std::ops::{Deref, DerefMut};
#[derive(Clone, Debug, PartialEq)]
pub struct NonEmpty<T>(pub Vec<T>);
impl<T> NonEmpty<T> {
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(Clone, Debug, PartialEq)]
pub enum Path {
Absolute(String),
Relative(String),
}
#[derive(Debug)]
pub enum IdentifierError {
StartsWithDigit,
ContainsNonASCIIAlphaNum,
}
impl std::error::Error for IdentifierError {}
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() || c == '_')
== 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,
Attribute,
Varying,
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>),
}
impl FunIdentifier {
pub(crate) fn into_expr(self) -> Option<Expr> {
match self {
FunIdentifier::Identifier(..) => None,
FunIdentifier::Expr(expr) => Some(*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 {
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(Option<Box<Expr>>),
Discard,
}
#[derive(Clone, Debug, PartialEq)]
pub enum Preprocessor {
Define(PreprocessorDefine),
Else,
ElseIf(PreprocessorElseIf),
EndIf,
Error(PreprocessorError),
If(PreprocessorIf),
IfDef(PreprocessorIfDef),
IfNDef(PreprocessorIfNDef),
Include(PreprocessorInclude),
Line(PreprocessorLine),
Pragma(PreprocessorPragma),
Undef(PreprocessorUndef),
Version(PreprocessorVersion),
Extension(PreprocessorExtension),
}
#[derive(Clone, Debug, PartialEq)]
pub enum PreprocessorDefine {
ObjectLike {
ident: Identifier,
value: String,
},
FunctionLike {
ident: Identifier,
args: Vec<Identifier>,
value: String,
},
}
#[derive(Clone, Debug, PartialEq)]
pub struct PreprocessorElseIf {
pub condition: String,
}
#[derive(Clone, Debug, PartialEq)]
pub struct PreprocessorError {
pub message: String,
}
#[derive(Clone, Debug, PartialEq)]
pub struct PreprocessorIf {
pub condition: String,
}
#[derive(Clone, Debug, PartialEq)]
pub struct PreprocessorIfDef {
pub ident: Identifier,
}
#[derive(Clone, Debug, PartialEq)]
pub struct PreprocessorIfNDef {
pub ident: Identifier,
}
#[derive(Clone, Debug, PartialEq)]
pub struct PreprocessorInclude {
pub path: Path,
}
#[derive(Clone, Debug, PartialEq)]
pub struct PreprocessorLine {
pub line: u32,
pub source_string_number: Option<u32>,
}
#[derive(Clone, Debug, PartialEq)]
pub struct PreprocessorPragma {
pub command: String,
}
#[derive(Clone, Debug, PartialEq)]
pub struct PreprocessorUndef {
pub name: Identifier,
}
#[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_ok());
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_ok());
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();
}
}