aboveaveragescript
v1.0.0
Published
Ever so slightly above average
Downloads
42
Readme
#AboveAverageScript
Javascript forcefully mutated into a syntactically beautiful language. This is AboveAverageScript. Formed from a mixture of ECMAScript 6, Python, and CoffeeScript, AboveAverageScript forces you to space your code perfectly, without confining you to one specific style for doing so. In addition, several new operators await you, allowing you to hastily deal with objects and properties. Give it a shot. Love it or hate it, one thing is for sure: It sure as hell beats writing in Java.
##Grammar ###Macrosyntax
Program ::= Stmt Block EOF
Block ::= (Newline Stmt)*
Stmt ::= DeclareStmt
| AssignStmt
| NativeStmt
| SwitchStmt
| Loop
| IfStmt
| ConsumeStmt
| ReturnStmt
| ControlStmt
| Exp
DeclareStmt ::= 'let' (ExpList '=' (ObjInd | ExpList)) | (SetEqual (',' Indent Newline SetEqual (',' Newline SetEqual)* Dedent ) )
AssignStmt ::= (ExpList AssignOp (ObjInd | ExpList)) | (SetAssign (',' Indent Newline SetAssign (',' Newline SetAssign)* Dedent ) )
ConsumeStmt ::= ExpList? '<-' Exp
ReturnStmt ::= 'ret' Exp?
ControlStmt ::= 'stop' | 'skip'
SetAssign ::= Exp AssignOp Exp
SetEqual ::= Exp '=' Exp
IfStmt ::= 'if' Exp ':' Indent Block Dedent (Newline 'elif' Exp ':' Indent Block Dedent)* (Newline 'else' Indent Block Dedent)?
SwitchStmt ::= 'switch' Exp ':' Indent Case+ Defaults? Dedent
Case ::= Newline 'case' Exp18 ':' Indent Block Dedent
Defaults ::= Newline 'default' ':' Indent Block Dedent
NativeStmt ::= '***native***'
Loop ::= WhileLoop | ForLoop
WhileLoop ::= DoWhile | While
DoWhile ::= 'do' Indent Block Dedent Newline 'while' Exp
While ::= 'while' Exp ':' Indent Block Dedent
ForLoop ::= (ForIn | ForColon | For) ':' Indent Block Dedent
ForIn ::= 'for' Id (',' Id)? 'in' Exp
ForColon ::= 'for' Id ':' Exp
For ::= 'for' ( ('let'? Id '=')? Exp ',')? Exp ',' Exp
Exp ::= Exp1 (ForIn | ForColon)*
Exp1 ::= Exp2 ('if' Exp2 ('else' Exp2)?)?
Exp2 ::= Exp3 ('in' Exp3)*
Exp3 ::= Exp4 ('?' Exp4 ':' Exp4)?
Exp4 ::= Exp5 ('or' Exp5)*
Exp5 ::= Exp6 ('and' Exp6)*
Exp6 ::= Exp7 ('|' Exp7)*
Exp7 ::= Exp8 ('^' Exp8)*
Exp8 ::= Exp9 ('&' Exp9)*
Exp9 ::= Exp10 (EqualOp Exp10)*
Exp10 ::= Exp11 (CompareOp Exp11)*
Exp11 ::= Exp12 (ShiftOp Exp12)*
Exp12 ::= Exp13 (AddOp Exp13)*
Exp13 ::= Exp14 (MulOp Exp14)*
Exp14 ::= PrefixOp? Exp15
Exp15 ::= Exp16 PostfixOp?
Exp16 ::= 'new'? Exp17 Call?
Exp17 ::= Exp18 (ArrayCont | Call | '.' Exp17)*
Exp18 ::= Id | BoolLit | IntLit | StringLit | '(' Exp Newline? ')' | Func | ArrayLit | ObjectInline | This | RegExpLit
ArrayLit ::= ('[' ']') | ArrayCont
ArrayCont ::= '[' (Exp (',' Exp)*) | (Indent Newline Exp (',' Newline? Exp)* Dedent Newline) Newline? ']'
ExpList ::= Exp (Newline? ',' Exp)*
RegExpLit ::= '\/[^\/\\]+(?:\\.[^\/\\]*)*\/[igm]{0,3}'
Func ::= 'func' (Id (',' Id)* )? '->' ('ret'? Exp) | (Indent Block Dedent)
ObjectInline ::= '{' (Property (',' Property)*) | (Indent Newline Property (',' Newline Property)* Dedent Newline) '}'
ObjInd ::= Indent (Newline (Prop|PropInd) )+ Dedent
Prop ::= (Id | BoolLit | StringLit) ':' Exp
PropInd ::= (Id | BoolLit | StringLit) ':' (Exp | ObjInd)
Call ::= '(' ( ExpList (Newline? ',' Indent Newline Exp (Newline ',' Exp)* Dedent)? Newline?)? ')'
###Microsyntax
AssignOp ::= '=' | '+=' |'-=' | '*=' | '/=' | '%=' | '<<=' | '>>=' | '>>>=' | '&=' | '^=' | '|='
EqualOp ::= '!==' | '===' | '!=' | '=='
CompareOp ::= '>=' | '>' | '<=' | '<'
ShiftOp ::= '>>>' | '>>' | '<<'
AddOp ::= '+' | '-'
MulOp ::= '%' | '/' | '*'
PrefixOp ::= '--' | '++' | '-' | '+' | '~' | 'not'
PostfixOp ::= '--' | '++'
IntLit ::= '[+-]?((0x[a-fA-F0-9]+)|(\d+(\.\d+)?([eE][+-]?\d+)?))'
StringLit ::= '\"[^\"\\]*(?:\\.[^\"\\]*)*\"|\'[^\'\\]*(?:\\.[^\'\\]*)*\''
Id ::= '[_$a-zA-Z][$\w]*(?=[^$\w]|$)'
This ::= '_'
Newline ::= '\n'
Indent ::= '\i'
Dedent ::= '\d'
EOF ::= '@EOF'
The Macrosyntax doesn't actually capture everything, in particular indents within expressions. The reason being that it isn't context free, and for good reason. If it were based on context, it would completely ruin precedence. So, indents and dedents follow a simple rule: indent before or after any operator, and dedent at the end of an expression. If you enter a parenthesized expression or enter a series of dot accessors, you're in a new expression until it stops. Long story short, just take a look at the examples. You'll see the pattern. It's hard to explain what perfect style means.
Here's some basic variable code:
let a = 70 var a = 70;
a++ a++;
let b, c = a/20 _['$t0'] = a/20;
var b = _['$t0'];
var c = _['$t0'];
a %= c a %= c;
b, c = a, b _['$t0'] = a;
_['$t1'] = b;
b = _['$t0'];
c = _['$t1'];
let d = a/b, var d = a/b;
e = b/c, var e = b/c;
f = c/d var f = c/d;
a, b, c, d, e, f >>= 1 _['$t0'] = 1;
a >>= _['$t0'], b >>= _['$t0'], c >>= _['$t0'],
d >>= _['$t0'], e >>= _['$t0'], f >>= _['$t0'];
AboveAverageScript is still Javascript, and as such is object oriented.
let fib = func a, amt -> var fib = function(a, amt) {
amt = defaults(amt, 1) amt = defaults(amt, 1);
ret amt if a in '01' else fib(a - 1, amt * a) if('01'.indexOf(a) >= 0) {
return amt;
else {
return fib(a - 1, amt*a);
}
}
let z = fib(3) var z = fib(30;)
let Chicken = var Chicken = {
breed: 'Bantam' breed: 'Bantam',
gender: 'Male' gender: 'Male',
eggsLaid: 14 eggsLaid: 14,
cry: func -> log('COCKADOODLEDOO!') cry: function() {
log('COCKADOODLEDOO!');
}
let Circle = func props -> // For the translation of the rest of this section, check
_['x', 'y', 'radius'] = 0 // the wiki. It can get quite involved when explaining how
_ <- props // the property consumption ('<-') operator works.
_.setLocation = func point ->
_ <- point
let Ellipse = new Circle({x: 0, y: 0, radius: 5})
Ellipse <- {stroke: 'dashed', color: 'rgb(100,200,50)'}
I'm sure you noticed the funny little operator above, not to mention the odd new syntax for property access. Well, that's part of the new design. In a nutshell, the property consumption operator will look for named properties on the outermost expression of the righthand side, and assign them with the same name to the left hand side as properties. If no named properties are found, then it will simply take ALL properties from the right hand side. Please note that means the right hand side MUST be an object. Now, as for the left hand side, you have a few options. You can put in a series of expressions, whom all of which will recieve the properties. However, if no expression is given, then it will actually assign those variables to the local scope. However, assigning to the local scope tends to be slower (because it prevents modern Javascript engines from optimizing that code fragment), so you're better off not using it too often or too rapidly. As this is a much more involved concept, especially the code it translates to, you can find far more information on the wiki.
Of course, there was that other thing. The property access that was treated as if it were an array. Well, that's actually the most accurate description I can give. It's just your average property access with square brackets, except that you can list multiple items. Oh, and in case it wasn't clear, AboveAverageScript uses _
to specify the containing object, opposed to using this
.
Pressing on...
let term = 300, var term = 300;
list = [3, 5, 7, 9], var list = [3, 5, 7, 9];
index = 0 var index = 0;
while term > 0: while(term > 0) {
for(i, val in list): for(var i = 0; i < list.length; i++) {
var val = list[i];
term -= val term -= val;
index = i index = i;
if term <= 0: if(term <= 0) {
stop break;
}
}
}
Conditionals look a tad different, however.
let x = int(input("Please enter a number")) var x = int( input("Please enter a number") ); // input function is user defined.
if x > 0: if( x > 0 ) {
log("Feeling positive?") log("Feeling positive?");
elif x === 0: } else if( x === 0 ) {
log("Zero? Really?") log("Zero? Really?");
else } else {
log("Don't be so negative") log("Don't be so negative");
}
Comments are casual.
let teascript = "Awesome" var teascript = "Awesome"; // Variables should be declared with let.
CoffeeScript = "Casual" CoffeeScript = "Casual"; // Variables can be declared without let,
$ = "$" $ = "$"; // but its far less clear.
/* Multiline comments are also available! */
Moving on. We've all used JQuery at one time or another. Well, since AboveAverageScript creates a few built-in functions, they need to be placed somewhere. When using JQuery, the $(function() { })
often proves helpful for ensuring your webpage loads quickly. Should you want these built-ins to be placed within your JQuery function, simply say ***native***
, and the compiler will know to place the built-ins there. Otherwise, they will just go to the top of your script.
$(func ->
***native***
log("Now you can use these built-ins in your code without slowing down your webpage!")
)
Here are the current (more pythonic) built-ins:
type(x) // A replacement for typeof, function-ified.
defaults(a, b) // A function that helps make default parameters. If a is defined, then it returns a. Otherwise, b is returned.
int(x, base) // A function that is a wrapper for the much more verbose parseInt function
float(x) // A function that is a wrapper for the much more verbose parseFloat function
is(x, y) // A replacement for instanceof, function-ified, translating into 'x instanceof y'
log(x) // A wrapper for console.log
error(x) // A wrapper for console.error
del(x, y) // A replacement for delete, function-ified, translating into 'delete y[x]'
len(obj) // Quite literally a method call instead of saying '.length'
size(obj) // Returns the number of keys the object has.
range(x, y, z) // It works exactly the same way it does in Python. To save space, I'll defer you to their documentation.
isUndef(val) // Returns true if val is undefined. Its like isNaN for undefined.
abs(x) // A wrapper for Math.abs
pow(x, y) // A wrapper for Math.pow
lazy(x, *) // Returns a function that calls x with all of the remaining arguments when called.
lazier(x, args) // Returns a function that calls x with the all of the arguments in the array args when called.
Just to make sure everything has been listed, here are all of the available loops.
let y = ["true", "false", true, 0, 9, {}]
// for val in -> iterates over property values of object
log(x) for x in y // prints: "true", "false", true, 0, 9, {}
// for key, val in -> iterates over property values of object
log(a, b) for a, b in y // prints: 0 "true", 1 "false", 2 true, 3 0, 4 9, 5 {}
// for key: -> iterates over key-value pairs?
log(x) for x : y // prints: 0, 1, 2, 3, 4, 5
Minor notes:
- Camel Casing is preferred
- Spacing norm is 4 spaces (NOT TABS)
- Expect the (ever so slightly) above average
- Not sure if you should use a semicolon? Don't use it. Ever. Ever. They have been banned.