module Parser (parse) where

import Ast
import BasicNumber
import Lexer
import Op

-- parse string to ast
parse :: String -> Ast

parse str = if succ then parser lexeme
		    else SyntaxError
	where
		(lexeme, succ) = lexer str

-- parse lexeme list to ast
parser :: [Lexeme] -> Ast

parser lexeme = if rest == [] then ast else SyntaxError
		where (ast,rest) = parse_command lexeme

-- parse a lexeme list, return an ast and the rest of the lexeme list
parse_command :: [Lexeme] -> (Ast, [Lexeme])
parse_command [] = (NullCmd,[])
parse_command ((Evar evar):(Op "="):bexpr) =
		case bexpr of
		    []              -> (NullCmd,[])
		    (Op "'"):bexpr1 -> ((Set evar ast), rest)
				where (ast,rest) = parse_bexpr bexpr1
		    _          	    -> ((EvalSet evar ast), rest)
				where (ast,rest) = parse_bexpr bexpr
parse_command bexpr = ((Eval ast), rest)
			where
				(ast,rest) = parse_bexpr bexpr

-- parse an expression
parse_bexpr :: [Lexeme] -> (BasicExp, [Lexeme])
parse_bexpr [] = (BSError, [])
parse_bexpr expr = parse_prec 7 expr

parse_prec :: Int -> [Lexeme] -> (BasicExp, [Lexeme])
-- we are now in front of an expression
parse_prec prec rest =
    if prec == 0 then parse_bexpr3 rest
    else
	case rest of
	    ((Op op):rs) -> if opname == "" then (BSError,rest)
			    else parse_op_acum prec sofar r
			    where
				(t,r) = parse_prec ((opPrec1 op)-1) rs
				sofar = Func opname [t]
				opname = opName1 op
	    _		 -> parse_op_acum prec t r
			    where
				(t,r) = parse_prec (prec-1) rest
	where
	    parse_op_acum prec sofar r =
                case r of
                    ((Op op):rs) -> if prec >= opPrec op then
                                	let
                                          (s1,r1) = parse_op op sofar rs
                                        in parse_op_acum prec s1 r1
                        	    else (sofar,r)
                    _            -> (sofar,r)

-- in front of an operator
parse_op :: String -> BasicExp -> [Lexeme] -> (BasicExp, [Lexeme])
parse_op op sofar rest =
    if opname == "" then (BSError, rest)
    else
	if opAssoc op == "right" then
		let (t2,r2) = parse_prec (opPrec op) rest
                in ((Func opname [sofar,t2]), r2)
	else if opAssoc op == "left" then
		parse_left op sofar rest
	     else
	    	parse_non op sofar rest
    where opname = opName op

-- parse operators with no fixity
parse_non :: String -> BasicExp -> [Lexeme] -> (BasicExp, [Lexeme])
parse_non op sofar rest =
	((Func (opName op) [sofar,t2]), r2)
	where
		(t2,r2) = parse_prec ((opPrec op)-1) rest

-- parsing left-associative operators
parse_left :: String -> BasicExp -> [Lexeme] -> (BasicExp, [Lexeme])
parse_left op sofar rest =
	case r1 of
	    ((Op nop):rs) ->
		if (opPrec op) == (opPrec nop) then
		    parse_left nop nsofar rs
		else
		    (nsofar,r1)
--		    parse_op nop (Func (opName op) [sofar,t1]) rs
	    _ 		  -> (nsofar,r1)
	where
	    (t1,r1) = parse_prec ((opPrec op)-1) rest
	    nsofar = Func (opName op) [sofar,t1]

-- atomic expression
parse_bexpr3 :: [Lexeme] -> (BasicExp, [Lexeme])
parse_bexpr3 ((Evar evar):rest)      = ((EVar evar), rest)
parse_bexpr3 ((Ide var):Lparen:rest) =
			if succ then ((Func var args), r)
				else (BSError,r)
			where
				(args,r,succ) = parse_arglist [] rest
parse_bexpr3 ((Ide var):rest)       = ((Var var), rest)
parse_bexpr3 ((Num num):rest)       = ((Numb (read num)), rest)
parse_bexpr3 (Lparen:rest)          = case r1 of
				        (Rparen:r2) -> (exp,r2)
				        _	    -> (BSError,r1)
				      where
					(exp,r1) = parse_bexpr rest
parse_bexpr3 x 			    = (BSError,x)

-- parse argument list
parse_arglist :: [BasicExp] -> [Lexeme] -> ([BasicExp], [Lexeme], Bool)
parse_arglist acum (Rparen:x) = (acum, x, True)
parse_arglist acum x = case r1 of
			(Comma:rs)  -> parse_arglist (acum++[arg]) rs
			(Rparen:rs) -> (acum++[arg],rs,True)
			_	    -> ([],[],False)
		where
			(arg,r1) = parse_bexpr x
