package parser.grammars import com.github.h0tk3y.betterParse.combinators.* import com.github.h0tk3y.betterParse.grammar.parser import com.github.h0tk3y.betterParse.parser.Parser import prolog.ast.arithmetic.Float import prolog.ast.arithmetic.Integer import prolog.ast.lists.List import prolog.ast.terms.* import prolog.builtins.Dynamic import prolog.ast.lists.List.Empty import prolog.ast.lists.List.Cons /** * Precedence is based on the following table: * * | Precedence | Type | Operators | * |------------|------|-----------------------------------------------------------------------------------------------| * | 1200 | xfx | --\>, :-, =\>, ==\> | * | 1200 | fx | :-, ?- | * | 1150 | fx | dynamic | * | 1105 | xfy | | | * | 1100 | xfy | ; | * | 1050 | xfy | ->, *-> | * | 1000 | xfy | , | * | 990 | xfx | := | * | 900 | fy | \+ | * | 700 | xfx | <, =, =.., =:=, =<, ==, =\=, >, >=, \=, \==, as, is, >:<, :< | * | 600 | xfy | : | * | 500 | yfx | +, -, /\, \/, xor | * | 500 | fx | ? | * | 400 | yfx | *, /, //, div, rdiv, <<, >>, mod, rem | * | 200 | xfx | ** | * | 200 | xfy | ^ | * | 200 | fy | +, -, \ | * | 100 | yfx | . | * | 1 | fx | $ | * * It is very easy to extend this grammar to support more operators. Just add them at the appropriate rule or create a * new rule and chain it to the existing ones. * * @see [SWI-Prolog Predicate op/3](https://www.swi-prolog.org/pldoc/man?predicate=op/3) */ open class TermsGrammar : Tokens() { // Basic named terms protected val variable: Parser by (variableToken or anonymousVariableToken) use { Variable(text) } protected val simpleAtom: Parser by (nameToken or exclamation) use { Atom(text) } protected val quotedAtom: Parser by (dummy or ticked or doubleTicked or backTicked ) use { Atom(text.substring(1, text.length - 1)) } protected val atom: Parser by (quotedAtom or simpleAtom) protected val compound: Parser by (atom * -leftParenthesis * separated( parser(::termNoConjunction), comma, acceptZero = true ) * -rightParenthesis) use { Structure(t1, t2.terms) } // Basic arithmetic protected val int: Parser by integerToken use { Integer(text.toInt()) } protected val float: Parser by floatToken use { Float(text.toFloat()) } protected val functor: Parser by (nameToken * divide * int) use { "${t1.text}${t2.text}$t3" } // Base terms (atoms, compounds, variables, numbers) protected val baseTerm: Parser by (dummy or (-leftParenthesis * parser(::term) * -rightParenthesis) or parser(::list) or compound or atom or variable or float or int ) protected val op200: Parser by ((plus or minus) * parser(::term200)) use { CompoundTerm(Atom(t1.text), listOf(t2)) } protected val term200: Parser by (op200 or baseTerm) protected val op400: Parser by (multiply or divide) use { text } protected val term400: Parser by (term200 * zeroOrMore(op400 * term200)) use { t2.fold(t1) { acc, (op, term) -> CompoundTerm(Atom(op), listOf(acc, term)) } } protected val op500: Parser by (plus or minus) use { text } protected val term500: Parser by (term400 * zeroOrMore(op500 * term400)) use { t2.fold(t1) { acc, (op, term) -> CompoundTerm(Atom(op), listOf(acc, term)) } } protected val op700: Parser by (univOp or equivalent or notEquivalent or equals or notEquals or isOp) use { text } protected val term700: Parser by (term500 * optional(op700 * term500)) use { if (t2 == null) t1 else CompoundTerm(Atom(t2!!.t1), listOf(t1, t2!!.t2)) } protected val op1000: Parser by (comma) use { text } protected val term1000: Parser by (term700 * zeroOrMore(op1000 * term700)) use { t2.fold(t1) { acc, (op, term) -> CompoundTerm(Atom(op), listOf(acc, term)) } } protected val op1100: Parser by (semicolon) use { text } protected val term1100: Parser by (term1000 * zeroOrMore(op1100 * term1000)) use { t2.fold(t1) { acc, (op, term) -> CompoundTerm(Atom(op), listOf(acc, term)) } } protected val dynamic: Parser by (dynamicOp * functor) use { CompoundTerm( Atom(t1.text), listOf(Atom(t2)) ) } protected val term1150: Parser by (dynamic or term1100) use { this } protected val op1200: Parser by (neck) use { text } protected val term1200: Parser by (term1150 * zeroOrMore(op1200 * term1100)) use { t2.fold(t1) { acc, (op, term) -> CompoundTerm(Atom(op), listOf(acc, term)) } } // Lists protected val list: Parser by (-leftBracket * separated( parser(::termNoConjunction), comma, acceptZero = true ) * -rightBracket) use { var list: List = Empty // Construct the list in reverse order for (term in this.terms.reversed()) { list = Cons(term, list) } list } // Term - highest level expression protected val term: Parser by term1200 protected val termNoConjunction: Parser by term700 // Parts for clauses protected val head: Parser by (compound or atom) protected val body: Parser by term use { this as Body } override val rootParser: Parser by term }