Skip to content

Commit

Permalink
unify expression types
Browse files Browse the repository at this point in the history
yosida95 committed Dec 1, 2016
1 parent d37a289 commit 4adff32
Showing 5 changed files with 95 additions and 181 deletions.
93 changes: 17 additions & 76 deletions expression.go
Original file line number Diff line number Diff line change
@@ -7,94 +7,35 @@
package uritemplate

import (
"io"
"bytes"
)

type varspec struct {
name string
maxlen int
explode bool
}

type expression interface {
expand(io.Writer, map[string]Value) error
}

type expLiterals string

func (exp expLiterals) expand(w io.Writer, _ map[string]Value) error {
w.Write([]byte(exp))
return nil
}

type expSimple struct {
vars []varspec
}

func (exp *expSimple) expand(w io.Writer, varmap map[string]Value) error {
// TODO(yosida95): implement here
return nil
}

type expPlus struct {
vars []varspec
}

func (exp *expPlus) expand(w io.Writer, varmap map[string]Value) error {
// TODO(yosida95): implement here
return nil
}

type expCrosshatch struct {
vars []varspec
}

func (exp *expCrosshatch) expand(w io.Writer, varmap map[string]Value) error {
// TODO(yosida95): implement here
return nil
type template interface {
expand(*bytes.Buffer, Values) error
}

type expDot struct {
vars []varspec
}
type literals string

func (exp *expDot) expand(w io.Writer, varmap map[string]Value) error {
// TODO(yosida95): implement here
func (l literals) expand(w *bytes.Buffer, _ Values) error {
w.Write([]byte(l))
return nil
}

type expSlash struct {
vars []varspec
}

func (exp *expSlash) expand(w io.Writer, varmap map[string]Value) error {
// TODO(yosida95): implement here
return nil
}

type expSemicolon struct {
vars []varspec
}

func (exp *expSemicolon) expand(w io.Writer, varmap map[string]Value) error {
// TODO(yosida95): implement here
return nil
}

type expQuestion struct {
vars []varspec
}

func (exp *expQuestion) expand(w io.Writer, varmap map[string]Value) error {
// TODO(yosida95): implement here
return nil
type varspec struct {
name string
maxlen int
explode bool
}

type expAmpersand struct {
vars []varspec
type expression struct {
vars []varspec
first string
sep string
named bool
ifemp string
}

func (exp *expAmpersand) expand(w io.Writer, varmap map[string]Value) error {
func (e *expression) expand(w *bytes.Buffer, values Values) error {
// TODO(yosida95): implement here
return nil
}
43 changes: 28 additions & 15 deletions parse.go
Original file line number Diff line number Diff line change
@@ -231,7 +231,7 @@ func (p *parser) consumeVariableList() ([]varspec, error) {
}
}

func (p *parser) consumeExpression() (expression, error) {
func (p *parser) consumeExpression() (template, error) {
debug.Printf("consumeExpression: %q", p.r)

p.dropN(1) // '{'
@@ -253,29 +253,42 @@ func (p *parser) consumeExpression() (expression, error) {
}
p.dropN(1) // '}'

ret := expression{
vars: varspecs,
}
switch op {
case parseOpSimple:
return &expSimple{vars: varspecs}, nil
ret.sep = ","
case parseOpPlus:
return &expPlus{vars: varspecs}, nil
ret.sep = ","
case parseOpCrosshatch:
return &expCrosshatch{vars: varspecs}, nil
ret.first = "#"
ret.sep = ","
case parseOpDot:
return &expDot{vars: varspecs}, nil
ret.first = "."
ret.sep = "."
case parseOpSlash:
return &expSlash{vars: varspecs}, nil
ret.first = "/"
ret.sep = "/"
case parseOpSemicolon:
return &expSemicolon{vars: varspecs}, nil
ret.first = ";"
ret.sep = ";"
ret.named = true
case parseOpQuestion:
return &expQuestion{vars: varspecs}, nil
ret.first = "?"
ret.sep = "&"
ret.named = true
ret.ifemp = "="
case parseOpAmpersand:
return &expAmpersand{vars: varspecs}, nil
default:
return nil, errorf(p.read, "unsupported operator")
ret.first = "&"
ret.sep = "&"
ret.named = true
ret.ifemp = "="
}
return &ret, nil
}

func (p *parser) consumeLiterals() (expression, error) {
func (p *parser) consumeLiterals() (template, error) {
debug.Printf("consumeLiterals: %q", p.r)
state := parseStateDefault
i := 0
@@ -316,22 +329,22 @@ Loop:
if state != parseStateDefault {
return nil, errorf(p.read+i, "invalid pct-encoded")
}
exp := expLiterals(p.r[:i])
exp := literals(p.r[:i])
p.dropN(i)
return exp, nil
}

func (p *parser) parseURITemplate() (*Template, error) {
debug.Printf("parseURITemplate: %q", p.r)
tmpl := Template{
exprs: []expression{},
exprs: []template{},
}
for {
if len(p.r) == 0 {
break
}

var expr expression
var expr template
var err error
if p.r[0] == '{' {
expr, err = p.consumeExpression()
30 changes: 2 additions & 28 deletions uritemplate.go
Original file line number Diff line number Diff line change
@@ -23,35 +23,9 @@ func (t debugT) Printf(format string, v ...interface{}) {
}
}

type Value interface {
}

// String returns Value that represents string.
func String(v string) Value {
return List(v)
}

// List returns Value that represents list.
func List(v ...string) Value {
return valueList(v)
}

// KV returns Value that represents associative list.
// KV panics if len(kv) is not even.
func KV(kv ...string) Value {
if len(kv)%2 != 0 {
panic("uritemplate.go: count of the kv must be even number")
}
return valueKV(kv)
}

type valueKV []string

type valueList []string

// Template represents an URI Template.
type Template struct {
exprs []expression
exprs []template
}

// New parse and construct new Template instance based on the template.
@@ -70,7 +44,7 @@ func MustNew(template string) *Template {
}

// Expand returns an URI reference corresponding t and vars.
func (t *Template) Expand(vars map[string]Value) (string, error) {
func (t *Template) Expand(vars Values) (string, error) {
w := bytes.Buffer{}
for i := range t.exprs {
expr := t.exprs[i]
62 changes: 0 additions & 62 deletions uritemplate_test.go

This file was deleted.

48 changes: 48 additions & 0 deletions value.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright (C) 2016 Kohei YOSHIDA. All rights reserved.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of The BSD 3-Clause License
// that can be found in the LICENSE file.

package uritemplate

type Values map[string]Value

func (v Values) Set(name string, value Value) {
v[name] = value // TODO(yosida95): canonicalize pct-encoded in the name
}

func (v Values) Get(name string) Value {
if v == nil {
return nil
}
return v[name] // TODO(yosida95): canonicalize pct-encoded in the name
}

type Value interface {
}

// String returns Value that represents string.
func String(v string) Value {
return valueString(v)
}

type valueString string

// List returns Value that represents list.
func List(v ...string) Value {
return valueList(v)
}

type valueList []string

// KV returns Value that represents associative list.
// KV panics if len(kv) is not even.
func KV(kv ...string) Value {
if len(kv)%2 != 0 {
panic("uritemplate.go: count of the kv must be even number")
}
return valueKV(kv)
}

type valueKV []string

0 comments on commit 4adff32

Please sign in to comment.