Skip to content

Commit

Permalink
chore: clean up implementation (#30)
Browse files Browse the repository at this point in the history
  • Loading branch information
muktihari authored Jan 1, 2024
1 parent a801aaa commit 6caabae
Show file tree
Hide file tree
Showing 16 changed files with 402 additions and 239 deletions.
112 changes: 46 additions & 66 deletions arithmetic.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,25 +34,23 @@ func arithmetic(v, vx, vy *Visitor, binaryExpr *ast.BinaryExpr) {
}

switch v.options.numericType {
case NumericTypeAuto:
if vx.kind == KindImag || vy.kind == KindImag {
calculateComplex(v, parseComplex(vx.value), parseComplex(vy.value), binaryExpr.Op, binaryExpr.OpPos)
return
}
calculateFloat(v, parseFloat(vx.value), parseFloat(vy.value), binaryExpr.Op)
return
case NumericTypeComplex:
calculateComplex(v, vx, vy, binaryExpr)
calculateComplex(v, parseComplex(vx.value), parseComplex(vy.value), binaryExpr.Op, binaryExpr.OpPos)
return
case NumericTypeFloat:
calculateFloat(v, vx, vy, binaryExpr)
calculateFloat(v, parseFloat(vx.value), parseFloat(vy.value), binaryExpr.Op)
return
case NumericTypeInt:
calculateInt(v, vx, vy, binaryExpr)
return
}

// NumericTypeAuto: Auto figure out value type
if vx.kind == KindImag || vy.kind == KindImag {
calculateComplex(v, vx, vy, binaryExpr)
calculateInt(v, parseInt(vx.value), parseInt(vy.value), vy.pos, binaryExpr.Op)
return
}

// calculate other types as float64
calculateFloat(v, vx, vy, binaryExpr)
}

func newArithmeticNonNumericError(v *Visitor, e ast.Expr) error {
Expand All @@ -64,12 +62,9 @@ func newArithmeticNonNumericError(v *Visitor, e ast.Expr) error {
}
}

func calculateComplex(v, vx, vy *Visitor, binaryExpr *ast.BinaryExpr) {
func calculateComplex(v *Visitor, x, y complex128, op token.Token, opPos token.Pos) {
v.kind = KindImag
x := parseComplex(vx.value, vx.kind)
y := parseComplex(vy.value, vy.kind)

switch binaryExpr.Op {
switch op {
case token.ADD:
v.value = x + y
case token.SUB:
Expand All @@ -79,22 +74,17 @@ func calculateComplex(v, vx, vy *Visitor, binaryExpr *ast.BinaryExpr) {
case token.QUO:
v.value = x / y
case token.REM:
v.kind = KindIllegal
v.err = &SyntaxError{
Msg: "operator \"" + binaryExpr.Op.String() + "\" is not supported to do arithmetic on complex number",
Pos: int(binaryExpr.OpPos),
Msg: "operator \"" + op.String() + "\" is not supported to do arithmetic on complex number",
Pos: int(opPos),
Err: ErrArithmeticOperation,
}
return
}
}

func calculateFloat(v, vx, vy *Visitor, binaryExpr *ast.BinaryExpr) {
func calculateFloat(v *Visitor, x, y float64, op token.Token) {
v.kind = KindFloat
x := parseFloat(vx.value, vx.kind)
y := parseFloat(vy.value, vy.kind)

switch binaryExpr.Op {
switch op {
case token.ADD:
v.value = x + y
case token.SUB:
Expand All @@ -108,12 +98,9 @@ func calculateFloat(v, vx, vy *Visitor, binaryExpr *ast.BinaryExpr) {
}
}

func calculateInt(v, vx, vy *Visitor, binaryExpr *ast.BinaryExpr) {
func calculateInt(v *Visitor, x, y int64, yPos int, op token.Token) {
v.kind = KindInt
x := parseInt(vx.value, vx.kind)
y := parseInt(vy.value, vy.kind)

switch binaryExpr.Op {
switch op {
case token.ADD:
v.value = x + y
case token.SUB:
Expand All @@ -126,10 +113,9 @@ func calculateInt(v, vx, vy *Visitor, binaryExpr *ast.BinaryExpr) {
v.value = int64(0)
return
}
v.kind = KindIllegal
v.err = &SyntaxError{
Msg: "could not divide x with zero y, allowIntegerDividedByZero == false",
Pos: vy.pos,
Pos: yPos,
Err: ErrIntegerDividedByZero,
}
return
Expand All @@ -140,44 +126,38 @@ func calculateInt(v, vx, vy *Visitor, binaryExpr *ast.BinaryExpr) {
}
}

func parseComplex(v interface{}, kind Kind) complex128 { // kind must be numeric
switch kind {
case KindImag:
v := v.(complex128)
return v
case KindFloat:
v := v.(float64)
return complex(v, 0)
default: // INT: 0xFF, 0b1010, 0o77, 071, 90
v := v.(int64)
return complex(float64(v), 0)
func parseComplex(value interface{}) complex128 { // kind must be numeric
switch val := value.(type) {
case complex128:
return val
case float64:
return complex(val, 0)
case int64:
return complex(float64(val), 0)
}
return 0
}

func parseFloat(v interface{}, kind Kind) float64 { // kind must be numeric
switch kind {
case KindImag:
v := v.(complex128)
return real(v)
case KindFloat:
v := v.(float64)
return v
default: // INT: 0xFF, 0b1010, 0o77, 071, 90
v := v.(int64)
return float64(v)
func parseFloat(value interface{}) float64 {
switch val := value.(type) {
case complex128:
return real(val)
case float64:
return val
case int64:
return float64(val)
}
return 0
}

func parseInt(v interface{}, kind Kind) int64 { // kind must be numeric
switch kind {
case KindImag:
v := v.(complex128)
return int64(real(v))
case KindFloat:
v := v.(float64)
return int64(v)
default: // INT: 0xFF, 0b1010, 0o77, 071, 90
v := v.(int64)
return v
func parseInt(value interface{}) int64 {
switch val := value.(type) {
case complex128:
return int64(real(val))
case float64:
return int64(val)
case int64:
return val
}
return 0
}
29 changes: 22 additions & 7 deletions arithmetic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ func TestArithmetic(t *testing.T) {
be := &ast.BinaryExpr{Op: tc.op}
arithmetic(tc.v, tc.vx, tc.vy, be)
if !errors.Is(tc.v.err, tc.expectedErr) {
t.Fatalf("expected err: %s, got: %s", tc.expectedErr, tc.v.err)
t.Fatalf("expected err: %v, got: %v", tc.expectedErr, tc.v.err)
}
if tc.v.value != tc.expectedValue {
t.Fatalf("expected value: %v (%T), got: %v (%T)", tc.expectedValue, tc.expectedValue,
Expand Down Expand Up @@ -189,9 +189,9 @@ func TestCalculateComplex(t *testing.T) {
name := fmt.Sprintf("%v%s%v", tc.vx.value, op, tc.vy.value)
t.Run(name, func(t *testing.T) {
be := &ast.BinaryExpr{Op: op}
calculateComplex(tc.v, tc.vx, tc.vy, be)
calculateComplex(tc.v, parseComplex(tc.vx.value), parseComplex(tc.vy.value), be.Op, be.OpPos)
if !errors.Is(tc.v.err, tc.expectedErrs[i]) {
t.Fatalf("expected err: %s, got: %s", tc.expectedErrs[i], tc.v.err)
t.Fatalf("expected err: %v, got: %v", tc.expectedErrs[i], tc.v.err)
}
if tc.v.value != tc.expectedValues[i] {
t.Fatalf("expected value: %v (%T), got: % (%T)", tc.expectedValues[i], tc.expectedValues[i],
Expand Down Expand Up @@ -252,9 +252,9 @@ func TestCalculateFloat(t *testing.T) {
name := fmt.Sprintf("%v%s%v", tc.vx.value, op, tc.vy.value)
t.Run(name, func(t *testing.T) {
be := &ast.BinaryExpr{Op: op}
calculateFloat(tc.v, tc.vx, tc.vy, be)
calculateFloat(tc.v, parseFloat(tc.vx.value), parseFloat(tc.vy.value), be.Op)
if !errors.Is(tc.v.err, tc.expectedErrs[i]) {
t.Fatalf("expected err: %s, got: %s", tc.expectedErrs[i], tc.v.err)
t.Fatalf("expected err: %v, got: %v", tc.expectedErrs[i], tc.v.err)
}
if tc.v.value != tc.expectedValues[i] {
t.Fatalf("expected value: %v (%T), got: %s (%T)", tc.expectedValues[i], tc.expectedValues[i],
Expand Down Expand Up @@ -336,9 +336,9 @@ func TestCalculateInt(t *testing.T) {
name := fmt.Sprintf("%v%s%v", tc.vx.value, op, tc.vy.value)
t.Run(name, func(t *testing.T) {
be := &ast.BinaryExpr{Op: op}
calculateInt(tc.v, tc.vx, tc.vy, be)
calculateInt(tc.v, parseInt(tc.vx.value), parseInt(tc.vy.value), tc.vy.pos, be.Op)
if !errors.Is(tc.v.err, tc.expectedErrs[i]) {
t.Fatalf("expected err: %s, got: %s", tc.expectedErrs[i], tc.v.err)
t.Fatalf("expected err: %v, got: %v", tc.expectedErrs[i], tc.v.err)
}
if tc.v.value != tc.expectedValues[i] {
t.Fatalf("expected value: %v (%T), got: %v (%T)", tc.expectedValues[i], tc.expectedValues[i],
Expand All @@ -349,3 +349,18 @@ func TestCalculateInt(t *testing.T) {
})
}
}

func TestParseInvalidValue(t *testing.T) {
i64 := parseInt("invalid")
if i64 != 0 {
t.Fatalf("expected 0, got: %v", i64)
}
f64 := parseFloat(true)
if f64 != 0 {
t.Fatalf("expected 0, got: %v", f64)
}
c128 := parseComplex(false)
if c128 != 0 {
t.Fatalf("expected 0, got: %v", c128)
}
}
48 changes: 31 additions & 17 deletions bitwise.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,39 +22,41 @@ import (
)

func bitwise(v, vx, vy *Visitor, binaryExpr *ast.BinaryExpr) {
// No matters what options, having bolean here is invalid.
if vx.kind == KindBoolean {
// numeric guards:
if vx.kind <= numeric_beg || vx.kind >= numeric_end {
v.err = newBitwiseNonIntegerError(vx, binaryExpr.X)
return
}
if vy.kind == KindBoolean {
v.err = newBitwiseNonIntegerError(vx, binaryExpr.Y)
if vy.kind <= numeric_beg || vy.kind >= numeric_end {
v.err = newBitwiseNonIntegerError(vy, binaryExpr.Y)
return
}

var x, y int64
switch v.options.numericType {
case NumericTypeFloat:
v.err = newBitwiseNonIntegerError(v, binaryExpr)
return
case NumericTypeComplex:
v.err = newBitwiseNonIntegerError(v, binaryExpr)
return
case NumericTypeInt:
x = parseInt(vx.value)
y = parseInt(vy.value)
case NumericTypeAuto:
// NumericTypeAuto: check whether both values are represent integers
x := parseFloat(vx.value, vx.kind)
y := parseFloat(vy.value, vy.kind)

if x != float64(int64(x)) {
var ok bool
x, ok = convertToInt64(vx.value)
if !ok {
v.err = newBitwiseNonIntegerError(vx, binaryExpr.X)
return
}

if y != float64(int64(y)) {
y, ok = convertToInt64(vy.value)
if !ok {
v.err = newBitwiseNonIntegerError(vy, binaryExpr.Y)
return
}
case NumericTypeFloat, NumericTypeComplex:
v.err = newBitwiseNonIntegerError(vy, binaryExpr.Y)
return
}

x := parseInt(vx.value, vx.kind)
y := parseInt(vy.value, vy.kind)

v.kind = KindInt
switch binaryExpr.Op {
case token.AND:
Expand All @@ -80,3 +82,15 @@ func newBitwiseNonIntegerError(v *Visitor, e ast.Expr) error {
Err: ErrBitwiseOperation,
}
}

func convertToInt64(value interface{}) (int64, bool) {
switch val := value.(type) {
case float64:
if float64(int64(val)) == val { // only if it doesn't have decimal.
return int64(val), true
}
case int64:
return val, true
}
return 0, false
}
7 changes: 7 additions & 0 deletions codecov.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
ignore:
# Example:
# - "path/to/folder" # ignore folders and all its contents
# - "test_*.rb" # wildcards accepted
# - "**/*.py" # glob accepted
# Please specify the rules below:
- "exp"
Loading

0 comments on commit 6caabae

Please sign in to comment.