Skip to content

Commit 67878a1

Browse files
committed
Add int() and float() builtins
1 parent 5fa2a40 commit 67878a1

File tree

4 files changed

+67
-1
lines changed

4 files changed

+67
-1
lines changed

builtin/builtin.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
var (
99
anyType = reflect.TypeOf(new(interface{})).Elem()
1010
integerType = reflect.TypeOf(0)
11+
floatType = reflect.TypeOf(float64(0))
1112
)
1213

1314
type Function struct {
@@ -21,6 +22,8 @@ type Function struct {
2122
const (
2223
Len = iota + 1
2324
Abs
25+
Int
26+
Float
2427
)
2528

2629
var Builtins = []*Function{
@@ -52,4 +55,40 @@ var Builtins = []*Function{
5255
return anyType, fmt.Errorf("invalid argument for abs (type %s)", args[0])
5356
},
5457
},
58+
{
59+
Name: "int",
60+
BuiltinId: Int,
61+
Validate: func(args []reflect.Type) (reflect.Type, error) {
62+
if len(args) != 1 {
63+
return anyType, fmt.Errorf("invalid number of arguments for int (expected 1, got %d)", len(args))
64+
}
65+
switch args[0].Kind() {
66+
case reflect.Interface:
67+
return integerType, nil
68+
case reflect.Float32, reflect.Float64, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
69+
return integerType, nil
70+
case reflect.String:
71+
return integerType, nil
72+
}
73+
return anyType, fmt.Errorf("invalid argument for int (type %s)", args[0])
74+
},
75+
},
76+
{
77+
Name: "float",
78+
BuiltinId: Float,
79+
Validate: func(args []reflect.Type) (reflect.Type, error) {
80+
if len(args) != 1 {
81+
return anyType, fmt.Errorf("invalid number of arguments for float (expected 1, got %d)", len(args))
82+
}
83+
switch args[0].Kind() {
84+
case reflect.Interface:
85+
return floatType, nil
86+
case reflect.Float32, reflect.Float64, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
87+
return floatType, nil
88+
case reflect.String:
89+
return floatType, nil
90+
}
91+
return anyType, fmt.Errorf("invalid argument for float (type %s)", args[0])
92+
},
93+
},
5594
}

builtin/builtin_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ var tests = []struct {
1616
{`len("hello")`, 5},
1717
{`abs(-5)`, 5},
1818
{`abs(-.5)`, .5},
19+
{`int(5.5)`, 5},
20+
{`int(5)`, 5},
21+
{`int("5")`, 5},
22+
{`float(5)`, 5.0},
23+
{`float(5.5)`, 5.5},
24+
{`float("5.5")`, 5.5},
1925
}
2026

2127
func TestBuiltin(t *testing.T) {
@@ -37,6 +43,10 @@ var errorTests = []struct {
3743
{`abs()`, `invalid number of arguments for abs (expected 1, got 0)`},
3844
{`abs(1, 2)`, `invalid number of arguments for abs (expected 1, got 2)`},
3945
{`abs("foo")`, `invalid argument for abs (type string)`},
46+
{`int()`, `invalid number of arguments for int (expected 1, got 0)`},
47+
{`int(1, 2)`, `invalid number of arguments for int (expected 1, got 2)`},
48+
{`float()`, `invalid number of arguments for float (expected 1, got 0)`},
49+
{`float(1, 2)`, `invalid number of arguments for float (expected 1, got 2)`},
4050
}
4151

4252
func TestBuiltinErrors(t *testing.T) {

vm/runtime/runtime.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"fmt"
77
"math"
88
"reflect"
9+
"strconv"
910
)
1011

1112
func Fetch(from, i interface{}) interface{} {
@@ -325,6 +326,12 @@ func ToInt(a interface{}) int {
325326
return int(x)
326327
case uint64:
327328
return int(x)
329+
case string:
330+
i, err := strconv.Atoi(x)
331+
if err != nil {
332+
panic(fmt.Sprintf("invalid operation: int(%s)", x))
333+
}
334+
return i
328335
default:
329336
panic(fmt.Sprintf("invalid operation: int(%T)", x))
330337
}
@@ -387,8 +394,14 @@ func ToFloat64(a interface{}) float64 {
387394
return float64(x)
388395
case uint64:
389396
return float64(x)
397+
case string:
398+
f, err := strconv.ParseFloat(x, 64)
399+
if err != nil {
400+
panic(fmt.Sprintf("invalid operation: float(%s)", x))
401+
}
402+
return f
390403
default:
391-
panic(fmt.Sprintf("invalid operation: float64(%T)", x))
404+
panic(fmt.Sprintf("invalid operation: float(%T)", x))
392405
}
393406
}
394407

vm/vm.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,10 @@ func (vm *VM) Run(program *Program, env interface{}) (_ interface{}, err error)
373373
vm.push(runtime.Len(vm.pop()))
374374
case builtin.Abs:
375375
vm.push(runtime.Abs(vm.pop()))
376+
case builtin.Int:
377+
vm.push(runtime.ToInt(vm.pop()))
378+
case builtin.Float:
379+
vm.push(runtime.ToFloat64(vm.pop()))
376380
}
377381

378382
case OpArray:

0 commit comments

Comments
 (0)