####################################################################################################
#
# PySpice - A Spice Package for Python
# Copyright (C) 2017 Fabrice Salvaire
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
####################################################################################################
"""This module implements Abstract Syntactic Tree for Spice expressions.
"""
####################################################################################################
import logging
import os
####################################################################################################
_module_logger = logging.getLogger(__name__)
####################################################################################################
[docs]class StatementList:
##############################################
def __init__(self, *statements):
self._statements = list(statements)
##############################################
def __nonzero__(self):
return bool(self._statements)
##############################################
def __iter__(self):
return iter(self._statements)
##############################################
[docs] def add(self, statement):
self._statements.append(statement)
##############################################
def __str__(self):
return os.linesep.join([str(statement) for statement in self])
####################################################################################################
[docs]class Program(StatementList):
pass
####################################################################################################
[docs]class Variable:
##############################################
def __init__(self, name):
self._name = name
##############################################
@property
def name(self):
return self._name
##############################################
def __str__(self):
return self._name
####################################################################################################
[docs]class Constant:
##############################################
def __init__(self, value):
self._value = value
##############################################
def __str__(self):
return str(self._value)
####################################################################################################
[docs]class IntConstant(Constant):
##############################################
def __int__(self):
return self._value
####################################################################################################
[docs]class FloatConstant(Constant):
##############################################
def __float__(self):
return self._value
####################################################################################################
[docs]class Expression:
NUMBER_OF_OPERANDS = None
##############################################
def __init__(self, *args, **kwargs):
if (self.NUMBER_OF_OPERANDS is not None
and len(args) != self.NUMBER_OF_OPERANDS):
raise ValueError("Wrong number of operands")
self._operands = args
##############################################
[docs] def iter_on_operands(self):
return iter(self._operands)
##############################################
@property
def operand(self):
return self._operands[0]
@property
def operand1(self):
return self._operands[0]
@property
def operand2(self):
return self._operands[1]
@property
def operand3(self):
return self._operands[2]
[docs]class UnaryExpression(Expression):
NUMBER_OF_OPERANDS = 1
[docs]class BinaryExpression(Expression):
NUMBER_OF_OPERANDS = 2
[docs]class TernaryExpression(Expression):
NUMBER_OF_OPERANDS = 3
####################################################################################################
####################################################################################################
[docs]class OperatorMixin(metaclass=OperatorMetaclass):
OPERATOR = None
_declaration_order = 0
####################################################################################################
[docs]class UnaryOperator(UnaryExpression, OperatorMixin):
def __str__(self):
return ' '.join((self.OPERATOR, str(self.operand1)))
####################################################################################################
[docs]class BinaryOperator(BinaryExpression, OperatorMixin):
def __str__(self):
return ' '.join((str(self.operand1), self.OPERATOR, str(self.operand2)))
####################################################################################################
[docs]class Assignation(BinaryExpression):
@property
def variable(self):
return self._operands[1]
@property
def value(self):
return self._operands[0]
def __str__(self):
return ' '.join((str(self.destination), '=', str(self.value)))
####################################################################################################
[docs]class Negation(UnaryOperator):
OPERATOR = '-'
PRECEDENCE = 1
[docs]class Not(UnaryOperator):
OPERATOR = '!'
PRECEDENCE = 1
####################################################################################################
[docs]class power(BinaryOperator):
OPERATOR = '**'
PRECEDENCE = 2
[docs]class Multiplication(BinaryOperator):
OPERATOR = '*'
PRECEDENCE = 3
[docs]class Division(BinaryOperator):
OPERATOR = '/'
PRECEDENCE = 3
[docs]class Modulo(BinaryOperator):
OPERATOR = '%'
PRECEDENCE = 3
[docs]class IntegerDivision(BinaryOperator):
OPERATOR = '\\'
PRECEDENCE = 3
[docs]class Addition(BinaryOperator):
OPERATOR = '+'
PRECEDENCE = 4
[docs]class Subtraction(BinaryOperator):
OPERATOR = '-'
PRECEDENCE = 4
####################################################################################################
[docs]class Equal(BinaryOperator):
OPERATOR = '=='
PRECEDENCE = 5
[docs]class NotEqual(BinaryOperator):
OPERATOR = '!='
PRECEDENCE = 5
[docs]class LessEqual(BinaryOperator):
OPERATOR = '<='
[docs]class GreaterEqual(BinaryOperator):
OPERATOR = '>='
PRECEDENCE = 5
[docs]class Less(BinaryOperator):
OPERATOR = '<'
PRECEDENCE = 5
[docs]class Greater(BinaryOperator):
OPERATOR = '>'
PRECEDENCE = 5
####################################################################################################
[docs]class And(BinaryOperator):
OPERATOR = '&&'
PRECEDENCE = 6
[docs]class Or(BinaryOperator):
OPERATOR = '||'
PRECEDENCE = 7
####################################################################################################
[docs]class If: #(TernaryExpression)
# c ? x : y
PRECEDENCE = 8
##############################################
def __init__(self, condition, then_expression, else_expression):
self._condition = condition
self._then_expression = then_expression
self._else_expression = else_expression
##############################################
@property
def condition(self):
return self._condition
##############################################
@property
def then_expression(self):
return self._then_expression
##############################################
@property
def else_expression(self):
return self._else_expression
##############################################
# def _str_compound_expression(self, expressions):
# string = '(' + os.linesep
# if expressions:
# string += str(expressions) + os.linesep
# string += ')'
# return string
##############################################
def __str__(self):
return '{} ? {} : {}'.format(self._condition, self._then_expression, self._else_expression)
####################################################################################################
[docs]class Function(Expression):
##############################################
def __init__(self, name, *args):
super(Function, self).__init__(*args)
self._name = name
##############################################
@property
def name(self):
return self._name
##############################################
def __str__(self):
parameters = ', '.join([str(operand) for operand in self.iter_on_operands()])
return self._name + ' (' + parameters + ')'