LoginLogin
Might make SBS readonly: thread

Lowerdash Reference Manual

Root / Submissions / [.]

kldck_hulCreated:

1 | Intro | | Performance |

2 | Structure | | Imports | | Modules | | Dynamic Objects |

3 | Examples | | Standard Library |

4 | Notes | | Roadmap | | Limitations | | Version History | | Comments |

9/15/16 - Added 0.7 features. Moved some commands to a separate list to write more text.
Update History 3/20/16 - Added 0.6.5 features 2/28/16 - Added benchmarks for New 3DS 2/10/16 - Ballerific changes

To use Lowerdash initially, load "LDC" into PRG2.
EXEC "PRG2:LDC"

Lowerdash provides "syntactic sugar" for SmileBasic. The Lowerdash language is a superset of the commands available in SmileBasic, and when compiled, the new commands and data structures are transformed into correct SmileBasic code. Lowerdash is designed to follow modern practices, enabling you split up your code into easy-to-understand bite-sized chunks with descriptive names. Object-oriented encapsulation means you can re-use variable and function names and not end up with a soup of BX,CX,DX,EX,FX,... and the mental gymnastic that come with keeping those names straight. What makes Lowerdash different, is that it does not attempt to emulate an entire runtime environment in an interpreted language. Lowerdash takes advantage of the fact that commands that came with the language (built-ins) are compiled code that runs much faster. For example, VAR and GOTO both conform to the interface of a dictionary and both provide O(1) access time. Lowerdash code is compiled to plain old SmileBasic, and the runtime tries to step out of the way.
  • Immutable Dictionaries are a common DEF using built-ins to be extremely fast.
  • Modules are dictionaries with an extra check for available DEFs
  • Lowerdash only has to search for properties on objects created using new. You can write code that is 1:1 performance with Vanilla SB if you do not use dynamic objects.
  • Using new to create an instance will generate a string. When evaluated this string is parsed and takes at most 3 levels of recursion to return.
How the object model works: When an instance is created, a pointer is returned. This pointer is a vector of the offsets in memory for each member. This vector is encoded as a string. Object members are converted to metadata in the same symbol table as EXPORT DEFs. Special methods are generated for getters and setters: _getMember, _setMember

Benchmarks from New 3DS:

(times are averaged over 3 runs of 5000 iterations) *Dynamic Object Context Switch - 0.004 frames | 63ns *Dynamic Object Member Lookup - 0.003 frames | 53ns *Static Module Member Lookup - 0.001 frames | 3ns *Referenced Module Member Lookup - 0.002 frames | 23ns *Static Module Member By Name - 0.001 frames | 1ns This means that <200 lookups or context switches a frame will run at 60fps. Assuming each object makes an average of 5 updates to its data a frame: *60fps - ~30 objects / frame *30fps - ~70 objects / frame The Lowerdash runtime is loaded automatically into PRG3 by the compiler. The runtime stores the temporary program code in its slot and stores object instance related data. Once compiled, a Lowerdash program can be loaded into PRG3 instead of going through the compilation process. Your main program should live in PRG0 and be structured into 2 sections: Compilation and Main. This main program only has access to Syntax Level 1. At the time MAIN is called, LDC is unloaded, and PRG2 is free

Compilation ━━━━━━━━━━━━━━━━━━━━

Compilation is started by the [icode]head[/icode] command. The head of your main program should contain a list of [b]import[/b] statements - these are the files to be compiled. After the list of imports, the head block must be closed with either hend or compile The head block can contain compiler options like _debug to add features such as the ability to run a stack trace.

example

head
  _debug
  import "_MyModule"
  import "RayCast.LIB"
hend

Main ━━━━━━━━━━━━━━━━━━━━

Main is started by the main command In the main section, a simplified set of syntax is available as SmileBasic functions; Collectively this syntax is called Level 1 syntax. All standard library function are COMMON DEFs. Files are only imported once and then cached by Lowerdash. Normal files are parsed and desugared; Importing a file that ends in .LIB causes Lowerdash to treat it as a library. Libraries will not be processed and can be any code that does not need to be compiled. Imports can contain MODULE definitions, DICT definitions, IMPORTs, DEFs, VARs, and code to run at the start of the program. Standard DEFs and VARs are not namespaced, and can cause duplicate name errors if used in multiple files.

Modules

An import can contain any number of MODULE definitions. A module definition starts with the MODULE command. You can end a MODULEDefinition with END or omit it - Any module definition implicitly ends at the next module definition, or the end of the file. MODULE can be immediately be followed by PROTO to provide a prototype for inheritance. The new module will inherit the functions and members belonging to the prototype (including the prototype of the prototype). VARs and MEMs can be declared after MODULE but before any DEFs to namespace them under the current module. Module related DEFs, STATIC DEFs and EXPORT DEFs, can be declared after VARs and MEMs. MODULEs can also be used as object-oriented classes if they contain a constructor function

example

MODULE MyMod PROTO MyProto
  VAR sharedVar = 42
  MEM instanceValue$ = "Default Value"

  STATIC DEF sharedPrint
    PRINT me.sharedVar
  END

  EXPORT DEF new(customValue$)
    me.instanceValue$ = customValue$
    return me
  END
END

Scoping in Modules

While working with object-oriented code, the variable names available to you will be changing depending on where in the program you are working. The variables currently "visible" and useable are considered to be "in scope". Scopes are recursive, if a variable isn't inside of a DEF SB will look in the Global Scope. When outside of a DEF: the scope will always be the Global Scope. This is where any standard DEFs and VARs live. When inside a STATIC DEF: ME is bound to the current MODULE. ME Lookups generate statically dispatched code referencing the MODULE directly. TYPE will dynamically dispatch to the current type of the first object instance on the stack. When inside an EXPORT DEF: ME is bound to the current object instance. ME Lookups will generate code that is dynamically dispatched at runtime. TYPE will dynamically dispatch to the current type of the first object instance on the stack.

example

VAR myVar$ = "outer"
MODULE MyMod PROTO MyProto
  VAR outer = 2
  MEM instance% = 3

  STATIC DEF sharedPrint
    VAR myVar$ = "inner"
    PRINT myVar$ # prints "inner"
    PRINT outer # not defined, prints 0
    PRINT me.outer # prints 2
    PRINT type.outer # could print any value set in a sub-module of MyMod.
  END

  EXPORT DEF new()
    return me
  END

  EXPORT DEF instancePrint
    PRINT me.instance% # prints 3
    PRINT instance% # not defined, prints 0
  END
END

The State of Scoping

Right now theres a bit of ambiguity as to whether your lookup will respect dynamic dispatch. ME uses both types. Languages such as Java solve this issue with something called Lexical Scoping. For example:
class MyClass {
  List[Int] myList = new ArrayList<Int>();

  public void doSomething() {
    System.out.println(myList);
  }
}
myList will reference the correct ArrayList, because doSomething is nested inside MyClass. In the future, I would love to add Lexical Scoping and deprecate the current workings of ME and TYPE. ME would always serve to do dynamic dispatch expecting a heap object. TYPE could be used for dynamic dispatch directly to the Module, skipping pointer dereferencing. And MODULE variables could be statically dispatched if found where it makes lexical sense without a lookup. The problem is, keeping track of these scopes requires either a linear search for every ID (slow down compilation by a significant factor) or an advanced data structure (need to do 2-pass compilation, or maintain a secondary temp file). This area is one of the focuses for Lowerdash 0.8.

Basics

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

DO

Level 2 <>

DO F$[,args...]

Call a function that would normally return something ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

To let people know you made a whoopsy, use ERR

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

ERR

Level 1 <>

ERR MSG$

Print the message, stack state, and memory Stop execution ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

example

ERR "Oh god! I am not good at petit computer!"

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

I appreciate that you take the time to make a documentation. It's good to see that the static method could be called with [module]_[method] instead of using the CALL command. I have some questions about the array how the VAR syntax: How the setter generated for arrays work? It assign the entire array or an index of the array?. Also, could we override the setters. I ask this because I'm considering to use lowerdash instead of SB3CC just for the namespace but I have modules that are like a POJO and I'm worried if I need to make too many changes on the name of the functions.

Replying to:raimondz
I appreciate that you take the time to make a documentation. It's good to see that the static method could be called with [module]_[method] instead of using the CALL command. I have some questions about the array how the VAR syntax: How the setter generated for arrays work? It assign the entire array or an index of the array?. Also, could we override the setters. I ask this because I'm considering to use lowerdash instead of SB3CC just for the namespace but I have modules that are like a POJO and I'm worried if I need to make too many changes on the name of the functions.
Thanks! The setter is generated the same for every type of variable. Its a simple function that sets the VAR to the passed in value. In the case of arrays, the setters will take an argument V that will have to be an array reference.
MODULE MyMod
VAR ARR[5]
...
VAR newArr[12]
MyMod_setARR newArr
Overriding setters is not currently possible, but does bring up a good point. The idea behind autogenerating the setters is to give you a way to do so from another slot. I usually code a more descriptive name when I want to have more side-effects than just setting the value. For the future, I may want to move the setter's name a little out of the way like _setARR. I'm sorry, I'm not sure what you meant with the part about POJOs. You can reuse the same DEFs in different namespaces. If you want to make function more generic, you can definitely pass references to functions and use a lookup.

Replying to:raimondz
I appreciate that you take the time to make a documentation. It's good to see that the static method could be called with [module]_[method] instead of using the CALL command. I have some questions about the array how the VAR syntax: How the setter generated for arrays work? It assign the entire array or an index of the array?. Also, could we override the setters. I ask this because I'm considering to use lowerdash instead of SB3CC just for the namespace but I have modules that are like a POJO and I'm worried if I need to make too many changes on the name of the functions.
Just to fill in a gap: You can assign individual indexes in an array the same as always.
MyMod_ARR[3] = 42

Can I change the category to "Additional Content" (new)? I want to keep "Tutorials" for actual SmileBASIC tutorials.

Replying to:haloopdy
Can I change the category to "Additional Content" (new)? I want to keep "Tutorials" for actual SmileBASIC tutorials.
Oh sorry, I've already changed it. We now have "Basic Tutorials" and "Advanced Tutorials", both of which are dedicated to SmileBASIC stuff.

Replying to:haloopdy
Can I change the category to "Additional Content" (new)? I want to keep "Tutorials" for actual SmileBASIC tutorials.
Sounds like a great idea!

Why do you use a non-standard _ as you would with dot syntax in JavaScript, C#, VB.NET, etc?

Replying to:MasterR3C0RD
Why do you use a non-standard _ as you would with dot syntax in JavaScript, C#, VB.NET, etc?
>Lowerdash >>_ >>>Lowerdash

Replying to:MasterR3C0RD
Why do you use a non-standard _ as you would with dot syntax in JavaScript, C#, VB.NET, etc?
> _ >> Underscore

Replying to:MasterR3C0RD
Why do you use a non-standard _ as you would with dot syntax in JavaScript, C#, VB.NET, etc?

Replying to:MasterR3C0RD
Why do you use a non-standard _ as you would with dot syntax in JavaScript, C#, VB.NET, etc?
... Nothing from Underscore.js is in Lowerdash?

Replying to:MasterR3C0RD
Why do you use a non-standard _ as you would with dot syntax in JavaScript, C#, VB.NET, etc?
It's a pun. It's a library, like underscorejs, but in smilebasic. So they decided on lowerdash. > - > Dash > _ > Lower It looks like a lower dash

Replying to:MasterR3C0RD
Why do you use a non-standard _ as you would with dot syntax in JavaScript, C#, VB.NET, etc?
As everyone else has already said, the name is a pun on the Underscore family of Javascript libraries. The real reason behind a "non-standard _" is that it doesn't fill the same role as dot syntax, and dot syntax is a different feature. _ is valid in SB variable and DEF names; by using it, you are literally typing the static name of the thing that you want. In those languages you listed, the dot serves as a way to pass a message to the object prior to the dot. The dot is asking the object what its response to the message is. This is accomplished through some lookup in some table. Compiled languages will do this early. Lowerdash does have a lookup, but because of how it currently parses code, catching every case where dot syntax is valid is almost impossible. With the move to REGEX things like me.myList$.get(3) are fully supported. ( that would be CALL(_(me("myList$"), "get"), 3) if you broke it down into lookups or were using 0.6.5 )

Would it be fine if I were to start making this in a Google Docs document because (Yes, I know I'm old school) I would like to be able to print this out in an easily printable format, and I figure, if I'm definitely going to work on it for personal reasons, why not make it for the public also!