Created
December 30, 2016 02:48
-
-
Save tenntenn/8426d5ac72e14f6ad634b306130b85de to your computer and use it in GitHub Desktop.
【実践goパッケージ】文字列から複素数型の値をパースする #golang ref: http://qiita.com/tenntenn/items/02e9a211d791901312a3
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
func ParseComplex(s string, bitSize int) (complex128, error) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type complexParser struct { | |
expr ast.Expr | |
bitSize int | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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") | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
func (p *complexParser) parseBasicLit(expr *ast.BasicLit) constant.Value { | |
return constant.MakeFromLiteral(expr.Value, expr.Kind, 0) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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