Skip to content

Commit

Permalink
Implement "defined" operator.
Browse files Browse the repository at this point in the history
  • Loading branch information
plusvic committed Jan 13, 2022
1 parent 8a06e34 commit df3c87b
Show file tree
Hide file tree
Showing 12 changed files with 1,108 additions and 1,001 deletions.
26 changes: 26 additions & 0 deletions ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,11 @@ type Not struct {
Expression
}

// Defined is an Expression that represents the "defined" operation.
type Defined struct {
Expression
}

// BitwiseNot is an Expression that represents the bitwise not operation.
type BitwiseNot struct {
Expression
Expand Down Expand Up @@ -289,6 +294,15 @@ func (m *Minus) WriteSource(w io.Writer) error {
return err
}

// WriteSource writes the node's source into the writer w.
func (d *Defined) WriteSource(w io.Writer) error {
_, err := io.WriteString(w, "defined ")
if err == nil {
err = d.Expression.WriteSource(w)
}
return err
}

// WriteSource writes the node's source into the writer w.
func (n *Not) WriteSource(w io.Writer) error {
_, err := io.WriteString(w, "not ")
Expand Down Expand Up @@ -757,6 +771,18 @@ func (m *Minus) AsProto() *pb.Expression {
}
}

// AsProto returns the Expression serialized as a pb.Expression.
func (d *Defined) AsProto() *pb.Expression {
return &pb.Expression{
Expression: &pb.Expression_UnaryExpression{
UnaryExpression: &pb.UnaryExpression{
Operator: pb.UnaryExpression_DEFINED.Enum(),
Expression: d.Expression.AsProto(),
},
},
}
}

// AsProto returns the Expression serialized as a pb.Expression.
func (n *Not) AsProto() *pb.Expression {
return &pb.Expression{
Expand Down
9 changes: 6 additions & 3 deletions ast/operations.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ const (
OpUnknown OperatorType = ""
OpOr OperatorType = "or"
OpAnd OperatorType = "and"
OpNot OperatorType = "not"
OpDefined OperatorType = "defined"
OpBitOr OperatorType = "|"
OpBitXor OperatorType = "^"
OpBitAnd OperatorType = "&"
Expand Down Expand Up @@ -41,8 +43,9 @@ const (

// OpPrecedence is the operator precedence table.
var OpPrecedence = map[OperatorType]int{
OpOr: 1,
OpAnd: 2,
OpOr: 0,
OpAnd: 1,
OpNot: 2,
OpEqual: 3,
OpNotEqual: 3,
OpLessThan: 4,
Expand Down Expand Up @@ -70,5 +73,5 @@ var OpPrecedence = map[OperatorType]int{
}

// OpMaxPrecedence is the maximum possible precedence. This is also the precedence
// for unary operators "not", "~" and "-".
// for unary operators "~" and "-".
const OpMaxPrecedence = 11
20 changes: 13 additions & 7 deletions ast/serialization.go
Original file line number Diff line number Diff line change
Expand Up @@ -485,23 +485,29 @@ func expressionFromProto(e *pb.Expression) Expression {
case *pb.Expression_NotExpression:
operand := expressionFromProto(v.NotExpression)
// If the operand is an operation with lower precedence than "not",
// the operand must be enclosed in parenthesis.
if expressionPrecedence(operand) < OpMaxPrecedence {
// the operand must be enclosed in parentheses.
if expressionPrecedence(operand) < OpPrecedence[OpNot] {
operand = &Group{operand}
}
return &Not{operand}
case *pb.Expression_UnaryExpression:
operand := expressionFromProto(v.UnaryExpression.GetExpression())
// If the operand is an operation with lower precedence than "-" or "~",
// the operand must be enclosed in parenthesis.
if expressionPrecedence(operand) < OpMaxPrecedence {
operand = &Group{operand}
}
switch op := v.UnaryExpression.Operator; *op {
case pb.UnaryExpression_UNARY_MINUS:
if expressionPrecedence(operand) < OpMaxPrecedence {
operand = &Group{operand}
}
return &Minus{operand}
case pb.UnaryExpression_BITWISE_NOT:
if expressionPrecedence(operand) < OpMaxPrecedence {
operand = &Group{operand}
}
return &BitwiseNot{operand}
case pb.UnaryExpression_DEFINED:
if expressionPrecedence(operand) < OpPrecedence[OpDefined] {
operand = &Group{operand}
}
return &Defined{operand}
default:
panic(fmt.Sprintf(`unexpected unary operator "%v"`, op))
}
Expand Down
12 changes: 12 additions & 0 deletions gyp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,18 @@ rule foo {
condition:
foo(1, 2 + 3, 4) == bar()
}
`,
`
rule foo {
condition:
defined some_value
}
`,
`
rule foo {
condition:
not defined some_value
}
`,
`
rule foo {
Expand Down
8 changes: 7 additions & 1 deletion parser/grammar.y
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,11 @@ type stringModifiers struct {
%token _TRUE_
%token _FALSE_
%token _INCLUDE_
%token _DEFINED_

%left _OR_
%left _AND_
%right _NOT_ _DEFINED_
%left '|'
%left '^'
%left '&'
Expand All @@ -131,7 +133,7 @@ type stringModifiers struct {
%left _SHIFT_LEFT_ _SHIFT_RIGHT_
%left '+' '-'
%left '*' '\\' '%'
%right _NOT_ '~' UNARY_MINUS
%right '~' UNARY_MINUS

%type <s> import
%type <rule> rule
Expand Down Expand Up @@ -870,6 +872,10 @@ expression
{
$$ = &ast.Not{$2}
}
| _DEFINED_ boolean_expression
{
$$ = &ast.Defined{$2}
}
| boolean_expression _AND_ boolean_expression
{
$$ = operation(ast.OpAnd, $1, $3)
Expand Down
Loading

0 comments on commit df3c87b

Please sign in to comment.