separate number into float and integer
This commit is contained in:
parent
10f55313b0
commit
daab50d54c
22 changed files with 848 additions and 428 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -16,13 +17,13 @@ func GetAllTestCases() map[string]AllTestCase {
|
||||||
[]Value{
|
[]Value{
|
||||||
&VariableValue{
|
&VariableValue{
|
||||||
"a",
|
"a",
|
||||||
&NumberValue{1},
|
&IntegerValue{new(big.Int).SetInt64(1)},
|
||||||
0,
|
0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"func": {
|
"func": {
|
||||||
"func sum(a: number, b: number) number {\n\treturn a + b\n}\n_ = sum(1, 2)",
|
"fn sum(a: int, b: int) -> int {\n\treturn a + b\n}\n_ = sum(1, 2)",
|
||||||
[]Value{
|
[]Value{
|
||||||
&VariableValue{
|
&VariableValue{
|
||||||
"sum",
|
"sum",
|
||||||
|
|
@ -31,11 +32,11 @@ func GetAllTestCases() map[string]AllTestCase {
|
||||||
Params: []FunctionParameter{
|
Params: []FunctionParameter{
|
||||||
{
|
{
|
||||||
"a",
|
"a",
|
||||||
&NumberSignature{},
|
&IntegerSignature{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"b",
|
"b",
|
||||||
&NumberSignature{},
|
&IntegerSignature{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Chunk: &Chunk{
|
Chunk: &Chunk{
|
||||||
|
|
@ -43,7 +44,7 @@ func GetAllTestCases() map[string]AllTestCase {
|
||||||
InstructionDescend,
|
InstructionDescend,
|
||||||
InstructionGetLocal, 0,
|
InstructionGetLocal, 0,
|
||||||
InstructionGetLocal, 1,
|
InstructionGetLocal, 1,
|
||||||
InstructionAdd,
|
InstructionAddInt,
|
||||||
InstructionReturn,
|
InstructionReturn,
|
||||||
InstructionAscend,
|
InstructionAscend,
|
||||||
},
|
},
|
||||||
|
|
@ -55,14 +56,14 @@ func GetAllTestCases() map[string]AllTestCase {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"list": {
|
"list": {
|
||||||
"a := [1, 2]",
|
"a := [1.0, 2.0]",
|
||||||
[]Value{
|
[]Value{
|
||||||
&VariableValue{
|
&VariableValue{
|
||||||
"a",
|
"a",
|
||||||
&ListValue{
|
&ListValue{
|
||||||
[]Value{
|
[]Value{
|
||||||
&NumberValue{1},
|
&FloatValue{1},
|
||||||
&NumberValue{2},
|
&FloatValue{2},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
0,
|
0,
|
||||||
|
|
@ -76,9 +77,9 @@ func GetAllTestCases() map[string]AllTestCase {
|
||||||
"a",
|
"a",
|
||||||
&ListValue{
|
&ListValue{
|
||||||
[]Value{
|
[]Value{
|
||||||
&NumberValue{1},
|
&IntegerValue{big.NewInt(1)},
|
||||||
&NumberValue{2},
|
&IntegerValue{big.NewInt(2)},
|
||||||
&NumberValue{3},
|
&IntegerValue{big.NewInt(3)},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
0,
|
0,
|
||||||
|
|
@ -86,14 +87,14 @@ func GetAllTestCases() map[string]AllTestCase {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"list_concat": {
|
"list_concat": {
|
||||||
"a := [1, 2]\nb := a + [3]",
|
"a := [1.0, 2.0]\nb := a + [3.0]",
|
||||||
[]Value{
|
[]Value{
|
||||||
&VariableValue{
|
&VariableValue{
|
||||||
"a",
|
"a",
|
||||||
&ListValue{
|
&ListValue{
|
||||||
[]Value{
|
[]Value{
|
||||||
&NumberValue{1},
|
&FloatValue{1},
|
||||||
&NumberValue{2},
|
&FloatValue{2},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
0,
|
0,
|
||||||
|
|
@ -102,9 +103,9 @@ func GetAllTestCases() map[string]AllTestCase {
|
||||||
"b",
|
"b",
|
||||||
&ListValue{
|
&ListValue{
|
||||||
[]Value{
|
[]Value{
|
||||||
&NumberValue{1},
|
&FloatValue{1},
|
||||||
&NumberValue{2},
|
&FloatValue{2},
|
||||||
&NumberValue{3},
|
&FloatValue{3},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
0,
|
0,
|
||||||
|
|
|
||||||
191
core/compiler.go
191
core/compiler.go
|
|
@ -2,6 +2,7 @@ package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math/big"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -191,9 +192,13 @@ func (c *Compiler) compile(tree Node) error {
|
||||||
tree.(*StringNode).value,
|
tree.(*StringNode).value,
|
||||||
})
|
})
|
||||||
|
|
||||||
case NumberNodeType:
|
case FloatNodeType:
|
||||||
c.add(InstructionConstant)
|
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:
|
case ListNodeType:
|
||||||
l := tree.(*ListNode)
|
l := tree.(*ListNode)
|
||||||
|
|
@ -243,9 +248,19 @@ func (c *Compiler) compile(tree Node) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vt, err := c.deduceSignature(tree.(*UnaryNode).value)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
switch tree.(*UnaryNode).UnaryOperation {
|
switch tree.(*UnaryNode).UnaryOperation {
|
||||||
case UnaryNegate:
|
case UnaryNegate:
|
||||||
c.add(InstructionNegate)
|
if vt.Type() == TypeInteger {
|
||||||
|
c.add(InstructionNegateInt)
|
||||||
|
} else {
|
||||||
|
c.add(InstructionNegateFloat)
|
||||||
|
}
|
||||||
|
|
||||||
case UnaryNot:
|
case UnaryNot:
|
||||||
c.add(InstructionNot)
|
c.add(InstructionNot)
|
||||||
}
|
}
|
||||||
|
|
@ -593,38 +608,72 @@ func (c *Compiler) compileBinary(binary *BinaryNode) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
res, err := c.deduceSignature(binary)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
switch binary.BinaryOperation {
|
switch binary.BinaryOperation {
|
||||||
case BinaryAddition:
|
case BinaryAddition:
|
||||||
res, err := c.deduceSignature(binary)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if res.Type() == TypeString {
|
if res.Type() == TypeString {
|
||||||
c.add(InstructionStringConcatenation)
|
c.add(InstructionStringConcatenation)
|
||||||
} else if res.Type() == TypeList {
|
} else if res.Type() == TypeList {
|
||||||
c.add(InstructionConcatLists)
|
c.add(InstructionConcatLists)
|
||||||
|
} else if res.Type() == TypeFloat {
|
||||||
|
c.add(InstructionAddFloat)
|
||||||
|
} else if res.Type() == TypeInteger {
|
||||||
|
c.add(InstructionAddInt)
|
||||||
} else {
|
} else {
|
||||||
c.add(InstructionAdd)
|
return c.error("unimplemented binary compilation", binary)
|
||||||
}
|
}
|
||||||
case BinarySubtraction:
|
case BinarySubtraction:
|
||||||
c.add(InstructionSub)
|
if res.Type() == TypeFloat {
|
||||||
|
c.add(InstructionSubFloat)
|
||||||
|
} else {
|
||||||
|
c.add(InstructionSubInt)
|
||||||
|
}
|
||||||
case BinaryMultiplication:
|
case BinaryMultiplication:
|
||||||
c.add(InstructionMul)
|
if res.Type() == TypeFloat {
|
||||||
|
c.add(InstructionMulFloat)
|
||||||
|
} else {
|
||||||
|
c.add(InstructionMulInt)
|
||||||
|
}
|
||||||
case BinaryDivision:
|
case BinaryDivision:
|
||||||
c.add(InstructionDiv)
|
if res.Type() == TypeFloat {
|
||||||
|
c.add(InstructionDivFloat)
|
||||||
|
} else {
|
||||||
|
c.add(InstructionDivInt)
|
||||||
|
}
|
||||||
case BinaryEquality:
|
case BinaryEquality:
|
||||||
c.add(InstructionEquals)
|
c.add(InstructionEquals)
|
||||||
case BinaryInequality:
|
case BinaryInequality:
|
||||||
c.add(InstructionNotEqual)
|
c.add(InstructionNotEqual)
|
||||||
|
|
||||||
case BinaryLess:
|
case BinaryLess:
|
||||||
c.add(InstructionLess)
|
if res.Type() == TypeFloat {
|
||||||
|
c.add(InstructionLessFloat)
|
||||||
|
} else {
|
||||||
|
c.add(InstructionLessInt)
|
||||||
|
}
|
||||||
case BinaryGreater:
|
case BinaryGreater:
|
||||||
c.add(InstructionGreater)
|
if res.Type() == TypeFloat {
|
||||||
|
c.add(InstructionGreaterFloat)
|
||||||
|
} else {
|
||||||
|
c.add(InstructionGreaterInt)
|
||||||
|
}
|
||||||
case BinaryLessEqual:
|
case BinaryLessEqual:
|
||||||
c.add(InstructionLessOrEqual)
|
if res.Type() == TypeFloat {
|
||||||
|
c.add(InstructionLessOrEqualFloat)
|
||||||
|
} else {
|
||||||
|
c.add(InstructionLessOrEqualInt)
|
||||||
|
}
|
||||||
case BinaryGreaterEqual:
|
case BinaryGreaterEqual:
|
||||||
c.add(InstructionGreaterOrEqual)
|
if res.Type() == TypeFloat {
|
||||||
|
c.add(InstructionGreaterOrEqualFloat)
|
||||||
|
} else {
|
||||||
|
c.add(InstructionGreaterOrEqualInt)
|
||||||
|
}
|
||||||
|
|
||||||
case BinaryAnd:
|
case BinaryAnd:
|
||||||
c.add(InstructionAnd)
|
c.add(InstructionAnd)
|
||||||
case BinaryOr:
|
case BinaryOr:
|
||||||
|
|
@ -638,8 +687,10 @@ func (c *Compiler) deduceSignature(tree Node) (TypeSignature, error) {
|
||||||
switch tree.Type() {
|
switch tree.Type() {
|
||||||
case StringNodeType:
|
case StringNodeType:
|
||||||
return &StringSignature{}, nil
|
return &StringSignature{}, nil
|
||||||
case NumberNodeType:
|
case FloatNodeType:
|
||||||
return &NumberSignature{}, nil
|
return &FloatSignature{}, nil
|
||||||
|
case IntegerNodeType:
|
||||||
|
return &IntegerSignature{}, nil
|
||||||
case ReferenceNodeType:
|
case ReferenceNodeType:
|
||||||
n := tree.(*ReferenceNode)
|
n := tree.(*ReferenceNode)
|
||||||
sig, err := c.getVarSignature(n.name, n)
|
sig, err := c.getVarSignature(n.name, n)
|
||||||
|
|
@ -695,17 +746,23 @@ func (c *Compiler) deduceSignature(tree Node) (TypeSignature, error) {
|
||||||
|
|
||||||
switch n.BinaryOperation {
|
switch n.BinaryOperation {
|
||||||
case BinarySubtraction, BinaryMultiplication, BinaryDivision:
|
case BinarySubtraction, BinaryMultiplication, BinaryDivision:
|
||||||
if l.Type() != TypeNumber {
|
if l.Type() == TypeInteger {
|
||||||
return nil, c.error(fmt.Sprintf("cannot %s values of non-number type %s", n.BinaryOperation, l), n)
|
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:
|
case BinaryAddition:
|
||||||
switch l.Type() {
|
switch l.Type() {
|
||||||
case TypeString:
|
case TypeString:
|
||||||
return &StringSignature{}, nil
|
return &StringSignature{}, nil
|
||||||
case TypeNumber:
|
case TypeInteger:
|
||||||
return &NumberSignature{}, nil
|
return &IntegerSignature{}, nil
|
||||||
|
case TypeFloat:
|
||||||
|
return &FloatSignature{}, nil
|
||||||
case TypeList:
|
case TypeList:
|
||||||
return &ListSignature{
|
return &ListSignature{
|
||||||
l.(*ListSignature).Contents,
|
l.(*ListSignature).Contents,
|
||||||
|
|
@ -722,7 +779,7 @@ func (c *Compiler) deduceSignature(tree Node) (TypeSignature, error) {
|
||||||
case BinaryEquality, BinaryInequality:
|
case BinaryEquality, BinaryInequality:
|
||||||
return &BooleanSignature{}, nil
|
return &BooleanSignature{}, nil
|
||||||
case BinaryLess, BinaryGreater, BinaryLessEqual, BinaryGreaterEqual:
|
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)
|
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 {
|
switch n.UnaryOperation {
|
||||||
case UnaryNegate:
|
case UnaryNegate:
|
||||||
if sig.Type() != TypeNumber {
|
if sig.Type() == TypeFloat {
|
||||||
return nil, c.error(fmt.Sprintf("cannot perform negation on type %s (must be number)", n.UnaryOperation), n)
|
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:
|
case UnaryNot:
|
||||||
if sig.Type() != TypeBoolean {
|
if sig.Type() != TypeBoolean {
|
||||||
return nil, c.error(fmt.Sprintf("cannot perform negation on type %s (must be boolean)", n.UnaryOperation), n)
|
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)
|
// isTreeConstant check if a node tree is constant (predictable)
|
||||||
func (c *Compiler) isTreeConstant(tree Node) bool {
|
func (c *Compiler) isTreeConstant(tree Node) bool {
|
||||||
switch tree.Type() {
|
switch tree.Type() {
|
||||||
case StringNodeType, NumberNodeType, BooleanNodeType, NilNodeType:
|
case StringNodeType, FloatNodeType, IntegerNodeType, BooleanNodeType, NilNodeType:
|
||||||
return true
|
return true
|
||||||
case ListNodeType:
|
case ListNodeType:
|
||||||
for _, item := range tree.(*ListNode).items {
|
for _, item := range tree.(*ListNode).items {
|
||||||
|
|
@ -1076,8 +1136,13 @@ func (c *Compiler) compute(tree Node) (Value, error) {
|
||||||
n.value,
|
n.value,
|
||||||
}, nil
|
}, nil
|
||||||
|
|
||||||
case *NumberNode:
|
case *FloatNode:
|
||||||
return &NumberValue{
|
return &FloatValue{
|
||||||
|
n.value,
|
||||||
|
}, nil
|
||||||
|
|
||||||
|
case *IntegerNode:
|
||||||
|
return &IntegerValue{
|
||||||
n.value,
|
n.value,
|
||||||
}, nil
|
}, nil
|
||||||
|
|
||||||
|
|
@ -1114,13 +1179,17 @@ func (c *Compiler) compute(tree Node) (Value, error) {
|
||||||
|
|
||||||
switch n.UnaryOperation {
|
switch n.UnaryOperation {
|
||||||
case UnaryNegate:
|
case UnaryNegate:
|
||||||
if v.Type() != NumberValueType {
|
if v.Type() == FloatValueType {
|
||||||
return nil, c.error(fmt.Sprintf("cannot negate %s value (not a number)", v.Type()), n)
|
return &FloatValue{
|
||||||
|
-v.(*FloatValue).Number,
|
||||||
|
}, nil
|
||||||
|
} else if v.Type() == IntegerValueType {
|
||||||
|
return &IntegerValue{
|
||||||
|
new(big.Int).Neg(v.(*IntegerValue).Number),
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return &NumberValue{
|
return nil, c.error(fmt.Sprintf("cannot negate %s value (not a number)", v.Type()), n)
|
||||||
-v.(*NumberValue).Number,
|
|
||||||
}, nil
|
|
||||||
case UnaryNot:
|
case UnaryNot:
|
||||||
if v.Type() != BoolValueType {
|
if v.Type() != BoolValueType {
|
||||||
return nil, c.error(fmt.Sprintf("cannot invert %s value (not a boolean)", v.Type()), n)
|
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
|
// perform type check
|
||||||
switch n.BinaryOperation {
|
switch n.BinaryOperation {
|
||||||
case BinarySubtraction, BinaryMultiplication, BinaryDivision, BinaryLess, BinaryGreater, BinaryLessEqual, BinaryGreaterEqual:
|
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)
|
return nil, c.error(fmt.Sprintf("cannot %s values of non-number type %s", n.BinaryOperation, l.Type()), n)
|
||||||
}
|
}
|
||||||
case BinaryAnd, BinaryOr:
|
case BinaryAnd, BinaryOr:
|
||||||
|
|
@ -1196,37 +1265,67 @@ func (c *Compiler) computeBinary(n *BinaryNode) (Value, error) {
|
||||||
switch n.BinaryOperation {
|
switch n.BinaryOperation {
|
||||||
case BinaryAddition:
|
case BinaryAddition:
|
||||||
switch l.Type() {
|
switch l.Type() {
|
||||||
case NumberValueType:
|
case FloatValueType:
|
||||||
v = l.(*NumberValue).Number + r.(*NumberValue).Number
|
v = l.(*FloatValue).Number + r.(*FloatValue).Number
|
||||||
case StringValueType:
|
case StringValueType:
|
||||||
v = l.(*StringValue).Text + r.(*StringValue).Text
|
v = l.(*StringValue).Text + r.(*StringValue).Text
|
||||||
case ListValueType:
|
case ListValueType:
|
||||||
v = append(l.(*ListValue).Items, r.(*ListValue).Items...)
|
v = append(l.(*ListValue).Items, r.(*ListValue).Items...)
|
||||||
|
case IntegerValueType:
|
||||||
|
v = new(big.Int).Add(l.(*IntegerValue).Number, r.(*IntegerValue).Number)
|
||||||
default:
|
default:
|
||||||
return nil, c.error(fmt.Sprintf("cannot add values of type %s", l.Type()), n)
|
return nil, c.error(fmt.Sprintf("cannot add values of type %s", l.Type()), n)
|
||||||
}
|
}
|
||||||
case BinarySubtraction:
|
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:
|
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:
|
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:
|
case BinaryAnd:
|
||||||
v = l.(*BoolValue).Boolean && r.(*BoolValue).Boolean
|
v = l.(*BoolValue).Boolean && r.(*BoolValue).Boolean
|
||||||
case BinaryOr:
|
case BinaryOr:
|
||||||
v = l.(*BoolValue).Boolean && r.(*BoolValue).Boolean
|
v = l.(*BoolValue).Boolean || r.(*BoolValue).Boolean
|
||||||
case BinaryEquality:
|
case BinaryEquality:
|
||||||
v = l.Equals(r)
|
v = l.Equals(r)
|
||||||
case BinaryInequality:
|
case BinaryInequality:
|
||||||
v = !l.Equals(r)
|
v = !l.Equals(r)
|
||||||
case BinaryLess:
|
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:
|
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:
|
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:
|
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
|
return GoToValue(v), nil
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ func GetCompileTestData() map[string]CompileTestData {
|
||||||
[]Node{
|
[]Node{
|
||||||
&AssignNode{
|
&AssignNode{
|
||||||
"a",
|
"a",
|
||||||
&NumberNode{
|
&FloatNode{
|
||||||
0,
|
0,
|
||||||
0, 0,
|
0, 0,
|
||||||
},
|
},
|
||||||
|
|
@ -85,7 +85,7 @@ func GetCompileTestData() map[string]CompileTestData {
|
||||||
[]Node{
|
[]Node{
|
||||||
&AssignNode{
|
&AssignNode{
|
||||||
"a",
|
"a",
|
||||||
&NumberNode{
|
&FloatNode{
|
||||||
1,
|
1,
|
||||||
0, 0,
|
0, 0,
|
||||||
},
|
},
|
||||||
|
|
@ -106,7 +106,7 @@ func GetCompileTestData() map[string]CompileTestData {
|
||||||
[]Value{
|
[]Value{
|
||||||
&VariableValue{
|
&VariableValue{
|
||||||
"a",
|
"a",
|
||||||
&NumberValue{0},
|
&FloatValue{0},
|
||||||
0,
|
0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -118,7 +118,7 @@ func GetCompileTestData() map[string]CompileTestData {
|
||||||
[]Node{
|
[]Node{
|
||||||
&AssignNode{
|
&AssignNode{
|
||||||
"a",
|
"a",
|
||||||
&NumberNode{
|
&FloatNode{
|
||||||
0,
|
0,
|
||||||
0, 0,
|
0, 0,
|
||||||
},
|
},
|
||||||
|
|
@ -134,7 +134,7 @@ func GetCompileTestData() map[string]CompileTestData {
|
||||||
[]Node{
|
[]Node{
|
||||||
&AssignNode{
|
&AssignNode{
|
||||||
"a",
|
"a",
|
||||||
&NumberNode{
|
&FloatNode{
|
||||||
1,
|
1,
|
||||||
0, 0,
|
0, 0,
|
||||||
},
|
},
|
||||||
|
|
@ -155,7 +155,7 @@ func GetCompileTestData() map[string]CompileTestData {
|
||||||
[]Value{
|
[]Value{
|
||||||
&VariableValue{
|
&VariableValue{
|
||||||
"a",
|
"a",
|
||||||
&NumberValue{1},
|
&FloatValue{1},
|
||||||
0,
|
0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -167,7 +167,7 @@ func GetCompileTestData() map[string]CompileTestData {
|
||||||
[]Node{
|
[]Node{
|
||||||
&AssignNode{
|
&AssignNode{
|
||||||
"a",
|
"a",
|
||||||
&NumberNode{
|
&FloatNode{
|
||||||
0,
|
0,
|
||||||
0, 0,
|
0, 0,
|
||||||
},
|
},
|
||||||
|
|
@ -183,7 +183,7 @@ func GetCompileTestData() map[string]CompileTestData {
|
||||||
[]Node{
|
[]Node{
|
||||||
&AssignNode{
|
&AssignNode{
|
||||||
"a",
|
"a",
|
||||||
&NumberNode{
|
&FloatNode{
|
||||||
1,
|
1,
|
||||||
0, 0,
|
0, 0,
|
||||||
},
|
},
|
||||||
|
|
@ -197,7 +197,7 @@ func GetCompileTestData() map[string]CompileTestData {
|
||||||
[]Node{
|
[]Node{
|
||||||
&AssignNode{
|
&AssignNode{
|
||||||
"a",
|
"a",
|
||||||
&NumberNode{
|
&FloatNode{
|
||||||
2,
|
2,
|
||||||
0, 0,
|
0, 0,
|
||||||
},
|
},
|
||||||
|
|
@ -217,7 +217,7 @@ func GetCompileTestData() map[string]CompileTestData {
|
||||||
[]Value{
|
[]Value{
|
||||||
&VariableValue{
|
&VariableValue{
|
||||||
"a",
|
"a",
|
||||||
&NumberValue{2},
|
&FloatValue{2},
|
||||||
0,
|
0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -229,7 +229,7 @@ func GetCompileTestData() map[string]CompileTestData {
|
||||||
[]Node{
|
[]Node{
|
||||||
&AssignNode{
|
&AssignNode{
|
||||||
"a",
|
"a",
|
||||||
&NumberNode{
|
&FloatNode{
|
||||||
0,
|
0,
|
||||||
0, 0,
|
0, 0,
|
||||||
},
|
},
|
||||||
|
|
@ -245,7 +245,7 @@ func GetCompileTestData() map[string]CompileTestData {
|
||||||
[]Node{
|
[]Node{
|
||||||
&AssignNode{
|
&AssignNode{
|
||||||
"a",
|
"a",
|
||||||
&NumberNode{
|
&FloatNode{
|
||||||
1,
|
1,
|
||||||
0, 0,
|
0, 0,
|
||||||
},
|
},
|
||||||
|
|
@ -259,7 +259,7 @@ func GetCompileTestData() map[string]CompileTestData {
|
||||||
[]Node{
|
[]Node{
|
||||||
&AssignNode{
|
&AssignNode{
|
||||||
"a",
|
"a",
|
||||||
&NumberNode{
|
&FloatNode{
|
||||||
2,
|
2,
|
||||||
0, 0,
|
0, 0,
|
||||||
},
|
},
|
||||||
|
|
@ -279,7 +279,7 @@ func GetCompileTestData() map[string]CompileTestData {
|
||||||
[]Value{
|
[]Value{
|
||||||
&VariableValue{
|
&VariableValue{
|
||||||
"a",
|
"a",
|
||||||
&NumberValue{1},
|
&FloatValue{1},
|
||||||
0,
|
0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -293,11 +293,11 @@ func GetCompileTestData() map[string]CompileTestData {
|
||||||
"a",
|
"a",
|
||||||
&BinaryNode{
|
&BinaryNode{
|
||||||
BinaryAddition,
|
BinaryAddition,
|
||||||
&NumberNode{
|
&FloatNode{
|
||||||
1,
|
1,
|
||||||
0, 0,
|
0, 0,
|
||||||
},
|
},
|
||||||
&NumberNode{
|
&FloatNode{
|
||||||
2,
|
2,
|
||||||
0, 0,
|
0, 0,
|
||||||
},
|
},
|
||||||
|
|
@ -314,7 +314,7 @@ func GetCompileTestData() map[string]CompileTestData {
|
||||||
[]Value{
|
[]Value{
|
||||||
&VariableValue{
|
&VariableValue{
|
||||||
"a",
|
"a",
|
||||||
&NumberValue{3},
|
&FloatValue{3},
|
||||||
0,
|
0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -331,14 +331,14 @@ func GetCompileTestData() map[string]CompileTestData {
|
||||||
[]FunctionParameter{
|
[]FunctionParameter{
|
||||||
{
|
{
|
||||||
"a",
|
"a",
|
||||||
&NumberSignature{},
|
&FloatSignature{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"b",
|
"b",
|
||||||
&NumberSignature{},
|
&FloatSignature{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
&NumberSignature{},
|
&FloatSignature{},
|
||||||
&BlockNode{
|
&BlockNode{
|
||||||
[]Node{
|
[]Node{
|
||||||
&ReturnNode{
|
&ReturnNode{
|
||||||
|
|
@ -378,20 +378,20 @@ func GetCompileTestData() map[string]CompileTestData {
|
||||||
[]FunctionParameter{
|
[]FunctionParameter{
|
||||||
{
|
{
|
||||||
"a",
|
"a",
|
||||||
&NumberSignature{},
|
&FloatSignature{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"b",
|
"b",
|
||||||
&NumberSignature{},
|
&FloatSignature{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
&NumberSignature{},
|
&FloatSignature{},
|
||||||
NewChunk(
|
NewChunk(
|
||||||
[]Bytecode{
|
[]Bytecode{
|
||||||
InstructionDescend,
|
InstructionDescend,
|
||||||
InstructionGetLocal, 0,
|
InstructionGetLocal, 0,
|
||||||
InstructionGetLocal, 1,
|
InstructionGetLocal, 1,
|
||||||
InstructionAdd,
|
InstructionAddFloat,
|
||||||
InstructionReturn,
|
InstructionReturn,
|
||||||
InstructionAscend,
|
InstructionAscend,
|
||||||
},
|
},
|
||||||
|
|
@ -415,12 +415,12 @@ func GetCompileTestData() map[string]CompileTestData {
|
||||||
&FunctionNode{
|
&FunctionNode{
|
||||||
"a",
|
"a",
|
||||||
[]FunctionParameter{},
|
[]FunctionParameter{},
|
||||||
&NumberSignature{},
|
&FloatSignature{},
|
||||||
&BlockNode{
|
&BlockNode{
|
||||||
[]Node{
|
[]Node{
|
||||||
&AssignNode{
|
&AssignNode{
|
||||||
"b",
|
"b",
|
||||||
&NumberNode{
|
&FloatNode{
|
||||||
1,
|
1,
|
||||||
0, 0,
|
0, 0,
|
||||||
},
|
},
|
||||||
|
|
@ -462,7 +462,7 @@ func GetCompileTestData() map[string]CompileTestData {
|
||||||
&FunctionValue{
|
&FunctionValue{
|
||||||
"a",
|
"a",
|
||||||
[]FunctionParameter{},
|
[]FunctionParameter{},
|
||||||
&NumberSignature{},
|
&FloatSignature{},
|
||||||
NewChunk(
|
NewChunk(
|
||||||
[]Bytecode{
|
[]Bytecode{
|
||||||
InstructionDescend,
|
InstructionDescend,
|
||||||
|
|
@ -473,7 +473,7 @@ func GetCompileTestData() map[string]CompileTestData {
|
||||||
InstructionAscend,
|
InstructionAscend,
|
||||||
},
|
},
|
||||||
[]Value{
|
[]Value{
|
||||||
&NumberValue{1}, &StringValue{"b"},
|
&FloatValue{1}, &StringValue{"b"},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
nil,
|
nil,
|
||||||
|
|
@ -491,8 +491,8 @@ func GetCompileTestData() map[string]CompileTestData {
|
||||||
name: "a",
|
name: "a",
|
||||||
value: &ListNode{
|
value: &ListNode{
|
||||||
items: []Node{
|
items: []Node{
|
||||||
&NumberNode{value: 1},
|
&FloatNode{value: 1},
|
||||||
&NumberNode{value: 2},
|
&FloatNode{value: 2},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
declare: true,
|
declare: true,
|
||||||
|
|
@ -516,8 +516,8 @@ func GetCompileTestData() map[string]CompileTestData {
|
||||||
name: "a",
|
name: "a",
|
||||||
value: &ListValue{
|
value: &ListValue{
|
||||||
Items: []Value{
|
Items: []Value{
|
||||||
&NumberValue{1},
|
&FloatValue{1},
|
||||||
&NumberValue{2},
|
&FloatValue{2},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
scope: 0,
|
scope: 0,
|
||||||
|
|
@ -543,7 +543,7 @@ func GetCompileTestData() map[string]CompileTestData {
|
||||||
name: "a",
|
name: "a",
|
||||||
value: &UnaryNode{
|
value: &UnaryNode{
|
||||||
UnaryNegate,
|
UnaryNegate,
|
||||||
&NumberNode{
|
&FloatNode{
|
||||||
1,
|
1,
|
||||||
0, 0,
|
0, 0,
|
||||||
},
|
},
|
||||||
|
|
@ -559,7 +559,7 @@ func GetCompileTestData() map[string]CompileTestData {
|
||||||
expectedStack: []Value{
|
expectedStack: []Value{
|
||||||
&VariableValue{
|
&VariableValue{
|
||||||
name: "a",
|
name: "a",
|
||||||
value: &NumberValue{-1},
|
value: &FloatValue{-1},
|
||||||
scope: 0,
|
scope: 0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,8 @@ const (
|
||||||
TokenBang
|
TokenBang
|
||||||
TokenSemicolon
|
TokenSemicolon
|
||||||
|
|
||||||
TokenNumber
|
TokenInteger
|
||||||
|
TokenFloat
|
||||||
TokenHexadecimal
|
TokenHexadecimal
|
||||||
TokenString
|
TokenString
|
||||||
TokenName
|
TokenName
|
||||||
|
|
@ -55,6 +56,7 @@ const (
|
||||||
TokenComma
|
TokenComma
|
||||||
TokenDot
|
TokenDot
|
||||||
TokenColon
|
TokenColon
|
||||||
|
TokenArrow
|
||||||
|
|
||||||
TokenAssign
|
TokenAssign
|
||||||
TokenDeclare
|
TokenDeclare
|
||||||
|
|
@ -86,8 +88,10 @@ func (t TokenType) String() string {
|
||||||
return "slash"
|
return "slash"
|
||||||
case TokenBang:
|
case TokenBang:
|
||||||
return "bang"
|
return "bang"
|
||||||
case TokenNumber:
|
case TokenFloat:
|
||||||
return "number"
|
return "float"
|
||||||
|
case TokenInteger:
|
||||||
|
return "integer"
|
||||||
case TokenString:
|
case TokenString:
|
||||||
return "string"
|
return "string"
|
||||||
case TokenTrue:
|
case TokenTrue:
|
||||||
|
|
@ -135,7 +139,7 @@ func (t TokenType) String() string {
|
||||||
case TokenDeclare:
|
case TokenDeclare:
|
||||||
return "declare"
|
return "declare"
|
||||||
case TokenFunc:
|
case TokenFunc:
|
||||||
return "func"
|
return "fn"
|
||||||
case TokenReturn:
|
case TokenReturn:
|
||||||
return "return"
|
return "return"
|
||||||
case TokenWhile:
|
case TokenWhile:
|
||||||
|
|
@ -162,6 +166,8 @@ func (t TokenType) String() string {
|
||||||
return "pipe"
|
return "pipe"
|
||||||
case TokenHexadecimal:
|
case TokenHexadecimal:
|
||||||
return "hexadecimal"
|
return "hexadecimal"
|
||||||
|
case TokenArrow:
|
||||||
|
return "arrow"
|
||||||
}
|
}
|
||||||
|
|
||||||
panic("UNDEFINED TOKENTYPE STRING CONVERSION")
|
panic("UNDEFINED TOKENTYPE STRING CONVERSION")
|
||||||
|
|
@ -209,6 +215,9 @@ func (l *Lexer) NextToken() (Token, error) {
|
||||||
case '+':
|
case '+':
|
||||||
return l.makeToken(TokenPlus), nil
|
return l.makeToken(TokenPlus), nil
|
||||||
case '-':
|
case '-':
|
||||||
|
if l.accept('>') {
|
||||||
|
return l.makeToken(TokenArrow), nil
|
||||||
|
}
|
||||||
return l.makeToken(TokenMinus), nil
|
return l.makeToken(TokenMinus), nil
|
||||||
case '*':
|
case '*':
|
||||||
return l.makeToken(TokenStar), nil
|
return l.makeToken(TokenStar), nil
|
||||||
|
|
@ -339,7 +348,7 @@ func (l *Lexer) NextToken() (Token, error) {
|
||||||
return l.makeToken(TokenElse), nil
|
return l.makeToken(TokenElse), nil
|
||||||
case "var":
|
case "var":
|
||||||
return l.makeToken(TokenVar), nil
|
return l.makeToken(TokenVar), nil
|
||||||
case "func":
|
case "fn":
|
||||||
return l.makeToken(TokenFunc), nil
|
return l.makeToken(TokenFunc), nil
|
||||||
case "while":
|
case "while":
|
||||||
return l.makeToken(TokenWhile), nil
|
return l.makeToken(TokenWhile), nil
|
||||||
|
|
@ -364,7 +373,7 @@ func (l *Lexer) NextToken() (Token, error) {
|
||||||
return l.makeToken(TokenHexadecimal), nil
|
return l.makeToken(TokenHexadecimal), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return l.makeToken(TokenNumber), nil
|
return l.makeToken(TokenInteger), nil
|
||||||
} else if unicode.IsDigit(c) {
|
} else if unicode.IsDigit(c) {
|
||||||
for unicode.IsDigit(l.peek()) {
|
for unicode.IsDigit(l.peek()) {
|
||||||
l.advance()
|
l.advance()
|
||||||
|
|
@ -375,9 +384,11 @@ func (l *Lexer) NextToken() (Token, error) {
|
||||||
for unicode.IsDigit(l.peek()) {
|
for unicode.IsDigit(l.peek()) {
|
||||||
l.advance()
|
l.advance()
|
||||||
}
|
}
|
||||||
|
return l.makeToken(TokenFloat), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return l.makeToken(TokenNumber), nil
|
return l.makeToken(TokenInteger), nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return l.makeToken(TokenError), errors.New(fmt.Sprintf("invalid token %c", c))
|
return l.makeToken(TokenError), errors.New(fmt.Sprintf("invalid token %c", c))
|
||||||
|
|
|
||||||
|
|
@ -21,23 +21,23 @@ func GetLexerTestData() map[string]LexerTestData {
|
||||||
},
|
},
|
||||||
"simple number(1)": {
|
"simple number(1)": {
|
||||||
"1024",
|
"1024",
|
||||||
[]TokenType{TokenNumber, TokenEOF},
|
[]TokenType{TokenInteger, TokenEOF},
|
||||||
},
|
},
|
||||||
"simple_arithmetics(7)": {
|
"simple_arithmetics(7)": {
|
||||||
"1 + 23 / 4 * 3",
|
"1 + 23 / 4 * 3",
|
||||||
[]TokenType{
|
[]TokenType{
|
||||||
TokenNumber, TokenPlus, TokenNumber, TokenSlash,
|
TokenInteger, TokenPlus, TokenInteger, TokenSlash,
|
||||||
TokenNumber, TokenStar, TokenNumber, TokenEOF,
|
TokenInteger, TokenStar, TokenInteger, TokenEOF,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"condition(3)": {
|
"condition(3)": {
|
||||||
"a <= 200",
|
"a <= 200",
|
||||||
[]TokenType{TokenName, TokenLessThanOrEqual, TokenNumber, TokenEOF},
|
[]TokenType{TokenName, TokenLessThanOrEqual, TokenInteger, TokenEOF},
|
||||||
},
|
},
|
||||||
"if_statement(10)": {
|
"if_statement(10)": {
|
||||||
"if a >= 200 {\n write(\"Hello world!\")\n}",
|
"if a >= 200 {\n write(\"Hello world!\")\n}",
|
||||||
[]TokenType{
|
[]TokenType{
|
||||||
TokenIf, TokenName, TokenGreaterThanOrEqual, TokenNumber, TokenOpenBrace,
|
TokenIf, TokenName, TokenGreaterThanOrEqual, TokenInteger, TokenOpenBrace,
|
||||||
TokenName, TokenOpenParenthesis, TokenString, TokenCloseParenthesis, TokenCloseBrace,
|
TokenName, TokenOpenParenthesis, TokenString, TokenCloseParenthesis, TokenCloseBrace,
|
||||||
TokenEOF,
|
TokenEOF,
|
||||||
},
|
},
|
||||||
|
|
@ -45,7 +45,7 @@ func GetLexerTestData() map[string]LexerTestData {
|
||||||
"if_else_statement(20)": {
|
"if_else_statement(20)": {
|
||||||
"if 23 * 2/3 > 32 {\n write(\"It is larger!\")\n} else {\n write(\"It is lower!\")\n}",
|
"if 23 * 2/3 > 32 {\n write(\"It is larger!\")\n} else {\n write(\"It is lower!\")\n}",
|
||||||
[]TokenType{
|
[]TokenType{
|
||||||
TokenIf, TokenNumber, TokenStar, TokenNumber, TokenSlash, TokenNumber, TokenGreaterThan, TokenNumber, TokenOpenBrace,
|
TokenIf, TokenInteger, TokenStar, TokenInteger, TokenSlash, TokenInteger, TokenGreaterThan, TokenInteger, TokenOpenBrace,
|
||||||
TokenName, TokenOpenParenthesis, TokenString, TokenCloseParenthesis, TokenCloseBrace,
|
TokenName, TokenOpenParenthesis, TokenString, TokenCloseParenthesis, TokenCloseBrace,
|
||||||
TokenElse, TokenOpenBrace, TokenName, TokenOpenParenthesis, TokenString, TokenCloseParenthesis, TokenCloseBrace,
|
TokenElse, TokenOpenBrace, TokenName, TokenOpenParenthesis, TokenString, TokenCloseParenthesis, TokenCloseBrace,
|
||||||
TokenEOF,
|
TokenEOF,
|
||||||
|
|
@ -58,8 +58,8 @@ func GetLexerTestData() map[string]LexerTestData {
|
||||||
"full_arithmetic_equality": {
|
"full_arithmetic_equality": {
|
||||||
"a + 2 == 10 * 2 / 3",
|
"a + 2 == 10 * 2 / 3",
|
||||||
[]TokenType{
|
[]TokenType{
|
||||||
TokenName, TokenPlus, TokenNumber, TokenEquals,
|
TokenName, TokenPlus, TokenInteger, TokenEquals,
|
||||||
TokenNumber, TokenStar, TokenNumber, TokenSlash, TokenNumber,
|
TokenInteger, TokenStar, TokenInteger, TokenSlash, TokenInteger,
|
||||||
TokenEOF,
|
TokenEOF,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -86,21 +86,21 @@ func GetLexerTestData() map[string]LexerTestData {
|
||||||
"complex_comparison": {
|
"complex_comparison": {
|
||||||
"!(h__elo123 >= 1)",
|
"!(h__elo123 >= 1)",
|
||||||
[]TokenType{
|
[]TokenType{
|
||||||
TokenBang, TokenOpenParenthesis, TokenName, TokenGreaterThanOrEqual, TokenNumber, TokenCloseParenthesis,
|
TokenBang, TokenOpenParenthesis, TokenName, TokenGreaterThanOrEqual, TokenInteger, TokenCloseParenthesis,
|
||||||
TokenEOF,
|
TokenEOF,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"3assignments_1condition": {
|
"3assignments_1condition": {
|
||||||
"a = 8 * 32\nb = a > 256\nc = a <= 256\n!b == c",
|
"a = 8 * 32\nb = a > 256\nc = a <= 256\n!b == c",
|
||||||
[]TokenType{
|
[]TokenType{
|
||||||
TokenName, TokenAssign, TokenNumber, TokenStar, TokenNumber,
|
TokenName, TokenAssign, TokenInteger, TokenStar, TokenInteger,
|
||||||
TokenName, TokenAssign, TokenName, TokenGreaterThan, TokenNumber,
|
TokenName, TokenAssign, TokenName, TokenGreaterThan, TokenInteger,
|
||||||
TokenName, TokenAssign, TokenName, TokenLessThanOrEqual, TokenNumber,
|
TokenName, TokenAssign, TokenName, TokenLessThanOrEqual, TokenInteger,
|
||||||
TokenBang, TokenName, TokenEquals, TokenName, TokenEOF,
|
TokenBang, TokenName, TokenEquals, TokenName, TokenEOF,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"func": {
|
"function": {
|
||||||
"func sum(a, b) {\n return a + b\n}",
|
"fn sum(a, b) {\n return a + b\n}",
|
||||||
[]TokenType{
|
[]TokenType{
|
||||||
TokenFunc, TokenName, TokenOpenParenthesis, TokenName, TokenComma, TokenName, TokenCloseParenthesis,
|
TokenFunc, TokenName, TokenOpenParenthesis, TokenName, TokenComma, TokenName, TokenCloseParenthesis,
|
||||||
TokenOpenBrace, TokenReturn, TokenName, TokenPlus, TokenName, TokenCloseBrace,
|
TokenOpenBrace, TokenReturn, TokenName, TokenPlus, TokenName, TokenCloseBrace,
|
||||||
|
|
@ -109,12 +109,12 @@ func GetLexerTestData() map[string]LexerTestData {
|
||||||
"while_loop": {
|
"while_loop": {
|
||||||
"while a < 5 {\n a = a + 1\n}",
|
"while a < 5 {\n a = a + 1\n}",
|
||||||
[]TokenType{
|
[]TokenType{
|
||||||
TokenWhile, TokenName, TokenLessThan, TokenNumber, TokenOpenBrace,
|
TokenWhile, TokenName, TokenLessThan, TokenInteger, TokenOpenBrace,
|
||||||
TokenName, TokenAssign, TokenName, TokenPlus, TokenNumber, TokenCloseBrace,
|
TokenName, TokenAssign, TokenName, TokenPlus, TokenInteger, TokenCloseBrace,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"lambda": {
|
"lambda": {
|
||||||
"sum := func(a, b) {\n" +
|
"sum := fn(a, b) {\n" +
|
||||||
" return a + b\n" +
|
" return a + b\n" +
|
||||||
"}",
|
"}",
|
||||||
[]TokenType{
|
[]TokenType{
|
||||||
|
|
@ -125,7 +125,7 @@ func GetLexerTestData() map[string]LexerTestData {
|
||||||
"list": {
|
"list": {
|
||||||
"data := [3, 1, 4, 1]",
|
"data := [3, 1, 4, 1]",
|
||||||
[]TokenType{
|
[]TokenType{
|
||||||
TokenName, TokenDeclare, TokenOpenBracket, TokenNumber, TokenComma, TokenNumber, TokenComma, TokenNumber, TokenComma, TokenNumber, TokenCloseBracket,
|
TokenName, TokenDeclare, TokenOpenBracket, TokenInteger, TokenComma, TokenInteger, TokenComma, TokenInteger, TokenComma, TokenInteger, TokenCloseBracket,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math/big"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
@ -21,7 +22,8 @@ type Boundary interface {
|
||||||
|
|
||||||
const (
|
const (
|
||||||
StringNodeType NodeType = iota
|
StringNodeType NodeType = iota
|
||||||
NumberNodeType
|
FloatNodeType
|
||||||
|
IntegerNodeType
|
||||||
ReferenceNodeType
|
ReferenceNodeType
|
||||||
BooleanNodeType
|
BooleanNodeType
|
||||||
NilNodeType
|
NilNodeType
|
||||||
|
|
@ -43,8 +45,10 @@ func (n NodeType) String() string {
|
||||||
switch n {
|
switch n {
|
||||||
case StringNodeType:
|
case StringNodeType:
|
||||||
return "String"
|
return "String"
|
||||||
case NumberNodeType:
|
case FloatNodeType:
|
||||||
return "Number"
|
return "Float"
|
||||||
|
case IntegerNodeType:
|
||||||
|
return "Integer"
|
||||||
case ReferenceNodeType:
|
case ReferenceNodeType:
|
||||||
return "Reference"
|
return "Reference"
|
||||||
case BinaryNodeType:
|
case BinaryNodeType:
|
||||||
|
|
@ -120,22 +124,41 @@ func (n StringNode) Bounds() (Pos, Pos) {
|
||||||
return n.start, n.end
|
return n.start, n.end
|
||||||
}
|
}
|
||||||
|
|
||||||
type NumberNode struct {
|
type FloatNode struct {
|
||||||
value float64
|
value float64
|
||||||
|
|
||||||
start Pos
|
start Pos
|
||||||
end Pos
|
end Pos
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n NumberNode) Type() NodeType {
|
func (n FloatNode) Type() NodeType {
|
||||||
return NumberNodeType
|
return FloatNodeType
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n NumberNode) String() string {
|
func (n FloatNode) String() string {
|
||||||
return strconv.FormatFloat(n.value, 'g', -1, NumberSize)
|
return strconv.FormatFloat(n.value, 'g', -1, FloatSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n NumberNode) Bounds() (Pos, Pos) {
|
func (n FloatNode) Bounds() (Pos, Pos) {
|
||||||
|
return n.start, n.end
|
||||||
|
}
|
||||||
|
|
||||||
|
type IntegerNode struct {
|
||||||
|
value *big.Int
|
||||||
|
|
||||||
|
start Pos
|
||||||
|
end Pos
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n IntegerNode) Type() NodeType {
|
||||||
|
return IntegerNodeType
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n IntegerNode) String() string {
|
||||||
|
return n.value.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n IntegerNode) Bounds() (Pos, Pos) {
|
||||||
return n.start, n.end
|
return n.start, n.end
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"math/big"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
@ -203,10 +204,11 @@ func (p *Parser) advance() {
|
||||||
|
|
||||||
if p.pos < Pos(len(p.tokens)) {
|
if p.pos < Pos(len(p.tokens)) {
|
||||||
p.curr = &p.tokens[p.pos]
|
p.curr = &p.tokens[p.pos]
|
||||||
p.pos++
|
|
||||||
} else {
|
} else {
|
||||||
panic("no more tokens")
|
p.curr = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p.pos++
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) error(error string, causer *Token) error {
|
func (p *Parser) error(error string, causer *Token) error {
|
||||||
|
|
@ -229,15 +231,29 @@ func (p *Parser) factor() (Node, error) {
|
||||||
p.prev.Start + p.prev.Length,
|
p.prev.Start + p.prev.Length,
|
||||||
}, nil
|
}, nil
|
||||||
|
|
||||||
case TokenNumber:
|
case TokenInteger:
|
||||||
p.advance()
|
p.advance()
|
||||||
num, err := strconv.ParseFloat((*p.prev).Lexeme, NumberSize)
|
|
||||||
|
num, success := new(big.Int).SetString(p.prev.Lexeme, 10)
|
||||||
|
if !success {
|
||||||
|
return nil, p.error(fmt.Sprintf("cannot parse integer base 10: %s", p.prev.Lexeme), p.prev)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &IntegerNode{
|
||||||
|
num,
|
||||||
|
p.prev.Start,
|
||||||
|
p.prev.Start + p.prev.Length,
|
||||||
|
}, nil
|
||||||
|
|
||||||
|
case TokenFloat:
|
||||||
|
p.advance()
|
||||||
|
num, err := strconv.ParseFloat((*p.prev).Lexeme, FloatSize)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, p.error(fmt.Sprintf("Error parsing number: %v", err), p.prev)
|
return nil, p.error(fmt.Sprintf("Error parsing number: %v", err), p.prev)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &NumberNode{
|
return &FloatNode{
|
||||||
num,
|
num,
|
||||||
p.prev.Start,
|
p.prev.Start,
|
||||||
p.prev.Start + p.prev.Length,
|
p.prev.Start + p.prev.Length,
|
||||||
|
|
@ -246,13 +262,13 @@ func (p *Parser) factor() (Node, error) {
|
||||||
case TokenHexadecimal:
|
case TokenHexadecimal:
|
||||||
p.advance()
|
p.advance()
|
||||||
start := (*p.prev).Start
|
start := (*p.prev).Start
|
||||||
num, err := strconv.ParseUint((*p.prev).Lexeme[2:], 16, NumberSize)
|
num, ok := new(big.Int).SetString(p.prev.Lexeme[2:], 16)
|
||||||
if err != nil {
|
if !ok {
|
||||||
return nil, err
|
return nil, p.error(fmt.Sprintf("cannot parse hexadecimal: %v", p.prev.Lexeme), p.prev)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &NumberNode{
|
return &IntegerNode{
|
||||||
float64(num),
|
num,
|
||||||
start,
|
start,
|
||||||
p.prev.Start + p.prev.Length,
|
p.prev.Start + p.prev.Length,
|
||||||
}, nil
|
}, nil
|
||||||
|
|
@ -280,6 +296,8 @@ func (p *Parser) factor() (Node, error) {
|
||||||
p.advance()
|
p.advance()
|
||||||
start := p.prev.Start
|
start := p.prev.Start
|
||||||
|
|
||||||
|
// TODO: find better solution; current one is messy
|
||||||
|
// Maybe perform better analysis to determine the kind of the list...
|
||||||
if p.accept(TokenCloseBracket) {
|
if p.accept(TokenCloseBracket) {
|
||||||
s, err := p.parseSignature()
|
s, err := p.parseSignature()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -390,7 +408,7 @@ func (p *Parser) factor() (Node, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var sig TypeSignature = &NilSignature{}
|
var sig TypeSignature = &NilSignature{}
|
||||||
if p.curr.Type != TokenOpenBrace {
|
if p.accept(TokenArrow) {
|
||||||
sig, err = p.parseSignature()
|
sig, err = p.parseSignature()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -744,7 +762,7 @@ func (p *Parser) statement() (Node, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var yield TypeSignature = &NilSignature{}
|
var yield TypeSignature = &NilSignature{}
|
||||||
if p.curr.Type != TokenOpenBrace {
|
if p.accept(TokenArrow) {
|
||||||
yield, err = p.parseSignature()
|
yield, err = p.parseSignature()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -983,8 +1001,10 @@ func (p *Parser) parseSignature() (TypeSignature, error) {
|
||||||
switch name {
|
switch name {
|
||||||
case "string":
|
case "string":
|
||||||
s = &StringSignature{}
|
s = &StringSignature{}
|
||||||
case "number":
|
case "int":
|
||||||
s = &NumberSignature{}
|
s = &IntegerSignature{}
|
||||||
|
case "float":
|
||||||
|
s = &FloatSignature{}
|
||||||
case "boolean":
|
case "boolean":
|
||||||
s = &BooleanSignature{}
|
s = &BooleanSignature{}
|
||||||
case "list":
|
case "list":
|
||||||
|
|
|
||||||
|
|
@ -55,9 +55,9 @@ func GetTokenTestData() map[string]TokenTestData {
|
||||||
[]Token{
|
[]Token{
|
||||||
NewToken(TokenName, 0, 1, 0, "_"),
|
NewToken(TokenName, 0, 1, 0, "_"),
|
||||||
NewToken(TokenAssign, 1, 1, 0, "="),
|
NewToken(TokenAssign, 1, 1, 0, "="),
|
||||||
NewToken(TokenNumber, 3, 1, 0, "1"),
|
NewToken(TokenFloat, 3, 1, 0, "1"),
|
||||||
NewToken(TokenPlus, 4, 1, 0, "+"),
|
NewToken(TokenPlus, 4, 1, 0, "+"),
|
||||||
NewToken(TokenNumber, 5, 1, 0, "2"),
|
NewToken(TokenFloat, 5, 1, 0, "2"),
|
||||||
NewToken(TokenEOF, 6, 0, 0, ""),
|
NewToken(TokenEOF, 6, 0, 0, ""),
|
||||||
},
|
},
|
||||||
&BlockNode{
|
&BlockNode{
|
||||||
|
|
@ -66,11 +66,11 @@ func GetTokenTestData() map[string]TokenTestData {
|
||||||
"_",
|
"_",
|
||||||
&BinaryNode{
|
&BinaryNode{
|
||||||
BinaryAddition,
|
BinaryAddition,
|
||||||
&NumberNode{
|
&FloatNode{
|
||||||
1,
|
1,
|
||||||
0, 0,
|
0, 0,
|
||||||
},
|
},
|
||||||
&NumberNode{
|
&FloatNode{
|
||||||
2,
|
2,
|
||||||
0, 0,
|
0, 0,
|
||||||
},
|
},
|
||||||
|
|
@ -110,7 +110,7 @@ func GetTokenTestData() map[string]TokenTestData {
|
||||||
[]Token{
|
[]Token{
|
||||||
NewToken(TokenName, 0, 1, 0, "a"),
|
NewToken(TokenName, 0, 1, 0, "a"),
|
||||||
NewToken(TokenDeclare, 1, 2, 0, ":="),
|
NewToken(TokenDeclare, 1, 2, 0, ":="),
|
||||||
NewToken(TokenNumber, 3, 1, 0, "1"),
|
NewToken(TokenFloat, 3, 1, 0, "1"),
|
||||||
NewToken(TokenPlus, 4, 1, 0, "+"),
|
NewToken(TokenPlus, 4, 1, 0, "+"),
|
||||||
NewToken(TokenName, 5, 1, 0, "b"),
|
NewToken(TokenName, 5, 1, 0, "b"),
|
||||||
NewToken(TokenEOF, 6, 0, 0, ""),
|
NewToken(TokenEOF, 6, 0, 0, ""),
|
||||||
|
|
@ -121,7 +121,7 @@ func GetTokenTestData() map[string]TokenTestData {
|
||||||
"a",
|
"a",
|
||||||
&BinaryNode{
|
&BinaryNode{
|
||||||
BinaryAddition,
|
BinaryAddition,
|
||||||
&NumberNode{
|
&FloatNode{
|
||||||
1,
|
1,
|
||||||
0, 0,
|
0, 0,
|
||||||
},
|
},
|
||||||
|
|
@ -145,28 +145,28 @@ func GetTokenTestData() map[string]TokenTestData {
|
||||||
NewToken(TokenAssign, 1, 2, 0, "="),
|
NewToken(TokenAssign, 1, 2, 0, "="),
|
||||||
|
|
||||||
NewToken(TokenOpenParenthesis, 3, 1, 0, "("),
|
NewToken(TokenOpenParenthesis, 3, 1, 0, "("),
|
||||||
NewToken(TokenNumber, 4, 1, 0, "2"),
|
NewToken(TokenFloat, 4, 1, 0, "2"),
|
||||||
NewToken(TokenPlus, 5, 1, 0, "+"),
|
NewToken(TokenPlus, 5, 1, 0, "+"),
|
||||||
NewToken(TokenNumber, 6, 1, 0, "1"),
|
NewToken(TokenFloat, 6, 1, 0, "1"),
|
||||||
NewToken(TokenCloseParenthesis, 7, 1, 0, ")"),
|
NewToken(TokenCloseParenthesis, 7, 1, 0, ")"),
|
||||||
NewToken(TokenStar, 8, 1, 0, "*"),
|
NewToken(TokenStar, 8, 1, 0, "*"),
|
||||||
NewToken(TokenNumber, 9, 1, 0, "5"),
|
NewToken(TokenFloat, 9, 1, 0, "5"),
|
||||||
|
|
||||||
NewToken(TokenPlus, 10, 1, 0, "+"),
|
NewToken(TokenPlus, 10, 1, 0, "+"),
|
||||||
|
|
||||||
NewToken(TokenNumber, 11, 1, 0, "3"),
|
NewToken(TokenFloat, 11, 1, 0, "3"),
|
||||||
NewToken(TokenSlash, 12, 1, 0, "/"),
|
NewToken(TokenSlash, 12, 1, 0, "/"),
|
||||||
NewToken(TokenOpenParenthesis, 13, 1, 0, "("),
|
NewToken(TokenOpenParenthesis, 13, 1, 0, "("),
|
||||||
NewToken(TokenNumber, 14, 1, 0, "6"),
|
NewToken(TokenFloat, 14, 1, 0, "6"),
|
||||||
NewToken(TokenMinus, 15, 1, 0, "-"),
|
NewToken(TokenMinus, 15, 1, 0, "-"),
|
||||||
NewToken(TokenNumber, 16, 1, 0, "2"),
|
NewToken(TokenFloat, 16, 1, 0, "2"),
|
||||||
NewToken(TokenCloseParenthesis, 17, 1, 0, ")"),
|
NewToken(TokenCloseParenthesis, 17, 1, 0, ")"),
|
||||||
|
|
||||||
NewToken(TokenMinus, 18, 1, 0, "-"),
|
NewToken(TokenMinus, 18, 1, 0, "-"),
|
||||||
|
|
||||||
NewToken(TokenNumber, 19, 2, 0, "10"),
|
NewToken(TokenFloat, 19, 2, 0, "10"),
|
||||||
NewToken(TokenSlash, 20, 1, 0, "/"),
|
NewToken(TokenSlash, 20, 1, 0, "/"),
|
||||||
NewToken(TokenNumber, 21, 1, 0, "2"),
|
NewToken(TokenFloat, 21, 1, 0, "2"),
|
||||||
NewToken(TokenEOF, 22, 0, 0, ""),
|
NewToken(TokenEOF, 22, 0, 0, ""),
|
||||||
},
|
},
|
||||||
// (2 + 1) * 5 + 3 / (6 - 2) - 10 / 2
|
// (2 + 1) * 5 + 3 / (6 - 2) - 10 / 2
|
||||||
|
|
@ -182,17 +182,17 @@ func GetTokenTestData() map[string]TokenTestData {
|
||||||
BinaryMultiplication,
|
BinaryMultiplication,
|
||||||
&BinaryNode{
|
&BinaryNode{
|
||||||
BinaryAddition,
|
BinaryAddition,
|
||||||
&NumberNode{
|
&FloatNode{
|
||||||
2,
|
2,
|
||||||
0, 0,
|
0, 0,
|
||||||
},
|
},
|
||||||
&NumberNode{
|
&FloatNode{
|
||||||
1,
|
1,
|
||||||
0, 0,
|
0, 0,
|
||||||
},
|
},
|
||||||
0, 0,
|
0, 0,
|
||||||
},
|
},
|
||||||
&NumberNode{
|
&FloatNode{
|
||||||
5,
|
5,
|
||||||
0, 0,
|
0, 0,
|
||||||
},
|
},
|
||||||
|
|
@ -200,17 +200,17 @@ func GetTokenTestData() map[string]TokenTestData {
|
||||||
},
|
},
|
||||||
&BinaryNode{
|
&BinaryNode{
|
||||||
BinaryDivision,
|
BinaryDivision,
|
||||||
&NumberNode{
|
&FloatNode{
|
||||||
3,
|
3,
|
||||||
0, 0,
|
0, 0,
|
||||||
},
|
},
|
||||||
&BinaryNode{
|
&BinaryNode{
|
||||||
BinarySubtraction,
|
BinarySubtraction,
|
||||||
&NumberNode{
|
&FloatNode{
|
||||||
6,
|
6,
|
||||||
0, 0,
|
0, 0,
|
||||||
},
|
},
|
||||||
&NumberNode{
|
&FloatNode{
|
||||||
2,
|
2,
|
||||||
0, 0,
|
0, 0,
|
||||||
},
|
},
|
||||||
|
|
@ -222,11 +222,11 @@ func GetTokenTestData() map[string]TokenTestData {
|
||||||
},
|
},
|
||||||
&BinaryNode{
|
&BinaryNode{
|
||||||
BinaryDivision,
|
BinaryDivision,
|
||||||
&NumberNode{
|
&FloatNode{
|
||||||
10,
|
10,
|
||||||
0, 0,
|
0, 0,
|
||||||
},
|
},
|
||||||
&NumberNode{
|
&FloatNode{
|
||||||
2,
|
2,
|
||||||
0, 0,
|
0, 0,
|
||||||
},
|
},
|
||||||
|
|
@ -245,9 +245,9 @@ func GetTokenTestData() map[string]TokenTestData {
|
||||||
[]Token{
|
[]Token{
|
||||||
NewToken(TokenName, 0, 1, 0, "_"),
|
NewToken(TokenName, 0, 1, 0, "_"),
|
||||||
NewToken(TokenAssign, 1, 1, 0, "="),
|
NewToken(TokenAssign, 1, 1, 0, "="),
|
||||||
NewToken(TokenNumber, 2, 2, 0, "20"),
|
NewToken(TokenFloat, 2, 2, 0, "20"),
|
||||||
NewToken(TokenEquals, 4, 2, 0, "=="),
|
NewToken(TokenEquals, 4, 2, 0, "=="),
|
||||||
NewToken(TokenNumber, 6, 2, 0, "15"),
|
NewToken(TokenFloat, 6, 2, 0, "15"),
|
||||||
NewToken(TokenEOF, 8, 0, 0, ""),
|
NewToken(TokenEOF, 8, 0, 0, ""),
|
||||||
},
|
},
|
||||||
&BlockNode{
|
&BlockNode{
|
||||||
|
|
@ -256,11 +256,11 @@ func GetTokenTestData() map[string]TokenTestData {
|
||||||
"_",
|
"_",
|
||||||
&BinaryNode{
|
&BinaryNode{
|
||||||
BinaryEquality,
|
BinaryEquality,
|
||||||
&NumberNode{
|
&FloatNode{
|
||||||
20,
|
20,
|
||||||
0, 0,
|
0, 0,
|
||||||
},
|
},
|
||||||
&NumberNode{
|
&FloatNode{
|
||||||
15,
|
15,
|
||||||
0, 0,
|
0, 0,
|
||||||
},
|
},
|
||||||
|
|
@ -278,11 +278,11 @@ func GetTokenTestData() map[string]TokenTestData {
|
||||||
NewToken(TokenIf, 0, 2, 0, "if"),
|
NewToken(TokenIf, 0, 2, 0, "if"),
|
||||||
NewToken(TokenName, 2, 1, 0, "a"),
|
NewToken(TokenName, 2, 1, 0, "a"),
|
||||||
NewToken(TokenEquals, 3, 2, 0, "=="),
|
NewToken(TokenEquals, 3, 2, 0, "=="),
|
||||||
NewToken(TokenNumber, 5, 1, 0, "0"),
|
NewToken(TokenFloat, 5, 1, 0, "0"),
|
||||||
NewToken(TokenOpenBrace, 6, 1, 0, "{"),
|
NewToken(TokenOpenBrace, 6, 1, 0, "{"),
|
||||||
NewToken(TokenName, 7, 1, 1, "b"),
|
NewToken(TokenName, 7, 1, 1, "b"),
|
||||||
NewToken(TokenAssign, 8, 1, 1, "="),
|
NewToken(TokenAssign, 8, 1, 1, "="),
|
||||||
NewToken(TokenNumber, 9, 1, 1, "1"),
|
NewToken(TokenFloat, 9, 1, 1, "1"),
|
||||||
NewToken(TokenCloseBrace, 10, 1, 2, "}"),
|
NewToken(TokenCloseBrace, 10, 1, 2, "}"),
|
||||||
NewToken(TokenEOF, 11, 0, 2, ""),
|
NewToken(TokenEOF, 11, 0, 2, ""),
|
||||||
},
|
},
|
||||||
|
|
@ -295,7 +295,7 @@ func GetTokenTestData() map[string]TokenTestData {
|
||||||
"a",
|
"a",
|
||||||
0, 0,
|
0, 0,
|
||||||
},
|
},
|
||||||
&NumberNode{
|
&FloatNode{
|
||||||
0,
|
0,
|
||||||
0, 0,
|
0, 0,
|
||||||
},
|
},
|
||||||
|
|
@ -305,7 +305,7 @@ func GetTokenTestData() map[string]TokenTestData {
|
||||||
[]Node{
|
[]Node{
|
||||||
&AssignNode{
|
&AssignNode{
|
||||||
"b",
|
"b",
|
||||||
&NumberNode{
|
&FloatNode{
|
||||||
1,
|
1,
|
||||||
0, 0,
|
0, 0,
|
||||||
},
|
},
|
||||||
|
|
@ -325,17 +325,17 @@ func GetTokenTestData() map[string]TokenTestData {
|
||||||
NewToken(TokenIf, 0, 2, 0, "if"),
|
NewToken(TokenIf, 0, 2, 0, "if"),
|
||||||
NewToken(TokenName, 2, 1, 0, "a"),
|
NewToken(TokenName, 2, 1, 0, "a"),
|
||||||
NewToken(TokenEquals, 3, 2, 0, "=="),
|
NewToken(TokenEquals, 3, 2, 0, "=="),
|
||||||
NewToken(TokenNumber, 5, 1, 0, "0"),
|
NewToken(TokenFloat, 5, 1, 0, "0"),
|
||||||
NewToken(TokenOpenBrace, 6, 1, 0, "{"),
|
NewToken(TokenOpenBrace, 6, 1, 0, "{"),
|
||||||
NewToken(TokenName, 7, 1, 1, "b"),
|
NewToken(TokenName, 7, 1, 1, "b"),
|
||||||
NewToken(TokenAssign, 8, 1, 1, "="),
|
NewToken(TokenAssign, 8, 1, 1, "="),
|
||||||
NewToken(TokenNumber, 9, 1, 1, "1"),
|
NewToken(TokenFloat, 9, 1, 1, "1"),
|
||||||
NewToken(TokenCloseBrace, 10, 1, 2, "}"),
|
NewToken(TokenCloseBrace, 10, 1, 2, "}"),
|
||||||
NewToken(TokenElse, 11, 4, 2, "else"),
|
NewToken(TokenElse, 11, 4, 2, "else"),
|
||||||
NewToken(TokenOpenBrace, 15, 1, 2, "{"),
|
NewToken(TokenOpenBrace, 15, 1, 2, "{"),
|
||||||
NewToken(TokenName, 16, 1, 2, "b"),
|
NewToken(TokenName, 16, 1, 2, "b"),
|
||||||
NewToken(TokenAssign, 17, 1, 2, "="),
|
NewToken(TokenAssign, 17, 1, 2, "="),
|
||||||
NewToken(TokenNumber, 18, 1, 2, "0"),
|
NewToken(TokenFloat, 18, 1, 2, "0"),
|
||||||
NewToken(TokenCloseBrace, 19, 1, 2, "}"),
|
NewToken(TokenCloseBrace, 19, 1, 2, "}"),
|
||||||
NewToken(TokenEOF, 20, 0, 2, ""),
|
NewToken(TokenEOF, 20, 0, 2, ""),
|
||||||
},
|
},
|
||||||
|
|
@ -348,7 +348,7 @@ func GetTokenTestData() map[string]TokenTestData {
|
||||||
"a",
|
"a",
|
||||||
0, 0,
|
0, 0,
|
||||||
},
|
},
|
||||||
&NumberNode{
|
&FloatNode{
|
||||||
0,
|
0,
|
||||||
0, 0,
|
0, 0,
|
||||||
},
|
},
|
||||||
|
|
@ -358,7 +358,7 @@ func GetTokenTestData() map[string]TokenTestData {
|
||||||
[]Node{
|
[]Node{
|
||||||
&AssignNode{
|
&AssignNode{
|
||||||
"b",
|
"b",
|
||||||
&NumberNode{
|
&FloatNode{
|
||||||
1,
|
1,
|
||||||
0, 0,
|
0, 0,
|
||||||
},
|
},
|
||||||
|
|
@ -372,7 +372,7 @@ func GetTokenTestData() map[string]TokenTestData {
|
||||||
[]Node{
|
[]Node{
|
||||||
&AssignNode{
|
&AssignNode{
|
||||||
"b",
|
"b",
|
||||||
&NumberNode{
|
&FloatNode{
|
||||||
0,
|
0,
|
||||||
0, 0,
|
0, 0,
|
||||||
},
|
},
|
||||||
|
|
@ -403,21 +403,22 @@ func GetTokenTestData() map[string]TokenTestData {
|
||||||
0, 0,
|
0, 0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"lambda": { // a := func(a, b) { return a + b }
|
"lambda": { // a := fn(a: float, b: float) -> float { return a + b }
|
||||||
[]Token{
|
[]Token{
|
||||||
NewToken(TokenName, 0, 1, 0, "a"),
|
NewToken(TokenName, 0, 1, 0, "a"),
|
||||||
NewToken(TokenDeclare, 1, 2, 0, ":="),
|
NewToken(TokenDeclare, 1, 2, 0, ":="),
|
||||||
NewToken(TokenFunc, 3, 4, 0, "func"),
|
NewToken(TokenFunc, 3, 2, 0, "fn"),
|
||||||
NewToken(TokenOpenParenthesis, 7, 1, 0, "("),
|
NewToken(TokenOpenParenthesis, 5, 1, 0, "("),
|
||||||
NewToken(TokenName, 8, 1, 0, "a"),
|
NewToken(TokenName, 6, 1, 0, "a"),
|
||||||
NewToken(TokenColon, 9, 1, 0, ":"),
|
NewToken(TokenColon, 6, 1, 0, ":"),
|
||||||
NewToken(TokenName, 10, 5, 0, "number"),
|
NewToken(TokenName, 10, 5, 0, "float"),
|
||||||
NewToken(TokenComma, 9, 1, 0, ","),
|
NewToken(TokenComma, 9, 1, 0, ","),
|
||||||
NewToken(TokenName, 10, 1, 0, "b"),
|
NewToken(TokenName, 10, 1, 0, "b"),
|
||||||
NewToken(TokenColon, 9, 1, 0, ":"),
|
NewToken(TokenColon, 9, 1, 0, ":"),
|
||||||
NewToken(TokenName, 10, 5, 0, "number"),
|
NewToken(TokenName, 10, 5, 0, "float"),
|
||||||
NewToken(TokenCloseParenthesis, 11, 1, 0, ")"),
|
NewToken(TokenCloseParenthesis, 11, 1, 0, ")"),
|
||||||
NewToken(TokenName, 10, 5, 0, "number"),
|
NewToken(TokenArrow, 12, 1, 0, "->"),
|
||||||
|
NewToken(TokenName, 10, 5, 0, "float"),
|
||||||
|
|
||||||
NewToken(TokenOpenBrace, 12, 1, 1, "{"),
|
NewToken(TokenOpenBrace, 12, 1, 1, "{"),
|
||||||
NewToken(TokenReturn, 13, 6, 1, "return"),
|
NewToken(TokenReturn, 13, 6, 1, "return"),
|
||||||
|
|
@ -437,14 +438,14 @@ func GetTokenTestData() map[string]TokenTestData {
|
||||||
[]FunctionParameter{
|
[]FunctionParameter{
|
||||||
{
|
{
|
||||||
"a",
|
"a",
|
||||||
&NumberSignature{},
|
&FloatSignature{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"b",
|
"b",
|
||||||
&NumberSignature{},
|
&FloatSignature{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
&NumberSignature{},
|
&FloatSignature{},
|
||||||
&BlockNode{
|
&BlockNode{
|
||||||
[]Node{
|
[]Node{
|
||||||
&ReturnNode{
|
&ReturnNode{
|
||||||
|
|
@ -476,13 +477,19 @@ func GetTokenTestData() map[string]TokenTestData {
|
||||||
},
|
},
|
||||||
"function_declaration": {
|
"function_declaration": {
|
||||||
[]Token{
|
[]Token{
|
||||||
NewToken(TokenFunc, 0, 4, 0, "func"),
|
NewToken(TokenFunc, 0, 2, 0, "fn"),
|
||||||
NewToken(TokenName, 4, 3, 0, "a"),
|
NewToken(TokenName, 4, 3, 0, "a"),
|
||||||
NewToken(TokenOpenParenthesis, 7, 1, 0, "("),
|
NewToken(TokenOpenParenthesis, 7, 1, 0, "("),
|
||||||
NewToken(TokenName, 8, 1, 0, "a"),
|
NewToken(TokenName, 8, 1, 0, "a"),
|
||||||
|
NewToken(TokenColon, 9, 1, 0, ":"),
|
||||||
|
NewToken(TokenName, 8, 1, 0, "float"),
|
||||||
NewToken(TokenComma, 9, 1, 0, ","),
|
NewToken(TokenComma, 9, 1, 0, ","),
|
||||||
NewToken(TokenName, 10, 1, 0, "b"),
|
NewToken(TokenName, 10, 1, 0, "b"),
|
||||||
|
NewToken(TokenColon, 9, 1, 0, ":"),
|
||||||
|
NewToken(TokenName, 8, 1, 0, "float"),
|
||||||
NewToken(TokenCloseParenthesis, 11, 1, 0, ")"),
|
NewToken(TokenCloseParenthesis, 11, 1, 0, ")"),
|
||||||
|
NewToken(TokenArrow, 9, 1, 0, "->"),
|
||||||
|
NewToken(TokenName, 8, 1, 0, "float"),
|
||||||
|
|
||||||
NewToken(TokenOpenBrace, 12, 1, 1, "{"),
|
NewToken(TokenOpenBrace, 12, 1, 1, "{"),
|
||||||
NewToken(TokenReturn, 13, 6, 1, "return"),
|
NewToken(TokenReturn, 13, 6, 1, "return"),
|
||||||
|
|
@ -502,14 +509,14 @@ func GetTokenTestData() map[string]TokenTestData {
|
||||||
[]FunctionParameter{
|
[]FunctionParameter{
|
||||||
{
|
{
|
||||||
"a",
|
"a",
|
||||||
&NumberSignature{},
|
&FloatSignature{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"b",
|
"b",
|
||||||
&NumberSignature{},
|
&FloatSignature{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
&NumberSignature{},
|
&FloatSignature{},
|
||||||
&BlockNode{
|
&BlockNode{
|
||||||
[]Node{
|
[]Node{
|
||||||
&ReturnNode{
|
&ReturnNode{
|
||||||
|
|
@ -577,7 +584,7 @@ func GetTokenTestData() map[string]TokenTestData {
|
||||||
NewToken(TokenName, 8, 1, 0, "a"),
|
NewToken(TokenName, 8, 1, 0, "a"),
|
||||||
NewToken(TokenComma, 11, 1, 0, ","),
|
NewToken(TokenComma, 11, 1, 0, ","),
|
||||||
|
|
||||||
NewToken(TokenNumber, 8, 1, 0, "3.141"),
|
NewToken(TokenFloat, 8, 1, 0, "3.141"),
|
||||||
NewToken(TokenComma, 11, 1, 0, ","),
|
NewToken(TokenComma, 11, 1, 0, ","),
|
||||||
|
|
||||||
NewToken(TokenString, 6, 1, 0, "\"Hello world!\""),
|
NewToken(TokenString, 6, 1, 0, "\"Hello world!\""),
|
||||||
|
|
@ -587,10 +594,10 @@ func GetTokenTestData() map[string]TokenTestData {
|
||||||
NewToken(TokenComma, 11, 1, 0, ","),
|
NewToken(TokenComma, 11, 1, 0, ","),
|
||||||
|
|
||||||
NewToken(TokenOpenBracket, 6, 1, 0, "["),
|
NewToken(TokenOpenBracket, 6, 1, 0, "["),
|
||||||
NewToken(TokenNumber, 6, 1, 0, "2"),
|
NewToken(TokenFloat, 6, 1, 0, "2"),
|
||||||
NewToken(TokenComma, 11, 1, 0, ","),
|
NewToken(TokenComma, 11, 1, 0, ","),
|
||||||
|
|
||||||
NewToken(TokenNumber, 6, 1, 0, "3"),
|
NewToken(TokenFloat, 6, 1, 0, "3"),
|
||||||
NewToken(TokenCloseBracket, 6, 1, 0, "]"),
|
NewToken(TokenCloseBracket, 6, 1, 0, "]"),
|
||||||
|
|
||||||
NewToken(TokenCloseBracket, 6, 1, 0, "]"),
|
NewToken(TokenCloseBracket, 6, 1, 0, "]"),
|
||||||
|
|
@ -607,7 +614,7 @@ func GetTokenTestData() map[string]TokenTestData {
|
||||||
"a",
|
"a",
|
||||||
0, 0,
|
0, 0,
|
||||||
},
|
},
|
||||||
&NumberNode{
|
&FloatNode{
|
||||||
3.141,
|
3.141,
|
||||||
0, 0,
|
0, 0,
|
||||||
},
|
},
|
||||||
|
|
@ -622,10 +629,10 @@ func GetTokenTestData() map[string]TokenTestData {
|
||||||
},
|
},
|
||||||
&ListNode{
|
&ListNode{
|
||||||
[]Node{
|
[]Node{
|
||||||
&NumberNode{
|
&FloatNode{
|
||||||
2,
|
2,
|
||||||
0, 0,
|
0, 0,
|
||||||
}, &NumberNode{
|
}, &FloatNode{
|
||||||
3,
|
3,
|
||||||
0, 0,
|
0, 0,
|
||||||
},
|
},
|
||||||
|
|
@ -677,12 +684,20 @@ func NodeEquality(t *testing.T, n1 Node, n2 Node) {
|
||||||
t.Logf("String node quoted values match (%s)", n1.(*StringNode).value)
|
t.Logf("String node quoted values match (%s)", n1.(*StringNode).value)
|
||||||
}
|
}
|
||||||
|
|
||||||
case NumberNodeType:
|
case FloatNodeType:
|
||||||
if n1.(*NumberNode).value != n2.(*NumberNode).value {
|
if n1.(*FloatNode).value != n2.(*FloatNode).value {
|
||||||
t.Errorf("Number node values don't match (%f and %f)", n1.(*NumberNode).value, n2.(*NumberNode).value)
|
t.Errorf("Float node values don't match (%f and %f)", n1.(*FloatNode).value, n2.(*FloatNode).value)
|
||||||
} else {
|
} else {
|
||||||
t.Logf("Number node values match (%f)", n1.(*NumberNode).value)
|
t.Logf("Float node values match (%f)", n1.(*FloatNode).value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case IntegerNodeType:
|
||||||
|
if n1.(*IntegerNode).value.Cmp(n2.(*IntegerNode).value) != 0 {
|
||||||
|
t.Errorf("Integer node values don't match (%d and %d)", n1.(*IntegerNode).value, n2.(*IntegerNode).value)
|
||||||
|
} else {
|
||||||
|
t.Logf("Integer node values match (%d)", n1.(*IntegerNode).value)
|
||||||
|
}
|
||||||
|
|
||||||
case ReferenceNodeType:
|
case ReferenceNodeType:
|
||||||
if n1.(*ReferenceNode).name != n2.(*ReferenceNode).name {
|
if n1.(*ReferenceNode).name != n2.(*ReferenceNode).name {
|
||||||
t.Errorf("Reference node values don't match (%s and %s)", n1.(*ReferenceNode).name, n2.(*ReferenceNode).name)
|
t.Errorf("Reference node values don't match (%s and %s)", n1.(*ReferenceNode).name, n2.(*ReferenceNode).name)
|
||||||
|
|
@ -795,6 +810,37 @@ func NodeEquality(t *testing.T, n1 Node, n2 Node) {
|
||||||
|
|
||||||
case ReturnNodeType:
|
case ReturnNodeType:
|
||||||
NodeEquality(t, n1.(*ReturnNode).value, n2.(*ReturnNode).value)
|
NodeEquality(t, n1.(*ReturnNode).value, n2.(*ReturnNode).value)
|
||||||
|
|
||||||
|
case AccessNodeType:
|
||||||
|
a1 := n1.(*AccessNode)
|
||||||
|
a2 := n2.(*AccessNode)
|
||||||
|
|
||||||
|
if a1.property != a2.property {
|
||||||
|
t.Errorf("Access node property does not match: .%s != .%s", a1.property, a2.property)
|
||||||
|
} else {
|
||||||
|
t.Logf("Access node property matches: .%s", a1.property)
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeEquality(t, a1.source, a2.source)
|
||||||
|
|
||||||
|
case ListNodeType:
|
||||||
|
l1 := n1.(*ListNode)
|
||||||
|
l2 := n2.(*ListNode)
|
||||||
|
|
||||||
|
if l1.content == nil && l2.content == nil {
|
||||||
|
// fine
|
||||||
|
t.Logf("Both content types are yet to be determined")
|
||||||
|
} else if l1.content != nil || l2.content != nil {
|
||||||
|
t.Errorf("one is nil, one is not")
|
||||||
|
} else if !l1.content.Matches(l2.content) {
|
||||||
|
t.Errorf("signature doesn't match")
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, v1 := range l1.items {
|
||||||
|
t.Logf("Checking item %d", i)
|
||||||
|
NodeEquality(t, v1, l2.items[i])
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
panic("unimplemented node equality")
|
panic("unimplemented node equality")
|
||||||
}
|
}
|
||||||
|
|
@ -818,7 +864,7 @@ func SerializeTokens(tokens []Token) string {
|
||||||
out.WriteString("!")
|
out.WriteString("!")
|
||||||
case TokenSemicolon:
|
case TokenSemicolon:
|
||||||
out.WriteString(";")
|
out.WriteString(";")
|
||||||
case TokenNumber:
|
case TokenFloat:
|
||||||
out.WriteString(token.Lexeme)
|
out.WriteString(token.Lexeme)
|
||||||
case TokenString:
|
case TokenString:
|
||||||
out.WriteString(fmt.Sprintf("\"%s\"", token.Lexeme))
|
out.WriteString(fmt.Sprintf("\"%s\"", token.Lexeme))
|
||||||
|
|
@ -845,7 +891,7 @@ func SerializeTokens(tokens []Token) string {
|
||||||
case TokenNil:
|
case TokenNil:
|
||||||
out.WriteString("nil")
|
out.WriteString("nil")
|
||||||
case TokenFunc:
|
case TokenFunc:
|
||||||
out.WriteString("func")
|
out.WriteString("fn")
|
||||||
case TokenReturn:
|
case TokenReturn:
|
||||||
out.WriteString("return ")
|
out.WriteString("return ")
|
||||||
case TokenWhile:
|
case TokenWhile:
|
||||||
|
|
@ -904,10 +950,6 @@ func TestParser_Parse(t *testing.T) {
|
||||||
tokenData := GetTokenTestData()
|
tokenData := GetTokenTestData()
|
||||||
|
|
||||||
for name, data := range tokenData {
|
for name, data := range tokenData {
|
||||||
if name != "empty_block" && name != "lambda" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
t.Logf("Initializing parser")
|
t.Logf("Initializing parser")
|
||||||
p := NewParser("", []string{}, data.tokens)
|
p := NewParser("", []string{}, data.tokens)
|
||||||
|
|
@ -916,7 +958,7 @@ func TestParser_Parse(t *testing.T) {
|
||||||
tree, err := p.Parse("")
|
tree, err := p.Parse("")
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Unexpected error(s): %s", err.(ParsingError).Format())
|
t.Fatalf("Unexpected error(s): %s", err.(ParsingError).Description)
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Logf("Checking parsed tree")
|
t.Logf("Checking parsed tree")
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,10 @@ type Stack[T any] struct {
|
||||||
items []T
|
items []T
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStack[T any](capacity Pos) *Stack[T] {
|
func NewStack[T any](maxCapacity Pos) *Stack[T] {
|
||||||
return &Stack[T]{
|
return &Stack[T]{
|
||||||
items: make([]T, 16),
|
items: make([]T, min(maxCapacity, 16)),
|
||||||
Capacity: capacity,
|
Capacity: maxCapacity,
|
||||||
Current: 0,
|
Current: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,8 @@ type Type int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
TypeString Type = iota
|
TypeString Type = iota
|
||||||
TypeNumber
|
TypeInteger
|
||||||
|
TypeFloat
|
||||||
TypeBoolean
|
TypeBoolean
|
||||||
TypeNil
|
TypeNil
|
||||||
TypeList
|
TypeList
|
||||||
|
|
@ -24,8 +25,10 @@ func (t Type) String() string {
|
||||||
switch t {
|
switch t {
|
||||||
case TypeString:
|
case TypeString:
|
||||||
return "string"
|
return "string"
|
||||||
case TypeNumber:
|
case TypeInteger:
|
||||||
return "number"
|
return "integer"
|
||||||
|
case TypeFloat:
|
||||||
|
return "float"
|
||||||
case TypeBoolean:
|
case TypeBoolean:
|
||||||
return "boolean"
|
return "boolean"
|
||||||
case TypeNil:
|
case TypeNil:
|
||||||
|
|
@ -51,8 +54,10 @@ func SignatureOf(v Value) TypeSignature {
|
||||||
switch t := v.(type) {
|
switch t := v.(type) {
|
||||||
case *StringValue:
|
case *StringValue:
|
||||||
return &StringSignature{}
|
return &StringSignature{}
|
||||||
case *NumberValue:
|
case *FloatValue:
|
||||||
return &NumberSignature{}
|
return &FloatSignature{}
|
||||||
|
case *IntegerValue:
|
||||||
|
return &IntegerSignature{}
|
||||||
case *BoolValue:
|
case *BoolValue:
|
||||||
return &BooleanSignature{}
|
return &BooleanSignature{}
|
||||||
case *ListValue:
|
case *ListValue:
|
||||||
|
|
@ -138,22 +143,40 @@ func (*StringSignature) String() string {
|
||||||
return "string"
|
return "string"
|
||||||
}
|
}
|
||||||
|
|
||||||
type NumberSignature struct{}
|
type FloatSignature struct{}
|
||||||
|
|
||||||
func (*NumberSignature) Type() Type {
|
func (*FloatSignature) Type() Type {
|
||||||
return TypeNumber
|
return TypeFloat
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *NumberSignature) Matches(other TypeSignature) bool {
|
func (s *FloatSignature) Matches(other TypeSignature) bool {
|
||||||
if other.Type() == TypeComposite {
|
if other.Type() == TypeComposite {
|
||||||
return other.Matches(s)
|
return other.Matches(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
return other.Type() == TypeAny || other.Type() == TypeNumber
|
return other.Type() == TypeAny || other.Type() == TypeFloat
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*NumberSignature) String() string {
|
func (*FloatSignature) String() string {
|
||||||
return "number"
|
return "float"
|
||||||
|
}
|
||||||
|
|
||||||
|
type IntegerSignature struct{}
|
||||||
|
|
||||||
|
func (*IntegerSignature) Type() Type {
|
||||||
|
return TypeInteger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *IntegerSignature) Matches(other TypeSignature) bool {
|
||||||
|
if other.Type() == TypeComposite {
|
||||||
|
return other.Matches(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
return other.Type() == TypeAny || other.Type() == TypeInteger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*IntegerSignature) String() string {
|
||||||
|
return "int"
|
||||||
}
|
}
|
||||||
|
|
||||||
type BooleanSignature struct{}
|
type BooleanSignature struct{}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package core
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math/big"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
@ -13,7 +13,8 @@ type ValueType int
|
||||||
const (
|
const (
|
||||||
NilValueType ValueType = iota
|
NilValueType ValueType = iota
|
||||||
BoolValueType
|
BoolValueType
|
||||||
NumberValueType
|
FloatValueType
|
||||||
|
IntegerValueType
|
||||||
StringValueType
|
StringValueType
|
||||||
ListValueType
|
ListValueType
|
||||||
ObjectValueType
|
ObjectValueType
|
||||||
|
|
@ -30,8 +31,10 @@ func (v ValueType) String() string {
|
||||||
return "bool"
|
return "bool"
|
||||||
case ObjectValueType:
|
case ObjectValueType:
|
||||||
return "object"
|
return "object"
|
||||||
case NumberValueType:
|
case FloatValueType:
|
||||||
return "number"
|
return "float"
|
||||||
|
case IntegerValueType:
|
||||||
|
return "int"
|
||||||
case StringValueType:
|
case StringValueType:
|
||||||
return "string"
|
return "string"
|
||||||
case ListValueType:
|
case ListValueType:
|
||||||
|
|
@ -57,11 +60,15 @@ func GoToValue(gov interface{}) Value {
|
||||||
v,
|
v,
|
||||||
}
|
}
|
||||||
case int:
|
case int:
|
||||||
return &NumberValue{
|
return &IntegerValue{
|
||||||
float64(v),
|
new(big.Int).SetInt64(int64(v)),
|
||||||
|
}
|
||||||
|
case *big.Int:
|
||||||
|
return &IntegerValue{
|
||||||
|
v,
|
||||||
}
|
}
|
||||||
case float64:
|
case float64:
|
||||||
return &NumberValue{
|
return &FloatValue{
|
||||||
v,
|
v,
|
||||||
}
|
}
|
||||||
case string:
|
case string:
|
||||||
|
|
@ -259,40 +266,71 @@ func (v *ObjectValue) Clone() Value {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NumberValue Integer or floating-point values
|
// FloatValue floating-point values
|
||||||
type NumberValue struct {
|
type FloatValue struct {
|
||||||
Number float64
|
Number float64
|
||||||
}
|
}
|
||||||
|
|
||||||
const NumberSize int = 64
|
const FloatSize int = 64
|
||||||
|
|
||||||
func (v *NumberValue) Type() ValueType {
|
func (v *FloatValue) Type() ValueType {
|
||||||
return NumberValueType
|
return FloatValueType
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *NumberValue) String() string {
|
func (v *FloatValue) String() string {
|
||||||
return strconv.FormatFloat(v.Number, 'g', -1, NumberSize)
|
return strconv.FormatFloat(v.Number, 'g', -1, FloatSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *NumberValue) DebugString() string {
|
func (v *FloatValue) DebugString() string {
|
||||||
return v.String()
|
return v.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *NumberValue) Equals(other Value) bool {
|
func (v *FloatValue) Equals(other Value) bool {
|
||||||
return other.Type() == NumberValueType && other.(*NumberValue).Number == v.Number
|
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?
|
// TODO maybe add standard functions for number values?
|
||||||
return nil, errors.New("numbers have no properties")
|
return nil, errors.New("numbers have no properties")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *NumberValue) Clone() Value {
|
func (v *FloatValue) Clone() Value {
|
||||||
return &NumberValue{
|
return &FloatValue{
|
||||||
v.Number,
|
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 {
|
type StringValue struct {
|
||||||
Text string
|
Text string
|
||||||
}
|
}
|
||||||
|
|
@ -348,7 +386,7 @@ var StringPrototype = map[string]*BuiltinFunctionValue{
|
||||||
Name: "length",
|
Name: "length",
|
||||||
Signature: &FunctionSignature{
|
Signature: &FunctionSignature{
|
||||||
[]TypeSignature{},
|
[]TypeSignature{},
|
||||||
&NumberSignature{},
|
&IntegerSignature{},
|
||||||
},
|
},
|
||||||
F: func(vm *VM, this Value, _ []Value) (Value, error) {
|
F: func(vm *VM, this Value, _ []Value) (Value, error) {
|
||||||
return GoToValue(len(this.(*StringValue).Text)), nil
|
return GoToValue(len(this.(*StringValue).Text)), nil
|
||||||
|
|
@ -357,11 +395,11 @@ var StringPrototype = map[string]*BuiltinFunctionValue{
|
||||||
"at": {
|
"at": {
|
||||||
Name: "at",
|
Name: "at",
|
||||||
Signature: &FunctionSignature{
|
Signature: &FunctionSignature{
|
||||||
[]TypeSignature{&NumberSignature{}},
|
[]TypeSignature{&IntegerSignature{}},
|
||||||
&StringSignature{},
|
&StringSignature{},
|
||||||
},
|
},
|
||||||
F: func(vm *VM, this Value, args []Value) (Value, error) {
|
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) {
|
if i < 0 || i >= len(this.(*StringValue).Text) {
|
||||||
return nil, errors.New("index is out of range")
|
return nil, errors.New("index is out of range")
|
||||||
|
|
@ -450,13 +488,13 @@ var ListPrototype = map[string]*BuiltinFunctionValue{
|
||||||
"at",
|
"at",
|
||||||
&FunctionSignature{
|
&FunctionSignature{
|
||||||
[]TypeSignature{
|
[]TypeSignature{
|
||||||
&NumberSignature{},
|
&IntegerSignature{},
|
||||||
},
|
},
|
||||||
&InnerSignature{},
|
&InnerSignature{},
|
||||||
},
|
},
|
||||||
func(_ *VM, this Value, p []Value) (Value, error) {
|
func(_ *VM, this Value, p []Value) (Value, error) {
|
||||||
items := this.(*ListValue).Items
|
items := this.(*ListValue).Items
|
||||||
index := int(p[0].(*NumberValue).Number)
|
index := int(p[0].(*IntegerValue).Number.Int64())
|
||||||
|
|
||||||
if index >= len(items) {
|
if index >= len(items) {
|
||||||
return nil, errors.New(fmt.Sprintf("list index %x out of range", index))
|
return nil, errors.New(fmt.Sprintf("list index %x out of range", index))
|
||||||
|
|
@ -471,13 +509,13 @@ var ListPrototype = map[string]*BuiltinFunctionValue{
|
||||||
"put",
|
"put",
|
||||||
&FunctionSignature{
|
&FunctionSignature{
|
||||||
[]TypeSignature{
|
[]TypeSignature{
|
||||||
&NumberSignature{}, &InnerSignature{},
|
&FloatSignature{}, &InnerSignature{},
|
||||||
},
|
},
|
||||||
&NilSignature{},
|
&NilSignature{},
|
||||||
},
|
},
|
||||||
func(_ *VM, this Value, args []Value) (Value, error) {
|
func(_ *VM, this Value, args []Value) (Value, error) {
|
||||||
l := this.(*ListValue)
|
l := this.(*ListValue)
|
||||||
i := int(args[0].(*NumberValue).Number)
|
i := int(args[0].(*FloatValue).Number)
|
||||||
v := args[1]
|
v := args[1]
|
||||||
|
|
||||||
// bounds check
|
// bounds check
|
||||||
|
|
@ -496,7 +534,7 @@ var ListPrototype = map[string]*BuiltinFunctionValue{
|
||||||
"length",
|
"length",
|
||||||
&FunctionSignature{
|
&FunctionSignature{
|
||||||
[]TypeSignature{},
|
[]TypeSignature{},
|
||||||
&NumberSignature{},
|
&IntegerSignature{},
|
||||||
},
|
},
|
||||||
func(_ *VM, this Value, _ []Value) (Value, error) {
|
func(_ *VM, this Value, _ []Value) (Value, error) {
|
||||||
return GoToValue(len(this.(*ListValue).Items)), nil
|
return GoToValue(len(this.(*ListValue).Items)), nil
|
||||||
|
|
|
||||||
|
|
@ -21,15 +21,21 @@ func CompareValues(t *testing.T, got Value, want Value) {
|
||||||
} else {
|
} else {
|
||||||
t.Logf("Both are same boolean (%s)", want.(*BoolValue).String())
|
t.Logf("Both are same boolean (%s)", want.(*BoolValue).String())
|
||||||
}
|
}
|
||||||
case NumberValueType:
|
case FloatValueType:
|
||||||
if got.(*NumberValue).Number != want.(*NumberValue).Number {
|
if got.(*FloatValue).Number != want.(*FloatValue).Number {
|
||||||
t.Errorf("number value mismatch: got %v, want %v", got.(*NumberValue), want.(*NumberValue))
|
t.Errorf("number value mismatch: got %v, want %v", got.(*FloatValue), want.(*FloatValue))
|
||||||
} else {
|
} else {
|
||||||
t.Logf("Both are same number (%s)", got.(*NumberValue).String())
|
t.Logf("Both are same number (%s)", got.(*FloatValue).String())
|
||||||
|
}
|
||||||
|
case IntegerValueType:
|
||||||
|
if got.(*IntegerValue).Number.String() != want.(*IntegerValue).Number.String() {
|
||||||
|
t.Errorf("number value mismatch: got %v, want %v", got.(*IntegerValue), want.(*IntegerValue))
|
||||||
|
} else {
|
||||||
|
t.Logf("Both are same number (%s)", got.(*IntegerValue).String())
|
||||||
}
|
}
|
||||||
case StringValueType:
|
case StringValueType:
|
||||||
if got.(*StringValue).Text != want.(*StringValue).Text {
|
if got.(*StringValue).Text != want.(*StringValue).Text {
|
||||||
t.Errorf("string value mismatch: got %v, want %v", got.(*StringValue), want.(*StringValue))
|
t.Errorf("string value mismatch: got %s, want %s", got.(*StringValue), want.(*StringValue))
|
||||||
} else {
|
} else {
|
||||||
t.Logf("Both are same string (%s)", got.(*StringValue).String())
|
t.Logf("Both are same string (%s)", got.(*StringValue).String())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
333
core/vm.go
333
core/vm.go
|
|
@ -7,7 +7,9 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"math"
|
"math"
|
||||||
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -20,30 +22,52 @@ const (
|
||||||
// InstructionPop pop and delete the first item on the stack
|
// InstructionPop pop and delete the first item on the stack
|
||||||
InstructionPop
|
InstructionPop
|
||||||
|
|
||||||
// InstructionAdd pop two and add them
|
// InstructionAddFloat pop two floats and add them
|
||||||
InstructionAdd
|
InstructionAddFloat
|
||||||
// InstructionSub pop two and subtract the second from the first
|
// InstructionSubFloat pop two floats and subtract the second from the first
|
||||||
InstructionSub
|
InstructionSubFloat
|
||||||
// InstructionMul pop two and multiply them
|
// InstructionMulFloat pop two floats and multiply them
|
||||||
InstructionMul
|
InstructionMulFloat
|
||||||
// InstructionDiv pop two and divide the second by the first
|
// InstructionDivFloat pop two floats and divide the second by the first
|
||||||
InstructionDiv
|
InstructionDivFloat
|
||||||
// InstructionNegate negate the value; if it was positive, make it negative, and vice versa.
|
// InstructionNegateFloat negate the float; if it was positive, make it negative, and vice versa.
|
||||||
InstructionNegate
|
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 whether the two top values on the stack are equal
|
||||||
InstructionEquals
|
InstructionEquals
|
||||||
// InstructionNotEqual whether the two top values on the stack are not equal
|
// InstructionNotEqual whether the two top values on the stack are not equal
|
||||||
InstructionNotEqual
|
InstructionNotEqual
|
||||||
// InstructionNot inverts boolean (true => false, false => true)
|
// InstructionNot inverts boolean (true => false, false => true)
|
||||||
InstructionNot
|
InstructionNot
|
||||||
// InstructionLess pops two from stack, pushes whether the lowest is less than the highest
|
|
||||||
InstructionLess
|
// InstructionLessFloat pops two from stack, pushes whether the lowest is less than the highest
|
||||||
// InstructionLessOrEqual pops two from stack, pushes whether the lowest is less or equal than the highest
|
InstructionLessFloat
|
||||||
InstructionLessOrEqual
|
// InstructionLessOrEqualFloat pops two from stack, pushes whether the lowest is less or equal than the highest
|
||||||
// InstructionGreater pops two from stack, pushes whether the lowest is greater than the highest
|
InstructionLessOrEqualFloat
|
||||||
InstructionGreater
|
// InstructionGreaterFloat pops two from stack, pushes whether the lowest is greater than the highest
|
||||||
// InstructionGreaterOrEqual pops two from stack, pushes whether the lowest is greater or equal than the highest
|
InstructionGreaterFloat
|
||||||
InstructionGreaterOrEqual
|
// 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 gets a property from a value, and pops it onto the stack
|
||||||
InstructionAccessProperty
|
InstructionAccessProperty
|
||||||
|
|
@ -116,30 +140,48 @@ func (b Bytecode) String() string {
|
||||||
return "RETURN"
|
return "RETURN"
|
||||||
case InstructionPop:
|
case InstructionPop:
|
||||||
return "POP"
|
return "POP"
|
||||||
case InstructionAdd:
|
case InstructionAddFloat:
|
||||||
return "ADD"
|
return "ADD_FLOAT"
|
||||||
case InstructionSub:
|
case InstructionSubFloat:
|
||||||
return "SUB"
|
return "SUB_FLOAT"
|
||||||
case InstructionMul:
|
case InstructionMulFloat:
|
||||||
return "MUL"
|
return "MUL_FLOAT"
|
||||||
case InstructionDiv:
|
case InstructionDivFloat:
|
||||||
return "DIV"
|
return "DIV_FLOAT"
|
||||||
case InstructionNegate:
|
case InstructionNegateFloat:
|
||||||
return "NEGATE"
|
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:
|
case InstructionEquals:
|
||||||
return "EQUALS"
|
return "EQUALS"
|
||||||
case InstructionNotEqual:
|
case InstructionNotEqual:
|
||||||
return "NOT_EQUALS"
|
return "NOT_EQUALS"
|
||||||
case InstructionNot:
|
case InstructionNot:
|
||||||
return "NOT"
|
return "NOT"
|
||||||
case InstructionLess:
|
case InstructionLessFloat:
|
||||||
return "LESS"
|
return "LESS_FLOAT"
|
||||||
case InstructionLessOrEqual:
|
case InstructionLessOrEqualFloat:
|
||||||
return "LESS_OR_EQUAL"
|
return "LESS_OR_EQUAL_FLOAT"
|
||||||
case InstructionGreater:
|
case InstructionGreaterFloat:
|
||||||
return "GREATER_OR_EQUAL"
|
return "GREATER_FLOAT"
|
||||||
case InstructionGreaterOrEqual:
|
case InstructionGreaterOrEqualFloat:
|
||||||
return "GREATER_OR_EQUAL"
|
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:
|
case InstructionJump:
|
||||||
return "JUMP"
|
return "JUMP"
|
||||||
case InstructionJumpFalse:
|
case InstructionJumpFalse:
|
||||||
|
|
@ -232,7 +274,7 @@ func NewChunk(bytecode []Bytecode, constants []Value) *Chunk {
|
||||||
func RegisterGOBTypes() {
|
func RegisterGOBTypes() {
|
||||||
gob.Register(&StringValue{""})
|
gob.Register(&StringValue{""})
|
||||||
gob.Register(&BoolValue{false})
|
gob.Register(&BoolValue{false})
|
||||||
gob.Register(&NumberValue{0})
|
gob.Register(&FloatValue{0})
|
||||||
gob.Register(&FunctionValue{
|
gob.Register(&FunctionValue{
|
||||||
Name: "",
|
Name: "",
|
||||||
Params: nil,
|
Params: nil,
|
||||||
|
|
@ -241,7 +283,7 @@ func RegisterGOBTypes() {
|
||||||
|
|
||||||
// Signatures
|
// Signatures
|
||||||
gob.Register(&NilSignature{})
|
gob.Register(&NilSignature{})
|
||||||
gob.Register(&NumberSignature{})
|
gob.Register(&FloatSignature{})
|
||||||
gob.Register(&StringSignature{})
|
gob.Register(&StringSignature{})
|
||||||
gob.Register(&FunctionSignature{})
|
gob.Register(&FunctionSignature{})
|
||||||
gob.Register(&ListSignature{})
|
gob.Register(&ListSignature{})
|
||||||
|
|
@ -368,12 +410,12 @@ var DefaultGlobals = map[string]Value{
|
||||||
"char": &BuiltinFunctionValue{
|
"char": &BuiltinFunctionValue{
|
||||||
"char",
|
"char",
|
||||||
&FunctionSignature{
|
&FunctionSignature{
|
||||||
[]TypeSignature{&NumberSignature{}},
|
[]TypeSignature{&IntegerSignature{}},
|
||||||
&StringSignature{},
|
&StringSignature{},
|
||||||
},
|
},
|
||||||
func(vm *VM, this Value, args []Value) (Value, error) {
|
func(vm *VM, this Value, args []Value) (Value, error) {
|
||||||
n := args[0].(*NumberValue).Number
|
n := args[0].(*IntegerValue).Number
|
||||||
b := byte(n)
|
b := n.Bytes()[0]
|
||||||
|
|
||||||
return &StringValue{
|
return &StringValue{
|
||||||
string([]byte{b}),
|
string([]byte{b}),
|
||||||
|
|
@ -383,16 +425,16 @@ var DefaultGlobals = map[string]Value{
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
"byte": &BuiltinFunctionValue{
|
"byte": &BuiltinFunctionValue{
|
||||||
"char",
|
"byte",
|
||||||
&FunctionSignature{
|
&FunctionSignature{
|
||||||
[]TypeSignature{&StringSignature{}},
|
[]TypeSignature{&StringSignature{}},
|
||||||
&NumberSignature{},
|
&IntegerSignature{},
|
||||||
},
|
},
|
||||||
func(vm *VM, this Value, args []Value) (Value, error) {
|
func(vm *VM, this Value, args []Value) (Value, error) {
|
||||||
s := args[0].(*StringValue).Text
|
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,
|
nil,
|
||||||
true,
|
true,
|
||||||
|
|
@ -453,6 +495,66 @@ var DefaultGlobals = map[string]Value{
|
||||||
nil,
|
nil,
|
||||||
true,
|
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{
|
"type": &BuiltinFunctionValue{
|
||||||
Name: "type",
|
Name: "type",
|
||||||
Signature: &FunctionSignature{
|
Signature: &FunctionSignature{
|
||||||
|
|
@ -470,11 +572,11 @@ var DefaultGlobals = map[string]Value{
|
||||||
"exit": &BuiltinFunctionValue{
|
"exit": &BuiltinFunctionValue{
|
||||||
"exit",
|
"exit",
|
||||||
&FunctionSignature{
|
&FunctionSignature{
|
||||||
[]TypeSignature{&NumberSignature{}},
|
[]TypeSignature{&FloatSignature{}},
|
||||||
&NilSignature{},
|
&NilSignature{},
|
||||||
},
|
},
|
||||||
func(vm *VM, this Value, args []Value) (Value, error) {
|
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
|
return &NilValue{}, nil
|
||||||
},
|
},
|
||||||
nil,
|
nil,
|
||||||
|
|
@ -483,11 +585,11 @@ var DefaultGlobals = map[string]Value{
|
||||||
"floor": &BuiltinFunctionValue{
|
"floor": &BuiltinFunctionValue{
|
||||||
"floor",
|
"floor",
|
||||||
&FunctionSignature{
|
&FunctionSignature{
|
||||||
[]TypeSignature{&NumberSignature{}},
|
[]TypeSignature{&FloatSignature{}},
|
||||||
&NumberSignature{},
|
&FloatSignature{},
|
||||||
},
|
},
|
||||||
func(vm *VM, this Value, args []Value) (Value, error) {
|
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,
|
nil,
|
||||||
true,
|
true,
|
||||||
|
|
@ -495,11 +597,11 @@ var DefaultGlobals = map[string]Value{
|
||||||
"ceil": &BuiltinFunctionValue{
|
"ceil": &BuiltinFunctionValue{
|
||||||
"ceil",
|
"ceil",
|
||||||
&FunctionSignature{
|
&FunctionSignature{
|
||||||
[]TypeSignature{&NumberSignature{}},
|
[]TypeSignature{&FloatSignature{}},
|
||||||
&NumberSignature{},
|
&FloatSignature{},
|
||||||
},
|
},
|
||||||
func(vm *VM, this Value, args []Value) (Value, error) {
|
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,
|
nil,
|
||||||
true,
|
true,
|
||||||
|
|
@ -507,14 +609,14 @@ var DefaultGlobals = map[string]Value{
|
||||||
"roundd": &BuiltinFunctionValue{
|
"roundd": &BuiltinFunctionValue{
|
||||||
"roundd",
|
"roundd",
|
||||||
&FunctionSignature{
|
&FunctionSignature{
|
||||||
[]TypeSignature{&NumberSignature{}, &NumberSignature{}},
|
[]TypeSignature{&FloatSignature{}, &FloatSignature{}},
|
||||||
&NumberSignature{},
|
&FloatSignature{},
|
||||||
},
|
},
|
||||||
func(vm *VM, this Value, args []Value) (Value, error) {
|
func(vm *VM, this Value, args []Value) (Value, error) {
|
||||||
x := args[0].(*NumberValue).Number
|
x := args[0].(*FloatValue).Number
|
||||||
decimals := args[1].(*NumberValue).Number
|
decimals := args[1].(*FloatValue).Number
|
||||||
multiplier := math.Pow(10, decimals)
|
multiplier := math.Pow(10, decimals)
|
||||||
return &NumberValue{math.Round(x*multiplier) / multiplier}, nil
|
return &FloatValue{math.Round(x*multiplier) / multiplier}, nil
|
||||||
},
|
},
|
||||||
nil,
|
nil,
|
||||||
true,
|
true,
|
||||||
|
|
@ -568,34 +670,63 @@ func (vm *VM) Next() bool {
|
||||||
case InstructionConstant:
|
case InstructionConstant:
|
||||||
vm.stack.Push(vm.ReadConstant())
|
vm.stack.Push(vm.ReadConstant())
|
||||||
|
|
||||||
case InstructionAdd:
|
case InstructionAddFloat:
|
||||||
r := vm.stack.Pop().(*NumberValue).Number
|
r := vm.stack.Pop().(*FloatValue).Number
|
||||||
l := vm.stack.Pop().(*NumberValue).Number
|
l := vm.stack.Pop().(*FloatValue).Number
|
||||||
|
|
||||||
vm.stack.Push(&NumberValue{l + r})
|
vm.stack.Push(&FloatValue{l + r})
|
||||||
|
|
||||||
case InstructionSub:
|
case InstructionSubFloat:
|
||||||
r := vm.stack.Pop().(*NumberValue).Number
|
r := vm.stack.Pop().(*FloatValue).Number
|
||||||
l := vm.stack.Pop().(*NumberValue).Number
|
l := vm.stack.Pop().(*FloatValue).Number
|
||||||
|
|
||||||
vm.stack.Push(&NumberValue{l - r})
|
vm.stack.Push(&FloatValue{l - r})
|
||||||
|
|
||||||
case InstructionMul:
|
case InstructionMulFloat:
|
||||||
r := vm.stack.Pop().(*NumberValue).Number
|
r := vm.stack.Pop().(*FloatValue).Number
|
||||||
l := vm.stack.Pop().(*NumberValue).Number
|
l := vm.stack.Pop().(*FloatValue).Number
|
||||||
|
|
||||||
vm.stack.Push(&NumberValue{l * r})
|
vm.stack.Push(&FloatValue{l * r})
|
||||||
|
|
||||||
case InstructionDiv:
|
case InstructionDivFloat:
|
||||||
r := vm.stack.Pop().(*NumberValue).Number
|
r := vm.stack.Pop().(*FloatValue).Number
|
||||||
l := vm.stack.Pop().(*NumberValue).Number
|
l := vm.stack.Pop().(*FloatValue).Number
|
||||||
|
|
||||||
vm.stack.Push(&NumberValue{l / r})
|
vm.stack.Push(&FloatValue{l / r})
|
||||||
|
|
||||||
case InstructionNegate:
|
case InstructionNegateFloat:
|
||||||
v := vm.stack.Pop().(*NumberValue).Number
|
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:
|
case InstructionEquals:
|
||||||
vm.stack.Push(
|
vm.stack.Push(
|
||||||
|
|
@ -621,30 +752,54 @@ func (vm *VM) Next() bool {
|
||||||
l := vm.stack.Pop().(*BoolValue).Boolean
|
l := vm.stack.Pop().(*BoolValue).Boolean
|
||||||
vm.stack.Push(&BoolValue{l || r})
|
vm.stack.Push(&BoolValue{l || r})
|
||||||
|
|
||||||
case InstructionLess:
|
case InstructionLessFloat:
|
||||||
r := vm.stack.Pop().(*NumberValue).Number
|
r := vm.stack.Pop().(*FloatValue).Number
|
||||||
l := vm.stack.Pop().(*NumberValue).Number
|
l := vm.stack.Pop().(*FloatValue).Number
|
||||||
|
|
||||||
vm.stack.Push(&BoolValue{l < r})
|
vm.stack.Push(&BoolValue{l < r})
|
||||||
|
|
||||||
case InstructionLessOrEqual:
|
case InstructionLessOrEqualFloat:
|
||||||
r := vm.stack.Pop().(*NumberValue).Number
|
r := vm.stack.Pop().(*FloatValue).Number
|
||||||
l := vm.stack.Pop().(*NumberValue).Number
|
l := vm.stack.Pop().(*FloatValue).Number
|
||||||
|
|
||||||
vm.stack.Push(&BoolValue{l <= r})
|
vm.stack.Push(&BoolValue{l <= r})
|
||||||
|
|
||||||
case InstructionGreater:
|
case InstructionGreaterFloat:
|
||||||
r := vm.stack.Pop().(*NumberValue).Number
|
r := vm.stack.Pop().(*FloatValue).Number
|
||||||
l := vm.stack.Pop().(*NumberValue).Number
|
l := vm.stack.Pop().(*FloatValue).Number
|
||||||
|
|
||||||
vm.stack.Push(&BoolValue{l > r})
|
vm.stack.Push(&BoolValue{l > r})
|
||||||
|
|
||||||
case InstructionGreaterOrEqual:
|
case InstructionGreaterOrEqualFloat:
|
||||||
r := vm.stack.Pop().(*NumberValue).Number
|
r := vm.stack.Pop().(*FloatValue).Number
|
||||||
l := vm.stack.Pop().(*NumberValue).Number
|
l := vm.stack.Pop().(*FloatValue).Number
|
||||||
|
|
||||||
vm.stack.Push(&BoolValue{l >= r})
|
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:
|
case InstructionCall:
|
||||||
v := vm.stack.Pop()
|
v := vm.stack.Pop()
|
||||||
switch f := v.(type) {
|
switch f := v.(type) {
|
||||||
|
|
|
||||||
126
core/vm_test.go
126
core/vm_test.go
|
|
@ -49,7 +49,7 @@ func TestNewVM(t *testing.T) {
|
||||||
chunk := NewChunk([]Bytecode{
|
chunk := NewChunk([]Bytecode{
|
||||||
InstructionConstant, 0,
|
InstructionConstant, 0,
|
||||||
}, []Value{
|
}, []Value{
|
||||||
&NumberValue{0},
|
&FloatValue{0},
|
||||||
})
|
})
|
||||||
stackSize := Pos(256)
|
stackSize := Pos(256)
|
||||||
callstackSize := Pos(256)
|
callstackSize := Pos(256)
|
||||||
|
|
@ -104,13 +104,13 @@ func GetExecutionTestData() map[string]struct {
|
||||||
NewChunk([]Bytecode{
|
NewChunk([]Bytecode{
|
||||||
InstructionConstant, 0,
|
InstructionConstant, 0,
|
||||||
InstructionConstant, 1,
|
InstructionConstant, 1,
|
||||||
InstructionAdd,
|
InstructionAddFloat,
|
||||||
},
|
},
|
||||||
[]Value{
|
[]Value{
|
||||||
&NumberValue{1}, &NumberValue{2},
|
&FloatValue{1}, &FloatValue{2},
|
||||||
}),
|
}),
|
||||||
[]Value{
|
[]Value{
|
||||||
&NumberValue{3},
|
&FloatValue{3},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"push_constant": {
|
"push_constant": {
|
||||||
|
|
@ -119,11 +119,11 @@ func GetExecutionTestData() map[string]struct {
|
||||||
InstructionConstant, 0,
|
InstructionConstant, 0,
|
||||||
},
|
},
|
||||||
[]Value{
|
[]Value{
|
||||||
&NumberValue{1},
|
&FloatValue{1},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
[]Value{
|
[]Value{
|
||||||
&NumberValue{1},
|
&FloatValue{1},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"push_true": {
|
"push_true": {
|
||||||
|
|
@ -172,20 +172,20 @@ func GetExecutionTestData() map[string]struct {
|
||||||
[]Bytecode{
|
[]Bytecode{
|
||||||
InstructionConstant, 0,
|
InstructionConstant, 0,
|
||||||
InstructionConstant, 1,
|
InstructionConstant, 1,
|
||||||
InstructionAdd,
|
InstructionAddFloat,
|
||||||
InstructionConstant, 2,
|
InstructionConstant, 2,
|
||||||
InstructionMul,
|
InstructionMulFloat,
|
||||||
InstructionConstant, 3,
|
InstructionConstant, 3,
|
||||||
InstructionConstant, 0,
|
InstructionConstant, 0,
|
||||||
InstructionSub,
|
InstructionSubFloat,
|
||||||
InstructionDiv,
|
InstructionDivFloat,
|
||||||
},
|
},
|
||||||
[]Value{
|
[]Value{
|
||||||
&NumberValue{2}, &NumberValue{1}, &NumberValue{5}, &NumberValue{6},
|
&FloatValue{2}, &FloatValue{1}, &FloatValue{5}, &FloatValue{6},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
[]Value{
|
[]Value{
|
||||||
&NumberValue{3.75},
|
&FloatValue{3.75},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"equality_true": {
|
"equality_true": {
|
||||||
|
|
@ -196,7 +196,7 @@ func GetExecutionTestData() map[string]struct {
|
||||||
InstructionEquals,
|
InstructionEquals,
|
||||||
},
|
},
|
||||||
[]Value{
|
[]Value{
|
||||||
&NumberValue{1},
|
&FloatValue{1},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
[]Value{
|
[]Value{
|
||||||
|
|
@ -211,7 +211,7 @@ func GetExecutionTestData() map[string]struct {
|
||||||
InstructionEquals,
|
InstructionEquals,
|
||||||
},
|
},
|
||||||
[]Value{
|
[]Value{
|
||||||
&NumberValue{1}, &NumberValue{2},
|
&FloatValue{1}, &FloatValue{2},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
[]Value{
|
[]Value{
|
||||||
|
|
@ -226,7 +226,7 @@ func GetExecutionTestData() map[string]struct {
|
||||||
InstructionNotEqual,
|
InstructionNotEqual,
|
||||||
},
|
},
|
||||||
[]Value{
|
[]Value{
|
||||||
&NumberValue{1},
|
&FloatValue{1},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
[]Value{
|
[]Value{
|
||||||
|
|
@ -241,7 +241,7 @@ func GetExecutionTestData() map[string]struct {
|
||||||
InstructionNotEqual,
|
InstructionNotEqual,
|
||||||
},
|
},
|
||||||
[]Value{
|
[]Value{
|
||||||
&NumberValue{1}, &NumberValue{2},
|
&FloatValue{1}, &FloatValue{2},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
[]Value{
|
[]Value{
|
||||||
|
|
@ -280,11 +280,11 @@ func GetExecutionTestData() map[string]struct {
|
||||||
InstructionConstant, 1, // should execute
|
InstructionConstant, 1, // should execute
|
||||||
},
|
},
|
||||||
[]Value{
|
[]Value{
|
||||||
&NumberValue{0}, &NumberValue{1},
|
&FloatValue{0}, &FloatValue{1},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
[]Value{
|
[]Value{
|
||||||
&NumberValue{1},
|
&FloatValue{1},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"jump_false/false": {
|
"jump_false/false": {
|
||||||
|
|
@ -296,11 +296,11 @@ func GetExecutionTestData() map[string]struct {
|
||||||
InstructionConstant, 1, // should execute
|
InstructionConstant, 1, // should execute
|
||||||
},
|
},
|
||||||
[]Value{
|
[]Value{
|
||||||
&NumberValue{0}, &NumberValue{1},
|
&FloatValue{0}, &FloatValue{1},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
[]Value{
|
[]Value{
|
||||||
&NumberValue{1},
|
&FloatValue{1},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"jump_false/true": {
|
"jump_false/true": {
|
||||||
|
|
@ -312,11 +312,11 @@ func GetExecutionTestData() map[string]struct {
|
||||||
InstructionConstant, 1, // should execute
|
InstructionConstant, 1, // should execute
|
||||||
},
|
},
|
||||||
[]Value{
|
[]Value{
|
||||||
&NumberValue{0}, &NumberValue{1},
|
&FloatValue{0}, &FloatValue{1},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
[]Value{
|
[]Value{
|
||||||
&NumberValue{0}, &NumberValue{1},
|
&FloatValue{0}, &FloatValue{1},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"declare_local": {
|
"declare_local": {
|
||||||
|
|
@ -326,13 +326,13 @@ func GetExecutionTestData() map[string]struct {
|
||||||
InstructionDeclareLocal, 1,
|
InstructionDeclareLocal, 1,
|
||||||
},
|
},
|
||||||
[]Value{
|
[]Value{
|
||||||
&NumberValue{0}, &StringValue{"a"},
|
&FloatValue{0}, &StringValue{"a"},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
[]Value{
|
[]Value{
|
||||||
&VariableValue{
|
&VariableValue{
|
||||||
"a",
|
"a",
|
||||||
&NumberValue{0},
|
&FloatValue{0},
|
||||||
0,
|
0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -346,13 +346,13 @@ func GetExecutionTestData() map[string]struct {
|
||||||
InstructionSetLocal, 1, // reassign
|
InstructionSetLocal, 1, // reassign
|
||||||
},
|
},
|
||||||
[]Value{
|
[]Value{
|
||||||
&NumberValue{0}, &StringValue{"a"}, &NumberValue{1},
|
&FloatValue{0}, &StringValue{"a"}, &FloatValue{1},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
[]Value{
|
[]Value{
|
||||||
&VariableValue{
|
&VariableValue{
|
||||||
"a",
|
"a",
|
||||||
&NumberValue{1},
|
&FloatValue{1},
|
||||||
0,
|
0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -365,16 +365,16 @@ func GetExecutionTestData() map[string]struct {
|
||||||
InstructionGetLocal, 1, // reassign
|
InstructionGetLocal, 1, // reassign
|
||||||
},
|
},
|
||||||
[]Value{
|
[]Value{
|
||||||
&NumberValue{0}, &StringValue{"a"},
|
&FloatValue{0}, &StringValue{"a"},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
[]Value{
|
[]Value{
|
||||||
&VariableValue{
|
&VariableValue{
|
||||||
"a",
|
"a",
|
||||||
&NumberValue{0},
|
&FloatValue{0},
|
||||||
0,
|
0,
|
||||||
},
|
},
|
||||||
&NumberValue{0},
|
&FloatValue{0},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"get_reassigned_local": {
|
"get_reassigned_local": {
|
||||||
|
|
@ -388,17 +388,17 @@ func GetExecutionTestData() map[string]struct {
|
||||||
InstructionGetLocal, 1,
|
InstructionGetLocal, 1,
|
||||||
},
|
},
|
||||||
[]Value{
|
[]Value{
|
||||||
&NumberValue{0}, &StringValue{"a"}, &NumberValue{1},
|
&FloatValue{0}, &StringValue{"a"}, &FloatValue{1},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
[]Value{
|
[]Value{
|
||||||
&VariableValue{
|
&VariableValue{
|
||||||
"a",
|
"a",
|
||||||
&NumberValue{1},
|
&FloatValue{1},
|
||||||
0,
|
0,
|
||||||
},
|
},
|
||||||
&NumberValue{0},
|
&FloatValue{0},
|
||||||
&NumberValue{1},
|
&FloatValue{1},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"variable_scope": {
|
"variable_scope": {
|
||||||
|
|
@ -416,15 +416,15 @@ func GetExecutionTestData() map[string]struct {
|
||||||
InstructionAscend,
|
InstructionAscend,
|
||||||
},
|
},
|
||||||
[]Value{
|
[]Value{
|
||||||
&NumberValue{0}, &StringValue{"a"},
|
&FloatValue{0}, &StringValue{"a"},
|
||||||
&NumberValue{1}, &StringValue{"b"},
|
&FloatValue{1}, &StringValue{"b"},
|
||||||
&NumberValue{2}, &StringValue{"c"},
|
&FloatValue{2}, &StringValue{"c"},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
[]Value{
|
[]Value{
|
||||||
&VariableValue{
|
&VariableValue{
|
||||||
"a",
|
"a",
|
||||||
&NumberValue{0},
|
&FloatValue{0},
|
||||||
0,
|
0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -438,25 +438,25 @@ func GetExecutionTestData() map[string]struct {
|
||||||
InstructionCall,
|
InstructionCall,
|
||||||
},
|
},
|
||||||
[]Value{
|
[]Value{
|
||||||
&NumberValue{1},
|
&FloatValue{1},
|
||||||
&NumberValue{2},
|
&FloatValue{2},
|
||||||
&FunctionValue{
|
&FunctionValue{
|
||||||
Name: "sum",
|
Name: "sum",
|
||||||
Params: []FunctionParameter{
|
Params: []FunctionParameter{
|
||||||
{
|
{
|
||||||
"a",
|
"a",
|
||||||
&NumberSignature{},
|
&FloatSignature{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"b",
|
"b",
|
||||||
&NumberSignature{},
|
&FloatSignature{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Chunk: NewChunk(
|
Chunk: NewChunk(
|
||||||
[]Bytecode{
|
[]Bytecode{
|
||||||
InstructionGetLocal, 0,
|
InstructionGetLocal, 0,
|
||||||
InstructionGetLocal, 1,
|
InstructionGetLocal, 1,
|
||||||
InstructionAdd,
|
InstructionAddFloat,
|
||||||
InstructionReturn,
|
InstructionReturn,
|
||||||
},
|
},
|
||||||
[]Value{
|
[]Value{
|
||||||
|
|
@ -467,7 +467,7 @@ func GetExecutionTestData() map[string]struct {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
[]Value{
|
[]Value{
|
||||||
&NumberValue{3},
|
&FloatValue{3},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"function_calling_function": {
|
"function_calling_function": {
|
||||||
|
|
@ -481,18 +481,18 @@ func GetExecutionTestData() map[string]struct {
|
||||||
InstructionCall,
|
InstructionCall,
|
||||||
},
|
},
|
||||||
[]Value{
|
[]Value{
|
||||||
&NumberValue{1},
|
&FloatValue{1},
|
||||||
&NumberValue{2},
|
&FloatValue{2},
|
||||||
&FunctionValue{
|
&FunctionValue{
|
||||||
Name: "sum",
|
Name: "sum",
|
||||||
Params: []FunctionParameter{
|
Params: []FunctionParameter{
|
||||||
{
|
{
|
||||||
"a",
|
"a",
|
||||||
&NumberSignature{},
|
&FloatSignature{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"b",
|
"b",
|
||||||
&NumberSignature{},
|
&FloatSignature{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Chunk: NewChunk(
|
Chunk: NewChunk(
|
||||||
|
|
@ -501,7 +501,7 @@ func GetExecutionTestData() map[string]struct {
|
||||||
InstructionGetLocal, 2, InstructionCall, // square the number
|
InstructionGetLocal, 2, InstructionCall, // square the number
|
||||||
InstructionGetLocal, 1,
|
InstructionGetLocal, 1,
|
||||||
InstructionGetLocal, 2, InstructionCall, // square the number
|
InstructionGetLocal, 2, InstructionCall, // square the number
|
||||||
InstructionAdd,
|
InstructionAddFloat,
|
||||||
InstructionReturn,
|
InstructionReturn,
|
||||||
},
|
},
|
||||||
[]Value{
|
[]Value{
|
||||||
|
|
@ -514,14 +514,14 @@ func GetExecutionTestData() map[string]struct {
|
||||||
Params: []FunctionParameter{
|
Params: []FunctionParameter{
|
||||||
{
|
{
|
||||||
"n",
|
"n",
|
||||||
&NumberSignature{},
|
&FloatSignature{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Chunk: NewChunk(
|
Chunk: NewChunk(
|
||||||
[]Bytecode{
|
[]Bytecode{
|
||||||
InstructionGetLocal, 0,
|
InstructionGetLocal, 0,
|
||||||
InstructionGetLocal, 0,
|
InstructionGetLocal, 0,
|
||||||
InstructionMul,
|
InstructionMulFloat,
|
||||||
InstructionReturn,
|
InstructionReturn,
|
||||||
},
|
},
|
||||||
[]Value{
|
[]Value{
|
||||||
|
|
@ -540,14 +540,14 @@ func GetExecutionTestData() map[string]struct {
|
||||||
Params: []FunctionParameter{
|
Params: []FunctionParameter{
|
||||||
{
|
{
|
||||||
"n",
|
"n",
|
||||||
&NumberSignature{},
|
&FloatSignature{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Chunk: NewChunk(
|
Chunk: NewChunk(
|
||||||
[]Bytecode{
|
[]Bytecode{
|
||||||
InstructionGetLocal, 0,
|
InstructionGetLocal, 0,
|
||||||
InstructionGetLocal, 0,
|
InstructionGetLocal, 0,
|
||||||
InstructionMul,
|
InstructionMulFloat,
|
||||||
InstructionReturn,
|
InstructionReturn,
|
||||||
},
|
},
|
||||||
[]Value{
|
[]Value{
|
||||||
|
|
@ -557,7 +557,7 @@ func GetExecutionTestData() map[string]struct {
|
||||||
},
|
},
|
||||||
0,
|
0,
|
||||||
},
|
},
|
||||||
&NumberValue{5},
|
&FloatValue{5},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"list_concat": {
|
"list_concat": {
|
||||||
|
|
@ -570,13 +570,13 @@ func GetExecutionTestData() map[string]struct {
|
||||||
[]Value{
|
[]Value{
|
||||||
&ListValue{
|
&ListValue{
|
||||||
[]Value{
|
[]Value{
|
||||||
&NumberValue{1},
|
&FloatValue{1},
|
||||||
&NumberValue{2},
|
&FloatValue{2},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
&ListValue{
|
&ListValue{
|
||||||
[]Value{
|
[]Value{
|
||||||
&NumberValue{3},
|
&FloatValue{3},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -584,9 +584,9 @@ func GetExecutionTestData() map[string]struct {
|
||||||
[]Value{
|
[]Value{
|
||||||
&ListValue{
|
&ListValue{
|
||||||
[]Value{
|
[]Value{
|
||||||
&NumberValue{1},
|
&FloatValue{1},
|
||||||
&NumberValue{2},
|
&FloatValue{2},
|
||||||
&NumberValue{3},
|
&FloatValue{3},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -630,7 +630,7 @@ func TestVM_NextByte(t *testing.T) {
|
||||||
InstructionConstant, 0,
|
InstructionConstant, 0,
|
||||||
},
|
},
|
||||||
[]Value{
|
[]Value{
|
||||||
&NumberValue{0},
|
&FloatValue{0},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
16,
|
16,
|
||||||
|
|
@ -741,7 +741,7 @@ func TestVM_Jump(t *testing.T) {
|
||||||
InstructionConstant, 2,
|
InstructionConstant, 2,
|
||||||
},
|
},
|
||||||
[]Value{
|
[]Value{
|
||||||
&NumberValue{0}, &NumberValue{1}, &NumberValue{2},
|
&FloatValue{0}, &FloatValue{1}, &FloatValue{2},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
16,
|
16,
|
||||||
|
|
@ -766,7 +766,7 @@ func TestVM_JumpFalse(t *testing.T) {
|
||||||
InstructionConstant, 2,
|
InstructionConstant, 2,
|
||||||
},
|
},
|
||||||
[]Value{
|
[]Value{
|
||||||
&NumberValue{0}, &NumberValue{1}, &NumberValue{2},
|
&FloatValue{0}, &FloatValue{1}, &FloatValue{2},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
16,
|
16,
|
||||||
|
|
@ -792,7 +792,7 @@ func TestVM_DontJumpFalse(t *testing.T) {
|
||||||
InstructionConstant, 2,
|
InstructionConstant, 2,
|
||||||
},
|
},
|
||||||
[]Value{
|
[]Value{
|
||||||
&NumberValue{0}, &NumberValue{1}, &NumberValue{2},
|
&FloatValue{0}, &FloatValue{1}, &FloatValue{2},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
16,
|
16,
|
||||||
|
|
|
||||||
6
era3.ang
Normal file
6
era3.ang
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
fn double(a: int) -> int {
|
||||||
|
2*a
|
||||||
|
}
|
||||||
|
|
||||||
|
println(double(2) == 4)
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
assertEq(1+1, 2)
|
assertEq(1+1, 2)
|
||||||
assertEq(3*2, 6)
|
assertEq(3*2, 6)
|
||||||
assertEq(3/4, 0.75)
|
assertEq(3.0/4.0, 0.75)
|
||||||
assertEq(2 - 5, -3)
|
assertEq(2 - 5, -3)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ assertEq(1, 1)
|
||||||
assertEq(0, 0)
|
assertEq(0, 0)
|
||||||
assertEq("", "")
|
assertEq("", "")
|
||||||
|
|
||||||
assertEq([]number, []number)
|
assertEq([]int, []int)
|
||||||
assertEq([3, 1, 4, 1], [3, 1, 4, 1])
|
assertEq([3, 1, 4, 1], [3, 1, 4, 1])
|
||||||
|
|
||||||
# Inequality
|
# Inequality
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,20 @@
|
||||||
list := []number
|
list := []int
|
||||||
|
|
||||||
x := 1
|
x := 1
|
||||||
while x <= 1000 {
|
while x <= 1000 {
|
||||||
list.append(x)
|
list.append(x)
|
||||||
assertEq(list.reduce(func(tot: number, a: number) number {
|
assertEq(list.reduce(fn(tot: int, a: int) -> int {
|
||||||
return tot + a
|
return tot + a
|
||||||
}, 0), x*(x + 1)/2)
|
}, 0), x*(x + 1)/2)
|
||||||
|
|
||||||
x = x + 1
|
x = x + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func sum(a: number, b: number) number {
|
fn sum(a: int, b: int) -> int {
|
||||||
return a + b
|
return a + b
|
||||||
}
|
}
|
||||||
|
|
||||||
list = []number
|
list = []int
|
||||||
x = 1
|
x = 1
|
||||||
while x <= 100 {
|
while x <= 100 {
|
||||||
list.append(2*x - 1)
|
list.append(2*x - 1)
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ fibonacci_numbers := [
|
||||||
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377
|
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377
|
||||||
]
|
]
|
||||||
|
|
||||||
func fib(n: number) number {
|
fn fib(n: int) -> int {
|
||||||
if n < 2 {
|
if n < 2 {
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
list := []number
|
list := []int
|
||||||
|
|
||||||
list.append(1)
|
list.append(1)
|
||||||
list.append(2)
|
list.append(2)
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,8 @@
|
||||||
|
|
||||||
func sum(a: number, b: number) number {
|
fn sum(a: int, b: int) -> int {
|
||||||
return a + b
|
return a + b
|
||||||
}
|
}
|
||||||
|
|
||||||
breakpoint
|
|
||||||
|
|
||||||
assertEq(sum(1, 2), 3)
|
assertEq(sum(1, 2), 3)
|
||||||
breakpoint
|
|
||||||
|
|
||||||
assertEq(sum(3, 3), 6)
|
assertEq(sum(3, 3), 6)
|
||||||
breakpoint
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
|
|
||||||
assertEq(type(1), "number")
|
assertEq(type(1), "int")
|
||||||
assertEq(type("Hello"), "string")
|
assertEq(type("Hello"), "string")
|
||||||
assertEq(type(true), "boolean")
|
assertEq(type(true), "boolean")
|
||||||
|
|
||||||
# lists
|
# lists
|
||||||
assertEq(type(["Hello", "world"]), "list[string]")
|
assertEq(type(["Hello", "world"]), "list[string]")
|
||||||
assertEq(type([0, 1]), "list[number]")
|
assertEq(type([0, 1]), "list[int]")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue