Skip to content

Instantly share code, notes, and snippets.

@tenntenn
Created December 30, 2016 02:48
Show Gist options
  • Save tenntenn/8426d5ac72e14f6ad634b306130b85de to your computer and use it in GitHub Desktop.
Save tenntenn/8426d5ac72e14f6ad634b306130b85de to your computer and use it in GitHub Desktop.
【実践goパッケージ】文字列から複素数型の値をパースする #golang ref: http://qiita.com/tenntenn/items/02e9a211d791901312a3
func ParseComplex(s string, bitSize int) (complex128, error)
func ParseComplex(s string, bitSize int) (complex128, error) {
expr, err := parser.ParseExpr(s)
if err != nil {
return 0, err
}
p := &complexParser{
expr: expr,
bitSize: bitSize,
}
c, err := p.parse()
if err != nil {
return 0, err
}
return c, nil
}
type complexParser struct {
expr ast.Expr
bitSize int
}
func (p *complexParser) parse() (complex128, error) {
v, err := p.parseExpr(p.expr)
if err != nil {
return 0, err
}
if v.Kind() != constant.Complex {
return 0, errors.New("cannot parse")
}
return p.complexVal(v)
}
func (p *complexParser) complexVal(v constant.Value) (complex128, error) {
rv := constant.Real(v)
iv := constant.Imag(v)
// complex64
if p.bitSize == 64 {
r, ok := constant.Float32Val(rv)
if !ok {
return 0, errors.New("cannot parse real part")
}
i, ok := constant.Float32Val(iv)
if !ok {
return 0, errors.New("cannot parse imag part")
}
return complex128(complex(r, i)), nil
}
// complex128
r, ok := constant.Float64Val(rv)
if !ok {
return 0, errors.New("cannot parse real part")
}
i, ok := constant.Float64Val(iv)
if !ok {
return 0, errors.New("cannot parse imag part")
}
return complex(r, i), nil
}
func (p *complexParser) parseExpr(expr ast.Expr) (rv constant.Value, rerr error) {
defer func() {
if r := recover(); r != nil {
switch err := r.(type) {
case error:
rv, rerr = constant.MakeUnknown(), err
default:
rv, rerr = constant.MakeUnknown(), fmt.Errorf("%v", err)
}
}
}()
switch expr := expr.(type) {
case *ast.UnaryExpr:
return p.parseUnaryExpr(expr)
case *ast.BinaryExpr:
return p.parseBinaryExpr(expr)
case *ast.BasicLit:
return p.parseBasicLit(expr), nil
}
return constant.MakeUnknown(), errors.New("cannot parse")
}
func (p *complexParser) parseUnaryExpr(expr *ast.UnaryExpr) (constant.Value, error) {
x, err := p.parseExpr(expr.X)
if err != nil {
return constant.MakeUnknown(), err
}
return constant.UnaryOp(expr.Op, x, 0), nil
}
func (p *complexParser) parseBinaryExpr(expr *ast.BinaryExpr) (constant.Value, error) {
x, err := p.parseExpr(expr.X)
if err != nil {
return constant.MakeUnknown(), err
}
y, err := p.parseExpr(expr.Y)
if err != nil {
return constant.MakeUnknown(), err
}
return constant.BinaryOp(x, expr.Op, y), nil
}
func (p *complexParser) parseBasicLit(expr *ast.BasicLit) constant.Value {
return constant.MakeFromLiteral(expr.Value, expr.Kind, 0)
}
package main
import (
"errors"
"fmt"
"go/ast"
"go/constant"
"go/parser"
)
type complexParser struct {
expr ast.Expr
bitSize int
}
func (p *complexParser) parse() (complex128, error) {
v, err := p.parseExpr(p.expr)
if err != nil {
return 0, err
}
if v.Kind() != constant.Complex {
return 0, errors.New("cannot parse")
}
return p.complexVal(v)
}
func (p *complexParser) complexVal(v constant.Value) (complex128, error) {
rv := constant.Real(v)
iv := constant.Imag(v)
// complex64
if p.bitSize == 64 {
r, ok := constant.Float32Val(rv)
if !ok {
return 0, errors.New("cannot parse real part")
}
i, ok := constant.Float32Val(iv)
if !ok {
return 0, errors.New("cannot parse imag part")
}
return complex128(complex(r, i)), nil
}
// complex128
r, ok := constant.Float64Val(rv)
if !ok {
return 0, errors.New("cannot parse real part")
}
i, ok := constant.Float64Val(iv)
if !ok {
return 0, errors.New("cannot parse imag part")
}
return complex(r, i), nil
}
func (p *complexParser) parseExpr(expr ast.Expr) (rv constant.Value, rerr error) {
defer func() {
if r := recover(); r != nil {
switch err := r.(type) {
case error:
rv, rerr = constant.MakeUnknown(), err
default:
rv, rerr = constant.MakeUnknown(), fmt.Errorf("%v", err)
}
}
}()
switch expr := expr.(type) {
case *ast.UnaryExpr:
return p.parseUnaryExpr(expr)
case *ast.BinaryExpr:
return p.parseBinaryExpr(expr)
case *ast.BasicLit:
return p.parseBasicLit(expr), nil
}
return constant.MakeUnknown(), errors.New("cannot parse")
}
func (p *complexParser) parseUnaryExpr(expr *ast.UnaryExpr) (constant.Value, error) {
x, err := p.parseExpr(expr.X)
if err != nil {
return constant.MakeUnknown(), err
}
return constant.UnaryOp(expr.Op, x, 0), nil
}
func (p *complexParser) parseBinaryExpr(expr *ast.BinaryExpr) (constant.Value, error) {
x, err := p.parseExpr(expr.X)
if err != nil {
return constant.MakeUnknown(), err
}
y, err := p.parseExpr(expr.Y)
if err != nil {
return constant.MakeUnknown(), err
}
return constant.BinaryOp(x, expr.Op, y), nil
}
func (p *complexParser) parseBasicLit(expr *ast.BasicLit) constant.Value {
return constant.MakeFromLiteral(expr.Value, expr.Kind, 0)
}
func ParseComplex(s string, bitSize int) (complex128, error) {
expr, err := parser.ParseExpr(s)
if err != nil {
return 0, err
}
p := &complexParser{
expr: expr,
bitSize: bitSize,
}
c, err := p.parse()
if err != nil {
return 0, err
}
return c, nil
}
func main() {
fmt.Println(ParseComplex("1 + 10i", 128))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment