separate number into float and integer
This commit is contained in:
parent
10f55313b0
commit
daab50d54c
22 changed files with 848 additions and 428 deletions
333
core/vm.go
333
core/vm.go
|
|
@ -7,7 +7,9 @@ import (
|
|||
"fmt"
|
||||
"log"
|
||||
"math"
|
||||
"math/big"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
|
@ -20,30 +22,52 @@ const (
|
|||
// InstructionPop pop and delete the first item on the stack
|
||||
InstructionPop
|
||||
|
||||
// InstructionAdd pop two and add them
|
||||
InstructionAdd
|
||||
// InstructionSub pop two and subtract the second from the first
|
||||
InstructionSub
|
||||
// InstructionMul pop two and multiply them
|
||||
InstructionMul
|
||||
// InstructionDiv pop two and divide the second by the first
|
||||
InstructionDiv
|
||||
// InstructionNegate negate the value; if it was positive, make it negative, and vice versa.
|
||||
InstructionNegate
|
||||
// InstructionAddFloat pop two floats and add them
|
||||
InstructionAddFloat
|
||||
// InstructionSubFloat pop two floats and subtract the second from the first
|
||||
InstructionSubFloat
|
||||
// InstructionMulFloat pop two floats and multiply them
|
||||
InstructionMulFloat
|
||||
// InstructionDivFloat pop two floats and divide the second by the first
|
||||
InstructionDivFloat
|
||||
// InstructionNegateFloat negate the float; if it was positive, make it negative, and vice versa.
|
||||
InstructionNegateFloat
|
||||
|
||||
// InstructionAddInt pop two ints and add them
|
||||
InstructionAddInt
|
||||
// InstructionSubInt pop two ints and subtract the second from the first
|
||||
InstructionSubInt
|
||||
// InstructionMulInt pop two ints and multiply them
|
||||
InstructionMulInt
|
||||
// InstructionDivInt pop two ints and divide the second by the first
|
||||
InstructionDivInt
|
||||
// InstructionNegateInt negate the int; if it was positive, make it negative, and vice versa.
|
||||
InstructionNegateInt
|
||||
|
||||
// InstructionEquals whether the two top values on the stack are equal
|
||||
InstructionEquals
|
||||
// InstructionNotEqual whether the two top values on the stack are not equal
|
||||
InstructionNotEqual
|
||||
// InstructionNot inverts boolean (true => false, false => true)
|
||||
InstructionNot
|
||||
// InstructionLess pops two from stack, pushes whether the lowest is less than the highest
|
||||
InstructionLess
|
||||
// InstructionLessOrEqual pops two from stack, pushes whether the lowest is less or equal than the highest
|
||||
InstructionLessOrEqual
|
||||
// InstructionGreater pops two from stack, pushes whether the lowest is greater than the highest
|
||||
InstructionGreater
|
||||
// InstructionGreaterOrEqual pops two from stack, pushes whether the lowest is greater or equal than the highest
|
||||
InstructionGreaterOrEqual
|
||||
|
||||
// InstructionLessFloat pops two from stack, pushes whether the lowest is less than the highest
|
||||
InstructionLessFloat
|
||||
// InstructionLessOrEqualFloat pops two from stack, pushes whether the lowest is less or equal than the highest
|
||||
InstructionLessOrEqualFloat
|
||||
// InstructionGreaterFloat pops two from stack, pushes whether the lowest is greater than the highest
|
||||
InstructionGreaterFloat
|
||||
// InstructionGreaterOrEqualFloat pops two from stack, pushes whether the lowest is greater or equal than the highest
|
||||
InstructionGreaterOrEqualFloat
|
||||
|
||||
// InstructionLessInt pops two from stack, pushes whether the lowest is less than the highest
|
||||
InstructionLessInt
|
||||
// InstructionLessOrEqualInt pops two from stack, pushes whether the lowest is less or equal than the highest
|
||||
InstructionLessOrEqualInt
|
||||
// InstructionGreaterInt pops two from stack, pushes whether the lowest is greater than the highest
|
||||
InstructionGreaterInt
|
||||
// InstructionGreaterOrEqualInt pops two from stack, pushes whether the lowest is greater or equal than the highest
|
||||
InstructionGreaterOrEqualInt
|
||||
|
||||
// InstructionAccessProperty gets a property from a value, and pops it onto the stack
|
||||
InstructionAccessProperty
|
||||
|
|
@ -116,30 +140,48 @@ func (b Bytecode) String() string {
|
|||
return "RETURN"
|
||||
case InstructionPop:
|
||||
return "POP"
|
||||
case InstructionAdd:
|
||||
return "ADD"
|
||||
case InstructionSub:
|
||||
return "SUB"
|
||||
case InstructionMul:
|
||||
return "MUL"
|
||||
case InstructionDiv:
|
||||
return "DIV"
|
||||
case InstructionNegate:
|
||||
return "NEGATE"
|
||||
case InstructionAddFloat:
|
||||
return "ADD_FLOAT"
|
||||
case InstructionSubFloat:
|
||||
return "SUB_FLOAT"
|
||||
case InstructionMulFloat:
|
||||
return "MUL_FLOAT"
|
||||
case InstructionDivFloat:
|
||||
return "DIV_FLOAT"
|
||||
case InstructionNegateFloat:
|
||||
return "NEGATE_FLOAT"
|
||||
case InstructionAddInt:
|
||||
return "ADD_INT"
|
||||
case InstructionSubInt:
|
||||
return "SUB_INT"
|
||||
case InstructionMulInt:
|
||||
return "MUL_INT"
|
||||
case InstructionDivInt:
|
||||
return "DIV_INT"
|
||||
case InstructionNegateInt:
|
||||
return "NEGATE_INT"
|
||||
case InstructionEquals:
|
||||
return "EQUALS"
|
||||
case InstructionNotEqual:
|
||||
return "NOT_EQUALS"
|
||||
case InstructionNot:
|
||||
return "NOT"
|
||||
case InstructionLess:
|
||||
return "LESS"
|
||||
case InstructionLessOrEqual:
|
||||
return "LESS_OR_EQUAL"
|
||||
case InstructionGreater:
|
||||
return "GREATER_OR_EQUAL"
|
||||
case InstructionGreaterOrEqual:
|
||||
return "GREATER_OR_EQUAL"
|
||||
case InstructionLessFloat:
|
||||
return "LESS_FLOAT"
|
||||
case InstructionLessOrEqualFloat:
|
||||
return "LESS_OR_EQUAL_FLOAT"
|
||||
case InstructionGreaterFloat:
|
||||
return "GREATER_FLOAT"
|
||||
case InstructionGreaterOrEqualFloat:
|
||||
return "GREATER_OR_EQUAL_FLOAT"
|
||||
case InstructionLessInt:
|
||||
return "LESS_INT"
|
||||
case InstructionLessOrEqualInt:
|
||||
return "LESS_OR_EQUAL_INT"
|
||||
case InstructionGreaterInt:
|
||||
return "GREATER_INT"
|
||||
case InstructionGreaterOrEqualInt:
|
||||
return "GREATER_OR_EQUAL_INT"
|
||||
case InstructionJump:
|
||||
return "JUMP"
|
||||
case InstructionJumpFalse:
|
||||
|
|
@ -232,7 +274,7 @@ func NewChunk(bytecode []Bytecode, constants []Value) *Chunk {
|
|||
func RegisterGOBTypes() {
|
||||
gob.Register(&StringValue{""})
|
||||
gob.Register(&BoolValue{false})
|
||||
gob.Register(&NumberValue{0})
|
||||
gob.Register(&FloatValue{0})
|
||||
gob.Register(&FunctionValue{
|
||||
Name: "",
|
||||
Params: nil,
|
||||
|
|
@ -241,7 +283,7 @@ func RegisterGOBTypes() {
|
|||
|
||||
// Signatures
|
||||
gob.Register(&NilSignature{})
|
||||
gob.Register(&NumberSignature{})
|
||||
gob.Register(&FloatSignature{})
|
||||
gob.Register(&StringSignature{})
|
||||
gob.Register(&FunctionSignature{})
|
||||
gob.Register(&ListSignature{})
|
||||
|
|
@ -368,12 +410,12 @@ var DefaultGlobals = map[string]Value{
|
|||
"char": &BuiltinFunctionValue{
|
||||
"char",
|
||||
&FunctionSignature{
|
||||
[]TypeSignature{&NumberSignature{}},
|
||||
[]TypeSignature{&IntegerSignature{}},
|
||||
&StringSignature{},
|
||||
},
|
||||
func(vm *VM, this Value, args []Value) (Value, error) {
|
||||
n := args[0].(*NumberValue).Number
|
||||
b := byte(n)
|
||||
n := args[0].(*IntegerValue).Number
|
||||
b := n.Bytes()[0]
|
||||
|
||||
return &StringValue{
|
||||
string([]byte{b}),
|
||||
|
|
@ -383,16 +425,16 @@ var DefaultGlobals = map[string]Value{
|
|||
true,
|
||||
},
|
||||
"byte": &BuiltinFunctionValue{
|
||||
"char",
|
||||
"byte",
|
||||
&FunctionSignature{
|
||||
[]TypeSignature{&StringSignature{}},
|
||||
&NumberSignature{},
|
||||
&IntegerSignature{},
|
||||
},
|
||||
func(vm *VM, this Value, args []Value) (Value, error) {
|
||||
s := args[0].(*StringValue).Text
|
||||
b := []byte(s)[0]
|
||||
n := new(big.Int).SetBytes([]byte(s))
|
||||
|
||||
return &NumberValue{float64(b)}, nil
|
||||
return &IntegerValue{n}, nil
|
||||
},
|
||||
nil,
|
||||
true,
|
||||
|
|
@ -453,6 +495,66 @@ var DefaultGlobals = map[string]Value{
|
|||
nil,
|
||||
true,
|
||||
},
|
||||
"int": &BuiltinFunctionValue{
|
||||
"int",
|
||||
&FunctionSignature{
|
||||
[]TypeSignature{&AnySignature{}},
|
||||
&CompositeSignature{
|
||||
&IntegerSignature{},
|
||||
&NilSignature{},
|
||||
},
|
||||
},
|
||||
func(vm *VM, _ Value, args []Value) (Value, error) {
|
||||
switch v := args[0].(type) {
|
||||
case *IntegerValue:
|
||||
return &IntegerValue{v.Number}, nil // this might need to clone the value instead
|
||||
case *FloatValue:
|
||||
n := new(big.Int).SetInt64(int64(v.Number))
|
||||
return &IntegerValue{n}, nil
|
||||
case *StringValue:
|
||||
n, success := new(big.Int).SetString(v.Text, 0) // determine base
|
||||
if !success {
|
||||
return &NilValue{}, nil
|
||||
}
|
||||
|
||||
return &IntegerValue{n}, nil
|
||||
default:
|
||||
return nil, errors.New(fmt.Sprintf("%s cannot become an integer", v))
|
||||
}
|
||||
},
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
"float": &BuiltinFunctionValue{
|
||||
"float",
|
||||
&FunctionSignature{
|
||||
[]TypeSignature{&AnySignature{}},
|
||||
&CompositeSignature{
|
||||
&FloatSignature{},
|
||||
&NilSignature{},
|
||||
},
|
||||
},
|
||||
func(vm *VM, _ Value, args []Value) (Value, error) {
|
||||
switch v := args[0].(type) {
|
||||
case *IntegerValue:
|
||||
n, _ := v.Number.Float64()
|
||||
return &FloatValue{n}, nil // this might need to clone the value instead
|
||||
case *FloatValue:
|
||||
return &FloatValue{v.Number}, nil
|
||||
case *StringValue:
|
||||
num, err := strconv.ParseFloat(v.Text, FloatSize)
|
||||
if err != nil {
|
||||
return &NilValue{}, nil
|
||||
}
|
||||
|
||||
return &FloatValue{num}, nil
|
||||
default:
|
||||
return nil, errors.New(fmt.Sprintf("%s cannot become an integer", v))
|
||||
}
|
||||
},
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
"type": &BuiltinFunctionValue{
|
||||
Name: "type",
|
||||
Signature: &FunctionSignature{
|
||||
|
|
@ -470,11 +572,11 @@ var DefaultGlobals = map[string]Value{
|
|||
"exit": &BuiltinFunctionValue{
|
||||
"exit",
|
||||
&FunctionSignature{
|
||||
[]TypeSignature{&NumberSignature{}},
|
||||
[]TypeSignature{&FloatSignature{}},
|
||||
&NilSignature{},
|
||||
},
|
||||
func(vm *VM, this Value, args []Value) (Value, error) {
|
||||
os.Exit(int(args[0].(*NumberValue).Number))
|
||||
os.Exit(int(args[0].(*FloatValue).Number))
|
||||
return &NilValue{}, nil
|
||||
},
|
||||
nil,
|
||||
|
|
@ -483,11 +585,11 @@ var DefaultGlobals = map[string]Value{
|
|||
"floor": &BuiltinFunctionValue{
|
||||
"floor",
|
||||
&FunctionSignature{
|
||||
[]TypeSignature{&NumberSignature{}},
|
||||
&NumberSignature{},
|
||||
[]TypeSignature{&FloatSignature{}},
|
||||
&FloatSignature{},
|
||||
},
|
||||
func(vm *VM, this Value, args []Value) (Value, error) {
|
||||
return &NumberValue{math.Floor(args[0].(*NumberValue).Number)}, nil
|
||||
return &FloatValue{math.Floor(args[0].(*FloatValue).Number)}, nil
|
||||
},
|
||||
nil,
|
||||
true,
|
||||
|
|
@ -495,11 +597,11 @@ var DefaultGlobals = map[string]Value{
|
|||
"ceil": &BuiltinFunctionValue{
|
||||
"ceil",
|
||||
&FunctionSignature{
|
||||
[]TypeSignature{&NumberSignature{}},
|
||||
&NumberSignature{},
|
||||
[]TypeSignature{&FloatSignature{}},
|
||||
&FloatSignature{},
|
||||
},
|
||||
func(vm *VM, this Value, args []Value) (Value, error) {
|
||||
return &NumberValue{math.Ceil(args[0].(*NumberValue).Number)}, nil
|
||||
return &FloatValue{math.Ceil(args[0].(*FloatValue).Number)}, nil
|
||||
},
|
||||
nil,
|
||||
true,
|
||||
|
|
@ -507,14 +609,14 @@ var DefaultGlobals = map[string]Value{
|
|||
"roundd": &BuiltinFunctionValue{
|
||||
"roundd",
|
||||
&FunctionSignature{
|
||||
[]TypeSignature{&NumberSignature{}, &NumberSignature{}},
|
||||
&NumberSignature{},
|
||||
[]TypeSignature{&FloatSignature{}, &FloatSignature{}},
|
||||
&FloatSignature{},
|
||||
},
|
||||
func(vm *VM, this Value, args []Value) (Value, error) {
|
||||
x := args[0].(*NumberValue).Number
|
||||
decimals := args[1].(*NumberValue).Number
|
||||
x := args[0].(*FloatValue).Number
|
||||
decimals := args[1].(*FloatValue).Number
|
||||
multiplier := math.Pow(10, decimals)
|
||||
return &NumberValue{math.Round(x*multiplier) / multiplier}, nil
|
||||
return &FloatValue{math.Round(x*multiplier) / multiplier}, nil
|
||||
},
|
||||
nil,
|
||||
true,
|
||||
|
|
@ -568,34 +670,63 @@ func (vm *VM) Next() bool {
|
|||
case InstructionConstant:
|
||||
vm.stack.Push(vm.ReadConstant())
|
||||
|
||||
case InstructionAdd:
|
||||
r := vm.stack.Pop().(*NumberValue).Number
|
||||
l := vm.stack.Pop().(*NumberValue).Number
|
||||
case InstructionAddFloat:
|
||||
r := vm.stack.Pop().(*FloatValue).Number
|
||||
l := vm.stack.Pop().(*FloatValue).Number
|
||||
|
||||
vm.stack.Push(&NumberValue{l + r})
|
||||
vm.stack.Push(&FloatValue{l + r})
|
||||
|
||||
case InstructionSub:
|
||||
r := vm.stack.Pop().(*NumberValue).Number
|
||||
l := vm.stack.Pop().(*NumberValue).Number
|
||||
case InstructionSubFloat:
|
||||
r := vm.stack.Pop().(*FloatValue).Number
|
||||
l := vm.stack.Pop().(*FloatValue).Number
|
||||
|
||||
vm.stack.Push(&NumberValue{l - r})
|
||||
vm.stack.Push(&FloatValue{l - r})
|
||||
|
||||
case InstructionMul:
|
||||
r := vm.stack.Pop().(*NumberValue).Number
|
||||
l := vm.stack.Pop().(*NumberValue).Number
|
||||
case InstructionMulFloat:
|
||||
r := vm.stack.Pop().(*FloatValue).Number
|
||||
l := vm.stack.Pop().(*FloatValue).Number
|
||||
|
||||
vm.stack.Push(&NumberValue{l * r})
|
||||
vm.stack.Push(&FloatValue{l * r})
|
||||
|
||||
case InstructionDiv:
|
||||
r := vm.stack.Pop().(*NumberValue).Number
|
||||
l := vm.stack.Pop().(*NumberValue).Number
|
||||
case InstructionDivFloat:
|
||||
r := vm.stack.Pop().(*FloatValue).Number
|
||||
l := vm.stack.Pop().(*FloatValue).Number
|
||||
|
||||
vm.stack.Push(&NumberValue{l / r})
|
||||
vm.stack.Push(&FloatValue{l / r})
|
||||
|
||||
case InstructionNegate:
|
||||
v := vm.stack.Pop().(*NumberValue).Number
|
||||
case InstructionNegateFloat:
|
||||
v := vm.stack.Pop().(*FloatValue).Number
|
||||
|
||||
vm.stack.Push(&NumberValue{-v})
|
||||
vm.stack.Push(&FloatValue{-v})
|
||||
|
||||
case InstructionAddInt:
|
||||
r := vm.stack.Pop().(*IntegerValue).Number
|
||||
l := vm.stack.Pop().(*IntegerValue).Number
|
||||
|
||||
vm.stack.Push(&IntegerValue{new(big.Int).Add(l, r)})
|
||||
|
||||
case InstructionSubInt:
|
||||
r := vm.stack.Pop().(*IntegerValue).Number
|
||||
l := vm.stack.Pop().(*IntegerValue).Number
|
||||
|
||||
vm.stack.Push(&IntegerValue{new(big.Int).Sub(l, r)})
|
||||
|
||||
case InstructionMulInt:
|
||||
r := vm.stack.Pop().(*IntegerValue).Number
|
||||
l := vm.stack.Pop().(*IntegerValue).Number
|
||||
|
||||
vm.stack.Push(&IntegerValue{new(big.Int).Mul(l, r)})
|
||||
|
||||
case InstructionDivInt:
|
||||
r := vm.stack.Pop().(*IntegerValue).Number
|
||||
l := vm.stack.Pop().(*IntegerValue).Number
|
||||
|
||||
vm.stack.Push(&IntegerValue{new(big.Int).Div(l, r)})
|
||||
|
||||
case InstructionNegateInt:
|
||||
v := vm.stack.Pop().(*IntegerValue).Number
|
||||
|
||||
vm.stack.Push(&IntegerValue{new(big.Int).Neg(v)})
|
||||
|
||||
case InstructionEquals:
|
||||
vm.stack.Push(
|
||||
|
|
@ -621,30 +752,54 @@ func (vm *VM) Next() bool {
|
|||
l := vm.stack.Pop().(*BoolValue).Boolean
|
||||
vm.stack.Push(&BoolValue{l || r})
|
||||
|
||||
case InstructionLess:
|
||||
r := vm.stack.Pop().(*NumberValue).Number
|
||||
l := vm.stack.Pop().(*NumberValue).Number
|
||||
case InstructionLessFloat:
|
||||
r := vm.stack.Pop().(*FloatValue).Number
|
||||
l := vm.stack.Pop().(*FloatValue).Number
|
||||
|
||||
vm.stack.Push(&BoolValue{l < r})
|
||||
|
||||
case InstructionLessOrEqual:
|
||||
r := vm.stack.Pop().(*NumberValue).Number
|
||||
l := vm.stack.Pop().(*NumberValue).Number
|
||||
case InstructionLessOrEqualFloat:
|
||||
r := vm.stack.Pop().(*FloatValue).Number
|
||||
l := vm.stack.Pop().(*FloatValue).Number
|
||||
|
||||
vm.stack.Push(&BoolValue{l <= r})
|
||||
|
||||
case InstructionGreater:
|
||||
r := vm.stack.Pop().(*NumberValue).Number
|
||||
l := vm.stack.Pop().(*NumberValue).Number
|
||||
case InstructionGreaterFloat:
|
||||
r := vm.stack.Pop().(*FloatValue).Number
|
||||
l := vm.stack.Pop().(*FloatValue).Number
|
||||
|
||||
vm.stack.Push(&BoolValue{l > r})
|
||||
|
||||
case InstructionGreaterOrEqual:
|
||||
r := vm.stack.Pop().(*NumberValue).Number
|
||||
l := vm.stack.Pop().(*NumberValue).Number
|
||||
case InstructionGreaterOrEqualFloat:
|
||||
r := vm.stack.Pop().(*FloatValue).Number
|
||||
l := vm.stack.Pop().(*FloatValue).Number
|
||||
|
||||
vm.stack.Push(&BoolValue{l >= r})
|
||||
|
||||
case InstructionLessInt:
|
||||
r := vm.stack.Pop().(*IntegerValue).Number
|
||||
l := vm.stack.Pop().(*IntegerValue).Number
|
||||
|
||||
vm.stack.Push(&BoolValue{l.Cmp(r) == -1})
|
||||
|
||||
case InstructionLessOrEqualInt:
|
||||
r := vm.stack.Pop().(*IntegerValue).Number
|
||||
l := vm.stack.Pop().(*IntegerValue).Number
|
||||
|
||||
vm.stack.Push(&BoolValue{l.Cmp(r) != 1})
|
||||
|
||||
case InstructionGreaterInt:
|
||||
r := vm.stack.Pop().(*IntegerValue).Number
|
||||
l := vm.stack.Pop().(*IntegerValue).Number
|
||||
|
||||
vm.stack.Push(&BoolValue{l.Cmp(r) == 1})
|
||||
|
||||
case InstructionGreaterOrEqualInt:
|
||||
r := vm.stack.Pop().(*IntegerValue).Number
|
||||
l := vm.stack.Pop().(*IntegerValue).Number
|
||||
|
||||
vm.stack.Push(&BoolValue{l.Cmp(r) != -1})
|
||||
|
||||
case InstructionCall:
|
||||
v := vm.stack.Pop()
|
||||
switch f := v.(type) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue