forked from Imagelibrary/littlefs
scripts: Enabled full C exprs in test/bench define ranges
This enables full C exprs in test/bench define ranges by simply passing them on to the C compiler. So this: defines.N = 'range(1,20+1)' Becomes this, in N's define function: if (i < 0 + ((((20+1)-1-(1))/(1) + 1))) return ((i-(0))*(1) + (1)); Which is a bit of a mess, but generates the correct range at runtime. This allows for much more flexible exprs in range defines without needing a full expr parser in Python. Note though that we need to evaluate the range length at compile time. This is notably before the test/bench define system is initialized, so all three range args (start, stop, step) are limited to really only simple C literals and exprs.
This commit is contained in:
@@ -17,6 +17,7 @@ import csv
|
|||||||
import errno
|
import errno
|
||||||
import fnmatch
|
import fnmatch
|
||||||
import itertools as it
|
import itertools as it
|
||||||
|
import functools as ft
|
||||||
import os
|
import os
|
||||||
import pty
|
import pty
|
||||||
import re
|
import re
|
||||||
@@ -47,6 +48,24 @@ def openio(path, mode='r', buffering=-1):
|
|||||||
else:
|
else:
|
||||||
return open(path, mode, buffering)
|
return open(path, mode, buffering)
|
||||||
|
|
||||||
|
# a define range
|
||||||
|
class DRange:
|
||||||
|
def __init__(self, start, stop=None, step=None):
|
||||||
|
if stop is None:
|
||||||
|
start, stop = None, start
|
||||||
|
self.start = start if start is not None else '0'
|
||||||
|
self.stop = stop
|
||||||
|
self.step = step if step is not None else '1'
|
||||||
|
|
||||||
|
def len(self):
|
||||||
|
return '(((%s)-1-(%s))/(%s) + 1)' % (
|
||||||
|
self.stop, self.start, self.step)
|
||||||
|
|
||||||
|
def next(self, i):
|
||||||
|
return '((%s)*(%s) + (%s))' % (
|
||||||
|
i, self.step, self.start)
|
||||||
|
|
||||||
|
|
||||||
class BenchCase:
|
class BenchCase:
|
||||||
# create a BenchCase object from a config
|
# create a BenchCase object from a config
|
||||||
def __init__(self, config, args={}):
|
def __init__(self, config, args={}):
|
||||||
@@ -105,21 +124,10 @@ class BenchCase:
|
|||||||
# the runner itself.
|
# the runner itself.
|
||||||
vs = []
|
vs = []
|
||||||
for v_ in csplit(v):
|
for v_ in csplit(v):
|
||||||
m = re.search(r'\brange\b\s*\('
|
m = re.match(r'^\s*range\b\s*\((?P<range>.*)\)\s*$', v_)
|
||||||
'(?P<start>[^,\s]*)'
|
|
||||||
'\s*(?:,\s*(?P<stop>[^,\s]*)'
|
|
||||||
'\s*(?:,\s*(?P<step>[^,\s]*)\s*)?)?\)',
|
|
||||||
v_)
|
|
||||||
if m:
|
if m:
|
||||||
start = (int(m.group('start'), 0)
|
vs.append(DRange(*[
|
||||||
if m.group('start') else 0)
|
s.strip() for s in csplit(m.group('range'))]))
|
||||||
stop = (int(m.group('stop'), 0)
|
|
||||||
if m.group('stop') else None)
|
|
||||||
step = (int(m.group('step'), 0)
|
|
||||||
if m.group('step') else 1)
|
|
||||||
if m.lastindex <= 1:
|
|
||||||
start, stop = 0, start
|
|
||||||
vs.append(range(start, stop, step))
|
|
||||||
else:
|
else:
|
||||||
vs.append(v_)
|
vs.append(v_)
|
||||||
return vs
|
return vs
|
||||||
@@ -384,17 +392,21 @@ def compile(bench_paths, **args):
|
|||||||
j = 0
|
j = 0
|
||||||
for v in vs:
|
for v in vs:
|
||||||
# generate range
|
# generate range
|
||||||
if isinstance(v, range):
|
if isinstance(v, DRange):
|
||||||
f.writeln(4*' '+'if (i < %d) '
|
f.writeln(4*' '+'if (i < %s + (%s)) '
|
||||||
'return (i-%d)*%d + %d;' % (
|
'return %s;' % (
|
||||||
j+len(v), j, v.step, v.start))
|
j, v.len(),
|
||||||
j += len(v)
|
v.next('i-(%s)' % j)))
|
||||||
|
j = '%s + %s' % (j, v.len())
|
||||||
# translate index to define
|
# translate index to define
|
||||||
else:
|
else:
|
||||||
f.writeln(4*' '+'if (i == %d) '
|
f.writeln(4*' '+'if (i == %s) '
|
||||||
'return %s;' % (
|
'return %s;' % (
|
||||||
j, v))
|
j, v))
|
||||||
j += 1;
|
if isinstance(j, str):
|
||||||
|
j += ' + 1'
|
||||||
|
else:
|
||||||
|
j += 1;
|
||||||
|
|
||||||
f.writeln(4*' '+'__builtin_unreachable();')
|
f.writeln(4*' '+'__builtin_unreachable();')
|
||||||
f.writeln('}')
|
f.writeln('}')
|
||||||
@@ -532,13 +544,22 @@ def compile(bench_paths, **args):
|
|||||||
f.writeln(20*' '+'[%d] = {'
|
f.writeln(20*' '+'[%d] = {'
|
||||||
'"%s", &%s, '
|
'"%s", &%s, '
|
||||||
'__bench__%s__%s__%d, '
|
'__bench__%s__%s__%d, '
|
||||||
'NULL, %d},' % (
|
'NULL, %s},' % (
|
||||||
sorted(suite.defines).index(k),
|
sorted(suite.defines).index(k),
|
||||||
k, k, case.name, k, i,
|
k, k, case.name, k, i,
|
||||||
sum(len(v)
|
ft.reduce(
|
||||||
if isinstance(v, range)
|
lambda x, y:
|
||||||
else 1
|
'%s + %s' % (x, y)
|
||||||
for v in vs)))
|
if isinstance(
|
||||||
|
x, str)
|
||||||
|
or isinstance(
|
||||||
|
y, str)
|
||||||
|
else x + y,
|
||||||
|
(v.len()
|
||||||
|
if isinstance(
|
||||||
|
v, DRange)
|
||||||
|
else 1
|
||||||
|
for v in vs))))
|
||||||
f.writeln(16*' '+'},')
|
f.writeln(16*' '+'},')
|
||||||
f.writeln(12*' '+'},')
|
f.writeln(12*' '+'},')
|
||||||
f.writeln(12*' '+'.permutations = %d,' % (
|
f.writeln(12*' '+'.permutations = %d,' % (
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import csv
|
|||||||
import errno
|
import errno
|
||||||
import fnmatch
|
import fnmatch
|
||||||
import itertools as it
|
import itertools as it
|
||||||
|
import functools as ft
|
||||||
import math as mt
|
import math as mt
|
||||||
import os
|
import os
|
||||||
import pty
|
import pty
|
||||||
@@ -48,6 +49,24 @@ def openio(path, mode='r', buffering=-1):
|
|||||||
else:
|
else:
|
||||||
return open(path, mode, buffering)
|
return open(path, mode, buffering)
|
||||||
|
|
||||||
|
# a define range
|
||||||
|
class DRange:
|
||||||
|
def __init__(self, start, stop=None, step=None):
|
||||||
|
if stop is None:
|
||||||
|
start, stop = None, start
|
||||||
|
self.start = start if start is not None else '0'
|
||||||
|
self.stop = stop
|
||||||
|
self.step = step if step is not None else '1'
|
||||||
|
|
||||||
|
def len(self):
|
||||||
|
return '(((%s)-1-(%s))/(%s) + 1)' % (
|
||||||
|
self.stop, self.start, self.step)
|
||||||
|
|
||||||
|
def next(self, i):
|
||||||
|
return '((%s)*(%s) + (%s))' % (
|
||||||
|
i, self.step, self.start)
|
||||||
|
|
||||||
|
|
||||||
class TestCase:
|
class TestCase:
|
||||||
# create a TestCase object from a config
|
# create a TestCase object from a config
|
||||||
def __init__(self, config, args={}):
|
def __init__(self, config, args={}):
|
||||||
@@ -111,21 +130,10 @@ class TestCase:
|
|||||||
# the runner itself.
|
# the runner itself.
|
||||||
vs = []
|
vs = []
|
||||||
for v_ in csplit(v):
|
for v_ in csplit(v):
|
||||||
m = re.search(r'\brange\b\s*\('
|
m = re.match(r'^\s*range\b\s*\((?P<range>.*)\)\s*$', v_)
|
||||||
'(?P<start>[^,\s]*)'
|
|
||||||
'\s*(?:,\s*(?P<stop>[^,\s]*)'
|
|
||||||
'\s*(?:,\s*(?P<step>[^,\s]*)\s*)?)?\)',
|
|
||||||
v_)
|
|
||||||
if m:
|
if m:
|
||||||
start = (int(m.group('start'), 0)
|
vs.append(DRange(*[
|
||||||
if m.group('start') else 0)
|
s.strip() for s in csplit(m.group('range'))]))
|
||||||
stop = (int(m.group('stop'), 0)
|
|
||||||
if m.group('stop') else None)
|
|
||||||
step = (int(m.group('step'), 0)
|
|
||||||
if m.group('step') else 1)
|
|
||||||
if m.lastindex <= 1:
|
|
||||||
start, stop = 0, start
|
|
||||||
vs.append(range(start, stop, step))
|
|
||||||
else:
|
else:
|
||||||
vs.append(v_)
|
vs.append(v_)
|
||||||
return vs
|
return vs
|
||||||
@@ -396,17 +404,21 @@ def compile(test_paths, **args):
|
|||||||
j = 0
|
j = 0
|
||||||
for v in vs:
|
for v in vs:
|
||||||
# generate range
|
# generate range
|
||||||
if isinstance(v, range):
|
if isinstance(v, DRange):
|
||||||
f.writeln(4*' '+'if (i < %d) '
|
f.writeln(4*' '+'if (i < %s + (%s)) '
|
||||||
'return (i-%d)*%d + %d;' % (
|
'return %s;' % (
|
||||||
j+len(v), j, v.step, v.start))
|
j, v.len(),
|
||||||
j += len(v)
|
v.next('i-(%s)' % j)))
|
||||||
|
j = '%s + %s' % (j, v.len())
|
||||||
# translate index to define
|
# translate index to define
|
||||||
else:
|
else:
|
||||||
f.writeln(4*' '+'if (i == %d) '
|
f.writeln(4*' '+'if (i == %s) '
|
||||||
'return %s;' % (
|
'return %s;' % (
|
||||||
j, v))
|
j, v))
|
||||||
j += 1;
|
if isinstance(j, str):
|
||||||
|
j += ' + 1'
|
||||||
|
else:
|
||||||
|
j += 1;
|
||||||
|
|
||||||
f.writeln(4*' '+'__builtin_unreachable();')
|
f.writeln(4*' '+'__builtin_unreachable();')
|
||||||
f.writeln('}')
|
f.writeln('}')
|
||||||
@@ -550,13 +562,22 @@ def compile(test_paths, **args):
|
|||||||
f.writeln(20*' '+'[%d] = {'
|
f.writeln(20*' '+'[%d] = {'
|
||||||
'"%s", &%s, '
|
'"%s", &%s, '
|
||||||
'__test__%s__%s__%d, '
|
'__test__%s__%s__%d, '
|
||||||
'NULL, %d},' % (
|
'NULL, %s},' % (
|
||||||
sorted(suite.defines).index(k),
|
sorted(suite.defines).index(k),
|
||||||
k, k, case.name, k, i,
|
k, k, case.name, k, i,
|
||||||
sum(len(v)
|
ft.reduce(
|
||||||
if isinstance(v, range)
|
lambda x, y:
|
||||||
else 1
|
'%s + %s' % (x, y)
|
||||||
for v in vs)))
|
if isinstance(
|
||||||
|
x, str)
|
||||||
|
or isinstance(
|
||||||
|
y, str)
|
||||||
|
else x + y,
|
||||||
|
(v.len()
|
||||||
|
if isinstance(
|
||||||
|
v, DRange)
|
||||||
|
else 1
|
||||||
|
for v in vs))))
|
||||||
f.writeln(16*' '+'},')
|
f.writeln(16*' '+'},')
|
||||||
f.writeln(12*' '+'},')
|
f.writeln(12*' '+'},')
|
||||||
f.writeln(12*' '+'.permutations = %d,' % (
|
f.writeln(12*' '+'.permutations = %d,' % (
|
||||||
|
|||||||
Reference in New Issue
Block a user