diff --git a/src/front/glsl_new/ast.rs b/src/front/glsl_new/ast.rs index f3a5813817..baee50c6ab 100644 --- a/src/front/glsl_new/ast.rs +++ b/src/front/glsl_new/ast.rs @@ -1,6 +1,6 @@ use crate::{ - Arena, Constant, Expression, FastHashMap, Function, GlobalVariable, Handle, LocalVariable, - ShaderStage, Statement, Type, + Arena, Binding, Constant, Expression, FastHashMap, Function, GlobalVariable, Handle, + LocalVariable, ShaderStage, Statement, StorageClass, Type, }; #[derive(Debug)] @@ -14,6 +14,7 @@ pub struct Program { pub types: Arena, pub constants: Arena, pub global_variables: Arena, + pub lookup_global_variables: FastHashMap>, pub context: Context, } @@ -29,6 +30,7 @@ impl Program { types: Arena::::new(), constants: Arena::::new(), global_variables: Arena::::new(), + lookup_global_variables: FastHashMap::default(), context: Context { expressions: Arena::::new(), local_variables: Arena::::new(), @@ -53,3 +55,9 @@ pub struct ExpressionRule { pub expression: Handle, pub statements: Vec, } + +#[derive(Debug)] +pub enum TypeQualifier { + StorageClass(StorageClass), + Binding(Binding), +} diff --git a/src/front/glsl_new/error.rs b/src/front/glsl_new/error.rs index 61e0ae7e67..726eee1c85 100644 --- a/src/front/glsl_new/error.rs +++ b/src/front/glsl_new/error.rs @@ -13,6 +13,9 @@ pub enum ErrorKind { ParserFail, ParserStackOverflow, NotImplemented(&'static str), + UnknownVariable(TokenMetadata, String), + ExpectedConstant, + SemanticError(&'static str), } impl fmt::Display for ErrorKind { @@ -31,6 +34,11 @@ impl fmt::Display for ErrorKind { ErrorKind::ParserFail => write!(f, "Parser failed"), ErrorKind::ParserStackOverflow => write!(f, "Parser stack overflow"), ErrorKind::NotImplemented(msg) => write!(f, "Not implemented: {}", msg), + ErrorKind::UnknownVariable(meta, val) => { + write!(f, "Unknown variable {} at {:?}", val, meta) + } + ErrorKind::ExpectedConstant => write!(f, "Expected constant"), + ErrorKind::SemanticError(msg) => write!(f, "Semantic error: {}", msg), } } } diff --git a/src/front/glsl_new/lex.rs b/src/front/glsl_new/lex.rs index 4eec42bc13..898236723b 100644 --- a/src/front/glsl_new/lex.rs +++ b/src/front/glsl_new/lex.rs @@ -110,6 +110,10 @@ pub fn consume_token(mut input: &str) -> (Option, &str) { let (word, rest, pos) = consume_any(input, |c| c.is_ascii_alphanumeric() || c == '_'); meta.chars.end = start + pos; match word { + "layout" => (Some(Token::Layout(meta)), rest), + "in" => (Some(Token::In(meta)), rest), + "out" => (Some(Token::Out(meta)), rest), + // types "void" => (Some(Token::Void(meta)), rest), "vec2" => (Some(Token::Vec2(meta)), rest), "vec3" => (Some(Token::Vec3(meta)), rest), diff --git a/src/front/glsl_new/parser.rs b/src/front/glsl_new/parser.rs index 755b9d8e20..ecf2e058c3 100644 --- a/src/front/glsl_new/parser.rs +++ b/src/front/glsl_new/parser.rs @@ -45,6 +45,7 @@ pomelo! { %type function_declarator Function; %type function_header Function; %type function_definition Function; + // statements %type compound_statement Block; %type compound_statement_no_new_scope Block; @@ -52,6 +53,7 @@ pomelo! { %type statement Statement; %type simple_statement Statement; %type expression_statement Statement; + %type declaration_statement Statement; // expressions %type unary_expression ExpressionRule; @@ -82,9 +84,18 @@ pomelo! { %type assignment_expression ExpressionRule; %type assignment_operator BinaryOperator; %type expression ExpressionRule; + %type constant_expression Handle; + + // decalartions + %type layout_qualifier Binding; + %type layout_qualifier_id_list Binding; + %type layout_qualifier_id Binding; + %type type_qualifier Vec; + %type single_type_qualifier TypeQualifier; + %type storage_qualifier StorageClass; // types - %type fully_specified_type Option>; + %type fully_specified_type (Vec, Option>); %type type_specifier Option>; %type type_specifier_nonarray Option; @@ -116,7 +127,7 @@ pomelo! { extra.shader_stage == ShaderStage::Fragment) { let h = extra.global_variables.fetch_or_append( GlobalVariable { - name: Some(v.1), + name: Some(v.1.clone()), class: match extra.shader_stage { ShaderStage::Vertex => StorageClass::Output, ShaderStage::Fragment => StorageClass::Input, @@ -133,12 +144,21 @@ pomelo! { }), }, ); + extra.lookup_global_variables.insert(v.1, h); ExpressionRule{ expression: extra.context.expressions.append(Expression::GlobalVariable(h)), statements: vec![], } } else { - return Err(ErrorKind::NotImplemented("var")) + // try global vars + if let Some(global_var) = extra.lookup_global_variables.get(&v.1) { + ExpressionRule{ + expression: extra.context.expressions.append(Expression::GlobalVariable(global_var.clone())), + statements: vec![], + } + } else { + return Err(ErrorKind::UnknownVariable(v.0, v.1)) + } } } @@ -401,12 +421,108 @@ pomelo! { } } + constant_expression ::= conditional_expression(e) { + if let Expression::Constant(h) = extra.context.expressions[e] { + h + } else { + return Err(ErrorKind::ExpectedConstant) + } + } + + // declaration + declaration ::= init_declarator_list Semicolon; + init_declarator_list ::= single_declaration; + single_declaration ::= fully_specified_type; + single_declaration ::= fully_specified_type(t) Identifier(i) { + //TODO: global or local? For now always global + if let Some(ty) = t.1 { + if let Some(TypeQualifier::StorageClass(sc)) = t.0.iter().find(|tq| { + if let TypeQualifier::StorageClass(_) = tq { true } else { false } + }) { + let binding = t.0.iter().find_map(|tq| { + if let TypeQualifier::Binding(b) = tq { Some(b.clone()) } else { None } + }); + + let h = extra.global_variables.fetch_or_append( + GlobalVariable { + name: Some(i.1.clone()), + class: *sc, + binding: binding, + ty: ty, + }, + ); + extra.lookup_global_variables.insert(i.1, h); + + } else { + return Err(ErrorKind::SemanticError("Missing storage class for declaration")) + } + } else { + return Err(ErrorKind::SemanticError("Empty type for declaration")) + } + } + + fully_specified_type ::= type_specifier(t) {(vec![], t)} + fully_specified_type ::= type_qualifier(q) type_specifier(t) {(q,t)} + + layout_qualifier ::= Layout LeftParen layout_qualifier_id_list(l) RightParen {l} + layout_qualifier_id_list ::= layout_qualifier_id; + layout_qualifier_id_list ::= layout_qualifier_id_list Comma layout_qualifier_id(l) { + //TODO: for now always pick last + l + } + // layout_qualifier_id ::= Identifier; + layout_qualifier_id ::= Identifier(i) Equal constant_expression(c) { + if i.1.as_str() == "location" { + if let ConstantInner::Sint(loc) = extra.constants[c].inner { + Binding::Location(loc as u32) + } else { + return Err(ErrorKind::NotImplemented("location not Sint")); + } + } else { + return Err(ErrorKind::NotImplemented("non location layout qualifier")); + } + } + // layout_qualifier_id ::= Shared; + + // precise_qualifier ::= Precise; + + type_qualifier ::= single_type_qualifier(t) { + vec![t] + } + type_qualifier ::= type_qualifier(mut l) single_type_qualifier(t) { + l.push(t); + l + } + + single_type_qualifier ::= storage_qualifier(s) { + TypeQualifier::StorageClass(s) + } + single_type_qualifier ::= layout_qualifier(l) { + TypeQualifier::Binding(l) + } + // single_type_qualifier ::= precision_qualifier; + // single_type_qualifier ::= interpolation_qualifier; + // single_type_qualifier ::= invariant_qualifier; + // single_type_qualifier ::= precise_qualifier; + + storage_qualifier ::= Const {StorageClass::Constant} + // storage_qualifier ::= InOut; + storage_qualifier ::= In {StorageClass::Input} + storage_qualifier ::= Out {StorageClass::Output} + //TODO: other storage qualifiers + + + declaration_statement ::= declaration { + //TODO: Should declarations be able to genereate expression/statements? + Statement::Empty + } + // statement statement ::= compound_statement(cs) {Statement::Block(cs)} statement ::= simple_statement; // Grammar Note: labeled statements for SWITCH only; 'goto' is not supported. - //simple_statement ::= declaration_statement; + simple_statement ::= declaration_statement; simple_statement ::= expression_statement; //simple_statement ::= selection_statement; //simple_statement ::= switch_statement; @@ -440,7 +556,7 @@ pomelo! { Function { name: Some(n.1), parameter_types: vec![], - return_type: t, + return_type: t.1, global_usage: vec![], local_variables: Arena::::new(), expressions: Arena::::new(), @@ -449,7 +565,6 @@ pomelo! { } // type - fully_specified_type ::= type_specifier; type_specifier ::= type_specifier_nonarray(t) { t.map(|t| { let name = t.name.clone(); @@ -505,6 +620,7 @@ pomelo! { extra.lookup_function.insert(name, handle); } } + external_declaration ::= declaration; function_definition ::= function_prototype(mut f) compound_statement_no_new_scope(cs) { std::mem::swap(&mut f.expressions, &mut extra.context.expressions); diff --git a/test-data/simple.vert b/test-data/simple.vert index 515cc82a58..761b17ed05 100644 --- a/test-data/simple.vert +++ b/test-data/simple.vert @@ -1,5 +1,7 @@ #version 450 core +layout(location = 0) in vec2 position; + void main() { - gl_Position = vec4(1.0); + gl_Position = vec4(position, 0.0, 1.0); }