#include "Parser.h"
#include "iostream"

Parser::Parser(vector<Token> tokens)
{
    error_message = "***ERRORS DURING PARSING***\n";
    report_message = "***PARSER REPORT***\n";
    token_stream = tokens;
    position_in_stream = 0;
    read_next();
}

Parser::~Parser()
{
    //dtor
}

void Parser::report(string s)
{
    report_message += s ;
}

void Parser::error(string s)
{
    error_message += s ;
}

bool Parser::read_next()
{
    if(position_in_stream < token_stream.size())
    {
        current_token = token_stream[position_in_stream];
        tok_value = current_token.get_value();
        position_in_stream++;
        return true;
    }
    else
    {
        current_token = Token(t_invalid_token, "");
        tok_value = current_token.get_value();
        return false;
    }
}

void Parser::interpret()
{
    while(tok_value!= "")
    {
        if(is_type())
        {
            report("Identifier: " + tok_value + "\n");
            read_next();

            if(accept("="))
            {
                expr();
                report(" :=\n");
            }
            if(accept(";"))
            {
                report("Variable definition\n");
                continue;
            }

            expect("(");
            int argc = 0;
            while(true)
            {
                argc++;
                is_type();
                report("function argument: " + tok_value + "\n");
                read_next();
                if(peek(")"))
                {
                    break;
                }
                expect(",");
            }
            expect(")");

            if(!accept(";"))
            {
                report("function body:\n");
                statement();
            }
        }

        else {
            report("Regular statement:\n");
            statement();
        }
    }
}

bool Parser::peek(string s)
{
    return tok_value == s;
}

bool Parser::accept(string s)
{
    if(peek(s))
    {
        read_next();
        return true;
    }
    else return false;
}

bool Parser::expect(string s)
{
    if(!accept(s))
    {
        string error_message = "Error: expected ";
        error_message += s;
        error_message += " but received: " + tok_value + "\n";

        error(error_message);
        return false;
    }
    else return true;
}

bool Parser::is_type()
{
    if(current_token.get_type() == t_symbol || current_token.get_type() == t_keyword)
    {
        if(tok_value == "def" || tok_value == "string" || tok_value == "num")
        {
            read_next();
            return true;
        }
        else return false;

    }
    else return false;
}

void Parser::statement()
{
    if(accept("{"))
    {
         while(!accept("}"))
         {
             statement();
         }
    }
    else if(is_type())
    {
        report("Local variable: " + tok_value + "\n");
        read_next();
        if(accept("="))
        {
            expr();
            report(" :=\n");
        }
        expect(";");
    }
    else if(accept("if"))
    {
        //stuff
        //TODO implement that
    }
    else if(accept("while"))
    {
        //similar stuff
    }
    else if(accept("return"))
    {

        if(!peek(";"))
        {
            expr();
        }
        expect(";");
        report("RETURN\n");

    }
    else
    {
        expr();
        while(!expect(";")) read_next();

    }
}

void Parser::prim_expr()
{
    if(current_token.get_type() == t_integer)
    {
        report("Number: " + tok_value + "\n");
    }
    else if(current_token.get_type() == t_symbol)
    {
        report("Variable: " + tok_value + "\n");
    }
    else if(current_token.get_type() == t_literal)
    {
        report("Character literal: " + tok_value + "\n");
    }
    else if(accept("("))
    {
        expr();
        expect(")");
    }
    else
    {
        error("ERROR: unexpected primary expression" + tok_value + "\n");

    }
    read_next();
}

void Parser::postfix_expr()
{
    prim_expr();
    if(accept("["))
    {
       expr();
       expect("]");
       report(" [] ");

    }
    else if(accept("("))
    {
        if(!accept(")"))
        {
            expr();
            report("function argument\n");
            while(accept(","))
            {
                expr();
                report("function argument\n");
            }
            expect(")");
        }
        report("FUNC_CALL\n");
    }
}

void Parser::add_expr()
{
    postfix_expr();
    while(peek("+") || peek("-"))
    {
        if(accept("+"))
        {
            postfix_expr();
            report(" +\n");
        } else if(accept("-"))
        {
            postfix_expr();
            report(" -\n");
        }
    }
}

void Parser::rel_expr()
{
    add_expr();
    while(peek("<"))
    {
        accept("<");
        add_expr();
        report(" <\n");
    }
}

void Parser::eq_expr()
{
    rel_expr();
    while(peek("==") || peek("!="))
    {
        if(accept("=="))
        {
            rel_expr();
            report("==\n");
        }
        else if(accept("!="))
        {
            rel_expr();
            report("!=\n");
        }
    }
}

void Parser::expr()
{
    eq_expr();
    if(accept("="))
    {
        expr();
        report(" := ");
    }
}
