1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
#!/usr/bin/env python3
import re
from variables import Var
from templates import *
from statement import *
PATTERN_PRAGMA = re.compile(flags=re.VERBOSE, pattern=r'''
\s*\#\s*pragma\s+ # '#pragma'
(?P<pragma>(?: # pragma name
GLSL[PHF]?
))\s*
(?P<rest>.*)$ # rest of line (pragma body)
''')
# Represents a single #pragma macro
class Macro(object):
PRAGMAS = {
'GLSL': 'SH_BUF_BODY',
'GLSLP': 'SH_BUF_PRELUDE',
'GLSLH': 'SH_BUF_HEADER',
'GLSLF': 'SH_BUF_FOOTER',
}
def __init__(self, linenr=0, type='GLSL'):
self.linenr = linenr
self.buf = Macro.PRAGMAS[type]
self.name = '_glsl_' + str(linenr)
self.body = [] # list of statements
self.last = None # previous GLSLBlock (if unterminated)
self.vars = VarSet()
def needs_single_line(self):
if not self.body:
return False
prev = self.body[-1]
return isinstance(prev, BlockStart) and not prev.multiline
def push_line(self, line):
self.vars.merge(line.vars)
if isinstance(line, GLSLLine):
if self.last:
self.last.append(line)
elif self.needs_single_line():
self.body.append(GLSLBlock(line))
else:
# start new GLSL block
self.last = GLSLBlock(line)
self.body.append(self.last)
else:
self.body.append(line)
self.last = None
def render_struct(self):
return STRUCT_TEMPLATE.render(macro=self)
def render_call(self):
return CALL_TEMPLATE.render(macro=self)
def render_fun(self):
return FUNCTION_TEMPLATE.render(macro=self, Var=Var)
# yields output lines
@staticmethod
def process_file(lines, strip=False):
macro = None
macros = []
for linenr, line_orig in enumerate(lines, start=1):
line = line_orig.rstrip()
# Strip leading spaces, due to C indent. Skip first pragma line.
if macro and leading_spaces is None:
leading_spaces = len(line) - len(line.lstrip())
# check for start of macro
if not macro:
leading_spaces = None
if result := re.match(PATTERN_PRAGMA, line):
macro = Macro(linenr, type=result['pragma'])
line = result['rest'] # strip pragma prefix
if macro:
if leading_spaces:
line = re.sub(f'^\s{{1,{leading_spaces}}}', '', line)
if more_lines := line.endswith('\\'):
line = line[:-1]
if statement := Statement.parse(line, strip=strip, linenr=linenr):
macro.push_line(statement)
if more_lines:
continue # stay in macro
else:
yield macro.render_call()
yield '#line {}\n'.format(linenr + 1)
macros.append(macro)
macro = None
else:
yield line_orig
if macros:
yield '\n// Auto-generated template functions:'
for macro in macros:
yield macro.render_fun()
|