Spellscript

From Hack/Mine Wiki
(Difference between revisions)
Jump to: navigation, search
(Lists)
 
(30 intermediate revisions by 7 users not shown)
Line 1: Line 1:
Spellscript is a programming language for Minecraft, introduced in Hack/Mine v0.6.4 and planned for eventual status as an independent Minecraft mod.  Spellscript allows you to mod Minecraft while in-game, ''no recompilation required.''  In other words, there's no installation hassle, no fiddling with jars, etc-- just writing or copy/pasting code into an in-game text editor, and you're done.  Minecraft objects are represented in Spellscript as first-class objects, just like they are in Java, allowing for all sorts of amazing possibilities...
+
{{stack begin}}
 +
 
 +
[[Image:ss_ide.png|400px|thumb|The Spellscript IDE displaying the contents of ''maze.ss'']]
 +
 
 +
{{stack mid}}
 +
 
 +
{{multiple image
 +
| align = right
 +
| direction = horizontal
 +
| width = 200
 +
| footer = Depth-first-search mazes generated with ''maze.ss''
 +
| footer_align = center
 +
 
 +
| image1 = mc_maze2.jpg
 +
| image2 = mc_maze1.jpg
 +
}}
 +
 
 +
{{stack mid}}
 +
 
 +
[[Image:mc_sphere1.jpg|200px|thumb|A sphere generated with ''sphere.ss'' and ''fill.ss'']]
 +
 
 +
{{stack end}}
 +
 
 +
Spellscript is a programming language for Minecraft, introduced in Hack/Mine v0.6.4 and planned for eventual status as an independent Minecraft mod.  Spellscript allows you to mod Minecraft while in-game, ''no recompilation required.''  In other words, there's no installation hassle, no fiddling with jars, etc-- just writing or copy/pasting code into an in-game text editor, and you're done.  Minecraft objects are represented in Spellscript as first-class objects, just like they are in Java, and you're given complete access to JVM libraries, allowing for all sorts of amazing possibilities...
  
 
Spellscript is still in the early development stages, so:
 
Spellscript is still in the early development stages, so:
*Note that the amount of things that can be modded is still growing (see the section below for currently available hooks)
+
*Note that the amount of things that can be scripted or modified is still growing (see the section below for currently available hooks)
 
*Be prepared to report bugs!
 
*Be prepared to report bugs!
  
Line 8: Line 31:
 
*For a Spellscript tutorial geared towards beginner programmers, see [[Spellscript Tutorial]].
 
*For a Spellscript tutorial geared towards beginner programmers, see [[Spellscript Tutorial]].
 
*For details on how to use the IDE (i.e. code editor), see [[Spellscript IDE]].
 
*For details on how to use the IDE (i.e. code editor), see [[Spellscript IDE]].
*For a list of bugs, see [[Spellscript Bugs]] (since we're in the initial release, this is a '''must read'''!)
+
*For a list of bugs, see [[Spellscript Bugs]] (since we're in the initial phases, this is a '''must read'''!)
 
*For a [http://www.sublimetext.com/2 Sublime Text 2] language package, see [http://www.mediafire.com/download.php?foak1j6b381huzz here].
 
*For a [http://www.sublimetext.com/2 Sublime Text 2] language package, see [http://www.mediafire.com/download.php?foak1j6b381huzz here].
 
*For a general-purpose language reference, read on...
 
*For a general-purpose language reference, read on...
  
 
==Spellscript Hooks in Hack/Mine==
 
==Spellscript Hooks in Hack/Mine==
Hack/Mine outsources a growing amount of its functionality to Spellscript, such that users can thoroughly customize their RPG experience.  Currently, all of the spells and item effects are implemented with Spellscript.  Also, currently, '''only admins can create Spellscript scripts!'''  Of course, users can ''run'' these scripts, provided they've been setup to do so.
+
Hack/Mine outsources a growing amount of its functionality to Spellscript, such that users can thoroughly customize their RPG experience.  Currently, all of the spells and item effects are implemented with Spellscript.  Also, currently, '''only admins and ops can create Spellscript scripts!'''  Of course, users can ''run'' these scripts, provided they've been setup to do so.
  
 
Admins may currently employ Spellscript in the following ways:
 
Admins may currently employ Spellscript in the following ways:
  
 
===In-Game Hooks===
 
===In-Game Hooks===
*Spellscript-Blocks (placeable from the Creative Inventory)
+
*[[Spellscript blocks]] (placeable from the Creative Inventory)
*Script-Scheduling (brought up by pressing 'tilde' by default)
+
*[[Schedulable scripts]] (brought up by pressing 'tilde' by default)
 +
*[[Console scripts]] (brought up via 'ss edit <scriptName>')
  
 
===External Hooks===
 
===External Hooks===
Line 26: Line 50:
  
 
==Language Mechanics==
 
==Language Mechanics==
{{mbox|text=This section is totally a work-in-progress, y'all. Expect updates over the next several days!}}
+
{{mbox|text=This section is totally a work-in-progress, y'all.}}
 
{{mbox|text=Note: you'll need to be viewing Minecraft's console output if you want to see expressions output via the ''print'' statement ([[Viewing Spellscript Output|instructions]]).}}
 
{{mbox|text=Note: you'll need to be viewing Minecraft's console output if you want to see expressions output via the ''print'' statement ([[Viewing Spellscript Output|instructions]]).}}
  
Line 34: Line 58:
 
At the highest level, Spellscript is a list of ''statements''.  As mentioned, lexical scoping is accomplished in Spellscript via indentation.  Additionally, statements in Spellscript are delimited with newlines-- semi-colons may be used to concatenate statements into a single-line snippet of code.
 
At the highest level, Spellscript is a list of ''statements''.  As mentioned, lexical scoping is accomplished in Spellscript via indentation.  Additionally, statements in Spellscript are delimited with newlines-- semi-colons may be used to concatenate statements into a single-line snippet of code.
  
Here's the context-free grammar (CFG) for Spellscript-- note that "decl" is short for "declaration", and that ''identifiers'' are any string of characters containing only letters, numbers, and underscores, and beginning with a letter:
+
Here's the context-free grammar (CFG) for Spellscript-- note that "decl" is short for "declaration", and that ''identifiers'' are any string of characters containing only letters, numbers, and underscores, and not beginning with a number:
 
  <nowiki><script> => <statement_list>
 
  <nowiki><script> => <statement_list>
  
Line 54: Line 78:
 
<inner_var_decl> => IDENTIFIER ['=' <expression>] [',' <inner_var_decl>]
 
<inner_var_decl> => IDENTIFIER ['=' <expression>] [',' <inner_var_decl>]
  
<type> => <basic_type> | (<type> '[' ']') | <func_ptr_type>
+
<type> => <basic_type> | <class_type> | (<type> '[' ']') | <func_ptr_type>
 +
<basic_type> => 'bool' | 'int' | 'float' | 'double' | 'str'
 +
<class_type> => IDENTIFIER ['<' <class_type> {',' <class_type>} '>']
 
<func_ptr_type> => <type> '$' '(' [<type> {',' <type>}] ')'
 
<func_ptr_type> => <type> '$' '(' [<type> {',' <type>}] ')'
<basic_type> => 'bool' | 'int' | 'float' | 'double' | 'string' | IDENTIFIER
 
  
<assignment> => IDENTIFIER ('=' | '+=' | '-=' | '/=' | '%=') <expression></nowiki>
+
<assignment> => IDENTIFIER ('=' | '+=' | '-=' | '/=' | '%=')<expression></nowiki>
  
 
''expression'',  ''control_statement'', ''function_decl'', ''class_decl'', will all be defined later.
 
''expression'',  ''control_statement'', ''function_decl'', ''class_decl'', will all be defined later.
  
 
===Type System===
 
===Type System===
Spellscript features classes, strings, lists, and function pointers (which follow a pass-by-reference model), and primitive types (which follow a pass-by-value model).  The primitive types are ''bool'', ''int'', ''float'', and ''double''.
+
Spellscript features classes and function pointers (which follow a pass-by-reference model) along with primitive types (which follow a pass-by-value model).  The primitive types are analagous to those of Java: ''bool'', ''long'', ''int'', ''short'', ''char'', ''byte'', ''float'', and ''double''.
  
 
Assuming you had a class ''MyClass'' in scope, and a function ''int someFunction(int, float)'' in scope, some variable declarations would look like...
 
Assuming you had a class ''MyClass'' in scope, and a function ''int someFunction(int, float)'' in scope, some variable declarations would look like...
Line 70: Line 95:
 
float f = 2f
 
float f = 2f
 
double d = 1d
 
double d = 1d
string s = "Hello world!"
+
str s = "Hello world!"
string t = None
+
str t = None
 
MyClass m = MyClass()
 
MyClass m = MyClass()
 
int$(int, float) funcPtr = someFunction</nowiki>
 
int$(int, float) funcPtr = someFunction</nowiki>
 +
 +
Furthermore, Spellscript features the ''var'' keyword, analagous to that of C#.  A variable declaration with ''var'' will infer the type of the declaration for you, at compile-time.
 +
 +
<nowiki>var mc = MyClass()
 +
var s = "Hi again!"
 +
var fp = someFunction</nowiki>
  
 
A notable distinction from Python is that variables '''must''' be declared before they are used.
 
A notable distinction from Python is that variables '''must''' be declared before they are used.
 +
 +
====Generic Types====
 +
Spellscript also features generic types, analogous to those of Java.  Classes may accept ''type parameters'' when instantiated, which the current implementation erases at compile-time.  Methods may also accept type parameters, which the compiler will infer if omitted from method calls.  [http://docs.oracle.com/javase/tutorial/java/generics/ This tutorial on Java generics] would be an excellent read on the topic, especially since there are only a few differences in generics between Spellscript and Java.
 +
 +
Generics in Spellscript currently differ from those of Java in the following ways:
 +
*There are no "raw types"
 +
*Regarding wildcards, "? extends X" and "? super X" are replaced with "out X" and "in X", respectively.
 +
*While type parameters may be passed (e.g., to existing methods in Java libraries), type parameters have yet to be made declarable.  I.e., you cannot yet define classes or methods accepting type parameters.
  
 
===Expressions===
 
===Expressions===
The best way to describe expressions in a language is define some basic literals and the operations available on them, along with their order of precedence.  So, here you are...
+
The best way to describe expressions in a language is to define some basic literals and the operations available on them, along with their order of precedence.  So, here you are...
  
 
====Literals====
 
====Literals====
Line 101: Line 140:
  
 
Note that all reference-types (strings, class instances, function pointers, etc) may be assigned ''None''.
 
Note that all reference-types (strings, class instances, function pointers, etc) may be assigned ''None''.
 +
 +
Literals for all primitives are still being added, but until then, you may safely rely on implicit and explicit coercion to do the job.  (In the case of literals, the coercion will generally occur at compile-time.)
  
 
====Operations====
 
====Operations====
Line 119: Line 160:
 
| Right-to-Left
 
| Right-to-Left
 
|-
 
|-
! instanceof, as
+
! isa, isnota, as
| Type Test, Safe-Cast
+
| Type Tests, Safe-Cast/Coercion
 
| --
 
| --
 
|-
 
|-
Line 129: Line 170:
 
! and
 
! and
 
| Boolean AND
 
| Boolean AND
 +
| Left-to-Right
 +
|-
 +
! not ''x''
 +
| Inversion
 +
| Right-to-Left
 +
|-
 +
! in, not in
 +
| Containment Testing
 
| Left-to-Right
 
| Left-to-Right
 
|-
 
|-
 
! < <= >= >
 
! < <= >= >
 
| Comparison
 
| Comparison
| Right-to-Left
+
| Left-to-Right
 
|-
 
|-
 
! + -
 
! + -
Line 143: Line 192:
 
| Left-to-Right
 
| Left-to-Right
 
|-
 
|-
! not ''x'', -''x''
+
! -''x''
| Inversion, Negation
+
| Negation
 
| Right-to-Left
 
| Right-to-Left
 
|-
 
|-
Line 166: Line 215:
 
                     ('if' | 'elif') <expression>
 
                     ('if' | 'elif') <expression>
 
                     'else'
 
                     'else'
                     'for' [<type>] IDENTIFIER 'in' <expression> ['to' <expression>]</nowiki>
+
                     'for' [<type>] IDENTIFIER 'in' <expression> ['to' <expression>]
 +
                    'try'
 +
                    'except' <type> IDENTIFIER
 +
                    'finally'</nowiki>
 
And here are some use cases:
 
And here are some use cases:
 
  <nowiki>int i = 0
 
  <nowiki>int i = 0
Line 189: Line 241:
  
 
for i in 0 to 15:
 
for i in 0 to 15:
     print i</nowiki>
+
     print i
 +
 
 +
try:
 +
    print "try!"
 +
except Error e:
 +
    print e
 +
finally:
 +
    print "finally!"</nowiki>
  
 
Careful with the looping constructs: as with any programming language, getting stuck in an infinite loop is a real possibility.
 
Careful with the looping constructs: as with any programming language, getting stuck in an infinite loop is a real possibility.
Line 195: Line 254:
 
The for loop can iterate over either a list or a range of integers over ''[bound1..bound2)''.  Note that if the second bound is less than or equal to the first, no iteration will take place.  Also, note that if the for loop's optional component is omitted and the first bound is an integer, it will treat the first bound as "0" and the second bound as the one it was given.
 
The for loop can iterate over either a list or a range of integers over ''[bound1..bound2)''.  Note that if the second bound is less than or equal to the first, no iteration will take place.  Also, note that if the for loop's optional component is omitted and the first bound is an integer, it will treat the first bound as "0" and the second bound as the one it was given.
  
''break'' and ''continue'' statements are available within the ''while'', ''until'', and ''for'' control-statements.  The ''break'' statement will exit the inner-most applicable construct, whereas ''continue'' will skip to its next iteration.  The ''return'' statement has the effect of ceasing all control-statements immediately, up until the "top level" is reached (generally, the current function declaration's lowest scope).  Naturally, if the function has a return type, ''return <value>'' may be used to return that value.  (If no return type is specified but values are given, one will be inferred for the function declaration.)
+
''break'' and ''continue'' statements are available within the ''while'', ''until'', and ''for'' control-statements.  The ''break'' statement will exit the inner-most applicable construct, whereas ''continue'' will skip to its next iteration.  The ''return'' statement has the effect of ceasing all control-statements immediately, up until the "top level" is reached (generally, the current function declaration's highest scope).  Naturally, if the function has a return type, ''return <value>'' may be used to return that value.  (If no return type is specified but values are given, one will be inferred for the function declaration.)
  
 
===Lists===
 
===Lists===
A list is an ordered collection of objects.  Lists have an "inner type", which limits which kinds of objects can be added to them (but also guarantee which kind of objects we retrieve from them.) Here's an example of list creation and usage:
+
A List is an ordered collection of objects.  Lists have one type parameter, which limits which kinds of objects can be added to them, but guarantee which kind of objects we retrieve from them.  Here's an example of List creation and usage:
  
 
  <nowiki>int[] numbers = [2, 4, 5, 4]
 
  <nowiki>int[] numbers = [2, 4, 5, 4]
float[] reals = [float: 0f, 1f, 4f]
+
float[] reals = <float>[0f, 1f, 4f]
int[] emptyList = [int:]
+
int[] emptyList = <int>[]
  
for int n in numbers:
+
for var n in numbers:
 
     print n
 
     print n
  
numbers.append(17)
+
numbers.add(17)
  
 
for int i in numbers.size():
 
for int i in numbers.size():
 
     print numbers[i]
 
     print numbers[i]
  
for int j in [1, 2, 3, 4, 5]:
+
for var j in [1, 2, 3, 4, 5]:
 
     print j</nowiki>
 
     print j</nowiki>
  
Line 220: Line 279:
  
 
Finally, we show a convenient way of iterating through some specific numbers, simply by instantiating the list in the for loop's declaration.
 
Finally, we show a convenient way of iterating through some specific numbers, simply by instantiating the list in the for loop's declaration.
 +
 +
===Maps===
 +
A Map is a collection of associations from one type of object to another (keys and values, respectively).  Essentially, values may be added to the Map along with a unique key, by which the value may later be retrieved.  Maps accept two type parameters, for types of keys and values, respectively.
 +
 +
<nowiki>var animalNoises = { "dog" : "bark", "duck" : "quack" }
 +
Map<Str, Int> bookRankings = { "Huck Finn" : 4, "The Grapes of Wrath" : 1 }
 +
Map<Int, Int> emptyMap = <Int, Int>{}
 +
 +
print "Animal noises:"
 +
 +
for var entry in animalNoises.entrySet():
 +
    print "The " + entry.getKey() + " goes '" + entry.getValue() + "'!"
 +
 +
animalNoises["frog"] = "ribbit"
 +
animalNoises["cow"] = "moo"
 +
 +
print ""
 +
print "New noises:"
 +
 +
for var key in animalNoises.keySet():
 +
    print "The " + key + " goes '" + animalNoises[key] + "'!"</nowiki>
 +
 +
At the beginning, you'll notice the map's types may be either explicitly given or omitted-- if the map is empty, the type ''must'' be made explicit, or else the compiler won't be able to deduce it's types and will throw an error.
 +
 +
We then iterate through each entry of the map, and print it to the console.  Next, we add a few entries to the map, then print the whole thing again.
  
 
===Functions===
 
===Functions===
 
A function is essentially a snippet of code that can be defined then executed later (or 'declared' and 'called' later, in programmer jargon).  Functions can accept ''parameters'', which are basically variables you can pass it which can in turn be used by the function itself.  Functions may also optionally ''return'' a variable to the caller.  The CFG for a function declaration is as follows:
 
A function is essentially a snippet of code that can be defined then executed later (or 'declared' and 'called' later, in programmer jargon).  Functions can accept ''parameters'', which are basically variables you can pass it which can in turn be used by the function itself.  Functions may also optionally ''return'' a variable to the caller.  The CFG for a function declaration is as follows:
  <nowiki><function_decl> => 'def' [<return_type>] IDENTIFIER '(' [<param_list>] ')' ':' <suite>
+
  <nowiki><function_decl> => 'def' IDENTIFIER '(' [<param_list>] ')' ['as' <return_type>] ':' <suite>
  
 
<return_type> => <type>
 
<return_type> => <type>
Line 240: Line 324:
 
helloWorld()
 
helloWorld()
  
def int foo(int a, int b):
+
def foo(int a, int b) as int:
 
     return a + b
 
     return a + b
  
Line 265: Line 349:
 
''<field_decl>'' is a special kind of variable declaration, since it must not be an assignment-declaration (this may be supported in the future.)  For now, initial assignments should occur in the ''constructor'', which will be discussed later.
 
''<field_decl>'' is a special kind of variable declaration, since it must not be an assignment-declaration (this may be supported in the future.)  For now, initial assignments should occur in the ''constructor'', which will be discussed later.
  
''<method_decl>'' is a special kind of function declaration.  Firstly, its first parameter must be ''self'', which refers to the class instance itself-- it must not have a ''<type>'' preceding it, as it's inferred automatically.  Secondly, 'def' may be replaced with 'redef' if requirement of an overridden method is desired.
+
In the case of ''<method_decl>'', 'def' may be replaced with 'redef' if requirement of an overridden method is desired.  Also note that, unlike Python (and as was previously required), there is no 'self' parameter on methods.
  
 
Here's an example class declaration, creation, and method call:
 
Here's an example class declaration, creation, and method call:
Line 272: Line 356:
 
     int my_field
 
     int my_field
  
     def __init__(self):
+
     def __init__():
 
         self.my_field = 2
 
         self.my_field = 2
  
     def someMethod(self, int i):
+
     def someMethod(int i):
 
         return self.my_field * i
 
         return self.my_field * i
  
Line 290: Line 374:
 
Function pointers' syntax is highly subject to change at the time of this writing, so if things stop working (or there's any general doubt), consult this section of the wiki for the current syntax.
 
Function pointers' syntax is highly subject to change at the time of this writing, so if things stop working (or there's any general doubt), consult this section of the wiki for the current syntax.
  
The type of a function pointer is declared as follows: ''<param_type> '$' ([<param_type> {',' <param_type>}])''
+
The type of a function pointer is declared as follows: ''<param_type> '$' '(' [<param_type> {',' <param_type>}] ')' ''
  
The simplest way to reference a function declaration as a function pointer is to use its name, without parenthesis at the end.  However, this will cause a compilation error if the call is ambiguous (suppose the function/method is overloaded)-- thus, to clarify, one can use the following syntax: ''<function name> ('$' '(' ')' | ['$'] '(' '$' <param_type> {',' '$' <param_type>} ')') '' Notice how a lack of parameter types requires a '$' to be included before the parenthesis, otherwise it would be ambiguous with a function call.  This complexity is part of the reason the syntax may be revised in the future.
+
Meanwhile, a function pointer is ''referenced'' as follows: '' 'IDENTIFIER '$' '(' [<param> {',' <param>}] ')' '', where ''<param>'' is '' '$'<param_type> | <expression>''
  
 
Here's some code to demonstrate valid usage:
 
Here's some code to demonstrate valid usage:
Line 312: Line 396:
 
# 7 should be printed to the console</nowiki>
 
# 7 should be printed to the console</nowiki>
  
This is implicitly what happens when a function pointer is referenced from a class instance (i.e. the instance is bound to the function pointer as the ''self'' parameter).
+
This is implicitly what happens when a function pointer is referenced from a class instance (i.e. the instance is bound to the function pointer as the hidden ''self'' parameter).

Latest revision as of 04:46, 1 September 2014

The Spellscript IDE displaying the contents of maze.ss
Depth-first-search mazes generated with maze.ss
A sphere generated with sphere.ss and fill.ss

Spellscript is a programming language for Minecraft, introduced in Hack/Mine v0.6.4 and planned for eventual status as an independent Minecraft mod. Spellscript allows you to mod Minecraft while in-game, no recompilation required. In other words, there's no installation hassle, no fiddling with jars, etc-- just writing or copy/pasting code into an in-game text editor, and you're done. Minecraft objects are represented in Spellscript as first-class objects, just like they are in Java, and you're given complete access to JVM libraries, allowing for all sorts of amazing possibilities...

Spellscript is still in the early development stages, so:

  • Note that the amount of things that can be scripted or modified is still growing (see the section below for currently available hooks)
  • Be prepared to report bugs!

Contents

[edit] Important Places

  • For a Spellscript tutorial geared towards beginner programmers, see Spellscript Tutorial.
  • For details on how to use the IDE (i.e. code editor), see Spellscript IDE.
  • For a list of bugs, see Spellscript Bugs (since we're in the initial phases, this is a must read!)
  • For a Sublime Text 2 language package, see here.
  • For a general-purpose language reference, read on...

[edit] Spellscript Hooks in Hack/Mine

Hack/Mine outsources a growing amount of its functionality to Spellscript, such that users can thoroughly customize their RPG experience. Currently, all of the spells and item effects are implemented with Spellscript. Also, currently, only admins and ops can create Spellscript scripts! Of course, users can run these scripts, provided they've been setup to do so.

Admins may currently employ Spellscript in the following ways:

[edit] In-Game Hooks

[edit] External Hooks

  • Command-line Access
  • Files in the ".minecraft/spells" directory

[edit] Language Mechanics

Spellscript is best construed as a healthy mix of Java and Python. Like Java, it is statically typed and features single-inheritance. Like Python, lexical scopes are signified by indentation and the syntax is relatively terse. Where Java would normally require explicit typing, Spellscript does its best to infer type implicitly. Where Python's flexibility allows unsound behavior, Spellscript introduces robustness to keep things sane.

[edit] Basic Syntax

At the highest level, Spellscript is a list of statements. As mentioned, lexical scoping is accomplished in Spellscript via indentation. Additionally, statements in Spellscript are delimited with newlines-- semi-colons may be used to concatenate statements into a single-line snippet of code.

Here's the context-free grammar (CFG) for Spellscript-- note that "decl" is short for "declaration", and that identifiers are any string of characters containing only letters, numbers, and underscores, and not beginning with a number:

<script> => <statement_list>

<statement_list> => <statement_line> [NEW_LINE <statement_list>]

<statement_line> => <statement> [';' <statement_line>]

<statement> => 'pass'
               'print' <expression>
               <variable_decl>
               <assignment>
               <control_statement>
               <function_decl>
               <class_decl>
               'return' [<expression>]
               'break' | 'continue'

<variable_decl> => <type> <inner_var_decl>
<inner_var_decl> => IDENTIFIER ['=' <expression>] [',' <inner_var_decl>]

<type> => <basic_type> | <class_type> | (<type> '[' ']') | <func_ptr_type>
<basic_type> => 'bool' | 'int' | 'float' | 'double' | 'str'
<class_type> => IDENTIFIER ['<' <class_type> {',' <class_type>} '>']
<func_ptr_type> => <type> '$' '(' [<type> {',' <type>}] ')'

<assignment> => IDENTIFIER ('=' | '+=' | '-=' | '/=' | '%=')<expression>

expression, control_statement, function_decl, class_decl, will all be defined later.

[edit] Type System

Spellscript features classes and function pointers (which follow a pass-by-reference model) along with primitive types (which follow a pass-by-value model). The primitive types are analagous to those of Java: bool, long, int, short, char, byte, float, and double.

Assuming you had a class MyClass in scope, and a function int someFunction(int, float) in scope, some variable declarations would look like...

bool b = True
int i = 3
float f = 2f
double d = 1d
str s = "Hello world!"
str t = None
MyClass m = MyClass()
int$(int, float) funcPtr = someFunction

Furthermore, Spellscript features the var keyword, analagous to that of C#. A variable declaration with var will infer the type of the declaration for you, at compile-time.

var mc = MyClass()
var s = "Hi again!"
var fp = someFunction

A notable distinction from Python is that variables must be declared before they are used.

[edit] Generic Types

Spellscript also features generic types, analogous to those of Java. Classes may accept type parameters when instantiated, which the current implementation erases at compile-time. Methods may also accept type parameters, which the compiler will infer if omitted from method calls. This tutorial on Java generics would be an excellent read on the topic, especially since there are only a few differences in generics between Spellscript and Java.

Generics in Spellscript currently differ from those of Java in the following ways:

  • There are no "raw types"
  • Regarding wildcards, "? extends X" and "? super X" are replaced with "out X" and "in X", respectively.
  • While type parameters may be passed (e.g., to existing methods in Java libraries), type parameters have yet to be made declarable. I.e., you cannot yet define classes or methods accepting type parameters.

[edit] Expressions

The best way to describe expressions in a language is to define some basic literals and the operations available on them, along with their order of precedence. So, here you are...

[edit] Literals

Type Literals
bool True, False
int 0, -15, 2, 0xf931, etc
float 3.1412f, 1f, -3.f, 0F, .1F, etc
double 3.1412, 1., -3d, 0D, etc
string None, "hello world", "oh hai!", "", etc

Note that all reference-types (strings, class instances, function pointers, etc) may be assigned None.

Literals for all primitives are still being added, but until then, you may safely rely on implicit and explicit coercion to do the job. (In the case of literals, the coercion will generally occur at compile-time.)

[edit] Operations

This table lists all the available operations in their order of precedence. In other words, operations towards the top of the table are bound later than operations toward the bottom (so for example, a and b or c and d would be executed as (a and b) or (c and d))

Operator Description Order
= += -= *= /= %= Assignment, Compound Assignment Right-to-Left
is, is not Identity Tests Right-to-Left
== != Equality Tests Right-to-Left
isa, isnota, as Type Tests, Safe-Cast/Coercion --
or Boolean OR Left-to-Right
and Boolean AND Left-to-Right
not x Inversion Right-to-Left
in, not in Containment Testing Left-to-Right
< <= >= > Comparison Left-to-Right
+ - Addition, Subtraction Left-to-Right
* / % Multiplication, Division, Modulo Left-to-Right
-x Negation Right-to-Left
** Exponentiation Right-to-Left
x.y, x[y], (x) Method/Field Reference, Array Indexing, Grouping Left-to-Right

[edit] Control Statements

The general structure of a <control statement> is as follows:

<control_statement> => <control_header> ':' <suite>

<suite> => <statement_line>
           INDENT <statement_list> UNINDENT

<control_header> => ('while' | 'until') <expression>
                    ('if' | 'elif') <expression>
                    'else'
                    'for' [<type>] IDENTIFIER 'in' <expression> ['to' <expression>]
                    'try'
                    'except' <type> IDENTIFIER
                    'finally'

And here are some use cases:

int i = 0

while i < 15:
    print "loop!"
    i += 1

until i <= 0:
    print "more loop!"
    i -= 1

if i == 0:
    print "yep, i sure is 0!"
elif i > 0:
    print "i is positive!"
else:
    print "i is negative!"

for i in [3, 4, 2, 17]:
    print i

for i in 0 to 15:
    print i

try:
    print "try!"
except Error e:
    print e
finally:
    print "finally!"

Careful with the looping constructs: as with any programming language, getting stuck in an infinite loop is a real possibility.

The for loop can iterate over either a list or a range of integers over [bound1..bound2). Note that if the second bound is less than or equal to the first, no iteration will take place. Also, note that if the for loop's optional component is omitted and the first bound is an integer, it will treat the first bound as "0" and the second bound as the one it was given.

break and continue statements are available within the while, until, and for control-statements. The break statement will exit the inner-most applicable construct, whereas continue will skip to its next iteration. The return statement has the effect of ceasing all control-statements immediately, up until the "top level" is reached (generally, the current function declaration's highest scope). Naturally, if the function has a return type, return <value> may be used to return that value. (If no return type is specified but values are given, one will be inferred for the function declaration.)

[edit] Lists

A List is an ordered collection of objects. Lists have one type parameter, which limits which kinds of objects can be added to them, but guarantee which kind of objects we retrieve from them. Here's an example of List creation and usage:

int[] numbers = [2, 4, 5, 4]
float[] reals = <float>[0f, 1f, 4f]
int[] emptyList = <int>[]

for var n in numbers:
    print n

numbers.add(17)

for int i in numbers.size():
    print numbers[i]

for var j in [1, 2, 3, 4, 5]:
    print j

At the beginning, you'll notice the list type may be either explicitly given or omitted-- if the list is empty, the type must be made explicit, or else the compiler won't be able to deduce it's type and will throw an error.

We then iterate through each element of the list, and print it to the console. Next, we append '17' to the list, then print the whole thing again.

Finally, we show a convenient way of iterating through some specific numbers, simply by instantiating the list in the for loop's declaration.

[edit] Maps

A Map is a collection of associations from one type of object to another (keys and values, respectively). Essentially, values may be added to the Map along with a unique key, by which the value may later be retrieved. Maps accept two type parameters, for types of keys and values, respectively.

var animalNoises = { "dog" : "bark", "duck" : "quack" }
Map<Str, Int> bookRankings = { "Huck Finn" : 4, "The Grapes of Wrath" : 1 }
Map<Int, Int> emptyMap = <Int, Int>{}

print "Animal noises:"

for var entry in animalNoises.entrySet():
    print "The " + entry.getKey() + " goes '" + entry.getValue() + "'!"

animalNoises["frog"] = "ribbit"
animalNoises["cow"] = "moo"

print ""
print "New noises:"

for var key in animalNoises.keySet():
    print "The " + key + " goes '" + animalNoises[key] + "'!"

At the beginning, you'll notice the map's types may be either explicitly given or omitted-- if the map is empty, the type must be made explicit, or else the compiler won't be able to deduce it's types and will throw an error.

We then iterate through each entry of the map, and print it to the console. Next, we add a few entries to the map, then print the whole thing again.

[edit] Functions

A function is essentially a snippet of code that can be defined then executed later (or 'declared' and 'called' later, in programmer jargon). Functions can accept parameters, which are basically variables you can pass it which can in turn be used by the function itself. Functions may also optionally return a variable to the caller. The CFG for a function declaration is as follows:

<function_decl> => 'def' IDENTIFIER '(' [<param_list>] ')' ['as' <return_type>] ':' <suite>

<return_type> => <type>

<param_list> => <parameter> [',' <param_list>]

<parameter> => <type> IDENTIFIER

<suite> => <statement_line>
           INDENT <statement_list> UNINDENT

And here are some example function declarations and calls:

def helloWorld():
    print "Hello world!"

# Print "Hello world!" to the console
helloWorld()

def foo(int a, int b) as int:
    return a + b

# Print '5' to the console
print foo(2, 3)

# This time, we omit the return type and Spellscript infers it automatically
def bar(int x):
    return x * 2

# Print '14' to the console
print bar(foo(3, 4))

[edit] Classes and Objects

Like many programming languages, Spellscript is object-oriented. This basically means you can organize your code into classes (or types), creates instances of those classes, then pass those instances around just like any other variable. Special functions called methods may bound to classes, and called through instances of those classes via the dot operator ('.'). Variables termed fields may also be bound to classes, meaning instances of those classes will have those variables bound to them, and may also be accessed via the dot operator.

In Spellscript, classes may also inherit from other classes and override their methods (in C++ jargon, all methods in Spellscript are virtual). Spellscript follows a single-inheritance model, and will feature Java-style multiple-inheritance with interfaces in the future.

The CFG for a class declaration is as follows:

<class_decl> => 'class' IDENTIFIER ['(' IDENTIFIER ')'] ':' INDENT ('pass' | <class_body>) UNINDENT

<class_body> => <method_decl> | <field_decl> [NEWLINES <class_body>]

<field_decl> is a special kind of variable declaration, since it must not be an assignment-declaration (this may be supported in the future.) For now, initial assignments should occur in the constructor, which will be discussed later.

In the case of <method_decl>, 'def' may be replaced with 'redef' if requirement of an overridden method is desired. Also note that, unlike Python (and as was previously required), there is no 'self' parameter on methods.

Here's an example class declaration, creation, and method call:

class MyClass:

    int my_field

    def __init__():
        self.my_field = 2

    def someMethod(int i):
        return self.my_field * i

MyClass some_class = MyClass()
print some_class.someMethod(3)

# prints "6" to the console!

You'll notice two method definitions in the class body: the first is a special method called the constructor, whereas the second is just a regular method accepting one parameter, i. In the above example, calling "some_class.someMethod(3)" passes "some_class" as the self parameter and 3 as the i parameter.

The constructor is declared by specifying a method with name __init__, and is called when the class is first instantiated. Like any other method, it can accept an arbitrary set of parameters; however, its return type must remain unspecified. A class instantiation is simply a function call with the class's name as the function name, and a set of parameters passed to it as defined by the constructor-- the newly created class instance is the instantiation's return value.

[edit] Function Pointers

Function pointers' syntax is highly subject to change at the time of this writing, so if things stop working (or there's any general doubt), consult this section of the wiki for the current syntax.

The type of a function pointer is declared as follows: <param_type> '$' '(' [<param_type> {',' <param_type>}] ')'

Meanwhile, a function pointer is referenced as follows: 'IDENTIFIER '$' '(' [<param> {',' <param>}] ')' , where <param> is '$'<param_type> | <expression>

Here's some code to demonstrate valid usage:

def globalFunc(int i, int j):
  return i + j

def execute(int$(int, int) func, int a, int b):
  return func(a, b)
  
print execute(globalFunc($int, $int), 4, 5)

Function pointers can also have variables bound to them, resulting in a function pointer with the newly bound parameters removed. Consider the following:

def globalFunc(int i, int j):
  return i + j

int$(int) ptr = globalFunc$($int, 3)
print ptr(4)
# 7 should be printed to the console

This is implicitly what happens when a function pointer is referenced from a class instance (i.e. the instance is bound to the function pointer as the hidden self parameter).

Personal tools
Namespaces

Variants
Actions
Navigation
Toolbox