Files
gsc.src
- // GreyScript Compiler (gsc)
- // This program is self-hosting. THE FIRST TIME YOU COMPILE, however, you will
- // need to insert an import code directive with the absolute path to Util.src
- // If the first file specified for building contains "// @import" then the built
- // binary will be importable irrespective of passed arguments.
- // @dep:Util.src
- // @import
- // To use this as a library, create a Globals.src and unset GSC_STANDALONE.
- // Your main script should FIRST depend on Globals.src and secondly on gsc.
- // The global object "GsCompiler" will be available to you.
- if not globals.hasIndex("GSC_STANDALONE") then globals.GSC_STANDALONE = true
- if GSC_STANDALONE and params.len == 0 then exit("Nothing to compile")
- __scope = function()
- absPath = function(path)
- if path[0] == "/" then return path
- if path == "." then return current_path
- if path == ".." then return get_shell.host_computer.File(current_path).parent_path
- return current_path + "/" + path
- end function
- Dep = {}
- Dep._shl = get_shell
- Dep._comp = Dep._shl.host_computer
- Dep.build = function(files, depList = null)
- if depList == null then depList = {}
- ret = self._build(files.pull, depList)
- for file in files
- ret._subDeps.push(outer.self._build(file, outer.depList))
- end for
- errors = ret._get_errors
- if errors then return errors
- return ret
- end function
- Dep._build = function(file, depList)
- ret = new self
- ret._depList = depList
- ret._subDeps = []
- ret._file = absPath(file)
- ret._depList[ret._file] = true
- ret._error = ret._process
- return ret
- end function
- Dep._get_errors = function(self)
- return self._error + self._subDeps.flatMap(@self._get_errors).join("")
- end function
- Dep.filterStr = function(str)
- return str.indexOf("// @dep:") == 0 or str.indexOf("//@dep:") == 0
- end function
- Dep.mapDeps = function(str)
- return str.split("@dep:")[1].trim
- end function
- Dep.toSubDep = function(self, str)
- return self._build(str, self._depList)
- end function
- Dep.makeCurry = function(toCurry)
- self = self
- ret = function(obj)
- return toCurry(outer.self, obj)
- end function
- return @ret
- end function
- Dep._process = function()
- file = self._comp.File(self._file)
- if not file then return "Unable to open " + self._file + "\n"
- if file.is_binary then return ""
- self._subDeps = file.get_content.
- split(char(10)).
- filter(@self.filterStr).
- map(@self.mapDeps).
- map(self.makeCurry(@self.toSubDep))
- return ""
- end function
- Dep._collect = function(self)
- return self._subDeps.flatMap(@self._collect) + [self._file]
- end function
- Dep.collect = function(self)
- return self._collect.unique
- end function
- Builder = {}
- Builder._shl = Dep._shl
- Builder._comp = Dep._shl.host_computer
- Builder.makeStr = function(str)
- // GreyHack is stupid, this is required.
- return "import" + "_code(""" + str + """)"
- end function
- Builder.init = function(files, outFile, stdout = null)
- ret = new self
- if not stdout then stdout = @print
- mainFile = files[0]
- ret._import = self._comp.File(mainFile).
- get_content.
- split(char(10)).
- findOrElse("// @import", "").
- indexOf("// @import") == 0
- ret._root = Dep.build(files)
- if not ret._root isa Dep then return ret._root
- out = absPath(outFile).split("/")
- ret._outDir = out[:-1].join("/")
- ret._outName = out[-1]
- f = self._comp.File(outFile)
- if f and f.is_folder then
- ret._outDir = outFile
- ret._outName = self._comp.File(mainFile).name.replace("\.src", "")
- end if
- ret._stdout = @stdout
- s = "Compiling "
- if ret._import then s = s + "importable "
- stdout s + "to: " + ret._outDir + "/" + ret._outName
- return ret
- end function
- Builder.compile = function(allowImport, verbose, keepTempFile)
- depStrs = self._root.collect
if not self._comp.touch(current_path, "0.") then exit("Unable to create temp file. No permissions?")
tmpFile = self._comp.File(current_path + "/0.")
- if not self._comp.touch(current_path, "__gscTemp0P.src") then exit("Unable to create temp file. No permissions?")
- tmpFile = self._comp.File(current_path + "/__gscTemp0P.src")
- if verbose then depStrs.forEach(@self._stdout)
- tmpFile.set_content depStrs.map(@self.makeStr).join(char(10))
- ret = self._shl.build(tmpFile.path, current_path, allowImport or self._import)
- if not keepTempFile then tmpFile.delete
bin = self._comp.File(current_path + "/0")
- bin = self._comp.File(current_path + "/__gscTemp0P")
- if bin then bin.move(self._outDir, self._outName)
- return ret
- end function
- if get_custom_object.hasIndex("__Gsh") then globals.print = get_custom_object.__Gsh[0]
- ArgP = {}
- ArgP.verbose = false
- ArgP.keepTempFile = false
- ArgP.allowImport = false
- ArgP["-h"] = function()
- print "GreyScript Compiler - v0.1.0\n"
- print "Designed to support nested permissions. Instead of using import code."
- print "You should place (for example) ""// @dep:MyDep.src"" somewhere in your code.\n"
- print "<b>Relative paths in source code must match where you run this compiler.</b>"
- print "Argument format: gsc [-t/--keep-temp-file] [-v/--verbose] [-i/--importable] file.src... [OUTFILE]\n"
- print "-t: Keep the 0. file that is generated in the working dir when compiling."
- print "-v: Write the dependency chain to the terminal. This should match the temp file.\n"
- print "-i: Make the generated binary importable. This is also true if the first source file"
- print " that you pass contains ""// @import"" anywhere in the file. Other files are ignored."
- print "-h: Print this help info"
- exit "If you do not supply an output file name, it will default to the first source file's name"
- end function
- ArgP["--help"] = @ArgP["-h"]
- ArgP["-t"] = function()
- self.keepTempFile = true
- end function
- ArgP["--keep-temp-file"] = @ArgP["-t"]
- ArgP["-v"] = function()
- self.verbose = true
- end function
- ArgP["--verbose"] = @ArgP["-v"]
- ArgP["-i"] = function()
- self.allowImport = true
- end function
- ArgP["--importable"] = @ArgP["-i"]
- ArgP.tocwd = function(path)
- return current_path + "/" + path.split("/")[-1]
- end function
- ArgP.main = function()
- while params.len > 0 and params[0][0] == "-"
- arg = params.pull
- if self.hasIndex(arg) then self[arg]()
- end while
- src_files = function(s)
- return s.indexOf(".src") != null
- end function
- not_file = function(s); return not src_files(s); end function
- files = params.filter(@src_files)
- outFile = params.findOrElse(@not_file, self.tocwd(files[0].replace("\.src", "")))
- b = Builder.init(files, outFile)
- if not b isa Builder then return print(b + "Compilation failed")
- err = b.compile(self.allowImport, self.verbose, self.keepTempFile)
- if err then print(err)
- end function
- if GSC_STANDALONE then ArgP.main()
- return Builder
- end function // end scope
- globals.GsCompiler = __scope