def glsl_parse_control(source): """Parse control block.""" (control, content) = extract_tokens(source, "?c") if not control: return (None, source) # 'else' is simpler. if control.format(False) == "else": return (GlslBlockControl(control, None, None), content) # Other control structures require scope. (scope, remaining) = extract_tokens(content, "?(") if not scope: return (None, source) # 'for' may require declaration at the beginning. declaration = None if control.format(False) == "for": (declaration, intermediate) = glsl_parse_declaration(scope) if declaration: scope = intermediate # Parse the rest of the statements, regardless if declaration was found. (statements, scope_remaining) = glsl_parse_statements(scope) if not statements: return (None, source) if scope_remaining: raise RuntimeError( "control scope cannot have remaining elements: '%s'" % str(scope_remaining)) return (GlslBlockControl(control, declaration, statements), remaining)
def glsl_parse_inout(source): """Parse inout block.""" (layout, content) = glsl_parse_layout(source) if not layout: content = source # It is possible to have an inout block without anything. (inout, remaining) = extract_tokens(content, ("?o", ";")) if inout: return (GlslBlockInOut(layout, inout), remaining) # Scoped version first. (inout, type_name, scope, name, intermediate) = extract_tokens(content, ("?o", "?n", "?{", "?n")) if inout and type_name and scope and name: members = glsl_parse_member_list(scope) if not members[0]: raise RuntimeError("wat?") if not members: raise RuntimeError("empty member list for inout struct") # May have an array. (size, remaining) = extract_tokens(intermediate, ("[", "?u", "]", ";")) if size: return (GlslBlockInOutStruct(layout, inout, type_name, members, name, size), remaining) # Did not have an array. (terminator, remaining) = extract_tokens(intermediate, "?|;") if terminator: return (GlslBlockInOutStruct(layout, inout, type_name, members, name), remaining) # Regular inout. (inout, typeid, name, remaining) = extract_tokens(content, ("?o", "?t", "?n", ";")) if not inout or not typeid or not name: return (None, source) return (GlslBlockInOutTyped(layout, inout, typeid, name), remaining)
def glsl_parse_layout(source): """Parse layout block.""" (scope, remaining) = extract_tokens(source, ("layout", "?(")) if not scope: return (None, source) lst = [] while scope: (location, assignment, index, intermediate) = extract_tokens(scope, ("?|location", "?=", "?u")) if location and assignment and index: lst += [[location, assignment, index]] scope = intermediate continue primitive_selector = "?" + "|".join(get_list_primitives()) (primitive, intermediate) = extract_tokens(scope, (primitive_selector,)) if primitive: lst += [[primitive]] scope = intermediate continue (max_vertices, assignment, amount, intermediate) = extract_tokens(scope, ("?|max_vertices", "?=", "?u")) if max_vertices and assignment and amount: lst += [[max_vertices, assignment, amount]] scope = intermediate continue (comma, intermediate) = extract_tokens(scope, "?|,") if comma: scope = intermediate continue raise RuntimeError("unknown layout directive %s" % (str(list(map(str, scope))))) return (GlslBlockLayout(lst), remaining)
def glsl_parse_parameter(source): """Parse parameter block.""" (inout, typeid, content) = extract_tokens(source, ("?o", "?t")) if not inout: (typeid, content) = extract_tokens(source, ("?t")) if not typeid: return (None, source) (assignment, remaining) = glsl_parse_assignment(content, False) if not assignment: raise RuntimeError("could not parse assignment from '%s'" % (str(list(map(str, content))))) if inout and (not inout.format(False) in ("in", "inout", "out")): raise RuntimeError("invalid inout directive for parameter: '%s'" % (inout.format(False))) return (GlslBlockParameter(inout, typeid, assignment), remaining)
def glsl_parse_pervertex(source): """Parse inout block.""" (inout, scope, remaining) = extract_tokens(source, ("?o", "gl_PerVertex", "?{", ";")) if (not inout) or (not scope): return (None, source) # Split scope into elements. lst = [] while scope: (typeid, name, content) = extract_tokens(scope, ("?t", "?n", ";")) if not typeid or not name: return (None, source) lst += [(typeid, name)] scope = content return (GlslBlockPerVertex(inout, lst), remaining)
def glsl_parse_return(source): """Parse return block.""" (ret, content) = extract_tokens(source, "?|return") if not ret: return (None, source) (statements, remaining) = glsl_parse_statements(content, ";") if not statements: return (None, source) return (GlslBlockReturn(statements), remaining)
def glsl_parse_unary(source): """Parse unary block.""" # Try prefix unary. (operator, name, terminator, remaining) = extract_tokens(source, ("?p", "?n", "?;")) if operator in g_allowed_operators: (statement, discarded) = glsl_parse_statement([operator, name, terminator]) if discarded: raise RuntimeError("discarded elements in prefix unary") return (GlslBlockUnary(statement), remaining) # Try postfix unary. (name, operator, terminator, remaining) = extract_tokens(source, ("?n", "?p", "?;")) if operator in g_allowed_operators: (statement, discarded) = glsl_parse_statement([name, operator, terminator]) if discarded: raise RuntimeError("discarded elements in postfix unary") return (GlslBlockUnary(statement), remaining) # No match. return (None, source)
def glsl_parse_flow(source): """Parse flow block.""" (name, terminator, remaining) = extract_tokens(source, ("?n", "?;")) if name in ("break", "continue"): (statement, discarded) = glsl_parse_statement([name, terminator]) if discarded: raise RuntimeError( "discarded elements after flow control statement") return (GlslBlockFlow(statement), remaining) return (None, source)
def glsl_parse_function(source): """Parse function block.""" (typeid, name, param_scope, content) = extract_tokens(source, ("?t", "?n", "?(")) if (not typeid) or (not name) or (param_scope is None): return (None, source) parameters = glsl_parse_parameter_list(param_scope) if parameters is None: return (None, source) (scope, remaining) = glsl_parse_scope(content) if not scope: return (None, source) return (GlslBlockFunction(typeid, name, parameters, scope), remaining)
def glsl_parse_uniform(source): """Parse preprocessor block.""" (layout, content) = glsl_parse_layout(source) if not layout: content = source # Extract actual uniform definition. (typeid, content) = extract_tokens(content, ("uniform", "?t")) if not typeid: return (None, source) # Try array types. (name, size, content) = extract_tokens(content, ("?n", "[", "?u", "]", ";")) if name and size: return (GlslBlockUniform(layout, typeid, size, name), content) (size, name, content) = extract_tokens(content, ("[", "?u", "]", "?n", ";")) if size and name: return (GlslBlockUniform(layout, typeid, size, name), content) # No array types, default to just name. (name, content) = extract_tokens(content, ("?n", ";")) if not name: return (None, source) return (GlslBlockUniform(layout, typeid, size, name), content)
def glsl_parse_assignment(source, explicit=True): """Parse assignment block.""" # Must have name. Name must not be just 'return'. (name, content) = extract_tokens(source, ("?n", )) if (not name) or (name == "return"): return (None, source) # Completely empty assignment. Acceptable if not in explicit mode. if (not content) and (not explicit): return (GlslBlockAssignment(name, None, None, None), content) # Empty assignment. (terminator, intermediate) = extract_tokens(content, ("?,|;", )) if terminator: (statement, remaining) = glsl_parse_statement([terminator] + intermediate) return (GlslBlockAssignment(name, None, None, statement), remaining) # Non-empty assignment. Gather index and swizzle. lst = [] while True: (index_scope, remaining) = extract_tokens(content, ("?[", )) if index_scope: lst += [GlslParen("[")] + index_scope + [GlslParen("]")] content = remaining continue (access, remaining) = extract_tokens(content, ("?a", )) if access: lst += [access] content = remaining continue (operator, remaining) = extract_tokens(content, ("?=", )) if operator: content = remaining break # Can't be an assignment. return (None, source) # Gather statement. (statement, remaining) = glsl_parse_statement(content, explicit) if not statement: return (None, source) return (GlslBlockAssignment(name, lst, operator, statement), remaining)
def glsl_parse_struct(source): """Parse struct block.""" (type_name, scope, content) = extract_tokens(source, ("struct", "?n", "?{")) if not type_name: return (None, source) # Get potential name and size. (name, size, remaining) = extract_tokens(content, ("?n", "[", "?i", "]", ";")) if not name: size = None (name, remaining) = extract_tokens(content, ("?n", ";")) if not name: name = None (terminator, remaining) = extract_tokens(content, ("?;", )) if not terminator: return (None, source) # Parse members members = glsl_parse_member_list(scope) if not members: raise RuntimeError("empty member list for struct") return (GlslBlockStruct(type_name, members, name, size), remaining)
def glsl_parse_call(source): """Parse call block.""" (name, scope, terminator, remaining) = extract_tokens(source, ("?n", "?(", "?;")) if not name: return (None, source) if scope: (statements, scope_remaining) = glsl_parse_statements(scope) if not statements: return (None, source) if scope_remaining: raise RuntimeError( "call scope cannot have remaining elements: '%s'" % str(scope_remaining)) return (GlslBlockCall(name, statements, terminator), remaining) return (GlslBlockCall(name, [], terminator), remaining)
def glsl_parse_declaration(source): """Parse declaration block.""" (typeid, content) = extract_tokens(source, ("?t",)) if not typeid: return (None, source) # Loop until nothing found. lst = [] while True: (assignment, remaining) = glsl_parse_assignment(content) if assignment: lst += [assignment] # Might have been last assignement. if assignment.getTerminator() == ";": return (GlslBlockDeclaration(typeid, lst), remaining) # Otherwise keep going. content = remaining continue # Unknown element, not a valid declaration. return (None, source)
def glsl_parse_scope(source, explicit=True): """Parse scope block.""" (content, remaining) = extract_tokens(source, ("?{", )) if not (content is None): return (GlslBlockScope(glsl_parse_content(content), explicit), remaining) # If explicit scope is not expected, try legal one-statement scopes. elif not explicit: (block, remaining) = glsl_parse_flow(source) if block: return (GlslBlockScope([block], explicit), remaining) (block, remaining) = glsl_parse_unary(source) if block: return (GlslBlockScope([block], explicit), remaining) (block, remaining) = glsl_parse_assignment(source) if block: return (GlslBlockScope([block], explicit), remaining) # No scope found. return (None, source)