// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.

// operator-pre-inc-dec.go
package expr

import (
	"git.portale-stac.it/go-pkg/expr/kern"
	"git.portale-stac.it/go-pkg/expr/scan"
	"git.portale-stac.it/go-pkg/expr/sym"
	"git.portale-stac.it/go-pkg/expr/types"
)

// -------- pre increment term

func newPreIncTerm(tk *scan.Token) *scan.Term {
	return &scan.Term{
		Tk:       *tk,
		Children: make([]*scan.Term, 0, 1),
		Position: scan.PosPrefix,
		Priority: scan.PriIncDec,
		EvalFunc: evalPreInc,
	}
}

func evalPreInc(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
	var childValue any
	if childValue, err = opTerm.EvalPrefix(ctx); err != nil {
		return
	}

	if types.IsInteger(childValue) && opTerm.Children[0].Symbol() == sym.SymVariable {
		i := childValue.(int64) + 1
		ctx.SetVar(opTerm.Children[0].Source(), i)
		v = i
	} else {
		err = opTerm.ErrIncompatiblePrefixPostfixType(childValue)
	}
	return
}

// -------- pre decrement term

func newPreDecTerm(tk *scan.Token) *scan.Term {
	return &scan.Term{
		Tk:       *tk,
		Parent:   nil,
		Children: make([]*scan.Term, 0, 1),
		Position: scan.PosPrefix,
		Priority: scan.PriIncDec,
		EvalFunc: evalPreDec,
	}
}

func evalPreDec(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
	var childValue any
	if childValue, err = opTerm.EvalPrefix(ctx); err != nil {
		return
	}

	if types.IsInteger(childValue) && opTerm.Children[0].Symbol() == sym.SymVariable {
		i := childValue.(int64) - 1
		ctx.SetVar(opTerm.Children[0].Source(), i)
		v = i
	} else {
		err = opTerm.ErrIncompatiblePrefixPostfixType(childValue)
	}
	return
}

// init
func init() {
	scan.RegisterTermConstructor(sym.SymPreInc, newPreIncTerm)
	scan.RegisterTermConstructor(sym.SymPreDec, newPreDecTerm)
}
