diff --git a/number/parse.go b/number/parse.go new file mode 100644 index 0000000..f2b89f9 --- /dev/null +++ b/number/parse.go @@ -0,0 +1,110 @@ +package rfc8259number + +import ( + "io" + + "sourcecode.social/reiver/go-rfc8259/errors" + "sourcecode.social/reiver/go-rfc8259/exponentnumber" + "sourcecode.social/reiver/go-rfc8259/fractionalnumber" + "sourcecode.social/reiver/go-rfc8259/naturalnumber" +) + +// Parse tries to parse a JSON number literal. +// If it succeeds, then it return nil, and sets ‘dst’ to the parsed value. +// If it failed, it returns an error. +// +// Example usage: +// +// var rs io.RuneScaner +// +// // ... +// +// var value rfc8259number.Number +// err := rfc8259number.Parse(rs, &value) +// +// if nil != err { +// return err +// } +// +// fmt.Printf("value = %#v\n", value) +func Parse(runescanner io.RuneScanner, dst *Number) error { + if nil == runescanner { + return rfc8259errors.ErrNilRuneScanner + } + if nil == dst { + return rfc8259errors.ErrNilDestination + } + + var natPart rfc8259naturalnumber.NaturalNumber // [ minus ] int + var fracPart rfc8259fractionalnumber.FractionalNumber // [ frac ] + var expPart rfc8259exponentnumber.ExponentNumber // [ exp ] + + // [ minus ] int + { + if err := rfc8259naturalnumber.Parse(runescanner, &natPart); nil != err { + return err + } + if rfc8259naturalnumber.Nothing() == natPart { + return rfc8259errors.ErrInternalError("expected the result of a natural-number, but it is actually nothing") + } + } + + // [ frac ] + { + var r rune + { + var err error + + r, _, err = runescanner.ReadRune() + if nil != err { + if io.EOF == err { + natPart.WhenSomething(func(value string){ + *dst = Something(value) + }) + return nil + } + + return rfc8259errors.ErrProblemReadingRune(err) + } + if err := runescanner.UnreadRune(); nil != err { + return rfc8259errors.ErrProblemUnreadingRune(err, r) + } + } + + if '.' == r { + if err := rfc8259fractionalnumber.Parse(runescanner, &fracPart); nil != err { + return err + } + } + } + + // [ exp ] + { + var r rune + { + var err error + + r, _, err = runescanner.ReadRune() + if nil != err { + if io.EOF == err { + *dst = Something(natPart.GetElse("") + fracPart.GetElse("")) + return nil + } + + return rfc8259errors.ErrProblemReadingRune(err) + } + if err := runescanner.UnreadRune(); nil != err { + return rfc8259errors.ErrProblemUnreadingRune(err, r) + } + } + + if 'E' == r || 'e' == r { + if err := rfc8259exponentnumber.Parse(runescanner, &expPart); nil != err { + return err + } + } + } + + *dst = Something(natPart.GetElse("") + fracPart.GetElse("") + expPart.GetElse("")) + return nil +}