separate number into float and integer

This commit is contained in:
Neemek 2026-07-07 23:24:44 +02:00
parent 10f55313b0
commit daab50d54c
Signed by: neemek
GPG key ID: 84FFE4D7D40AB25E
22 changed files with 848 additions and 428 deletions

View file

@ -3,7 +3,7 @@ package core
import (
"errors"
"fmt"
"math"
"math/big"
"reflect"
"strconv"
)
@ -13,7 +13,8 @@ type ValueType int
const (
NilValueType ValueType = iota
BoolValueType
NumberValueType
FloatValueType
IntegerValueType
StringValueType
ListValueType
ObjectValueType
@ -30,8 +31,10 @@ func (v ValueType) String() string {
return "bool"
case ObjectValueType:
return "object"
case NumberValueType:
return "number"
case FloatValueType:
return "float"
case IntegerValueType:
return "int"
case StringValueType:
return "string"
case ListValueType:
@ -57,11 +60,15 @@ func GoToValue(gov interface{}) Value {
v,
}
case int:
return &NumberValue{
float64(v),
return &IntegerValue{
new(big.Int).SetInt64(int64(v)),
}
case *big.Int:
return &IntegerValue{
v,
}
case float64:
return &NumberValue{
return &FloatValue{
v,
}
case string:
@ -259,40 +266,71 @@ func (v *ObjectValue) Clone() Value {
}
}
// NumberValue Integer or floating-point values
type NumberValue struct {
// FloatValue floating-point values
type FloatValue struct {
Number float64
}
const NumberSize int = 64
const FloatSize int = 64
func (v *NumberValue) Type() ValueType {
return NumberValueType
func (v *FloatValue) Type() ValueType {
return FloatValueType
}
func (v *NumberValue) String() string {
return strconv.FormatFloat(v.Number, 'g', -1, NumberSize)
func (v *FloatValue) String() string {
return strconv.FormatFloat(v.Number, 'g', -1, FloatSize)
}
func (v *NumberValue) DebugString() string {
func (v *FloatValue) DebugString() string {
return v.String()
}
func (v *NumberValue) Equals(other Value) bool {
return other.Type() == NumberValueType && other.(*NumberValue).Number == v.Number
func (v *FloatValue) Equals(other Value) bool {
return other.Type() == FloatValueType && other.(*FloatValue).Number == v.Number
}
func (v *NumberValue) Get(_ string) (Value, error) {
func (v *FloatValue) Get(_ string) (Value, error) {
// TODO maybe add standard functions for number values?
return nil, errors.New("numbers have no properties")
}
func (v *NumberValue) Clone() Value {
return &NumberValue{
func (v *FloatValue) Clone() Value {
return &FloatValue{
v.Number,
}
}
// IntegerValue whole number/integer values
type IntegerValue struct {
Number *big.Int
}
func (v *IntegerValue) Type() ValueType {
return IntegerValueType
}
func (v *IntegerValue) String() string {
return v.Number.String()
}
func (v *IntegerValue) DebugString() string {
return v.String()
}
func (v *IntegerValue) Equals(other Value) bool {
return other.Type() == IntegerValueType && other.(*IntegerValue).Number.Cmp(v.Number) == 0
}
func (v *IntegerValue) Get(_ string) (Value, error) {
return nil, errors.New("numbers have no properties")
}
func (v *IntegerValue) Clone() Value {
return &IntegerValue{
new(big.Int).Set(v.Number),
}
}
type StringValue struct {
Text string
}
@ -348,7 +386,7 @@ var StringPrototype = map[string]*BuiltinFunctionValue{
Name: "length",
Signature: &FunctionSignature{
[]TypeSignature{},
&NumberSignature{},
&IntegerSignature{},
},
F: func(vm *VM, this Value, _ []Value) (Value, error) {
return GoToValue(len(this.(*StringValue).Text)), nil
@ -357,11 +395,11 @@ var StringPrototype = map[string]*BuiltinFunctionValue{
"at": {
Name: "at",
Signature: &FunctionSignature{
[]TypeSignature{&NumberSignature{}},
[]TypeSignature{&IntegerSignature{}},
&StringSignature{},
},
F: func(vm *VM, this Value, args []Value) (Value, error) {
i := int(math.Floor(args[0].(*NumberValue).Number))
i := int(args[0].(*IntegerValue).Number.Int64())
if i < 0 || i >= len(this.(*StringValue).Text) {
return nil, errors.New("index is out of range")
@ -450,13 +488,13 @@ var ListPrototype = map[string]*BuiltinFunctionValue{
"at",
&FunctionSignature{
[]TypeSignature{
&NumberSignature{},
&IntegerSignature{},
},
&InnerSignature{},
},
func(_ *VM, this Value, p []Value) (Value, error) {
items := this.(*ListValue).Items
index := int(p[0].(*NumberValue).Number)
index := int(p[0].(*IntegerValue).Number.Int64())
if index >= len(items) {
return nil, errors.New(fmt.Sprintf("list index %x out of range", index))
@ -471,13 +509,13 @@ var ListPrototype = map[string]*BuiltinFunctionValue{
"put",
&FunctionSignature{
[]TypeSignature{
&NumberSignature{}, &InnerSignature{},
&FloatSignature{}, &InnerSignature{},
},
&NilSignature{},
},
func(_ *VM, this Value, args []Value) (Value, error) {
l := this.(*ListValue)
i := int(args[0].(*NumberValue).Number)
i := int(args[0].(*FloatValue).Number)
v := args[1]
// bounds check
@ -496,7 +534,7 @@ var ListPrototype = map[string]*BuiltinFunctionValue{
"length",
&FunctionSignature{
[]TypeSignature{},
&NumberSignature{},
&IntegerSignature{},
},
func(_ *VM, this Value, _ []Value) (Value, error) {
return GoToValue(len(this.(*ListValue).Items)), nil