├── temp └── .gitignore ├── tests ├── small.2.gloa ├── .gitignore ├── types.errorLocal.gloa ├── types.errorGlobal.gloa ├── basic.load.gloa ├── ffi │ ├── zlibwapi.dll │ ├── conf.gloa │ ├── zlib.license │ └── main.gloa ├── suite.template.ini ├── deepCompilation.2.gloa ├── types.load.gloa ├── small.gloa ├── deepCompilation.1.gloa ├── deepCompilation.luaModule.gloa ├── assignmentsWithBinaryOperations.gloa ├── compileTimeExecution.gloa ├── deepCompilation.gloa ├── suite.gloa ├── modules.gloa ├── parsing.gloa └── languageOverview.gloa ├── .gitattributes ├── .gitignore ├── modules ├── test.gloa ├── loveRevised │ ├── timer.gloa │ ├── image.gloa │ ├── data.gloa │ ├── thread.gloa │ ├── window.gloa │ ├── keyboard.gloa │ ├── joystick.gloa │ ├── basic.gloa │ ├── filesystem.gloa │ └── math.gloa ├── math │ ├── vector2.gloa │ ├── intersect2.gloa │ └── math.gloa ├── utils.gloa ├── gc.gloa ├── lua.gloa ├── macos │ └── icns.gloa ├── love │ ├── artal.gloa │ ├── config.gloa │ └── physfs.gloa ├── utf8.gloa ├── wx │ ├── wxgl_gl.gloa │ ├── wxxrc_xrc.gloa │ ├── common.gloa │ ├── wxluasocket.gloa │ ├── wxcore_help.gloa │ ├── wxmedia_media.gloa │ ├── wxxml_xml.gloa │ ├── wxbase_config.gloa │ └── wxlua.gloa ├── print.gloa ├── preload.gloa ├── compiler.gloa ├── color.gloa ├── os.gloa ├── ffi.gloa └── io │ └── io.gloa ├── src ├── messengerEnums.luapart ├── runner.luapart ├── ready.luapart ├── unicodeConversions.luapart ├── messenger.luapart └── compilerApi.luapart ├── LICENSE.txt └── docs └── Confusion.txt /temp/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /tests/small.2.gloa: -------------------------------------------------------------------------------- 1 | -- export_value 8 2 | -------------------------------------------------------------------------------- /tests/.gitignore: -------------------------------------------------------------------------------- 1 | *.lua 2 | 3 | /suite.ini 4 | -------------------------------------------------------------------------------- /tests/types.errorLocal.gloa: -------------------------------------------------------------------------------- 1 | local other :: () {} 2 | -------------------------------------------------------------------------------- /tests/types.errorGlobal.gloa: -------------------------------------------------------------------------------- 1 | export other :: () {} 2 | -------------------------------------------------------------------------------- /tests/basic.load.gloa: -------------------------------------------------------------------------------- 1 | export triple :: (n:int) -> (result:int) { 2 | return 3*n 3 | } 4 | -------------------------------------------------------------------------------- /tests/ffi/zlibwapi.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReFreezed/Gloa/HEAD/tests/ffi/zlibwapi.dll -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.gloa linguist-language=Lua 2 | *.lua2p linguist-language=Lua 3 | *.luapart linguist-language=Lua 4 | -------------------------------------------------------------------------------- /tests/suite.template.ini: -------------------------------------------------------------------------------- 1 | # To make the test suite script use this file, copy it and rename the copy to suite.ini 2 | examplesFolder= 3 | -------------------------------------------------------------------------------- /tests/deepCompilation.2.gloa: -------------------------------------------------------------------------------- 1 | local main :: () { 2 | !import "basic" 3 | !import "string" 4 | print((replace("Program 2!", "gram", "ton"))) 5 | } 6 | -------------------------------------------------------------------------------- /tests/types.load.gloa: -------------------------------------------------------------------------------- 1 | local ThingInOtherFile :: struct {} 2 | 3 | export funcInOtherFile :: (a:int) -> ThingInOtherFile { 4 | local b:ThingInOtherFile 5 | myGlobalFunc() 6 | return b 7 | } 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gloa.* 2 | local/ 3 | 4 | /*.sublime-* 5 | /.run 6 | /gloa.lua 7 | /gloa.meta.lua 8 | /examples/ 9 | 10 | # Eclipse garbage. Sigh... 11 | /.buildpath 12 | /.project 13 | /.settings/ 14 | -------------------------------------------------------------------------------- /tests/small.gloa: -------------------------------------------------------------------------------- 1 | local assert :: (b:bool) !foreign lua "assert" 2 | local print :: (...:any) !foreign lua "print" 3 | 4 | local main :: () { 5 | do { 6 | } 7 | -- Errors: 8 | do { 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /modules/test.gloa: -------------------------------------------------------------------------------- 1 | -- 2 | -- Test module. Do not use! 3 | -- 4 | 5 | local ANY :: any 6 | local invisible :: () {} 7 | 8 | export testFunction :: () { 9 | local print :: (...:ANY) !foreign lua "print" 10 | print("Inside testFunction.") 11 | } 12 | 13 | --====== Things that should result in an error. ======-- 14 | 15 | -- ... 16 | -------------------------------------------------------------------------------- /tests/deepCompilation.1.gloa: -------------------------------------------------------------------------------- 1 | local main :: () { 2 | !import "basic" 3 | print("Program 1!") 4 | } 5 | 6 | local Foo :: struct {} 7 | local Bar :: struct (n:int) {} 8 | 9 | local Animal :: namespace { 10 | export Dog :: struct (color:string) {} 11 | } 12 | 13 | local thing = "tree" @Foo @Bar(5) 14 | local iAmInt = 5; @Animal.Dog"green" -- Notes go after any semicolon. 15 | -------------------------------------------------------------------------------- /modules/loveRevised/timer.gloa: -------------------------------------------------------------------------------- 1 | --[[============================================================ 2 | --= 3 | --= LÖVE bindings (love2d.org) 4 | --= love.timer 5 | --= 6 | --= Supported versions: 11.3 7 | --= 8 | --============================================================== 9 | 10 | getTime 11 | 12 | --============================================================]] 13 | 14 | -- !import "loveRevised/basic" 15 | 16 | export getTime :: () -> float !foreign lua "love.timer.getTime" 17 | -------------------------------------------------------------------------------- /modules/loveRevised/image.gloa: -------------------------------------------------------------------------------- 1 | --[[============================================================ 2 | --= 3 | --= LÖVE bindings (love2d.org) 4 | --= love.image 5 | --= 6 | --= Supported versions: 11.3 7 | --= 8 | --============================================================== 9 | 10 | -- Types: 11 | ImageData 12 | 13 | --============================================================]] 14 | 15 | !import "loveRevised/basic" 16 | 17 | export ImageData :: !foreign struct { using Data } 18 | 19 | -- @Incomplete! 20 | -------------------------------------------------------------------------------- /modules/loveRevised/data.gloa: -------------------------------------------------------------------------------- 1 | --[[============================================================ 2 | --= 3 | --= LÖVE bindings (love2d.org) 4 | --= love.data 5 | --= 6 | --= Supported versions: 11.3 7 | --= 8 | --============================================================== 9 | 10 | -- Enums: 11 | ContainerType 12 | 13 | --============================================================]] 14 | 15 | -- !import "loveRevised/basic" 16 | 17 | export ContainerType :: enum { 18 | DATA :: "data", 19 | STRING :: "string", 20 | } 21 | 22 | -- @Incomplete! 23 | -------------------------------------------------------------------------------- /tests/deepCompilation.luaModule.gloa: -------------------------------------------------------------------------------- 1 | !run { 2 | !import "compiler" 3 | 4 | local options = getBuildOptions() 5 | options.outputType = BuildOutputType.LUA_MODULE 6 | setBuildOptions(options) 7 | } 8 | 9 | local someFunc :: () { 10 | !import "basic" 11 | print("So funky!") 12 | } 13 | 14 | local round :: !import"math".round 15 | 16 | local Module :: struct { 17 | foo: string = NULL, 18 | func: () = NULL, 19 | round: (x:float) -> int = NULL, 20 | } 21 | export_value cast(Module) { 22 | foo = "bar"; 23 | func = someFunc; 24 | round = round; 25 | } 26 | -------------------------------------------------------------------------------- /tests/ffi/conf.gloa: -------------------------------------------------------------------------------- 1 | !import "loveRevised/event" 2 | 3 | local main :: () { 4 | setConfigHandler((using conf:Config) { 5 | modules.audio = false 6 | modules.data = false 7 | modules.event = true 8 | modules.font = false 9 | modules.graphics = false 10 | modules.image = false 11 | modules.joystick = false 12 | modules.keyboard = false 13 | modules.math = false 14 | modules.mouse = false 15 | modules.physics = false 16 | modules.sound = false 17 | modules.system = false 18 | modules.thread = false 19 | modules.timer = false 20 | modules.touch = false 21 | modules.video = false 22 | modules.window = false 23 | }) 24 | } 25 | -------------------------------------------------------------------------------- /modules/loveRevised/thread.gloa: -------------------------------------------------------------------------------- 1 | --[[============================================================ 2 | --= 3 | --= LÖVE bindings (love2d.org) 4 | --= love.thread 5 | --= 6 | --= Supported versions: 11.3 7 | --= 8 | --============================================================== 9 | 10 | -- Types: 11 | Thread 12 | 13 | --============================================================]] 14 | 15 | !import "loveRevised/basic" 16 | 17 | export Thread :: !foreign struct { 18 | using Object, 19 | 20 | isRunning :: (thread:Thread) -> bool !foreign method "isRunning", 21 | start :: (thread:Thread, --[[args]]...:Variant) !foreign method "start", 22 | wait :: (thread:Thread) !foreign method "wait", 23 | 24 | getError :: (thread:Thread) -> string|none !foreign method "getError", -- Returns nil if there has been no error. 25 | } 26 | 27 | -- @Incomplete! 28 | -------------------------------------------------------------------------------- /modules/loveRevised/window.gloa: -------------------------------------------------------------------------------- 1 | --[[============================================================ 2 | --= 3 | --= LÖVE bindings (love2d.org) 4 | --= love.window 5 | --= 6 | --= Supported versions: 11.3 7 | --= 8 | --============================================================== 9 | 10 | -- Enums: 11 | DisplayOrientation 12 | FullscreenType 13 | 14 | --============================================================]] 15 | 16 | -- !import "loveRevised/basic" 17 | 18 | export DisplayOrientation :: enum { 19 | UNKNOWN :: "unknown", 20 | LANDSCAPE :: "landscape", 21 | LANDSCAPE_FLIPPED :: "landscapeflipped", 22 | PORTRAIT :: "portrait", 23 | PORTRAIT_FLIPPED :: "portraitflipped", 24 | } 25 | 26 | export FullscreenType :: enum { 27 | DESKTOP :: "desktop", -- Windowed mode. 28 | FULLSCREEN :: "fullscreen", -- Borderless fullscreen. 29 | EXCLUSIVE :: "exclusive", -- Exclusive fullscreen. 30 | } 31 | 32 | -- @Incomplete! 33 | -------------------------------------------------------------------------------- /src/messengerEnums.luapart: -------------------------------------------------------------------------------- 1 | --[[============================================================ 2 | --= 3 | --= Messenger enums 4 | --= 5 | --= These are reflected in modules/compiler.gloa 6 | --= 7 | --=------------------------------------------------------------- 8 | --= 9 | --= Glóa - a language that compiles into Lua 10 | --= by Marcus 'ReFreezed' Thunström 11 | --= 12 | --============================================================]] 13 | !recordLineNumber(@file, @line) 14 | 15 | !( 16 | _G.MESSAGE_CODE_TYPECHECKED = 1 17 | _G.MESSAGE_COMPILATION_PHASE = 2 18 | _G.MESSAGE_COMPLETE = 3 19 | _G.MESSAGE_FILE = 4 20 | 21 | _G.COMPILATION_PHASE_SOURCE_CODE_PARSED = 1 22 | _G.COMPILATION_PHASE_PRE_WRITE_OUTPUT = 2 23 | _G.COMPILATION_PHASE_POST_WRITE_OUTPUT = 3 24 | 25 | N(0) 26 | _G.CODE_DECLARATION = incN() 27 | _G.CODE_IDENTIFIER = incN() 28 | _G.CODE_LITERAL = incN() 29 | _G.CODE_OPERATOR_EXPRESSION = incN() 30 | -- @Incomplete... 31 | ) 32 | -------------------------------------------------------------------------------- /modules/math/vector2.gloa: -------------------------------------------------------------------------------- 1 | --[[============================================================ 2 | --= 3 | --= Glóa 2D vector module 4 | --= 5 | --============================================================== 6 | 7 | add 8 | dot 9 | rotate 10 | translate, translateTowards 11 | 12 | --============================================================]] 13 | 14 | local math :: !import "math" 15 | 16 | export rotate :: (x,y:float, angle:float) -> (x,y:float) { 17 | local c = math.cos(angle) 18 | local s = math.sin(angle) 19 | return c*x-s*y, s*x+c*y 20 | } 21 | 22 | export dot :: (x,y:float, otherX,otherY:float) -> float { 23 | return x*otherX + y*otherY 24 | } 25 | 26 | export translate :: (x1,y1:float, x2,y2:float) -> (x,y:float) { 27 | return x1+x2, y1+y2 28 | } 29 | export translateTowards :: (x,y:float, angle:float, distance:float) -> (x,y:float) { 30 | return x+distance*math.cos(angle), y+distance*math.sin(angle) 31 | } 32 | export translateTowards :: (x,y:float, targetX,targetY:float, distance:float) -> (x,y:float) { 33 | return translate(x,y, math.atan(targetY-y, targetX-x), distance) 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright © 2019-2021 Marcus 'ReFreezed' Thunström 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /tests/ffi/zlib.license: -------------------------------------------------------------------------------- 1 | zlib.h -- interface of the 'zlib' general purpose compression library 2 | version 1.2.11, January 15th, 2017 3 | 4 | Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler 5 | 6 | This software is provided 'as-is', without any express or implied 7 | warranty. In no event will the authors be held liable for any damages 8 | arising from the use of this software. 9 | 10 | Permission is granted to anyone to use this software for any purpose, 11 | including commercial applications, and to alter it and redistribute it 12 | freely, subject to the following restrictions: 13 | 14 | 1. The origin of this software must not be misrepresented; you must not 15 | claim that you wrote the original software. If you use this software 16 | in a product, an acknowledgment in the product documentation would be 17 | appreciated but is not required. 18 | 2. Altered source versions must be plainly marked as such, and must not be 19 | misrepresented as being the original software. 20 | 3. This notice may not be removed or altered from any source distribution. 21 | 22 | Jean-loup Gailly Mark Adler 23 | jloup@gzip.org madler@alumni.caltech.edu 24 | -------------------------------------------------------------------------------- /modules/utils.gloa: -------------------------------------------------------------------------------- 1 | --[[============================================================ 2 | --= 3 | --= Glóa utils module 4 | --= 5 | --============================================================== 6 | 7 | getProgramArguments, getCommandLineArguments 8 | wrapFunctionInGloaErrorHandler 9 | 10 | --============================================================]] 11 | 12 | -- Get the command line arguments for the program. (Also see getCompilerArguments) 13 | export getProgramArguments :: () -> []string !foreign compiler "getProgramArguments" 14 | 15 | -- Get all arguments from the command line, including Lua's arguments at index 16 | -- 0 and below (https://www.lua.org/manual/5.1/manual.html#6). At compile-time 17 | -- it also includes compiler arguments. 18 | export getCommandLineArguments :: () -> []string !foreign compiler "getCommandLineArguments" 19 | 20 | -- 21 | -- Make Glóa handle errors triggered by a function. 22 | -- 23 | -- This is useful if an external library or framework tries to handle an error 24 | -- triggered by a callback provided by you, but you instead want to trigger a 25 | -- normal Glóa error before the library knows what happened. 26 | -- 27 | export wrapFunctionInGloaErrorHandler :: (func:any) -> ...any !foreign compiler "wrapFunctionInGloaErrorHandler" 28 | -------------------------------------------------------------------------------- /modules/loveRevised/keyboard.gloa: -------------------------------------------------------------------------------- 1 | --[[============================================================ 2 | --= 3 | --= LÖVE bindings (love2d.org) 4 | --= love.keyboard 5 | --= 6 | --= Supported versions: 11.3 7 | --= 8 | --============================================================== 9 | 10 | hasKeyRepeat, setKeyRepeat 11 | hasTextInput, setTextInput 12 | isKeyDown, isScancodeDown 13 | keyToScancode, scancodeToKey 14 | 15 | Enums: 16 | Key, Scancode 17 | 18 | --============================================================]] 19 | 20 | -- !import "loveRevised/basic" 21 | 22 | -- 23 | -- Enums 24 | -- 25 | 26 | -- @Incomplete @Robustness: Use enums for keys and scancodes. (Maybe it's a bad idea actually...) 27 | export Key :: string 28 | export Scancode :: string 29 | 30 | -- 31 | -- Functions 32 | -- 33 | 34 | export keyToScancode :: (key:Key) -> (scancode:Scancode) !foreign lua "love.keyboard.getScancodeFromKey" 35 | export scancodeToKey :: (scancode:Scancode) -> (key:Key) !foreign lua "love.keyboard.getKeyFromScancode" 36 | 37 | export hasKeyRepeat :: () -> (enabled:bool) !foreign lua "love.keyboard.hasKeyRepeat" 38 | export setKeyRepeat :: (enabled:bool) !foreign lua "love.keyboard.setKeyRepeat" 39 | 40 | export hasTextInput :: () -> (enabled:bool) !foreign lua "love.keyboard.hasTextInput" 41 | export setTextInput :: (enabled:bool) !foreign lua "love.keyboard.setTextInput" 42 | export setTextInput :: (enabled:bool, x,y,w,h:int) !foreign lua "love.keyboard.setTextInput" 43 | 44 | export isKeyDown :: (key, ...: Key) -> bool !foreign lua "love.keyboard.isDown" 45 | export isScancodeDown :: (scancode, ...: Scancode) -> bool !foreign lua "love.keyboard.isScancodeDown" 46 | -------------------------------------------------------------------------------- /modules/loveRevised/joystick.gloa: -------------------------------------------------------------------------------- 1 | --[[============================================================ 2 | --= 3 | --= LÖVE bindings (love2d.org) 4 | --= love.joystick 5 | --= 6 | --= Supported versions: 11.3 7 | --= 8 | --============================================================== 9 | 10 | -- Types: 11 | Joystick 12 | 13 | -- Enums: 14 | GamepadAxis, GamepadButton 15 | JoystickHat, JoystickInputType 16 | 17 | --============================================================]] 18 | 19 | !import "loveRevised/basic" 20 | 21 | export GamepadAxis :: enum { 22 | LEFT_X :: "leftx", 23 | LEFT_Y :: "lefty", 24 | RIGHT_X :: "rightx", 25 | RIGHT_Y :: "righty", 26 | TRIGGER_LEFT :: "triggerleft", 27 | TRIGGER_RIGHT :: "triggerright", 28 | } 29 | export GamepadButton :: enum { 30 | A :: "a", 31 | B :: "b", 32 | X :: "x", 33 | Y :: "y", 34 | BACK :: "back", 35 | GUIDE :: "guide", 36 | START :: "start", 37 | LEFT_STICK :: "leftstick", 38 | RIGHT_STICK :: "rightstick", 39 | LEFT_SHOULDER :: "leftshoulder", 40 | RIGHT_SHOULDER :: "rightshoulder", 41 | DP_UP :: "dpup", 42 | DP_DOWN :: "dpdown", 43 | DP_LEFT :: "dpleft", 44 | DP_RIGHT :: "dpright", 45 | } 46 | 47 | export JoystickHat :: enum { 48 | CENTER :: "c", 49 | DOWN :: "d", 50 | LEFT :: "l", 51 | LEFT_DOWN :: "ld", 52 | LEFT_UP :: "lu", 53 | RIGHT :: "r", 54 | RIGHT_DOWN :: "rd", 55 | RIGHT_UP :: "ru", 56 | UP :: "u", 57 | } 58 | export JoystickInputType :: enum { 59 | AXIS :: "axis", 60 | BUTTON :: "button", 61 | HAT :: "hat", 62 | } 63 | 64 | export Joystick :: !foreign struct { 65 | using Object, 66 | -- @Incomplete 67 | } 68 | 69 | -- @Incomplete! 70 | -------------------------------------------------------------------------------- /modules/gc.gloa: -------------------------------------------------------------------------------- 1 | --[[============================================================ 2 | --= 3 | --= Glóa garbage collector module 4 | --= 5 | --============================================================== 6 | 7 | collect, stop, restart 8 | getMemoryUsage, getMemoryUsageInBytes 9 | getPause, setPause 10 | getStepMultiplier, setStepMultiplier 11 | step 12 | 13 | --============================================================]] 14 | 15 | local collectgarbage :: (opt:string, arg:int|none=nil) -> any !foreign lua "collectgarbage" 16 | 17 | export collect :: () !foreign lua "collectgarbage" 18 | export stop :: () { collectgarbage("stop") } 19 | export restart :: () { collectgarbage("restart") } 20 | 21 | export step :: (size:int) -> (finishedCollectionCycle:bool) { 22 | return cast(bool) collectgarbage("step", size) 23 | } 24 | 25 | export getMemoryUsage :: () -> (kiloBytes:float) { 26 | return cast(float) collectgarbage("count") 27 | } 28 | export getMemoryUsageInBytes :: () -> (bytes:int) { 29 | local floor :: (x:float) -> int !foreign lua "math.floor" 30 | return floor(getMemoryUsage()*1024+.5) -- Not sure if rounding is absolutely necessary to ensure an int here. 31 | } 32 | 33 | local Percent :: int 34 | 35 | export getPause :: () -> Percent { 36 | local value = cast(Percent) collectgarbage("setpause", 1000) -- Hacky, but there's no other way to do this. 37 | collectgarbage("setpause", value) 38 | return value 39 | } 40 | export setPause :: (value:Percent) -> (previousValue:Percent) { 41 | return cast(Percent) collectgarbage("setpause", value) 42 | } 43 | 44 | export getStepMultiplier :: () -> Percent { 45 | local multiplier = cast(Percent) collectgarbage("setstepmul", 0) -- Hacky, but there's no other way to do this. 46 | collectgarbage("setstepmul", multiplier) 47 | return multiplier 48 | } 49 | export setStepMultiplier :: (multiplier:Percent) -> (previousMultiplier:Percent) { 50 | return cast(Percent) collectgarbage("setstepmul", multiplier) 51 | } 52 | -------------------------------------------------------------------------------- /modules/lua.gloa: -------------------------------------------------------------------------------- 1 | --[[============================================================ 2 | --= 3 | --= Glóa Lua module 4 | --= 5 | --============================================================== 6 | 7 | ENVIRONMENT 8 | VERSION_STRING 9 | 10 | getType 11 | doFile, loadFile, loadString 12 | 13 | -- Enums: 14 | LuaType 15 | 16 | --============================================================]] 17 | 18 | export VERSION_STRING : string : !foreign lua "_VERSION" 19 | export ENVIRONMENT : table : !foreign lua "_G" 20 | 21 | export LuaType :: enum { 22 | BOOLEAN :: "boolean", 23 | FUNCTION :: "function", 24 | NIL :: "nil", 25 | NUMBER :: "number", 26 | STRING :: "string", 27 | TABLE :: "table", 28 | THREAD :: "thread", -- Coroutine. 29 | USERDATA :: "userdata", -- C data. 30 | -- CDATA :: "cdata", -- Special type by LuaFFI. (Not sure it should be included here.) 31 | } 32 | export getType :: (v:any) -> LuaType !foreign lua "type" 33 | 34 | export doFile :: (path:string) -> ...any !foreign lua "dofile" 35 | 36 | export loadFile :: (path:string, $ChunkType:Type) -> (success:bool, chunk:ChunkType, err:string) { 37 | local helper :: (path:string) -> (chunk:any, err:string) !foreign lua "loadfile" 38 | 39 | local chunk, err = helper(path) 40 | if chunk == nil return false, NULL, err 41 | 42 | return true, cast(ChunkType)chunk, "" 43 | } 44 | 45 | export loadString :: (lua:string, $ChunkType:Type, chunkName="") -> (success:bool, chunk:ChunkType, err:string) { 46 | local helper :: (lua:string, chunkName="") -> (chunk:any, err:string) !foreign lua "loadstring" 47 | 48 | local chunk, err = helper(lua, chunkName) 49 | if chunk == nil return false, NULL, err 50 | 51 | return true, cast(ChunkType)chunk, "" 52 | } 53 | 54 | -- Not sure this function is really needed. Lua modules should maybe always be 55 | -- required directly inside !foreign expressions or possibly using !preload. 56 | -- export requireModule :: (moduleName:string) -> any !foreign lua "require" 57 | -------------------------------------------------------------------------------- /tests/assignmentsWithBinaryOperations.gloa: -------------------------------------------------------------------------------- 1 | -- Trying to optimize output for assignments with binary operations... 2 | 3 | local main :: () { 4 | local i: int 5 | local o: struct { oo:int } 6 | local x: struct { y:struct{z:int} } 7 | static arr = {0, 0, 0, 0, 0} -- Static or local or whatever doesn't matter. 8 | 9 | local get3 :: () -> int, int, int { 10 | return 1, 2, 3 11 | } 12 | 13 | -- Targets: 14 | -- 1: Don't fetch i because no-op. 15 | -- 2: Don't fetch i because no-op. 16 | -- Values: 17 | -- 1: Don't fetch 1 because const. 18 | -- 2: Don't fetch 2 because const. 19 | i, i += 1, 2 20 | -- Preparation: 21 | -- (none) -- There are only consts and no-ops here. 22 | -- Assignment: 23 | -- i, i 24 | -- = i+1, i+2 25 | 26 | -- Targets: 27 | -- 1: Don't fetch o because no-op. 28 | -- Don't fetch oo because const. 29 | -- 2: Fetch x.y. 30 | -- Don't fetch z because const. 31 | -- 3: Don't fetch arr because no-op. 32 | -- Don't fetch i because no-op. 33 | -- Values: 34 | -- 1: Don't fetch 5 because const. 35 | -- 2: Don't fetch i because no-op. 36 | -- 3: Don't fetch x.y.z because evaluation order is fine. 37 | o.oo, x.y.z, arr[i] //= 5, i, x.y.z 38 | -- Preparation: 39 | -- local OBJ2 = x.y 40 | -- Assignment: 41 | -- o.oo, OBJ2.z, arr[i] 42 | -- = o.oo + 5, OBJ2.z + i, arr[i] + x.y.z 43 | 44 | -- Targets: 45 | -- 1: Don't fetch o because no-op. 46 | -- Don't fetch oo because const. 47 | -- 2: Fetch x.y. 48 | -- Don't fetch z because const. 49 | -- 3: Don't fetch arr because no-op. 50 | -- Fetch i+1. 51 | -- Values: 52 | -- 1: Fetch get3() because return values after first value is needed unpacked. 53 | o.oo, x.y.z, arr[i+1] += get3() 54 | -- Preparation: 55 | -- local OBJ2 = x.y 56 | -- local KEY3 = i+1 57 | -- local VAL1,VAL2,VAL3 = get3() 58 | -- Assignment: 59 | -- o.oo, OBJ2.z, arr[KEY3] 60 | -- = o.oo + VAL1, OBJ2.z + VAL2, arr[KEY3] + VAL3 61 | 62 | o.oo += 1 63 | o.oo, arr[i] += 1, 2 64 | } 65 | -------------------------------------------------------------------------------- /tests/compileTimeExecution.gloa: -------------------------------------------------------------------------------- 1 | -- 2 | -- Compile-time execution test. 3 | -- 4 | 5 | local getInt :: (less=0) -> int { 6 | !import "basic" 7 | 8 | local insideInt = globalInt 9 | insideInt += 5-less 10 | outsideString = "foo" 11 | 12 | print("What?", insideInt, outsideString) 13 | return globalInt 14 | } 15 | 16 | local fileLocalInt = !run getInt(1) 17 | export globalInt:int 18 | local outsideString = "" 19 | 20 | !assert type_of(fileLocalInt) == int 21 | 22 | local arr:[]int = !run ({0, 5*getInt()}) -- The parenthesis is only a parsing aid here. 23 | 24 | local getIntArrayType :: () -> Type { 25 | return type_of(arr) 26 | } 27 | local IntArray :: !run getIntArrayType() 28 | 29 | local main :: () { 30 | !import "basic" 31 | print("outsideString = '"..outsideString.."'") -- Should be empty. (Variables in metaprograms don't affect the final output.) 32 | print(getInt(-10)) 33 | local pear = Fruit.PEAR 34 | local enumInt = Numeric.INT 35 | } 36 | 37 | !run valueFunction1() 38 | !run valueFunction2() 39 | 40 | local Vector2 :: struct { x:float, y:float } 41 | 42 | local Fruit :: enum { 43 | APPLE :: 1, 44 | PEAR :: 2, 45 | ORANGE :: 3, 46 | } 47 | local Numeric :: enum { 48 | INT :: int, 49 | FLOAT :: float, 50 | } 51 | 52 | local valueAny = !run cast(any) 5 53 | local valueBool = !run true 54 | local valueInt = !run 5 55 | local valueNone = !run nil 56 | local valueFloat = !run 3.14 57 | local valueString = !run "foo" 58 | local valueTable = !run cast(table) {a=7, !import "math".getRandom()} 59 | local valueType = !run int 60 | local valueArray = !run cast([]int) {5} 61 | local valueFunction1 = !run (main) -- '!run main' without the parenthesis is an error because it's too ambiguous. :RunAmbiguity 62 | local valueFunction2 = !run (){} 63 | local valueStruct = !run cast(Vector2) {y=11.7} 64 | local valueEnum1 = !run (Fruit.PEAR) -- :RunAmbiguity 65 | local valueEnum2 = !run (Numeric.FLOAT) -- :RunAmbiguity 66 | !assert cast(Type)Numeric.FLOAT == float 67 | 68 | local add :: (a,b:float) -> float { return a+b } 69 | local chain = 1 + !run add(20, !run !import "math".sqrt(900)) 70 | -------------------------------------------------------------------------------- /docs/Confusion.txt: -------------------------------------------------------------------------------- 1 | Confusion 2 | Glóa 3 | 4 | Declarations, types, values, function/method calls, parameters... it can all get very confusing! 5 | 6 | local funcType : = ( arg:MyType (OtherType, int) ) -- Getting the type of a function (AKA a function signature) that takes a type as its one argument. 7 | local func : = ( arg:MyType (OtherType, int) ) {} -- Getting a reference to an anonymous function. 8 | local value : = ( obj.method!(OtherType, int) ) -- Calling a method which takes two types as arguments. 9 | local value : = ( obj.method!(OtherType, int) ) {} -- Invalid curly brackets! (Doesn't make sense.) 10 | 11 | local obj : MyType (OtherType, int) -- Specifying a variable type and implicitly instantiating a parameterized struct. (Note: Compare this to 'obj:int', which would implicitly initialize to 0.) 12 | local obj : MyType (OtherType, int) {} -- Invalid curly brackets! (Doesn't make sense.) 13 | 14 | local structType : = MyType (OtherType, int) -- Assigning a type to a variable. 15 | local structType : = MyType (OtherType, int) {} -- Invalid curly brackets! (Doesn't make sense.) 16 | local invalid : = (OtherType, int) -- Invalid! 17 | local invalid : = (OtherType, int) {} -- Invalid! Super invalid! 18 | local someType : = (OtherType ) -- Assigning a type to a variable. 19 | local someType : = (OtherType ) {} -- Invalid curly brackets! (Doesn't make sense.) 20 | 21 | local structType : : MyType (OtherType, int) -- Creating a (constant) alias for a type. 22 | local structType : : MyType (OtherType, int) {} -- Invalid curly brackets! (Doesn't make sense.) 23 | local invalid : : (OtherType, int) -- Invalid! 24 | local invalid : : (OtherType, int) {} -- Invalid! Super invalid! 25 | local someType : : (OtherType ) -- Creating a (constant) alias for a type. 26 | local someType : : (OtherType ) {} -- Invalid curly brackets! (Doesn't make sense.) 27 | 28 | A function takes another function as a parameter: 29 | 30 | transformAndDouble :: (transformer:(n:int)->string) -> string { 31 | local s = transformer(6) 32 | return s..s 33 | } 34 | -------------------------------------------------------------------------------- /modules/macos/icns.gloa: -------------------------------------------------------------------------------- 1 | --[[============================================================ 2 | --= 3 | --= Apple Icon Image module 4 | --= https://en.wikipedia.org/wiki/Apple_Icon_Image_format 5 | --= 6 | --============================================================== 7 | 8 | -- Functions: 9 | create 10 | 11 | ---------------------------------------------------------------- 12 | 13 | -- Usage: 14 | local icns :: !import "macos/icns" 15 | icns.create("MyIcon.icns", { 16 | {path="icon_32x32.png", size=32}, 17 | {path="icon_1024x1024.png", size=1024}, 18 | }) 19 | 20 | --============================================================]] 21 | 22 | !import "basic" 23 | local io :: !import "io" 24 | 25 | export ImageFile :: struct { 26 | path: string, -- Images must be PNG or JPEG 2000. 27 | size: int, -- Supported sizes: 16, 32, 64, 128, 256, 512, 1024 28 | } 29 | 30 | local SIZEOF_SIGNATURE :: 4 31 | local SIZEOF_TOTAL_SIZE :: 4 32 | local SIZEOF_ICON_TYPE :: 4 33 | local SIZEOF_ITEM_SIZE :: 4 34 | 35 | local ICON_TYPE: Table(int, string) : { 36 | [16] = "icp4", -- Supported OS version: 10.7 37 | [32] = "icp5", -- Supported OS version: 10.7 38 | [64] = "icp6", -- Supported OS version: 10.7 39 | [128] = "ic07", -- Supported OS version: 10.7 40 | [256] = "ic08", -- Supported OS version: 10.5 41 | [512] = "ic09", -- Supported OS version: 10.5 42 | [1024] = "ic10", -- Supported OS version: 10.7 43 | } 44 | 45 | export create :: (outputPath:string, imageFiles:[]ImageFile) -> (success:bool, err:string) { 46 | if not imageFiles return false, "File list is empty." 47 | 48 | for imageFiles if ICON_TYPE[it.size] == NULL { 49 | return false, format("Unsupported image size '%d'.", it.size) 50 | } 51 | 52 | local fileDatas: []string 53 | local totalSize = SIZEOF_SIGNATURE + SIZEOF_TOTAL_SIZE 54 | 55 | for imageFiles { 56 | local ok, contents, err = io.readEntireFile(it.path) 57 | if not ok return false, err 58 | 59 | fileDatas[itIndex] = contents 60 | totalSize += SIZEOF_ICON_TYPE + SIZEOF_ITEM_SIZE + #contents 61 | } 62 | 63 | local buffer: []string 64 | 65 | insert (buffer, "icns") 66 | writeInt(buffer, totalSize, SIZEOF_TOTAL_SIZE) 67 | 68 | for imageFiles { 69 | local iconType = ICON_TYPE[it.size] 70 | local itemSize = SIZEOF_ICON_TYPE + SIZEOF_ITEM_SIZE + #fileDatas[itIndex] 71 | insert (buffer, iconType) 72 | writeInt(buffer, itemSize, SIZEOF_ITEM_SIZE) 73 | insert (buffer, fileDatas[itIndex]) 74 | } 75 | 76 | local ok, err = io.writeEntireFile(outputPath, concatenate(buffer)) 77 | return ok, err 78 | } 79 | 80 | local writeInt :: (buffer:[]string, n:int, bytes:int) { 81 | local byteToString :: (byte:int) -> string !foreign lua "string.char" 82 | 83 | for pow = bytes-1, 0, -1 { 84 | local c = byteToString((n // 256^pow) % 256) 85 | insert(buffer, c) 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /modules/love/artal.gloa: -------------------------------------------------------------------------------- 1 | --[[============================================================ 2 | --= 3 | --= Artal bindings 4 | --= Load .psd (Photoshop) files in LÖVE. 5 | --= https://github.com/unXedDani/Artal 6 | --= 7 | --= Requires artal.lua 8 | --= 9 | --============================================================== 10 | 11 | loadAll, loadInfo, loadLayer, loadComposed 12 | 13 | Types: 14 | Psd 15 | 16 | Enums: 17 | PsdBlendMode 18 | PsdLayerType 19 | 20 | --============================================================]] 21 | 22 | local love :: !import "love" 23 | local FileData :: love.filesystem.FileData 24 | local Image :: love.graphics.Image 25 | local ImageData :: love.image.ImageData 26 | 27 | export PsdLayerType :: enum { 28 | IMAGE :: "image", -- Image layer with ImageData. 29 | EMPTY :: "empty", -- Image layer without ImageData. 30 | OPEN :: "open", -- Beginning of group layer. 31 | CLOSE :: "close", -- End of group layer. 32 | } 33 | 34 | export PsdBlendMode :: enum { 35 | NORMAL :: "norm", 36 | PASS_THROUGH :: "pass", 37 | MULTIPLY :: "mul", 38 | SCREEN :: "scrn", 39 | OVERLAY :: "over", 40 | DISSOLVE :: "diss", 41 | DARKEN :: "dark", 42 | COLOR_BURN :: "idiv", 43 | LINEAR_BURN :: "lbrn", 44 | DARKER_COLOR :: "dkCl", 45 | LIGHTEN :: "lite", 46 | COLOR_DODGE :: "div", 47 | LINEAR_DODGE :: "lddg", 48 | LIGHTER_COLOR :: "lgCl", 49 | SOFT_LIGHT :: "sLit", 50 | HARD_LIGHT :: "hLit", 51 | VIVID_LIGHT :: "vLit", 52 | LINEAR_LIGHT :: "lLit", 53 | PIN_LIGHT :: "pLit", 54 | HARD_MIX :: "hMix", 55 | DIFFERENCE :: "diff", 56 | EXCLUSION :: "smud", 57 | SUBTRACT :: "fsub", 58 | DIVIDE :: "fdiv", 59 | HUE :: "hue", 60 | SATURATION :: "sat", 61 | COLOR :: "colr", 62 | LUMINOSITY :: "lum", 63 | } 64 | 65 | export Psd :: !foreign struct { 66 | width: int, 67 | height: int, 68 | 69 | -- Layers... 70 | !value: !foreign struct { 71 | name: string, 72 | type: PsdLayerType, 73 | blend: PsdBlendMode, 74 | clip: bool, 75 | ox: int, 76 | oy: int, 77 | image: Image|none, -- Only set by loadAll(). 78 | }, 79 | } 80 | 81 | local Filename :: string 82 | local loadHelper :: (file:Filename|FileData, what:string|int|none=nil) -> Psd|ImageData|none !foreign lua "require'artal'.newPSD" 83 | 84 | export loadAll :: (file:Filename|FileData) -> Psd { return cast(Psd) loadHelper(file ) } 85 | export loadInfo :: (file:Filename|FileData) -> Psd { return cast(Psd) loadHelper(file, "info" ) } 86 | export loadComposed :: (file:Filename|FileData) -> ImageData { return cast(ImageData) loadHelper(file, "composed") } 87 | 88 | export loadLayer :: (file:Filename|FileData, layerNumber:int) -> (ok:bool, imageData:ImageData) { 89 | local imageData = loadHelper(file, layerNumber) 90 | if imageData == nil return false, NULL 91 | 92 | return true, cast(ImageData)imageData 93 | } 94 | -------------------------------------------------------------------------------- /modules/utf8.gloa: -------------------------------------------------------------------------------- 1 | --[[============================================================ 2 | --= 3 | --= Lua UTF-8 module bindings 4 | --= https://www.lua.org/manual/5.3/manual.html#6.5 5 | --= 6 | --============================================================== 7 | 8 | -- Types: 9 | Codepoint 10 | 11 | -- Functions: 12 | eachCodepoint 13 | getCodepoint, codepointsToString 14 | getLength 15 | getOffset, getBounds 16 | isValid 17 | 18 | -- Values: 19 | CHARACTER_PATTERN 20 | 21 | --============================================================]] 22 | 23 | !import "basic" 24 | 25 | export CHARACTER_PATTERN :: "[%z\1-\x7F\xC2-\xF4][\x80-\xBF]*" 26 | 27 | export Codepoint :: int 28 | 29 | export getCodepoint :: (s:string, bytePos=1) -> Codepoint|none !foreign lua "require'utf8'.codepoint" 30 | export getCodepoint :: (s:string, fromBytePos,toBytePos:int) -> ...Codepoint !foreign lua "require'utf8'.codepoint" 31 | export codepointsToString :: (...:Codepoint) -> string !foreign lua "require'utf8'.char" 32 | 33 | local CodepointIterator :: (_,_:none) -> (bytePos:int|none, cp:Codepoint) 34 | export eachCodepoint :: (s:string) -> CodepointIterator, none, none !foreign lua "require'utf8'.codes" 35 | 36 | local utf8Len :: (s:string, fromBytePos=1, toBytePos=-1) -> (len:int, errPos:int) !foreign lua "require'utf8'.len" 37 | local utf8Offset :: (s:string, charNum:int, fromBytePos=1--[[if charNum is positive, otherwise #s+1]]) -> (bytePos:int|none) !foreign lua "require'utf8'.offset" 38 | 39 | -- Returns -1 if the string is invalid UTF-8. 40 | export getLength :: (s:string, fromBytePos=1, toBytePos=-1) -> int { 41 | local len, errPos = utf8Len(s, fromBytePos, toBytePos) 42 | if errPos ~= NULL return -1 43 | return cast(int) len 44 | } 45 | 46 | export isValid :: (s:string, fromBytePos=1, toBytePos=-1) -> (valid:bool, errPos:int) { 47 | local _, errPos = utf8Len(s, fromBytePos, toBytePos) 48 | if errPos == NULL return true, 0 49 | return false, errPos 50 | } 51 | 52 | -- Returns -1 if charNum isn't in the subject nor right after it's end. 53 | export getOffset :: (s:string, charNum:int) -> (startBytePos:int) { 54 | local i = utf8Offset(s, charNum) 55 | if i == nil return -1 56 | return cast(int) i 57 | } 58 | 59 | -- Returns -1 if charNum isn't in the subject nor right after it's end. 60 | -- Note: fromBytePos must be at the start of a character (except if charNum is 0). 61 | export getOffset :: (s:string, charNum:int, fromBytePos:int) -> (startBytePos:int) { 62 | local i = utf8Offset(s, charNum, fromBytePos) 63 | if i == nil return -1 64 | return cast(int) i 65 | } 66 | 67 | -- Returns -1 if charNum isn't in the subject. 68 | export getBounds :: (s:string, charNum:int) -> (startBytePos,endBytePos:int) { 69 | local i = getOffset(s, charNum) 70 | if i < 0 or i > #s return -1, -1 71 | 72 | local len = getLength(s, i, i) 73 | 74 | return i, i+len-1 75 | } 76 | 77 | -- Returns -1 if charNum isn't in the subject. 78 | export getBounds :: (s:string, charNum:int, fromBytePos:int) -> (startBytePos,endBytePos:int) { 79 | local i = getOffset(s, 0, fromBytePos) 80 | if i < 0 or i > #s return -1, -1 81 | 82 | i = getOffset(s, charNum, i) 83 | local len = getLength(s, i, i) 84 | 85 | return i, i+len-1 86 | } 87 | -------------------------------------------------------------------------------- /modules/math/intersect2.gloa: -------------------------------------------------------------------------------- 1 | --[[============================================================ 2 | --= 3 | --= Glóa 2D shape intersection module 4 | --= 5 | --============================================================== 6 | 7 | isRectangleIntersectingAabb 8 | isRectangleIntersectingRectangle 9 | 10 | --============================================================]] 11 | 12 | !import "math" 13 | !import "math/vector2" 14 | 15 | export isRectangleIntersectingAabb :: (rectX,rectY:float, rectW,rectH:float, angle:float, aabbX,aabbY:float, aabbW,aabbH:float) -> bool { 16 | return isRectangleIntersectingRectangle(rectX,rectY, rectW,rectH, angle, aabbX,aabbY, aabbW,aabbH, 0) -- @Speed: AABB optimization. 17 | } 18 | export isRectangleIntersectingRectangle :: (ax,ay:float, aw,ah:float, aAngle:float, bx,by:float, bw,bh:float, bAngle:float) -> bool { 19 | local getMinMax :: (vectors:[]float, axisX,axisY:float) -> (minProj,maxProj:float) { 20 | local minProj = dot(vectors[1],vectors[2], axisX,axisY) 21 | local maxProj = minProj 22 | 23 | for 3, #vectors, 2 { 24 | local proj = dot(vectors[it],vectors[it+1], axisX,axisY) 25 | minProj = min(minProj, proj) 26 | maxProj = max(maxProj, proj) 27 | } 28 | 29 | return minProj, maxProj 30 | } 31 | 32 | local getRectCorners :: (x,y:float, w,h:float, angle:float, corners:[]float) { 33 | local wHalf = w/2 34 | local hHalf = h/2 35 | 36 | local rotatedX, rotatedY: float 37 | rotatedX, rotatedY = rotate( wHalf, -hHalf, angle) ; local ax, ay = translate(x,y, rotatedX,rotatedY) 38 | rotatedX, rotatedY = rotate( wHalf, hHalf, angle) ; local bx, by = translate(x,y, rotatedX,rotatedY) 39 | rotatedX, rotatedY = rotate(-wHalf, hHalf, angle) ; local cx, cy = translate(x,y, rotatedX,rotatedY) 40 | rotatedX, rotatedY = rotate(-wHalf, -hHalf, angle) ; local dx, dy = translate(x,y, rotatedX,rotatedY) 41 | 42 | corners[1], corners[2] = ax, ay 43 | corners[3], corners[4] = bx, by 44 | corners[5], corners[6] = cx, cy 45 | corners[7], corners[8] = dx, dy 46 | } 47 | 48 | local getRectNormals :: (angle:float) { 49 | local ax,ay = rotate(1, 0, angle ) 50 | local bx,by = rotate(ax,ay, 1*TAU/4) 51 | local cx,cy = rotate(ax,ay, 2*TAU/4) 52 | local dx,dy = rotate(ax,ay, 3*TAU/4) 53 | 54 | normals[1], normals[2] = ax, ay 55 | normals[3], normals[4] = bx, by 56 | normals[5], normals[6] = cx, cy 57 | normals[7], normals[8] = dx, dy 58 | } 59 | 60 | static aCorners : []float = {} 61 | static bCorners : []float = {} 62 | static normals : []float = {} 63 | 64 | getRectCorners(ax,ay, aw,ah, aAngle, aCorners) 65 | getRectCorners(bx,by, bw,bh, bAngle, bCorners) 66 | 67 | getRectNormals(aAngle) 68 | for 1, 8, 2 { 69 | local normalX, normalY = normals[it], normals[it+1] 70 | local minProj1, maxProj1 = getMinMax(aCorners, normalX, normalY) 71 | local minProj2, maxProj2 = getMinMax(bCorners, normalX, normalY) 72 | if maxProj1 < minProj2 or maxProj2 < minProj1 return false 73 | } 74 | 75 | getRectNormals(bAngle) 76 | for 1, 8, 2 { 77 | local normalX, normalY = normals[it], normals[it+1] 78 | local minProj1, maxProj1 = getMinMax(aCorners, normalX, normalY) 79 | local minProj2, maxProj2 = getMinMax(bCorners, normalX, normalY) 80 | if maxProj1 < minProj2 or maxProj2 < minProj1 return false 81 | } 82 | 83 | return true 84 | } 85 | -------------------------------------------------------------------------------- /modules/wx/wxgl_gl.gloa: -------------------------------------------------------------------------------- 1 | --[[============================================================ 2 | --= 3 | --= wxLua/wxWidget bindings for Glóa 4 | --= Interface source: wxgl_gl.i 5 | --= 6 | --= Tested with: 7 | --= - wxLua 2.8.7.0 / wxWidgets 2.8.8 8 | --= 9 | --= Note: Most bindings have not been tested yet! 10 | --= 11 | --============================================================]] 12 | 13 | !import "wx/wxcore_windows" 14 | !import "wx/common" 15 | !import "wx/wxcore_defsutils" 16 | !import "wx/wxcore_gdi" 17 | 18 | 19 | export WX_GL_RGBA: wxEnum : !foreign lua "wx.WX_GL_RGBA" 20 | export WX_GL_BUFFER_SIZE: wxEnum : !foreign lua "wx.WX_GL_BUFFER_SIZE" 21 | export WX_GL_LEVEL: wxEnum : !foreign lua "wx.WX_GL_LEVEL" 22 | export WX_GL_DOUBLEBUFFER: wxEnum : !foreign lua "wx.WX_GL_DOUBLEBUFFER" 23 | export WX_GL_STEREO: wxEnum : !foreign lua "wx.WX_GL_STEREO" 24 | export WX_GL_AUX_BUFFERS: wxEnum : !foreign lua "wx.WX_GL_AUX_BUFFERS" 25 | export WX_GL_MIN_RED: wxEnum : !foreign lua "wx.WX_GL_MIN_RED" 26 | export WX_GL_MIN_GREEN: wxEnum : !foreign lua "wx.WX_GL_MIN_GREEN" 27 | export WX_GL_MIN_BLUE: wxEnum : !foreign lua "wx.WX_GL_MIN_BLUE" 28 | export WX_GL_MIN_ALPHA: wxEnum : !foreign lua "wx.WX_GL_MIN_ALPHA" 29 | export WX_GL_DEPTH_SIZE: wxEnum : !foreign lua "wx.WX_GL_DEPTH_SIZE" 30 | export WX_GL_STENCIL_SIZE: wxEnum : !foreign lua "wx.WX_GL_STENCIL_SIZE" 31 | export WX_GL_MIN_ACCUM_RED: wxEnum : !foreign lua "wx.WX_GL_MIN_ACCUM_RED" 32 | export WX_GL_MIN_ACCUM_GREEN: wxEnum : !foreign lua "wx.WX_GL_MIN_ACCUM_GREEN" 33 | export WX_GL_MIN_ACCUM_BLUE: wxEnum : !foreign lua "wx.WX_GL_MIN_ACCUM_BLUE" 34 | export WX_GL_MIN_ACCUM_ALPHA: wxEnum : !foreign lua "wx.WX_GL_MIN_ACCUM_ALPHA" 35 | 36 | export wxGLCanvas :: !foreign struct { 37 | using wxWindow, 38 | 39 | !call :: (parent:wxWindow, id:wxWindowID=wxID_ANY, pos:wxPoint=wxDefaultPosition, size:wxSize=wxDefaultSize, style:int--[[long]]=0, name:wxString|string="GLCanvas", attribList:[]int=NULL, palette:wxPalette=wxNullPalette) -> wxGLCanvas !foreign lua "wx.wxGLCanvas", 40 | !call :: (parent:wxWindow, sharedContext:wxGLContext, id:wxWindowID=-1, pos:wxPoint=wxDefaultPosition, size:wxSize=wxDefaultSize, style:int--[[long]]=0, name:wxString|string="GLCanvas", attribList:[]int=NULL, palette:wxPalette=wxNullPalette) -> wxGLCanvas !foreign lua "wx.wxGLCanvas", 41 | !call :: (parent:wxWindow, sharedCanvas:wxGLCanvas, id:wxWindowID=-1, pos:wxPoint=wxDefaultPosition, size:wxSize=wxDefaultSize, style:int--[[long]]=0, name:wxString|string="GLCanvas", attribList:[]int=NULL, palette:wxPalette=wxNullPalette) -> wxGLCanvas !foreign lua "wx.wxGLCanvas", 42 | 43 | GetContext :: (self:wxGLCanvas) -> wxGLContext !foreign method "GetContext", 44 | SetCurrent :: (self:wxGLCanvas, RC:wxGLContext) !foreign method "SetCurrent", 45 | SetColour :: (self:wxGLCanvas, colour:wxString|string) !foreign method "SetColour", 46 | SwapBuffers :: (self:wxGLCanvas) !foreign method "SwapBuffers", 47 | } 48 | 49 | export wxGLContext :: !foreign struct { 50 | using wxObject, 51 | 52 | null: wxGLContext : !foreign lua "wx.NULL", 53 | 54 | !call :: (win:wxGLCanvas, other:wxGLContext=wxGLContext.null) -> wxGLContext !foreign lua "wx.wxGLContext", 55 | 56 | SetCurrent :: (self:wxGLContext, win:wxGLCanvas) !foreign method "SetCurrent", 57 | } 58 | -------------------------------------------------------------------------------- /tests/ffi/main.gloa: -------------------------------------------------------------------------------- 1 | -- 2 | -- LuaJIT FFI test 3 | -- 4 | -- This project uses FFI through the LÖVE framework! 5 | -- 6 | -- It also uses zlib for testing, but we only have a .dll at the moment. 7 | -- So, Windows-only for now. 8 | -- 9 | -- Original source for some of the code: luajit.org/ext_ffi_tutorial.html 10 | -- 11 | 12 | !import "basic" 13 | !import "io" 14 | !import "os" 15 | local ffi :: !import "ffi" 16 | 17 | local getSource :: () -> string !foreign lua "love.filesystem.getSource" 18 | local quit :: () !foreign lua "love.event.quit" 19 | 20 | !run { 21 | !import "compiler" 22 | compile("conf.gloa") 23 | } 24 | 25 | local main :: () { 26 | disableBuffering(STDOUT) 27 | disableBuffering(STDERR) 28 | print() 29 | 30 | testStandardSystemFunctions() 31 | testDynamicLibraries() 32 | 33 | print() 34 | quit() 35 | } 36 | 37 | local testStandardSystemFunctions :: () { 38 | ffi.define[[ 39 | void Sleep(int ms); // Windows. 40 | int poll(struct pollfd *fds, unsigned long nfds, int timeout); // Most non-Windows systems (supposedly). 41 | ]] 42 | 43 | local C = ffi.newInterface(!foreign struct { 44 | Sleep: (ms:int); 45 | poll: (fds:ffi.Cdata|none, nfds:int, timeout:int) -> int; 46 | }) 47 | 48 | local sleep = [C] (sec:float) { 49 | C.Sleep(cast(int) (sec*1000)) 50 | } 51 | 52 | for 1, 100 { 53 | write(STDOUT, ".") 54 | sleep(0.01) 55 | } 56 | write(STDOUT, "\n") 57 | } 58 | 59 | local testDynamicLibraries :: () { 60 | ffi.define[[ 61 | unsigned long compressBound(unsigned long sourceLen); 62 | int compress2 (uint8_t *dest, unsigned long *destLen, const uint8_t *source, unsigned long sourceLen, int level); 63 | int uncompress(uint8_t *dest, unsigned long *destLen, const uint8_t *source, unsigned long sourceLen); 64 | ]] 65 | 66 | static zlib: !foreign struct { 67 | compressBound: (sourceLen:int) -> int; 68 | compress2: (dest:ffi.Cdata, destLen:ffi.Cdata, source:string, sourceLen:int, level:int) -> int; 69 | uncompress: (dest:ffi.Cdata, destLen:ffi.Cdata, source:string, sourceLen:int) -> int; 70 | } = NULL 71 | 72 | local ok, ^zlib, err = ffi.load(getSource().."/zlibwapi", type_of(zlib)) 73 | assert(ok, err) 74 | 75 | local IntArray :: ffi.Carray(int) -- Allows zero-indexing. 76 | 77 | local compress :: (data:string) -> string { 78 | local bound = zlib.compressBound(#data) 79 | local _, buffer = ffi.newArray("uint8_t[?]", bound) 80 | local _, bufferLength = ffi.new("unsigned long[1]", bound) 81 | 82 | local result = zlib.compress2(buffer, bufferLength, data, #data, 9) 83 | assert(result == 0) 84 | 85 | return ffi.toString(buffer, bufferLength.as!(IntArray)[0]) 86 | } 87 | 88 | local uncompress :: (comp:string, length:int) -> string { 89 | local _, buffer = ffi.newArray("uint8_t[?]", length) 90 | local _, bufferLength = ffi.new("unsigned long[1]", length) 91 | 92 | local result = zlib.uncompress(buffer, bufferLength, comp, #comp) 93 | assert(result == 0) 94 | 95 | return ffi.toString(buffer, bufferLength.as!(IntArray)[0]) 96 | } 97 | 98 | local data = "abcd" * 1000 99 | printf("Uncompressed size: %d", #data) 100 | local compressed = compress(data) 101 | printf("Compressed size: %d", #compressed) 102 | local uncompressed = uncompress(compressed, #data) 103 | assert(uncompressed == data) 104 | } 105 | -------------------------------------------------------------------------------- /tests/deepCompilation.gloa: -------------------------------------------------------------------------------- 1 | -- 2 | -- Deep compilation test. 3 | -- 4 | 5 | !import "basic" 6 | !import "string" 7 | !import "os" 8 | !import "compiler" 9 | 10 | !run { 11 | local options = getBuildOptions() 12 | options.outputType = BuildOutputType.NONE 13 | setBuildOptions(options) 14 | 15 | local FILENAMES :: { 16 | "deepCompilation.1.gloa", 17 | "deepCompilation.2.gloa", 18 | } 19 | 20 | compileApps(FILENAMES) 21 | compileLuaModule() 22 | compileUsingMessageSystem(FILENAMES[1]) 23 | 24 | print("All sub-compilations done!") 25 | } 26 | 27 | local compileApps :: (filenames:[]string) { 28 | for filenames { 29 | print("Compiling "..it.."...") 30 | compile(it) 31 | } 32 | print("Both compiled!") 33 | 34 | for filenames { 35 | local path 36 | = getProjectDirectory().."/" 37 | ..replacePattern(it, "%.gloa$", ".lua") 38 | 39 | print("Running "..path.."...") 40 | 41 | local args: []string = {path} 42 | local ok, err, code = execute("lua", args) 43 | 44 | if not (ok and code == 0) 45 | error(err ?: "Failed!") 46 | } 47 | print("Both ran!") 48 | } 49 | 50 | local compileLuaModule :: () { 51 | local FILENAME = "deepCompilation.luaModule.gloa" 52 | print("Compiling "..FILENAME.."...") 53 | compile(FILENAME) 54 | 55 | local path 56 | = getProjectDirectory().."/" 57 | ..replacePattern(FILENAME, "%.gloa$", ".lua") 58 | 59 | local requireLuaModuleByPath :: (path:string, $ModuleType:Type) -> ModuleType !foreign lua "dofile" 60 | 61 | local luaModule = requireLuaModuleByPath(path, !foreign struct { 62 | foo: string = NULL, 63 | func: () = NULL, 64 | round: (x:float) -> int = NULL, 65 | }) 66 | 67 | printf("foo = %s", luaModule.foo) 68 | luaModule.func() 69 | printf("round(11.65) = %d", luaModule.round(11.65)) 70 | } 71 | 72 | local compileUsingMessageSystem :: (filename:string) { 73 | print("Intercepted compilation of "..filename.."...") 74 | 75 | local state = newCompilation(filename) 76 | defer compilerFinish(state) 77 | 78 | while true { 79 | using CompilerMessage.Kind 80 | 81 | local hasMessage, message = compilerWaitForMessage(state) 82 | if not hasMessage break 83 | 84 | if message.kind == { 85 | case COMPILATION_PHASE: 86 | local phaseMessage = cast(CompilerMessageCompilationPhase) message 87 | using phaseMessage.phase 88 | 89 | if !complete phaseMessage.phase == { 90 | case SOURCE_CODE_PARSED: 91 | print("Message phase SOURCE_CODE_PARSED") 92 | case PRE_WRITE_OUTPUT: 93 | print("Message phase PRE_WRITE_OUTPUT "..phaseMessage.outputPath) 94 | case POST_WRITE_OUTPUT: 95 | print("Message phase POST_WRITE_OUTPUT "..phaseMessage.outputPath) 96 | } 97 | 98 | case FILE: 99 | local fileMessage = cast(CompilerMessageFile) message 100 | print("Message file "..fileMessage.path) 101 | 102 | case CODE_TYPECHECKED: 103 | local typechecked = cast(CompilerMessageCodeTypechecked) message 104 | local decl = typechecked.declaration 105 | printf("Message typechecked %s (type %d) @ %s:%d", decl.name, decl.typeInfo.id, decl.filepath, decl.lineNumber) 106 | 107 | for note, i: decl.notes { 108 | printf(" Note %d: %d", i, note) 109 | } 110 | 111 | case COMPLETE: 112 | print("Message complete") 113 | 114 | case: 115 | printf("Message (kind=%d)", cast(int) message.kind) 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/runner.luapart: -------------------------------------------------------------------------------- 1 | --[[============================================================ 2 | --= 3 | --= Compile-time execution 4 | --= 5 | --=------------------------------------------------------------- 6 | --= 7 | --= Glóa - a language that compiles into Lua 8 | --= by Marcus 'ReFreezed' Thunström 9 | --= 10 | --============================================================== 11 | 12 | runnerConvertCurrentOutputToChunk, runnerRunCurrentOutputAsChunkIfNotEmpty 13 | runnerSetup 14 | 15 | --============================================================]] 16 | !recordLineNumber(@file, @line) 17 | 18 | 19 | 20 | -- Note: runnerRunCurrentOutputAsChunkIfNotEmpty() needs to be called at some point after this! 21 | function _G.runnerSetup(state) 22 | local writer = state.runnerWriter 23 | if writer then return end 24 | 25 | state.runnerPath = (state.projectDirectory.."/.gloa.metaprogram"..state.id..".lua"):gsub("^%./", "") 26 | if isReadableFile(state.runnerPath) then 27 | assert(os.remove(state.runnerPath)) 28 | end 29 | 30 | writer = WriterState() 31 | writer.luaMainChunkBody = !!(LUA_STATEMENT"do end") 32 | state.runnerWriter = writer 33 | 34 | --[[ Should we copy these fields so the user can do pairs(_G) in !preload blocks? 35 | for k, v in pairs(DEFAULT_GLOBALS) do 36 | state.runnerEnvironment[k] = v 37 | end 38 | --]] 39 | state.runnerEnvironment._G = state.runnerEnvironment 40 | 41 | state.runnerEnvironment.metaprogramTypeIds = state.publicTypeInfoIds 42 | state.runnerEnvironment.metaprogramTypeTable = state.publicTypeInfoById 43 | state.runnerEnvironment.metaprogramArguments = metaprogramArguments 44 | state.runnerEnvironment.metaprogramAppPath = state.pathToFirstFile 45 | state.runnerEnvironment.metaprogramAppDirectory = state.projectDirectory 46 | state.runnerEnvironment.compilerLuaArguments = LUA_ARGUMENTS 47 | state.runnerEnvironment.compilerArguments = compilerArguments 48 | state.runnerEnvironment.compilerErrorHandler = compilerErrorHandler 49 | state.runnerEnvironment._STATE = state 50 | state.runnerEnvironment._COMPILER = compilerApi 51 | state.runnerEnvironment._META_ENV = {} -- (Populated after compiler symbols have been created. @Cleanup) 52 | 53 | setmetatable(state.runnerEnvironment, {__index=DEFAULT_ENVIRONMENT}) -- :CompilerEnvironment :MultipleMetaEnvironments 54 | 55 | state.runnerLineMappings = { 56 | files = writer.lineMappingFiles, 57 | lines = writer.lineMappingLines, 58 | } 59 | 60 | for _, typeInfo in ipairs(state.allTypeInfos) do 61 | if typeInfo.isReady and isTypePublic(typeInfo) then 62 | getPublicType(state, typeInfo) 63 | end 64 | end 65 | 66 | writeCompilerSymbols(state, writer, writer.luaMainChunkBody, nil) 67 | end 68 | 69 | 70 | 71 | local function runnerConvertCurrentOutputToChunk(state) 72 | local writer = state.runnerWriter 73 | local lua = createLuaOutput(writer, state.runnerWrittenLines+1) 74 | writer.luaMainChunkBody = !!(LUA_STATEMENT"do end") 75 | 76 | local debugFile = assert(io.open(state.runnerPath, "a")) -- @Speed: Can we keep this file open? 77 | debugFile:write(lua) 78 | debugFile:close() 79 | 80 | local chunk, err = loadstring(("\n"):rep(state.runnerWrittenLines)..lua, "@"..state.runnerPath) 81 | if not chunk then 82 | -- astPrintTree(state.globalScope) 83 | errorInternal("%s", err) 84 | end 85 | setfenv(chunk, state.runnerEnvironment) 86 | 87 | state.runnerWrittenLines = state.runnerWrittenLines + countString(lua, "\n", true) 88 | return chunk 89 | end 90 | 91 | function _G.runnerRunCurrentOutputAsChunkIfNotEmpty(state) 92 | if not state.runnerWriter.luaMainChunkBody.statements[1] then return end 93 | 94 | local chunk = runnerConvertCurrentOutputToChunk(state) 95 | chunk() 96 | end 97 | 98 | 99 | -------------------------------------------------------------------------------- /modules/love/config.gloa: -------------------------------------------------------------------------------- 1 | --[[============================================================ 2 | --= 3 | --= LÖVE config module (love2d.org) 4 | --= This file contains the minimal stuff needed for conf.lua. 5 | --= 6 | --= Supported versions: 11.3 7 | --= 8 | --============================================================== 9 | 10 | -- Copy+paste this into conf.gloa: 11 | 12 | !import "love/config" 13 | 14 | local main :: () { 15 | config((using t:Config) { 16 | window.title = "Hello, World!" 17 | -- ... 18 | }) 19 | } 20 | 21 | --============================================================]] 22 | 23 | export FullscreenType :: enum { 24 | DESKTOP :: "desktop", 25 | EXCLUSIVE :: "exclusive", 26 | NORMAL :: "normal", 27 | } 28 | 29 | export Config :: !foreign struct { 30 | identity: string|none = nil, -- The name of the save directory. 31 | appendidentity = false, -- Search files in source directory before save directory. 32 | version = "11.3", -- The LÖVE version this game was made for. 33 | console = false, -- Attach a console. (Windows only.) 34 | accelerometerjoystick = true, -- Enable the accelerometer on iOS and Android by exposing it as a Joystick. 35 | externalstorage = false, -- True to save files (and read from the save directory) in external storage on Android. 36 | gammacorrect = false, -- Enable gamma-correct rendering, when supported by the system. 37 | 38 | audio: struct { 39 | mic = false, -- Request and use microphone capabilities in Android. 40 | mixwithsystem = true, -- Keep background music playing when opening LÖVE. (iOS and Android only.) 41 | }, 42 | 43 | window: struct { 44 | title = "Untitled", -- The window title. 45 | icon: string|none = nil, -- Filepath to an image to use as the window's icon. 46 | width = 800, -- The window width. 47 | height = 600, -- The window height. 48 | borderless = false, -- Remove all border visuals from the window. 49 | resizable = false, -- Let the window be user-resizable. 50 | minwidth = 1, -- Minimum window width if the window is resizable. 51 | minheight = 1, -- Minimum window height if the window is resizable. 52 | fullscreen = false, -- Enable fullscreen. 53 | fullscreentype = FullscreenType.DESKTOP, 54 | usedpiscale = true, -- Enable automatic DPI scaling. 55 | vsync = 1, -- Vertical sync mode. 56 | msaa = 0, -- The number of samples to use with multi-sampled antialiasing. 57 | depth: int|none = nil, -- The number of bits per sample in the depth buffer. 58 | stencil: int|none = nil, -- The number of bits per sample in the stencil buffer. 59 | display = 1, -- Index of the monitor to show the window in. 60 | highdpi = false, -- Enable high-dpi mode for the window on a Retina display. 61 | x: int|none = nil, -- The x-coordinate of the window's position in the specified display. 62 | y: int|none = nil, -- The y-coordinate of the window's position in the specified display. 63 | }, 64 | 65 | modules: struct { 66 | -- Enable/disable modules. 67 | audio = true, 68 | data = true, 69 | event = true, 70 | font = true, 71 | graphics = true, 72 | image = true, 73 | joystick = true, 74 | keyboard = true, 75 | math = true, 76 | mouse = true, 77 | physics = true, 78 | sound = true, 79 | system = true, 80 | thread = true, 81 | timer = true, 82 | touch = true, 83 | video = true, 84 | window = true, 85 | }, 86 | } 87 | 88 | export config :: (handler:(t:Config)) { 89 | local loveTable: table : !foreign lua "love" 90 | loveTable.conf = handler 91 | } 92 | -------------------------------------------------------------------------------- /modules/wx/wxxrc_xrc.gloa: -------------------------------------------------------------------------------- 1 | --[[============================================================ 2 | --= 3 | --= wxLua/wxWidget bindings for Glóa 4 | --= Interface source: wxxrc_xrc.i 5 | --= 6 | --= Tested with: 7 | --= - wxLua 2.8.7.0 / wxWidgets 2.8.8 8 | --= 9 | --= Note: Most bindings have not been tested yet! 10 | --= 11 | --============================================================]] 12 | 13 | !import "wx/common" 14 | !import "wx/wxcore_windows" 15 | !import "wx/wxcore_defsutils" 16 | !import "wx/wxcore_gdi" 17 | !import "wx/wxcore_dialogs" 18 | !import "wx/wxcore_appframe" 19 | !import "wx/wxcore_menutool" 20 | 21 | 22 | export wxXmlResourceFlags :: wxEnum 23 | export wxXRC_USE_LOCALE: wxXmlResourceFlags : !foreign lua "wx.wxXRC_USE_LOCALE" 24 | export wxXRC_NO_SUBCLASSING: wxXmlResourceFlags : !foreign lua "wx.wxXRC_NO_SUBCLASSING" 25 | export wxXRC_NO_RELOADING: wxXmlResourceFlags : !foreign lua "wx.wxXRC_NO_RELOADING" 26 | 27 | export wxXmlResource :: !foreign struct { 28 | using wxObject, 29 | 30 | !call :: (flags:int=wxXRC_USE_LOCALE, domain:wxString|string="") -> wxXmlResource !foreign lua "wx.wxXmlResource", 31 | !call :: (filemask:wxString|string, flags:int=wxXRC_USE_LOCALE, domain:wxString|string="") -> wxXmlResource !foreign lua "wx.wxXmlResource", 32 | Get :: () -> wxXmlResource !foreign lua "wx.wxXmlResource.Get", 33 | GetXRCID :: (stringID:wxString|string, value_if_not_found:int=wxID_NONE) -> int !foreign lua "wx.wxXmlResource.GetXRCID", 34 | Set :: (res:wxXmlResource) -> wxXmlResource !foreign lua "wx.wxXmlResource.Set", 35 | 36 | AttachUnknownControl :: (self:wxXmlResource, name:wxString|string, control:wxWindow, parent:wxWindow=wxWindow.null) -> bool !foreign method "AttachUnknownControl", 37 | ClearHandlers :: (self:wxXmlResource) !foreign method "ClearHandlers", 38 | CompareVersion :: (self:wxXmlResource, major:int, minor:int, release:int, revision:int) -> int !foreign method "CompareVersion", 39 | GetFlags :: (self:wxXmlResource) -> int !foreign method "GetFlags", 40 | GetVersion :: (self:wxXmlResource) -> int--[[long]] !foreign method "GetVersion", 41 | InitAllHandlers :: (self:wxXmlResource) !foreign method "InitAllHandlers", 42 | Load :: (self:wxXmlResource, filemask:wxString|string) -> bool !foreign method "Load", 43 | LoadBitmap :: (self:wxXmlResource, name:wxString|string) -> wxBitmap !foreign method "LoadBitmap", 44 | LoadDialog :: (self:wxXmlResource, parent:wxWindow, name:wxString|string) -> wxDialog !foreign method "LoadDialog", 45 | LoadDialog :: (self:wxXmlResource, dlg:wxDialog, parent:wxWindow, name:wxString|string) -> bool !foreign method "LoadDialog", 46 | LoadFrame :: (self:wxXmlResource, frame:wxFrame, parent:wxWindow, name:wxString|string) -> bool !foreign method "LoadFrame", 47 | LoadIcon :: (self:wxXmlResource, name:wxString|string) -> wxIcon !foreign method "LoadIcon", 48 | LoadMenu :: (self:wxXmlResource, name:wxString|string) -> wxMenu !foreign method "LoadMenu", 49 | LoadMenuBar :: (self:wxXmlResource, parent:wxWindow, name:wxString|string) -> wxMenuBar !foreign method "LoadMenuBar", 50 | LoadMenuBar :: (self:wxXmlResource, name:wxString|string) -> wxMenuBar !foreign method "LoadMenuBar", 51 | LoadPanel :: (self:wxXmlResource, parent:wxWindow, name:wxString|string) -> wxPanel !foreign method "LoadPanel", 52 | LoadPanel :: (self:wxXmlResource, panel:wxPanel, parent:wxWindow, name:wxString|string) -> bool !foreign method "LoadPanel", 53 | LoadToolBar :: (self:wxXmlResource, parent:wxWindow, name:wxString|string) -> wxToolBar !foreign method "LoadToolBar", 54 | SetDomain :: (self:wxXmlResource, domain:wxString|string) !foreign method "SetDomain", 55 | SetFlags :: (self:wxXmlResource, flags:int) !foreign method "SetFlags", 56 | Unload :: (self:wxXmlResource, filename:wxString|string) -> bool !foreign method "Unload", 57 | } 58 | -------------------------------------------------------------------------------- /modules/wx/common.gloa: -------------------------------------------------------------------------------- 1 | --[[============================================================ 2 | --= 3 | --= wxLua/wxWidget bindings for Glóa 4 | --= Interface source: (generator) 5 | --= 6 | --= Tested with: 7 | --= - wxLua 2.8.7.0 / wxWidgets 2.8.8 8 | --= 9 | --= Note: Most bindings have not been tested yet! 10 | --= 11 | --============================================================]] 12 | 13 | 14 | !preload [=[ 15 | local _print = print 16 | 17 | _G.wx = require"wx" -- Adds globals: wx, wxlua, wxaui, wxstc, bit. 18 | 19 | -- wxLua loves making life miserable, so let's undo some damage it has made... 20 | _G.print = _print 21 | ]=] 22 | 23 | export time_t :: int 24 | export wxEnum :: int 25 | export wxEventType :: int 26 | export wxFileOffset :: int 27 | export wxWindowID :: int 28 | 29 | export wxLuaUserdata :: !foreign struct { 30 | delete :: (obj:wxLuaUserdata) !foreign method "delete", -- wxLua adds this method to all class userdata. 31 | } 32 | export wxNULL: wxLuaUserdata : !foreign lua "wx.NULL" 33 | 34 | export wxEmptyString: wxString: !foreign lua "wx.wxEmptyString" 35 | 36 | export wxTraceMask :: int--[[unsigned long]] 37 | export wxLogLevel :: int--[[unsigned long]] 38 | export wxTextCoord :: int--[[long]] 39 | export wxInt32 :: int 40 | export wxDouble :: float--[[double]] 41 | 42 | export wxString :: !foreign struct { 43 | using wxLuaUserdata, 44 | 45 | null: wxString : !foreign lua "wx.NULL", 46 | 47 | !call :: (str:wxString|string="") -> wxString !foreign lua "wx.wxString", 48 | 49 | GetData :: (self:wxString) -> string !foreign method "GetData", 50 | } 51 | 52 | export wxObject :: !foreign struct { 53 | using wxLuaUserdata, 54 | 55 | null: wxObject : !foreign lua "wx.NULL", 56 | 57 | !call :: () -> wxObject !foreign lua "wx.wxObject", 58 | 59 | DynamicCast :: (self:wxObject, classname:wxString|string) -> wxObject--[[new class type]] !foreign method "DynamicCast", 60 | GetClassInfo :: (self:wxObject) -> wxClassInfo !foreign method "GetClassInfo", 61 | GetRefData :: (self:wxObject) -> wxObjectRefData !foreign method "GetRefData", 62 | IsKindOf :: (self:wxObject, info:wxClassInfo) -> bool !foreign method "IsKindOf", 63 | IsSameAs :: (self:wxObject, o:wxObject) -> bool !foreign method "IsSameAs", 64 | Ref :: (self:wxObject, clone:wxObject) !foreign method "Ref", 65 | SetRefData :: (self:wxObject, data:wxObjectRefData) !foreign method "SetRefData", 66 | UnRef :: (self:wxObject) !foreign method "UnRef", 67 | } 68 | 69 | export wxObjectRefData :: !foreign struct { 70 | using wxLuaUserdata, 71 | 72 | GetRefCount :: (self:wxObjectRefData) -> int !foreign method "GetRefCount", 73 | } 74 | 75 | export wxClassInfo :: !foreign struct { 76 | using wxLuaUserdata, 77 | 78 | null: wxClassInfo : !foreign lua "wx.NULL", 79 | 80 | !call :: () -> wxClassInfo !foreign lua "wx.wxClassInfo", 81 | FindClass :: (name:wxString|string) -> wxClassInfo !foreign lua "wx.wxClassInfo.FindClass", 82 | GetFirst :: () -> wxClassInfo !foreign lua "wx.wxClassInfo.GetFirst", 83 | 84 | CreateObject :: (self:wxClassInfo) -> wxObject !foreign method "CreateObject", 85 | GetBaseClassName1 :: (self:wxClassInfo) -> string !foreign method "GetBaseClassName1", 86 | GetBaseClassName2 :: (self:wxClassInfo) -> string !foreign method "GetBaseClassName2", 87 | GetBaseClass1 :: (self:wxClassInfo) -> wxClassInfo !foreign method "GetBaseClass1", 88 | GetBaseClass2 :: (self:wxClassInfo) -> wxClassInfo !foreign method "GetBaseClass2", 89 | GetClassName :: (self:wxClassInfo) -> string !foreign method "GetClassName", 90 | GetSize :: (self:wxClassInfo) -> int !foreign method "GetSize", 91 | IsDynamic :: (self:wxClassInfo) -> bool !foreign method "IsDynamic", 92 | IsKindOf :: (self:wxClassInfo, info:wxClassInfo) -> bool !foreign method "IsKindOf", 93 | GetNext :: (self:wxClassInfo) -> wxClassInfo !foreign method "GetNext", 94 | } 95 | 96 | export wxCreateDynamicObject :: (className:wxString|string) -> wxObject !foreign lua "wx.wxCreateDynamicObject" 97 | -------------------------------------------------------------------------------- /modules/print.gloa: -------------------------------------------------------------------------------- 1 | --[[============================================================ 2 | --= 3 | --= Glóa advanced printing module 4 | --= 5 | --============================================================== 6 | 7 | print 8 | printf 9 | printNice 10 | 11 | --============================================================]] 12 | 13 | !import "string" 14 | local basic :: !import "basic" 15 | local lua :: !import "lua" 16 | local LuaType :: lua.LuaType 17 | 18 | local stdoutWrite :: (...:int|float|string|Type) !foreign lua "io.write" 19 | 20 | export print :: basic.print 21 | export printf :: basic.printf 22 | 23 | export printNice :: (v:$T) { _printNice(v, T, 0) } 24 | export printNice :: (prefix:string, v:$T) { stdoutWrite(prefix) ; _printNice(v, T, 0) } 25 | 26 | local _printNice :: (v:any, T:Type, indent:int) { 27 | -- @Incomplete: Recursive printing for table-likes. 28 | -- @Polish: Better member printing. 29 | 30 | local isLuaValueTableLike :: (v:any) -> bool { 31 | local luaType = lua.getType(v) 32 | return luaType == LuaType.TABLE or luaType == LuaType.USERDATA 33 | } 34 | 35 | using basic 36 | using TypeTag 37 | 38 | local typeInfo = getTypeInfo(T) 39 | local indentStr = ""--"\t" * indent 40 | 41 | if typeInfo.tag == { 42 | case INT: 43 | printf("%.0f", cast(int) v) 44 | 45 | case FLOAT: 46 | if lua.getType(v) ~= LuaType.NUMBER { print(v) ; return } 47 | 48 | local nStr = toString(v) 49 | stdoutWrite(nStr) 50 | if not find(nStr, ".") stdoutWrite(".0") 51 | stdoutWrite("\n") 52 | 53 | case ENUM: 54 | local enumInfo = cast(TypeInfoEnum) typeInfo 55 | -- if enumInfo.name stdoutWrite(indentStr, enumInfo.name, ": ") -- @Incomplete: Print "enumName.enumMemberName" before the literal value. 56 | _printNice(v, enumInfo.memberType, indent) 57 | 58 | case STRING: 59 | if lua.getType(v) ~= LuaType.STRING { print(v) ; return } 60 | 61 | stdoutWrite(indentStr, '"', cast(string) v, '"\n') 62 | 63 | case TABLE: 64 | if lua.getType(v) ~= LuaType.TABLE { print(v) ; return } 65 | 66 | stdoutWrite(indentStr, toString(v), " {\n") 67 | for cast(table) v { 68 | stdoutWrite(indentStr, "\t", toString(itIndex), " = ", toString(it), "\n") 69 | } 70 | stdoutWrite(indentStr, "}\n") 71 | 72 | case ARRAY: 73 | if not isLuaValueTableLike(v) { print(v) ; return } 74 | 75 | stdoutWrite(indentStr, toString(v), " {\n") 76 | for cast([]any) v { 77 | stdoutWrite(indentStr, "\t", toString(itIndex), " = ", toString(it), "\n") 78 | } 79 | stdoutWrite(indentStr, "}\n") 80 | 81 | case STRUCT: 82 | if not isLuaValueTableLike(v) { print(v) ; return } 83 | 84 | local structInfo = cast(TypeInfoStruct) typeInfo 85 | local obj = cast(table) v 86 | 87 | if structInfo.kind == structInfo.Kind.TABLE { 88 | _printNice(obj, table, indent) 89 | return 90 | } 91 | 92 | local objStr = toString(obj) 93 | objStr = replacePattern(objStr, "^table: ", "") 94 | objStr = replacePattern(objStr, "^userdata: ", "") 95 | 96 | stdoutWrite(indentStr, structInfo.name?:"(struct)", ": ", objStr, " {\n") 97 | 98 | for member: structInfo.members { 99 | local name = member.name 100 | stdoutWrite(indentStr, "\t", name, " = ", toString(obj[name]), "\n") 101 | } 102 | 103 | if structInfo.kind == structInfo.Kind.ARRAY { 104 | for cast([]any) v stdoutWrite(indentStr, "\t", toString(itIndex), " = ", toString(it), "\n") 105 | } 106 | 107 | stdoutWrite(indentStr, "}\n") 108 | 109 | case TYPE: 110 | if lua.getType(v) ~= LuaType.NUMBER { print(v) ; return } 111 | 112 | -- @Incomplete: Print the type info struct instead of just the ID. 113 | printf("type: %.0f", cast(int) v) 114 | 115 | case ANY: 116 | if lua.getType(v) == { 117 | case LuaType.BOOLEAN: _printNice(v, bool, indent) 118 | case LuaType.NIL: _printNice(v, none, indent) 119 | case LuaType.NUMBER: _printNice(v, float, indent) 120 | case LuaType.STRING: _printNice(v, string, indent) 121 | case LuaType.TABLE: _printNice(v, table, indent) 122 | case: print(v) 123 | } 124 | 125 | case: 126 | print(v) 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /modules/love/physfs.gloa: -------------------------------------------------------------------------------- 1 | --[[============================================================ 2 | --= 3 | --= PhysFS functionality through LÖVE 4 | --= 5 | --============================================================== 6 | 7 | getSearchPaths 8 | getWriteDirectory, setWriteDirectory, disableWriting 9 | mount 10 | mountReadDirectory, unmountReadDirectory 11 | 12 | --============================================================]] 13 | 14 | !import "basic" 15 | !import "string" 16 | local ffi :: !import "ffi" 17 | 18 | -- https://icculus.org/physfs/docs/html/physfs_8h.html 19 | local DEFINITIONS = [[//C 20 | bool PHYSFS_mount (const char *dir, const char *mountPoint, bool appendToPath); 21 | bool PHYSFS_unmount (const char *dir); 22 | char ** PHYSFS_getSearchPath (void); 23 | const char * PHYSFS_getWriteDir (void); 24 | bool PHYSFS_setWriteDir (const char *dir); 25 | ]] 26 | local loveLib: !foreign struct { 27 | PHYSFS_mount: (dir:string, mountPoint:string, appendToPath:bool) -> bool; 28 | PHYSFS_unmount: (dir:string) -> bool; 29 | PHYSFS_getSearchPath: () -> ffi.Cdata; 30 | PHYSFS_getWriteDir: () -> ffi.Cdata; 31 | PHYSFS_setWriteDir: (dir:string) -> bool; 32 | } = NULL 33 | 34 | local init :: () { 35 | static initted = false 36 | if initted return 37 | 38 | ffi.define(DEFINITIONS) 39 | 40 | if ffi.OS == .WINDOWS { 41 | local ok, ^loveLib = ffi.load("love", type_of(loveLib)) 42 | if not ok error("FFI: Failed loading 'love' library.") 43 | } else { 44 | loveLib = ffi.newInterface(type_of(loveLib)) -- Should we try ffi.load() first and fall back to this? 45 | } 46 | 47 | initted = true 48 | } 49 | 50 | -- 51 | -- mount() 52 | -- Conveniently read from/save to anywhere on the computer in LÖVE. 53 | -- To use, wrap paths with mount() at the calling site. 54 | -- Raises an error on failure. 55 | -- 56 | -- WARNING: This may add a lot of directory paths to an internal list in PhysFS. 57 | -- Use mountReadDirectory(), unmountReadDirectory() and getSearchPaths() for more control. 58 | -- 59 | -- Examples: 60 | -- local mount :: physfs.mount 61 | -- love.graphics.newImage(mount"D:/Foo/Bar/test.png") 62 | -- imageData.encode!(mount"D:/Foo/Bar/test.png") 63 | -- love.filesystem.getDirectoryItems(mount"D:/Foo/Bar") 64 | -- love.filesystem.createDirectory(mount"D:/Foo/Bar") 65 | -- 66 | -- https://love2d.org/forums/viewtopic.php?p=227121#p227121 67 | -- 68 | export mount :: (path:string) -> (name:string) { 69 | init() 70 | 71 | local ok, parentDir, name = matchPattern(path, "^(.+)[/\\]([^/\\]+)$") 72 | assert(ok) 73 | 74 | assert(loveLib.PHYSFS_mount(cast(string)parentDir, NULL, false)) 75 | assert(loveLib.PHYSFS_setWriteDir(cast(string)parentDir)) 76 | 77 | return cast(string) name 78 | } 79 | 80 | export getWriteDirectory :: () -> (hasWriteDir:bool, dir:string) { 81 | init() 82 | 83 | local cDir = loveLib.PHYSFS_getWriteDir() 84 | if ffi.isNull(cDir) return false, "" 85 | 86 | return true, ffi.toString(cDir) 87 | } 88 | export setWriteDirectory :: (dir:string) -> (success:bool) { 89 | init() 90 | return loveLib.PHYSFS_setWriteDir(dir) 91 | } 92 | export disableWriting :: () -> (success:bool) { 93 | init() 94 | return loveLib.PHYSFS_setWriteDir(NULL) 95 | } 96 | 97 | -- Mount a directory to the root ("/"). 98 | -- If append is false then the directory gets prepended. 99 | export mountReadDirectory :: (dir:string, append=false) -> (success:bool) { 100 | init() 101 | return loveLib.PHYSFS_mount(dir, NULL, append) 102 | } 103 | -- Mount a directory to a specific mount point. 104 | export mountReadDirectory :: (dir:string, mountPoint:string, append=false) -> (success:bool) { 105 | init() 106 | return loveLib.PHYSFS_mount(dir, mountPoint, append) 107 | } 108 | 109 | -- Note: This function wants the mounted directory - not the mount point! 110 | export unmountReadDirectory :: (dir:string) -> (success:bool) { 111 | init() 112 | return loveLib.PHYSFS_unmount(dir) 113 | } 114 | 115 | export getSearchPaths :: () -> []string { 116 | init() 117 | 118 | local paths: []string 119 | local cPaths = loveLib.PHYSFS_getSearchPath() 120 | 121 | for i = 0, 256^3 { 122 | if ffi.isNull(cPaths[i]) break 123 | paths[i+1] = ffi.toString(cPaths[i]) 124 | } 125 | 126 | return paths 127 | } 128 | -------------------------------------------------------------------------------- /modules/preload.gloa: -------------------------------------------------------------------------------- 1 | --[[============================================================ 2 | --= 3 | --= Glóa preload module 4 | --= 5 | --= This module is imported automatically in every file and 6 | --= thus everything here is always available everywhere. 7 | --= 8 | --============================================================== 9 | 10 | getAllTypes, getTypeInfo 11 | 12 | -- Enums: 13 | TypeTag 14 | 15 | -- Types: 16 | SourceCodeLocation 17 | Table 18 | TypeInfo, TypeInfoArray, TypeInfoCompound, TypeInfoEnum, TypeInfoFunction, TypeInfoStruct, TypeInfoVararg 19 | 20 | --============================================================]] 21 | 22 | export TypeTag :: enum { 23 | ANY :: !compiler "typeTagAny", 24 | ARRAY :: !compiler "typeTagArray", 25 | BOOL :: !compiler "typeTagBool", 26 | COMPOUND :: !compiler "typeTagCompound", 27 | ENUM :: !compiler "typeTagEnum", 28 | FLOAT :: !compiler "typeTagFloat", 29 | FUNCTION :: !compiler "typeTagFunction", 30 | INT :: !compiler "typeTagInt", 31 | NONE :: !compiler "typeTagNone", 32 | STRING :: !compiler "typeTagString", 33 | STRUCT :: !compiler "typeTagStruct", 34 | TABLE :: !compiler "typeTagTable", 35 | TYPE :: !compiler "typeTagType", 36 | VARARG :: !compiler "typeTagVararg", 37 | VOID :: !compiler "typeTagVoid", 38 | } 39 | 40 | export TypeInfo :: !foreign struct { 41 | tag: TypeTag, 42 | id: Type, 43 | } 44 | 45 | export TypeInfoArray :: !foreign struct { 46 | using TypeInfo, 47 | itemType: Type, 48 | } 49 | export TypeInfoVararg :: !foreign struct { 50 | using TypeInfo, 51 | itemType: Type, 52 | } 53 | 54 | export TypeInfoFunction :: !foreign struct { 55 | Argument :: !foreign struct { 56 | argumentType: Type, 57 | }, 58 | 59 | using TypeInfo, 60 | argumentsIn: []Argument, 61 | argumentsOut: []Argument, 62 | } 63 | 64 | export TypeInfoStruct :: !foreign struct { 65 | Kind :: enum { 66 | NORMAL :: 1, 67 | TABLE :: 2, 68 | ARRAY :: 3, 69 | }, 70 | Member :: !foreign struct { 71 | name: string, 72 | memberType: Type, 73 | notes: []Type, -- @Cleanup: Should this be here? They are already on CodeDeclaration (where they truly belong). 74 | }, 75 | 76 | using TypeInfo, 77 | name: string, -- May be empty. 78 | kind: Kind, 79 | keyType: Type, 80 | valueType: Type, 81 | members: []Member, 82 | } 83 | 84 | export TypeInfoEnum :: !foreign struct { 85 | Member :: !foreign struct { 86 | name: string, 87 | notes: []Type, -- @Cleanup: Should this be here? They are already on CodeDeclaration (where they truly belong). 88 | }, 89 | 90 | using TypeInfo, 91 | name: string, -- May be empty. 92 | memberType: Type, 93 | members: []Member, 94 | } 95 | 96 | export TypeInfoCompound :: !foreign struct { 97 | using TypeInfo, 98 | types: []Type, 99 | } 100 | 101 | export SourceCodeLocation :: !foreign struct { 102 | filePath: string, -- Note: This will not be a real file path if the location was generated from a string (i.e. from !body_text). @Compiler @UX: Change this fact. 103 | lineNumber: int, 104 | position: int, -- Byte position (after line ending normalization). @Cleanup: Rename to filePosition. 105 | } 106 | 107 | -- 108 | -- This is like the native table type but keys and values are restricted to one type. 109 | -- 110 | -- Note: KeyType cannot be string because KeyType and ValueType become static members 111 | -- of the struct and there would be ambiguity when accessing fields of instances. 112 | -- @Compiler: Can we enable string keys in polymorphic table-like structs somehow? 113 | -- 114 | export Table :: struct (KeyType:Type, ValueType:Type) { 115 | !key: KeyType, 116 | !value: ValueType, 117 | } 118 | 119 | -- Get a list of all types. During compilation this returns only the types available so far. 120 | -- Warning: If this function is used anywhere in runtime code, the size of the program may become a lot bigger if there are many types! 121 | export getAllTypes :: () -> []Type !foreign compiler "getAllTypes" 122 | 123 | -- Dynamically get info for a type. 124 | -- Warning: If this function is used anywhere in runtime code, the size of the program may become a lot bigger if there are many types! type_info() should be used instead whenever possible. 125 | export getTypeInfo :: (T:Type) -> TypeInfo !foreign compiler "getTypeInfo" 126 | -------------------------------------------------------------------------------- /modules/compiler.gloa: -------------------------------------------------------------------------------- 1 | --[[============================================================ 2 | --= 3 | --= Glóa compiler module 4 | --= 5 | --= Note: Some functions here can only be used at compile time. 6 | --= 7 | --============================================================== 8 | 9 | BuildOptions 10 | 11 | compile 12 | getBuildOptions, setBuildOptions 13 | getCompilerArguments 14 | getProjectDirectory 15 | 16 | --============================================================]] 17 | 18 | export compile :: (filepath:string) !foreign compiler "compile" 19 | 20 | export BuildOutputType :: enum { 21 | NONE :: 0, 22 | LUA_APP :: 1, 23 | LUA_MODULE :: 2, 24 | } 25 | export BuildOptions :: !foreign struct { 26 | outputType = BuildOutputType.LUA_APP, 27 | outputFilePath = "", -- This is pre-filled when getBuildOptions() is called the first time. 28 | entryPointName = "main", 29 | } 30 | export getBuildOptions :: ( ) -> BuildOptions !foreign compiler "getBuildOptions" 31 | export getBuildOptions :: (state:CompilationState) -> BuildOptions !foreign compiler "getBuildOptions" 32 | export setBuildOptions :: ( options:BuildOptions) !foreign compiler "setBuildOptions" 33 | export setBuildOptions :: (state:CompilationState, options:BuildOptions) !foreign compiler "setBuildOptions" 34 | 35 | export getProjectDirectory :: () -> string !foreign compiler "getProjectDirectory" 36 | 37 | export getCompilerArguments :: () -> []string !foreign compiler "getCompilerArguments" 38 | 39 | export compilerReportError :: (filename:string, lineNumber:int, column:int, message:string) !foreign compiler "compilerReportError" 40 | 41 | export CompilationState :: !foreign struct {} 42 | 43 | export newCompilation :: (pathToFirstFile:string) -> CompilationState !foreign compiler "newCompilation" 44 | export compilerWaitForMessage :: (state:CompilationState) -> (hasMessage:bool, message:CompilerMessage) !foreign compiler "compilerWaitForMessage" 45 | export compilerFinish :: (state:CompilationState) !foreign compiler "compilerFinish" 46 | 47 | -- 48 | -- Messages 49 | -- 50 | 51 | export CompilationPhase :: enum { 52 | SOURCE_CODE_PARSED :: 1, 53 | PRE_WRITE_OUTPUT :: 2, 54 | POST_WRITE_OUTPUT :: 3, 55 | } 56 | 57 | export CompilerMessage :: !foreign struct { 58 | Kind :: enum { 59 | CODE_TYPECHECKED :: 1, -- CompilerMessageCodeTypechecked 60 | COMPILATION_PHASE :: 2, -- CompilerMessageCompilationPhase 61 | COMPLETE :: 3, -- CompilerMessage 62 | FILE :: 4, -- CompilerMessageFile 63 | }, 64 | kind: Kind, 65 | } 66 | export CompilerMessageFile :: !foreign struct { 67 | using CompilerMessage, 68 | path: string, 69 | } 70 | export CompilerMessageCompilationPhase :: !foreign struct { 71 | using CompilerMessage, 72 | phase: CompilationPhase, 73 | outputPath: string, -- Set if phase is *_WRITE_OUTPUT. 74 | } 75 | export CompilerMessageCodeTypechecked :: !foreign struct { 76 | using CompilerMessage, 77 | declaration: CodeDeclaration, -- Only top-level declarations. 78 | } 79 | 80 | -- 81 | -- Code nodes 82 | -- 83 | 84 | export CodeNode :: !foreign struct { 85 | Kind :: enum { 86 | DECLARATION, 87 | IDENTIFIER, 88 | LITERAL, 89 | OPERATOR_EXPRESSION, 90 | -- @Incomplete... 91 | }, 92 | 93 | kind: Kind, 94 | serial: int, 95 | 96 | typeInfo: TypeInfo, 97 | 98 | filepath: string, 99 | lineNumber: string, 100 | filePosition: string, 101 | } 102 | 103 | export CodeDeclaration :: !foreign struct { 104 | using CodeNode, 105 | name: string, 106 | expressions: []CodeNode, -- Flattened array of expressions expressing the assigned value, if any. @Incomplete 107 | rootExpression: none,--CodeNode, -- @Incomplete 108 | isConstant: bool, 109 | notes: []Type, 110 | } 111 | 112 | export CodeIdentifier :: !foreign struct { 113 | using CodeNode, 114 | name: string, 115 | declaration: CodeDeclaration, 116 | } 117 | 118 | export CodeLiteral :: !foreign struct { 119 | using CodeNode, 120 | value: int|float|bool|string, -- Use .typeInfo to know what exactly this is. 121 | } 122 | 123 | export CodeOperator :: !foreign struct { 124 | using CodeNode, 125 | operator: string, -- "+"|"//"|"or"|"#"|"?:"|etc. 126 | left: CodeNode|none, -- Not set for unary operators. 127 | middle: CodeNode|none, -- Only set for ternary operators. 128 | right: CodeNode, 129 | } 130 | 131 | -- @Incomplete... 132 | -------------------------------------------------------------------------------- /modules/wx/wxluasocket.gloa: -------------------------------------------------------------------------------- 1 | --[[============================================================ 2 | --= 3 | --= wxLua/wxWidget bindings for Glóa 4 | --= Interface source: wxluasocket.i 5 | --= 6 | --= Tested with: 7 | --= - wxLua 2.8.7.0 / wxWidgets 2.8.8 8 | --= 9 | --= Note: Most bindings have not been tested yet! 10 | --= 11 | --============================================================]] 12 | 13 | !import "wx/wxcore_event" 14 | !import "wx/common" 15 | !import "wx/wxcore_windows" 16 | !import "wx/wxcore_defsutils" 17 | 18 | export wxEVT_WXLUA_DEBUGGER_DEBUGGEE_CONNECTED: wxEventType : !foreign lua "wxlua.wxEVT_WXLUA_DEBUGGER_DEBUGGEE_CONNECTED" -- EVT_WXLUA_DEBUGGER_DEBUGGEE_CONNECTED(id, fn) 19 | export wxEVT_WXLUA_DEBUGGER_DEBUGGEE_DISCONNECTED: wxEventType : !foreign lua "wxlua.wxEVT_WXLUA_DEBUGGER_DEBUGGEE_DISCONNECTED" -- EVT_WXLUA_DEBUGGER_DEBUGGEE_DISCONNECTED(id, fn) 20 | export wxEVT_WXLUA_DEBUGGER_BREAK: wxEventType : !foreign lua "wxlua.wxEVT_WXLUA_DEBUGGER_BREAK" -- EVT_WXLUA_DEBUGGER_BREAK(id, fn) 21 | export wxEVT_WXLUA_DEBUGGER_PRINT: wxEventType : !foreign lua "wxlua.wxEVT_WXLUA_DEBUGGER_PRINT" -- EVT_WXLUA_DEBUGGER_PRINT(id, fn) 22 | export wxEVT_WXLUA_DEBUGGER_ERROR: wxEventType : !foreign lua "wxlua.wxEVT_WXLUA_DEBUGGER_ERROR" -- EVT_WXLUA_DEBUGGER_ERROR(id, fn) 23 | export wxEVT_WXLUA_DEBUGGER_EXIT: wxEventType : !foreign lua "wxlua.wxEVT_WXLUA_DEBUGGER_EXIT" -- EVT_WXLUA_DEBUGGER_EXIT(id, fn) 24 | export wxEVT_WXLUA_DEBUGGER_STACK_ENUM: wxEventType : !foreign lua "wxlua.wxEVT_WXLUA_DEBUGGER_STACK_ENUM" -- EVT_WXLUA_DEBUGGER_STACK_ENUM(id, fn) 25 | export wxEVT_WXLUA_DEBUGGER_STACK_ENTRY_ENUM: wxEventType : !foreign lua "wxlua.wxEVT_WXLUA_DEBUGGER_STACK_ENTRY_ENUM" -- EVT_WXLUA_DEBUGGER_STACK_ENTRY_ENUM(id, fn) 26 | export wxEVT_WXLUA_DEBUGGER_TABLE_ENUM: wxEventType : !foreign lua "wxlua.wxEVT_WXLUA_DEBUGGER_TABLE_ENUM" -- EVT_WXLUA_DEBUGGER_TABLE_ENUM(id, fn) 27 | export wxEVT_WXLUA_DEBUGGER_EVALUATE_EXPR: wxEventType : !foreign lua "wxlua.wxEVT_WXLUA_DEBUGGER_EVALUATE_EXPR" -- EVT_WXLUA_DEBUGGER_EVALUATE_EXPR(id, fn) 28 | 29 | export wxLuaDebuggerServer :: !foreign struct { 30 | using wxEvtHandler, 31 | 32 | !call :: (portNumber:int) -> wxLuaDebuggerServer !foreign lua "wxlua.wxLuaDebuggerServer", 33 | GetProgramName :: () -> string !foreign lua "wxlua.wxLuaDebuggerServer.GetProgramName", 34 | GetNetworkName :: () -> string !foreign lua "wxlua.wxLuaDebuggerServer.GetNetworkName", 35 | 36 | StartServer :: (self:wxLuaDebuggerServer) -> bool !foreign method "StartServer", 37 | StopServer :: (self:wxLuaDebuggerServer) -> bool !foreign method "StopServer", 38 | StartClient :: (self:wxLuaDebuggerServer) -> int--[[long]] !foreign method "StartClient", 39 | AddBreakPoint :: (self:wxLuaDebuggerServer, fileName:wxString|string, lineNumber:int) -> bool !foreign method "AddBreakPoint", 40 | RemoveBreakPoint :: (self:wxLuaDebuggerServer, fileName:wxString|string, lineNumber:int) -> bool !foreign method "RemoveBreakPoint", 41 | ClearAllBreakPoints :: (self:wxLuaDebuggerServer) -> bool !foreign method "ClearAllBreakPoints", 42 | Run :: (self:wxLuaDebuggerServer, fileName:wxString|string, buffer:wxString|string) -> bool !foreign method "Run", 43 | Step :: (self:wxLuaDebuggerServer) -> bool !foreign method "Step", 44 | StepOver :: (self:wxLuaDebuggerServer) -> bool !foreign method "StepOver", 45 | StepOut :: (self:wxLuaDebuggerServer) -> bool !foreign method "StepOut", 46 | Continue :: (self:wxLuaDebuggerServer) -> bool !foreign method "Continue", 47 | Break :: (self:wxLuaDebuggerServer) -> bool !foreign method "Break", 48 | Reset :: (self:wxLuaDebuggerServer) -> bool !foreign method "Reset", 49 | EvaluateExpr :: (self:wxLuaDebuggerServer, exprRef:int, expr:wxString|string) -> bool !foreign method "EvaluateExpr", 50 | DisplayStackDialog :: (self:wxLuaDebuggerServer, pParent:wxWindow, id:wxWindowID=wxID_ANY) !foreign method "DisplayStackDialog", 51 | GetDebuggeeProcessId :: (self:wxLuaDebuggerServer) -> int--[[long]] !foreign method "GetDebuggeeProcessId", 52 | KillDebuggee :: (self:wxLuaDebuggerServer) -> bool !foreign method "KillDebuggee", 53 | } 54 | 55 | export wxLuaDebuggerEvent :: !foreign struct { 56 | using wxEvent, 57 | 58 | GetLineNumber :: (self:wxLuaDebuggerEvent) -> int !foreign method "GetLineNumber", 59 | GetReference :: (self:wxLuaDebuggerEvent) -> int !foreign method "GetReference", 60 | GetFileName :: (self:wxLuaDebuggerEvent) -> string !foreign method "GetFileName", 61 | GetMessage :: (self:wxLuaDebuggerEvent) -> string !foreign method "GetMessage", 62 | } 63 | 64 | export StackDialog :: () !foreign lua "wxlua.StackDialog" 65 | -------------------------------------------------------------------------------- /modules/loveRevised/basic.gloa: -------------------------------------------------------------------------------- 1 | --[[============================================================ 2 | --= 3 | --= LÖVE bindings (love2d.org) 4 | --= 5 | --= Supported versions: 11.3 6 | --= 7 | --============================================================== 8 | 9 | parseArguments 10 | 11 | -- Types: 12 | Data 13 | Object 14 | Pointer, LightUserdata 15 | Variant 16 | 17 | -- Enums: 18 | ObjectName 19 | Event 20 | FullscreenType 21 | HintingMode 22 | 23 | --============================================================]] 24 | 25 | 26 | 27 | ---------------------------------------------------------------- 28 | -- Enums. 29 | ---------------------------------------------------------------- 30 | 31 | export ObjectName :: enum { 32 | BEZIER_CURVE :: "BezierCurve", 33 | BODY :: "Body", 34 | BYTE_DATA :: "ByteData", 35 | CANVAS :: "Canvas", 36 | CHAIN_SHAPE :: "ChainShape", 37 | CHANNEL :: "Channel", 38 | CIRCLE_SHAPE :: "CircleShape", 39 | COMPRESSED_DATA :: "CompressedData", 40 | COMPRESSED_IMAGE_DATA :: "CompressedImageData", 41 | CONTACT :: "Contact", 42 | CURSOR :: "Cursor", 43 | DATA :: "Data", 44 | DECODER :: "Decoder", 45 | DISTANCE_JOINT :: "DistanceJoint", 46 | DRAWABLE :: "Drawable", 47 | DROPPED_FILE :: "DroppedFile", 48 | EDGE_SHAPE :: "EdgeShape", 49 | FILE :: "File", 50 | FILE_DATA :: "FileData", 51 | FIXTURE :: "Fixture", 52 | FONT :: "Font", 53 | FRICTION_JOINT :: "FrictionJoint", 54 | GEAR_JOINT :: "GearJoint", 55 | GLYPH_DATA :: "GlyphData", 56 | IMAGE :: "Image", 57 | IMAGE_DATA :: "ImageData", 58 | JOINT :: "Joint", 59 | JOYSTICK :: "Joystick", 60 | MESH :: "Mesh", 61 | MOTOR_JOINT :: "MotorJoint", 62 | MOUSE_JOINT :: "MouseJoint", 63 | PARTICLE_SYSTEM :: "ParticleSystem", 64 | POLYGON_SHAPE :: "PolygonShape", 65 | PRISMATIC_JOINT :: "PrismaticJoint", 66 | PULLEY_JOINT :: "PulleyJoint", 67 | QUAD :: "Quad", 68 | RANDOM_GENERATOR :: "RandomGenerator", 69 | RASTERIZER :: "Rasterizer", 70 | RECORDING_DEVICE :: "RecordingDevice", 71 | REVOLUTE_JOINT :: "RevoluteJoint", 72 | ROPE_JOINT :: "RopeJoint", 73 | SHADER :: "Shader", 74 | SHAPE :: "Shape", 75 | SOUND_DATA :: "SoundData", 76 | SOURCE :: "Source", 77 | SPRITE_BATCH :: "SpriteBatch", 78 | TEXT :: "Text", 79 | TEXTURE :: "Texture", 80 | THREAD :: "Thread", 81 | TRANSFORM :: "Transform", 82 | VIDEO :: "Video", 83 | VIDEO_STREAM :: "VideoStream", 84 | WELD_JOINT :: "WeldJoint", 85 | WHEEL_JOINT :: "WheelJoint", 86 | WORLD :: "World", 87 | } 88 | 89 | 90 | 91 | ---------------------------------------------------------------- 92 | -- Types. 93 | ---------------------------------------------------------------- 94 | 95 | export Pointer :: !foreign struct {} 96 | export LightUserdata :: !foreign struct {} -- Actually a value (int) representing a pointer, but for the sake of type safety it's probably better to say it's its own type. 97 | 98 | export Object :: !foreign struct { 99 | release :: (obj:Object) -> (success:bool) !foreign method "release", 100 | 101 | getType :: (obj:Object) -> (name:ObjectName) !foreign method "type", 102 | isType :: (obj:Object, name:ObjectName) -> bool !foreign method "typeOf", 103 | } 104 | 105 | export Data :: !foreign struct { 106 | using Object, 107 | 108 | clone :: (data:Data) -> Data !foreign method "clone", 109 | getFFIPointer :: (data:Data) -> !import "ffi".Cdata !foreign method "getFFIPointer", 110 | getPointer :: (data:Data) -> Pointer !foreign method "getPointer", -- Use getFFIPointer() instead! 111 | getSize :: (data:Data) -> int !foreign method "getSize", 112 | getString :: (data:Data) -> string !foreign method "getString", 113 | } 114 | 115 | export Variant :: string|float|bool|table|Object -- Functions and Lua userdata are not supported. Tables have to be "simple". 116 | 117 | 118 | 119 | ---------------------------------------------------------------- 120 | -- Functions. 121 | ---------------------------------------------------------------- 122 | 123 | export parseArguments :: (argsRaw:[]string) -> (args:[]string) !foreign lua "love.arg.parseGameArguments" 124 | 125 | 126 | -------------------------------------------------------------------------------- /modules/loveRevised/filesystem.gloa: -------------------------------------------------------------------------------- 1 | --[[============================================================ 2 | --= 3 | --= LÖVE bindings (love2d.org) 4 | --= love.filesystem 5 | --= 6 | --= Supported versions: 11.3 7 | --= 8 | --============================================================== 9 | 10 | setAppDataFolderName 11 | read, write 12 | 13 | -- Types: 14 | File, DroppedFile 15 | FileData 16 | 17 | -- Enum: 18 | BufferMode 19 | FileMode 20 | 21 | --============================================================]] 22 | 23 | !import "loveRevised/basic" 24 | 25 | -- 26 | -- Enums 27 | -- 28 | 29 | export FileMode :: enum { 30 | READ :: "r", -- Open a file for read. 31 | WRITE :: "w", -- Open a file for write. 32 | APPEND :: "a", -- Open a file for append. 33 | CLOSED :: "c", -- Do not open a file (represents a closed file). 34 | } 35 | 36 | export BufferMode :: enum { 37 | NONE :: "none", 38 | LINE :: "line", 39 | FULL :: "full", 40 | } 41 | 42 | -- 43 | -- Types 44 | -- 45 | 46 | local readIntoDataHelper :: (file:File, container:string) -> (contents:FileData, bytes:int) !foreign method "read" 47 | local readIntoDataHelper :: (file:File, container:string, bytes:int) -> (contents:FileData, bytes:int) !foreign method "read" 48 | 49 | export File :: !foreign struct { 50 | using Object, 51 | 52 | open :: (file:File, mode:FileMode) -> (success:bool, err:string|none) !foreign method "open", 53 | close :: (file:File) -> (success:bool) !foreign method "close", 54 | isOpen :: (file:File) -> bool !foreign method "isOpen", 55 | 56 | getFilename :: (file:File) -> string !foreign method "getFilename", 57 | getMode :: (file:File) -> FileMode !foreign method "getMode", 58 | getSize :: (file:File) -> int !foreign method "getSize", 59 | 60 | readAll :: (file:File) -> (contents:string, bytes:int) !foreign method "read", 61 | read :: (file:File, bytes:int) -> (contents:string, bytes:int) !foreign method "read", 62 | readAllIntoData :: (file:File) -> (data:FileData, bytes:int) { return readIntoDataHelper(file, "data") }, 63 | readIntoData :: (file:File, bytes:int) -> (data:FileData, bytes:int) { return readIntoDataHelper(file, "data", bytes) }, 64 | 65 | write :: (file:File, data:string|Data) -> (success:bool, err:string|none) !foreign method "write", 66 | write :: (file:File, data:string|Data, bytesToWrite:int) -> (success:bool, err:string|none) !foreign method "write", 67 | 68 | isEOF :: (file:File) -> bool !foreign method "isEOF", 69 | 70 | eachLine :: (file:File) -> (iter:(_1,_2:none)->(line:string|none), _1,_2:none) !foreign method "lines", 71 | 72 | tell :: (file:File) -> (position:int) !foreign method "tell", 73 | seek :: (file:File, position:int) -> (success:bool) !foreign method "seek", 74 | 75 | getBuffer :: (file:File) -> (mode:BufferMode, size:int) !foreign method "getBuffer", -- @Cleanup: Be more like io module. 76 | setBuffer :: (file:File, mode:BufferMode, size=0) -> (success:bool, err:string|none) !foreign method "setBuffer", 77 | flush :: (file:File) -> (success:bool, err:string|none) !foreign method "flush", 78 | } 79 | 80 | export DroppedFile :: !foreign struct { using File } 81 | 82 | export FileData :: !foreign struct { 83 | using Data, 84 | 85 | getExtension :: (data:FileData) -> string !foreign method "getExtension", 86 | getFilename :: (data:FileData) -> string !foreign method "getFilename", 87 | } 88 | 89 | -- 90 | -- Functions 91 | -- 92 | 93 | export setAppDataFolderName :: (name:string) !foreign lua "love.filesystem.setIdentity" 94 | 95 | export read :: (path:string) -> (success:bool, data:string, error:string) { 96 | local helper :: (path:string) -> string|none, int|string !foreign lua "love.filesystem.read" 97 | 98 | local data, sizeOrErr = helper(path) 99 | if data == nil return false, "", cast(string)sizeOrErr 100 | 101 | return true, cast(string)data, "" 102 | } 103 | 104 | export write :: (path:string, data:string) -> (success:bool, error:string) { 105 | local helper :: (path:string, data:string) -> bool, none|string !foreign lua "love.filesystem.write" 106 | 107 | local ok, err = helper(path, data) 108 | if not ok return false, cast(string)err 109 | 110 | return true, "" 111 | } 112 | 113 | export newFileData :: (contents:string, filename:string) -> FileData!must !foreign lua "love.filesystem.newFileData" 114 | 115 | export newFileData :: (filename:string) -> (success:bool, fileData:FileData!must, error:string) { 116 | local helper :: (filename:string) -> FileData|none, none|string !foreign lua "love.filesystem.newFileData" 117 | 118 | local fileData, err = helper(filename) 119 | if fileData == nil return false, NULL, cast(string)err 120 | 121 | return true, cast(FileData)fileData , "" 122 | } 123 | -------------------------------------------------------------------------------- /tests/suite.gloa: -------------------------------------------------------------------------------- 1 | -- 2 | -- Glóa test suite 3 | -- 4 | -- Usage: 5 | -- $ lua gloa.lua suite.gloa -- [testToRun] 6 | -- 7 | -- Arguments: 8 | -- * testToRun: Name or partial name of a specific test to run. (Optional, default is all.) 9 | -- 10 | 11 | local TEST_FILES :: { 12 | "tests/assignmentsWithBinaryOperations.gloa", 13 | "tests/basic.gloa", 14 | "tests/compileTimeExecution.gloa", 15 | "tests/deepCompilation.gloa", 16 | "tests/modules.gloa", 17 | "tests/types.gloa", 18 | } 19 | local FILES_TO_COPY_TO_TEMP_FOLDER :: { 20 | -- These are used by TEST_FILES. 21 | "tests/types.errorGlobal.gloa", 22 | "tests/types.errorLocal.gloa", 23 | "tests/types.load.gloa", 24 | } 25 | 26 | local EXAMPLES: [] struct {folder:string, main:string} : { 27 | -- These only run if 'examplesFolder' in suite.ini is set. 28 | {folder="calendar", main="main.gloa"}, 29 | {folder="lovelyBlaster", main="src/main.gloa"}, 30 | {folder="lovelySnake", main="main.gloa"}, 31 | } 32 | 33 | local COMPILER_OPTIONS :: "--debug --nogc --silent" 34 | local OUTPUT_REDIRECTION :: ">NUL" -- ">NUL 2>&1" 35 | 36 | 37 | 38 | !import "basic" 39 | !import "compiler" 40 | !import "io" 41 | !import "os" 42 | !import "string" 43 | !import "utils" 44 | 45 | !load "suite.fails" 46 | 47 | !run { 48 | local options = getBuildOptions() 49 | options.outputType = BuildOutputType.NONE 50 | setBuildOptions(options) 51 | 52 | disableBuffering(STDOUT) 53 | disableBuffering(STDERR) 54 | 55 | print("Running test suite...") 56 | 57 | local examplesFolder = "" 58 | 59 | do { 60 | local ok, file = openForReadingText(APP_DIRECTORY.."/suite.ini") 61 | if ok { 62 | local ln = 0 63 | for line in eachLine(file) { 64 | ln += 1 65 | if not line or line[1] == !char "#" continue 66 | 67 | local ok, k, v = matchPattern(line, "^(%w+)=(.*)$") !shadow 68 | if not ok 69 | errorLine("suite.ini:%d: Bad line format: %s", ln, line) 70 | elseif k == "examplesFolder" 71 | examplesFolder = cast(string) v 72 | else 73 | errorLine("suite.ini:%d: Unknown key '%s'.", ln, k) 74 | } 75 | } 76 | } 77 | 78 | print(examplesFolder ? "Including examples." : "Excluding examples.") 79 | 80 | local testToRun = getProgramArguments()[1] 81 | testToRun = testToRun ~= NULL ? toLower(testToRun) : "" 82 | 83 | if testToRun printf("Looking for test '%s'.", testToRun) 84 | 85 | local testCount = 0 86 | local failCount = 0 87 | local results: []string 88 | 89 | local shouldRunTest = [testToRun] (name:string) -> bool { 90 | if not testToRun return true 91 | name = replacePattern(name, "%.gloa$", "") 92 | return (find(toLower(name), testToRun)) 93 | } 94 | 95 | local runTest = [testCount,failCount,results] (name:string, expectSuccess:bool, cmd:string) { 96 | print(cmd) 97 | testCount += 1 98 | 99 | if (execute(cmd) == 0) == expectSuccess { 100 | insert(results, format("ok %s", name)) 101 | } else { 102 | insert(results, format("NOT_OK %s", name)) 103 | failCount = failCount+1 104 | } 105 | } 106 | 107 | for path: TEST_FILES { 108 | if shouldRunTest(path) { 109 | runTest(path, true, format( 110 | [["lua "%s" %s "%s" %s"]], 111 | COMPILER_PATH, COMPILER_OPTIONS, 112 | path, 113 | OUTPUT_REDIRECTION 114 | )) 115 | if testToRun break 116 | } 117 | } 118 | 119 | if examplesFolder for example: EXAMPLES { 120 | local path = format("%s/%s/%s", examplesFolder, example.folder, example.main) 121 | 122 | if shouldRunTest(example.folder) { 123 | runTest(path, true, format( 124 | [["lua "%s" %s --root "%s/%s" "%s" %s"]], 125 | COMPILER_PATH, COMPILER_OPTIONS, 126 | examplesFolder, example.folder, example.main, 127 | OUTPUT_REDIRECTION 128 | )) 129 | if testToRun break 130 | } 131 | } 132 | 133 | for path: FILES_TO_COPY_TO_TEMP_FOLDER { 134 | local ok, filename = matchPattern(path, "[^/]+$") 135 | assert(ok, path) 136 | 137 | local tempPath = "temp/" .. cast(string) filename 138 | copy(path, tempPath) 139 | } 140 | 141 | for gloa, i: TESTS_THAT_SHOULD_FAIL { 142 | local tempPath = format("temp/shouldFail%d.gloa", i) 143 | 144 | if shouldRunTest(tempPath) { 145 | if not find(gloa, "main ::") 146 | gloa = gloa.."\nlocal main :: () {}\n" 147 | 148 | local ok, err = writeEntireFile(tempPath, gloa) 149 | assert(ok, err) 150 | 151 | runTest(tempPath, false, format( 152 | [["lua "%s" %s "%s" %s"]], 153 | COMPILER_PATH, COMPILER_OPTIONS, 154 | tempPath, 155 | OUTPUT_REDIRECTION 156 | )) 157 | if testToRun break 158 | } 159 | } 160 | 161 | print("-"*64) 162 | for results print(it) 163 | print("-"*64) 164 | 165 | if testCount == 0 166 | print("No tests ran!") 167 | elseif failCount == 0 168 | printf("Completed all %d tests successfully. Yay!", testCount) 169 | else 170 | printf("Failed %d of %d", failCount, testCount) 171 | 172 | print() 173 | 174 | if failCount > 0 exit(1) 175 | } 176 | -------------------------------------------------------------------------------- /tests/modules.gloa: -------------------------------------------------------------------------------- 1 | -- 2 | -- Tests for modules. 3 | -- 4 | 5 | local main :: () { 6 | local print :: (...:any) !foreign lua "print" 7 | print("Doing testBasicModule()") ; testBasicModule() 8 | print("Doing testStringModule()") ; testStringModule() 9 | print("Doing testLuaModule()") ; testLuaModule() 10 | print("All done!") 11 | } 12 | 13 | local assert :: (b:bool, err="assertion failed!") !foreign lua "assert" 14 | 15 | 16 | 17 | local testBasicModule :: () { 18 | !import "basic" 19 | 20 | print("Print test") 21 | 22 | assert(format("a%d%%b%s", 5, "c") == "a5%bc") 23 | 24 | do { 25 | local arr: []string = {"a","b","c"} 26 | insert(arr, "d") 27 | assert(#arr == 4) 28 | assert(arr[4] == "d") 29 | remove(arr, 3) 30 | assert(arr[3] == "d") 31 | } 32 | 33 | do { 34 | local ok, n = stringToFloat("8.0") 35 | assert(ok) 36 | assert(n == 8.0) 37 | ok, n = stringToFloat("abc") 38 | assert(not ok) 39 | } 40 | do { 41 | local ok, n = stringToInt("8") 42 | assert(ok) 43 | assert(n == 8) 44 | ok, n = stringToInt("f0", 16) 45 | assert(ok) 46 | assert(n == 240) 47 | ok, n = stringToInt("abc") 48 | assert(not ok) 49 | ok, n = stringToInt("8", 8) 50 | assert(not ok) 51 | } 52 | 53 | do { 54 | local getVararg :: () -> ...int { 55 | return 1, 2, 3 56 | } 57 | local a, b, c = select(2, getVararg()) 58 | assert(a == 2) 59 | assert(b == 3) 60 | assert(c == nil) 61 | } 62 | } 63 | 64 | 65 | 66 | local testStringModule :: () { 67 | !import "string" 68 | 69 | assert(getByte("ab") == !char "a") 70 | assert(getByte("ab", 2) == !char "b") 71 | 72 | assert(bytesToString() == "") 73 | assert(bytesToString(!char "a", !char "b") == "ab") 74 | 75 | do { 76 | local found, i1, i2 = find("What is a foo?", "foo.") 77 | assert(not found) 78 | found, i1, i2 = find("What is a foo?", "a") 79 | assert(found) 80 | assert(i1 == 3) 81 | assert(i2 == 3) 82 | found, i1, i2 = find("What is a foo?", "a", 4) 83 | assert(found) 84 | assert(i1 == 9) 85 | assert(i2 == 9) 86 | } 87 | 88 | do { 89 | local found, i1, i2, oo = findPattern("What is a foo?", "f(oo).") 90 | assert(found) 91 | assert(i1 == 11) 92 | assert(i2 == 14) 93 | assert(oo == "oo") 94 | found, i1, i2, oo = findPattern("What is a foo?", "f(oo).", 99) 95 | assert(not found) 96 | } 97 | 98 | do { 99 | local pattern = "(ba[gt])" 100 | local found, word = matchPattern("Half-full bag.", pattern) 101 | assert(found) 102 | assert(word == "bag") 103 | found, word = matchPattern("Look out for the bat!", pattern) 104 | assert(found) 105 | assert(word == "bat") 106 | } 107 | 108 | local i = 0 109 | for word in eachPatternMatch("That rat is quite fat.", "[fr]at") { 110 | i = i+1 111 | if i == 1 assert(word == "rat") 112 | if i == 2 assert(word == "fat") 113 | if i == 3 assert(false) 114 | } 115 | assert(i == 2) 116 | 117 | assert(escapePattern("foo(bar)?") == "foo%(bar%)%?") 118 | assert(reverse("123") == "321") 119 | assert(toLower("AbCd!") == "abcd!") 120 | assert(toUpper("AbCd!") == "ABCD!") 121 | 122 | assert(repeat("ab", 3) == "ababab") 123 | -- assert(repeat("ab", 3, "|") == "ab|ab|ab") -- @Incomplete 124 | 125 | local chunkString = getBinaryRepresentationOfLuaFunction(main) 126 | 127 | assert(getSubstring("abc 123", 3, 5) == "c 1") 128 | assert(getSubstring("abc 123", 5, -2) == "12") 129 | assert(getSubstring("abc 123", -3) == "123") 130 | assert(getSubstring("abc 123", 99) == "") 131 | 132 | do { 133 | local s = "The dog spotted the other dog." 134 | local result:string 135 | local reps:int 136 | 137 | result, reps = replace(s, "dog", "cat") 138 | assert(result == "The cat spotted the other cat.") 139 | assert(reps == 2) 140 | result, reps = replace(s, "dog", "cat", 1) 141 | assert(result == "The cat spotted the other dog.") 142 | assert(reps == 1) 143 | 144 | result, reps = replacePattern(s, "[Tt]he ", "One ") 145 | assert(result == "One dog spotted One other dog.") 146 | assert(reps == 2) 147 | result, reps = replacePattern(s, "[Tt]he ", "One ", 1) 148 | assert(result == "One dog spotted the other dog.") 149 | assert(reps == 1) 150 | 151 | result, reps = replaceWithPattern(s, "dog", "%0-cat") 152 | assert(result == "The dog-cat spotted the other dog-cat.") 153 | assert(reps == 2) 154 | result, reps = replaceWithPattern(s, "dog", "%0-cat", 1) 155 | assert(result == "The dog-cat spotted the other dog.") 156 | assert(reps == 1) 157 | 158 | result, reps = replacePatternWithPattern(s, "[Tt]he ", "%0silly ") 159 | assert(result == "The silly dog spotted the silly other dog.") 160 | assert(reps == 2) 161 | result, reps = replacePatternWithPattern(s, "[Tt]he ", "%0silly ", 1) 162 | assert(result == "The silly dog spotted the other dog.") 163 | assert(reps == 1) 164 | 165 | result, reps = replace("\0\0.\0", "\0.", "a") 166 | assert(result == "\0a\0") 167 | assert(reps == 1) 168 | result, reps = replace(result, "\0", "b") 169 | assert(result == "bab") 170 | assert(reps == 2) 171 | } 172 | } 173 | 174 | 175 | 176 | local testLuaModule :: () { 177 | !import "lua" 178 | 179 | do { 180 | local arr = {"a","b","c"} 181 | assert(getType(arr) == LuaType.TABLE) 182 | } 183 | 184 | do { 185 | local ok, chunk, err = loadString([[return 8]], ()->int) 186 | assert(ok) 187 | assert(chunk() == 8) 188 | } 189 | do { 190 | local ok, chunk, err = loadString([[nope nope]], ()) 191 | assert(not ok) 192 | } 193 | } 194 | 195 | 196 | -------------------------------------------------------------------------------- /modules/wx/wxcore_help.gloa: -------------------------------------------------------------------------------- 1 | --[[============================================================ 2 | --= 3 | --= wxLua/wxWidget bindings for Glóa 4 | --= Interface source: wxcore_help.i 5 | --= 6 | --= Tested with: 7 | --= - wxLua 2.8.7.0 / wxWidgets 2.8.8 8 | --= 9 | --= Note: Most bindings have not been tested yet! 10 | --= 11 | --============================================================]] 12 | 13 | !import "wx/common" 14 | !import "wx/wxcore_windows" 15 | !import "wx/wxcore_controls" 16 | !import "wx/wxcore_defsutils" 17 | !import "wx/wxcore_gdi" 18 | !import "wx/wxcore_event" 19 | !import "wx/wxcore_appframe" 20 | !import "wx/wxhtml_html" 21 | 22 | export wxHELP_NETSCAPE: int : !foreign lua "wx.wxHELP_NETSCAPE" 23 | 24 | export wxHelpSearchMode :: wxEnum 25 | export wxHELP_SEARCH_INDEX: wxHelpSearchMode : !foreign lua "wx.wxHELP_SEARCH_INDEX" 26 | export wxHELP_SEARCH_ALL: wxHelpSearchMode : !foreign lua "wx.wxHELP_SEARCH_ALL" 27 | 28 | export wxContextHelp :: !foreign struct { 29 | using wxObject, 30 | 31 | !call :: (win:wxWindow=wxWindow.null, beginHelp:bool=true) -> wxContextHelp !foreign lua "wx.wxContextHelp", 32 | 33 | BeginContextHelp :: (self:wxContextHelp, win:wxWindow) -> bool !foreign method "BeginContextHelp", 34 | EndContextHelp :: (self:wxContextHelp) -> bool !foreign method "EndContextHelp", 35 | } 36 | 37 | export wxContextHelpButton :: !foreign struct { 38 | using wxBitmapButton, 39 | 40 | !call :: (parent:wxWindow, id:wxWindowID=wxID_CONTEXT_HELP, pos:wxPoint=wxDefaultPosition, size:wxSize=wxDefaultSize, style:int--[[long]]=wxBU_AUTODRAW) -> wxContextHelpButton !foreign lua "wx.wxContextHelpButton", 41 | } 42 | 43 | export wxHelpProvider :: !foreign struct { 44 | using wxLuaUserdata, 45 | 46 | Set :: (helpProvider:wxHelpProvider) -> wxHelpProvider !foreign lua "wx.wxHelpProvider.Set", 47 | Get :: () -> wxHelpProvider !foreign lua "wx.wxHelpProvider.Get", 48 | 49 | GetHelp :: (self:wxHelpProvider, window:wxWindow) -> string !foreign method "GetHelp", 50 | ShowHelpAtPoint :: (self:wxHelpProvider, window:wxWindow, pt:wxPoint, origin:wxHelpEvent.Origin) -> bool !foreign method "ShowHelpAtPoint", 51 | ShowHelp :: (self:wxHelpProvider, window:wxWindow) -> bool !foreign method "ShowHelp", 52 | AddHelp :: (self:wxHelpProvider, window:wxWindow, text:wxString|string) !foreign method "AddHelp", 53 | RemoveHelp :: (self:wxHelpProvider, window:wxWindow) !foreign method "RemoveHelp", 54 | } 55 | 56 | export wxSimpleHelpProvider :: !foreign struct { 57 | using wxHelpProvider, 58 | 59 | !call :: () -> wxSimpleHelpProvider !foreign lua "wx.wxSimpleHelpProvider", 60 | } 61 | 62 | export wxHelpControllerHelpProvider :: !foreign struct { 63 | using wxSimpleHelpProvider, 64 | 65 | !call :: (hc:wxHelpController=wxHelpController.null) -> wxHelpControllerHelpProvider !foreign lua "wx.wxHelpControllerHelpProvider", 66 | 67 | SetHelpController :: (self:wxHelpControllerHelpProvider, hc:wxHelpController) !foreign method "SetHelpController", 68 | GetHelpController :: (self:wxHelpControllerHelpProvider) -> wxHelpController !foreign method "GetHelpController", 69 | } 70 | 71 | export wxHelpControllerBase :: !foreign struct { 72 | using wxObject, 73 | 74 | Initialize :: (self:wxHelpControllerBase, file:wxString|string) !foreign method "Initialize", 75 | DisplayBlock :: (self:wxHelpControllerBase, blockNo:int--[[long]]) -> bool !foreign method "DisplayBlock", 76 | DisplayContents :: (self:wxHelpControllerBase) -> bool !foreign method "DisplayContents", 77 | DisplayContextPopup :: (self:wxHelpControllerBase, contextId:int) -> bool !foreign method "DisplayContextPopup", 78 | DisplaySection :: (self:wxHelpControllerBase, sectionNo:int) -> bool !foreign method "DisplaySection", 79 | DisplaySection :: (self:wxHelpControllerBase, section:wxString|string) -> bool !foreign method "DisplaySection", 80 | DisplayTextPopup :: (self:wxHelpControllerBase, text:wxString|string, pos:wxPoint) -> bool !foreign method "DisplayTextPopup", 81 | GetFrameParameters :: (self:wxHelpControllerBase) -> wxFrame, wxSize, wxPoint, bool !foreign method "GetFrameParameters", 82 | GetParentWindow :: (self:wxHelpControllerBase) -> wxWindow !foreign method "GetParentWindow", 83 | KeywordSearch :: (self:wxHelpControllerBase, keyWord:wxString|string, mode:wxHelpSearchMode=wxHELP_SEARCH_ALL) -> bool !foreign method "KeywordSearch", 84 | LoadFile :: (self:wxHelpControllerBase, file:wxString|string="") -> bool !foreign method "LoadFile", 85 | SetFrameParameters :: (self:wxHelpControllerBase, title:wxString|string, size:wxSize, pos:wxPoint=wxDefaultPosition, newFrameEachTime:bool=false) !foreign method "SetFrameParameters", 86 | SetParentWindow :: (self:wxHelpControllerBase, win:wxWindow) !foreign method "SetParentWindow", 87 | SetViewer :: (self:wxHelpControllerBase, viewer:wxString|string, flags:int--[[long]]) !foreign method "SetViewer", 88 | Quit :: (self:wxHelpControllerBase) -> bool !foreign method "Quit", 89 | } 90 | 91 | export wxHelpController :: !foreign struct { 92 | using wxHelpControllerBase, 93 | 94 | null: wxHelpController : !foreign lua "wx.NULL", 95 | 96 | !call :: () -> wxHelpController !foreign lua "wx.wxHelpController", 97 | } 98 | 99 | export wxWinHelpController :: !foreign struct { 100 | using wxHelpControllerBase, 101 | 102 | !call :: () -> wxWinHelpController !foreign lua "wx.wxWinHelpController", 103 | } 104 | 105 | export wxBestHelpController :: !foreign struct { 106 | using wxHelpControllerBase, 107 | 108 | !call :: (parentWindow:wxWindow=wxWindow.null, style:int=wxHF_DEFAULT_STYLE) -> wxBestHelpController !foreign lua "wx.wxBestHelpController", 109 | } 110 | -------------------------------------------------------------------------------- /src/ready.luapart: -------------------------------------------------------------------------------- 1 | --[[============================================================ 2 | --= 3 | --= Type-ready pipe stuff 4 | --= Here we wait for types to be, or make them, ready! 5 | --= 6 | --=------------------------------------------------------------- 7 | --= 8 | --= Glóa - a language that compiles into Lua 9 | --= by Marcus 'ReFreezed' Thunström 10 | --= 11 | --============================================================== 12 | 13 | handleTypeReadyPipe 14 | 15 | --============================================================]] 16 | !recordLineNumber(@file, @line) 17 | 18 | 19 | 20 | function _G.handleTypeReadyPipe(state, node) 21 | local typeInfo = node.inferredType 22 | 23 | -- 24 | -- Nodes. 25 | -- 26 | 27 | if node.nodeType == !(AST_STRUCT) then 28 | local struct = node 29 | local structInfo = struct.representedType 30 | 31 | for _, member in ipairs(structInfo.members) do 32 | if not member.typeInfo.isReady and not member.typeInfo.seen[structInfo] then 33 | !DEPEND_AND_RETURN(`struct`, DEPEND_TYPE_READY, `member.typeInfo`) 34 | end 35 | end 36 | 37 | if structInfo.keyType and not structInfo.keyType.isReady and not structInfo.keyType.seen[structInfo] then 38 | !DEPEND_AND_RETURN(`struct`, DEPEND_TYPE_READY, `structInfo.keyType`) 39 | end 40 | if structInfo.valueType and not structInfo.valueType.isReady and not structInfo.valueType.seen[structInfo] then 41 | !DEPEND_AND_RETURN(`struct`, DEPEND_TYPE_READY, `structInfo.valueType`) 42 | end 43 | 44 | markTypeAsReady(state, structInfo) 45 | moveToNextRelevantPipe(state, struct) 46 | 47 | elseif node.nodeType == !(AST_TYPE) then 48 | local typeNode = node 49 | local typeInfo = typeNode.representedType 50 | 51 | if typeNode.kind == !(TYPE_KIND_SIMPLE_BUILTIN) then 52 | moveToNextRelevantPipe(state, typeNode) 53 | 54 | elseif typeNode.kind == !(TYPE_KIND_USER) then 55 | if not typeInfo.isReady then 56 | !DEPEND_AND_RETURN(`typeNode`, DEPEND_TYPE_READY, `typeInfo`) 57 | end 58 | 59 | moveToNextRelevantPipe(state, typeNode) 60 | 61 | elseif typeNode.kind == !(TYPE_KIND_FUNCTION) then -- Extra data: Function signature. 62 | local funcSig = typeInfo 63 | if funcSig.isReady then 64 | moveToNextRelevantPipe(state, typeNode) 65 | return 66 | end 67 | 68 | for _, argTypeInfo in ipairs(funcSig.argumentTypesIn) do 69 | if not argTypeInfo.isReady and not argTypeInfo.seen[funcSig] then 70 | !DEPEND_AND_RETURN(`typeNode`, DEPEND_TYPE_READY, `argTypeInfo`) 71 | end 72 | end 73 | for _, argTypeInfo in ipairs(funcSig.argumentTypesOut) do 74 | if not argTypeInfo.isReady and not argTypeInfo.seen[funcSig] then 75 | !DEPEND_AND_RETURN(`typeNode`, DEPEND_TYPE_READY, `argTypeInfo`) 76 | end 77 | end 78 | 79 | markTypeAsReady(state, funcSig) 80 | moveToNextRelevantPipe(state, typeNode) 81 | 82 | elseif typeNode.kind == !(TYPE_KIND_ARRAY) then -- Extra data: Item type. 83 | if typeInfo.isReady then 84 | moveToNextRelevantPipe(state, typeNode) 85 | return 86 | end 87 | if not typeInfo.itemType.isReady and not typeInfo.itemType.seen[typeInfo] then 88 | !DEPEND_AND_RETURN(`typeNode`, DEPEND_TYPE_READY, `typeInfo.itemType`) 89 | end 90 | 91 | markTypeAsReady(state, typeInfo) 92 | moveToNextRelevantPipe(state, typeNode) 93 | 94 | elseif typeNode.kind == !(TYPE_KIND_COMPOUND) then -- Extra data: Types. 95 | local compoundOrListSig = typeInfo 96 | if compoundOrListSig.isReady then 97 | moveToNextRelevantPipe(state, typeNode) 98 | return 99 | end 100 | 101 | for _, itemType in ipairs(compoundOrListSig) do 102 | if not itemType.isReady and not itemType.seen[compoundOrListSig] then 103 | !DEPEND_AND_RETURN(`typeNode`, DEPEND_TYPE_READY, `itemType`) 104 | end 105 | end 106 | 107 | markTypeAsReady(state, compoundOrListSig) 108 | moveToNextRelevantPipe(state, typeNode) 109 | 110 | else 111 | errorInternal(state, typeNode, typeNode.kind) 112 | end 113 | 114 | -- 115 | -- Types. 116 | -- 117 | 118 | -- Type marked ready from elsewhere. 119 | elseif typeInfo.isReady then 120 | moveToNextRelevantPipe(state, node) 121 | 122 | elseif typeInfo.tag == !(TYPE_ARRAY) or typeInfo.tag == !(TYPE_VARARG) then 123 | if not typeInfo.itemType.isReady and not typeInfo.itemType.seen[typeInfo] then 124 | !DEPEND_AND_RETURN(`node`, DEPEND_TYPE_READY, `typeInfo.itemType`) 125 | end 126 | 127 | markTypeAsReady(state, typeInfo) 128 | moveToNextRelevantPipe(state, node) 129 | 130 | elseif typeInfo.tag == !(TYPE_COMPOUND) or typeInfo.tag == !(TYPE_LIST) then 131 | local compoundOrListSig = typeInfo 132 | 133 | for _, itemType in ipairs(compoundOrListSig) do 134 | if not itemType.isReady and not itemType.seen[compoundOrListSig] then 135 | !DEPEND_AND_RETURN(`node`, DEPEND_TYPE_READY, `itemType`) 136 | end 137 | end 138 | 139 | markTypeAsReady(state, compoundOrListSig) 140 | moveToNextRelevantPipe(state, node) 141 | 142 | elseif typeInfo.tag == !(TYPE_FUNCTION) then 143 | local funcSig = typeInfo 144 | 145 | for _, argTypeInfo in ipairs(funcSig.argumentTypesIn) do 146 | if not argTypeInfo.isReady and not argTypeInfo.seen[funcSig] then 147 | !DEPEND_AND_RETURN(`node`, DEPEND_TYPE_READY, `argTypeInfo`) 148 | end 149 | end 150 | for _, argTypeInfo in ipairs(funcSig.argumentTypesOut) do 151 | if not argTypeInfo.isReady and not argTypeInfo.seen[funcSig] then 152 | !DEPEND_AND_RETURN(`node`, DEPEND_TYPE_READY, `argTypeInfo`) 153 | end 154 | end 155 | 156 | markTypeAsReady(state, funcSig) 157 | moveToNextRelevantPipe(state, node) 158 | 159 | else 160 | !DEPEND_AND_RETURN(`node`, DEPEND_TYPE_READY, `typeInfo`) 161 | end 162 | end 163 | 164 | 165 | -------------------------------------------------------------------------------- /modules/wx/wxmedia_media.gloa: -------------------------------------------------------------------------------- 1 | --[[============================================================ 2 | --= 3 | --= wxLua/wxWidget bindings for Glóa 4 | --= Interface source: wxmedia_media.i 5 | --= 6 | --= Tested with: 7 | --= - wxLua 2.8.7.0 / wxWidgets 2.8.8 8 | --= 9 | --= Note: Most bindings have not been tested yet! 10 | --= 11 | --============================================================]] 12 | 13 | !import "wx/wxcore_windows" 14 | !import "wx/common" 15 | !import "wx/wxcore_gdi" 16 | !import "wx/wxcore_core" 17 | !import "wx/wxnet_net" 18 | !import "wx/wxbase_file" 19 | !import "wx/wxcore_event" 20 | 21 | export wxMEDIA_FINISHED_ID: int : !foreign lua "wx.wxMEDIA_FINISHED_ID" 22 | export wxMEDIA_STOP_ID: int : !foreign lua "wx.wxMEDIA_STOP_ID" 23 | export wxMEDIA_LOADED_ID: int : !foreign lua "wx.wxMEDIA_LOADED_ID" 24 | export wxMEDIA_STATECHANGED_ID: int : !foreign lua "wx.wxMEDIA_STATECHANGED_ID" 25 | export wxMEDIA_PLAY_ID: int : !foreign lua "wx.wxMEDIA_PLAY_ID" 26 | export wxMEDIA_PAUSE_ID: int : !foreign lua "wx.wxMEDIA_PAUSE_ID" 27 | export wxMEDIABACKEND_DIRECTSHOW: string : !foreign lua "wx.wxMEDIABACKEND_DIRECTSHOW" 28 | export wxMEDIABACKEND_MCI: string : !foreign lua "wx.wxMEDIABACKEND_MCI" 29 | export wxMEDIABACKEND_QUICKTIME: string : !foreign lua "wx.wxMEDIABACKEND_QUICKTIME" 30 | export wxMEDIABACKEND_GSTREAMER: string : !foreign lua "wx.wxMEDIABACKEND_GSTREAMER" 31 | export wxMEDIABACKEND_REALPLAYER: string : !foreign lua "wx.wxMEDIABACKEND_REALPLAYER" 32 | export wxMEDIABACKEND_WMP10: string : !foreign lua "wx.wxMEDIABACKEND_WMP10" 33 | export wxEVT_MEDIA_FINISHED: wxEventType : !foreign lua "wx.wxEVT_MEDIA_FINISHED" -- EVT_MEDIA_FINISHED(winid, fn) 34 | export wxEVT_MEDIA_STOP: wxEventType : !foreign lua "wx.wxEVT_MEDIA_STOP" -- EVT_MEDIA_STOP(winid, fn) 35 | export wxEVT_MEDIA_LOADED: wxEventType : !foreign lua "wx.wxEVT_MEDIA_LOADED" -- EVT_MEDIA_LOADED(winid, fn) 36 | export wxEVT_MEDIA_STATECHANGED: wxEventType : !foreign lua "wx.wxEVT_MEDIA_STATECHANGED" -- EVT_MEDIA_STATECHANGED(winid, fn) 37 | export wxEVT_MEDIA_PLAY: wxEventType : !foreign lua "wx.wxEVT_MEDIA_PLAY" -- EVT_MEDIA_PLAY(winid, fn) 38 | export wxEVT_MEDIA_PAUSE: wxEventType : !foreign lua "wx.wxEVT_MEDIA_PAUSE" -- EVT_MEDIA_PAUSE(winid, fn) 39 | 40 | export wxMediaState :: wxEnum 41 | export wxMEDIASTATE_STOPPED: wxMediaState : !foreign lua "wx.wxMEDIASTATE_STOPPED" 42 | export wxMEDIASTATE_PAUSED: wxMediaState : !foreign lua "wx.wxMEDIASTATE_PAUSED" 43 | export wxMEDIASTATE_PLAYING: wxMediaState : !foreign lua "wx.wxMEDIASTATE_PLAYING" 44 | 45 | export wxMediaCtrlPlayerControls :: wxEnum 46 | export wxMEDIACTRLPLAYERCONTROLS_NONE: wxMediaCtrlPlayerControls : !foreign lua "wx.wxMEDIACTRLPLAYERCONTROLS_NONE" 47 | export wxMEDIACTRLPLAYERCONTROLS_STEP: wxMediaCtrlPlayerControls : !foreign lua "wx.wxMEDIACTRLPLAYERCONTROLS_STEP" 48 | export wxMEDIACTRLPLAYERCONTROLS_VOLUME: wxMediaCtrlPlayerControls : !foreign lua "wx.wxMEDIACTRLPLAYERCONTROLS_VOLUME" 49 | export wxMEDIACTRLPLAYERCONTROLS_DEFAULT: wxMediaCtrlPlayerControls : !foreign lua "wx.wxMEDIACTRLPLAYERCONTROLS_DEFAULT" 50 | 51 | export wxMediaCtrl :: !foreign struct { 52 | using wxControl, 53 | 54 | !call :: () -> wxMediaCtrl !foreign lua "wx.wxMediaCtrl", 55 | !call :: (parent:wxWindow, winid:wxWindowID, fileName:wxString|string="", pos:wxPoint=wxDefaultPosition, size:wxSize=wxDefaultSize, style:int--[[long]]=0, szBackend:wxString|string="", val:wxValidator=wxDefaultValidator, name:wxString|string="wxMediaCtrl") -> wxMediaCtrl !foreign lua "wx.wxMediaCtrl", 56 | 57 | Create :: (self:wxMediaCtrl, parent:wxWindow, winid:wxWindowID, fileName:wxString|string="", pos:wxPoint=wxDefaultPosition, size:wxSize=wxDefaultSize, style:int--[[long]]=0, szBackend:wxString|string="", val:wxValidator=wxDefaultValidator, name:wxString|string="wxMediaCtrl") -> bool !foreign method "Create", 58 | GetDownloadProgress :: (self:wxMediaCtrl) -> wxFileOffset !foreign method "GetDownloadProgress", 59 | GetDownloadTotal :: (self:wxMediaCtrl) -> wxFileOffset !foreign method "GetDownloadTotal", 60 | GetState :: (self:wxMediaCtrl) -> wxMediaState !foreign method "GetState", 61 | GetVolume :: (self:wxMediaCtrl) -> float--[[double]] !foreign method "GetVolume", 62 | Length :: (self:wxMediaCtrl) -> wxFileOffset !foreign method "Length", 63 | Load :: (self:wxMediaCtrl, fileName:wxString|string) -> bool !foreign method "Load", 64 | Load :: (self:wxMediaCtrl, location:wxURI) -> bool !foreign method "Load", 65 | Load :: (self:wxMediaCtrl, location:wxURI, proxy:wxURI) -> bool !foreign method "Load", 66 | LoadURI :: (self:wxMediaCtrl, fileName:wxString|string) -> bool !foreign method "LoadURI", 67 | LoadURIWithProxy :: (self:wxMediaCtrl, fileName:wxString|string, proxy:wxString|string) -> bool !foreign method "LoadURIWithProxy", 68 | Pause :: (self:wxMediaCtrl) -> bool !foreign method "Pause", 69 | Play :: (self:wxMediaCtrl) -> bool !foreign method "Play", 70 | Seek :: (self:wxMediaCtrl, where:wxFileOffset, mode:wxSeekMode=wxFromStart) -> wxFileOffset !foreign method "Seek", 71 | Stop :: (self:wxMediaCtrl) -> bool !foreign method "Stop", 72 | SetVolume :: (self:wxMediaCtrl, dVolume:float--[[double]]) -> bool !foreign method "SetVolume", 73 | ShowPlayerControls :: (self:wxMediaCtrl, flags:wxMediaCtrlPlayerControls=wxMEDIACTRLPLAYERCONTROLS_DEFAULT) -> bool !foreign method "ShowPlayerControls", 74 | Tell :: (self:wxMediaCtrl) -> wxFileOffset !foreign method "Tell", 75 | } 76 | 77 | export wxMediaEvent :: !foreign struct { 78 | using wxNotifyEvent, 79 | 80 | !call :: (commandType:wxEventType=wxEVT_NULL, winid:int=0) -> wxMediaEvent !foreign lua "wx.wxMediaEvent", 81 | } 82 | -------------------------------------------------------------------------------- /tests/parsing.gloa: -------------------------------------------------------------------------------- 1 | -- 2 | -- Parsing tests. 3 | -- 4 | 5 | local n = 1+2*3+4 -- 1+(2*3)+4 6 | local n = a+i < b/2+1 -- (a+i) < ((b/2)+1) 7 | local n = 5+x^2*8 -- 5+((x^2)*8) 8 | local n = a < y and y <= z -- (a < y) and (y <= z) 9 | local n = -x^2 -- -(x^2) 10 | local n = x^y^z -- x^(y^z) 11 | 12 | local str = "a\nb\tc" .. 1+2 .. 4 13 | 14 | local flag = true 15 | local NIL = nil 16 | 17 | local t1 = {a=5, ["hello"]=nil, [true]=false, nil} 18 | local t2 = {[{1+-2}]=true and false; [(b)]=((5))} 19 | local t3 = { [f(1)] = g; "x", "y"; x = 1, f(x), [30] = 23; 45 } 20 | 21 | local v = func(5, "hello") 22 | local v = bar({a=true}) + bat("?") 23 | 24 | local a = 5 25 | local b : : false 26 | local c : any = nil 27 | local d : string = "hello" 28 | local e : Thing 29 | local f : Poly(int, Other(bool), bad("")) 30 | local g : type_of(d) 31 | local h : : type_of(g) 32 | 33 | local arr : [] int = {1,2,3} 34 | local arr : [] [] Thing( [] int, bool ) 35 | 36 | local v = func(5, hello) + "aaaa" 37 | 38 | local sig :: () 39 | local sig :: (a:float) -> void 40 | local sig :: (a:float, b:Groot) -> bool, Tree 41 | 42 | local func :: (b:Bar(Dog,Cat(int,int)), n:float=-1) -> (ok:bool, thing:Thing) { 43 | local x:float = 2; 44 | local y = 85; 45 | } 46 | 47 | local sig :: (a, b: bool, x: any) 48 | local sig :: (a, b: []int = nil) 49 | 50 | !import "math" 51 | !load "src/foo" 52 | export ioLib :: !import "io" 53 | 54 | local importsAndLoads :: () { 55 | !import "math" 56 | !load "src/foo" 57 | local ioLib :: !import "io" 58 | } 59 | 60 | local io1, io2 :: !import "io", !import "io" 61 | 62 | local Entity :: struct { 63 | entityType: string, 64 | id: Id, 65 | x:float = 0.0, 66 | y = 0.0; 67 | WHAT_IS_3 :: 1+2, 68 | } 69 | 70 | local Empty :: struct {} 71 | 72 | local Dummy: Type : struct (a,b:int=0) { a:int } 73 | 74 | local EntityType :: enum { 75 | PLAYER :: 0x01, 76 | MONSTER :: 0x02; 77 | BUTTON :: 0x03, 78 | DOOR :: 0x04 79 | } 80 | 81 | local MELEE_NAME :: "Knight" 82 | local ClassName: Type : enum string { 83 | MELEE :: MELEE_NAME, 84 | RANGED :: "Archer", 85 | MAGIC :: "Mage", 86 | } 87 | 88 | local badFunc: (a:float, b:Groot) -- This is a type error but it should parse. 89 | local funcReturningFunc :: () -> (func:(n:int)->string) {} 90 | local sig1, sig2 :: (() -> bool), (n:int) -> string 91 | local sig1, sig2 :: (() -> bool), () -> string 92 | local sig, Bool :: (() -> (()->string)), bool 93 | local sig, Bool :: (() -> (n:int)->string), bool 94 | local sig, Bool :: (() -> (n:int)->void), bool 95 | local sig :: () -> (n:int)->void , bool -- Note: void cannot be followed by anything else in a function signature, so 'bool' here is part of the return values for the outer signature. 96 | 97 | local x, Struct :: 1, struct {} 98 | 99 | local main :: () { 100 | local a: int 101 | a, b += 5, 7+-6 102 | s ..= "a".."b" 103 | 104 | local n = cast(float) ("6") + 5 105 | 106 | local hëllô_日本語 = 한국어_ٱلْعَرَبِيَّة 107 | 108 | local len = #t 109 | 110 | func() 111 | func(6, 7) 112 | func("bar") 113 | func({})("bar")() 114 | func() ; (obj).x = 6 115 | func() ; (a and b).x = 6 116 | 117 | if x func() 118 | if x and y { 119 | local n = dirt() 120 | n += grass() 121 | } 122 | 123 | if x local f = 7 124 | if x func() 125 | 126 | if x a() 127 | elseif y b() 128 | else if z c() 129 | else d() 130 | 131 | local x = 5 132 | while x > 0 x -= 1 133 | while x > 0 local i:int 134 | while x > 0 { x -= 1 } 135 | 136 | for 1, 3 print(it) 137 | for arr print(itIndex, it) 138 | for v: arr print(itIndex, v) 139 | for v, i: arr print(i, v) 140 | for i = 1, 3 print(i) 141 | for i = 3, 1, -1 print(i) 142 | for i, v in ipairs(arr) print(i, v) 143 | for k, v in next, t, nil print(k, v) 144 | for v1, v2, v3: obj print(i, v) 145 | for v1, v2, v3 in myIterator, obj print(v1, v2, v3) 146 | 147 | local v1 = t1.t2[i].k 148 | local v2 = obj.k1.m1(m1Arg)(fArg).k2.m2(m2Arg).k3 149 | local v3 = obj.k1.m1!(m1Arg)(fArg).k2.m2!(m2Arg).k3 150 | local v4 = (t).k 151 | 152 | t.m() 153 | t.m!() 154 | obj.k1.m1(m1Arg)(fArg).k2.m2(m2Arg) 155 | obj.k1.m1!(m1Arg)(fArg).k2.m2!(m2Arg) 156 | 157 | t.n = 99 158 | t[1] = 99 159 | t.s, t.b = "foo", true 160 | f(arg).k, t[k] += 1, 2 161 | t[k], f(arg).k = 2, 1 162 | a, b = f(arg) 163 | a, b = (f(arg)) 164 | 165 | local a:int = f() 166 | local a, b = f() 167 | local a, b = (f()) 168 | local a, b, c = 100, f() 169 | local a,b:int : 1,2 170 | 171 | local var:float|none = 0 172 | local func :: (a:int, b:int|none=nil) -> (a:int, b:int|none) {} 173 | local sig :: (a, b: int|([]string)|none) 174 | 175 | defer file.close!() 176 | defer { file.close!() ; print("yo") } 177 | 178 | -- These work if we got out args. 179 | local func :: () -> int { 180 | do return 1, func() 181 | do return 2, (func()) 182 | } 183 | 184 | -- Ambiguity for return, kind of! Parsing here depends on 185 | -- whether the current function has return values or not. 186 | if x return 187 | func() 188 | 189 | for 1, 5 190 | if it < 3 191 | print(it) 192 | else 193 | break 194 | func() 195 | 196 | for v: arr { 197 | if x continue 198 | func1() 199 | if y break(v) 200 | func2() 201 | } 202 | 203 | local func :: (a:string, ...:int) { 204 | local x, y, z: int = 5, ... 205 | local x, y, z: int = 5, (...) 206 | } 207 | local a, b : int = func() 208 | 209 | local func :: (a, b: int = 5) {} 210 | 211 | local func :: (a=0) {} 212 | local func :: (a:=0) {} 213 | local func :: (a:int) {} 214 | local func :: (a:int=0) {} 215 | 216 | local func :: (void) {} 217 | local func :: (void) -> void {} 218 | local func :: (void) -> (void) {} 219 | 220 | local n = 0 ; n += 1 221 | local s = 0 ; s ..= "" 222 | local b = 0 ; b and= true 223 | } 224 | -------------------------------------------------------------------------------- /src/unicodeConversions.luapart: -------------------------------------------------------------------------------- 1 | --[[============================================================ 2 | --= 3 | --= Unicode conversions for Lua identifiers 4 | --= 5 | --= Lua does not have support for Unicode identifiers like Glóa 6 | --= does so we have to subsitute Unicode characters with ASCII 7 | --= characters when outputting Lua. 8 | --= 9 | --= Note: All characters here must currently be represented by 10 | --= a single Unicode codepoint. Combining characters are not 11 | --= supported. 12 | --= 13 | --= Note: Any non-ASCII character not present here will be 14 | --= replaced with "_" (underscore). 15 | --= 16 | --=------------------------------------------------------------- 17 | --= 18 | --= Glóa - a language that compiles into Lua 19 | --= by Marcus 'ReFreezed' Thunström 20 | --= 21 | --============================================================]] 22 | 23 | !({ 24 | -- A 25 | ["À"] = "A", 26 | ["à"] = "a", 27 | ["Á"] = "A", 28 | ["á"] = "a", 29 | ["Â"] = "A", 30 | ["â"] = "a", 31 | ["Ã"] = "A", 32 | ["ã"] = "a", 33 | ["Ä"] = "A", 34 | ["ä"] = "a", 35 | ["Å"] = "A", 36 | ["å"] = "a", 37 | ["Ā"] = "A", 38 | ["ā"] = "a", 39 | ["Ă"] = "A", 40 | ["ă"] = "a", 41 | ["Ą"] = "A", 42 | ["ą"] = "a", 43 | ["Ȧ"] = "A", 44 | ["ȧ"] = "a", 45 | -- B 46 | ["Ƀ"] = "B", 47 | ["ƀ"] = "b", 48 | ["Ɓ"] = "B", 49 | ["ɓ"] = "b", 50 | ["Ḇ"] = "B", 51 | ["ḇ"] = "b", 52 | ["Ꞗ"] = "B", -- B with flourish. 53 | ["ꞗ"] = "b", -- b with flourish. 54 | -- C 55 | ["Ç"] = "C", 56 | ["ç"] = "c", 57 | ["Ć"] = "C", 58 | ["ć"] = "c", 59 | ["Ĉ"] = "C", 60 | ["ĉ"] = "c", 61 | ["Ċ"] = "C", 62 | ["ċ"] = "c", 63 | ["Č"] = "C", 64 | ["č"] = "c", 65 | ["Ƈ"] = "C", 66 | ["ƈ"] = "c", 67 | ["Ꞓ"] = "C", -- C with bar. 68 | ["ꞓ"] = "c", -- c with bar. 69 | -- D 70 | ["Ð"] = "D", 71 | ["ð"] = "d", 72 | ["Ď"] = "D", 73 | ["ď"] = "d", 74 | ["Đ"] = "D", 75 | ["đ"] = "d", 76 | ["ȷ"] = "j", 77 | ["Ɖ"] = "D", 78 | ["ɖ"] = "d", 79 | ["Ɗ"] = "D", 80 | ["ɗ"] = "d", 81 | ["Ḍ"] = "D", 82 | ["ḍ"] = "d", 83 | ["Ḏ"] = "D", 84 | ["ḏ"] = "d", 85 | ["Ḑ"] = "D", 86 | ["ḑ"] = "d", 87 | -- E 88 | ["È"] = "E", 89 | ["è"] = "e", 90 | ["É"] = "E", 91 | ["é"] = "e", 92 | ["Ê"] = "E", 93 | ["ê"] = "e", 94 | ["Ë"] = "E", 95 | ["ë"] = "e", 96 | ["Ė"] = "E", 97 | ["ė"] = "e", 98 | ["Ę"] = "E", 99 | ["ę"] = "e", 100 | ["Ě"] = "E", 101 | ["ě"] = "e", 102 | ["Ɇ"] = "E", 103 | ["ɇ"] = "e", 104 | ["Ẽ"] = "E", 105 | ["ẽ"] = "e", 106 | -- F 107 | -- G 108 | ["Ĝ"] = "G", 109 | ["ĝ"] = "g", 110 | ["Ğ"] = "G", 111 | ["ğ"] = "g", 112 | ["Ġ"] = "G", 113 | ["ġ"] = "g", 114 | ["Ǥ"] = "G", 115 | ["ǥ"] = "g", 116 | ["Ǧ"] = "G", 117 | ["ǧ"] = "g", 118 | ["Ǵ"] = "G", 119 | ["ǵ"] = "g", 120 | ["Ɠ"] = "G", 121 | ["ɠ"] = "g", 122 | -- H 123 | ["Ĥ"] = "H", 124 | ["ĥ"] = "h", 125 | ["Ḥ"] = "H", 126 | ["ḥ"] = "h", 127 | ["Ḫ"] = "H", 128 | ["ḫ"] = "h", 129 | -- I 130 | ["İ"] = "I", 131 | ["Ì"] = "I", 132 | ["ì"] = "i", 133 | ["Í"] = "I", 134 | ["í"] = "i", 135 | ["Î"] = "I", 136 | ["î"] = "i", 137 | ["Ï"] = "I", 138 | ["ï"] = "i", 139 | ["ı"] = "i", 140 | ["Ɨ"] = "I", 141 | ["ɨ"] = "i", 142 | -- J 143 | ["Ĵ"] = "J", 144 | ["ĵ"] = "j", 145 | ["Ɉ"] = "J", 146 | ["ɉ"] = "j", 147 | -- K 148 | ["Ķ"] = "K", 149 | ["ķ"] = "k", 150 | ["Ƙ"] = "K", 151 | ["ƙ"] = "k", 152 | ["Ǩ"] = "K", 153 | ["ǩ"] = "k", 154 | ["Ḱ"] = "K", 155 | ["ḱ"] = "k", 156 | ["Ꝁ"] = "K", -- K with stroke. 157 | ["ꝁ"] = "k", -- k with stroke. 158 | ["Ꝃ"] = "K", -- K with diagonal stroke. 159 | ["ꝃ"] = "k", -- k with diagonal stroke. 160 | ["Ꝅ"] = "K", -- K with stroke and diagonal stroke. 161 | ["ꝅ"] = "k", -- k with stroke and diagonal stroke. 162 | -- L 163 | ["Ľ"] = "L", 164 | ["ľ"] = "l", 165 | ["Ł"] = "L", 166 | ["ł"] = "l", 167 | ["Ḷ"] = "L", 168 | ["ḷ"] = "l", 169 | -- M 170 | ["ḿ"] = "m", 171 | ["Ḿ"] = "M", 172 | -- N 173 | ["Ñ"] = "N", 174 | ["ñ"] = "n", 175 | ["Ń"] = "N", 176 | ["ń"] = "n", 177 | ["Ň"] = "N", 178 | ["ň"] = "n", 179 | ["ʼn"] = "n", 180 | ["Ǹ"] = "N", 181 | ["ǹ"] = "n", 182 | ["Ṅ"] = "N", 183 | ["ṅ"] = "n", 184 | ["Ṉ"] = "N", 185 | ["ṉ"] = "n", 186 | -- O 187 | ["Ò"] = "O", 188 | ["ò"] = "o", 189 | ["Ó"] = "O", 190 | ["ó"] = "o", 191 | ["Õ"] = "O", 192 | ["õ"] = "o", 193 | ["Ö"] = "O", 194 | ["ö"] = "o", 195 | ["Ơ"] = "O", 196 | ["ơ"] = "o", 197 | -- P 198 | ["Ᵽ"] = "P", 199 | ["ᵽ"] = "p", 200 | -- Q 201 | ["Ꝗ"] = "Q", -- Q with stroke. 202 | ["ꝗ"] = "q", -- q with stroke. 203 | -- R 204 | ["Ŕ"] = "R", 205 | ["ŕ"] = "r", 206 | ["Ř"] = "R", 207 | ["ř"] = "r", 208 | ["Ȓ"] = "R", 209 | ["ȓ"] = "r", 210 | ["Ɍ"] = "R", 211 | ["ɍ"] = "r", 212 | ["Ṛ"] = "R", 213 | ["ṛ"] = "r", 214 | -- S 215 | ["Ś"] = "S", 216 | ["ś"] = "s", 217 | ["Ŝ"] = "S", 218 | ["ŝ"] = "s", 219 | ["Ş"] = "S", 220 | ["ş"] = "s", 221 | ["Š"] = "S", 222 | ["š"] = "s", 223 | ["Ș"] = "S", 224 | ["ș"] = "s", 225 | ["Ṡ"] = "S", 226 | ["ṡ"] = "s", 227 | ["Ṣ"] = "S", 228 | ["ṣ"] = "s", 229 | -- T 230 | ["Ţ"] = "T", 231 | ["ţ"] = "t", 232 | ["Ť"] = "T", 233 | ["ť"] = "t", 234 | ["Ŧ"] = "T", 235 | ["ŧ"] = "t", 236 | ["Ț"] = "T", 237 | ["ț"] = "t", 238 | ["ᵵ"] = "t", 239 | ["Ṭ"] = "T", 240 | ["ṭ"] = "t", 241 | ["ẗ"] = "t", 242 | -- U 243 | ["Ú"] = "U", 244 | ["ú"] = "u", 245 | ["Û"] = "U", 246 | ["û"] = "u", 247 | ["Ü"] = "U", 248 | ["ü"] = "u", 249 | ["Ŭ"] = "U", 250 | ["ŭ"] = "u", 251 | ["Ư"] = "U", 252 | ["ư"] = "u", 253 | ["Ʉ"] = "U", 254 | ["ʉ"] = "u", 255 | -- V 256 | ["Ꝟ"] = "V", -- V with diagonal stroke. 257 | ["ꝟ"] = "v", -- v with diagonal stroke. 258 | -- X 259 | ["Ẋ"] = "X", 260 | ["ẋ"] = "x", 261 | -- Y 262 | ["Ƴ"] = "Y", 263 | ["ƴ"] = "y", 264 | ["Ȳ"] = "Y", 265 | ["ȳ"] = "y", 266 | ["Ɏ"] = "Y", 267 | ["ɏ"] = "y", 268 | -- Z 269 | ["Ź"] = "Z", 270 | ["ź"] = "z", 271 | ["Ž"] = "Z", 272 | ["ž"] = "z", 273 | ["Ƶ"] = "Z", 274 | ["ƶ"] = "z", 275 | ["Ǯ"] = "Z", 276 | ["ǯ"] = "z", 277 | ["Ẑ"] = "Z", 278 | ["ẑ"] = "z", 279 | ["Ẓ"] = "Z", 280 | ["ẓ"] = "z", 281 | -- Other 282 | ["Æ"] = "AE", 283 | ["æ"] = "ae", 284 | }) 285 | -------------------------------------------------------------------------------- /modules/wx/wxxml_xml.gloa: -------------------------------------------------------------------------------- 1 | --[[============================================================ 2 | --= 3 | --= wxLua/wxWidget bindings for Glóa 4 | --= Interface source: wxxml_xml.i 5 | --= 6 | --= Tested with: 7 | --= - wxLua 2.8.7.0 / wxWidgets 2.8.8 8 | --= 9 | --= Note: Most bindings have not been tested yet! 10 | --= 11 | --============================================================]] 12 | 13 | !import "wx/common" 14 | 15 | 16 | export wxXmlNodeType :: wxEnum 17 | export wxXML_ELEMENT_NODE: wxXmlNodeType : !foreign lua "wx.wxXML_ELEMENT_NODE" 18 | export wxXML_ATTRIBUTE_NODE: wxXmlNodeType : !foreign lua "wx.wxXML_ATTRIBUTE_NODE" 19 | export wxXML_TEXT_NODE: wxXmlNodeType : !foreign lua "wx.wxXML_TEXT_NODE" 20 | export wxXML_CDATA_SECTION_NODE: wxXmlNodeType : !foreign lua "wx.wxXML_CDATA_SECTION_NODE" 21 | export wxXML_ENTITY_REF_NODE: wxXmlNodeType : !foreign lua "wx.wxXML_ENTITY_REF_NODE" 22 | export wxXML_ENTITY_NODE: wxXmlNodeType : !foreign lua "wx.wxXML_ENTITY_NODE" 23 | export wxXML_PI_NODE: wxXmlNodeType : !foreign lua "wx.wxXML_PI_NODE" 24 | export wxXML_COMMENT_NODE: wxXmlNodeType : !foreign lua "wx.wxXML_COMMENT_NODE" 25 | export wxXML_DOCUMENT_NODE: wxXmlNodeType : !foreign lua "wx.wxXML_DOCUMENT_NODE" 26 | export wxXML_DOCUMENT_TYPE_NODE: wxXmlNodeType : !foreign lua "wx.wxXML_DOCUMENT_TYPE_NODE" 27 | export wxXML_DOCUMENT_FRAG_NODE: wxXmlNodeType : !foreign lua "wx.wxXML_DOCUMENT_FRAG_NODE" 28 | export wxXML_NOTATION_NODE: wxXmlNodeType : !foreign lua "wx.wxXML_NOTATION_NODE" 29 | export wxXML_HTML_DOCUMENT_NODE: wxXmlNodeType : !foreign lua "wx.wxXML_HTML_DOCUMENT_NODE" 30 | 31 | export wxXmlNode :: !foreign struct { 32 | using wxLuaUserdata, 33 | 34 | !call :: () -> wxXmlNode !foreign lua "wx.wxXmlNode", 35 | !call :: (type:wxXmlNodeType, name:wxString|string, content:wxString|string="") -> wxXmlNode !foreign lua "wx.wxXmlNode", 36 | !call :: (parent:wxXmlNode, type:wxXmlNodeType, name:wxString|string, content:wxString|string, props:wxXmlProperty, next:wxXmlNode) -> wxXmlNode !foreign lua "wx.wxXmlNode", 37 | 38 | AddChild :: (self:wxXmlNode, child:wxXmlNode) !foreign method "AddChild", 39 | InsertChild :: (self:wxXmlNode, child:wxXmlNode, before_node:wxXmlNode) !foreign method "InsertChild", 40 | RemoveChild :: (self:wxXmlNode, child:wxXmlNode) -> bool !foreign method "RemoveChild", 41 | AddProperty :: (self:wxXmlNode, name:wxString|string, value:wxString|string) !foreign method "AddProperty", 42 | DeleteProperty :: (self:wxXmlNode, name:wxString|string) -> bool !foreign method "DeleteProperty", 43 | GetType :: (self:wxXmlNode) -> wxXmlNodeType !foreign method "GetType", 44 | GetName :: (self:wxXmlNode) -> string !foreign method "GetName", 45 | GetContent :: (self:wxXmlNode) -> string !foreign method "GetContent", 46 | GetParent :: (self:wxXmlNode) -> wxXmlNode !foreign method "GetParent", 47 | GetNext :: (self:wxXmlNode) -> wxXmlNode !foreign method "GetNext", 48 | GetChildren :: (self:wxXmlNode) -> wxXmlNode !foreign method "GetChildren", 49 | GetProperties :: (self:wxXmlNode) -> wxXmlProperty !foreign method "GetProperties", 50 | GetPropValPtr :: (self:wxXmlNode, propName:wxString|string) -> bool, string !foreign method "GetPropValPtr", 51 | GetPropVal :: (self:wxXmlNode, propName:wxString|string, defaultVal:wxString|string) -> string !foreign method "GetPropVal", 52 | HasProp :: (self:wxXmlNode, propName:wxString|string) -> bool !foreign method "HasProp", 53 | SetType :: (self:wxXmlNode, type:wxXmlNodeType) !foreign method "SetType", 54 | SetName :: (self:wxXmlNode, name:wxString|string) !foreign method "SetName", 55 | SetContent :: (self:wxXmlNode, con:wxString|string) !foreign method "SetContent", 56 | SetParent :: (self:wxXmlNode, parent:wxXmlNode) !foreign method "SetParent", 57 | SetNext :: (self:wxXmlNode, next:wxXmlNode) !foreign method "SetNext", 58 | SetChildren :: (self:wxXmlNode, child:wxXmlNode) !foreign method "SetChildren", 59 | SetProperties :: (self:wxXmlNode, prop:wxXmlProperty) !foreign method "SetProperties", 60 | AddProperty :: (self:wxXmlNode, prop:wxXmlProperty) !foreign method "AddProperty", 61 | } 62 | 63 | export wxXmlProperty :: !foreign struct { 64 | using wxLuaUserdata, 65 | 66 | !call :: () -> wxXmlProperty !foreign lua "wx.wxXmlProperty", 67 | !call :: (name:wxString|string, value:wxString|string, next:wxXmlProperty) -> wxXmlProperty !foreign lua "wx.wxXmlProperty", 68 | 69 | GetName :: (self:wxXmlProperty) -> string !foreign method "GetName", 70 | GetValue :: (self:wxXmlProperty) -> string !foreign method "GetValue", 71 | GetNext :: (self:wxXmlProperty) -> wxXmlProperty !foreign method "GetNext", 72 | SetName :: (self:wxXmlProperty, name:wxString|string) !foreign method "SetName", 73 | SetValue :: (self:wxXmlProperty, value:wxString|string) !foreign method "SetValue", 74 | SetNext :: (self:wxXmlProperty, next:wxXmlProperty) !foreign method "SetNext", 75 | } 76 | 77 | export wxXmlDocument :: !foreign struct { 78 | using wxObject, 79 | 80 | !call :: () -> wxXmlDocument !foreign lua "wx.wxXmlDocument", 81 | !call :: (filename:wxString|string, encoding:wxString|string="UTF-8") -> wxXmlDocument !foreign lua "wx.wxXmlDocument", 82 | 83 | Load :: (self:wxXmlDocument, filename:wxString|string, encoding:wxString|string="UTF-8") -> bool !foreign method "Load", 84 | Save :: (self:wxXmlDocument, filename:wxString|string) -> bool !foreign method "Save", 85 | IsOk :: (self:wxXmlDocument) -> bool !foreign method "IsOk", 86 | GetRoot :: (self:wxXmlDocument) -> wxXmlNode !foreign method "GetRoot", 87 | GetVersion :: (self:wxXmlDocument) -> string !foreign method "GetVersion", 88 | GetFileEncoding :: (self:wxXmlDocument) -> string !foreign method "GetFileEncoding", 89 | SetRoot :: (self:wxXmlDocument, node:wxXmlNode) !foreign method "SetRoot", 90 | SetVersion :: (self:wxXmlDocument, version:wxString|string) !foreign method "SetVersion", 91 | SetFileEncoding :: (self:wxXmlDocument, encoding:wxString|string) !foreign method "SetFileEncoding", 92 | } 93 | -------------------------------------------------------------------------------- /modules/wx/wxbase_config.gloa: -------------------------------------------------------------------------------- 1 | --[[============================================================ 2 | --= 3 | --= wxLua/wxWidget bindings for Glóa 4 | --= Interface source: wxbase_config.i 5 | --= 6 | --= Tested with: 7 | --= - wxLua 2.8.7.0 / wxWidgets 2.8.8 8 | --= 9 | --= Note: Most bindings have not been tested yet! 10 | --= 11 | --============================================================]] 12 | 13 | !import "wx/common" 14 | 15 | 16 | export wxCONFIG_USE_LOCAL_FILE: wxEnum : !foreign lua "wx.wxCONFIG_USE_LOCAL_FILE" 17 | export wxCONFIG_USE_GLOBAL_FILE: wxEnum : !foreign lua "wx.wxCONFIG_USE_GLOBAL_FILE" 18 | export wxCONFIG_USE_RELATIVE_PATH: wxEnum : !foreign lua "wx.wxCONFIG_USE_RELATIVE_PATH" 19 | export wxCONFIG_USE_NO_ESCAPE_CHARACTERS: wxEnum : !foreign lua "wx.wxCONFIG_USE_NO_ESCAPE_CHARACTERS" 20 | export wxCONFIG_USE_SUBDIR: wxEnum : !foreign lua "wx.wxCONFIG_USE_SUBDIR" 21 | 22 | export wxConfigBase :: !foreign struct { 23 | using wxLuaUserdata, 24 | 25 | null: wxConfigBase : !foreign lua "wx.NULL", 26 | 27 | EntryType :: wxEnum, 28 | Type_Unknown: EntryType : !foreign lua "wx.wxConfigBase.Type_Unknown", 29 | Type_String: EntryType : !foreign lua "wx.wxConfigBase.Type_String", 30 | Type_Boolean: EntryType : !foreign lua "wx.wxConfigBase.Type_Boolean", 31 | Type_Integer: EntryType : !foreign lua "wx.wxConfigBase.Type_Integer", 32 | Type_Float: EntryType : !foreign lua "wx.wxConfigBase.Type_Float", 33 | 34 | Create :: () -> wxConfigBase !foreign lua "wx.wxConfigBase.Create", 35 | DontCreateOnDemand :: () !foreign lua "wx.wxConfigBase.DontCreateOnDemand", 36 | Get :: (CreateOnDemand:bool=true) -> wxConfigBase !foreign lua "wx.wxConfigBase.Get", 37 | Set :: (pConfig:wxConfigBase=wxConfigBase.null) -> wxConfigBase !foreign lua "wx.wxConfigBase.Set", 38 | 39 | DeleteAll :: (self:wxConfigBase) -> bool !foreign method "DeleteAll", 40 | DeleteEntry :: (self:wxConfigBase, key:wxString|string, bDeleteGroupIfEmpty:bool=true) -> bool !foreign method "DeleteEntry", 41 | DeleteGroup :: (self:wxConfigBase, key:wxString|string) -> bool !foreign method "DeleteGroup", 42 | Exists :: (self:wxConfigBase, strName:wxString|string) -> bool !foreign method "Exists", 43 | Flush :: (self:wxConfigBase, bCurrentOnly:bool=false) -> bool !foreign method "Flush", 44 | GetAppName :: (self:wxConfigBase) -> string !foreign method "GetAppName", 45 | GetEntryType :: (self:wxConfigBase, name:wxString|string) -> wxConfigBase.EntryType !foreign method "GetEntryType", 46 | GetFirstGroup :: (self:wxConfigBase) -> bool, string, int--[[long]] !foreign method "GetFirstGroup", 47 | GetFirstEntry :: (self:wxConfigBase) -> bool, string, int--[[long]] !foreign method "GetFirstEntry", 48 | GetNextGroup :: (self:wxConfigBase, index:int--[[long]]) -> bool, string, int--[[long]] !foreign method "GetNextGroup", 49 | GetNextEntry :: (self:wxConfigBase, index:int--[[long]]) -> bool, string, int--[[long]] !foreign method "GetNextEntry", 50 | GetNumberOfEntries :: (self:wxConfigBase, bRecursive:bool=false) -> int !foreign method "GetNumberOfEntries", 51 | GetNumberOfGroups :: (self:wxConfigBase, bRecursive:bool=false) -> int !foreign method "GetNumberOfGroups", 52 | GetPath :: (self:wxConfigBase) -> string !foreign method "GetPath", 53 | GetVendorName :: (self:wxConfigBase) -> string !foreign method "GetVendorName", 54 | HasEntry :: (self:wxConfigBase, strName:wxString|string) -> bool !foreign method "HasEntry", 55 | HasGroup :: (self:wxConfigBase, strName:wxString|string) -> bool !foreign method "HasGroup", 56 | IsExpandingEnvVars :: (self:wxConfigBase) -> bool !foreign method "IsExpandingEnvVars", 57 | IsRecordingDefaults :: (self:wxConfigBase) -> bool !foreign method "IsRecordingDefaults", 58 | Read :: (self:wxConfigBase, key:wxString|string, defaultVal:wxString|string="") -> bool, string !foreign method "Read", 59 | Read :: (self:wxConfigBase, key:wxString|string, defaultVal:float--[[double]]) -> bool, float--[[double]] !foreign method "Read", 60 | RenameEntry :: (self:wxConfigBase, oldName:wxString|string, newName:wxString|string) -> bool !foreign method "RenameEntry", 61 | RenameGroup :: (self:wxConfigBase, oldName:wxString|string, newName:wxString|string) -> bool !foreign method "RenameGroup", 62 | SetExpandEnvVars :: (self:wxConfigBase, bDoIt:bool=true) !foreign method "SetExpandEnvVars", 63 | SetPath :: (self:wxConfigBase, strPath:wxString|string) !foreign method "SetPath", 64 | SetRecordDefaults :: (self:wxConfigBase, bDoIt:bool=true) !foreign method "SetRecordDefaults", 65 | Write :: (self:wxConfigBase, key:wxString|string, value:wxString|string) -> bool !foreign method "Write", 66 | Write :: (self:wxConfigBase, key:wxString|string, value:float--[[double]]) -> bool !foreign method "Write", 67 | } 68 | 69 | export wxConfig :: !foreign struct { 70 | using wxConfigBase, 71 | 72 | !call :: (appName:wxString|string="", vendorName:wxString|string="", localFilename:wxString|string="", globalFilename:wxString|string="", style:int--[[long]]=0) -> wxConfig !foreign lua "wx.wxConfig", 73 | } 74 | 75 | export wxFileConfig :: !foreign struct { 76 | using wxConfigBase, 77 | 78 | !call :: (appName:wxString|string="", vendorName:wxString|string="", localFilename:wxString|string="", globalFilename:wxString|string="", style:int--[[long]]=0--[[bitwise(wxCONFIG_USE_LOCAL_FILE|wxCONFIG_USE_GLOBAL_FILE)]]) -> wxFileConfig !foreign lua "wx.wxFileConfig", 79 | 80 | SetUmask :: (self:wxFileConfig, mode:int) !foreign method "SetUmask", 81 | } 82 | 83 | export wxMemoryConfig :: !foreign struct { 84 | using wxFileConfig, 85 | 86 | !call :: () -> wxMemoryConfig !foreign lua "wx.wxMemoryConfig", 87 | } 88 | 89 | export wxConfigPathChanger :: !foreign struct { 90 | using wxLuaUserdata, 91 | 92 | !call :: (pContainer:wxConfigBase, strEntry:wxString|string) -> wxConfigPathChanger !foreign lua "wx.wxConfigPathChanger", 93 | 94 | Name :: (self:wxConfigPathChanger) -> string !foreign method "Name", 95 | UpdateIfDeleted :: (self:wxConfigPathChanger) !foreign method "UpdateIfDeleted", 96 | } 97 | -------------------------------------------------------------------------------- /src/messenger.luapart: -------------------------------------------------------------------------------- 1 | --[[============================================================ 2 | --= 3 | --= Messenger 4 | --= 5 | --= Structs here are reflected in modules/compiler.gloa and modules/preload.gloa 6 | --= Relevant enums are in messengerEnums.luapart 7 | --= 8 | --=------------------------------------------------------------- 9 | --= 10 | --= Glóa - a language that compiles into Lua 11 | --= by Marcus 'ReFreezed' Thunström 12 | --= 13 | --============================================================== 14 | 15 | ... 16 | 17 | --============================================================]] 18 | !recordLineNumber(@file, @line) 19 | 20 | local !struct"CompilerMessage"{ 21 | {`kind`, 0}, 22 | } 23 | 24 | local !struct"CompilerMessageFile:CompilerMessage"{ 25 | {`path`, ""}, 26 | } 27 | 28 | local !struct"CompilerMessageCompilationPhase:CompilerMessage"{ 29 | {`phase`, 0}, 30 | {`outputPath`, ""}, 31 | } 32 | 33 | local !struct"CompilerMessageCodeTypechecked:CompilerMessage"{ 34 | {`declaration`, nil}, -- CodeDeclaration 35 | } 36 | 37 | local MESSAGE_KIND_TO_STRUCT = { 38 | [!(MESSAGE_CODE_TYPECHECKED)] = CompilerMessageCodeTypechecked, 39 | [!(MESSAGE_COMPILATION_PHASE)] = CompilerMessageCompilationPhase, 40 | [!(MESSAGE_COMPLETE)] = CompilerMessage, 41 | [!(MESSAGE_FILE)] = CompilerMessageFile, 42 | } 43 | 44 | function _G.newMessage(messageKind) 45 | local Message = MESSAGE_KIND_TO_STRUCT[messageKind] or errorInternal("Incomplete: Handle messageKind=%d", messageKind) 46 | local message = Message() 47 | message.kind = messageKind 48 | return message 49 | end 50 | 51 | -- 52 | -- Public-facing type info 53 | -- 54 | 55 | function _G.getPublicType(state, typeInfo) 56 | local publicType = state.publicTypeInfoById[typeInfo.id] 57 | if publicType then return publicType end 58 | 59 | !ASSERT `typeInfo.isReady` 60 | !ASSERT `isTypePublic(typeInfo)` 61 | 62 | local tag = typeInfo.tag 63 | 64 | -- Note: These tables must be synced with preload and programWriter! 65 | 66 | if tag == !(TYPE_ARRAY) then 67 | local arraySig = typeInfo 68 | 69 | publicType = { 70 | tag = tag, 71 | id = arraySig.id, 72 | itemType = arraySig.itemType.id, 73 | } 74 | state.publicTypeInfoById[typeInfo.id] = publicType 75 | 76 | elseif tag == !(TYPE_VARARG) then 77 | local varargSig = typeInfo 78 | 79 | publicType = { 80 | tag = tag, 81 | id = varargSig.id, 82 | itemType = varargSig.itemType.id, 83 | } 84 | state.publicTypeInfoById[typeInfo.id] = publicType 85 | 86 | elseif tag == !(TYPE_FUNCTION) then 87 | local funcSig = typeInfo 88 | 89 | publicType = { 90 | tag = tag, 91 | id = funcSig.id, 92 | argumentsIn = {}, 93 | argumentsOut = {}, 94 | } 95 | state.publicTypeInfoById[typeInfo.id] = publicType 96 | 97 | for i, argType in ipairs(funcSig.argumentTypesIn) do 98 | publicType.argumentsIn[i] = {argumentType=argType.id} 99 | end 100 | for i, argType in ipairs(funcSig.argumentTypesOut) do 101 | publicType.argumentsOut[i] = {argumentType=argType.id} 102 | end 103 | 104 | elseif tag == !(TYPE_STRUCT) then 105 | local structInfo = typeInfo 106 | 107 | publicType = { 108 | tag = tag, 109 | id = structInfo.id, 110 | name = structInfo.name, 111 | kind = structInfo.kind, 112 | keyType = structInfo.keyType and structInfo.keyType.id or !(TYPE_VOID), 113 | valueType = structInfo.valueType and structInfo.valueType.id or !(TYPE_VOID), 114 | members = {}, 115 | } 116 | state.publicTypeInfoById[typeInfo.id] = publicType 117 | 118 | for i, member in ipairs(structInfo.members) do 119 | publicType.members[i] = {name=member.name, memberType=member.typeInfo.id} 120 | end 121 | 122 | elseif tag == !(TYPE_ENUM) then 123 | local enumInfo = typeInfo 124 | 125 | publicType = { 126 | tag = tag, 127 | id = enumInfo.id, 128 | name = enumInfo.name, 129 | memberType = enumInfo.memberTypeInfo.id, 130 | members = {}, 131 | } 132 | state.publicTypeInfoById[typeInfo.id] = publicType 133 | 134 | for i, member in ipairs(enumInfo.members) do 135 | publicType.members[i] = {name=member.name} 136 | end 137 | 138 | elseif tag == !(TYPE_COMPOUND) then 139 | local compound = typeInfo 140 | 141 | publicType = { 142 | tag = tag, 143 | id = compound.id, 144 | types = {}, 145 | } 146 | state.publicTypeInfoById[typeInfo.id] = publicType 147 | 148 | for i, compoundItem in ipairs(compound) do 149 | publicType.types[i] = compoundItem.id 150 | end 151 | 152 | elseif !!(CONST_SET{ -- :SimplePublicTypeInfo 153 | TYPE_ANY, 154 | TYPE_BOOL, 155 | TYPE_FLOAT, 156 | TYPE_INT, 157 | TYPE_NONE, 158 | TYPE_PLACEHOLDER, 159 | TYPE_STRING, 160 | TYPE_TABLE, 161 | TYPE_TYPE, 162 | TYPE_VOID, 163 | })[tag] then 164 | publicType = { 165 | tag = tag, 166 | id = typeInfo.id, 167 | -- No extra type-specific information. 168 | } 169 | state.publicTypeInfoById[typeInfo.id] = publicType 170 | 171 | else 172 | errorInternal("Incomplete: Generate PublicTypeInfo for type group '%s'.", TYPE_TAG_NAMES[tag]) 173 | end 174 | 175 | table.insert(state.publicTypeInfoIds, typeInfo.id) 176 | return publicType 177 | end 178 | 179 | -- 180 | -- Code nodes 181 | -- 182 | 183 | !struct"_CodeNode"{ 184 | {`kind`, 0}, -- CODE_* 185 | {`serial`, 0}, 186 | 187 | {`typeInfo`, nil}, -- PublicTypeInfo 188 | 189 | {`filepath`, ""}, 190 | {`lineNumber`, 0}, 191 | {`filePosition`, 0}, 192 | } 193 | 194 | _G.!struct"CodeDeclaration:_CodeNode"{ 195 | _overrides={{`kind`,CODE_DECLARATION}}, 196 | {`name`, ""}, 197 | {`expressions`, {}}, -- []CodeNode 198 | {`rootExpression`, nil}, -- CodeNode 199 | {`isConstant`, false}, 200 | {`notes`, {}}, -- []typeId 201 | } 202 | 203 | _G.!struct"CodeIdentifier:_CodeNode"{ 204 | _overrides={{`kind`,CODE_IDENTIFIER}}, 205 | {`name`, ""}, 206 | {`declaration`, nil}, -- CodeDeclaration 207 | } 208 | 209 | _G.!struct"CodeLiteral:_CodeNode"{ 210 | _overrides={{`kind`,CODE_LITERAL}}, 211 | {`value`, nil}, 212 | } 213 | 214 | _G.!struct"CodeOperator:_CodeNode"{ 215 | _overrides={{`kind`,CODE_OPERATOR_EXPRESSION}}, 216 | {`operator`, ""}, 217 | {`left`, nil}, -- CodeNode 218 | {`middle`, nil}, -- CodeNode 219 | {`right`, nil}, -- CodeNode 220 | } 221 | 222 | -- @Incomplete... 223 | -------------------------------------------------------------------------------- /modules/math/math.gloa: -------------------------------------------------------------------------------- 1 | --[[============================================================ 2 | --= 3 | --= Glóa math module 4 | --= 5 | --============================================================== 6 | 7 | HUGE 8 | NAN 9 | PI, TAU 10 | 11 | abs 12 | acos, asin, atan, cos, cosh, cos01, sin, sinh, sin01, tan, tanh 13 | ceil, floor, round 14 | clamp, clamp01 15 | distance, distanceSq 16 | exp, frexp, ldexp 17 | fmod 18 | getRandom, setRandomSeed 19 | getSign, getSign0 20 | lerp 21 | log, log10 22 | min, max 23 | moveTowards 24 | normalizeAngle, deltaAngle, angleDistance 25 | pow, powKeepSign 26 | splitFraction 27 | sqrt 28 | toDegrees, toRadians 29 | 30 | --============================================================]] 31 | 32 | export HUGE : float : 1/0 33 | export NAN : float : 0/0 34 | export PI : float : !foreign lua "math.pi" 35 | export TAU : float : !foreign lua "math.pi*2" 36 | 37 | export abs :: (x:float) -> float !foreign lua "math.abs" 38 | export abs :: (x:int) -> int !foreign lua "math.abs" 39 | 40 | export ceil :: (x:float) -> int !foreign lua "math.ceil" 41 | export floor :: (x:float) -> int !foreign lua "math.floor" 42 | export round :: (x:float) -> int { return floor(x+.5) } 43 | 44 | export min :: (n1,n2,...:float) -> float !foreign lua "math.min" 45 | export max :: (n1,n2,...:float) -> float !foreign lua "math.max" 46 | export min :: (n1,n2,...:int) -> int !foreign lua "math.min" 47 | export max :: (n1,n2,...:int) -> int !foreign lua "math.max" 48 | 49 | export clamp :: (x:int, low,high:int) -> int { return min(max(x, low), high) } 50 | export clamp :: (x:float, low,high:float) -> float { return min(max(x, low), high) } 51 | export clamp01 :: (x:float) -> float { return min(max(x, 0 ), 1 ) } 52 | 53 | export lerp :: (v1,v2:float, k:float) -> float { return v1+k*(v2-v1) } 54 | 55 | export damp :: (current:float, target:float, lambda:float, dt:float) -> float { 56 | -- http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/ 57 | return lerp(current, target, 1-exp(-lambda*dt)) 58 | -- return lerp(current, target, 1-smoothing^dt) 59 | } 60 | export damp :: (x1,y1:float, x2,y2:float, lambda:float, dt:float) -> float, float { 61 | local k = 1-exp(-lambda*dt) -- See damp() above. 62 | return lerp(x1, x2, k), lerp(y1, y2, k) 63 | } 64 | 65 | export fmod :: (x:float, divisor:float) -> float !foreign lua "math.fmod" 66 | export fmod :: (x:int, divisor:int) -> int !foreign lua "math.fmod" 67 | 68 | export splitFraction :: (x:float) -> (integral:int, fraction:float) !foreign lua "math.modf" 69 | 70 | export exp :: (power:float) -> float !foreign lua "math.exp" -- E^power 71 | export frexp :: (x:float) -> (mantissa:float, exponent:int) !foreign lua "math.frexp" -- x = mantissa*2^exponent 72 | export ldexp :: (mantissa:float, exponent:int) -> float !foreign lua "math.ldexp" -- x*2^exponent 73 | 74 | export log :: (x:float) -> float !foreign lua "math.log" 75 | export log10 :: (x:float) -> float !foreign lua "math.log10" 76 | -- export log :: (x:float, base:int) -> float { @Incomplete } 77 | 78 | export acos :: (x:float) -> float !foreign lua "math.acos" 79 | export asin :: (x:float) -> float !foreign lua "math.asin" 80 | export atan :: (x:float) -> float !foreign lua "math.atan" 81 | export atan :: (y:float, x:float) -> float !foreign lua "math.atan2" 82 | export cos :: (angle:float) -> float !foreign lua "math.cos" 83 | export cosh :: (x:float) -> float !foreign lua "math.cosh" 84 | export cos01 :: (angle:float) -> float { return .5+.5*cos(angle) } 85 | export sin :: (angle:float) -> float !foreign lua "math.sin" 86 | export sinh :: (x:float) -> float !foreign lua "math.sinh" 87 | export sin01 :: (angle:float) -> float { return .5+.5*sin(angle) } 88 | export tan :: (angle:float) -> float !foreign lua "math.tan" 89 | export tanh :: (x:float) -> float !foreign lua "math.tanh" 90 | 91 | export toDegrees :: (radians:float) -> (degrees:float) !foreign lua "math.deg" 92 | export toRadians :: (degrees:float) -> (radians:float) !foreign lua "math.rad" 93 | 94 | export sqrt :: (x:float) -> float !foreign lua "math.sqrt" 95 | export pow :: (x,power:float) -> float !foreign lua "math.pow" -- '^' should be used instead whenever possible! 96 | export powKeepSign :: (x,power:float) -> float { return abs(x) ^ power * getSign(x) } 97 | 98 | export getRandom :: ( high:int) -> int !foreign lua "math.random" -- Same as getRandom(1, high) 99 | export getRandom :: (low,high:int) -> int !foreign lua "math.random" 100 | 101 | export getRandom :: ( ) -> float !foreign lua "math.random" 102 | export getRandom :: ( high:float) -> float { return high * getRandom() } 103 | export getRandom :: (low,high:float) -> float { return low + (high-low) * getRandom() } 104 | 105 | export setRandomSeed :: (seed:int) { 106 | local _setRandomSeed :: (seed:int) !foreign lua "math.randomseed" 107 | _setRandomSeed(seed) 108 | getRandom() -- Gets rid of the lingering random number from the last seed. Why is this even a thing, Lua... 109 | } 110 | 111 | export moveTowards :: (current,target:float, speed:float) -> (value:float, targetReached:bool) { 112 | if current < target 113 | current = min(current+speed, target) 114 | elseif current > target 115 | current = max(current-speed, target) 116 | return current, (current == target) 117 | } 118 | 119 | export distance :: (x1,y1:float, x2,y2:float) -> float { 120 | return sqrt(distanceSq(x1,y1, x2,y2)) 121 | } 122 | export distance :: (x1,y1,z1:float, x2,y2,z2:float) -> float { 123 | return sqrt(distanceSq(x1,y1,z1, x2,y2,z2)) 124 | } 125 | 126 | export distanceSq :: (x1,y1:float, x2,y2:float) -> float { 127 | local dx = x2-x1 128 | local dy = y2-y1 129 | return dx*dx + dy*dy 130 | } 131 | export distanceSq :: (x1,y1,z1:float, x2,y2,z2:float) -> float { 132 | local dx = x2-x1 133 | local dy = y2-y1 134 | local dz = z2-z1 135 | return dx*dx + dy*dy + dz*dz 136 | } 137 | 138 | export getSign :: (n:float) -> int { return n<0 ? -1 : 1 } 139 | export getSign0 :: (n:float) -> int { return n<0 ? -1 : n>0 ? 1 : 0 } 140 | 141 | export normalizeAngle :: (angle:float) -> float { 142 | return (angle+PI)%TAU-PI 143 | } 144 | export deltaAngle :: (sourceAngle:float, angle:float) -> float { 145 | local delta = angle-sourceAngle 146 | return atan(sin(delta), cos(delta)) 147 | } 148 | export angleDistance :: (angleA,angleB:float) -> float { 149 | return abs(deltaAngle(angleA, angleB)) 150 | } 151 | -------------------------------------------------------------------------------- /modules/wx/wxlua.gloa: -------------------------------------------------------------------------------- 1 | --[[============================================================ 2 | --= 3 | --= wxLua/wxWidget bindings for Glóa 4 | --= Interface source: wxlua.i 5 | --= 6 | --= Tested with: 7 | --= - wxLua 2.8.7.0 / wxWidgets 2.8.8 8 | --= 9 | --= Note: Most bindings have not been tested yet! 10 | --= 11 | --============================================================]] 12 | 13 | !import "wx/common" 14 | !import "wx/wxcore_appframe" 15 | !import "wx/wxcore_event" 16 | 17 | export wxLUA_MAJOR_VERSION: int : !foreign lua "wxlua.wxLUA_MAJOR_VERSION" 18 | export wxLUA_MINOR_VERSION: int : !foreign lua "wxlua.wxLUA_MINOR_VERSION" 19 | export wxLUA_RELEASE_NUMBER: int : !foreign lua "wxlua.wxLUA_RELEASE_NUMBER" 20 | export wxLUA_SUBRELEASE_NUMBER: int : !foreign lua "wxlua.wxLUA_SUBRELEASE_NUMBER" 21 | export WXLUA_TNONE: int : !foreign lua "wxlua.WXLUA_TNONE" 22 | export WXLUA_TNIL: int : !foreign lua "wxlua.WXLUA_TNIL" 23 | export WXLUA_TBOOLEAN: int : !foreign lua "wxlua.WXLUA_TBOOLEAN" 24 | export WXLUA_TLIGHTUSERDATA: int : !foreign lua "wxlua.WXLUA_TLIGHTUSERDATA" 25 | export WXLUA_TNUMBER: int : !foreign lua "wxlua.WXLUA_TNUMBER" 26 | export WXLUA_TSTRING: int : !foreign lua "wxlua.WXLUA_TSTRING" 27 | export WXLUA_TTABLE: int : !foreign lua "wxlua.WXLUA_TTABLE" 28 | export WXLUA_TFUNCTION: int : !foreign lua "wxlua.WXLUA_TFUNCTION" 29 | export WXLUA_TUSERDATA: int : !foreign lua "wxlua.WXLUA_TUSERDATA" 30 | export WXLUA_TTHREAD: int : !foreign lua "wxlua.WXLUA_TTHREAD" 31 | export WXLUA_TINTEGER: int : !foreign lua "wxlua.WXLUA_TINTEGER" 32 | export WXLUA_TCFUNCTION: int : !foreign lua "wxlua.WXLUA_TCFUNCTION" 33 | export WXLUA_T_MAX: int : !foreign lua "wxlua.WXLUA_T_MAX" 34 | export LUA_TNONE: int : !foreign lua "wxlua.LUA_TNONE" 35 | export LUA_TNIL: int : !foreign lua "wxlua.LUA_TNIL" 36 | export LUA_TBOOLEAN: int : !foreign lua "wxlua.LUA_TBOOLEAN" 37 | export LUA_TLIGHTUSERDATA: int : !foreign lua "wxlua.LUA_TLIGHTUSERDATA" 38 | export LUA_TNUMBER: int : !foreign lua "wxlua.LUA_TNUMBER" 39 | export LUA_TSTRING: int : !foreign lua "wxlua.LUA_TSTRING" 40 | export LUA_TTABLE: int : !foreign lua "wxlua.LUA_TTABLE" 41 | export LUA_TFUNCTION: int : !foreign lua "wxlua.LUA_TFUNCTION" 42 | export LUA_TUSERDATA: int : !foreign lua "wxlua.LUA_TUSERDATA" 43 | export LUA_TTHREAD: int : !foreign lua "wxlua.LUA_TTHREAD" 44 | export wxLUA_VERSION_STRING: string : !foreign lua "wxlua.wxLUA_VERSION_STRING" 45 | 46 | export wxLuaMethod_Type :: wxEnum 47 | export WXLUAMETHOD_CONSTRUCTOR: wxLuaMethod_Type : !foreign lua "wxlua.WXLUAMETHOD_CONSTRUCTOR" 48 | export WXLUAMETHOD_METHOD: wxLuaMethod_Type : !foreign lua "wxlua.WXLUAMETHOD_METHOD" 49 | export WXLUAMETHOD_CFUNCTION: wxLuaMethod_Type : !foreign lua "wxlua.WXLUAMETHOD_CFUNCTION" 50 | export WXLUAMETHOD_GETPROP: wxLuaMethod_Type : !foreign lua "wxlua.WXLUAMETHOD_GETPROP" 51 | export WXLUAMETHOD_SETPROP: wxLuaMethod_Type : !foreign lua "wxlua.WXLUAMETHOD_SETPROP" 52 | export WXLUAMETHOD_STATIC: wxLuaMethod_Type : !foreign lua "wxlua.WXLUAMETHOD_STATIC" 53 | export WXLUAMETHOD_DELETE: wxLuaMethod_Type : !foreign lua "wxlua.WXLUAMETHOD_DELETE" 54 | export WXLUAMETHOD_CHECKED_OVERLOAD: wxLuaMethod_Type : !foreign lua "wxlua.WXLUAMETHOD_CHECKED_OVERLOAD" 55 | 56 | export wxLuaObject_Type :: wxEnum 57 | export wxLUAOBJECT_NONE: wxLuaObject_Type : !foreign lua "wxlua.wxLUAOBJECT_NONE" 58 | export wxLUAOBJECT_BOOL: wxLuaObject_Type : !foreign lua "wxlua.wxLUAOBJECT_BOOL" 59 | export wxLUAOBJECT_INT: wxLuaObject_Type : !foreign lua "wxlua.wxLUAOBJECT_INT" 60 | export wxLUAOBJECT_STRING: wxLuaObject_Type : !foreign lua "wxlua.wxLUAOBJECT_STRING" 61 | export wxLUAOBJECT_ARRAYINT: wxLuaObject_Type : !foreign lua "wxlua.wxLUAOBJECT_ARRAYINT" 62 | 63 | export wxLuaState :: !foreign struct { 64 | using wxObject, 65 | } 66 | 67 | export wxLuaObject :: !foreign struct { 68 | using wxObject, 69 | 70 | null: wxLuaObject : !foreign lua "wx.NULL", 71 | 72 | !call :: (arg1:any) -> wxLuaObject !foreign lua "wxlua.wxLuaObject", 73 | 74 | SetObject :: (self:wxLuaObject, arg1:any) !foreign method "SetObject", 75 | GetObject :: (self:wxLuaObject) -> any !foreign method "GetObject", 76 | GetAllocationFlag :: (self:wxLuaObject) -> int !foreign method "GetAllocationFlag", 77 | } 78 | 79 | export wxLUA_CHECK_VERSION :: (major:int, minor:int, release:int) -> bool !foreign lua "wxlua.wxLUA_CHECK_VERSION" 80 | export wxLUA_CHECK_VERSION_FULL :: (major:int, minor:int, release:int, subrel:int) -> bool !foreign lua "wxlua.wxLUA_CHECK_VERSION_FULL" 81 | export CompileLuaScript :: (luaScript:wxString|string, fileName:wxString|string) -> (\return:int, err_msg:string, line_number:int) !foreign lua "wxlua.CompileLuaScript" 82 | export GetTrackedWindowInfo :: (as_string:bool=false) -> ([]wxTopLevelWindow)|([]string) !foreign lua "wxlua.GetTrackedWindowInfo" 83 | export GetGCUserdataInfo :: (as_string:bool=false) -> ([]wxLuaUserdata)|([]string) !foreign lua "wxlua.GetGCUserdataInfo" 84 | export GetTrackedObjectInfo :: (as_string:bool=false) -> ([]wxLuaUserdata)|([]string) !foreign lua "wxlua.GetTrackedObjectInfo" 85 | export GetTrackedEventCallbackInfo :: (as_string:bool=false) -> ([](event:wxEvent)->void)|([]string) !foreign lua "wxlua.GetTrackedEventCallbackInfo" 86 | export GetTrackedWinDestroyCallbackInfo :: (as_string:bool=false) -> ([]wxLuaUserdata)|([]string) !foreign lua "wxlua.GetTrackedWinDestroyCallbackInfo" 87 | export isgcobject :: (object:wxLuaUserdata--[[void*]]) -> bool !foreign lua "wxlua.isgcobject" 88 | export istrackedobject :: (object:wxLuaUserdata--[[void*]]) -> bool !foreign lua "wxlua.istrackedobject" 89 | export isrefed :: (object:wxLuaUserdata--[[void*]]) -> bool !foreign lua "wxlua.isrefed" 90 | export ungcobject :: (object:wxLuaUserdata--[[void*]]) -> bool !foreign lua "wxlua.ungcobject" 91 | export iswxluatype :: (luatype:int, wxluaarg_tag:int) -> int !foreign lua "wxlua.iswxluatype" 92 | export type :: (arg1:any) -> (wxlua_typename:string, wxlua_typenum:int, lua_typename:string, lua_typenum:int) !foreign lua "wxlua.type" 93 | export typename :: (wxluaarg_tag:int) -> string !foreign lua "wxlua.typename" 94 | export GetBindings :: () -> []table--[[wxLuaBinding]] !foreign lua "wxlua.GetBindings" 95 | -------------------------------------------------------------------------------- /src/compilerApi.luapart: -------------------------------------------------------------------------------- 1 | --[[============================================================ 2 | --= 3 | --= Compiler API 4 | --= 5 | --= Everything in compilerApi is reflected in modules/compiler.gloa 6 | --= 7 | --=------------------------------------------------------------- 8 | --= 9 | --= Glóa - a language that compiles into Lua 10 | --= by Marcus 'ReFreezed' Thunström 11 | --= 12 | --============================================================== 13 | 14 | compile 15 | getBuildOptions, setBuildOptions 16 | getCompilerArguments 17 | getProjectDirectory 18 | 19 | --============================================================]] 20 | !recordLineNumber(@file, @line) 21 | 22 | local function getCurrentCompilationState() 23 | !( 24 | -- Level 1 = this function 25 | -- Level 2 = function in this file 26 | -- Level 3 = user's metaprogram (hopefully!) 27 | local LEVEL = 3 28 | ) 29 | return getfenv(!(LEVEL))._STATE or errorInternal("Unknown environment.") 30 | end 31 | 32 | _G.compilerApi = {} 33 | 34 | 35 | 36 | -- @Incomplete: Make projectDirectory an optional argument. 37 | function compilerApi.compile(path) 38 | local state = getCurrentCompilationState() 39 | 40 | if not (isPathAbsolute(path) or rootDirectory ~= "") then -- @Cleanup: Don't check rootDirectory here. 41 | path = (state.projectDirectory.."/"..path):gsub("^%./", "") 42 | end 43 | 44 | compileProgram(path) 45 | end 46 | 47 | 48 | 49 | -- options = getBuildOptions( [ state=current ] ) 50 | function compilerApi.getBuildOptions(state) 51 | state = state or getCurrentCompilationState() 52 | 53 | local options = { 54 | -- See BuildOptions in modules/compiler.gloa 55 | outputType = state.settings.outputType, 56 | outputFilePath = state.settings.outputFilePath, 57 | entryPointName = state.settings.entryPointName, 58 | } 59 | 60 | return options 61 | end 62 | 63 | -- setBuildOptions( [ state=current, ] options ) 64 | function compilerApi.setBuildOptions(state, options) 65 | if not options then 66 | state, options = getCurrentCompilationState(), state 67 | end 68 | 69 | if options.outputType ~= !(OUTPUT_TYPE_NONE) and options.outputFilePath == "" then 70 | error("options.outputFilePath is empty.", 2) 71 | elseif options.outputType == !(OUTPUT_TYPE_LUA_APP) and options.entryPointName == "" then 72 | error("options.entryPointName is empty.", 2) 73 | end 74 | 75 | state.settings.outputType = options.outputType 76 | state.settings.outputFilePath = options.outputFilePath 77 | state.settings.entryPointName = options.entryPointName 78 | end 79 | 80 | 81 | 82 | function compilerApi.getProjectDirectory() 83 | return getCurrentCompilationState().projectDirectory 84 | end 85 | 86 | 87 | 88 | function compilerApi.getCompilerArguments() 89 | return {unpack(compilerArguments)} 90 | end 91 | 92 | 93 | 94 | function compilerApi.compilerReportError(filename, lineNumber, column, message) 95 | local state = getCurrentCompilationState() 96 | errorInternal("@Incomplete: compilerReportError") 97 | end 98 | 99 | 100 | 101 | -- @Incomplete: Make projectDirectory an optional argument. 102 | function compilerApi.newCompilation(path) 103 | if not (isPathAbsolute(path) or rootDirectory ~= "") then -- @Cleanup: Don't check rootDirectory here. 104 | path = (getCurrentCompilationState().projectDirectory.."/"..path):gsub("^%./", "") 105 | end 106 | 107 | local state = compilationInitState(path) 108 | state.sendMessages = true 109 | return state 110 | end 111 | 112 | !( 113 | local PHASE_START = 0 114 | local PHASE_PIPES = 1 115 | local PHASE_OUTPUT_PRE = 2 116 | local PHASE_OUTPUT_POST = 3 117 | local PHASE_COMPLETE = 4 118 | ) 119 | 120 | -- finished, message = compilerApi.compilerWaitForMessage( state ) 121 | function compilerApi.compilerWaitForMessage(state) 122 | -- 123 | -- Not sure if the message queueing system is any good. It may be preferred to send 124 | -- messages as they appear instead of queueing them. Maybe use coroutines here? 125 | -- 126 | !local RETURN_NEXT_MESSAGE = trimTemplate` 127 | state.nextMessageToSend = state.nextMessageToSend+1 128 | return true, state.messages[state.nextMessageToSend-1] 129 | ` 130 | !local MAYBE_RETURN_NEXT_MESSAGE = trimTemplate` 131 | local message = state.messages[state.nextMessageToSend] 132 | if message then 133 | state.nextMessageToSend = state.nextMessageToSend+1 134 | return true, message 135 | end 136 | ` 137 | 138 | !!(MAYBE_RETURN_NEXT_MESSAGE) 139 | 140 | if state.phase == !(PHASE_START) then 141 | compilationStart(state) 142 | addToQueueRecursively(state, state.globalScope) 143 | 144 | -- @UX: We get this message after only the first file has been parsed, 145 | -- which is too early! (Not sure when exactly it should be sent though 146 | -- as more parsing may happen because of a static if somewhere. Maybe 147 | -- the message is actually pretty useless.) 148 | state.phase = state.phase+1 149 | local message = newMessage(!(MESSAGE_COMPILATION_PHASE)) 150 | message.phase = !(COMPILATION_PHASE_SOURCE_CODE_PARSED) 151 | table.insert(state.messages, message) 152 | !!(RETURN_NEXT_MESSAGE) 153 | end 154 | 155 | if state.phase == !(PHASE_PIPES) then 156 | while true do 157 | if compilationDoOneCycle(state) then break end 158 | !!(MAYBE_RETURN_NEXT_MESSAGE) 159 | end 160 | 161 | state.phase = state.phase+1 162 | !!(MAYBE_RETURN_NEXT_MESSAGE) 163 | end 164 | 165 | if state.phase == !(PHASE_OUTPUT_PRE) then 166 | if state.settings.outputType == !(OUTPUT_TYPE_NONE) then 167 | state.phase = state.phase+1 168 | 169 | else 170 | state.phase = state.phase+1 171 | local message = newMessage(!(MESSAGE_COMPILATION_PHASE)) 172 | message.phase = !(COMPILATION_PHASE_PRE_WRITE_OUTPUT) 173 | message.outputPath = state.settings.outputFilePath 174 | table.insert(state.messages, message) 175 | !!(RETURN_NEXT_MESSAGE) 176 | end 177 | end 178 | 179 | if state.phase == !(PHASE_OUTPUT_POST) then 180 | if state.settings.outputType == !(OUTPUT_TYPE_NONE) then 181 | state.phase = state.phase+1 182 | 183 | else 184 | maybeWriteProgram(state) 185 | 186 | state.phase = state.phase+1 187 | local message = newMessage(!(MESSAGE_COMPILATION_PHASE)) 188 | message.phase = !(COMPILATION_PHASE_POST_WRITE_OUTPUT) 189 | message.outputPath = state.settings.outputFilePath 190 | table.insert(state.messages, message) 191 | !!(RETURN_NEXT_MESSAGE) 192 | end 193 | end 194 | 195 | if state.phase == !(PHASE_COMPLETE) then 196 | state.phase = state.phase+1 197 | 198 | local message = newMessage(!(MESSAGE_COMPLETE)) 199 | table.insert(state.messages, message) 200 | !!(RETURN_NEXT_MESSAGE) 201 | end 202 | 203 | return false, nil -- Compilation has finished! 204 | end 205 | 206 | function compilerApi.compilerFinish(state) 207 | local waitForMessage = compilerApi.compilerWaitForMessage 208 | 209 | while waitForMessage(state) do --[[void]] end 210 | end 211 | 212 | 213 | -------------------------------------------------------------------------------- /modules/loveRevised/math.gloa: -------------------------------------------------------------------------------- 1 | --[[============================================================ 2 | --= 3 | --= LÖVE bindings (love2d.org) 4 | --= love.math 5 | --= 6 | --= Supported versions: 11.3 7 | --= 8 | --============================================================== 9 | 10 | bytesToColor, colorToBytes 11 | gammaToLinear, linearToGamma 12 | getRandomSeed, setRandomSeed 13 | getRandomState, setRandomState 14 | isConvex 15 | newBezierCurve 16 | newRandomGenerator 17 | newTransform 18 | noise 19 | random, randomNormal 20 | triangulate 21 | 22 | -- Types: 23 | BezierCurve 24 | CompressedData 25 | RandomGenerator 26 | Transform 27 | 28 | --============================================================]] 29 | 30 | !import "loveRevised/basic" 31 | 32 | 33 | 34 | ---------------------------------------------------------------- 35 | -- Types and enums. 36 | ---------------------------------------------------------------- 37 | 38 | export BezierCurve :: !foreign struct { 39 | using Object, 40 | 41 | getControlPoint :: (curve:BezierCurve, index:int) -> (x,y:float) !foreign method "getControlPoint", 42 | setControlPoint :: (curve:BezierCurve, index:int, x,y:float) !foreign method "setControlPoint", 43 | insertControlPoint :: (curve:BezierCurve, x,y:float, i=-1) !foreign method "insertControlPoint", 44 | removeControlPoint :: (curve:BezierCurve, index:int) !foreign method "removeControlPoint", 45 | 46 | evaluate :: (curve:BezierCurve, v:float) -> (x,y:float) !foreign method "evaluate", 47 | 48 | getControlPointCount :: (curve:BezierCurve) -> int !foreign method "getControlPointCount", 49 | getDegree :: (curve:BezierCurve) -> int !foreign method "getDegree", 50 | 51 | getDerivative :: (curve:BezierCurve) -> BezierCurve !foreign method "getDerivative", 52 | getSegment :: (curve:BezierCurve, start,end:float) -> BezierCurve !foreign method "getSegment", 53 | 54 | -- points = {x1,y1, x2,y2, ...} 55 | render :: (curve:BezierCurve, depth=5) -> (points:[]float) !foreign method "render", 56 | render :: (curve:BezierCurve, start,end:float, depth=5) -> (points:[]float) !foreign method "renderSegment", 57 | 58 | curveRotate :: (curve:BezierCurve, angle:float, ox,oy=0.0) !foreign method "rotate", 59 | curveScale :: (curve:BezierCurve, scale:float, ox,oy=0.0) !foreign method "scale", 60 | curveTranslate :: (curve:BezierCurve, dx,dy:float) !foreign method "translate", 61 | } 62 | 63 | -- @Incomplete: 64 | export CompressedData :: !foreign struct { using Object } 65 | export RandomGenerator :: !foreign struct { using Object } 66 | export Transform :: !foreign struct { using Object } 67 | 68 | 69 | 70 | ---------------------------------------------------------------- 71 | -- Functions. 72 | ---------------------------------------------------------------- 73 | 74 | export bytesToColor :: (br,bg,bb:int) -> (r,g,b:float) !foreign lua "love.math.colorFromBytes" 75 | export bytesToColor :: (br,bg,bb,ba:int) -> (r,g,b,a:float) !foreign lua "love.math.colorFromBytes" 76 | export colorToBytes :: (r,g,b:float) -> (br,bg,bb:int) !foreign lua "love.math.colorToBytes" 77 | export colorToBytes :: (r,g,b,a:float) -> (br,bg,bb,ba:int) !foreign lua "love.math.colorToBytes" 78 | 79 | export gammaToLinear :: (gammaR,gammaG,gammaB:float) -> (linearR,linearG,linearB:float) !foreign lua "love.math.gammaToLinear" 80 | export gammaToLinear :: (gammaRgb:[]float) -> (linearR,linearG,linearB:float) !foreign lua "love.math.gammaToLinear" 81 | export gammaToLinear :: (gammaComponent:float) -> (linearComponent:float) !foreign lua "love.math.gammaToLinear" 82 | export linearToGamma :: (linearR,linearG,linearB:float) -> (gammaR,gammaG,gammaB:float) !foreign lua "love.math.linearToGamma" 83 | export linearToGamma :: (linearRgb:[]float) -> (gammaR,gammaG,gammaB:float) !foreign lua "love.math.linearToGamma" 84 | export linearToGamma :: (linearComponent:float) -> (gammaComponent:float) !foreign lua "love.math.linearToGamma" 85 | 86 | -- polygonVertices = {x1,y1, x2,y2, x3,y3, ...} 87 | export isConvex :: (polygonVertices:[]float) -> bool !foreign lua "love.math.isConvex" 88 | export isConvex :: (x1,y1,x2,y2,x3,y3,...:float) -> bool !foreign lua "love.math.isConvex" 89 | 90 | -- polygonVertices = {x1,y1, x2,y2, x3,y3, ...} 91 | -- triangles = {{x1,y1, x2,y2, x3,y3}, {x1,y1, x2,y2, x3,y3}, ...} 92 | export triangulate :: (polygonVertices:[]float) -> (triangles:[][]float) !foreign lua "love.math.triangulate" 93 | export triangulate :: (x1,y1,x2,y2,x3,y3,...:float) -> (triangles:[][]float) !foreign lua "love.math.triangulate" 94 | 95 | -- vertices = {x1,y1, x2,y2, x3,y3, ...} 96 | export newBezierCurve :: (vertices:[]float) -> BezierCurve !foreign lua "love.math.newBezierCurve" 97 | export newBezierCurve :: (x1,y1,x2,y2,x3,y3,...:float) -> BezierCurve !foreign lua "love.math.newBezierCurve" 98 | 99 | export newTransform :: () -> Transform !foreign lua "love.math.newTransform" 100 | export newTransform :: (x,y:float, r=0.0, sx=1.0,sy=sx, ox,oy=0.0, kx,ky=0.0) -> Transform !foreign lua "love.math.newTransform" 101 | 102 | export noise :: (x:float) -> (value:float) !foreign lua "love.math.noise" -- Simplex noise. 103 | export noise :: (x,y:float) -> (value:float) !foreign lua "love.math.noise" -- Simplex noise. 104 | export noise :: (x,y,z:float) -> (value:float) !foreign lua "love.math.noise" -- Perlin noise. 105 | export noise :: (x,y,z,w:float) -> (value:float) !foreign lua "love.math.noise" -- Perlin noise. 106 | 107 | export random :: ( high:int) -> int !foreign lua "love.math.random" -- Same as random(1, high) 108 | export random :: (low,high:int) -> int !foreign lua "love.math.random" 109 | 110 | export random :: ( ) -> float !foreign lua "love.math.random" 111 | export random :: ( high:float) -> float { return high * random() } -- Same as random(0.0, high) 112 | export random :: (low,high:float) -> float { return low + (high-low) * random() } 113 | 114 | export randomNormal :: (standardDeviation=1.0, mean=0.0) -> float !foreign lua "love.math.randomNormal" 115 | 116 | export getRandomSeed :: () -> (seedLow32Bits,seedHigh32Bits:int) !foreign lua "love.math.getRandomSeed" 117 | export setRandomSeed :: (seed:int) !foreign lua "love.math.setRandomSeed" -- The number must be in range 0..(2^53-1) 118 | export setRandomSeed :: (seedLow32Bits,seedHigh32Bits:int) !foreign lua "love.math.setRandomSeed" -- The numbers must be in range 0..(2^32-1) 119 | 120 | export getRandomState :: () -> string !foreign lua "love.math.getRandomState" 121 | export setRandomState :: (state:string) !foreign lua "love.math.setRandomState" 122 | 123 | export newRandomGenerator :: () -> RandomGenerator !foreign lua "love.math.newRandomGenerator" 124 | export newRandomGenerator :: (seed:int) -> RandomGenerator !foreign lua "love.math.newRandomGenerator" 125 | export newRandomGenerator :: (seedLow32Bits,seedHigh32Bits:int) -> RandomGenerator !foreign lua "love.math.newRandomGenerator" 126 | -------------------------------------------------------------------------------- /modules/color.gloa: -------------------------------------------------------------------------------- 1 | --[[============================================================ 2 | --= 3 | --= Glóa color module 4 | --= 5 | --============================================================== 6 | 7 | rgbToHsl, hslToRgb 8 | rgbToHsp, hspToRgb 9 | rgbToHsv, hsvToRgb 10 | 11 | --============================================================]] 12 | 13 | local math :: !import "math" 14 | 15 | 16 | 17 | -- 18 | -- HSL (hue, saturation, lightness) 19 | -- 20 | 21 | export rgbToHsl :: (rgb:[]float) -> (h,s,l:float) { 22 | return rgbToHsl(rgb[1], rgb[2], rgb[3]) 23 | } 24 | export rgbToHsl :: (r,g,b:float) -> (h,s,l:float) { 25 | local max = math.max(r, g, b) 26 | local min = math.min(r, g, b) 27 | 28 | local h, s, l: float = NULL, NULL, NULL 29 | l = (max+min)/2 30 | 31 | if max == min { 32 | h, s = 0, 0 -- Achromatic. 33 | } else { 34 | local d = max-min 35 | s = (l > .5) ? d/(2-max-min) : d/(max+min) 36 | 37 | if max == r { 38 | h = (g-b)/d 39 | if g < b { h = h+6 } 40 | } elseif max == g { 41 | h = (b-r)/d+2 42 | } elseif max == b { 43 | h = (r-g)/d+4 44 | } 45 | 46 | h = h/6 47 | } 48 | 49 | return h, s, l 50 | } 51 | 52 | export hslToRgb :: (hsl:[]float) -> (r,g,b:float) { 53 | return hslToRgb(hsl[1], hsl[2], hsl[3]) 54 | } 55 | export hslToRgb :: (h,s,l:float) -> (r,g,b:float) { 56 | local r, g, b: float = NULL, NULL, NULL 57 | 58 | if s == 0 { 59 | r, g, b = l, l, l -- Achromatic. 60 | } else { 61 | local q = (l < .5) ? l*(1+s) : l+s-l*s 62 | local p = 2*l-q 63 | 64 | local hue2rgb :: (p,q,t:float) -> float { 65 | if t < 0 t = t+1 66 | if t > 1 t = t-1 67 | if t < 1/6 return p+(q-p)*6*t 68 | if t < 1/2 return q 69 | if t < 2/3 return p+(q-p)*(2/3-t)*6 70 | return p 71 | } 72 | r = hue2rgb(p, q, h+1/3) 73 | g = hue2rgb(p, q, h) 74 | b = hue2rgb(p, q, h-1/3) 75 | } 76 | 77 | return r, g, b 78 | } 79 | 80 | 81 | 82 | -- 83 | -- HSV (hue, saturation, value) 84 | -- 85 | 86 | export rgbToHsv :: (rgb:[]float) -> (h,s,v:float) { 87 | return rgbToHsv(rgb[1], rgb[2], rgb[3]) 88 | } 89 | export rgbToHsv :: (r,g,b:float) -> (h,s,v:float) { 90 | local max, min = math.max(r, g, b), math.min(r, g, b) 91 | local h, s, v: float = NULL, NULL, NULL 92 | v = max 93 | 94 | local d = max-min 95 | s = (max == 0) ? .0 : d/max 96 | 97 | if max == min { 98 | h = 0 -- Achromatic. 99 | } else { 100 | if max == r { 101 | h = (g-b)/d 102 | if g < b { h = h+6 } 103 | } elseif max == g { 104 | h = (b-r)/d+2 105 | } elseif max == b { 106 | h = (r-g)/d+4 107 | } 108 | h = h/6 109 | } 110 | 111 | return h, s, v 112 | } 113 | 114 | export hsvToRgb :: (hsv:[]float) -> (r,g,b:float) { 115 | return hsvToRgb(hsv[1], hsv[2], hsv[3]) 116 | } 117 | export hsvToRgb :: (h,s,v:float) -> (r,g,b:float) { 118 | local r, g, b: float = NULL, NULL, NULL 119 | 120 | local i = math.floor(h*6) 121 | local f = h*6-i 122 | local p = v*(1-s) 123 | local q = v*(1-f*s) 124 | local t = v*(1-(1-f)*s) 125 | 126 | i = i%6 127 | 128 | if i == 0 r, g, b = v, t, p 129 | elseif i == 1 r, g, b = q, v, p 130 | elseif i == 2 r, g, b = p, v, t 131 | elseif i == 3 r, g, b = p, q, v 132 | elseif i == 4 r, g, b = t, p, v 133 | else r, g, b = v, p, q 134 | 135 | return r, g, b 136 | } 137 | 138 | 139 | 140 | -- 141 | -- HSP (hue, saturation, perceived brightness) 142 | -- 143 | -- Public domain, Darel Rex Finley, 2006 144 | -- http://alienryderflex.com/hsp.html 145 | -- 146 | 147 | local PR :: .299 148 | local PG :: .587 149 | local PB :: .114 150 | 151 | -- This function expects the passed-in values to be on a scale 152 | -- of 0 to 1, and uses that same scale for the return values. 153 | export rgbToHsp :: (rgb:[]float) -> (h,s,p:float) { 154 | return rgbToHsp(rgb[1], rgb[2], rgb[3]) 155 | } 156 | export rgbToHsp :: (r,g,b:float) -> (h,s,p:float) { 157 | -- Calculate the Perceived brightness. 158 | local p = math.sqrt(r*r*PR + g*g*PG + b*b*PB) 159 | 160 | -- Calculate the Hue and Saturation. (This part works 161 | -- the same way as in the HSV/b and HSL systems?) 162 | local h, s: float = NULL, NULL 163 | if r == g and r == b { 164 | h, s = 0, 0 165 | } elseif r >= g and r >= b { -- R is largest. 166 | if b >= g 167 | h, s = 6/6-1/6*(b-g)/(r-g), 1-g/r 168 | else 169 | h, s = 0/6+1/6*(g-b)/(r-b), 1-b/r 170 | } elseif g >= r and g >= b { -- G is largest. 171 | if r >= b 172 | h, s = 2/6-1/6*(r-b)/(g-b), 1-b/g 173 | else 174 | h, s = 2/6+1/6*(b-r)/(g-r), 1-r/g 175 | } else { -- B is largest. 176 | if g >= r 177 | h, s = 4/6-1/6*(g-r)/(b-r), 1-r/b 178 | else 179 | h, s = 4/6+1/6*(r-g)/(b-g), 1-g/b 180 | } 181 | 182 | return h, s, p 183 | } 184 | 185 | -- 186 | -- This function expects the passed-in values to be on a scale 187 | -- of 0 to 1, and uses that same scale for the return values. 188 | -- 189 | -- Note that some combinations of HSP, even if in the scale 190 | -- 0-1, may return RGB values that exceed a value of 1. For 191 | -- example, if you pass in the HSP color 0,1,1, the result 192 | -- will be the RGB color 2.037,0,0. 193 | -- 194 | export hspToRgb :: (hsp:[]float) -> (r,g,b:float) { 195 | return hspToRgb(hsp[1], hsp[2], hsp[3]) 196 | } 197 | export hspToRgb :: (h,s,p:float) -> (r,g,b:float) { 198 | local r, g, b: float = NULL, NULL, NULL 199 | local part: float = NULL 200 | local minOverMax = 1-s 201 | 202 | if minOverMax > 0 { 203 | if h < 1/6 { -- R>G>B 204 | h = 6*( h-0/6) ; part = 1+h*(1/minOverMax-1) 205 | b = p / math.sqrt(PR/minOverMax/minOverMax + PG*part*part + PB) 206 | r = b/minOverMax ; g = b+h*(r-b) 207 | } elseif h < 2/6 { -- G>R>B 208 | h = 6*(-h+2/6) ; part = 1+h*(1/minOverMax-1) 209 | b = p / math.sqrt(PG/minOverMax/minOverMax + PR*part*part + PB) 210 | g = b/minOverMax ; r = b+h*(g-b) 211 | } elseif h < 3/6 { -- G>B>R 212 | h = 6*( h-2/6) ; part = 1+h*(1/minOverMax-1) 213 | r = p / math.sqrt(PG/minOverMax/minOverMax + PB*part*part + PR) 214 | g = r/minOverMax ; b = r+h*(g-r) 215 | } elseif h < 4/6 { -- B>G>R 216 | h = 6*(-h+4/6) ; part = 1+h*(1/minOverMax-1) 217 | r = p / math.sqrt(PB/minOverMax/minOverMax + PG*part*part + PR) 218 | b = r/minOverMax ; g = r+h*(b-r) 219 | } elseif h < 5/6 { -- B>R>G 220 | h = 6*( h-4/6) ; part = 1+h*(1/minOverMax-1) 221 | g = p / math.sqrt(PB/minOverMax/minOverMax + PR*part*part + PG) 222 | b = g/minOverMax ; r = g+h*(b-g) 223 | } else { -- R>B>G 224 | h = 6*(-h+6/6) ; part = 1+h*(1/minOverMax-1) 225 | g = p / math.sqrt(PR/minOverMax/minOverMax + PB*part*part + PG) 226 | r = g/minOverMax ; b = g+h*(r-g) 227 | } 228 | } else { 229 | if h < 1/6 { h = 6*( h-0/6) ; r = math.sqrt(p*p / (PR+PG*h*h)) ; g, b = r*h, 0 } -- R>G>B 230 | elseif h < 2/6 { h = 6*(-h+2/6) ; g = math.sqrt(p*p / (PG+PR*h*h)) ; r, b = g*h, 0 } -- G>R>B 231 | elseif h < 3/6 { h = 6*( h-2/6) ; g = math.sqrt(p*p / (PG+PB*h*h)) ; b, r = g*h, 0 } -- G>B>R 232 | elseif h < 4/6 { h = 6*(-h+4/6) ; b = math.sqrt(p*p / (PB+PG*h*h)) ; g, r = b*h, 0 } -- B>G>R 233 | elseif h < 5/6 { h = 6*( h-4/6) ; b = math.sqrt(p*p / (PB+PR*h*h)) ; r, g = b*h, 0 } -- B>R>G 234 | else { h = 6*(-h+6/6) ; r = math.sqrt(p*p / (PR+PB*h*h)) ; b, g = r*h, 0 } -- R>B>G 235 | } 236 | 237 | return r, g, b 238 | } 239 | 240 | 241 | -------------------------------------------------------------------------------- /tests/languageOverview.gloa: -------------------------------------------------------------------------------- 1 | -- 2 | -- Glóa language overview. 3 | -- 4 | -- !!! OUTDATED !!! 5 | -- !!! OUTDATED !!! 6 | -- !!! OUTDATED !!! 7 | -- 8 | 9 | 10 | 11 | -- Control structures. 12 | ---------------------------------------------------------------- 13 | 14 | local foo :: () { 15 | local arr:[]int = {1,2,3} 16 | 17 | -- If statement. 18 | if 5 < 1 19 | print("No way!") 20 | elseif #arr > 0 21 | print('arr is a '..getLuaType(arr)) 22 | else 23 | print([[This cannot be!]]) 24 | 25 | -- Do scope. 26 | do { 27 | local x = a() 28 | } 29 | local x = 4 -- No shadowing happens here so this is ok. 30 | 31 | -- For loops. 32 | -- Short: 33 | for 1, 3 34 | print(it) 35 | for arr 36 | print(itIndex, it) 37 | for v: arr 38 | print(itIndex, v) 39 | for v, i: arr 40 | print(i, v) 41 | -- Traditional: 42 | for i = 1, 3 43 | print(i) 44 | for i = 3, 1, -1 45 | print(i) 46 | for i, v in ipairs(arr) 47 | print(i, v) 48 | for k, v in next, t, nil 49 | print(k, v) 50 | -- Custom: 51 | for v1, v2, v3: obj -- Using a defined default iterator. 52 | print(i, v) 53 | for v1, v2, v3 in myIterator, obj 54 | print(v1, v2, v3) 55 | 56 | -- While loop. (There's no repeat/until loop (yet?)) 57 | local x = 10 58 | while x > 0 59 | x -= 1 60 | 61 | -- Loop control. 62 | for x = 1, 10 { 63 | if x == 7 continue 64 | 65 | for y = 1, 10 { 66 | if x-y == 0 continue 67 | 68 | if y == 10 and x < 5 break(x) -- Break from the outer loop. 69 | 70 | print("x"..tostring(x).." y"..tostring(y)) 71 | } 72 | } 73 | 74 | -- Switch statement. 75 | local count = 2 76 | 77 | if count == { 78 | case 1: print("We got one!") 79 | 80 | case 2: !through 81 | case 3: print("We got two or three!") 82 | 83 | case: 84 | printf("We got %d...", count) 85 | print("That's a lot!") 86 | } 87 | 88 | -- Defer. 89 | do { 90 | local file, err = io.open("dog.png", "rb") 91 | if not file { 92 | print("Error: "..tostring(err)) 93 | } else { 94 | defer file.close!() 95 | 96 | local contents = file.read!("*a") 97 | print("File size: "..tostring(#contents)) 98 | } -- Defer fires here at scope exit. 99 | } 100 | } 101 | 102 | 103 | 104 | -- Variables/constants. 105 | ---------------------------------------------------------------- 106 | 107 | -- Variables. 108 | local a = 0.0 -- Inferred type. 109 | local b : float = 0.0 -- Explicit type. 110 | local c : float -- Getting a default value. 111 | 112 | -- Constants. 113 | local A : : 0.0 -- Inferred type. 114 | local B : float : 0.0 -- Explicit type. 115 | 116 | 117 | 118 | -- Functions. 119 | ---------------------------------------------------------------- 120 | 121 | -- File-scope. 122 | local a :: (n:float) -> float { 123 | if n == 0.0 return n 124 | return a()+b() -- b exists! Order doesn't matter in file scope. 125 | } 126 | local b : (n:float)->float : (n:float)->float { -- Explicit type for function. Verbose and unnecessary, but valid. 127 | return a() 128 | } 129 | 130 | -- Global scope. 131 | export callMeAnytime :: () -> void { 132 | foo() 133 | } 134 | 135 | -- Main function. (The program's entry point.) 136 | local main :: () { -- The return type can be omitted if the function returns nothing (void). 137 | print("We're on!") 138 | } 139 | 140 | -- @Incomplete: Named arguments. 141 | -- @Incomplete: !must for returns. 142 | 143 | 144 | 145 | -- Types. 146 | ---------------------------------------------------------------- 147 | 148 | local doer :: (n:float, t1,t2:table, anything:any, optional:int=10) -> success:bool { 149 | local sum = n + #t1 + #t2 + optional 150 | 151 | print("Sum is "..tostring(sum)) 152 | print("Anything:", anything) 153 | 154 | return true 155 | } 156 | 157 | local func :: () { 158 | local integers:[]int = {1,2,3} 159 | 160 | local words:table = nil 161 | words = {"Hello", id=5} 162 | words[2] = "World" 163 | 164 | local ok = doer(5, cast(table)integers, words, func) 165 | } 166 | 167 | local multiply :: (...:float) -> (result:float) { 168 | local result = 0.0 169 | for ... result *= it 170 | return result 171 | } 172 | 173 | 174 | 175 | -- Enums and data structures. 176 | ---------------------------------------------------------------- 177 | 178 | local EntityType :: enum { 179 | PLAYER :: 0x01, 180 | MONSTER :: 0x02, 181 | BUTTON :: 0x03, 182 | DOOR :: 0x04, 183 | } 184 | 185 | local Id : : int 186 | local AnotherId : Type : int 187 | 188 | local Entity :: struct { 189 | entityType: EntityType, 190 | id: Id, 191 | 192 | x = 0.0, 193 | y = 0.0, 194 | } 195 | 196 | local testEnum :: () { 197 | local ent:Entity = {x=5, y=7} 198 | 199 | local entType:EntityType = MONSTER 200 | 201 | if !complete entType == { 202 | case PLAYER: say("Hello.") 203 | case MONSTER: say("Rawr!") 204 | case BUTTON: say("Click") 205 | case DOOR: say("Slam") 206 | } 207 | } 208 | 209 | -- @Incomplete: "Sub structs". 210 | 211 | 212 | 213 | -- Polymorphism/overloading. 214 | ---------------------------------------------------------------- 215 | 216 | local testStuff :: () { 217 | printValue("Feather in a hat") 218 | printValue(-98) 219 | print(performConcat("boats")) 220 | print(performConcat(12345)) 221 | } 222 | 223 | local printValue :: (value:string) { 224 | print("Value is the string '"..value.."'.") 225 | } 226 | local printValue :: (value:float) { 227 | print("Value is the number '"..tostring(value).."'.") 228 | } 229 | 230 | local performConcat :: (v:string|float) -> string { 231 | return "safe concat: "..tostring(v) 232 | } 233 | 234 | local justReturnIt :: (v:$T/Entity) -> T { 235 | print("Type:", T) 236 | return v 237 | } 238 | 239 | -- Parameterized struct. 240 | local Wrapper :: struct (T:Type, n:int=0) { 241 | value: T, 242 | num: int = n, 243 | } 244 | 245 | -- 246 | -- @Incomplete: Operator overloading on structs, somehow? (We need metatables which 247 | -- might be outside of the compiler's scope. Maybe we don't allow metatables?) 248 | -- 249 | -- Actually, do we need metatables? Can't we just desugar 250 | -- local a, b: MyObject 251 | -- local c = a+b 252 | -- into 253 | -- local a, b: MyObject 254 | -- local c = add(a, b) 255 | -- ? 2019-11-18 256 | -- 257 | 258 | 259 | 260 | -- Metaprogram. (Recursive, even!) 261 | ---------------------------------------------------------------- 262 | 263 | local prog :: () { 264 | local something = !run getSomething() 265 | print(something) 266 | } 267 | 268 | local LOCATION :: !run getLocation("[", "]") 269 | 270 | local getSomething :: () -> string { 271 | return "Quite a 'something' right "..LOCATION.."." 272 | } 273 | 274 | local getLocation :: (prefix,suffix:string) -> string { 275 | local where = math.random() < 0.5 and "here" or "there" 276 | return prefix..where..suffix 277 | } 278 | 279 | -- @Incomplete: !if 280 | 281 | 282 | 283 | -- Generation/introspection. 284 | ---------------------------------------------------------------- 285 | 286 | local printString5Times :: (s:string) !body_text { 287 | local buffer:[]string 288 | 289 | for 1, 5 tableInsert(buffer, "print(s)\n") 290 | 291 | return tableConcat(buffer) 292 | } 293 | 294 | -- @Incomplete: Introspection. 295 | 296 | 297 | 298 | -- Modules. 299 | ---------------------------------------------------------------- 300 | 301 | -- Add the exports of modules as locals here. 302 | !import "assetManager" -- Looks in some common folder on the computer. 303 | !load "src/appFunctions" -- Looks in the local project folder. 304 | 305 | -- Grab things from modules into local identifiers. 306 | local utils :: !import "utilities" 307 | local stringConcat :: utils.stringConcat 308 | 309 | local bar :: () { 310 | print("A humble tumble.") 311 | 312 | local s:string = stringConcat({"A","humble","tumble."}, " ") 313 | print(s) 314 | } 315 | 316 | export print5 :: printString5Times 317 | export bat :: () { print("Screech!") } 318 | export someValue = 8 319 | 320 | -- Jai 321 | -- pow :: (x: float, power: float) -> float #foreign Crt "powf"; 322 | 323 | 324 | -------------------------------------------------------------------------------- /modules/os.gloa: -------------------------------------------------------------------------------- 1 | --[[============================================================ 2 | --= 3 | --= Glóa operative system module 4 | --= 5 | --============================================================== 6 | 7 | execute, escapeArguments, isShellAvailable 8 | exit 9 | getClock 10 | getDate, getDateUtc 11 | getEnvironmentVariable 12 | getLocale, setLocale 13 | getTime, getTimeDifference 14 | 15 | -- Types: 16 | LocaleTable 17 | 18 | -- Enums: 19 | LocaleCategory 20 | 21 | --============================================================]] 22 | 23 | !import "basic" 24 | !import "string" 25 | 26 | export escapeArguments :: (arguments:[]string) -> (success:bool, error:string, result:string) { 27 | local buffer:[]string = {} 28 | 29 | for arg, i: arguments { 30 | if findPattern(arg, '[%z\n\r]') 31 | return false, format('Argument %d contains invalid characters.', i), "" 32 | 33 | if i > 1 insert(buffer, ' ') 34 | 35 | if arg == '' { 36 | insert(buffer, '""') 37 | } elseif not findPattern(arg, '[%s"]') { 38 | insert(buffer, arg) 39 | } else { 40 | arg = replacePatternWithPattern(arg, '(\\*)"', '%1%1\\"') 41 | arg = replacePatternWithPattern(arg, '(\\+)$', '%1%1') 42 | insert(buffer, '"') 43 | insert(buffer, arg) 44 | insert(buffer, '"') 45 | } 46 | } 47 | 48 | return true, "", concatenate(buffer) 49 | } 50 | 51 | export execute :: (command:string) -> (statusCode:int) !foreign lua "os.execute" 52 | 53 | export execute :: (program:string, arguments:[]string) -> (success:bool, error:string, statusCode:int, command:string) { 54 | if not program return false, "Program value is empty.", 1, "" 55 | 56 | local programArray: []string 57 | programArray[1] = program 58 | 59 | local ok, err, programStr = escapeArguments(programArray) 60 | if not ok return false, "Bad program value.", 1, "" 61 | 62 | local ^ok, ^err, argsStr = escapeArguments(arguments) 63 | if not ok return false, err, 1, "" 64 | 65 | local command 66 | = programStr[1] == !char '"' 67 | ? format([["%s %s"]], programStr, argsStr) 68 | : format([[%s %s]], programStr, argsStr) 69 | 70 | return true, "", execute(command), command 71 | } 72 | 73 | export isShellAvailable :: () -> bool { 74 | local helper :: () -> int !foreign lua "os.execute" 75 | return helper() ~= 0 76 | } 77 | 78 | export exit :: (statusCode=0--[[or whatever is the success code for the OS]]) !foreign lua "os.exit" 79 | 80 | export getClock :: () -> float !foreign lua "os.clock" 81 | 82 | local Date :: struct { 83 | year: int, 84 | month: int, 85 | day: int, 86 | hour: int|none = nil, 87 | min: int|none = nil, 88 | sec: int|none = nil, 89 | isdst: bool|none = nil, 90 | } 91 | local date:Date 92 | 93 | local _getTime :: (_date:Date) -> int !foreign lua "os.time" 94 | 95 | export getTime :: () -> int !foreign lua "os.time" 96 | export getTime :: (year,month,day:int, hour,min,sec=0) -> int { 97 | date.year = year 98 | date.month = month 99 | date.day = day 100 | date.hour = hour 101 | date.min = min 102 | date.sec = sec 103 | date.isdst = nil 104 | return _getTime(date) 105 | } 106 | export getTime :: (year,month,day:int, hour,min,sec:int, isDst:bool) -> int { 107 | date.year = year 108 | date.month = month 109 | date.day = day 110 | date.hour = hour 111 | date.min = min 112 | date.sec = sec 113 | date.isdst = isDst 114 | return _getTime(date) 115 | } 116 | 117 | export getTimeDifference :: (time2:int, time1:int) !foreign lua "os.difftime" -- This usually returns time2-time1. 118 | 119 | local _getDate :: (dateFormat:string) -> string|Date !foreign lua "os.date" 120 | local _getDate :: (dateFormat:string, time:int) -> string|Date !foreign lua "os.date" 121 | 122 | local validateDateFormat :: (dateFormat:string) { 123 | local b = getByte(dateFormat, 1) 124 | if (b == !char "*" or b == !char "!") errorf("Date format cannot start with '*' or '!'. (Format is %s)", dateFormat) 125 | } 126 | 127 | export getDate :: () -> (year,month,day:int, hour,min,sec:int, isDst:bool) { 128 | date = cast(Date) _getDate("*t") 129 | return date.year, date.month, date.day, cast(int)date.hour, cast(int)date.min, cast(int)date.sec, cast(bool)date.isdst 130 | } 131 | export getDate :: (time:int) -> (year,month,day:int, hour,min,sec:int, isDst:bool) { 132 | date = cast(Date) _getDate("*t", time) 133 | return date.year, date.month, date.day, cast(int)date.hour, cast(int)date.min, cast(int)date.sec, cast(bool)date.isdst 134 | } 135 | export getDate :: (dateFormat:string) -> string { 136 | validateDateFormat(dateFormat) 137 | return cast(string) _getDate(dateFormat) 138 | } 139 | export getDate :: (dateFormat:string, time:int) -> string { 140 | validateDateFormat(dateFormat) 141 | return cast(string) _getDate(dateFormat, time) 142 | } 143 | 144 | export getDateUtc :: () -> (year,month,day:int, hour,min,sec:int, isDst:bool) { 145 | date = cast(Date) _getDate("!*t") 146 | return date.year, date.month, date.day, cast(int)date.hour, cast(int)date.min, cast(int)date.sec, cast(bool)date.isdst 147 | } 148 | export getDateUtc :: (time:int) -> (year,month,day:int, hour,min,sec:int, isDst:bool) { 149 | date = cast(Date) _getDate("!*t", time) 150 | return date.year, date.month, date.day, cast(int)date.hour, cast(int)date.min, cast(int)date.sec, cast(bool)date.isdst 151 | } 152 | export getDateUtc :: (dateFormat:string) -> string { 153 | validateDateFormat(dateFormat) 154 | return cast(string) _getDate("!"..dateFormat) 155 | } 156 | export getDateUtc :: (dateFormat:string, time:int) -> string { 157 | validateDateFormat(dateFormat) 158 | return cast(string) _getDate("!"..dateFormat, time) 159 | } 160 | 161 | export getEnvironmentVariable :: (name:string) -> (isDefined:bool, value:string) { 162 | local getenv :: (name:string) -> string|none !foreign lua "os.getenv" 163 | 164 | local v = getenv(name) 165 | if v == nil return false, "" 166 | 167 | return true, cast(string) v 168 | } 169 | 170 | export LocaleCategory :: enum { 171 | ALL :: "all", 172 | COLLATE :: "collate", 173 | CTYPE :: "ctype", 174 | MONETARY :: "monetary", 175 | NUMERIC :: "numeric", 176 | TIME :: "time", 177 | } 178 | 179 | export LocaleTable :: struct { 180 | collate:string, 181 | ctype:string, 182 | monetary:string, 183 | numeric:string, 184 | time:string, 185 | } 186 | 187 | local getOrSetLocale :: (locale:string|none, category:LocaleCategory) -> string|none !foreign lua "os.setlocale" 188 | 189 | export getLocale :: (category:LocaleCategory) -> string { 190 | if category == LocaleCategory.ALL error("Cannot retrieve locale for all categories with getLocale(). (Use getLocaleForAllCategories() instead.)") 191 | return cast(string) getOrSetLocale(nil, category) 192 | } 193 | export setLocale :: (locale:string, category=LocaleCategory.ALL) -> (success:bool, locale:string) { 194 | local newLocale = getOrSetLocale(locale, category) 195 | if newLocale == nil return false, "" 196 | return true, cast(string) newLocale 197 | } 198 | 199 | export getLocaleForAllCategories :: () -> LocaleTable { 200 | local Iterator :: (_1,_2:none) -> string|none, string -- @Temp until iterators are better. @Compiler 201 | local each :: (s:string, pattern:string) -> Iterator, none, none !foreign lua "string.gmatch" 202 | 203 | local localeSequence = cast(string) getOrSetLocale(nil, LocaleCategory.ALL) 204 | local t:LocaleTable 205 | 206 | if find(localeSequence, "=") { 207 | for categoryName, locale in each(localeSequence, "LC_(%a+)=([^;]+)") { 208 | if categoryName == { 209 | case "COLLATE": t.collate = locale 210 | case "CTYPE": t.ctype = locale 211 | case "MONETARY": t.monetary = locale 212 | case "NUMERIC": t.numeric = locale 213 | case "TIME": t.time = locale 214 | case: 215 | !import "io" 216 | writeLine(STDERR, "Error: getLocaleForAllCategories: Unknown category name: ", categoryName) 217 | } 218 | } 219 | } else { 220 | t.collate = localeSequence 221 | t.ctype = localeSequence 222 | t.monetary = localeSequence 223 | t.numeric = localeSequence 224 | t.time = localeSequence 225 | } 226 | 227 | return t 228 | } 229 | -------------------------------------------------------------------------------- /modules/ffi.gloa: -------------------------------------------------------------------------------- 1 | --[=[=========================================================== 2 | --= 3 | --= LuaJIT FFI bindings 4 | --= 5 | --============================================================== 6 | 7 | castTo 8 | getType 9 | hasAbi 10 | isNull 11 | load, loadGlobal 12 | new, newArray 13 | newInterface 14 | pointerToInt, pointerToUint 15 | toInt, toFloat 16 | toString 17 | 18 | -- Types: 19 | Carray 20 | Cdata 21 | Cdecl 22 | Ctype, CtypeSpec 23 | 24 | -- Enums: 25 | AbiName 26 | ArchName 27 | OsName 28 | 29 | ---------------------------------------------------------------- 30 | 31 | -- Example: 32 | local ffi :: !import "ffi" 33 | 34 | local basicUsage :: { 35 | ffi.define[[ 36 | void Sleep(int ms); 37 | ]] 38 | local C = ffi.newInterface( !foreign struct { 39 | Sleep: (ms:int) -> void; 40 | }) 41 | 42 | C.Sleep(2000) 43 | } 44 | 45 | --===========================================================]=] 46 | 47 | !import "basic" 48 | 49 | 50 | 51 | export OsName :: enum { 52 | WINDOWS :: "Windows", 53 | LINUX :: "Linux", 54 | OSX :: "OSX", 55 | BSD :: "BSD", 56 | POSIX :: "POSIX", 57 | OTHER :: "Other", 58 | } 59 | export ArchName :: enum { 60 | X86 :: "x86", 61 | X64 :: "x64", 62 | ARM :: "arm", 63 | PPC :: "ppc", 64 | PPCSPE :: "ppcspe", 65 | MIPS :: "mips", 66 | } 67 | export AbiName :: enum { 68 | BIT32 :: "32bit", -- 32-bit architecture. 69 | BIT64 :: "64bit", -- 64-bit architecture. 70 | LE :: "le", -- Little-endian architecture. 71 | BE :: "be", -- Big-endian architecture. 72 | FPU :: "fpu", -- Target has a hardware FPU. 73 | SOFTFP :: "softfp", -- softfp calling conventions. 74 | HARDFP :: "hardfp", -- hardfp calling conventions. 75 | EABI :: "eabi", -- EABI variant of the standard ABI. 76 | WIN :: "win", -- Windows variant of the standard ABI. 77 | } 78 | 79 | 80 | 81 | export OS: OsName : !foreign lua "require'ffi'.os" 82 | export ARCH: ArchName : !foreign lua "require'ffi'.arch" 83 | 84 | export Cdecl :: string 85 | export CtypeSpec :: Cdecl|Ctype|Cdata 86 | 87 | local ParamForNew :: int|float|string|Cdata|table -- (Not sure what exact types are allowed here.) 88 | 89 | 90 | 91 | export Cdata :: !foreign struct { 92 | !value: Cdata, 93 | 94 | as :: (cdata:Cdata, $T:Type) -> T { 95 | return cast(T) cast(any) cdata 96 | }, 97 | } 98 | 99 | local ffi :: !self 100 | 101 | export Ctype :: !foreign struct { 102 | using Cdata, 103 | 104 | !call :: new, 105 | new :: (ctype:Ctype, ...:ParamForNew) -> (success:bool, cdata:Cdata, err:string) { return ffi.new (ctype, ...) }, -- @Cleanup @Speed: Should we just say new::ffi.new here? 106 | newArray :: (ctype:Ctype, count:int, ...:ParamForNew) -> (success:bool, cdata:Cdata, err:string) { return ffi.newArray(ctype, count, ...) }, -- @Cleanup @Speed: Should we just say newArray::ffi.newArray here? 107 | } 108 | 109 | export Carray :: !foreign struct (Item:Type) { 110 | -- We want zero-indexed arrays and this is the only way to achieve that (otherwise expressions like arr[0] will trigger a compiler error). 111 | !key: int, 112 | !value: Item, 113 | 114 | -- @Incomplete: Iterator. (Can we detect the length of the array? Maybe we need the array to be zero-terminated?) 115 | -- !iterator :: (arr:Carray(Item), i:int) -> (i:int|none, v:Item) { 116 | -- if arr[i] == NULL return nil, NULL -- I have a feeling this may read outside allocated memory... 117 | -- return i+1, arr[i] 118 | -- }, 119 | } 120 | 121 | 122 | 123 | export define :: (definitions:Cdecl) !foreign lua "require'ffi'.cdef" 124 | 125 | local pcall :: (func:any, ...:any) -> bool, ...any !foreign lua "pcall" 126 | local _new :: (ct:CtypeSpec, ...:ParamForNew) -> Cdata !foreign lua "require'ffi'.new" 127 | 128 | export new :: (ct:CtypeSpec, ...:ParamForNew) -> (success:bool, cdata:Cdata, err:string) { 129 | local ok, cdataOrErr = pcall(_new, ct, ...) 130 | if not ok return false, NULL, cast(string)cdataOrErr 131 | 132 | return true, cast(Cdata)cdataOrErr, "" 133 | } 134 | 135 | -- newArray() is exactly the same as new() - only, the first "parameter" must always be an array length. 136 | -- If ct is Cdecl (string) then it should end with "[?]". 137 | export newArray :: (ct:CtypeSpec, count:int, ...:ParamForNew) -> (success:bool, variableLengthObject:Cdata, err:string) { 138 | local ok, cdataOrErr = pcall(_new, ct, count, ...) 139 | if not ok return false, NULL, cast(string)cdataOrErr 140 | 141 | return true, cast(Cdata)cdataOrErr, "" 142 | } 143 | 144 | 145 | 146 | local Clib :: !foreign struct {} 147 | 148 | local _newInterface :: (clib:Clib, $Interface:Type, $callerName:string) -> Interface { 149 | !run { 150 | local _info = cast(TypeInfo) type_info(Interface) 151 | -- @Compiler @Bug: _info is (sometimes?) nil here! :| 152 | -- if _info.tag ~= TypeTag.STRUCT errorf("%s: The interface argument must be a struct.", callerName) 153 | 154 | -- @Incomplete: Ensure the struct is foreign. @Compiler: Expose that property. 155 | -- local info = cast(TypeInfoStruct) _info 156 | -- if not info.isForeign errorf("%s: The interface struct must be !foreign.", callerName) 157 | } 158 | return cast(Interface) cast(any) clib 159 | } 160 | 161 | export newInterface :: ($Interface:Type) -> Interface { 162 | local GLOBAL_SYMBOLS: Clib : !foreign lua "require'ffi'.C" 163 | return _newInterface(GLOBAL_SYMBOLS, Interface, "ffi.newInterface") 164 | } 165 | 166 | local loadHelper :: (name:string, intoGlobalNamespace=false) -> Clib !foreign lua "require'ffi'.load" 167 | 168 | export load :: (name:string, $Interface:Type) -> (success:bool, interface:Interface, err:string) { 169 | local ok, clibOrErr = pcall(loadHelper, name) 170 | if not ok return false, NULL, cast(string)clibOrErr 171 | 172 | return true, _newInterface(cast(Clib)clibOrErr, Interface, "ffi.load"), "" 173 | } 174 | -- This only works on POSIX systems. 175 | export loadGlobal :: (name:string) -> (success:bool, err:string) { 176 | local ok, err = pcall(loadHelper, name, true) 177 | if not ok return false, cast(string)err 178 | 179 | return true, "" 180 | } 181 | 182 | 183 | 184 | export toString :: (ptr:Cdata, len=0--[[strlen(ptr)]]) -> string !foreign lua "require'ffi'.string" -- Note: Does not work on "wide" strings in Windows (or any string with NULL bytes) if len is omitted. 185 | 186 | export toInt :: (cdata:Cdata) -> int { return cast(int) toFloat(cdata) } 187 | export toFloat :: (cdata:Cdata) -> float !foreign lua "tonumber" 188 | 189 | local pointerToNumber :: (cdata:Cdata) -> int !foreign lua "tonumber" 190 | 191 | export pointerToInt :: (ptr:Cdata) -> int { -- Returns a signed integer! 192 | return pointerToNumber(castTo("intptr_t", castTo("void *", ptr))) 193 | } 194 | export pointerToUint :: (ptr:Cdata) -> int { -- Is slower than pointerToInt() in LuaJIT! (See http://wiki.luajit.org/ffi-knowledge#convert-a-cdata-pointer-to-lua-number) 195 | return pointerToNumber(castTo("uintptr_t", castTo("void *", ptr))) 196 | } 197 | 198 | 199 | 200 | export getType :: (cdata:CtypeSpec) -> Ctype !foreign lua "require'ffi'.typeof" 201 | 202 | export castTo :: (ct:CtypeSpec, init:Cdata) -> Cdata !foreign lua "require'ffi'.cast" 203 | 204 | export isNull :: (ptr:Cdata) -> bool { 205 | return ptr == NULL -- A null pointer can be compared to nil (at least in LuaJIT). Nil itself will be treated like a null pointer in this case. 206 | -- return pointerToInt(ptr) == 0 -- If the above turns out not to work then we can fall back on this. 207 | } 208 | 209 | export hasAbi :: (name:AbiName) -> bool !foreign lua "require'ffi'.abi" 210 | 211 | -- @Incomplete: 212 | -- ctype = ffi.metatype(ct, metatable) 213 | -- cdata = ffi.gc(cdata, finalizer) 214 | -- size = ffi.sizeof(ct [,nelem]) 215 | -- align = ffi.alignof(ct) 216 | -- ofs [,bpos,bsize] = ffi.offsetof(ct, field) 217 | -- status = ffi.istype(ct, obj) 218 | -- err = ffi.errno([newerr]) 219 | -- ffi.copy(dst, src, len) 220 | -- ffi.copy(dst, str) 221 | -- ffi.fill(dst, len [,c]) 222 | -- cb:free() 223 | -- cb:set(func) 224 | -- iter, obj, start = pairs(cdata) 225 | -- iter, obj, start = ipairs(cdata) 226 | 227 | 228 | -------------------------------------------------------------------------------- /modules/io/io.gloa: -------------------------------------------------------------------------------- 1 | --[[============================================================ 2 | --= 3 | --= Glóa I/O and filesystem module 4 | --= 5 | --============================================================== 6 | 7 | -- Types: 8 | File 9 | 10 | -- Functions: 11 | close 12 | disableBuffering, enableBuffering, enableLineBuffering, flush 13 | eachLine 14 | openForReading, openForReadingText, openForWriting, openForWritingText 15 | readEntireFile, writeEntireFile 16 | readNumber, readRemaining, readLine, readBytes 17 | remove, rename, copy 18 | stdWrite 19 | write, writef, writeLine 20 | 21 | -- Values: 22 | APP_PATH, APP_DIRECTORY, COMPILER_PATH, COMPILER_DIRECTORY 23 | STDIN, STDERR, STDOUT 24 | 25 | --============================================================]] 26 | 27 | !import "basic" 28 | 29 | -- Get the path to the application file. The path may be relative to the current working directory. 30 | export APP_PATH : string : !foreign compiler "appPath" 31 | -- Get the path to the directory the application is located in. The path may be relative to the current working directory. 32 | export APP_DIRECTORY : string : !foreign compiler "appDirectory" 33 | -- Get the path to the compiler. (This will be a hardcoded value in the compiled program.) 34 | export COMPILER_PATH : string : !foreign compiler "compilerPath" 35 | -- Get the path to the directory the compiler is located in. (This will be a hardcoded value in the compiled program.) 36 | export COMPILER_DIRECTORY : string : !foreign compiler "compilerDirectory" 37 | 38 | export STDIN : File : !foreign lua "io.stdin" 39 | export STDERR : File : !foreign lua "io.stderr" 40 | export STDOUT : File : !foreign lua "io.stdout" 41 | 42 | export File :: !foreign struct {} 43 | 44 | local openFile :: (path:string, mode:string) -> bool, File, string { 45 | local helper :: (path:string, mode:string) -> File|none, none|string !foreign lua "io.open" 46 | 47 | local file, err = helper(path, mode) 48 | if file == nil return false, NULL, cast(string) err 49 | 50 | return true, cast(File) file, "" 51 | } 52 | export openForReading :: (path:string) -> (success:bool, file:File!must, error:string) { return openFile(path, "rb") } -- 'b' is only used in Windows. 53 | export openForReadingText :: (path:string) -> (success:bool, file:File!must, error:string) { return openFile(path, "r") } 54 | export openForWriting :: (path:string) -> (success:bool, file:File!must, error:string) { return openFile(path, "wb") } -- 'b' is only used in Windows. 55 | export openForWritingText :: (path:string) -> (success:bool, file:File!must, error:string) { return openFile(path, "w") } 56 | 57 | export close :: (file:File) !foreign lua "io.close" 58 | 59 | local readHelper :: (file:File, what:string|int) -> string|float|none !foreign method "read" 60 | export readNumber :: (file:File) -> (success:bool, number:float) { 61 | local data = readHelper(file, "*n") 62 | if data == nil return false, 0 63 | return true, cast(float) data 64 | } 65 | export readRemaining :: (file:File) -> (success:bool, data:string) { 66 | local data = readHelper(file, "*a") -- @Cleanup: I think this always returns a string? 67 | if data == nil return false, "" 68 | return true, cast(string) data 69 | } 70 | export readLine :: (file:File) -> (success:bool, line:string) { 71 | local data = readHelper(file, "*l") 72 | if data == nil return false, "" 73 | return true, cast(string) data 74 | } 75 | export readBytes :: (file:File, maxBytes:int) -> (success:bool, data:string) { 76 | local data = readHelper(file, maxBytes) 77 | if data == nil return false, "" 78 | return true, cast(string) data 79 | } 80 | 81 | export write :: (file:File, ...:string) !foreign method "write" 82 | export write :: (file:File, strings:[]string) { 83 | for strings write(file, it) 84 | } 85 | export writef :: (file:File, s:string, ...:string|int|float|Type) { 86 | write(file, format(s, ...)) 87 | } 88 | export writeLine :: (file:File, ...:string) { 89 | write(file, ...) 90 | write(file, "\n") 91 | } 92 | 93 | local _readEntireFile :: ($text:bool, path:string) -> (success:bool, data:string, error:string) { 94 | !if text local ok, file, err = openForReadingText(path) 95 | else local ok, file, err = openForReading(path) 96 | 97 | if not ok return false, "", err 98 | 99 | local ^ok, data = readRemaining(file) 100 | close(file) 101 | if not ok return false, "", "Could not read from the file." 102 | 103 | return true, data, "" 104 | } 105 | local _writeEntireFile :: ($text:bool, path:string, data:string) -> (success:bool, error:string) { 106 | !if text local ok, file, err = openForWritingText(path) 107 | else local ok, file, err = openForWriting(path) 108 | 109 | if not ok return false, err 110 | 111 | write(file, data) 112 | close(file) 113 | return true, "" 114 | } 115 | local _writeEntireFile2 :: ($text:bool, path:string, data:[]string, dataSuffix="") -> (success:bool, error:string) { 116 | !if text local ok, file, err = openForWritingText(path) 117 | else local ok, file, err = openForWriting(path) 118 | 119 | if not ok return false, err 120 | 121 | for data { 122 | write(file, it) 123 | if dataSuffix write(file, dataSuffix) 124 | } 125 | close(file) 126 | return true, "" 127 | } 128 | export readEntireFile : (path:string) -> (success:bool, data:string, error:string) : variant_of( _readEntireFile (false, "") ) 129 | export readEntireTextFile : (path:string) -> (success:bool, data:string, error:string) : variant_of( _readEntireFile (true, "") ) 130 | export writeEntireFile : (path:string, data:string) -> (success:bool, error:string) : variant_of( _writeEntireFile (false, "", "") ) 131 | export writeEntireTextFile : (path:string, data:string) -> (success:bool, error:string) : variant_of( _writeEntireFile (true, "", "") ) 132 | export writeEntireFile : (path:string, data:[]string, dataSuffix="") -> (success:bool, error:string) : variant_of( _writeEntireFile2(false, "", cast([]string)NULL, "") ) 133 | export writeEntireTextFile : (path:string, data:[]string, dataSuffix="") -> (success:bool, error:string) : variant_of( _writeEntireFile2(true, "", cast([]string)NULL, "") ) 134 | 135 | export eachLine :: (path:string) -> (iter:(_,_:none)->(line:string|none), _,_:none) !foreign lua "io.lines" 136 | export eachLine :: (file:File) -> (iter:(_,_:none)->(line:string|none), _,_:none) !foreign method "lines" 137 | 138 | export remove :: (path:string) -> (success:bool, error:string) { 139 | local helper :: (path:string) -> bool|none, none|string !foreign lua "os.remove" 140 | local ok, err = helper(path) 141 | if ok == nil return false, cast(string) err 142 | return true, "" 143 | } 144 | export rename :: (oldPath:string, newPath:string) -> (success:bool, error:string) { 145 | local helper :: (oldPath:string, newPath:string) -> bool|none, none|string !foreign lua "os.rename" 146 | local ok, err = helper(oldPath, newPath) 147 | if ok == nil return false, cast(string) err 148 | return true, "" 149 | } 150 | export copy :: (sourcePath:string, targetPath:string) -> (success:bool, error:string) { 151 | local ok, data, err = readEntireFile(sourcePath) 152 | if not ok return false, err 153 | return writeEntireFile(targetPath, data) 154 | } 155 | 156 | local setvbuf :: (file:File, mode:string, size:int|none) !foreign method "setvbuf" 157 | export disableBuffering :: (file:File) { setvbuf(file, "no", nil) } 158 | export enableBuffering :: (file:File) { setvbuf(file, "full", nil) } 159 | export enableBuffering :: (file:File, size:int) { setvbuf(file, "full", size) } 160 | export enableLineBuffering :: (file:File) { setvbuf(file, "line", nil) } 161 | export enableLineBuffering :: (file:File, size:int) { setvbuf(file, "line", size) } 162 | 163 | export flush :: (file:File) !foreign method "flush" 164 | 165 | export stdWrite :: (...:string) !foreign lua "io.write" 166 | 167 | export openTemporaryFile :: () -> File !foreign lua "io.tmpfile" -- Opened in update mode. 168 | export getTemporaryName :: () -> string !foreign lua "os.tmpname" -- Warning: On Windows this may return a name ending with "." which is an illegal filename. 169 | --------------------------------------------------------------------------------