mirror of
https://github.com/open-policy-agent/opa.git
synced 2026-08-12 19:32:48 -06:00
157e4f083a
The special iterator variable ("_") is not supported yet. The _ variable will
be handled by mangling the variable name while parsing the rules (which are
still to come).
Also refactored terms to use type declaration and type switches. All terms are
now represented by underlying Go types without relying on extra structs. The
Kind attribute on Term has been removed in favour of type switches.
Lastly, removing the generated parser from the repository for now. Once the
grammar has stabilized, we can add the generated code back. The diffs were
unpleasant.
156 lines
4.1 KiB
Plaintext
156 lines
4.1 KiB
Plaintext
{
|
|
package opalog
|
|
|
|
//
|
|
// BUGS: the escaped forward solidus (`\/`) is not currently handled for strings.
|
|
//
|
|
|
|
func currentLocation(c *current) *Location {
|
|
// TODO: Is it possible to propagate file names into the parser?
|
|
return NewLocation(c.text, "", c.pos.line, c.pos.col)
|
|
}
|
|
|
|
}
|
|
|
|
Prog <- _ head:Term tail:( ws Term )* EOF {
|
|
if head == nil {
|
|
return make([]interface{}, 0), nil
|
|
}
|
|
tailSlice := tail.([]interface{})
|
|
return append([]interface{}{head}, tailSlice...), nil
|
|
}
|
|
|
|
Term <- val:( Composite / Scalar / Ref / Var ) {
|
|
return val, nil
|
|
}
|
|
|
|
Composite <- Object / Array
|
|
|
|
Scalar <- Number / String / Bool / Null
|
|
|
|
Key <- Scalar / Ref / Var
|
|
|
|
Object <- '{' _ head:(Key _ ':' _ Term)? tail:( _ ',' _ Key _ ':' _ Term )* _ '}' {
|
|
var buf [][2]*Term
|
|
|
|
// Empty object.
|
|
if head == nil {
|
|
return ObjectTermWithLoc(buf, currentLocation(c)), nil
|
|
}
|
|
|
|
// Non-empty object, first key/value pair.
|
|
// The "head" variable is a slice containing exactly 5 elements (see rule definition above):
|
|
// [key whitespace colon whitespace key] where the whitespace elements may be nil.
|
|
headSlice := head.([]interface{})
|
|
buf = append(buf, Item(headSlice[0].(*Term), headSlice[len(headSlice) - 1].(*Term)))
|
|
|
|
// Non-empty object, remaining key/value pairs.
|
|
tailSlice := tail.([]interface{})
|
|
for _, v := range tailSlice {
|
|
s := v.([]interface{})
|
|
// The "s" variable is a slice containing exactly 8 elements (see rule definition above).
|
|
// This is similar to the "head" variable."
|
|
buf = append(buf, Item(s[3].(*Term), s[len(s) - 1].(*Term)))
|
|
}
|
|
|
|
return ObjectTermWithLoc(buf, currentLocation(c)), nil
|
|
}
|
|
|
|
Array <- '[' _ head:Term? tail:(_ ',' _ Term)* _ ']' {
|
|
|
|
var buf []*Term
|
|
|
|
// Empty array.
|
|
if head == nil {
|
|
return ArrayTermWithLoc(buf, currentLocation(c)), nil
|
|
}
|
|
|
|
// Non-empty array, first element.
|
|
buf = append(buf, head.(*Term))
|
|
|
|
// Non-empty array, remaining elements.
|
|
tailSlice := tail.([]interface{})
|
|
for _, v := range tailSlice {
|
|
s := v.([]interface{})
|
|
// The "s" is a slice containing exactly 4 elements (see rule definition above).
|
|
// [whitespace comma whitespace value] where the whitespace elements may be nil.
|
|
buf = append(buf, s[len(s) - 1].(*Term))
|
|
}
|
|
|
|
return ArrayTermWithLoc(buf, currentLocation(c)), nil
|
|
}
|
|
|
|
Ref <- head:Var tail:( RefDot / RefBracket )+ {
|
|
buf := []*Term{head.(*Term)}
|
|
|
|
tailSlice := tail.([]interface{})
|
|
for _, v := range tailSlice {
|
|
buf = append(buf, v.(*Term))
|
|
}
|
|
|
|
return RefTermWithLoc(buf, currentLocation(c)), nil
|
|
}
|
|
|
|
RefDot <- "." val:Var {
|
|
// Convert the Var into a string because 'foo.bar.baz' is equivalent to 'foo["bar"]["baz"]'.
|
|
return StringTermWithLoc(string(val.(*Term).Value.(Var)), currentLocation(c)), nil
|
|
}
|
|
|
|
RefBracket <- "[" val:(Scalar / Var) "]" {
|
|
return val, nil
|
|
}
|
|
|
|
Var <- vals:( AsciiLetter (AsciiLetter / DecimalDigit)* ) {
|
|
return VarTermWithLoc(string(c.text), currentLocation(c)), nil
|
|
}
|
|
|
|
Number <- '-'? Integer ( '.' DecimalDigit+ )? Exponent? {
|
|
// JSON numbers have the same syntax as Go's, and are parseable using
|
|
// strconv.
|
|
v, err := strconv.ParseFloat(string(c.text), 64)
|
|
return NumberTermWithLoc(v, currentLocation(c)), err
|
|
}
|
|
|
|
String <- '"' ( !EscapedChar . / '\\' EscapeSequence )* '"' {
|
|
// TODO : the forward slash (solidus) is not a valid escape in Go, it will
|
|
// fail if there's one in the string
|
|
v, err := strconv.Unquote(string(c.text))
|
|
return StringTermWithLoc(v, currentLocation(c)), err
|
|
}
|
|
|
|
Bool <- "true" {
|
|
return BooleanTermWithLoc(true, currentLocation(c)), nil
|
|
} / "false" {
|
|
return BooleanTermWithLoc(false, currentLocation(c)), nil
|
|
}
|
|
|
|
Null <- "null" {
|
|
return NullTermWithLoc(currentLocation(c)), nil
|
|
}
|
|
|
|
Integer <- '0' / NonZeroDecimalDigit DecimalDigit*
|
|
|
|
Exponent <- 'e'i [+-]? DecimalDigit+
|
|
|
|
AsciiLetter <- [A-Za-z_]
|
|
|
|
EscapedChar <- [\x00-\x1f"\\]
|
|
|
|
EscapeSequence <- SingleCharEscape / UnicodeEscape
|
|
|
|
SingleCharEscape <- ["\\/bfnrt]
|
|
|
|
UnicodeEscape <- 'u' HexDigit HexDigit HexDigit HexDigit
|
|
|
|
DecimalDigit <- [0-9]
|
|
|
|
NonZeroDecimalDigit <- [1-9]
|
|
|
|
HexDigit <- [0-9a-f]i
|
|
|
|
_ "whitespace" <- [ \t\r\n]*
|
|
|
|
ws "whitespace" <- [ \t\r\n]+
|
|
|
|
EOF <- !.
|