Repository: d5/tengo
Pull request #437 (2023-12-11 08:28:44)

Add `os.arch` and `os.platform`


Patch:
diff --git a/.gitignore b/.gitignore
index 7773828..37eb85e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,1 +1,3 @@
-dist/
\ No newline at end of file
+dist/
+
+.idea
\ No newline at end of file
diff --git a/docs/stdlib-os.md b/docs/stdlib-os.md
index fec5d67..dadc5a6 100644
--- a/docs/stdlib-os.md
+++ b/docs/stdlib-os.md
@@ -6,6 +6,8 @@ os := import("os")
 
 ## Constants
 
+- `platform`
+- `arch`
 - `o_rdonly`
 - `o_wronly`
 - `o_rdwr`
diff --git a/instructions.go b/instructions.go
index eb1fbf2..27f7af3 100644
--- a/instructions.go
+++ b/instructions.go
@@ -28,6 +28,12 @@ func MakeInstruction(opcode parser.Opcode, operands ...int) []byte {
 			n := uint16(o)
 			instruction[offset] = byte(n >> 8)
 			instruction[offset+1] = byte(n)
+		case 4:
+			n := uint32(o)
+			instruction[offset] = byte(n >> 24)
+			instruction[offset+1] = byte(n >> 16)
+			instruction[offset+2] = byte(n >> 8)
+			instruction[offset+3] = byte(n)
 		}
 		offset += width
 	}
diff --git a/parser/expr.go b/parser/expr.go
index b6b6c62..ea4b8b1 100644
--- a/parser/expr.go
+++ b/parser/expr.go
@@ -351,7 +351,7 @@ func (e *ImportExpr) End() Pos {
 }
 
 func (e *ImportExpr) String() string {
-	return `import("` + e.ModuleName + `")"`
+	return `import("` + e.ModuleName + `")`
 }
 
 // IndexExpr represents an index expression.
diff --git a/parser/opcodes.go b/parser/opcodes.go
index d97f489..c1e94c1 100644
--- a/parser/opcodes.go
+++ b/parser/opcodes.go
@@ -106,10 +106,10 @@ var OpcodeOperands = [...][]int{
 	OpNotEqual:      {},
 	OpMinus:         {},
 	OpLNot:          {},
-	OpJumpFalsy:     {2},
-	OpAndJump:       {2},
-	OpOrJump:        {2},
-	OpJump:          {2},
+	OpJumpFalsy:     {4},
+	OpAndJump:       {4},
+	OpOrJump:        {4},
+	OpJump:          {4},
 	OpNull:          {},
 	OpGetGlobal:     {2},
 	OpSetGlobal:     {2},
@@ -149,6 +149,8 @@ func ReadOperands(numOperands []int, ins []byte) (operands []int, offset int) {
 			operands = append(operands, int(ins[offset]))
 		case 2:
 			operands = append(operands, int(ins[offset+1])|int(ins[offset])<<8)
+		case 4:
+			operands = append(operands, int(ins[offset+3])|int(ins[offset+2])<<8|int(ins[offset+1])<<16|int(ins[offset])<<24)
 		}
 		offset += width
 	}
diff --git a/stdlib/os.go b/stdlib/os.go
index 576bc94..5af4b60 100644
--- a/stdlib/os.go
+++ b/stdlib/os.go
@@ -6,11 +6,14 @@ import (
 	"io/ioutil"
 	"os"
 	"os/exec"
+	"runtime"
 
 	"github.com/d5/tengo/v2"
 )
 
 var osModule = map[string]tengo.Object{
+	"platform":            &tengo.String{Value: runtime.GOOS},
+	"arch":                &tengo.String{Value: runtime.GOARCH},
 	"o_rdonly":            &tengo.Int{Value: int64(os.O_RDONLY)},
 	"o_wronly":            &tengo.Int{Value: int64(os.O_WRONLY)},
 	"o_rdwr":              &tengo.Int{Value: int64(os.O_RDWR)},
diff --git a/vm.go b/vm.go
index 64bd23b..2e0240b 100644
--- a/vm.go
+++ b/vm.go
@@ -218,30 +218,30 @@ func (v *VM) run() {
 				return
 			}
 		case parser.OpJumpFalsy:
-			v.ip += 2
+			v.ip += 4
 			v.sp--
 			if v.stack[v.sp].IsFalsy() {
-				pos := int(v.curInsts[v.ip]) | int(v.curInsts[v.ip-1])<<8
+				pos := int(v.curInsts[v.ip]) | int(v.curInsts[v.ip-1])<<8 | int(v.curInsts[v.ip-2])<<16 | int(v.curInsts[v.ip-3])<<24
 				v.ip = pos - 1
 			}
 		case parser.OpAndJump:
-			v.ip += 2
+			v.ip += 4
 			if v.stack[v.sp-1].IsFalsy() {
-				pos := int(v.curInsts[v.ip]) | int(v.curInsts[v.ip-1])<<8
+				pos := int(v.curInsts[v.ip]) | int(v.curInsts[v.ip-1])<<8 | int(v.curInsts[v.ip-2])<<16 | int(v.curInsts[v.ip-3])<<24
 				v.ip = pos - 1
 			} else {
 				v.sp--
 			}
 		case parser.OpOrJump:
-			v.ip += 2
+			v.ip += 4
 			if v.stack[v.sp-1].IsFalsy() {
 				v.sp--
 			} else {
-				pos := int(v.curInsts[v.ip]) | int(v.curInsts[v.ip-1])<<8
+				pos := int(v.curInsts[v.ip]) | int(v.curInsts[v.ip-1])<<8 | int(v.curInsts[v.ip-2])<<16 | int(v.curInsts[v.ip-3])<<24
 				v.ip = pos - 1
 			}
 		case parser.OpJump:
-			pos := int(v.curInsts[v.ip+2]) | int(v.curInsts[v.ip+1])<<8
+			pos := int(v.curInsts[v.ip+4]) | int(v.curInsts[v.ip+3])<<8 | int(v.curInsts[v.ip+2])<<16 | int(v.curInsts[v.ip+1])<<24
 			v.ip = pos - 1
 		case parser.OpSetGlobal:
 			v.ip += 2
@@ -534,6 +534,8 @@ func (v *VM) run() {
 				}
 				v.stack[v.sp] = val
 				v.sp++
+			default:
+				v.err = fmt.Errorf("not indexable: %s", left.TypeName())
 			}
 		case parser.OpCall:
 			numArgs := int(v.curInsts[v.ip+1])


Test patch:
diff --git a/compiler_test.go b/compiler_test.go
index 28cc901..5caf2b0 100644
--- a/compiler_test.go
+++ b/compiler_test.go
@@ -204,11 +204,11 @@ func TestCompiler_Compile(t *testing.T) {
 	expectCompile(t, `if true { 10 }; 3333`,
 		bytecode(
 			concatInsts(
-				tengo.MakeInstruction(parser.OpTrue),         // 0000
-				tengo.MakeInstruction(parser.OpJumpFalsy, 8), // 0001
-				tengo.MakeInstruction(parser.OpConstant, 0),  // 0004
-				tengo.MakeInstruction(parser.OpPop),          // 0007
-				tengo.MakeInstruction(parser.OpConstant, 1),  // 0008
+				tengo.MakeInstruction(parser.OpTrue),          // 0000
+				tengo.MakeInstruction(parser.OpJumpFalsy, 10), // 0001
+				tengo.MakeInstruction(parser.OpConstant, 0),   // 0004
+				tengo.MakeInstruction(parser.OpPop),           // 0007
+				tengo.MakeInstruction(parser.OpConstant, 1),   // 0008
 				tengo.MakeInstruction(parser.OpPop),
 				tengo.MakeInstruction(parser.OpSuspend)), // 0011
 			objectsArray(
@@ -219,10 +219,10 @@ func TestCompiler_Compile(t *testing.T) {
 		bytecode(
 			concatInsts(
 				tengo.MakeInstruction(parser.OpTrue),          // 0000
-				tengo.MakeInstruction(parser.OpJumpFalsy, 11), // 0001
+				tengo.MakeInstruction(parser.OpJumpFalsy, 15), // 0001
 				tengo.MakeInstruction(parser.OpConstant, 0),   // 0004
 				tengo.MakeInstruction(parser.OpPop),           // 0007
-				tengo.MakeInstruction(parser.OpJump, 15),      // 0008
+				tengo.MakeInstruction(parser.OpJump, 19),      // 0008
 				tengo.MakeInstruction(parser.OpConstant, 1),   // 0011
 				tengo.MakeInstruction(parser.OpPop),           // 0014
 				tengo.MakeInstruction(parser.OpConstant, 2),   // 0015
@@ -577,12 +577,12 @@ func TestCompiler_Compile(t *testing.T) {
 				intObject(1),
 				intObject(2),
 				compiledFunction(0, 0,
-					tengo.MakeInstruction(parser.OpTrue),         // 0000
-					tengo.MakeInstruction(parser.OpJumpFalsy, 9), // 0001
-					tengo.MakeInstruction(parser.OpConstant, 0),  // 0004
-					tengo.MakeInstruction(parser.OpReturn, 1),    // 0007
-					tengo.MakeInstruction(parser.OpConstant, 1),  // 0009
-					tengo.MakeInstruction(parser.OpReturn, 1))))) // 0012
+					tengo.MakeInstruction(parser.OpTrue),          // 0000
+					tengo.MakeInstruction(parser.OpJumpFalsy, 11), // 0001
+					tengo.MakeInstruction(parser.OpConstant, 0),   // 0004
+					tengo.MakeInstruction(parser.OpReturn, 1),     // 0007
+					tengo.MakeInstruction(parser.OpConstant, 1),   // 0009
+					tengo.MakeInstruction(parser.OpReturn, 1)))))  // 0012
 
 	expectCompile(t, `func() { 1; if(true) { 2 } else { 3 }; 4 }`,
 		bytecode(
@@ -599,10 +599,10 @@ func TestCompiler_Compile(t *testing.T) {
 					tengo.MakeInstruction(parser.OpConstant, 0),   // 0000
 					tengo.MakeInstruction(parser.OpPop),           // 0003
 					tengo.MakeInstruction(parser.OpTrue),          // 0004
-					tengo.MakeInstruction(parser.OpJumpFalsy, 15), // 0005
+					tengo.MakeInstruction(parser.OpJumpFalsy, 19), // 0005
 					tengo.MakeInstruction(parser.OpConstant, 1),   // 0008
 					tengo.MakeInstruction(parser.OpPop),           // 0011
-					tengo.MakeInstruction(parser.OpJump, 19),      // 0012
+					tengo.MakeInstruction(parser.OpJump, 23),      // 0012
 					tengo.MakeInstruction(parser.OpConstant, 2),   // 0015
 					tengo.MakeInstruction(parser.OpPop),           // 0018
 					tengo.MakeInstruction(parser.OpConstant, 3),   // 0019
@@ -932,7 +932,7 @@ func() {
 				tengo.MakeInstruction(parser.OpGetGlobal, 0),
 				tengo.MakeInstruction(parser.OpConstant, 1),
 				tengo.MakeInstruction(parser.OpBinaryOp, 38),
-				tengo.MakeInstruction(parser.OpJumpFalsy, 31),
+				tengo.MakeInstruction(parser.OpJumpFalsy, 35),
 				tengo.MakeInstruction(parser.OpGetGlobal, 0),
 				tengo.MakeInstruction(parser.OpConstant, 2),
 				tengo.MakeInstruction(parser.OpBinaryOp, 11),
@@ -954,7 +954,7 @@ func() {
 				tengo.MakeInstruction(parser.OpSetGlobal, 1),
 				tengo.MakeInstruction(parser.OpGetGlobal, 1),
 				tengo.MakeInstruction(parser.OpIteratorNext),
-				tengo.MakeInstruction(parser.OpJumpFalsy, 37),
+				tengo.MakeInstruction(parser.OpJumpFalsy, 41),
 				tengo.MakeInstruction(parser.OpGetGlobal, 1),
 				tengo.MakeInstruction(parser.OpIteratorKey),
 				tengo.MakeInstruction(parser.OpSetGlobal, 2),
@@ -973,11 +973,11 @@ func() {
 				tengo.MakeInstruction(parser.OpGetGlobal, 0),
 				tengo.MakeInstruction(parser.OpConstant, 0),
 				tengo.MakeInstruction(parser.OpEqual),
-				tengo.MakeInstruction(parser.OpAndJump, 23),
+				tengo.MakeInstruction(parser.OpAndJump, 25),
 				tengo.MakeInstruction(parser.OpGetGlobal, 0),
 				tengo.MakeInstruction(parser.OpConstant, 1),
 				tengo.MakeInstruction(parser.OpNotEqual),
-				tengo.MakeInstruction(parser.OpOrJump, 34),
+				tengo.MakeInstruction(parser.OpOrJump, 38),
 				tengo.MakeInstruction(parser.OpGetGlobal, 0),
 				tengo.MakeInstruction(parser.OpConstant, 1),
 				tengo.MakeInstruction(parser.OpBinaryOp, 38),
@@ -1089,7 +1089,7 @@ func() {
 			intObject(4),
 			compiledFunction(0, 0,
 				tengo.MakeInstruction(parser.OpTrue),
-				tengo.MakeInstruction(parser.OpJumpFalsy, 9),
+				tengo.MakeInstruction(parser.OpJumpFalsy, 11),
 				tengo.MakeInstruction(parser.OpConstant, 0),
 				tengo.MakeInstruction(parser.OpReturn, 1),
 				tengo.MakeInstruction(parser.OpConstant, 1),
@@ -1123,7 +1123,7 @@ func() {
 				tengo.MakeInstruction(parser.OpGetLocal, 0),
 				tengo.MakeInstruction(parser.OpConstant, 1),
 				tengo.MakeInstruction(parser.OpEqual),
-				tengo.MakeInstruction(parser.OpJumpFalsy, 19),
+				tengo.MakeInstruction(parser.OpJumpFalsy, 21),
 				tengo.MakeInstruction(parser.OpConstant, 2),
 				tengo.MakeInstruction(parser.OpReturn, 1),
 				tengo.MakeInstruction(parser.OpConstant, 1),
@@ -1156,7 +1156,7 @@ func() {
 			intObject(4),
 			compiledFunction(0, 0,
 				tengo.MakeInstruction(parser.OpTrue),
-				tengo.MakeInstruction(parser.OpJumpFalsy, 9),
+				tengo.MakeInstruction(parser.OpJumpFalsy, 11),
 				tengo.MakeInstruction(parser.OpConstant, 0),
 				tengo.MakeInstruction(parser.OpReturn, 1),
 				tengo.MakeInstruction(parser.OpConstant, 1),
@@ -1180,7 +1180,7 @@ func() {
 			intObject(123),
 			compiledFunction(0, 0,
 				tengo.MakeInstruction(parser.OpTrue),
-				tengo.MakeInstruction(parser.OpJumpFalsy, 6),
+				tengo.MakeInstruction(parser.OpJumpFalsy, 8),
 				tengo.MakeInstruction(parser.OpReturn, 0),
 				tengo.MakeInstruction(parser.OpReturn, 0),
 				tengo.MakeInstruction(parser.OpConstant, 0),
@@ -1200,12 +1200,12 @@ if a := 1; a {
 			tengo.MakeInstruction(parser.OpConstant, 0),
 			tengo.MakeInstruction(parser.OpSetGlobal, 0),
 			tengo.MakeInstruction(parser.OpGetGlobal, 0),
-			tengo.MakeInstruction(parser.OpJumpFalsy, 27),
+			tengo.MakeInstruction(parser.OpJumpFalsy, 31),
 			tengo.MakeInstruction(parser.OpConstant, 1),
 			tengo.MakeInstruction(parser.OpSetGlobal, 0),
 			tengo.MakeInstruction(parser.OpGetGlobal, 0),
 			tengo.MakeInstruction(parser.OpSetGlobal, 1),
-			tengo.MakeInstruction(parser.OpJump, 39),
+			tengo.MakeInstruction(parser.OpJump, 43),
 			tengo.MakeInstruction(parser.OpConstant, 2),
 			tengo.MakeInstruction(parser.OpSetGlobal, 0),
 			tengo.MakeInstruction(parser.OpGetGlobal, 0),
@@ -1238,12 +1238,12 @@ func() {
 				tengo.MakeInstruction(parser.OpConstant, 0),
 				tengo.MakeInstruction(parser.OpDefineLocal, 0),
 				tengo.MakeInstruction(parser.OpGetLocal, 0),
-				tengo.MakeInstruction(parser.OpJumpFalsy, 22),
+				tengo.MakeInstruction(parser.OpJumpFalsy, 26),
 				tengo.MakeInstruction(parser.OpConstant, 1),
 				tengo.MakeInstruction(parser.OpSetLocal, 0),
 				tengo.MakeInstruction(parser.OpGetLocal, 0),
 				tengo.MakeInstruction(parser.OpDefineLocal, 1),
-				tengo.MakeInstruction(parser.OpJump, 31),
+				tengo.MakeInstruction(parser.OpJump, 35),
 				tengo.MakeInstruction(parser.OpConstant, 2),
 				tengo.MakeInstruction(parser.OpSetLocal, 0),
 				tengo.MakeInstruction(parser.OpGetLocal, 0),
diff --git a/vm_test.go b/vm_test.go
index 8c98b5a..49c93de 100644
--- a/vm_test.go
+++ b/vm_test.go
@@ -3634,6 +3634,12 @@ func TestSpread(t *testing.T) {
 		"Runtime Error: wrong number of arguments: want=3, got=2")
 }
 
+func TestSliceIndex(t *testing.T) {
+	expectError(t, `undefined[:1]`, nil, "Runtime Error: not indexable")
+	expectError(t, `123[-1:2]`, nil, "Runtime Error: not indexable")
+	expectError(t, `{}[:]`, nil, "Runtime Error: not indexable")
+}
+
 func expectRun(
 	t *testing.T,
 	input string,