Favascript is a small, statically typed language that compiles down to Javascript. Notably, Favascript borrows simple syntax and type inference from Python, curly braces from Javascript and simplified matching from OCaml. Favascript's goal is to enable the programmer to sketch out ideas quickly. Explicit type declaration will be left later for programs like Java or C. Favascript is a testbed for ideas. For example, the language is designed with a minimalistic approach to reduce the amount of time programmers have to spend typing a worrying about types and language-specific syntax. Similarly, Favascript incorporates simple matching and the for-in loop to produce an easier coding experience.
Favascript's most notable features include type inference, first class functions and higher-order functions. Types are never declared in Favascript - the language is not only able to infer types, but able to catch errors when implied types may be incompatible with the code. The language is also able to automatically convert between integers and floats if the given operation allows it. Constants are inferred through their all-capital identifiers.
Taking inspiration from Python and OCaml, first class functions and higher-order functions enable Favascript to be highly expressive. Functions may be passed as arguments and used as parameters. Optional function parameters also make Favascript's functions more useful.
- .fav File Extension
- Curly Braces
- Simple Matching
- Object-oriented
- First Class Functions
- Higher Order Functions
- Type Inference
- Static Typing
- Strong Typing
- Optional Parameters
- Additive:
+
,-
- Multiplicative:
*
,/
,//
- Exponentiation:
^
- Relational:
<
,>
,>=
,<=
,==
,!=
- Boolean:
&&
,||
- Int:
4
,8
,666
- Float:
4.0
,3.1415926
,0.7734
- Boolean:
true
,false
- String:
“fava”
,“Don’t throw favas in the lavas”
,“The fava said, \“I am delicious.\””
- List:
[1, 2, 3, 4, 5]
,["I", "like", "fava", "beans"]
- Tuple:
(30, 0.5, “fava”)
- Dictionary:
{key:“value”, bestColor:“fava”, worstLanguage: “php”}
- Comments:
# Single line comment
Favascript on the left, Javascript on the right
Variable Declarations
name = "fav" let name = “fav”
age = 21 var age = 21
female = true let female = true
Constant Declarations
PI = 3.14159265359 const PI = 3.14159265359
Arithmetic
x = ((2 + 3) * (6 - 1) ^ 2) / 4 x = ((2 + 3) * Math.pow((6 - 1), 2)) / 4
While Statements
while true { while (true) {
ret true return true
} }
Conditional Statements
x == 2 ? x -= 1 : x += 1 (x == 2) ? x -= 1 : x += 1
Match Statements
match fruit with
| pear -> puke.exe() if (fruit == pear) { puke.exe(); }
| apple -> puke.exe() else if (fruit == apple) { puke.exe(); }
| banana -> puke.exe() else if (fruit == banana) { puke.exe(); }
| fava -> observe("delicious") else if (fruit == fava) {
observe("nutritious") observe("delicious");
| _ -> puke.exe() observe("nutritious");
} else { puke.exe(); }
Functions
multiply (x, y) { var multiply = (x, y) => {
ret x * y return x * y;
} }
numbers = [1, 2, 3, 4, 5, 6] let numbers = [1, 2, 3, 4, 5, 6];
add_even_numbers() { add_even_numbers = () => {
result = 0 var result = 0;
for num in numbers { for (var i in numbers) {
if num % 2 == 0 { if (numbers[i] % 2 === 0) {
result += i result += i;
} }
} }
ret result return result;
} }
Higher-Order Functions
doTwice (f, x) { var doTwice = (f, x) => {
ret f(f(x)) return f(f(x));
} }
Class Declarations
class Ball { class Ball {
Ball (radius, weight = 1.0) { constructor(radius, weight) {
this.radius = radius this.radius = radius;
this.weight = weight this.weight = weight;
} }
is_round() { var is_round = () => {
ret true return true
} }
} }
bouncyBall = Ball(0.2) let bouncyBall = new Ball(0.2, 1.0);
bouncyBall.is_round() bouncyBall.is_round();
The following is a list of semantic errors and example output.
changedImmutableType
: tried to change x from type INTEGER to STRINGisNotAFunction
: f is not a functionisNotAList
: l is not a listisNotADictionary
: d is not a dictionaryinvalidBinaryOperands
: LIST and INTEGER cannot be used with +invalidUnaryOperand
: STRING cannot be used with !parameterArgumentMismatch
: f has signature INT, LIST, FLOAT but was called with signature STRING, LIST, FLOATexpressionIsNotTypeBoolean
: x + 3 is type INTEGER but must be type BOOLEANunusedLocalVariable
: local variable x is declared but never useduseBeforeDeclaration
: tried to use x before it was declaredreturnOutsideFunction
: found a return statement outside of a functionmultipleReturnsInABlock
: found more than one return statement in a blockcantResolveTypes
: cannot cast a STRING to a FLOATinvalidAccessType
: cannot use OBJECT to access LIST. Expected INTEGERnoClassConstructor
: did not find a constructor in class C
Favascript {
Program = Block
Block = Statement+
Statement = Exp "?" Block ":" Block -- conditional
| id "(" (Param ("," Param)*)? ")"
"{" Block "}" -- funcDecl
| "class" classId "{" Block "}" -- classDecl
| MatchExp -- match
| "if" Exp "{" Block "}"
("elif" Exp "{" Block "}" )*
("else" "{" Block "}")? -- ifElse
| "while" Exp "{" Block "}" -- while
| "for" id "in" IdExp "{" Block "}" -- forIn
| "print" "(" Exp ")" -- print
| IdExp assignOp (Exp | MatchExp) -- assign
| IdExp -- identifier
| "ret" Exp -- return
Param = id ("=" Var)?
MatchExp = ("match" IdExp "with" "|"? Var Match
("|" Var Match)* ("|" "_" Match)?)
Match = "->" (Block | Var)
Exp = Exp orOp BoolAndExp -- reg
| BoolAndExp -- pass
BoolAndExp = BoolAndExp andOp RelExp -- reg
| RelExp -- pass
RelExp = AddExp relOp AddExp -- reg
| AddExp -- pass
AddExp = AddExp addOp MulExp -- reg
| MulExp -- pass
MulExp = MulExp mulOp ExponExp -- reg
| ExponExp -- pass
ExponExp = PrefixExp exponOp AddExp -- reg
| PrefixExp -- pass
PrefixExp = prefixOp ParenExp -- reg
| ParenExp -- pass
ParenExp = "(" Exp ")" -- reg
| Var -- pass
Var = (boolLit | IdExp | List | Tuple | Dictionary
| intLit | floatLit | stringLit | nullLit)
IdExp = IdExpBody idPostOp?
IdExpBody = IdExpBody (periodId | Arguments | IdSelector) -- recursive
| (id | "this") -- base
periodId = "." id
Arguments = "(" VarList ")"
IdSelector = "[" Var "]"
idPostOp = "++" | "--"
List = "[" VarList "]"
Tuple = "(" VarList ")"
Dictionary = "{" (IdValuePair ("," IdValuePair)*)? "}"
IdValuePair = id ":" Var
VarList = (Var ("," Var)*)?
orOp = "||"
andOp = "&&"
exponOp = "^"
assignOp = "=" | "+=" | "-=" | "*=" | "/="
addOp = "+" | "-"
mulOp = "*" | "//" | "/" | "%"
relOp = "<=" | "<" | "==" | "!=" | ">=" | ">"
prefixOp = "--" | "-" | "!" | "++"
boolLit = "true" | "false"
intLit = ~floatLit digit+
floatLit = digit+ "." digit+
stringLit = "\"" ("\\\"" | (~"\"" any))* "\""
nullLit = "null"
keyword = ("class" | "true" | "false" | "match" | "with" | "if"
| "else" | "while" | "for" | "in" | "this" | "print" | "ret" | "null") ~idrest
id = ~keyword letter idrest* -- variable
| constId -- constant
idrest = "_" | alnum
constId = ~keyword upper ("_" | upper)*
classId = upper idrest*
space += comment
comment = "#" (~"\n" any)* "\n"
}