restructure project
This commit is contained in:
8
.gitignore
vendored
8
.gitignore
vendored
@@ -81,11 +81,13 @@ fabric.properties
|
|||||||
*-e
|
*-e
|
||||||
*.so
|
*.so
|
||||||
*.bak
|
*.bak
|
||||||
*.txt
|
*.out
|
||||||
*.swo
|
*.swo
|
||||||
*.swn
|
*.swn
|
||||||
.DS_Store
|
*.prof
|
||||||
|
|
||||||
|
**/.DS_Store
|
||||||
|
|
||||||
/dist
|
/dist
|
||||||
/.vscode
|
/.vscode
|
||||||
/monkey-lang
|
/monkey
|
||||||
@@ -3,18 +3,21 @@ package main
|
|||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/pkg/profile"
|
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"monkey/compiler"
|
|
||||||
"monkey/lexer"
|
|
||||||
"monkey/object"
|
|
||||||
"monkey/parser"
|
|
||||||
"monkey/repl"
|
|
||||||
"os"
|
"os"
|
||||||
"os/user"
|
"os/user"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/pkg/profile"
|
||||||
|
|
||||||
|
"monkey/internal"
|
||||||
|
"monkey/internal/compiler"
|
||||||
|
"monkey/internal/lexer"
|
||||||
|
"monkey/internal/object"
|
||||||
|
"monkey/internal/parser"
|
||||||
|
"monkey/internal/repl"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -66,7 +69,7 @@ func main() {
|
|||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
if version {
|
if version {
|
||||||
fmt.Printf("%s %s", path.Base(os.Args[0]), FullVersion())
|
fmt.Printf("%s %s", path.Base(os.Args[0]), internal.FullVersion())
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5,4 +5,10 @@ fib := fn(x) {
|
|||||||
return fib(x-1) + fib(x-2)
|
return fib(x-1) + fib(x-2)
|
||||||
}
|
}
|
||||||
|
|
||||||
print(fib(35))
|
N := 35
|
||||||
|
|
||||||
|
if (len(args()) == 1) {
|
||||||
|
N = int(args()[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
print(fib(N))
|
||||||
@@ -3,7 +3,7 @@ package ast
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"monkey/token"
|
"monkey/internal/token"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -2,7 +2,7 @@ package ast
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"monkey/token"
|
"monkey/internal/token"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package builtins
|
package builtins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Abs ...
|
// Abs ...
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package builtins
|
package builtins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package builtins
|
package builtins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Args ...
|
// Args ...
|
||||||
@@ -1,12 +1,9 @@
|
|||||||
package builtins
|
package builtins
|
||||||
|
|
||||||
import (
|
|
||||||
"monkey/object"
|
|
||||||
"monkey/typing"
|
|
||||||
)
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"monkey/internal/object"
|
||||||
|
"monkey/internal/typing"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -2,8 +2,8 @@ package builtins
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package builtins
|
package builtins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package builtins
|
package builtins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Bool ...
|
// Bool ...
|
||||||
@@ -2,7 +2,7 @@ package builtins
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"sort"
|
"sort"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -2,8 +2,8 @@ package builtins
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Chr ...
|
// Chr ...
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package builtins
|
package builtins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package builtins
|
package builtins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package builtins
|
package builtins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Divmod ...
|
// Divmod ...
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package builtins
|
package builtins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Exit ...
|
// Exit ...
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package builtins
|
package builtins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
)
|
)
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package builtins
|
package builtins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
"sort"
|
"sort"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package builtins
|
package builtins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// First ...
|
// First ...
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package builtins
|
package builtins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// HashOf ...
|
// HashOf ...
|
||||||
@@ -2,8 +2,8 @@ package builtins
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -2,8 +2,8 @@ package builtins
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// IdOf ...
|
// IdOf ...
|
||||||
@@ -1,14 +1,11 @@
|
|||||||
package builtins
|
package builtins
|
||||||
|
|
||||||
import (
|
|
||||||
"monkey/object"
|
|
||||||
"monkey/typing"
|
|
||||||
)
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"monkey/internal/object"
|
||||||
|
"monkey/internal/typing"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1,12 +1,11 @@
|
|||||||
package builtins
|
package builtins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
import "strconv"
|
|
||||||
|
|
||||||
// Int ...
|
// Int ...
|
||||||
func Int(args ...object.Object) object.Object {
|
func Int(args ...object.Object) object.Object {
|
||||||
if err := typing.Check(
|
if err := typing.Check(
|
||||||
@@ -1,11 +1,8 @@
|
|||||||
package builtins
|
package builtins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
)
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package builtins
|
package builtins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Last ...
|
// Last ...
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package builtins
|
package builtins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Len ...
|
// Len ...
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package builtins
|
package builtins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1,12 +1,11 @@
|
|||||||
package builtins
|
package builtins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
import "strings"
|
|
||||||
|
|
||||||
// Lower ...
|
// Lower ...
|
||||||
func Lower(args ...object.Object) object.Object {
|
func Lower(args ...object.Object) object.Object {
|
||||||
if err := typing.Check(
|
if err := typing.Check(
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package builtins
|
package builtins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
"sort"
|
"sort"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package builtins
|
package builtins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
"sort"
|
"sort"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -2,8 +2,8 @@ package builtins
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -3,8 +3,8 @@ package builtins
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
"os"
|
"os"
|
||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package builtins
|
package builtins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Ord ...
|
// Ord ...
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package builtins
|
package builtins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Pop ...
|
// Pop ...
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package builtins
|
package builtins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func pow(x, y int64) int64 {
|
func pow(x, y int64) int64 {
|
||||||
@@ -1,12 +1,11 @@
|
|||||||
package builtins
|
package builtins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"monkey/object"
|
"fmt"
|
||||||
"monkey/typing"
|
"monkey/internal/object"
|
||||||
|
"monkey/internal/typing"
|
||||||
)
|
)
|
||||||
|
|
||||||
import "fmt"
|
|
||||||
|
|
||||||
// Print ...
|
// Print ...
|
||||||
func Print(args ...object.Object) object.Object {
|
func Print(args ...object.Object) object.Object {
|
||||||
if err := typing.Check(
|
if err := typing.Check(
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package builtins
|
package builtins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Push ...
|
// Push ...
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package builtins
|
package builtins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -2,8 +2,8 @@ package builtins
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ReadFile ...
|
// ReadFile ...
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package builtins
|
package builtins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Rest ...
|
// Rest ...
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package builtins
|
package builtins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Reversed ...
|
// Reversed ...
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package builtins
|
package builtins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package builtins
|
package builtins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package builtins
|
package builtins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
"sort"
|
"sort"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1,11 +1,8 @@
|
|||||||
package builtins
|
package builtins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
)
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package builtins
|
package builtins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Str ...
|
// Str ...
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package builtins
|
package builtins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TypeOf ...
|
// TypeOf ...
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package builtins
|
package builtins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package builtins
|
package builtins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -2,8 +2,8 @@ package builtins
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/typing"
|
"monkey/internal/typing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// WriteFile ...
|
// WriteFile ...
|
||||||
@@ -3,10 +3,10 @@ package compiler
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"monkey/ast"
|
"monkey/internal/ast"
|
||||||
"monkey/builtins"
|
"monkey/internal/builtins"
|
||||||
"monkey/code"
|
"monkey/internal/code"
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@@ -3,11 +3,11 @@ package compiler
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"monkey/ast"
|
"monkey/internal/ast"
|
||||||
"monkey/code"
|
"monkey/internal/code"
|
||||||
"monkey/lexer"
|
"monkey/internal/lexer"
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/parser"
|
"monkey/internal/parser"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -2,12 +2,12 @@ package evaluator
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"monkey/ast"
|
"monkey/internal/ast"
|
||||||
"monkey/builtins"
|
"monkey/internal/builtins"
|
||||||
"monkey/lexer"
|
"monkey/internal/lexer"
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/parser"
|
"monkey/internal/parser"
|
||||||
"monkey/utils"
|
"monkey/internal/utils"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@@ -3,10 +3,10 @@ package evaluator
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"monkey/lexer"
|
"monkey/internal/lexer"
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/parser"
|
"monkey/internal/parser"
|
||||||
"monkey/utils"
|
"monkey/internal/utils"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -862,9 +862,9 @@ func TestImportExpressions(t *testing.T) {
|
|||||||
input string
|
input string
|
||||||
expected interface{}
|
expected interface{}
|
||||||
}{
|
}{
|
||||||
{`mod := import("../testdata/mod"); mod.A`, 5},
|
{`mod := import("../../testdata/mod"); mod.A`, 5},
|
||||||
{`mod := import("../testdata/mod"); mod.Sum(2, 3)`, 5},
|
{`mod := import("../../testdata/mod"); mod.Sum(2, 3)`, 5},
|
||||||
{`mod := import("../testdata/mod"); mod.a`, nil},
|
{`mod := import("../../testdata/mod"); mod.a`, nil},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
@@ -890,7 +890,7 @@ func TestImportSearchPaths(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestExamples(t *testing.T) {
|
func TestExamples(t *testing.T) {
|
||||||
matches, err := filepath.Glob("./examples/*.monkey")
|
matches, err := filepath.Glob("../../examples/*.monkey")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,7 @@ package lexer
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"monkey/token"
|
"monkey/internal/token"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package lexer
|
package lexer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"monkey/token"
|
"monkey/internal/token"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -2,7 +2,7 @@ package object
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"monkey/code"
|
"monkey/internal/code"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CompiledFunction struct {
|
type CompiledFunction struct {
|
||||||
@@ -2,7 +2,7 @@ package object
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"monkey/ast"
|
"monkey/internal/ast"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -2,9 +2,9 @@ package parser
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"monkey/ast"
|
"monkey/internal/ast"
|
||||||
"monkey/lexer"
|
"monkey/internal/lexer"
|
||||||
"monkey/token"
|
"monkey/internal/token"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -3,8 +3,8 @@ package parser
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"monkey/ast"
|
"monkey/internal/ast"
|
||||||
"monkey/lexer"
|
"monkey/internal/lexer"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package main
|
package internal
|
||||||
|
|
||||||
import "monkey/object"
|
import "monkey/internal/object"
|
||||||
|
|
||||||
// Hello ...
|
// Hello ...
|
||||||
func Hello(args ...object.Object) object.Object {
|
func Hello(args ...object.Object) object.Object {
|
||||||
@@ -8,12 +8,12 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"monkey/compiler"
|
"monkey/internal/compiler"
|
||||||
"monkey/evaluator"
|
"monkey/internal/evaluator"
|
||||||
"monkey/lexer"
|
"monkey/internal/lexer"
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/parser"
|
"monkey/internal/parser"
|
||||||
"monkey/vm"
|
"monkey/internal/vm"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -2,7 +2,7 @@ package typing
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CheckFunc func(name string, args []object.Object) error
|
type CheckFunc func(name string, args []object.Object) error
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package main
|
package internal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
270
internal/vm/cache.go
Normal file
270
internal/vm/cache.go
Normal file
@@ -0,0 +1,270 @@
|
|||||||
|
package vm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"container/list"
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type cachedFrame struct {
|
||||||
|
Key uint // pointer to key
|
||||||
|
Value *Frame // pointer to value
|
||||||
|
Frequency uint // frequency of access
|
||||||
|
}
|
||||||
|
|
||||||
|
type frequencyNode struct {
|
||||||
|
count uint // frequency count - never decreases
|
||||||
|
valuesList *list.List // valuesList contains pointer to the head of values linked list
|
||||||
|
inner *list.Element // actual content of the next element
|
||||||
|
}
|
||||||
|
|
||||||
|
// creates a new frequency list node with the given count
|
||||||
|
func newFrequencyNode(count uint) *frequencyNode {
|
||||||
|
return &frequencyNode{
|
||||||
|
count: count,
|
||||||
|
valuesList: list.New(),
|
||||||
|
inner: nil,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type keyRefNode struct {
|
||||||
|
inner *list.Element // contains the actual value wrapped by a list element
|
||||||
|
parentFreqNode *list.Element // contains reference to the frequency node element
|
||||||
|
keyRef uint // contains pointer to the key
|
||||||
|
valueRef *Frame // value
|
||||||
|
}
|
||||||
|
|
||||||
|
// creates a new KeyRef node which is used to represent the value in linked list
|
||||||
|
func newKeyRefNode(keyRef uint, valueRef *Frame, parent *list.Element) *keyRefNode {
|
||||||
|
return &keyRefNode{
|
||||||
|
inner: nil,
|
||||||
|
parentFreqNode: parent,
|
||||||
|
keyRef: keyRef,
|
||||||
|
valueRef: valueRef,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FrameCache implements all the methods and data-structures required for a LFU cache for caching frames.
|
||||||
|
type FrameCache struct {
|
||||||
|
rwLock sync.RWMutex // rwLock is a read-write mutex which provides concurrent reads but exclusive writes
|
||||||
|
lookupTable map[uint]*keyRefNode // a hash table of <KeyType, *ValueType> for quick reference of values based on keys
|
||||||
|
frequencies *list.List // internal linked list that contains frequency mapping
|
||||||
|
maxSize uint // maxSize represents the maximum number of elements that can be in the cache before eviction
|
||||||
|
}
|
||||||
|
|
||||||
|
// MaxSize returns the maximum size of the cache at that point in time
|
||||||
|
func (lfu *FrameCache) MaxSize() uint {
|
||||||
|
lfu.rwLock.RLock()
|
||||||
|
defer lfu.rwLock.RUnlock()
|
||||||
|
|
||||||
|
return lfu.maxSize
|
||||||
|
}
|
||||||
|
|
||||||
|
// CurrentSize returns the number of elements in that cache
|
||||||
|
func (lfu *FrameCache) CurrentSize() uint {
|
||||||
|
lfu.rwLock.RLock()
|
||||||
|
defer lfu.rwLock.RUnlock()
|
||||||
|
|
||||||
|
return uint(len(lfu.lookupTable))
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsFull checks if the LFU cache is full
|
||||||
|
func (lfu *FrameCache) IsFull() bool {
|
||||||
|
lfu.rwLock.RLock()
|
||||||
|
defer lfu.rwLock.RUnlock()
|
||||||
|
|
||||||
|
return uint(len(lfu.lookupTable)) == lfu.maxSize
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMaxSize updates the max size of the LFU cache
|
||||||
|
func (lfu *FrameCache) SetMaxSize(size uint) {
|
||||||
|
lfu.rwLock.Lock()
|
||||||
|
defer lfu.rwLock.Unlock()
|
||||||
|
|
||||||
|
lfu.maxSize = size
|
||||||
|
}
|
||||||
|
|
||||||
|
// evict the least recently used element from the cache, this function is unsafe to be called externally
|
||||||
|
// because it doesn't provide locking mechanism.
|
||||||
|
func (lfu *FrameCache) unsafeEvict() error {
|
||||||
|
// WARNING: This function assumes that a write lock has been held by the caller already
|
||||||
|
|
||||||
|
// get the head node of the list
|
||||||
|
headFreq := lfu.frequencies.Front()
|
||||||
|
if headFreq == nil {
|
||||||
|
// list is empty, this is a very unusual condition
|
||||||
|
return fmt.Errorf("internal error: failed to evict, empty frequency list")
|
||||||
|
}
|
||||||
|
|
||||||
|
headFreqInner := (headFreq.Value).(*frequencyNode)
|
||||||
|
|
||||||
|
if headFreqInner.valuesList.Len() == 0 {
|
||||||
|
// again this is a very unusual condition
|
||||||
|
return fmt.Errorf("internal error: failed to evict, empty values list")
|
||||||
|
}
|
||||||
|
|
||||||
|
headValuesList := headFreqInner.valuesList
|
||||||
|
// pop the head of this this values list
|
||||||
|
headValueNode := headValuesList.Front()
|
||||||
|
removeResult := headValuesList.Remove(headValueNode).(*keyRefNode)
|
||||||
|
|
||||||
|
// update the values list
|
||||||
|
headFreqInner.valuesList = headValuesList
|
||||||
|
|
||||||
|
if headFreqInner.valuesList.Len() == 0 && headFreqInner.count > 1 {
|
||||||
|
// this node can be removed from the frequency list
|
||||||
|
freqList := lfu.frequencies
|
||||||
|
freqList.Remove(headFreq)
|
||||||
|
lfu.frequencies = freqList
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove the key from lookup table
|
||||||
|
key := removeResult.keyRef
|
||||||
|
delete(lfu.lookupTable, key)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put method inserts a `<KeyType, ValueType>` to the LFU cache and updates internal
|
||||||
|
// data structures to keep track of access frequencies, if the cache is full, it evicts the
|
||||||
|
// least frequently used value from the cache.
|
||||||
|
func (lfu *FrameCache) Put(key uint, value *Frame) error {
|
||||||
|
// get write lock
|
||||||
|
lfu.rwLock.Lock()
|
||||||
|
defer lfu.rwLock.Unlock()
|
||||||
|
|
||||||
|
if _, ok := lfu.lookupTable[key]; ok {
|
||||||
|
// update the cache value
|
||||||
|
lfu.lookupTable[key].valueRef = value
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if lfu.maxSize == uint(len(lfu.lookupTable)) {
|
||||||
|
lfu.unsafeEvict()
|
||||||
|
}
|
||||||
|
|
||||||
|
valueNode := newKeyRefNode(key, value, nil)
|
||||||
|
|
||||||
|
head := lfu.frequencies.Front()
|
||||||
|
if head == nil {
|
||||||
|
// fresh linked list
|
||||||
|
freqNode := newFrequencyNode(1)
|
||||||
|
head = lfu.frequencies.PushFront(freqNode)
|
||||||
|
freqNode.inner = head
|
||||||
|
|
||||||
|
} else {
|
||||||
|
node := head.Value.(*frequencyNode)
|
||||||
|
if node.count != 1 {
|
||||||
|
freqNode := newFrequencyNode(1)
|
||||||
|
head = lfu.frequencies.PushFront(freqNode)
|
||||||
|
freqNode.inner = head
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
valueNode.parentFreqNode = head
|
||||||
|
node := head.Value.(*frequencyNode)
|
||||||
|
head = node.valuesList.PushBack(valueNode)
|
||||||
|
valueNode.inner = head
|
||||||
|
|
||||||
|
lfu.lookupTable[key] = valueNode
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Evict can be called to manually perform eviction
|
||||||
|
func (lfu *FrameCache) Evict() error {
|
||||||
|
lfu.rwLock.Lock()
|
||||||
|
defer lfu.rwLock.Unlock()
|
||||||
|
|
||||||
|
return lfu.unsafeEvict()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lfu *FrameCache) unsafeUpdateFrequency(valueNode *keyRefNode) {
|
||||||
|
parentFreqNode := valueNode.parentFreqNode
|
||||||
|
currentNode := parentFreqNode.Value.(*frequencyNode)
|
||||||
|
nextParentFreqNode := parentFreqNode.Next()
|
||||||
|
|
||||||
|
var newParent *list.Element = nil
|
||||||
|
|
||||||
|
if nextParentFreqNode == nil {
|
||||||
|
// this is the last node
|
||||||
|
// create a new node with frequency + 1
|
||||||
|
newFreqNode := newFrequencyNode(currentNode.count + 1)
|
||||||
|
lfu.frequencies.PushBack(newFreqNode)
|
||||||
|
newParent = parentFreqNode.Next()
|
||||||
|
|
||||||
|
} else {
|
||||||
|
nextNode := nextParentFreqNode.Value.(*frequencyNode)
|
||||||
|
if nextNode.count == (currentNode.count + 1) {
|
||||||
|
newParent = nextParentFreqNode
|
||||||
|
} else {
|
||||||
|
// insert a node in between
|
||||||
|
newFreqNode := newFrequencyNode(currentNode.count + 1)
|
||||||
|
|
||||||
|
lfu.frequencies.InsertAfter(newFreqNode, parentFreqNode)
|
||||||
|
newParent = parentFreqNode.Next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove from the existing list
|
||||||
|
currentNode.valuesList.Remove(valueNode.inner)
|
||||||
|
|
||||||
|
newParentNode := newParent.Value.(*frequencyNode)
|
||||||
|
valueNode.parentFreqNode = newParent
|
||||||
|
newValueNode := newParentNode.valuesList.PushBack(valueNode)
|
||||||
|
valueNode.inner = newValueNode
|
||||||
|
|
||||||
|
// check if the current node is empty
|
||||||
|
if currentNode.valuesList.Len() == 0 {
|
||||||
|
// remove the current node
|
||||||
|
lfu.frequencies.Remove(parentFreqNode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get can be called to obtain the value for given key
|
||||||
|
func (lfu *FrameCache) Get(key uint) (*Frame, bool) {
|
||||||
|
lfu.rwLock.Lock()
|
||||||
|
defer lfu.rwLock.Unlock()
|
||||||
|
|
||||||
|
// check if data is in the map
|
||||||
|
valueNode, found := lfu.lookupTable[key]
|
||||||
|
if !found {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
lfu.unsafeUpdateFrequency(valueNode)
|
||||||
|
|
||||||
|
return valueNode.valueRef, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete removes the specified entry from LFU cache
|
||||||
|
func (lfu *FrameCache) Delete(key uint) error {
|
||||||
|
lfu.rwLock.Lock()
|
||||||
|
defer lfu.rwLock.Unlock()
|
||||||
|
|
||||||
|
// check if the key is in the map
|
||||||
|
valueNode, found := lfu.lookupTable[key]
|
||||||
|
if !found {
|
||||||
|
return fmt.Errorf("key %v not found", key)
|
||||||
|
}
|
||||||
|
|
||||||
|
parentFreqNode := valueNode.parentFreqNode
|
||||||
|
|
||||||
|
currentNode := (parentFreqNode.Value).(*frequencyNode)
|
||||||
|
currentNode.valuesList.Remove(valueNode.inner)
|
||||||
|
|
||||||
|
if currentNode.valuesList.Len() == 0 {
|
||||||
|
lfu.frequencies.Remove(parentFreqNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(lfu.lookupTable, key)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFrameCache ...
|
||||||
|
func NewFrameCache(maxSize uint) *FrameCache {
|
||||||
|
return &FrameCache{
|
||||||
|
rwLock: sync.RWMutex{},
|
||||||
|
lookupTable: make(map[uint]*keyRefNode),
|
||||||
|
maxSize: maxSize,
|
||||||
|
frequencies: list.New(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,13 @@
|
|||||||
package vm
|
package vm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"monkey/code"
|
"monkey/internal/code"
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var cache = NewFrameCache(32)
|
||||||
|
|
||||||
type Frame struct {
|
type Frame struct {
|
||||||
cl *object.Closure
|
cl *object.Closure
|
||||||
ip int
|
ip int
|
||||||
@@ -12,16 +15,32 @@ type Frame struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewFrame(cl *object.Closure, basePointer int) *Frame {
|
func NewFrame(cl *object.Closure, basePointer int) *Frame {
|
||||||
return &Frame{
|
key := uint(uintptr(unsafe.Pointer(cl))) + uint(basePointer)
|
||||||
|
if frame, ok := cache.Get(key); ok {
|
||||||
|
frame.Reset()
|
||||||
|
return frame
|
||||||
|
}
|
||||||
|
|
||||||
|
frame := &Frame{
|
||||||
cl: cl,
|
cl: cl,
|
||||||
ip: -1,
|
ip: -1,
|
||||||
basePointer: basePointer}
|
basePointer: basePointer,
|
||||||
|
}
|
||||||
|
|
||||||
|
cache.Put(key, frame)
|
||||||
|
|
||||||
|
return frame
|
||||||
|
}
|
||||||
|
|
||||||
|
// NextOp ...
|
||||||
|
func (f *Frame) NextOp() code.Opcode {
|
||||||
|
return code.Opcode(f.Instructions()[f.ip+1])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Frame) Reset() {
|
||||||
|
f.ip = -1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Frame) Instructions() code.Instructions {
|
func (f *Frame) Instructions() code.Instructions {
|
||||||
return f.cl.Fn.Instructions
|
return f.cl.Fn.Instructions
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Frame) NextOp() code.Opcode {
|
|
||||||
return code.Opcode(f.Instructions()[f.ip+1])
|
|
||||||
}
|
|
||||||
@@ -4,13 +4,13 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"monkey/builtins"
|
"monkey/internal/builtins"
|
||||||
"monkey/code"
|
"monkey/internal/code"
|
||||||
"monkey/compiler"
|
"monkey/internal/compiler"
|
||||||
"monkey/lexer"
|
"monkey/internal/lexer"
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/parser"
|
"monkey/internal/parser"
|
||||||
"monkey/utils"
|
"monkey/internal/utils"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode"
|
"unicode"
|
||||||
)
|
)
|
||||||
@@ -2,12 +2,12 @@ package vm
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"monkey/ast"
|
"monkey/internal/ast"
|
||||||
"monkey/compiler"
|
"monkey/internal/compiler"
|
||||||
"monkey/lexer"
|
"monkey/internal/lexer"
|
||||||
"monkey/object"
|
"monkey/internal/object"
|
||||||
"monkey/parser"
|
"monkey/internal/parser"
|
||||||
"monkey/utils"
|
"monkey/internal/utils"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -1185,15 +1185,15 @@ func BenchmarkFibonacci(b *testing.B) {
|
|||||||
func TestImportExpressions(t *testing.T) {
|
func TestImportExpressions(t *testing.T) {
|
||||||
tests := []vmTestCase{
|
tests := []vmTestCase{
|
||||||
{
|
{
|
||||||
input: `mod := import("../testdata/mod"); mod.A`,
|
input: `mod := import("../../testdata/mod"); mod.A`,
|
||||||
expected: 5,
|
expected: 5,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: `mod := import("../testdata/mod"); mod.Sum(2, 3)`,
|
input: `mod := import("../../testdata/mod"); mod.Sum(2, 3)`,
|
||||||
expected: 5,
|
expected: 5,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: `mod := import("../testdata/mod"); mod.a`,
|
input: `mod := import("../../testdata/mod"); mod.a`,
|
||||||
expected: nil,
|
expected: nil,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -1202,11 +1202,11 @@ func TestImportExpressions(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestImportSearchPaths(t *testing.T) {
|
func TestImportSearchPaths(t *testing.T) {
|
||||||
utils.AddPath("../testdata")
|
utils.AddPath("../../testdata")
|
||||||
|
|
||||||
tests := []vmTestCase{
|
tests := []vmTestCase{
|
||||||
{
|
{
|
||||||
input: `mod := import("../testdata/mod"); mod.A`,
|
input: `mod := import("../../testdata/mod"); mod.A`,
|
||||||
expected: 5,
|
expected: 5,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user