gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

machine.go.rl (3309B)


      1 package urn
      2 
      3 import (
      4     "fmt"
      5 )
      6 
      7 var (
      8     errPrefix         = "expecting the prefix to be the \"urn\" string (whatever case) [col %d]"
      9     errIdentifier     = "expecting the identifier to be string (1..31 alnum chars, also containing dashes but not at its start) [col %d]"
     10     errSpecificString = "expecting the specific string to be a string containing alnum, hex, or others ([()+,-.:=@;$_!*']) chars [col %d]"
     11     errNoUrnWithinID  = "expecting the identifier to not contain the \"urn\" reserved string [col %d]"
     12     errHex            = "expecting the specific string hex chars to be well-formed (%%alnum{2}) [col %d]"
     13     errParse          = "parsing error [col %d]"
     14 )
     15 
     16 %%{
     17 machine urn;
     18 
     19 # unsigned alphabet
     20 alphtype uint8;
     21 
     22 action mark {
     23     m.pb = m.p
     24 }
     25 
     26 action tolower {
     27     m.tolower = append(m.tolower, m.p - m.pb)
     28 }
     29 
     30 action set_pre {
     31     output.prefix = string(m.text())
     32 }
     33 
     34 action set_nid {
     35     output.ID = string(m.text())
     36 }
     37 
     38 action set_nss {
     39     raw := m.text()
     40     output.SS = string(raw)
     41     // Iterate upper letters lowering them
     42     for _, i := range m.tolower {
     43         raw[i] = raw[i] + 32
     44     }
     45     output.norm = string(raw)
     46 }
     47 
     48 action err_pre {
     49     m.err = fmt.Errorf(errPrefix, m.p)
     50     fhold;
     51     fgoto fail;
     52 }
     53 
     54 action err_nid {
     55     m.err = fmt.Errorf(errIdentifier, m.p)
     56     fhold;
     57     fgoto fail;
     58 }
     59 
     60 action err_nss {
     61     m.err = fmt.Errorf(errSpecificString, m.p)
     62     fhold;
     63     fgoto fail;
     64 }
     65 
     66 action err_urn {
     67     m.err = fmt.Errorf(errNoUrnWithinID, m.p)
     68     fhold;
     69     fgoto fail;
     70 }
     71 
     72 action err_hex {
     73     m.err = fmt.Errorf(errHex, m.p)
     74     fhold;
     75     fgoto fail;
     76 }
     77 
     78 action err_parse {
     79     m.err = fmt.Errorf(errParse, m.p)
     80     fhold;
     81     fgoto fail;
     82 }
     83 
     84 pre = ([uU][rR][nN] @err(err_pre)) >mark %set_pre;
     85 
     86 nid = (alnum >mark (alnum | '-'){0,31}) %set_nid;
     87 
     88 hex = '%' (digit | lower | upper >tolower){2} $err(err_hex);
     89 
     90 sss = (alnum | [()+,\-.:=@;$_!*']);
     91 
     92 nss = (sss | hex)+ $err(err_nss);
     93 
     94 fail := (any - [\n\r])* @err{ fgoto main; };
     95 
     96 main := (pre ':' (nid - pre %err(err_urn)) $err(err_nid) ':' nss >mark %set_nss) $err(err_parse);
     97 
     98 }%%
     99 
    100 %% write data noerror noprefix;
    101 
    102 // Machine is the interface representing the FSM
    103 type Machine interface {
    104     Error() error
    105     Parse(input []byte) (*URN, error)
    106 }
    107 
    108 type machine struct {
    109     data              []byte
    110     cs                int
    111     p, pe, eof, pb    int
    112     err               error
    113     tolower           []int
    114 }
    115 
    116 // NewMachine creates a new FSM able to parse RFC 2141 strings.
    117 func NewMachine() Machine {
    118     m := &machine{}
    119 
    120     %% access m.;
    121     %% variable p m.p;
    122     %% variable pe m.pe;
    123     %% variable eof m.eof;
    124     %% variable data m.data;
    125 
    126     return m
    127 }
    128 
    129 // Err returns the error that occurred on the last call to Parse.
    130 //
    131 // If the result is nil, then the line was parsed successfully.
    132 func (m *machine) Error() error {
    133     return m.err
    134 }
    135 
    136 func (m *machine) text() []byte {
    137     return m.data[m.pb:m.p]
    138 }
    139 
    140 // Parse parses the input byte array as a RFC 2141 string.
    141 func (m *machine) Parse(input []byte) (*URN, error) {
    142     m.data = input
    143     m.p = 0
    144     m.pb = 0
    145     m.pe = len(input)
    146     m.eof = len(input)
    147     m.err = nil
    148     m.tolower = []int{}
    149     output := &URN{}
    150 
    151     %% write init;
    152     %% write exec;
    153 
    154     if m.cs < first_final || m.cs == en_fail {
    155         return nil, m.err
    156     }
    157 
    158     return output, nil
    159 }