If you don't know what happened
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
_callstack
Level 1 <>
_callstack
If your program has stopped, and debug compiling has been enabled
Print the last state of the callstack.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
example
Program Structure
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
head
Level 1 <>
head
Initialize the Lowerdash Compiler
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
_debug
Level 1 <>
_debug
Enable debug compiling for imports after this point
Allows using _callstack
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
IMPORT
Level 1 <>
IMPORT FILE$
Import a file.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
hend
Level 1 <>
hend
Compiles the temporary file and makes it executable
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
compile
Level 1 <>
compile FILE$
Compile to the file system.
You can load this in place of Lowerdash to skip compilation
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
compile_lib
Level 1 <>
compile_lib FILE$
Compile to the file system as a Lowerdash library;
this file does not include Lowerdash
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
main
Level 1 <>
main
Execute module code and initialize Lowerdash runtime. Program execution should not return above this point.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Data Management
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
DICT
Level 2 <>
[COMMON] DICT myDict
Create a callable function myDict(KEY$)[icode
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
A dictionary is a table of strings, each pointing to their own unique value.
DICT is immutable. See MDICT for a dictionary you can update.
DICT is built at compile time and each key can only point to a static statement. Its useful for namespacing singleton members or exporting configuration
example
DICT myDict
KEY-> "RESULT"
END
PRINT myDict.KEY
*Dictionaries return Nil$ when a key is not found.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
TUPLE
Level 2 <>
KEY -> {STATEMENT}
Add a tuple to a DICT or MODULE definition
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
PROTIP: A tuple can return a function pointer!
examples
ANS->42
SUB->"mySubModule"
WOAH->(privateVar + privateArr[0])
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[]
Level 2 <>
VAR arr[] = [{literal list}]
Assign a list of literal values to a new array.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
example
VAR myArr$[] = ["dog", "cat", "bird"]
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
FOR
Level 2 <>
FOR {ITEM} IN {ARRAY} [INDEX {I} [STEP STEP%]]
...
NEXT
Iterate through an array, setting ITEM equal to each value
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
example
FOR S$ IN myStrings$
PRINT S$
NEXT
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
MODULE
Level 2 <>
MODULE MyMod [PROTO parentModule]
Sets the current module, creating a new "namespace".
Creates a callable function MyMod(KEY$) to lookup
properties in the module's namespace
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
VAR
Level 2 <>
VAR myVar[,myVar...]
Declare a variable in the current modules namespace.
Also generates a setter function MyMod__setMyVar V
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
This will set an entire array reference
example
MODULE MyMod
...
VAR myVar
VAR myArr[0]
Use in MODULEs
PRINT me.myVar
me.myVar = 42
PRINT MyMod_myVar
me.myVar will be desugared to to include the current MODULE name at compile time if myVar exists at the module level.
Use Everywhere
PRINT MyMod("myVar")
CALL MyMod("setMyVar"), 5
PRINT _("MyMod","myVar")
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
STATIC
Level 2 <>
STATIC DEF myStatic [args...]
Define a callable function in the current MODULE's namespace
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
STATIC DEFs can be accessed through the module, or any of its instances:
CALL MyMod("myStatic")
CALL MyMod_myStatic
myO$.myStatic
example
MODULE Math
STATIC DEF add(A, B)
RETURN A+B
END
PRINT Math_add(1, 2)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
@@LABEL
Level 2 <>
@@LABEL
Define a label in slot 3 under the current MODULE's namespace
Should end with RETURN
@@LABEL
Shortcut for labels that belong to the current MODULE
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
@@LABELs can be accessed by name only
example
MODULE Hello
@@myLabel
PRINT "Howdy!"
GOTO @@myOtherLabel
RETURN
@@myOtherLabel
PRINT "Ho!"
RETURN
GOSUB "3:@Hello_myLabel"
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
PROTO
Level 2 <>
PROTO(K$)
Lookup a property on the PROTO of the current ME.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
example
DO proto.new
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
CONSTRUCTOR
Level 2 <>
EXPORT DEF new([args...])
Define a constructor for the current module
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
When a constructor is defined on a module, Instances of that module can be instantiated using new.
It should return me
or another pointer to store for reuse. #TODO BETTER WAY?
example
MODULE Hello
...
EXPORT DEF new()
RETURN me
END
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
new
Level 2 <>
new <Module>([args...])
Create a new instance of a module and return a pointer.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
example
VAR myO$ = new MyMod([args...])
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
EXPORT
Level 2 <>
EXPORT DEF myMethod [args...]
Create a callable function under the current module that
operates on a dynamic instance
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Export DEFs can be defined after a MODULE's VARs and MEMs just like STATIC DEFs
An EXPORT DEF is namespaced under the current module, and always operates on an instance. Calling an EXPORT DEF from a Module will cause an error.
EXPORT DEFs get access to ME references.
example
MODULE Hello
...
EXPORT DEF greeting
PRINT "Hello, " + me.who$ + "!"
END
EXPORT'd DEFs are available on instances of a module.
myO$.greeting
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
MEM
Level 2 <>
MEM myMem%[,myMem...]
MEM myMem#[,myMem...]
MEM myMem$[,myMem...]
Define a member that will be allocated when new is used
Generates an export DEF _setMyMem
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Heap members must be typed
Calling new on a module will allocate memory for each member ( and any members on the prototype chain ) and create setters under the namespace of the created instance. Members are not available on the module itself.
example
MODULE Hello
...
MEM who$
...
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ME
Level 2 <>
ME(KEY$)
Lookup members on the current instance if there is one, as well as
VARs and STATIC DEFs on the current module
ME("")
Return a reference to the current instance
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
examples
VAR V# = me.myDouble#
CALL me("maybe")
me.maybe
me.myString$ = "Value"
me is bound to the MODULE in STATIC DEFs and will use a Static Dispatch at compile time rather than runtime.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
TYPE
Level 2 <>
TYPE(KEY$)
Lookup static members on the current instance if there is one
TYPE("")
Return a reference to the current instance's type
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
examples
VAR items$ = type.items$
protip:Can be used to dynamically dispatch from a prototype!
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
_DEL
Level 1 <>
_DEL O$
Delete the passed reference.
Deallocates all memory and destroys the reference.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
example
EXPORT DEF delete
_del me
END
Level 1 Syntax
To access members, methods, statics, and constants on any object use the lower dash!
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
_
Level 1 <>
_(Mod$,Key$)
Lookup a property on any object
Level 1
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Use Level 2 syntax when available!
examples
PRINT _(O$,"key")
CALL _(O$,"method"), arg1,arg2,...
When looking up STATIC and EXPORT DEFs, they'll be returned as strings to be used with the CALL command. EXPORT DEFs strings should be used immediately to avoid a stale "pointer".
To access module VARs and STATIC DEFs directly, without a lookup cost
PRINT MyModule_myStatic
MyModule_myStaticDef "msg"
To create an instance of a module with a public constructor use new
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
new
Level 1 <>
new(Mod$)[, args...]
Create a new instance of a module,
and return its constructor function
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
YOU SHOULD CALL THE CONSTRUCTOR IMMEDIATELY
example
VAR myO$ = CALL(new("MyMod")[, args...])
Hello World!
_HELLO
MODULE Hello
MEM who$
EXPORT DEF new()
return me
END
EXPORT DEF greet
PRINT "Hello, " + me.who$ + "!"
END
STATIC DEF run
VAR greeter$ = new Hello()
greeter$.setWho$("World")
greeter$.greet
END
HELLO_WORLD
EXEC "PRG2:LDC"
head
━━━━
import "_HELLO"
━━━━
hend
main
━━━━
Hello_run
Objects! (Using Level 1 Syntax)
BALLS
LOAD "PRG2:LOWERDASH_C",0: USE 2
head
━━━
import "_SCREEN"
import "_BALL"
hend
ACLS
main
━━━━
VAR Bs$[10]
FOR i=0 to 9
VAR b$ = CALL(new("Ball"))
PUSH Bs$, b$
NEXT
WHILE TRUE
GCLS
FOR i=0 to 9
CALL _(Bs$[i],"update") '*
CALL _(Bs$[i],"draw") '*
NEXT
WEND
_BALL
MODULE BALL PROTO INBOUNDS
━━━━━━━━━━━━━━━━━━━━
VAR R% = 20
MEM C#,DX#,DY#
EXPORT DEF new()
me.X# = Screen("W")/2
me.Y# = Screen("H")/(RND(5)+1)
me.C# = (&HFF<<24)+RND(&H1000000)
'Make all the balls smaller
DEC Ball_R%
return me
END
EXPORT DEF draw
GCIRCLE me.X#, me.Y#, me.R%, me.C#
END
EXPORT DEF update
'Move the ball
me.X# = me.X# + me.DX#
me.Y# = me.X# + me.DX#
'Check if it should bounce
if me.clamp("X#", "W") THEN me.DX#=-me.DX#
if me.clamp("Y#", "H") THEN me.DY#=-me.DY#
END
_SCREEN
COMMON DICT SCREEN
W->400
H->240
D->1024
END
MODULE INBOUNDS
━━━━━━━━━━━━━
MEM X#
MEM Y#
' Keep something in screen and let the caller know it tried to leave.
' could be a ball or a bullet
DEF clamp(V$,D$)
IF me(V$) < 0 THEN
me(V$) = 0
RETURN TRUE
ELSEIF me(V$) > Screen(D$)
me(V$) = Screen(D$)
RETURN TRUE
ENDIF
RETURN FALSE
END
* _(Bs$[i],...) will cause a context switch. Two of them per entity per loop is expensive. Use sprites and IDs in groups.
Lowerdash includes a set of definitions used to do the parsing and hacking.
All of these functions are COMMON DEF'd in the standard Lowerdash main file.
Data
EAT V
Ignore a value.
isNil$(V)
Check if a value is equivalent to Nil$.
isObj$(V)
Check if a value is an object reference
typeOf(V)
Checks the type of a value
0 Double
1 Int
2 String
rando(MAX%)
A random with a random seed. Double your entropy!
aDel a
Empties an array regardless of type.
Strings
trim_r$(S$)
Remove trailing character. Might be a line break, who knows!
trim_s$(S%)
Remove white spaaaaaace from the beginning and end of the string
drop$(S$,N%)
Remove the first N% characters of S$
splitAt$ S$,I% OUT L$, R$
Split S$ at I%
split$ S$,K$ OUT L$, R$
Split S$ at the first occurance of K$
splitI$ S$,K$ OUT L$, R$
Split S$ while ignoring case
splitA$ S$,K$ OUT L$, R$
Split S$ after K$
splitB$ S$,K$ OUT L$, R$
Split S$ before K$
startsWith$(S$,K$)
;)
endsWith$(S$,K$)
;]
contains$($S,K$)
K$ is in S$ at least once
containsw$($S,K$)
K$ is separated by spaces. tokenize a string.
allcaps$(S$)
Upcases any lowercase letters in S$
From ColeslawProductions