Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions ast/number.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ package ast

import (
"ghostlang.org/x/ghost/token"
"github.com/shopspring/decimal"
)

type Number struct {
ExpressionNode
Token token.Token
Value decimal.Decimal
Token token.Token
IntValue int64
FloatValue float64
IsFloat bool
}
2 changes: 1 addition & 1 deletion evaluator/assign.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func evaluateIndexAssignment(node *ast.Index, assignmentValue object.Object, sco

switch obj := left.(type) {
case *object.List:
idx := int(index.(*object.Number).Value.IntPart())
idx := int(index.(*object.Number).Int64())
elements := obj.Elements

if idx < 0 {
Expand Down
4 changes: 2 additions & 2 deletions evaluator/evaluator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -552,8 +552,8 @@ func isNumberObject(t *testing.T, obj object.Object, expected int64) bool {
return false
}

if number.Value.IntPart() != expected {
t.Errorf("object has wrong value. got=%d, expected=%d", number.Value.IntPart(), expected)
if number.Int64() != expected {
t.Errorf("object has wrong value. got=%d, expected=%d", number.Int64(), expected)
return false
}

Expand Down
3 changes: 1 addition & 2 deletions evaluator/for_in.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package evaluator
import (
"ghostlang.org/x/ghost/ast"
"ghostlang.org/x/ghost/object"
"github.com/shopspring/decimal"
)

func evaluateForIn(node *ast.ForIn, scope *object.Scope) object.Object {
Expand Down Expand Up @@ -33,7 +32,7 @@ func evaluateForIn(node *ast.ForIn, scope *object.Scope) object.Object {
switch obj := iterable.(type) {
case *object.List:
for k, v := range obj.Elements {
scope.Environment.Set(node.Key.Value, &object.Number{Value: decimal.NewFromInt(int64(k))})
scope.Environment.Set(node.Key.Value, object.NewInt(int64(k)))
scope.Environment.Set(node.Value.Value, v)

block := Evaluate(node.Block, scope)
Expand Down
4 changes: 2 additions & 2 deletions evaluator/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func evaluateIndex(node *ast.Index, scope *object.Scope) object.Object {

func evaluateListIndex(node *ast.Index, left, index object.Object) object.Object {
list := left.(*object.List)
idx := index.(*object.Number).Value.IntPart()
idx := index.(*object.Number).Int64()
max := int64(len(list.Elements) - 1)

if idx < 0 || idx > max {
Expand Down Expand Up @@ -63,7 +63,7 @@ func evaluateMapIndex(node *ast.Index, left, index object.Object) object.Object

func evaluateStringIndex(node *ast.Index, left, index object.Object) object.Object {
str := left.(*object.String)
idx := index.(*object.Number).Value.IntPart()
idx := index.(*object.Number).Int64()
max := int64(len(str.Value) - 1)

if idx < 0 || idx > max {
Expand Down
51 changes: 24 additions & 27 deletions evaluator/number.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,57 +3,54 @@ package evaluator
import (
"ghostlang.org/x/ghost/ast"
"ghostlang.org/x/ghost/object"
"github.com/shopspring/decimal"
)

func evaluateNumber(node *ast.Number, scope *object.Scope) object.Object {
return &object.Number{Value: node.Value}
if node.IsFloat {
return object.NewFloat(node.FloatValue)
}
return object.NewInt(node.IntValue)
}

func evaluateNumberInfix(node *ast.Infix, left object.Object, right object.Object) object.Object {
leftValue := left.(*object.Number).Value
rightValue := right.(*object.Number).Value
leftNum := left.(*object.Number)
rightNum := right.(*object.Number)

switch node.Operator {
case "+":
return &object.Number{Value: leftValue.Add(rightValue)}
return leftNum.Add(rightNum)
case "-":
return &object.Number{Value: leftValue.Sub(rightValue)}
return leftNum.Sub(rightNum)
case "*":
return &object.Number{Value: leftValue.Mul(rightValue)}
return leftNum.Mul(rightNum)
case "/":
return &object.Number{Value: leftValue.Div(rightValue)}
return leftNum.Div(rightNum)
case "%":
return &object.Number{Value: leftValue.Mod(rightValue)}
return leftNum.Mod(rightNum)
case "<":
return toBooleanValue(leftValue.LessThan(rightValue))
return toBooleanValue(leftNum.LessThan(rightNum))
case "<=":
return toBooleanValue(leftValue.LessThanOrEqual(rightValue))
return toBooleanValue(leftNum.LessThanOrEqual(rightNum))
case ">":
return toBooleanValue(leftValue.GreaterThan(rightValue))
return toBooleanValue(leftNum.GreaterThan(rightNum))
case ">=":
return toBooleanValue(leftValue.GreaterThanOrEqual(rightValue))
return toBooleanValue(leftNum.GreaterThanOrEqual(rightNum))
case "==":
return toBooleanValue(leftValue.Equal(rightValue))
return toBooleanValue(leftNum.Equal(rightNum))
case "!=":
return toBooleanValue(!leftValue.Equal(rightValue))
return toBooleanValue(!leftNum.Equal(rightNum))
case "..":
numbers := make([]object.Object, 0)
one := decimal.NewFromInt(1)
number := leftValue
start := leftNum.Int64()
end := rightNum.Int64()

if leftValue.GreaterThan(rightValue) {
return &object.List{Elements: numbers}
if start > end {
return &object.List{Elements: []object.Object{}}
}

for {
numbers = append(numbers, &object.Number{Value: number})

if number.GreaterThanOrEqual(rightValue) {
break
}
numbers := make([]object.Object, 0, end-start+1)

number = number.Add(one)
for i := start; i <= end; i++ {
numbers = append(numbers, object.NewInt(i))
}

return &object.List{Elements: numbers}
Expand Down
13 changes: 2 additions & 11 deletions evaluator/postfix.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package evaluator
import (
"ghostlang.org/x/ghost/ast"
"ghostlang.org/x/ghost/object"
"github.com/shopspring/decimal"
)

func evaluatePostfix(node *ast.Postfix, scope *object.Scope) object.Object {
Expand All @@ -19,11 +18,7 @@ func evaluatePostfix(node *ast.Postfix, scope *object.Scope) object.Object {
return newError("%d:%d:%s: runtime error: identifier is not a number: %s", node.Token.Line, node.Token.Column, node.Token.File, node.Token.Lexeme)
}

one := decimal.NewFromInt(1)

newValue := &object.Number{
Value: value.(*object.Number).Value.Add(one),
}
newValue := value.(*object.Number).Increment()

scope.Environment.Set(node.Token.Lexeme, newValue)

Expand All @@ -39,11 +34,7 @@ func evaluatePostfix(node *ast.Postfix, scope *object.Scope) object.Object {
return newError("%d:%d:%s: runtime error: identifier is not a number: %s", node.Token.Line, node.Token.Column, node.Token.File, node.Token.Lexeme)
}

one := decimal.NewFromInt(1)

newValue := &object.Number{
Value: value.(*object.Number).Value.Sub(one),
}
newValue := value.(*object.Number).Decrement()

scope.Environment.Set(node.Token.Lexeme, newValue)

Expand Down
4 changes: 1 addition & 3 deletions evaluator/prefix.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,7 @@ func evaluatePrefix(node *ast.Prefix, scope *object.Scope) object.Object {
return newError("%d:%d:%s: runtime error: unknown operator: -%s", node.Token.Line, node.Token.Column, node.Token.File, right.Type())
}

numberValue := right.(*object.Number).Value.Neg()

return &object.Number{Value: numberValue}
return right.(*object.Number).Neg()
}

return newError("%d:%d:%s: runtime error: unknown operator: %s%s", node.Token.Line, node.Token.Column, node.Token.File, node.Operator, right.Type())
Expand Down
5 changes: 1 addition & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ module ghostlang.org/x/ghost

go 1.21.1

require (
github.com/peterh/liner v1.2.1
github.com/shopspring/decimal v1.3.1
)
require github.com/peterh/liner v1.2.1

require github.com/mattn/go-runewidth v0.0.3 // indirect
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,3 @@ github.com/mattn/go-runewidth v0.0.3 h1:a+kO+98RDGEfo6asOGMmpodZq4FNtnGP54yps8Bz
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/peterh/liner v1.2.1 h1:O4BlKaq/LWu6VRWmol4ByWfzx6MfXc5Op5HETyIy5yg=
github.com/peterh/liner v1.2.1/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0=
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
5 changes: 2 additions & 3 deletions library/modules/json_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@ import (

"ghostlang.org/x/ghost/object"
"ghostlang.org/x/ghost/token"
"github.com/shopspring/decimal"
)

func TestJsonDecode(t *testing.T) {
input := `{"name": "John", "age": 30, "city": "New York"}`

expected := &object.Map{Pairs: map[object.MapKey]object.MapPair{
(&object.String{Value: "name"}).MapKey(): {Key: &object.String{Value: "name"}, Value: &object.String{Value: "Kai"}},
(&object.String{Value: "age"}).MapKey(): {Key: &object.String{Value: "age"}, Value: &object.Number{Value: decimal.NewFromInt(34)}},
(&object.String{Value: "age"}).MapKey(): {Key: &object.String{Value: "age"}, Value: object.NewInt(34)},
}}

result := jsonDecode(nil, token.Token{}, &object.String{Value: input})
Expand All @@ -26,7 +25,7 @@ func TestJsonDecode(t *testing.T) {
func TestJsonEncode(t *testing.T) {
input := &object.Map{Pairs: map[object.MapKey]object.MapPair{
(&object.String{Value: "name"}).MapKey(): {Key: &object.String{Value: "name"}, Value: &object.String{Value: "Kai"}},
(&object.String{Value: "age"}).MapKey(): {Key: &object.String{Value: "age"}, Value: &object.Number{Value: decimal.NewFromInt(34)}},
(&object.String{Value: "age"}).MapKey(): {Key: &object.String{Value: "age"}, Value: object.NewInt(34)},
}}

expected := `{"age":34,"name":"Kai"}`
Expand Down
39 changes: 16 additions & 23 deletions library/modules/math.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package modules

import (
"math"

"ghostlang.org/x/ghost/object"
"ghostlang.org/x/ghost/token"
"github.com/shopspring/decimal"
)

var MathMethods = map[string]*object.LibraryFunction{}
Expand Down Expand Up @@ -38,7 +39,7 @@ func mathAbs(scope *object.Scope, tok token.Token, args ...object.Object) object

number := args[0].(*object.Number)

return &object.Number{Value: number.Value.Abs()}
return number.Abs()
}

// mathCos returns the cosine value of the referenced number.
Expand All @@ -53,7 +54,7 @@ func mathCos(scope *object.Scope, tok token.Token, args ...object.Object) object

number := args[0].(*object.Number)

return &object.Number{Value: number.Value.Cos()}
return number.Cos()
}

// mathisNegative returns true if the referenced number is negative.
Expand All @@ -68,7 +69,7 @@ func mathIsNegative(scope *object.Scope, tok token.Token, args ...object.Object)

number := args[0].(*object.Number)

return &object.Boolean{Value: number.Value.IsNegative()}
return &object.Boolean{Value: number.IsNeg()}
}

// mathisPositive returns true if the referenced number is positive.
Expand All @@ -83,7 +84,7 @@ func mathIsPositive(scope *object.Scope, tok token.Token, args ...object.Object)

number := args[0].(*object.Number)

return &object.Boolean{Value: number.Value.IsPositive()}
return &object.Boolean{Value: number.IsPos()}
}

// mathisZero returns true if the referenced number is zero.
Expand All @@ -98,7 +99,7 @@ func mathIsZero(scope *object.Scope, tok token.Token, args ...object.Object) obj

number := args[0].(*object.Number)

return &object.Boolean{Value: number.Value.IsZero()}
return &object.Boolean{Value: number.IsZero()}
}

// mathSin returns the sine value of the referenced number.
Expand All @@ -113,7 +114,7 @@ func mathSin(scope *object.Scope, tok token.Token, args ...object.Object) object

number := args[0].(*object.Number)

return &object.Number{Value: number.Value.Sin()}
return number.Sin()
}

// mathTan returns the tangent value of the referenced number.
Expand All @@ -128,7 +129,7 @@ func mathTan(scope *object.Scope, tok token.Token, args ...object.Object) object

number := args[0].(*object.Number)

return &object.Number{Value: number.Value.Tan()}
return number.Tan()
}

// mathMax returns the largest number of the referenced numbers.
Expand All @@ -148,7 +149,7 @@ func mathMax(scope *object.Scope, tok token.Token, args ...object.Object) object
number1 := args[0].(*object.Number)
number2 := args[1].(*object.Number)

if number1.Value.GreaterThan(number2.Value) {
if number1.GreaterThan(number2) {
return number1
}

Expand All @@ -172,7 +173,7 @@ func mathMin(scope *object.Scope, tok token.Token, args ...object.Object) object
number1 := args[0].(*object.Number)
number2 := args[1].(*object.Number)

if number1.Value.LessThan(number2.Value) {
if number1.LessThan(number2) {
return number1
}

Expand All @@ -183,31 +184,23 @@ func mathMin(scope *object.Scope, tok token.Token, args ...object.Object) object

// mathPi returns the value of π, othewise known as Pi.
func mathPi(scope *object.Scope, tok token.Token) object.Object {
pi, _ := decimal.NewFromString("3.141592653589793")

return &object.Number{Value: pi}
return object.NewFloat(math.Pi)
}

// mathE returns the value of e, otherwise known as Euler's number.
func mathE(scope *object.Scope, tok token.Token) object.Object {
e, _ := decimal.NewFromString("2.718281828459045")

return &object.Number{Value: e}
return object.NewFloat(math.E)
}

// mathTau returns the value of τ, otherwise known as Tau. Tau is a circle
// constant equal to 2π, the ratio of a circles circumference to its radius.
// constant equal to 2π, the ratio of a circle's circumference to its radius.
func mathTau(scope *object.Scope, tok token.Token) object.Object {
tau, _ := decimal.NewFromString("6.283185307179586")

return &object.Number{Value: tau}
return object.NewFloat(2 * math.Pi)
}

// mathEpsilon returns the value of ϵ, otherwise known as Epsilon. Epsilon
// represents the difference between 1 and the smallest floating point number
// greater than 1.
func mathEpsilon(scope *object.Scope, tok token.Token) object.Object {
epsilon, _ := decimal.NewFromString("2.2204460492503130808472633361816E-16")

return &object.Number{Value: epsilon}
return object.NewFloat(math.SmallestNonzeroFloat64)
}
7 changes: 2 additions & 5 deletions library/modules/os.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (

"ghostlang.org/x/ghost/object"
"ghostlang.org/x/ghost/token"
"github.com/shopspring/decimal"
)

var OsMethods = map[string]*object.LibraryFunction{}
Expand All @@ -34,9 +33,7 @@ func osArgs(scope *object.Scope, tok token.Token, args ...object.Object) object.
}

func osClock(scope *object.Scope, tok token.Token, args ...object.Object) object.Object {
seconds := decimal.NewFromInt(time.Now().UnixNano())

return &object.Number{Value: seconds}
return object.NewInt(time.Now().UnixNano())
}

func osExit(scope *object.Scope, tok token.Token, args ...object.Object) object.Object {
Expand Down Expand Up @@ -70,7 +67,7 @@ func osExit(scope *object.Scope, tok token.Token, args ...object.Object) object.

arg := args[0].(*object.Number)

os.Exit(int(arg.Value.IntPart()))
os.Exit(int(arg.Int64()))

return arg
}
Expand Down
Loading
Loading