github.com/hirochachacha/plua@v0.0.0-20170217012138-c82f520cc725/internal/errors/errors.go (about)

     1  package errors
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/hirochachacha/plua/object"
     7  )
     8  
     9  func NaNIndexError() *object.RuntimeError {
    10  	return object.NewRuntimeError("table index is nan")
    11  }
    12  
    13  func NilIndexError() *object.RuntimeError {
    14  	return object.NewRuntimeError("table index is nil")
    15  }
    16  
    17  func StackOverflowError() *object.RuntimeError {
    18  	return object.NewRuntimeError("Go stack overflow")
    19  }
    20  
    21  func InvalidByteCodeError() *object.RuntimeError {
    22  	return object.NewRuntimeError("malformed bytecode detected")
    23  }
    24  
    25  func ForLoopError(elem string) *object.RuntimeError {
    26  	return object.NewRuntimeError(fmt.Sprintf("'for' %s value must be a number", elem))
    27  }
    28  
    29  func typeName(th object.Thread, arg object.Value) string {
    30  	if mt := th.GetMetatable(arg); mt != nil {
    31  		if name := mt.Get(object.TM_NAME); name != nil {
    32  			if name, ok := name.(object.String); ok {
    33  				return string(name)
    34  			}
    35  			if _, ok := arg.(object.LightUserdata); ok {
    36  				return "light userdata"
    37  			}
    38  			return object.ToType(arg).String()
    39  		}
    40  	}
    41  	if _, ok := arg.(object.LightUserdata); ok {
    42  		return "light userdata"
    43  	}
    44  	return object.ToType(arg).String()
    45  }
    46  
    47  func TypeError(th object.Thread, op string, x object.Value) *object.RuntimeError {
    48  	return object.NewRuntimeError(fmt.Sprintf("attempt to %s a %s value%s", op, typeName(th, x), varinfo(th, x)))
    49  }
    50  
    51  func CallError(th object.Thread, fn object.Value) *object.RuntimeError {
    52  	return TypeError(th, "call", fn)
    53  }
    54  
    55  func IndexError(th object.Thread, t object.Value) *object.RuntimeError {
    56  	return TypeError(th, "index", t)
    57  }
    58  
    59  func UnaryError(th object.Thread, tag object.Value, x object.Value) *object.RuntimeError {
    60  	switch tag {
    61  	case object.TM_LEN:
    62  		return LengthError(th, x)
    63  	case object.TM_UNM:
    64  		return UnaryMinusError(th, x)
    65  	case object.TM_BNOT:
    66  		return BinaryNotError(th, x)
    67  	default:
    68  		panic("unreachable")
    69  	}
    70  }
    71  
    72  func BinaryError(th object.Thread, tag object.Value, x, y object.Value) *object.RuntimeError {
    73  	switch tag {
    74  	case object.TM_ADD, object.TM_SUB, object.TM_MUL, object.TM_MOD, object.TM_POW, object.TM_DIV:
    75  		return ArithError(th, x, y)
    76  	case object.TM_IDIV, object.TM_BAND, object.TM_BOR, object.TM_BXOR, object.TM_SHL, object.TM_SHR:
    77  		return BitwiseError(th, x, y)
    78  	case object.TM_CONCAT:
    79  		return ConcatError(th, x, y)
    80  	default:
    81  		panic("unreachable")
    82  	}
    83  }
    84  
    85  func LengthError(th object.Thread, x object.Value) *object.RuntimeError {
    86  	return TypeError(th, "get length of", x)
    87  }
    88  
    89  func UnaryMinusError(th object.Thread, x object.Value) *object.RuntimeError {
    90  	return TypeError(th, "negate", x)
    91  }
    92  
    93  func BinaryNotError(th object.Thread, x object.Value) *object.RuntimeError {
    94  	if _, ok := object.ToNumber(x); ok {
    95  		return object.NewRuntimeError(fmt.Sprintf("number%s has no integer representation", varinfo(th, x)))
    96  	}
    97  	return TypeError(th, "bitwise negation on", x)
    98  }
    99  
   100  func CompareError(th object.Thread, x, y object.Value) *object.RuntimeError {
   101  	t1 := typeName(th, x)
   102  	t2 := typeName(th, y)
   103  
   104  	if t1 == t2 {
   105  		return object.NewRuntimeError(fmt.Sprintf("attempt to compare two %s values", t1))
   106  	}
   107  
   108  	return object.NewRuntimeError(fmt.Sprintf("attempt to compare %s with %s", t1, t2))
   109  }
   110  
   111  func ArithError(th object.Thread, x, y object.Value) *object.RuntimeError {
   112  	if _, ok := object.ToNumber(x); ok {
   113  		return TypeError(th, "perform arithmetic on", y)
   114  	}
   115  	return TypeError(th, "perform arithmetic on", x)
   116  }
   117  
   118  func BitwiseError(th object.Thread, x, y object.Value) *object.RuntimeError {
   119  	if _, ok := object.ToInteger(x); ok {
   120  		if _, ok := object.ToNumber(y); ok {
   121  			return object.NewRuntimeError(fmt.Sprintf("number%s has no integer representation", varinfo(th, y)))
   122  		}
   123  		return TypeError(th, "perform bitwise operation on", y)
   124  	}
   125  	if _, ok := object.ToNumber(x); ok {
   126  		return object.NewRuntimeError(fmt.Sprintf("number%s has no integer representation", varinfo(th, x)))
   127  	}
   128  	return TypeError(th, "perform bitwise operation on", x)
   129  }
   130  
   131  func ConcatError(th object.Thread, x, y object.Value) *object.RuntimeError {
   132  	if _, ok := object.ToString(x); ok {
   133  		return TypeError(th, "concatenate", y)
   134  	}
   135  	return TypeError(th, "concatenate", x)
   136  }
   137  
   138  func varinfo(th object.Thread, x object.Value) string {
   139  	// TODO? INCOMPATIBLE
   140  	// Current implementation uses value instead of pointer everywhere.
   141  	// So there is no way to identify two object is exactly same.
   142  	// That's why I can't implement this.
   143  	return ""
   144  }