| 1 | # Copyright 2019 Wilke Schwiedop. All rights reserved.
 | 
| 2 | # Licensed under the Apache License, Version 2.0 (the "License");
 | 
| 3 | # you may not use this file except in compliance with the License.
 | 
| 4 | # You may obtain a copy of the License at
 | 
| 5 | #
 | 
| 6 | #   http://www.apache.org/licenses/LICENSE-2.0
 | 
| 7 | """
 | 
| 8 | ast.py: AST utilities for find.
 | 
| 9 | """
 | 
| 10 | 
 | 
| 11 | import stat
 | 
| 12 | 
 | 
| 13 | from _devbuild.gen import find_asdl as asdl
 | 
| 14 | from _devbuild.gen import find_nt
 | 
| 15 | 
 | 
| 16 | import tokenizer
 | 
| 17 | import parser
 | 
| 18 | 
 | 
| 19 | #
 | 
| 20 | # path tests
 | 
| 21 | #
 | 
| 22 | def _name(glob):
 | 
| 23 | 	return asdl.expr.PathTest(
 | 
| 24 | 		asdl.pathAccessor_e.Filename,
 | 
| 25 | 		asdl.predicate.GlobMatch(glob)
 | 
| 26 | 	)
 | 
| 27 | def _iname(glob):
 | 
| 28 | 	return asdl.expr.PathTest(
 | 
| 29 | 		asdl.pathAccessor_e.Filename,
 | 
| 30 | 		asdl.predicate.GlobMatch(glob, ignoreCase=True)
 | 
| 31 | 	)
 | 
| 32 | def _lname(glob):
 | 
| 33 | 	assert False
 | 
| 34 | def _ilname(glob):
 | 
| 35 | 	assert False
 | 
| 36 | def _path(glob):
 | 
| 37 | 	return asdl.expr.PathTest(
 | 
| 38 | 		asdl.pathAccessor_e.FullPath,
 | 
| 39 | 		asdl.predicate.GlobMatch(glob)
 | 
| 40 | 	)
 | 
| 41 | def _ipath(glob):
 | 
| 42 | 	return asdl.expr.PathTest(
 | 
| 43 | 		asdl.pathAccessor_e.FullPath,
 | 
| 44 | 		asdl.predicate.GlobMatch(glob, ignoreCase=True)
 | 
| 45 | 	)
 | 
| 46 | def _regex(re):
 | 
| 47 | 	return asdl.expr.PathTest(
 | 
| 48 | 		asdl.pathAccessor_e.FullPath,
 | 
| 49 | 		asdl.predicate.RegexMatch(re)
 | 
| 50 | 	)
 | 
| 51 | def _iregex(re):
 | 
| 52 | 	return asdl.expr.PathTest(
 | 
| 53 | 		asdl.pathAccessor_e.FullPath,
 | 
| 54 | 		asdl.predicate.RegexMatch(re, ignoreCase=True)
 | 
| 55 | 	)
 | 
| 56 | def _readable():
 | 
| 57 | 	return asdl.expr.PathTest(
 | 
| 58 | 		asdl.pathAccessor_e.FullPath,
 | 
| 59 | 		asdl.predicate.Readable()
 | 
| 60 | 	)
 | 
| 61 | def _writable():
 | 
| 62 | 	return asdl.expr.PathTest(
 | 
| 63 | 		asdl.pathAccessor_e.FullPath,
 | 
| 64 | 		asdl.predicate.Writable()
 | 
| 65 | 	)
 | 
| 66 | def _executable():
 | 
| 67 | 	return asdl.expr.PathTest(
 | 
| 68 | 		asdl.pathAccessor_e.FullPath,
 | 
| 69 | 		asdl.predicate.Executable()
 | 
| 70 | 	)
 | 
| 71 | #
 | 
| 72 | # stat tests
 | 
| 73 | #
 | 
| 74 | def parse_number_predicate(n_str, factor=1):
 | 
| 75 | 	if n_str[0] == '+':
 | 
| 76 | 		return asdl.predicate.GE(int(n_str[1:]) * factor)
 | 
| 77 | 	if n_str[0] == '-':
 | 
| 78 | 		return asdl.predicate.LE(int(n_str[1:]) * factor)
 | 
| 79 | 	return asdl.predicate.EQ(int(n_str) * factor)
 | 
| 80 | def _amin(n_str):
 | 
| 81 | 	assert False
 | 
| 82 | def _anewer(f):
 | 
| 83 | 	assert False
 | 
| 84 | def _atime(n_str):
 | 
| 85 | 	return asdl.expr.StatTest(asdl.statAccessor_e.AccessTime, parse_number_predicate(n_str))
 | 
| 86 | def _cmin(n_str):
 | 
| 87 | 	assert False
 | 
| 88 | def _cnewer(f):
 | 
| 89 | 	assert False
 | 
| 90 | def _ctime(n_str):
 | 
| 91 | 	return asdl.expr.StatTest(asdl.statAccessor_e.CreationTime, parse_number_predicate(n_str))
 | 
| 92 | def _mmin(n_str):
 | 
| 93 | 	assert False
 | 
| 94 | def _mnewer(f):
 | 
| 95 | 	assert False
 | 
| 96 | def _mtime(n_str):
 | 
| 97 | 	return asdl.expr.StatTest(asdl.statAccessor_e.ModificationTime, parse_number_predicate(n_str))
 | 
| 98 | def _newerXY(): # TODO: read manpage
 | 
| 99 | 	assert False
 | 
| 100 | def _used(n_str):
 | 
| 101 | 	assert False
 | 
| 102 | def _empty():
 | 
| 103 | 	return asdl.expr.StatTest(
 | 
| 104 | 		asdl.statAccessor_e.Size,
 | 
| 105 | 		asdl.predicate.EQ(0)
 | 
| 106 | 	)
 | 
| 107 | def _size(n_str):
 | 
| 108 | 	suffixMap = {
 | 
| 109 | 		'b'	: 512, # default
 | 
| 110 | 		'c'	: 1,
 | 
| 111 | 		'w'	: 2,
 | 
| 112 | 		'k'	: 1024**1,
 | 
| 113 | 		'M'	: 1024**2,
 | 
| 114 | 		'G'	: 1024**3,
 | 
| 115 | 	}
 | 
| 116 | 	if n_str[-1] in suffixMap:
 | 
| 117 | 		factor = suffixMap[n_str[-1]]
 | 
| 118 | 		n_str = n_str[:-1]
 | 
| 119 | 	else:
 | 
| 120 | 		factor = suffixMap['b']
 | 
| 121 | 	return asdl.expr.StatTest(asdl.statAccessor_e.Size, parse_number_predicate(n_str, factor=factor))
 | 
| 122 | def _inum(n_str):
 | 
| 123 | 	return asdl.expr.StatTest(asdl.statAccessor_e.Inode, parse_number_predicate(n_str))
 | 
| 124 | def _samefile(f):
 | 
| 125 | 	assert False
 | 
| 126 | def _links(n_str):
 | 
| 127 | 	return asdl.expr.StatTest(asdl.statAccessor_e.LinkCount, parse_number_predicate(n_str))
 | 
| 128 | def _perm(mode): # [+-/]mode
 | 
| 129 | 	assert False
 | 
| 130 | def _type(t_str):
 | 
| 131 | 	tMap = {
 | 
| 132 | 		's'	: stat.S_IFSOCK,
 | 
| 133 | 		'l'	: stat.S_IFLNK,
 | 
| 134 | 		'f'	: stat.S_IFREG,
 | 
| 135 | 		'b'	: stat.S_IFBLK,
 | 
| 136 | 		'd'	: stat.S_IFDIR,
 | 
| 137 | 		'c'	: stat.S_IFCHR,
 | 
| 138 | 		'p'	: stat.S_IFIFO,
 | 
| 139 | 	}
 | 
| 140 | 	t = tMap[t_str]
 | 
| 141 | 	return asdl.expr.StatTest(
 | 
| 142 | 		asdl.statAccessor_e.Filetype,
 | 
| 143 | 		asdl.predicate.EQ(t)
 | 
| 144 | 	)
 | 
| 145 | def _xtype(t_str):
 | 
| 146 | 	assert False
 | 
| 147 | def _uid(uid_str):
 | 
| 148 | 	uid = int(uid)
 | 
| 149 | 	return asdl.expr.StatTest(
 | 
| 150 | 		asdl.statAccessor_e.Uid,
 | 
| 151 | 		asdl.predicate.EQ(uid)
 | 
| 152 | 	)
 | 
| 153 | def _gid(gid_str):
 | 
| 154 | 	gid = int(gid)
 | 
| 155 | 	return asdl.expr.StatTest(
 | 
| 156 | 		asdl.statAccessor_e.Gid,
 | 
| 157 | 		asdl.predicate.EQ(gid)
 | 
| 158 | 	)
 | 
| 159 | def _user(user):
 | 
| 160 | 	return asdl.expr.StatTest(
 | 
| 161 | 		asdl.statAccessor_e.Username,
 | 
| 162 | 		asdl.predicate.StringMatch(user)
 | 
| 163 | 	)
 | 
| 164 | def _group(group):
 | 
| 165 | 	return asdl.expr.StatTest(
 | 
| 166 | 		asdl.statAccessor_e.Groupname,
 | 
| 167 | 		asdl.predicate.StringMatch(group)
 | 
| 168 | 	)
 | 
| 169 | def _nouser():
 | 
| 170 | 	assert False
 | 
| 171 | def _nogroup():
 | 
| 172 | 	assert False
 | 
| 173 | def _fstype(fsType):
 | 
| 174 | 	assert False
 | 
| 175 | #
 | 
| 176 | # actions
 | 
| 177 | #
 | 
| 178 | def _print():
 | 
| 179 | 	return asdl.expr.PrintAction()
 | 
| 180 | def _print0():
 | 
| 181 | 	# TODO verify fmt
 | 
| 182 | 	return asdl.expr.PrintAction(format="%P\0")
 | 
| 183 | def _printf(fmt):
 | 
| 184 | 	return asdl.expr.PrintAction(format=fmt)
 | 
| 185 | def _fprint(f):
 | 
| 186 | 	return asdl.expr.PrintAction(file=f)
 | 
| 187 | def _fprint0(f):
 | 
| 188 | 	# TODO verify fmt
 | 
| 189 | 	return asdl.expr.PrintAction(file=f, format="%P\0")
 | 
| 190 | def _fprintf(f, fmt):
 | 
| 191 | 	return asdl.expr.PrintAction(file=f, format=fmt)
 | 
| 192 | def _ls():
 | 
| 193 | 	return asdl.expr.LsAction()
 | 
| 194 | def _fls(f):
 | 
| 195 | 	return asdl.expr.LsAction(file=f)
 | 
| 196 | def _exec(*argv):
 | 
| 197 | 	argv = list(argv)
 | 
| 198 | 	batch = True if argv[-1] == '+' else False if argv[-1] == ';' else None
 | 
| 199 | 	if batch is None:
 | 
| 200 | 		assert False
 | 
| 201 | 	return asdl.expr.ExecAction(batch=batch, dir=False, ok=False, argv=argv[:-1])
 | 
| 202 | def _execdir(*argv):
 | 
| 203 | 	argv = list(argv)
 | 
| 204 | 	batch = True if argv[-1] == '+' else False if argv[-1] == ';' else None
 | 
| 205 | 	if batch is None:
 | 
| 206 | 		assert False
 | 
| 207 | 	return asdl.expr.ExecAction(batch=batch, dir=True, ok=False, argv=argv[:-1])
 | 
| 208 | def _ok(*argv):
 | 
| 209 | 	argv = list(argv)
 | 
| 210 | 	batch = True if argv[-1] == '+' else False if argv[-1] == ';' else None
 | 
| 211 | 	if batch is None:
 | 
| 212 | 		assert False
 | 
| 213 | 	return asdl.expr.ExecAction(batch=batch, dir=False, ok=True, argv=argv[:-1])
 | 
| 214 | def _okdir(*argv):
 | 
| 215 | 	argv = list(argv)
 | 
| 216 | 	batch = True if argv[-1] == '+' else False if argv[-1] == ';' else None
 | 
| 217 | 	if batch is None:
 | 
| 218 | 		assert False
 | 
| 219 | 	return asdl.expr.ExecAction(batch=batch, dir=True, ok=True, argv=argv[:-1])
 | 
| 220 | def _delete():
 | 
| 221 | 	return asdl.expr.DeleteAction()
 | 
| 222 | def _prune():
 | 
| 223 | 	return asdl.expr.PruneAction()
 | 
| 224 | def _quit():
 | 
| 225 | 	return asdl.expr.QuitAction()
 | 
| 226 | 
 | 
| 227 | exprMap = {
 | 
| 228 | 	# atoms
 | 
| 229 | 	tokenizer.TRUE		: asdl.expr.True_,
 | 
| 230 | 	tokenizer.FALSE	: asdl.expr.False_,
 | 
| 231 | 	# path tests
 | 
| 232 | 	tokenizer.NAME		: _name,
 | 
| 233 | 	tokenizer.INAME	: _iname,
 | 
| 234 | 	tokenizer.LNAME	: _lname,
 | 
| 235 | 	tokenizer.ILNAME	: _ilname,
 | 
| 236 | 	tokenizer.PATH		: _path,
 | 
| 237 | 	tokenizer.IPATH	: _ipath,
 | 
| 238 | 	tokenizer.REGEX	: _regex,
 | 
| 239 | 	tokenizer.IREGEX	: _iregex,
 | 
| 240 | 	# stat tests
 | 
| 241 | 	tokenizer.AMIN		: _amin,
 | 
| 242 | 	tokenizer.ANEWER	: _anewer,
 | 
| 243 | 	tokenizer.ATIME	: _atime,
 | 
| 244 | 	tokenizer.CMIN		: _cmin,
 | 
| 245 | 	tokenizer.CNEWER	: _cnewer,
 | 
| 246 | 	tokenizer.CTIME	: _ctime,
 | 
| 247 | 	tokenizer.MMIN		: _mmin,
 | 
| 248 | 	tokenizer.MNEWER	: _mnewer,
 | 
| 249 | 	tokenizer.MTIME	: _mtime,
 | 
| 250 | 	tokenizer.NEWERXY	: _newerXY,
 | 
| 251 | #	tokenizer.USED		: _used,
 | 
| 252 | 	tokenizer.EMPTY	: _empty,
 | 
| 253 | 	tokenizer.SIZE		: _size,
 | 
| 254 | 	tokenizer.READABLE	: _readable,
 | 
| 255 | 	tokenizer.WRITABLE	: _writable,
 | 
| 256 | 	tokenizer.EXECUTABLE	: _executable,
 | 
| 257 | #	tokenizer.INUM		: _inum,
 | 
| 258 | #	tokenizer.SAMEFILE	: _samefile,
 | 
| 259 | #	tokenizer.LINKS	: _links,
 | 
| 260 | 	tokenizer.PERM		: _perm,
 | 
| 261 | 	tokenizer.TYPE		: _type,
 | 
| 262 | 	tokenizer.XTYPE	: _xtype,
 | 
| 263 | 	tokenizer.UID		: _uid,
 | 
| 264 | 	tokenizer.GID		: _gid,
 | 
| 265 | 	tokenizer.USER		: _user,
 | 
| 266 | 	tokenizer.GROUP	: _group,
 | 
| 267 | 	tokenizer.NOUSER	: _nouser,
 | 
| 268 | 	tokenizer.NOGROUP	: _nogroup,
 | 
| 269 | #	tokenizer.FSTYPE	: _fstype,
 | 
| 270 | 	# actions
 | 
| 271 | 	tokenizer.PRINT	: _print,
 | 
| 272 | 	tokenizer.PRINT0	: _print0,
 | 
| 273 | 	tokenizer.PRINTF	: _printf,
 | 
| 274 | 	tokenizer.FPRINT	: _fprint,
 | 
| 275 | 	tokenizer.FPRINT0	: _fprint0,
 | 
| 276 | 	tokenizer.FPRINTF	: _fprintf,
 | 
| 277 | 	tokenizer.EXEC		: _exec,
 | 
| 278 | 	tokenizer.EXECDIR	: _execdir,
 | 
| 279 | 	tokenizer.OK		: _ok,
 | 
| 280 | 	tokenizer.OKDIR	: _okdir,
 | 
| 281 | 	tokenizer.DELETE	: _delete,
 | 
| 282 | 	tokenizer.PRUNE	: _prune,
 | 
| 283 | 	tokenizer.QUIT		: _quit,
 | 
| 284 | }
 | 
| 285 | 
 | 
| 286 | def _start(children):
 | 
| 287 | 	assert len(children) == 2
 | 
| 288 | 	assert tokenizer.is_eof(children[1].typ)
 | 
| 289 | 	return AST(children[0])
 | 
| 290 | def _concatenation(children):
 | 
| 291 | 	assert len(children) >= 2
 | 
| 292 | 	return asdl.expr.Concatenation(
 | 
| 293 | 		[AST(c) for c in children if c.typ != tokenizer.COMMA]
 | 
| 294 | 	)
 | 
| 295 | def _disjunction(children):
 | 
| 296 | 	assert len(children) >= 2
 | 
| 297 | 	return asdl.expr.Disjunction(
 | 
| 298 | 		[AST(c) for c in children if c.typ != tokenizer.OR]
 | 
| 299 | 	)
 | 
| 300 | def _conjunction(children):
 | 
| 301 | 	assert len(children) >= 2
 | 
| 302 | 	return asdl.expr.Conjunction(
 | 
| 303 | 		[AST(c) for c in children if c.typ != tokenizer.AND]
 | 
| 304 | 	)
 | 
| 305 | def _negation(children):
 | 
| 306 | 	assert len(children) == 2
 | 
| 307 | 	assert children[0].typ == tokenizer.BANG
 | 
| 308 | 	return asdl.expr.Negation(AST(children[1]))
 | 
| 309 | def _group(children):
 | 
| 310 | 	assert len(children) == 3
 | 
| 311 | 	assert children[0].typ == tokenizer.LPAR
 | 
| 312 | 	assert children[2].typ == tokenizer.RPAR
 | 
| 313 | 	return AST(children[1])
 | 
| 314 | def _expr(children):
 | 
| 315 | 	f = exprMap[children[0].typ]
 | 
| 316 | 	return f(*(c.tok[0] for c in children[1:]))
 | 
| 317 | 
 | 
| 318 | ntMap = {
 | 
| 319 | 	find_nt.start            : _start,
 | 
| 320 | 	find_nt.concatenation    : _concatenation,
 | 
| 321 | 	find_nt.disjunction      : _disjunction,
 | 
| 322 | 	find_nt.conjunction      : _conjunction,
 | 
| 323 | 	find_nt.negation         : _negation,
 | 
| 324 | 	find_nt.group            : _group,
 | 
| 325 | 	find_nt.expr             : _expr,
 | 
| 326 | }
 | 
| 327 | 
 | 
| 328 | def AST(pnode):
 | 
| 329 | 	if tokenizer.is_nonterminal(pnode.typ):
 | 
| 330 | 		assert pnode.typ not in exprMap
 | 
| 331 | 		return ntMap[pnode.typ](pnode.children)
 | 
| 332 | 	else:
 | 
| 333 | 		assert pnode.typ not in ntMap
 | 
| 334 | 		return exprMap[pnode.typ]()
 |