diff options
author | Daniel Weipert <git@mail.dweipert.de> | 2024-07-08 15:03:42 +0200 |
---|---|---|
committer | Daniel Weipert <git@mail.dweipert.de> | 2024-07-08 15:03:42 +0200 |
commit | b858cc223a936a522bb5f88065f6686489841955 (patch) | |
tree | abc50b990c0e73bcc8f79c7b394451bd12ad4b9e | |
parent | c96a938727ef0f7864bf99d767ed1ae2f5e7040c (diff) |
array and map
-rwxr-xr-x | henshin | 189 | ||||
-rw-r--r-- | test/test.test | 10 |
2 files changed, 176 insertions, 23 deletions
@@ -37,6 +37,9 @@ log = logging.getLogger() + + + # Lexer reserved = { @@ -51,6 +54,9 @@ reserved = { "integer": "TYPE_INTEGER", "string": "TYPE_STRING", "void": "TYPE_VOID", + + "and": "AND", + "or": "OR", } tokens = [ @@ -72,12 +78,6 @@ tokens = [ "BRACKET_RIGHT", - "AND", - "OR", - "BIT_AND", - "BIT_OR", - - "NAMESPACE_ACCESSOR", @@ -93,6 +93,7 @@ tokens = [ ] + list(reserved.values()) + t_OPERATOR_PLUS = r'\+' t_OPERATOR_MINUS = r'-' t_OPERATOR_MULTIPLY = r'\*' @@ -111,12 +112,6 @@ t_BRACE_LEFT = r'{' t_BRACE_RIGHT = r'}' -t_AND = r'\&\&' -t_OR = r'\|\|' -t_BIT_AND = r'\&' -t_BIT_OR = r'\|' - - t_NAMESPACE_ACCESSOR = r'\.' @@ -125,6 +120,7 @@ t_COLON = r':' t_SEMICOLON = r';' + def t_IDENTIFIER(t): r'[a-zA-Z][a-zA-Z0-9_]*' @@ -140,7 +136,7 @@ def t_NUMBER(t): return t def t_STRING(t): - r'(".+"|\'.*\')' + r'(".*?")' return t @@ -157,6 +153,7 @@ def t_newline(t): t_ignore = ' \t' + def t_error(t): print("undefined: '%s'" % t.value[0]) t.lexer.skip(1) @@ -171,18 +168,23 @@ for token in lexer: lineno = token.lineno print("\nLine %s:" % token.lineno) - # print('%s: "%s" --' % (token.type, token.value), end=' ') - print(token.value, end=' ') + print('%s: "%s" --' % (token.type, token.value), end=' ') + # print(token.value, end=' ') print("\n") + + + # Parser class AstNodeExpressionType(Enum): IDENTIFIER = 'identifier' NUMBER = 'number' STRING = 'string' + ARRAY = 'array' + MAP = 'map' class AstNode: pass @@ -198,6 +200,27 @@ class AstNodeVariableReassignmentStatement(AstNode): self.name = name self.value = value +class AstNodeVariableTypes(AstNode): + def __init__(self, operator, left, right): + self.operator = operator + self.left = left + self.right = right + +class AstNodeVariableTypeArray(AstNode): + def __init__(self, type, length): + self.type = type + self.length = length + +class AstNodeVariableTypeMap(AstNode): + def __init__(self, key_type, value_type): + self.key_type = key_type + self.value_type = value_type + +class AstNodeMapElement(AstNode): + def __init__(self, key, value): + self.key = key + self.value = value + class AstNodeExpression(AstNode): def __init__(self, type, value): self.type = type @@ -236,12 +259,16 @@ class AstNodeFunctionCallParameter(AstNode): self.value = value + precedence = ( ('left', 'OPERATOR_PLUS', 'OPERATOR_MINUS'), ('left', 'OPERATOR_MULTIPLY', 'OPERATOR_DIVIDE'), + ('left', 'OR', 'OR'), + ('left', 'AND', 'AND'), ) + def p_statements(p): '''statements : statement | statement statements''' @@ -275,114 +302,219 @@ def p_statements(p): statements.extend(p[2]) p[0] = statements + def p_statement(p): '''statement : variable_declaration_statement | variable_reassignment_statement | function_declaration + | function_call | return_statement''' p[0] = p[1] + + def p_function_declaration(p): '''function_declaration : FUNCTION IDENTIFIER PARENTHESIS_LEFT function_declaration_parameters PARENTHESIS_RIGHT COLON return_type BRACE_LEFT statements BRACE_RIGHT''' p[0] = AstNodeFunctionDeclaration(p[2], p[4], p[7], p[9]) + def p_function_declaration_parameters(p): '''function_declaration_parameters : function_declaration_parameter COMMA function_declaration_parameters + | function_declaration_parameter COMMA | function_declaration_parameter |''' parameters = [p[1]] - if len(p) > 2: - parameters.append(p[3]) + if len(p) == 4: + parameters.extend(p[3]) p[0] = parameters + def p_function_declaration_parameter(p): '''function_declaration_parameter : IDENTIFIER COLON variable_type''' p[0] = AstNodeFunctionDeclarationParameter(p[1], p[3]) + + def p_function_call(p): '''function_call : IDENTIFIER PARENTHESIS_LEFT function_call_parameters PARENTHESIS_RIGHT SEMICOLON''' p[0] = AstNodeFunctionCall(p[1], p[3]) + def p_function_call_parameters(p): '''function_call_parameters : function_call_parameter COMMA function_call_parameters + | function_call_parameter COMMA | function_call_parameter |''' parameters = [p[1]] - if len(p) > 2: - parameters.append(p[3]) + if len(p) == 4: + parameters.extend(p[3]) p[0] = parameters + def p_function_call_parameter(p): '''function_call_parameter : IDENTIFIER ASSIGN expression | expression''' - if len(p) > 2: + if len(p) == 4: p[0] = AstNodeFunctionCallParameter(p[1], p[3]) else: p[0] = AstNodeFunctionCallParameter("", p[1]) + + def p_variable_declaration_statement(p): '''variable_declaration_statement : variable_declarator IDENTIFIER COLON variable_type ASSIGN expression SEMICOLON''' p[0] = AstNodeVariableDeclarationStatement(p[1], p[2], p[4], p[6]) + def p_variable_reassignment_statement(p): '''variable_reassignment_statement : IDENTIFIER ASSIGN expression SEMICOLON''' p[0] = AstNodeVariableReassignmentStatement(p[1], p[3]) + def p_variable_declarator(p): '''variable_declarator : CONST | VAR''' p[0] = p[1] + def p_variable_type(p): - '''variable_type : TYPE_INTEGER + '''variable_type : variable_type_array + | variable_type_map + | TYPE_INTEGER | TYPE_STRING''' p[0] = p[1] +def p_variable_types(p): + '''variable_types : variable_type OR variable_types + | variable_type''' + + if len(p) == 4: + p[0] = AstNodeVariableTypes(p[2], p[1], p[3]) + else: + p[0] = p[1] + + +def p_variable_type_array(p): + '''variable_type_array : BRACKET_LEFT variable_types BRACKET_RIGHT BRACKET_LEFT NUMBER BRACKET_RIGHT''' + + p[0] = AstNodeVariableTypeArray(p[2], p[5]) + + +def p_variable_type_map(p): + '''variable_type_map : BRACKET_LEFT variable_types BRACKET_RIGHT BRACKET_LEFT variable_types BRACKET_RIGHT''' + + p[0] = AstNodeVariableTypeMap(p[2], p[5]) + + + def p_return_statement(p): '''return_statement : RETURN expression SEMICOLON''' p[0] = AstNodeReturnStatement(p[2]) + def p_return_type(p): '''return_type : variable_type | TYPE_VOID''' p[0] = p[1] + + def p_identifier(p): '''identifier : IDENTIFIER''' p[0] = AstNodeExpression(AstNodeExpressionType.IDENTIFIER, p[1]) + def p_number(p): '''number : NUMBER''' p[0] = AstNodeExpression(AstNodeExpressionType.NUMBER, p[1]) + def p_string(p): '''string : STRING''' p[0] = AstNodeExpression(AstNodeExpressionType.STRING, p[1]) + +def p_array(p): + '''array : BRACKET_LEFT array_elements BRACKET_RIGHT''' + + p[0] = AstNodeExpression(AstNodeExpressionType.ARRAY, p[2]) + + +def p_array_elements(p): + '''array_elements : array_element COMMA array_elements + | array_element COMMA + | array_element''' + + elements = [p[1]] + if len(p) == 4: + elements.extend(p[3]) + + p[0] = elements + + +def p_array_element(p): + '''array_element : expression''' + + p[0] = p[1] + + +def p_map(p): + '''map : BRACKET_LEFT map_elements BRACKET_RIGHT''' + + p[0] = AstNodeExpression(AstNodeExpressionType.MAP, p[2]) + + +def p_map_elements(p): + '''map_elements : map_element COMMA map_elements + | map_element COMMA + | map_element''' + + elements = [p[1]] + if len(p) == 4: + elements.extend(p[3]) + + p[0] = elements + + +def p_map_element(p): + '''map_element : map_element_key COLON expression''' + + p[0] = AstNodeMapElement(p[1], p[3]) + +def p_map_element_key(p): + '''map_element_key : identifier + | number + | string''' + + p[0] = p[1] + + def p_expression(p): '''expression : identifier | number | string + | array + | map | function_call | expression OPERATOR_PLUS expression | expression OPERATOR_MINUS expression @@ -395,13 +527,26 @@ def p_expression(p): p[0] = p[1] + + def p_error(p): print("Syntax error in input!", p) + + parser = yacc.yacc(debug=True, debuglog=log) result = parser.parse(input) -# print(result) + + + + +if result: + for ast_node in result: + print(ast_node) + + + # if __name__ == "__main__": # lex.runmain() diff --git a/test/test.test b/test/test.test index 2ffe743..af1bf76 100644 --- a/test/test.test +++ b/test/test.test @@ -14,4 +14,12 @@ function main(input: string): void { return hello; } -main(test); +main(input = "hello!"); + +const array: [integer][3] = [1, 2, 3]; +const map: [string][string or integer] = [ + "first": 1, + "second": "two", + "third": "3", + "fourth": 4, +]; |