From 76eb307d350e63073bd378e0d2d4fc7d2e5676f9 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Sat, 14 Mar 2020 00:15:37 -0400 Subject: [PATCH] Local variables, [wgsl] statement context --- src/front/spirv.rs | 1 + src/front/wgsl.rs | 137 +++++++++++++++++++++++++++++++++++---------- src/lib.rs | 21 +++++-- 3 files changed, 125 insertions(+), 34 deletions(-) diff --git a/src/front/spirv.rs b/src/front/spirv.rs index 4c922257a3..8777f6f60c 100644 --- a/src/front/spirv.rs +++ b/src/front/spirv.rs @@ -1269,6 +1269,7 @@ impl> Parser { } else { Some(self.lookup_type.lookup(result_type)?.handle) }, + local_variables: Arena::new(), expressions: self.make_expression_storage(), body: Vec::new(), } diff --git a/src/front/wgsl.rs b/src/front/wgsl.rs index a809cc6844..e6113c0764 100644 --- a/src/front/wgsl.rs +++ b/src/front/wgsl.rs @@ -251,8 +251,37 @@ impl<'a> StringValueLookup<'a> for FastHashMap<&'a str, Handle { +struct StatementContext<'input, 'temp, 'out> { lookup_ident: &'temp mut FastHashMap<&'input str, Handle>, + variables: &'out mut Arena, + expressions: &'out mut Arena, + types: &'out mut Arena, + constants: &'out mut Arena, +} + +impl<'a> StatementContext<'a, '_, '_> { + fn reborrow(&mut self) -> StatementContext<'a, '_, '_> { + StatementContext { + lookup_ident: self.lookup_ident, + variables: self.variables, + expressions: self.expressions, + types: self.types, + constants: self.constants, + } + } + + fn as_expression(&mut self) -> ExpressionContext<'a, '_, '_> { + ExpressionContext { + lookup_ident: self.lookup_ident, + expressions: self.expressions, + types: self.types, + constants: self.constants, + } + } +} + +struct ExpressionContext<'input, 'temp, 'out> { + lookup_ident: &'temp FastHashMap<&'input str, Handle>, expressions: &'out mut Arena, types: &'out mut Arena, constants: &'out mut Arena, @@ -481,6 +510,38 @@ impl Parser { Ok(ctx.expressions.append(expression)) } + fn parse_postfix<'a>( + &mut self, + lexer: &mut Lexer<'a>, + mut ctx: ExpressionContext<'a, '_, '_>, + mut handle: Handle, + ) -> Result, Error<'a>> { + loop { + match lexer.peek() { + Token::Separator('.') => { + let _ = lexer.next(); + let _name = lexer.next_ident()?; + let expr = crate::Expression::AccessIndex { + base: handle, + index: 0, //TODO: compute from `name` + }; + handle = ctx.expressions.append(expr); + } + Token::Paren('[') => { + let _ = lexer.next(); + let index = self.parse_general_expression(lexer, ctx.reborrow())?; + lexer.expect(Token::Paren(']'))?; + let expr = crate::Expression::Access { + base: handle, + index, + }; + handle = ctx.expressions.append(expr); + } + _ => return Ok(handle), + } + } + } + fn parse_singular_expression<'a>( &mut self, lexer: &mut Lexer<'a>, @@ -562,16 +623,8 @@ impl Parser { Some(expr) => ctx.expressions.append(expr), None => { *lexer = backup; - let mut handle = self.parse_primary_expression(lexer, ctx.reborrow())?; - while lexer.skip(Token::Separator('.')) { - let _name = lexer.next_ident()?; - let expr = crate::Expression::AccessIndex { - base: handle, - index: 0, //TODO: compute from `name` - }; - handle = ctx.expressions.append(expr); - } - handle + let handle = self.parse_primary_expression(lexer, ctx.reborrow())?; + self.parse_postfix(lexer, ctx, handle)? } }; self.scopes.pop(); @@ -894,7 +947,7 @@ impl Parser { fn parse_statement<'a>( &mut self, lexer: &mut Lexer<'a>, - mut context: ExpressionContext<'a, '_, '_>, + mut context: StatementContext<'a, '_, '_>, ) -> Result, Error<'a>> { match lexer.next() { Token::Separator(';') => Ok(Some(crate::Statement::Empty)), @@ -904,23 +957,24 @@ impl Parser { let statement = match word { "var" => { let (name, ty) = self.parse_variable_ident_decl(lexer, context.types)?; - let value = if lexer.skip(Token::Operation('=')) { - let value = self.parse_general_expression(lexer, context.reborrow())?; - context.lookup_ident.insert(name, value); - Some(value) + let init = if lexer.skip(Token::Operation('=')) { + Some(self.parse_general_expression(lexer, context.as_expression())?) } else { None }; lexer.expect(Token::Separator(';'))?; - crate::Statement::VariableDeclaration { - name: name.to_owned(), + let var_id = context.variables.append(crate::LocalVariable { + name: Some(name.to_owned()), ty, - value, - } + init, + }); + let expr_id = context.expressions.append(crate::Expression::LocalVariable(var_id)); + context.lookup_ident.insert(name, expr_id); + crate::Statement::Empty } "return" => { let value = if lexer.peek() != Token::Separator(';') { - Some(self.parse_general_expression(lexer, context)?) + Some(self.parse_general_expression(lexer, context.as_expression())?) } else { None }; @@ -931,7 +985,7 @@ impl Parser { } "if" => { lexer.expect(Token::Paren('('))?; - let condition = self.parse_general_expression(lexer, context.reborrow())?; + let condition = self.parse_general_expression(lexer, context.as_expression())?; lexer.expect(Token::Paren(')'))?; let accept = self.parse_block(lexer, context.reborrow())?; let reject = if lexer.skip(Token::Word("else")) { @@ -939,18 +993,40 @@ impl Parser { } else { Vec::new() }; - let statement = crate::Statement::If { + crate::Statement::If { condition, accept, reject, - }; - statement + } } + "loop" => { + let mut body = Vec::new(); + let mut continuing = Vec::new(); + lexer.expect(Token::Paren('{'))?; + loop { + if lexer.skip(Token::Word("continuing")) { + continuing = self.parse_block(lexer, context.reborrow())?; + lexer.expect(Token::Paren('}'))?; + break; + } + match self.parse_statement(lexer, context.reborrow())? { + Some(s) => body.push(s), + None => break, + } + } + crate::Statement::Loop { + body, + continuing + } + } + "break" => crate::Statement::Break, + "continue" => crate::Statement::Continue, ident => { // assignment - let left = context.lookup_ident.lookup(ident)?; + let var_expr = context.lookup_ident.lookup(ident)?; + let left = self.parse_postfix(lexer, context.as_expression(), var_expr)?; lexer.expect(Token::Operation('='))?; - let value = self.parse_general_expression(lexer, context)?; + let value = self.parse_general_expression(lexer, context.as_expression())?; lexer.expect(Token::Separator(';'))?; crate::Statement::Store { pointer: left, @@ -968,7 +1044,7 @@ impl Parser { fn parse_block<'a>( &mut self, lexer: &mut Lexer<'a>, - mut context: ExpressionContext<'a, '_, '_>, + mut context: StatementContext<'a, '_, '_>, ) -> Result, Error<'a>> { self.scopes.push(Scope::Block); lexer.expect(Token::Paren('{'))?; @@ -1017,8 +1093,10 @@ impl Parser { Some(self.parse_type_decl(lexer, &mut module.types)?) }; // read body - let body = self.parse_block(lexer, ExpressionContext { + let mut local_variables = Arena::new(); + let body = self.parse_block(lexer, StatementContext { lookup_ident: &mut lookup_ident, + variables: &mut local_variables, expressions: &mut expressions, types: &mut module.types, constants: &mut module.constants, @@ -1030,6 +1108,7 @@ impl Parser { control: spirv::FunctionControl::empty(), parameter_types, return_type, + local_variables, expressions, body, }; diff --git a/src/lib.rs b/src/lib.rs index f8b237f915..59fc5e9e6d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -110,6 +110,13 @@ pub struct GlobalVariable { pub ty: Handle, } +#[derive(Clone, Debug)] +pub struct LocalVariable { + pub name: Option, + pub ty: Handle, + pub init: Option>, +} + #[derive(Clone, Copy, Debug, PartialEq)] pub enum UnaryOperator { Negate, @@ -173,6 +180,7 @@ pub enum Expression { }, FunctionParameter(u32), GlobalVariable(Handle), + LocalVariable(Handle), Load { pointer: Handle, }, @@ -216,11 +224,6 @@ pub struct FallThrough; pub enum Statement { Empty, Block(Block), - VariableDeclaration { - name: String, - ty: Handle, - value: Option>, - }, If { condition: Handle, //bool accept: Block, @@ -231,6 +234,13 @@ pub enum Statement { cases: FastHashMap)>, default: Block, }, + Loop { + body: Block, + continuing: Block, + }, + //TODO: move terminator variations into a separate enum? + Break, + Continue, Return { value: Option>, }, @@ -247,6 +257,7 @@ pub struct Function { pub control: spirv::FunctionControl, pub parameter_types: Vec>, pub return_type: Option>, + pub local_variables: Arena, pub expressions: Arena, pub body: Block, }