Coverage Summary for Class: TermValues (it.unibo.tuprolog.argumentation.core.model.terms)

Class Class, % Method, % Branch, % Line, % Instruction, %
TermValues 100% (1/1) 100% (8/8) 83.3% (15/18) 100% (16/16) 94.4% (202/214)


 package it.unibo.tuprolog.argumentation.core.model.terms
 
 import it.unibo.tuprolog.argumentation.InternalArg2pApi
 import it.unibo.tuprolog.argumentation.Value
 import it.unibo.tuprolog.argumentation.core.Arg2pSolver
 import it.unibo.tuprolog.core.Term
 import it.unibo.tuprolog.core.TermFormatter
 import it.unibo.tuprolog.core.operators.OperatorSet
 import it.unibo.tuprolog.core.parsing.parse
 
 /**
  * The terms of tuProlog as the values of arg2p ([Value]) and as text, written with the operators of arg2p: the
  * passage between the API of arg2p and tuProlog
  */
 @InternalArg2pApi
 object TermValues {
     /** The operators of the theories of arg2p, and the default ones */
     val operators: OperatorSet by lazy { Arg2pSolver.default().operators() }
 
     private val formatter by lazy { TermFormatter.prettyExpressions(operators) }
 
     // a prefix negation as arg2p writes it (-a, ~a), rather than - a: at the start, or after an opening or a separator;
     // a quoted atom or string is matched whole, to be left as it is
     private val negation = Regex("""('(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*")|(^|[(\[,|]\s*)([-~]) (?=\S)""")
 
     /** The term written in [text], a goal or a value (its final dot left out), read with [operators] */
     fun term(
         text: String,
         operators: OperatorSet = this.operators,
     ): Term = Term.parse(text.trim().removeSuffix("."), operators)
 
     /** [term] as Prolog text, written with the operators of arg2p */
     fun format(term: Term): String =
         negation.replace(formatter.format(term)) { match ->
             match.groups[1]?.value ?: (match.groupValues[2] + match.groupValues[3])
         }
 
     /** The value of [term] */
     fun of(term: Term): Value =
         when {
             term.isVar -> Value.Variable(term.castToVar().name)
             term.isInteger ->
                 term.castToInteger().value.let { value ->
                     runCatching { Value.Integer(value.toIntExact()) }.getOrElse { Value.Real(value.toDouble()) }
                 }
             term.isReal -> Value.Real(term.castToReal().value.toDouble())
             term.isList && term.castToList().isWellFormed -> Value.List(term.castToList().toList().map { of(it) })
             term.isAtom -> Value.Atom(term.castToAtom().value)
             else -> term.castToStruct().let { struct -> Value.Struct(struct.functor, struct.args.map { of(it) }) }
         }
 }