parse imports with fixed paths before running all the code

This commit is contained in:
2024-02-23 21:50:53 +00:00
parent 7f86d345ae
commit b3a07d7f63
6 changed files with 134 additions and 68 deletions

View File

@@ -7,6 +7,7 @@ import (
) )
var imported = make(map[string]ArObject) var imported = make(map[string]ArObject)
var translatedImports = make(map[string]translatedImport)
var importing = make(map[string]bool) var importing = make(map[string]bool)
const modules_folder = "argon_modules" const modules_folder = "argon_modules"
@@ -41,7 +42,58 @@ func readFile(path string) ([]UNPARSEcode, error) {
return output, nil return output, nil
} }
func importMod(realpath string, origin string, main bool, global ArObject) (ArObject, ArErr) { type translatedImport struct {
translated []any
p string
path string
ex string
exc string
origin string
}
var runTranslatedImport func(translatedImport, ArObject) (ArObject, ArErr)
func init() {
runTranslatedImport = __runTranslatedImport
}
func __runTranslatedImport(translatedImport translatedImport, global ArObject) (ArObject, ArErr) {
if _, ok := imported[translatedImport.p]; ok {
return imported[translatedImport.p], ArErr{}
}
ArgsArArray := []any{}
withoutarfile := []string{}
if len(Args) > 1 {
withoutarfile = Args[1:]
}
for _, arg := range withoutarfile {
ArgsArArray = append(ArgsArArray, arg)
}
local := newscope()
localvars := Map(anymap{
"program": Map(anymap{
"args": ArArray(ArgsArArray),
"origin": ArString(translatedImport.origin),
"cwd": ArString(translatedImport.ex),
"exc": ArString(translatedImport.exc),
"file": Map(anymap{
"name": ArString(filepath.Base(translatedImport.p)),
"path": ArString(translatedImport.p),
}),
"main": main,
}),
})
_, runimeErr := run(translatedImport.translated, stack{global, localvars, local})
if runimeErr.EXISTS {
return ArObject{}, runimeErr
}
imported[translatedImport.p] = local
return local, ArErr{}
}
func translateImport(realpath string, origin string, main bool) (translatedImport, ArErr) {
extention := filepath.Ext(realpath) extention := filepath.Ext(realpath)
path := realpath path := realpath
if extention == "" { if extention == "" {
@@ -49,11 +101,11 @@ func importMod(realpath string, origin string, main bool, global ArObject) (ArOb
} }
ex, err := os.Getwd() ex, err := os.Getwd()
if err != nil { if err != nil {
return ArObject{}, ArErr{TYPE: "Import Error", message: "Could not get working directory", EXISTS: true} return translatedImport{}, ArErr{TYPE: "Import Error", message: "Could not get working directory", EXISTS: true}
} }
exc, err := os.Executable() exc, err := os.Executable()
if err != nil { if err != nil {
return ArObject{}, ArErr{TYPE: "Import Error", message: "Could not get executable", EXISTS: true} return translatedImport{}, ArErr{TYPE: "Import Error", message: "Could not get executable", EXISTS: true}
} }
executable := filepath.Dir(exc) executable := filepath.Dir(exc)
isABS := filepath.IsAbs(path) isABS := filepath.IsAbs(path)
@@ -86,58 +138,26 @@ func importMod(realpath string, origin string, main bool, global ArObject) (ArOb
} }
if !found { if !found {
return ArObject{}, ArErr{TYPE: "Import Error", message: "File does not exist: " + path, EXISTS: true} return translatedImport{}, ArErr{TYPE: "Import Error", message: "File does not exist: " + path, EXISTS: true}
} else if importing[p] { } else if importing[p] {
return ArObject{}, ArErr{TYPE: "Import Error", message: "Circular import: " + path, EXISTS: true} return translatedImport{}, ArErr{TYPE: "Import Error", message: "Circular import: " + path, EXISTS: true}
} else if _, ok := imported[p]; ok { } else if _, ok := translatedImports[p]; ok {
return imported[p], ArErr{} return translatedImports[p], ArErr{}
} }
importing[p] = true importing[p] = true
codelines, err := readFile(p) codelines, err := readFile(p)
if err != nil { if err != nil {
return ArObject{}, ArErr{TYPE: "Import Error", message: "Could not read file: " + path, EXISTS: true} return translatedImport{}, ArErr{TYPE: "Import Error", message: "Could not read file: " + path, EXISTS: true}
} }
importing[p] = true
translated, translationerr := translate(codelines) translated, translationerr := translate(codelines)
importing[p] = false
if translationerr.EXISTS { if translationerr.EXISTS {
return ArObject{}, translationerr return translatedImport{}, translationerr
} }
ArgsArArray := []any{}
withoutarfile := []string{} translatedImports[p] = translatedImport{translated, p, path, ex, exc, origin}
if len(Args) > 1 { return translatedImports[p], ArErr{}
withoutarfile = Args[1:]
}
for _, arg := range withoutarfile {
ArgsArArray = append(ArgsArArray, arg)
}
local := newscope()
localvars := Map(anymap{
"program": Map(anymap{
"args": ArArray(ArgsArArray),
"origin": ArString(origin),
"import": builtinFunc{"import", func(args ...any) (any, ArErr) {
if len(args) != 1 {
return nil, ArErr{"Import Error", "Invalid number of arguments", 0, realpath, "", true}
}
if _, ok := args[0].(string); !ok {
return nil, ArErr{"Import Error", "Invalid argument type", 0, realpath, "", true}
}
return importMod(args[0].(string), filepath.Dir(filepath.ToSlash(p)), false, global)
}},
"cwd": ArString(ex),
"exc": ArString(exc),
"file": Map(anymap{
"name": ArString(filepath.Base(p)),
"path": ArString(p),
}),
"main": main,
}),
})
_, runimeErr := run(translated, stack{global, localvars, local})
importing[p] = false
if runimeErr.EXISTS {
return ArObject{}, runimeErr
}
imported[p] = local
return local, ArErr{}
} }

View File

@@ -61,11 +61,16 @@ func main() {
if e != nil { if e != nil {
panic(e) panic(e)
} }
_, err := importMod(Args[0], ex, true, global) translated, err := translateImport(Args[0], ex, true)
if err.EXISTS { if err.EXISTS {
panicErr(err) panicErr(err)
os.Exit(1) os.Exit(1)
} }
_, runimeErr := runTranslatedImport(translated, global)
if runimeErr.EXISTS {
panicErr(runimeErr)
os.Exit(1)
}
if threadCount > 0 { if threadCount > 0 {
<-threadChan <-threadChan
} }

View File

@@ -8,11 +8,13 @@ import (
var genericImportCompiled = makeRegex(`import( )+(.|\n)+(( )+as( )+([a-zA-Z_]|(\p{L}\p{M}*))([a-zA-Z0-9_]|(\p{L}\p{M}*))*)?( *)`) var genericImportCompiled = makeRegex(`import( )+(.|\n)+(( )+as( )+([a-zA-Z_]|(\p{L}\p{M}*))([a-zA-Z0-9_]|(\p{L}\p{M}*))*)?( *)`)
type ArImport struct { type ArImport struct {
FilePath any pretranslated bool
Values any translated translatedImport
Code string FilePath any
Line int Values any
Path string Code string
Line int
Path string
} }
func isGenericImport(code UNPARSEcode) bool { func isGenericImport(code UNPARSEcode) bool {
@@ -67,27 +69,64 @@ func parseGenericImport(code UNPARSEcode, index int, codeline []UNPARSEcode) (Ar
} }
} }
return ArImport{ importOBJ := ArImport{
false,
translatedImport{},
toImport, toImport,
asStr, asStr,
code.realcode, code.realcode,
code.line, code.line,
code.path, code.path,
}, true, ArErr{}, i }
if str, ok := toImport.(string); ok {
importOBJ.pretranslated = true
var err ArErr
importOBJ.translated, err = translateImport(str, filepath.Dir(filepath.ToSlash(code.path)), false)
if err.EXISTS {
if err.line == 0 {
err.line = importOBJ.Line
}
if err.path == "" {
err.path = importOBJ.Path
}
if err.code == "" {
err.code = importOBJ.Code
}
return importOBJ, false, err, i
}
}
return importOBJ, true, ArErr{}, i
} }
func runImport(importOBJ ArImport, stack stack, stacklevel int) (any, ArErr) { func runImport(importOBJ ArImport, stack stack, stacklevel int) (any, ArErr) {
val, err := runVal(importOBJ.FilePath, stack, stacklevel+1) var translated = importOBJ.translated
val = ArValidToAny(val) if !importOBJ.pretranslated {
if err.EXISTS { val, err := runVal(importOBJ.FilePath, stack, stacklevel+1)
return nil, err val = ArValidToAny(val)
if err.EXISTS {
return nil, err
}
if typeof(val) != "string" {
return nil, ArErr{"Type Error", "import requires a string, got type '" + typeof(val) + "'", importOBJ.Line, importOBJ.Path, importOBJ.Code, true}
}
parent := filepath.Dir(filepath.ToSlash(importOBJ.Path))
translated, err = translateImport(val.(string), parent, false)
if err.EXISTS {
if err.line == 0 {
err.line = importOBJ.Line
}
if err.path == "" {
err.path = importOBJ.Path
}
if err.code == "" {
err.code = importOBJ.Code
}
return nil, err
}
} }
if typeof(val) != "string" { stackMap, err := runTranslatedImport(translated, stack[0])
return nil, ArErr{"Type Error", "import requires a string, got type '" + typeof(val) + "'", importOBJ.Line, importOBJ.Path, importOBJ.Code, true}
}
path := val.(string)
parent := filepath.Dir(filepath.ToSlash(importOBJ.Path))
stackMap, err := importMod(path, parent, false, stack[0])
if err.EXISTS { if err.EXISTS {
if err.line == 0 { if err.line == 0 {
err.line = importOBJ.Line err.line = importOBJ.Line
@@ -116,7 +155,7 @@ func runImport(importOBJ ArImport, stack stack, stacklevel int) (any, ArErr) {
for _, v := range x { for _, v := range x {
val, ok := stackMap.obj[v] val, ok := stackMap.obj[v]
if !ok { if !ok {
return nil, ArErr{"Import Error", "could not find value " + anyToArgon(v, true, false, 3, 0, false, 0) + " in module " + anyToArgon(path, true, false, 3, 0, false, 0), importOBJ.Line, importOBJ.Path, importOBJ.Code, true} return nil, ArErr{"Import Error", "could not find value " + anyToArgon(v, true, false, 3, 0, false, 0) + " in module " + anyToArgon(translated.path, true, false, 3, 0, false, 0), importOBJ.Line, importOBJ.Path, importOBJ.Code, true}
} }
builtinCall(setindex, []any{v, val}) builtinCall(setindex, []any{v, val})
} }

1
tests/circular_import.ar Normal file
View File

@@ -0,0 +1 @@
import "circular_test"

1
tests/circular_test.ar Normal file
View File

@@ -0,0 +1 @@
import "circular_import"

View File

@@ -1,5 +1,5 @@
let zero = 1e-1000 let h = 1e-1000
let diff(f) = (x) = (f(x + zero) - f(x)) / zero let diff(f) = (x) = (f(x + h) - f(x)) / h
let f(x) = x^10+x^9+x^8+x^7+x^6+x^5+x^4+x^3+x^2+x+1 let f(x) = x^10+x^9+x^8+x^7+x^6+x^5+x^4+x^3+x^2+x+1