├── Run.hx ├── test ├── TestProject.hx ├── TestConfig.hx └── TestMain.hx ├── .haxerc ├── hxml ├── deps.hxml ├── prepare-test.hxml ├── test-main-func.hxml ├── test.hxml └── build.hxml ├── .gitignore ├── scripts ├── Format.hx ├── Test.hx ├── Build.hx ├── PrepareTest.hx └── Pack.hx ├── public-files.txt ├── haxe_libraries ├── locator.hxml ├── greeter.hxml ├── sinker.hxml ├── hashlink.hxml └── formatter.hxml ├── all.hxml ├── src └── hlc_compiler │ ├── import.hx │ ├── types │ ├── Library.hx │ ├── HlcCompilerError.hx │ ├── HlcJson.hx │ ├── LibraryList.hx │ ├── LibrarySpecifier.hx │ └── Arguments.hx │ ├── internal │ ├── Constants.hx │ ├── Printer.hx │ └── Common.hx │ ├── Main.hx │ ├── Environment.hx │ ├── MainHaxelib.hx │ ├── CommandOptions.hx │ ├── save │ ├── ShellCommandBuilder.hx │ ├── SaveCommandTools.hx │ └── BatchBuilder.hx │ ├── CompilerCommandBuilder.hx │ ├── HlcCompiler.hx │ ├── LibrarySearcher.hx │ └── OptionsParser.hx ├── .vscode ├── tasks.json └── settings.json ├── haxelib.json ├── COPYRIGHT ├── development.md ├── hxformat.json ├── README.md └── LICENSE /Run.hx: -------------------------------------------------------------------------------- 1 | function main() 2 | hlc_compiler.MainHaxelib.main(); 3 | -------------------------------------------------------------------------------- /test/TestProject.hx: -------------------------------------------------------------------------------- 1 | function main() 2 | Sys.println('Hello world!'); 3 | -------------------------------------------------------------------------------- /.haxerc: -------------------------------------------------------------------------------- 1 | { 2 | "version": "4.2.3", 3 | "resolveLibs": "scoped" 4 | } 5 | -------------------------------------------------------------------------------- /hxml/deps.hxml: -------------------------------------------------------------------------------- 1 | --library sinker 2 | --library greeter 3 | --library locator 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /out/ 3 | /dump/ 4 | /test/src-c/ 5 | /lib.zip 6 | /run.n 7 | -------------------------------------------------------------------------------- /scripts/Format.hx: -------------------------------------------------------------------------------- 1 | function main() 2 | Sys.command("lix run formatter -s src -s test"); 3 | -------------------------------------------------------------------------------- /public-files.txt: -------------------------------------------------------------------------------- 1 | src/ 2 | haxelib.json 3 | LICENSE 4 | README.md 5 | COPYRIGHT 6 | Run.hx 7 | run.n 8 | -------------------------------------------------------------------------------- /scripts/Test.hx: -------------------------------------------------------------------------------- 1 | private function main() 2 | Sys.command("haxe", ["hxml/test.hxml"].concat(Sys.args())); 3 | -------------------------------------------------------------------------------- /hxml/prepare-test.hxml: -------------------------------------------------------------------------------- 1 | # Prepares test/src-c/ 2 | 3 | --class-path test 4 | --main TestProject 5 | --hl test/src-c/main.c 6 | -------------------------------------------------------------------------------- /hxml/test-main-func.hxml: -------------------------------------------------------------------------------- 1 | # Invoke hlc_compiler.Main.main() 2 | 3 | hxml/deps.hxml 4 | --class-path src 5 | 6 | --run hlc_compiler.Main 7 | -------------------------------------------------------------------------------- /scripts/Build.hx: -------------------------------------------------------------------------------- 1 | private function main() { 2 | Sys.command("haxe", ["hxml/build.hxml"]); 3 | Sys.println('Built neko bytecode of hlc-compiler.'); 4 | } 5 | -------------------------------------------------------------------------------- /scripts/PrepareTest.hx: -------------------------------------------------------------------------------- 1 | private function main() { 2 | Sys.command("haxe", ["hxml/prepare-test.hxml"]); 3 | Sys.println("Generated HL/C for test."); 4 | } 5 | -------------------------------------------------------------------------------- /hxml/test.hxml: -------------------------------------------------------------------------------- 1 | # Prerequisites: HL/C code should be located in ./test/src-c/ 2 | 3 | hxml/deps.hxml 4 | --class-path src 5 | --class-path test 6 | 7 | --run TestMain 8 | -------------------------------------------------------------------------------- /haxe_libraries/locator.hxml: -------------------------------------------------------------------------------- 1 | # @install: lix --silent download "haxelib:/locator#0.5.0" into locator/0.5.0/haxelib 2 | -lib greeter 3 | -lib sinker 4 | -cp ${HAXE_LIBCACHE}/locator/0.5.0/haxelib/src/ 5 | -D locator=0.5.0 6 | -------------------------------------------------------------------------------- /haxe_libraries/greeter.hxml: -------------------------------------------------------------------------------- 1 | # @install: lix --silent download "haxelib:/greeter#0.1.0" into greeter/0.1.0/haxelib 2 | -lib sinker 3 | -cp ${HAXE_LIBCACHE}/greeter/0.1.0/haxelib/src/ 4 | -D greeter=0.1.0 5 | --library sinker 6 | -------------------------------------------------------------------------------- /haxe_libraries/sinker.hxml: -------------------------------------------------------------------------------- 1 | # @install: lix --silent download "haxelib:/sinker#0.6.0" into sinker/0.6.0/haxelib 2 | -cp ${HAXE_LIBCACHE}/sinker/0.6.0/haxelib/src/ 3 | -D sinker=0.6.0 4 | --macro sinker.internal.Initialization.run() 5 | -------------------------------------------------------------------------------- /hxml/build.hxml: -------------------------------------------------------------------------------- 1 | # Build neko bytecode for 'haxelib run hlc-compiler' 2 | 3 | hxml/deps.hxml 4 | --class-path src 5 | 6 | --main hlc_compiler.MainHaxelib 7 | 8 | --dce full 9 | --define analyzer-optimize 10 | 11 | --neko run.n 12 | -------------------------------------------------------------------------------- /all.hxml: -------------------------------------------------------------------------------- 1 | --class-path src 2 | --class-path test 3 | --class-path scripts 4 | --library sinker 5 | --library greeter 6 | --library locator 7 | --main hlc_compiler.Main 8 | --macro nullSafety("hlc_compiler", Strict) 9 | 10 | --neko _.n 11 | --no-output 12 | -------------------------------------------------------------------------------- /haxe_libraries/hashlink.hxml: -------------------------------------------------------------------------------- 1 | # @install: lix --silent download "haxelib:/hashlink#0.1.0" into hashlink/0.1.0/haxelib 2 | # @run: haxelib run-dir hashlink "${HAXE_LIBCACHE}/hashlink/0.1.0/haxelib" 3 | -cp ${HAXE_LIBCACHE}/hashlink/0.1.0/haxelib/ 4 | -D hashlink=0.1.0 -------------------------------------------------------------------------------- /haxe_libraries/formatter.hxml: -------------------------------------------------------------------------------- 1 | # @install: lix --silent download "haxelib:/formatter#1.13.0" into formatter/1.13.0/haxelib 2 | # @run: haxelib run-dir formatter "${HAXE_LIBCACHE}/formatter/1.13.0/haxelib" 3 | -cp ${HAXE_LIBCACHE}/formatter/1.13.0/haxelib/src 4 | -D formatter=1.13.0 -------------------------------------------------------------------------------- /src/hlc_compiler/import.hx: -------------------------------------------------------------------------------- 1 | package hlc_compiler; 2 | 3 | import greeter.*; 4 | import hlc_compiler.internal.Printer; 5 | import hlc_compiler.types.HlcCompilerError.error; 6 | import locator.*; 7 | import sinker.*; 8 | 9 | using StringTools; 10 | using sinker.extensions.Index; 11 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "type": "hxml", 6 | "file": "test.hxml", 7 | "problemMatcher": [ 8 | "$haxe-absolute", 9 | "$haxe", 10 | "$haxe-error", 11 | "$haxe-trace" 12 | ], 13 | "group": { 14 | "kind": "build", 15 | "isDefault": true 16 | }, 17 | "label": "haxe: test.hxml" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /scripts/Pack.hx: -------------------------------------------------------------------------------- 1 | /** 2 | Packs files to be published. 3 | Requires that the `7z` command is available. 4 | **/ 5 | private function main() { 6 | final zipName = "lib.zip"; 7 | final fileList = "public-files.txt"; 8 | 9 | if (sys.FileSystem.exists(zipName)) { 10 | sys.FileSystem.deleteFile(zipName); 11 | Sys.println('Deleted: $zipName'); 12 | } 13 | 14 | Sys.command("7z", [ 15 | "a", 16 | "-tzip", 17 | zipName, 18 | '@$fileList' 19 | ]); 20 | } 21 | -------------------------------------------------------------------------------- /src/hlc_compiler/types/Library.hx: -------------------------------------------------------------------------------- 1 | package hlc_compiler.types; 2 | 3 | /** 4 | Library to be linked with executable. 5 | **/ 6 | enum Library { 7 | /** 8 | Library to be linked statically in buildtime. 9 | **/ 10 | Static(nameOrFile: LibrarySpecifier); 11 | 12 | /** 13 | Library to be linked in runtime. 14 | **/ 15 | Shared(file: FileRef); 16 | 17 | /** 18 | Library required both in buildtime and runtime. 19 | **/ 20 | StaticShared(file: FileRef, name: Maybe); 21 | } 22 | -------------------------------------------------------------------------------- /src/hlc_compiler/types/HlcCompilerError.hx: -------------------------------------------------------------------------------- 1 | package hlc_compiler.types; 2 | 3 | import haxe.Exception; 4 | 5 | /** 6 | Exception object that may be thrown from `hlc-compiler`. 7 | **/ 8 | class HlcCompilerError extends Exception { 9 | /** 10 | Alias for `new HlcCompilerError()`. 11 | **/ 12 | public static function error( 13 | message: String, 14 | ?previous: Exception, 15 | ?native: Any 16 | ): HlcCompilerError { 17 | return new HlcCompilerError(message, previous, native); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/hlc_compiler/internal/Constants.hx: -------------------------------------------------------------------------------- 1 | package hlc_compiler.internal; 2 | 3 | /** 4 | The name of this library. 5 | **/ 6 | inline final libName = "hlc-compiler"; 7 | 8 | /** 9 | The version of this library. 10 | **/ 11 | inline final version = "0.3.0"; 12 | 13 | /** 14 | The URL of the repository. 15 | **/ 16 | inline final repositoryUrl = 'https://github.com/fal-works/$libName'; 17 | 18 | /** 19 | The URL of haxelib page. 20 | **/ 21 | inline final haxelibUrl = 'https://lib.haxe.org/p/$libName'; 22 | -------------------------------------------------------------------------------- /src/hlc_compiler/internal/Printer.hx: -------------------------------------------------------------------------------- 1 | package hlc_compiler.internal; 2 | 3 | /** 4 | Prints `message` in yellow with a warning prefix. 5 | **/ 6 | function warn(message: String): Void { 7 | final msg = '[WARNING] $message'; 8 | Sys.println('\u001b[33m${msg}\u001b[0m'); 9 | } 10 | 11 | /** 12 | Prints `exception` in red with an error prefix. 13 | **/ 14 | function printError(exception: haxe.Exception): Void { 15 | final msg = '[ERROR] Caught exception:\n$exception'; 16 | Sys.println('\u001b[31m${msg}\u001b[0m'); 17 | } 18 | -------------------------------------------------------------------------------- /src/hlc_compiler/Main.hx: -------------------------------------------------------------------------------- 1 | package hlc_compiler; 2 | 3 | import hlc_compiler.OptionsParser.parseOptions; 4 | import hlc_compiler.internal.Common; 5 | 6 | /** 7 | Entry point to be called directly. 8 | Not used if called from `haxelib`. 9 | **/ 10 | function main(): Void { 11 | tryDo(() -> parseRun(Sys.args())); 12 | } 13 | 14 | /** 15 | Parses the given arguments and then runs the main process of `hlc-compiler`. 16 | **/ 17 | function parseRun(args: Array): Void { 18 | parseOptions(args).may(HlcCompiler.run); 19 | } 20 | -------------------------------------------------------------------------------- /src/hlc_compiler/Environment.hx: -------------------------------------------------------------------------------- 1 | package hlc_compiler; 2 | 3 | /** 4 | The system on which the program is running. 5 | **/ 6 | final systemType = { 7 | final name = Sys.systemName(); 8 | switch name { 9 | case "Windows": Windows; 10 | case "Mac": Mac; 11 | default: 12 | warn('Unknown system: $name'); 13 | warn('Continue running in Mac mode, but this is not tested on $name.'); 14 | Mac; 15 | }; 16 | } 17 | 18 | /** 19 | System types that are currently supported by hlc-compiler. 20 | **/ 21 | enum abstract SystemType(String) { 22 | final Windows; 23 | final Mac; 24 | } 25 | -------------------------------------------------------------------------------- /haxelib.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hlc-compiler", 3 | "url": "https://github.com/fal-works/hlc-compiler/", 4 | "license": "Apache", 5 | "tags": ["utility", "tool", "hashlink", "native"], 6 | "description": "Helps you compile HashLink/C code into executable using GCC or Clang.", 7 | "version": "0.3.0", 8 | "classPath": "src/", 9 | "releasenote": "Enable to select GCC/Clang. Include neko bytecode. Refactor overall. Change license to Apache 2.0.", 10 | "contributors": [ 11 | "fal-works" 12 | ], 13 | "dependencies": { 14 | "sinker": "", 15 | "greeter": "", 16 | "locator": "" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /COPYRIGHT: -------------------------------------------------------------------------------- 1 | Copyright 2020-2022 FAL Works 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this project except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /src/hlc_compiler/MainHaxelib.hx: -------------------------------------------------------------------------------- 1 | package hlc_compiler; 2 | 3 | import hlc_compiler.internal.Common; 4 | 5 | /** 6 | Entry point to be called from `haxelib run hlc-compiler`. 7 | 8 | The last argument should be the current working directory. 9 | **/ 10 | function main(): Void { 11 | tryDo(() -> Main.parseRun(processHaxelibArguments())); 12 | } 13 | 14 | /** 15 | Reads arguments via `Sys.args()`, 16 | consumes the last one as the current working directory 17 | and returns the rest. 18 | **/ 19 | function processHaxelibArguments(): Array { 20 | final args: Array = Sys.args(); 21 | 22 | inline function cwdError() { 23 | var msg = 'Cannot get current working directory.'; 24 | msg += '\n Passed command arguments (the last should be the cwd):'; 25 | msg += '\n ${Sys.args().join(" ")}'; 26 | throw error(msg); 27 | } 28 | 29 | final lastArg = args.pop(); 30 | if (lastArg.isNone()) cwdError(); 31 | final cwdPath = DirectoryPath.from(lastArg.unwrap()); 32 | if (!cwdPath.exists()) cwdError(); 33 | 34 | cwdPath.find().setAsCurrent(); 35 | 36 | return args; 37 | } 38 | -------------------------------------------------------------------------------- /src/hlc_compiler/types/HlcJson.hx: -------------------------------------------------------------------------------- 1 | package hlc_compiler.types; 2 | 3 | import haxe.Json; 4 | 5 | /** 6 | Content of `hlc.json`. 7 | **/ 8 | @:structInit 9 | class HlcJson { 10 | public static function parse(file: FileRef): HlcJson { 11 | final obj = try { 12 | Json.parse(file.getContent()); 13 | } catch (e) { 14 | final msg = 'Failed to parse JSON: ${file.path}\n$e'; 15 | throw error(msg); 16 | } 17 | 18 | final libs = Maybe.from(Reflect.field(obj, "libs")).map(x -> { 19 | if (!Std.isOfType(x, std.Array)) { 20 | final msg = 'Failed to parse: ${file.path}\n libs must be Array.'; 21 | throw error(msg); 22 | } 23 | return (x : Array); 24 | }).orElse(() -> { 25 | throw error('Field libs not found in: ${file.path}'); 26 | }); 27 | 28 | return { 29 | libs: libs.map(x -> { 30 | if (!Std.isOfType(x, String)) { 31 | final msg = 'Failed to parse: ${file.path}\n libs must be Array.'; 32 | throw error(msg); 33 | } 34 | return (x : String); 35 | }) 36 | }; 37 | } 38 | 39 | public final libs: Array; 40 | } 41 | -------------------------------------------------------------------------------- /test/TestConfig.hx: -------------------------------------------------------------------------------- 1 | import greeter.Cli; 2 | import sys.FileSystem; 3 | 4 | using Lambda; 5 | 6 | function getTestArguments(): Array { 7 | var args = []; 8 | args.push('--srcDir test/src-c'); 9 | args.push('--outDir out/bin'); 10 | args.push('--copyRuntimeFiles'); 11 | args.push('--saveCmd out/compile'); 12 | args.push('-w'); 13 | switch Cli.current.type { 14 | case Unix: 15 | case Dos: 16 | args.push('--exFile C:/Windows/System32/dbghelp.dll'); 17 | } 18 | 19 | return args.join(" ").split(" "); 20 | } 21 | 22 | function clearOutput() { 23 | deleteRecursive("out/bin"); 24 | } 25 | 26 | function runOutput() { 27 | Sys.println("Run the compiled executable..."); 28 | switch Cli.current.type { 29 | case Unix: Sys.command("out/bin/main"); 30 | case Dos: Sys.command("call", ["out\\bin\\main"]); 31 | } 32 | } 33 | 34 | private function deleteRecursive(path: String) { 35 | if (!FileSystem.exists(path)) return; 36 | if (!FileSystem.isDirectory(path)) { 37 | FileSystem.deleteFile(path); 38 | return; 39 | } 40 | 41 | FileSystem.readDirectory(path).map(x -> '$path/$x').iter(deleteRecursive); 42 | FileSystem.deleteDirectory(path); 43 | } 44 | -------------------------------------------------------------------------------- /src/hlc_compiler/types/LibraryList.hx: -------------------------------------------------------------------------------- 1 | package hlc_compiler.types; 2 | 3 | /** 4 | List of libraries to be linked. 5 | **/ 6 | @:notNull @:forward 7 | abstract LibraryList(Array) from Array { 8 | /** 9 | Function that returns a specifier if `library` should be statically linked. 10 | **/ 11 | static final getStatic = (library: Library) -> Maybe.from(switch library { 12 | case Static(nameOrFile): nameOrFile; 13 | case Shared(_): null; 14 | case StaticShared(file, name): 15 | (if (name.isSome()) Name(name.unwrap()) else File(file) : LibrarySpecifier); 16 | }); 17 | 18 | /** 19 | Function that returns a file if `library` is required in runtime. 20 | **/ 21 | static final getShared = (library: Library) -> Maybe.from(switch library { 22 | case Static(_): null; 23 | case Shared(file): file; 24 | case StaticShared(file, _): file; 25 | }); 26 | 27 | /** 28 | @return List of libraries required in buildtime. 29 | **/ 30 | public inline function filterStatic() 31 | return this.filterMap(getStatic); 32 | 33 | /** 34 | @return List of libraries required in runtime. 35 | **/ 36 | public inline function filterShared() 37 | return this.filterMap(getShared); 38 | } 39 | -------------------------------------------------------------------------------- /src/hlc_compiler/CommandOptions.hx: -------------------------------------------------------------------------------- 1 | package hlc_compiler; 2 | 3 | /** 4 | Settings of command options passed to hlc-compiler. 5 | **/ 6 | class CommandOptions { 7 | /** 8 | Rule set about how to parse option argument strings. 9 | **/ 10 | public static final rules = OptionParseRules.from([ 11 | "--version" => [], 12 | "--srcDir" => [Space], 13 | "--srcFile" => [Space], 14 | "--hlcJsonFile" => [Space], 15 | "--outDir" => [Space], 16 | "--outFile" => [Space], 17 | "-o" => [Space, None], 18 | "--hlLibDir" => [Space], 19 | "--hlIncludeDir" => [Space], 20 | "--copyRuntimeFiles" => [], 21 | "--exFile" => [Space], 22 | "--runtime" => [Space], 23 | "--saveCmd" => [Space], 24 | "--relative" => [], 25 | "--compiler" => [Space], 26 | "--verbose" => [], 27 | "-std" => [Equal] 28 | ]); 29 | 30 | /** 31 | Set of all command option instances used in hlc-compiler 32 | (excluding the ones that should be treated as external gcc options). 33 | **/ 34 | public static final set = rules.getAllOptions(); 35 | 36 | /** 37 | Mapping from alias options to representative options. 38 | **/ 39 | public static final aliases: Map = ["-o" => "--outFile"]; 40 | } 41 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | // --------------------------------------------------------------------------- 3 | // Haxe settings 4 | "[haxe]": { 5 | "editor.insertSpaces": false, 6 | "editor.codeActionsOnSave": { 7 | "source.sortImports": true 8 | }, 9 | }, 10 | // --------------------------------------------------------------------------- 11 | // Common settings 12 | "editor.tabSize": 2, 13 | "files.eol": "\n", 14 | "files.trimTrailingWhitespace": true, 15 | "files.trimFinalNewlines": true, 16 | "files.insertFinalNewline": true, 17 | "files.associations": { 18 | "LICENSE": "plaintext", 19 | "COPYRIGHT": "plaintext", 20 | }, 21 | "[plaintext]": { 22 | "files.trimTrailingWhitespace": false, 23 | "files.trimFinalNewlines": false, 24 | "files.insertFinalNewline": false, 25 | }, 26 | "[markdown]": { 27 | "editor.tabSize": 4, 28 | "editor.insertSpaces": true, 29 | "editor.wordWrap": "on", 30 | "editor.renderWhitespace": "boundary", 31 | "files.trimTrailingWhitespace": false, 32 | }, 33 | "[json]": { 34 | "editor.defaultFormatter": "vscode.json-language-features" 35 | }, 36 | "[jsonc]": { 37 | "editor.defaultFormatter": "vscode.json-language-features" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/hlc_compiler/internal/Common.hx: -------------------------------------------------------------------------------- 1 | package hlc_compiler.internal; 2 | 3 | import hlc_compiler.internal.Constants; 4 | 5 | /** 6 | Prints version info of this library. 7 | **/ 8 | function showVersion(emptyLineBefore: Bool, emptyLineAfter: Bool): Void { 9 | showText( 10 | '$libName v$version\n $haxelibUrl', 11 | emptyLineBefore, 12 | emptyLineAfter 13 | ); 14 | } 15 | 16 | /** 17 | Prints hint message. 18 | **/ 19 | function showHint(emptyLineBefore: Bool, emptyLineAfter: Bool): Void { 20 | showText( 21 | 'For a list of options, see:\n $repositoryUrl', 22 | emptyLineBefore, 23 | emptyLineAfter 24 | ); 25 | } 26 | 27 | /** 28 | Wraps `proc` with a `try`-`catch` block. 29 | 30 | If caught any exception, prints it with a hint info and exits the current process with code `1`. 31 | **/ 32 | inline function tryDo(proc: () -> Void): Void { 33 | try { 34 | proc(); 35 | } catch (e) { 36 | printError(e); 37 | Common.showHint(true, true); 38 | Sys.exit(1); 39 | } 40 | } 41 | 42 | /** 43 | Prints text with or without empty lines. 44 | **/ 45 | private function showText( 46 | text: String, 47 | emptyLineBefore: Bool, 48 | emptyLineAfter: Bool 49 | ): Void { 50 | if (emptyLineBefore) Sys.println(""); 51 | Sys.println(text); 52 | if (emptyLineAfter) Sys.println(""); 53 | } 54 | -------------------------------------------------------------------------------- /src/hlc_compiler/types/LibrarySpecifier.hx: -------------------------------------------------------------------------------- 1 | package hlc_compiler.types; 2 | 3 | /** 4 | Either name or file of a library. 5 | **/ 6 | @:using(LibrarySpecifier.LibrarySpecifierExtension) 7 | enum LibrarySpecifier { 8 | /** 9 | Library specified by a name and can be linked by `-l` option of `gcc`. 10 | **/ 11 | Name(s: String); 12 | 13 | /** 14 | Library specified by a file path. 15 | **/ 16 | File(file: FileRef); 17 | } 18 | 19 | class LibrarySpecifierExtension { 20 | /** 21 | Checks if `this` can be used in `cli`. If not, throws an error. 22 | No effect if `this` is `Name`. 23 | @return `String` representation of `this`. 24 | **/ 25 | public static function validatePathString(_this: LibrarySpecifier, cli: Cli): String { 26 | return switch _this { 27 | case Name(s): s; 28 | case File(file): 29 | try { 30 | file.path.validate(cli); 31 | } catch (e) { 32 | final msg = 'Invalid library path: ${file.path}'; 33 | throw error(msg); 34 | } 35 | } 36 | } 37 | 38 | /** 39 | @return `String` that can be used in `cli`. 40 | **/ 41 | public static function quote(_this: LibrarySpecifier, cli: Cli): String { 42 | return switch _this { 43 | case Name(s): cli.quoteArgument(s); 44 | case File(file): file.path.quote(cli); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /test/TestMain.hx: -------------------------------------------------------------------------------- 1 | import hlc_compiler.Main.parseRun; 2 | 3 | using Lambda; 4 | using StringTools; 5 | 6 | function main() { 7 | final args = Sys.args(); 8 | 9 | if (args.has("all")) testAll(); 10 | else if (args.has("main")) testMain(); 11 | else if (args.has("neko")) testNeko(); 12 | else if (args.has("no-args")) testNoArgs(); 13 | else testParseRun(); 14 | } 15 | 16 | function testAll() { 17 | testParseRun(); 18 | testMain(); 19 | testNeko(); 20 | testNoArgs(); 21 | } 22 | 23 | function testParseRun() { 24 | heading("test parseRun()"); 25 | TestConfig.clearOutput(); 26 | parseRun(TestConfig.getTestArguments()); 27 | TestConfig.runOutput(); 28 | } 29 | 30 | function testMain() { 31 | heading("test main()"); 32 | TestConfig.clearOutput(); 33 | Sys.command("haxe", [ 34 | ["hxml/test-main-func.hxml"], 35 | TestConfig.getTestArguments(), 36 | ].flatten()); 37 | TestConfig.runOutput(); 38 | } 39 | 40 | function testNeko() { 41 | heading("test neko run.n"); 42 | TestConfig.clearOutput(); 43 | // Emulating call by haxelib 44 | Sys.command("neko", [ 45 | ["run.n"], 46 | TestConfig.getTestArguments(), 47 | [Sys.getCwd()] 48 | ].flatten()); 49 | TestConfig.runOutput(); 50 | } 51 | 52 | function testNoArgs() { 53 | heading("test parseRun() without arguments"); 54 | parseRun([]); 55 | } 56 | 57 | function heading(s: String) 58 | Sys.println('---- $s '.rpad("-", 80)); 59 | -------------------------------------------------------------------------------- /development.md: -------------------------------------------------------------------------------- 1 | # Development guide 2 | 3 | ## Environment/Tools 4 | 5 | - [VS Code](https://code.visualstudio.com/) 6 | - [lix](https://github.com/lix-pm/lix.client) 7 | 8 | 9 | ## Build 10 | 11 | Run `lix Build` in the terminal to build the neko bytecode. 12 | 13 | 14 | ## Test 15 | 16 | Run the following in the terminal: 17 | 18 | 1. `lix PrepareTest` to generate a HL/C code sample (which is a simple Hello World). This only needs to be done once. 19 | 1. `lix Test` to test compiling the HL/C code generated above, using the current source code of `hlc-compiler`. 20 | - Additional arguments: 21 | - `main` for testing the `main()` function 22 | - `neko` for testing the neko bytecode 23 | - `no-args` for testing without arguments 24 | - `all` for all of the above 25 | 26 | 27 | ## Maintain 28 | 29 | - Run `lix Format` to format code. 30 | - Run `lix Build` to update the neko bytecode. 31 | - Run `lix Test all` to test everything. 32 | - Check if [hlc-compiler-sample](https://github.com/fal-works/hlc-compiler-sample) still works. 33 | 34 | 35 | ## Submission to [Haxelib](https://lib.haxe.org/) 36 | 37 | 1. Update the library version. 38 | - Update `version` in the `Constants` module. 39 | - Update `haxelib.json`. 40 | 1. Check and update everything (see the "Maintain" section above). 41 | 1. Reflect to the main branch on GitHub, and add a version tag. 42 | 1. Pack the library by `lix Pack`, which generates `lib.zip`. 43 | 1. Submit the library by `haxelib submit lib.zip`. 44 | -------------------------------------------------------------------------------- /src/hlc_compiler/save/ShellCommandBuilder.hx: -------------------------------------------------------------------------------- 1 | package hlc_compiler.save; 2 | 3 | class ShellCommandBuilder { 4 | /** 5 | Builds content of a shell command file. 6 | **/ 7 | public static function build( 8 | outDir: DirectoryRef, 9 | compileCommandBlock: String, 10 | copyList: FileOrDirectoryList, 11 | relative: Bool 12 | ): String { 13 | final cli = Cli.unix; 14 | final outDirStr = switch relative { 15 | case false: outDir.path.quote(cli); 16 | case true: cli.quoteArgument(outDir.path.toRelative()); 17 | }; 18 | final mkOutDirCmd = 'mkdir -p $outDirStr'; 19 | final mkDirCatcher = exitIfError("Failed to prepare output directory. Aborting."); 20 | 21 | final contents = [ 22 | "#!/bin/sh", 23 | '$mkOutDirCmd\n$mkDirCatcher', 24 | "echo Compiling...", 25 | compileCommandBlock.trim(), 26 | exitIfError("Compilation command failed. Aborting.") 27 | ]; 28 | 29 | if (0 < copyList.length) { 30 | contents.push("echo Copying runtime files..."); 31 | final copyCatcher = exitIfError("Copy failed. Aborting."); 32 | 33 | for (element in copyList) { 34 | final srcAbsPath = element.toPath(); 35 | final srcPath = switch relative { 36 | case false: srcAbsPath.quote(cli); 37 | case true: cli.quoteArgument(srcAbsPath.toRelative()); 38 | }; 39 | final destPath = outDirStr + switch srcAbsPath.toEnum() { 40 | case File(path): path.getName(); 41 | case Directory(path): path.getName() + "/"; 42 | }; 43 | final copyCommand = 'cp -r $srcPath $destPath'; 44 | 45 | contents.push('$copyCommand\n$copyCatcher'); 46 | } 47 | } 48 | 49 | contents.push("echo Completed."); 50 | 51 | return contents.join("\n\n") + "\n"; 52 | } 53 | 54 | /** 55 | @return Shell command block for aborting on any error. 56 | **/ 57 | static function exitIfError(message: String): String 58 | return 'trap \'echo $message\' ERR'; 59 | } 60 | -------------------------------------------------------------------------------- /src/hlc_compiler/save/SaveCommandTools.hx: -------------------------------------------------------------------------------- 1 | package hlc_compiler.save; 2 | 3 | class SaveCommandTools { 4 | /** 5 | Saves commands (including `gcc`) as a shell script. 6 | @return Path to the saved file (with extension). 7 | **/ 8 | public static function saveCommandShell( 9 | savePath: FilePath, 10 | outDir: DirectoryRef, 11 | compileCommand: CommandLine, 12 | copyList: FileOrDirectoryList, 13 | relative: Bool 14 | ): FilePath { 15 | final content = ShellCommandBuilder.build( 16 | outDir, 17 | compileCommand.format(Cli.unix), 18 | copyList, 19 | relative 20 | ); 21 | 22 | // TODO: use Environment after supporting Linux 23 | final defaultExtension = switch Sys.systemName() { 24 | case "Mac": "command"; 25 | default: "sh"; 26 | }; 27 | final savedPath = saveFile(savePath, content, defaultExtension); 28 | 29 | Sys.command("chmod", ["u+x", savedPath]); 30 | 31 | return savedPath; 32 | } 33 | 34 | /** 35 | Saves commands (including `gcc`) as a Windows batch file. 36 | @return Path to the saved file (with extension). 37 | **/ 38 | public static function saveCommandBat( 39 | savePath: FilePath, 40 | outDir: DirectoryRef, 41 | compileCommand: CommandLine, 42 | copyList: FileOrDirectoryList, 43 | relative: Bool 44 | ): FilePath { 45 | final content = BatchBuilder.build( 46 | outDir, 47 | compileCommand.format(Cli.dos), 48 | copyList, 49 | relative 50 | ); 51 | 52 | return saveFile(savePath, content, "bat"); 53 | } 54 | 55 | /** 56 | Saves `content` in the file specified by `savePath`. 57 | @return Path to the saved file (with extension). 58 | **/ 59 | static function saveFile( 60 | savePath: FilePath, 61 | content: String, 62 | defaultExtension: String 63 | ): FilePath { 64 | if (savePath.getExtension().isNone()) 65 | savePath = savePath.setExtension(defaultExtension); 66 | 67 | savePath.saveContent(content); 68 | 69 | return savePath; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/hlc_compiler/save/BatchBuilder.hx: -------------------------------------------------------------------------------- 1 | package hlc_compiler.save; 2 | 3 | class BatchBuilder { 4 | /** 5 | Builds content of a Windows batch (`.bat`) file. 6 | **/ 7 | public static function build( 8 | outDir: DirectoryRef, 9 | compileCommandBlock: String, 10 | copyList: FileOrDirectoryList, 11 | relative: Bool 12 | ): String { 13 | final cli = Cli.dos; 14 | final outDirStr = switch relative { 15 | case false: outDir.path.quote(cli); 16 | case true: cli.quoteArgument(outDir.path.toRelative()); 17 | }; 18 | final mkOutDirCmd = 'if not exist $outDirStr ^\nmkdir $outDirStr'; 19 | final mkDirCatcher = exitIfError("Failed to prepare output directory. Aborting."); 20 | 21 | final contents = [ 22 | "@echo off", 23 | '$mkOutDirCmd\n$mkDirCatcher', 24 | "echo Compiling...", 25 | compileCommandBlock.trim(), 26 | exitIfError("Compilation command failed. Aborting.") 27 | ]; 28 | 29 | if (0 < copyList.length) { 30 | contents.push("echo Copying runtime files..."); 31 | final copyCatcher = exitIfError("Copy failed. Aborting."); 32 | 33 | for (element in copyList) { 34 | final srcAbsPath = element.toPath(); 35 | var srcPath = switch relative { 36 | case false: srcAbsPath.toString(); 37 | case true: srcAbsPath.toRelative(); 38 | }; 39 | if (srcPath.endsWith("\\")) 40 | srcPath = srcPath.substr(0, srcPath.length - 1); 41 | srcPath = cli.quoteArgument(srcPath); 42 | 43 | final copyCommand = switch srcAbsPath.toEnum() { 44 | case File(_): 45 | 'copy /y $srcPath $outDirStr > nul'; 46 | case Directory(path): 47 | final destPath = outDirStr + path.getName() + "\\"; 48 | 'xcopy /y /e $srcPath $destPath > nul'; 49 | }; 50 | 51 | contents.push('$copyCommand\n$copyCatcher'); 52 | } 53 | } 54 | 55 | contents.push("echo Completed."); 56 | 57 | return contents.join("\n\n") + "\n"; 58 | } 59 | 60 | /** 61 | @return BAT command block for aborting on any error. 62 | **/ 63 | static function exitIfError(message: String): String 64 | return 'if %ERRORLEVEL% neq 0 (\n echo $message\n exit /b 1\n)'; 65 | } 66 | -------------------------------------------------------------------------------- /src/hlc_compiler/CompilerCommandBuilder.hx: -------------------------------------------------------------------------------- 1 | package hlc_compiler; 2 | 3 | import hlc_compiler.types.Arguments; 4 | import hlc_compiler.types.LibrarySpecifier; 5 | 6 | /** 7 | Converts provided data to `CommandLine` that runs the specified C compiler. 8 | **/ 9 | function buildCompilerCommand( 10 | arguments: Arguments, 11 | basicLibraries: Array, 12 | cli: Cli 13 | ): CommandLine { 14 | final srcDir = arguments.srcDir; 15 | final srcFile = arguments.srcFile; 16 | final outFile = arguments.outFile; 17 | final hlLibDir = arguments.hlLibDir; 18 | final hlIncludeDir = arguments.hlIncludeDir; 19 | final exOptions = arguments.exOptions; 20 | 21 | final files = [srcFile].concat(arguments.exFiles); 22 | final libs = basicLibraries; 23 | 24 | final filePath = switch arguments.relative { 25 | case false: (path: FilePath) -> path.validate(cli).toString(); 26 | case true: (path: FilePath) -> path.validate(cli).toRelative(); 27 | }; 28 | final dirPath = switch arguments.relative { 29 | case false: (path: DirectoryPath) -> path.validate(cli).toString(); 30 | case true: (path: DirectoryPath) -> path.validate(cli).toRelative(); 31 | }; 32 | 33 | final args: CommandArgumentList = []; 34 | 35 | args.push(OptionParameter("-o", Space, filePath(outFile))); 36 | 37 | args.push(OptionParameter("-I", Space, dirPath(srcDir.path))); 38 | if (hlIncludeDir.isSome()) { 39 | final path = dirPath(hlIncludeDir.unwrap().path); 40 | args.push(OptionParameter("-I", Space, path)); 41 | } 42 | 43 | args.push(OptionParameter("-L", Space, dirPath(hlLibDir.path))); 44 | 45 | for (exOption in exOptions) 46 | args.push(Parameter(exOption)); 47 | if (!exOptions.hasAny(s -> s.startsWith("-std="))) 48 | args.push(Parameter("-std=c11")); 49 | 50 | for (file in files) 51 | args.push(Parameter(filePath(file.path))); 52 | 53 | for (lib in libs) switch lib { 54 | case File(file): 55 | args.push(Parameter(filePath(file.path))); 56 | default: 57 | }; 58 | 59 | for (lib in libs) switch lib { 60 | case Name(name): 61 | args.push(OptionParameter("-l", None, cli.quoteArgument(name))); 62 | default: 63 | } 64 | 65 | return new CommandLine(arguments.compiler, args); 66 | } 67 | -------------------------------------------------------------------------------- /src/hlc_compiler/HlcCompiler.hx: -------------------------------------------------------------------------------- 1 | package hlc_compiler; 2 | 3 | import hlc_compiler.CompilerCommandBuilder.buildCompilerCommand; 4 | import hlc_compiler.save.SaveCommandTools; 5 | import hlc_compiler.types.Arguments; 6 | 7 | /** 8 | Runs the main process of hlc-compiler according to `arguments`. 9 | - Compiles HL/C into executable. 10 | - (If specified) Copies runtime files. 11 | - (If specified) Saves command lines. 12 | **/ 13 | function run(arguments: Arguments): Void { 14 | final verbose = arguments.verbose; 15 | 16 | final prepared = prepareRun(arguments); 17 | final compileCommand = prepared.compileCommand; 18 | final copyList = prepared.copyList; 19 | 20 | final outDir = arguments.outDir.findOrCreate(); // Prepare dir before compiling 21 | 22 | Sys.println("Compiling..."); 23 | final errorLevel = compileCommand.run(verbose); 24 | 25 | if (errorLevel != 0) { 26 | final msg = if (verbose) { 27 | "Compilation command failed."; // Command already printed if verbose 28 | } else { 29 | 'Compilation command failed:\n${compileCommand.quote(Cli.current)}'; 30 | } 31 | throw error(msg); 32 | } 33 | 34 | if (0 < copyList.length) { 35 | Sys.println("Copying runtime files..."); 36 | if (verbose) Sys.println('${copyList.getNames()} => ${outDir.path}'); 37 | copyList.copyTo(outDir.path); 38 | } 39 | 40 | Sys.println("Completed."); 41 | 42 | final saveCmdPath = arguments.saveCmdPath; 43 | if (saveCmdPath.isSome()) { 44 | final savePath = saveCmdPath.unwrap(); 45 | final savedPath = switch Environment.systemType { 46 | case Windows: 47 | SaveCommandTools.saveCommandBat( 48 | savePath, 49 | outDir, 50 | compileCommand, 51 | copyList, 52 | arguments.relative 53 | ); 54 | case Mac: 55 | SaveCommandTools.saveCommandShell( 56 | savePath, 57 | outDir, 58 | compileCommand, 59 | copyList, 60 | arguments.relative 61 | ); 62 | } 63 | Sys.println('Saved command: $savedPath'); 64 | } 65 | } 66 | 67 | /** 68 | Prepares for `run()`. 69 | **/ 70 | private function prepareRun(arguments: Arguments): PreparedData { 71 | final hlLibs = LibrarySearcher.getRequiredLibraries( 72 | arguments.hlcJsonFile, 73 | arguments.hlLibDir 74 | ); 75 | 76 | final compileCommand = buildCompilerCommand( 77 | arguments, 78 | hlLibs.filterStatic(), 79 | Cli.current 80 | ); 81 | final copyList = if (arguments.copyRuntimeFiles) { 82 | final hlLibsToCopy = hlLibs.filterShared().map(x -> FileOrDirectoryRef.fromFile(x)); 83 | hlLibsToCopy.concat(arguments.runtime); 84 | } else []; 85 | 86 | return { 87 | compileCommand: compileCommand, 88 | copyList: copyList, 89 | } 90 | } 91 | 92 | private typedef PreparedData = { 93 | final compileCommand: CommandLine; 94 | final copyList: FileOrDirectoryList; 95 | }; 96 | -------------------------------------------------------------------------------- /src/hlc_compiler/types/Arguments.hx: -------------------------------------------------------------------------------- 1 | package hlc_compiler.types; 2 | 3 | // TODO: optional constructor args 4 | 5 | /** 6 | Sanitized arguments for hlc-compiler, completed with default values. 7 | Converted from command line arguments. 8 | **/ 9 | @:structInit 10 | class Arguments { 11 | /** 12 | Directory containing `main.c` and `hlc.json`. 13 | **/ 14 | public final srcDir: DirectoryRef; 15 | 16 | /** 17 | Source `*.c` file. 18 | **/ 19 | public final srcFile: FileRef; 20 | 21 | /** 22 | `hlc.json` in the HL/C source directory. 23 | **/ 24 | public final hlcJsonFile: FileRef; 25 | 26 | /** 27 | Output file path. 28 | **/ 29 | public final outFile: FilePath; 30 | 31 | /** 32 | Output directory path. 33 | **/ 34 | public final outDir: DirectoryPath; 35 | 36 | /** 37 | Directory containing `*.hdll` and other library files bundled with HashLink. 38 | **/ 39 | public final hlLibDir: DirectoryRef; 40 | 41 | /** 42 | Directory containing HL files to be included (such as `hlc.h`). 43 | Is not mandatory because the directory may be automatically searched by the C compiler (especially if not Windows). 44 | **/ 45 | public final hlIncludeDir: Maybe; 46 | 47 | /** 48 | `true` if files that are required at runtime should be copied to the output directory. 49 | **/ 50 | public final copyRuntimeFiles: Bool; 51 | 52 | /** 53 | Additional files that should be passed to the C compiler. 54 | These are not copied to the destination directory. 55 | **/ 56 | public final exFiles: Array; 57 | 58 | /** 59 | Additional files that should be copied if `--copyRuntimeFiles` is specified. 60 | No effect on compilation. 61 | **/ 62 | public final runtime: FileOrDirectoryList; 63 | 64 | /** 65 | Additional options that should be passed to the C compiler. 66 | **/ 67 | public final exOptions: Array; 68 | 69 | /** 70 | The file path where the command should be saved. 71 | Does not emit file if `null`. 72 | **/ 73 | public final saveCmdPath: Maybe; 74 | 75 | /** 76 | `true` if file/directory paths should be converted to relative paths when creating commands lines. 77 | **/ 78 | public final relative: Bool; 79 | 80 | /** 81 | C compiler to use. Either `gcc` or `clang`. 82 | **/ 83 | public final compiler: CCompiler; 84 | 85 | /** 86 | `true` if verbose logging should be enabled. 87 | **/ 88 | public final verbose: Bool; 89 | 90 | /** 91 | Formats `this`. 92 | **/ 93 | public function format(indent = ""): String { 94 | var s = ""; 95 | s += '${indent}srcDir: ${this.srcDir.toString()}\n'; 96 | s += '${indent}srcFile: ${this.srcFile.toString()}\n'; 97 | s += '${indent}hlcJsonFile: ${this.hlcJsonFile.toString()}\n'; 98 | s += '${indent}outDir: ${this.outDir.toString()}\n'; 99 | s += '${indent}outFile: ${this.outFile.toString()}\n'; 100 | s += '${indent}hlLibDir: ${this.hlLibDir.toString()}\n'; 101 | s += '${indent}hlIncludeDir: ${this.hlIncludeDir.toString()}\n'; 102 | s += '${indent}copyRuntimeFiles: ${this.copyRuntimeFiles}\n'; 103 | s += '${indent}exFiles: ${this.exFiles.toString()}\n'; 104 | s += '${indent}runtime: ${this.runtime.toString()}\n'; 105 | s += '${indent}exOptions: ${this.exOptions.toString()}\n'; 106 | s += '${indent}relative: ${this.relative}\n'; 107 | s += '${indent}compiler: ${this.compiler}\n'; 108 | s += '${indent}saveCmd: ${this.saveCmdPath.toString()}'; 109 | return s; 110 | } 111 | 112 | /** 113 | @return `this` as a formatted `String`. 114 | **/ 115 | public function toString(): String 116 | return format(); 117 | } 118 | 119 | /** 120 | Type of the C compiler, either GCC or Clang. 121 | **/ 122 | enum abstract CCompiler(String) to String { 123 | final Gcc = "gcc"; 124 | final Clang = "clang"; 125 | } 126 | -------------------------------------------------------------------------------- /src/hlc_compiler/LibrarySearcher.hx: -------------------------------------------------------------------------------- 1 | package hlc_compiler; 2 | 3 | import hlc_compiler.types.HlcJson; 4 | import hlc_compiler.types.Library; 5 | import hlc_compiler.types.LibraryList; 6 | 7 | /** 8 | List of environment variable names for searching HashLink installation directory. 9 | **/ 10 | final hlPathEnvVarCandidates = [ 11 | "HASHLINKPATH", 12 | "HASHLINK", 13 | "HASHLINK_BIN" 14 | ]; 15 | 16 | /** 17 | @return Default direcotry path of HashLink-bundled libraries (`*.hdll` etc). 18 | **/ 19 | function suggestHashLinkLibraryDirectory(): Maybe { 20 | return switch Environment.systemType { 21 | case Windows: searchHashLinkDirectory(); 22 | case Mac: Maybe.from(DirectoryRef.from("/usr/local/lib/")); 23 | } 24 | } 25 | 26 | /** 27 | @return Default directory path of HashLink files to be included (`*.h`/`*.c`). 28 | **/ 29 | function suggestHashLinkIncludeDirectory(hlLibDir: DirectoryRef): Maybe { 30 | return switch Environment.systemType { 31 | case Windows: hlLibDir.tryFindDirectory("./include"); 32 | case Mac: Maybe.none(); 33 | } 34 | } 35 | 36 | /** 37 | Tries to find HashLink installation directory from environment variables. 38 | **/ 39 | function searchHashLinkDirectory(): Maybe { 40 | return hlPathEnvVarCandidates.mapFirst(varName -> { 41 | final envVarValue = Maybe.from(Sys.getEnv(varName)); 42 | if (envVarValue.isNone()) return Maybe.none(); 43 | return DirectoryPath.from(envVarValue.unwrap()).tryFind(); 44 | }); 45 | } 46 | 47 | /** 48 | @return Library files required by `hlcJsonFile`. 49 | **/ 50 | function getRequiredLibraries( 51 | hlcJsonFile: FileRef, 52 | hlLibDir: DirectoryRef 53 | ): LibraryList { 54 | inline function findHdll(name: String): FileRef 55 | return hlLibDir.findFile('$name.hdll'); 56 | 57 | inline function getHdllPath(name: String): FilePath 58 | return hlLibDir.path.makeFilePath('$name.hdll'); 59 | 60 | inline function findDll(name: String): FileRef 61 | return hlLibDir.findFile('$name.dll'); 62 | 63 | final libs: Array = []; 64 | final hlcJson = HlcJson.parse(hlcJsonFile); 65 | 66 | switch Environment.systemType { 67 | case Windows: 68 | for (lib in hlcJson.libs) switch lib { 69 | case "std": 70 | libs.push(Static(Name("libhl"))); // "-lhl" seems to hit another file 71 | libs.push(Shared(findDll("libhl"))); 72 | case "openal": 73 | libs.push(StaticShared(findHdll("openal"), null)); 74 | libs.push(Shared(findDll("OpenAL32"))); 75 | case "sdl": 76 | libs.push(StaticShared(findHdll("sdl"), null)); 77 | libs.push(Shared(findDll("SDL2"))); 78 | case "fmt" | "directx" | "ui" | "uv" | "ssl" | "mysql" | "sqlite": 79 | libs.push(StaticShared(findHdll(lib), null)); 80 | default: 81 | warn('Unknown library: $lib'); 82 | final hdllPath = getHdllPath(lib); 83 | if (hdllPath.exists()) { 84 | libs.push(StaticShared(hdllPath.find(), null)); 85 | } else { 86 | final libPath = hlLibDir.makeFilePath('$lib.lib') 87 | .or(hlLibDir.makeFilePath('lib$lib.lib')); 88 | final dllPath = hlLibDir.makeFilePath('$lib.dll') 89 | .or(hlLibDir.makeFilePath('lib$lib.dll')); 90 | if (libPath.or(dllPath).exists()) 91 | libs.push(Static(Name(lib))); 92 | if (dllPath.exists()) 93 | libs.push(Shared(dllPath.find())); 94 | } 95 | }; 96 | case Mac: 97 | for (lib in hlcJson.libs) switch lib { 98 | case "std": 99 | libs.push(Static(Name("hl"))); 100 | case "fmt" | "openal" | "ui" | "mysql" | "ssl": 101 | libs.push(Static(File(findHdll(lib)))); 102 | case "sdl": 103 | libs.push(Static(Name("sdl2"))); 104 | libs.push(Static(File(findHdll(lib)))); 105 | case "uv": 106 | libs.push(Static(Name(lib))); 107 | libs.push(Static(File(findHdll(lib)))); 108 | case "sqlite": 109 | final hdllPath = getHdllPath(lib); 110 | if (!hdllPath.exists()) { 111 | var msg = "File not found: sqlite.hdll"; 112 | msg += "\n See also: https://github.com/HaxeFoundation/hashlink/pull/323"; 113 | throw error(msg); 114 | } 115 | libs.push(Static(File(hdllPath.find()))); 116 | default: 117 | warn('Unknown library: $lib'); 118 | final hdllPath = getHdllPath(lib); 119 | if (hdllPath.exists()) { 120 | libs.push(Static(File(hdllPath.find()))); 121 | } else { 122 | libs.push(Static(Name(lib))); 123 | } 124 | }; 125 | } 126 | 127 | return libs; 128 | } 129 | -------------------------------------------------------------------------------- /src/hlc_compiler/OptionsParser.hx: -------------------------------------------------------------------------------- 1 | package hlc_compiler; 2 | 3 | import hlc_compiler.LibrarySearcher; 4 | import hlc_compiler.internal.Common; 5 | import hlc_compiler.types.Arguments; 6 | import locator.DirectoryRef.fromStringCallback as toDir; 7 | import locator.FileOrDirectoryRef.fromStringCallback as toFileOrDir; 8 | import locator.FileRef.fromStringCallback as toFile; 9 | 10 | /** 11 | Parses an array of raw argument strings and returns an `Arguments` instance. 12 | 13 | If only 0..1 arguments are provided, prints some messages and returns `Maybe.none()`. 14 | **/ 15 | function parseOptions(rawArguments: Array): Maybe { 16 | final argList = Cli.current.parseArguments( 17 | rawArguments, 18 | CommandOptions.rules 19 | ); 20 | final argSummary = argList.summary(CommandOptions.aliases); 21 | final options = argSummary.optionValuesMap; 22 | 23 | if (options.exists("--verbose")) { 24 | Sys.println("Passed options:"); 25 | Sys.println(argSummary.formatOptions(" ")); 26 | } 27 | 28 | return switch argList.length { 29 | case 0 | 1: 30 | showVersion(true, true); 31 | showHint(false, true); 32 | Maybe.none(); 33 | 34 | default: 35 | Maybe.from(validateArguments(argSummary)); 36 | } 37 | } 38 | 39 | /** 40 | Validates file/directory paths and completes them with default values. 41 | @return Arguments for hlc-compiler in `Arguments` representation. 42 | **/ 43 | function validateArguments(args: CommandArgumentSummary): Arguments { 44 | final currentDirectory = DirectoryRef.current(); 45 | final options = args.optionValuesMap; 46 | 47 | if (options.exists("--version")) 48 | showVersion(false, true); 49 | 50 | final srcDir = options.one("--srcDir").map(toDir).or(currentDirectory); 51 | final srcFile = srcDir.findFile(options.one("--srcFile").or("main.c")); 52 | final hlcJsonFile = srcDir.findFile(options.one("--hlcJsonFile").or("hlc.json")); 53 | 54 | final outDirOption = options.one("--outDir"); 55 | final outFileOption = options.one("--outFile"); 56 | final defaultOutFileName = srcFile.getNameWithoutExtension(); 57 | var outDir: DirectoryPath; 58 | var outFile: FilePath; 59 | switch outDirOption.toOption() { 60 | case Some(outDirStr): 61 | outDir = DirectoryPath.from(outDirStr); 62 | outFile = outDir.makeFilePath(outFileOption.or(defaultOutFileName)); 63 | case None: 64 | switch outFileOption.toOption() { 65 | case Some(outFileStr): 66 | outFile = FilePath.from(outFileStr); 67 | outDir = outFile.getParentPath(); 68 | case None: 69 | outDir = currentDirectory.path; 70 | outFile = outDir.makeFilePath(defaultOutFileName); 71 | } 72 | } 73 | 74 | final hlLibDir = options.one("--hlLibDir") 75 | .map(toDir) 76 | .coalesceWith(() -> suggestHashLinkLibraryDirectory()) 77 | .or(currentDirectory); 78 | 79 | final hlIncludeDir = options.one("--hlIncludeDir") 80 | .map(toDir) 81 | .coalesceWith(() -> suggestHashLinkIncludeDirectory(hlLibDir)); 82 | 83 | final copyRuntimeFiles = options.exists("--copyRuntimeFiles"); 84 | final exFiles = options.oneOrMore("--exFile").or([]).map(toFile); 85 | final runtime = options.oneOrMore("--runtime").or([]).map(toFileOrDir); 86 | final saveCmdPath = options.zeroOrOne("--saveCmd").map(path -> switch path { 87 | case Zero: FilePath.from("./compile_hlc"); 88 | case One(relPath): FilePath.from(relPath); 89 | }); 90 | final relative = options.exists("--relative"); 91 | final compiler = options.one("--compiler") 92 | .map(validateCompiler) 93 | .orElse(() -> switch Environment.systemType { 94 | case Windows: Gcc; 95 | case Mac: Clang; 96 | }); 97 | final verbose = options.exists("--verbose"); 98 | 99 | final exOptions: Array = []; 100 | 101 | final hlcCompilerOptionSet = CommandOptions.set; 102 | for (option in options.keys()) 103 | if (!hlcCompilerOptionSet.has(option)) exOptions.push(option.toString()); 104 | 105 | final arguments: Arguments = { 106 | srcDir: srcDir, 107 | srcFile: srcFile, 108 | hlcJsonFile: hlcJsonFile, 109 | outDir: outDir, 110 | outFile: outFile, 111 | hlLibDir: hlLibDir, 112 | hlIncludeDir: hlIncludeDir, 113 | copyRuntimeFiles: copyRuntimeFiles, 114 | exFiles: exFiles, 115 | runtime: runtime, 116 | exOptions: exOptions, 117 | saveCmdPath: saveCmdPath, 118 | relative: relative, 119 | compiler: compiler, 120 | verbose: verbose 121 | }; 122 | 123 | if (verbose) { 124 | Sys.println('Set $currentDirectory as current directory.\n'); 125 | Sys.println('Sanitized arguments:\n${arguments.format(" ")}\n'); 126 | } 127 | 128 | return arguments; 129 | } 130 | 131 | private function validateCompiler(compilerStr: String): CCompiler { 132 | return switch compilerStr.toLowerCase() { 133 | case "gcc": Gcc; 134 | case "clang": Clang; 135 | default: 136 | final msg = 'Unknown compiler: $compilerStr\n This should be either gcc or clang.'; 137 | throw error(msg); 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /hxformat.json: -------------------------------------------------------------------------------- 1 | { 2 | "indentation": { 3 | "character": "tab", 4 | "tabWidth": 2, 5 | "conditionalPolicy": "alignedNestedIncrease" 6 | }, 7 | "sameLine": { 8 | "caseBody": "keep", 9 | "elseBody": "keep", 10 | "elseIf": "keep", 11 | "forBody": "keep", 12 | "ifBody": "keep", 13 | "ifElse": "keep", 14 | "whileBody": "keep" 15 | }, 16 | "whitespace": { 17 | "typeHintColonPolicy": "onlyAfter", 18 | "bracesConfig": { 19 | "anonTypeBraces": { 20 | "openingPolicy": "around", 21 | "closingPolicy": "around", 22 | "removeInnerWhenEmpty": true 23 | }, 24 | "blockBraces": { 25 | "openingPolicy": "around", 26 | "closingPolicy": "around", 27 | "removeInnerWhenEmpty": true 28 | }, 29 | "objectLiteralBraces": { 30 | "openingPolicy": "around", 31 | "closingPolicy": "around", 32 | "removeInnerWhenEmpty": true 33 | }, 34 | "typedefBraces": { 35 | "openingPolicy": "around", 36 | "closingPolicy": "around", 37 | "removeInnerWhenEmpty": true 38 | }, 39 | "unknownBraces": { 40 | "openingPolicy": "around", 41 | "closingPolicy": "around", 42 | "removeInnerWhenEmpty": true 43 | } 44 | } 45 | }, 46 | "wrapping": { 47 | "anonFunctionSignature": { 48 | "defaultWrap": "noWrap", 49 | "rules": [ 50 | { 51 | "conditions": [ 52 | { 53 | "cond": "itemCount >= n", 54 | "value": 7 55 | } 56 | ], 57 | "type": "onePerLine", 58 | "additionalIndent": 1 59 | }, 60 | { 61 | "conditions": [ 62 | { 63 | "cond": "totalItemLength >= n", 64 | "value": 60 65 | } 66 | ], 67 | "type": "onePerLine", 68 | "additionalIndent": 1 69 | }, 70 | { 71 | "conditions": [ 72 | { 73 | "cond": "lineLength >= n", 74 | "value": 80 75 | } 76 | ], 77 | "type": "onePerLine", 78 | "additionalIndent": 1 79 | } 80 | ] 81 | }, 82 | "arrayWrap": { 83 | "defaultWrap": "onePerLine", 84 | "rules": [ 85 | { 86 | "conditions": [ 87 | { 88 | "cond": "totalItemLength >= n", 89 | "value": 60 90 | } 91 | ], 92 | "type": "onePerLine" 93 | }, 94 | { 95 | "conditions": [ 96 | { 97 | "cond": "itemCount <= n", 98 | "value": 2 99 | } 100 | ], 101 | "type": "noWrap" 102 | }, 103 | { 104 | "conditions": [ 105 | { 106 | "cond": "itemCount >= n", 107 | "value": 10 108 | } 109 | ], 110 | "type": "noWrap" 111 | } 112 | ] 113 | }, 114 | "callParameter": { 115 | "defaultWrap": "noWrap", 116 | "rules": [ 117 | { 118 | "conditions": [ 119 | { 120 | "cond": "itemCount <= n", 121 | "value": 1 122 | } 123 | ], 124 | "type": "noWrap" 125 | }, 126 | { 127 | "conditions": [ 128 | { 129 | "cond": "totalItemLength >= n", 130 | "value": 60 131 | } 132 | ], 133 | "type": "onePerLine" 134 | }, 135 | { 136 | "conditions": [ 137 | { 138 | "cond": "lineLength >= n", 139 | "value": 81 140 | } 141 | ], 142 | "type": "onePerLine" 143 | }, 144 | { 145 | "conditions": [ 146 | { 147 | "cond": "itemCount >= n", 148 | "value": 7 149 | } 150 | ], 151 | "type": "fillLine" 152 | }, 153 | { 154 | "conditions": [ 155 | { 156 | "cond": "anyItemLength >= n", 157 | "value": 90 158 | } 159 | ], 160 | "type": "fillLine" 161 | } 162 | ] 163 | }, 164 | "functionSignature": { 165 | "defaultWrap": "fillLine", 166 | "rules": [ 167 | { 168 | "conditions": [ 169 | { 170 | "cond": "totalItemLength <= n", 171 | "value": 12 172 | } 173 | ], 174 | "type": "fillLine" 175 | }, 176 | { 177 | "conditions": [ 178 | { 179 | "cond": "itemCount >= n", 180 | "value": 3 181 | } 182 | ], 183 | "type": "onePerLine" 184 | }, 185 | { 186 | "conditions": [ 187 | { 188 | "cond": "totalItemLength >= n", 189 | "value": 60 190 | } 191 | ], 192 | "type": "onePerLine" 193 | }, 194 | { 195 | "conditions": [ 196 | { 197 | "cond": "lineLength >= n", 198 | "value": 90 199 | } 200 | ], 201 | "type": "onePerLine" 202 | } 203 | ] 204 | }, 205 | "implementsExtends": { 206 | "defaultWrap": "noWrap", 207 | "rules": [ 208 | { 209 | "conditions": [ 210 | { 211 | "cond": "lineLength >= n", 212 | "value": 90 213 | } 214 | ], 215 | "type": "onePerLine", 216 | "additionalIndent": 1 217 | }, 218 | { 219 | "conditions": [ 220 | { 221 | "cond": "itemCount >= n", 222 | "value": 4 223 | } 224 | ], 225 | "type": "onePerLine", 226 | "additionalIndent": 1 227 | } 228 | ] 229 | }, 230 | "metadataCallParameter": { 231 | "defaultWrap": "noWrap", 232 | "rules": [ 233 | { 234 | "conditions": [ 235 | { 236 | "cond": "itemCount <= n", 237 | "value": 2 238 | } 239 | ], 240 | "type": "noWrap" 241 | }, 242 | { 243 | "conditions": [ 244 | { 245 | "cond": "totalItemLength >= n", 246 | "value": 70 247 | } 248 | ], 249 | "type": "onePerLine" 250 | }, 251 | { 252 | "conditions": [ 253 | { 254 | "cond": "lineLength >= n", 255 | "value": 80 256 | } 257 | ], 258 | "type": "onePerLine" 259 | } 260 | ] 261 | }, 262 | "typeParameter": { 263 | "defaultWrap": "noWrap", 264 | "rules": [ 265 | { 266 | "conditions": [ 267 | { 268 | "cond": "itemCount <= n", 269 | "value": 2 270 | } 271 | ], 272 | "type": "keep" 273 | }, 274 | { 275 | "conditions": [ 276 | { 277 | "cond": "anyItemLength >= n", 278 | "value": 50 279 | } 280 | ], 281 | "type": "fillLine" 282 | }, 283 | { 284 | "conditions": [ 285 | { 286 | "cond": "totalItemLength >= n", 287 | "value": 70 288 | } 289 | ], 290 | "type": "fillLine" 291 | } 292 | ] 293 | }, 294 | "maxLineLength": 90 295 | } 296 | } 297 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # hlc-compiler 2 | 3 | Helps you compile HashLink/C code into executable. 4 | 5 | Inspired by [HLCC](https://github.com/Yanrishatum/HLCC), but hlc-compiler uses GCC/Clang while HLCC uses MS Visual Studio. 6 | 7 | See also for an example using Heaps.io. 8 | 9 | 10 | ## Install 11 | 12 | ```console 13 | haxelib install hlc-compiler 14 | ``` 15 | 16 | 17 | ## Prerequisites 18 | 19 | ### Supported OS 20 | 21 | - Windows 22 | - Mac 23 | 24 | ### Required Tools 25 | 26 | - [Haxe](https://haxe.org/) + [Haxelib](https://lib.haxe.org/) 27 | - [HashLink](https://hashlink.haxe.org/) 28 | - Either [GCC](https://gcc.gnu.org/) or [Clang](https://clang.llvm.org/) (see the `--compiler` option described below) 29 | 30 | ### Development Environment 31 | 32 | #### Windows 33 | 34 | - Windows 10 64bit 35 | - Haxe 4.2.3 + Haxelib 4.0.2 (via [lix](https://github.com/lix-pm/lix.client)) 36 | - HashLink 1.11.0 (via [scoop](https://scoop.sh/)) 37 | - GCC 11.2.0-9.0.0-r3 (via [scoop](https://scoop.sh/)) 38 | 39 | #### Mac 40 | 41 | - macOS Monterey 42 | - Haxe 4.2.3 + Haxelib 4.0.2 (via [lix](https://github.com/lix-pm/lix.client)) 43 | - HashLink 1.11.0 (via [homebrew](https://brew.sh/)) 44 | - Clang 13.1.6 (bundled with Xcode) 45 | 46 | 47 | ## Usage 48 | 49 | First you have to output HashLink/C code, e.g. `haxe --main Main --hl out/c/main.c`. 50 | 51 | For compiling the C code into executable, call `haxelib run hlc-compiler` with some options described below. 52 | 53 | ### hlc-compiler Options 54 | 55 | Basically there is no "mandatory" option, however sometimes you might have to specify some options explicitly depending 56 | on your environment. 57 | 58 | #### `--srcDir [path]` 59 | 60 | Directory where your HashLink/C code (including `main.c` and `hlc.json`) are located. 61 | 62 | Defaults to `./` (current working directory). 63 | 64 | #### `--srcFile [path]` 65 | 66 | File path to the `*.c` file to be compiled. 67 | 68 | The path should be either absolute or relative from `--srcDir` directory. 69 | 70 | Defaults to `main.c`. 71 | 72 | #### `--hlcJsonFile [path]` 73 | 74 | File path to the JSON file in your HashLink/C output. 75 | 76 | This can be any JSON file that unifies `{ libs: Array }` where `libs` is an array of required library names. 77 | 78 | The path should be either absolute or relative from `--srcDir` directory. 79 | 80 | Defaults to `hlc.json`. 81 | 82 | #### `--outDir [path]` 83 | 84 | Directory path of the output executable. 85 | 86 | This will also the destination directory when copying files if `--copyRuntimeFiles` is specified. 87 | 88 | - If not specified and `--outFile` is specified, `--outDir` defaults to the parent directory of `--outFile`. 89 | - If both not specified, defaults to the current working directory. 90 | 91 | *Note: hlc-compiler does not clean up old files/directories unless they are to be overwritten.* 92 | 93 | #### `--outFile [path]` / `-o [path]` 94 | 95 | File path of the output executable. 96 | 97 | If `--outDir` is sepcified as well, `--outFile` should be either absolute or relative from `--outDir` directory. 98 | 99 | Defaults to `./main`. 100 | 101 | #### `--hlLibDir [path]` 102 | 103 | Directory that contains required library files (`*.hdll` etc). 104 | 105 | If not specified: 106 | 107 | - On windows, hlc-compiler tries to find the HashLink installation directory from your environment variables (`HASHLINKPATH`, `HASHLINK` or `HASHLINK_BIN`) as it should contain the files in question. 108 | - On Mac, defaults to `/usr/local/lib/` if it exists, as the library files are typically located here. 109 | - If nothing found, defaults to `./` (current working directory). 110 | 111 | #### `--hlIncludeDir [path]` 112 | 113 | Directory that contains HashLink built-in files to be included (`.h`/`.c` files, such as `hlc.h`). 114 | 115 | This will be passed to the C compiler (`gcc`/`clang`) as an `-I` option. 116 | 117 | - On Windows: Defaults to directory named `include` in the `--hlLibDir` directory (because it should exist in the HashLink directory, to which `--hlLibDir` is typically set). `null` (will not be passed) if not found. 118 | - On Mac: Defaults to `null`, as the files in question are typically located in `/usr/local/include/`, which is automaticaly searched by the C compiler at default. 119 | - Alternatively you can set an environment variable `C_INCLUDE_PATH` to the path of this `include` directory so that it is automatically searched by the C compiler as well. 120 | - If something goes wrong, try passing `-v` option and see which directories are searched by the C compiler. 121 | 122 | #### `--copyRuntimeFiles` 123 | 124 | Copies files that are required at runtime (such as dynamic linked libraries) to output directory. 125 | 126 | Not set at default. 127 | 128 | #### `--exFile [path]` 129 | 130 | Additional file to be passed to the C compiler (for instance you might have to pass `dbghelp.dll`). 131 | 132 | Can be specified multiple times. Not copied even if `--copyRuntimeFiles` is set. 133 | 134 | #### `--runtime [path]` 135 | 136 | Additional file or directory that should be copied if `--copyRuntimeFiles` is specified. 137 | 138 | The path should be either absolute or relative from the current working directory. 139 | 140 | Can be specified multiple times. No effect on compilation. 141 | 142 | #### `--saveCmd [path]` 143 | 144 | File path where command-lines should be saved (as batch file on Windows, shell command file on Mac). 145 | 146 | Not set (= does not save) at default. 147 | 148 | If `--saveCmd` is given without any argument value, the file path defaults to `./compile-hlc.bat` or `./compile-hlc.command` in the current directory. 149 | 150 | #### `--relative` 151 | 152 | Tries to convert all file/directory paths to relative paths from the current working directory when building command lines. 153 | 154 | #### `--compiler` 155 | 156 | The C compiler to use. 157 | 158 | Allowed values: `gcc`, `clang` 159 | 160 | Defaults to `gcc` if Windows, `clang` if Mac. 161 | 162 | #### `--verbose` 163 | 164 | Prints verbose log of hlc-compiler. 165 | 166 | #### `(other)` 167 | 168 | If using GCC, you can pass any [gcc option](https://gcc.gnu.org/onlinedocs/gcc/Option-Summary.html). 169 | (If Clang, most options should be the same but I'm not sure) 170 | 171 | If no `-std` option is provided, `-std=c11` is automatically added. 172 | 173 | Other examples: 174 | 175 | - `-O3` for highest optimization 176 | - `-w` to suppress warnings 177 | - `-v` to see more detailed log of the C compiler 178 | - `-mwindows` for making a Windows GUI app 179 | 180 | 181 | ## Usage Example 182 | 183 | ### Windows 184 | 185 | Assuming that you: 186 | 187 | - have compiled your Haxe code with `haxe --main Main --hl out\c\main.c` 188 | - installed HashLink in `C:\hashlink\1.11.0\` 189 | 190 | Then an example would be: 191 | 192 | ```console 193 | haxelib run hlc-compiler --srcDir out\c --outFile bin\main --hlLibDir c:\hashlink\1.11.0\ --copyRuntimeFiles --exFile c:\Windows\System32\dbghelp.dll --saveCmd out\run_gcc.bat -w 194 | ``` 195 | 196 | This will: 197 | 198 | - run `gcc` command so that your code is compiled into `bin\main.exe` 199 | - GCC warnings are suppressed (by `-w`) 200 | - copy files that are required at runtime into `bin\` 201 | - save command lines as `out\run_gcc.bat` 202 | 203 | The batch file looks like: 204 | 205 | ```Batchfile 206 | @echo off 207 | 208 | if not exist c:\yourDir\bin\ ^ 209 | mkdir c:\yourDir\bin\ 210 | 211 | echo Compiling... 212 | 213 | gcc ^ 214 | -o c:\yourDir\bin\main ^ 215 | -I c:\hashlink\1.11.0\include\ ^ 216 | -I c:\yourDir\out\c\ ^ 217 | -w ^ 218 | -std=c11 ^ 219 | c:\yourDir\out\c\main.c ^ 220 | c:\Windows\System32\dbghelp.dll ^ 221 | c:\hashlink\1.11.0\libhl.lib 222 | 223 | echo Copying runtime files... 224 | 225 | copy c:\hashlink\1.11.0\libhl.dll c:\yourDir\bin\ > nul 226 | 227 | echo Completed. 228 | ``` 229 | 230 | It depends on your `hlc.json` which library files are required. 231 | 232 | 233 | ## What comes next 234 | 235 | - File format (something similar to `*.hxml`) for describing options 236 | - Haxe API (which is type-safer) 237 | 238 | 239 | ## Library Dependencies 240 | 241 | - [sinker](https://github.com/fal-works/sinker) v0.6.0 or compatible 242 | - [greeter](https://github.com/fal-works/greeter) v0.1.0 or compatible 243 | - [locator](https://github.com/fal-works/banker) v0.5.0 or compatible 244 | 245 | See also: 246 | [FAL Haxe libraries](https://github.com/fal-works/fal-haxe-libraries) 247 | 248 | 249 | ## Something other 250 | 251 | [hlc-compiler wiki](https://github.com/fal-works/hlc-compiler/wiki) 252 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. --------------------------------------------------------------------------------