Falcon is a language designed for App Inventor to enable syntax-based programming and for incorporating agenting coding abilities.
- Falcon follows 1-based indexing.
- Falcon variables are dynamically typed. Do not declare variables.
- Lists and dictionaries are passed as references.
- Falcon follows Kotlin's style of functional expressions.
- Falcon does not have a return statement; the last expression in a body is returned.
- Falcon does NOT have a try-catch or a throw statement.
- Only single-line comments using double slash
//are supported. - Do not use
_in place of unused variables - Variables can never be uninitialized.
- Always keep the last expression for returning functions.
- Always generate codes between ``` and code tag falcon.
- If the contents of two strings are numeric, then they can be numerically operated on, e.g.
"2" + "3.14"is a valid code.
- String
"Hello, world!" - Boolean
trueandfalse - Number
123and3.14 - List
[1, 2, 3, 4] - Dictionary
{"Animal": "Tiger", "Scientific Name": "Panthera tigris"} - Colour
#FFFFFF
- Arithmetic:
+,-,*,/,%(remainder),^(power) - Logical:
&&, and|| - Bitwise:
&,|,~(xor) - Equality:
==, and!= - Relational:
<,<=,>, and>= - Text lexicographic:
===(text equals),!==(text not equals),<<(text less than),>>(text greater than) - Unary:
!(not), and-(negate) - Join:
"Hello " _ "World!" - Pair:
"Fruit": "Mango" - Question (
?):- To check a value for a specific type (
text,number,list,dict)- E.g.,"Hello" ? text`
- Check for a number type (
number,base10,hexa,bin)- E.g.
"1010" ? binis a true expression.
- E.g.
- Check for empty text (
emptyText) or an empty list (emptyList)- E.g.
[] ? emptyListor"Cat" ? emptyText
- E.g.
- To check a value for a specific type (
Operator precedence
The precedence of an operator dictates its parse order. E.g. * and / is parsed before + and -.
It is similar to that of Java. Below is a ranking from the lowest to the highest precedence.
- Assignment
= - Pair
: - TextJoin
_ - LogicOr
|| - LogicAnd
&& - BitwiseOr
| - BitwiseAnd
& - BitwiseXor
~ - Equality
==,!=,===, and!== - Relational
<,<=,>,>=,<<, and>> - Binary
+, and- - BinaryL1
*,/, and% - BinaryL2
^
A global variable is always declared at the root:
global name = "Kumaraswamy B G"
// access the global variable
println(this.name)
local age = 17
// access the local variable
println(age)
If-else can be a statement or an expression depending on the context.
local x = 8
local y = 12
if (x > y) {
println("X is greater")
} else if (y > x) {
println("Y is greater")
} else {
println("They both are equal!")
}
Used an expression:
println( if (x > y) "X is greater" else if (y > x) "Y is greater" else "They both are equal!" )
local x = 8
while (true) {
x = x + 1
if (x == 5) {
break
}
}
for (i: 1 .. 10 step 2) {
println(i)
}
The step clause is optional and defaults to 1.
To iterate over a list:
local names = ["India", "Japan", "Russia", "Germany"]
for (country in names) {
println(country)
}
Or over a dictionary:
local animalInfo = { "Animal": "Tiger", "Scientific Name": "Panthera tigris" }
for (key, value in animalDetail) {
println(key _ " : " _ value) // e.g prints "Animal: Tiger" to the console
}
Functions are declared using the func keyword.
func fooBar(x, y) {
println(x + y)
}
Use the = symbol followed by an expression between curly braces.
func double(n) = { n * 2 }
Or multiple expressions:
func FibSum(n) = {
if (n < 2) {
n
} else {
FibSum(n - 1) + FibSum(n - 2)
}
}
Note that there is no return statement in Falcon. The last statement in a body is taken as the output of an expression.
-
dec(string),bin(string),octal(string),hexa(string)
Parse a static constant string from the respective base. e.g.bin("1010") -
sqrt(number) -
abs(number) -
neg(number) -
log(number) -
exp(number) -
round(number) -
ceil(number) -
floor(number) -
sin(number) -
cos(number) -
tan(number) -
asin(number) -
acos(number) -
atan(number) -
degrees(number) -
radians(number) -
decToHex(number) -
decToBin(number) -
hexToDec(number) -
binToDec(number) -
randInt(from, to) -
randFloat() -
setRandSeed(number)sets the random generator seed -
min(...)andmax(...) -
avgOf(list),maxOf(list),minOf(list),geoMeanOf(),stdDevOf(),stdErrOf() -
modeOf(list) -
mod(x, y),rem(x, y),quot(x, y)for modulus, remainder and quotient -
atan2(a, b) -
formatDecimal(number, places)
println(any)openScreen(name)opens an App Inventor screenopenScreenWithValue()opens App Inventor screen with a valuecloseScreenWithValue()closes the screen with a valgetStartValue()returns start value of the AppcloseSceen()closes current App Inventor screencloseApp()closes the Android AppgetPlainStartText()returns plain start text of the App
copyList(list)copyDict(dict)makeColor(rgb list)splitColor(number)
e.g. "Hello ".trim()
textLen()trim()uppercase()lowercase()startsWith(piece)contains(piece)containsAny(word list)containsAll(word list)split(at)splitAtFirst(at)splitAtAny(word list)splitAtFirstOfAny(word list)splitAtSpaces()reverse()csvRowToList()csvTableToList()segment(from number, length number)replace(target, replacement)replaceFrom(map dictionary)replaceFromLongestFirst(map dictionary)
listLen()add(any...)containsItem(any)indexOf(any)insert(at_index, any)remove(at_index)appendList(another list)lookupInPairs(key, notfound)join(text separator)slice(index1, index2)random()reverseList()toCsvRow()toCsvTable()sort()allButFirst()allButLast()pairsToDict()
dictLen()get(key)set(key, value)delete(key)getAtPath(path_list, notfound)setAtPath(path_list, value)containsKey(key)mergeInto(another_dict)walkTree(path)keys()values()toPairs()
local numbers = [1, 2, 4]
// access second element (1 based indexing)
println(numbers[2])
// change the first element
numbers[1] = 8
local animalInfo = { "Animal": "Tiger", "Scientific Name": "Panthera tigris" }
// Get a value by key
println(animalInfo.get("Scientific Name", "Not found"))
Inspired by Kotlin, list lambdas allow for list manipulation.
Maps each element of a list to a new value.
local numbers = [1, 2, 3]
// Double all the numbers
local doubled = numbers.map { n -> n * 2 }
println(doubled) // Output: [2, 4, 6]
Filters out unwanted elements.
local numbers = [1, 2, 3, 4]
// Filter for even numbers
local evens = numbers.filter { n -> n % 2 == 0 }
println(evens) // Output: [2, 4]
Helps to define a custom sort method.
Usage .sort { m, n -> bool_m_preceeds_n }
local names = ["Bob", "Alice", "John"]
// Sort names in descending order
local namesSorted = names
.sort { m, n -> m.textLen() > m.textLen() }
println(namesSorted) // Output: ["John", "Alice", "Bob"]
Sorts the elements in a list and returns the maximum or minimum value.
Usage .min { m, n -> bool_m_preceeds_n } and .max { m, n -> bool_m_preceeds_n }
local names = ["Bob", "Alice", "John"]
// Find the longest name
local longestName = names
.max { m, n -> n.textLen() > m.textLen() } // use min { } for the shortest name
println(longestName)
Reduce lambda reduces many elements to a single element.
Usage .reduce(initValue) { x, valueSoFar -> newValue }
local numbers = [1, 2, 3, 4, 5, 6, 7]
// Sum up all the numbers
local numbersSum = numbers.reduce(0) { x, valueSoFar -> x + valueSoFar }
println(numbersSum) // Output: 28
For example, let’s say Bob has a list of lemons sold per day for the last week and he’d like to calculate his revenue for lemon priced at $2 each.
The days he missed are marked as "N/A"
global LemonadeSold = [9, 12, "N/A", 15, 18, "N/A", 8]
Then we create a function that calculates the total revenue using list lambdas:
func GetTotalRevenue() = {
this.LemonadeSold
.filter { n -> n ? number } // Filters for numeric entries, "N/A" is dropped
.map { n -> n * 2 } // Multiply lemons sold in a day by the price of a lemon
.reduce(0) { x, soFar -> x + soFar } // Sum up all the entries
}
Now, when we call GetTotalRevenue():
println("Last week’s revenue was " _ GetTotalRevenue())
