mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
[glsl-in][New parser] WIP support for functions
This commit is contained in:
committed by
Dzmitry Malyshau
parent
ff8f15e034
commit
786194ec67
@@ -1,9 +1,9 @@
|
||||
use super::{super::Typifier, constants::ConstantSolver, error::ErrorKind};
|
||||
use crate::{
|
||||
proc::ResolveContext, Arena, ArraySize, BinaryOperator, Binding, Constant, Expression,
|
||||
FastHashMap, Function, FunctionArgument, GlobalVariable, Handle, Interpolation, LocalVariable,
|
||||
Module, RelationalFunction, ResourceBinding, Sampling, ShaderStage, Statement, StorageClass,
|
||||
Type, UnaryOperator,
|
||||
FastHashMap, Function, FunctionArgument, GlobalVariable, Handle, Interpolation, Module,
|
||||
RelationalFunction, ResourceBinding, Sampling, ShaderStage, Statement, StorageClass, Type,
|
||||
UnaryOperator,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -15,7 +15,6 @@ pub struct Program<'a> {
|
||||
pub lookup_type: FastHashMap<String, Handle<Type>>,
|
||||
pub lookup_global_variables: FastHashMap<String, Handle<GlobalVariable>>,
|
||||
pub lookup_constants: FastHashMap<String, Handle<Constant>>,
|
||||
pub context: Context,
|
||||
pub module: Module,
|
||||
}
|
||||
|
||||
@@ -29,34 +28,31 @@ impl<'a> Program<'a> {
|
||||
lookup_type: FastHashMap::default(),
|
||||
lookup_global_variables: FastHashMap::default(),
|
||||
lookup_constants: FastHashMap::default(),
|
||||
context: Context {
|
||||
expressions: Arena::<Expression>::new(),
|
||||
local_variables: Arena::<LocalVariable>::new(),
|
||||
arguments: Vec::new(),
|
||||
scopes: vec![FastHashMap::default()],
|
||||
lookup_global_var_exps: FastHashMap::default(),
|
||||
lookup_constant_exps: FastHashMap::default(),
|
||||
typifier: Typifier::new(),
|
||||
},
|
||||
module: Module::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn binary_expr(
|
||||
&mut self,
|
||||
function: &mut Function,
|
||||
op: BinaryOperator,
|
||||
left: &ExpressionRule,
|
||||
right: &ExpressionRule,
|
||||
) -> ExpressionRule {
|
||||
ExpressionRule::from_expression(self.context.expressions.append(Expression::Binary {
|
||||
ExpressionRule::from_expression(function.expressions.append(Expression::Binary {
|
||||
op,
|
||||
left: left.expression,
|
||||
right: right.expression,
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn unary_expr(&mut self, op: UnaryOperator, tgt: &ExpressionRule) -> ExpressionRule {
|
||||
ExpressionRule::from_expression(self.context.expressions.append(Expression::Unary {
|
||||
pub fn unary_expr(
|
||||
&mut self,
|
||||
function: &mut Function,
|
||||
op: UnaryOperator,
|
||||
tgt: &ExpressionRule,
|
||||
) -> ExpressionRule {
|
||||
ExpressionRule::from_expression(function.expressions.append(Expression::Unary {
|
||||
op,
|
||||
expr: tgt.expression,
|
||||
}))
|
||||
@@ -67,16 +63,17 @@ impl<'a> Program<'a> {
|
||||
/// represented as `all(equal(vec1, vec2))` and `any(notEqual(vec1, vec2))`
|
||||
pub fn equality_expr(
|
||||
&mut self,
|
||||
context: &mut FunctionContext,
|
||||
equals: bool,
|
||||
left: &ExpressionRule,
|
||||
right: &ExpressionRule,
|
||||
) -> Result<ExpressionRule, ErrorKind> {
|
||||
let left_is_vector = match *self.resolve_type(left.expression)? {
|
||||
let left_is_vector = match *self.resolve_type(context, left.expression)? {
|
||||
crate::TypeInner::Vector { .. } => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
let right_is_vector = match *self.resolve_type(right.expression)? {
|
||||
let right_is_vector = match *self.resolve_type(context, right.expression)? {
|
||||
crate::TypeInner::Vector { .. } => true,
|
||||
_ => false,
|
||||
};
|
||||
@@ -86,15 +83,16 @@ impl<'a> Program<'a> {
|
||||
false => (BinaryOperator::NotEqual, RelationalFunction::Any),
|
||||
};
|
||||
|
||||
let expr =
|
||||
ExpressionRule::from_expression(self.context.expressions.append(Expression::Binary {
|
||||
let expr = ExpressionRule::from_expression(context.function.expressions.append(
|
||||
Expression::Binary {
|
||||
op,
|
||||
left: left.expression,
|
||||
right: right.expression,
|
||||
}));
|
||||
},
|
||||
));
|
||||
|
||||
Ok(if left_is_vector && right_is_vector {
|
||||
ExpressionRule::from_expression(self.context.expressions.append(
|
||||
ExpressionRule::from_expression(context.function.expressions.append(
|
||||
Expression::Relational {
|
||||
fun,
|
||||
argument: expr.expression,
|
||||
@@ -105,20 +103,21 @@ impl<'a> Program<'a> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn resolve_type(
|
||||
&mut self,
|
||||
pub fn resolve_type<'b>(
|
||||
&'b mut self,
|
||||
context: &'b mut FunctionContext,
|
||||
handle: Handle<Expression>,
|
||||
) -> Result<&crate::TypeInner, ErrorKind> {
|
||||
) -> Result<&'b crate::TypeInner, ErrorKind> {
|
||||
let resolve_ctx = ResolveContext {
|
||||
constants: &self.module.constants,
|
||||
global_vars: &self.module.global_variables,
|
||||
local_vars: &self.context.local_variables,
|
||||
local_vars: &context.function.local_variables,
|
||||
functions: &self.module.functions,
|
||||
arguments: &self.context.arguments,
|
||||
arguments: &context.function.arguments,
|
||||
};
|
||||
match self.context.typifier.grow(
|
||||
match context.typifier.grow(
|
||||
handle,
|
||||
&self.context.expressions,
|
||||
&context.function.expressions,
|
||||
&mut self.module.types,
|
||||
&resolve_ctx,
|
||||
) {
|
||||
@@ -126,17 +125,18 @@ impl<'a> Program<'a> {
|
||||
Err(error) => Err(ErrorKind::SemanticError(
|
||||
format!("Can't resolve type: {:?}", error).into(),
|
||||
)),
|
||||
Ok(()) => Ok(self.context.typifier.get(handle, &self.module.types)),
|
||||
Ok(()) => Ok(context.typifier.get(handle, &self.module.types)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn solve_constant(
|
||||
&mut self,
|
||||
expressions: &Arena<Expression>,
|
||||
root: Handle<Expression>,
|
||||
) -> Result<Handle<Constant>, ErrorKind> {
|
||||
let mut solver = ConstantSolver {
|
||||
types: &self.module.types,
|
||||
expressions: &self.context.expressions,
|
||||
expressions,
|
||||
constants: &mut self.module.constants,
|
||||
};
|
||||
|
||||
@@ -197,10 +197,8 @@ pub enum Profile {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Context {
|
||||
pub expressions: Arena<Expression>,
|
||||
pub local_variables: Arena<LocalVariable>,
|
||||
pub arguments: Vec<FunctionArgument>,
|
||||
pub struct FunctionContext<'function> {
|
||||
pub function: &'function mut Function,
|
||||
//TODO: Find less allocation heavy representation
|
||||
pub scopes: Vec<FastHashMap<String, Handle<Expression>>>,
|
||||
pub lookup_global_var_exps: FastHashMap<String, Handle<Expression>>,
|
||||
@@ -208,7 +206,17 @@ pub struct Context {
|
||||
pub typifier: Typifier,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
impl<'function> FunctionContext<'function> {
|
||||
pub fn new(function: &'function mut Function) -> Self {
|
||||
FunctionContext {
|
||||
function,
|
||||
scopes: vec![FastHashMap::default()],
|
||||
lookup_global_var_exps: FastHashMap::default(),
|
||||
lookup_constant_exps: FastHashMap::default(),
|
||||
typifier: Typifier::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lookup_local_var(&self, name: &str) -> Option<Handle<Expression>> {
|
||||
for scope in self.scopes.iter().rev() {
|
||||
if let Some(var) = scope.get(name) {
|
||||
@@ -236,6 +244,7 @@ impl Context {
|
||||
pub fn add_local_var(&mut self, name: String, handle: Handle<Expression>) {
|
||||
if let Some(current) = self.scopes.last_mut() {
|
||||
let expr = self
|
||||
.function
|
||||
.expressions
|
||||
.append(Expression::Load { pointer: handle });
|
||||
(*current).insert(name, expr);
|
||||
@@ -243,9 +252,22 @@ impl Context {
|
||||
}
|
||||
|
||||
/// Add function argument to current scope
|
||||
pub fn add_function_arg(&mut self, name: String, expr: Handle<Expression>) {
|
||||
if let Some(current) = self.scopes.last_mut() {
|
||||
(*current).insert(name, expr);
|
||||
pub fn add_function_arg(&mut self, name: Option<String>, ty: Handle<Type>) {
|
||||
let index = self.function.arguments.len();
|
||||
self.function.arguments.push(FunctionArgument {
|
||||
name: name.clone(),
|
||||
ty,
|
||||
binding: None,
|
||||
});
|
||||
|
||||
if let Some(name) = name {
|
||||
if let Some(current) = self.scopes.last_mut() {
|
||||
let expr = self
|
||||
.function
|
||||
.expressions
|
||||
.append(Expression::FunctionArgument(index as u32));
|
||||
(*current).insert(name, expr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -309,6 +331,7 @@ pub enum StorageQualifier {
|
||||
StorageClass(StorageClass),
|
||||
Input,
|
||||
Output,
|
||||
InOut,
|
||||
Const,
|
||||
}
|
||||
|
||||
|
||||
@@ -1,31 +1,34 @@
|
||||
use super::super::Typifier;
|
||||
use crate::{
|
||||
proc::ensure_block_returns, BinaryOperator, Block, EntryPoint, Expression, Function,
|
||||
MathFunction, RelationalFunction, SampleLevel, ScalarKind, TypeInner,
|
||||
BinaryOperator, Expression, MathFunction, RelationalFunction, SampleLevel, ScalarKind,
|
||||
TypeInner,
|
||||
};
|
||||
|
||||
use super::{ast::*, error::ErrorKind};
|
||||
|
||||
impl Program<'_> {
|
||||
pub fn function_call(&mut self, fc: FunctionCall) -> Result<ExpressionRule, ErrorKind> {
|
||||
pub fn function_call(
|
||||
&mut self,
|
||||
context: &mut FunctionContext,
|
||||
fc: FunctionCall,
|
||||
) -> Result<ExpressionRule, ErrorKind> {
|
||||
match fc.kind {
|
||||
FunctionCallKind::TypeConstructor(ty) => {
|
||||
let h = if fc.args.len() == 1 {
|
||||
let is_vec = match *self.resolve_type(fc.args[0].expression)? {
|
||||
let is_vec = match *self.resolve_type(context, fc.args[0].expression)? {
|
||||
TypeInner::Vector { .. } => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
match self.module.types[ty].inner {
|
||||
TypeInner::Vector { size, .. } if !is_vec => {
|
||||
self.context.expressions.append(Expression::Splat {
|
||||
context.function.expressions.append(Expression::Splat {
|
||||
size,
|
||||
value: fc.args[0].expression,
|
||||
})
|
||||
}
|
||||
TypeInner::Scalar { kind, width }
|
||||
| TypeInner::Vector { kind, width, .. } => {
|
||||
self.context.expressions.append(Expression::As {
|
||||
context.function.expressions.append(Expression::As {
|
||||
kind,
|
||||
expr: fc.args[0].expression,
|
||||
convert: Some(width),
|
||||
@@ -36,7 +39,7 @@ impl Program<'_> {
|
||||
rows,
|
||||
width,
|
||||
} => {
|
||||
let value = self.context.expressions.append(Expression::As {
|
||||
let value = context.function.expressions.append(Expression::As {
|
||||
kind: ScalarKind::Float,
|
||||
expr: fc.args[0].expression,
|
||||
convert: Some(width),
|
||||
@@ -45,7 +48,8 @@ impl Program<'_> {
|
||||
let column = if is_vec {
|
||||
value
|
||||
} else {
|
||||
self.context
|
||||
context
|
||||
.function
|
||||
.expressions
|
||||
.append(Expression::Splat { size: rows, value })
|
||||
};
|
||||
@@ -53,7 +57,7 @@ impl Program<'_> {
|
||||
let columns =
|
||||
std::iter::repeat(column).take(columns as usize).collect();
|
||||
|
||||
self.context.expressions.append(Expression::Compose {
|
||||
context.function.expressions.append(Expression::Compose {
|
||||
ty,
|
||||
components: columns,
|
||||
})
|
||||
@@ -61,7 +65,7 @@ impl Program<'_> {
|
||||
_ => return Err(ErrorKind::SemanticError("Bad cast".into())),
|
||||
}
|
||||
} else {
|
||||
self.context.expressions.append(Expression::Compose {
|
||||
context.function.expressions.append(Expression::Compose {
|
||||
ty,
|
||||
components: fc.args.iter().map(|a| a.expression).collect(),
|
||||
})
|
||||
@@ -101,7 +105,7 @@ impl Program<'_> {
|
||||
}
|
||||
if let Some(sampler) = fc.args[0].sampler {
|
||||
Ok(ExpressionRule {
|
||||
expression: self.context.expressions.append(
|
||||
expression: context.function.expressions.append(
|
||||
Expression::ImageSample {
|
||||
image: fc.args[0].expression,
|
||||
sampler,
|
||||
@@ -130,7 +134,7 @@ impl Program<'_> {
|
||||
}
|
||||
if let Some(sampler) = fc.args[0].sampler {
|
||||
Ok(ExpressionRule {
|
||||
expression: self.context.expressions.append(
|
||||
expression: context.function.expressions.append(
|
||||
Expression::ImageSample {
|
||||
image: fc.args[0].expression,
|
||||
sampler,
|
||||
@@ -160,7 +164,7 @@ impl Program<'_> {
|
||||
return Err(ErrorKind::WrongNumberArgs(name, 1, fc.args.len()));
|
||||
}
|
||||
Ok(ExpressionRule {
|
||||
expression: self.context.expressions.append(Expression::Math {
|
||||
expression: context.function.expressions.append(Expression::Math {
|
||||
fun: match name.as_str() {
|
||||
"ceil" => MathFunction::Ceil,
|
||||
"round" => MathFunction::Round,
|
||||
@@ -192,7 +196,7 @@ impl Program<'_> {
|
||||
return Err(ErrorKind::WrongNumberArgs(name, 2, fc.args.len()));
|
||||
}
|
||||
Ok(ExpressionRule {
|
||||
expression: self.context.expressions.append(Expression::Math {
|
||||
expression: context.function.expressions.append(Expression::Math {
|
||||
fun: match name.as_str() {
|
||||
"pow" => MathFunction::Pow,
|
||||
"dot" => MathFunction::Dot,
|
||||
@@ -212,7 +216,7 @@ impl Program<'_> {
|
||||
return Err(ErrorKind::WrongNumberArgs(name, 3, fc.args.len()));
|
||||
}
|
||||
Ok(ExpressionRule {
|
||||
expression: self.context.expressions.append(Expression::Math {
|
||||
expression: context.function.expressions.append(Expression::Math {
|
||||
fun: match name.as_str() {
|
||||
"mix" => MathFunction::Mix,
|
||||
"clamp" => MathFunction::Clamp,
|
||||
@@ -232,7 +236,7 @@ impl Program<'_> {
|
||||
return Err(ErrorKind::WrongNumberArgs(name, 2, fc.args.len()));
|
||||
}
|
||||
Ok(ExpressionRule {
|
||||
expression: self.context.expressions.append(Expression::Binary {
|
||||
expression: context.function.expressions.append(Expression::Binary {
|
||||
op: match name.as_str() {
|
||||
"lessThan" => BinaryOperator::Less,
|
||||
"greaterThan" => BinaryOperator::Greater,
|
||||
@@ -249,10 +253,18 @@ impl Program<'_> {
|
||||
statements: fc.args.into_iter().flat_map(|a| a.statements).collect(),
|
||||
})
|
||||
}
|
||||
"isinf" => self.parse_relational_fun(name, fc.args, RelationalFunction::IsInf),
|
||||
"isnan" => self.parse_relational_fun(name, fc.args, RelationalFunction::IsNan),
|
||||
"all" => self.parse_relational_fun(name, fc.args, RelationalFunction::All),
|
||||
"any" => self.parse_relational_fun(name, fc.args, RelationalFunction::Any),
|
||||
"isinf" => {
|
||||
self.parse_relational_fun(context, name, fc.args, RelationalFunction::IsInf)
|
||||
}
|
||||
"isnan" => {
|
||||
self.parse_relational_fun(context, name, fc.args, RelationalFunction::IsNan)
|
||||
}
|
||||
"all" => {
|
||||
self.parse_relational_fun(context, name, fc.args, RelationalFunction::All)
|
||||
}
|
||||
"any" => {
|
||||
self.parse_relational_fun(context, name, fc.args, RelationalFunction::Any)
|
||||
}
|
||||
func_name => {
|
||||
let function = *self.lookup_function.get(func_name).ok_or_else(|| {
|
||||
ErrorKind::SemanticError(
|
||||
@@ -262,8 +274,10 @@ impl Program<'_> {
|
||||
let arguments: Vec<_> = fc.args.iter().map(|a| a.expression).collect();
|
||||
let mut statements: Vec<_> =
|
||||
fc.args.into_iter().flat_map(|a| a.statements).collect();
|
||||
let expression =
|
||||
self.context.expressions.append(Expression::Call(function));
|
||||
let expression = context
|
||||
.function
|
||||
.expressions
|
||||
.append(Expression::Call(function));
|
||||
statements.push(crate::Statement::Call {
|
||||
function,
|
||||
arguments,
|
||||
@@ -282,6 +296,7 @@ impl Program<'_> {
|
||||
|
||||
pub fn parse_relational_fun(
|
||||
&mut self,
|
||||
context: &mut FunctionContext,
|
||||
name: String,
|
||||
args: Vec<ExpressionRule>,
|
||||
fun: RelationalFunction,
|
||||
@@ -290,7 +305,7 @@ impl Program<'_> {
|
||||
return Err(ErrorKind::WrongNumberArgs(name, 1, args.len()));
|
||||
}
|
||||
Ok(ExpressionRule {
|
||||
expression: self.context.expressions.append(Expression::Relational {
|
||||
expression: context.function.expressions.append(Expression::Relational {
|
||||
fun,
|
||||
argument: args[0].expression,
|
||||
}),
|
||||
@@ -299,33 +314,33 @@ impl Program<'_> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn add_function_prelude(&mut self) {
|
||||
pub fn add_function_prelude(&mut self, context: &mut FunctionContext) {
|
||||
for (var_handle, var) in self.module.global_variables.iter() {
|
||||
if let Some(name) = var.name.as_ref() {
|
||||
let expr = self
|
||||
.context
|
||||
let expr = context
|
||||
.function
|
||||
.expressions
|
||||
.append(Expression::GlobalVariable(var_handle));
|
||||
self.context
|
||||
.lookup_global_var_exps
|
||||
.insert(name.clone(), expr);
|
||||
context.lookup_global_var_exps.insert(name.clone(), expr);
|
||||
} else {
|
||||
let ty = &self.module.types[var.ty];
|
||||
// anonymous structs
|
||||
if let TypeInner::Struct { ref members, .. } = ty.inner {
|
||||
let base = self
|
||||
.context
|
||||
let base = context
|
||||
.function
|
||||
.expressions
|
||||
.append(Expression::GlobalVariable(var_handle));
|
||||
for (idx, member) in members.iter().enumerate() {
|
||||
if let Some(name) = member.name.as_ref() {
|
||||
let exp = self.context.expressions.append(Expression::AccessIndex {
|
||||
base,
|
||||
index: idx as u32,
|
||||
});
|
||||
self.context
|
||||
.lookup_global_var_exps
|
||||
.insert(name.clone(), exp);
|
||||
let exp =
|
||||
context
|
||||
.function
|
||||
.expressions
|
||||
.append(Expression::AccessIndex {
|
||||
base,
|
||||
index: idx as u32,
|
||||
});
|
||||
context.lookup_global_var_exps.insert(name.clone(), exp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -334,45 +349,12 @@ impl Program<'_> {
|
||||
|
||||
for (handle, constant) in self.module.constants.iter() {
|
||||
if let Some(name) = constant.name.as_ref() {
|
||||
let expr = self
|
||||
.context
|
||||
let expr = context
|
||||
.function
|
||||
.expressions
|
||||
.append(Expression::Constant(handle));
|
||||
self.context.lookup_constant_exps.insert(name.clone(), expr);
|
||||
context.lookup_constant_exps.insert(name.clone(), expr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn function_definition(&mut self, mut f: Function, mut block: Block) -> Function {
|
||||
std::mem::swap(&mut f.expressions, &mut self.context.expressions);
|
||||
std::mem::swap(&mut f.local_variables, &mut self.context.local_variables);
|
||||
std::mem::swap(&mut f.arguments, &mut self.context.arguments);
|
||||
self.context.clear_scopes();
|
||||
self.context.lookup_global_var_exps.clear();
|
||||
self.context.typifier = Typifier::new();
|
||||
ensure_block_returns(&mut block);
|
||||
f.body = block;
|
||||
f
|
||||
}
|
||||
|
||||
pub fn declare_function(&mut self, f: Function) -> Result<(), ErrorKind> {
|
||||
let name = f
|
||||
.name
|
||||
.clone()
|
||||
.ok_or_else(|| ErrorKind::SemanticError("Unnamed function".into()))?;
|
||||
let stage = self.entry_points.get(&name);
|
||||
if let Some(&stage) = stage {
|
||||
self.module.entry_points.push(EntryPoint {
|
||||
name,
|
||||
stage,
|
||||
early_depth_test: None,
|
||||
workgroup_size: [0; 3], //TODO
|
||||
function: f,
|
||||
});
|
||||
} else {
|
||||
let handle = self.module.functions.append(f);
|
||||
self.lookup_function.insert(name, handle);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,6 +96,7 @@ impl<'a> Iterator for Lexer<'a> {
|
||||
"for" => TokenValue::For,
|
||||
// types
|
||||
"void" => TokenValue::Void,
|
||||
"struct" => TokenValue::Struct,
|
||||
word => match parse_type(word) {
|
||||
Some(t) => TokenValue::TypeName(t),
|
||||
None => TokenValue::Identifier(String::from(word)),
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
use super::{
|
||||
ast::Profile,
|
||||
ast::{FunctionContext, Profile, StorageQualifier, TypeQualifier},
|
||||
error::ErrorKind,
|
||||
lex::Lexer,
|
||||
token::{Token, TokenMetadata, TokenValue},
|
||||
Program,
|
||||
};
|
||||
use crate::{arena::Handle, ArraySize, Function, FunctionResult, StorageClass, Type, TypeInner};
|
||||
use std::iter::Peekable;
|
||||
|
||||
type Result<T> = std::result::Result<T, ErrorKind>;
|
||||
|
||||
pub struct Parser<'source, 'program, 'options> {
|
||||
program: &'program mut Program<'options>,
|
||||
lexer: Peekable<Lexer<'source>>,
|
||||
@@ -20,17 +23,44 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse(&mut self) -> Result<(), ErrorKind> {
|
||||
self.parse_version()?;
|
||||
fn expect_ident(&mut self) -> Result<(String, TokenMetadata)> {
|
||||
let token = self.bump()?;
|
||||
|
||||
if let Some(token) = self.lexer.next() {
|
||||
Err(ErrorKind::InvalidToken(token))
|
||||
} else {
|
||||
Ok(())
|
||||
match token.value {
|
||||
TokenValue::Identifier(name) => Ok((name, token.meta)),
|
||||
_ => Err(ErrorKind::InvalidToken(token)),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_version(&mut self) -> Result<(), ErrorKind> {
|
||||
fn expect(&mut self, value: TokenValue) -> Result<Token> {
|
||||
let token = self.bump()?;
|
||||
|
||||
if token.value != value {
|
||||
Err(ErrorKind::InvalidToken(token))
|
||||
} else {
|
||||
Ok(token)
|
||||
}
|
||||
}
|
||||
|
||||
fn bump(&mut self) -> Result<Token> {
|
||||
self.lexer.next().ok_or(ErrorKind::EndOfFile)
|
||||
}
|
||||
|
||||
fn expect_peek(&mut self) -> Result<&Token> {
|
||||
self.lexer.peek().ok_or(ErrorKind::EndOfFile)
|
||||
}
|
||||
|
||||
pub fn parse(&mut self) -> Result<()> {
|
||||
self.parse_version()?;
|
||||
|
||||
while self.lexer.peek().is_some() {
|
||||
self.parse_external_declaration()?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_version(&mut self) -> Result<()> {
|
||||
self.expect(TokenValue::Version)?;
|
||||
|
||||
let version = self.bump()?;
|
||||
@@ -61,26 +91,205 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn expect_ident(&mut self) -> Result<(String, TokenMetadata), ErrorKind> {
|
||||
let token = self.bump()?;
|
||||
fn parse_array_specifier(&mut self) -> Result<Option<ArraySize>> {
|
||||
// TODO: expressions
|
||||
if let Some(&TokenValue::LeftBracket) = self.lexer.peek().map(|t| &t.value) {
|
||||
self.bump()?;
|
||||
|
||||
match token.value {
|
||||
TokenValue::Identifier(name) => Ok((name, token.meta)),
|
||||
_ => Err(ErrorKind::InvalidToken(token)),
|
||||
}
|
||||
}
|
||||
self.expect(TokenValue::RightBracket)?;
|
||||
|
||||
fn expect(&mut self, value: TokenValue) -> Result<Token, ErrorKind> {
|
||||
let token = self.bump()?;
|
||||
|
||||
if token.value != value {
|
||||
Err(ErrorKind::InvalidToken(token))
|
||||
Ok(Some(ArraySize::Dynamic))
|
||||
} else {
|
||||
Ok(token)
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
fn bump(&mut self) -> Result<Token, ErrorKind> {
|
||||
self.lexer.next().ok_or(ErrorKind::EndOfFile)
|
||||
fn parse_type(&mut self) -> Result<Option<Handle<Type>>> {
|
||||
let token = self.bump()?;
|
||||
let ty = match token.value {
|
||||
TokenValue::Void => None,
|
||||
TokenValue::TypeName(ty) => Some(ty),
|
||||
TokenValue::Struct => todo!(),
|
||||
_ => return Err(ErrorKind::InvalidToken(token)),
|
||||
};
|
||||
let handle = ty.map(|t| self.program.module.types.append(t));
|
||||
|
||||
let size = self.parse_array_specifier()?;
|
||||
Ok(handle.map(|ty| self.maybe_array(ty, size)))
|
||||
}
|
||||
|
||||
fn parse_type_non_void(&mut self) -> Result<Handle<Type>> {
|
||||
self.parse_type()?
|
||||
.ok_or_else(|| ErrorKind::SemanticError("Type can't be void".into()))
|
||||
}
|
||||
|
||||
fn maybe_array(&mut self, base: Handle<Type>, size: Option<ArraySize>) -> Handle<Type> {
|
||||
size.map(|size| {
|
||||
self.program.module.types.append(Type {
|
||||
name: None,
|
||||
inner: TypeInner::Array {
|
||||
base,
|
||||
size,
|
||||
stride: self.program.module.types[base]
|
||||
.inner
|
||||
.span(&self.program.module.constants),
|
||||
},
|
||||
})
|
||||
})
|
||||
.unwrap_or(base)
|
||||
}
|
||||
|
||||
fn peek_type_qualifier(&mut self) -> bool {
|
||||
self.lexer.peek().map_or(false, |t| match t.value {
|
||||
TokenValue::Interpolation(_)
|
||||
| TokenValue::Const
|
||||
| TokenValue::In
|
||||
| TokenValue::Out
|
||||
| TokenValue::InOut
|
||||
| TokenValue::Uniform => true,
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_type_qualifiers(&mut self) -> Result<Vec<TypeQualifier>> {
|
||||
let mut qualifiers = Vec::new();
|
||||
|
||||
if self.peek_type_qualifier() {
|
||||
let token = self.bump()?;
|
||||
qualifiers.push(match token.value {
|
||||
TokenValue::Interpolation(i) => TypeQualifier::Interpolation(i),
|
||||
TokenValue::Const => TypeQualifier::StorageQualifier(StorageQualifier::Const),
|
||||
TokenValue::In => TypeQualifier::StorageQualifier(StorageQualifier::Input),
|
||||
TokenValue::Out => TypeQualifier::StorageQualifier(StorageQualifier::Output),
|
||||
TokenValue::InOut => TypeQualifier::StorageQualifier(StorageQualifier::InOut),
|
||||
TokenValue::Uniform => TypeQualifier::StorageQualifier(
|
||||
StorageQualifier::StorageClass(StorageClass::Uniform),
|
||||
),
|
||||
_ => unreachable!(),
|
||||
})
|
||||
}
|
||||
|
||||
Ok(qualifiers)
|
||||
}
|
||||
|
||||
fn parse_external_declaration(&mut self) -> Result<()> {
|
||||
if !self.parse_declaration(true)? {
|
||||
let token = self.bump()?;
|
||||
match token.value {
|
||||
TokenValue::Semicolon if self.program.version == 460 => Ok(()),
|
||||
_ => Err(ErrorKind::InvalidToken(token)),
|
||||
}
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn peek_type_name(&mut self) -> bool {
|
||||
self.lexer.peek().map_or(false, |t| match t.value {
|
||||
TokenValue::TypeName(_) | TokenValue::Void => true,
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
|
||||
/// `external` wheter or not we are in a global or local context
|
||||
fn parse_declaration(&mut self, external: bool) -> Result<bool> {
|
||||
// TODO: Handle precision qualifiers
|
||||
if self.peek_type_qualifier() || self.peek_type_name() {
|
||||
// TODO: Use qualifiers
|
||||
let _qualifiers = self.parse_type_qualifiers()?;
|
||||
|
||||
if self.peek_type_name() {
|
||||
// Functions and variable declarations
|
||||
let ty = self.parse_type()?;
|
||||
|
||||
let token = self.bump()?;
|
||||
|
||||
match token.value {
|
||||
TokenValue::Semicolon => Ok(true),
|
||||
TokenValue::Identifier(name) => match self.expect_peek()?.value {
|
||||
// Function definition/prototype
|
||||
TokenValue::LeftParen => {
|
||||
self.bump()?;
|
||||
|
||||
let mut function = Function {
|
||||
name: Some(name),
|
||||
result: ty.map(|ty| FunctionResult { ty, binding: None }),
|
||||
..Default::default()
|
||||
};
|
||||
let mut context = FunctionContext::new(&mut function);
|
||||
|
||||
self.parse_function_args(&mut context)?;
|
||||
|
||||
self.expect(TokenValue::RightParen)?;
|
||||
|
||||
let token = self.bump()?;
|
||||
match token.value {
|
||||
// Function prototypes
|
||||
TokenValue::Semicolon => todo!(),
|
||||
TokenValue::LeftBrace if external => {
|
||||
// TODO: body
|
||||
self.expect(TokenValue::RightBrace)?;
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
_ => Err(ErrorKind::InvalidToken(token)),
|
||||
}
|
||||
}
|
||||
// Variable Declaration
|
||||
TokenValue::Semicolon => todo!(),
|
||||
TokenValue::Comma => todo!(),
|
||||
_ => Err(ErrorKind::InvalidToken(self.bump()?)),
|
||||
},
|
||||
_ => Err(ErrorKind::InvalidToken(token)),
|
||||
}
|
||||
} else {
|
||||
// Structs and modifiers
|
||||
let token = self.bump()?;
|
||||
match token.value {
|
||||
TokenValue::Identifier(_) => todo!(),
|
||||
TokenValue::Semicolon => Ok(true),
|
||||
_ => Err(ErrorKind::InvalidToken(token)),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_function_args(&mut self, context: &mut FunctionContext) -> Result<()> {
|
||||
loop {
|
||||
// TODO: parameter qualifier
|
||||
if self.peek_type_name() {
|
||||
let ty = self.parse_type_non_void()?;
|
||||
|
||||
match self.expect_peek()?.value {
|
||||
TokenValue::Comma => {
|
||||
self.bump()?;
|
||||
context.add_function_arg(None, ty);
|
||||
continue;
|
||||
}
|
||||
TokenValue::Identifier(_) => {
|
||||
let name = self.expect_ident()?.0;
|
||||
|
||||
let size = self.parse_array_specifier()?;
|
||||
let ty = self.maybe_array(ty, size);
|
||||
|
||||
context.add_function_arg(Some(name), ty);
|
||||
|
||||
if self.expect_peek()?.value == TokenValue::Comma {
|
||||
self.bump()?;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
_ => break,
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,35 +50,34 @@ fn version() {
|
||||
"InvalidProfile(TokenMetadata { line: 1, chars: 13..14 }, \"smart\")" //TODO: location
|
||||
);
|
||||
|
||||
// TODO: Reenable tests later
|
||||
// assert_eq!(
|
||||
// format!(
|
||||
// "{:?}",
|
||||
// parse_program("#version 450\nvoid f(){} #version 450", &entry_points)
|
||||
// .err()
|
||||
// .unwrap()
|
||||
// ),
|
||||
// "InvalidToken(Unknown((TokenMetadata { line: 2, chars: 11..12 }, UnexpectedHash)))"
|
||||
// );
|
||||
assert_eq!(
|
||||
format!(
|
||||
"{:?}",
|
||||
parse_program("#version 450\nvoid f(){} #version 450", &entry_points)
|
||||
.err()
|
||||
.unwrap()
|
||||
),
|
||||
"InvalidToken(Token { value: Unknown(UnexpectedHash), meta: TokenMetadata { line: 2, chars: 11..12 } })"
|
||||
);
|
||||
|
||||
// // valid versions
|
||||
// let program = parse_program(" # version 450\nvoid main() {}", &entry_points).unwrap();
|
||||
// assert_eq!(
|
||||
// format!("{:?}", (program.version, program.profile)),
|
||||
// "(450, Core)"
|
||||
// );
|
||||
// valid versions
|
||||
let program = parse_program(" # version 450\nvoid main() {}", &entry_points).unwrap();
|
||||
assert_eq!(
|
||||
format!("{:?}", (program.version, program.profile)),
|
||||
"(450, Core)"
|
||||
);
|
||||
|
||||
// let program = parse_program("#version 450\nvoid main() {}", &entry_points).unwrap();
|
||||
// assert_eq!(
|
||||
// format!("{:?}", (program.version, program.profile)),
|
||||
// "(450, Core)"
|
||||
// );
|
||||
let program = parse_program("#version 450\nvoid main() {}", &entry_points).unwrap();
|
||||
assert_eq!(
|
||||
format!("{:?}", (program.version, program.profile)),
|
||||
"(450, Core)"
|
||||
);
|
||||
|
||||
// let program = parse_program("#version 450 core\nvoid main() {}", &entry_points).unwrap();
|
||||
// assert_eq!(
|
||||
// format!("{:?}", (program.version, program.profile)),
|
||||
// "(450, Core)"
|
||||
// );
|
||||
let program = parse_program("#version 450 core\nvoid main() {}", &entry_points).unwrap();
|
||||
assert_eq!(
|
||||
format!("{:?}", (program.version, program.profile)),
|
||||
"(450, Core)"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -193,9 +192,8 @@ fn textures() {
|
||||
|
||||
#[test]
|
||||
fn functions() {
|
||||
// TODO: Reenable tests later
|
||||
// let mut entry_points = crate::FastHashMap::default();
|
||||
// entry_points.insert("".to_string(), ShaderStage::Vertex);
|
||||
let mut entry_points = crate::FastHashMap::default();
|
||||
entry_points.insert("".to_string(), ShaderStage::Vertex);
|
||||
|
||||
// TODO: Add support for function prototypes
|
||||
// parse_program(
|
||||
@@ -204,25 +202,25 @@ fn functions() {
|
||||
// void test1(float);
|
||||
// void test1(float) {}
|
||||
|
||||
// void main() {}
|
||||
// "#,
|
||||
// ShaderStage::Vertex,
|
||||
// )
|
||||
// .unwrap();
|
||||
|
||||
// parse_program(
|
||||
// r#"
|
||||
// # version 450
|
||||
// void test2(float a) {}
|
||||
// void test3(float a, float b) {}
|
||||
// void test4(float, float) {}
|
||||
|
||||
// void main() {}
|
||||
// "#,
|
||||
// &entry_points,
|
||||
// )
|
||||
// .unwrap();
|
||||
|
||||
parse_program(
|
||||
r#"
|
||||
# version 450
|
||||
void test2(float a) {}
|
||||
void test3(float a, float b) {}
|
||||
void test4(float, float) {}
|
||||
|
||||
void main() {}
|
||||
"#,
|
||||
&entry_points,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// parse_program(
|
||||
// r#"
|
||||
// # version 450
|
||||
|
||||
@@ -53,6 +53,7 @@ pub enum TokenValue {
|
||||
For,
|
||||
|
||||
Void,
|
||||
Struct,
|
||||
TypeName(Type),
|
||||
|
||||
Assign,
|
||||
|
||||
@@ -5,14 +5,18 @@ use super::error::ErrorKind;
|
||||
use super::token::TokenMetadata;
|
||||
|
||||
impl Program<'_> {
|
||||
pub fn lookup_variable(&mut self, name: &str) -> Result<Option<Handle<Expression>>, ErrorKind> {
|
||||
if let Some(local_var) = self.context.lookup_local_var(name) {
|
||||
pub fn lookup_variable(
|
||||
&mut self,
|
||||
context: &mut FunctionContext,
|
||||
name: &str,
|
||||
) -> Result<Option<Handle<Expression>>, ErrorKind> {
|
||||
if let Some(local_var) = context.lookup_local_var(name) {
|
||||
return Ok(Some(local_var));
|
||||
}
|
||||
if let Some(global_var) = self.context.lookup_global_var_exps.get(name) {
|
||||
if let Some(global_var) = context.lookup_global_var_exps.get(name) {
|
||||
return Ok(Some(*global_var));
|
||||
}
|
||||
if let Some(constant) = self.context.lookup_constant_exps.get(name) {
|
||||
if let Some(constant) = context.lookup_constant_exps.get(name) {
|
||||
return Ok(Some(*constant));
|
||||
}
|
||||
match name {
|
||||
@@ -38,11 +42,11 @@ impl Program<'_> {
|
||||
.context
|
||||
.expressions
|
||||
.append(Expression::GlobalVariable(h));*/
|
||||
let exp = self
|
||||
.context
|
||||
let exp = context
|
||||
.function
|
||||
.expressions
|
||||
.append(Expression::FunctionArgument(0)); //TODO
|
||||
self.context.lookup_global_var_exps.insert(name.into(), exp);
|
||||
context.lookup_global_var_exps.insert(name.into(), exp);
|
||||
|
||||
Ok(Some(exp))
|
||||
}
|
||||
@@ -74,13 +78,11 @@ impl Program<'_> {
|
||||
convert: true,
|
||||
});
|
||||
*/
|
||||
let expr = self
|
||||
.context
|
||||
let expr = context
|
||||
.function
|
||||
.expressions
|
||||
.append(Expression::FunctionArgument(0)); //TODO
|
||||
self.context
|
||||
.lookup_global_var_exps
|
||||
.insert(name.into(), expr);
|
||||
context.lookup_global_var_exps.insert(name.into(), expr);
|
||||
|
||||
Ok(Some(expr))
|
||||
}
|
||||
@@ -112,13 +114,11 @@ impl Program<'_> {
|
||||
convert: true,
|
||||
});
|
||||
*/
|
||||
let expr = self
|
||||
.context
|
||||
let expr = context
|
||||
.function
|
||||
.expressions
|
||||
.append(Expression::FunctionArgument(0)); //TODO
|
||||
self.context
|
||||
.lookup_global_var_exps
|
||||
.insert(name.into(), expr);
|
||||
context.lookup_global_var_exps.insert(name.into(), expr);
|
||||
|
||||
Ok(Some(expr))
|
||||
}
|
||||
@@ -128,20 +128,24 @@ impl Program<'_> {
|
||||
|
||||
pub fn field_selection(
|
||||
&mut self,
|
||||
context: &mut FunctionContext,
|
||||
expression: Handle<Expression>,
|
||||
name: &str,
|
||||
meta: TokenMetadata,
|
||||
) -> Result<Handle<Expression>, ErrorKind> {
|
||||
match *self.resolve_type(expression)? {
|
||||
match *self.resolve_type(context, expression)? {
|
||||
TypeInner::Struct { ref members, .. } => {
|
||||
let index = members
|
||||
.iter()
|
||||
.position(|m| m.name == Some(name.into()))
|
||||
.ok_or_else(|| ErrorKind::UnknownField(meta, name.into()))?;
|
||||
Ok(self.context.expressions.append(Expression::AccessIndex {
|
||||
base: expression,
|
||||
index: index as u32,
|
||||
}))
|
||||
Ok(context
|
||||
.function
|
||||
.expressions
|
||||
.append(Expression::AccessIndex {
|
||||
base: expression,
|
||||
index: index as u32,
|
||||
}))
|
||||
}
|
||||
// swizzles (xyzw, rgba, stpq)
|
||||
TypeInner::Vector { size, kind, width } => {
|
||||
@@ -170,17 +174,20 @@ impl Program<'_> {
|
||||
let components: Vec<Handle<Expression>> = v
|
||||
.iter()
|
||||
.map(|idx| {
|
||||
self.context.expressions.append(Expression::AccessIndex {
|
||||
base: expression,
|
||||
index: *idx as u32,
|
||||
})
|
||||
context
|
||||
.function
|
||||
.expressions
|
||||
.append(Expression::AccessIndex {
|
||||
base: expression,
|
||||
index: *idx as u32,
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
if components.len() == 1 {
|
||||
// only single element swizzle, like pos.y, just return that component
|
||||
Ok(components[0])
|
||||
} else {
|
||||
Ok(self.context.expressions.append(Expression::Compose {
|
||||
Ok(context.function.expressions.append(Expression::Compose {
|
||||
ty: self.module.types.fetch_or_append(Type {
|
||||
name: None,
|
||||
inner: TypeInner::Vector {
|
||||
|
||||
Reference in New Issue
Block a user