| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224 |
- // 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
- import (
- "fmt"
- "unicode/utf8"
- )
- type compiler struct {
- prog *prog
- }
- func (c *compiler) init() {
- c.prog = &prog{}
- }
- func (c *compiler) op(opcode progOpcode) uint32 {
- i := len(c.prog.op)
- c.prog.op = append(c.prog.op, progOp{code: opcode})
- return uint32(i)
- }
- func (c *compiler) opWithRune(opcode progOpcode, r rune) uint32 {
- addr := c.op(opcode)
- (&c.prog.op[addr]).r = r
- return addr
- }
- func (c *compiler) opWithRuneClass(opcode progOpcode, rc runeClass) uint32 {
- addr := c.op(opcode)
- (&c.prog.op[addr]).rc = rc
- return addr
- }
- func (c *compiler) opWithAddr(opcode progOpcode, absaddr uint32) uint32 {
- addr := c.op(opcode)
- (&c.prog.op[addr]).i = absaddr
- return addr
- }
- func (c *compiler) opWithAddrDelta(opcode progOpcode, delta uint32) uint32 {
- return c.opWithAddr(opcode, uint32(len(c.prog.op))+delta)
- }
- func (c *compiler) opWithName(opcode progOpcode, name string) uint32 {
- addr := c.op(opcode)
- (&c.prog.op[addr]).name = name
- return addr
- }
- func (c *compiler) compileString(str string) {
- for i := 0; i < len(str); {
- // NOTE(yosida95): It is confirmed at parse time that literals
- // consist of only valid-UTF8 runes.
- r, size := utf8.DecodeRuneInString(str[i:])
- c.opWithRune(opRune, r)
- i += size
- }
- }
- func (c *compiler) compileRuneClass(rc runeClass, maxlen int) {
- for i := 0; i < maxlen; i++ {
- if i > 0 {
- c.opWithAddrDelta(opSplit, 7)
- }
- c.opWithAddrDelta(opSplit, 3) // raw rune or pct-encoded
- c.opWithRuneClass(opRuneClass, rc) // raw rune
- c.opWithAddrDelta(opJmp, 4) //
- c.opWithRune(opRune, '%') // pct-encoded
- c.opWithRuneClass(opRuneClass, runeClassPctE) //
- c.opWithRuneClass(opRuneClass, runeClassPctE) //
- }
- }
- func (c *compiler) compileRuneClassInfinite(rc runeClass) {
- start := c.opWithAddrDelta(opSplit, 3) // raw rune or pct-encoded
- c.opWithRuneClass(opRuneClass, rc) // raw rune
- c.opWithAddrDelta(opJmp, 4) //
- c.opWithRune(opRune, '%') // pct-encoded
- c.opWithRuneClass(opRuneClass, runeClassPctE) //
- c.opWithRuneClass(opRuneClass, runeClassPctE) //
- c.opWithAddrDelta(opSplit, 2) // loop
- c.opWithAddr(opJmp, start) //
- }
- func (c *compiler) compileVarspecValue(spec varspec, expr *expression) {
- var specname string
- if spec.maxlen > 0 {
- specname = fmt.Sprintf("%s:%d", spec.name, spec.maxlen)
- } else {
- specname = spec.name
- }
- c.prog.numCap++
- c.opWithName(opCapStart, specname)
- split := c.op(opSplit)
- if spec.maxlen > 0 {
- c.compileRuneClass(expr.allow, spec.maxlen)
- } else {
- c.compileRuneClassInfinite(expr.allow)
- }
- capEnd := c.opWithName(opCapEnd, specname)
- c.prog.op[split].i = capEnd
- }
- func (c *compiler) compileVarspec(spec varspec, expr *expression) {
- switch {
- case expr.named && spec.explode:
- split1 := c.op(opSplit)
- noop := c.op(opNoop)
- c.compileString(spec.name)
- split2 := c.op(opSplit)
- c.opWithRune(opRune, '=')
- c.compileVarspecValue(spec, expr)
- split3 := c.op(opSplit)
- c.compileString(expr.sep)
- c.opWithAddr(opJmp, noop)
- c.prog.op[split2].i = uint32(len(c.prog.op))
- c.compileString(expr.ifemp)
- c.opWithAddr(opJmp, split3)
- c.prog.op[split1].i = uint32(len(c.prog.op))
- c.prog.op[split3].i = uint32(len(c.prog.op))
- case expr.named && !spec.explode:
- c.compileString(spec.name)
- split2 := c.op(opSplit)
- c.opWithRune(opRune, '=')
- split3 := c.op(opSplit)
- split4 := c.op(opSplit)
- c.compileVarspecValue(spec, expr)
- split5 := c.op(opSplit)
- c.prog.op[split4].i = split5
- c.compileString(",")
- c.opWithAddr(opJmp, split4)
- c.prog.op[split3].i = uint32(len(c.prog.op))
- c.compileString(",")
- jmp1 := c.op(opJmp)
- c.prog.op[split2].i = uint32(len(c.prog.op))
- c.compileString(expr.ifemp)
- c.prog.op[split5].i = uint32(len(c.prog.op))
- c.prog.op[jmp1].i = uint32(len(c.prog.op))
- case !expr.named:
- start := uint32(len(c.prog.op))
- c.compileVarspecValue(spec, expr)
- split1 := c.op(opSplit)
- jmp := c.op(opJmp)
- c.prog.op[split1].i = uint32(len(c.prog.op))
- if spec.explode {
- c.compileString(expr.sep)
- } else {
- c.opWithRune(opRune, ',')
- }
- c.opWithAddr(opJmp, start)
- c.prog.op[jmp].i = uint32(len(c.prog.op))
- }
- }
- func (c *compiler) compileExpression(expr *expression) {
- if len(expr.vars) < 1 {
- return
- }
- split1 := c.op(opSplit)
- c.compileString(expr.first)
- for i, size := 0, len(expr.vars); i < size; i++ {
- spec := expr.vars[i]
- split2 := c.op(opSplit)
- if i > 0 {
- split3 := c.op(opSplit)
- c.compileString(expr.sep)
- c.prog.op[split3].i = uint32(len(c.prog.op))
- }
- c.compileVarspec(spec, expr)
- c.prog.op[split2].i = uint32(len(c.prog.op))
- }
- c.prog.op[split1].i = uint32(len(c.prog.op))
- }
- func (c *compiler) compileLiterals(lt literals) {
- c.compileString(string(lt))
- }
- func (c *compiler) compile(tmpl *Template) {
- c.op(opLineBegin)
- for i := range tmpl.exprs {
- expr := tmpl.exprs[i]
- switch expr := expr.(type) {
- default:
- panic("unhandled expression")
- case *expression:
- c.compileExpression(expr)
- case literals:
- c.compileLiterals(expr)
- }
- }
- c.op(opLineEnd)
- c.op(opEnd)
- }
|