[glsl-in][New parser] WIP support for functions

This commit is contained in:
João Capucho
2021-05-01 14:06:27 +01:00
committed by Dzmitry Malyshau
parent ff8f15e034
commit 786194ec67
7 changed files with 427 additions and 206 deletions

View File

@@ -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,
}

View File

@@ -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(())
}
}

View File

@@ -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)),

View File

@@ -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(())
}
}

View File

@@ -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

View File

@@ -53,6 +53,7 @@ pub enum TokenValue {
For,
Void,
Struct,
TypeName(Type),
Assign,

View File

@@ -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 {