Skip to content

Commit

Permalink
Merge pull request #25 from bvwells/interpreter
Browse files Browse the repository at this point in the history
Implement interpreter design pattern #11
  • Loading branch information
bvwells committed Jan 12, 2018
2 parents edd9e63 + 0c355e7 commit f11402f
Show file tree
Hide file tree
Showing 3 changed files with 164 additions and 30 deletions.
60 changes: 30 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,42 +36,42 @@ Behavioral | [`github.com/bvwells/go-patterns/behavioral`][behavioral-ref] | Beh

## Creational [![GoDoc](https://godoc.org/github.com/bvwells/go-patterns/creational?status.svg)](https://godoc.org/github.com/bvwells/go-patterns/creational)

Name | Description | Status
-----------|-------------------------------------------|------------
[`Abstract Factory`](./creational/abstract_factory.go) | Provide an interface for creating families of related or dependent objects without specifying their concrete classes. | Implemented
[`Builder`](./creational/builder.go) | Separate the construction of a complex object from its representation, allowing the same construction process to create various representations. | Implemented
[`Factory Method`](./creational/factory_method.go) | Define an interface for creating a single object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses. | Implemented
[`Object Pool`](./creational/object_pool.go) | Avoid expensive acquisition and release of resources by recycling objects that are no longer in use. Can be considered a generalisation of connection pool and thread pool patterns. | Implemented
[`Prototype`](./creational/prototype.go) | Specify the kinds of objects to create using a prototypical instance, and create new objects from the 'skeleton' of an existing object, thus boosting performance and keeping memory footprints to a minimum. | Implemented
[`Singleton`](./creational/singleton.go) | Ensure a class has only one instance, and provide a global point of access to it. | Implemented
Name | Description
-----------|-------------------------------------------
[`Abstract Factory`](./creational/abstract_factory.go) | Provide an interface for creating families of related or dependent objects without specifying their concrete classes.
[`Builder`](./creational/builder.go) | Separate the construction of a complex object from its representation, allowing the same construction process to create various representations.
[`Factory Method`](./creational/factory_method.go) | Define an interface for creating a single object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.
[`Object Pool`](./creational/object_pool.go) | Avoid expensive acquisition and release of resources by recycling objects that are no longer in use. Can be considered a generalisation of connection pool and thread pool patterns.
[`Prototype`](./creational/prototype.go) | Specify the kinds of objects to create using a prototypical instance, and create new objects from the 'skeleton' of an existing object, thus boosting performance and keeping memory footprints to a minimum.
[`Singleton`](./creational/singleton.go) | Ensure a class has only one instance, and provide a global point of access to it.

## Structural [![GoDoc](https://godoc.org/github.com/bvwells/go-patterns/structural?status.svg)](https://godoc.org/github.com/bvwells/go-patterns/structutal)

Name | Description | Status
-----------|-------------------------------------------|------------
[`Adapter`](./structural/adapter.go) | Convert the interface of a class into another interface clients expect. An adapter lets classes work together that could not otherwise because of incompatible interfaces. The enterprise integration pattern equivalent is the translator. | Implemented
[`Bridge`](./structural/bridge.go) | Decouple an abstraction from its implementation allowing the two to vary independently. | Implemented
[`Composite`](./structural/composite.go) | Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly. | Implemented
[`Decorator`](./structural/decorator.go) | Attach additional responsibilities to an object dynamically keeping the same interface. Decorators provide a flexible alternative to subclassing for extending functionality. | Implemented
[`Facade`](./structural/facade.go) | Provide a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use. | Implemented
[`Flyweight`](./structural/flyweight.go) | Use sharing to support large numbers of similar objects efficiently. | Implemented
[`Proxy`](./structural/proxy.go) | Provide a surrogate or placeholder for another object to control access to it. | Implemented
Name | Description
-----------|-------------------------------------------
[`Adapter`](./structural/adapter.go) | Convert the interface of a class into another interface clients expect. An adapter lets classes work together that could not otherwise because of incompatible interfaces. The enterprise integration pattern equivalent is the translator.
[`Bridge`](./structural/bridge.go) | Decouple an abstraction from its implementation allowing the two to vary independently.
[`Composite`](./structural/composite.go) | Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.
[`Decorator`](./structural/decorator.go) | Attach additional responsibilities to an object dynamically keeping the same interface. Decorators provide a flexible alternative to subclassing for extending functionality.
[`Facade`](./structural/facade.go) | Provide a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use.
[`Flyweight`](./structural/flyweight.go) | Use sharing to support large numbers of similar objects efficiently.
[`Proxy`](./structural/proxy.go) | Provide a surrogate or placeholder for another object to control access to it.

## Behavioral [![GoDoc](https://godoc.org/github.com/bvwells/go-patterns/behavioral?status.svg)](https://godoc.org/github.com/bvwells/go-patterns/behavioral)

Name | Description | Status
-----------|-------------------------------------------|------------
[`Chain of Responsibility`](./behavioral/chain_of_responsibility.go) | Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it. | Implemented
[`Command`](./behavioral/command.go) | Encapsulate a request as an object, thereby allowing for the parameterization of clients with different requests, and the queuing or logging of requests. It also allows for the support of undoable operations. | Implemented
[`Interpreter`](./behavioral/interpreter.go) | Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language. |
[`Iterator`](./behavioral/iterator.go) | Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation. | Implemented
[`Mediator`](./behavioral/mediator.go) | Define an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it allows their interaction to vary independently. | Implemented
[`Memento`](./behavioral/memento.go) | Without violating encapsulation, capture and externalize an object's internal state allowing the object to be restored to this state later. | Implemented
[`Observer`](./behavioral/observer.go) | Define a one-to-many dependency between objects where a state change in one object results in all its dependents being notified and updated automatically. | Implemented
[`State`](./behavioral/state.go) | Allow an object to alter its behavior when its internal state changes. The object will appear to change its class. | Implemented
[`Strategy`](./behavioral/strategy.go) | Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it. | Implemented
[`Template Method`](./behavioral/template_method.go) | Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure. | Implemented
[`Visitor`](./behavioral/visitor.go) | Represent an operation to be performed on the elements of an object structure. Visitor lets a new operation be defined without changing the classes of the elements on which it operates. | Implemented
Name | Description
-----------|-------------------------------------------
[`Chain of Responsibility`](./behavioral/chain_of_responsibility.go) | Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.
[`Command`](./behavioral/command.go) | Encapsulate a request as an object, thereby allowing for the parameterization of clients with different requests, and the queuing or logging of requests. It also allows for the support of undoable operations.
[`Interpreter`](./behavioral/interpreter.go) | Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.
[`Iterator`](./behavioral/iterator.go) | Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.
[`Mediator`](./behavioral/mediator.go) | Define an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it allows their interaction to vary independently.
[`Memento`](./behavioral/memento.go) | Without violating encapsulation, capture and externalize an object's internal state allowing the object to be restored to this state later.
[`Observer`](./behavioral/observer.go) | Define a one-to-many dependency between objects where a state change in one object results in all its dependents being notified and updated automatically.
[`State`](./behavioral/state.go) | Allow an object to alter its behavior when its internal state changes. The object will appear to change its class.
[`Strategy`](./behavioral/strategy.go) | Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.
[`Template Method`](./behavioral/template_method.go) | Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.
[`Visitor`](./behavioral/visitor.go) | Represent an operation to be performed on the elements of an object structure. Visitor lets a new operation be defined without changing the classes of the elements on which it operates.

## Go Versions Supported

Expand Down
116 changes: 116 additions & 0 deletions behavioral/interpreter.go
Original file line number Diff line number Diff line change
@@ -1 +1,117 @@
package behavioral

import (
"strings"
)

// Expression represents an expression to evaluate.
type Expression interface {
Interpret(variables *map[string]Expression) int
}

// Integer represents an integer number.
type Integer struct {
integer int
}

// Interpret returns the integer representation of the number.
func (n *Integer) Interpret(variables *map[string]Expression) int {
return n.integer
}

// Plus represents the addition operation.
type Plus struct {
leftOperand Expression
rightOperand Expression
}

// Interpret interprets by adding the left and right variables.
func (p *Plus) Interpret(variables *map[string]Expression) int {
return p.leftOperand.Interpret(variables) + p.rightOperand.Interpret(variables)
}

// Minus represents the substraction operation.
type Minus struct {
leftOperand Expression
rightOperand Expression
}

// Interpret interprets by subtracting the right from left variables.
func (m *Minus) Interpret(variables *map[string]Expression) int {
return m.leftOperand.Interpret(variables) - m.rightOperand.Interpret(variables)
}

// Variable represents a variable.
type Variable struct {
name string
}

// Interpret looks up the variable value and returns it, if not found returns zero.
func (v *Variable) Interpret(variables *map[string]Expression) int {
value, found := (*variables)[v.name]
if found == false {
return 0
}
return value.Interpret(variables)
}

// Evaluator evaluates the expression.
type Evaluator struct {
syntaxTree Expression
}

// NewEvaluator creates a new Evaluator.
func NewEvaluator(expression string) *Evaluator {
expressionStack := new(Stack)
for _, token := range strings.Split(expression, " ") {
if token == "+" {
right := expressionStack.Pop().(Expression)
left := expressionStack.Pop().(Expression)
subExpression := &Plus{left, right}
expressionStack.Push(subExpression)
} else if token == "-" {
right := expressionStack.Pop().(Expression)
left := expressionStack.Pop().(Expression)
subExpression := &Minus{left, right}
expressionStack.Push(subExpression)
} else {
expressionStack.Push(&Variable{token})
}
}
syntaxTree := expressionStack.Pop().(Expression)
return &Evaluator{syntaxTree}
}

// Interpret interprets the expression syntax tree.
func (e *Evaluator) Interpret(context *map[string]Expression) int {
return e.syntaxTree.Interpret(context)
}

// Node represents a node in the stack.
type Node struct {
value interface{}
next *Node
}

// Stack represents a stack with push and pop operations.
type Stack struct {
top *Node
size int
}

// Push pushes a new value into the stack.
func (s *Stack) Push(value interface{}) {
s.top = &Node{value, s.top}
s.size++
}

// Pop pops a value out the stack.
func (s *Stack) Pop() interface{} {
if s.size == 0 {
return nil
}
value := s.top.value
s.top = s.top.next
s.size--
return value
}
18 changes: 18 additions & 0 deletions behavioral/interpreter_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package behavioral

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestInterpreter(t *testing.T) {
expression := "w x z - +"
sentence := NewEvaluator(expression)
variables := make(map[string]Expression)
variables["w"] = &Integer{5}
variables["x"] = &Integer{10}
variables["z"] = &Integer{42}
result := sentence.Interpret(&variables)
assert.Equal(t, -27, result)
}

0 comments on commit f11402f

Please sign in to comment.