#![feature(box_syntax)]
#![feature(box_patterns)]
extern crate glsl;
#[macro_use]
extern crate nom;
extern crate warmy;
use glsl::syntax::*;
pub use glsl::parser::{ParseError, ParseResult};
use glsl::parser;
use glsl::parsers::{external_declaration, identifier};
use glsl::transpiler;
use nom::alphanumeric;
use std::collections::HashSet;
use std::fmt::{self, Debug, Display, Write};
use std::fs::File;
use std::io::Read;
use std::iter::once;
use std::path::PathBuf;
use std::str::from_utf8_unchecked;
use warmy::{FSKey, Load, Loaded, Res, Storage};
pub type GLSL = Vec<ExternalDeclaration>;
pub fn parse<S>(source: S) -> ParseResult<Module> where S: AsRef<[u8]> {
parser::parse(source.as_ref(), module)
}
pub fn parse_str<S>(source: S) -> ParseResult<Module> where S: AsRef<str> {
parser::parse_str(source.as_ref(), module)
}
#[derive(Clone, Debug, PartialEq)]
pub struct Module {
pub imports: Vec<ImportList>,
pub glsl: GLSL
}
impl Module {
pub fn substitute_imports<C>(
&self,
current_key:
&FSKey,
storage:
&mut Storage<C>,
ctx: &mut C
) -> Result<(Self, Vec<FSKey>), ModuleError>
where C: 'static {
let mut visited = HashSet::new();
let mut parents = HashSet::new();
let mut glsl = Vec::new();
self.rec_substitute_imports(current_key, storage, ctx, &mut visited, &mut parents, &mut glsl)?;
let module = Module { imports: Vec::new(), glsl };
let dep_keys = visited.into_iter().collect();
Ok((module, dep_keys))
}
fn rec_substitute_imports<C>(
&self,
current_key: &FSKey,
storage: &mut Storage<C>,
ctx: &mut C,
visited: &mut HashSet<FSKey>,
parents: &mut HashSet<FSKey>,
glsl: &mut GLSL
) -> Result<(), ModuleError>
where C: 'static {
parents.insert(current_key.clone());
visited.insert(current_key.clone());
for il in &self.imports {
let path = il.to_path();
let key = FSKey::new(&path);
if parents.contains(&key) {
return Err(ModuleError::DepsError(DepsError::Cycle(current_key.clone(), key.clone())));
}
if visited.contains(&key) {
continue;
}
let module: Res<Self> = storage.get(&key, ctx).map_err(|e| ModuleError::DepsError(DepsError::LoadError(key.clone(), box e)))?;
module.borrow().rec_substitute_imports(&key, storage, ctx, visited, parents, glsl)?;
}
glsl.extend(self.glsl.iter().cloned());
parents.remove(current_key);
Ok(())
}
pub fn to_glsl_setup(&self) -> Result<ModuleFold, GLSLConversionError> {
let uniforms = self.uniforms();
let blocks = self.blocks();
let structs = self.structs();
let functions = self.functions();
let globals = self.globals();
let mut common = String::new();
let mut vs = String::new();
let mut gs = String::new();
let mut fs = String::new();
let mut structs_str = String::new();
for uniform in &uniforms {
transpiler::glsl::show_single_declaration(&mut common, uniform);
let _ = common.write_str(";\n");
}
for block in &blocks {
transpiler::glsl::show_block(&mut common, block);
let _ = common.write_str(";\n");
}
for global in &globals {
transpiler::glsl::show_single_declaration(&mut common, global);
let _ = common.write_str(";\n");
}
for f in filter_out_special_functions(functions.iter()) {
transpiler::glsl::show_function_definition(&mut common, f)
}
let mut filter_out_struct_def = Vec::new();
let map_vertex = functions.iter().find(|fd| &fd.prototype.name == "map_vertex")
.ok_or(GLSLConversionError::NoVertexShader)?;
let concat_map_prim = functions.iter().find(|fd| &fd.prototype.name == "concat_map_prim");
let map_frag_data = functions.iter().find(|fd| &fd.prototype.name == "map_frag_data")
.ok_or(GLSLConversionError::NoFragmentShader)?;
let (vertex_ret_ty, vertex_outputs) = sink_vertex_shader(&mut vs, map_vertex, &structs)?;
filter_out_struct_def.push(vertex_ret_ty.name.clone());
let (fs_prev_ret_ty, fs_prev_outputs) = if let Some(concat_map_prim) = concat_map_prim {
let (ret_ty, outputs) = sink_geometry_shader(&mut gs,
&concat_map_prim,
&structs,
&vertex_ret_ty,
&vertex_outputs)?;
filter_out_struct_def.push(ret_ty.name.clone());
(ret_ty, outputs)
} else {
(vertex_ret_ty, vertex_outputs)
};
let (fragment_ret_ty, _) = sink_fragment_shader(&mut fs,
&map_frag_data,
&structs,
&fs_prev_ret_ty,
&fs_prev_outputs)?;
filter_out_struct_def.push(fragment_ret_ty.name.clone());
for s in &structs {
if !filter_out_struct_def.contains(&s.name) {
transpiler::glsl::show_struct(&mut structs_str, s);
}
}
common = structs_str + &common;
if vs.is_empty() {
Err(GLSLConversionError::NoVertexShader)
} else if fs.is_empty() {
Err(GLSLConversionError::NoFragmentShader)
} else {
let setup = ModuleFold {
vs: common.clone() + &vs,
gs: if gs.is_empty() { None } else { Some(gs.clone()) },
fs: common.clone() + &fs
};
Ok(setup)
}
}
fn uniforms(&self) -> Vec<SingleDeclaration> {
let mut uniforms = Vec::new();
for glsl in &self.glsl {
if let ExternalDeclaration::Declaration(Declaration::InitDeclaratorList(ref i)) = *glsl {
if let Some(ref q) = i.head.ty.qualifier {
if q.qualifiers.contains(&TypeQualifierSpec::Storage(StorageQualifier::Uniform)) {
uniforms.push(i.head.clone());
for next in &i.tail {
uniforms.push(SingleDeclaration {
ty: i.head.ty.clone(),
name: Some(next.name.clone()),
array_specifier: next.array_specifier.clone(),
initializer: None
})
}
}
}
}
}
uniforms
}
fn blocks(&self) -> Vec<Block> {
self.glsl.iter().filter_map(|ed| {
match *ed {
ExternalDeclaration::Declaration(Declaration::Block(ref b)) =>
Some(b.clone()),
_ => None
}
}).collect()
}
fn functions(&self) -> Vec<FunctionDefinition> {
self.glsl.iter().filter_map(|ed| match *ed {
ExternalDeclaration::FunctionDefinition(ref def) => Some(def.clone()),
_ => None
}).collect()
}
fn structs(&self) -> Vec<StructSpecifier> {
self.glsl.iter().filter_map(|ed| {
match *ed {
ExternalDeclaration::Declaration(
Declaration::InitDeclaratorList(
InitDeclaratorList {
head: SingleDeclaration {
ty: FullySpecifiedType {
ty: TypeSpecifier {
ty: TypeSpecifierNonArray::Struct(ref s),
..
},
..
},
..
},
..
}
)
) => Some(s.clone()),
_ => None
}
}).collect()
}
fn globals(&self) -> Vec<SingleDeclaration> {
let mut consts = Vec::new();
{
let mut push_const = |i: &InitDeclaratorList| {
consts.push(i.head.clone());
for next in &i.tail {
consts.push(SingleDeclaration {
ty: i.head.ty.clone(),
name: Some(next.name.clone()),
array_specifier: next.array_specifier.clone(),
initializer: None
});
}
};
for glsl in &self.glsl {
if let ExternalDeclaration::Declaration(Declaration::InitDeclaratorList(ref i)) = *glsl {
if let TypeSpecifierNonArray::Struct(_) = i.head.ty.ty.ty {
continue;
}
if let Some(ref q) = i.head.ty.qualifier {
match q.qualifiers.as_slice() {
&[TypeQualifierSpec::Storage(StorageQualifier::Const)] => {
push_const(i);
}
_ => ()
}
} else {
push_const(i);
}
}
}
}
consts
}
}
impl<C> Load<C> for Module {
type Key = FSKey;
type Error = ModuleError;
fn load(key: Self::Key, _: &mut Storage<C>, _: &mut C) -> Result<Loaded<Self>, Self::Error> {
let path = key.as_path();
let mut fh = File::open(path).map_err(|_| ModuleError::FileNotFound(path.into()))?;
let mut src = String::new();
let _ = fh.read_to_string(&mut src);
match parser::parse_str(&src[..], module) {
ParseResult::Ok(module) => {
Ok(module.into())
}
ParseResult::Err(e) => Err(ModuleError::ParseFailed(e)),
_ => Err(ModuleError::IncompleteInput)
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ImportList {
pub module: ModulePath,
pub list: Vec<ModuleSymbol>
}
impl ImportList {
pub fn to_path(&self) -> PathBuf {
PathBuf::from(self.module.path.join("/") + ".chdr")
}
}
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
pub struct ModulePath {
pub path: Vec<ModuleName>
}
pub type ModuleName = String;
pub type ModuleSymbol = String;
pub type ExpectedNumberOfArgs = usize;
pub type FoundNumberOfArgs = usize;
#[derive(Clone, Debug, PartialEq)]
pub enum GLSLConversionError {
NoVertexShader,
NoFragmentShader,
OutputHasMainQualifier,
ReturnTypeMustBeAStruct(TypeSpecifier),
WrongOutputFirstField(StructFieldSpecifier),
OutputFieldCannotBeStruct(usize, StructSpecifier),
OutputFieldCannotBeTypeName(usize, TypeName),
OutputFieldCannotHaveSeveralIdentifiers(usize, StructFieldSpecifier),
UnknownInputType(TypeName),
WrongNumberOfArgs(ExpectedNumberOfArgs, FoundNumberOfArgs),
NotTypeName,
WrongGeometryInput,
WrongGeometryInputDim(usize),
WrongGeometryOutputLayout(Option<TypeQualifier>)
}
impl Display for GLSLConversionError {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
GLSLConversionError::NoVertexShader => {
f.write_str("no vertex shader")
}
GLSLConversionError::NoFragmentShader => {
f.write_str("no fragment shader")
}
GLSLConversionError::OutputHasMainQualifier => {
f.write_str("output has main qualifier(s)")
}
GLSLConversionError::ReturnTypeMustBeAStruct(_) => {
write!(f, "return type is not a struct")
}
GLSLConversionError::WrongOutputFirstField(_) => {
write!(f, "first field’s type is forbidden as output")
}
GLSLConversionError::OutputFieldCannotBeStruct(idx, _) => {
write!(f, "output field {} cannot be a struct", idx)
}
GLSLConversionError::OutputFieldCannotBeTypeName(idx, _) => {
write!(f, "output field {} cannot be a type name", idx)
}
GLSLConversionError::OutputFieldCannotHaveSeveralIdentifiers(idx, _) => {
write!(f, "output field {} cannot have several identifiers", idx)
}
GLSLConversionError::UnknownInputType(ref ty) => {
write!(f, "unknown input type {}", ty)
}
GLSLConversionError::WrongNumberOfArgs(expected, found) => {
write!(f, "expected {} arguments, found {}", expected, found)
}
GLSLConversionError::NotTypeName => {
f.write_str("not a type name")
}
GLSLConversionError::WrongGeometryInput => {
f.write_str("wrong geometry input")
}
GLSLConversionError::WrongGeometryInputDim(dim) => {
write!(f, "wrong geometry input’s dimension {}", dim)
}
GLSLConversionError::WrongGeometryOutputLayout(_) => {
f.write_str("wrong geometry output layout")
}
}
}
}
#[derive(Debug)]
pub enum DepsError {
Cycle(FSKey, FSKey),
LoadError(FSKey, Box<Debug>),
}
impl Display for DepsError {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
DepsError::Cycle(ref a, ref b) => {
write!(f, "module cycle beetwen {} and {}", a.as_path().display(), b.as_path().display())
}
DepsError::LoadError(ref path, ref e) => {
write!(f, "error in {}: {:?}", path.as_path().display(), e)
}
}
}
}
#[derive(Debug)]
pub enum ModuleError {
FileNotFound(PathBuf),
ParseFailed(ParseError),
IncompleteInput,
DepsError(DepsError)
}
impl Display for ModuleError {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
ModuleError::FileNotFound(ref path) => {
write!(f, "cannot find {}", path.display())
}
ModuleError::ParseFailed(ref e) => {
write!(f, "parse error: {}", e)
}
ModuleError::IncompleteInput => {
f.write_str("incomplete input")
}
ModuleError::DepsError(ref e) => {
write!(f, "dependency error: {}", e)
}
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ModuleFold {
pub vs: String,
pub gs: Option<String>,
pub fs: String
}
fn sink_single_as_ext_decls<'a, F, I>(sink: &mut F, s: I)
where I: IntoIterator<Item = &'a SingleDeclaration>,
F: Write {
for sd in s {
let ed = single_to_external_declaration(sd.clone());
transpiler::glsl::show_external_declaration(sink, &ed);
}
}
fn single_to_external_declaration(sd: SingleDeclaration) -> ExternalDeclaration {
ExternalDeclaration::Declaration(
Declaration::InitDeclaratorList(
InitDeclaratorList {
head: sd,
tail: Vec::new()
}
)
)
}
fn input_from_output(output: SingleDeclaration, has_array: bool) -> SingleDeclaration {
let
qualifier = output.ty.qualifier.map(|q| {
TypeQualifier {
qualifiers: q.qualifiers.into_iter().map(|qs| {
match qs {
TypeQualifierSpec::Storage(StorageQualifier::Out) =>
TypeQualifierSpec::Storage(StorageQualifier::In),
_ => qs
}
}).collect()
}
});
let ty =
TypeSpecifier {
array_specifier: if has_array { Some(ArraySpecifier::Unsized) } else { None },
.. output.ty.ty
};
SingleDeclaration {
ty: FullySpecifiedType { qualifier, ty },
.. output
}
}
fn inputs_from_outputs(outputs: &[SingleDeclaration], has_array: bool) -> Vec<SingleDeclaration> {
outputs.into_iter().map(|sd| input_from_output(sd.clone(), has_array)).collect()
}
fn field_to_single_decl(field: &StructFieldSpecifier, prefix: &str) -> SingleDeclaration {
let base_qualifier = TypeQualifierSpec::Storage(StorageQualifier::Out);
let qualifier = match field.qualifier {
Some(ref qual) =>
TypeQualifier {
qualifiers: qual.clone().qualifiers.into_iter().chain(once(base_qualifier)).collect()
},
None => TypeQualifier {
qualifiers: vec![base_qualifier]
}
};
let fsty = FullySpecifiedType {
qualifier: Some(qualifier),
ty: field.ty.clone()
};
SingleDeclaration {
ty: fsty,
name: Some(prefix.to_owned() + &field.identifiers[0].0),
array_specifier: field.identifiers[0].1.clone(),
initializer: None
}
}
fn fields_to_single_decls(fields: &[StructFieldSpecifier], prefix: &str)
-> Result<Vec<SingleDeclaration>, GLSLConversionError> {
let mut outputs = Vec::new();
for (i, field) in fields.into_iter().enumerate() {
match field.ty.ty {
TypeSpecifierNonArray::Struct(ref s) => {
return Err(GLSLConversionError::OutputFieldCannotBeStruct(i + 1, s.clone()));
}
TypeSpecifierNonArray::TypeName(ref t) => {
return Err(GLSLConversionError::OutputFieldCannotBeTypeName(i + 1, t.clone()));
}
_ => ()
}
if field.identifiers.len() > 1 {
return Err(GLSLConversionError::OutputFieldCannotHaveSeveralIdentifiers(i + 1, field.clone()));
}
outputs.push(field_to_single_decl(&field, prefix));
}
Ok(outputs)
}
fn remove_unused_args_fn(f: &FunctionDefinition) -> FunctionDefinition {
let f = f.clone();
FunctionDefinition {
prototype: FunctionPrototype {
parameters: f.prototype.parameters.into_iter().filter(is_fn_arg_named).collect(),
.. f.prototype
},
.. f
}
}
fn is_fn_arg_named(arg: &FunctionParameterDeclaration) -> bool {
if let FunctionParameterDeclaration::Named(..) = *arg {
true
} else {
false
}
}
fn fn_arg_as_fully_spec_ty(arg: &FunctionParameterDeclaration) -> FullySpecifiedType {
match *arg {
FunctionParameterDeclaration::Named(ref qualifier, FunctionParameterDeclarator {
ref ty,
..
}) => FullySpecifiedType {
qualifier: qualifier.clone(),
ty: ty.clone()
},
FunctionParameterDeclaration::Unnamed(ref qualifier, ref ty) => {
FullySpecifiedType {
qualifier: qualifier.clone(),
ty: ty.clone()
}
}
}
}
fn get_ty_name_from_fully_spec_ty(fst: &FullySpecifiedType) -> Result<TypeName, GLSLConversionError> {
if let TypeSpecifierNonArray::TypeName(ref n) = fst.ty.ty {
Ok(n.clone())
} else {
Err(GLSLConversionError::NotTypeName)
}
}
fn get_fn1_input_ty_name(f: &FunctionDefinition) -> Result<TypeName, GLSLConversionError> {
let slice = f.prototype.parameters.as_slice();
match slice {
&[ref arg] => {
let fst = fn_arg_as_fully_spec_ty(arg);
get_ty_name_from_fully_spec_ty(&fst)
}
_ => Err(GLSLConversionError::WrongNumberOfArgs(1, slice.len()))
}
}
fn get_fn_ret_ty(f: &FunctionDefinition, structs: &[StructSpecifier]) -> Result<StructSpecifier, GLSLConversionError> {
struct_from_ty_spec(&f.prototype.ty.ty, structs)
}
fn struct_from_ty_spec(
ty_spec: &TypeSpecifier,
structs: &[StructSpecifier]
) -> Result<StructSpecifier, GLSLConversionError> {
if let TypeSpecifierNonArray::TypeName(ref name) = ty_spec.ty {
if let Some(ref ty) = structs.iter().find(|ref s| s.name.as_ref() == Some(name)) {
Ok((*ty).clone())
} else {
Err(GLSLConversionError::ReturnTypeMustBeAStruct(ty_spec.clone()))
}
} else {
Err(GLSLConversionError::ReturnTypeMustBeAStruct(ty_spec.clone()))
}
}
fn drop_1st_field(s: &StructSpecifier) -> StructSpecifier {
StructSpecifier {
name: s.name.clone(),
fields: s.fields.iter().skip(1).cloned().collect(),
}
}
#[inline]
fn bytes_to_string(bytes: &[u8]) -> String {
unsafe { from_utf8_unchecked(bytes).to_owned() }
}
named!(module_sep_n_name,
do_parse!(
char!('.') >>
name: alphanumeric >>
(name)
)
);
named!(module_path<&[u8], ModulePath>,
do_parse!(
base: identifier >>
rest: many0!(module_sep_n_name) >>
({
let mut rest = rest.clone();
rest.insert(0, base.as_bytes());
ModulePath {
path: rest.into_iter().map(bytes_to_string).collect()
}
})
)
);
named!(symbol_list<&[u8], Vec<ModuleSymbol>>,
ws!(
delimited!(char!('('),
separated_list!(char!(','), identifier),
char!(')')
)
)
);
named!(import_list<&[u8], ImportList>,
ws!(do_parse!(
tag!("use") >>
from_module: module_path >>
symbols: symbol_list >>
(ImportList { module: from_module, list: symbols })
))
);
named!(module<&[u8], Module>,
ws!(do_parse!(
imports: many0!(import_list) >>
glsl: many0!(external_declaration) >>
(Module { imports, glsl })
))
);
fn sink_vertex_shader<F>(sink: &mut F,
map_vertex: &FunctionDefinition,
structs: &[StructSpecifier])
-> Result<(StructSpecifier, Vec<SingleDeclaration>), GLSLConversionError>
where F: Write {
let inputs = vertex_shader_inputs(&map_vertex.prototype.parameters)?;
let outputs = vertex_shader_outputs(&map_vertex.prototype.ty, structs)?;
let ret_ty = get_fn_ret_ty(map_vertex, structs)?;
sink_single_as_ext_decls(sink, inputs.iter().chain(&outputs));
transpiler::glsl::show_struct(sink, &ret_ty);
let map_vertex_reduced = remove_unused_args_fn(map_vertex);
transpiler::glsl::show_function_definition(sink, &map_vertex_reduced);
let _ = sink.write_str("void main() {\n ");
let mut assigns = String::new();
sink_vertex_shader_output(sink, &mut assigns, &ret_ty);
let _ = sink.write_str(" v = map_vertex(");
sink_vertex_shader_input_args(sink, &map_vertex_reduced);
let _ = sink.write_str(");\n");
let _ = sink.write_str(&assigns);
let _ = sink.write_str("}\n\n");
Ok((ret_ty, outputs))
}
fn sink_vertex_shader_output<F, G>(sink: &mut F, assigns: &mut G, ty: &StructSpecifier) where F: Write, G: Write {
if let Some(ref name) = ty.name {
let _ = sink.write_str(name);
} else {
panic!("cannot happen");
}
let _ = assigns.write_str(" gl_Position = v.chdr_Position;\n");
for field in &ty.fields[1..] {
for &(ref identifier, _) in &field.identifiers {
let _ = write!(assigns, " chdr_v_{0} = v.{0};\n", identifier);
}
}
}
fn sink_vertex_shader_input_args<F>(sink: &mut F, map_vertex: &FunctionDefinition) where F: Write {
let args = &map_vertex.prototype.parameters;
if !args.is_empty() {
let first_arg = &args[0];
sink_vertex_shader_input_arg(sink, 0, first_arg);
for (i, arg) in map_vertex.prototype.parameters[1..].iter().enumerate() {
if is_fn_arg_named(arg) {
let _ = sink.write_str(", ");
sink_vertex_shader_input_arg(sink, i + 1, arg);
}
}
}
}
fn sink_vertex_shader_input_arg<F>(sink: &mut F, i: usize, arg: &FunctionParameterDeclaration) where F: Write {
match *arg {
FunctionParameterDeclaration::Named(_, ref d) => {
let _ = write!(sink, "chdr_{}", d.name);
}
FunctionParameterDeclaration::Unnamed(..) => {
let _ = write!(sink, "chdr_unused{}", i);
}
}
}
fn vertex_shader_input_qualifier(i: usize, ty_qual: &Option<TypeQualifier>) -> TypeQualifier {
let layout_qualifier = LayoutQualifier {
ids: vec![LayoutQualifierSpec::Identifier("location".to_owned(),
Some(box Expr::IntConst(i as i32)))]
};
let base_qualifier = TypeQualifier {
qualifiers: vec![
TypeQualifierSpec::Layout(layout_qualifier),
TypeQualifierSpec::Storage(StorageQualifier::In)
]
};
match *ty_qual {
Some(ref qual) => TypeQualifier {
qualifiers: base_qualifier.qualifiers.into_iter().chain(qual.clone().qualifiers).collect()
},
None => base_qualifier
}
}
fn vertex_shader_inputs<'a, I>(args: I) -> Result<Vec<SingleDeclaration>, GLSLConversionError>
where I: IntoIterator<Item = &'a FunctionParameterDeclaration> {
let mut inputs = Vec::new();
for (i, arg) in args.into_iter().enumerate() {
match *arg {
FunctionParameterDeclaration::Named(ref ty_qual, ref decl) => {
let qualifier = vertex_shader_input_qualifier(i, ty_qual);
let ty = decl.ty.clone();
let name = Some(format!("chdr_{}", decl.name));
let array_spec = decl.array_spec.clone();
let sd =
SingleDeclaration {
ty: FullySpecifiedType {
qualifier: Some(qualifier),
ty
},
name,
array_specifier: array_spec,
initializer: None
};
inputs.push(sd);
}
_ => ()
}
}
Ok(inputs)
}
fn vertex_shader_outputs(fsty: &FullySpecifiedType, structs: &[StructSpecifier]) -> Result<Vec<SingleDeclaration>, GLSLConversionError> {
if fsty.qualifier.is_some() {
return Err(GLSLConversionError::OutputHasMainQualifier);
}
let ty = &fsty.ty;
match ty.ty {
TypeSpecifierNonArray::TypeName(ref ty_name) => {
let real_ty = structs.iter().find(|ref s| s.name.as_ref() == Some(ty_name));
match real_ty {
Some(ref s) => {
check_1st_field_chdr_position(&s.fields[0])?;
fields_to_single_decls(&s.fields[1..], "chdr_v_")
}
_ => Err(GLSLConversionError::ReturnTypeMustBeAStruct(ty.clone()))
}
}
_ => Err(GLSLConversionError::ReturnTypeMustBeAStruct(ty.clone()))
}
}
fn check_1st_field_chdr_position(field: &StructFieldSpecifier) -> Result<(), GLSLConversionError> {
if field.qualifier.is_some() ||
field.ty.ty != TypeSpecifierNonArray::Vec4 ||
field.identifiers.as_slice() != &[("chdr_Position".to_owned(), None)] {
Err(GLSLConversionError::WrongOutputFirstField(field.clone()))
} else {
Ok(())
}
}
fn sink_geometry_shader<F>(
sink: &mut F,
concat_map_prim: &FunctionDefinition,
structs: &[StructSpecifier],
prev_ret_ty: &StructSpecifier,
prev_inputs: &[SingleDeclaration],
) -> Result<(StructSpecifier, Vec<SingleDeclaration>),
GLSLConversionError>
where F: Write {
let fn_args = concat_map_prim.prototype.parameters.as_slice();
let (input_ty_name, input_dim, input_layout, output_ty, output_layout) = match fn_args {
&[ref arg0, ref arg1] => {
let input = fn_arg_as_fully_spec_ty(arg0);
let output = fn_arg_as_fully_spec_ty(arg1);
let output_ty = struct_from_ty_spec(&output.ty, structs)?;
let input_ty_name = get_ty_name_from_fully_spec_ty(&input)?;
let (input_dim, input_layout) = guess_gs_input_prim(&input.ty.array_specifier)?;
let output_layout = get_gs_output_layout_metadata(&output.qualifier)?;
Ok((input_ty_name, input_dim, input_layout, output_ty, output_layout))
}
_ => Err(GLSLConversionError::WrongNumberOfArgs(2, fn_args.len()))
}?;
if Some(&input_ty_name) != prev_ret_ty.name.as_ref() {
return Err(GLSLConversionError::UnknownInputType(input_ty_name.clone()));
}
check_1st_field_chdr_position(&output_ty.fields[0])?;
let gs_metadata_input = gs_layout_storage_external_decl(input_layout, StorageQualifier::In);
let gs_metadata_output = gs_layout_storage_external_decl(output_layout, StorageQualifier::Out);
transpiler::glsl::show_external_declaration(sink, &gs_metadata_input);
transpiler::glsl::show_external_declaration(sink, &gs_metadata_output);
let inputs = inputs_from_outputs(prev_inputs, true);
let outputs = fields_to_single_decls(&output_ty.fields[1..], "chdr_g_")?;
sink_single_as_ext_decls(sink, inputs.iter().chain(&outputs));
transpiler::glsl::show_struct(sink, prev_ret_ty);
transpiler::glsl::show_struct(sink, &output_ty);
let concat_map_prim_fixed = unannotate_concat_map_prim(concat_map_prim.clone(), &output_ty)?;
transpiler::glsl::show_function_definition(sink, &concat_map_prim_fixed);
let _ = sink.write_str("void main() {\n ");
let v_name = "v";
let _ = transpiler::glsl::show_statement(sink, &gs_create_vertex_array(&prev_ret_ty, input_dim, v_name));
let _ = write!(sink, " concat_map_prim({});\n", v_name);
let _ = sink.write_str("}\n\n");
Ok((output_ty, outputs))
}
fn sink_fragment_shader<F>(sink: &mut F,
map_frag_data: &FunctionDefinition,
structs: &[StructSpecifier],
prev_ret_ty: &StructSpecifier,
prev_inputs: &[SingleDeclaration],
) -> Result<(StructSpecifier, Vec<SingleDeclaration>), GLSLConversionError>
where F: Write {
let input_ty_name = get_fn1_input_ty_name(map_frag_data)?;
if Some(&input_ty_name) != prev_ret_ty.name.as_ref() {
return Err(GLSLConversionError::UnknownInputType(input_ty_name.clone()));
}
let inputs = inputs_from_outputs(prev_inputs, false);
let ret_ty = get_fn_ret_ty(map_frag_data, structs)?;
let outputs = fields_to_single_decls(&ret_ty.fields, "chdr_f_")?;
sink_single_as_ext_decls(sink, inputs.iter().chain(&outputs));
if prev_ret_ty.fields.len() > 1 {
let dropped_ret_ty = drop_1st_field(&prev_ret_ty);
transpiler::glsl::show_struct(sink, &dropped_ret_ty);
}
transpiler::glsl::show_struct(sink, &ret_ty);
let map_frag_data_reduced = remove_unused_args_fn(map_frag_data);
transpiler::glsl::show_function_definition(sink, &map_frag_data_reduced);
let _ = sink.write_str("void main() {\n");
if inputs.len() > 0 {
let _ = write!(sink, "{0} i = {0}(", prev_ret_ty.name.as_ref().unwrap());
let _ = sink.write_str(inputs[0].name.as_ref().unwrap());
for input in &inputs[1..] {
let _ = write!(sink, ", {}", input.name.as_ref().unwrap());
}
let _ = sink.write_str(");\n");
let _ = write!(sink, " {} o = {}(i);\n", ret_ty.name.as_ref().unwrap(), "map_frag_data");
} else {
let _ = write!(sink, " {} o = {}();\n", ret_ty.name.as_ref().unwrap(), "map_frag_data");
}
for (output, ret_ty_field) in outputs.iter().zip(&ret_ty.fields) {
let _ = write!(sink, " {} = o.{};\n", output.name.as_ref().unwrap(), ret_ty_field.identifiers[0].0);
}
let _ = sink.write_str("}\n\n");
Ok((ret_ty, outputs))
}
fn filter_out_special_functions<'a, I>(
functions: I
) -> impl Iterator<Item = &'a FunctionDefinition>
where I: Iterator<Item = &'a FunctionDefinition>
{
functions.filter(|f| {
let n: &str = &f.prototype.name;
n != "map_vertex" && n != "concat_map_prim" && n != "map_frag_data"
})
}
fn guess_gs_input_prim(array_specifier: &Option<ArraySpecifier>) -> Result<(usize, LayoutQualifier), GLSLConversionError> {
match *array_specifier {
Some(ArraySpecifier::ExplicitlySized(box Expr::IntConst(size))) => {
match size {
1 => Ok((1, LayoutQualifier { ids: vec![LayoutQualifierSpec::Identifier("points".to_owned(), None)] })),
2 => Ok((2, LayoutQualifier { ids: vec![LayoutQualifierSpec::Identifier("lines".to_owned(), None)] })),
3 => Ok((3, LayoutQualifier { ids: vec![LayoutQualifierSpec::Identifier("triangles".to_owned(), None)] })),
4 => Ok((4, LayoutQualifier { ids: vec![LayoutQualifierSpec::Identifier("lines_adjacency".to_owned(), None)] })),
6 => Ok((6, LayoutQualifier { ids: vec![LayoutQualifierSpec::Identifier("triangles_adjacency".to_owned(), None)] })),
_ => Err(GLSLConversionError::WrongGeometryInputDim(size as usize))
}
},
_ => Err(GLSLConversionError::WrongGeometryInput)
}
}
fn gs_layout_storage_external_decl(
layout: LayoutQualifier,
storage: StorageQualifier
) -> ExternalDeclaration {
let ty_qual =
TypeQualifier {
qualifiers:
vec![
TypeQualifierSpec::Layout(layout),
TypeQualifierSpec::Storage(storage)
]
};
ExternalDeclaration::Declaration(Declaration::Global(ty_qual, Vec::new()))
}
fn get_gs_output_layout_metadata(qual: &Option<TypeQualifier>) -> Result<LayoutQualifier, GLSLConversionError> {
let qual = qual.as_ref().ok_or(GLSLConversionError::WrongGeometryOutputLayout(qual.clone()))?;
match qual.qualifiers.as_slice() {
&[TypeQualifierSpec::Layout(ref layout_qual), TypeQualifierSpec::Storage(StorageQualifier::Out)] => {
match layout_qual.ids.as_slice() {
&[LayoutQualifierSpec::Identifier(ref output_prim_str, None),
LayoutQualifierSpec::Identifier(ref max_vertices_str, Some(box Expr::IntConst(_)))] if max_vertices_str == "max_vertices" => {
if check_gs_output_prim(output_prim_str) {
Ok(layout_qual.clone())
} else {
Err(GLSLConversionError::WrongGeometryOutputLayout(Some(qual.clone())))
}
},
_ => Err(GLSLConversionError::WrongGeometryOutputLayout(Some(qual.clone())))
}
},
_ => Err(GLSLConversionError::WrongGeometryOutputLayout(Some(qual.clone())))
}
}
fn check_gs_output_prim(s: &str) -> bool {
match s {
"points" | "line_strip" | "triangle_strip" => true,
_ => false
}
}
fn unannotate_concat_map_prim(f: FunctionDefinition, out_ty: &StructSpecifier) -> Result<FunctionDefinition, GLSLConversionError> {
let st = f.statement.statement_list.iter().map(|st| unyield_stmt(st, out_ty)).collect::<Result<_, _>>()?;
Ok(FunctionDefinition {
prototype: FunctionPrototype {
parameters: f.prototype.parameters.into_iter().take(1).collect(),
.. f.prototype
},
statement: CompoundStatement {
statement_list: st
}
})
}
fn unyield_stmt(st: &Statement, out_ty: &StructSpecifier) -> Result<Statement, GLSLConversionError> {
match *st {
Statement::Simple(box ref sst) => {
match *sst {
SimpleStatement::Expression(
Some(
Expr::FunCall(FunIdentifier::Identifier(ref fni), ref args))) => {
match fni.as_str() {
"yield_vertex" => yield_vertex(&args, out_ty),
"yield_primitive" => Ok(yield_primitive()),
_ => Ok(st.clone())
}
}
SimpleStatement::Selection(ref sst) => {
let st =
Statement::Simple(
box SimpleStatement::Selection(
SelectionStatement {
rest:
match sst.rest {
SelectionRestStatement::Statement(box ref st) =>
SelectionRestStatement::Statement(box unyield_stmt(&st, out_ty)?),
SelectionRestStatement::Else(box ref ist, box ref est) =>
SelectionRestStatement::Else(box unyield_stmt(&ist, out_ty)?, box unyield_stmt(&est, out_ty)?)
},
.. sst.clone()
}
)
);
Ok(st)
}
SimpleStatement::Switch(ref sst) => {
let st =
Statement::Simple(
box SimpleStatement::Switch(
SwitchStatement {
head: sst.head.clone(),
body: sst.body.iter().map(|s| unyield_stmt(&s, out_ty)).collect::<Result<_, _>>()?
}
)
);
Ok(st)
}
SimpleStatement::Iteration(ref ist) => {
match *ist {
IterationStatement::While(ref cond, box ref s) => {
let st =
Statement::Simple(
box SimpleStatement::Iteration(
IterationStatement::While(cond.clone(), box unyield_stmt(&s, out_ty)?)
)
);
Ok(st)
}
IterationStatement::DoWhile(box ref s, ref x) => {
let st =
Statement::Simple(
box SimpleStatement::Iteration(
IterationStatement::DoWhile(box unyield_stmt(&s, out_ty)?, x.clone())
)
);
Ok(st)
}
IterationStatement::For(ref i, ref cond, box ref s) => {
let st =
Statement::Simple(
box SimpleStatement::Iteration(
IterationStatement::For(i.clone(), cond.clone(), box unyield_stmt(&s, out_ty)?)
)
);
Ok(st)
}
}
}
_ => Ok(st.clone())
}
}
Statement::Compound(box CompoundStatement { statement_list: ref stmts }) => {
let st =
Statement::Compound(
box CompoundStatement {
statement_list: stmts.iter().map(|s| unyield_stmt(s, out_ty)).collect::<Result<_, _>>()?
}
);
Ok(st)
}
}
}
fn yield_vertex(args: &[Expr], out_ty: &StructSpecifier) -> Result<Statement, GLSLConversionError> {
match args {
&[ref arg] => {
let binding = Statement::Simple(
box SimpleStatement::Declaration(
Declaration::InitDeclaratorList(
InitDeclaratorList {
head: SingleDeclaration {
ty: FullySpecifiedType {
qualifier: None,
ty: TypeSpecifier {
ty: TypeSpecifierNonArray::TypeName(out_ty.name.as_ref().unwrap().clone()),
array_specifier: None
},
},
name: Some("chdr_v".to_owned()),
array_specifier: None,
initializer: Some(Initializer::Simple(box arg.clone()))
},
tail: Vec::new()
}
)
)
);
let bvar = box Expr::Variable("chdr_v".to_owned());
let assign_gl_position =
Statement::Simple(
box SimpleStatement::Expression(
Some(Expr::Assignment(
box Expr::Variable("gl_Position".to_owned()),
AssignmentOp::Equal,
box Expr::Dot(bvar.clone(), "chdr_Position".to_owned())
))
)
);
let assigns = out_ty.fields.iter().skip(1).flat_map(|field| field.identifiers.iter().map(|&(ref field_name, _)| {
Statement::Simple(
box SimpleStatement::Expression(
Some(Expr::Assignment(
box Expr::Variable("chdr_g_".to_owned() + field_name),
AssignmentOp::Equal,
box Expr::Dot(bvar.clone(), field_name.to_owned())
))
)
)
}));
let emit =
Statement::Simple(
box SimpleStatement::Expression(
Some(Expr::FunCall(FunIdentifier::Identifier("EmitVertex".to_owned()),
Vec::new()))
)
);
let block =
CompoundStatement {
statement_list:
once(binding)
.chain(once(assign_gl_position))
.chain(assigns)
.chain(once(emit))
.collect()
};
Ok(Statement::Compound(box block))
},
_ => Err(GLSLConversionError::WrongNumberOfArgs(1, args.len()))
}
}
fn yield_primitive() -> Statement {
Statement::Simple(
box SimpleStatement::Expression(
Some(Expr::FunCall(
FunIdentifier::Identifier("EndPrimitive".to_owned()),
Vec::new())
)
)
)
}
fn gs_create_vertex_array(v_ty: &StructSpecifier, dim: usize, binding_name: &str) -> Statement {
let v_ty_name = v_ty.name.as_ref().unwrap();
let fun_id =
FunIdentifier::Expr(
box Expr::Bracket(box Expr::Variable(v_ty_name.to_owned()),
ArraySpecifier::Unsized
)
);
let fun_args =
(0..dim).into_iter().map(|i| {
let v_ctor_args =
v_ty.fields.iter().flat_map(|field| field.identifiers.iter().map(|&(ref field_name, _)| {
Expr::Bracket(box Expr::Variable(format!("chdr_v_{}", field_name)),
ArraySpecifier::ExplicitlySized(
box Expr::IntConst(i as i32)
)
)
})).collect();
Expr::FunCall(FunIdentifier::Identifier(v_ty_name.to_owned()), v_ctor_args)
}).collect();
let rhs = Expr::FunCall(fun_id, fun_args);
let res_ty = TypeSpecifier {
ty: TypeSpecifierNonArray::TypeName(v_ty_name.to_owned()),
array_specifier: Some(ArraySpecifier::ExplicitlySized(box Expr::IntConst(dim as i32)))
};
Statement::Simple(
box SimpleStatement::Declaration(
Declaration::InitDeclaratorList(
InitDeclaratorList {
head:
SingleDeclaration {
ty:
FullySpecifiedType {
qualifier: None,
ty: res_ty,
},
name: Some(binding_name.to_owned()),
array_specifier: None,
initializer: Some(Initializer::Simple(box rhs))
},
tail: Vec::new()
}
)
)
)
}
#[cfg(test)]
mod tests {
use nom::IResult;
use super::*;
#[test]
fn parse_module_sep_n_name() {
assert_eq!(module_sep_n_name(&b".foo"[..]), IResult::Done(&b""[..], &b"foo"[..]));
assert_eq!(module_sep_n_name(&b".foo.bar"[..]), IResult::Done(&b".bar"[..], &b"foo"[..]));
}
#[test]
fn parse_module_path_simple() {
assert_eq!(module_path(&b"foo"[..]), IResult::Done(&b""[..], ModulePath { path: vec!["foo".into()] }));
assert_eq!(module_path(&b" \n\tfoo \n"[..]), IResult::Done(&b""[..], ModulePath { path: vec!["foo".into()] }));
}
#[test]
fn parse_module_path_several() {
assert_eq!(module_path(&b"foo.bar.zoo"[..]), IResult::Done(&b""[..], ModulePath { path: vec!["foo".into(), "bar".into(), "zoo".into()] }));
}
#[test]
fn parse_symbol_list() {
let foo = "foo".to_owned();
let bar = "bar".to_owned();
let zoo = "zoo".to_owned();
let list = vec![foo, bar, zoo];
assert_eq!(symbol_list(&b"(foo,bar,zoo)"[..]), IResult::Done(&b""[..], list.clone()));
assert_eq!(symbol_list(&b" ( foo,bar,zoo ) "[..]), IResult::Done(&b""[..], list.clone()));
assert_eq!(symbol_list(&b"( foo, bar , zoo )"[..]), IResult::Done(&b""[..], list.clone()));
}
#[test]
fn parse_import_list() {
let foo = "foo".to_owned();
let bar = "bar".to_owned();
let zoo_woo = ModulePath { path: vec!["zoo".into(), "woo".into()] };
let expected = ImportList { module: zoo_woo, list: vec![foo, bar] };
assert_eq!(import_list(&b"use zoo.woo (foo, bar)"[..]), IResult::Done(&b""[..], expected.clone()));
assert_eq!(import_list(&b" use zoo.woo ( foo , bar )"[..]), IResult::Done(&b""[..], expected.clone()));
assert_eq!(import_list(&b"use zoo.woo (foo,\nbar)"[..]), IResult::Done(&b""[..], expected.clone()));
}
}