summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xhenshin126
-rw-r--r--test/test.test7
2 files changed, 117 insertions, 16 deletions
diff --git a/henshin b/henshin
index da03c62..44ba911 100755
--- a/henshin
+++ b/henshin
@@ -7,6 +7,7 @@ import logging
import ply.lex as lex
import ply.yacc as yacc
from enum import Enum
+import collections.abc
@@ -674,6 +675,7 @@ result = parser.parse(input)
variables = {
"print": print,
}
+types = {}
def is_statement(statement):
@@ -705,6 +707,51 @@ def to_parameters_dict(parameters, context):
return dictionary
+def merge_dict(dict1, dict2):
+ for key, val in dict1.items():
+ if type(val) == dict:
+ if key in dict2 and type(dict2[key] == dict):
+ merge_dict(dict1[key], dict2[key])
+ else:
+ if key in dict2:
+ dict1[key] = dict2[key]
+
+ for key, val in dict2.items():
+ if not key in dict1:
+ dict1[key] = val
+
+ return dict1
+
+def nested_set(dic, keys, value):
+ for key in keys[:-1]:
+ dic = dic.setdefault(key, {})
+ dic[keys[-1]] = value
+
+def update(d, u):
+ for k, v in u.items():
+ if isinstance(v, collections.abc.Mapping):
+ d[k] = update(d.get(k, {}), v)
+ else:
+ d[k] = v
+ return d
+
+
+def get_namespace_path(namespace, context):
+ path = []
+
+ left = evaluate_expression(namespace.left, context | {"NAMESPACE_ACCESS": True})
+ right = evaluate_expression(namespace.right, context | {"NAMESPACE_ACCESS": True})
+
+ if type(left) is list:
+ path.extend(left)
+ else:
+ path.append(left)
+
+ path.append(right)
+
+ return path
+
+
def evaluate_statement(statement, context):
scoped_variables = {}
@@ -712,22 +759,36 @@ def evaluate_statement(statement, context):
if type(statement) is AstNodeVariableDeclarationStatement:
value = evaluate_expression(statement.value, context)
scoped_variables[statement.name] = value
+ types[statement.name] = statement.variable_type
- # variavle reassignment
+ # variable reassignment
elif type(statement) is AstNodeVariableReassignmentStatement:
value = evaluate_expression(statement.value, context)
- if not statement.name in variables:
- print("ERROR: Reassignment on non-existent variable: {variable}".format(variable=statement.name))
+ name = statement.name
+
+ if type(name) is AstNodeNamespaceAccess:
+ namespace_path = get_namespace_path(name, context)
+
+ nested_update = {}
+ nested_set(nested_update, namespace_path, value)
+ scoped_variables = update(context, nested_update)
else:
- scoped_variables[statement.name] = value
+ if not name in context:
+ print("ERROR: Reassignment on non-existent variable: {variable}".format(variable=statement.name))
+ else:
+ scoped_variables[name] = value
# function call
elif type(statement) is AstNodeFunctionCall:
- function = context[statement.name]
+ if type(statement.name) is AstNodeNamespaceAccess:
+ namespace = evaluate_expression(statement.name, context)
+ function = namespace["function"]
+ context["self"] = namespace["self"]
+ else:
+ function = context[statement.name]
# in-built
if callable(function):
- pass
function(*[evaluate_expression(parameter, context) for parameter in statement.parameters])
# else
@@ -760,6 +821,19 @@ def evaluate_statement(statement, context):
scoped_variables = right
+ # namespace access
+ elif type(statement) is AstNodeNamespaceAccess:
+ left = evaluate_expression(statement.left, context)
+ right = evaluate_expression(statement.right, left)
+
+ self = list(context.keys())[list(context.values()).index(left)]
+
+ if type(right) is AstNodeFunctionDeclaration:
+ scoped_variables = {"self": self, "function": right}
+ else:
+ scoped_variables = right
+
+
return scoped_variables
@@ -786,7 +860,12 @@ def evaluate_expression(expression, scoped_variables):
# general expression
elif type(expression) is AstNodeExpression:
if expression.type is AstNodeExpressionType.IDENTIFIER:
- result = scoped_variables[expression.value]
+ if expression.value == "self":
+ result = scoped_variables[scoped_variables["self"]]
+ elif "NAMESPACE_ACCESS" in scoped_variables:
+ result = expression.value
+ else:
+ result = scoped_variables[expression.value]
elif expression.type is AstNodeExpressionType.ARRAY:
result = [evaluate_expression(element.value, scoped_variables) for element in expression.value]
elif expression.type is AstNodeExpressionType.MAP:
@@ -798,26 +877,47 @@ def evaluate_expression(expression, scoped_variables):
# function call / type instantiation
elif type(expression) is AstNodeFunctionCall:
- function = scoped_variables[expression.name]
+ if type(expression.name) is AstNodeNamespaceAccess:
+ namespace = evaluate_expression(expression.name, scoped_variables)
+ function = namespace["function"]
+ scoped_variables["self"] = namespace["self"]
+ else:
+ function = scoped_variables[expression.name]
# function call
if type(function) is AstNodeFunctionDeclaration:
result = evaluate_statement(expression, scoped_variables)
# type instantiation
- elif type(function) is AstNodeTypeDeclaration:
- instance_variables = {}
- for node in function.body:
- instance_variables |= evaluate_statement(node, scoped_variables)
-
+ elif type(function) is dict:
+ instance_variables = evaluate_expression(function, scoped_variables)
result = instance_variables
+ variable_type = types[expression.name]
+ if type(variable_type) is AstNodeVariableTypeType:
+ type_type = evaluate_expression(variable_type.base_type, scoped_variables)
+ result |= type_type
+
# function call parameter
elif type(expression) is AstNodeFunctionCallParameter:
result = evaluate_expression(expression.value, scoped_variables)
if result == "$":
result = scoped_variables["$"]
+ elif type(expression) is AstNodeNamespaceAccess:
+ if "NAMESPACE_ACCESS" in scoped_variables:
+ result = get_namespace_path(expression, scoped_variables)
+ else:
+ result = evaluate_statement(expression, scoped_variables)
+
+ elif type(expression) is AstNodeTypeDeclaration:
+ instance_variables = {}
+ for node in expression.body:
+ instance_variables |= evaluate_statement(node, scoped_variables)
+
+ result = instance_variables
+
+
return result
diff --git a/test/test.test b/test/test.test
index 149f1a6..58be29b 100644
--- a/test/test.test
+++ b/test/test.test
@@ -55,6 +55,7 @@ const inherited_type: type[test_type] = {
}
const object: inherited_type = inherited_type()
-//object.test_field = "hey"
-//object.test_function() => print($)
-//object.nested.another_function(add = 2)
+object.test_field = "hey"
+object.test_function() => print($)
+object.nested.another_field = 5
+object.nested.another_function(add = 2) => print($)