mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
[glsl-in] Expression emitting
This commit is contained in:
committed by
Dzmitry Malyshau
parent
a7100b14eb
commit
c22fa54642
@@ -1,12 +1,12 @@
|
||||
use super::{super::Typifier, constants::ConstantSolver, error::ErrorKind, SourceMetadata};
|
||||
use crate::{
|
||||
proc::ResolveContext, Arena, BinaryOperator, Binding, Block, Constant, Expression, FastHashMap,
|
||||
Function, FunctionArgument, GlobalVariable, Handle, Interpolation, LocalVariable, Module,
|
||||
RelationalFunction, ResourceBinding, Sampling, ShaderStage, Statement, StorageClass, Type,
|
||||
TypeInner, UnaryOperator,
|
||||
front::Emitter, proc::ResolveContext, Arena, BinaryOperator, Binding, Block, Constant,
|
||||
Expression, FastHashMap, Function, FunctionArgument, GlobalVariable, Handle, Interpolation,
|
||||
LocalVariable, Module, RelationalFunction, ResourceBinding, Sampling, ShaderStage, Statement,
|
||||
StorageClass, Type, TypeInner, UnaryOperator,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum GlobalLookup {
|
||||
Variable(Handle<GlobalVariable>),
|
||||
BlockSelect(Handle<GlobalVariable>, u32),
|
||||
@@ -34,8 +34,9 @@ pub struct Program<'a> {
|
||||
|
||||
pub lookup_function: FastHashMap<FunctionSignature, FunctionDeclaration>,
|
||||
pub lookup_type: FastHashMap<String, Handle<Type>>,
|
||||
pub lookup_global_variables: FastHashMap<String, GlobalLookup>,
|
||||
pub lookup_constants: FastHashMap<String, Handle<Constant>>,
|
||||
|
||||
pub global_variables: Vec<(String, GlobalLookup)>,
|
||||
pub constants: Vec<(String, Handle<Constant>)>,
|
||||
|
||||
pub entry_args: Vec<(Binding, bool, Handle<GlobalVariable>)>,
|
||||
pub entries: Vec<(String, ShaderStage, Handle<Function>)>,
|
||||
@@ -52,8 +53,8 @@ impl<'a> Program<'a> {
|
||||
|
||||
lookup_function: FastHashMap::default(),
|
||||
lookup_type: FastHashMap::default(),
|
||||
lookup_global_variables: FastHashMap::default(),
|
||||
lookup_constants: FastHashMap::default(),
|
||||
global_variables: Vec::new(),
|
||||
constants: Vec::new(),
|
||||
|
||||
entry_args: Vec::new(),
|
||||
entries: Vec::new(),
|
||||
@@ -120,13 +121,13 @@ impl<'a> Program<'a> {
|
||||
|
||||
pub fn solve_constant(
|
||||
&mut self,
|
||||
expressions: &Arena<Expression>,
|
||||
ctx: &Context,
|
||||
root: Handle<Expression>,
|
||||
meta: SourceMetadata,
|
||||
) -> Result<Handle<Constant>, ErrorKind> {
|
||||
let mut solver = ConstantSolver {
|
||||
types: &self.module.types,
|
||||
expressions,
|
||||
expressions: ctx.expressions,
|
||||
constants: &mut self.module.constants,
|
||||
};
|
||||
|
||||
@@ -141,38 +142,98 @@ pub enum Profile {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Context<'function> {
|
||||
pub expressions: &'function mut Arena<Expression>,
|
||||
expressions: &'function mut Arena<Expression>,
|
||||
pub locals: &'function mut Arena<LocalVariable>,
|
||||
pub arguments: &'function mut Vec<FunctionArgument>,
|
||||
|
||||
//TODO: Find less allocation heavy representation
|
||||
pub scopes: Vec<FastHashMap<String, VariableReference>>,
|
||||
pub lookup_global_var_exps: FastHashMap<String, VariableReference>,
|
||||
pub lookup_constant_exps: FastHashMap<String, VariableReference>,
|
||||
pub typifier: Typifier,
|
||||
pub samplers: FastHashMap<Handle<Expression>, Handle<Expression>>,
|
||||
pub typifier: Typifier,
|
||||
|
||||
pub hir_exprs: Arena<HirExpr>,
|
||||
emitter: Emitter,
|
||||
}
|
||||
|
||||
impl<'function> Context<'function> {
|
||||
pub fn new(
|
||||
program: &mut Program,
|
||||
body: &mut Block,
|
||||
expressions: &'function mut Arena<Expression>,
|
||||
locals: &'function mut Arena<LocalVariable>,
|
||||
arguments: &'function mut Vec<FunctionArgument>,
|
||||
) -> Self {
|
||||
Context {
|
||||
let mut this = Context {
|
||||
expressions,
|
||||
locals,
|
||||
arguments,
|
||||
|
||||
scopes: vec![FastHashMap::default()],
|
||||
lookup_global_var_exps: FastHashMap::default(),
|
||||
lookup_constant_exps: FastHashMap::default(),
|
||||
lookup_global_var_exps: FastHashMap::with_capacity_and_hasher(
|
||||
program.constants.len() + program.global_variables.len(),
|
||||
Default::default(),
|
||||
),
|
||||
typifier: Typifier::new(),
|
||||
samplers: FastHashMap::default(),
|
||||
|
||||
hir_exprs: Arena::default(),
|
||||
emitter: Emitter::default(),
|
||||
};
|
||||
|
||||
this.emit_start();
|
||||
|
||||
for &(ref name, lookup) in program.global_variables.iter() {
|
||||
let expr = match lookup {
|
||||
GlobalLookup::Variable(v) => Expression::GlobalVariable(v),
|
||||
GlobalLookup::BlockSelect(handle, index) => {
|
||||
let base = this.add_expression(Expression::GlobalVariable(handle), body);
|
||||
|
||||
Expression::AccessIndex { base, index }
|
||||
}
|
||||
};
|
||||
|
||||
let expr = this.add_expression(expr, body);
|
||||
let var = VariableReference {
|
||||
expr,
|
||||
load: Some(this.add_expression(Expression::Load { pointer: expr }, body)),
|
||||
// TODO: respect constant qualifier
|
||||
mutable: true,
|
||||
};
|
||||
|
||||
this.lookup_global_var_exps.insert(name.into(), var);
|
||||
}
|
||||
|
||||
for &(ref name, handle) in program.constants.iter() {
|
||||
let expr = this.add_expression(Expression::Constant(handle), body);
|
||||
let var = VariableReference {
|
||||
expr,
|
||||
load: None,
|
||||
mutable: false,
|
||||
};
|
||||
|
||||
this.lookup_global_var_exps.insert(name.into(), var);
|
||||
}
|
||||
|
||||
this
|
||||
}
|
||||
|
||||
pub fn emit_start(&mut self) {
|
||||
self.emitter.start(&self.expressions)
|
||||
}
|
||||
|
||||
pub fn emit_flush(&mut self, body: &mut Block) {
|
||||
body.extend(self.emitter.finish(&self.expressions))
|
||||
}
|
||||
|
||||
pub fn add_expression(&mut self, expr: Expression, body: &mut Block) -> Handle<Expression> {
|
||||
if expr.needs_pre_emit() {
|
||||
self.emit_flush(body);
|
||||
let expr = self.expressions.append(expr);
|
||||
self.emit_start();
|
||||
expr
|
||||
} else {
|
||||
self.expressions.append(expr)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,55 +246,8 @@ impl<'function> Context<'function> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn lookup_global_var(
|
||||
&mut self,
|
||||
program: &mut Program,
|
||||
name: &str,
|
||||
) -> Option<VariableReference> {
|
||||
self.lookup_global_var_exps.get(name).cloned().or_else(|| {
|
||||
let expr = match *program.lookup_global_variables.get(name)? {
|
||||
GlobalLookup::Variable(v) => Expression::GlobalVariable(v),
|
||||
GlobalLookup::BlockSelect(handle, index) => {
|
||||
let base = self.expressions.append(Expression::GlobalVariable(handle));
|
||||
|
||||
Expression::AccessIndex { base, index }
|
||||
}
|
||||
};
|
||||
|
||||
let expr = self.expressions.append(expr);
|
||||
let var = VariableReference {
|
||||
expr,
|
||||
load: Some(self.expressions.append(Expression::Load { pointer: expr })),
|
||||
// TODO: respect constant qualifier
|
||||
mutable: true,
|
||||
};
|
||||
|
||||
self.lookup_global_var_exps.insert(name.into(), var.clone());
|
||||
|
||||
Some(var)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn lookup_constants_var(
|
||||
&mut self,
|
||||
program: &mut Program,
|
||||
name: &str,
|
||||
) -> Option<VariableReference> {
|
||||
self.lookup_constant_exps.get(name).cloned().or_else(|| {
|
||||
let expr = self
|
||||
.expressions
|
||||
.append(Expression::Constant(*program.lookup_constants.get(name)?));
|
||||
|
||||
let var = VariableReference {
|
||||
expr,
|
||||
load: None,
|
||||
mutable: false,
|
||||
};
|
||||
|
||||
self.lookup_constant_exps.insert(name.into(), var.clone());
|
||||
|
||||
Some(var)
|
||||
})
|
||||
pub fn lookup_global_var(&mut self, name: &str) -> Option<VariableReference> {
|
||||
self.lookup_global_var_exps.get(name).cloned()
|
||||
}
|
||||
|
||||
#[cfg(feature = "glsl-validate")]
|
||||
@@ -311,15 +325,15 @@ impl<'function> Context<'function> {
|
||||
let base = self.lower(program, base, lhs, body)?.0;
|
||||
let index = self.lower(program, index, false, body)?.0;
|
||||
|
||||
self.expressions.append(Expression::Access { base, index })
|
||||
self.add_expression(Expression::Access { base, index }, body)
|
||||
}
|
||||
HirExprKind::Select { base, field } => {
|
||||
let base = self.lower(program, base, lhs, body)?.0;
|
||||
|
||||
program.field_selection(self, base, &field, meta)?
|
||||
program.field_selection(self, body, base, &field, meta)?
|
||||
}
|
||||
HirExprKind::Constant(constant) if !lhs => {
|
||||
self.expressions.append(Expression::Constant(constant))
|
||||
self.add_expression(Expression::Constant(constant), body)
|
||||
}
|
||||
HirExprKind::Binary { left, op, right } if !lhs => {
|
||||
let (left, left_meta) = self.lower(program, left, false, body)?;
|
||||
@@ -353,20 +367,18 @@ impl<'function> Context<'function> {
|
||||
if left_dims != right_dims {
|
||||
return Err(ErrorKind::SemanticError(meta, "Cannot compare".into()));
|
||||
} else if left_is_vector && right_is_vector {
|
||||
self.expressions
|
||||
.append(Expression::Relational { fun, argument })
|
||||
self.add_expression(Expression::Relational { fun, argument }, body)
|
||||
} else {
|
||||
argument
|
||||
}
|
||||
} else {
|
||||
self.expressions
|
||||
.append(Expression::Binary { left, op, right })
|
||||
self.add_expression(Expression::Binary { left, op, right }, body)
|
||||
}
|
||||
}
|
||||
HirExprKind::Unary { op, expr } if !lhs => {
|
||||
let expr = self.lower(program, expr, false, body)?.0;
|
||||
|
||||
self.expressions.append(Expression::Unary { op, expr })
|
||||
self.add_expression(Expression::Unary { op, expr }, body)
|
||||
}
|
||||
HirExprKind::Variable(var) => {
|
||||
if lhs {
|
||||
@@ -394,16 +406,22 @@ impl<'function> Context<'function> {
|
||||
let accept = self.lower(program, accept, false, body)?.0;
|
||||
let reject = self.lower(program, reject, false, body)?.0;
|
||||
|
||||
self.expressions.append(Expression::Select {
|
||||
condition,
|
||||
accept,
|
||||
reject,
|
||||
})
|
||||
self.add_expression(
|
||||
Expression::Select {
|
||||
condition,
|
||||
accept,
|
||||
reject,
|
||||
},
|
||||
body,
|
||||
)
|
||||
}
|
||||
HirExprKind::Assign { tgt, value } if !lhs => {
|
||||
let pointer = self.lower(program, tgt, true, body)?.0;
|
||||
let value = self.lower(program, value, false, body)?.0;
|
||||
|
||||
self.emit_flush(body);
|
||||
self.emit_start();
|
||||
|
||||
body.push(Statement::Store { pointer, value });
|
||||
|
||||
value
|
||||
|
||||
@@ -30,53 +30,63 @@ impl Program<'_> {
|
||||
};
|
||||
|
||||
match self.module.types[ty].inner {
|
||||
TypeInner::Vector { size, .. } if !is_vec => {
|
||||
ctx.expressions.append(Expression::Splat {
|
||||
TypeInner::Vector { size, .. } if !is_vec => ctx.add_expression(
|
||||
Expression::Splat {
|
||||
size,
|
||||
value: args[0].0,
|
||||
})
|
||||
}
|
||||
},
|
||||
body,
|
||||
),
|
||||
TypeInner::Scalar { kind, width }
|
||||
| TypeInner::Vector { kind, width, .. } => {
|
||||
ctx.expressions.append(Expression::As {
|
||||
| TypeInner::Vector { kind, width, .. } => ctx.add_expression(
|
||||
Expression::As {
|
||||
kind,
|
||||
expr: args[0].0,
|
||||
convert: Some(width),
|
||||
})
|
||||
}
|
||||
},
|
||||
body,
|
||||
),
|
||||
TypeInner::Matrix {
|
||||
columns,
|
||||
rows,
|
||||
width,
|
||||
} => {
|
||||
let value = ctx.expressions.append(Expression::As {
|
||||
kind: ScalarKind::Float,
|
||||
expr: args[0].0,
|
||||
convert: Some(width),
|
||||
});
|
||||
let value = ctx.add_expression(
|
||||
Expression::As {
|
||||
kind: ScalarKind::Float,
|
||||
expr: args[0].0,
|
||||
convert: Some(width),
|
||||
},
|
||||
body,
|
||||
);
|
||||
|
||||
let column = if is_vec {
|
||||
value
|
||||
} else {
|
||||
ctx.expressions
|
||||
.append(Expression::Splat { size: rows, value })
|
||||
ctx.add_expression(Expression::Splat { size: rows, value }, body)
|
||||
};
|
||||
|
||||
let columns =
|
||||
std::iter::repeat(column).take(columns as usize).collect();
|
||||
|
||||
ctx.expressions.append(Expression::Compose {
|
||||
ty,
|
||||
components: columns,
|
||||
})
|
||||
ctx.add_expression(
|
||||
Expression::Compose {
|
||||
ty,
|
||||
components: columns,
|
||||
},
|
||||
body,
|
||||
)
|
||||
}
|
||||
_ => return Err(ErrorKind::SemanticError(meta, "Bad cast".into())),
|
||||
}
|
||||
} else {
|
||||
ctx.expressions.append(Expression::Compose {
|
||||
ty,
|
||||
components: args.iter().map(|e| e.0).collect(),
|
||||
})
|
||||
ctx.add_expression(
|
||||
Expression::Compose {
|
||||
ty,
|
||||
components: args.iter().map(|e| e.0).collect(),
|
||||
},
|
||||
body,
|
||||
)
|
||||
};
|
||||
|
||||
Ok(h)
|
||||
@@ -95,15 +105,18 @@ impl Program<'_> {
|
||||
return Err(ErrorKind::wrong_function_args(name, 2, args.len(), meta));
|
||||
}
|
||||
if let Some(sampler) = ctx.samplers.get(&args[0].0).copied() {
|
||||
Ok(ctx.expressions.append(Expression::ImageSample {
|
||||
image: args[0].0,
|
||||
sampler,
|
||||
coordinate: args[1].0,
|
||||
array_index: None, //TODO
|
||||
offset: None, //TODO
|
||||
level: SampleLevel::Auto,
|
||||
depth_ref: None,
|
||||
}))
|
||||
Ok(ctx.add_expression(
|
||||
Expression::ImageSample {
|
||||
image: args[0].0,
|
||||
sampler,
|
||||
coordinate: args[1].0,
|
||||
array_index: None, //TODO
|
||||
offset: None, //TODO
|
||||
level: SampleLevel::Auto,
|
||||
depth_ref: None,
|
||||
},
|
||||
body,
|
||||
))
|
||||
} else {
|
||||
Err(ErrorKind::SemanticError(meta, "Bad call to texture".into()))
|
||||
}
|
||||
@@ -113,15 +126,18 @@ impl Program<'_> {
|
||||
return Err(ErrorKind::wrong_function_args(name, 3, args.len(), meta));
|
||||
}
|
||||
if let Some(sampler) = ctx.samplers.get(&args[0].0).copied() {
|
||||
Ok(ctx.expressions.append(Expression::ImageSample {
|
||||
image: args[0].0,
|
||||
sampler,
|
||||
coordinate: args[1].0,
|
||||
array_index: None, //TODO
|
||||
offset: None, //TODO
|
||||
level: SampleLevel::Exact(args[2].0),
|
||||
depth_ref: None,
|
||||
}))
|
||||
Ok(ctx.add_expression(
|
||||
Expression::ImageSample {
|
||||
image: args[0].0,
|
||||
sampler,
|
||||
coordinate: args[1].0,
|
||||
array_index: None, //TODO
|
||||
offset: None, //TODO
|
||||
level: SampleLevel::Exact(args[2].0),
|
||||
depth_ref: None,
|
||||
},
|
||||
body,
|
||||
))
|
||||
} else {
|
||||
Err(ErrorKind::SemanticError(
|
||||
meta,
|
||||
@@ -135,91 +151,102 @@ impl Program<'_> {
|
||||
if args.len() != 1 {
|
||||
return Err(ErrorKind::wrong_function_args(name, 1, args.len(), meta));
|
||||
}
|
||||
Ok(ctx.expressions.append(Expression::Math {
|
||||
fun: match name.as_str() {
|
||||
"ceil" => MathFunction::Ceil,
|
||||
"round" => MathFunction::Round,
|
||||
"floor" => MathFunction::Floor,
|
||||
"fract" => MathFunction::Fract,
|
||||
"trunc" => MathFunction::Trunc,
|
||||
"sin" => MathFunction::Sin,
|
||||
"abs" => MathFunction::Abs,
|
||||
"sqrt" => MathFunction::Sqrt,
|
||||
"inversesqrt" => MathFunction::InverseSqrt,
|
||||
"exp" => MathFunction::Exp,
|
||||
"exp2" => MathFunction::Exp2,
|
||||
"sign" => MathFunction::Sign,
|
||||
"transpose" => MathFunction::Transpose,
|
||||
"inverse" => MathFunction::Inverse,
|
||||
"normalize" => MathFunction::Normalize,
|
||||
_ => unreachable!(),
|
||||
Ok(ctx.add_expression(
|
||||
Expression::Math {
|
||||
fun: match name.as_str() {
|
||||
"ceil" => MathFunction::Ceil,
|
||||
"round" => MathFunction::Round,
|
||||
"floor" => MathFunction::Floor,
|
||||
"fract" => MathFunction::Fract,
|
||||
"trunc" => MathFunction::Trunc,
|
||||
"sin" => MathFunction::Sin,
|
||||
"abs" => MathFunction::Abs,
|
||||
"sqrt" => MathFunction::Sqrt,
|
||||
"inversesqrt" => MathFunction::InverseSqrt,
|
||||
"exp" => MathFunction::Exp,
|
||||
"exp2" => MathFunction::Exp2,
|
||||
"sign" => MathFunction::Sign,
|
||||
"transpose" => MathFunction::Transpose,
|
||||
"inverse" => MathFunction::Inverse,
|
||||
"normalize" => MathFunction::Normalize,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
arg: args[0].0,
|
||||
arg1: None,
|
||||
arg2: None,
|
||||
},
|
||||
arg: args[0].0,
|
||||
arg1: None,
|
||||
arg2: None,
|
||||
}))
|
||||
body,
|
||||
))
|
||||
}
|
||||
"pow" | "dot" | "max" => {
|
||||
if args.len() != 2 {
|
||||
return Err(ErrorKind::wrong_function_args(name, 2, args.len(), meta));
|
||||
}
|
||||
Ok(ctx.expressions.append(Expression::Math {
|
||||
fun: match name.as_str() {
|
||||
"pow" => MathFunction::Pow,
|
||||
"dot" => MathFunction::Dot,
|
||||
"max" => MathFunction::Max,
|
||||
_ => unreachable!(),
|
||||
Ok(ctx.add_expression(
|
||||
Expression::Math {
|
||||
fun: match name.as_str() {
|
||||
"pow" => MathFunction::Pow,
|
||||
"dot" => MathFunction::Dot,
|
||||
"max" => MathFunction::Max,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
arg: args[0].0,
|
||||
arg1: Some(args[1].0),
|
||||
arg2: None,
|
||||
},
|
||||
arg: args[0].0,
|
||||
arg1: Some(args[1].0),
|
||||
arg2: None,
|
||||
}))
|
||||
body,
|
||||
))
|
||||
}
|
||||
"mix" | "clamp" => {
|
||||
if args.len() != 3 {
|
||||
return Err(ErrorKind::wrong_function_args(name, 3, args.len(), meta));
|
||||
}
|
||||
Ok(ctx.expressions.append(Expression::Math {
|
||||
fun: match name.as_str() {
|
||||
"mix" => MathFunction::Mix,
|
||||
"clamp" => MathFunction::Clamp,
|
||||
_ => unreachable!(),
|
||||
Ok(ctx.add_expression(
|
||||
Expression::Math {
|
||||
fun: match name.as_str() {
|
||||
"mix" => MathFunction::Mix,
|
||||
"clamp" => MathFunction::Clamp,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
arg: args[0].0,
|
||||
arg1: Some(args[1].0),
|
||||
arg2: Some(args[2].0),
|
||||
},
|
||||
arg: args[0].0,
|
||||
arg1: Some(args[1].0),
|
||||
arg2: Some(args[2].0),
|
||||
}))
|
||||
body,
|
||||
))
|
||||
}
|
||||
"lessThan" | "greaterThan" | "lessThanEqual" | "greaterThanEqual" | "equal"
|
||||
| "notEqual" => {
|
||||
if args.len() != 2 {
|
||||
return Err(ErrorKind::wrong_function_args(name, 2, args.len(), meta));
|
||||
}
|
||||
Ok(ctx.expressions.append(Expression::Binary {
|
||||
op: match name.as_str() {
|
||||
"lessThan" => BinaryOperator::Less,
|
||||
"greaterThan" => BinaryOperator::Greater,
|
||||
"lessThanEqual" => BinaryOperator::LessEqual,
|
||||
"greaterThanEqual" => BinaryOperator::GreaterEqual,
|
||||
"equal" => BinaryOperator::Equal,
|
||||
"notEqual" => BinaryOperator::NotEqual,
|
||||
_ => unreachable!(),
|
||||
Ok(ctx.add_expression(
|
||||
Expression::Binary {
|
||||
op: match name.as_str() {
|
||||
"lessThan" => BinaryOperator::Less,
|
||||
"greaterThan" => BinaryOperator::Greater,
|
||||
"lessThanEqual" => BinaryOperator::LessEqual,
|
||||
"greaterThanEqual" => BinaryOperator::GreaterEqual,
|
||||
"equal" => BinaryOperator::Equal,
|
||||
"notEqual" => BinaryOperator::NotEqual,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
left: args[0].0,
|
||||
right: args[1].0,
|
||||
},
|
||||
left: args[0].0,
|
||||
right: args[1].0,
|
||||
}))
|
||||
body,
|
||||
))
|
||||
}
|
||||
"isinf" => {
|
||||
self.parse_relational_fun(ctx, name, &args, RelationalFunction::IsInf, meta)
|
||||
}
|
||||
"isnan" => {
|
||||
self.parse_relational_fun(ctx, name, &args, RelationalFunction::IsNan, meta)
|
||||
}
|
||||
"all" => {
|
||||
self.parse_relational_fun(ctx, name, &args, RelationalFunction::All, meta)
|
||||
}
|
||||
"any" => {
|
||||
self.parse_relational_fun(ctx, name, &args, RelationalFunction::Any, meta)
|
||||
"isinf" | "isnan" | "all" | "any" => {
|
||||
let fun = match name.as_str() {
|
||||
"isinf" => RelationalFunction::IsInf,
|
||||
"isnan" => RelationalFunction::IsNan,
|
||||
"all" => RelationalFunction::All,
|
||||
"any" => RelationalFunction::Any,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
self.parse_relational_fun(ctx, body, name, &args, fun, meta)
|
||||
}
|
||||
_ => {
|
||||
let mut parameters = Vec::new();
|
||||
@@ -250,12 +277,17 @@ impl Program<'_> {
|
||||
arguments.push(handle)
|
||||
}
|
||||
|
||||
let expression = ctx.expressions.append(Expression::Call(fun.handle));
|
||||
ctx.emit_flush(body);
|
||||
|
||||
let expression = ctx.add_expression(Expression::Call(fun.handle), body);
|
||||
body.push(crate::Statement::Call {
|
||||
function: fun.handle,
|
||||
arguments,
|
||||
result: Some(expression),
|
||||
});
|
||||
|
||||
ctx.emit_start();
|
||||
|
||||
Ok(expression)
|
||||
}
|
||||
}
|
||||
@@ -266,6 +298,7 @@ impl Program<'_> {
|
||||
pub fn parse_relational_fun(
|
||||
&mut self,
|
||||
ctx: &mut Context,
|
||||
body: &mut Block,
|
||||
name: String,
|
||||
args: &[(Handle<Expression>, SourceMetadata)],
|
||||
fun: RelationalFunction,
|
||||
@@ -275,10 +308,13 @@ impl Program<'_> {
|
||||
return Err(ErrorKind::wrong_function_args(name, 1, args.len(), meta));
|
||||
}
|
||||
|
||||
Ok(ctx.expressions.append(Expression::Relational {
|
||||
fun,
|
||||
argument: args[0].0,
|
||||
}))
|
||||
Ok(ctx.add_expression(
|
||||
Expression::Relational {
|
||||
fun,
|
||||
argument: args[0].0,
|
||||
},
|
||||
body,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn add_function(
|
||||
@@ -438,7 +474,9 @@ impl Program<'_> {
|
||||
span += self.module.types[ty].inner.span(&self.module.constants);
|
||||
|
||||
let pointer = expressions.append(Expression::GlobalVariable(handle));
|
||||
let len = expressions.len();
|
||||
let load = expressions.append(Expression::Load { pointer });
|
||||
body.push(Statement::Emit(expressions.range_from(len)));
|
||||
components.push(load)
|
||||
}
|
||||
|
||||
@@ -451,7 +489,9 @@ impl Program<'_> {
|
||||
},
|
||||
});
|
||||
|
||||
let len = expressions.len();
|
||||
let res = expressions.append(Expression::Compose { ty, components });
|
||||
body.push(Statement::Emit(expressions.range_from(len)));
|
||||
body.push(Statement::Return { value: Some(res) });
|
||||
|
||||
self.module.entry_points.push(EntryPoint {
|
||||
|
||||
@@ -319,13 +319,20 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> {
|
||||
let mut expressions = Arena::new();
|
||||
let mut locals = Arena::new();
|
||||
let mut arguments = Vec::new();
|
||||
let mut block = Block::new();
|
||||
|
||||
let mut ctx = Context::new(&mut expressions, &mut locals, &mut arguments);
|
||||
let mut ctx = Context::new(
|
||||
self.program,
|
||||
&mut block,
|
||||
&mut expressions,
|
||||
&mut locals,
|
||||
&mut arguments,
|
||||
);
|
||||
|
||||
let expr = self.parse_conditional(&mut ctx, None)?;
|
||||
let (root, meta) = ctx.lower(self.program, expr, false, &mut Block::new())?;
|
||||
let expr = self.parse_conditional(&mut ctx, &mut block, None)?;
|
||||
let (root, meta) = ctx.lower(self.program, expr, false, &mut block)?;
|
||||
|
||||
Ok((self.program.solve_constant(&expressions, root, meta)?, meta))
|
||||
Ok((self.program.solve_constant(&ctx, root, meta)?, meta))
|
||||
}
|
||||
|
||||
fn parse_external_declaration(&mut self) -> Result<()> {
|
||||
@@ -339,8 +346,8 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> {
|
||||
// void main() {}
|
||||
// ```
|
||||
let (mut e, mut l, mut a) = (Arena::new(), Arena::new(), Vec::new());
|
||||
let mut ctx = Context::new(&mut e, &mut l, &mut a);
|
||||
let mut body = Block::new();
|
||||
let mut ctx = Context::new(self.program, &mut body, &mut e, &mut l, &mut a);
|
||||
|
||||
if !self.parse_declaration(&mut ctx, &mut body, true)? {
|
||||
let token = self.bump()?;
|
||||
@@ -422,12 +429,11 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> {
|
||||
}
|
||||
|
||||
Ok((
|
||||
ctx.expressions
|
||||
.append(Expression::Compose { ty, components }),
|
||||
ctx.add_expression(Expression::Compose { ty, components }, body),
|
||||
meta,
|
||||
))
|
||||
} else {
|
||||
let expr = self.parse_assignment(ctx)?;
|
||||
let expr = self.parse_assignment(ctx, body)?;
|
||||
Ok(ctx.lower(self.program, expr, false, body)?)
|
||||
}
|
||||
}
|
||||
@@ -499,15 +505,15 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> {
|
||||
// TODO: Should we try to make constants here?
|
||||
// This is mostly a hack because we don't yet support adding
|
||||
// bodies to entry points for variable initialization
|
||||
let maybe_constant = init.clone().and_then(|(root, meta)| {
|
||||
self.program
|
||||
.solve_constant(ctx.ctx.expressions, root, meta)
|
||||
.ok()
|
||||
});
|
||||
let maybe_constant = init
|
||||
.clone()
|
||||
.and_then(|(root, meta)| self.program.solve_constant(ctx.ctx, root, meta).ok());
|
||||
|
||||
let pointer = ctx.add_var(self.program, ty, name, maybe_constant, meta)?;
|
||||
|
||||
if let Some((value, _)) = init {
|
||||
ctx.ctx.emit_flush(ctx.body);
|
||||
ctx.ctx.emit_start();
|
||||
ctx.body.push(Statement::Store { pointer, value });
|
||||
}
|
||||
|
||||
@@ -561,8 +567,11 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> {
|
||||
let mut local_variables = Arena::new();
|
||||
let mut arguments = Vec::new();
|
||||
let mut parameters = Vec::new();
|
||||
let mut body = Block::new();
|
||||
|
||||
let mut context = Context::new(
|
||||
self.program,
|
||||
&mut body,
|
||||
&mut expressions,
|
||||
&mut local_variables,
|
||||
&mut arguments,
|
||||
@@ -594,10 +603,10 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> {
|
||||
// This branch handles function definitions
|
||||
// as you can see by the guard this branch
|
||||
// only happens if external is also true
|
||||
let mut body = Block::new();
|
||||
|
||||
// parse the body
|
||||
self.parse_compound_statement(&mut context, &mut body)?;
|
||||
|
||||
self.program.add_function(
|
||||
Function {
|
||||
name: Some(name),
|
||||
@@ -773,8 +782,8 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> {
|
||||
|
||||
if let Some(k) = name {
|
||||
self.program
|
||||
.lookup_global_variables
|
||||
.insert(k, GlobalLookup::Variable(handle));
|
||||
.global_variables
|
||||
.push((k, GlobalLookup::Variable(handle)));
|
||||
}
|
||||
|
||||
for (i, k) in members
|
||||
@@ -783,8 +792,8 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> {
|
||||
.filter_map(|(i, m)| m.name.map(|s| (i as u32, s)))
|
||||
{
|
||||
self.program
|
||||
.lookup_global_variables
|
||||
.insert(k, GlobalLookup::BlockSelect(handle, i));
|
||||
.global_variables
|
||||
.push((k, GlobalLookup::BlockSelect(handle, i)));
|
||||
}
|
||||
|
||||
Ok(true)
|
||||
@@ -819,7 +828,7 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> {
|
||||
Ok(span)
|
||||
}
|
||||
|
||||
fn parse_primary(&mut self, ctx: &mut Context) -> Result<Handle<HirExpr>> {
|
||||
fn parse_primary(&mut self, ctx: &mut Context, body: &mut Block) -> Result<Handle<HirExpr>> {
|
||||
let mut token = self.bump()?;
|
||||
|
||||
let (width, value) = match token.value {
|
||||
@@ -837,7 +846,7 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> {
|
||||
),
|
||||
TokenValue::BoolConstant(value) => (1, ScalarValue::Bool(value)),
|
||||
TokenValue::LeftParen => {
|
||||
let expr = self.parse_expression(ctx)?;
|
||||
let expr = self.parse_expression(ctx, body)?;
|
||||
let meta = self.expect(TokenValue::RightParen)?.meta;
|
||||
|
||||
token.meta = token.meta.union(&meta);
|
||||
@@ -862,6 +871,7 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> {
|
||||
fn parse_function_call_args(
|
||||
&mut self,
|
||||
ctx: &mut Context,
|
||||
body: &mut Block,
|
||||
meta: &mut SourceMetadata,
|
||||
) -> Result<Vec<Handle<HirExpr>>> {
|
||||
let mut args = Vec::new();
|
||||
@@ -869,7 +879,7 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> {
|
||||
*meta = meta.union(&token.meta);
|
||||
} else {
|
||||
loop {
|
||||
args.push(self.parse_assignment(ctx)?);
|
||||
args.push(self.parse_assignment(ctx, body)?);
|
||||
|
||||
let token = self.bump()?;
|
||||
match token.value {
|
||||
@@ -886,13 +896,13 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> {
|
||||
Ok(args)
|
||||
}
|
||||
|
||||
fn parse_postfix(&mut self, ctx: &mut Context) -> Result<Handle<HirExpr>> {
|
||||
fn parse_postfix(&mut self, ctx: &mut Context, body: &mut Block) -> Result<Handle<HirExpr>> {
|
||||
let mut base = match self.expect_peek()?.value {
|
||||
TokenValue::Identifier(_) => {
|
||||
let (name, mut meta) = self.expect_ident()?;
|
||||
|
||||
let expr = if self.bump_if(TokenValue::LeftParen).is_some() {
|
||||
let args = self.parse_function_call_args(ctx, &mut meta)?;
|
||||
let args = self.parse_function_call_args(ctx, body, &mut meta)?;
|
||||
|
||||
HirExpr {
|
||||
kind: HirExprKind::Call(FunctionCall {
|
||||
@@ -902,7 +912,7 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> {
|
||||
meta,
|
||||
}
|
||||
} else {
|
||||
let var = match self.program.lookup_variable(ctx, &name)? {
|
||||
let var = match self.program.lookup_variable(ctx, body, &name)? {
|
||||
Some(var) => var,
|
||||
None => return Err(ErrorKind::UnknownVariable(meta, name)),
|
||||
};
|
||||
@@ -925,7 +935,7 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> {
|
||||
};
|
||||
|
||||
self.expect(TokenValue::LeftParen)?;
|
||||
let args = self.parse_function_call_args(ctx, &mut meta)?;
|
||||
let args = self.parse_function_call_args(ctx, body, &mut meta)?;
|
||||
|
||||
ctx.hir_exprs.append(HirExpr {
|
||||
kind: HirExprKind::Call(FunctionCall {
|
||||
@@ -935,7 +945,7 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> {
|
||||
meta,
|
||||
})
|
||||
}
|
||||
_ => self.parse_primary(ctx)?,
|
||||
_ => self.parse_primary(ctx, body)?,
|
||||
};
|
||||
|
||||
// TODO: postfix inc/dec
|
||||
@@ -944,7 +954,7 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> {
|
||||
|
||||
match value {
|
||||
TokenValue::LeftBracket => {
|
||||
let index = self.parse_expression(ctx)?;
|
||||
let index = self.parse_expression(ctx, body)?;
|
||||
let end_meta = self.expect(TokenValue::RightBracket)?.meta;
|
||||
|
||||
base = ctx.hir_exprs.append(HirExpr {
|
||||
@@ -967,13 +977,13 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> {
|
||||
Ok(base)
|
||||
}
|
||||
|
||||
fn parse_unary(&mut self, ctx: &mut Context) -> Result<Handle<HirExpr>> {
|
||||
fn parse_unary(&mut self, ctx: &mut Context, body: &mut Block) -> Result<Handle<HirExpr>> {
|
||||
// TODO: prefix inc/dec
|
||||
Ok(match self.expect_peek()?.value {
|
||||
TokenValue::Plus | TokenValue::Dash | TokenValue::Bang | TokenValue::Tilde => {
|
||||
let Token { value, meta } = self.bump()?;
|
||||
|
||||
let expr = self.parse_unary(ctx)?;
|
||||
let expr = self.parse_unary(ctx, body)?;
|
||||
let end_meta = ctx.hir_exprs[expr].meta;
|
||||
|
||||
let kind = match value {
|
||||
@@ -993,19 +1003,20 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> {
|
||||
meta: meta.union(&end_meta),
|
||||
})
|
||||
}
|
||||
_ => self.parse_postfix(ctx)?,
|
||||
_ => self.parse_postfix(ctx, body)?,
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_binary(
|
||||
&mut self,
|
||||
ctx: &mut Context,
|
||||
body: &mut Block,
|
||||
passtrough: Option<Handle<HirExpr>>,
|
||||
min_bp: u8,
|
||||
) -> Result<Handle<HirExpr>> {
|
||||
let mut left = passtrough
|
||||
.ok_or(ErrorKind::EndOfFile /* Dummy error */)
|
||||
.or_else(|_| self.parse_unary(ctx))?;
|
||||
.or_else(|_| self.parse_unary(ctx, body))?;
|
||||
let start_meta = ctx.hir_exprs[left].meta;
|
||||
|
||||
while let Some((l_bp, r_bp)) = binding_power(&self.expect_peek()?.value) {
|
||||
@@ -1015,7 +1026,7 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> {
|
||||
|
||||
let Token { value, .. } = self.bump()?;
|
||||
|
||||
let right = self.parse_binary(ctx, None, r_bp)?;
|
||||
let right = self.parse_binary(ctx, body, None, r_bp)?;
|
||||
let end_meta = ctx.hir_exprs[right].meta;
|
||||
|
||||
left = ctx.hir_exprs.append(HirExpr {
|
||||
@@ -1055,15 +1066,16 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> {
|
||||
fn parse_conditional(
|
||||
&mut self,
|
||||
ctx: &mut Context,
|
||||
body: &mut Block,
|
||||
passtrough: Option<Handle<HirExpr>>,
|
||||
) -> Result<Handle<HirExpr>> {
|
||||
let mut condition = self.parse_binary(ctx, passtrough, 0)?;
|
||||
let mut condition = self.parse_binary(ctx, body, passtrough, 0)?;
|
||||
let start_meta = ctx.hir_exprs[condition].meta;
|
||||
|
||||
if self.bump_if(TokenValue::Question).is_some() {
|
||||
let accept = self.parse_expression(ctx)?;
|
||||
let accept = self.parse_expression(ctx, body)?;
|
||||
self.expect(TokenValue::Colon)?;
|
||||
let reject = self.parse_assignment(ctx)?;
|
||||
let reject = self.parse_assignment(ctx, body)?;
|
||||
let end_meta = ctx.hir_exprs[reject].meta;
|
||||
|
||||
condition = ctx.hir_exprs.append(HirExpr {
|
||||
@@ -1079,14 +1091,14 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> {
|
||||
Ok(condition)
|
||||
}
|
||||
|
||||
fn parse_assignment(&mut self, ctx: &mut Context) -> Result<Handle<HirExpr>> {
|
||||
let tgt = self.parse_unary(ctx)?;
|
||||
fn parse_assignment(&mut self, ctx: &mut Context, body: &mut Block) -> Result<Handle<HirExpr>> {
|
||||
let tgt = self.parse_unary(ctx, body)?;
|
||||
let start_meta = ctx.hir_exprs[tgt].meta;
|
||||
|
||||
Ok(match self.expect_peek()?.value {
|
||||
TokenValue::Assign => {
|
||||
self.bump()?;
|
||||
let value = self.parse_assignment(ctx)?;
|
||||
let value = self.parse_assignment(ctx, body)?;
|
||||
let end_meta = ctx.hir_exprs[value].meta;
|
||||
|
||||
ctx.hir_exprs.append(HirExpr {
|
||||
@@ -1105,7 +1117,7 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> {
|
||||
| TokenValue::RightShiftAssign
|
||||
| TokenValue::XorAssign => {
|
||||
let token = self.bump()?;
|
||||
let right = self.parse_assignment(ctx)?;
|
||||
let right = self.parse_assignment(ctx, body)?;
|
||||
let end_meta = ctx.hir_exprs[right].meta;
|
||||
|
||||
let value = ctx.hir_exprs.append(HirExpr {
|
||||
@@ -1134,16 +1146,16 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> {
|
||||
meta: start_meta.union(&end_meta),
|
||||
})
|
||||
}
|
||||
_ => self.parse_conditional(ctx, Some(tgt))?,
|
||||
_ => self.parse_conditional(ctx, body, Some(tgt))?,
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_expression(&mut self, ctx: &mut Context) -> Result<Handle<HirExpr>> {
|
||||
let mut expr = self.parse_assignment(ctx)?;
|
||||
fn parse_expression(&mut self, ctx: &mut Context, body: &mut Block) -> Result<Handle<HirExpr>> {
|
||||
let mut expr = self.parse_assignment(ctx, body)?;
|
||||
|
||||
while let TokenValue::Comma = self.expect_peek()?.value {
|
||||
self.bump()?;
|
||||
expr = self.parse_assignment(ctx)?;
|
||||
expr = self.parse_assignment(ctx, body)?;
|
||||
}
|
||||
|
||||
Ok(expr)
|
||||
@@ -1169,12 +1181,15 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> {
|
||||
None
|
||||
}
|
||||
_ => {
|
||||
let expr = self.parse_expression(ctx)?;
|
||||
let expr = self.parse_expression(ctx, body)?;
|
||||
self.expect(TokenValue::Semicolon)?;
|
||||
Some(ctx.lower(self.program, expr, false, body)?.0)
|
||||
}
|
||||
};
|
||||
|
||||
ctx.emit_flush(body);
|
||||
ctx.emit_start();
|
||||
|
||||
body.push(Statement::Return { value })
|
||||
}
|
||||
TokenValue::Discard => {
|
||||
@@ -1187,11 +1202,14 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> {
|
||||
|
||||
self.expect(TokenValue::LeftParen)?;
|
||||
let condition = {
|
||||
let expr = self.parse_expression(ctx)?;
|
||||
let expr = self.parse_expression(ctx, body)?;
|
||||
ctx.lower(self.program, expr, false, body)?.0
|
||||
};
|
||||
self.expect(TokenValue::RightParen)?;
|
||||
|
||||
ctx.emit_flush(body);
|
||||
ctx.emit_start();
|
||||
|
||||
let mut accept = Block::new();
|
||||
self.parse_statement(ctx, &mut accept)?;
|
||||
|
||||
@@ -1211,11 +1229,14 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> {
|
||||
|
||||
self.expect(TokenValue::LeftParen)?;
|
||||
let selector = {
|
||||
let expr = self.parse_expression(ctx)?;
|
||||
let expr = self.parse_expression(ctx, body)?;
|
||||
ctx.lower(self.program, expr, false, body)?.0
|
||||
};
|
||||
self.expect(TokenValue::RightParen)?;
|
||||
|
||||
ctx.emit_flush(body);
|
||||
ctx.emit_start();
|
||||
|
||||
let mut cases = Vec::new();
|
||||
let mut default = Block::new();
|
||||
|
||||
@@ -1225,10 +1246,9 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> {
|
||||
TokenValue::Case => {
|
||||
self.bump()?;
|
||||
let value = {
|
||||
let expr = self.parse_expression(ctx)?;
|
||||
let expr = self.parse_expression(ctx, body)?;
|
||||
let (root, meta) = ctx.lower(self.program, expr, false, body)?;
|
||||
let constant =
|
||||
self.program.solve_constant(&ctx.expressions, root, meta)?;
|
||||
let constant = self.program.solve_constant(&ctx, root, meta)?;
|
||||
|
||||
match self.program.module.constants[constant].inner {
|
||||
ConstantInner::Scalar {
|
||||
@@ -1306,17 +1326,23 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> {
|
||||
TokenValue::While => {
|
||||
self.bump()?;
|
||||
|
||||
self.expect(TokenValue::LeftParen)?;
|
||||
let root = self.parse_expression(ctx)?;
|
||||
self.expect(TokenValue::RightParen)?;
|
||||
|
||||
let mut loop_body = Block::new();
|
||||
|
||||
self.expect(TokenValue::LeftParen)?;
|
||||
let root = self.parse_expression(ctx, &mut loop_body)?;
|
||||
self.expect(TokenValue::RightParen)?;
|
||||
|
||||
let expr = ctx.lower(self.program, root, false, &mut loop_body)?.0;
|
||||
let condition = ctx.expressions.append(Expression::Unary {
|
||||
op: UnaryOperator::Not,
|
||||
expr,
|
||||
});
|
||||
let condition = ctx.add_expression(
|
||||
Expression::Unary {
|
||||
op: UnaryOperator::Not,
|
||||
expr,
|
||||
},
|
||||
&mut loop_body,
|
||||
);
|
||||
|
||||
ctx.emit_flush(&mut loop_body);
|
||||
ctx.emit_start();
|
||||
|
||||
loop_body.push(Statement::If {
|
||||
condition,
|
||||
@@ -1339,14 +1365,20 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> {
|
||||
|
||||
self.expect(TokenValue::While)?;
|
||||
self.expect(TokenValue::LeftParen)?;
|
||||
let root = self.parse_expression(ctx)?;
|
||||
let root = self.parse_expression(ctx, &mut loop_body)?;
|
||||
self.expect(TokenValue::RightParen)?;
|
||||
|
||||
let expr = ctx.lower(self.program, root, false, &mut loop_body)?.0;
|
||||
let condition = ctx.expressions.append(Expression::Unary {
|
||||
op: UnaryOperator::Not,
|
||||
expr,
|
||||
});
|
||||
let condition = ctx.add_expression(
|
||||
Expression::Unary {
|
||||
op: UnaryOperator::Not,
|
||||
expr,
|
||||
},
|
||||
&mut loop_body,
|
||||
);
|
||||
|
||||
ctx.emit_flush(&mut loop_body);
|
||||
ctx.emit_start();
|
||||
|
||||
loop_body.push(Statement::If {
|
||||
condition,
|
||||
@@ -1369,11 +1401,14 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> {
|
||||
if self.peek_type_name() || self.peek_type_qualifier() {
|
||||
self.parse_declaration(ctx, body, false)?;
|
||||
} else {
|
||||
self.parse_expression(ctx)?;
|
||||
self.parse_expression(ctx, body)?;
|
||||
self.expect(TokenValue::Semicolon)?;
|
||||
}
|
||||
}
|
||||
|
||||
ctx.emit_flush(body);
|
||||
ctx.emit_start();
|
||||
|
||||
let (mut block, mut continuing) = (Block::new(), Block::new());
|
||||
|
||||
if self.bump_if(TokenValue::Semicolon).is_none() {
|
||||
@@ -1394,21 +1429,32 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> {
|
||||
meta: meta.union(&end_meta),
|
||||
};
|
||||
|
||||
let pointer = self.program.add_local_var(ctx, decl)?;
|
||||
let pointer = self.program.add_local_var(ctx, &mut block, decl)?;
|
||||
|
||||
ctx.emit_flush(&mut block);
|
||||
ctx.emit_start();
|
||||
|
||||
block.push(Statement::Store { pointer, value });
|
||||
|
||||
value
|
||||
} else {
|
||||
let root = self.parse_expression(ctx)?;
|
||||
let root = self.parse_expression(ctx, &mut block)?;
|
||||
ctx.lower(self.program, root, false, &mut block)?.0
|
||||
};
|
||||
|
||||
body.push(Statement::If {
|
||||
condition: ctx.expressions.append(Expression::Unary {
|
||||
let condition = ctx.add_expression(
|
||||
Expression::Unary {
|
||||
op: UnaryOperator::Not,
|
||||
expr,
|
||||
}),
|
||||
},
|
||||
&mut block,
|
||||
);
|
||||
|
||||
ctx.emit_flush(&mut block);
|
||||
ctx.emit_start();
|
||||
|
||||
body.push(Statement::If {
|
||||
condition,
|
||||
accept: vec![Statement::Break],
|
||||
reject: Block::new(),
|
||||
});
|
||||
@@ -1419,7 +1465,7 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> {
|
||||
match self.expect_peek()?.value {
|
||||
TokenValue::RightParen => {}
|
||||
_ => {
|
||||
let rest = self.parse_expression(ctx)?;
|
||||
let rest = self.parse_expression(ctx, &mut continuing)?;
|
||||
ctx.lower(self.program, rest, false, &mut continuing)?;
|
||||
}
|
||||
}
|
||||
@@ -1462,7 +1508,7 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> {
|
||||
| TokenValue::IntConstant(_)
|
||||
| TokenValue::BoolConstant(_)
|
||||
| TokenValue::FloatConstant(_) => {
|
||||
let expr = self.parse_expression(ctx)?;
|
||||
let expr = self.parse_expression(ctx, body)?;
|
||||
ctx.lower(self.program, expr, false, body)?;
|
||||
self.expect(TokenValue::Semicolon)?;
|
||||
}
|
||||
@@ -1560,8 +1606,8 @@ impl<'ctx, 'fun> DeclarationContext<'ctx, 'fun> {
|
||||
};
|
||||
|
||||
match self.external {
|
||||
true => program.add_global_var(self.ctx, decl),
|
||||
false => program.add_local_var(self.ctx, decl),
|
||||
true => program.add_global_var(self.ctx, self.body, decl),
|
||||
false => program.add_local_var(self.ctx, self.body, decl),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
Binding, BuiltIn, Constant, Expression, GlobalVariable, Handle, LocalVariable, ScalarKind,
|
||||
StorageAccess, StorageClass, Type, TypeInner, VectorSize,
|
||||
Binding, Block, BuiltIn, Constant, Expression, GlobalVariable, Handle, LocalVariable,
|
||||
ScalarKind, StorageAccess, StorageClass, Type, TypeInner, VectorSize,
|
||||
};
|
||||
|
||||
use super::ast::*;
|
||||
@@ -18,119 +18,102 @@ pub struct VarDeclaration<'a> {
|
||||
impl Program<'_> {
|
||||
pub fn lookup_variable(
|
||||
&mut self,
|
||||
context: &mut Context,
|
||||
ctx: &mut Context,
|
||||
body: &mut Block,
|
||||
name: &str,
|
||||
) -> Result<Option<VariableReference>, ErrorKind> {
|
||||
if let Some(local_var) = context.lookup_local_var(name) {
|
||||
if let Some(local_var) = ctx.lookup_local_var(name) {
|
||||
return Ok(Some(local_var));
|
||||
}
|
||||
if let Some(global_var) = context.lookup_global_var(self, name) {
|
||||
if let Some(global_var) = ctx.lookup_global_var(name) {
|
||||
return Ok(Some(global_var));
|
||||
}
|
||||
if let Some(constant) = context.lookup_constants_var(self, name) {
|
||||
return Ok(Some(constant));
|
||||
}
|
||||
|
||||
let mut add_builtin = |inner, builtin, mutable| {
|
||||
let ty = self
|
||||
.module
|
||||
.types
|
||||
.fetch_or_append(Type { name: None, inner });
|
||||
|
||||
let handle = self.module.global_variables.append(GlobalVariable {
|
||||
name: Some(name.into()),
|
||||
class: StorageClass::Private,
|
||||
binding: None,
|
||||
ty,
|
||||
init: None,
|
||||
storage_access: StorageAccess::all(),
|
||||
});
|
||||
|
||||
self.entry_args
|
||||
.push((Binding::BuiltIn(builtin), true, handle));
|
||||
|
||||
self.global_variables
|
||||
.push((name.into(), GlobalLookup::Variable(handle)));
|
||||
|
||||
let expr = ctx.add_expression(Expression::GlobalVariable(handle), body);
|
||||
let load = ctx.add_expression(Expression::Load { pointer: expr }, body);
|
||||
ctx.lookup_global_var_exps.insert(
|
||||
name.into(),
|
||||
VariableReference {
|
||||
expr,
|
||||
load: Some(load),
|
||||
mutable,
|
||||
},
|
||||
);
|
||||
|
||||
Ok(ctx.lookup_global_var(name))
|
||||
};
|
||||
match name {
|
||||
"gl_Position" => {
|
||||
let ty = self.module.types.fetch_or_append(Type {
|
||||
name: None,
|
||||
inner: TypeInner::Vector {
|
||||
size: VectorSize::Quad,
|
||||
kind: ScalarKind::Float,
|
||||
width: 4,
|
||||
},
|
||||
});
|
||||
|
||||
let handle = self.module.global_variables.append(GlobalVariable {
|
||||
name: Some(name.into()),
|
||||
class: StorageClass::Private,
|
||||
binding: None,
|
||||
ty,
|
||||
init: None,
|
||||
storage_access: StorageAccess::all(),
|
||||
});
|
||||
|
||||
self.entry_args
|
||||
.push((Binding::BuiltIn(BuiltIn::Position), true, handle));
|
||||
|
||||
self.lookup_global_variables
|
||||
.insert(name.into(), GlobalLookup::Variable(handle));
|
||||
|
||||
Ok(context.lookup_global_var(self, name))
|
||||
}
|
||||
"gl_VertexIndex" => {
|
||||
let ty = self.module.types.fetch_or_append(Type {
|
||||
name: None,
|
||||
inner: TypeInner::Scalar {
|
||||
kind: ScalarKind::Sint,
|
||||
width: 4,
|
||||
},
|
||||
});
|
||||
|
||||
let handle = self.module.global_variables.append(GlobalVariable {
|
||||
name: Some(name.into()),
|
||||
class: StorageClass::Private,
|
||||
binding: None,
|
||||
ty,
|
||||
init: None,
|
||||
storage_access: StorageAccess::all(),
|
||||
});
|
||||
|
||||
self.entry_args
|
||||
.push((Binding::BuiltIn(BuiltIn::VertexIndex), true, handle));
|
||||
|
||||
self.lookup_global_variables
|
||||
.insert(name.into(), GlobalLookup::Variable(handle));
|
||||
|
||||
Ok(context.lookup_global_var(self, name))
|
||||
}
|
||||
"gl_InstanceIndex" => {
|
||||
let ty = self.module.types.fetch_or_append(Type {
|
||||
name: None,
|
||||
inner: TypeInner::Scalar {
|
||||
kind: ScalarKind::Sint,
|
||||
width: 4,
|
||||
},
|
||||
});
|
||||
|
||||
let handle = self.module.global_variables.append(GlobalVariable {
|
||||
name: Some(name.into()),
|
||||
class: StorageClass::Private,
|
||||
binding: None,
|
||||
ty,
|
||||
init: None,
|
||||
storage_access: StorageAccess::all(),
|
||||
});
|
||||
|
||||
self.entry_args
|
||||
.push((Binding::BuiltIn(BuiltIn::InstanceIndex), true, handle));
|
||||
|
||||
self.lookup_global_variables
|
||||
.insert(name.into(), GlobalLookup::Variable(handle));
|
||||
|
||||
Ok(context.lookup_global_var(self, name))
|
||||
}
|
||||
"gl_Position" => add_builtin(
|
||||
TypeInner::Vector {
|
||||
size: VectorSize::Quad,
|
||||
kind: ScalarKind::Float,
|
||||
width: 4,
|
||||
},
|
||||
BuiltIn::Position,
|
||||
true,
|
||||
),
|
||||
"gl_VertexIndex" => add_builtin(
|
||||
TypeInner::Scalar {
|
||||
kind: ScalarKind::Sint,
|
||||
width: 4,
|
||||
},
|
||||
BuiltIn::VertexIndex,
|
||||
false,
|
||||
),
|
||||
"gl_InstanceIndex" => add_builtin(
|
||||
TypeInner::Scalar {
|
||||
kind: ScalarKind::Sint,
|
||||
width: 4,
|
||||
},
|
||||
BuiltIn::InstanceIndex,
|
||||
false,
|
||||
),
|
||||
_ => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn field_selection(
|
||||
&mut self,
|
||||
context: &mut Context,
|
||||
ctx: &mut Context,
|
||||
body: &mut Block,
|
||||
expression: Handle<Expression>,
|
||||
name: &str,
|
||||
meta: SourceMetadata,
|
||||
) -> Result<Handle<Expression>, ErrorKind> {
|
||||
match *self.resolve_type(context, expression, meta)? {
|
||||
match *self.resolve_type(ctx, expression, meta)? {
|
||||
TypeInner::Struct { ref members, .. } => {
|
||||
let index = members
|
||||
.iter()
|
||||
.position(|m| m.name == Some(name.into()))
|
||||
.ok_or_else(|| ErrorKind::UnknownField(meta, name.into()))?;
|
||||
Ok(context.expressions.append(Expression::AccessIndex {
|
||||
base: expression,
|
||||
index: index as u32,
|
||||
}))
|
||||
Ok(ctx.add_expression(
|
||||
Expression::AccessIndex {
|
||||
base: expression,
|
||||
index: index as u32,
|
||||
},
|
||||
body,
|
||||
))
|
||||
}
|
||||
// swizzles (xyzw, rgba, stpq)
|
||||
TypeInner::Vector { size, kind, width } => {
|
||||
@@ -159,41 +142,40 @@ impl Program<'_> {
|
||||
let components: Vec<Handle<Expression>> = v
|
||||
.iter()
|
||||
.map(|idx| {
|
||||
context.expressions.append(Expression::AccessIndex {
|
||||
base: expression,
|
||||
index: *idx as u32,
|
||||
})
|
||||
ctx.add_expression(
|
||||
Expression::AccessIndex {
|
||||
base: expression,
|
||||
index: *idx as u32,
|
||||
},
|
||||
body,
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
if components.len() == 1 {
|
||||
// only single element swizzle, like pos.y, just return that component
|
||||
Ok(components[0])
|
||||
} else {
|
||||
Ok(context.expressions.append(Expression::Compose {
|
||||
ty: self.module.types.fetch_or_append(Type {
|
||||
name: None,
|
||||
inner: TypeInner::Vector {
|
||||
kind,
|
||||
width,
|
||||
size: match components.len() {
|
||||
2 => VectorSize::Bi,
|
||||
3 => VectorSize::Tri,
|
||||
4 => VectorSize::Quad,
|
||||
_ => {
|
||||
return Err(ErrorKind::SemanticError(
|
||||
meta,
|
||||
format!(
|
||||
"Bad swizzle size for \"{:?}\": {:?}",
|
||||
name, v
|
||||
)
|
||||
.into(),
|
||||
));
|
||||
}
|
||||
},
|
||||
},
|
||||
}),
|
||||
components,
|
||||
}))
|
||||
let size = match components.len() {
|
||||
2 => VectorSize::Bi,
|
||||
3 => VectorSize::Tri,
|
||||
4 => VectorSize::Quad,
|
||||
_ => {
|
||||
return Err(ErrorKind::SemanticError(
|
||||
meta,
|
||||
format!("Bad swizzle size for \"{:?}\": {:?}", name, v).into(),
|
||||
));
|
||||
}
|
||||
};
|
||||
Ok(ctx.add_expression(
|
||||
Expression::Compose {
|
||||
ty: self.module.types.fetch_or_append(Type {
|
||||
name: None,
|
||||
inner: TypeInner::Vector { kind, width, size },
|
||||
}),
|
||||
components,
|
||||
},
|
||||
body,
|
||||
))
|
||||
}
|
||||
} else {
|
||||
Err(ErrorKind::SemanticError(
|
||||
@@ -212,6 +194,7 @@ impl Program<'_> {
|
||||
pub fn add_global_var(
|
||||
&mut self,
|
||||
ctx: &mut Context,
|
||||
body: &mut Block,
|
||||
VarDeclaration {
|
||||
qualifiers,
|
||||
ty,
|
||||
@@ -334,18 +317,18 @@ impl Program<'_> {
|
||||
handle,
|
||||
));
|
||||
|
||||
self.lookup_global_variables
|
||||
.insert(name, GlobalLookup::Variable(handle));
|
||||
self.global_variables
|
||||
.push((name, GlobalLookup::Variable(handle)));
|
||||
|
||||
return Ok(ctx.expressions.append(Expression::GlobalVariable(handle)));
|
||||
return Ok(ctx.add_expression(Expression::GlobalVariable(handle), body));
|
||||
} else if let StorageQualifier::Const = storage {
|
||||
let handle = init.ok_or_else(|| {
|
||||
ErrorKind::SemanticError(meta, "Constant must have a initializer".into())
|
||||
})?;
|
||||
|
||||
self.lookup_constants.insert(name, handle);
|
||||
self.constants.push((name, handle));
|
||||
|
||||
return Ok(ctx.expressions.append(Expression::Constant(handle)));
|
||||
return Ok(ctx.add_expression(Expression::Constant(handle), body));
|
||||
}
|
||||
|
||||
let class = match storage {
|
||||
@@ -363,15 +346,16 @@ impl Program<'_> {
|
||||
storage_access: StorageAccess::all(),
|
||||
});
|
||||
|
||||
self.lookup_global_variables
|
||||
.insert(name, GlobalLookup::Variable(handle));
|
||||
self.global_variables
|
||||
.push((name, GlobalLookup::Variable(handle)));
|
||||
|
||||
Ok(ctx.expressions.append(Expression::GlobalVariable(handle)))
|
||||
Ok(ctx.add_expression(Expression::GlobalVariable(handle), body))
|
||||
}
|
||||
|
||||
pub fn add_local_var(
|
||||
&mut self,
|
||||
ctx: &mut Context,
|
||||
body: &mut Block,
|
||||
VarDeclaration {
|
||||
qualifiers,
|
||||
ty,
|
||||
@@ -413,7 +397,7 @@ impl Program<'_> {
|
||||
ty,
|
||||
init,
|
||||
});
|
||||
let expr = ctx.expressions.append(Expression::LocalVariable(handle));
|
||||
let expr = ctx.add_expression(Expression::LocalVariable(handle), body);
|
||||
|
||||
ctx.add_local_var(name, expr, mutable);
|
||||
|
||||
|
||||
@@ -14,8 +14,8 @@ use crate::{
|
||||
|
||||
/// Helper class to emit expressions
|
||||
#[allow(dead_code)]
|
||||
#[derive(Default)]
|
||||
struct Emitter {
|
||||
#[derive(Default, Debug)]
|
||||
pub(crate) struct Emitter {
|
||||
start_len: Option<usize>,
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user