Added ExactConceptParser
This commit is contained in:
+76
-5
@@ -2,6 +2,8 @@ import hashlib
|
||||
from enum import Enum
|
||||
import logging
|
||||
|
||||
from core.tokenizer import Tokenizer, TokenKind
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -20,6 +22,8 @@ class Concept:
|
||||
"""
|
||||
props_to_serialize = ("id", "is_builtin", "name", "where", "pre", "post", "body", "desc")
|
||||
|
||||
PROPERTY_PREFIX = "__var__"
|
||||
|
||||
def __init__(self, name=None, is_builtin=False, where=None, pre=None, post=None, body=None, desc=None, key=None):
|
||||
self.name = name
|
||||
self.is_builtin = is_builtin
|
||||
@@ -31,7 +35,7 @@ class Concept:
|
||||
self.id = None
|
||||
self.key = key
|
||||
|
||||
self.props = [] # list of Property for this concept
|
||||
self.props = {} # list of Property for this concept
|
||||
self.functions = {} # list of helper functions
|
||||
|
||||
self.codes = {} # cached ast for the where, pre, post and body parts
|
||||
@@ -54,10 +58,48 @@ class Concept:
|
||||
def get_key(self):
|
||||
return self.key
|
||||
|
||||
def init_key(self, tokens=None):
|
||||
"""
|
||||
Create the key for this concept.
|
||||
Must be called only when the concept if fully initialized
|
||||
|
||||
The method is not called set_key to make sure that no other class set the key by mistake
|
||||
:param tokens:
|
||||
:return:
|
||||
"""
|
||||
if self.key is not None:
|
||||
return self.key
|
||||
|
||||
if tokens is None:
|
||||
tokens = iter(Tokenizer(self.name))
|
||||
|
||||
variables = list(self.props.keys())
|
||||
|
||||
key = ""
|
||||
first = True
|
||||
for token in tokens:
|
||||
if token.type == TokenKind.EOF:
|
||||
break
|
||||
if token.type == TokenKind.WHITESPACE:
|
||||
continue
|
||||
if not first:
|
||||
key += " "
|
||||
if variables is not None and token.value in variables:
|
||||
key += self.PROPERTY_PREFIX + str(variables.index(token.value))
|
||||
else:
|
||||
key += token.value[1:-1] if token.type == TokenKind.STRING else token.value
|
||||
first = False
|
||||
|
||||
self.key = key
|
||||
return self
|
||||
|
||||
def add_codes(self, codes):
|
||||
"""
|
||||
From a dict of <ConceptParts, AST>
|
||||
fill the codes
|
||||
Gets the ASTs for 'where', 'pre', 'post' and 'body'
|
||||
There ASTs are know when the concept is freshly parsed.
|
||||
So the values are kept in cache.
|
||||
|
||||
For concepts loaded from sdp, these ASTs must be created again
|
||||
:param codes:
|
||||
:return:
|
||||
"""
|
||||
@@ -68,6 +110,8 @@ class Concept:
|
||||
if key in possibles_codes:
|
||||
self.codes[ConceptParts(key)] = codes[key]
|
||||
|
||||
return self
|
||||
|
||||
def get_digest(self):
|
||||
"""
|
||||
Returns the digest of the event
|
||||
@@ -76,23 +120,47 @@ class Concept:
|
||||
return hashlib.sha256(f"Concept:{self.name}{self.pre}{self.post}{self.body}".encode("utf-8")).hexdigest()
|
||||
|
||||
def to_dict(self):
|
||||
"""
|
||||
Returns a dict representing 'self'
|
||||
:return:
|
||||
"""
|
||||
props_as_dict = dict((prop, getattr(self, prop)) for prop in self.props_to_serialize)
|
||||
props_as_dict["props"] = [(p.name, p.value) for p in self.props]
|
||||
props_as_dict["props"] = [(p, self.props[p].value) for p in self.props]
|
||||
return props_as_dict
|
||||
|
||||
def from_dict(self, as_dict):
|
||||
"""
|
||||
Initializes 'self' from a dict
|
||||
:param as_dict:
|
||||
:return:
|
||||
"""
|
||||
for prop in self.props_to_serialize:
|
||||
if prop in as_dict:
|
||||
setattr(self, prop, as_dict[prop])
|
||||
if "props" in as_dict:
|
||||
for n, v in as_dict["props"]:
|
||||
self.props.append(Property(n, v))
|
||||
self.set_prop(n, v)
|
||||
return self
|
||||
|
||||
def update_from(self, other):
|
||||
"""
|
||||
Update self using the properties of another concept
|
||||
This method is to mimic the class to instance pattern
|
||||
'other' is the class, the template, and 'self' is a new instance
|
||||
:param other:
|
||||
:return:
|
||||
"""
|
||||
for prop in self.props_to_serialize:
|
||||
setattr(self, prop, getattr(other, prop))
|
||||
|
||||
return self
|
||||
|
||||
def set_prop(self, prop_name, prop_value):
|
||||
self.props[prop_name] = Property(prop_name, prop_value)
|
||||
|
||||
def set_prop_by_index(self, index, prop_value):
|
||||
prop_name = list(self.props.keys())[index]
|
||||
self.props[prop_name] = Property(prop_name, prop_value)
|
||||
|
||||
class ErrorConcept(Concept):
|
||||
NAME = "Error"
|
||||
@@ -132,3 +200,6 @@ class Property:
|
||||
def __init__(self, name, value):
|
||||
self.name = name
|
||||
self.value = value
|
||||
|
||||
def __repr__(self):
|
||||
return f"{self.name}={self.value}"
|
||||
|
||||
Reference in New Issue
Block a user