|
|
@@ -1,6 +1,6 @@
|
|
|
-import { Program, FunctionDeclaration, Switch, For, AccessorElements, Ternary, Varying, DynamicElement, StaticElement, FunctionParameter, Unary, Conditional, VariableDeclaration, Operator, Number, String, FunctionCall, Return, Accessor, Uniform, Discard, SwitchCase, Continue, Break, While, Comment } from './AST.js';
|
|
|
+import { Program, FunctionDeclaration, Switch, For, AccessorElements, Ternary, Varying, DynamicElement, StaticElement, FunctionParameter, Unary, Conditional, VariableDeclaration, Operator, Number, String, FunctionCall, Return, Accessor, Uniform, Discard, SwitchCase, Continue, Break, While, Comment, StructMember, StructDefinition } from './AST.js';
|
|
|
|
|
|
-import { isType } from './TranspilerUtils.js';
|
|
|
+import { isBuiltinType } from './TranspilerUtils.js';
|
|
|
|
|
|
const unaryOperators = [
|
|
|
'+', '-', '~', '!', '++', '--'
|
|
|
@@ -255,6 +255,7 @@ class GLSLDecoder {
|
|
|
this.index = 0;
|
|
|
this.tokenizer = null;
|
|
|
this.keywords = [];
|
|
|
+ this.structTypes = new Map();
|
|
|
|
|
|
this.addPolyfill( 'gl_FragCoord', 'vec3 gl_FragCoord = vec3( screenCoordinate.x, screenCoordinate.y.oneMinus(), screenCoordinate.z );' );
|
|
|
|
|
|
@@ -780,6 +781,54 @@ class GLSLDecoder {
|
|
|
|
|
|
}
|
|
|
|
|
|
+ parseStructDefinition() {
|
|
|
+
|
|
|
+ const tokens = this.readTokensUntil( ';' );
|
|
|
+
|
|
|
+ const structName = tokens[ 1 ].str;
|
|
|
+
|
|
|
+ if ( tokens[ 2 ].str !== '{' ) {
|
|
|
+
|
|
|
+ throw new Error( 'Expected \'{\' after struct name ' );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ const structMembers = [];
|
|
|
+ for ( let i = 3; i < tokens.length - 2; i += 3 ) {
|
|
|
+
|
|
|
+ const typeToken = tokens[ i ];
|
|
|
+ const nameToken = tokens[ i + 1 ];
|
|
|
+
|
|
|
+ if ( typeToken.type != 'literal' || nameToken.type != 'literal' ) {
|
|
|
+
|
|
|
+ throw new Error( 'Invalid struct declaration' );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ if ( tokens[ i + 2 ].str !== ';' ) {
|
|
|
+
|
|
|
+ throw new Error( 'Missing \';\' after struct member name' );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ const member = new StructMember( typeToken.str, nameToken.str );
|
|
|
+ structMembers.push( member );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ if ( tokens[ tokens.length - 2 ].str !== '}' ) {
|
|
|
+
|
|
|
+ throw new Error( 'Missing closing \'}\' for struct ' + structName );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ const definition = new StructDefinition( structName, structMembers );
|
|
|
+ this.structTypes.set( structName, definition );
|
|
|
+
|
|
|
+ return definition;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
parseReturn() {
|
|
|
|
|
|
this.readToken(); // skip 'return'
|
|
|
@@ -827,7 +876,9 @@ class GLSLDecoder {
|
|
|
|
|
|
let initialization;
|
|
|
|
|
|
- if ( initializationTokens[ 0 ] && isType( initializationTokens[ 0 ].str ) ) {
|
|
|
+ const firstToken = initializationTokens[ 0 ];
|
|
|
+
|
|
|
+ if ( firstToken && ( isBuiltinType( firstToken.str ) || this.structTypes.has( firstToken.str ) ) ) {
|
|
|
|
|
|
initialization = this.parseVariablesFromToken( initializationTokens );
|
|
|
|
|
|
@@ -1079,7 +1130,11 @@ class GLSLDecoder {
|
|
|
|
|
|
statement = this.parseVarying();
|
|
|
|
|
|
- } else if ( isType( token.str ) ) {
|
|
|
+ } else if ( token.str === 'struct' ) {
|
|
|
+
|
|
|
+ statement = this.parseStructDefinition();
|
|
|
+
|
|
|
+ } else if ( isBuiltinType( token.str ) || this.structTypes.has( token.str ) ) {
|
|
|
|
|
|
if ( this.getToken( 2 ).str === '(' ) {
|
|
|
|
|
|
@@ -1159,7 +1214,9 @@ class GLSLDecoder {
|
|
|
this.tokenizer = new Tokenizer( polyfill + source ).tokenize();
|
|
|
|
|
|
const body = this.parseBlock();
|
|
|
+
|
|
|
const program = new Program( body );
|
|
|
+ program.structTypes = this.structTypes;
|
|
|
|
|
|
return program;
|
|
|
|