Skip to content

Commit

Permalink
actions.py: Create enums for type and emit_type
Browse files Browse the repository at this point in the history
Signed-off-by: Alexander McClain <serial@sata.lol>
  • Loading branch information
Serial-ATA committed Apr 10, 2024
1 parent 6d87b54 commit 2ba7e5d
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 43 deletions.
89 changes: 61 additions & 28 deletions pysrc/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
# limitations under the License.
#
#END_LEGAL
from enum import Enum, auto
from typing import Optional

from verbosity import *
import patterns
import genutil
Expand All @@ -35,7 +38,7 @@ def dummy_emit(act_in,name):
dummy emit type and name as the field name'''

action = copy.deepcopy(act_in)
action.emit_type = 'dummy'
action.emit_type = ActionEmitType.DUMMY
action.field_name = name
return action

Expand All @@ -58,36 +61,66 @@ def gen_nt_action(nt):
action = action_t(str)
return action


class ActionType(Enum):
FIELD_BINDING = auto()
EMIT = auto()
NONTERMINAL = auto()
NONTERMINAL_LOOKUP_FN = auto()
ERROR = auto()
NOTHING = auto()
RETURN = auto()

def __str__(self):
if self == ActionType.FIELD_BINDING:
return "FB"
if self == ActionType.NONTERMINAL:
return "nt"
if self == ActionType.NONTERMINAL_LOOKUP_FN:
return "ntluf"
return self.name.lower()


class ActionEmitType(Enum):
NUMERIC = auto()
LETTERS = auto()
REG = auto()
DUMMY = auto()

def __str__(self):
return self.name.lower()


class action_t(object):
"""This is the right hand side of the rule_t. It can be a (1)
field binding (2) a byte encoding, (3) 'error' or (4) 'nothing'."""


def __init__(self, arg_action):
# field bindings (FB) are OD=value
self.type = None # 'FB', 'emit', 'nt', 'error', 'nothing', 'return'
self.type: Optional[ActionType] = None
self.field_name = None
self.value = None
self.nt = None
self.ntluf = None
self.int_value = None
self.emit_type = None # 'numeric', 'letters', 'reg'
self.emit_type: Optional[ActionEmitType] = None
self.nbits = 0
if vaction():
msgb("ARGACTION", arg_action)
if arg_action in ['nothing', "NOTHING"]:
self.type = 'nothing'
self.type = ActionType.NOTHING
return

b = patterns.return_pattern.search(arg_action)
if b:
self.type = 'return'
self.type = ActionType.RETURN
self.value = b.group('retval')
return

# in the inputs, "error" gets expanded to "ERROR=1" via the statebits.
if arg_action == 'error' or arg_action == "ERROR" or arg_action == 'ERROR=1':
self.type = 'error'
self.type = ActionType.ERROR
return

b = patterns.bit_expand_pattern.search(arg_action)
Expand All @@ -114,33 +147,33 @@ def __init__(self, arg_action):
else:
self.value = rhs

self.type = 'FB'
self.type = ActionType.FIELD_BINDING
return

nt = patterns.nt_name_pattern.match(action)
if nt:
# NTLUF or NT. Only shows up on decode-oriented rules
self.nt = nt.group('ntname')
self.type = 'nt'
self.type = ActionType.NONTERMINAL
return
ntluf = patterns.ntluf_name_pattern.match(action)
if ntluf:
# NTLUF or NT. Only shows up on decode-oriented rules
self.ntluf = ntluf.group('ntname')
self.type = 'ntluf'
self.type = ActionType.NONTERMINAL_LOOKUP_FN
return

cp = patterns.lhs_capture_pattern_end.match(action)
if cp:
self.type = 'emit'
self.type = ActionType.EMIT
self.value = cp.group('bits')
self.field_name = cp.group('name').lower()
#msgerr("EMIT ACTION %s" % action)
self.classify()
return

# simple byte encoding
self.type = 'emit'
self.type = ActionType.EMIT
self.field_name = None
#msgerr("EMIT ACTION %s" % action)
self.value = action
Expand All @@ -149,7 +182,7 @@ def __init__(self, arg_action):

def classify(self):
if patterns.decimal_pattern.match(self.value):
self.emit_type = 'numeric'
self.emit_type = ActionEmitType.NUMERIC
self.int_value = int(self.value)
t = hex(self.int_value)
self.nbits = 4*len(t[2:])
Expand All @@ -158,14 +191,14 @@ def classify(self):
return

if patterns.hex_pattern.match(self.value):
self.emit_type = 'numeric'
self.emit_type = ActionEmitType.NUMERIC
self.int_value = int(self.value,16)
self.nbits = 4*(len(self.value)-2) # drop the 0x, convert nibbles to bits
if vclassify():
msgb("CLASSIFY", "%s as hex" % (self.value))
return
if patterns.letter_and_underscore_pattern.match(self.value):
self.emit_type = 'letters'
self.emit_type = ActionEmitType.LETTERS
t = self.value
t = genutil.no_underscores(t)
self.nbits = len(t)
Expand All @@ -174,7 +207,7 @@ def classify(self):
return
b = patterns.binary_pattern.match(self.value) # leading "0b"
if b:
self.emit_type = 'numeric'
self.emit_type = ActionEmitType.NUMERIC
t = '0b' + b.group('bits') # pattern match strips out 0b
self.int_value = genutil.make_numeric(t)
bits_str = genutil.make_binary(t)
Expand All @@ -183,7 +216,7 @@ def classify(self):
msgb("CLASSIFY", "%s as explicit-binary -> int = %d nbits=%d [%s,%s]" % (self.value,self.int_value,self.nbits,t,bits_str))
return
if patterns.bits_and_letters_underscore_pattern.match(self.value):
self.emit_type = 'letters'
self.emit_type = ActionEmitType.LETTERS
v = genutil.no_underscores(self.value)
self.nbits = len(v)
if vclassify():
Expand All @@ -192,7 +225,7 @@ def classify(self):


if patterns.simple_number_pattern.match(self.value):
self.emit_type = 'numeric'
self.emit_type = ActionEmitType.NUMERIC
self.int_value = genutil.make_numeric(self.value)
t = hex(self.int_value)
self.nbits = 4*len(t[2:])
Expand All @@ -204,16 +237,16 @@ def classify(self):

def naked_bits(self):
''' returns True if the type is emit but there is no field name. '''
if self.type == 'emit' and self.field_name == None:
if self.type == ActionType.EMIT and self.field_name == None:
return True
return False

def is_nothing(self):
return self.type == 'nothing'
return self.type == ActionType.NOTHING
def is_error(self):
return self.type == 'error'
return self.type == ActionType.ERROR
def is_return(self):
return self.type == 'return'
return self.type == ActionType.RETURN

def is_nonterminal(self):
if self.nt:
Expand All @@ -226,13 +259,13 @@ def is_ntluf(self):

def is_field_binding(self):
"""Return True if this action is a field binding."""
if self.type == 'FB':
if self.type == ActionType.FIELD_BINDING:
return True
return False

def is_emit_action(self):
"""Return True if this action is an emit action."""
if self.type == 'emit':
if self.type == ActionType.EMIT:
return True
return False

Expand All @@ -248,7 +281,7 @@ def __str__(self):
s.append(" ")
s.append(self.value)
if self.emit_type:
s.append(" emit_type=%s" % self.emit_type)
s.append(" emit_type=%s" % str(self.emit_type))
if self.int_value != None:
s.append(" value=0x%x" % self.int_value)
if self.nbits != 0:
Expand Down Expand Up @@ -304,9 +337,9 @@ def _generate_code_for_field_binding(self, bind_or_emit):
def _generate_code_for_emit_action(self,bind_or_emit):
"""Emit code for emit action """
if bind_or_emit == 'BIND':
if self.emit_type == 'letters' or self.field_name == None:
if self.emit_type == ActionEmitType.LETTERS or self.field_name == None:
return ''
elif self.emit_type == 'numeric':
elif self.emit_type == ActionEmitType.NUMERIC:
op_accessor = encutil.enc_strings['op_accessor']
operand_setter = "%s_set_%s" % (op_accessor,
self.field_name.lower())
Expand All @@ -315,14 +348,14 @@ def _generate_code_for_emit_action(self,bind_or_emit):
code = "%s(%s, %s);" % (operand_setter, obj_name, hex_val)
return [' ' + code]
else:
genutil.die("Unknown emit_type %s" % self.emit_type)
genutil.die("Unknown emit_type %s" % str(self.emit_type))
else: # EMIT
emit_util_function = encutil.enc_strings['emit_util_function']
obj_name = encutil.enc_strings['obj_str']
nbits = self.nbits
code = ''
if self.field_name == None:
if self.emit_type == 'numeric':
if self.emit_type == ActionEmitType.NUMERIC:
hex_val = hex(self.int_value)
code = "%s(%s, %d, %s);" % (emit_util_function,obj_name,
nbits,hex_val)
Expand Down
19 changes: 10 additions & 9 deletions pysrc/ins_emit.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import encutil
import genutil
import actions
from actions import ActionType, ActionEmitType
import verbosity

max_in_byte = 256 #max unsigned int per byte
Expand Down Expand Up @@ -727,12 +728,12 @@ def _make_field_bindings_pattern(self,iform):

bind_actions = []
for action in iform.rule.actions:
if action.type == 'nt':
if action.type == ActionType.NONTERMINAL:
pass
elif action.type == 'FB':
elif action.type == ActionType.FIELD_BINDING:
bind_actions.append(action.field_name)
elif action.type == 'emit':
if action.emit_type == 'numeric' and action.field_name:
elif action.type == ActionType.EMIT:
if action.emit_type == ActionEmitType.NUMERIC and action.field_name:
bind_actions.append(action.field_name)
else:
pass
Expand All @@ -754,7 +755,7 @@ def _make_emit_pattern(self,iform):
def _make_emit_pattern_low(self,iform):
emit_pattern = []
for action in iform.rule.actions:
if action.type == 'emit':
if action.type == ActionType.EMIT:
# if no field_name, then we must differentiate the
# emit patterns using the value to avoid collisions.
if action.field_name == None:
Expand All @@ -767,14 +768,14 @@ def _make_emit_pattern_low(self,iform):
action.field_name,
action.nbits))

elif action.type == 'nt':
elif action.type == ActionType.NONTERMINAL:
emit_pattern.append(str(action))
elif action.type == 'FB':
elif action.type == ActionType.FIELD_BINDING:
# FB are not used in emit phase so we do not factor them
# in to the string that represents the pattern
pass
else:
genutil.die("unexpected action type: %s" % action.type)
genutil.die("unexpected action type: %s" % str(action.type))
emit_actions_str = ', '.join(emit_pattern)
return emit_actions_str

Expand All @@ -783,7 +784,7 @@ def _make_bind_pattern(self,iform):

bind_ptrn = [ str(iform.rule.conditions) ]
for action in iform.rule.actions:
if action.type == 'nt':
if action.type == ActionType.NONTERMINAL:
bind_ptrn.append(str(action))

iform.bind_ptrn = ''
Expand Down
13 changes: 7 additions & 6 deletions pysrc/read-encfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ def find_dir(d):
sys.exit(1)

import actions
from actions import ActionEmitType, ActionType
import ins_emit
import encutil
from patterns import *
Expand Down Expand Up @@ -721,7 +722,7 @@ def compute_field_capture_list(self):

def prepare_value_for_emit(self, a):
"""@return: (length-in-bits, value-as-hex)"""
if a.emit_type == 'numeric':
if a.emit_type == ActionEmitType.NUMERIC:
v = hex(a.int_value)
return (a.nbits, v) # return v with the leading 0x
s = a.value
Expand Down Expand Up @@ -996,7 +997,7 @@ def emit_rule_emit(self, ith_rule_arg, nt_name, captures):

if vtuples():
msgb("TUPLES", (" ,".join( [str(x) for x in list_of_tuples] )))
if len(list_of_tuples) == 0 or a.emit_type == 'numeric':
if len(list_of_tuples) == 0 or a.emit_type == ActionEmitType.NUMERIC:
# no substitutions required
(length, s) = self.prepare_value_for_emit(a)
if veemit():
Expand Down Expand Up @@ -1045,7 +1046,7 @@ def get_all_fbs(self):
fbs.append(action)
if action.field_name == 'MAP':
found_map_fb = True
if action.is_emit_action() and action.emit_type == 'numeric':
if action.is_emit_action() and action.emit_type == ActionEmitType.NUMERIC:
if action.field_name:
fbs.append(action)

Expand Down Expand Up @@ -1321,15 +1322,15 @@ def _remove_overlapping_actions(self, action_list):
modifying to input action_list
'''

emit_actions = list(filter(lambda x: x.type == 'emit', action_list))
fb_actions = list(filter(lambda x: x.type == 'FB', action_list))
emit_actions = list(filter(lambda x: x.type == ActionType.EMIT, action_list))
fb_actions = list(filter(lambda x: x.type == ActionType.FIELD_BINDING, action_list))

#iterate to find overlapping actions
action_to_remove = []
for fb in fb_actions:
for emit in emit_actions:
if fb.field_name.lower() == emit.field_name and \
emit.emit_type == 'numeric':
emit.emit_type == ActionEmitType.NUMERIC:
if fb.int_value == emit.int_value:
# overlapping actions, recored this action
# and remove later
Expand Down

0 comments on commit 2ba7e5d

Please sign in to comment.