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

@ -2,6 +2,7 @@ package core
import (
"fmt"
"math/big"
"strings"
)
@ -191,9 +192,13 @@ func (c *Compiler) compile(tree Node) error {
tree.(*StringNode).value,
})
case NumberNodeType:
case FloatNodeType:
c.add(InstructionConstant)
c.addConstant(&NumberValue{tree.(*NumberNode).value})
c.addConstant(&FloatValue{tree.(*FloatNode).value})
case IntegerNodeType:
c.add(InstructionConstant)
c.addConstant(&IntegerValue{tree.(*IntegerNode).value})
case ListNodeType:
l := tree.(*ListNode)
@ -243,9 +248,19 @@ func (c *Compiler) compile(tree Node) error {
return err
}
vt, err := c.deduceSignature(tree.(*UnaryNode).value)
if err != nil {
return err
}
switch tree.(*UnaryNode).UnaryOperation {
case UnaryNegate:
c.add(InstructionNegate)
if vt.Type() == TypeInteger {
c.add(InstructionNegateInt)
} else {
c.add(InstructionNegateFloat)
}
case UnaryNot:
c.add(InstructionNot)
}
@ -593,38 +608,72 @@ func (c *Compiler) compileBinary(binary *BinaryNode) error {
return err
}
res, err := c.deduceSignature(binary)
if err != nil {
return err
}
switch binary.BinaryOperation {
case BinaryAddition:
res, err := c.deduceSignature(binary)
if err != nil {
return err
}
if res.Type() == TypeString {
c.add(InstructionStringConcatenation)
} else if res.Type() == TypeList {
c.add(InstructionConcatLists)
} else if res.Type() == TypeFloat {
c.add(InstructionAddFloat)
} else if res.Type() == TypeInteger {
c.add(InstructionAddInt)
} else {
c.add(InstructionAdd)
return c.error("unimplemented binary compilation", binary)
}
case BinarySubtraction:
c.add(InstructionSub)
if res.Type() == TypeFloat {
c.add(InstructionSubFloat)
} else {
c.add(InstructionSubInt)
}
case BinaryMultiplication:
c.add(InstructionMul)
if res.Type() == TypeFloat {
c.add(InstructionMulFloat)
} else {
c.add(InstructionMulInt)
}
case BinaryDivision:
c.add(InstructionDiv)
if res.Type() == TypeFloat {
c.add(InstructionDivFloat)
} else {
c.add(InstructionDivInt)
}
case BinaryEquality:
c.add(InstructionEquals)
case BinaryInequality:
c.add(InstructionNotEqual)
case BinaryLess:
c.add(InstructionLess)
if res.Type() == TypeFloat {
c.add(InstructionLessFloat)
} else {
c.add(InstructionLessInt)
}
case BinaryGreater:
c.add(InstructionGreater)
if res.Type() == TypeFloat {
c.add(InstructionGreaterFloat)
} else {
c.add(InstructionGreaterInt)
}
case BinaryLessEqual:
c.add(InstructionLessOrEqual)
if res.Type() == TypeFloat {
c.add(InstructionLessOrEqualFloat)
} else {
c.add(InstructionLessOrEqualInt)
}
case BinaryGreaterEqual:
c.add(InstructionGreaterOrEqual)
if res.Type() == TypeFloat {
c.add(InstructionGreaterOrEqualFloat)
} else {
c.add(InstructionGreaterOrEqualInt)
}
case BinaryAnd:
c.add(InstructionAnd)
case BinaryOr:
@ -638,8 +687,10 @@ func (c *Compiler) deduceSignature(tree Node) (TypeSignature, error) {
switch tree.Type() {
case StringNodeType:
return &StringSignature{}, nil
case NumberNodeType:
return &NumberSignature{}, nil
case FloatNodeType:
return &FloatSignature{}, nil
case IntegerNodeType:
return &IntegerSignature{}, nil
case ReferenceNodeType:
n := tree.(*ReferenceNode)
sig, err := c.getVarSignature(n.name, n)
@ -695,17 +746,23 @@ func (c *Compiler) deduceSignature(tree Node) (TypeSignature, error) {
switch n.BinaryOperation {
case BinarySubtraction, BinaryMultiplication, BinaryDivision:
if l.Type() != TypeNumber {
return nil, c.error(fmt.Sprintf("cannot %s values of non-number type %s", n.BinaryOperation, l), n)
if l.Type() == TypeInteger {
return &IntegerSignature{}, nil
}
return &NumberSignature{}, nil
if l.Type() == TypeFloat {
return &FloatSignature{}, nil
}
return nil, c.error(fmt.Sprintf("cannot %s values of non-number type %s", n.BinaryOperation, l), n)
case BinaryAddition:
switch l.Type() {
case TypeString:
return &StringSignature{}, nil
case TypeNumber:
return &NumberSignature{}, nil
case TypeInteger:
return &IntegerSignature{}, nil
case TypeFloat:
return &FloatSignature{}, nil
case TypeList:
return &ListSignature{
l.(*ListSignature).Contents,
@ -722,7 +779,7 @@ func (c *Compiler) deduceSignature(tree Node) (TypeSignature, error) {
case BinaryEquality, BinaryInequality:
return &BooleanSignature{}, nil
case BinaryLess, BinaryGreater, BinaryLessEqual, BinaryGreaterEqual:
if l.Type() != TypeNumber {
if l.Type() != TypeInteger && l.Type() != TypeFloat {
return nil, c.error(fmt.Sprintf("cannot perform number comparison (%s) on non-number type %s", n.BinaryOperation, l), n)
}
@ -852,10 +909,13 @@ func (c *Compiler) deduceSignature(tree Node) (TypeSignature, error) {
switch n.UnaryOperation {
case UnaryNegate:
if sig.Type() != TypeNumber {
return nil, c.error(fmt.Sprintf("cannot perform negation on type %s (must be number)", n.UnaryOperation), n)
if sig.Type() == TypeFloat {
return &FloatSignature{}, nil
} else if sig.Type() == TypeInteger {
return &IntegerSignature{}, nil
}
return &NumberSignature{}, nil
return nil, c.error(fmt.Sprintf("cannot perform negation on type %s (must be number)", n.UnaryOperation), n)
case UnaryNot:
if sig.Type() != TypeBoolean {
return nil, c.error(fmt.Sprintf("cannot perform negation on type %s (must be boolean)", n.UnaryOperation), n)
@ -1040,7 +1100,7 @@ func (c *Compiler) isLocal(name string) bool {
// isTreeConstant check if a node tree is constant (predictable)
func (c *Compiler) isTreeConstant(tree Node) bool {
switch tree.Type() {
case StringNodeType, NumberNodeType, BooleanNodeType, NilNodeType:
case StringNodeType, FloatNodeType, IntegerNodeType, BooleanNodeType, NilNodeType:
return true
case ListNodeType:
for _, item := range tree.(*ListNode).items {
@ -1076,8 +1136,13 @@ func (c *Compiler) compute(tree Node) (Value, error) {
n.value,
}, nil
case *NumberNode:
return &NumberValue{
case *FloatNode:
return &FloatValue{
n.value,
}, nil
case *IntegerNode:
return &IntegerValue{
n.value,
}, nil
@ -1114,13 +1179,17 @@ func (c *Compiler) compute(tree Node) (Value, error) {
switch n.UnaryOperation {
case UnaryNegate:
if v.Type() != NumberValueType {
return nil, c.error(fmt.Sprintf("cannot negate %s value (not a number)", v.Type()), n)
if v.Type() == FloatValueType {
return &FloatValue{
-v.(*FloatValue).Number,
}, nil
} else if v.Type() == IntegerValueType {
return &IntegerValue{
new(big.Int).Neg(v.(*IntegerValue).Number),
}, nil
}
return &NumberValue{
-v.(*NumberValue).Number,
}, nil
return nil, c.error(fmt.Sprintf("cannot negate %s value (not a number)", v.Type()), n)
case UnaryNot:
if v.Type() != BoolValueType {
return nil, c.error(fmt.Sprintf("cannot invert %s value (not a boolean)", v.Type()), n)
@ -1180,7 +1249,7 @@ func (c *Compiler) computeBinary(n *BinaryNode) (Value, error) {
// perform type check
switch n.BinaryOperation {
case BinarySubtraction, BinaryMultiplication, BinaryDivision, BinaryLess, BinaryGreater, BinaryLessEqual, BinaryGreaterEqual:
if l.Type() != NumberValueType {
if l.Type() != FloatValueType && l.Type() != IntegerValueType {
return nil, c.error(fmt.Sprintf("cannot %s values of non-number type %s", n.BinaryOperation, l.Type()), n)
}
case BinaryAnd, BinaryOr:
@ -1196,37 +1265,67 @@ func (c *Compiler) computeBinary(n *BinaryNode) (Value, error) {
switch n.BinaryOperation {
case BinaryAddition:
switch l.Type() {
case NumberValueType:
v = l.(*NumberValue).Number + r.(*NumberValue).Number
case FloatValueType:
v = l.(*FloatValue).Number + r.(*FloatValue).Number
case StringValueType:
v = l.(*StringValue).Text + r.(*StringValue).Text
case ListValueType:
v = append(l.(*ListValue).Items, r.(*ListValue).Items...)
case IntegerValueType:
v = new(big.Int).Add(l.(*IntegerValue).Number, r.(*IntegerValue).Number)
default:
return nil, c.error(fmt.Sprintf("cannot add values of type %s", l.Type()), n)
}
case BinarySubtraction:
v = l.(*NumberValue).Number - r.(*NumberValue).Number
if l.Type() == FloatValueType {
v = l.(*FloatValue).Number - r.(*FloatValue).Number
} else {
v = new(big.Int).Sub(l.(*IntegerValue).Number, r.(*IntegerValue).Number)
}
case BinaryMultiplication:
v = l.(*NumberValue).Number * r.(*NumberValue).Number
if l.Type() == FloatValueType {
v = l.(*FloatValue).Number * r.(*FloatValue).Number
} else {
v = new(big.Int).Mul(l.(*IntegerValue).Number, r.(*IntegerValue).Number)
}
case BinaryDivision:
v = l.(*NumberValue).Number / r.(*NumberValue).Number
if l.Type() == FloatValueType {
v = l.(*FloatValue).Number / r.(*FloatValue).Number
} else {
v = new(big.Int).Div(l.(*IntegerValue).Number, r.(*IntegerValue).Number)
}
case BinaryAnd:
v = l.(*BoolValue).Boolean && r.(*BoolValue).Boolean
case BinaryOr:
v = l.(*BoolValue).Boolean && r.(*BoolValue).Boolean
v = l.(*BoolValue).Boolean || r.(*BoolValue).Boolean
case BinaryEquality:
v = l.Equals(r)
case BinaryInequality:
v = !l.Equals(r)
case BinaryLess:
v = l.(*NumberValue).Number < r.(*NumberValue).Number
if l.Type() == FloatValueType {
v = l.(*FloatValue).Number < r.(*FloatValue).Number
} else {
v = l.(*IntegerValue).Number.Cmp(r.(*IntegerValue).Number) == -1
}
case BinaryGreater:
v = l.(*NumberValue).Number > r.(*NumberValue).Number
if l.Type() == FloatValueType {
v = l.(*FloatValue).Number > r.(*FloatValue).Number
} else {
v = l.(*IntegerValue).Number.Cmp(r.(*IntegerValue).Number) == 1
}
case BinaryLessEqual:
v = l.(*NumberValue).Number <= r.(*NumberValue).Number
if l.Type() == FloatValueType {
v = l.(*FloatValue).Number <= r.(*FloatValue).Number
} else {
v = l.(*IntegerValue).Number.Cmp(r.(*IntegerValue).Number) != 1
}
case BinaryGreaterEqual:
v = l.(*NumberValue).Number >= r.(*NumberValue).Number
if l.Type() == FloatValueType {
v = l.(*FloatValue).Number >= r.(*FloatValue).Number
} else {
v = l.(*IntegerValue).Number.Cmp(r.(*IntegerValue).Number) != 1
}
}
return GoToValue(v), nil