diff --git a/src/import.go b/src/import.go index 0efb2b6..b070beb 100644 --- a/src/import.go +++ b/src/import.go @@ -7,6 +7,7 @@ import ( ) var imported = make(map[string]ArObject) +var translatedImports = make(map[string]translatedImport) var importing = make(map[string]bool) const modules_folder = "argon_modules" @@ -41,7 +42,58 @@ func readFile(path string) ([]UNPARSEcode, error) { 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) path := realpath if extention == "" { @@ -49,11 +101,11 @@ func importMod(realpath string, origin string, main bool, global ArObject) (ArOb } ex, err := os.Getwd() 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() 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) isABS := filepath.IsAbs(path) @@ -86,58 +138,26 @@ func importMod(realpath string, origin string, main bool, global ArObject) (ArOb } 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] { - return ArObject{}, ArErr{TYPE: "Import Error", message: "Circular import: " + path, EXISTS: true} - } else if _, ok := imported[p]; ok { - return imported[p], ArErr{} + return translatedImport{}, ArErr{TYPE: "Import Error", message: "Circular import: " + path, EXISTS: true} + } else if _, ok := translatedImports[p]; ok { + return translatedImports[p], ArErr{} } importing[p] = true codelines, err := readFile(p) 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) + importing[p] = false if translationerr.EXISTS { - return ArObject{}, translationerr + return translatedImport{}, translationerr } - 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(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{} + + translatedImports[p] = translatedImport{translated, p, path, ex, exc, origin} + return translatedImports[p], ArErr{} } diff --git a/src/main.go b/src/main.go index b023f9a..46ae1ff 100644 --- a/src/main.go +++ b/src/main.go @@ -61,11 +61,16 @@ func main() { if e != nil { panic(e) } - _, err := importMod(Args[0], ex, true, global) + translated, err := translateImport(Args[0], ex, true) if err.EXISTS { panicErr(err) os.Exit(1) } + _, runimeErr := runTranslatedImport(translated, global) + if runimeErr.EXISTS { + panicErr(runimeErr) + os.Exit(1) + } if threadCount > 0 { <-threadChan } diff --git a/src/parseImport.go b/src/parseImport.go index ad47cb8..e9fe82b 100644 --- a/src/parseImport.go +++ b/src/parseImport.go @@ -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}*))*)?( *)`) type ArImport struct { - FilePath any - Values any - Code string - Line int - Path string + pretranslated bool + translated translatedImport + FilePath any + Values any + Code string + Line int + Path string } 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, asStr, code.realcode, code.line, 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) { - val, err := runVal(importOBJ.FilePath, stack, stacklevel+1) - val = ArValidToAny(val) - if err.EXISTS { - return nil, err + var translated = importOBJ.translated + if !importOBJ.pretranslated { + val, err := runVal(importOBJ.FilePath, stack, stacklevel+1) + 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" { - 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]) + stackMap, err := runTranslatedImport(translated, stack[0]) if err.EXISTS { if err.line == 0 { err.line = importOBJ.Line @@ -116,7 +155,7 @@ func runImport(importOBJ ArImport, stack stack, stacklevel int) (any, ArErr) { for _, v := range x { val, ok := stackMap.obj[v] 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}) } diff --git a/tests/circular_import.ar b/tests/circular_import.ar new file mode 100644 index 0000000..71b749a --- /dev/null +++ b/tests/circular_import.ar @@ -0,0 +1 @@ +import "circular_test" \ No newline at end of file diff --git a/tests/circular_test.ar b/tests/circular_test.ar new file mode 100644 index 0000000..fac8c91 --- /dev/null +++ b/tests/circular_test.ar @@ -0,0 +1 @@ +import "circular_import" \ No newline at end of file diff --git a/tests/diff.ar b/tests/diff.ar index 3c1199e..94a3a65 100644 --- a/tests/diff.ar +++ b/tests/diff.ar @@ -1,5 +1,5 @@ -let zero = 1e-1000 -let diff(f) = (x) = (f(x + zero) - f(x)) / zero +let h = 1e-1000 +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