Source code for sirepo.template.elegant_command_parser
# -*- coding: utf-8 -*-
u"""elegant command parser.
:copyright: Copyright (c) 2016 RadiaSoft LLC. All Rights Reserved.
:license: http://www.apache.org/licenses/LICENSE-2.0.html
"""
from __future__ import absolute_import, division, print_function
import re
from sirepo.template.line_parser import LineParser
_SKIP_COMMANDS = ['subprocess']
[docs]def parse_file(command_text):
parser = LineParser(0)
lines = command_text.replace('\r', '').split('\n')
prev_line = ''
commands = []
for line in lines:
parser.increment_line_number()
if re.search(r'^#', line):
continue
line = re.sub(r'\!.*$', '', line)
if not line:
continue
if re.search(r'\&end', line):
if not _parse_line(parser, prev_line + ' ' + line, commands):
break
prev_line = ''
elif re.search(r'\&', line) or len(prev_line):
prev_line += ' ' + line
else:
# ignoring lines between command markers
pass
if prev_line and re.search(r'\&', prev_line):
parser.raise_error('missing &end for command: {}'.format(prev_line))
_update_lattice_names(commands)
return commands
def _parse_array_value(parser):
# read off the end of the array value list
# parse values until a "&end" or "value =" is reached
#
# response[2] = %s.vhrm, %s.hvrm,
# distribution_type[0] = "gaussian", "gaussian",
# enforce_rms_values[0] = 1,1,1,
# distribution_type[0] = gaussian, gaussian, hard-edge,
# distribution_type[0] = 3*"gaussian",
# distribution_cutoff[0] = 3*3,
res = ''
index = parser.get_index()
while True:
value = parser.parse_value()
if value == '&end':
parser.reset_index(index)
break
parser.ignore_whitespace()
if parser.peek_char() == '=':
parser.reset_index(index)
break
if value:
res += value
else:
if parser.peek_char() == ',':
parser.assert_char(',')
res += ','
elif parser.peek_char() == '*':
parser.assert_char('*')
res += '*'
else:
parser.raise_error('expecting an array value')
index = parser.get_index()
if not res:
parser.raise_error('missing array value')
res = re.sub(r',$', '', res)
return res
def _parse_line(parser, line, commands):
parser.set_line(line)
parser.ignore_whitespace()
parser.assert_char('&')
command = {
'_id': parser.next_id(),
'_type': parser.parse_value(r'\s+'),
}
if command['_type'] == 'stop':
return False
parser.ignore_whitespace()
while True:
value = parser.parse_value()
if not value:
if parser.peek_char() == ',':
parser.assert_char(',')
continue
parser.raise_error('expecting a command element')
if value == '&end':
break
if parser.peek_char() == '=':
parser.assert_char('=')
if re.search(r'\[', value):
command[value] = _parse_array_value(parser)
else:
command[value] = parser.parse_value(r'[\s,=\!)]')
else:
parser.raise_error('trailing input: {}'.format(value))
parser.assert_end_of_line()
if not command['_type'] in _SKIP_COMMANDS:
commands.append(command)
return True
def _update_lattice_names(commands):
# preserve the name of the first run_setup.lattic
# others may map to previous save_lattice names
is_first_run_setup = True
save_lattices = []
for cmd in commands:
if cmd['_type'] == 'save_lattice':
name = re.sub(r'\%s', '', cmd['filename'])
save_lattices.append(name)
if cmd['_type'] == 'run_setup':
if is_first_run_setup:
is_first_run_setup = False
continue
for index in reversed(range(len(save_lattices))):
if re.search(re.escape(save_lattices[index]), cmd['lattice'], re.IGNORECASE):
cmd['lattice'] = 'save_lattice' if index == 0 else 'save_lattice{}'.format(index + 1)
break
else:
cmd['lattice'] = 'Lattice'