From ad9c8bc0746f7219d525d8a11db2e1c6e9fb8e20 Mon Sep 17 00:00:00 2001 From: Iaroslav Zeigerman Date: Sat, 12 Jan 2019 18:36:49 -0800 Subject: [PATCH] First commit --- .gitignore | 3 ++ LICENSE | 21 +++++++++ README.md | 0 m2cgen/__init__.py | 0 m2cgen/ast.py | 84 ++++++++++++++++++++++++++++++++++ m2cgen/interpreter/__init__.py | 0 m2cgen/interpreter/base.py | 35 ++++++++++++++ m2cgen/interpreter/basic.py | 19 ++++++++ requirements.txt | 3 ++ 9 files changed, 165 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 m2cgen/__init__.py create mode 100644 m2cgen/ast.py create mode 100644 m2cgen/interpreter/__init__.py create mode 100644 m2cgen/interpreter/base.py create mode 100644 m2cgen/interpreter/basic.py create mode 100644 requirements.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..a9f60d66 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.idea +**/__pycache__ +**/*.pyc diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..70504daa --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2019 Iaroslav Zeigerman + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 00000000..e69de29b diff --git a/m2cgen/__init__.py b/m2cgen/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/m2cgen/ast.py b/m2cgen/ast.py new file mode 100644 index 00000000..99339fb5 --- /dev/null +++ b/m2cgen/ast.py @@ -0,0 +1,84 @@ +from enum import Enum + + +class Expr: + pass + + +class FeatureRef(Expr): + def __init__(self, index): + self.index = index + + +# Numeric Expressions. + +class NumExpr(Expr): + pass + + +class NumVal(NumExpr): + def __init__(self, value): + self.value = value + + +class BinNumOpType(Enum): + ADD = 0 + SUB = 1 + MUL = 2 + DIV = 3 + + +class BinNumExpr(NumExpr): + def __init__(self, left, right, op): + self.left = left + self.right = right + self.op = op + + +# Boolean Expressions. + +class BoolExpr(Expr): + pass + + +class BoolValue(BoolExpr): + def __init__(self, value): + self.value = value + + +class BinBoolOpType(Enum): + GT = 0 + GTE = 1 + LT = 2 + LTE = 3 + EQ = 4 + + +class BinBoolExpr(BoolExpr): + def __init__(self, left, right, op): + self.left = left + self.right = right + self.op = op + + +class UnaryBoolOpType(Enum): + NOT = 0 + + +class UnaryBoolExpr(BoolExpr): + def __init__(self, expr, op): + self.expr = expr + self.op = op + + +# Control Expressions. + +class CtrlExpr(Expr): + pass + + +class IfExpr(CtrlExpr): + def __init__(self, test, body, orelse): + self.test = test + self.body = body + self.orelse = orelse diff --git a/m2cgen/interpreter/__init__.py b/m2cgen/interpreter/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/m2cgen/interpreter/base.py b/m2cgen/interpreter/base.py new file mode 100644 index 00000000..7d630818 --- /dev/null +++ b/m2cgen/interpreter/base.py @@ -0,0 +1,35 @@ +import re +from m2cgen.ast import NumExpr, BoolExpr, CtrlExpr + + +class BaseInterpreter: + + def interpret(self, expr): + return self._do_interpret(expr) + + def _do_interpret(self, expr): + handler = self._select_handler(expr, (NumExpr, BoolExpr, CtrlExpr)) + return handler(expr) + + def _select_handler(self, expr, fallback_tpes): + handler_name = self._handler_name(type(expr)) + if hasattr(self, handler_name): + return getattr(self, handler_name) + + for expr_tpe in fallback_tpes: + if isinstance(expr, expr_tpe): + handler_name = self._handler_name(expr_tpe) + if hasattr(self, handler_name): + return getattr(self, handler_name) + + raise NotImplementedError( + 'No handler found for {}'.format(type(expr).__name__)) + + @staticmethod + def _handler_name(expr_tpe): + expr_name = BaseInterpreter._normalize_expr_name(expr_tpe.__name__) + return 'interpret_' + expr_name + + @staticmethod + def _normalize_expr_name(name): + return re.sub('(?!^)([A-Z]+)', r'_\1', name).lower() diff --git a/m2cgen/interpreter/basic.py b/m2cgen/interpreter/basic.py new file mode 100644 index 00000000..066f3df0 --- /dev/null +++ b/m2cgen/interpreter/basic.py @@ -0,0 +1,19 @@ +from m2cgen.interpreter.base import BaseInterpreter +from m2cgen.ast import BinNumOpType + + +class BasicInterpreter(BaseInterpreter): + + def interpret_num_val(self, expr): + return expr.value + + def interpret_bin_num_expr(self, expr): + left_val = self._do_interpret(expr.left) + right_val = self._do_interpret(expr.right) + ops = { + BinNumOpType.ADD: lambda x, y: x + y, + BinNumOpType.SUB: lambda x, y: x - y, + BinNumOpType.MUL: lambda x, y: x * y, + BinNumOpType.DIV: lambda x, y: x / y, + } + return ops[expr.op](left_val, right_val) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..d9c3157f --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +numpy==1.15.1 +scipy==1.1.0 +scikit-learn==0.19.2