scripts: csv.py: Switched to semicolon (;) for by exprs
A slightly different syntax I found while exploring generic/template syntax in other languages. Instead of multiple brackets/parens for specialization, just deliminate by (or type) fields from regular fields with a semicolon: Before: -fx=enumerate() -fy=enumerate[a,b]() -fz=accumulate[a,b](z) After: -fx=enumerate() -fy=enumerate(a,b;) -fz=accumulate(a,b;z) The result is a flexible call syntax that avoids overloading operators future exprs may want to use. And if we ever want type specialization, we can always add more semicolons: -fx=enumerate(int;;) -fy=enumerate(float;a,b;) -fz=accumulate(frac;a,b;z)
This commit is contained in:
+12
-34
@@ -673,9 +673,9 @@ class CsvExpr:
|
|||||||
return sum(1 for _ in self)
|
return sum(1 for _ in self)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '%s%s(%s)' % (
|
return '%s(%s%s)' % (
|
||||||
self.__class__.__name__,
|
self.__class__.__name__,
|
||||||
'[%s]' % (','.join(repr(k) for k in self.by))
|
'%s;' % (','.join(repr(k) for k in self.by))
|
||||||
if self.by else '',
|
if self.by else '',
|
||||||
','.join(repr(v) for v in self))
|
','.join(repr(v) for v in self))
|
||||||
|
|
||||||
@@ -755,7 +755,6 @@ class CsvExpr:
|
|||||||
by, args = None, by
|
by, args = None, by
|
||||||
def func(f):
|
def func(f):
|
||||||
f._func = name
|
f._func = name
|
||||||
f._fby = by
|
|
||||||
f._fargs = args
|
f._fargs = args
|
||||||
funcs[f._func] = f
|
funcs[f._func] = f
|
||||||
return f
|
return f
|
||||||
@@ -972,7 +971,7 @@ class CsvExpr:
|
|||||||
return CsvGStddev()([v.eval(fields, state) for v in self])
|
return CsvGStddev()([v.eval(fields, state) for v in self])
|
||||||
|
|
||||||
# enumerate exprs
|
# enumerate exprs
|
||||||
@func('enumerate', 'by', '')
|
@func('enumerate', '[by;]')
|
||||||
class Enumerate(Expr):
|
class Enumerate(Expr):
|
||||||
"""A [per by] number incremented for each result"""
|
"""A [per by] number incremented for each result"""
|
||||||
def fields(self):
|
def fields(self):
|
||||||
@@ -1000,7 +999,7 @@ class CsvExpr:
|
|||||||
state[k] = z
|
state[k] = z
|
||||||
return CsvInt(z)
|
return CsvInt(z)
|
||||||
|
|
||||||
@func('accumulate', 'by', 'a')
|
@func('accumulate', '[by;] a')
|
||||||
class Accumulate(Expr):
|
class Accumulate(Expr):
|
||||||
"""A [per by] running sum across results"""
|
"""A [per by] running sum across results"""
|
||||||
def eval(self, fields={}, state=None):
|
def eval(self, fields={}, state=None):
|
||||||
@@ -1020,7 +1019,7 @@ class CsvExpr:
|
|||||||
state[k] = z
|
state[k] = z
|
||||||
return z
|
return z
|
||||||
|
|
||||||
@func('delta', 'by', 'a')
|
@func('delta', '[by;] a')
|
||||||
class Delta(Expr):
|
class Delta(Expr):
|
||||||
"""A [per by] difference between subsequent results"""
|
"""A [per by] difference between subsequent results"""
|
||||||
def eval(self, fields={}, state=None):
|
def eval(self, fields={}, state=None):
|
||||||
@@ -1505,11 +1504,8 @@ class CsvExpr:
|
|||||||
print('funcs:')
|
print('funcs:')
|
||||||
for func in cls.funcs.keys():
|
for func in cls.funcs.keys():
|
||||||
print(' %-21s %s' % (
|
print(' %-21s %s' % (
|
||||||
'%s%s(%s)' % (
|
'%s(%s)' % (
|
||||||
func,
|
func,
|
||||||
'[%s]' % CsvExpr.funcs[func]._fby
|
|
||||||
if CsvExpr.funcs[func]._fby
|
|
||||||
else '',
|
|
||||||
CsvExpr.funcs[func]._fargs),
|
CsvExpr.funcs[func]._fargs),
|
||||||
CsvExpr.funcs[func].__doc__))
|
CsvExpr.funcs[func].__doc__))
|
||||||
|
|
||||||
@@ -1539,29 +1535,11 @@ class CsvExpr:
|
|||||||
elif p.match('[_a-zA-Z][_a-zA-Z0-9]*'):
|
elif p.match('[_a-zA-Z][_a-zA-Z0-9]*'):
|
||||||
a = p.chomp()
|
a = p.chomp()
|
||||||
|
|
||||||
by = None
|
|
||||||
if p.match('\['):
|
|
||||||
p.chomp()
|
|
||||||
if a not in CsvExpr.funcs:
|
|
||||||
raise CsvExpr.Error("unknown function? %s" % a)
|
|
||||||
by = []
|
|
||||||
while True:
|
|
||||||
if not p.match('\]'):
|
|
||||||
b = p_expr(p)
|
|
||||||
by.append(b)
|
|
||||||
if p.match(','):
|
|
||||||
p.chomp()
|
|
||||||
continue
|
|
||||||
if not p.match('\]'):
|
|
||||||
raise CsvExpr.Error("mismatched squares? %s" % p)
|
|
||||||
p.chomp()
|
|
||||||
break
|
|
||||||
|
|
||||||
args = None
|
|
||||||
if p.match('\('):
|
if p.match('\('):
|
||||||
p.chomp()
|
p.chomp()
|
||||||
if a not in CsvExpr.funcs:
|
if a not in CsvExpr.funcs:
|
||||||
raise CsvExpr.Error("unknown function? %s" % a)
|
raise CsvExpr.Error("unknown function? %s" % a)
|
||||||
|
by = None
|
||||||
args = []
|
args = []
|
||||||
while True:
|
while True:
|
||||||
if not p.match('\)'):
|
if not p.match('\)'):
|
||||||
@@ -1570,15 +1548,15 @@ class CsvExpr:
|
|||||||
if p.match(','):
|
if p.match(','):
|
||||||
p.chomp()
|
p.chomp()
|
||||||
continue
|
continue
|
||||||
|
elif p.match(';'):
|
||||||
|
by, args = args, []
|
||||||
|
p.chomp()
|
||||||
|
continue
|
||||||
if not p.match('\)'):
|
if not p.match('\)'):
|
||||||
raise CsvExpr.Error("mismatched parens? %s" % p)
|
raise CsvExpr.Error("mismatched parens? %s" % p)
|
||||||
p.chomp()
|
p.chomp()
|
||||||
|
a = CsvExpr.funcs[a](*args, by=by)
|
||||||
break
|
break
|
||||||
|
|
||||||
if args is not None:
|
|
||||||
a = CsvExpr.funcs[a](*args, by=by)
|
|
||||||
elif by is not None:
|
|
||||||
raise CsvExpr.Error("expected parens? %s" % p)
|
|
||||||
else:
|
else:
|
||||||
a = CsvExpr.Field(a)
|
a = CsvExpr.Field(a)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user