Skip to content

Commit

Permalink
wasm: Add support for pattern matching on composites
Browse files Browse the repository at this point in the history
These changes add basic support for pattern matching on arrays and
objects. Sets and comprehensions not supported yet.

Also, as part of these changes, remove the opa_value_not_equal
function as it's unnecessary given opa_value_compare.

ref open-policy-agent#1113

Signed-off-by: Torin Sandall <torinsandall@gmail.com>
  • Loading branch information
tsandall committed Jan 20, 2019
1 parent f6a611e commit afef234
Show file tree
Hide file tree
Showing 12 changed files with 435 additions and 44 deletions.
2 changes: 1 addition & 1 deletion internal/compiler/wasm/opa/opa.go

Large diffs are not rendered by default.

Binary file modified internal/compiler/wasm/opa/opa.wasm
Binary file not shown.
60 changes: 48 additions & 12 deletions internal/compiler/wasm/wasm.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,29 @@ import (
)

const (
opaFuncPrefix = "opa_"
opaJSONParse = "opa_json_parse"
opaNull = "opa_null"
opaBoolean = "opa_boolean"
opaStringTerminated = "opa_string_terminated"
opaNumberInt = "opa_number_int"
opaValueBooleanSet = "opa_value_boolean_set"
opaValueNotEqual = "opa_value_not_equal"
opaValueCompare = "opa_value_compare"
opaValueGet = "opa_value_get"
opaValueIter = "opa_value_iter"
opaTypeNull int32 = iota + 1
opaTypeBoolean
opaTypeNumber
opaTypeString
opaTypeArray
opaTypeObject
)

const (
opaFuncPrefix = "opa_"
opaJSONParse = "opa_json_parse"
opaNull = "opa_null"
opaBoolean = "opa_boolean"
opaStringTerminated = "opa_string_terminated"
opaNumberInt = "opa_number_int"
opaNumberSize = "opa_number_size"
opaValueBooleanSet = "opa_value_boolean_set"
opaValueNumberSetInt = "opa_value_number_set_int"
opaValueCompare = "opa_value_compare"
opaValueGet = "opa_value_get"
opaValueIter = "opa_value_iter"
opaValueLength = "opa_value_length"
opaValueType = "opa_value_type"
)

// Compiler implements an IR->WASM compiler backend.
Expand Down Expand Up @@ -165,6 +177,9 @@ func (c *Compiler) compileBlock(block ir.Block) ([]instruction.Instruction, erro
case ir.ReturnStmt:
instrs = append(instrs, instruction.I32Const{Value: int32(stmt.Code)})
instrs = append(instrs, instruction.Return{})
case ir.AssignVarStmt:
instrs = append(instrs, instruction.GetLocal{Index: c.local(stmt.Source)})
instrs = append(instrs, instruction.SetLocal{Index: c.local(stmt.Target)})
case ir.AssignBooleanStmt:
instrs = append(instrs, instruction.GetLocal{Index: c.local(stmt.Target)})
if stmt.Value {
Expand All @@ -173,6 +188,10 @@ func (c *Compiler) compileBlock(block ir.Block) ([]instruction.Instruction, erro
instrs = append(instrs, instruction.I32Const{Value: 0})
}
instrs = append(instrs, instruction.Call{Index: c.function(opaValueBooleanSet)})
case ir.AssignIntStmt:
instrs = append(instrs, instruction.GetLocal{Index: c.local(stmt.Target)})
instrs = append(instrs, instruction.I64Const{Value: stmt.Value})
instrs = append(instrs, instruction.Call{Index: c.function(opaValueNumberSetInt)})
case ir.ScanStmt:
if err := c.compileScan(stmt, &instrs); err != nil {
return nil, err
Expand All @@ -189,10 +208,15 @@ func (c *Compiler) compileBlock(block ir.Block) ([]instruction.Instruction, erro
instrs = append(instrs, instruction.GetLocal{Index: c.local(stmt.Target)})
instrs = append(instrs, instruction.I32Eqz{})
instrs = append(instrs, instruction.BrIf{Index: 0})
case ir.LenStmt:
instrs = append(instrs, instruction.GetLocal{Index: c.local(stmt.Source)})
instrs = append(instrs, instruction.Call{Index: c.function(opaValueLength)})
instrs = append(instrs, instruction.Call{Index: c.function(opaNumberSize)})
instrs = append(instrs, instruction.SetLocal{Index: c.local(stmt.Target)})
case ir.EqualStmt:
instrs = append(instrs, instruction.GetLocal{Index: c.local(stmt.A)})
instrs = append(instrs, instruction.GetLocal{Index: c.local(stmt.B)})
instrs = append(instrs, instruction.Call{Index: c.function(opaValueNotEqual)})
instrs = append(instrs, instruction.Call{Index: c.function(opaValueCompare)})
instrs = append(instrs, instruction.BrIf{Index: 0})
case ir.LessThanStmt:
instrs = append(instrs, instruction.GetLocal{Index: c.local(stmt.A)})
Expand Down Expand Up @@ -249,6 +273,18 @@ func (c *Compiler) compileBlock(block ir.Block) ([]instruction.Instruction, erro
instrs = append(instrs, instruction.I32Const{Value: c.stringAddr(stmt.Index)})
instrs = append(instrs, instruction.Call{Index: c.function(opaStringTerminated)})
instrs = append(instrs, instruction.SetLocal{Index: c.local(stmt.Target)})
case ir.IsArrayStmt:
instrs = append(instrs, instruction.GetLocal{Index: c.local(stmt.Source)})
instrs = append(instrs, instruction.Call{Index: c.function(opaValueType)})
instrs = append(instrs, instruction.I32Const{Value: opaTypeArray})
instrs = append(instrs, instruction.I32Ne{})
instrs = append(instrs, instruction.BrIf{Index: 0})
case ir.IsObjectStmt:
instrs = append(instrs, instruction.GetLocal{Index: c.local(stmt.Source)})
instrs = append(instrs, instruction.Call{Index: c.function(opaValueType)})
instrs = append(instrs, instruction.I32Const{Value: opaTypeObject})
instrs = append(instrs, instruction.I32Ne{})
instrs = append(instrs, instruction.BrIf{Index: 0})
default:
var buf bytes.Buffer
ir.Pretty(&buf, stmt)
Expand Down
30 changes: 30 additions & 0 deletions internal/ir/ir.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,13 @@ type DotStmt struct {
Target Local
}

// LenStmt represents a length() operation on a local variable. The
// result is stored in the target local variable.
type LenStmt struct {
Source Local
Target Local
}

// ScanStmt represents a linear scan over a composite value. The
// source may be a scalar in which case the block will never execute.
type ScanStmt struct {
Expand All @@ -159,6 +166,19 @@ type AssignBooleanStmt struct {
Target Local
}

// AssignIntStmt represents an assignment of an integer value to a
// local variable.
type AssignIntStmt struct {
Value int64
Target Local
}

// AssignVarStmt represents an assignment of one local variable to another.
type AssignVarStmt struct {
Source Local
Target Local
}

// MakeStringStmt constructs a local variable that refers to a string constant.
type MakeStringStmt struct {
Index int
Expand Down Expand Up @@ -217,3 +237,13 @@ type NotEqualStmt struct {
A Local
B Local
}

// IsArrayStmt represents a dynamic type check on a local variable.
type IsArrayStmt struct {
Source Local
}

// IsObjectStmt represents a dynamic type check on a local variable.
type IsObjectStmt struct {
Source Local
}
Loading

0 comments on commit afef234

Please sign in to comment.