├── .gitignore ├── examples ├── friends.pl ├── light-meal.pl └── potions.pl ├── astnodetype_string.go ├── Makefile ├── INSTALL.md ├── LICENSE.md ├── CITATION.cff ├── README.md ├── qa-prolog.go ├── preproc.go ├── run.go ├── verilog.go ├── type-inf.go ├── parser.peg └── parser.go /.gitignore: -------------------------------------------------------------------------------- 1 | qa-prolog 2 | -------------------------------------------------------------------------------- /examples/friends.pl: -------------------------------------------------------------------------------- 1 | /* "The enemy of my enemy is my friend." */ 2 | 3 | hates(alice, bob). 4 | hates(bob, charlie). 5 | 6 | enemies(P, Q) :- hates(P, Q). 7 | enemies(P, Q) :- hates(Q, P). 8 | 9 | friends(A, B) :- 10 | enemies(A, X), 11 | enemies(X, B), 12 | A \= B. 13 | -------------------------------------------------------------------------------- /examples/light-meal.pl: -------------------------------------------------------------------------------- 1 | /* 2 | * Produce a menu with light meals (caloric value < 10Kcal) 3 | * 4 | * Extracted from the presentation, 5 | * 6 | * Inês Dutra 7 | * "Constraint Logic Programming: a short tutorial" 8 | * https://www.dcc.fc.up.pt/~ines/talks/clp-v1.pdf 9 | * June 2010 10 | */ 11 | 12 | light_meal(A, M, D) :- 13 | I > 0, J > 0, K > 0, 14 | I + J + K =< 10, 15 | starter(A, I), 16 | main_course(M, J), 17 | dessert(D, K). 18 | 19 | meat(steak, 5). 20 | meat(pork, 7). 21 | fish(sole, 2). 22 | fish(tuna, 4). 23 | dessert(fruit, 2). 24 | dessert(icecream, 6). 25 | 26 | main_course(M, I) :- 27 | meat(M, I). 28 | main_course(M, I) :- 29 | fish(M, I). 30 | 31 | starter(salad, 1). 32 | starter(soup, 6). 33 | -------------------------------------------------------------------------------- /astnodetype_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type=ASTNodeType"; DO NOT EDIT. 2 | 3 | package main 4 | 5 | import "strconv" 6 | 7 | const _ASTNodeType_name = "UnknownTypeNumeralTypeAtomTypeVariableTypeTermTypeTermListTypeListTailTypeListTypePrimaryExprTypeUnaryExprTypeUnaryOpTypeMultiplicativeExprTypeMultiplicativeOpTypeAdditiveExprTypeAdditiveOpTypeRelationOpTypeRelationTypePredicateTypeStructureTypePredicateListTypeClauseTypeClauseListTypeQueryTypeProgramType" 8 | 9 | var _ASTNodeType_index = [...]uint16{0, 11, 22, 30, 42, 50, 62, 74, 82, 97, 110, 121, 143, 163, 179, 193, 207, 219, 232, 245, 262, 272, 286, 295, 306} 10 | 11 | func (i ASTNodeType) String() string { 12 | if i < 0 || i >= ASTNodeType(len(_ASTNodeType_index)-1) { 13 | return "ASTNodeType(" + strconv.FormatInt(int64(i), 10) + ")" 14 | } 15 | return _ASTNodeType_name[_ASTNodeType_index[i]:_ASTNodeType_index[i+1]] 16 | } 17 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ############################################### 2 | # Build the Quantum Annealing Prolog compiler # 3 | # By Scott Pakin # 4 | ############################################### 5 | 6 | prefix = /usr/local 7 | bindir = $(prefix)/bin 8 | INSTALL = install 9 | GO = go 10 | GO_SOURCES = \ 11 | qa-prolog.go \ 12 | parser.go \ 13 | preproc.go \ 14 | run.go \ 15 | verilog.go \ 16 | type-inf.go \ 17 | astnodetype_string.go 18 | 19 | all: qa-prolog 20 | 21 | qa-prolog: $(GO_SOURCES) 22 | $(GO) build $(GO_SOURCES) 23 | 24 | parser.go astnodetype_string.go: parser.peg 25 | $(GO) generate 26 | 27 | clean: 28 | $(RM) qa-prolog 29 | 30 | maintainer-clean: 31 | $(RM) parser.go astnodetype_string.go 32 | 33 | install: qa-prolog 34 | $(INSTALL) -m 0755 -d $(DESTDIR)$(bindir) 35 | $(INSTALL) -m 0755 qa-prolog $(DESTDIR)$(bindir)/qa-prolog 36 | 37 | .PHONY: all clean maintainer-clean install 38 | -------------------------------------------------------------------------------- /INSTALL.md: -------------------------------------------------------------------------------- 1 | QA Prolog installation 2 | ====================== 3 | 4 | Dependencies 5 | ------------ 6 | 7 | A number of dependencies must be satisfied before QA Prolog can be built and run. Specifically, you will need 8 | 9 | * a [Go compiler](https://golang.org/), 10 | * the [Yosys Open SYnthesis Suite](http://www.clifford.at/yosys/), 11 | * [edif2qmasm](https://github.com/lanl/edif2qmasm), 12 | * [QMASM](https://github.com/lanl/qmasm), and 13 | * either [SAPI](https://www.dwavesys.com/software) (proprietary, for running on D‑Wave hardware) or [qbsolv](https://github.com/dwavesystems/qbsolv) (for classical solution). 14 | 15 | Building QA Prolog 16 | ------------------ 17 | 18 | QA Prolog itself is written in the [Go programming language](https://en.wikipedia.org/wiki/Go_(programming_language)) so you'll need a [Go compiler](https://golang.org/) to build it. One you have that, a simple 19 | ```bash 20 | go get github.com/lanl/QA-Prolog 21 | ``` 22 | should suffice to download and build the code. Alternatively, you can clone the GitHub repository and run either `go build` or `make`. 23 | 24 | The Makefile additionally supports `install`, `clean`, and `maintainer-clean` targets. The `install` target honors `DESTDIR`, `prefix`, and `bindir`. After cleaning with `make maintainer-clean`, you will need to run `go generate` to regenerate a few `.go` files. Regeneration relies on a couple of additional Go tools: 25 | 26 | | Tool | Installation command | 27 | | ------------------------------------------------------------- | ---------------------------------------- | 28 | | [stringer](https://godoc.org/golang.org/x/tools/cmd/stringer) | `go get golang.org/x/tools/cmd/stringer` | 29 | | [pigeon](https://godoc.org/github.com/mna/pigeon) | `go get github.com/mna/pigeon` | 30 | 31 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright © 2016, Triad National Security, LLC 2 | All rights reserved. 3 | 4 | This software was produced under U.S. Government contract 89233218CNA000001 for Los Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC for the U.S. Department of Energy/National Nuclear Security Administration. All rights in the program are reserved by Triad National Security, LLC, and the U.S. Department of Energy/National Nuclear Security Administration. The Government is granted for itself and others acting on its behalf a nonexclusive, paid-up, irrevocable worldwide license in this material to reproduce, prepare derivative works, distribute copies to the public, perform publicly and display publicly, and to permit others to do so. NEITHER THE GOVERNMENT NOR TRIAD NATIONAL SECURITY, LLC MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to produce derivative works, such modified software should be clearly marked, so as not to confuse it with the version available from LANL. 5 | 6 | Additionally, redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 11 | 12 | * Neither the name of Triad National Security, LLC, Los Alamos National Laboratory, LANL, the U.S. Government, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 13 | 14 | THIS SOFTWARE IS PROVIDED BY TRIAD NATIONAL SECURITY, LLC AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TRIAD NATIONAL SECURITY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 15 | -------------------------------------------------------------------------------- /CITATION.cff: -------------------------------------------------------------------------------- 1 | cff-version: 1.2.0 2 | message: "Please cite the following publication when referencing QA Prolog" 3 | title: "QA Prolog" 4 | type: software 5 | authors: 6 | - given-names: Scott 7 | family-names: Pakin 8 | orcid: "https://orcid.org/0000-0002-5220-1985" 9 | repository-code: "https://github.com/lanl/QA-Prolog" 10 | license-url: "https://github.com/lanl/QA-Prolog/blob/master/LICENSE.md" 11 | preferred-citation: 12 | type: article 13 | authors: 14 | - given-names: Scott 15 | family-names: Pakin 16 | orcid: "https://orcid.org/0000-0002-5220-1985" 17 | editors: 18 | - given-names: Ferdinando 19 | family-names: Fioretto 20 | - given-names: Enrico 21 | family-names: Pontelli 22 | publisher: 23 | name: "Cambridge University Press" 24 | doi: "10.1017/S1471068418000066" 25 | url: "https://www.cambridge.org/core/journals/theory-and-practice-of-logic-programming/article/performing-fully-parallel-constraint-logic-programming-on-a-quantum-annealer/AB4CCF2D913D0325F770B3DA02AA262D" 26 | journal: "Theory and Practice of Logic Programming" 27 | issue-title: "Special Issue on Parallel and Distributed Logic Programming" 28 | month: 9 29 | start: 928 30 | end: 949 31 | title: "Performing Fully Parallel Constraint Logic Programming on a Quantum Annealer" 32 | volume: 18 33 | issue: 5-6 34 | year: 2018 35 | issn: 1475-3081 36 | identifiers: 37 | - type: other 38 | value: "arXiv:1804.00036 [cs.PL]" 39 | description: "The arXiv preprint of the paper" 40 | languages: 41 | - en 42 | keywords: 43 | - quantum annealing 44 | - quantum computing 45 | - constraint logic programming 46 | - Prolog 47 | - D-Wave 48 | abstract: >- 49 | A quantum annealer exploits quantum effects to solve a particular 50 | type of optimization problem. The advantage of this specialized 51 | hardware is that it effectively considers all possible solutions 52 | in parallel, thereby potentially outperforming classical computing 53 | systems. However, despite quantum annealers having recently become 54 | commercially available, there are relatively few high-level 55 | programming models that target these devices. In this article, we 56 | show how to compile a subset of Prolog enhanced with support for 57 | constraint logic programming into a two-local Ising-model 58 | Hamiltonian suitable for execution on a quantum annealer. In 59 | particular, we describe the series of transformations one can 60 | apply to convert constraint logic programs expressed in Prolog 61 | into an executable form that bears virtually no resemblance to a 62 | classical machine model yet that evaluates the specified 63 | constraints in a fully parallel manner. We evaluate our efforts on 64 | a 1,095-qubit D-Wave 2X quantum annealer and describe the 65 | approach's associated capabilities and shortcomings. 66 | -------------------------------------------------------------------------------- /examples/potions.pl: -------------------------------------------------------------------------------- 1 | /* 2 | * Solve the Riddle of the Potions from "Harry Potter and the 3 | * Philosopher's Stone" by J. K. Rowling. 4 | * 5 | * QA Prolog implementation by Scott Pakin . 6 | */ 7 | 8 | %! eq_bit(?A:atom, ?B:atom, ?Eq:Atom) is nondet. 9 | % 10 | % Eq is 1 if A and B are the same atom, 0 otherwise. 11 | eq_bit(A, B, 0) :- atom(A), atom(B), A \= B. 12 | eq_bit(A, B, 1) :- atom(A), atom(B), A = B. 13 | 14 | %! cardinality_of(-Type:atom, ?A:atom, ?B:atom, ?C:atom, ?D:atom, 15 | %! ?E:atom, ?F:atom, ?G:atom, ?Value:int) is nondet. 16 | % 17 | % There are Value elements in [A, B, C, D, E, F, G] that match Type. 18 | cardinality_of(Type, A, B, C, D, E, F, G, Value) :- 19 | eq_bit(Type, A, Aval), 20 | eq_bit(Type, B, Bval), 21 | eq_bit(Type, C, Cval), 22 | eq_bit(Type, D, Dval), 23 | eq_bit(Type, E, Eval), 24 | eq_bit(Type, F, Fval), 25 | eq_bit(Type, G, Gval), 26 | Aval + Bval + Cval + Dval + Eval + Fval + Gval = Value. 27 | 28 | %! poison_before_wine(?A:atom, ?B:atom) is nondet. 29 | % 30 | % Given adjacent bottles, poison_before_wine is true unless wine 31 | % does not have poison to its left. 32 | poison_before_wine(_, Right) :- Right \= wine. 33 | poison_before_wine(poison, wine). 34 | 35 | %! bottles(?A:atom, ?B:atom, ?C:atom, ?D:atom, ?E:atom, ?F:atom, ?G:atom) is nondet. 36 | % 37 | % bottles solves the potions puzzle. 38 | bottles(A, B, C, D, E, F, G) :- 39 | % "Danger lies before you, while safety lies behind, 40 | % Two of us will help you, whichever you would find, 41 | % One among us seven will let you move ahead, 42 | % Another will transport the drinker back instead, 43 | % Two among our number hold only nettle wine, 44 | % Three of us are killers, waiting hidden in line. 45 | % Choose, unless you wish to stay here for evermore, 46 | % To help you in your choice, we give you these clues four:" 47 | cardinality_of(forward, A, B, C, D, E, F, G, 1), 48 | cardinality_of(backward, A, B, C, D, E, F, G, 1), 49 | cardinality_of(wine, A, B, C, D, E, F, G, 2), 50 | cardinality_of(poison, A, B, C, D, E, F, G, 3), 51 | 52 | % "First, however slyly the poison tries to hide 53 | % You will always find some on nettle wine's left side;" 54 | A \= wine, 55 | poison_before_wine(A, B), 56 | poison_before_wine(B, C), 57 | poison_before_wine(C, D), 58 | poison_before_wine(D, E), 59 | poison_before_wine(E, F), 60 | poison_before_wine(F, G), 61 | 62 | % "Second, different are those who stand at either end," 63 | % "But if you would move onwards, neither is your friend;" 64 | A \= G, 65 | A \= forward, 66 | G \= forward, 67 | 68 | % "Third, as you see clearly, all are different size, 69 | % Neither dwarf nor giant holds death in their insides;" 70 | C \= poison, % Assume smallest. 71 | F \= poison, % Assume largest. 72 | 73 | % "Fourth, the second left and the second on the right 74 | % Are twins once you taste them, though different at first sight." 75 | B = F. 76 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | QA Prolog 2 | ========= 3 | 4 | [![Go Report Card](https://goreportcard.com/badge/github.com/lanl/QA-Prolog)](https://goreportcard.com/report/github.com/lanl/QA-Prolog) 5 | 6 | Description 7 | ----------- 8 | 9 | QA Prolog ("Quantum Annealing Prolog") compiles a subset of the [Prolog programming language](https://en.wikipedia.org/wiki/Prolog), enhanced with some native support for [constraint-logic programming](https://en.wikipedia.org/wiki/Constraint_logic_programming), into a [2-local Ising-model Hamiltonian function](https://en.wikipedia.org/wiki/Ising_model) suitable for execution on a [D‑Wave quantum annealer](https://www.dwavesys.com/). Technically, though, QA Prolog produces a *classical* Hamiltonian function so it can in principle target classical annealers as well. 10 | 11 | QA Prolog is largely a proof of concept, but it does hold out the possibility—not yet demonstrated—of improving Prolog program execution time by replacing backtracking with fully parallel annealing into a solution state. 12 | 13 | Installation 14 | ------------ 15 | 16 | See [`INSTALL.md`](INSTALL.md). 17 | 18 | Usage 19 | ----- 20 | 21 | Run `qa-prolog --help` for a list of command-line options. At a minimum, you'll need to provide `--query=`〈*Prolog goal*〉 and a filename corresponding to a database of Prolog facts and rules. 22 | 23 | Here's an example (running on D‑Wave hardware): 24 | 25 | ``` 26 | $ qa-prolog --verbose --qmasm-args="-O1 --postproc=opt" --query='friends(P1, P2).' examples/friends.pl 27 | qa-prolog: INFO: Parsing examples/friends.pl as Prolog code 28 | qa-prolog: INFO: Representing symbols with 3 bit(s) and integers with 1 bit(s) 29 | qa-prolog: INFO: Storing intermediate files in /tmp/qap-227417173 30 | qa-prolog: INFO: Writing Verilog code to friends.v 31 | qa-prolog: INFO: Writing a Yosys synthesis script to friends.ys 32 | qa-prolog: INFO: Converting Verilog code to an EDIF netlist 33 | qa-prolog: INFO: Executing yosys -q friends.v friends.ys -b edif -o friends.edif 34 | qa-prolog: INFO: Converting the EDIF netlist to QMASM code 35 | qa-prolog: INFO: Executing edif2qmasm -o friends.qmasm friends.edif 36 | qa-prolog: INFO: Executing qmasm --run --values=ints -O1 --postproc=opt --pin=Query.Valid := true friends.qmasm 37 | P1 = charlie 38 | P2 = alice 39 | 40 | P1 = alice 41 | P2 = charlie 42 | ``` 43 | 44 | Citation 45 | -------- 46 | 47 | The following journal publication discusses the design and implementation of QA Prolog: 48 | 49 | > Pakin, Scott. “Performing Fully Parallel Constraint Logic Programming on a Quantum Annealer.” [*Theory and Practice of Logic Programming*](https://www.cambridge.org/core/journals/theory-and-practice-of-logic-programming), [vol. 18, no. 5–6](https://www.cambridge.org/core/journals/theory-and-practice-of-logic-programming/issue/2E19771FEA173F5FEA03108D2142054C), pp. 928–949, September 2018. Eds.: Ferdinando Fioretto and Enrico Pontelli. Cambridge University Press. ISSN: [1475‑3081](https://www.cambridge.org/core/journals/theory-and-practice-of-logic-programming), DOI: [10.1017/S1471068418000066](https://dx.doi.org/10.1017/S1471068418000066), [arXiv:1804.00036 [cs.PL]](https://arxiv.org/abs/1804.00036). 50 | 51 | License 52 | ------- 53 | 54 | QA Prolog is provided under a BSD-ish license with a "modifications must be indicated" clause. See [the LICENSE file](LICENSE.md) for the full text. 55 | 56 | QA Prolog is part of the Hybrid Quantum-Classical Computing suite, known internally as LA-CC-16-032. 57 | 58 | Author 59 | ------ 60 | 61 | Scott Pakin, 62 | -------------------------------------------------------------------------------- /qa-prolog.go: -------------------------------------------------------------------------------- 1 | // This program implements a compiler for Quantum-Annealing Prolog. It accepts 2 | // a small subset of Prolog and generates weights for a Hamiltonian expression, 3 | // which can be fed to a quantum annealer such as the D-Wave supercomputer. 4 | package main 5 | 6 | import ( 7 | "flag" 8 | "fmt" 9 | "io" 10 | "log" 11 | "os" 12 | "path" 13 | "strings" 14 | ) 15 | 16 | //go:generate pigeon -o parser.go parser.peg 17 | //go:generate stringer -type=ASTNodeType 18 | 19 | var notify *log.Logger // Help notify the user of warnings and errors. 20 | 21 | // Empty is used to treat maps as sets. 22 | type Empty struct{} 23 | 24 | // CheckError aborts with an error message if an error value is non-nil. 25 | func CheckError(err error) { 26 | if err != nil { 27 | notify.Fatal(err) 28 | } 29 | } 30 | 31 | // BaseName returns a file path with the directory and extension removed. 32 | func BaseName(filename string) string { 33 | return path.Base(strings.TrimSuffix(filename, path.Ext(filename))) 34 | } 35 | 36 | // Parameters encapsulates all command-line parameters as well as various 37 | // global values computed from the AST. 38 | type Parameters struct { 39 | // Command-line parameters 40 | ProgName string // Name of this program 41 | InFileName string // Name of the input file 42 | WorkDir string // Directory for holding intermediate files 43 | IntBits uint // Number of bits to use for each program integer 44 | Verbose bool // Whether to output verbose execution information 45 | Query string // Query to apply to the program 46 | QmasmArgs []string // Additional qmasm command-line arguments 47 | 48 | // Computed values 49 | SymToInt map[string]int // Map from a symbol to an integer 50 | IntToSym []string // Map from an integer to a symbol 51 | TopLevel map[string][]*ASTNode // Top-level clauses, grouped by name and arity 52 | SymBits uint // Number of bits to use for each symbol 53 | OutFileBase string // Base name (no path or extension) for output files 54 | DeleteWorkDir bool // Whether to delete WorkDir at the end of the program 55 | } 56 | 57 | // ParseError reports a parse error at a given position. 58 | var ParseError func(pos position, format string, args ...interface{}) 59 | 60 | // VerbosePrintf outputs a message only if verbose output is enabled. 61 | func VerbosePrintf(p *Parameters, fmt string, args ...interface{}) { 62 | if !p.Verbose { 63 | return 64 | } 65 | notify.Printf("INFO: "+fmt, args...) 66 | } 67 | 68 | func main() { 69 | // Parse the command line. 70 | p := Parameters{} 71 | p.ProgName = BaseName(os.Args[0]) 72 | notify = log.New(os.Stderr, p.ProgName+": ", 0) 73 | flag.Usage = func() { 74 | fmt.Fprintf(os.Stderr, "Usage: %s [] []\n\n", p.ProgName) 75 | flag.PrintDefaults() 76 | } 77 | flag.StringVar(&p.Query, "query", "", "Prolog query to apply to the program") 78 | flag.UintVar(&p.IntBits, "int-bits", 0, "minimum integer width in bits") 79 | flag.StringVar(&p.WorkDir, "work-dir", "", "directory for storing intermediate files (default: "+path.Join(os.TempDir(), "qap-*")+")") 80 | flag.BoolVar(&p.Verbose, "verbose", false, "output informational messages during execution") 81 | flag.BoolVar(&p.Verbose, "v", false, "same as -verbose") 82 | qmasmStr := flag.String("qmasm-args", "", "additional command-line arguments to pass to qmasm") 83 | flag.Parse() 84 | if flag.NArg() == 0 { 85 | p.InFileName = "" 86 | } else { 87 | p.InFileName = flag.Arg(0) 88 | } 89 | p.QmasmArgs = strings.Fields(*qmasmStr) 90 | ParseError = func(pos position, format string, args ...interface{}) { 91 | fmt.Fprintf(os.Stderr, "%s:%d:%d: ", p.InFileName, pos.line, pos.col) 92 | fmt.Fprintf(os.Stderr, format, args...) 93 | fmt.Fprintln(os.Stderr, "") 94 | os.Exit(1) 95 | } 96 | 97 | // Open the input file. 98 | var r io.Reader = os.Stdin 99 | if flag.NArg() > 0 { 100 | f, err := os.Open(p.InFileName) 101 | CheckError(err) 102 | defer f.Close() 103 | r = f 104 | } 105 | 106 | // If a query was specified, append it to the input file. 107 | if p.Query != "" { 108 | q := "?- " + p.Query 109 | if !strings.HasSuffix(q, ".") { 110 | q += "." 111 | } 112 | r = io.MultiReader(r, strings.NewReader(q)) 113 | } 114 | 115 | // Parse the input file into an AST. 116 | VerbosePrintf(&p, "Parsing %s as Prolog code", p.InFileName) 117 | a, err := ParseReader(p.InFileName, r) 118 | CheckError(err) 119 | ast := a.(*ASTNode) 120 | 121 | // Preprocess the AST. 122 | if len(ast.FindByType(QueryType)) == 0 { 123 | notify.Fatal("A query must be specified") 124 | } 125 | ast.RejectUnimplemented(&p) 126 | ast.StoreAtomNames(&p) 127 | ast.AdjustIntBits(&p) 128 | ast.BinClauses(&p) 129 | VerbosePrintf(&p, "Representing symbols with %d bit(s) and integers with %d bit(s)", p.SymBits, p.IntBits) 130 | 131 | // Perform type inference on the AST. 132 | nm2tys, clVarTys := ast.PerformTypeInference() 133 | 134 | // Create a working directory and switch to it. 135 | CreateWorkDir(&p) 136 | err = os.Chdir(p.WorkDir) 137 | CheckError(err) 138 | 139 | // Output Verilog code. 140 | p.OutFileBase = BaseName(p.InFileName) 141 | vName := p.OutFileBase + ".v" 142 | vf, err := os.Create(vName) 143 | CheckError(err) 144 | VerbosePrintf(&p, "Writing Verilog code to %s", vName) 145 | ast.WriteVerilog(vf, &p, nm2tys, clVarTys) 146 | vf.Close() 147 | 148 | // Compile the Verilog code to an EDIF netlist. 149 | CreateYosysScript(&p) 150 | VerbosePrintf(&p, "Converting Verilog code to an EDIF netlist") 151 | RunCommand(&p, "yosys", "-q", "-s", p.OutFileBase+".ys", 152 | "-b", "edif", "-o", p.OutFileBase+".edif", p.OutFileBase+".v") 153 | 154 | // Compile the EDIF netlist to QMASM code. 155 | VerbosePrintf(&p, "Converting the EDIF netlist to QMASM code") 156 | RunCommand(&p, "edif2qmasm", "-o", p.OutFileBase+".qmasm", p.OutFileBase+".edif") 157 | 158 | // Run the QMASM code and report the results. 159 | ast.RunQMASM(&p, clVarTys) 160 | 161 | // Optionally remove the working directory. 162 | if p.DeleteWorkDir { 163 | err = os.RemoveAll(p.WorkDir) 164 | CheckError(err) 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /preproc.go: -------------------------------------------------------------------------------- 1 | // Preprocess an AST before generating code. 2 | 3 | package main 4 | 5 | import ( 6 | "fmt" 7 | "sort" 8 | ) 9 | 10 | // BitsNeeded reports the number of bits needed to represent a given 11 | // nonnegative integer. 12 | func BitsNeeded(n int) uint { 13 | b := uint(0) 14 | for ; n > 0; n >>= 1 { 15 | b++ 16 | } 17 | return b 18 | } 19 | 20 | // RejectUnimplemented rejects the AST (i.e., aborts the program) if it 21 | // contains elements we do not currently know how to process. 22 | func (a *ASTNode) RejectUnimplemented(p *Parameters) { 23 | if n := a.FindByType(ListType); len(n) > 0 { 24 | ParseError(n[0].Pos, "Lists are not currently supported") 25 | } 26 | if n := a.FindByType(StructureType); len(n) > 0 { 27 | ParseError(n[0].Pos, "Structures are not currently supported") 28 | } 29 | } 30 | 31 | // FindByType walks an AST and returns a list of all nodes of a given type. 32 | func (a *ASTNode) FindByType(t ASTNodeType) []*ASTNode { 33 | nodes := make([]*ASTNode, 0, 8) 34 | var walker func(n *ASTNode) 35 | walker = func(n *ASTNode) { 36 | if n.Type == t { 37 | nodes = append(nodes, n) 38 | } 39 | for _, c := range n.Children { 40 | walker(c) 41 | } 42 | } 43 | walker(a) 44 | return nodes 45 | } 46 | 47 | // StoreAtomNames stores both a forward and reverse map between all atoms named 48 | // in an AST (except predicate names) and integers. 49 | func (a *ASTNode) StoreAtomNames(p *Parameters) { 50 | // Construct a map from integers to symbols. 51 | nmSet := make(map[string]Empty) 52 | a.uniqueAtomNames(nmSet, false) 53 | p.IntToSym = make([]string, 0, len(nmSet)) 54 | for nm := range nmSet { 55 | p.IntToSym = append(p.IntToSym, nm) 56 | } 57 | sort.Strings(p.IntToSym) 58 | 59 | // Construct a map from symbols to integers. 60 | p.SymToInt = make(map[string]int, len(p.IntToSym)) 61 | for i, s := range p.IntToSym { 62 | p.SymToInt[s] = i 63 | } 64 | p.SymBits = BitsNeeded(len(p.IntToSym) - 1) 65 | if p.SymBits == 0 { 66 | p.SymBits = 1 // Need at least one bit 67 | } 68 | } 69 | 70 | // uniqueAtomNames constructs a set of all atoms named in an AST except 71 | // predicate names. It performs most of the work for AtomNames. 72 | func (a *ASTNode) uniqueAtomNames(names map[string]Empty, skip1 bool) { 73 | // Process the current AST node. 74 | if a.Type == AtomType { 75 | nm, ok := a.Value.(string) 76 | if !ok { 77 | notify.Fatalf("Internal error parsing %#v", *a) 78 | } 79 | names[nm] = Empty{} 80 | } 81 | 82 | // Recursively process the current node's children. If the current 83 | // node is a clause or a query, skip its first child's first child (the 84 | // name of the clause/query itself). 85 | kids := a.Children 86 | if skip1 { 87 | kids = kids[1:] 88 | } 89 | skip1 = (a.Type == ClauseType || a.Type == QueryType) 90 | for _, aa := range kids { 91 | aa.uniqueAtomNames(names, skip1) 92 | skip1 = false 93 | } 94 | } 95 | 96 | // maxNumeral returns the maximum-valued numeric literal. 97 | func (a *ASTNode) maxNumeral() int { 98 | // Process the current node. 99 | max := 0 100 | if a.Type == NumeralType { 101 | m := a.Value.(int) 102 | if m > max { 103 | max = m 104 | } 105 | } 106 | 107 | // Recursively process each of the node's children. 108 | for _, aa := range a.Children { 109 | m := aa.maxNumeral() 110 | if m > max { 111 | max = m 112 | } 113 | } 114 | return max 115 | } 116 | 117 | // AdjustIntBits increments the integer width to accommodate both the 118 | // maximum-valued numeric literal and the number of symbol literals. This 119 | // function assumes that StoreAtomNames has already been called. 120 | func (a *ASTNode) AdjustIntBits(p *Parameters) { 121 | // Ensure we can store the maximum integer literal. 122 | b := BitsNeeded(a.maxNumeral()) 123 | if p.IntBits < b { 124 | p.IntBits = b 125 | } 126 | 127 | // We can't handle 0-bit integers so round up to 1 if necessary. 128 | if p.IntBits == 0 { 129 | p.IntBits = 1 130 | } 131 | } 132 | 133 | // BinClauses groups all of the clauses in the program by name and arity. The 134 | // function returns a map with keys are of the form "/" and values 135 | // being the corresponding lists of clauses. 136 | func (a *ASTNode) BinClauses(p *Parameters) { 137 | bins := make(map[string][]*ASTNode, 8) 138 | csAndQs := append(a.FindByType(ClauseType), a.FindByType(QueryType)...) 139 | for _, cl := range csAndQs { 140 | // Perform a lot of error-checking as we search for the clause 141 | // name. 142 | if len(cl.Children) == 0 { 143 | notify.Fatal("Internal error: Clause with no children") 144 | } 145 | pr := cl.Children[0] 146 | if pr.Type != PredicateType { 147 | notify.Fatal("Internal error: Clause with no predicate first child") 148 | } 149 | if len(pr.Children) == 0 { 150 | notify.Fatal("Internal error: Predicate with no children") 151 | } 152 | 153 | // Extract the symbol name (/). 154 | nm := pr.Children[0].Value 155 | ar := len(pr.Children[1:]) 156 | sym := fmt.Sprintf("%s/%d", nm, ar) 157 | 158 | // Associate the current clause with the symbol name. 159 | bins[sym] = append(bins[sym], cl) 160 | } 161 | p.TopLevel = bins 162 | } 163 | 164 | // numToVerVar converts a parameter number from 0-701 (e.g., 5) to a 165 | // lettered Verilog variable (e.g., "E"). 166 | func numToVerVar(n int) string { 167 | const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 168 | const nChars = len(chars) 169 | switch { 170 | case n < nChars: 171 | return chars[n : n+1] 172 | case n < nChars*(nChars+1): 173 | n0 := n % nChars 174 | n1 := n / nChars 175 | return chars[n1-1:n1] + chars[n0:n0+1] 176 | default: 177 | notify.Fatal("Too many parameters") 178 | } 179 | return "" // Will never get here. 180 | } 181 | 182 | // augmentVerilogVars associates Verilog variables with Prolog variables unless 183 | // they already appear in the given map. 184 | func (a *ASTNode) augmentVerilogVars(minN int, p2v map[string]string) map[string]string { 185 | varNodes := a.FindByType(VariableType) 186 | newP2v := make(map[string]string, len(varNodes)) 187 | for _, pv := range varNodes { 188 | pVar := pv.Text 189 | if _, seen := p2v[pVar]; seen { 190 | continue 191 | } 192 | if _, seen := newP2v[pVar]; seen { 193 | continue 194 | } 195 | newP2v[pVar] = numToVerVar(minN) 196 | minN++ 197 | } 198 | return newP2v 199 | } 200 | -------------------------------------------------------------------------------- /run.go: -------------------------------------------------------------------------------- 1 | // Execute an external command 2 | 3 | package main 4 | 5 | import ( 6 | "bufio" 7 | "fmt" 8 | "io" 9 | "io/ioutil" 10 | "os" 11 | "os/exec" 12 | "path/filepath" 13 | "strconv" 14 | "strings" 15 | "unicode" 16 | ) 17 | 18 | // CreateWorkDir creates a directory to hold byproducts of Prolog compilation. 19 | // If the parameter list names a directory, that one is used. Otherwise, a 20 | // temporary directory is created and used. 21 | func CreateWorkDir(p *Parameters) { 22 | // Before we return, output the name we chose. 23 | if p.Verbose { 24 | defer func() { 25 | dir, err := filepath.Abs(p.WorkDir) 26 | CheckError(err) 27 | VerbosePrintf(p, "Storing intermediate files in %s", dir) 28 | }() 29 | } 30 | 31 | // If the user specified a directory, create it if necessary and return. 32 | if p.WorkDir != "" { 33 | err := os.MkdirAll(p.WorkDir, 0777) 34 | CheckError(err) 35 | p.DeleteWorkDir = false 36 | return 37 | } 38 | 39 | // If the user did not specify a directory, create a random one. 40 | nm, err := ioutil.TempDir("", "qap-") 41 | CheckError(err) 42 | p.WorkDir = nm 43 | p.DeleteWorkDir = true 44 | } 45 | 46 | // CreateYosysScript creates a synthesis script for Yosys. 47 | func CreateYosysScript(p *Parameters) { 48 | // Create a .ys file. 49 | yName := p.OutFileBase + ".ys" 50 | VerbosePrintf(p, "Writing a Yosys synthesis script to %s", yName) 51 | ys, err := os.Create(filepath.Join(p.WorkDir, yName)) 52 | CheckError(err) 53 | 54 | // Write some boilerplate text to it. 55 | fmt.Fprintln(ys, "### Design synthesis") 56 | fmt.Fprintf(ys, "### Usage: yosys -s %s.ys -b edif -o %s.edif %s.v\n", 57 | p.OutFileBase, p.OutFileBase, p.OutFileBase) 58 | fmt.Fprint(ys, ` 59 | # Check design hierarchy. 60 | hierarchy -top Query 61 | 62 | # Translate processes. 63 | proc; opt 64 | 65 | # Detect and optimize FSM encodings. 66 | fsm; opt 67 | 68 | # Convert to gate logic. 69 | techmap; opt 70 | 71 | # Recast in terms of more gate types. 72 | abc -g AND,NAND,OR,NOR,XOR,XNOR,MUX,AOI3,OAI3,AOI4,OAI4; opt 73 | 74 | # Clean up. 75 | clean 76 | `) 77 | } 78 | 79 | // RunCommand executes a given command, aborting on error. 80 | func RunCommand(p *Parameters, name string, arg ...string) { 81 | cmd := exec.Command(name, arg...) 82 | cmd.Stderr = os.Stderr 83 | VerbosePrintf(p, "Executing %s %s", name, strings.Join(arg, " ")) 84 | err := cmd.Run() 85 | CheckError(err) 86 | } 87 | 88 | // parseQMASMOutputLine is a helper function for parseQMASMOutput that parses a 89 | // single line of QMASM output and outputs it in a user-friendly format. 90 | func (a *ASTNode) parseQMASMOutputLine(p *Parameters, haveVar bool, tys TypeInfo, ln string) { 91 | // Output a blank line between solutions. 92 | if len(ln) > 10 && ln[:10] == "Solution #" { 93 | fmt.Println("") 94 | return 95 | } 96 | 97 | // Extract a query variable and decimal value if both are 98 | // present. 99 | fields := strings.Fields(ln) 100 | if len(fields) != 3 { 101 | return 102 | } 103 | if len(fields[0]) < 7 || fields[0][:6] != "Query." { 104 | return 105 | } 106 | nm := fields[0][6:] 107 | val, err := strconv.Atoi(fields[2]) 108 | CheckError(err) 109 | 110 | // Output the variable and its value. 111 | switch { 112 | case nm == "Valid": 113 | switch { 114 | case haveVar: 115 | case val == 0: 116 | fmt.Println("false") 117 | case val == 1: 118 | fmt.Println("true") 119 | } 120 | 121 | case tys[nm] == InfNumeral: 122 | // Output numeric values. 123 | fmt.Printf("%s = %d\n", nm, val) 124 | 125 | case tys[nm] == InfAtom: 126 | // Output symbolic values. 127 | sym := "[invalid]" 128 | if val >= 0 && val < len(p.IntToSym) { 129 | sym = p.IntToSym[val] 130 | } 131 | fmt.Printf("%s = %s\n", nm, sym) 132 | 133 | default: 134 | // Ignore non-variables. 135 | } 136 | } 137 | 138 | // parseQMASMOutput is a helper function for RunQMASM that parses all of the 139 | // solutions and reports them in a user-friendly format. 140 | func (a *ASTNode) parseQMASMOutput(p *Parameters, haveVar bool, tys TypeInfo) { 141 | // Open the QMASM output file. 142 | r, err := os.Open(p.OutFileBase + ".out") 143 | CheckError(err) 144 | rb := bufio.NewReader(r) 145 | 146 | // Discard lines until we find a solution. 147 | for { 148 | ln, err := rb.ReadString('\n') 149 | if err == io.EOF { 150 | notify.Fatal("No solutions were found") 151 | } 152 | CheckError(err) 153 | if len(ln) > 10 && ln[:10] == "Solution #" { 154 | break 155 | } 156 | } 157 | 158 | // Parse lines until we reach the end of the file. 159 | for { 160 | // Read a line. 161 | ln, err := rb.ReadString('\n') 162 | if err == io.EOF { 163 | break 164 | } 165 | CheckError(err) 166 | a.parseQMASMOutputLine(p, haveVar, tys, ln) 167 | } 168 | err = r.Close() 169 | CheckError(err) 170 | } 171 | 172 | // showTail is a helper function for RunQMASM that outputs the last non-blank 173 | // line of a file. 174 | func (a *ASTNode) showTail(fn string) error { 175 | r, err := os.Open(fn) 176 | if err != nil { 177 | return err 178 | } 179 | rb := bufio.NewReader(r) 180 | last := "" 181 | for { 182 | ln, err := rb.ReadString('\n') 183 | if err == io.EOF { 184 | break 185 | } 186 | if err != nil { 187 | return err 188 | } 189 | if ln != "" { 190 | last = ln 191 | } 192 | } 193 | if last != "" { 194 | fmt.Fprint(os.Stderr, last) 195 | } 196 | return nil 197 | } 198 | 199 | // RunQMASM runs qmasm, parses the results, and outputs them. 200 | func (a *ASTNode) RunQMASM(p *Parameters, clVarTys map[*ASTNode]TypeInfo) { 201 | // Find the type of each query argument. 202 | cl := a.FindByType(QueryType)[0] 203 | tys := clVarTys[cl] 204 | 205 | // Write verbose output to a file in case the user wants to look at it 206 | // later. 207 | out, err := os.Create(p.OutFileBase + ".out") 208 | CheckError(err) 209 | 210 | // Construct a QMASM argument list. 211 | args := make([]string, 0, 4+len(p.QmasmArgs)) 212 | args = append(args, "--run", "--values=ints") // Mandatory arguments 213 | args = append(args, p.QmasmArgs...) // Additional, user-specified arguments 214 | haveVar := false 215 | for nm := range tys { 216 | if unicode.IsUpper(rune(nm[0])) { 217 | // If the query contains at least one variable, we're 218 | // trying to find valid values for all variables. 219 | // Otherwise, we're trying to determine if the 220 | // arguments represent a true statement. 221 | haveVar = true 222 | args = append(args, "--pin=Query.Valid := true") 223 | break 224 | } 225 | } 226 | args = append(args, p.OutFileBase+".qmasm") 227 | 228 | // Execute QMASM. 229 | cmd := exec.Command("qmasm", args...) 230 | cmd.Stdout = out 231 | cmd.Stderr = out 232 | VerbosePrintf(p, "Executing qmasm %s", strings.Join(args, " ")) 233 | err = cmd.Run() 234 | out.Close() 235 | if err != nil { 236 | // Output the last line of the .out file before aborting. 237 | _ = a.showTail(p.OutFileBase + ".out") 238 | CheckError(err) 239 | } 240 | 241 | // Report QMASM's output in terms of the query variables. 242 | a.parseQMASMOutput(p, haveVar, tys) 243 | } 244 | -------------------------------------------------------------------------------- /verilog.go: -------------------------------------------------------------------------------- 1 | // Output an AST as Verilog code. 2 | 3 | package main 4 | 5 | import ( 6 | "fmt" 7 | "io" 8 | "math/rand" 9 | "strings" 10 | "unicode" 11 | ) 12 | 13 | // Return a random string to use for an instance name. 14 | func generateSuffix() string { 15 | const nChars = 5 // Number of characters to generate 16 | const nmChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" 17 | suffix := make([]byte, nChars) 18 | for i := range suffix { 19 | suffix[i] = nmChars[rand.Intn(len(nmChars))] 20 | } 21 | return string(suffix) 22 | } 23 | 24 | // writeSymbols defines all of an AST's symbols as Verilog constants. 25 | func (a *ASTNode) writeSymbols(w io.Writer, p *Parameters) { 26 | // Determine the minimum number of characters needed to represent all 27 | // symbol names. 28 | nSymChars := 1 29 | for _, s := range p.IntToSym { 30 | if len(s) > nSymChars { 31 | nSymChars = len(s) 32 | } 33 | } 34 | 35 | // Output nicely formatted symbol definitions. 36 | fmt.Fprintln(w, "// Define all of the symbols used in this program.") 37 | for i, s := range p.IntToSym { 38 | fmt.Fprintf(w, "`define %-*s %d'd%d\n", nSymChars, s, p.SymBits, i) 39 | } 40 | } 41 | 42 | // args retrieves a clause's or a query's arguments in both Prolog and Verilog 43 | // format. In the former case, arguments are renamed to A, B, C, etc. This is 44 | // needed to handle both non-variable arguments (i.e., numerals or atoms) and 45 | // repeated variable arguments (as in "same(X, X)"). In the latter case, the 46 | // original names are preserved. This is needed to report results in terms of 47 | // the program-specified variables names (and it is known a priori that clauses 48 | // contain only unique variable names in their argument lists). 49 | func (a *ASTNode) args() (pArgs, vArgs []string) { 50 | pred := a.Children[0] 51 | terms := pred.Children[1:] 52 | pArgs = make([]string, len(terms)) // Prolog arguments (terms) 53 | vArgs = make([]string, len(terms)) // Verilog arguments (variables) 54 | for i, t := range terms { 55 | pArgs[i] = t.Text 56 | if a.Type == ClauseType { 57 | vArgs[i] = numToVerVar(i) 58 | } else { 59 | vArgs[i] = pArgs[i] 60 | } 61 | } 62 | return 63 | } 64 | 65 | // prologToVerilogUnary maps a Prolog unary operator to a Verilog unary 66 | // operator. 67 | var prologToVerilogUnary = map[string]string{"-": "-"} 68 | 69 | // prologToVerilogAdd maps a Prolog additive operator to a Verilog additive 70 | // operator. 71 | var prologToVerilogAdd = map[string]string{ 72 | "+": "+", 73 | "-": "-", 74 | } 75 | 76 | // prologToVerilogMult maps a Prolog multiplicative operator to a Verilog 77 | // multiplicative operator. 78 | var prologToVerilogMult = map[string]string{"*": "*"} 79 | 80 | // prologToVerilogRel maps a Prolog relational operator to a Verilog relational 81 | // operator. 82 | var prologToVerilogRel = map[string]string{ 83 | "=<": "<=", 84 | ">=": ">=", 85 | "<": "<", 86 | ">": ">", 87 | "=": "==", 88 | "\\=": "!=", 89 | "is": "==", 90 | } 91 | 92 | // toVerilogExpr recursively converts an AST, starting from a clause's body 93 | // predicate, to an expression. 94 | func (a *ASTNode) toVerilogExpr(p *Parameters, p2v map[string]string) string { 95 | switch a.Type { 96 | case NumeralType: 97 | return fmt.Sprintf("%d'd%s", p.IntBits, a.Text) 98 | 99 | case AtomType: 100 | return "`" + a.Value.(string) 101 | 102 | case VariableType: 103 | v, ok := p2v[a.Value.(string)] 104 | if !ok { 105 | notify.Fatalf("Internal error: Failed to convert variable %s from Prolog to Verilog", a.Value.(string)) 106 | } 107 | return v 108 | 109 | case UnaryOpType: 110 | v, ok := prologToVerilogUnary[a.Value.(string)] 111 | if !ok { 112 | notify.Fatalf("Internal error: Failed to convert %s %q from Prolog to Verilog", a.Type, a.Value.(string)) 113 | } 114 | return v 115 | 116 | case AdditiveOpType: 117 | v, ok := prologToVerilogAdd[a.Value.(string)] 118 | if !ok { 119 | notify.Fatalf("Internal error: Failed to convert %s %q from Prolog to Verilog", a.Type, a.Value.(string)) 120 | } 121 | return v 122 | 123 | case MultiplicativeOpType: 124 | v, ok := prologToVerilogMult[a.Value.(string)] 125 | if !ok { 126 | notify.Fatalf("Internal error: Failed to convert %s %q from Prolog to Verilog", a.Type, a.Value.(string)) 127 | } 128 | return v 129 | 130 | case RelationOpType: 131 | v, ok := prologToVerilogRel[a.Value.(string)] 132 | if !ok { 133 | notify.Fatalf("Internal error: Failed to convert %s %q from Prolog to Verilog", a.Type, a.Value.(string)) 134 | } 135 | return v 136 | 137 | case PrimaryExprType: 138 | c := a.Children[0].toVerilogExpr(p, p2v) 139 | if a.Value.(string) == "()" { 140 | return "(" + c + ")" 141 | } 142 | return c 143 | 144 | case UnaryExprType: 145 | if len(a.Children) == 1 { 146 | return a.Children[0].toVerilogExpr(p, p2v) 147 | } 148 | return a.Children[0].toVerilogExpr(p, p2v) + a.Children[1].toVerilogExpr(p, p2v) 149 | 150 | case MultiplicativeExprType: 151 | if len(a.Children) == 1 { 152 | return a.Children[0].toVerilogExpr(p, p2v) 153 | } 154 | c1 := a.Children[0].toVerilogExpr(p, p2v) 155 | v := a.Children[1].toVerilogExpr(p, p2v) 156 | c2 := a.Children[2].toVerilogExpr(p, p2v) 157 | return c1 + v + c2 158 | 159 | case AdditiveExprType: 160 | if len(a.Children) == 1 { 161 | return a.Children[0].toVerilogExpr(p, p2v) 162 | } 163 | c1 := a.Children[0].toVerilogExpr(p, p2v) 164 | v := a.Children[1].toVerilogExpr(p, p2v) 165 | c2 := a.Children[2].toVerilogExpr(p, p2v) 166 | return c1 + " " + v + " " + c2 167 | 168 | case RelationType: 169 | c1 := a.Children[0].toVerilogExpr(p, p2v) 170 | v := a.Children[1].toVerilogExpr(p, p2v) 171 | c2 := a.Children[2].toVerilogExpr(p, p2v) 172 | return c1 + " " + v + " " + c2 173 | 174 | case TermType: 175 | return a.Children[0].toVerilogExpr(p, p2v) 176 | 177 | case PredicateType: 178 | // Handle predicate AST nodes that are really just wrappers for 179 | // expressions. 180 | if len(a.Children) == 1 { 181 | return a.Children[0].toVerilogExpr(p, p2v) 182 | } 183 | 184 | // Ignore atom/1 and integer/1, which exist solely for the type 185 | // system. 186 | if len(a.Children) == 2 { 187 | pName := a.Children[0].Value.(string) 188 | if pName == "atom" || pName == "integer" { 189 | return "1'b1" 190 | } 191 | } 192 | 193 | cs := make([]string, 0, len(a.Children)*2) 194 | for i, c := range a.Children { 195 | switch i { 196 | case 0: 197 | vStr := c.toVerilogExpr(p, p2v) 198 | sfx := generateSuffix() 199 | arity := len(a.Children) - 1 200 | cs = append(cs, fmt.Sprintf("\\%s/%d \\%s_%s/%d", 201 | vStr[1:], arity, vStr[1:], sfx, arity)) // Strip leading "`" from vStr. 202 | case 1: 203 | cs = append(cs, " (") 204 | cs = append(cs, c.toVerilogExpr(p, p2v)) 205 | default: 206 | cs = append(cs, ", ") 207 | cs = append(cs, c.toVerilogExpr(p, p2v)) 208 | } 209 | } 210 | cs = append(cs, ", %s)") 211 | return strings.Join(cs, "") 212 | 213 | default: 214 | notify.Fatalf("Internal error: Unexpected AST node type %s", a.Type) 215 | } 216 | return "" // We should never get here. 217 | } 218 | 219 | // process converts each predicate in a clause to an assignment to a valid bit. 220 | func (a *ASTNode) process(p *Parameters, p2v map[string]string) []string { 221 | // Assign validity based on matches on any specified input symbols or 222 | // numbers. 223 | valid := make([]string, 0, len(a.Children)) 224 | pArgs, vArgs := a.args() 225 | for i, pa := range pArgs { 226 | r0 := rune(pa[0]) 227 | switch { 228 | case unicode.IsLower(r0): 229 | // Symbol 230 | valid = append(valid, fmt.Sprintf("%s == `%s", vArgs[i], pa)) 231 | case unicode.IsDigit(r0): 232 | // Numeral 233 | valid = append(valid, fmt.Sprintf("%s == %d'd%s", vArgs[i], p.IntBits, pa)) 234 | case unicode.IsUpper(r0), r0 == '_': 235 | // Variable 236 | 237 | default: 238 | notify.Fatalf("Internal error processing %q", pa) 239 | } 240 | } 241 | 242 | // Assign validity based on each predicate in the clause's body. 243 | for _, pred := range a.Children[1:] { 244 | v := pred.toVerilogExpr(p, p2v) 245 | if v != "1'b1" { 246 | valid = append(valid, v) 247 | } 248 | } 249 | return valid 250 | } 251 | 252 | // writeClauseGroupHeader is used by writeClauseGroup to write a Verilog module 253 | // header. 254 | func (a *ASTNode) writeClauseGroupHeader(w io.Writer, p *Parameters, nm string, cs []*ASTNode, tys ArgTypes) { 255 | // Write the module prototype. 256 | _, vArgs := cs[0].args() 257 | rawName := strings.Split(nm, "/")[0] 258 | if len(tys) == 0 { 259 | // No arguments (rare) 260 | fmt.Fprintf(w, "// Define %s.\n", rawName) 261 | } else { 262 | // At least one argument (common) 263 | for i, ty := range tys { 264 | if i == 0 { 265 | fmt.Fprintf(w, "// Define %s(%v", rawName, ty) 266 | } else { 267 | fmt.Fprintf(w, ", %v", ty) 268 | } 269 | } 270 | fmt.Fprintln(w, ").") 271 | } 272 | if rawName == "Query" { 273 | fmt.Fprint(w, "module Query (") // Exclude the arity from the top-level query. 274 | } else { 275 | fmt.Fprintf(w, "module \\%s (", nm) 276 | } 277 | for i, a := range vArgs { 278 | if i > 0 { 279 | fmt.Fprint(w, ", ") 280 | } 281 | fmt.Fprint(w, a) 282 | } 283 | if len(vArgs) > 0 { 284 | fmt.Fprintln(w, ", Valid);") 285 | } else { 286 | fmt.Fprintln(w, "Valid);") 287 | } 288 | 289 | // Write the module inputs. 290 | for i, a := range vArgs { 291 | bits := p.IntBits 292 | if tys[i] == InfAtom { 293 | bits = p.SymBits 294 | } 295 | if bits == 1 { 296 | fmt.Fprintf(w, " input %s;\n", a) 297 | } else { 298 | fmt.Fprintf(w, " input [%d:0] %s;\n", bits-1, a) 299 | } 300 | } 301 | 302 | // Write the module output. 303 | fmt.Fprintln(w, " output Valid;") 304 | } 305 | 306 | // writeClauseBody is used by writeClauseGroup to assign a Verilog bit for each 307 | // Prolog predicate in a clause's body. It returns the number of new variables 308 | // introduced. 309 | func (a *ASTNode) writeClauseBody(w io.Writer, p *Parameters, nm string, 310 | cNum int, nVars int, vTy TypeInfo) int { 311 | // Construct a map from Prolog variables to Verilog variables. As we 312 | // go along, constrain all variables with the same Prolog name to have 313 | // the same value. 314 | valid := make([]string, 0) 315 | pArgs, vArgs := a.args() 316 | p2v := make(map[string]string, len(pArgs)) 317 | for i, p := range pArgs { 318 | v, seen := p2v[p] 319 | if seen { 320 | valid = append(valid, vArgs[i]+" == "+v) 321 | } else { 322 | p2v[p] = vArgs[i] 323 | } 324 | } 325 | 326 | // Introduce more Verilog variables for local Prolog variables. 327 | for pName, vName := range a.augmentVerilogVars(nVars, p2v) { 328 | bits := p.IntBits 329 | if vTy[pName] == InfAtom { 330 | bits = p.SymBits 331 | } 332 | if bits == 1 { 333 | fmt.Fprintf(w, " (* keep *) wire %s;\n", vName) 334 | } else { 335 | fmt.Fprintf(w, " (* keep *) wire [%d:0] %s;\n", bits-1, vName) 336 | } 337 | p2v[pName] = vName 338 | nVars++ 339 | } 340 | 341 | // Convert the clause body to a list of Boolean Verilog 342 | // expressions. 343 | valid = append(valid, a.process(p, p2v)...) 344 | if len(valid) == 0 { 345 | // Although not normally used in practice, handle 346 | // useless clauses that accept all inputs (e.g., 347 | // "stupid(A, B, C)."). 348 | valid = append(valid, "1'b1") 349 | } 350 | if len(valid) == 1 { 351 | // Single bit 352 | fmt.Fprintf(w, " wire $v%d;\n", cNum+1) 353 | vBit := fmt.Sprintf("$v%d", cNum+1) 354 | v := valid[0] 355 | if strings.Contains(v, "%s") { 356 | fmt.Fprintf(w, " "+v+";\n", vBit) 357 | } else { 358 | fmt.Fprintf(w, " assign %s = %s;\n", vBit, v) 359 | } 360 | } else { 361 | // Multiple bits 362 | fmt.Fprintf(w, " wire [%d:0] $v%d;\n", len(valid)-1, cNum+1) 363 | for i, v := range valid { 364 | vBit := fmt.Sprintf("$v%d[%d]", cNum+1, i) 365 | if strings.Contains(v, "%s") { 366 | fmt.Fprintf(w, " "+v+";\n", vBit) 367 | } else { 368 | fmt.Fprintf(w, " assign %s = %s;\n", vBit, v) 369 | } 370 | } 371 | } 372 | return nVars 373 | } 374 | 375 | // writeClauseGroup writes a Verilog module corresponding to a group of clauses 376 | // that have the same name and arity. 377 | func (a *ASTNode) writeClauseGroup(w io.Writer, p *Parameters, nm string, 378 | cs []*ASTNode, tys ArgTypes, clVarTys map[*ASTNode]TypeInfo) { 379 | // Write a module header. 380 | a.writeClauseGroupHeader(w, p, nm, cs, tys) 381 | 382 | // Assign validity conditions based on each clause in the clause group. 383 | _, vArgs := cs[0].args() 384 | nVars := len(vArgs) 385 | for i, c := range cs { 386 | nVars += c.writeClauseBody(w, p, nm, i, nVars, clVarTys[c]) 387 | } 388 | 389 | // Set the final validity bit to the intersection of all predicate 390 | // validity bits. 391 | fmt.Fprint(w, " assign Valid = ") 392 | for i := range cs { 393 | if i > 0 { 394 | fmt.Fprint(w, " | ") 395 | } 396 | fmt.Fprintf(w, "&$v%d", i+1) 397 | } 398 | fmt.Fprintln(w, ";") 399 | fmt.Fprintln(w, "endmodule") 400 | } 401 | 402 | // WriteVerilog writes an entire (preprocessed) AST as Verilog code. 403 | func (a *ASTNode) WriteVerilog(w io.Writer, p *Parameters, 404 | nm2tys map[string]ArgTypes, clVarTys map[*ASTNode]TypeInfo) { 405 | // Output some header comments. 406 | fmt.Fprintf(w, "// Verilog version of Prolog program %s\n", p.InFileName) 407 | fmt.Fprintf(w, "// Conversion by %s, written by Scott Pakin \n", p.ProgName) 408 | fmt.Fprintln(w, `// 409 | // This program is intended to be passed to edif2qmasm, then to qmasm, and 410 | // finally run on a quantum annealer. 411 | //`) 412 | fmt.Fprintf(w, "// Note: This program uses %d bit(s) for atoms and %d bit(s) for (unsigned)\n", p.SymBits, p.IntBits) 413 | fmt.Fprintln(w, "// integers.") 414 | fmt.Fprintln(w, "") 415 | 416 | // Define constants for all of our symbols. 417 | a.writeSymbols(w, p) 418 | 419 | // Write each clause in turn. 420 | for nm, cs := range p.TopLevel { 421 | fmt.Fprintln(w, "") 422 | a.writeClauseGroup(w, p, nm, cs, nm2tys[nm], clVarTys) 423 | } 424 | } 425 | -------------------------------------------------------------------------------- /type-inf.go: -------------------------------------------------------------------------------- 1 | // Perform type inference on an AST. 2 | 3 | package main 4 | 5 | import ( 6 | "fmt" 7 | "unicode" 8 | ) 9 | 10 | // A VarType is the inferred type of a variable. 11 | type VarType int 12 | 13 | // We define three different variable types. 14 | const ( 15 | InfUnknown VarType = iota // Unknown type 16 | InfNumeral // Inferred numeral 17 | InfAtom // Inferred atom 18 | ) 19 | 20 | // Convert a VarType to a string. 21 | func (v VarType) String() string { 22 | switch v { 23 | case InfUnknown: 24 | return "*" 25 | case InfNumeral: 26 | return "num" 27 | case InfAtom: 28 | return "atom" 29 | default: 30 | notify.Fatalf("Internal error converting variable type %d to a string", v) 31 | } 32 | return "" // Will never get here 33 | } 34 | 35 | // TypeInfo represents a mapping from a variable to its type. 36 | type TypeInfo map[string]VarType 37 | 38 | // MergeTypes merges two type mappings. 39 | func MergeTypes(t1, t2 TypeInfo) (TypeInfo, error) { 40 | tm := make(TypeInfo, len(t1)+len(t2)) 41 | 42 | // Populate tm with the union of all variables in t1 and t2. 43 | for k := range t1 { 44 | tm[k] = InfUnknown 45 | } 46 | for k := range t2 { 47 | tm[k] = InfUnknown 48 | } 49 | 50 | // Look for type conflicts for each variable in turn. 51 | for k := range tm { 52 | // To reduce the number of cases to check, assign each variable 53 | // a default value of InfUnknown. 54 | v1, in1 := t1[k] 55 | if !in1 { 56 | v1 = InfUnknown 57 | } 58 | v2, in2 := t2[k] 59 | if !in2 { 60 | v2 = InfUnknown 61 | } 62 | 63 | // Any type overrides InfUnknown. Otherwise, types must match. 64 | switch { 65 | case v1 == v2: 66 | // Same type in both t1 and t2: retain that type. 67 | tm[k] = v1 68 | 69 | case v1 == InfUnknown: 70 | // v1 has an unknown type: use v2's type. 71 | tm[k] = v2 72 | 73 | case v2 == InfUnknown: 74 | // v2 has an unknown type: use v1's type. 75 | tm[k] = v1 76 | 77 | default: 78 | // v1 and v2 have incompatible types: complain. 79 | return nil, fmt.Errorf("Type conflict for variable %s", k) 80 | } 81 | } 82 | return tm, nil 83 | } 84 | 85 | // Return a map from clause name (e.g., "my_clause/3") to a list of AST nodes. 86 | func (a *ASTNode) clauseNames() map[string][]*ASTNode { 87 | nm2node := make(map[string][]*ASTNode) 88 | var walk func(c *ASTNode) 89 | walk = func(c *ASTNode) { 90 | if c.Type == ClauseType || c.Type == QueryType { 91 | name := c.Value.(string) 92 | old, seen := nm2node[name] 93 | if seen { 94 | nm2node[name] = append(old, c) 95 | } else { 96 | nm2node[name] = []*ASTNode{c} 97 | } 98 | return 99 | } 100 | for _, cc := range c.Children { 101 | walk(cc) 102 | } 103 | } 104 | walk(a) 105 | return nm2node 106 | } 107 | 108 | // ClauseDependencies maps a clause name to the names of all clauses that it 109 | // depends on. 110 | type ClauseDependencies map[string]map[string]Empty 111 | 112 | // findClauseDependencies walks an AST starting from a clause and reports its 113 | // immediate dependencies. 114 | func (a *ASTNode) findClauseDependencies() ClauseDependencies { 115 | // Find the name and arity of the current dependency (e.g., 116 | // "my_clause/3"). 117 | clName := a.Value.(string) 118 | deps := make(ClauseDependencies) 119 | 120 | // Define a function to recursively search an AST for dependencies. 121 | var findDeps func(c *ASTNode) 122 | findDeps = func(c *ASTNode) { 123 | if c.Type == PredicateType { 124 | // Ensure we're not an ordinary expression. 125 | if len(c.Children) <= 1 { 126 | // Not a reference to another clause 127 | return 128 | } 129 | 130 | // We have a dependency. Store it. 131 | chName := fmt.Sprintf("%s/%d", c.Children[0].Value.(string), len(c.Children)-1) 132 | if _, ok := deps[clName]; !ok { 133 | deps[clName] = make(map[string]Empty) 134 | } 135 | deps[clName][chName] = Empty{} 136 | return 137 | } 138 | for _, ch := range c.Children { 139 | findDeps(ch) 140 | } 141 | } 142 | 143 | // Search our children for dependencies. 144 | for _, ch := range a.Children[1:] { 145 | findDeps(ch) 146 | } 147 | return deps 148 | } 149 | 150 | // findRoots returns the roots of a dependency graph. 151 | func (d ClauseDependencies) findRoots() []string { 152 | // We don't currently support recursive functions. Search for and 153 | // reject recursion. 154 | seen := make(map[string]Empty, len(d)) 155 | var rejRec func(s string) 156 | rejRec = func(s string) { 157 | if _, found := seen[s]; found { 158 | notify.Fatalf("Recursion is not currently supported (%s)", s) 159 | } 160 | seen[s] = Empty{} 161 | for c := range d[s] { 162 | rejRec(c) 163 | } 164 | } 165 | 166 | // Start with every node that depends on another node as a potential 167 | // root. 168 | roots := make(map[string]Empty, len(d)*2) 169 | for r := range d { 170 | roots[r] = Empty{} 171 | } 172 | 173 | // Delete every node that another node depends upon. 174 | for _, cs := range d { 175 | for c := range cs { 176 | delete(roots, c) 177 | } 178 | } 179 | 180 | // Return the roots as a list. 181 | rList := make([]string, 0, len(roots)) 182 | for r := range roots { 183 | rList = append(rList, r) 184 | } 185 | return rList 186 | } 187 | 188 | // orderedClauses returns a list of all of an AST's clauses sorted in 189 | // dependency order. 190 | func (a *ASTNode) orderedClauses(nm2cls map[string][]*ASTNode) []*ASTNode { 191 | // Build a complete set of dependencies for all clauses. 192 | deps := make(ClauseDependencies) 193 | for _, cls := range nm2cls { 194 | for _, cl := range cls { 195 | deps[cl.Value.(string)] = make(map[string]Empty, 0) 196 | } 197 | } 198 | for _, cls := range nm2cls { 199 | for _, cl := range cls { 200 | for from, to2 := range cl.findClauseDependencies() { 201 | if _, ok := deps[from]; !ok { 202 | // First time we see from 203 | deps[from] = to2 204 | continue 205 | } 206 | for nm := range to2 { 207 | // Subsequent times we see from 208 | deps[from][nm] = Empty{} 209 | } 210 | } 211 | } 212 | } 213 | 214 | // Find a partial ordering of the dependency graph. 215 | roots := deps.findRoots() 216 | nodesSeen := make(map[string]Empty, len(roots)*2) 217 | ordNames := make([]string, 0, len(roots)*2) 218 | var makeOrder func(from string) 219 | makeOrder = func(nm string) { 220 | if _, seen := nodesSeen[nm]; seen { 221 | return 222 | } 223 | nodesSeen[nm] = Empty{} 224 | for c := range deps[nm] { 225 | makeOrder(c) 226 | } 227 | ordNames = append(ordNames, nm) 228 | } 229 | for _, r := range roots { 230 | makeOrder(r) 231 | } 232 | 233 | // Convert from strings to nodes. 234 | nDeps := len(ordNames) 235 | order := make([]*ASTNode, 0, nDeps) 236 | for _, nm := range ordNames { 237 | order = append(order, nm2cls[nm]...) 238 | } 239 | return order 240 | } 241 | 242 | // ArgTypes is a list of argument types for a clause. 243 | type ArgTypes []VarType 244 | 245 | // MergeArgTypes merges two lists of argument types. 246 | func MergeArgTypes(a1, a2 ArgTypes) (ArgTypes, error) { 247 | if len(a1) != len(a2) { 248 | notify.Fatalf("Internal error: Length mismatch between %v and %v", a1, a2) 249 | } 250 | aTypes := make(ArgTypes, len(a1)) 251 | for i, t1 := range a1 { 252 | t2 := a2[i] 253 | switch { 254 | case t1 == t2: 255 | aTypes[i] = t1 256 | case t1 == InfUnknown: 257 | aTypes[i] = t2 258 | case t2 == InfUnknown: 259 | aTypes[i] = t1 260 | default: 261 | return nil, fmt.Errorf("Polymorphic type signatures are not currently supported") 262 | } 263 | } 264 | return aTypes, nil 265 | } 266 | 267 | // When applied to a clause node, findClauseTypes augments a mapping from 268 | // clause name to argument types and returns the type of each variable used in 269 | // the clause. 270 | func (a *ASTNode) findClauseTypes(nm2tys map[string]ArgTypes) TypeInfo { 271 | // Determine the name of each clause argument. 272 | argNames := make([]string, len(a.Children[0].Children[1:])) 273 | for i, c := range a.Children[0].Children[1:] { 274 | argNames[i] = c.Value.(string) 275 | } 276 | 277 | // Initialize the list of argument types. 278 | argTypes := make(ArgTypes, len(argNames)) 279 | for i, nm := range argNames { 280 | r := rune(nm[0]) 281 | switch { 282 | case unicode.IsLower(r): 283 | argTypes[i] = InfAtom 284 | case unicode.IsDigit(r): 285 | argTypes[i] = InfNumeral 286 | default: 287 | argTypes[i] = InfUnknown 288 | } 289 | } 290 | 291 | // Update the list of argument types based on what we can infer about 292 | // all variables that appear in the clause. 293 | vTypes := a.findVariableTypes(nm2tys) 294 | for i, ty := range argTypes { 295 | if ty == InfUnknown { 296 | if newTy, ok := vTypes[argNames[i]]; ok { 297 | argTypes[i] = newTy 298 | } 299 | } 300 | } 301 | 302 | // Merge the new argument list with the existing list, if any. 303 | cl := a.Value.(string) 304 | if oldTys, ok := nm2tys[cl]; ok { 305 | var err error 306 | argTypes, err = MergeArgTypes(oldTys, argTypes) 307 | CheckError(err) 308 | } 309 | 310 | // Assign the same type to every instance of a variable name. 311 | var2ty := make(map[string]VarType, len(argTypes)) 312 | for i, v := range argNames { 313 | ty1 := argTypes[i] 314 | ty2, seen := var2ty[v] 315 | if seen { 316 | switch { 317 | case ty1 == ty2: 318 | case ty1 == InfUnknown: 319 | var2ty[v] = ty2 320 | case ty2 == InfUnknown: 321 | var2ty[v] = ty1 322 | default: 323 | notify.Fatalf("Type mismatch on variable %s in %s: %v vs. %v", v, cl, ty1, ty2) 324 | } 325 | } else { 326 | var2ty[v] = ty1 327 | } 328 | } 329 | for i, v := range argNames { 330 | argTypes[i] = var2ty[v] 331 | } 332 | 333 | // Update the map. 334 | nm2tys[cl] = argTypes 335 | return vTypes 336 | } 337 | 338 | // When applied to an expression node (specifically, RelationType or below), 339 | // findExprType returns the node's type. 340 | func (a *ASTNode) findExprType() VarType { 341 | switch a.Type { 342 | case NumeralType: 343 | return InfNumeral 344 | 345 | case AtomType: 346 | return InfAtom 347 | 348 | case VariableType: 349 | return InfUnknown 350 | 351 | case PrimaryExprType, UnaryExprType, MultiplicativeExprType, AdditiveExprType: 352 | // Arithmetic applies only to numerals. 353 | if len(a.Children) == 1 { 354 | // Trivial wrapper for an underlying expression: Ask 355 | // they underlying expression for its type. 356 | return a.Children[0].findExprType() 357 | } 358 | return InfNumeral 359 | 360 | case TermType: 361 | return a.Children[0].findExprType() 362 | 363 | case RelationType: 364 | // Relations are either numeric or unknown, depending on the 365 | // specific relation. 366 | op := a.Children[1].Value.(string) 367 | if op == "=" || op == "\\=" { 368 | // Equality and inequality are polymorphic. See if we 369 | // can determine the type from our arguments. 370 | t1 := a.Children[0].findExprType() 371 | t2 := a.Children[2].findExprType() 372 | switch { 373 | case t1 == t2: 374 | return t1 375 | case t1 == InfUnknown: 376 | return t2 377 | case t2 == InfUnknown: 378 | return t1 379 | default: 380 | notify.Fatalf("Can't apply %q to mixed types (%v and %v)", op, t1, t2) 381 | } 382 | } else { 383 | // All other relations apply only to numerals. 384 | return InfNumeral 385 | } 386 | 387 | default: 388 | notify.Fatalf("Internal error: findExprType doesn't recognize %v", a.Type) 389 | } 390 | return InfUnknown // Will never get here. 391 | } 392 | 393 | // When applied to any AST node, allVariables returns a set of all variables 394 | // named in that node. 395 | func (a *ASTNode) allVariables() map[string]Empty { 396 | var m map[string]Empty 397 | if a.Type == VariableType { 398 | m = make(map[string]Empty) 399 | m[a.Value.(string)] = Empty{} 400 | return m 401 | } 402 | for _, c := range a.Children { 403 | mm := c.allVariables() 404 | if m == nil { 405 | // Skip the copy for the first child. 406 | m = mm 407 | } else { 408 | // Merge the remaining children's variable lists. 409 | for v := range mm { 410 | m[v] = Empty{} 411 | } 412 | } 413 | } 414 | return m 415 | } 416 | 417 | // When applied to a clause node, findVariableTypes returns a mapping from 418 | // variable name to type. 419 | func (a *ASTNode) findVariableTypes(nm2tys map[string]ArgTypes) TypeInfo { 420 | var err error 421 | tm := make(TypeInfo, 1) // Type map to return 422 | type ForceSame struct { 423 | Vars map[string]Empty // Set of variable names 424 | Parent *ASTNode // Parent that includes all of the variables 425 | } 426 | same := make([]ForceSame, 0, 16) // Sets of variables that must wind up with the same type 427 | 428 | // Define a function that assigns the same type to all variables in all 429 | // of our child nodes. 430 | setAllChildren := func(c *ASTNode, ty VarType) { 431 | // Assign the same type to all children. 432 | vSet := c.allVariables() 433 | newTm := make(TypeInfo, len(vSet)) 434 | for k := range vSet { 435 | newTm[k] = ty 436 | } 437 | tm, err = MergeTypes(tm, newTm) 438 | 439 | // If the type is InfUnknown, check the types once we know what 440 | // they are. 441 | if ty != InfUnknown { 442 | return 443 | } 444 | same = append(same, ForceSame{Vars: vSet, Parent: c}) 445 | } 446 | 447 | // Figure out what to do based on the types of the clause's children. 448 | for _, p := range a.Children[1:] { 449 | c := p.Children[0] 450 | switch c.Type { 451 | case RelationType, TermType: 452 | // All variables in a relation or term must have the 453 | // same type. 454 | setAllChildren(c, c.findExprType()) 455 | 456 | case AtomType: 457 | // Line up the predicate's arguments with the 458 | // corresponding clause's argument types. 459 | name := fmt.Sprintf("%s/%d", c.Value, len(p.Children)-1) 460 | tys, ok := nm2tys[name] 461 | if !ok { 462 | notify.Fatalf("Internal error: Failed to find clause %s", name) 463 | } 464 | newTm := make(TypeInfo, len(tys)) 465 | for i, ty := range tys { 466 | newTm[p.Children[i+1].Value.(string)] = ty 467 | } 468 | tm, err = MergeTypes(tm, newTm) 469 | CheckError(err) 470 | 471 | default: 472 | notify.Fatalf("Internal error: findVariableTypes doesn't recognize %v", c.Type) 473 | } 474 | } 475 | 476 | // Ensure we didn't later find that two free variables in a relation 477 | // wound up with different types. 478 | for _, s := range same { 479 | k1 := "???" 480 | ty := InfUnknown 481 | for k := range s.Vars { 482 | if ty == InfUnknown { 483 | k1 = k 484 | ty = tm[k] 485 | } 486 | if tm[k] != ty { 487 | ParseError(s.Parent.Pos, "Type mismatch between variables %s and %s", k1, k) 488 | } 489 | } 490 | } 491 | return tm 492 | } 493 | 494 | // PerformTypeInference returns a mapping from clause name to argument types 495 | // for all clauses in the target AST. 496 | func (a *ASTNode) PerformTypeInference() (map[string]ArgTypes, map[*ASTNode]TypeInfo) { 497 | // Compute a clause order in which to apply type inference. 498 | nm2cls := a.clauseNames() 499 | clauses := a.orderedClauses(nm2cls) 500 | 501 | // Populate our mapping from clause name to argument types with a few 502 | // built-in names. 503 | nm2tys := make(map[string]ArgTypes, len(clauses)+2) 504 | nm2tys["integer/1"] = ArgTypes{InfNumeral} 505 | nm2tys["atom/1"] = ArgTypes{InfAtom} 506 | 507 | // Perform type inference on each clause in turn. 508 | clVarTys := make(map[*ASTNode]TypeInfo, len(clauses)) 509 | for _, cl := range clauses { 510 | clVarTys[cl] = cl.findClauseTypes(nm2tys) 511 | } 512 | 513 | // Ensure that we didn't wind up with any polymorphic clauses. 514 | for nm, tys := range nm2tys { 515 | for i, t := range tys { 516 | if t == InfUnknown { 517 | notify.Fatalf("%s is polymorphic (in argument %d), which is not currently supported", nm, i+1) 518 | } 519 | } 520 | } 521 | return nm2tys, clVarTys 522 | } 523 | -------------------------------------------------------------------------------- /parser.peg: -------------------------------------------------------------------------------- 1 | { 2 | // This is the parser for Quantum-Annealing Prolog. It was written using the 3 | // Pigeon parser generator's DSL (https://github.com/PuerkitoBio/pigeon) and is 4 | // inspired by the Prolog grammar found at 5 | // https://raw.githubusercontent.com/simonkrenger/ch.bfh.bti7064.w2013.PrologParser/master/doc/prolog-bnf-grammar.txt 6 | // but with various bugs corrected, support for relational and arithmetic 7 | // expressions added, and the whole grammar converted to a PEG. 8 | 9 | package main 10 | 11 | // An ASTNodeType indicates the type of AST node we're working with. 12 | type ASTNodeType int 13 | 14 | // Declare all of the AST node types we intend to use. 15 | const ( 16 | UnknownType ASTNodeType = iota // Should never be used 17 | NumeralType // Non-negative integer (e.g., "123") 18 | AtomType // Atom, with quotes stripped (e.g., "scott") 19 | VariableType // Variable (e.g., "Name") 20 | TermType // Term (a numeral, atom, or variable) 21 | TermListType // List of terms 22 | ListTailType // Tail of a list (e.g., the "T" in "[H|T]"). 23 | ListType // List (e.g., "[a, b, c]" or "[x, y, z|More]") 24 | PrimaryExprType // Primary expression (e.g., "(2+3)") 25 | UnaryExprType // Unary expression (e.g., "-X") 26 | UnaryOpType // Unary operator (e.g., "-") 27 | MultiplicativeExprType // Multiplicative expression (e.g., "7 * 5") 28 | MultiplicativeOpType // Multiplicative operator (e.g., "*") 29 | AdditiveExprType // Additive expression (e.g., "7 - 5") 30 | AdditiveOpType // Additive operator (e.g., "+") 31 | RelationOpType // Relation operator (e.g., "=<") 32 | RelationType // Relation (e.g., "happy(X) = Y" or "N < 10") 33 | PredicateType // Predicate (e.g., "likes(john, mary)") 34 | StructureType // Structure (e.g., "likes(john, mary)") 35 | PredicateListType // List of predicates (e.g., "likes(john, X), likes(X, mary)") 36 | ClauseType // Clause (e.g., "likes(john, X) :- likes(mary, X).") 37 | ClauseListType // List of clauses (e.g., "likes(john, X) :- likes(mary, X). likes(mary, cheese).") 38 | QueryType // Query (e.g., "?- likes(john, X).") 39 | ProgramType // A complete Prolog program 40 | ) 41 | 42 | // An ASTNode defines a single node in an abstract syntax tree. 43 | type ASTNode struct { 44 | Type ASTNodeType // What this node represents 45 | Text string // Node's textural represntation 46 | Pos position // Node's position in the input file 47 | Value interface{} // Node's value (int, string, etc.) 48 | Children []*ASTNode // Child AST node(s), if any 49 | } 50 | 51 | // String outputs an AST node and all its children, mostly for debugging. 52 | func (a *ASTNode) String() string { 53 | result := "" 54 | var showAll func(*ASTNode, int) 55 | showAll = func(n *ASTNode, depth int) { 56 | // Display this node. 57 | indent := strings.Repeat(" ", depth) 58 | result += fmt.Sprintf("%sType: %s\n", indent, n.Type) 59 | result += fmt.Sprintf("%sValue: %#v\n", indent, n.Value) 60 | result += fmt.Sprintf("%sText: %q\n", indent, n.Text) 61 | result += fmt.Sprintf("%sPos: %d:%d\n", indent, n.Pos.line, n.Pos.col) 62 | 63 | // Recursively display all children. 64 | for i, child := range n.Children { 65 | if i > 0 { 66 | result += "\n" 67 | } 68 | showAll(child, depth+1) 69 | } 70 | } 71 | showAll(a, 0) 72 | return result 73 | } 74 | 75 | // ConstructList constructs a list-type AST node from a parent type, a parent 76 | // value (which defaults to the node's textual representation), a head child, 77 | // and tail children. (Children may be nil.) The idea is to produce a single 78 | // list of children (e.g., [a, b, c]) rather than a degenerate tree (e.g., [a, 79 | // [b, [c]]]), which is what straightforward construction would naturally 80 | // produce. 81 | func (c *current) ConstructList(t ASTNodeType, v, n, ns interface{}) *ASTNode { 82 | head, hasHead := n.(*ASTNode) 83 | tail, hasTail := ns.(*ASTNode) 84 | node := ASTNode{ 85 | Type: t, 86 | Text: string(c.text), 87 | Value: v, 88 | Pos: c.pos, 89 | } 90 | if v == nil { 91 | node.Value = node.Text 92 | } 93 | if !hasHead { 94 | return &node 95 | } 96 | node.Children = []*ASTNode{head} 97 | if !hasTail { 98 | return &node 99 | } 100 | node.Children = append(node.Children, tail.Children...) 101 | return &node 102 | } 103 | 104 | // PrepareRelation takes two expressions and an operator and returns an ASTNode 105 | // representing that relation. 106 | func (c *current) PrepareRelation(e1, o, e2 interface{}) *ASTNode { 107 | kids := []*ASTNode{ 108 | e1.(*ASTNode), 109 | o.(*ASTNode), 110 | e2.(*ASTNode), 111 | } 112 | node := ASTNode{ 113 | Type: RelationType, 114 | Text: string(c.text), 115 | Pos: c.pos, 116 | Value: kids[1].Text, 117 | Children: kids, 118 | } 119 | return &node 120 | } 121 | 122 | } 123 | 124 | // For now, we define a Prolog program as a list of clauses followed by an 125 | // optional query. 126 | Program <- Skip cl:ClauseList Skip q:Query Skip '.' Skip EOF { 127 | // Append the query to the list of clauses. 128 | prog := c.ConstructList(ProgramType, nil, cl, nil) 129 | prog.Children = append(prog.Children, q.(*ASTNode)) 130 | return prog, nil 131 | } / Skip cl:ClauseList Skip EOF { 132 | return c.ConstructList(ProgramType, nil, cl, nil), nil 133 | } 134 | 135 | // Return an AST node of type QueryType. 136 | Query <- "?-" Skip ps:PredicateList { 137 | // Acquire a list of all variables that appear in the query. 138 | vSet := make(map[string]Empty) 139 | for _, v := range ps.(*ASTNode).FindByType(VariableType) { 140 | vSet[v.Value.(string)] = Empty{} 141 | } 142 | vList := make([]string, 0, len(vSet)) 143 | for v := range vSet { 144 | vList = append(vList, v) 145 | } 146 | 147 | // Insert a head predicate so we can process the query as if it were a 148 | // clause. 149 | pKids := make([]*ASTNode, 0, len(vList)+1) 150 | pKids = append(pKids, &ASTNode{ 151 | Type: AtomType, 152 | Value: "Query", 153 | Text: "Query", 154 | }) 155 | for _, v := range vList { 156 | vr := &ASTNode{ 157 | Type: VariableType, 158 | Value: v, 159 | Text: v, 160 | } 161 | trm := &ASTNode{ 162 | Type: TermType, 163 | Value: v, 164 | Text: v, 165 | Children: []*ASTNode{vr}, 166 | } 167 | pKids = append(pKids, trm) 168 | } 169 | hd := &ASTNode{ 170 | Type: PredicateType, 171 | Value: "Query", 172 | Text: "Query", 173 | Children: pKids, 174 | } 175 | name := fmt.Sprintf("Query/%d", len(vList)) 176 | return c.ConstructList(QueryType, name, hd, ps), nil 177 | } 178 | 179 | // Return an AST node of type ClauseListType. 180 | ClauseList <- cl:Clause Skip cls:ClauseList { 181 | return c.ConstructList(ClauseListType, nil, cl, cls), nil 182 | } / cl:Clause { 183 | return c.ConstructList(ClauseListType, nil, cl, nil), nil 184 | } 185 | 186 | // Return an AST node of type ClauseType. 187 | Clause <- p:Predicate Skip ":-" Skip ps:PredicateList Skip '.' { 188 | // Rule 189 | pn := p.(*ASTNode) 190 | name := fmt.Sprintf("%s/%d", pn.Children[0].Value.(string), len(pn.Children)-1) 191 | return c.ConstructList(ClauseType, name, p, ps), nil 192 | } / p:Predicate Skip '.' { 193 | // Fact 194 | pn := p.(*ASTNode) 195 | name := fmt.Sprintf("%s/%d", pn.Children[0].Value.(string), len(pn.Children)-1) 196 | return c.ConstructList(ClauseType, name, p, nil), nil 197 | } 198 | 199 | // Return an AST node of type PredicateListType. 200 | PredicateList <- p:Predicate Skip ',' Skip ps:PredicateList { 201 | return c.ConstructList(PredicateListType, nil, p, ps), nil 202 | } / p:Predicate { 203 | return c.ConstructList(PredicateListType, nil, p, nil), nil 204 | } 205 | 206 | // Return an AST node of type PredicateType. 207 | Predicate <- r:Relation { 208 | return c.ConstructList(PredicateType, nil, r, nil), nil 209 | } / a:Atom Skip '(' Skip ts:TermList Skip ')' { 210 | return c.ConstructList(PredicateType, nil, a, ts), nil 211 | } / a:Atom { 212 | return c.ConstructList(PredicateType, nil, a, nil), nil 213 | } 214 | 215 | // Return an AST node of type RelationType. 216 | Relation <- (e1:AdditiveExpr Skip o:RelationOperator Skip e2:AdditiveExpr) { 217 | return c.PrepareRelation(e1, o, e2), nil 218 | } / (e1:Term Skip o:EqualityOperator Skip e2:Term) { 219 | return c.PrepareRelation(e1, o, e2), nil 220 | } 221 | 222 | // A RelationOperator relates two numerical expressions. 223 | RelationOperator <- ("=<" / ">=" / "<" / ">" / "=" / "\\=") { 224 | return c.ConstructList(RelationOpType, nil, nil, nil), nil 225 | } 226 | 227 | // An EqualityOperator relates two arbitrary expressions by equality or 228 | // inequality. 229 | EqualityOperator <- ("=" / "\\=" ) { 230 | return c.ConstructList(RelationOpType, nil, nil, nil), nil 231 | } 232 | 233 | // An AdditiveExpr adds two values. 234 | AdditiveExpr <- e1:MultiplicativeExpr Skip o:AdditiveOperator Skip e2:AdditiveExpr { 235 | kids := []*ASTNode{ 236 | e1.(*ASTNode), 237 | o.(*ASTNode), 238 | e2.(*ASTNode), 239 | } 240 | node := ASTNode{ 241 | Type: AdditiveExprType, 242 | Text: string(c.text), 243 | Value: kids[1].Value, 244 | Pos: c.pos, 245 | Children: kids, 246 | } 247 | return &node, nil 248 | } / e:MultiplicativeExpr { 249 | return c.ConstructList(AdditiveExprType, "", e, nil), nil 250 | } 251 | 252 | // An AdditiveOperator applies to two values. 253 | AdditiveOperator <- ('+' / '-') { 254 | return c.ConstructList(AdditiveOpType, nil, nil, nil), nil 255 | } 256 | 257 | // A MultiplicativeExpr multiplies two values. 258 | MultiplicativeExpr <- e1:UnaryExpr Skip o:MultiplicativeOperator Skip e2:MultiplicativeExpr { 259 | kids := []*ASTNode{ 260 | e1.(*ASTNode), 261 | o.(*ASTNode), 262 | e2.(*ASTNode), 263 | } 264 | node := ASTNode{ 265 | Type: MultiplicativeExprType, 266 | Text: string(c.text), 267 | Value: kids[1].Value, 268 | Pos: c.pos, 269 | Children: kids, 270 | } 271 | return &node, nil 272 | } / e:UnaryExpr { 273 | return c.ConstructList(MultiplicativeExprType, "", e, nil), nil 274 | } 275 | 276 | // A MultiplicativeOperator applies to two values. 277 | MultiplicativeOperator <- '*' { 278 | return c.ConstructList(MultiplicativeOpType, nil, nil, nil), nil 279 | } 280 | 281 | // A UnaryExpr transforms a single value. 282 | UnaryExpr <- o:UnaryOperator Skip e:PrimaryExpr { 283 | kids := []*ASTNode{ 284 | o.(*ASTNode), 285 | e.(*ASTNode), 286 | } 287 | node := ASTNode{ 288 | Type: UnaryExprType, 289 | Text: string(c.text), 290 | Value: kids[1].Value, 291 | Pos: c.pos, 292 | Children: kids, 293 | } 294 | return &node, nil 295 | } / e:PrimaryExpr { 296 | return c.ConstructList(UnaryExprType, "", e, nil), nil 297 | } 298 | 299 | // A UnaryOperator applies to a single value. 300 | UnaryOperator <- '-' { 301 | return c.ConstructList(UnaryOpType, nil, nil, nil), nil 302 | } 303 | 304 | // A PrimaryExpr is the lowest-level expression, an atomic unit. 305 | PrimaryExpr <- '(' Skip a:AdditiveExpr Skip ')' { 306 | return c.ConstructList(PrimaryExprType, "()", a, nil), nil 307 | } / n:Numeral { 308 | return c.ConstructList(PrimaryExprType, "", n, nil), nil 309 | } / v:Variable { 310 | return c.ConstructList(PrimaryExprType, "", v, nil), nil 311 | } 312 | 313 | // Return an AST node of type TermListType. 314 | TermList <- t:Term Skip "," Skip ts:TermList { 315 | return c.ConstructList(TermListType, nil, t, ts), nil 316 | } / t:Term { 317 | return c.ConstructList(TermListType, nil, t, nil), nil 318 | } 319 | 320 | // Return an AST node of type TermType. 321 | Term <- child:(Numeral / Structure / Atom / Variable / List) { 322 | return c.ConstructList(TermType, nil, child, nil), nil 323 | } 324 | 325 | // A List can be either of bounded or unbounded extent (e.g., [1, 2, 3] vs. [1, 326 | // 2, 3|Rest]). 327 | List <- '[' Skip h:TermList Skip '|' Skip t:ListTail Skip ']' { 328 | // Unbounded extent 329 | return c.ConstructList(ListType, "[|]", h, t), nil 330 | } / '[' Skip h:TermList Skip ']' { 331 | // Bounded extent 332 | return c.ConstructList(ListType, "[]", h, nil), nil 333 | } 334 | 335 | // A ListTail represents the "everything else" part of a list. 336 | ListTail <- v:Variable { 337 | return c.ConstructList(ListTailType, nil, v, nil), nil 338 | } 339 | 340 | // Return an AST node of type StructureType. 341 | Structure <- a:Atom Skip '(' Skip ts:TermList Skip ')' { 342 | return c.ConstructList(StructureType, nil, a, ts), nil 343 | } 344 | 345 | // Return an AST node of type VariableType. 346 | Variable <- Uppercase_letter Symbol_trailer { 347 | return c.ConstructList(VariableType, nil, nil, nil), nil 348 | } 349 | 350 | // Return an AST node of type AtomType. 351 | Atom <- Small_atom { 352 | return c.ConstructList(AtomType, nil, nil, nil), nil 353 | } / Single_quoted_string { 354 | s := string(c.text) 355 | node := ASTNode{ 356 | Type: AtomType, 357 | Text: s, 358 | Pos: c.pos, 359 | Value: s[1 : len(s)-1], 360 | } 361 | return &node, nil 362 | } 363 | 364 | Single_quoted_string <- "'" Single_quoted_string_char* "'" 365 | 366 | Single_quoted_string_char <- Character / '\\' . 367 | 368 | Small_atom <- Lowercase_letter Symbol_trailer { 369 | return string(c.text), nil 370 | } 371 | 372 | Symbol_trailer <- (Lowercase_letter / Uppercase_letter / Digit)* 373 | 374 | Character <- Lowercase_letter / Uppercase_letter / Digit / Not_single_quote 375 | 376 | Lowercase_letter <- [\p{Ll}] 377 | 378 | Uppercase_letter <- [\p{Lu}_] 379 | 380 | Digit <- [\p{Nd}] 381 | 382 | Whitespace <- [\p{Zs}\n\r\t] 383 | 384 | One_line_comment <- '%' [^\n\r]* '\r'? '\n' 385 | 386 | Multi_line_comment <- "/*" (Multi_line_comment / '*' !'/' / [^*])* "*/" 387 | 388 | // Skip represents material to ignore, specifically whitespace and comments. 389 | Skip <- (Whitespace / One_line_comment / Multi_line_comment)* 390 | 391 | // Return an AST node of type NumeralType. 392 | Numeral <- Digit+ { 393 | num, err := strconv.Atoi(string(c.text)) 394 | if err != nil { 395 | return nil, err 396 | } 397 | node := ASTNode{ 398 | Type: NumeralType, 399 | Text: string(c.text), 400 | Value: num, 401 | Pos: c.pos, 402 | } 403 | return &node, nil 404 | } 405 | 406 | Not_single_quote <- [^'] 407 | 408 | EOF <- !. 409 | -------------------------------------------------------------------------------- /parser.go: -------------------------------------------------------------------------------- 1 | // Code generated by pigeon; DO NOT EDIT. 2 | 3 | // This is the parser for Quantum-Annealing Prolog. It was written using the 4 | // Pigeon parser generator's DSL (https://github.com/PuerkitoBio/pigeon) and is 5 | // inspired by the Prolog grammar found at 6 | // https://raw.githubusercontent.com/simonkrenger/ch.bfh.bti7064.w2013.PrologParser/master/doc/prolog-bnf-grammar.txt 7 | // but with various bugs corrected, support for relational and arithmetic 8 | // expressions added, and the whole grammar converted to a PEG. 9 | 10 | package main 11 | 12 | import ( 13 | "bytes" 14 | "errors" 15 | "fmt" 16 | "io" 17 | "io/ioutil" 18 | "math" 19 | "os" 20 | "sort" 21 | "strconv" 22 | "strings" 23 | "unicode" 24 | "unicode/utf8" 25 | ) 26 | 27 | // An ASTNodeType indicates the type of AST node we're working with. 28 | type ASTNodeType int 29 | 30 | // Declare all of the AST node types we intend to use. 31 | const ( 32 | UnknownType ASTNodeType = iota // Should never be used 33 | NumeralType // Non-negative integer (e.g., "123") 34 | AtomType // Atom, with quotes stripped (e.g., "scott") 35 | VariableType // Variable (e.g., "Name") 36 | TermType // Term (a numeral, atom, or variable) 37 | TermListType // List of terms 38 | ListTailType // Tail of a list (e.g., the "T" in "[H|T]"). 39 | ListType // List (e.g., "[a, b, c]" or "[x, y, z|More]") 40 | PrimaryExprType // Primary expression (e.g., "(2+3)") 41 | UnaryExprType // Unary expression (e.g., "-X") 42 | UnaryOpType // Unary operator (e.g., "-") 43 | MultiplicativeExprType // Multiplicative expression (e.g., "7 * 5") 44 | MultiplicativeOpType // Multiplicative operator (e.g., "*") 45 | AdditiveExprType // Additive expression (e.g., "7 - 5") 46 | AdditiveOpType // Additive operator (e.g., "+") 47 | RelationOpType // Relation operator (e.g., "=<") 48 | RelationType // Relation (e.g., "happy(X) = Y" or "N < 10") 49 | PredicateType // Predicate (e.g., "likes(john, mary)") 50 | StructureType // Structure (e.g., "likes(john, mary)") 51 | PredicateListType // List of predicates (e.g., "likes(john, X), likes(X, mary)") 52 | ClauseType // Clause (e.g., "likes(john, X) :- likes(mary, X).") 53 | ClauseListType // List of clauses (e.g., "likes(john, X) :- likes(mary, X). likes(mary, cheese).") 54 | QueryType // Query (e.g., "?- likes(john, X).") 55 | ProgramType // A complete Prolog program 56 | ) 57 | 58 | // An ASTNode defines a single node in an abstract syntax tree. 59 | type ASTNode struct { 60 | Type ASTNodeType // What this node represents 61 | Text string // Node's textural represntation 62 | Pos position // Node's position in the input file 63 | Value interface{} // Node's value (int, string, etc.) 64 | Children []*ASTNode // Child AST node(s), if any 65 | } 66 | 67 | // String outputs an AST node and all its children, mostly for debugging. 68 | func (a *ASTNode) String() string { 69 | result := "" 70 | var showAll func(*ASTNode, int) 71 | showAll = func(n *ASTNode, depth int) { 72 | // Display this node. 73 | indent := strings.Repeat(" ", depth) 74 | result += fmt.Sprintf("%sType: %s\n", indent, n.Type) 75 | result += fmt.Sprintf("%sValue: %#v\n", indent, n.Value) 76 | result += fmt.Sprintf("%sText: %q\n", indent, n.Text) 77 | result += fmt.Sprintf("%sPos: %d:%d\n", indent, n.Pos.line, n.Pos.col) 78 | 79 | // Recursively display all children. 80 | for i, child := range n.Children { 81 | if i > 0 { 82 | result += "\n" 83 | } 84 | showAll(child, depth+1) 85 | } 86 | } 87 | showAll(a, 0) 88 | return result 89 | } 90 | 91 | // ConstructList constructs a list-type AST node from a parent type, a parent 92 | // value (which defaults to the node's textual representation), a head child, 93 | // and tail children. (Children may be nil.) The idea is to produce a single 94 | // list of children (e.g., [a, b, c]) rather than a degenerate tree (e.g., [a, 95 | // [b, [c]]]), which is what straightforward construction would naturally 96 | // produce. 97 | func (c *current) ConstructList(t ASTNodeType, v, n, ns interface{}) *ASTNode { 98 | head, hasHead := n.(*ASTNode) 99 | tail, hasTail := ns.(*ASTNode) 100 | node := ASTNode{ 101 | Type: t, 102 | Text: string(c.text), 103 | Value: v, 104 | Pos: c.pos, 105 | } 106 | if v == nil { 107 | node.Value = node.Text 108 | } 109 | if !hasHead { 110 | return &node 111 | } 112 | node.Children = []*ASTNode{head} 113 | if !hasTail { 114 | return &node 115 | } 116 | node.Children = append(node.Children, tail.Children...) 117 | return &node 118 | } 119 | 120 | // PrepareRelation takes two expressions and an operator and returns an ASTNode 121 | // representing that relation. 122 | func (c *current) PrepareRelation(e1, o, e2 interface{}) *ASTNode { 123 | kids := []*ASTNode{ 124 | e1.(*ASTNode), 125 | o.(*ASTNode), 126 | e2.(*ASTNode), 127 | } 128 | node := ASTNode{ 129 | Type: RelationType, 130 | Text: string(c.text), 131 | Pos: c.pos, 132 | Value: kids[1].Text, 133 | Children: kids, 134 | } 135 | return &node 136 | } 137 | 138 | var g = &grammar{ 139 | rules: []*rule{ 140 | { 141 | name: "Program", 142 | pos: position{line: 126, col: 1, offset: 5840}, 143 | expr: &choiceExpr{ 144 | pos: position{line: 126, col: 12, offset: 5851}, 145 | alternatives: []interface{}{ 146 | &actionExpr{ 147 | pos: position{line: 126, col: 12, offset: 5851}, 148 | run: (*parser).callonProgram2, 149 | expr: &seqExpr{ 150 | pos: position{line: 126, col: 12, offset: 5851}, 151 | exprs: []interface{}{ 152 | &ruleRefExpr{ 153 | pos: position{line: 126, col: 12, offset: 5851}, 154 | name: "Skip", 155 | }, 156 | &labeledExpr{ 157 | pos: position{line: 126, col: 17, offset: 5856}, 158 | label: "cl", 159 | expr: &ruleRefExpr{ 160 | pos: position{line: 126, col: 20, offset: 5859}, 161 | name: "ClauseList", 162 | }, 163 | }, 164 | &ruleRefExpr{ 165 | pos: position{line: 126, col: 31, offset: 5870}, 166 | name: "Skip", 167 | }, 168 | &labeledExpr{ 169 | pos: position{line: 126, col: 36, offset: 5875}, 170 | label: "q", 171 | expr: &ruleRefExpr{ 172 | pos: position{line: 126, col: 38, offset: 5877}, 173 | name: "Query", 174 | }, 175 | }, 176 | &ruleRefExpr{ 177 | pos: position{line: 126, col: 44, offset: 5883}, 178 | name: "Skip", 179 | }, 180 | &litMatcher{ 181 | pos: position{line: 126, col: 49, offset: 5888}, 182 | val: ".", 183 | ignoreCase: false, 184 | }, 185 | &ruleRefExpr{ 186 | pos: position{line: 126, col: 53, offset: 5892}, 187 | name: "Skip", 188 | }, 189 | &ruleRefExpr{ 190 | pos: position{line: 126, col: 58, offset: 5897}, 191 | name: "EOF", 192 | }, 193 | }, 194 | }, 195 | }, 196 | &actionExpr{ 197 | pos: position{line: 131, col: 5, offset: 6075}, 198 | run: (*parser).callonProgram14, 199 | expr: &seqExpr{ 200 | pos: position{line: 131, col: 5, offset: 6075}, 201 | exprs: []interface{}{ 202 | &ruleRefExpr{ 203 | pos: position{line: 131, col: 5, offset: 6075}, 204 | name: "Skip", 205 | }, 206 | &labeledExpr{ 207 | pos: position{line: 131, col: 10, offset: 6080}, 208 | label: "cl", 209 | expr: &ruleRefExpr{ 210 | pos: position{line: 131, col: 13, offset: 6083}, 211 | name: "ClauseList", 212 | }, 213 | }, 214 | &ruleRefExpr{ 215 | pos: position{line: 131, col: 24, offset: 6094}, 216 | name: "Skip", 217 | }, 218 | &ruleRefExpr{ 219 | pos: position{line: 131, col: 29, offset: 6099}, 220 | name: "EOF", 221 | }, 222 | }, 223 | }, 224 | }, 225 | }, 226 | }, 227 | }, 228 | { 229 | name: "Query", 230 | pos: position{line: 136, col: 1, offset: 6212}, 231 | expr: &actionExpr{ 232 | pos: position{line: 136, col: 10, offset: 6221}, 233 | run: (*parser).callonQuery1, 234 | expr: &seqExpr{ 235 | pos: position{line: 136, col: 10, offset: 6221}, 236 | exprs: []interface{}{ 237 | &litMatcher{ 238 | pos: position{line: 136, col: 10, offset: 6221}, 239 | val: "?-", 240 | ignoreCase: false, 241 | }, 242 | &ruleRefExpr{ 243 | pos: position{line: 136, col: 15, offset: 6226}, 244 | name: "Skip", 245 | }, 246 | &labeledExpr{ 247 | pos: position{line: 136, col: 20, offset: 6231}, 248 | label: "ps", 249 | expr: &ruleRefExpr{ 250 | pos: position{line: 136, col: 23, offset: 6234}, 251 | name: "PredicateList", 252 | }, 253 | }, 254 | }, 255 | }, 256 | }, 257 | }, 258 | { 259 | name: "ClauseList", 260 | pos: position{line: 180, col: 1, offset: 7249}, 261 | expr: &choiceExpr{ 262 | pos: position{line: 180, col: 15, offset: 7263}, 263 | alternatives: []interface{}{ 264 | &actionExpr{ 265 | pos: position{line: 180, col: 15, offset: 7263}, 266 | run: (*parser).callonClauseList2, 267 | expr: &seqExpr{ 268 | pos: position{line: 180, col: 15, offset: 7263}, 269 | exprs: []interface{}{ 270 | &labeledExpr{ 271 | pos: position{line: 180, col: 15, offset: 7263}, 272 | label: "cl", 273 | expr: &ruleRefExpr{ 274 | pos: position{line: 180, col: 18, offset: 7266}, 275 | name: "Clause", 276 | }, 277 | }, 278 | &ruleRefExpr{ 279 | pos: position{line: 180, col: 25, offset: 7273}, 280 | name: "Skip", 281 | }, 282 | &labeledExpr{ 283 | pos: position{line: 180, col: 30, offset: 7278}, 284 | label: "cls", 285 | expr: &ruleRefExpr{ 286 | pos: position{line: 180, col: 34, offset: 7282}, 287 | name: "ClauseList", 288 | }, 289 | }, 290 | }, 291 | }, 292 | }, 293 | &actionExpr{ 294 | pos: position{line: 182, col: 5, offset: 7365}, 295 | run: (*parser).callonClauseList9, 296 | expr: &labeledExpr{ 297 | pos: position{line: 182, col: 5, offset: 7365}, 298 | label: "cl", 299 | expr: &ruleRefExpr{ 300 | pos: position{line: 182, col: 8, offset: 7368}, 301 | name: "Clause", 302 | }, 303 | }, 304 | }, 305 | }, 306 | }, 307 | }, 308 | { 309 | name: "Clause", 310 | pos: position{line: 187, col: 1, offset: 7488}, 311 | expr: &choiceExpr{ 312 | pos: position{line: 187, col: 11, offset: 7498}, 313 | alternatives: []interface{}{ 314 | &actionExpr{ 315 | pos: position{line: 187, col: 11, offset: 7498}, 316 | run: (*parser).callonClause2, 317 | expr: &seqExpr{ 318 | pos: position{line: 187, col: 11, offset: 7498}, 319 | exprs: []interface{}{ 320 | &labeledExpr{ 321 | pos: position{line: 187, col: 11, offset: 7498}, 322 | label: "p", 323 | expr: &ruleRefExpr{ 324 | pos: position{line: 187, col: 13, offset: 7500}, 325 | name: "Predicate", 326 | }, 327 | }, 328 | &ruleRefExpr{ 329 | pos: position{line: 187, col: 23, offset: 7510}, 330 | name: "Skip", 331 | }, 332 | &litMatcher{ 333 | pos: position{line: 187, col: 28, offset: 7515}, 334 | val: ":-", 335 | ignoreCase: false, 336 | }, 337 | &ruleRefExpr{ 338 | pos: position{line: 187, col: 33, offset: 7520}, 339 | name: "Skip", 340 | }, 341 | &labeledExpr{ 342 | pos: position{line: 187, col: 38, offset: 7525}, 343 | label: "ps", 344 | expr: &ruleRefExpr{ 345 | pos: position{line: 187, col: 41, offset: 7528}, 346 | name: "PredicateList", 347 | }, 348 | }, 349 | &ruleRefExpr{ 350 | pos: position{line: 187, col: 55, offset: 7542}, 351 | name: "Skip", 352 | }, 353 | &litMatcher{ 354 | pos: position{line: 187, col: 60, offset: 7547}, 355 | val: ".", 356 | ignoreCase: false, 357 | }, 358 | }, 359 | }, 360 | }, 361 | &actionExpr{ 362 | pos: position{line: 192, col: 5, offset: 7735}, 363 | run: (*parser).callonClause13, 364 | expr: &seqExpr{ 365 | pos: position{line: 192, col: 5, offset: 7735}, 366 | exprs: []interface{}{ 367 | &labeledExpr{ 368 | pos: position{line: 192, col: 5, offset: 7735}, 369 | label: "p", 370 | expr: &ruleRefExpr{ 371 | pos: position{line: 192, col: 7, offset: 7737}, 372 | name: "Predicate", 373 | }, 374 | }, 375 | &ruleRefExpr{ 376 | pos: position{line: 192, col: 17, offset: 7747}, 377 | name: "Skip", 378 | }, 379 | &litMatcher{ 380 | pos: position{line: 192, col: 22, offset: 7752}, 381 | val: ".", 382 | ignoreCase: false, 383 | }, 384 | }, 385 | }, 386 | }, 387 | }, 388 | }, 389 | }, 390 | { 391 | name: "PredicateList", 392 | pos: position{line: 200, col: 1, offset: 7989}, 393 | expr: &choiceExpr{ 394 | pos: position{line: 200, col: 18, offset: 8006}, 395 | alternatives: []interface{}{ 396 | &actionExpr{ 397 | pos: position{line: 200, col: 18, offset: 8006}, 398 | run: (*parser).callonPredicateList2, 399 | expr: &seqExpr{ 400 | pos: position{line: 200, col: 18, offset: 8006}, 401 | exprs: []interface{}{ 402 | &labeledExpr{ 403 | pos: position{line: 200, col: 18, offset: 8006}, 404 | label: "p", 405 | expr: &ruleRefExpr{ 406 | pos: position{line: 200, col: 20, offset: 8008}, 407 | name: "Predicate", 408 | }, 409 | }, 410 | &ruleRefExpr{ 411 | pos: position{line: 200, col: 30, offset: 8018}, 412 | name: "Skip", 413 | }, 414 | &litMatcher{ 415 | pos: position{line: 200, col: 35, offset: 8023}, 416 | val: ",", 417 | ignoreCase: false, 418 | }, 419 | &ruleRefExpr{ 420 | pos: position{line: 200, col: 39, offset: 8027}, 421 | name: "Skip", 422 | }, 423 | &labeledExpr{ 424 | pos: position{line: 200, col: 44, offset: 8032}, 425 | label: "ps", 426 | expr: &ruleRefExpr{ 427 | pos: position{line: 200, col: 47, offset: 8035}, 428 | name: "PredicateList", 429 | }, 430 | }, 431 | }, 432 | }, 433 | }, 434 | &actionExpr{ 435 | pos: position{line: 202, col: 5, offset: 8122}, 436 | run: (*parser).callonPredicateList11, 437 | expr: &labeledExpr{ 438 | pos: position{line: 202, col: 5, offset: 8122}, 439 | label: "p", 440 | expr: &ruleRefExpr{ 441 | pos: position{line: 202, col: 7, offset: 8124}, 442 | name: "Predicate", 443 | }, 444 | }, 445 | }, 446 | }, 447 | }, 448 | }, 449 | { 450 | name: "Predicate", 451 | pos: position{line: 207, col: 1, offset: 8252}, 452 | expr: &choiceExpr{ 453 | pos: position{line: 207, col: 14, offset: 8265}, 454 | alternatives: []interface{}{ 455 | &actionExpr{ 456 | pos: position{line: 207, col: 14, offset: 8265}, 457 | run: (*parser).callonPredicate2, 458 | expr: &labeledExpr{ 459 | pos: position{line: 207, col: 14, offset: 8265}, 460 | label: "r", 461 | expr: &ruleRefExpr{ 462 | pos: position{line: 207, col: 16, offset: 8267}, 463 | name: "Relation", 464 | }, 465 | }, 466 | }, 467 | &actionExpr{ 468 | pos: position{line: 209, col: 5, offset: 8346}, 469 | run: (*parser).callonPredicate5, 470 | expr: &seqExpr{ 471 | pos: position{line: 209, col: 5, offset: 8346}, 472 | exprs: []interface{}{ 473 | &labeledExpr{ 474 | pos: position{line: 209, col: 5, offset: 8346}, 475 | label: "a", 476 | expr: &ruleRefExpr{ 477 | pos: position{line: 209, col: 7, offset: 8348}, 478 | name: "Atom", 479 | }, 480 | }, 481 | &ruleRefExpr{ 482 | pos: position{line: 209, col: 12, offset: 8353}, 483 | name: "Skip", 484 | }, 485 | &litMatcher{ 486 | pos: position{line: 209, col: 17, offset: 8358}, 487 | val: "(", 488 | ignoreCase: false, 489 | }, 490 | &ruleRefExpr{ 491 | pos: position{line: 209, col: 21, offset: 8362}, 492 | name: "Skip", 493 | }, 494 | &labeledExpr{ 495 | pos: position{line: 209, col: 26, offset: 8367}, 496 | label: "ts", 497 | expr: &ruleRefExpr{ 498 | pos: position{line: 209, col: 29, offset: 8370}, 499 | name: "TermList", 500 | }, 501 | }, 502 | &ruleRefExpr{ 503 | pos: position{line: 209, col: 38, offset: 8379}, 504 | name: "Skip", 505 | }, 506 | &litMatcher{ 507 | pos: position{line: 209, col: 43, offset: 8384}, 508 | val: ")", 509 | ignoreCase: false, 510 | }, 511 | }, 512 | }, 513 | }, 514 | &actionExpr{ 515 | pos: position{line: 211, col: 5, offset: 8457}, 516 | run: (*parser).callonPredicate16, 517 | expr: &labeledExpr{ 518 | pos: position{line: 211, col: 5, offset: 8457}, 519 | label: "a", 520 | expr: &ruleRefExpr{ 521 | pos: position{line: 211, col: 7, offset: 8459}, 522 | name: "Atom", 523 | }, 524 | }, 525 | }, 526 | }, 527 | }, 528 | }, 529 | { 530 | name: "Relation", 531 | pos: position{line: 216, col: 1, offset: 8577}, 532 | expr: &choiceExpr{ 533 | pos: position{line: 216, col: 13, offset: 8589}, 534 | alternatives: []interface{}{ 535 | &actionExpr{ 536 | pos: position{line: 216, col: 13, offset: 8589}, 537 | run: (*parser).callonRelation2, 538 | expr: &seqExpr{ 539 | pos: position{line: 216, col: 14, offset: 8590}, 540 | exprs: []interface{}{ 541 | &labeledExpr{ 542 | pos: position{line: 216, col: 14, offset: 8590}, 543 | label: "e1", 544 | expr: &ruleRefExpr{ 545 | pos: position{line: 216, col: 17, offset: 8593}, 546 | name: "AdditiveExpr", 547 | }, 548 | }, 549 | &ruleRefExpr{ 550 | pos: position{line: 216, col: 30, offset: 8606}, 551 | name: "Skip", 552 | }, 553 | &labeledExpr{ 554 | pos: position{line: 216, col: 35, offset: 8611}, 555 | label: "o", 556 | expr: &ruleRefExpr{ 557 | pos: position{line: 216, col: 37, offset: 8613}, 558 | name: "RelationOperator", 559 | }, 560 | }, 561 | &ruleRefExpr{ 562 | pos: position{line: 216, col: 54, offset: 8630}, 563 | name: "Skip", 564 | }, 565 | &labeledExpr{ 566 | pos: position{line: 216, col: 59, offset: 8635}, 567 | label: "e2", 568 | expr: &ruleRefExpr{ 569 | pos: position{line: 216, col: 62, offset: 8638}, 570 | name: "AdditiveExpr", 571 | }, 572 | }, 573 | }, 574 | }, 575 | }, 576 | &actionExpr{ 577 | pos: position{line: 218, col: 5, offset: 8707}, 578 | run: (*parser).callonRelation12, 579 | expr: &seqExpr{ 580 | pos: position{line: 218, col: 6, offset: 8708}, 581 | exprs: []interface{}{ 582 | &labeledExpr{ 583 | pos: position{line: 218, col: 6, offset: 8708}, 584 | label: "e1", 585 | expr: &ruleRefExpr{ 586 | pos: position{line: 218, col: 9, offset: 8711}, 587 | name: "Term", 588 | }, 589 | }, 590 | &ruleRefExpr{ 591 | pos: position{line: 218, col: 14, offset: 8716}, 592 | name: "Skip", 593 | }, 594 | &labeledExpr{ 595 | pos: position{line: 218, col: 19, offset: 8721}, 596 | label: "o", 597 | expr: &ruleRefExpr{ 598 | pos: position{line: 218, col: 21, offset: 8723}, 599 | name: "EqualityOperator", 600 | }, 601 | }, 602 | &ruleRefExpr{ 603 | pos: position{line: 218, col: 38, offset: 8740}, 604 | name: "Skip", 605 | }, 606 | &labeledExpr{ 607 | pos: position{line: 218, col: 43, offset: 8745}, 608 | label: "e2", 609 | expr: &ruleRefExpr{ 610 | pos: position{line: 218, col: 46, offset: 8748}, 611 | name: "Term", 612 | }, 613 | }, 614 | }, 615 | }, 616 | }, 617 | }, 618 | }, 619 | }, 620 | { 621 | name: "RelationOperator", 622 | pos: position{line: 223, col: 1, offset: 8865}, 623 | expr: &actionExpr{ 624 | pos: position{line: 223, col: 21, offset: 8885}, 625 | run: (*parser).callonRelationOperator1, 626 | expr: &choiceExpr{ 627 | pos: position{line: 223, col: 22, offset: 8886}, 628 | alternatives: []interface{}{ 629 | &litMatcher{ 630 | pos: position{line: 223, col: 22, offset: 8886}, 631 | val: "=<", 632 | ignoreCase: false, 633 | }, 634 | &litMatcher{ 635 | pos: position{line: 223, col: 29, offset: 8893}, 636 | val: ">=", 637 | ignoreCase: false, 638 | }, 639 | &litMatcher{ 640 | pos: position{line: 223, col: 36, offset: 8900}, 641 | val: "<", 642 | ignoreCase: false, 643 | }, 644 | &litMatcher{ 645 | pos: position{line: 223, col: 42, offset: 8906}, 646 | val: ">", 647 | ignoreCase: false, 648 | }, 649 | &litMatcher{ 650 | pos: position{line: 223, col: 48, offset: 8912}, 651 | val: "=", 652 | ignoreCase: false, 653 | }, 654 | &litMatcher{ 655 | pos: position{line: 223, col: 54, offset: 8918}, 656 | val: "\\=", 657 | ignoreCase: false, 658 | }, 659 | }, 660 | }, 661 | }, 662 | }, 663 | { 664 | name: "EqualityOperator", 665 | pos: position{line: 229, col: 1, offset: 9084}, 666 | expr: &actionExpr{ 667 | pos: position{line: 229, col: 21, offset: 9104}, 668 | run: (*parser).callonEqualityOperator1, 669 | expr: &choiceExpr{ 670 | pos: position{line: 229, col: 22, offset: 9105}, 671 | alternatives: []interface{}{ 672 | &litMatcher{ 673 | pos: position{line: 229, col: 22, offset: 9105}, 674 | val: "=", 675 | ignoreCase: false, 676 | }, 677 | &litMatcher{ 678 | pos: position{line: 229, col: 28, offset: 9111}, 679 | val: "\\=", 680 | ignoreCase: false, 681 | }, 682 | }, 683 | }, 684 | }, 685 | }, 686 | { 687 | name: "AdditiveExpr", 688 | pos: position{line: 234, col: 1, offset: 9227}, 689 | expr: &choiceExpr{ 690 | pos: position{line: 234, col: 17, offset: 9243}, 691 | alternatives: []interface{}{ 692 | &actionExpr{ 693 | pos: position{line: 234, col: 17, offset: 9243}, 694 | run: (*parser).callonAdditiveExpr2, 695 | expr: &seqExpr{ 696 | pos: position{line: 234, col: 17, offset: 9243}, 697 | exprs: []interface{}{ 698 | &labeledExpr{ 699 | pos: position{line: 234, col: 17, offset: 9243}, 700 | label: "e1", 701 | expr: &ruleRefExpr{ 702 | pos: position{line: 234, col: 20, offset: 9246}, 703 | name: "MultiplicativeExpr", 704 | }, 705 | }, 706 | &ruleRefExpr{ 707 | pos: position{line: 234, col: 39, offset: 9265}, 708 | name: "Skip", 709 | }, 710 | &labeledExpr{ 711 | pos: position{line: 234, col: 44, offset: 9270}, 712 | label: "o", 713 | expr: &ruleRefExpr{ 714 | pos: position{line: 234, col: 46, offset: 9272}, 715 | name: "AdditiveOperator", 716 | }, 717 | }, 718 | &ruleRefExpr{ 719 | pos: position{line: 234, col: 63, offset: 9289}, 720 | name: "Skip", 721 | }, 722 | &labeledExpr{ 723 | pos: position{line: 234, col: 68, offset: 9294}, 724 | label: "e2", 725 | expr: &ruleRefExpr{ 726 | pos: position{line: 234, col: 71, offset: 9297}, 727 | name: "AdditiveExpr", 728 | }, 729 | }, 730 | }, 731 | }, 732 | }, 733 | &actionExpr{ 734 | pos: position{line: 248, col: 5, offset: 9699}, 735 | run: (*parser).callonAdditiveExpr12, 736 | expr: &labeledExpr{ 737 | pos: position{line: 248, col: 5, offset: 9699}, 738 | label: "e", 739 | expr: &ruleRefExpr{ 740 | pos: position{line: 248, col: 7, offset: 9701}, 741 | name: "MultiplicativeExpr", 742 | }, 743 | }, 744 | }, 745 | }, 746 | }, 747 | }, 748 | { 749 | name: "AdditiveOperator", 750 | pos: position{line: 253, col: 1, offset: 9837}, 751 | expr: &actionExpr{ 752 | pos: position{line: 253, col: 21, offset: 9857}, 753 | run: (*parser).callonAdditiveOperator1, 754 | expr: &choiceExpr{ 755 | pos: position{line: 253, col: 22, offset: 9858}, 756 | alternatives: []interface{}{ 757 | &litMatcher{ 758 | pos: position{line: 253, col: 22, offset: 9858}, 759 | val: "+", 760 | ignoreCase: false, 761 | }, 762 | &litMatcher{ 763 | pos: position{line: 253, col: 28, offset: 9864}, 764 | val: "-", 765 | ignoreCase: false, 766 | }, 767 | }, 768 | }, 769 | }, 770 | }, 771 | { 772 | name: "MultiplicativeExpr", 773 | pos: position{line: 258, col: 1, offset: 9988}, 774 | expr: &choiceExpr{ 775 | pos: position{line: 258, col: 23, offset: 10010}, 776 | alternatives: []interface{}{ 777 | &actionExpr{ 778 | pos: position{line: 258, col: 23, offset: 10010}, 779 | run: (*parser).callonMultiplicativeExpr2, 780 | expr: &seqExpr{ 781 | pos: position{line: 258, col: 23, offset: 10010}, 782 | exprs: []interface{}{ 783 | &labeledExpr{ 784 | pos: position{line: 258, col: 23, offset: 10010}, 785 | label: "e1", 786 | expr: &ruleRefExpr{ 787 | pos: position{line: 258, col: 26, offset: 10013}, 788 | name: "UnaryExpr", 789 | }, 790 | }, 791 | &ruleRefExpr{ 792 | pos: position{line: 258, col: 36, offset: 10023}, 793 | name: "Skip", 794 | }, 795 | &labeledExpr{ 796 | pos: position{line: 258, col: 41, offset: 10028}, 797 | label: "o", 798 | expr: &ruleRefExpr{ 799 | pos: position{line: 258, col: 43, offset: 10030}, 800 | name: "MultiplicativeOperator", 801 | }, 802 | }, 803 | &ruleRefExpr{ 804 | pos: position{line: 258, col: 66, offset: 10053}, 805 | name: "Skip", 806 | }, 807 | &labeledExpr{ 808 | pos: position{line: 258, col: 71, offset: 10058}, 809 | label: "e2", 810 | expr: &ruleRefExpr{ 811 | pos: position{line: 258, col: 74, offset: 10061}, 812 | name: "MultiplicativeExpr", 813 | }, 814 | }, 815 | }, 816 | }, 817 | }, 818 | &actionExpr{ 819 | pos: position{line: 272, col: 5, offset: 10475}, 820 | run: (*parser).callonMultiplicativeExpr12, 821 | expr: &labeledExpr{ 822 | pos: position{line: 272, col: 5, offset: 10475}, 823 | label: "e", 824 | expr: &ruleRefExpr{ 825 | pos: position{line: 272, col: 7, offset: 10477}, 826 | name: "UnaryExpr", 827 | }, 828 | }, 829 | }, 830 | }, 831 | }, 832 | }, 833 | { 834 | name: "MultiplicativeOperator", 835 | pos: position{line: 277, col: 1, offset: 10615}, 836 | expr: &actionExpr{ 837 | pos: position{line: 277, col: 27, offset: 10641}, 838 | run: (*parser).callonMultiplicativeOperator1, 839 | expr: &litMatcher{ 840 | pos: position{line: 277, col: 27, offset: 10641}, 841 | val: "*", 842 | ignoreCase: false, 843 | }, 844 | }, 845 | }, 846 | { 847 | name: "UnaryExpr", 848 | pos: position{line: 282, col: 1, offset: 10765}, 849 | expr: &choiceExpr{ 850 | pos: position{line: 282, col: 14, offset: 10778}, 851 | alternatives: []interface{}{ 852 | &actionExpr{ 853 | pos: position{line: 282, col: 14, offset: 10778}, 854 | run: (*parser).callonUnaryExpr2, 855 | expr: &seqExpr{ 856 | pos: position{line: 282, col: 14, offset: 10778}, 857 | exprs: []interface{}{ 858 | &labeledExpr{ 859 | pos: position{line: 282, col: 14, offset: 10778}, 860 | label: "o", 861 | expr: &ruleRefExpr{ 862 | pos: position{line: 282, col: 16, offset: 10780}, 863 | name: "UnaryOperator", 864 | }, 865 | }, 866 | &ruleRefExpr{ 867 | pos: position{line: 282, col: 30, offset: 10794}, 868 | name: "Skip", 869 | }, 870 | &labeledExpr{ 871 | pos: position{line: 282, col: 35, offset: 10799}, 872 | label: "e", 873 | expr: &ruleRefExpr{ 874 | pos: position{line: 282, col: 37, offset: 10801}, 875 | name: "PrimaryExpr", 876 | }, 877 | }, 878 | }, 879 | }, 880 | }, 881 | &actionExpr{ 882 | pos: position{line: 295, col: 5, offset: 11167}, 883 | run: (*parser).callonUnaryExpr9, 884 | expr: &labeledExpr{ 885 | pos: position{line: 295, col: 5, offset: 11167}, 886 | label: "e", 887 | expr: &ruleRefExpr{ 888 | pos: position{line: 295, col: 7, offset: 11169}, 889 | name: "PrimaryExpr", 890 | }, 891 | }, 892 | }, 893 | }, 894 | }, 895 | }, 896 | { 897 | name: "UnaryOperator", 898 | pos: position{line: 300, col: 1, offset: 11295}, 899 | expr: &actionExpr{ 900 | pos: position{line: 300, col: 18, offset: 11312}, 901 | run: (*parser).callonUnaryOperator1, 902 | expr: &litMatcher{ 903 | pos: position{line: 300, col: 18, offset: 11312}, 904 | val: "-", 905 | ignoreCase: false, 906 | }, 907 | }, 908 | }, 909 | { 910 | name: "PrimaryExpr", 911 | pos: position{line: 305, col: 1, offset: 11450}, 912 | expr: &choiceExpr{ 913 | pos: position{line: 305, col: 16, offset: 11465}, 914 | alternatives: []interface{}{ 915 | &actionExpr{ 916 | pos: position{line: 305, col: 16, offset: 11465}, 917 | run: (*parser).callonPrimaryExpr2, 918 | expr: &seqExpr{ 919 | pos: position{line: 305, col: 16, offset: 11465}, 920 | exprs: []interface{}{ 921 | &litMatcher{ 922 | pos: position{line: 305, col: 16, offset: 11465}, 923 | val: "(", 924 | ignoreCase: false, 925 | }, 926 | &ruleRefExpr{ 927 | pos: position{line: 305, col: 20, offset: 11469}, 928 | name: "Skip", 929 | }, 930 | &labeledExpr{ 931 | pos: position{line: 305, col: 25, offset: 11474}, 932 | label: "a", 933 | expr: &ruleRefExpr{ 934 | pos: position{line: 305, col: 27, offset: 11476}, 935 | name: "AdditiveExpr", 936 | }, 937 | }, 938 | &ruleRefExpr{ 939 | pos: position{line: 305, col: 40, offset: 11489}, 940 | name: "Skip", 941 | }, 942 | &litMatcher{ 943 | pos: position{line: 305, col: 45, offset: 11494}, 944 | val: ")", 945 | ignoreCase: false, 946 | }, 947 | }, 948 | }, 949 | }, 950 | &actionExpr{ 951 | pos: position{line: 307, col: 5, offset: 11571}, 952 | run: (*parser).callonPrimaryExpr10, 953 | expr: &labeledExpr{ 954 | pos: position{line: 307, col: 5, offset: 11571}, 955 | label: "n", 956 | expr: &ruleRefExpr{ 957 | pos: position{line: 307, col: 7, offset: 11573}, 958 | name: "Numeral", 959 | }, 960 | }, 961 | }, 962 | &actionExpr{ 963 | pos: position{line: 309, col: 5, offset: 11652}, 964 | run: (*parser).callonPrimaryExpr13, 965 | expr: &labeledExpr{ 966 | pos: position{line: 309, col: 5, offset: 11652}, 967 | label: "v", 968 | expr: &ruleRefExpr{ 969 | pos: position{line: 309, col: 7, offset: 11654}, 970 | name: "Variable", 971 | }, 972 | }, 973 | }, 974 | }, 975 | }, 976 | }, 977 | { 978 | name: "TermList", 979 | pos: position{line: 314, col: 1, offset: 11777}, 980 | expr: &choiceExpr{ 981 | pos: position{line: 314, col: 13, offset: 11789}, 982 | alternatives: []interface{}{ 983 | &actionExpr{ 984 | pos: position{line: 314, col: 13, offset: 11789}, 985 | run: (*parser).callonTermList2, 986 | expr: &seqExpr{ 987 | pos: position{line: 314, col: 13, offset: 11789}, 988 | exprs: []interface{}{ 989 | &labeledExpr{ 990 | pos: position{line: 314, col: 13, offset: 11789}, 991 | label: "t", 992 | expr: &ruleRefExpr{ 993 | pos: position{line: 314, col: 15, offset: 11791}, 994 | name: "Term", 995 | }, 996 | }, 997 | &ruleRefExpr{ 998 | pos: position{line: 314, col: 20, offset: 11796}, 999 | name: "Skip", 1000 | }, 1001 | &litMatcher{ 1002 | pos: position{line: 314, col: 25, offset: 11801}, 1003 | val: ",", 1004 | ignoreCase: false, 1005 | }, 1006 | &ruleRefExpr{ 1007 | pos: position{line: 314, col: 29, offset: 11805}, 1008 | name: "Skip", 1009 | }, 1010 | &labeledExpr{ 1011 | pos: position{line: 314, col: 34, offset: 11810}, 1012 | label: "ts", 1013 | expr: &ruleRefExpr{ 1014 | pos: position{line: 314, col: 37, offset: 11813}, 1015 | name: "TermList", 1016 | }, 1017 | }, 1018 | }, 1019 | }, 1020 | }, 1021 | &actionExpr{ 1022 | pos: position{line: 316, col: 5, offset: 11890}, 1023 | run: (*parser).callonTermList11, 1024 | expr: &labeledExpr{ 1025 | pos: position{line: 316, col: 5, offset: 11890}, 1026 | label: "t", 1027 | expr: &ruleRefExpr{ 1028 | pos: position{line: 316, col: 7, offset: 11892}, 1029 | name: "Term", 1030 | }, 1031 | }, 1032 | }, 1033 | }, 1034 | }, 1035 | }, 1036 | { 1037 | name: "Term", 1038 | pos: position{line: 321, col: 1, offset: 12005}, 1039 | expr: &actionExpr{ 1040 | pos: position{line: 321, col: 9, offset: 12013}, 1041 | run: (*parser).callonTerm1, 1042 | expr: &labeledExpr{ 1043 | pos: position{line: 321, col: 9, offset: 12013}, 1044 | label: "child", 1045 | expr: &choiceExpr{ 1046 | pos: position{line: 321, col: 16, offset: 12020}, 1047 | alternatives: []interface{}{ 1048 | &ruleRefExpr{ 1049 | pos: position{line: 321, col: 16, offset: 12020}, 1050 | name: "Numeral", 1051 | }, 1052 | &ruleRefExpr{ 1053 | pos: position{line: 321, col: 26, offset: 12030}, 1054 | name: "Structure", 1055 | }, 1056 | &ruleRefExpr{ 1057 | pos: position{line: 321, col: 38, offset: 12042}, 1058 | name: "Atom", 1059 | }, 1060 | &ruleRefExpr{ 1061 | pos: position{line: 321, col: 45, offset: 12049}, 1062 | name: "Variable", 1063 | }, 1064 | &ruleRefExpr{ 1065 | pos: position{line: 321, col: 56, offset: 12060}, 1066 | name: "List", 1067 | }, 1068 | }, 1069 | }, 1070 | }, 1071 | }, 1072 | }, 1073 | { 1074 | name: "List", 1075 | pos: position{line: 327, col: 1, offset: 12230}, 1076 | expr: &choiceExpr{ 1077 | pos: position{line: 327, col: 9, offset: 12238}, 1078 | alternatives: []interface{}{ 1079 | &actionExpr{ 1080 | pos: position{line: 327, col: 9, offset: 12238}, 1081 | run: (*parser).callonList2, 1082 | expr: &seqExpr{ 1083 | pos: position{line: 327, col: 9, offset: 12238}, 1084 | exprs: []interface{}{ 1085 | &litMatcher{ 1086 | pos: position{line: 327, col: 9, offset: 12238}, 1087 | val: "[", 1088 | ignoreCase: false, 1089 | }, 1090 | &ruleRefExpr{ 1091 | pos: position{line: 327, col: 13, offset: 12242}, 1092 | name: "Skip", 1093 | }, 1094 | &labeledExpr{ 1095 | pos: position{line: 327, col: 18, offset: 12247}, 1096 | label: "h", 1097 | expr: &ruleRefExpr{ 1098 | pos: position{line: 327, col: 20, offset: 12249}, 1099 | name: "TermList", 1100 | }, 1101 | }, 1102 | &ruleRefExpr{ 1103 | pos: position{line: 327, col: 29, offset: 12258}, 1104 | name: "Skip", 1105 | }, 1106 | &litMatcher{ 1107 | pos: position{line: 327, col: 34, offset: 12263}, 1108 | val: "|", 1109 | ignoreCase: false, 1110 | }, 1111 | &ruleRefExpr{ 1112 | pos: position{line: 327, col: 38, offset: 12267}, 1113 | name: "Skip", 1114 | }, 1115 | &labeledExpr{ 1116 | pos: position{line: 327, col: 43, offset: 12272}, 1117 | label: "t", 1118 | expr: &ruleRefExpr{ 1119 | pos: position{line: 327, col: 45, offset: 12274}, 1120 | name: "ListTail", 1121 | }, 1122 | }, 1123 | &ruleRefExpr{ 1124 | pos: position{line: 327, col: 54, offset: 12283}, 1125 | name: "Skip", 1126 | }, 1127 | &litMatcher{ 1128 | pos: position{line: 327, col: 59, offset: 12288}, 1129 | val: "]", 1130 | ignoreCase: false, 1131 | }, 1132 | }, 1133 | }, 1134 | }, 1135 | &actionExpr{ 1136 | pos: position{line: 330, col: 5, offset: 12385}, 1137 | run: (*parser).callonList15, 1138 | expr: &seqExpr{ 1139 | pos: position{line: 330, col: 5, offset: 12385}, 1140 | exprs: []interface{}{ 1141 | &litMatcher{ 1142 | pos: position{line: 330, col: 5, offset: 12385}, 1143 | val: "[", 1144 | ignoreCase: false, 1145 | }, 1146 | &ruleRefExpr{ 1147 | pos: position{line: 330, col: 9, offset: 12389}, 1148 | name: "Skip", 1149 | }, 1150 | &labeledExpr{ 1151 | pos: position{line: 330, col: 14, offset: 12394}, 1152 | label: "h", 1153 | expr: &ruleRefExpr{ 1154 | pos: position{line: 330, col: 16, offset: 12396}, 1155 | name: "TermList", 1156 | }, 1157 | }, 1158 | &ruleRefExpr{ 1159 | pos: position{line: 330, col: 25, offset: 12405}, 1160 | name: "Skip", 1161 | }, 1162 | &litMatcher{ 1163 | pos: position{line: 330, col: 30, offset: 12410}, 1164 | val: "]", 1165 | ignoreCase: false, 1166 | }, 1167 | }, 1168 | }, 1169 | }, 1170 | }, 1171 | }, 1172 | }, 1173 | { 1174 | name: "ListTail", 1175 | pos: position{line: 336, col: 1, offset: 12568}, 1176 | expr: &actionExpr{ 1177 | pos: position{line: 336, col: 13, offset: 12580}, 1178 | run: (*parser).callonListTail1, 1179 | expr: &labeledExpr{ 1180 | pos: position{line: 336, col: 13, offset: 12580}, 1181 | label: "v", 1182 | expr: &ruleRefExpr{ 1183 | pos: position{line: 336, col: 15, offset: 12582}, 1184 | name: "Variable", 1185 | }, 1186 | }, 1187 | }, 1188 | }, 1189 | { 1190 | name: "Structure", 1191 | pos: position{line: 341, col: 1, offset: 12704}, 1192 | expr: &actionExpr{ 1193 | pos: position{line: 341, col: 14, offset: 12717}, 1194 | run: (*parser).callonStructure1, 1195 | expr: &seqExpr{ 1196 | pos: position{line: 341, col: 14, offset: 12717}, 1197 | exprs: []interface{}{ 1198 | &labeledExpr{ 1199 | pos: position{line: 341, col: 14, offset: 12717}, 1200 | label: "a", 1201 | expr: &ruleRefExpr{ 1202 | pos: position{line: 341, col: 16, offset: 12719}, 1203 | name: "Atom", 1204 | }, 1205 | }, 1206 | &ruleRefExpr{ 1207 | pos: position{line: 341, col: 21, offset: 12724}, 1208 | name: "Skip", 1209 | }, 1210 | &litMatcher{ 1211 | pos: position{line: 341, col: 26, offset: 12729}, 1212 | val: "(", 1213 | ignoreCase: false, 1214 | }, 1215 | &ruleRefExpr{ 1216 | pos: position{line: 341, col: 30, offset: 12733}, 1217 | name: "Skip", 1218 | }, 1219 | &labeledExpr{ 1220 | pos: position{line: 341, col: 35, offset: 12738}, 1221 | label: "ts", 1222 | expr: &ruleRefExpr{ 1223 | pos: position{line: 341, col: 38, offset: 12741}, 1224 | name: "TermList", 1225 | }, 1226 | }, 1227 | &ruleRefExpr{ 1228 | pos: position{line: 341, col: 47, offset: 12750}, 1229 | name: "Skip", 1230 | }, 1231 | &litMatcher{ 1232 | pos: position{line: 341, col: 52, offset: 12755}, 1233 | val: ")", 1234 | ignoreCase: false, 1235 | }, 1236 | }, 1237 | }, 1238 | }, 1239 | }, 1240 | { 1241 | name: "Variable", 1242 | pos: position{line: 346, col: 1, offset: 12871}, 1243 | expr: &actionExpr{ 1244 | pos: position{line: 346, col: 13, offset: 12883}, 1245 | run: (*parser).callonVariable1, 1246 | expr: &seqExpr{ 1247 | pos: position{line: 346, col: 13, offset: 12883}, 1248 | exprs: []interface{}{ 1249 | &ruleRefExpr{ 1250 | pos: position{line: 346, col: 13, offset: 12883}, 1251 | name: "Uppercase_letter", 1252 | }, 1253 | &ruleRefExpr{ 1254 | pos: position{line: 346, col: 30, offset: 12900}, 1255 | name: "Symbol_trailer", 1256 | }, 1257 | }, 1258 | }, 1259 | }, 1260 | }, 1261 | { 1262 | name: "Atom", 1263 | pos: position{line: 351, col: 1, offset: 13025}, 1264 | expr: &choiceExpr{ 1265 | pos: position{line: 351, col: 9, offset: 13033}, 1266 | alternatives: []interface{}{ 1267 | &actionExpr{ 1268 | pos: position{line: 351, col: 9, offset: 13033}, 1269 | run: (*parser).callonAtom2, 1270 | expr: &ruleRefExpr{ 1271 | pos: position{line: 351, col: 9, offset: 13033}, 1272 | name: "Small_atom", 1273 | }, 1274 | }, 1275 | &actionExpr{ 1276 | pos: position{line: 353, col: 5, offset: 13111}, 1277 | run: (*parser).callonAtom4, 1278 | expr: &ruleRefExpr{ 1279 | pos: position{line: 353, col: 5, offset: 13111}, 1280 | name: "Single_quoted_string", 1281 | }, 1282 | }, 1283 | }, 1284 | }, 1285 | }, 1286 | { 1287 | name: "Single_quoted_string", 1288 | pos: position{line: 364, col: 1, offset: 13355}, 1289 | expr: &seqExpr{ 1290 | pos: position{line: 364, col: 25, offset: 13379}, 1291 | exprs: []interface{}{ 1292 | &litMatcher{ 1293 | pos: position{line: 364, col: 25, offset: 13379}, 1294 | val: "'", 1295 | ignoreCase: false, 1296 | }, 1297 | &zeroOrMoreExpr{ 1298 | pos: position{line: 364, col: 29, offset: 13383}, 1299 | expr: &ruleRefExpr{ 1300 | pos: position{line: 364, col: 29, offset: 13383}, 1301 | name: "Single_quoted_string_char", 1302 | }, 1303 | }, 1304 | &litMatcher{ 1305 | pos: position{line: 364, col: 56, offset: 13410}, 1306 | val: "'", 1307 | ignoreCase: false, 1308 | }, 1309 | }, 1310 | }, 1311 | }, 1312 | { 1313 | name: "Single_quoted_string_char", 1314 | pos: position{line: 366, col: 1, offset: 13415}, 1315 | expr: &choiceExpr{ 1316 | pos: position{line: 366, col: 30, offset: 13444}, 1317 | alternatives: []interface{}{ 1318 | &ruleRefExpr{ 1319 | pos: position{line: 366, col: 30, offset: 13444}, 1320 | name: "Character", 1321 | }, 1322 | &seqExpr{ 1323 | pos: position{line: 366, col: 42, offset: 13456}, 1324 | exprs: []interface{}{ 1325 | &litMatcher{ 1326 | pos: position{line: 366, col: 42, offset: 13456}, 1327 | val: "\\", 1328 | ignoreCase: false, 1329 | }, 1330 | &anyMatcher{ 1331 | line: 366, col: 47, offset: 13461, 1332 | }, 1333 | }, 1334 | }, 1335 | }, 1336 | }, 1337 | }, 1338 | { 1339 | name: "Small_atom", 1340 | pos: position{line: 368, col: 1, offset: 13464}, 1341 | expr: &actionExpr{ 1342 | pos: position{line: 368, col: 15, offset: 13478}, 1343 | run: (*parser).callonSmall_atom1, 1344 | expr: &seqExpr{ 1345 | pos: position{line: 368, col: 15, offset: 13478}, 1346 | exprs: []interface{}{ 1347 | &ruleRefExpr{ 1348 | pos: position{line: 368, col: 15, offset: 13478}, 1349 | name: "Lowercase_letter", 1350 | }, 1351 | &ruleRefExpr{ 1352 | pos: position{line: 368, col: 32, offset: 13495}, 1353 | name: "Symbol_trailer", 1354 | }, 1355 | }, 1356 | }, 1357 | }, 1358 | }, 1359 | { 1360 | name: "Symbol_trailer", 1361 | pos: position{line: 372, col: 1, offset: 13550}, 1362 | expr: &zeroOrMoreExpr{ 1363 | pos: position{line: 372, col: 19, offset: 13568}, 1364 | expr: &choiceExpr{ 1365 | pos: position{line: 372, col: 20, offset: 13569}, 1366 | alternatives: []interface{}{ 1367 | &ruleRefExpr{ 1368 | pos: position{line: 372, col: 20, offset: 13569}, 1369 | name: "Lowercase_letter", 1370 | }, 1371 | &ruleRefExpr{ 1372 | pos: position{line: 372, col: 39, offset: 13588}, 1373 | name: "Uppercase_letter", 1374 | }, 1375 | &ruleRefExpr{ 1376 | pos: position{line: 372, col: 58, offset: 13607}, 1377 | name: "Digit", 1378 | }, 1379 | }, 1380 | }, 1381 | }, 1382 | }, 1383 | { 1384 | name: "Character", 1385 | pos: position{line: 374, col: 1, offset: 13616}, 1386 | expr: &choiceExpr{ 1387 | pos: position{line: 374, col: 14, offset: 13629}, 1388 | alternatives: []interface{}{ 1389 | &ruleRefExpr{ 1390 | pos: position{line: 374, col: 14, offset: 13629}, 1391 | name: "Lowercase_letter", 1392 | }, 1393 | &ruleRefExpr{ 1394 | pos: position{line: 374, col: 33, offset: 13648}, 1395 | name: "Uppercase_letter", 1396 | }, 1397 | &ruleRefExpr{ 1398 | pos: position{line: 374, col: 52, offset: 13667}, 1399 | name: "Digit", 1400 | }, 1401 | &ruleRefExpr{ 1402 | pos: position{line: 374, col: 60, offset: 13675}, 1403 | name: "Not_single_quote", 1404 | }, 1405 | }, 1406 | }, 1407 | }, 1408 | { 1409 | name: "Lowercase_letter", 1410 | pos: position{line: 376, col: 1, offset: 13693}, 1411 | expr: &charClassMatcher{ 1412 | pos: position{line: 376, col: 21, offset: 13713}, 1413 | val: "[\\p{Ll}]", 1414 | classes: []*unicode.RangeTable{rangeTable("Ll")}, 1415 | ignoreCase: false, 1416 | inverted: false, 1417 | }, 1418 | }, 1419 | { 1420 | name: "Uppercase_letter", 1421 | pos: position{line: 378, col: 1, offset: 13723}, 1422 | expr: &charClassMatcher{ 1423 | pos: position{line: 378, col: 21, offset: 13743}, 1424 | val: "[\\p{Lu}_]", 1425 | chars: []rune{'_'}, 1426 | classes: []*unicode.RangeTable{rangeTable("Lu")}, 1427 | ignoreCase: false, 1428 | inverted: false, 1429 | }, 1430 | }, 1431 | { 1432 | name: "Digit", 1433 | pos: position{line: 380, col: 1, offset: 13754}, 1434 | expr: &charClassMatcher{ 1435 | pos: position{line: 380, col: 10, offset: 13763}, 1436 | val: "[\\p{Nd}]", 1437 | classes: []*unicode.RangeTable{rangeTable("Nd")}, 1438 | ignoreCase: false, 1439 | inverted: false, 1440 | }, 1441 | }, 1442 | { 1443 | name: "Whitespace", 1444 | pos: position{line: 382, col: 1, offset: 13773}, 1445 | expr: &charClassMatcher{ 1446 | pos: position{line: 382, col: 15, offset: 13787}, 1447 | val: "[\\p{Zs}\\n\\r\\t]", 1448 | chars: []rune{'\n', '\r', '\t'}, 1449 | classes: []*unicode.RangeTable{rangeTable("Zs")}, 1450 | ignoreCase: false, 1451 | inverted: false, 1452 | }, 1453 | }, 1454 | { 1455 | name: "One_line_comment", 1456 | pos: position{line: 384, col: 1, offset: 13803}, 1457 | expr: &seqExpr{ 1458 | pos: position{line: 384, col: 21, offset: 13823}, 1459 | exprs: []interface{}{ 1460 | &litMatcher{ 1461 | pos: position{line: 384, col: 21, offset: 13823}, 1462 | val: "%", 1463 | ignoreCase: false, 1464 | }, 1465 | &zeroOrMoreExpr{ 1466 | pos: position{line: 384, col: 25, offset: 13827}, 1467 | expr: &charClassMatcher{ 1468 | pos: position{line: 384, col: 25, offset: 13827}, 1469 | val: "[^\\n\\r]", 1470 | chars: []rune{'\n', '\r'}, 1471 | ignoreCase: false, 1472 | inverted: true, 1473 | }, 1474 | }, 1475 | &zeroOrOneExpr{ 1476 | pos: position{line: 384, col: 34, offset: 13836}, 1477 | expr: &litMatcher{ 1478 | pos: position{line: 384, col: 34, offset: 13836}, 1479 | val: "\r", 1480 | ignoreCase: false, 1481 | }, 1482 | }, 1483 | &litMatcher{ 1484 | pos: position{line: 384, col: 40, offset: 13842}, 1485 | val: "\n", 1486 | ignoreCase: false, 1487 | }, 1488 | }, 1489 | }, 1490 | }, 1491 | { 1492 | name: "Multi_line_comment", 1493 | pos: position{line: 386, col: 1, offset: 13848}, 1494 | expr: &seqExpr{ 1495 | pos: position{line: 386, col: 23, offset: 13870}, 1496 | exprs: []interface{}{ 1497 | &litMatcher{ 1498 | pos: position{line: 386, col: 23, offset: 13870}, 1499 | val: "/*", 1500 | ignoreCase: false, 1501 | }, 1502 | &zeroOrMoreExpr{ 1503 | pos: position{line: 386, col: 28, offset: 13875}, 1504 | expr: &choiceExpr{ 1505 | pos: position{line: 386, col: 29, offset: 13876}, 1506 | alternatives: []interface{}{ 1507 | &ruleRefExpr{ 1508 | pos: position{line: 386, col: 29, offset: 13876}, 1509 | name: "Multi_line_comment", 1510 | }, 1511 | &seqExpr{ 1512 | pos: position{line: 386, col: 50, offset: 13897}, 1513 | exprs: []interface{}{ 1514 | &litMatcher{ 1515 | pos: position{line: 386, col: 50, offset: 13897}, 1516 | val: "*", 1517 | ignoreCase: false, 1518 | }, 1519 | ¬Expr{ 1520 | pos: position{line: 386, col: 54, offset: 13901}, 1521 | expr: &litMatcher{ 1522 | pos: position{line: 386, col: 55, offset: 13902}, 1523 | val: "/", 1524 | ignoreCase: false, 1525 | }, 1526 | }, 1527 | }, 1528 | }, 1529 | &charClassMatcher{ 1530 | pos: position{line: 386, col: 61, offset: 13908}, 1531 | val: "[^*]", 1532 | chars: []rune{'*'}, 1533 | ignoreCase: false, 1534 | inverted: true, 1535 | }, 1536 | }, 1537 | }, 1538 | }, 1539 | &litMatcher{ 1540 | pos: position{line: 386, col: 68, offset: 13915}, 1541 | val: "*/", 1542 | ignoreCase: false, 1543 | }, 1544 | }, 1545 | }, 1546 | }, 1547 | { 1548 | name: "Skip", 1549 | pos: position{line: 389, col: 1, offset: 13998}, 1550 | expr: &zeroOrMoreExpr{ 1551 | pos: position{line: 389, col: 9, offset: 14006}, 1552 | expr: &choiceExpr{ 1553 | pos: position{line: 389, col: 10, offset: 14007}, 1554 | alternatives: []interface{}{ 1555 | &ruleRefExpr{ 1556 | pos: position{line: 389, col: 10, offset: 14007}, 1557 | name: "Whitespace", 1558 | }, 1559 | &ruleRefExpr{ 1560 | pos: position{line: 389, col: 23, offset: 14020}, 1561 | name: "One_line_comment", 1562 | }, 1563 | &ruleRefExpr{ 1564 | pos: position{line: 389, col: 42, offset: 14039}, 1565 | name: "Multi_line_comment", 1566 | }, 1567 | }, 1568 | }, 1569 | }, 1570 | }, 1571 | { 1572 | name: "Numeral", 1573 | pos: position{line: 392, col: 1, offset: 14104}, 1574 | expr: &actionExpr{ 1575 | pos: position{line: 392, col: 12, offset: 14115}, 1576 | run: (*parser).callonNumeral1, 1577 | expr: &oneOrMoreExpr{ 1578 | pos: position{line: 392, col: 12, offset: 14115}, 1579 | expr: &ruleRefExpr{ 1580 | pos: position{line: 392, col: 12, offset: 14115}, 1581 | name: "Digit", 1582 | }, 1583 | }, 1584 | }, 1585 | }, 1586 | { 1587 | name: "Not_single_quote", 1588 | pos: position{line: 406, col: 1, offset: 14436}, 1589 | expr: &charClassMatcher{ 1590 | pos: position{line: 406, col: 21, offset: 14456}, 1591 | val: "[^']", 1592 | chars: []rune{'\''}, 1593 | ignoreCase: false, 1594 | inverted: true, 1595 | }, 1596 | }, 1597 | { 1598 | name: "EOF", 1599 | pos: position{line: 408, col: 1, offset: 14462}, 1600 | expr: ¬Expr{ 1601 | pos: position{line: 408, col: 8, offset: 14469}, 1602 | expr: &anyMatcher{ 1603 | line: 408, col: 9, offset: 14470, 1604 | }, 1605 | }, 1606 | }, 1607 | }, 1608 | } 1609 | 1610 | func (c *current) onProgram2(cl, q interface{}) (interface{}, error) { 1611 | // Append the query to the list of clauses. 1612 | prog := c.ConstructList(ProgramType, nil, cl, nil) 1613 | prog.Children = append(prog.Children, q.(*ASTNode)) 1614 | return prog, nil 1615 | } 1616 | 1617 | func (p *parser) callonProgram2() (interface{}, error) { 1618 | stack := p.vstack[len(p.vstack)-1] 1619 | _ = stack 1620 | return p.cur.onProgram2(stack["cl"], stack["q"]) 1621 | } 1622 | 1623 | func (c *current) onProgram14(cl interface{}) (interface{}, error) { 1624 | return c.ConstructList(ProgramType, nil, cl, nil), nil 1625 | } 1626 | 1627 | func (p *parser) callonProgram14() (interface{}, error) { 1628 | stack := p.vstack[len(p.vstack)-1] 1629 | _ = stack 1630 | return p.cur.onProgram14(stack["cl"]) 1631 | } 1632 | 1633 | func (c *current) onQuery1(ps interface{}) (interface{}, error) { 1634 | // Acquire a list of all variables that appear in the query. 1635 | vSet := make(map[string]Empty) 1636 | for _, v := range ps.(*ASTNode).FindByType(VariableType) { 1637 | vSet[v.Value.(string)] = Empty{} 1638 | } 1639 | vList := make([]string, 0, len(vSet)) 1640 | for v := range vSet { 1641 | vList = append(vList, v) 1642 | } 1643 | 1644 | // Insert a head predicate so we can process the query as if it were a 1645 | // clause. 1646 | pKids := make([]*ASTNode, 0, len(vList)+1) 1647 | pKids = append(pKids, &ASTNode{ 1648 | Type: AtomType, 1649 | Value: "Query", 1650 | Text: "Query", 1651 | }) 1652 | for _, v := range vList { 1653 | vr := &ASTNode{ 1654 | Type: VariableType, 1655 | Value: v, 1656 | Text: v, 1657 | } 1658 | trm := &ASTNode{ 1659 | Type: TermType, 1660 | Value: v, 1661 | Text: v, 1662 | Children: []*ASTNode{vr}, 1663 | } 1664 | pKids = append(pKids, trm) 1665 | } 1666 | hd := &ASTNode{ 1667 | Type: PredicateType, 1668 | Value: "Query", 1669 | Text: "Query", 1670 | Children: pKids, 1671 | } 1672 | name := fmt.Sprintf("Query/%d", len(vList)) 1673 | return c.ConstructList(QueryType, name, hd, ps), nil 1674 | } 1675 | 1676 | func (p *parser) callonQuery1() (interface{}, error) { 1677 | stack := p.vstack[len(p.vstack)-1] 1678 | _ = stack 1679 | return p.cur.onQuery1(stack["ps"]) 1680 | } 1681 | 1682 | func (c *current) onClauseList2(cl, cls interface{}) (interface{}, error) { 1683 | return c.ConstructList(ClauseListType, nil, cl, cls), nil 1684 | } 1685 | 1686 | func (p *parser) callonClauseList2() (interface{}, error) { 1687 | stack := p.vstack[len(p.vstack)-1] 1688 | _ = stack 1689 | return p.cur.onClauseList2(stack["cl"], stack["cls"]) 1690 | } 1691 | 1692 | func (c *current) onClauseList9(cl interface{}) (interface{}, error) { 1693 | return c.ConstructList(ClauseListType, nil, cl, nil), nil 1694 | } 1695 | 1696 | func (p *parser) callonClauseList9() (interface{}, error) { 1697 | stack := p.vstack[len(p.vstack)-1] 1698 | _ = stack 1699 | return p.cur.onClauseList9(stack["cl"]) 1700 | } 1701 | 1702 | func (c *current) onClause2(p, ps interface{}) (interface{}, error) { 1703 | // Rule 1704 | pn := p.(*ASTNode) 1705 | name := fmt.Sprintf("%s/%d", pn.Children[0].Value.(string), len(pn.Children)-1) 1706 | return c.ConstructList(ClauseType, name, p, ps), nil 1707 | } 1708 | 1709 | func (p *parser) callonClause2() (interface{}, error) { 1710 | stack := p.vstack[len(p.vstack)-1] 1711 | _ = stack 1712 | return p.cur.onClause2(stack["p"], stack["ps"]) 1713 | } 1714 | 1715 | func (c *current) onClause13(p interface{}) (interface{}, error) { 1716 | // Fact 1717 | pn := p.(*ASTNode) 1718 | name := fmt.Sprintf("%s/%d", pn.Children[0].Value.(string), len(pn.Children)-1) 1719 | return c.ConstructList(ClauseType, name, p, nil), nil 1720 | } 1721 | 1722 | func (p *parser) callonClause13() (interface{}, error) { 1723 | stack := p.vstack[len(p.vstack)-1] 1724 | _ = stack 1725 | return p.cur.onClause13(stack["p"]) 1726 | } 1727 | 1728 | func (c *current) onPredicateList2(p, ps interface{}) (interface{}, error) { 1729 | return c.ConstructList(PredicateListType, nil, p, ps), nil 1730 | } 1731 | 1732 | func (p *parser) callonPredicateList2() (interface{}, error) { 1733 | stack := p.vstack[len(p.vstack)-1] 1734 | _ = stack 1735 | return p.cur.onPredicateList2(stack["p"], stack["ps"]) 1736 | } 1737 | 1738 | func (c *current) onPredicateList11(p interface{}) (interface{}, error) { 1739 | return c.ConstructList(PredicateListType, nil, p, nil), nil 1740 | } 1741 | 1742 | func (p *parser) callonPredicateList11() (interface{}, error) { 1743 | stack := p.vstack[len(p.vstack)-1] 1744 | _ = stack 1745 | return p.cur.onPredicateList11(stack["p"]) 1746 | } 1747 | 1748 | func (c *current) onPredicate2(r interface{}) (interface{}, error) { 1749 | return c.ConstructList(PredicateType, nil, r, nil), nil 1750 | } 1751 | 1752 | func (p *parser) callonPredicate2() (interface{}, error) { 1753 | stack := p.vstack[len(p.vstack)-1] 1754 | _ = stack 1755 | return p.cur.onPredicate2(stack["r"]) 1756 | } 1757 | 1758 | func (c *current) onPredicate5(a, ts interface{}) (interface{}, error) { 1759 | return c.ConstructList(PredicateType, nil, a, ts), nil 1760 | } 1761 | 1762 | func (p *parser) callonPredicate5() (interface{}, error) { 1763 | stack := p.vstack[len(p.vstack)-1] 1764 | _ = stack 1765 | return p.cur.onPredicate5(stack["a"], stack["ts"]) 1766 | } 1767 | 1768 | func (c *current) onPredicate16(a interface{}) (interface{}, error) { 1769 | return c.ConstructList(PredicateType, nil, a, nil), nil 1770 | } 1771 | 1772 | func (p *parser) callonPredicate16() (interface{}, error) { 1773 | stack := p.vstack[len(p.vstack)-1] 1774 | _ = stack 1775 | return p.cur.onPredicate16(stack["a"]) 1776 | } 1777 | 1778 | func (c *current) onRelation2(e1, o, e2 interface{}) (interface{}, error) { 1779 | return c.PrepareRelation(e1, o, e2), nil 1780 | } 1781 | 1782 | func (p *parser) callonRelation2() (interface{}, error) { 1783 | stack := p.vstack[len(p.vstack)-1] 1784 | _ = stack 1785 | return p.cur.onRelation2(stack["e1"], stack["o"], stack["e2"]) 1786 | } 1787 | 1788 | func (c *current) onRelation12(e1, o, e2 interface{}) (interface{}, error) { 1789 | return c.PrepareRelation(e1, o, e2), nil 1790 | } 1791 | 1792 | func (p *parser) callonRelation12() (interface{}, error) { 1793 | stack := p.vstack[len(p.vstack)-1] 1794 | _ = stack 1795 | return p.cur.onRelation12(stack["e1"], stack["o"], stack["e2"]) 1796 | } 1797 | 1798 | func (c *current) onRelationOperator1() (interface{}, error) { 1799 | return c.ConstructList(RelationOpType, nil, nil, nil), nil 1800 | } 1801 | 1802 | func (p *parser) callonRelationOperator1() (interface{}, error) { 1803 | stack := p.vstack[len(p.vstack)-1] 1804 | _ = stack 1805 | return p.cur.onRelationOperator1() 1806 | } 1807 | 1808 | func (c *current) onEqualityOperator1() (interface{}, error) { 1809 | return c.ConstructList(RelationOpType, nil, nil, nil), nil 1810 | } 1811 | 1812 | func (p *parser) callonEqualityOperator1() (interface{}, error) { 1813 | stack := p.vstack[len(p.vstack)-1] 1814 | _ = stack 1815 | return p.cur.onEqualityOperator1() 1816 | } 1817 | 1818 | func (c *current) onAdditiveExpr2(e1, o, e2 interface{}) (interface{}, error) { 1819 | kids := []*ASTNode{ 1820 | e1.(*ASTNode), 1821 | o.(*ASTNode), 1822 | e2.(*ASTNode), 1823 | } 1824 | node := ASTNode{ 1825 | Type: AdditiveExprType, 1826 | Text: string(c.text), 1827 | Value: kids[1].Value, 1828 | Pos: c.pos, 1829 | Children: kids, 1830 | } 1831 | return &node, nil 1832 | } 1833 | 1834 | func (p *parser) callonAdditiveExpr2() (interface{}, error) { 1835 | stack := p.vstack[len(p.vstack)-1] 1836 | _ = stack 1837 | return p.cur.onAdditiveExpr2(stack["e1"], stack["o"], stack["e2"]) 1838 | } 1839 | 1840 | func (c *current) onAdditiveExpr12(e interface{}) (interface{}, error) { 1841 | return c.ConstructList(AdditiveExprType, "", e, nil), nil 1842 | } 1843 | 1844 | func (p *parser) callonAdditiveExpr12() (interface{}, error) { 1845 | stack := p.vstack[len(p.vstack)-1] 1846 | _ = stack 1847 | return p.cur.onAdditiveExpr12(stack["e"]) 1848 | } 1849 | 1850 | func (c *current) onAdditiveOperator1() (interface{}, error) { 1851 | return c.ConstructList(AdditiveOpType, nil, nil, nil), nil 1852 | } 1853 | 1854 | func (p *parser) callonAdditiveOperator1() (interface{}, error) { 1855 | stack := p.vstack[len(p.vstack)-1] 1856 | _ = stack 1857 | return p.cur.onAdditiveOperator1() 1858 | } 1859 | 1860 | func (c *current) onMultiplicativeExpr2(e1, o, e2 interface{}) (interface{}, error) { 1861 | kids := []*ASTNode{ 1862 | e1.(*ASTNode), 1863 | o.(*ASTNode), 1864 | e2.(*ASTNode), 1865 | } 1866 | node := ASTNode{ 1867 | Type: MultiplicativeExprType, 1868 | Text: string(c.text), 1869 | Value: kids[1].Value, 1870 | Pos: c.pos, 1871 | Children: kids, 1872 | } 1873 | return &node, nil 1874 | } 1875 | 1876 | func (p *parser) callonMultiplicativeExpr2() (interface{}, error) { 1877 | stack := p.vstack[len(p.vstack)-1] 1878 | _ = stack 1879 | return p.cur.onMultiplicativeExpr2(stack["e1"], stack["o"], stack["e2"]) 1880 | } 1881 | 1882 | func (c *current) onMultiplicativeExpr12(e interface{}) (interface{}, error) { 1883 | return c.ConstructList(MultiplicativeExprType, "", e, nil), nil 1884 | } 1885 | 1886 | func (p *parser) callonMultiplicativeExpr12() (interface{}, error) { 1887 | stack := p.vstack[len(p.vstack)-1] 1888 | _ = stack 1889 | return p.cur.onMultiplicativeExpr12(stack["e"]) 1890 | } 1891 | 1892 | func (c *current) onMultiplicativeOperator1() (interface{}, error) { 1893 | return c.ConstructList(MultiplicativeOpType, nil, nil, nil), nil 1894 | } 1895 | 1896 | func (p *parser) callonMultiplicativeOperator1() (interface{}, error) { 1897 | stack := p.vstack[len(p.vstack)-1] 1898 | _ = stack 1899 | return p.cur.onMultiplicativeOperator1() 1900 | } 1901 | 1902 | func (c *current) onUnaryExpr2(o, e interface{}) (interface{}, error) { 1903 | kids := []*ASTNode{ 1904 | o.(*ASTNode), 1905 | e.(*ASTNode), 1906 | } 1907 | node := ASTNode{ 1908 | Type: UnaryExprType, 1909 | Text: string(c.text), 1910 | Value: kids[1].Value, 1911 | Pos: c.pos, 1912 | Children: kids, 1913 | } 1914 | return &node, nil 1915 | } 1916 | 1917 | func (p *parser) callonUnaryExpr2() (interface{}, error) { 1918 | stack := p.vstack[len(p.vstack)-1] 1919 | _ = stack 1920 | return p.cur.onUnaryExpr2(stack["o"], stack["e"]) 1921 | } 1922 | 1923 | func (c *current) onUnaryExpr9(e interface{}) (interface{}, error) { 1924 | return c.ConstructList(UnaryExprType, "", e, nil), nil 1925 | } 1926 | 1927 | func (p *parser) callonUnaryExpr9() (interface{}, error) { 1928 | stack := p.vstack[len(p.vstack)-1] 1929 | _ = stack 1930 | return p.cur.onUnaryExpr9(stack["e"]) 1931 | } 1932 | 1933 | func (c *current) onUnaryOperator1() (interface{}, error) { 1934 | return c.ConstructList(UnaryOpType, nil, nil, nil), nil 1935 | } 1936 | 1937 | func (p *parser) callonUnaryOperator1() (interface{}, error) { 1938 | stack := p.vstack[len(p.vstack)-1] 1939 | _ = stack 1940 | return p.cur.onUnaryOperator1() 1941 | } 1942 | 1943 | func (c *current) onPrimaryExpr2(a interface{}) (interface{}, error) { 1944 | return c.ConstructList(PrimaryExprType, "()", a, nil), nil 1945 | } 1946 | 1947 | func (p *parser) callonPrimaryExpr2() (interface{}, error) { 1948 | stack := p.vstack[len(p.vstack)-1] 1949 | _ = stack 1950 | return p.cur.onPrimaryExpr2(stack["a"]) 1951 | } 1952 | 1953 | func (c *current) onPrimaryExpr10(n interface{}) (interface{}, error) { 1954 | return c.ConstructList(PrimaryExprType, "", n, nil), nil 1955 | } 1956 | 1957 | func (p *parser) callonPrimaryExpr10() (interface{}, error) { 1958 | stack := p.vstack[len(p.vstack)-1] 1959 | _ = stack 1960 | return p.cur.onPrimaryExpr10(stack["n"]) 1961 | } 1962 | 1963 | func (c *current) onPrimaryExpr13(v interface{}) (interface{}, error) { 1964 | return c.ConstructList(PrimaryExprType, "", v, nil), nil 1965 | } 1966 | 1967 | func (p *parser) callonPrimaryExpr13() (interface{}, error) { 1968 | stack := p.vstack[len(p.vstack)-1] 1969 | _ = stack 1970 | return p.cur.onPrimaryExpr13(stack["v"]) 1971 | } 1972 | 1973 | func (c *current) onTermList2(t, ts interface{}) (interface{}, error) { 1974 | return c.ConstructList(TermListType, nil, t, ts), nil 1975 | } 1976 | 1977 | func (p *parser) callonTermList2() (interface{}, error) { 1978 | stack := p.vstack[len(p.vstack)-1] 1979 | _ = stack 1980 | return p.cur.onTermList2(stack["t"], stack["ts"]) 1981 | } 1982 | 1983 | func (c *current) onTermList11(t interface{}) (interface{}, error) { 1984 | return c.ConstructList(TermListType, nil, t, nil), nil 1985 | } 1986 | 1987 | func (p *parser) callonTermList11() (interface{}, error) { 1988 | stack := p.vstack[len(p.vstack)-1] 1989 | _ = stack 1990 | return p.cur.onTermList11(stack["t"]) 1991 | } 1992 | 1993 | func (c *current) onTerm1(child interface{}) (interface{}, error) { 1994 | return c.ConstructList(TermType, nil, child, nil), nil 1995 | } 1996 | 1997 | func (p *parser) callonTerm1() (interface{}, error) { 1998 | stack := p.vstack[len(p.vstack)-1] 1999 | _ = stack 2000 | return p.cur.onTerm1(stack["child"]) 2001 | } 2002 | 2003 | func (c *current) onList2(h, t interface{}) (interface{}, error) { 2004 | // Unbounded extent 2005 | return c.ConstructList(ListType, "[|]", h, t), nil 2006 | } 2007 | 2008 | func (p *parser) callonList2() (interface{}, error) { 2009 | stack := p.vstack[len(p.vstack)-1] 2010 | _ = stack 2011 | return p.cur.onList2(stack["h"], stack["t"]) 2012 | } 2013 | 2014 | func (c *current) onList15(h interface{}) (interface{}, error) { 2015 | // Bounded extent 2016 | return c.ConstructList(ListType, "[]", h, nil), nil 2017 | } 2018 | 2019 | func (p *parser) callonList15() (interface{}, error) { 2020 | stack := p.vstack[len(p.vstack)-1] 2021 | _ = stack 2022 | return p.cur.onList15(stack["h"]) 2023 | } 2024 | 2025 | func (c *current) onListTail1(v interface{}) (interface{}, error) { 2026 | return c.ConstructList(ListTailType, nil, v, nil), nil 2027 | } 2028 | 2029 | func (p *parser) callonListTail1() (interface{}, error) { 2030 | stack := p.vstack[len(p.vstack)-1] 2031 | _ = stack 2032 | return p.cur.onListTail1(stack["v"]) 2033 | } 2034 | 2035 | func (c *current) onStructure1(a, ts interface{}) (interface{}, error) { 2036 | return c.ConstructList(StructureType, nil, a, ts), nil 2037 | } 2038 | 2039 | func (p *parser) callonStructure1() (interface{}, error) { 2040 | stack := p.vstack[len(p.vstack)-1] 2041 | _ = stack 2042 | return p.cur.onStructure1(stack["a"], stack["ts"]) 2043 | } 2044 | 2045 | func (c *current) onVariable1() (interface{}, error) { 2046 | return c.ConstructList(VariableType, nil, nil, nil), nil 2047 | } 2048 | 2049 | func (p *parser) callonVariable1() (interface{}, error) { 2050 | stack := p.vstack[len(p.vstack)-1] 2051 | _ = stack 2052 | return p.cur.onVariable1() 2053 | } 2054 | 2055 | func (c *current) onAtom2() (interface{}, error) { 2056 | return c.ConstructList(AtomType, nil, nil, nil), nil 2057 | } 2058 | 2059 | func (p *parser) callonAtom2() (interface{}, error) { 2060 | stack := p.vstack[len(p.vstack)-1] 2061 | _ = stack 2062 | return p.cur.onAtom2() 2063 | } 2064 | 2065 | func (c *current) onAtom4() (interface{}, error) { 2066 | s := string(c.text) 2067 | node := ASTNode{ 2068 | Type: AtomType, 2069 | Text: s, 2070 | Pos: c.pos, 2071 | Value: s[1 : len(s)-1], 2072 | } 2073 | return &node, nil 2074 | } 2075 | 2076 | func (p *parser) callonAtom4() (interface{}, error) { 2077 | stack := p.vstack[len(p.vstack)-1] 2078 | _ = stack 2079 | return p.cur.onAtom4() 2080 | } 2081 | 2082 | func (c *current) onSmall_atom1() (interface{}, error) { 2083 | return string(c.text), nil 2084 | } 2085 | 2086 | func (p *parser) callonSmall_atom1() (interface{}, error) { 2087 | stack := p.vstack[len(p.vstack)-1] 2088 | _ = stack 2089 | return p.cur.onSmall_atom1() 2090 | } 2091 | 2092 | func (c *current) onNumeral1() (interface{}, error) { 2093 | num, err := strconv.Atoi(string(c.text)) 2094 | if err != nil { 2095 | return nil, err 2096 | } 2097 | node := ASTNode{ 2098 | Type: NumeralType, 2099 | Text: string(c.text), 2100 | Value: num, 2101 | Pos: c.pos, 2102 | } 2103 | return &node, nil 2104 | } 2105 | 2106 | func (p *parser) callonNumeral1() (interface{}, error) { 2107 | stack := p.vstack[len(p.vstack)-1] 2108 | _ = stack 2109 | return p.cur.onNumeral1() 2110 | } 2111 | 2112 | var ( 2113 | // errNoRule is returned when the grammar to parse has no rule. 2114 | errNoRule = errors.New("grammar has no rule") 2115 | 2116 | // errInvalidEntrypoint is returned when the specified entrypoint rule 2117 | // does not exit. 2118 | errInvalidEntrypoint = errors.New("invalid entrypoint") 2119 | 2120 | // errInvalidEncoding is returned when the source is not properly 2121 | // utf8-encoded. 2122 | errInvalidEncoding = errors.New("invalid encoding") 2123 | 2124 | // errMaxExprCnt is used to signal that the maximum number of 2125 | // expressions have been parsed. 2126 | errMaxExprCnt = errors.New("max number of expresssions parsed") 2127 | ) 2128 | 2129 | // Option is a function that can set an option on the parser. It returns 2130 | // the previous setting as an Option. 2131 | type Option func(*parser) Option 2132 | 2133 | // MaxExpressions creates an Option to stop parsing after the provided 2134 | // number of expressions have been parsed, if the value is 0 then the parser will 2135 | // parse for as many steps as needed (possibly an infinite number). 2136 | // 2137 | // The default for maxExprCnt is 0. 2138 | func MaxExpressions(maxExprCnt uint64) Option { 2139 | return func(p *parser) Option { 2140 | oldMaxExprCnt := p.maxExprCnt 2141 | p.maxExprCnt = maxExprCnt 2142 | return MaxExpressions(oldMaxExprCnt) 2143 | } 2144 | } 2145 | 2146 | // Entrypoint creates an Option to set the rule name to use as entrypoint. 2147 | // The rule name must have been specified in the -alternate-entrypoints 2148 | // if generating the parser with the -optimize-grammar flag, otherwise 2149 | // it may have been optimized out. Passing an empty string sets the 2150 | // entrypoint to the first rule in the grammar. 2151 | // 2152 | // The default is to start parsing at the first rule in the grammar. 2153 | func Entrypoint(ruleName string) Option { 2154 | return func(p *parser) Option { 2155 | oldEntrypoint := p.entrypoint 2156 | p.entrypoint = ruleName 2157 | if ruleName == "" { 2158 | p.entrypoint = g.rules[0].name 2159 | } 2160 | return Entrypoint(oldEntrypoint) 2161 | } 2162 | } 2163 | 2164 | // Statistics adds a user provided Stats struct to the parser to allow 2165 | // the user to process the results after the parsing has finished. 2166 | // Also the key for the "no match" counter is set. 2167 | // 2168 | // Example usage: 2169 | // 2170 | // input := "input" 2171 | // stats := Stats{} 2172 | // _, err := Parse("input-file", []byte(input), Statistics(&stats, "no match")) 2173 | // if err != nil { 2174 | // log.Panicln(err) 2175 | // } 2176 | // b, err := json.MarshalIndent(stats.ChoiceAltCnt, "", " ") 2177 | // if err != nil { 2178 | // log.Panicln(err) 2179 | // } 2180 | // fmt.Println(string(b)) 2181 | // 2182 | func Statistics(stats *Stats, choiceNoMatch string) Option { 2183 | return func(p *parser) Option { 2184 | oldStats := p.Stats 2185 | p.Stats = stats 2186 | oldChoiceNoMatch := p.choiceNoMatch 2187 | p.choiceNoMatch = choiceNoMatch 2188 | if p.Stats.ChoiceAltCnt == nil { 2189 | p.Stats.ChoiceAltCnt = make(map[string]map[string]int) 2190 | } 2191 | return Statistics(oldStats, oldChoiceNoMatch) 2192 | } 2193 | } 2194 | 2195 | // Debug creates an Option to set the debug flag to b. When set to true, 2196 | // debugging information is printed to stdout while parsing. 2197 | // 2198 | // The default is false. 2199 | func Debug(b bool) Option { 2200 | return func(p *parser) Option { 2201 | old := p.debug 2202 | p.debug = b 2203 | return Debug(old) 2204 | } 2205 | } 2206 | 2207 | // Memoize creates an Option to set the memoize flag to b. When set to true, 2208 | // the parser will cache all results so each expression is evaluated only 2209 | // once. This guarantees linear parsing time even for pathological cases, 2210 | // at the expense of more memory and slower times for typical cases. 2211 | // 2212 | // The default is false. 2213 | func Memoize(b bool) Option { 2214 | return func(p *parser) Option { 2215 | old := p.memoize 2216 | p.memoize = b 2217 | return Memoize(old) 2218 | } 2219 | } 2220 | 2221 | // AllowInvalidUTF8 creates an Option to allow invalid UTF-8 bytes. 2222 | // Every invalid UTF-8 byte is treated as a utf8.RuneError (U+FFFD) 2223 | // by character class matchers and is matched by the any matcher. 2224 | // The returned matched value, c.text and c.offset are NOT affected. 2225 | // 2226 | // The default is false. 2227 | func AllowInvalidUTF8(b bool) Option { 2228 | return func(p *parser) Option { 2229 | old := p.allowInvalidUTF8 2230 | p.allowInvalidUTF8 = b 2231 | return AllowInvalidUTF8(old) 2232 | } 2233 | } 2234 | 2235 | // Recover creates an Option to set the recover flag to b. When set to 2236 | // true, this causes the parser to recover from panics and convert it 2237 | // to an error. Setting it to false can be useful while debugging to 2238 | // access the full stack trace. 2239 | // 2240 | // The default is true. 2241 | func Recover(b bool) Option { 2242 | return func(p *parser) Option { 2243 | old := p.recover 2244 | p.recover = b 2245 | return Recover(old) 2246 | } 2247 | } 2248 | 2249 | // GlobalStore creates an Option to set a key to a certain value in 2250 | // the globalStore. 2251 | func GlobalStore(key string, value interface{}) Option { 2252 | return func(p *parser) Option { 2253 | old := p.cur.globalStore[key] 2254 | p.cur.globalStore[key] = value 2255 | return GlobalStore(key, old) 2256 | } 2257 | } 2258 | 2259 | // InitState creates an Option to set a key to a certain value in 2260 | // the global "state" store. 2261 | func InitState(key string, value interface{}) Option { 2262 | return func(p *parser) Option { 2263 | old := p.cur.state[key] 2264 | p.cur.state[key] = value 2265 | return InitState(key, old) 2266 | } 2267 | } 2268 | 2269 | // ParseFile parses the file identified by filename. 2270 | func ParseFile(filename string, opts ...Option) (i interface{}, err error) { 2271 | f, err := os.Open(filename) 2272 | if err != nil { 2273 | return nil, err 2274 | } 2275 | defer func() { 2276 | if closeErr := f.Close(); closeErr != nil { 2277 | err = closeErr 2278 | } 2279 | }() 2280 | return ParseReader(filename, f, opts...) 2281 | } 2282 | 2283 | // ParseReader parses the data from r using filename as information in the 2284 | // error messages. 2285 | func ParseReader(filename string, r io.Reader, opts ...Option) (interface{}, error) { 2286 | b, err := ioutil.ReadAll(r) 2287 | if err != nil { 2288 | return nil, err 2289 | } 2290 | 2291 | return Parse(filename, b, opts...) 2292 | } 2293 | 2294 | // Parse parses the data from b using filename as information in the 2295 | // error messages. 2296 | func Parse(filename string, b []byte, opts ...Option) (interface{}, error) { 2297 | return newParser(filename, b, opts...).parse(g) 2298 | } 2299 | 2300 | // position records a position in the text. 2301 | type position struct { 2302 | line, col, offset int 2303 | } 2304 | 2305 | func (p position) String() string { 2306 | return fmt.Sprintf("%d:%d [%d]", p.line, p.col, p.offset) 2307 | } 2308 | 2309 | // savepoint stores all state required to go back to this point in the 2310 | // parser. 2311 | type savepoint struct { 2312 | position 2313 | rn rune 2314 | w int 2315 | } 2316 | 2317 | type current struct { 2318 | pos position // start position of the match 2319 | text []byte // raw text of the match 2320 | 2321 | // state is a store for arbitrary key,value pairs that the user wants to be 2322 | // tied to the backtracking of the parser. 2323 | // This is always rolled back if a parsing rule fails. 2324 | state storeDict 2325 | 2326 | // globalStore is a general store for the user to store arbitrary key-value 2327 | // pairs that they need to manage and that they do not want tied to the 2328 | // backtracking of the parser. This is only modified by the user and never 2329 | // rolled back by the parser. It is always up to the user to keep this in a 2330 | // consistent state. 2331 | globalStore storeDict 2332 | } 2333 | 2334 | type storeDict map[string]interface{} 2335 | 2336 | // the AST types... 2337 | 2338 | type grammar struct { 2339 | pos position 2340 | rules []*rule 2341 | } 2342 | 2343 | type rule struct { 2344 | pos position 2345 | name string 2346 | displayName string 2347 | expr interface{} 2348 | } 2349 | 2350 | type choiceExpr struct { 2351 | pos position 2352 | alternatives []interface{} 2353 | } 2354 | 2355 | type actionExpr struct { 2356 | pos position 2357 | expr interface{} 2358 | run func(*parser) (interface{}, error) 2359 | } 2360 | 2361 | type recoveryExpr struct { 2362 | pos position 2363 | expr interface{} 2364 | recoverExpr interface{} 2365 | failureLabel []string 2366 | } 2367 | 2368 | type seqExpr struct { 2369 | pos position 2370 | exprs []interface{} 2371 | } 2372 | 2373 | type throwExpr struct { 2374 | pos position 2375 | label string 2376 | } 2377 | 2378 | type labeledExpr struct { 2379 | pos position 2380 | label string 2381 | expr interface{} 2382 | } 2383 | 2384 | type expr struct { 2385 | pos position 2386 | expr interface{} 2387 | } 2388 | 2389 | type andExpr expr 2390 | type notExpr expr 2391 | type zeroOrOneExpr expr 2392 | type zeroOrMoreExpr expr 2393 | type oneOrMoreExpr expr 2394 | 2395 | type ruleRefExpr struct { 2396 | pos position 2397 | name string 2398 | } 2399 | 2400 | type stateCodeExpr struct { 2401 | pos position 2402 | run func(*parser) error 2403 | } 2404 | 2405 | type andCodeExpr struct { 2406 | pos position 2407 | run func(*parser) (bool, error) 2408 | } 2409 | 2410 | type notCodeExpr struct { 2411 | pos position 2412 | run func(*parser) (bool, error) 2413 | } 2414 | 2415 | type litMatcher struct { 2416 | pos position 2417 | val string 2418 | ignoreCase bool 2419 | } 2420 | 2421 | type charClassMatcher struct { 2422 | pos position 2423 | val string 2424 | basicLatinChars [128]bool 2425 | chars []rune 2426 | ranges []rune 2427 | classes []*unicode.RangeTable 2428 | ignoreCase bool 2429 | inverted bool 2430 | } 2431 | 2432 | type anyMatcher position 2433 | 2434 | // errList cumulates the errors found by the parser. 2435 | type errList []error 2436 | 2437 | func (e *errList) add(err error) { 2438 | *e = append(*e, err) 2439 | } 2440 | 2441 | func (e errList) err() error { 2442 | if len(e) == 0 { 2443 | return nil 2444 | } 2445 | e.dedupe() 2446 | return e 2447 | } 2448 | 2449 | func (e *errList) dedupe() { 2450 | var cleaned []error 2451 | set := make(map[string]bool) 2452 | for _, err := range *e { 2453 | if msg := err.Error(); !set[msg] { 2454 | set[msg] = true 2455 | cleaned = append(cleaned, err) 2456 | } 2457 | } 2458 | *e = cleaned 2459 | } 2460 | 2461 | func (e errList) Error() string { 2462 | switch len(e) { 2463 | case 0: 2464 | return "" 2465 | case 1: 2466 | return e[0].Error() 2467 | default: 2468 | var buf bytes.Buffer 2469 | 2470 | for i, err := range e { 2471 | if i > 0 { 2472 | buf.WriteRune('\n') 2473 | } 2474 | buf.WriteString(err.Error()) 2475 | } 2476 | return buf.String() 2477 | } 2478 | } 2479 | 2480 | // parserError wraps an error with a prefix indicating the rule in which 2481 | // the error occurred. The original error is stored in the Inner field. 2482 | type parserError struct { 2483 | Inner error 2484 | pos position 2485 | prefix string 2486 | expected []string 2487 | } 2488 | 2489 | // Error returns the error message. 2490 | func (p *parserError) Error() string { 2491 | return p.prefix + ": " + p.Inner.Error() 2492 | } 2493 | 2494 | // newParser creates a parser with the specified input source and options. 2495 | func newParser(filename string, b []byte, opts ...Option) *parser { 2496 | stats := Stats{ 2497 | ChoiceAltCnt: make(map[string]map[string]int), 2498 | } 2499 | 2500 | p := &parser{ 2501 | filename: filename, 2502 | errs: new(errList), 2503 | data: b, 2504 | pt: savepoint{position: position{line: 1}}, 2505 | recover: true, 2506 | cur: current{ 2507 | state: make(storeDict), 2508 | globalStore: make(storeDict), 2509 | }, 2510 | maxFailPos: position{col: 1, line: 1}, 2511 | maxFailExpected: make([]string, 0, 20), 2512 | Stats: &stats, 2513 | // start rule is rule [0] unless an alternate entrypoint is specified 2514 | entrypoint: g.rules[0].name, 2515 | } 2516 | p.setOptions(opts) 2517 | 2518 | if p.maxExprCnt == 0 { 2519 | p.maxExprCnt = math.MaxUint64 2520 | } 2521 | 2522 | return p 2523 | } 2524 | 2525 | // setOptions applies the options to the parser. 2526 | func (p *parser) setOptions(opts []Option) { 2527 | for _, opt := range opts { 2528 | opt(p) 2529 | } 2530 | } 2531 | 2532 | type resultTuple struct { 2533 | v interface{} 2534 | b bool 2535 | end savepoint 2536 | } 2537 | 2538 | const choiceNoMatch = -1 2539 | 2540 | // Stats stores some statistics, gathered during parsing 2541 | type Stats struct { 2542 | // ExprCnt counts the number of expressions processed during parsing 2543 | // This value is compared to the maximum number of expressions allowed 2544 | // (set by the MaxExpressions option). 2545 | ExprCnt uint64 2546 | 2547 | // ChoiceAltCnt is used to count for each ordered choice expression, 2548 | // which alternative is used how may times. 2549 | // These numbers allow to optimize the order of the ordered choice expression 2550 | // to increase the performance of the parser 2551 | // 2552 | // The outer key of ChoiceAltCnt is composed of the name of the rule as well 2553 | // as the line and the column of the ordered choice. 2554 | // The inner key of ChoiceAltCnt is the number (one-based) of the matching alternative. 2555 | // For each alternative the number of matches are counted. If an ordered choice does not 2556 | // match, a special counter is incremented. The name of this counter is set with 2557 | // the parser option Statistics. 2558 | // For an alternative to be included in ChoiceAltCnt, it has to match at least once. 2559 | ChoiceAltCnt map[string]map[string]int 2560 | } 2561 | 2562 | type parser struct { 2563 | filename string 2564 | pt savepoint 2565 | cur current 2566 | 2567 | data []byte 2568 | errs *errList 2569 | 2570 | depth int 2571 | recover bool 2572 | debug bool 2573 | 2574 | memoize bool 2575 | // memoization table for the packrat algorithm: 2576 | // map[offset in source] map[expression or rule] {value, match} 2577 | memo map[int]map[interface{}]resultTuple 2578 | 2579 | // rules table, maps the rule identifier to the rule node 2580 | rules map[string]*rule 2581 | // variables stack, map of label to value 2582 | vstack []map[string]interface{} 2583 | // rule stack, allows identification of the current rule in errors 2584 | rstack []*rule 2585 | 2586 | // parse fail 2587 | maxFailPos position 2588 | maxFailExpected []string 2589 | maxFailInvertExpected bool 2590 | 2591 | // max number of expressions to be parsed 2592 | maxExprCnt uint64 2593 | // entrypoint for the parser 2594 | entrypoint string 2595 | 2596 | allowInvalidUTF8 bool 2597 | 2598 | *Stats 2599 | 2600 | choiceNoMatch string 2601 | // recovery expression stack, keeps track of the currently available recovery expression, these are traversed in reverse 2602 | recoveryStack []map[string]interface{} 2603 | } 2604 | 2605 | // push a variable set on the vstack. 2606 | func (p *parser) pushV() { 2607 | if cap(p.vstack) == len(p.vstack) { 2608 | // create new empty slot in the stack 2609 | p.vstack = append(p.vstack, nil) 2610 | } else { 2611 | // slice to 1 more 2612 | p.vstack = p.vstack[:len(p.vstack)+1] 2613 | } 2614 | 2615 | // get the last args set 2616 | m := p.vstack[len(p.vstack)-1] 2617 | if m != nil && len(m) == 0 { 2618 | // empty map, all good 2619 | return 2620 | } 2621 | 2622 | m = make(map[string]interface{}) 2623 | p.vstack[len(p.vstack)-1] = m 2624 | } 2625 | 2626 | // pop a variable set from the vstack. 2627 | func (p *parser) popV() { 2628 | // if the map is not empty, clear it 2629 | m := p.vstack[len(p.vstack)-1] 2630 | if len(m) > 0 { 2631 | // GC that map 2632 | p.vstack[len(p.vstack)-1] = nil 2633 | } 2634 | p.vstack = p.vstack[:len(p.vstack)-1] 2635 | } 2636 | 2637 | // push a recovery expression with its labels to the recoveryStack 2638 | func (p *parser) pushRecovery(labels []string, expr interface{}) { 2639 | if cap(p.recoveryStack) == len(p.recoveryStack) { 2640 | // create new empty slot in the stack 2641 | p.recoveryStack = append(p.recoveryStack, nil) 2642 | } else { 2643 | // slice to 1 more 2644 | p.recoveryStack = p.recoveryStack[:len(p.recoveryStack)+1] 2645 | } 2646 | 2647 | m := make(map[string]interface{}, len(labels)) 2648 | for _, fl := range labels { 2649 | m[fl] = expr 2650 | } 2651 | p.recoveryStack[len(p.recoveryStack)-1] = m 2652 | } 2653 | 2654 | // pop a recovery expression from the recoveryStack 2655 | func (p *parser) popRecovery() { 2656 | // GC that map 2657 | p.recoveryStack[len(p.recoveryStack)-1] = nil 2658 | 2659 | p.recoveryStack = p.recoveryStack[:len(p.recoveryStack)-1] 2660 | } 2661 | 2662 | func (p *parser) print(prefix, s string) string { 2663 | if !p.debug { 2664 | return s 2665 | } 2666 | 2667 | fmt.Printf("%s %d:%d:%d: %s [%#U]\n", 2668 | prefix, p.pt.line, p.pt.col, p.pt.offset, s, p.pt.rn) 2669 | return s 2670 | } 2671 | 2672 | func (p *parser) in(s string) string { 2673 | p.depth++ 2674 | return p.print(strings.Repeat(" ", p.depth)+">", s) 2675 | } 2676 | 2677 | func (p *parser) out(s string) string { 2678 | p.depth-- 2679 | return p.print(strings.Repeat(" ", p.depth)+"<", s) 2680 | } 2681 | 2682 | func (p *parser) addErr(err error) { 2683 | p.addErrAt(err, p.pt.position, []string{}) 2684 | } 2685 | 2686 | func (p *parser) addErrAt(err error, pos position, expected []string) { 2687 | var buf bytes.Buffer 2688 | if p.filename != "" { 2689 | buf.WriteString(p.filename) 2690 | } 2691 | if buf.Len() > 0 { 2692 | buf.WriteString(":") 2693 | } 2694 | buf.WriteString(fmt.Sprintf("%d:%d (%d)", pos.line, pos.col, pos.offset)) 2695 | if len(p.rstack) > 0 { 2696 | if buf.Len() > 0 { 2697 | buf.WriteString(": ") 2698 | } 2699 | rule := p.rstack[len(p.rstack)-1] 2700 | if rule.displayName != "" { 2701 | buf.WriteString("rule " + rule.displayName) 2702 | } else { 2703 | buf.WriteString("rule " + rule.name) 2704 | } 2705 | } 2706 | pe := &parserError{Inner: err, pos: pos, prefix: buf.String(), expected: expected} 2707 | p.errs.add(pe) 2708 | } 2709 | 2710 | func (p *parser) failAt(fail bool, pos position, want string) { 2711 | // process fail if parsing fails and not inverted or parsing succeeds and invert is set 2712 | if fail == p.maxFailInvertExpected { 2713 | if pos.offset < p.maxFailPos.offset { 2714 | return 2715 | } 2716 | 2717 | if pos.offset > p.maxFailPos.offset { 2718 | p.maxFailPos = pos 2719 | p.maxFailExpected = p.maxFailExpected[:0] 2720 | } 2721 | 2722 | if p.maxFailInvertExpected { 2723 | want = "!" + want 2724 | } 2725 | p.maxFailExpected = append(p.maxFailExpected, want) 2726 | } 2727 | } 2728 | 2729 | // read advances the parser to the next rune. 2730 | func (p *parser) read() { 2731 | p.pt.offset += p.pt.w 2732 | rn, n := utf8.DecodeRune(p.data[p.pt.offset:]) 2733 | p.pt.rn = rn 2734 | p.pt.w = n 2735 | p.pt.col++ 2736 | if rn == '\n' { 2737 | p.pt.line++ 2738 | p.pt.col = 0 2739 | } 2740 | 2741 | if rn == utf8.RuneError && n == 1 { // see utf8.DecodeRune 2742 | if !p.allowInvalidUTF8 { 2743 | p.addErr(errInvalidEncoding) 2744 | } 2745 | } 2746 | } 2747 | 2748 | // restore parser position to the savepoint pt. 2749 | func (p *parser) restore(pt savepoint) { 2750 | if p.debug { 2751 | defer p.out(p.in("restore")) 2752 | } 2753 | if pt.offset == p.pt.offset { 2754 | return 2755 | } 2756 | p.pt = pt 2757 | } 2758 | 2759 | // Cloner is implemented by any value that has a Clone method, which returns a 2760 | // copy of the value. This is mainly used for types which are not passed by 2761 | // value (e.g map, slice, chan) or structs that contain such types. 2762 | // 2763 | // This is used in conjunction with the global state feature to create proper 2764 | // copies of the state to allow the parser to properly restore the state in 2765 | // the case of backtracking. 2766 | type Cloner interface { 2767 | Clone() interface{} 2768 | } 2769 | 2770 | // clone and return parser current state. 2771 | func (p *parser) cloneState() storeDict { 2772 | if p.debug { 2773 | defer p.out(p.in("cloneState")) 2774 | } 2775 | 2776 | state := make(storeDict, len(p.cur.state)) 2777 | for k, v := range p.cur.state { 2778 | if c, ok := v.(Cloner); ok { 2779 | state[k] = c.Clone() 2780 | } else { 2781 | state[k] = v 2782 | } 2783 | } 2784 | return state 2785 | } 2786 | 2787 | // restore parser current state to the state storeDict. 2788 | // every restoreState should applied only one time for every cloned state 2789 | func (p *parser) restoreState(state storeDict) { 2790 | if p.debug { 2791 | defer p.out(p.in("restoreState")) 2792 | } 2793 | p.cur.state = state 2794 | } 2795 | 2796 | // get the slice of bytes from the savepoint start to the current position. 2797 | func (p *parser) sliceFrom(start savepoint) []byte { 2798 | return p.data[start.position.offset:p.pt.position.offset] 2799 | } 2800 | 2801 | func (p *parser) getMemoized(node interface{}) (resultTuple, bool) { 2802 | if len(p.memo) == 0 { 2803 | return resultTuple{}, false 2804 | } 2805 | m := p.memo[p.pt.offset] 2806 | if len(m) == 0 { 2807 | return resultTuple{}, false 2808 | } 2809 | res, ok := m[node] 2810 | return res, ok 2811 | } 2812 | 2813 | func (p *parser) setMemoized(pt savepoint, node interface{}, tuple resultTuple) { 2814 | if p.memo == nil { 2815 | p.memo = make(map[int]map[interface{}]resultTuple) 2816 | } 2817 | m := p.memo[pt.offset] 2818 | if m == nil { 2819 | m = make(map[interface{}]resultTuple) 2820 | p.memo[pt.offset] = m 2821 | } 2822 | m[node] = tuple 2823 | } 2824 | 2825 | func (p *parser) buildRulesTable(g *grammar) { 2826 | p.rules = make(map[string]*rule, len(g.rules)) 2827 | for _, r := range g.rules { 2828 | p.rules[r.name] = r 2829 | } 2830 | } 2831 | 2832 | func (p *parser) parse(g *grammar) (val interface{}, err error) { 2833 | if len(g.rules) == 0 { 2834 | p.addErr(errNoRule) 2835 | return nil, p.errs.err() 2836 | } 2837 | 2838 | // TODO : not super critical but this could be generated 2839 | p.buildRulesTable(g) 2840 | 2841 | if p.recover { 2842 | // panic can be used in action code to stop parsing immediately 2843 | // and return the panic as an error. 2844 | defer func() { 2845 | if e := recover(); e != nil { 2846 | if p.debug { 2847 | defer p.out(p.in("panic handler")) 2848 | } 2849 | val = nil 2850 | switch e := e.(type) { 2851 | case error: 2852 | p.addErr(e) 2853 | default: 2854 | p.addErr(fmt.Errorf("%v", e)) 2855 | } 2856 | err = p.errs.err() 2857 | } 2858 | }() 2859 | } 2860 | 2861 | startRule, ok := p.rules[p.entrypoint] 2862 | if !ok { 2863 | p.addErr(errInvalidEntrypoint) 2864 | return nil, p.errs.err() 2865 | } 2866 | 2867 | p.read() // advance to first rune 2868 | val, ok = p.parseRule(startRule) 2869 | if !ok { 2870 | if len(*p.errs) == 0 { 2871 | // If parsing fails, but no errors have been recorded, the expected values 2872 | // for the farthest parser position are returned as error. 2873 | maxFailExpectedMap := make(map[string]struct{}, len(p.maxFailExpected)) 2874 | for _, v := range p.maxFailExpected { 2875 | maxFailExpectedMap[v] = struct{}{} 2876 | } 2877 | expected := make([]string, 0, len(maxFailExpectedMap)) 2878 | eof := false 2879 | if _, ok := maxFailExpectedMap["!."]; ok { 2880 | delete(maxFailExpectedMap, "!.") 2881 | eof = true 2882 | } 2883 | for k := range maxFailExpectedMap { 2884 | expected = append(expected, k) 2885 | } 2886 | sort.Strings(expected) 2887 | if eof { 2888 | expected = append(expected, "EOF") 2889 | } 2890 | p.addErrAt(errors.New("no match found, expected: "+listJoin(expected, ", ", "or")), p.maxFailPos, expected) 2891 | } 2892 | 2893 | return nil, p.errs.err() 2894 | } 2895 | return val, p.errs.err() 2896 | } 2897 | 2898 | func listJoin(list []string, sep string, lastSep string) string { 2899 | switch len(list) { 2900 | case 0: 2901 | return "" 2902 | case 1: 2903 | return list[0] 2904 | default: 2905 | return fmt.Sprintf("%s %s %s", strings.Join(list[:len(list)-1], sep), lastSep, list[len(list)-1]) 2906 | } 2907 | } 2908 | 2909 | func (p *parser) parseRule(rule *rule) (interface{}, bool) { 2910 | if p.debug { 2911 | defer p.out(p.in("parseRule " + rule.name)) 2912 | } 2913 | 2914 | if p.memoize { 2915 | res, ok := p.getMemoized(rule) 2916 | if ok { 2917 | p.restore(res.end) 2918 | return res.v, res.b 2919 | } 2920 | } 2921 | 2922 | start := p.pt 2923 | p.rstack = append(p.rstack, rule) 2924 | p.pushV() 2925 | val, ok := p.parseExpr(rule.expr) 2926 | p.popV() 2927 | p.rstack = p.rstack[:len(p.rstack)-1] 2928 | if ok && p.debug { 2929 | p.print(strings.Repeat(" ", p.depth)+"MATCH", string(p.sliceFrom(start))) 2930 | } 2931 | 2932 | if p.memoize { 2933 | p.setMemoized(start, rule, resultTuple{val, ok, p.pt}) 2934 | } 2935 | return val, ok 2936 | } 2937 | 2938 | func (p *parser) parseExpr(expr interface{}) (interface{}, bool) { 2939 | var pt savepoint 2940 | 2941 | if p.memoize { 2942 | res, ok := p.getMemoized(expr) 2943 | if ok { 2944 | p.restore(res.end) 2945 | return res.v, res.b 2946 | } 2947 | pt = p.pt 2948 | } 2949 | 2950 | p.ExprCnt++ 2951 | if p.ExprCnt > p.maxExprCnt { 2952 | panic(errMaxExprCnt) 2953 | } 2954 | 2955 | var val interface{} 2956 | var ok bool 2957 | switch expr := expr.(type) { 2958 | case *actionExpr: 2959 | val, ok = p.parseActionExpr(expr) 2960 | case *andCodeExpr: 2961 | val, ok = p.parseAndCodeExpr(expr) 2962 | case *andExpr: 2963 | val, ok = p.parseAndExpr(expr) 2964 | case *anyMatcher: 2965 | val, ok = p.parseAnyMatcher(expr) 2966 | case *charClassMatcher: 2967 | val, ok = p.parseCharClassMatcher(expr) 2968 | case *choiceExpr: 2969 | val, ok = p.parseChoiceExpr(expr) 2970 | case *labeledExpr: 2971 | val, ok = p.parseLabeledExpr(expr) 2972 | case *litMatcher: 2973 | val, ok = p.parseLitMatcher(expr) 2974 | case *notCodeExpr: 2975 | val, ok = p.parseNotCodeExpr(expr) 2976 | case *notExpr: 2977 | val, ok = p.parseNotExpr(expr) 2978 | case *oneOrMoreExpr: 2979 | val, ok = p.parseOneOrMoreExpr(expr) 2980 | case *recoveryExpr: 2981 | val, ok = p.parseRecoveryExpr(expr) 2982 | case *ruleRefExpr: 2983 | val, ok = p.parseRuleRefExpr(expr) 2984 | case *seqExpr: 2985 | val, ok = p.parseSeqExpr(expr) 2986 | case *stateCodeExpr: 2987 | val, ok = p.parseStateCodeExpr(expr) 2988 | case *throwExpr: 2989 | val, ok = p.parseThrowExpr(expr) 2990 | case *zeroOrMoreExpr: 2991 | val, ok = p.parseZeroOrMoreExpr(expr) 2992 | case *zeroOrOneExpr: 2993 | val, ok = p.parseZeroOrOneExpr(expr) 2994 | default: 2995 | panic(fmt.Sprintf("unknown expression type %T", expr)) 2996 | } 2997 | if p.memoize { 2998 | p.setMemoized(pt, expr, resultTuple{val, ok, p.pt}) 2999 | } 3000 | return val, ok 3001 | } 3002 | 3003 | func (p *parser) parseActionExpr(act *actionExpr) (interface{}, bool) { 3004 | if p.debug { 3005 | defer p.out(p.in("parseActionExpr")) 3006 | } 3007 | 3008 | start := p.pt 3009 | val, ok := p.parseExpr(act.expr) 3010 | if ok { 3011 | p.cur.pos = start.position 3012 | p.cur.text = p.sliceFrom(start) 3013 | state := p.cloneState() 3014 | actVal, err := act.run(p) 3015 | if err != nil { 3016 | p.addErrAt(err, start.position, []string{}) 3017 | } 3018 | p.restoreState(state) 3019 | 3020 | val = actVal 3021 | } 3022 | if ok && p.debug { 3023 | p.print(strings.Repeat(" ", p.depth)+"MATCH", string(p.sliceFrom(start))) 3024 | } 3025 | return val, ok 3026 | } 3027 | 3028 | func (p *parser) parseAndCodeExpr(and *andCodeExpr) (interface{}, bool) { 3029 | if p.debug { 3030 | defer p.out(p.in("parseAndCodeExpr")) 3031 | } 3032 | 3033 | state := p.cloneState() 3034 | 3035 | ok, err := and.run(p) 3036 | if err != nil { 3037 | p.addErr(err) 3038 | } 3039 | p.restoreState(state) 3040 | 3041 | return nil, ok 3042 | } 3043 | 3044 | func (p *parser) parseAndExpr(and *andExpr) (interface{}, bool) { 3045 | if p.debug { 3046 | defer p.out(p.in("parseAndExpr")) 3047 | } 3048 | 3049 | pt := p.pt 3050 | state := p.cloneState() 3051 | p.pushV() 3052 | _, ok := p.parseExpr(and.expr) 3053 | p.popV() 3054 | p.restoreState(state) 3055 | p.restore(pt) 3056 | 3057 | return nil, ok 3058 | } 3059 | 3060 | func (p *parser) parseAnyMatcher(any *anyMatcher) (interface{}, bool) { 3061 | if p.debug { 3062 | defer p.out(p.in("parseAnyMatcher")) 3063 | } 3064 | 3065 | if p.pt.rn == utf8.RuneError && p.pt.w == 0 { 3066 | // EOF - see utf8.DecodeRune 3067 | p.failAt(false, p.pt.position, ".") 3068 | return nil, false 3069 | } 3070 | start := p.pt 3071 | p.read() 3072 | p.failAt(true, start.position, ".") 3073 | return p.sliceFrom(start), true 3074 | } 3075 | 3076 | func (p *parser) parseCharClassMatcher(chr *charClassMatcher) (interface{}, bool) { 3077 | if p.debug { 3078 | defer p.out(p.in("parseCharClassMatcher")) 3079 | } 3080 | 3081 | cur := p.pt.rn 3082 | start := p.pt 3083 | 3084 | // can't match EOF 3085 | if cur == utf8.RuneError && p.pt.w == 0 { // see utf8.DecodeRune 3086 | p.failAt(false, start.position, chr.val) 3087 | return nil, false 3088 | } 3089 | 3090 | if chr.ignoreCase { 3091 | cur = unicode.ToLower(cur) 3092 | } 3093 | 3094 | // try to match in the list of available chars 3095 | for _, rn := range chr.chars { 3096 | if rn == cur { 3097 | if chr.inverted { 3098 | p.failAt(false, start.position, chr.val) 3099 | return nil, false 3100 | } 3101 | p.read() 3102 | p.failAt(true, start.position, chr.val) 3103 | return p.sliceFrom(start), true 3104 | } 3105 | } 3106 | 3107 | // try to match in the list of ranges 3108 | for i := 0; i < len(chr.ranges); i += 2 { 3109 | if cur >= chr.ranges[i] && cur <= chr.ranges[i+1] { 3110 | if chr.inverted { 3111 | p.failAt(false, start.position, chr.val) 3112 | return nil, false 3113 | } 3114 | p.read() 3115 | p.failAt(true, start.position, chr.val) 3116 | return p.sliceFrom(start), true 3117 | } 3118 | } 3119 | 3120 | // try to match in the list of Unicode classes 3121 | for _, cl := range chr.classes { 3122 | if unicode.Is(cl, cur) { 3123 | if chr.inverted { 3124 | p.failAt(false, start.position, chr.val) 3125 | return nil, false 3126 | } 3127 | p.read() 3128 | p.failAt(true, start.position, chr.val) 3129 | return p.sliceFrom(start), true 3130 | } 3131 | } 3132 | 3133 | if chr.inverted { 3134 | p.read() 3135 | p.failAt(true, start.position, chr.val) 3136 | return p.sliceFrom(start), true 3137 | } 3138 | p.failAt(false, start.position, chr.val) 3139 | return nil, false 3140 | } 3141 | 3142 | func (p *parser) incChoiceAltCnt(ch *choiceExpr, altI int) { 3143 | choiceIdent := fmt.Sprintf("%s %d:%d", p.rstack[len(p.rstack)-1].name, ch.pos.line, ch.pos.col) 3144 | m := p.ChoiceAltCnt[choiceIdent] 3145 | if m == nil { 3146 | m = make(map[string]int) 3147 | p.ChoiceAltCnt[choiceIdent] = m 3148 | } 3149 | // We increment altI by 1, so the keys do not start at 0 3150 | alt := strconv.Itoa(altI + 1) 3151 | if altI == choiceNoMatch { 3152 | alt = p.choiceNoMatch 3153 | } 3154 | m[alt]++ 3155 | } 3156 | 3157 | func (p *parser) parseChoiceExpr(ch *choiceExpr) (interface{}, bool) { 3158 | if p.debug { 3159 | defer p.out(p.in("parseChoiceExpr")) 3160 | } 3161 | 3162 | for altI, alt := range ch.alternatives { 3163 | // dummy assignment to prevent compile error if optimized 3164 | _ = altI 3165 | 3166 | state := p.cloneState() 3167 | 3168 | p.pushV() 3169 | val, ok := p.parseExpr(alt) 3170 | p.popV() 3171 | if ok { 3172 | p.incChoiceAltCnt(ch, altI) 3173 | return val, ok 3174 | } 3175 | p.restoreState(state) 3176 | } 3177 | p.incChoiceAltCnt(ch, choiceNoMatch) 3178 | return nil, false 3179 | } 3180 | 3181 | func (p *parser) parseLabeledExpr(lab *labeledExpr) (interface{}, bool) { 3182 | if p.debug { 3183 | defer p.out(p.in("parseLabeledExpr")) 3184 | } 3185 | 3186 | p.pushV() 3187 | val, ok := p.parseExpr(lab.expr) 3188 | p.popV() 3189 | if ok && lab.label != "" { 3190 | m := p.vstack[len(p.vstack)-1] 3191 | m[lab.label] = val 3192 | } 3193 | return val, ok 3194 | } 3195 | 3196 | func (p *parser) parseLitMatcher(lit *litMatcher) (interface{}, bool) { 3197 | if p.debug { 3198 | defer p.out(p.in("parseLitMatcher")) 3199 | } 3200 | 3201 | ignoreCase := "" 3202 | if lit.ignoreCase { 3203 | ignoreCase = "i" 3204 | } 3205 | val := fmt.Sprintf("%q%s", lit.val, ignoreCase) 3206 | start := p.pt 3207 | for _, want := range lit.val { 3208 | cur := p.pt.rn 3209 | if lit.ignoreCase { 3210 | cur = unicode.ToLower(cur) 3211 | } 3212 | if cur != want { 3213 | p.failAt(false, start.position, val) 3214 | p.restore(start) 3215 | return nil, false 3216 | } 3217 | p.read() 3218 | } 3219 | p.failAt(true, start.position, val) 3220 | return p.sliceFrom(start), true 3221 | } 3222 | 3223 | func (p *parser) parseNotCodeExpr(not *notCodeExpr) (interface{}, bool) { 3224 | if p.debug { 3225 | defer p.out(p.in("parseNotCodeExpr")) 3226 | } 3227 | 3228 | state := p.cloneState() 3229 | 3230 | ok, err := not.run(p) 3231 | if err != nil { 3232 | p.addErr(err) 3233 | } 3234 | p.restoreState(state) 3235 | 3236 | return nil, !ok 3237 | } 3238 | 3239 | func (p *parser) parseNotExpr(not *notExpr) (interface{}, bool) { 3240 | if p.debug { 3241 | defer p.out(p.in("parseNotExpr")) 3242 | } 3243 | 3244 | pt := p.pt 3245 | state := p.cloneState() 3246 | p.pushV() 3247 | p.maxFailInvertExpected = !p.maxFailInvertExpected 3248 | _, ok := p.parseExpr(not.expr) 3249 | p.maxFailInvertExpected = !p.maxFailInvertExpected 3250 | p.popV() 3251 | p.restoreState(state) 3252 | p.restore(pt) 3253 | 3254 | return nil, !ok 3255 | } 3256 | 3257 | func (p *parser) parseOneOrMoreExpr(expr *oneOrMoreExpr) (interface{}, bool) { 3258 | if p.debug { 3259 | defer p.out(p.in("parseOneOrMoreExpr")) 3260 | } 3261 | 3262 | var vals []interface{} 3263 | 3264 | for { 3265 | p.pushV() 3266 | val, ok := p.parseExpr(expr.expr) 3267 | p.popV() 3268 | if !ok { 3269 | if len(vals) == 0 { 3270 | // did not match once, no match 3271 | return nil, false 3272 | } 3273 | return vals, true 3274 | } 3275 | vals = append(vals, val) 3276 | } 3277 | } 3278 | 3279 | func (p *parser) parseRecoveryExpr(recover *recoveryExpr) (interface{}, bool) { 3280 | if p.debug { 3281 | defer p.out(p.in("parseRecoveryExpr (" + strings.Join(recover.failureLabel, ",") + ")")) 3282 | } 3283 | 3284 | p.pushRecovery(recover.failureLabel, recover.recoverExpr) 3285 | val, ok := p.parseExpr(recover.expr) 3286 | p.popRecovery() 3287 | 3288 | return val, ok 3289 | } 3290 | 3291 | func (p *parser) parseRuleRefExpr(ref *ruleRefExpr) (interface{}, bool) { 3292 | if p.debug { 3293 | defer p.out(p.in("parseRuleRefExpr " + ref.name)) 3294 | } 3295 | 3296 | if ref.name == "" { 3297 | panic(fmt.Sprintf("%s: invalid rule: missing name", ref.pos)) 3298 | } 3299 | 3300 | rule := p.rules[ref.name] 3301 | if rule == nil { 3302 | p.addErr(fmt.Errorf("undefined rule: %s", ref.name)) 3303 | return nil, false 3304 | } 3305 | return p.parseRule(rule) 3306 | } 3307 | 3308 | func (p *parser) parseSeqExpr(seq *seqExpr) (interface{}, bool) { 3309 | if p.debug { 3310 | defer p.out(p.in("parseSeqExpr")) 3311 | } 3312 | 3313 | vals := make([]interface{}, 0, len(seq.exprs)) 3314 | 3315 | pt := p.pt 3316 | state := p.cloneState() 3317 | for _, expr := range seq.exprs { 3318 | val, ok := p.parseExpr(expr) 3319 | if !ok { 3320 | p.restoreState(state) 3321 | p.restore(pt) 3322 | return nil, false 3323 | } 3324 | vals = append(vals, val) 3325 | } 3326 | return vals, true 3327 | } 3328 | 3329 | func (p *parser) parseStateCodeExpr(state *stateCodeExpr) (interface{}, bool) { 3330 | if p.debug { 3331 | defer p.out(p.in("parseStateCodeExpr")) 3332 | } 3333 | 3334 | err := state.run(p) 3335 | if err != nil { 3336 | p.addErr(err) 3337 | } 3338 | return nil, true 3339 | } 3340 | 3341 | func (p *parser) parseThrowExpr(expr *throwExpr) (interface{}, bool) { 3342 | if p.debug { 3343 | defer p.out(p.in("parseThrowExpr")) 3344 | } 3345 | 3346 | for i := len(p.recoveryStack) - 1; i >= 0; i-- { 3347 | if recoverExpr, ok := p.recoveryStack[i][expr.label]; ok { 3348 | if val, ok := p.parseExpr(recoverExpr); ok { 3349 | return val, ok 3350 | } 3351 | } 3352 | } 3353 | 3354 | return nil, false 3355 | } 3356 | 3357 | func (p *parser) parseZeroOrMoreExpr(expr *zeroOrMoreExpr) (interface{}, bool) { 3358 | if p.debug { 3359 | defer p.out(p.in("parseZeroOrMoreExpr")) 3360 | } 3361 | 3362 | var vals []interface{} 3363 | 3364 | for { 3365 | p.pushV() 3366 | val, ok := p.parseExpr(expr.expr) 3367 | p.popV() 3368 | if !ok { 3369 | return vals, true 3370 | } 3371 | vals = append(vals, val) 3372 | } 3373 | } 3374 | 3375 | func (p *parser) parseZeroOrOneExpr(expr *zeroOrOneExpr) (interface{}, bool) { 3376 | if p.debug { 3377 | defer p.out(p.in("parseZeroOrOneExpr")) 3378 | } 3379 | 3380 | p.pushV() 3381 | val, _ := p.parseExpr(expr.expr) 3382 | p.popV() 3383 | // whether it matched or not, consider it a match 3384 | return val, true 3385 | } 3386 | 3387 | func rangeTable(class string) *unicode.RangeTable { 3388 | if rt, ok := unicode.Categories[class]; ok { 3389 | return rt 3390 | } 3391 | if rt, ok := unicode.Properties[class]; ok { 3392 | return rt 3393 | } 3394 | if rt, ok := unicode.Scripts[class]; ok { 3395 | return rt 3396 | } 3397 | 3398 | // cannot happen 3399 | panic(fmt.Sprintf("invalid Unicode class: %s", class)) 3400 | } 3401 | --------------------------------------------------------------------------------