Source code

Revision control

Copy as Markdown

Other Tools

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Large chunks of this file are derived from the glsl crate which is:
* Copyright (c) 2018, Dimitri Sabadie <dimitri.sabadie@gmail.com>
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* * Neither the name of Dimitri Sabadie <dimitri.sabadie@gmail.com> nor the names of other
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
use glsl::syntax;
use glsl::syntax::{ArrayedIdentifier, ArraySpecifier, ArraySpecifierDimension, AssignmentOp, BinaryOp, Identifier};
use glsl::syntax::{NonEmpty, PrecisionQualifier, StructFieldSpecifier, StructSpecifier};
use glsl::syntax::{TypeSpecifier, TypeSpecifierNonArray, UnaryOp};
use std::cell::{Cell, Ref, RefCell};
use std::collections::HashMap;
use std::iter::FromIterator;
use std::mem;
use std::ops::{Deref, DerefMut};
use std::rc::Rc;
trait LiftFrom<S> {
fn lift(state: &mut State, s: S) -> Self;
}
fn lift<S, T: LiftFrom<S>>(state: &mut State, s: S) -> T {
LiftFrom::lift(state, s)
}
#[derive(Debug)]
pub struct Symbol {
pub name: String,
pub decl: SymDecl,
}
#[derive(Debug, Clone, PartialEq)]
pub struct FunctionSignature {
ret: Type,
params: Vec<Type>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct FunctionType {
signatures: NonEmpty<FunctionSignature>,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum SamplerFormat {
Unknown,
RGBA8,
RGBA32F,
RGBA32I,
R8,
RG8,
}
impl SamplerFormat {
pub fn type_suffix(self) -> Option<&'static str> {
match self {
SamplerFormat::Unknown => None,
SamplerFormat::RGBA8 => Some("RGBA8"),
SamplerFormat::RGBA32F => Some("RGBA32F"),
SamplerFormat::RGBA32I => Some("RGBA32I"),
SamplerFormat::R8 => Some("R8"),
SamplerFormat::RG8 => Some("RG8"),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum StorageClass {
None,
Const,
In,
Out,
Uniform,
Sampler(SamplerFormat),
FragColor(i32),
}
#[derive(Clone, Debug, PartialEq)]
pub struct ArraySizes {
pub sizes: Vec<Expr>,
}
impl LiftFrom<&ArraySpecifier> for ArraySizes {
fn lift(state: &mut State, a: &ArraySpecifier) -> Self {
ArraySizes {
sizes: a.dimensions.0.iter().map(|a| match a {
ArraySpecifierDimension::Unsized => panic!(),
ArraySpecifierDimension::ExplicitlySized(expr) => translate_expression(state, expr),
}).collect(),
}
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum TypeKind {
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,
// floating point opaque types
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,
// signed integer opaque types
ISampler1D,
IImage1D,
ISampler2D,
IImage2D,
ISampler3D,
IImage3D,
ISamplerCube,
IImageCube,
ISampler2DRect,
IImage2DRect,
ISampler1DArray,
IImage1DArray,
ISampler2DArray,
IImage2DArray,
ISamplerBuffer,
IImageBuffer,
ISampler2DMS,
IImage2DMS,
ISampler2DMSArray,
IImage2DMSArray,
ISamplerCubeArray,
IImageCubeArray,
// unsigned integer opaque types
AtomicUInt,
USampler1D,
UImage1D,
USampler2D,
UImage2D,
USampler3D,
UImage3D,
USamplerCube,
UImageCube,
USampler2DRect,
UImage2DRect,
USampler1DArray,
UImage1DArray,
USampler2DArray,
UImage2DArray,
USamplerBuffer,
UImageBuffer,
USampler2DMS,
UImage2DMS,
USampler2DMSArray,
UImage2DMSArray,
USamplerCubeArray,
UImageCubeArray,
Struct(SymRef),
}
impl TypeKind {
pub fn is_sampler(&self) -> bool {
use TypeKind::*;
match self {
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
| USampler1D
| UImage1D
| USampler2D
| UImage2D
| USampler3D
| UImage3D
| USamplerCube
| UImageCube
| USampler2DRect
| UImage2DRect
| USampler1DArray
| UImage1DArray
| USampler2DArray
| UImage2DArray
| USamplerBuffer
| UImageBuffer
| USampler2DMS
| UImage2DMS
| USampler2DMSArray
| UImage2DMSArray
| USamplerCubeArray
| UImageCubeArray => true,
_ => false,
}
}
pub fn is_bool(&self) -> bool {
use TypeKind::*;
match self {
Bool | BVec2 | BVec3 | BVec4 => true,
_ => false,
}
}
pub fn to_bool(&self) -> Self {
use TypeKind::*;
match self {
Int | UInt | Float | Double => Bool,
IVec2 | UVec2 | Vec2 | DVec2 => BVec2,
IVec3 | UVec3 | Vec3 | DVec3 => BVec3,
IVec4 | UVec4 | Vec4 | DVec4 => BVec4,
_ => *self,
}
}
pub fn to_int(&self) -> Self {
use TypeKind::*;
match self {
Bool | UInt | Float | Double => Int,
BVec2 | UVec2 | Vec2 | DVec2 => IVec2,
BVec3 | UVec3 | Vec3 | DVec3 => IVec3,
BVec4 | UVec4 | Vec4 | DVec4 => IVec4,
_ => *self,
}
}
pub fn to_scalar(&self) -> Self {
use TypeKind::*;
match self {
IVec2 | IVec3 | IVec4 => Int,
UVec2 | UVec3 | UVec4 => UInt,
Vec2 | Vec3 | Vec4 => Float,
DVec2 | DVec3 | DVec4 => Double,
BVec2 | BVec3 | BVec4 => Bool,
_ => *self,
}
}
pub fn glsl_primitive_type_name(&self) -> Option<&'static str> {
use TypeKind::*;
Some(match self {
Void => "void",
Bool => "bool",
Int => "int",
UInt => "uint",
Float => "float",
Double => "double",
Vec2 => "vec2",
Vec3 => "vec3",
Vec4 => "vec4",
DVec2 => "dvec2",
DVec3 => "dvec3",
DVec4 => "dvec4",
BVec2 => "bvec2",
BVec3 => "bvec3",
BVec4 => "bvec4",
IVec2 => "ivec2",
IVec3 => "ivec3",
IVec4 => "ivec4",
UVec2 => "uvec2",
UVec3 => "uvec3",
UVec4 => "uvec4",
Mat2 => "mat2",
Mat3 => "mat3",
Mat4 => "mat4",
Mat23 => "mat23",
Mat24 => "mat24",
Mat32 => "mat32",
Mat34 => "mat34",
Mat42 => "mat42",
Mat43 => "mat43",
DMat2 => "dmat2",
DMat3 => "dmat3",
DMat4 => "dmat4",
DMat23 => "dmat23",
DMat24 => "dmat24",
DMat32 => "dmat32",
DMat34 => "dmat34",
DMat42 => "dmat42",
DMat43 => "dmat43",
Sampler1D => "sampler1D",
Image1D => "image1D",
Sampler2D => "sampler2D",
Image2D => "image2D",
Sampler3D => "sampler3D",
Image3D => "image3D",
SamplerCube => "samplerCube",
ImageCube => "imageCube",
Sampler2DRect => "sampler2DRect",
Image2DRect => "image2DRect",
Sampler1DArray => "sampler1DArray",
Image1DArray => "image1DArray",
Sampler2DArray => "sampler2DArray",
Image2DArray => "image2DArray",
SamplerBuffer => "samplerBuffer",
ImageBuffer => "imageBuffer",
Sampler2DMS => "sampler2DMS",
Image2DMS => "image2DMS",
Sampler2DMSArray => "sampler2DMSArray",
Image2DMSArray => "image2DMSArray",
SamplerCubeArray => "samplerCubeArray",
ImageCubeArray => "imageCubeArray",
Sampler1DShadow => "sampler1DShadow",
Sampler2DShadow => "sampler2DShadow",
Sampler2DRectShadow => "sampler2DRectShadow",
Sampler1DArrayShadow => "sampler1DArrayShadow",
Sampler2DArrayShadow => "sampler2DArrayShadow",
SamplerCubeShadow => "samplerCubeShadow",
SamplerCubeArrayShadow => "samplerCubeArrayShadow",
ISampler1D => "isampler1D",
IImage1D => "iimage1D",
ISampler2D => "isampler2D",
IImage2D => "iimage2D",
ISampler3D => "isampler3D",
IImage3D => "iimage3D",
ISamplerCube => "isamplerCube",
IImageCube => "iimageCube",
ISampler2DRect => "isampler2DRect",
IImage2DRect => "iimage2DRect",
ISampler1DArray => "isampler1DArray",
IImage1DArray => "iimage1DArray",
ISampler2DArray => "isampler2DArray",
IImage2DArray => "iimage2DArray",
ISamplerBuffer => "isamplerBuffer",
IImageBuffer => "iimageBuffer",
ISampler2DMS => "isampler2MS",
IImage2DMS => "iimage2DMS",
ISampler2DMSArray => "isampler2DMSArray",
IImage2DMSArray => "iimage2DMSArray",
ISamplerCubeArray => "isamplerCubeArray",
IImageCubeArray => "iimageCubeArray",
AtomicUInt => "atomic_uint",
USampler1D => "usampler1D",
UImage1D => "uimage1D",
USampler2D => "usampler2D",
UImage2D => "uimage2D",
USampler3D => "usampler3D",
UImage3D => "uimage3D",
USamplerCube => "usamplerCube",
UImageCube => "uimageCube",
USampler2DRect => "usampler2DRect",
UImage2DRect => "uimage2DRect",
USampler1DArray => "usampler1DArray",
UImage1DArray => "uimage1DArray",
USampler2DArray => "usampler2DArray",
UImage2DArray => "uimage2DArray",
USamplerBuffer => "usamplerBuffer",
UImageBuffer => "uimageBuffer",
USampler2DMS => "usampler2DMS",
UImage2DMS => "uimage2DMS",
USampler2DMSArray => "usamplerDMSArray",
UImage2DMSArray => "uimage2DMSArray",
USamplerCubeArray => "usamplerCubeArray",
UImageCubeArray => "uimageCubeArray",
Struct(..) => return None,
})
}
pub fn cxx_primitive_type_name(&self) -> Option<&'static str> {
use TypeKind::*;
match self {
Bool => Some("Bool"),
Int => Some("I32"),
UInt => Some("U32"),
Float => Some("Float"),
Double => Some("Double"),
_ => self.glsl_primitive_type_name(),
}
}
pub fn cxx_primitive_scalar_type_name(&self) -> Option<&'static str> {
use TypeKind::*;
match self {
Void => Some("void"),
Bool => Some("bool"),
Int => Some("int32_t"),
UInt => Some("uint32_t"),
Float => Some("float"),
Double => Some("double"),
_ => {
if self.is_sampler() {
self.cxx_primitive_type_name()
} else {
None
}
}
}
}
pub fn from_glsl_primitive_type_name(name: &str) -> Option<TypeKind> {
use TypeKind::*;
Some(match name {
"void" => Void,
"bool" => Bool,
"int" => Int,
"uint" => UInt,
"float" => Float,
"double" => Double,
"vec2" => Vec2,
"vec3" => Vec3,
"vec4" => Vec4,
"dvec2" => DVec2,
"dvec3" => DVec3,
"dvec4" => DVec4,
"bvec2" => BVec2,
"bvec3" => BVec3,
"bvec4" => BVec4,
"ivec2" => IVec2,
"ivec3" => IVec3,
"ivec4" => IVec4,
"uvec2" => UVec2,
"uvec3" => UVec3,
"uvec4" => UVec4,
"mat2" => Mat2,
"mat3" => Mat3,
"mat4" => Mat4,
"mat23" => Mat23,
"mat24" => Mat24,
"mat32" => Mat32,
"mat34" => Mat34,
"mat42" => Mat42,
"mat43" => Mat43,
"dmat2" => DMat2,
"dmat3" => DMat3,
"dmat4" => DMat4,
"dmat23" => DMat23,
"dmat24" => DMat24,
"dmat32" => DMat32,
"dmat34" => DMat34,
"dmat42" => DMat42,
"dmat43" => DMat43,
"sampler1D" => Sampler1D,
"image1D" => Image1D,
"sampler2D" => Sampler2D,
"image2D" => Image2D,
"sampler3D" => Sampler3D,
"image3D" => Image3D,
"samplerCube" => SamplerCube,
"imageCube" => ImageCube,
"sampler2DRect" => Sampler2DRect,
"image2DRect" => Image2DRect,
"sampler1DArray" => Sampler1DArray,
"image1DArray" => Image1DArray,
"sampler2DArray" => Sampler2DArray,
"image2DArray" => Image2DArray,
"samplerBuffer" => SamplerBuffer,
"imageBuffer" => ImageBuffer,
"sampler2DMS" => Sampler2DMS,
"image2DMS" => Image2DMS,
"sampler2DMSArray" => Sampler2DMSArray,
"image2DMSArray" => Image2DMSArray,
"samplerCubeArray" => SamplerCubeArray,
"imageCubeArray" => ImageCubeArray,
"sampler1DShadow" => Sampler1DShadow,
"sampler2DShadow" => Sampler2DShadow,
"sampler2DRectShadow" => Sampler2DRectShadow,
"sampler1DArrayShadow" => Sampler1DArrayShadow,
"sampler2DArrayShadow" => Sampler2DArrayShadow,
"samplerCubeShadow" => SamplerCubeShadow,
"samplerCubeArrayShadow" => SamplerCubeArrayShadow,
"isampler1D" => ISampler1D,
"iimage1D" => IImage1D,
"isampler2D" => ISampler2D,
"iimage2D" => IImage2D,
"isampler3D" => ISampler3D,
"iimage3D" => IImage3D,
"isamplerCube" => ISamplerCube,
"iimageCube" => IImageCube,
"isampler2DRect" => ISampler2DRect,
"iimage2DRect" => IImage2DRect,
"isampler1DArray" => ISampler1DArray,
"iimage1DArray" => IImage1DArray,
"isampler2DArray" => ISampler2DArray,
"iimage2DArray" => IImage2DArray,
"isamplerBuffer" => ISamplerBuffer,
"iimageBuffer" => IImageBuffer,
"isampler2MS" => ISampler2DMS,
"iimage2DMS" => IImage2DMS,
"isampler2DMSArray" => ISampler2DMSArray,
"iimage2DMSArray" => IImage2DMSArray,
"isamplerCubeArray" => ISamplerCubeArray,
"iimageCubeArray" => IImageCubeArray,
"atomic_uint" => AtomicUInt,
"usampler1D" => USampler1D,
"uimage1D" => UImage1D,
"usampler2D" => USampler2D,
"uimage2D" => UImage2D,
"usampler3D" => USampler3D,
"uimage3D" => UImage3D,
"usamplerCube" => USamplerCube,
"uimageCube" => UImageCube,
"usampler2DRect" => USampler2DRect,
"uimage2DRect" => UImage2DRect,
"usampler1DArray" => USampler1DArray,
"uimage1DArray" => UImage1DArray,
"usampler2DArray" => USampler2DArray,
"uimage2DArray" => UImage2DArray,
"usamplerBuffer" => USamplerBuffer,
"uimageBuffer" => UImageBuffer,
"usampler2DMS" => USampler2DMS,
"uimage2DMS" => UImage2DMS,
"usamplerDMSArray" => USampler2DMSArray,
"uimage2DMSArray" => UImage2DMSArray,
"usamplerCubeArray" => USamplerCubeArray,
"uimageCubeArray" => UImageCubeArray,
_ => return None,
})
}
pub fn from_primitive_type_specifier(spec: &syntax::TypeSpecifierNonArray) -> Option<TypeKind> {
use TypeKind::*;
Some(match spec {
TypeSpecifierNonArray::Void => Void,
TypeSpecifierNonArray::Bool => Bool,
TypeSpecifierNonArray::Int => Int,
TypeSpecifierNonArray::UInt => UInt,
TypeSpecifierNonArray::Float => Float,
TypeSpecifierNonArray::Double => Double,
TypeSpecifierNonArray::Vec2 => Vec2,
TypeSpecifierNonArray::Vec3 => Vec3,
TypeSpecifierNonArray::Vec4 => Vec4,
TypeSpecifierNonArray::DVec2 => DVec2,
TypeSpecifierNonArray::DVec3 => DVec3,
TypeSpecifierNonArray::DVec4 => DVec4,
TypeSpecifierNonArray::BVec2 => BVec2,
TypeSpecifierNonArray::BVec3 => BVec3,
TypeSpecifierNonArray::BVec4 => BVec4,
TypeSpecifierNonArray::IVec2 => IVec2,
TypeSpecifierNonArray::IVec3 => IVec3,
TypeSpecifierNonArray::IVec4 => IVec4,
TypeSpecifierNonArray::UVec2 => UVec2,
TypeSpecifierNonArray::UVec3 => UVec3,
TypeSpecifierNonArray::UVec4 => UVec4,
TypeSpecifierNonArray::Mat2 => Mat2,
TypeSpecifierNonArray::Mat3 => Mat3,
TypeSpecifierNonArray::Mat4 => Mat4,
TypeSpecifierNonArray::Mat23 => Mat23,
TypeSpecifierNonArray::Mat24 => Mat24,
TypeSpecifierNonArray::Mat32 => Mat32,
TypeSpecifierNonArray::Mat34 => Mat34,
TypeSpecifierNonArray::Mat42 => Mat42,
TypeSpecifierNonArray::Mat43 => Mat43,
TypeSpecifierNonArray::DMat2 => DMat2,
TypeSpecifierNonArray::DMat3 => DMat3,
TypeSpecifierNonArray::DMat4 => DMat4,
TypeSpecifierNonArray::DMat23 => DMat23,
TypeSpecifierNonArray::DMat24 => DMat24,
TypeSpecifierNonArray::DMat32 => DMat32,
TypeSpecifierNonArray::DMat34 => DMat34,
TypeSpecifierNonArray::DMat42 => DMat42,
TypeSpecifierNonArray::DMat43 => DMat43,
TypeSpecifierNonArray::Sampler1D => Sampler1D,
TypeSpecifierNonArray::Image1D => Image1D,
TypeSpecifierNonArray::Sampler2D => Sampler2D,
TypeSpecifierNonArray::Image2D => Image2D,
TypeSpecifierNonArray::Sampler3D => Sampler3D,
TypeSpecifierNonArray::Image3D => Image3D,
TypeSpecifierNonArray::SamplerCube => SamplerCube,
TypeSpecifierNonArray::ImageCube => ImageCube,
TypeSpecifierNonArray::Sampler2DRect => Sampler2DRect,
TypeSpecifierNonArray::Image2DRect => Image2DRect,
TypeSpecifierNonArray::Sampler1DArray => Sampler1DArray,
TypeSpecifierNonArray::Image1DArray => Image1DArray,
TypeSpecifierNonArray::Sampler2DArray => Sampler2DArray,
TypeSpecifierNonArray::Image2DArray => Image2DArray,
TypeSpecifierNonArray::SamplerBuffer => SamplerBuffer,
TypeSpecifierNonArray::ImageBuffer => ImageBuffer,
TypeSpecifierNonArray::Sampler2DMS => Sampler2DMS,
TypeSpecifierNonArray::Image2DMS => Image2DMS,
TypeSpecifierNonArray::Sampler2DMSArray => Sampler2DMSArray,
TypeSpecifierNonArray::Image2DMSArray => Image2DMSArray,
TypeSpecifierNonArray::SamplerCubeArray => SamplerCubeArray,
TypeSpecifierNonArray::ImageCubeArray => ImageCubeArray,
TypeSpecifierNonArray::Sampler1DShadow => Sampler1DShadow,
TypeSpecifierNonArray::Sampler2DShadow => Sampler2DShadow,
TypeSpecifierNonArray::Sampler2DRectShadow => Sampler2DRectShadow,
TypeSpecifierNonArray::Sampler1DArrayShadow => Sampler1DArrayShadow,
TypeSpecifierNonArray::Sampler2DArrayShadow => Sampler2DArrayShadow,
TypeSpecifierNonArray::SamplerCubeShadow => SamplerCubeShadow,
TypeSpecifierNonArray::SamplerCubeArrayShadow => SamplerCubeArrayShadow,
TypeSpecifierNonArray::ISampler1D => ISampler1D,
TypeSpecifierNonArray::IImage1D => IImage1D,
TypeSpecifierNonArray::ISampler2D => ISampler2D,
TypeSpecifierNonArray::IImage2D => IImage2D,
TypeSpecifierNonArray::ISampler3D => ISampler3D,
TypeSpecifierNonArray::IImage3D => IImage3D,
TypeSpecifierNonArray::ISamplerCube => ISamplerCube,
TypeSpecifierNonArray::IImageCube => IImageCube,
TypeSpecifierNonArray::ISampler2DRect => ISampler2DRect,
TypeSpecifierNonArray::IImage2DRect => IImage2DRect,
TypeSpecifierNonArray::ISampler1DArray => ISampler1DArray,
TypeSpecifierNonArray::IImage1DArray => IImage1DArray,
TypeSpecifierNonArray::ISampler2DArray => ISampler2DArray,
TypeSpecifierNonArray::IImage2DArray => IImage2DArray,
TypeSpecifierNonArray::ISamplerBuffer => ISamplerBuffer,
TypeSpecifierNonArray::IImageBuffer => IImageBuffer,
TypeSpecifierNonArray::ISampler2DMS => ISampler2DMS,
TypeSpecifierNonArray::IImage2DMS => IImage2DMS,
TypeSpecifierNonArray::ISampler2DMSArray => ISampler2DMSArray,
TypeSpecifierNonArray::IImage2DMSArray => IImage2DMSArray,
TypeSpecifierNonArray::ISamplerCubeArray => ISamplerCubeArray,
TypeSpecifierNonArray::IImageCubeArray => IImageCubeArray,
TypeSpecifierNonArray::AtomicUInt => AtomicUInt,
TypeSpecifierNonArray::USampler1D => USampler1D,
TypeSpecifierNonArray::UImage1D => UImage1D,
TypeSpecifierNonArray::USampler2D => USampler2D,
TypeSpecifierNonArray::UImage2D => UImage2D,
TypeSpecifierNonArray::USampler3D => USampler3D,
TypeSpecifierNonArray::UImage3D => UImage3D,
TypeSpecifierNonArray::USamplerCube => USamplerCube,
TypeSpecifierNonArray::UImageCube => UImageCube,
TypeSpecifierNonArray::USampler2DRect => USampler2DRect,
TypeSpecifierNonArray::UImage2DRect => UImage2DRect,
TypeSpecifierNonArray::USampler1DArray => USampler1DArray,
TypeSpecifierNonArray::UImage1DArray => UImage1DArray,
TypeSpecifierNonArray::USampler2DArray => USampler2DArray,
TypeSpecifierNonArray::UImage2DArray => UImage2DArray,
TypeSpecifierNonArray::USamplerBuffer => USamplerBuffer,
TypeSpecifierNonArray::UImageBuffer => UImageBuffer,
TypeSpecifierNonArray::USampler2DMS => USampler2DMS,
TypeSpecifierNonArray::UImage2DMS => UImage2DMS,
TypeSpecifierNonArray::USampler2DMSArray => USampler2DMSArray,
TypeSpecifierNonArray::UImage2DMSArray => UImage2DMSArray,
TypeSpecifierNonArray::USamplerCubeArray => USamplerCubeArray,
TypeSpecifierNonArray::UImageCubeArray => UImageCubeArray,
TypeSpecifierNonArray::Struct(..) | TypeSpecifierNonArray::TypeName(..) => return None,
})
}
}
impl LiftFrom<&syntax::TypeSpecifierNonArray> for TypeKind {
fn lift(state: &mut State, spec: &syntax::TypeSpecifierNonArray) -> Self {
use TypeKind::*;
if let Some(kind) = TypeKind::from_primitive_type_specifier(spec) {
kind
} else {
match spec {
TypeSpecifierNonArray::Struct(s) => {
Struct(state.lookup(s.name.as_ref().unwrap().as_str()).unwrap())
}
TypeSpecifierNonArray::TypeName(s) => Struct(state.lookup(&s.0).unwrap()),
_ => unreachable!(),
}
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Type {
pub kind: TypeKind,
pub precision: Option<PrecisionQualifier>,
pub array_sizes: Option<Box<ArraySizes>>,
}
impl Type {
pub fn new(kind: TypeKind) -> Self {
Type {
kind,
precision: None,
array_sizes: None,
}
}
pub fn new_array(kind: TypeKind, size: i32) -> Self {
Type {
kind,
precision: None,
array_sizes: Some(Box::new(ArraySizes { sizes: vec![make_const(TypeKind::Int, size)] })),
}
}
}
impl LiftFrom<&syntax::FullySpecifiedType> for Type {
fn lift(state: &mut State, ty: &syntax::FullySpecifiedType) -> Self {
let kind = lift(state, &ty.ty.ty);
let array_sizes = match ty.ty.array_specifier.as_ref() {
Some(x) => Some(Box::new(lift(state, x))),
None => None,
};
let precision = get_precision(&ty.qualifier);
Type {
kind,
precision,
array_sizes,
}
}
}
impl LiftFrom<&syntax::TypeSpecifier> for Type {
fn lift(state: &mut State, ty: &syntax::TypeSpecifier) -> Self {
let kind = lift(state, &ty.ty);
let array_sizes = ty
.array_specifier
.as_ref()
.map(|x| Box::new(lift(state, x)));
Type {
kind,
precision: None,
array_sizes,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct StructField {
pub ty: Type,
pub name: syntax::Identifier,
}
fn get_precision(qualifiers: &Option<syntax::TypeQualifier>) -> Option<PrecisionQualifier> {
let mut precision = None;
for qual in qualifiers.iter().flat_map(|x| x.qualifiers.0.iter()) {
match qual {
syntax::TypeQualifierSpec::Precision(p) => {
if precision.is_some() {
panic!("Multiple precisions");
}
precision = Some(p.clone());
}
_ => {}
}
}
precision
}
impl LiftFrom<&StructFieldSpecifier> for StructField {
fn lift(state: &mut State, f: &StructFieldSpecifier) -> Self {
let mut ty: Type = lift(state, &f.ty);
match &f.identifiers.0[..] {
[ident] => {
if let Some(a) = &ident.array_spec {
ty.array_sizes = Some(Box::new(lift(state, a)));
}
StructField {
ty,
name: ident.ident.clone(),
}
}
_ => panic!("bad number of identifiers"),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct StructFields {
pub fields: Vec<StructField>,
}
impl LiftFrom<&StructSpecifier> for StructFields {
fn lift(state: &mut State, s: &StructSpecifier) -> Self {
let fields = s.fields.0.iter().map(|field| lift(state, field)).collect();
Self { fields }
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum RunClass {
Unknown,
Scalar,
Vector,
Dependent(u32),
}
impl RunClass {
pub fn merge(self, run_class: RunClass) -> RunClass {
match (self, run_class) {
(RunClass::Vector, _) | (_, RunClass::Vector) => RunClass::Vector,
(RunClass::Dependent(x), RunClass::Dependent(y)) => RunClass::Dependent(x | y),
(RunClass::Unknown, _) | (_, RunClass::Dependent(..)) => run_class,
_ => self,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum SymDecl {
NativeFunction(FunctionType, Option<&'static str>, RunClass),
UserFunction(Rc<FunctionDefinition>, RunClass),
Local(StorageClass, Type, RunClass),
Global(
StorageClass,
Option<syntax::InterpolationQualifier>,
Type,
RunClass,
),
Struct(StructFields),
}
#[derive(Clone, Debug, PartialEq, Copy, Eq, Hash)]
pub struct SymRef(u32);
#[derive(Debug)]
struct Scope {
// The field is not actively used but useful for `Debug`.
#[allow(dead_code)]
name: String,
names: HashMap<String, SymRef>,
}
impl Scope {
fn new(name: String) -> Self {
Scope {
name,
names: HashMap::new(),
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct TexelFetchOffsets {
pub min_x: i32,
pub max_x: i32,
pub min_y: i32,
pub max_y: i32,
}
impl TexelFetchOffsets {
fn new(x: i32, y: i32) -> Self {
TexelFetchOffsets {
min_x: x,
max_x: x,
min_y: y,
max_y: y,
}
}
fn add_offset(&mut self, x: i32, y: i32) {
self.min_x = self.min_x.min(x);
self.max_x = self.max_x.max(x);
self.min_y = self.min_y.min(y);
self.max_y = self.max_y.max(y);
}
}
#[derive(Debug)]
pub struct State {
scopes: Vec<Scope>,
syms: Vec<RefCell<Symbol>>,
in_function: Option<SymRef>,
run_class_changed: Cell<bool>,
last_declaration: SymRef,
branch_run_class: RunClass,
branch_declaration: SymRef,
modified_globals: RefCell<Vec<SymRef>>,
pub used_globals: RefCell<Vec<SymRef>>,
pub texel_fetches: HashMap<(SymRef, SymRef), TexelFetchOffsets>,
clip_dist_sym: SymRef,
pub used_clip_dist: u32,
}
impl State {
pub fn new() -> Self {
State {
scopes: Vec::new(),
syms: Vec::new(),
in_function: None,
run_class_changed: Cell::new(false),
last_declaration: SymRef(0),
branch_run_class: RunClass::Unknown,
branch_declaration: SymRef(0),
modified_globals: RefCell::new(Vec::new()),
used_globals: RefCell::new(Vec::new()),
texel_fetches: HashMap::new(),
clip_dist_sym: SymRef(0),
used_clip_dist: 0,
}
}
pub fn lookup(&self, name: &str) -> Option<SymRef> {
for s in self.scopes.iter().rev() {
if let Some(sym) = s.names.get(name) {
return Some(*sym);
}
}
return None;
}
fn declare(&mut self, name: &str, decl: SymDecl) -> SymRef {
let s = SymRef(self.syms.len() as u32);
self.syms.push(RefCell::new(Symbol {
name: name.into(),
decl,
}));
self.scopes.last_mut().unwrap().names.insert(name.into(), s);
s
}
pub fn sym(&self, sym: SymRef) -> Ref<Symbol> {
self.syms[sym.0 as usize].borrow()
}
pub fn sym_mut(&mut self, sym: SymRef) -> &mut Symbol {
self.syms[sym.0 as usize].get_mut()
}
pub fn lookup_sym_mut(&mut self, name: &str) -> Option<&mut Symbol> {
self.lookup(name)
.map(move |x| self.syms[x.0 as usize].get_mut())
}
fn push_scope(&mut self, name: String) {
self.scopes.push(Scope::new(name));
}
fn pop_scope(&mut self) {
self.scopes.pop();
}
fn return_run_class(&self, mut new_run_class: RunClass) {
new_run_class = self.branch_run_class.merge(new_run_class);
if let Some(sym) = self.in_function {
let mut b = self.syms[sym.0 as usize].borrow_mut();
if let SymDecl::UserFunction(_, ref mut run_class) = b.decl {
*run_class = run_class.merge(new_run_class);
}
}
}
pub fn function_definition(&self, name: SymRef) -> Option<(Rc<FunctionDefinition>, RunClass)> {
if let SymDecl::UserFunction(ref fd, ref run_class) = &self.sym(name).decl {
Some((fd.clone(), *run_class))
} else {
None
}
}
fn merge_run_class(&self, sym: SymRef, mut new_run_class: RunClass) -> RunClass {
if sym.0 <= self.branch_declaration.0 {
new_run_class = self.branch_run_class.merge(new_run_class);
}
let mut b = self.syms[sym.0 as usize].borrow_mut();
let mut old_run_class = new_run_class;
if let SymDecl::Local(_, _, ref mut run_class) = b.decl {
old_run_class = *run_class;
new_run_class = old_run_class.merge(new_run_class);
*run_class = new_run_class;
}
if old_run_class != RunClass::Unknown && old_run_class != new_run_class {
self.run_class_changed.set(true);
}
new_run_class
}
}
/// A declaration.
#[derive(Clone, Debug, PartialEq)]
pub enum Declaration {
FunctionPrototype(FunctionPrototype),
StructDefinition(SymRef),
InitDeclaratorList(InitDeclaratorList),
Precision(PrecisionQualifier, TypeSpecifier),
Block(Block),
Global(TypeQualifier, Vec<Identifier>),
}
/// A general purpose block, containing fields and possibly a list of declared identifiers. Semantic
/// is given with the storage qualifier.
#[derive(Clone, Debug, PartialEq)]
pub struct Block {
pub qualifier: TypeQualifier,
pub name: Identifier,
pub fields: Vec<StructFieldSpecifier>,
pub identifier: Option<ArrayedIdentifier>,
}
/// Function identifier.
#[derive(Clone, Debug, PartialEq)]
pub enum FunIdentifier {
Identifier(SymRef),
Constructor(Type),
}
/// Function prototype.
#[derive(Clone, Debug, PartialEq)]
pub struct FunctionPrototype {
pub ty: Type,
pub name: Identifier,
pub parameters: Vec<FunctionParameterDeclaration>,
}
impl FunctionPrototype {
pub fn has_parameter(&self, sym: SymRef) -> bool {
for param in &self.parameters {
match param {
FunctionParameterDeclaration::Named(_, ref d) => {
if d.sym == sym {
return true;
}
}
_ => {}
}
}
false
}
}
/// Function parameter declaration.
#[derive(Clone, Debug, PartialEq)]
pub enum FunctionParameterDeclaration {
Named(Option<ParameterQualifier>, FunctionParameterDeclarator),
Unnamed(Option<ParameterQualifier>, TypeSpecifier),
}
/// Function parameter declarator.
#[derive(Clone, Debug, PartialEq)]
pub struct FunctionParameterDeclarator {
pub ty: Type,
pub name: Identifier,
pub sym: SymRef,
}
/// Init declarator list.
#[derive(Clone, Debug, PartialEq)]
pub struct InitDeclaratorList {
// XXX it feels like separating out the type and the names is better than
// head and tail
// Also, it might be nice to separate out type definitions from name definitions
pub head: SingleDeclaration,
pub tail: Vec<SingleDeclarationNoType>,
}
/// Type qualifier.
#[derive(Clone, Debug, PartialEq)]
pub struct TypeQualifier {
pub qualifiers: NonEmpty<TypeQualifierSpec>,
}
fn lift_type_qualifier_for_declaration(
_state: &mut State,
q: &Option<syntax::TypeQualifier>,
) -> Option<TypeQualifier> {
q.as_ref().and_then(|x| {
NonEmpty::from_non_empty_iter(x.qualifiers.0.iter().flat_map(|x| match x {
syntax::TypeQualifierSpec::Precision(_) => None,
syntax::TypeQualifierSpec::Interpolation(_) => None,
syntax::TypeQualifierSpec::Invariant => Some(TypeQualifierSpec::Invariant),
syntax::TypeQualifierSpec::Layout(l) => Some(TypeQualifierSpec::Layout(l.clone())),
syntax::TypeQualifierSpec::Precise => Some(TypeQualifierSpec::Precise),
syntax::TypeQualifierSpec::Storage(_) => None,
}))
.map(|x| TypeQualifier { qualifiers: x })
})
}
fn lift_type_qualifier_for_parameter(
_state: &mut State,
q: &Option<syntax::TypeQualifier>,
) -> Option<ParameterQualifier> {
let mut qp: Option<ParameterQualifier> = None;
if let Some(q) = q {
for x in &q.qualifiers.0 {
match (&qp, x) {
(None, syntax::TypeQualifierSpec::Storage(s)) => match s {
syntax::StorageQualifier::Const => qp = Some(ParameterQualifier::Const),
syntax::StorageQualifier::In => qp = Some(ParameterQualifier::In),
syntax::StorageQualifier::Out => qp = Some(ParameterQualifier::Out),
syntax::StorageQualifier::InOut => qp = Some(ParameterQualifier::InOut),
_ => panic!("Bad storage qualifier for parameter"),
},
(_, syntax::TypeQualifierSpec::Precision(_)) => {}
_ => panic!("Bad parameter qualifier {:?}", x),
}
}
}
qp
}
#[derive(Clone, Debug, PartialEq)]
pub enum ParameterQualifier {
Const,
In,
InOut,
Out,
}
#[derive(Clone, Debug, PartialEq)]
pub enum MemoryQualifier {
Coherent,
Volatile,
Restrict,
ReadOnly,
WriteOnly,
}
/// Type qualifier spec.
#[derive(Clone, Debug, PartialEq)]
pub enum TypeQualifierSpec {
Layout(syntax::LayoutQualifier),
Invariant,
Parameter(ParameterQualifier),
Memory(MemoryQualifier),
Precise,
}
/// Single declaration.
#[derive(Clone, Debug, PartialEq)]
pub struct SingleDeclaration {
pub ty: Type,
pub ty_def: Option<SymRef>,
pub qualifier: Option<TypeQualifier>,
pub name: SymRef,
pub initializer: Option<Initializer>,
}
/// A single declaration with implicit, already-defined type.
#[derive(Clone, Debug, PartialEq)]
pub struct SingleDeclarationNoType {
pub ident: ArrayedIdentifier,
pub initializer: Option<Initializer>,
}
/// 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 struct Expr {
pub kind: ExprKind,
pub ty: Type,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum FieldSet {
Rgba,
Xyzw,
Stpq,
}
#[derive(Clone, Debug, PartialEq)]
pub struct SwizzleSelector {
pub field_set: FieldSet,
pub components: Vec<i8>,
}
impl SwizzleSelector {
fn parse(s: &str) -> Self {
let mut components = Vec::new();
let mut field_set = Vec::new();
for c in s.chars() {
match c {
'r' => {
components.push(0);
field_set.push(FieldSet::Rgba);
}
'x' => {
components.push(0);
field_set.push(FieldSet::Xyzw);
}
's' => {
components.push(0);
field_set.push(FieldSet::Stpq);
}
'g' => {
components.push(1);
field_set.push(FieldSet::Rgba);
}
'y' => {
components.push(1);
field_set.push(FieldSet::Xyzw);
}
't' => {
components.push(1);
field_set.push(FieldSet::Stpq);
}
'b' => {
components.push(2);
field_set.push(FieldSet::Rgba);
}
'z' => {
components.push(2);
field_set.push(FieldSet::Xyzw);
}
'p' => {
components.push(2);
field_set.push(FieldSet::Stpq);
}
'a' => {
components.push(3);
field_set.push(FieldSet::Rgba);
}
'w' => {
components.push(3);
field_set.push(FieldSet::Xyzw);
}
'q' => {
components.push(3);
field_set.push(FieldSet::Stpq);
}
_ => panic!("bad selector"),
}
}
let first = &field_set[0];
assert!(field_set.iter().all(|item| item == first));
assert!(components.len() <= 4);
SwizzleSelector {
field_set: first.clone(),
components,
}
}
pub fn to_field_set(&self, field_set: FieldSet) -> String {
let mut s = String::new();
let fs = match field_set {
FieldSet::Rgba => ['r', 'g', 'b', 'a'],
FieldSet::Xyzw => ['x', 'y', 'z', 'w'],
FieldSet::Stpq => ['s', 't', 'p', 'q'],
};
for i in &self.components {
s.push(fs[*i as usize])
}
s
}
pub fn to_string(&self) -> String {
self.to_field_set(self.field_set)
}
}
/// The most general form of an expression. As you can see if you read the variant list, in GLSL, an
/// assignment is an expression. This is a bit silly but think of an assignment as a statement first
/// then an expression which evaluates to what the statement “returns”.
///
/// An expression is either an assignment or a list (comma) of assignments.
#[derive(Clone, Debug, PartialEq)]
pub enum ExprKind {
/// A variable expression, using an identifier.
Variable(SymRef),
/// Integral constant expression.
IntConst(i32),
/// Unsigned integral constant expression.
UIntConst(u32),
/// Boolean constant expression.
BoolConst(bool),
/// Single precision floating expression.
FloatConst(f32),
/// Double precision floating expression.
DoubleConst(f64),
/// A unary expression, gathering a single expression and a unary operator.
Unary(UnaryOp, Box<Expr>),
/// A binary expression, gathering two expressions and a binary operator.
Binary(BinaryOp, Box<Expr>, Box<Expr>),
/// A ternary conditional expression, gathering three expressions.
Ternary(Box<Expr>, Box<Expr>, Box<Expr>),
/// An assignment is also an expression. Gathers an expression that defines what to assign to, an
/// assignment operator and the value to associate with.
Assignment(Box<Expr>, AssignmentOp, Box<Expr>),
/// Add an array specifier to an expression.
Bracket(Box<Expr>, Vec<Expr>),
/// A functional call. It has a function identifier and a list of expressions (arguments).
FunCall(FunIdentifier, Vec<Expr>),
/// An expression associated with a field selection (struct).
Dot(Box<Expr>, Identifier),
/// An expression associated with a component selection
SwizzleSelector(Box<Expr>, SwizzleSelector),
/// Post-incrementation of an expression.
PostInc(Box<Expr>),
/// Post-decrementation of an expression.
PostDec(Box<Expr>),
/// An expression that contains several, separated with comma.
Comma(Box<Expr>, Box<Expr>),
/// A temporary condition variable
Cond(usize, Box<Expr>),
CondMask,
}
/*
impl From<i32> for Expr {
fn from(x: i32) -> Expr {
ExprKind::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)
}
}
*/
/// Starting rule.
#[derive(Clone, Debug, PartialEq)]
pub struct TranslationUnit(pub NonEmpty<ExternalDeclaration>);
impl TranslationUnit {
/// Construct a translation unit from an iterator.
///
/// # Errors
///
/// `None` if the iterator yields no value.
pub fn from_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()
}
}
/// External declaration.
#[derive(Clone, Debug, PartialEq)]
pub enum ExternalDeclaration {
Preprocessor(syntax::Preprocessor),
FunctionDefinition(Rc<FunctionDefinition>),
Declaration(Declaration),
}
/// Function definition.
#[derive(Clone, Debug, PartialEq)]
pub struct FunctionDefinition {
pub prototype: FunctionPrototype,
pub body: CompoundStatement,
pub globals: Vec<SymRef>,
pub texel_fetches: HashMap<(SymRef, SymRef), TexelFetchOffsets>,
}
/// Compound statement (with no new scope).
#[derive(Clone, Debug, PartialEq)]
pub struct CompoundStatement {
pub statement_list: Vec<Statement>,
}
impl CompoundStatement {
pub fn new() -> Self {
CompoundStatement {
statement_list: Vec::new(),
}
}
}
impl FromIterator<Statement> for CompoundStatement {
fn from_iter<T>(iter: T) -> Self
where
T: IntoIterator<Item = Statement>,
{
CompoundStatement {
statement_list: iter.into_iter().collect(),
}
}
}
/// Statement.
#[derive(Clone, Debug, PartialEq)]
pub enum Statement {
Compound(Box<CompoundStatement>),
Simple(Box<SimpleStatement>),
}
/// Simple statement.
#[derive(Clone, Debug, PartialEq)]
pub enum SimpleStatement {
Declaration(Declaration),
Expression(ExprStatement),
Selection(SelectionStatement),
Switch(SwitchStatement),
Iteration(IterationStatement),
Jump(JumpStatement),
}
impl SimpleStatement {
/// Create a new expression statement.
pub fn new_expr<E>(expr: E) -> Self
where
E: Into<Expr>,
{
SimpleStatement::Expression(Some(expr.into()))
}
/// Create a new selection statement (if / else).
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()),
body: Box::new(truee.into()),
else_stmt: Some(Box::new(falsee.into())),
})
}
/// Create a new while statement.
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()),
))
}
/// Create a new do-while statement.
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()),
))
}
}
/// Expression statement.
pub type ExprStatement = Option<Expr>;
/// Selection statement.
#[derive(Clone, Debug, PartialEq)]
pub struct SelectionStatement {
pub cond: Box<Expr>,
pub body: Box<Statement>,
// the else branch
pub else_stmt: Option<Box<Statement>>,
}
/// Condition.
#[derive(Clone, Debug, PartialEq)]
pub enum Condition {
Expr(Box<Expr>),
}
impl From<Expr> for Condition {
fn from(expr: Expr) -> Self {
Condition::Expr(Box::new(expr))
}
}
/// Switch statement.
#[derive(Clone, Debug, PartialEq)]
pub struct SwitchStatement {
pub head: Box<Expr>,
pub cases: Vec<Case>,
}
/// Case label statement.
#[derive(Clone, Debug, PartialEq)]
pub enum CaseLabel {
Case(Box<Expr>),
Def,
}
/// An individual case
#[derive(Clone, Debug, PartialEq)]
pub struct Case {
pub label: CaseLabel,
pub stmts: Vec<Statement>,
}
/// Iteration statement.
#[derive(Clone, Debug, PartialEq)]
pub enum IterationStatement {
While(Condition, Box<Statement>),
DoWhile(Box<Statement>, Box<Expr>),
For(ForInitStatement, ForRestStatement, Box<Statement>),
}
/// For init statement.
#[derive(Clone, Debug, PartialEq)]
pub enum ForInitStatement {
Expression(Option<Expr>),
Declaration(Box<Declaration>),
}
/// For init statement.
#[derive(Clone, Debug, PartialEq)]
pub struct ForRestStatement {
pub condition: Option<Condition>,
pub post_expr: Option<Box<Expr>>,
}
/// Jump statement.
#[derive(Clone, Debug, PartialEq)]
pub enum JumpStatement {
Continue,
Break,
Return(Option<Box<Expr>>),
Discard,
}
trait NonEmptyExt<T> {
fn map<U, F: FnMut(&mut State, &T) -> U>(&self, s: &mut State, f: F) -> NonEmpty<U>;
fn new(x: T) -> NonEmpty<T>;
}
impl<T> NonEmptyExt<T> for NonEmpty<T> {
fn map<U, F: FnMut(&mut State, &T) -> U>(&self, s: &mut State, mut f: F) -> NonEmpty<U> {
NonEmpty::from_non_empty_iter(self.into_iter().map(|x| f(s, &x))).unwrap()
}
fn new(x: T) -> NonEmpty<T> {
NonEmpty::from_non_empty_iter(vec![x].into_iter()).unwrap()
}
}
fn translate_initializater(state: &mut State, i: &syntax::Initializer) -> Initializer {
match i {
syntax::Initializer::Simple(i) => {
Initializer::Simple(Box::new(translate_expression(state, i)))
}
_ => panic!(),
}
}
fn translate_struct_declaration(state: &mut State, d: &syntax::SingleDeclaration) -> Declaration {
let ty = d.ty.clone();
let ty_def = match &ty.ty.ty {
TypeSpecifierNonArray::Struct(s) => {
let decl = SymDecl::Struct(lift(state, s));
Some(state.declare(s.name.as_ref().unwrap().as_str(), decl))
}
_ => None,
};
let ty_def = ty_def.expect("Must be type definition");
Declaration::StructDefinition(ty_def)
}
fn get_expr_index(e: &syntax::Expr) -> i32 {
match e {
syntax::Expr::IntConst(i) => *i,
syntax::Expr::UIntConst(u) => *u as i32,
syntax::Expr::FloatConst(f) => *f as i32,
syntax::Expr::DoubleConst(f) => *f as i32,
_ => panic!(),
}
}
fn translate_variable_declaration(
state: &mut State,
d: &syntax::InitDeclaratorList,
default_run_class: RunClass,
) -> Declaration {
let mut ty = d.head.ty.clone();
ty.ty.array_specifier = d.head.array_specifier.clone();
let ty_def = match &ty.ty.ty {
TypeSpecifierNonArray::Struct(s) => {
let decl = SymDecl::Struct(lift(state, s));
Some(state.declare(s.name.as_ref().unwrap().as_str(), decl))
}
_ => None,
};
let mut ty: Type = lift(state, &d.head.ty);
if let Some(array) = &d.head.array_specifier {
ty.array_sizes = Some(Box::new(lift(state, array)))
}
let (sym, decl) = match d.head.name.as_ref() {
Some(name) => {
let mut storage = StorageClass::None;
let mut interpolation = None;
for qual in d
.head
.ty
.qualifier
.iter()
.flat_map(|x| x.qualifiers.0.iter())
{
match qual {
syntax::TypeQualifierSpec::Storage(s) => match (&storage, s) {
(StorageClass::FragColor(..), syntax::StorageQualifier::Out) => {}
(StorageClass::Sampler(..), syntax::StorageQualifier::Uniform) => {}
(StorageClass::None, syntax::StorageQualifier::Out) => {
storage = StorageClass::Out;
}
(StorageClass::None, syntax::StorageQualifier::In) => {
storage = StorageClass::In;
}
(StorageClass::None, syntax::StorageQualifier::Uniform) => {
if ty.kind.is_sampler() {
storage = StorageClass::Sampler(SamplerFormat::Unknown);
} else {
storage = StorageClass::Uniform;
}
}
(StorageClass::None, syntax::StorageQualifier::Const) => {
storage = StorageClass::Const;
}
_ => panic!("bad storage {:?}", (storage, s)),
},
syntax::TypeQualifierSpec::Interpolation(i) => match (&interpolation, i) {
(None, i) => interpolation = Some(i.clone()),
_ => panic!("multiple interpolation"),
},
syntax::TypeQualifierSpec::Layout(l) => {
let mut loc = -1;
let mut index = -1;
for id in &l.ids {
match id {
syntax::LayoutQualifierSpec::Identifier(ref key, None) => {
match key.as_str() {
"rgba8" => {
storage = StorageClass::Sampler(SamplerFormat::RGBA8);
}
"rgba32f" => {
storage = StorageClass::Sampler(SamplerFormat::RGBA32F);
}
"rgba32i" => {
storage = StorageClass::Sampler(SamplerFormat::RGBA32I);
}
"r8" => {
storage = StorageClass::Sampler(SamplerFormat::R8);
}
"rg8" => {
storage = StorageClass::Sampler(SamplerFormat::RG8);
}
_ => {}
}
}
syntax::LayoutQualifierSpec::Identifier(ref key, Some(ref e)) => {
match key.as_str() {
"location" => {
loc = get_expr_index(e);
}
"index" => {
index = get_expr_index(e);
}
_ => {}
}
}
_ => {}
}
}
if index >= 0 {
assert!(loc == 0);
assert!(index <= 1);
assert!(storage == StorageClass::None);
storage = StorageClass::FragColor(index);
}
}
_ => {}
}
}
let decl = if state.in_function.is_some() {
let run_class = match storage {
StorageClass::Const => RunClass::Scalar,
StorageClass::None => default_run_class,
_ => panic!("bad local storage {:?}", storage),
};
SymDecl::Local(storage, ty.clone(), run_class)
} else {
let run_class = match storage {
StorageClass::Const | StorageClass::Uniform | StorageClass::Sampler(..) => {
RunClass::Scalar
}
StorageClass::In | StorageClass::Out | StorageClass::FragColor(..)
if interpolation == Some(syntax::InterpolationQualifier::Flat) =>
{
RunClass::Scalar
}
_ => RunClass::Vector,
};
SymDecl::Global(storage, interpolation, ty.clone(), run_class)
};
(state.declare(name.as_str(), decl.clone()), decl)
}
None => panic!(),
};
let head = SingleDeclaration {
qualifier: lift_type_qualifier_for_declaration(state, &d.head.ty.qualifier),
name: sym,
ty,
ty_def,
initializer: d
.head
.initializer
.as_ref()
.map(|x| translate_initializater(state, x)),
};
let tail = d
.tail
.iter()
.map(|d| {
if let Some(_array) = &d.ident.array_spec {
panic!("unhandled array")
}
state.declare(d.ident.ident.as_str(), decl.clone());
SingleDeclarationNoType {
ident: d.ident.clone(),
initializer: d
.initializer
.as_ref()
.map(|x| translate_initializater(state, x)),
}
})
.collect();
Declaration::InitDeclaratorList(InitDeclaratorList { head, tail })
}
fn translate_init_declarator_list(
state: &mut State,
l: &syntax::InitDeclaratorList,
default_run_class: RunClass,
) -> Declaration {
match &l.head.name {
Some(_name) => translate_variable_declaration(state, l, default_run_class),
None => translate_struct_declaration(state, &l.head),
}
}
fn translate_declaration(
state: &mut State,
d: &syntax::Declaration,
default_run_class: RunClass,
) -> Declaration {
match d {
syntax::Declaration::Block(_) => panic!(), //Declaration::Block(..),
syntax::Declaration::FunctionPrototype(p) => {
Declaration::FunctionPrototype(translate_function_prototype(state, p))
}
syntax::Declaration::Global(ty, ids) => {
// glsl non-es supports requalifying variables, but we don't yet.
// However, we still want to allow global layout qualifiers for
// KHR_advanced_blend_equation.
if !ids.is_empty() {
panic!();
}
let _ = for qual in &ty.qualifiers {
match qual {
syntax::TypeQualifierSpec::Layout(l) => {
for id in &l.ids {
match id {
syntax::LayoutQualifierSpec::Identifier(key, _) => {
match key.as_str() {
"blend_support_all_equations" => (),
_ => panic!(),
}
}
_ => panic!(),
}
}
}
syntax::TypeQualifierSpec::Storage(syntax::StorageQualifier::Out) => (),
_ => panic!(),
}
};
Declaration::Global(lift_type_qualifier_for_declaration(state, &Some(ty.clone())).unwrap(), ids.clone())
}
syntax::Declaration::InitDeclaratorList(dl) => {
translate_init_declarator_list(state, dl, default_run_class)
}
syntax::Declaration::Precision(p, ts) => Declaration::Precision(p.clone(), ts.clone()),
}
}
fn is_vector(ty: &Type) -> bool {
match ty.kind {
TypeKind::Vec2
| TypeKind::Vec3
| TypeKind::Vec4
| TypeKind::BVec2
| TypeKind::BVec3
| TypeKind::BVec4
| TypeKind::IVec2
| TypeKind::IVec3
| TypeKind::IVec4 => ty.array_sizes == None,
_ => false,
}
}
fn index_vector(ty: &Type) -> Option<TypeKind> {
use TypeKind::*;
if ty.array_sizes != None {
return None;
}
Some(match ty.kind {
Vec2 => Float,
Vec3 => Float,
Vec4 => Float,
DVec2 => Double,
DVec3 => Double,
DVec4 => Double,
BVec2 => Bool,
BVec3 => Bool,
BVec4 => Bool,
IVec2 => Int,
IVec3 => Int,
IVec4 => Int,
UVec2 => UInt,
UVec3 => UInt,
UVec4 => UInt,
_ => return None,
})
}
fn index_matrix(ty: &Type) -> Option<TypeKind> {
use TypeKind::*;
if ty.array_sizes != None {
return None;
}
Some(match ty.kind {
Mat2 => Vec2,
Mat3 => Vec3,
Mat4 => Vec4,
Mat23 => Vec3,
Mat24 => Vec4,
Mat32 => Vec2,
Mat34 => Vec4,
Mat42 => Vec2,
Mat43 => Vec3,
DMat2 => DVec2,
DMat3 => DVec3,
DMat4 => DVec4,
DMat23 => DVec3,
DMat24 => DVec4,
DMat32 => DVec2,
DMat34 => DVec4,
DMat42 => DVec2,
DMat43 => DVec3,
_ => return None,
})
}
fn is_ivec(ty: &Type) -> bool {
match ty.kind {
TypeKind::IVec2 | TypeKind::IVec3 | TypeKind::IVec4 => ty.array_sizes == None,
_ => false,
}
}
fn can_implicitly_convert_to(src: &Type, dst: &Type) -> bool {
// XXX: use an underlying type helper
if src == &Type::new(TypeKind::Double) && dst == &Type::new(TypeKind::Float) {
// We're not supposed to implicitly convert from double to float but glsl 4 has a bug
// where it parses unannotated float constants as double.
true
} else if dst == &Type::new(TypeKind::Double) && src == &Type::new(TypeKind::Float) {
true
} else if (dst == &Type::new(TypeKind::Float) || dst == &Type::new(TypeKind::Double)) &&
src == &Type::new(TypeKind::Int)
{
true
} else if (dst == &Type::new(TypeKind::Vec2) || dst == &Type::new(TypeKind::DVec2)) &&
src == &Type::new(TypeKind::IVec2)
{
true
} else if dst == &Type::new(TypeKind::IVec2) &&
(src == &Type::new(TypeKind::Vec2) || src == &Type::new(TypeKind::DVec2))
{
true
} else {
src.kind == dst.kind && src.array_sizes == dst.array_sizes
}
}
fn promoted_type(lhs: &Type, rhs: &Type) -> Type {
if lhs == &Type::new(TypeKind::Double) && rhs == &Type::new(TypeKind::Float) {
Type::new(TypeKind::Double)
} else if lhs == &Type::new(TypeKind::Float) && rhs == &Type::new(TypeKind::Double) {
Type::new(TypeKind::Double)
} else if lhs == &Type::new(TypeKind::Int) && rhs == &Type::new(TypeKind::Double) {
Type::new(TypeKind::Double)
} else if is_vector(&lhs) &&
(rhs == &Type::new(TypeKind::Float) ||
rhs == &Type::new(TypeKind::Double) ||
rhs == &Type::new(TypeKind::Int))
{
// scalars promote to vectors
lhs.clone()
} else if is_vector(&rhs) &&
(lhs == &Type::new(TypeKind::Float) ||
lhs == &Type::new(TypeKind::Double) ||
lhs == &Type::new(TypeKind::Int))
{
// scalars promote to vectors
rhs.clone()
} else if lhs == rhs {
lhs.clone()
} else if lhs.kind == rhs.kind {
if lhs.array_sizes == rhs.array_sizes {
// XXX: we need to be able to query the default precision here
match (&lhs.precision, &rhs.precision) {
(Some(PrecisionQualifier::High), _) => lhs.clone(),
(_, Some(PrecisionQualifier::High)) => rhs.clone(),
(None, _) => lhs.clone(),
(_, None) => rhs.clone(),
_ => panic!("precision mismatch {:?} {:?}", lhs.precision, rhs.precision),
}
} else {
panic!("array size mismatch")
}
} else {
assert_eq!(lhs, rhs);
lhs.clone()
}
}
pub fn is_output(expr: &Expr, state: &State) -> Option<SymRef> {
match &expr.kind {
ExprKind::Variable(i) => match state.sym(*i).decl {
SymDecl::Global(storage, ..) => match storage {
StorageClass::In | StorageClass::Out => return Some(*i),
_ => {}
},
SymDecl::Local(..) => {}
_ => panic!("should be variable"),
},
ExprKind::SwizzleSelector(e, ..) => {
return is_output(e, state);
}
ExprKind::Bracket(e, ..) => {
return is_output(e, state);
}
ExprKind::Dot(e, ..) => {
return is_output(e, state);
}
_ => {}
};
None
}
pub fn get_texel_fetch_offset(
state: &State,
sampler_expr: &Expr,
uv_expr: &Expr,
offset_expr: &Expr,
) -> Option<(SymRef, SymRef, i32, i32)> {
if let ExprKind::Variable(ref sampler) = &sampler_expr.kind {
//if let ExprKind::Binary(BinaryOp::Add, ref lhs, ref rhs) = &uv_expr.kind {
if let ExprKind::Variable(ref base) = &uv_expr.kind {
if let ExprKind::FunCall(ref fun, ref args) = &offset_expr.kind {
if let FunIdentifier::Identifier(ref offset) = fun {
if state.sym(*offset).name == "ivec2" {
if let ExprKind::IntConst(ref x) = &args[0].kind {
if let ExprKind::IntConst(ref y) = &args[1].kind {
return Some((*sampler, *base, *x, *y));
}
}
}
}
}
}
//}
}
None
}
fn make_const(t: TypeKind, v: i32) -> Expr {
Expr {
kind: match t {
TypeKind::Int => ExprKind::IntConst(v as _),
TypeKind::UInt => ExprKind::UIntConst(v as _),
TypeKind::Bool => ExprKind::BoolConst(v != 0),
TypeKind::Float => ExprKind::FloatConst(v as _),
TypeKind::Double => ExprKind::DoubleConst(v as _),
_ => panic!("bad constant type"),
},
ty: Type::new(t),
}
}
// Any parameters needing to convert to bool should just compare via != 0.
// This ensures they get the proper all-1s pattern for C++ OpenCL vectors.
fn force_params_to_bool(_state: &mut State, params: &mut Vec<Expr>) {
for e in params {
if !e.ty.kind.is_bool() {
let k = e.ty.kind;
*e = Expr {
kind: ExprKind::Binary(
BinaryOp::NonEqual,
Box::new(e.clone()),
Box::new(make_const(k.to_scalar(), 0)),
),
ty: Type::new(k.to_bool()),
};
}
}
}
// Transform bool params to int, then mask off the low bit so they become 0 or 1.
// C++ OpenCL vectors represent bool as all-1s patterns, which will erroneously
// convert to -1 otherwise.
fn force_params_from_bool(state: &mut State, params: &mut Vec<Expr>) {
for e in params {
if e.ty.kind.is_bool() {
let k = e.ty.kind.to_int();
let sym = state.lookup(k.glsl_primitive_type_name().unwrap()).unwrap();
*e = Expr {
kind: ExprKind::Binary(
BinaryOp::BitAnd,
Box::new(Expr {
kind: ExprKind::FunCall(
FunIdentifier::Identifier(sym),
vec![e.clone()],
),
ty: Type::new(k),
}),
Box::new(make_const(TypeKind::Int, 1)),
),
ty: Type::new(k),
};
}
}
}
fn translate_expression(state: &mut State, e: &syntax::Expr) -> Expr {
match e {
syntax::Expr::Variable(i) => {
let sym = match state.lookup(i.as_str()) {
Some(sym) => sym,
None => panic!("missing declaration {}", i.as_str()),
};
let ty = match &state.sym(sym).decl {
SymDecl::Global(_, _, ty, _) => {
let mut globals = state.used_globals.borrow_mut();
if !globals.contains(&sym) {
globals.push(sym);
}
ty.clone()
}
SymDecl::Local(_, ty, _) => ty.clone(),
_ => panic!("bad variable type"),
};
Expr {
kind: ExprKind::Variable(sym),
ty,
}
}
syntax::Expr::Assignment(lhs, op, rhs) => {
let lhs = Box::new(translate_expression(state, lhs));
let rhs = Box::new(translate_expression(state, rhs));
let ty = if op == &AssignmentOp::Mult {
if lhs.ty.kind == TypeKind::Vec4 && rhs.ty.kind == TypeKind::Float {
lhs.ty.clone()
} else {
promoted_type(&lhs.ty, &rhs.ty)
}
} else {
promoted_type(&lhs.ty, &rhs.ty)
};
if let Some(global) = is_output(&lhs, state) {
let mut globals = state.modified_globals.borrow_mut();
if !globals.contains(&global) {
globals.push(global);
}
if global == state.clip_dist_sym {
if let ExprKind::Bracket(_, idx) = &lhs.kind {
// Get the constant array index used for gl_ClipDistance and add it to the used mask.
for dimension in idx {
let idx = match dimension.kind {
ExprKind::IntConst(idx) => idx,
ExprKind::UIntConst(idx) => idx as i32,
_ => panic!("bad index for gl_ClipDistance"),
};
assert!(idx >= 0 && idx < 4);
state.used_clip_dist |= 1 << idx;
}
}
}
}
Expr {
kind: ExprKind::Assignment(lhs, op.clone(), rhs),
ty,
}
}
syntax::Expr::Binary(op, lhs, rhs) => {
let lhs = Box::new(translate_expression(state, lhs));
let rhs = Box::new(translate_expression(state, rhs));
let ty = match op {
BinaryOp::Equal | BinaryOp::NonEqual | BinaryOp::GT | BinaryOp::GTE | BinaryOp::LT | BinaryOp::LTE => {
// comparison operators have a bool result
Type::new(TypeKind::Bool)
}
BinaryOp::Mult => {
match (lhs.ty.kind, rhs.ty.kind) {
(TypeKind::Mat2, TypeKind::Vec2) |
(TypeKind::Mat3, TypeKind::Vec3) |
(TypeKind::Mat3, TypeKind::Mat3) |
(TypeKind::Mat3, TypeKind::Mat43) |
(TypeKind::Mat4, TypeKind::Vec4) => rhs.ty.clone(),
(TypeKind::Mat43, TypeKind::Vec4) => Type::new(TypeKind::Vec3),
(TypeKind::Mat2, TypeKind::Float) |
(TypeKind::Mat3, TypeKind::Float) |
(TypeKind::Mat4, TypeKind::Float) => lhs.ty.clone(),
_ => promoted_type(&lhs.ty, &rhs.ty),
}
}
_ => promoted_type(&lhs.ty, &rhs.ty),
};
Expr {
kind: ExprKind::Binary(op.clone(), lhs, rhs),
ty,
}
}
syntax::Expr::Unary(op, e) => {
let e = Box::new(translate_expression(state, e));
let ty = e.ty.clone();
Expr {
kind: ExprKind::Unary(op.clone(), e),
ty,
}
}
syntax::Expr::BoolConst(b) => Expr {
kind: ExprKind::BoolConst(*b),
ty: Type::new(TypeKind::Bool),
},
syntax::Expr::Comma(lhs, rhs) => {
let lhs = Box::new(translate_expression(state, lhs));
let rhs = Box::new(translate_expression(state, rhs));
assert_eq!(lhs.ty, rhs.ty);
let ty = lhs.ty.clone();
Expr {
kind: ExprKind::Comma(lhs, rhs),
ty,
}
}
syntax::Expr::DoubleConst(d) => Expr {
kind: ExprKind::DoubleConst(*d),
ty: Type::new(TypeKind::Double),
},
syntax::Expr::FloatConst(f) => Expr {
kind: ExprKind::FloatConst(*f),
ty: Type::new(TypeKind::Float),
},
syntax::Expr::FunCall(fun, params) => {
let ret_ty: Type;
let mut params: Vec<Expr> = params
.iter()
.map(|x| translate_expression(state, x))
.collect();
Expr {
kind: ExprKind::FunCall(
match fun {
syntax::FunIdentifier::Identifier(i) => {
let name = i.as_str();
if name == "texelFetchOffset" && params.len() >= 4 {
if let Some((sampler, base, x, y)) = get_texel_fetch_offset(
state, &params[0], &params[1], &params[3],
) {
if let Some(offsets) =
state.texel_fetches.get_mut(&(sampler, base))
{
offsets.add_offset(x, y);
} else {
state
.texel_fetches
.insert((sampler, base), TexelFetchOffsets::new(x, y));
}
}
} else if name == "swgl_stepInterp" {
let mut globals = state.modified_globals.borrow_mut();
for (i, sym) in state.syms.iter().enumerate() {
match &sym.borrow().decl {
SymDecl::Global(StorageClass::In, _, _, RunClass::Vector) => {
let symref = SymRef(i as u32);
if !globals.contains(&symref) {
globals.push(symref);
}
}
_ => {}
}
}
}
let sym = match state.lookup(name) {
Some(s) => s,
None => panic!("missing symbol {}", name),
};
// Force any boolean basic type constructors to generate correct
// bit patterns.
if let Some(t) = TypeKind::from_glsl_primitive_type_name(name) {
if t.is_bool() {
force_params_to_bool(state, &mut params);
} else {
force_params_from_bool(state, &mut params);
}
}
match &state.sym(sym).decl {
SymDecl::NativeFunction(fn_ty, _, _) => {
// Search for a signature where all parameter types are
// compatible. If there are many compatible signatures,
// then choose the one with the most exact matches.
// This is an approximation of the algorith described in
// the "Function Definitions" section of the spec.
let mut ret = None;
let mut best_score = 0;
'next_sig: for sig in &fn_ty.signatures {
let mut score = 0;
for (e, p) in params.iter().zip(sig.params.iter()) {
if e.ty == *p {
score += 1;
} else if !can_implicitly_convert_to(&e.ty, p) {
continue 'next_sig;
}
}
if score >= best_score {
ret = Some(sig.ret.clone());
best_score = score;
// If all parameters match exactly, then there
// is no need to search for other matches.
if best_score >= params.len() {
break;
}
}
}
ret_ty = match ret {
Some(t) => t,
None => {
dbg!(&fn_ty.signatures);
dbg!(params.iter().map(|p| p).collect::<Vec<_>>());
panic!("no matching func {}", i.as_str())
}
};
}
SymDecl::UserFunction(fd, _) => {
let mut globals = state.modified_globals.borrow_mut();
for global in &fd.globals {
if !globals.contains(global) {
globals.push(*global);
}
}
let mut matching = true;
for (e, p) in params.iter().zip(fd.prototype.parameters.iter())
{
matching &= match p {
FunctionParameterDeclaration::Named(q, d) => {
match q {
Some(ParameterQualifier::InOut)
| Some(ParameterQualifier::Out) => {
if let Some(global) = is_output(e, state) {
if !globals.contains(&global) {
globals.push(global);
}
}
}
_ => {}
}
can_implicitly_convert_to(&e.ty, &d.ty)
}
FunctionParameterDeclaration::Unnamed(..) => panic!(),
};
}
assert!(matching);
ret_ty = fd.prototype.ty.clone();
}
SymDecl::Struct(_) => ret_ty = Type::new(TypeKind::Struct(sym)),
_ => panic!("can only call functions"),
};
FunIdentifier::Identifier(sym)
}
// array constructor
syntax::FunIdentifier::Expr(e) => {
let ty = match &**e {
syntax::Expr::Bracket(i, array) => {
let kind = match &**i {
syntax::Expr::Variable(i) => match i.as_str() {
"vec4" => TypeKind::Vec4,
"vec2" => TypeKind::Vec2,
"int" => TypeKind::Int,
_ => panic!("unexpected type constructor {:?}", i),
},
_ => panic!(),
};
Type {
kind,
precision: None,
array_sizes: Some(Box::new(lift(state, array))),
}
}
_ => panic!(),
};
ret_ty = ty.clone();
FunIdentifier::Constructor(ty)
}
},
params,
),
ty: ret_ty,
}
}
syntax::Expr::IntConst(i) => Expr {
kind: ExprKind::IntConst(*i),
ty: Type::new(TypeKind::Int),
},
syntax::Expr::UIntConst(u) => Expr {
kind: ExprKind::UIntConst(*u),
ty: Type::new(TypeKind::UInt),
},
syntax::Expr::PostDec(e) => {
let e = Box::new(translate_expression(state, e));
let ty = e.ty.clone();
Expr {
kind: ExprKind::PostDec(e),
ty,
}
}
syntax::Expr::PostInc(e) => {
let e = Box::new(translate_expression(state, e));
let ty = e.ty.clone();
Expr {
kind: ExprKind::PostInc(e),
ty,
}
}
syntax::Expr::Ternary(cond, lhs, rhs) => {
let cond = Box::new(translate_expression(state, cond));
let lhs = Box::new(translate_expression(state, lhs));
let rhs = Box::new(translate_expression(state, rhs));
let ty = promoted_type(&lhs.ty, &rhs.ty);
Expr {
kind: ExprKind::Ternary(cond, lhs, rhs),
ty,
}
}
syntax::Expr::Dot(e, i) => {
let e = Box::new(translate_expression(state, e));
let ty = e.ty.clone();
let ivec = is_ivec(&ty);
if is_vector(&ty) {
let ty = Type::new(match i.as_str().len() {
1 => {
if ivec {
TypeKind::Int
} else {
TypeKind::Float
}
}
2 => {
if ivec {
TypeKind::IVec2
} else {
TypeKind::Vec2
}
}
3 => {
if ivec {
TypeKind::IVec3
} else {
TypeKind::Vec3
}
}
4 => {
if ivec {
TypeKind::IVec4
} else {
TypeKind::Vec4
}
}
_ => panic!(),
});
let sel = SwizzleSelector::parse(i.as_str());
Expr {
kind: ExprKind::SwizzleSelector(e, sel),
ty,
}
} else {
match ty.kind {
TypeKind::Struct(s) => {
let sym = state.sym(s);
let fields = match &sym.decl {
SymDecl::Struct(fields) => fields,
_ => panic!("expected struct"),
};
let field = fields
.fields
.iter()
.find(|x| &x.name == i)
.expect(&format!("missing field `{}` in `{}`", i, sym.name));
Expr {
kind: ExprKind::Dot(e, i.clone()),
ty: field.ty.clone(),
}
}
_ => panic!("expected struct found {:#?} {:#?}", e, ty),
}
}
}
syntax::Expr::Bracket(e, specifier) => {
let e = Box::new(translate_expression(state, e));
let ty = if let Some(ty) = index_vector(&e.ty) {
Type::new(ty)
} else if let Some(ty) = index_matrix(&e.ty) {
Type::new(ty)
} else {
let a = match &e.ty.array_sizes {
Some(a) => {
let mut a = *a.clone();
a.sizes.pop();
if a.sizes.len() == 0 {
None
} else {
Some(Box::new(a))
}
}
_ => panic!("{:#?}", e),
};
Type {
kind: e.ty.kind.clone(),
precision: e.ty.precision.clone(),
array_sizes: a,
}
};
let indx = specifier.dimensions.0.iter().map(|a| match a {
ArraySpecifierDimension::Unsized => panic!("need expression"),
ArraySpecifierDimension::ExplicitlySized(e) => translate_expression(state, e),
}).collect();
Expr {
kind: ExprKind::Bracket(e, indx),
ty,
}
}
}
}
fn translate_switch(state: &mut State, s: &syntax::SwitchStatement) -> SwitchStatement {
let mut cases = Vec::new();
let mut case = None;
for stmt in &s.body {
match stmt {
syntax::Statement::Simple(s) => match &**s {
syntax::SimpleStatement::CaseLabel(label) => {
match case.take() {
Some(case) => cases.push(case),
_ => {}
}
case = Some(Case {
label: translate_case(state, &label),
stmts: Vec::new(),
})
}
_ => match case {
Some(ref mut case) => case.stmts.push(translate_statement(state, stmt)),
_ => panic!("switch must start with case"),
},
},
_ => match case {
Some(ref mut case) => case.stmts.push(translate_statement(state, stmt)),
_ => panic!("switch must start with case"),
},
}
}
match case.take() {
Some(case) => cases.push(case),
_ => {}
}
SwitchStatement {
head: Box::new(translate_expression(state, &s.head)),
cases,
}
}
fn translate_jump(state: &mut State, s: &syntax::JumpStatement) -> JumpStatement {
match s {
syntax::JumpStatement::Break => JumpStatement::Break,
syntax::JumpStatement::Continue => JumpStatement::Continue,
syntax::JumpStatement::Discard => JumpStatement::Discard,
syntax::JumpStatement::Return(e) => {
JumpStatement::Return(e.as_ref().map(|e| Box::new(translate_expression(state, e))))
}
}
}
fn translate_condition(state: &mut State, c: &syntax::Condition) -> Condition {
match c {
syntax::Condition::Expr(e) => Condition::Expr(Box::new(translate_expression(state, e))),
_ => panic!(),
}
}
fn translate_for_init(state: &mut State, s: &syntax::ForInitStatement) -> ForInitStatement {
match s {
syntax::ForInitStatement::Expression(e) => {
ForInitStatement::Expression(e.as_ref().map(|e| translate_expression(state, e)))
}
syntax::ForInitStatement::Declaration(d) => ForInitStatement::Declaration(Box::new(
translate_declaration(state, d, RunClass::Scalar),
)),
}
}
fn translate_for_rest(state: &mut State, s: &syntax::ForRestStatement) -> ForRestStatement {
ForRestStatement {
condition: s.condition.as_ref().map(|c| translate_condition(state, c)),
post_expr: s
.post_expr
.as_ref()
.map(|e| Box::new(translate_expression(state, e))),
}
}
fn translate_iteration(state: &mut State, s: &syntax::IterationStatement) -> IterationStatement {
match s {
syntax::IterationStatement::While(cond, s) => IterationStatement::While(
translate_condition(state, cond),
Box::new(translate_statement(state, s)),
),
syntax::IterationStatement::For(init, rest, s) => IterationStatement::For(
translate_for_init(state, init),
translate_for_rest(state, rest),
Box::new(translate_statement(state, s)),
),
syntax::IterationStatement::DoWhile(s, e) => IterationStatement::DoWhile(
Box::new(translate_statement(state, s)),
Box::new(translate_expression(state, e)),
),
}
}
fn translate_case(state: &mut State, c: &syntax::CaseLabel) -> CaseLabel {
match c {
syntax::CaseLabel::Def => CaseLabel::Def,
syntax::CaseLabel::Case(e) => CaseLabel::Case(Box::new(translate_expression(state, e))),
}
}
fn translate_selection_rest(
state: &mut State,
s: &syntax::SelectionRestStatement,
) -> (Box<Statement>, Option<Box<Statement>>) {
match s {
syntax::SelectionRestStatement::Statement(s) => {
(Box::new(translate_statement(state, s)), None)
}
syntax::SelectionRestStatement::Else(if_body, rest) => (
Box::new(translate_statement(state, if_body)),
Some(Box::new(translate_statement(state, rest))),
),
}
}
fn translate_selection(state: &mut State, s: &syntax::SelectionStatement) -> SelectionStatement {
let cond = Box::new(translate_expression(state, &s.cond));
let (body, else_stmt) = translate_selection_rest(state, &s.rest);
SelectionStatement {
cond,
body,
else_stmt,
}
}
fn translate_simple_statement(state: &mut State, s: &syntax::SimpleStatement) -> SimpleStatement {
match s {
syntax::SimpleStatement::Declaration(d) => {
SimpleStatement::Declaration(translate_declaration(state, d, RunClass::Unknown))
}
syntax::SimpleStatement::Expression(e) => {
SimpleStatement::Expression(e.as_ref().map(|e| translate_expression(state, e)))
}
syntax::SimpleStatement::Iteration(i) => {
SimpleStatement::Iteration(translate_iteration(state, i))
}
syntax::SimpleStatement::Selection(s) => {
SimpleStatement::Selection(translate_selection(state, s))
}
syntax::SimpleStatement::Jump(j) => SimpleStatement::Jump(translate_jump(state, j)),
syntax::SimpleStatement::Switch(s) => SimpleStatement::Switch(translate_switch(state, s)),
syntax::SimpleStatement::CaseLabel(_) => panic!("should be handled by translate_switch"),
}
}
fn translate_statement(state: &mut State, s: &syntax::Statement) -> Statement {
match s {
syntax::Statement::Compound(s) => {
Statement::Compound(Box::new(translate_compound_statement(state, s)))
}
syntax::Statement::Simple(s) => {
Statement::Simple(Box::new(translate_simple_statement(state, s)))
}
}
}
fn translate_compound_statement(
state: &mut State,
cs: &syntax::CompoundStatement,
) -> CompoundStatement {
CompoundStatement {
statement_list: cs
.statement_list
.iter()
.map(|x| translate_statement(state, x))
.collect(),
}
}
fn translate_function_parameter_declaration(
state: &mut State,
p: &syntax::FunctionParameterDeclaration,
index: usize,
) -> FunctionParameterDeclaration {
match p {
syntax::FunctionParameterDeclaration::Named(qual, p) => {
let mut ty: Type = lift(state, &p.ty);
if let Some(a) = &p.ident.array_spec {
ty.array_sizes = Some(Box::new(lift(state, a)));
}
ty.precision = get_precision(qual);
let decl = SymDecl::Local(
StorageClass::None,
ty.clone(),
RunClass::Dependent(1 << index),
);
let d = FunctionParameterDeclarator {
ty,
name: p.ident.ident.clone(),
sym: state.declare(p.ident.ident.as_str(), decl),
};
FunctionParameterDeclaration::Named(lift_type_qualifier_for_parameter(state, qual), d)
}
syntax::FunctionParameterDeclaration::Unnamed(qual, p) => {
FunctionParameterDeclaration::Unnamed(
lift_type_qualifier_for_parameter(state, qual),
p.clone(),
)
}
}
}
fn translate_prototype(
state: &mut State,
cs: &syntax::FunctionPrototype,
) -> (FunctionPrototype, SymRef) {
let prototype = FunctionPrototype {
ty: lift(state, &cs.ty),
name: cs.name.clone(),
parameters: cs
.parameters
.iter()
.enumerate()
.map(|(i, x)| translate_function_parameter_declaration(state, x, i))
.collect(),
};
let sym = if let Some(sym) = state.lookup(prototype.name.as_str()) {
match &state.sym(sym).decl {
SymDecl::UserFunction(..) => {}
_ => panic!(
"prototype conflicts with existing symbol: {}",
prototype.name.as_str()
),
}
sym
} else {
let pfd = Rc::new(FunctionDefinition {
prototype: prototype.clone(),
body: CompoundStatement::new(),
globals: Vec::new(),
texel_fetches: HashMap::new(),
});
state.declare(
prototype.name.as_str(),
SymDecl::UserFunction(pfd, RunClass::Unknown),
)
};
(prototype, sym)
}
fn translate_function_prototype(
state: &mut State,
prototype: &syntax::FunctionPrototype,
) -> FunctionPrototype {
let (prototype, _) = translate_prototype(state, prototype);
prototype
}
fn translate_function_definition(
state: &mut State,
sfd: &syntax::FunctionDefinition,
) -> Rc<FunctionDefinition> {
let (prototype, sym) = translate_prototype(state, &sfd.prototype);
state.push_scope(prototype.name.as_str().into());
state.in_function = Some(sym);
state.modified_globals.get_mut().clear();
state.texel_fetches.clear();
let body = translate_compound_statement(state, &sfd.statement);
let mut globals = Vec::new();
mem::swap(&mut globals, state.modified_globals.get_mut());
let mut texel_fetches = HashMap::new();
mem::swap(&mut texel_fetches, &mut state.texel_fetches);
state.in_function = None;
state.pop_scope();
let fd = Rc::new(FunctionDefinition {
prototype,
body,
globals,
texel_fetches,
});
state.sym_mut(sym).decl = SymDecl::UserFunction(fd.clone(), RunClass::Unknown);
fd
}
fn translate_external_declaration(
state: &mut State,
ed: &syntax::ExternalDeclaration,
) -> ExternalDeclaration {
match ed {
syntax::ExternalDeclaration::Declaration(d) => {
ExternalDeclaration::Declaration(translate_declaration(state, d, RunClass::Unknown))
}
syntax::ExternalDeclaration::FunctionDefinition(fd) => {
ExternalDeclaration::FunctionDefinition(translate_function_definition(state, fd))
}
syntax::ExternalDeclaration::Preprocessor(p) => {
ExternalDeclaration::Preprocessor(p.clone())
}
}
}
fn declare_function_ext(
state: &mut State,
name: &str,
cxx_name: Option<&'static str>,
ret: Type,
params: Vec<Type>,
run_class: RunClass,
) {
let sig = FunctionSignature { ret, params };
match state.lookup_sym_mut(name) {
Some(Symbol {
decl: SymDecl::NativeFunction(f, ..),
..
}) => f.signatures.push(sig),
None => {
state.declare(
name,
SymDecl::NativeFunction(
FunctionType {
signatures: NonEmpty::new(sig),
},
cxx_name,
run_class,
),
);
}
_ => panic!("overloaded function name {}", name),
}
//state.declare(name, Type::Function(FunctionType{ v}))
}
fn declare_function(
state: &mut State,
name: &str,
cxx_name: Option<&'static str>,
ret: Type,
params: Vec<Type>,
) {
declare_function_ext(state, name, cxx_name, ret, params, RunClass::Unknown)
}
pub fn ast_to_hir(state: &mut State, tu: &syntax::TranslationUnit) -> TranslationUnit {
// global scope
state.push_scope("global".into());
use TypeKind::*;
declare_function(
state,
"vec2",
Some("make_vec2"),
Type::new(Vec2),
vec![Type::new(Float)],
);
declare_function(
state,
"vec2",
Some("make_vec2"),
Type::new(Vec2),
vec![Type::new(Float), Type::new(Float)],
);
declare_function(
state,
"vec2",
Some("make_vec2"),
Type::new(Vec2),
vec![Type::new(IVec2)],
);
declare_function(
state,
"vec2",
Some("make_vec2"),
Type::new(Vec2),
vec![Type::new(IVec3)],
);
declare_function(
state,
"vec3",
Some("make_vec3"),
Type::new(Vec3),
vec![Type::new(Float), Type::new(Float), Type::new(Float)],
);
declare_function(
state,
"vec3",
Some("make_vec3"),
Type::new(Vec3),
vec![Type::new(Float)],
);
declare_function(
state,
"vec3",
Some("make_vec3"),
Type::new(Vec3),
vec![Type::new(Vec2), Type::new(Float)],
);
declare_function(
state,
"vec4",
Some("make_vec4"),
Type::new(Vec4),
vec![Type::new(Float)],
);
declare_function(
state,
"vec4",
Some("make_vec4"),
Type::new(Vec4),
vec![Type::new(Vec3), Type::new(Float)],
);
declare_function(
state,
"vec4",
Some("make_vec4"),
Type::new(Vec4),
vec![
Type::new(Float),
Type::new(Float),
Type::new(Float),
Type::new(Float),
],
);
declare_function(
state,
"vec4",
Some("make_vec4"),
Type::new(Vec4),
vec![Type::new(Vec2), Type::new(Float), Type::new(Float)],
);
declare_function(
state,
"vec4",
Some("make_vec4"),
Type::new(Vec4),
vec![Type::new(Vec2), Type::new(Vec2)],
);
declare_function(
state,
"vec4",
Some("make_vec4"),
Type::new(Vec4),
vec![Type::new(Float), Type::new(Float), Type::new(Vec2)],
);
declare_function(
state,
"vec4",
Some("make_vec4"),
Type::new(Vec4),
vec![Type::new(Vec4)],
);
declare_function(
state,
"vec4",
Some("make_vec4"),
Type::new(Vec4),
vec![Type::new(IVec4)],
);
declare_function(
state,
"bvec2",
Some("make_bvec2"),
Type::new(BVec2),
vec![Type::new(Bool)],
);
declare_function(
state,
"bvec3",
Some("make_bvec3"),
Type::new(BVec3),
vec![Type::new(Bool)],
);
declare_function(
state,
"bvec4",
Some("make_bvec4"),
Type::new(BVec4),
vec![Type::new(Bool)],
);
declare_function(
state,
"bvec4",
Some("make_bvec4"),
Type::new(BVec4),
vec![Type::new(BVec2), Type::new(BVec2)],
);
declare_function(
state,
"bvec4",
Some("make_bvec4"),
Type::new(BVec4),
vec![Type::new(Bool), Type::new(Bool), Type::new(Bool), Type::new(Bool)],
);
declare_function(
state,
"int",
Some("make_int"),
Type::new(Int),
vec![Type::new(Float)],
);
declare_function(
state,
"float",
Some("make_float"),
Type::new(Float),
vec![Type::new(Float)],
);
declare_function(
state,
"float",
Some("make_float"),
Type::new(Float),
vec![Type::new(Int)],
);
declare_function(
state,
"int",
Some("make_int"),
Type::new(Int),
vec![Type::new(UInt)],
);
declare_function(
state,
"uint",
Some("make_uint"),
Type::new(UInt),
vec![Type::new(Float)],
);
declare_function(
state,
"uint",
Some("make_uint"),
Type::new(UInt),
vec![Type::new(Int)],
);
declare_function(
state,
"ivec2",
Some("make_ivec2"),
Type::new(IVec2),
vec![Type::new(UInt), Type::new(UInt)],
);
declare_function(
state,
"ivec2",
Some("make_ivec2"),
Type::new(IVec2),
vec![Type::new(Int), Type::new(Int)],
);
declare_function(
state,
"ivec2",
Some("make_ivec2"),
Type::new(IVec2),
vec![Type::new(Vec2)],
);
declare_function(
state,
"ivec3",
Some("make_ivec3"),
Type::new(IVec3),
vec![Type::new(IVec2), Type::new(Int)],
);
declare_function(
state,
"ivec4",
Some("make_ivec4"),
Type::new(IVec4),
vec![
Type::new(Int),
Type::new(Int),
Type::new(Int),
Type::new(Int),
],
);
declare_function(
state,
"ivec4",
Some("make_ivec4"),
Type::new(IVec4),
vec![Type::new(Vec4)],
);
declare_function(
state,
"ivec4",
Some("make_ivec4"),
Type::new(IVec4),
vec![Type::new(IVec2), Type::new(Int), Type::new(Int)],
);
declare_function(
state,
"mat2",
Some("make_mat2"),
Type::new(Mat2),
vec![Type::new(Vec2), Type::new(Vec2)],
);
declare_function(
state,
"mat2",
Some("make_mat2"),
Type::new(Mat2),
vec![Type::new(Float)],
);
declare_function(
state,
"mat2",
Some("make_mat2"),
Type::new(Mat2),
vec![Type::new(Mat4)],
);
declare_function(
state,
"mat3",
Some("make_mat3"),
Type::new(Mat3),
vec![Type::new(Vec3), Type::new(Vec3), Type::new(Vec3)],
);
declare_function(
state,
"mat3",
Some("make_mat3"),
Type::new(Mat3),
vec![Type::new(Mat4)],
);
declare_function(
state,
"mat3",
Some("make_mat3"),
Type::new(Mat3),
vec![
Type::new(Float),
Type::new(Float),
Type::new(Float),
Type::new(Float),
Type::new(Float),
Type::new(Float),
Type::new(Float),
Type::new(Float),
Type::new(Float),
],
);
declare_function(
state,
"mat3x4",
Some("make_mat3x4"),
Type::new(Mat34),
vec![
Type::new(Float),
Type::new(Float),
Type::new(Float),
Type::new(Float),
Type::new(Float),
Type::new(Float),
Type::new(Float),
Type::new(Float),
Type::new(Float),
Type::new(Float),
Type::new(Float),
Type::new(Float),
],
);
declare_function(
state,
"transpose",
None,
Type::new(Mat43),
vec![Type::new(Mat34)],
);
declare_function(
state,
"mat4",
Some("make_mat4"),
Type::new(Mat4),
vec![
Type::new(Vec4),
Type::new(Vec4),
Type::new(Vec4),
Type::new(Vec4),
],
);
declare_function(
state,
"mat4",
Some("make_mat4"),
Type::new(Mat4),
vec![
Type::new(Float),
Type::new(Float),
Type::new(Float),
Type::new(Float),
Type::new(Float),
Type::new(Float),
Type::new(Float),
Type::new(Float),
Type::new(Float),
Type::new(Float),
Type::new(Float),
Type::new(Float),
Type::new(Float),
Type::new(Float),
Type::new(Float),
Type::new(Float),
],
);
declare_function(state, "abs", None, Type::new(Vec2), vec![Type::new(Vec2)]);
declare_function(state, "abs", None, Type::new(Vec3), vec![Type::new(Vec3)]);
declare_function(state, "abs", None, Type::new(Float), vec![Type::new(Float)]);
declare_function(state, "sign", None, Type::new(Vec2), vec![Type::new(Vec2)]);
declare_function(state, "sign", None, Type::new(Vec3), vec![Type::new(Vec3)]);
declare_function(state, "sign", None, Type::new(Float), vec![Type::new(Float)]);
declare_function(
state,
"dot",
None,
Type::new(Float),
vec![Type::new(Vec3), Type::new(Vec3)],
);
declare_function(
state,
"dot",
None,
Type::new(Float),
vec![Type::new(Vec2), Type::new(Vec2)],
);
for t in &[Vec2, Vec3, Vec4] {
declare_function(
state,
"min",
None,
Type::new(*t),
vec![Type::new(*t), Type::new(Float)],
);
declare_function(
state,
"max",
None,
Type::new(*t),
vec![Type::new(*t), Type::new(Float)],
);
}
for t in &[Int, Float, Vec2, Vec3, Vec4] {
declare_function(
state,
"min",
None,
Type::new(*t),
vec![Type::new(*t), Type::new(*t)],
);
declare_function(
state,
"max",
None,
Type::new(*t),
vec![Type::new(*t), Type::new(*t)],
);
}
declare_function(
state,
"mix",
None,
Type::new(Vec2),
vec![Type::new(Vec2), Type::new(Vec2), Type::new(Vec2)],
);
declare_function(
state,
"mix",
None,
Type::new(Vec2),
vec![Type::new(Vec2), Type::new(Vec2), Type::new(BVec2)],
);
declare_function(
state,
"mix",
None,
Type::new(Vec2),
vec![Type::new(Vec2), Type::new(Vec2), Type::new(Float)],
);
declare_function(
state,
"mix",
None,
Type::new(Vec3),
vec![Type::new(Vec3), Type::new(Vec3), Type::new(Vec3)],
);
declare_function(
state,
"mix",
None,
Type::new(Vec4),
vec![Type::new(Vec4), Type::new(Vec4), Type::new(Vec4)],
);
declare_function(
state,
"mix",
None,
Type::new(Vec4),
vec![Type::new(Vec4), Type::new(Vec4), Type::new(Float)],
);
declare_function(
state,
"mix",
None,
Type::new(Vec3),
vec![Type::new(Vec3), Type::new(Vec3), Type::new(Float)],
);
declare_function(
state,
"mix",
None,
Type::new(Vec3),
vec![Type::new(Vec3), Type::new(Vec3), Type::new(BVec3)],
);
declare_function(
state,
"mix",
None,
Type::new(Float),
vec![Type::new(Float), Type::new(Float), Type::new(Float)],
);
declare_function(
state,
"mix",
None,
Type::new(Vec4),
vec![Type::new(Vec4), Type::new(Vec4), Type::new(BVec4)],
);
declare_function(
state,
"step",
None,
Type::new(Float),
vec![Type::new(Float), Type::new(Float)],
);
declare_function(
state,
"step",
None,
Type::new(Vec2),
vec![Type::new(Vec2), Type::new(Vec2)],
);
declare_function(
state,
"step",
None,
Type::new(Vec2),
vec![Type::new(Float), Type::new(Vec2)],
);
declare_function(
state,
"step",
None,
Type::new(Vec3),
vec![Type::new(Vec3), Type::new(Vec3)],
);
declare_function(
state,
"step",
None,
Type::new(Vec4),
vec![Type::new(Float), Type::new(Vec4)],
);
declare_function(
state,
"notEqual",
None,
Type::new(BVec4),
vec![Type::new(IVec4), Type::new(IVec4)],
);
declare_function_ext(
state,
"fwidth",
None,
Type::new(Vec2),
vec![Type::new(Vec2)],
RunClass::Scalar,
);
declare_function_ext(
state,
"dFdx",
None,
Type::new(Float),
vec![Type::new(Float)],
RunClass::Scalar,
);
declare_function_ext(
state,
"dFdx",
None,
Type::new(Vec2),
vec![Type::new(Vec2)],
RunClass::Scalar,
);
declare_function(state, "cos", None, Type::new(Float), vec![Type::new(Float)]);
declare_function(state, "sin", None, Type::new(Float), vec![Type::new(Float)]);
declare_function(state, "tan", None, Type::new(Float), vec![Type::new(Float)]);
declare_function(state, "atan", None, Type::new(Float), vec![Type::new(Float)]);
declare_function(state, "atan", None, Type::new(Float), vec![Type::new(Float), Type::new(Float)]);
for t in &[Vec2, Vec3, Vec4] {
declare_function(
state,
"clamp",
None,
Type::new(*t),
vec![Type::new(*t), Type::new(Float), Type::new(Float)],
);
}
for t in &[Float, Vec2, Vec3, Vec4] {
declare_function(
state,
"clamp",
None,
Type::new(*t),
vec![Type::new(*t), Type::new(*t), Type::new(*t)],
);
}
declare_function(
state,
"length",
None,
Type::new(Float),
vec![Type::new(Vec2)],
);
declare_function(state, "pow", None, Type::new(Vec3), vec![Type::new(Vec3)]);
declare_function(state, "pow", None, Type::new(Float), vec![Type::new(Float)]);
declare_function(state, "exp", None, Type::new(Float), vec![Type::new(Float)]);
declare_function(state, "exp2", None, Type::new(Float), vec![Type::new(Float)]);
declare_function(state, "log", None, Type::new(Float), vec![Type::new(Float)]);
declare_function(state, "log2", None, Type::new(Float), vec![Type::new(Float)]);
for t in &[Float, Vec2] {
// recip is non-standard
declare_function(
state,
"recip",
None,
Type::new(*t),
vec![Type::new(*t)],
);
declare_function(
state,
"inversesqrt",
None,
Type::new(*t),
vec![Type::new(*t)],
);
declare_function(
state,
"sqrt",
None,
Type::new(*t),
vec![Type::new(*t)],
);
}
declare_function(
state,
"distance",
None,
Type::new(Float),
vec![Type::new(Vec2), Type::new(Vec2)],
);
declare_function(
state,
"equal",
None,
Type::new(BVec2),
vec![Type::new(Vec2), Type::new(Vec2)],
);
declare_function(
state,
"equal",
None,
Type::new(BVec4),
vec![Type::new(Vec4), Type::new(Vec4)],
);
declare_function(
state,
"notEqual",
None,
Type::new(BVec2),
vec![Type::new(Vec2), Type::new(Vec2)],
);
declare_function(
state,
"notEqual",
None,
Type::new(BVec4),
vec![Type::new(Vec4), Type::new(Vec4)],
);
declare_function(
state,
"lessThanEqual",
None,
Type::new(BVec2),
vec![Type::new(Vec2), Type::new(Vec2)],
);
declare_function(
state,
"lessThanEqual",
None,
Type::new(BVec3),
vec![Type::new(Vec3), Type::new(Vec3)],
);
declare_function(
state,
"lessThanEqual",
None,
Type::new(BVec4),
vec![Type::new(Vec4), Type::new(Vec4)],
);
declare_function(
state,
"lessThan",
None,
Type::new(BVec2),
vec![Type::new(Vec2), Type::new(Vec2)],
);
declare_function(
state,
"lessThan",
None,
Type::new(BVec4),
vec![Type::new(Vec4), Type::new(Vec4)],
);
declare_function(
state,
"greaterThan",
None,
Type::new(BVec2),
vec![Type::new(Vec2), Type::new(Vec2)],
);
declare_function(
state,
"greaterThan",
None,
Type::new(BVec4),
vec![Type::new(Vec4), Type::new(Vec4)],
);
declare_function(
state,
"greaterThanEqual",
None,
Type::new(BVec2),
vec![Type::new(Vec2), Type::new(Vec2)],
);
declare_function(
state,
"greaterThanEqual",
None,
Type::new(BVec4),
vec![Type::new(Vec4), Type::new(Vec4)],
);
declare_function(state, "any", None, Type::new(Bool), vec![Type::new(BVec2)]);
declare_function(state, "all", None, Type::new(Bool), vec![Type::new(BVec2)]);
declare_function(state, "all", None, Type::new(Bool), vec![Type::new(BVec4)]);
declare_function(
state,
"if_then_else",
None,
Type::new(Vec3),
vec![Type::new(BVec3), Type::new(Vec3), Type::new(Vec3)],
);
declare_function(state, "floor", None, Type::new(Vec4), vec![Type::new(Vec4)]);
declare_function(state, "floor", None, Type::new(Vec2), vec![Type::new(Vec2)]);
declare_function(
state,
"floor",
None,
Type::new(Float),
vec![Type::new(Float)],
);
declare_function(
state,
"ceil",
None,
Type::new(Float),
vec![Type::new(Float)],
);
declare_function(
state,
"round",
None,
Type::new(Float),
vec![Type::new(Float)],
);
declare_function(
state,
"fract",
None,
Type::new(Float),
vec![Type::new(Float)],
);
declare_function(
state,
"fract",
None,
Type::new(Vec2),
vec![Type::new(Vec2)],
);
declare_function(state, "mod", None, Type::new(Vec2), vec![Type::new(Vec2)]);
declare_function(state, "mod", None, Type::new(Float), vec![Type::new(Float)]);
declare_function(
state,
"texelFetch",
None,
Type::new(Vec4),
vec![Type::new(Sampler2D), Type::new(IVec2), Type::new(Int)],
);
declare_function(
state,
"texelFetch",
None,
Type::new(IVec4),
vec![Type::new(ISampler2D), Type::new(IVec2), Type::new(Int)],
);
declare_function(
state,
"texelFetchOffset",
None,
Type::new(Vec4),
vec![
Type::new(Sampler2D),
Type::new(IVec2),
Type::new(Int),
Type::new(IVec2),
],
);
declare_function(
state,
"texelFetchOffset",
None,
Type::new(IVec4),
vec![
Type::new(ISampler2D),
Type::new(IVec2),
Type::new(Int),
Type::new(IVec2),
],
);
declare_function(
state,
"texture",
None,
Type::new(Vec4),
vec![Type::new(Sampler2D), Type::new(Vec2)],
);
declare_function(
state,
"texture",
None,
Type::new(Vec4),
vec![Type::new(Sampler2DRect), Type::new(Vec2)],
);
declare_function(
state,
"textureSize",
None,
Type::new(IVec2),
vec![Type::new(Sampler2D), Type::new(Int)],
);
declare_function(
state,
"textureSize",
None,
Type::new(IVec2),
vec![Type::new(Sampler2DRect), Type::new(Int)],
);
declare_function(
state,
"inverse",
None,
Type::new(Mat2),
vec![Type::new(Mat2)],
);
declare_function(
state,
"transpose",
None,
Type::new(Mat3),
vec![Type::new(Mat3)],
);
declare_function(
state,
"normalize",
None,
Type::new(Vec2),
vec![Type::new(Vec2)],
);
state.declare(
"gl_FragCoord",
SymDecl::Global(StorageClass::In, None, Type::new(Vec4), RunClass::Vector),
);
state.declare(
"gl_FragColor",
SymDecl::Global(StorageClass::Out, None, Type::new(Vec4), RunClass::Vector),
);
state.declare(
"gl_Position",
SymDecl::Global(StorageClass::Out, None, Type::new(Vec4), RunClass::Vector),
);
state.clip_dist_sym = state.declare(
"gl_ClipDistance",
SymDecl::Global(StorageClass::Out, None, Type::new_array(Float, 4), RunClass::Vector),
);
state.declare(
"swgl_SpanLength",
SymDecl::Global(StorageClass::In, None, Type::new(Int), RunClass::Scalar),
);
state.declare(
"swgl_StepSize",
SymDecl::Global(StorageClass::Const, None, Type::new(Int), RunClass::Scalar),
);
for t in &[Float, Vec2, Vec3, Vec4, Int, IVec2, IVec3, IVec4, Mat3, Mat4] {
declare_function_ext(
state,
"swgl_forceScalar",
None,
Type::new(*t),
vec![Type::new(*t)],
RunClass::Scalar,
);
}
// GL_ARB_shader_group_vote
for (name, cxx_name) in &[("anyInvocations", "test_any"),
("allInvocations", "test_all"),
("allInvocationsEqual", "test_equal")] {
declare_function_ext(
state,
name,
Some(cxx_name),
Type::new(Bool),
vec![Type::new(Bool)],
RunClass::Scalar,
);
}
declare_function(
state,
"swgl_stepInterp",
None,
Type::new(Void),
vec![],
);
for t in &[Float, Vec2, Vec3, Vec4] {
declare_function_ext(
state,
"swgl_interpStep",
None,
Type::new(*t),
vec![Type::new(*t)],
RunClass::Scalar,
);
}
declare_function(
state,
"swgl_commitPartialSolidRGBA8",
None,
Type::new(Void),
vec![Type::new(Int), Type::new(Vec4)],
);
declare_function(
state,
"swgl_commitPartialSolidR8",
None,
Type::new(Void),
vec![Type::new(Int), Type::new(Float)],
);
declare_function(
state,
"swgl_commitSolidRGBA8",
None,
Type::new(Void),
vec![Type::new(Vec4)],
);
declare_function(
state,
"swgl_commitSolidR8",
None,
Type::new(Void),
vec![Type::new(Float)],
);
declare_function(
state,
"swgl_commitColorRGBA8",
None,
Type::new(Void),
vec![Type::new(Vec4)],
);
declare_function(
state,
"swgl_commitColorR8",
None,
Type::new(Void),
vec![Type::new(Float)],
);
declare_function(
state,
"swgl_blendDropShadow",
None,
Type::new(Void),
vec![Type::new(Vec4)],
);
declare_function(
state,
"swgl_blendSubpixelText",
None,
Type::new(Void),
vec![Type::new(Vec4)],
);
declare_function(
state,
"swgl_clipMask",
None,
Type::new(Void),
vec![Type::new(Sampler2D), Type::new(Vec2), Type::new(Vec2), Type::new(Vec2)],
);
declare_function(
state,
"swgl_antiAlias",
None,
Type::new(Void),
vec![Type::new(Int)],
);
declare_function(
state,
"swgl_antiAlias",
None,
Type::new(Void),
vec![Type::new(BVec4)],
);
declare_function_ext(
state,
"swgl_validateGradient",
None,
Type::new(Int),
vec![Type::new(Sampler2D), Type::new(IVec2), Type::new(Int)],
RunClass::Scalar,
);
declare_function(
state,
"swgl_commitLinearGradientRGBA8",
None,
Type::new(Void),
vec![Type::new(Sampler2D), Type::new(Int), Type::new(Float), Type::new(Bool), Type::new(Bool),
Type::new(Vec2), Type::new(Vec2), Type::new(Float)],
);
declare_function(
state,
"swgl_commitRadialGradientRGBA8",
None,
Type::new(Void),
vec![Type::new(Sampler2D), Type::new(Int), Type::new(Float), Type::new(Bool), Type::new(Vec2),
Type::new(Float)],
);
declare_function(
state,
"swgl_commitGradientRGBA8",
None,
Type::new(Void),
vec![Type::new(Sampler2D), Type::new(Int), Type::new(Float)],
);
declare_function(
state,
"swgl_commitGradientColorRGBA8",
None,
Type::new(Void),
vec![Type::new(Sampler2D), Type::new(Int), Type::new(Float), Type::new(Float)],
);
for s in &[Sampler2D, Sampler2DRect] {
declare_function_ext(
state,
"swgl_isTextureLinear",
None,
Type::new(Bool),
vec![Type::new(*s)],
RunClass::Scalar,
);
declare_function_ext(
state,
"swgl_isTextureRGBA8",
None,
Type::new(Bool),
vec![Type::new(*s)],
RunClass::Scalar,
);
declare_function_ext(
state,
"swgl_isTextureR8",
None,
Type::new(Bool),
vec![Type::new(*s)],
RunClass::Scalar,
);
declare_function(
state,
"swgl_commitTextureLinearRGBA8",
None,
Type::new(Void),
vec![Type::new(*s), Type::new(Vec2), Type::new(Vec4)],
);
declare_function(
state,
"swgl_commitTextureLinearR8",
None,
Type::new(Void),
vec![Type::new(*s), Type::new(Vec2), Type::new(Vec4)],
);
declare_function(
state,
"swgl_commitTextureLinearR8ToRGBA8",
None,
Type::new(Void),
vec![Type::new(*s), Type::new(Vec2), Type::new(Vec4)],
);
declare_function(
state,
"swgl_commitPartialTextureLinearR8",
None,
Type::new(Void),
vec![Type::new(Int), Type::new(*s), Type::new(Vec2), Type::new(Vec4)],
);
declare_function(
state,
"swgl_commitPartialTextureLinearInvertR8",
None,
Type::new(Void),
vec![Type::new(Int), Type::new(*s), Type::new(Vec2), Type::new(Vec4)],
);
declare_function(
state,
"swgl_commitTextureLinearColorRGBA8",
None,
Type::new(Void),
vec![Type::new(*s), Type::new(Vec2), Type::new(Vec4), Type::new(Vec4)],
);
declare_function(
state,
"swgl_commitTextureLinearColorRGBA8",
None,
Type::new(Void),
vec![Type::new(*s), Type::new(Vec2), Type::new(Vec4), Type::new(Float)],
);
declare_function(
state,
"swgl_commitTextureLinearColorR8",
None,
Type::new(Void),
vec![Type::new(*s), Type::new(Vec2), Type::new(Vec4), Type::new(Float)],
);
declare_function(
state,
"swgl_commitTextureLinearColorR8ToRGBA8",
None,
Type::new(Void),
vec![Type::new(*s), Type::new(Vec2), Type::new(Vec4), Type::new(Vec4)],
);
declare_function(
state,
"swgl_commitTextureLinearRepeatRGBA8",
None,
Type::new(Void),
vec![Type::new(*s), Type::new(Vec2), Type::new(Vec2),
Type::new(Vec4), Type::new(Vec4)],
);
declare_function(
state,
"swgl_commitTextureLinearRepeatColorRGBA8",
None,
Type::new(Void),
vec![Type::new(*s), Type::new(Vec2), Type::new(Vec2),
Type::new(Vec4), Type::new(Vec4), Type::new(Vec4)],
);
declare_function(
state,
"swgl_commitTextureNearestRGBA8",
None,
Type::new(Void),
vec![Type::new(*s), Type::new(Vec2), Type::new(Vec4)],
);
declare_function(
state,
"swgl_commitTextureNearestColorRGBA8",
None,
Type::new(Void),
vec![Type::new(*s), Type::new(Vec2), Type::new(Vec4), Type::new(Vec4)],
);
declare_function(
state,
"swgl_commitTextureNearestRepeatRGBA8",
None,
Type::new(Void),
vec![Type::new(*s), Type::new(Vec2), Type::new(Vec2),
Type::new(Vec4), Type::new(Vec4)],
);
declare_function(
state,
"swgl_commitTextureNearestRepeatColorRGBA8",
None,
Type::new(Void),
vec![Type::new(*s), Type::new(Vec2), Type::new(Vec2),
Type::new(Vec4), Type::new(Vec4), Type::new(Vec4)],
);
declare_function(
state,
"swgl_commitTextureRGBA8",
None,
Type::new(Void),
vec![Type::new(*s), Type::new(Vec2), Type::new(Vec4)],
);
declare_function(
state,
"swgl_commitTextureColorRGBA8",
None,
Type::new(Void),
vec![Type::new(*s), Type::new(Vec2), Type::new(Vec4), Type::new(Vec4)],
);
declare_function(
state,
"swgl_commitTextureRepeatRGBA8",
None,
Type::new(Void),
vec![Type::new(*s), Type::new(Vec2), Type::new(Vec2),
Type::new(Vec4), Type::new(Vec4)],
);
declare_function(
state,
"swgl_commitTextureRepeatColorRGBA8",
None,
Type::new(Void),
vec![Type::new(*s), Type::new(Vec2), Type::new(Vec2),
Type::new(Vec4), Type::new(Vec4), Type::new(Vec4)],
);
declare_function(
state,
"swgl_commitGaussianBlurRGBA8",
None,
Type::new(Void),
vec![Type::new(*s), Type::new(Vec2), Type::new(Vec4), Type::new(Bool),
Type::new(Int), Type::new(Vec2)],
);
declare_function(
state,
"swgl_commitGaussianBlurR8",
None,
Type::new(Void),
vec![Type::new(*s), Type::new(Vec2), Type::new(Vec4), Type::new(Bool),
Type::new(Int), Type::new(Vec2)],
);
declare_function(
state,
"swgl_commitTextureLinearYUV",
None,
Type::new(Void),
vec![Type::new(*s), Type::new(Vec2), Type::new(Vec4),
Type::new(Vec3), Type::new(Mat3), Type::new(Int)],
);
declare_function(
state,
"swgl_commitTextureLinearYUV",
None,
Type::new(Void),
vec![Type::new(*s), Type::new(Vec2), Type::new(Vec4),
Type::new(*s), Type::new(Vec2), Type::new(Vec4),
Type::new(Vec3), Type::new(Mat3), Type::new(Int)],
);
declare_function(
state,
"swgl_commitTextureLinearYUV",
None,
Type::new(Void),
vec![Type::new(*s), Type::new(Vec2), Type::new(Vec4),
Type::new(*s), Type::new(Vec2), Type::new(Vec4),
Type::new(*s), Type::new(Vec2), Type::new(Vec4),
Type::new(Vec3), Type::new(Mat3), Type::new(Int)],
);
declare_function(
state,
"swgl_commitTextureLinearColorYUV",
None,
Type::new(Void),
vec![Type::new(*s), Type::new(Vec2), Type::new(Vec4),
Type::new(Vec3), Type::new(Mat3), Type::new(Int),
Type::new(Float)],
);
declare_function(
state,
"swgl_commitTextureLinearColorYUV",
None,
Type::new(Void),
vec![Type::new(*s), Type::new(Vec2), Type::new(Vec4),
Type::new(*s), Type::new(Vec2), Type::new(Vec4),
Type::new(Vec3), Type::new(Mat3), Type::new(Int),
Type::new(Float)],
);
declare_function(
state,
"swgl_commitTextureLinearColorYUV",
None,
Type::new(Void),
vec![Type::new(*s), Type::new(Vec2), Type::new(Vec4),
Type::new(*s), Type::new(Vec2), Type::new(Vec4),
Type::new(*s), Type::new(Vec2), Type::new(Vec4),
Type::new(Vec3), Type::new(Mat3), Type::new(Int),
Type::new(Float)],
);
}
TranslationUnit(tu.0.map(state, translate_external_declaration))
}
fn infer_expr_inner(state: &mut State, expr: &Expr, assign: &mut SymRef) -> RunClass {
match expr.kind {
ExprKind::Variable(ref i) => {
*assign = *i;
match &state.sym(*i).decl {
SymDecl::Local(_, _, ref run_class) => *run_class,
SymDecl::Global(_, _, _, ref run_class) => *run_class,
_ => panic!(),
}
}
ExprKind::IntConst(_)
| ExprKind::UIntConst(_)
| ExprKind::BoolConst(_)
| ExprKind::FloatConst(_)
| ExprKind::DoubleConst(_) => RunClass::Scalar,
ExprKind::Unary(_, ref e) => infer_expr(state, e),
ExprKind::Binary(_, ref l, ref r) => infer_expr(state, l).merge(infer_expr(state, r)),
ExprKind::Ternary(ref c, ref s, ref e) => infer_expr(state, c)
.merge(infer_expr(state, s))
.merge(infer_expr(state, e)),
ExprKind::Assignment(ref v, _, ref e) => {
let mut sym = SymRef(!0);
let run_class = infer_expr_inner(state, v, &mut sym).merge(infer_expr(state, e));
assert!(sym != SymRef(!0));
state.merge_run_class(sym, run_class)
}
ExprKind::Bracket(ref e, ref indx) => {
indx.iter().fold(
infer_expr_inner(state, e, assign),
|run_class, indx| run_class.merge(infer_expr(state, indx)),
)
}
ExprKind::FunCall(ref fun, ref args) => {
let arg_classes: Vec<(RunClass, SymRef)> = args
.iter()
.map(|e| {
let mut assign = SymRef(!0);
let run_class = infer_expr_inner(state, e, &mut assign);
(run_class, assign)
})
.collect();
let run_class = if args.is_empty() {
RunClass::Scalar
} else {
arg_classes
.iter()
.fold(RunClass::Unknown, |x, &(y, _)| x.merge(y))
};
match fun {
FunIdentifier::Identifier(ref sym) => match &state.sym(*sym).decl {
SymDecl::NativeFunction(_, _, ref ret_class) => {
if *ret_class != RunClass::Unknown {
*ret_class
} else {
run_class
}
}
SymDecl::UserFunction(ref fd, ref run_class) => {
for (&(mut arg_class, assign), param) in
arg_classes.iter().zip(fd.prototype.parameters.iter())
{
if let FunctionParameterDeclaration::Named(Some(qual), p) = param {
match qual {
ParameterQualifier::InOut | ParameterQualifier::Out => {
if let SymDecl::Local(_, _, param_class) =
&state.sym(p.sym).decl
{
match param_class {
RunClass::Unknown | RunClass::Vector => {
arg_class = RunClass::Vector;
}
RunClass::Dependent(mask) => {
for i in 0 .. 31 {
if (mask & (1 << i)) != 0 {
arg_class =
arg_class.merge(arg_classes[i].0);
}
}
}
RunClass::Scalar => {}
}
}
assert!(assign != SymRef(!0));
state.merge_run_class(assign, arg_class);
}
_ => {}
}
}
}
if fd.prototype.ty.kind == TypeKind::Void {
RunClass::Scalar
} else {
match *run_class {
RunClass::Unknown | RunClass::Vector => RunClass::Vector,
RunClass::Dependent(mask) => {
let mut ret_class = RunClass::Unknown;
for i in 0 .. 31 {
if (mask & (1 << i)) != 0 {
ret_class = ret_class.merge(arg_classes[i].0);
}
}
ret_class
}
RunClass::Scalar => RunClass::Scalar,
}
}
}
SymDecl::Struct(..) => run_class,
_ => panic!(),
},
FunIdentifier::Constructor(..) => run_class,
}
}
ExprKind::Dot(ref e, _) => infer_expr_inner(state, e, assign),
ExprKind::SwizzleSelector(ref e, _) => infer_expr_inner(state, e, assign),
ExprKind::PostInc(ref e) => infer_expr_inner(state, e, assign),
ExprKind::PostDec(ref e) => infer_expr_inner(state, e, assign),
ExprKind::Comma(ref a, ref b) => {
infer_expr(state, a);
infer_expr(state, b)
}
ExprKind::Cond(_, ref e) => infer_expr(state, e),
ExprKind::CondMask => RunClass::Vector,
}
}
fn infer_expr(state: &mut State, expr: &Expr) -> RunClass {
infer_expr_inner(state, expr, &mut SymRef(!0))
}
fn infer_condition(state: &mut State, c: &Condition) {
match *c {
Condition::Expr(ref e) => {
infer_expr(state, e);
}
}
}
fn infer_iteration_statement(state: &mut State, ist: &IterationStatement) {
let changed = state.run_class_changed.replace(true);
match *ist {
IterationStatement::While(ref cond, ref body) => {
while state.run_class_changed.replace(false) {
infer_condition(state, cond);
infer_statement(state, body);
}
}
IterationStatement::DoWhile(ref body, ref cond) => {
while state.run_class_changed.replace(false) {
infer_statement(state, body);
infer_expr(state, cond);
}
}
IterationStatement::For(ref init, ref rest, ref body) => {
match *init {
ForInitStatement::Expression(ref expr) => {
if let Some(ref e) = *expr {
infer_expr(state, e);
}
}
ForInitStatement::Declaration(ref d) => {
infer_declaration(state, d);
}
}
while state.run_class_changed.replace(false) {
if let Some(ref cond) = rest.condition {
infer_condition(state, cond);
}
if let Some(ref e) = rest.post_expr {
infer_expr(state, e);
}
infer_statement(state, body);
}
}
}
state.run_class_changed.set(changed);
}
fn infer_selection_statement(state: &mut State, sst: &SelectionStatement) {
let mut branch_run_class = state.branch_run_class.merge(infer_expr(state, &sst.cond));
mem::swap(&mut state.branch_run_class, &mut branch_run_class);
let branch_declaration = state.branch_declaration;
state.branch_declaration = state.last_declaration;
infer_statement(state, &sst.body);
if let Some(ref else_st) = sst.else_stmt {
infer_statement(state, else_st);
}
state.branch_run_class = branch_run_class;
state.branch_declaration = branch_declaration;
}
fn infer_expression_statement(state: &mut State, est: &ExprStatement) {
if let Some(ref e) = *est {
infer_expr(state, e);
}
}
fn infer_switch_statement(state: &mut State, sst: &SwitchStatement) {
let mut branch_run_class = state.branch_run_class.merge(infer_expr(state, &sst.head));
mem::swap(&mut state.branch_run_class, &mut branch_run_class);
let branch_declaration = state.branch_declaration;
state.branch_declaration = state.last_declaration;
for case in &sst.cases {
for st in &case.stmts {
infer_statement(state, st);
}
}
state.branch_run_class = branch_run_class;
state.branch_declaration = branch_declaration;
}
fn infer_jump_statement(state: &mut State, j: &JumpStatement) {
match *j {
JumpStatement::Continue => {}
JumpStatement::Break => {}
JumpStatement::Discard => {}
JumpStatement::Return(ref e) => {
if let Some(e) = e {
let run_class = infer_expr(state, e);
state.return_run_class(run_class);
}
}
}
}
fn infer_initializer(state: &mut State, i: &Initializer) -> RunClass {
match *i {
Initializer::Simple(ref e) => infer_expr(state, e),
Initializer::List(ref list) => {
let mut run_class = RunClass::Unknown;
for ini in list.0.iter() {
run_class = run_class.merge(infer_initializer(state, ini));
}
run_class
}
}
}
fn infer_declaration(state: &mut State, d: &Declaration) {
match *d {
Declaration::FunctionPrototype(..) => {}
Declaration::InitDeclaratorList(ref list) => {
state.last_declaration = list.head.name;
let mut run_class = RunClass::Unknown;
for decl in &list.tail {
if let Some(ref initializer) = decl.initializer {
run_class = run_class.merge(infer_initializer(state, initializer));
}
}
if let Some(ref initializer) = list.head.initializer {
run_class = run_class.merge(infer_initializer(state, initializer));
state.merge_run_class(list.head.name, run_class);
}
}
Declaration::Precision(..) => {}
Declaration::Block(..) => {}
Declaration::Global(..) => {}
Declaration::StructDefinition(..) => {}
}
}
fn infer_simple_statement(state: &mut State, sst: &SimpleStatement) {
match *sst {
SimpleStatement::Declaration(ref d) => infer_declaration(state, d),
SimpleStatement::Expression(ref e) => infer_expression_statement(state, e),
SimpleStatement::Selection(ref s) => infer_selection_statement(state, s),
SimpleStatement::Switch(ref s) => infer_switch_statement(state, s),
SimpleStatement::Iteration(ref i) => infer_iteration_statement(state, i),
SimpleStatement::Jump(ref j) => infer_jump_statement(state, j),
}
}
fn infer_compound_statement(state: &mut State, cst: &CompoundStatement) {
for st in &cst.statement_list {
infer_statement(state, st);
}
}
fn infer_statement(state: &mut State, st: &Statement) {
match *st {
Statement::Compound(ref cst) => infer_compound_statement(state, cst),
Statement::Simple(ref sst) => infer_simple_statement(state, sst),
}
}
fn infer_function_definition(state: &mut State, fd: &FunctionDefinition) {
state.in_function = Some(state.lookup(fd.prototype.name.as_str()).unwrap());
state.run_class_changed.set(true);
while state.run_class_changed.replace(false) {
for st in &fd.body.statement_list {
infer_statement(state, st);
}
}
state.in_function = None;
}
fn infer_external_declaration(state: &mut State, ed: &ExternalDeclaration) {
match *ed {
ExternalDeclaration::Preprocessor(_) => {}
ExternalDeclaration::FunctionDefinition(ref fd) => infer_function_definition(state, fd),
ExternalDeclaration::Declaration(_) => {}
}
}
pub fn infer_run_class(state: &mut State, tu: &TranslationUnit) {
for ed in &(tu.0).0 {
infer_external_declaration(state, ed);
}
}