added glad generator and a glad runtime

This commit is contained in:
Hartmut Seichter 2017-06-29 07:15:32 +02:00
parent 2017f6195e
commit ac18a84a9c
62 changed files with 32373 additions and 10 deletions

View file

@ -0,0 +1,242 @@
from collections import defaultdict
from datetime import datetime
from itertools import chain
import os.path
import sys
from glad.lang.common.loader import NullLoader
from glad.opener import URLOpener
from glad.util import api_name
import glad
if sys.version_info >= (3, 0):
from urllib.parse import urlencode
else:
from urllib import urlencode
HEADER_TEMPLATE = '''
{apis_named} loader generated by glad {version} on {date}.
Language/Generator: {language}
Specification: {specification}
APIs: {apis}
Profile: {profile}
Extensions:
{extensions}
Loader: {loader}
Local files: {local_files}
Omit khrplatform: {omit_khrplatform}
Commandline:
{commandline}
Online:
{online}
'''
class Generator(object):
NAME = None
NAME_LONG = None
URL = 'http://glad.dav1d.de'
def __init__(self, path, spec, api, extension_names=None, loader=None,
opener=None, local_files=False, omit_khrplatform=False,
header_template=HEADER_TEMPLATE):
self.path = os.path.abspath(path)
self.spec = spec
for a in api:
if a not in self.spec.features:
raise ValueError(
'Unknown API "{0}" for specification "{1}"'
.format(a, self.spec.NAME)
)
self.api = api
self.extension_names = extension_names
self.has_loader = not loader.disabled
self.loader = loader
if self.loader is None:
self.loader = NullLoader
self.opener = opener
if self.opener is None:
self.opener = URLOpener.default()
self.local_files = local_files
self.omit_khrplatform = omit_khrplatform
self._header_template = header_template
def open(self):
raise NotImplementedError
def close(self):
raise NotImplementedError
def __enter__(self):
self.open()
return self
def __exit__(self, exc_type, exc_value, traceback):
self.close()
def generate(self):
features = list()
for api, version in self.api.items():
features.extend(self.spec.features[api])
if version is None:
version = list(self.spec.features[api].keys())[-1]
self.api[api] = version
if version not in self.spec.features[api]:
raise ValueError(
'Unknown version "{0}" for specification "{1}"'
.format(version, self.spec.NAME)
)
if self.extension_names is None:
self.extension_names = list(chain.from_iterable(self.spec.extensions[a]
for a in self.api))
# sort and eliminate duplicates
self.extension_names = list(sorted(set(self.extension_names)))
e = list(chain.from_iterable(self.spec.extensions[a] for a in self.api))
for ext in self.extension_names:
if ext not in e:
raise ValueError(
'Invalid extension "{0}" for specification "{1}"'
.format(ext, self.spec.NAME)
)
self.generate_header()
types = [t for t in self.spec.types if t.api is None or t.api in self.api]
self.generate_types(types)
f = list()
for api, version in self.api.items():
f.extend([value for key, value in self.spec.features[api].items()
if key <= version])
enums, functions = merge(f)
self.generate_features(f)
extensions = list()
for api in self.api:
extensions.extend(self.spec.extensions[api][ext]
for ext in self.extension_names if ext
in self.spec.extensions[api])
self.generate_extensions(extensions, enums, functions)
fs = defaultdict(list)
es = defaultdict(list)
for api, version in self.api.items():
fs[api].extend(
[value for key, value in
self.spec.features[api].items() if key <= version]
)
es[api].extend(self.spec.extensions[api][ext]
for ext in self.extension_names if ext
in self.spec.extensions[api])
self.generate_loader(fs, es)
@property
def header(self):
apis_named = ', '.join(sorted(set(api_name(api) for api in self.api)))
date = datetime.now().strftime('%c')
language = self.NAME_LONG
specification = self.spec.NAME
apis = ', '.join('{}={}'.format(api, '.'.join(map(str, version))) for api, version in self.api.items())
profile = getattr(self.spec, 'profile', '-')
extensions = ',\n '.join(self.extension_names)
online = self.online
if len(online) > 2000:
online = 'Too many extensions'
return self._header_template.format(
apis_named=apis_named,
version=glad.__version__,
date=date,
language=language,
specification=specification,
apis=apis,
profile=profile,
extensions=extensions,
loader=self.has_loader,
local_files=self.local_files,
omit_khrplatform=self.omit_khrplatform,
commandline=self.commandline,
online=online
)
@property
def commandline(self):
profile = getattr(self.spec, 'profile', None)
if profile is not None:
profile = '--profile="{}"'.format(profile)
api = '--api="{}"'.format(','.join(
'{}={}'.format(api, '.'.join(map(str, version))) for api, version in self.api.items())
)
generator = '--generator="{}"'.format(self.NAME)
specification = '--spec="{}"'.format(self.spec.NAME)
loader = '' if self.has_loader else '--no-loader'
extensions = '--extensions="{}"'.format(','.join(self.extension_names))
local_files = '--local-files' if self.local_files else ''
omit_khrplatform = '--omit-khrplatform' if self.omit_khrplatform else ''
return ' '.join(filter(None, [
profile, api, generator, specification,
loader, local_files, omit_khrplatform, extensions
]))
@property
def online(self):
profile = getattr(self.spec, 'profile', None)
if profile is not None:
profile = ('profile', profile)
api = [('api', s) for s in ('{}={}'.format(api, '.'.join(map(str, version))) for api, version in self.api.items())]
generator = ('language', self.NAME)
specification = ('specification', self.spec.NAME)
loader = ('loader', 'on') if self.has_loader else None
extensions = [('extensions', ext) for ext in self.extension_names]
data = [profile, generator, specification, loader]
data.extend(api)
data.extend(extensions)
data = list(filter(None, data))
serialized = urlencode(data)
# TODO: --local-files, --omit-khrplatform
return '{}/#{}'.format(self.URL, serialized)
def generate_header(self):
raise NotImplementedError
def generate_loader(self, features, extensions):
raise NotImplementedError
def generate_types(self, types):
raise NotImplementedError
def generate_features(self, features):
raise NotImplementedError
def generate_extensions(self, extensions, enums, functions):
raise NotImplementedError
def merge(features):
enums = set()
functions = set()
for feature in features:
enums |= set(feature.enums)
functions |= set(feature.functions)
return enums, functions

View file

@ -0,0 +1,60 @@
class BaseLoader(object):
def __init__(self, apis, disabled=False, local_files=False):
self.apis = apis
self.disabled = disabled
self.local_files = local_files
def write(self, fobj):
raise NotImplementedError
def write_begin_load(self, fobj):
raise NotImplementedError
def write_end_load(self, fobj):
raise NotImplementedError
def write_find_core(self, fobj):
raise NotImplementedError
def write_has_ext(self, fobj):
raise NotImplementedError
def write_header(self, fobj):
raise NotImplementedError
def write_header_end(self, fobj):
raise NotImplementedError
class NullLoader(BaseLoader):
def write_begin_load(self, fobj):
pass
def write_end_load(self, fobj):
pass
def write_header_end(self, fobj):
pass
def write_has_ext(self, fobj):
pass
def write(self, fobj):
pass
def write_header(self, fobj):
pass
def write_find_core(self, fobj):
pass
def __getattr__(self, name):
try:
return self.__getattribute__(name)
except AttributeError:
pass
def dummy(*args, **kwargs):
pass
return dummy

View file

@ -0,0 +1,13 @@
import os.path
import os
def enforce(exp, message, exc):
if not exp:
raise exc(message)
def makefiledir(path):
dir = os.path.split(path)[0]
if not os.path.exists(dir):
os.makedirs(dir)