from __future__ import print_function
from ply import lex, yacc


reserved_list = [
    'begin',
    'end',
    'parameters',
    'molecule_types',
    'species',
    'reaction_rules',
    'observables',
    ]
reserved = dict((r, r.upper()) for r in reserved_list)

tokens = [
    'ID',
    
    'FLOAT',
    'INTEGER',

    'COMMA',
    'PLUS',
    'TILDE',
    'EXCLAMATION',
    'QUESTION',
    'PERIOD',
    'IRRARROW',
    'REVARROW',
    'LPAREN',
    'RPAREN',
    'NEWLINE',
    ] + list(reserved.values())

t_COMMA       = r','
t_PLUS        = r'\+'
t_TILDE       = r'~'
t_EXCLAMATION = '!'
t_QUESTION    = '\?'
t_PERIOD      = '\.'
t_IRRARROW    = r'-->'
t_REVARROW    = r'<->'
t_LPAREN      = r'\('
t_RPAREN      = r'\)'

# Define a rule so we can track line numbers
def t_NEWLINE(t):
    r'\n'
    t.lexer.lineno += 1
    return t

def t_FLOAT(t):
    r'[+-]?(\d*\.\d+([eE][+-]?\d+)?|\d+[eE][+-]?\d+)'
    try:
        t.value = float(t.value)    
    except ValueError:
        print("Line %d: Number '%s' has some kind of problem (ValueError)!" % (t.lineno,t.value))
        t.value = float("nan")
    return t

def t_INTEGER(t):
    r'\d+'
    try:
        t.value = int(t.value)    
    except ValueError:
        print("Line %d: Number '%s' has some kind of problem (ValueError)!" % (t.lineno,t.value))
        t.value = 0
    return t

def t_ID(t):
    r'[a-zA-Z_][a-zA-Z_0-9]*'
    t.type = reserved.get(t.value,'ID')  # check for reserved words
    return t

# Match and ignore comments (# to end of line)
def t_comment(t):
    r'\#[^\n]*'

# A string containing ignored characters (spaces and tabs)
t_ignore  = ' \t'

# Error handling rule
def t_error(t):
    print("Illegal character '%s' on line %d" % (t.value[0], t.lineno))
    t.lexer.skip(1)



#from toymodels import Model, Species, RuleReversible, RuleIrreversible


def list_helper(p):
    if len(p) == 1:
        p[0] = []
    if len(p) == 2:
        p[0] = [p[1]]
    elif len(p) == 3:
        p[0] = p[1] + [p[2]]
    p[0] = [v for v in p[0] if v != None] # filter out Nones


def p_model(p):
    'model : block_list'
    p[0] = p[1]
    print("model:", p[0])

def p_block_list(p):
    '''block_list : block_list block
                  | block'''
    list_helper(p)