├── .gitignore ├── expresol ├── Data.py ├── Memory.py ├── Parser.py └── __init__.py ├── readme.MD └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | expresol/Test.py 2 | expresol/__pycache__ -------------------------------------------------------------------------------- /expresol/Data.py: -------------------------------------------------------------------------------- 1 | class Marker(dict): 2 | def __init__(self, label): 3 | self['label'] = label 4 | 5 | class Operator(dict): 6 | def __init__(self, function=None, inputs=[]): 7 | self['function'] = function 8 | self['inputs'] = inputs 9 | def __call__(self, inputs): 10 | self['inputs'] = inputs 11 | return self.compute() 12 | def compute(self): 13 | return self['function'](self['inputs']) 14 | 15 | class Variable(dict): 16 | def __init__(self, value=None): 17 | self['value'] = value 18 | 19 | class Pointer(dict): 20 | def __init__(self, symbol=None, index=None): 21 | self['symbol'] = symbol 22 | self['index'] = index 23 | 24 | class Reference(dict): 25 | def __init__(self, index=None, symbol=None, datatype=None, value=None): 26 | self['symbol'] = symbol 27 | self['index'] = index 28 | self['type'] = datatype 29 | self['value'] = value 30 | 31 | 32 | -------------------------------------------------------------------------------- /expresol/Memory.py: -------------------------------------------------------------------------------- 1 | from .Data import * 2 | 3 | class Memory: 4 | def __init__(self, size): 5 | self.store = list() 6 | self.table = dict() 7 | for i in range(size): 8 | self.store.append(None) 9 | 10 | def var(self, index, value): 11 | self.store[index] = Variable(value) 12 | 13 | def ref(self, index, symbol, datatype): 14 | self.table[symbol] = Reference(index, symbol, datatype) 15 | 16 | def get(self, obj): 17 | if isinstance(obj, str): 18 | obj = self.table[obj] 19 | if isinstance(obj, Reference): 20 | index = obj['index'] 21 | var = self.store[index] 22 | obj['value'] = var['value'] 23 | return obj 24 | -------------------------------------------------------------------------------- /expresol/Parser.py: -------------------------------------------------------------------------------- 1 | from .Data import * 2 | 3 | class Parser: 4 | def __init__(self, types=[]): 5 | self.vocab = {} 6 | self.rules = [] 7 | for i in range(len(types)): 8 | self.vocab[types[i]] = None 9 | 10 | def __call__(self, script, memory): 11 | data = self.parse(script) 12 | model = self.convert(data, memory) 13 | return self.execute(model) 14 | 15 | def rule(self, type1, type2): 16 | self.rules.append((type1, type2)) 17 | 18 | def type(self, name, chars): 19 | self.vocab[name] = chars 20 | 21 | def parse(self, script): 22 | labels = [] 23 | types = list(self.vocab.keys()) 24 | script = combine(revise(script)) 25 | for i in range(len(types)): 26 | labels.append(assign_labels(script, self.vocab[types[i]], types[i])) 27 | objects = combine_elements(script, merge(labels), self.rules) 28 | return objects 29 | 30 | def convert(self, objects, memory): 31 | data = convert_objects(objects, memory) 32 | boundaries =define_boundaries(data) 33 | containers = assign_containers(boundaries) 34 | model = generate(boundaries, containers, data) 35 | return model 36 | 37 | def execute(self, model): 38 | for i in range(len(model)): 39 | if isinstance(model, list): 40 | function = None 41 | inputs = list() 42 | 43 | if len(model) == 1: 44 | function = ID 45 | inputs = [model[0]] 46 | elif len(model) == 2: 47 | function = model[0] 48 | inputs = [model[1]] 49 | elif len(model) == 3: 50 | function = model[1] 51 | inputs = [model[0], model[2]] 52 | 53 | operator = Operator(function) 54 | for j in range(len(inputs)): 55 | if isinstance(inputs[j], list): 56 | inputs[j] = self.execute(inputs[j]) 57 | return operator(inputs) 58 | 59 | def contains(r1, r2): 60 | i1, f1 = r1 61 | i2, f2 = r2 62 | return i1 < i2 and f1 > f2 63 | 64 | def combine(strings): 65 | string = '' 66 | for i in range(len(strings)): 67 | string += strings[i] 68 | return string 69 | 70 | def revise(statement): 71 | strings = [] 72 | string = '' 73 | statement += ' ' 74 | for i in range(len(statement)): 75 | char = statement[i] 76 | 77 | if char == ' ': 78 | if len(string) > 0: 79 | strings.append(string) 80 | string = '' 81 | else: 82 | string += char 83 | return strings 84 | 85 | def merge(sets): 86 | outputs = [] 87 | for i in range(len(sets[0])): 88 | labels = [] 89 | for j in range(len(sets)): 90 | label = sets[j][i] 91 | if label != None: 92 | labels.append(label) 93 | output = None 94 | if len(labels) > 0: 95 | output = labels[0] 96 | outputs.append(output) 97 | return outputs 98 | 99 | def assign_labels(statement, symbols, label): 100 | markers = [] 101 | for i in range(len(statement)): 102 | marker = None 103 | char = statement[i] 104 | if char in symbols: 105 | marker = label 106 | markers.append(marker) 107 | return markers 108 | 109 | def combine_elements(statement, markers, rules): 110 | pc = '' 111 | pm = 'none' 112 | string = '' 113 | labels = [] 114 | strings = [] 115 | for i in range(len(statement)): 116 | m = markers[i] 117 | c = statement[i] 118 | if (pm, m) in rules: 119 | string += c 120 | elif len(string) > 0: 121 | strings.append(string) 122 | labels.append(pm) 123 | string = c 124 | pc = c 125 | pm = m 126 | return strings 127 | 128 | def convert_objects(objects, memory): 129 | elements = [] 130 | for i in range(len(objects)): 131 | symbol = objects[i] 132 | elements.append(memory.get(symbol)) 133 | return elements 134 | 135 | def define_boundaries(elements): 136 | indices = [] 137 | markers = [] 138 | boundaries = [] 139 | for i in range(len(elements)): 140 | data = elements[i]['value'] 141 | if isinstance(data, Marker) and data['label'] != 'end': 142 | if data['label'] == 'open': 143 | indices.append(i) 144 | markers.append(data['label']) 145 | 146 | elif data['label'] == 'close': 147 | pm = markers[len(markers)-1] 148 | if pm == 'open': 149 | pi = indices[len(indices)-1] 150 | boundaries.append((pi, i)) 151 | del indices[len(indices)-1] 152 | del markers[len(markers)-1] 153 | else: 154 | boundaries.append((i, i)) 155 | return boundaries 156 | 157 | def assign_containers(boundaries): 158 | containers = [] 159 | for i in range(len(boundaries)): 160 | containers.append([]) 161 | for j in range(len(boundaries)): 162 | range1 = boundaries[i] 163 | range2 = boundaries[j] 164 | if contains(range1, range2): 165 | containers[i].append((j)) 166 | 167 | for i in range(len(containers)): 168 | indices = containers[i] 169 | for j in range(len(indices)): 170 | for k in range(len(indices)): 171 | child = indices[j] 172 | if indices[k] in containers[child]: 173 | indices[k] = None 174 | containers[i] = indices 175 | 176 | for i in range(len(containers)): 177 | indices = [] 178 | for j in range(len(containers[i])): 179 | if containers[i][j] != None: 180 | indices.append(containers[i][j]) 181 | containers[i] = indices 182 | return containers 183 | 184 | def generate(boundaries, containers, objects, index=None): 185 | if index == None: 186 | index = len(containers)-1 187 | if len(containers[index]) != 0: 188 | outputs = [] 189 | for i in range(len(containers[index])): 190 | child = containers[index][i] 191 | outputs.append(generate(boundaries, containers, objects, child)) 192 | return outputs 193 | else: 194 | i,f = boundaries[index] 195 | if i == f: 196 | return objects[i]['value'] 197 | else: 198 | for j in range(i, f): 199 | if isinstance(objects[j], Marker) == False: 200 | outputs.append(objects[j]['value']) -------------------------------------------------------------------------------- /expresol/__init__.py: -------------------------------------------------------------------------------- 1 | from .Memory import Memory 2 | from .Parser import Parser 3 | from .Data import Marker, Operator 4 | 5 | def TRUE(X): 6 | if len(X) != 1:raise Exception() 7 | return X[0] == True 8 | def FALSE(X): 9 | if len(X) != 1:raise Exception() 10 | return X[0] == False 11 | def NOT(X): 12 | if len(X) != 1:raise Exception() 13 | return not X[0] 14 | def AND(X): 15 | if len(X) != 2:raise Exception() 16 | return X[0] and X[1] 17 | def OR(X): 18 | if len(X) != 2:raise Exception() 19 | return X[0] or X[1] 20 | def EQ(X): 21 | if len(X) != 2:raise Exception() 22 | return X[0] == X[1] 23 | def MT(X): 24 | if len(X) != 2:raise Exception() 25 | return X[0] > X[1] 26 | def LT(X): 27 | if len(X) != 2:raise Exception() 28 | return X[0] < X[1] 29 | def ADD(X): 30 | if len(X) != 2:raise Exception() 31 | return X[0] + X[1] 32 | def SUB(X): 33 | if len(X) != 2:raise Exception() 34 | return X[0] - X[1] 35 | def MULT(X): 36 | if len(X) != 2:raise Exception() 37 | return X[0] * X[1] 38 | def DIV(X): 39 | if len(X) != 2:raise Exception() 40 | return X[0] / X[1] 41 | def LEN(X): 42 | if len(X) != 1: raise Exception() 43 | return len(X[0]) 44 | def ID(X): 45 | if len(X) != 1: raise Exception() 46 | return X[0] 47 | def GET(X): 48 | if len(X) != 2: raise Exception() 49 | return X[0][X[1]] 50 | def SET(X): 51 | if len(X) != 3: raise Exception() 52 | X[0][X[1]] = X[2] 53 | def CALL(X): 54 | if len(X) != 2: raise Exception() 55 | return X[0](X[1]) -------------------------------------------------------------------------------- /readme.MD: -------------------------------------------------------------------------------- 1 | # expresol 2 | 3 | Expresol is a library for executing customizable script-languages in python. The expresol library contains two main components, the memory and the parser, which collectively work as an information system whose data is accessible via statements that manipulate stored variables when executed. Each statement is converted to an executable form containing hierarchical sets of operators and data. Each set contains a set of elements, corresponding to either variables or operators. The most common possible structure of a valid statement is as follows: 4 | 5 | (a + b) 6 | 7 | containing three elements, 'a', '+' and 'b', where the middle element denotes an operator and the rest denote variables. 8 | 9 | The second possible structure is: 10 | 11 | (~ a) 12 | 13 | containing two elements, '~' and 'a', where The left symbol denotes an operator and the right denotes a variable. 14 | 15 | The last possible structure is: 16 | 17 | (a) 18 | 19 | where 'a' denotes a variable. The identity function is assigned by default if no operator is present, meaning the output of this statement simply returns the value of 'a'. 20 | 21 | --- 22 | 23 | ## Example 24 | 25 | - Import library and create memory with 10 elements 26 | 27 | from expresol import * 28 | memory = Memory(10) 29 | 30 | - Store functions, data, and syntax markers in memory 31 | 32 | memory.var(0, Marker('open')) 33 | memory.var(1, Marker('close')) 34 | memory.var(2, Marker('end')) 35 | memory.var(3, AND) 36 | memory.var(4, True) 37 | memory.var(5, True) 38 | 39 | - Assign symbols to elements that allow data to be accessed when observed in a statement 40 | 41 | memory.ref(0, '(', 'grammar') 42 | memory.ref(1, ')', 'grammar') 43 | memory.ref(2, ';', 'grammar') 44 | memory.ref(3, '&', 'operator') 45 | memory.ref(4, 'x1', 'data') 46 | memory.ref(5, 'x2', 'data') 47 | 48 | - Create parser and store data types with characters that are used to form valid symbols for instances of each type 49 | 50 | parser = Parser() 51 | parser.type('grammar', '();') 52 | parser.type('operator', '&|!+-*/=') 53 | parser.type('number', '1234567890') 54 | parser.type('data', 'abcdefghijklmnopqrstuvwxyz') 55 | 56 | - Store pairs of data types that reflect the valid transitions between consecutive elements in a statement 57 | 58 | parser.rule('operator','operator') 59 | parser.rule('grammar','none') 60 | parser.rule('none','grammar') 61 | parser.rule('data','number') 62 | parser.rule('data','data') 63 | 64 | - Define and execute statement 65 | 66 | statement = "(x1 & x2);" 67 | output = parser(statement, memory) 68 | 69 | __OUTPUT:__ `True` 70 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | setup(name='expresol', 4 | version='0.1', 5 | description='description', 6 | url='http://github.com/carsonscott/expresol', 7 | author='Carson Scott', 8 | author_email='carsonjscott14@gmail.com', 9 | license='MIT', 10 | packages=['expresol'], 11 | zip_safe=False) --------------------------------------------------------------------------------