syntactic predicates - Upgrading from Antlr 3 to Antlr 4 - antlr3

I have syntactic predicated that I have to convert into the Antlr 4. The grammar is not written my me so I have no idea how to convert them in a meaningful way. These are the main variations of the grammar that I have to convert.
1.
simpleSelector
: elementName
((esPred)=>elementSubsequent)*
| ((esPred)=>elementSubsequent)+
;
esPred
: HASH | DOT | LBRACKET | COLON
;
elementSubsequent
: HASH
| cssClass
| attrib
| pseudo
;
2.
fragment EMS :; // 'em'
fragment EXS :; // 'ex'
fragment LENGTH :; // 'px'. 'cm', 'mm', 'in'. 'pt', 'pc'
fragment ANGLE :; // 'deg', 'rad', 'grad'
fragment TIME :; // 'ms', 's'
fragment FREQ :; // 'khz', 'hz'
fragment DIMENSION :; // nnn'Somethingnotyetinvented'
fragment PERCENTAGE :; // '%'
NUMBER
:(
'0'..'9' ('.' '0'..'9'+)?
| '.' '0'..'9'+
)
(
(E (M|X))=>
E
(
M { $type = EMS; } //action in lexer rule 'NUMBER' must be last element of single outermost alt
| X { $type = EXS; }
)
| (P(X|T|C))=>
P
(
X
| T
| C
)
{ $type = LENGTH; }
| (C M)=>
C M { $type = LENGTH; }
| (M (M|S))=>
M
(
M { $type = LENGTH; }
| S { $type = TIME; }
)
| (I N)=>
I N { $type = LENGTH; }
| (D E G)=>
D E G { $type = ANGLE; }
| (R A D)=>
R A D { $type = ANGLE; }
| (S)=>S { $type = TIME; }
| (K? H Z)=>
K? H Z { $type = FREQ; }
| IDENT { $type = DIMENSION; }
| '%' { $type = PERCENTAGE; }
| // Just a number
)
;
3.
URI : U R L
'('
((WS)=>WS)? (URL|STRING) WS?
')'
;
some guidance is greatly appreciated.
Edit:
Is it as below.
simpleSelector
: elementName
(elementSubsequent)*
| (elementSubsequent)+
;

Syntactic predicates were only used to work around a prediction weakness in ANTLR 3 that is not present in ANTLR 4. You can simply remove them during your transition to ANTLR 4.
Edit:
A syntactic predicate in ANTLR 3 had the following form:
(stuff) =>
Wherever you see that form in your grammar, just remove it. Here's what your second example looks like with the predicates removed.
NUMBER
:(
'0'..'9' ('.' '0'..'9'+)?
| '.' '0'..'9'+
)
(
E
(
M { $type = EMS; }
| X { $type = EXS; }
)
| P
(
X
| T
| C
)
{ $type = LENGTH; }
| C M { $type = LENGTH; }
| M
(
M { $type = LENGTH; }
| S { $type = TIME; }
)
| I N { $type = LENGTH; }
| D E G { $type = ANGLE; }
| R A D { $type = ANGLE; }
| S { $type = TIME; }
| K? H Z { $type = FREQ; }
| IDENT { $type = DIMENSION; }
| '%' { $type = PERCENTAGE; }
| // Just a number
)
;

Related

How could I generate my abstract tree using this makefile? Why I see only an error at 1 line?

def.h
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
typedef enum
{
NPROGRAM,
NVARDECLLIST,
NFUNCDECLLIST,
NVARDECL,
NIDLIST,
NOPTPARAMLIST,
NSTATLIST,
NASSIGNSTAT,
NWHILESTAT,
NIFSTAT,
NFORSTAT,
NRELEXPR,
NRETURNSTAT,
NREADSTAT,
NLOGICEXPR,
NWRITESTAT,
NNEGEXPR,
NFUNCCALL,
NEXPRLIST,
NCONDEXPR,
NPARAMDECL,
NMATHEXPR,
NCASTING
} Nonterminal;
typedef enum
{
T_BREAK,
T_TYPE,
T_BOOLEAN,
T_INTCONST,
T_REALCONST,
T_BOOLCONST,
T_WRITEOP,
T_STRCONST,
T_ID,
T_NONTERMINAL
} Typenode;
typedef union
{
int ival;
float rval;
char *sval;
enum {FALSE, TRUE} bval;
} Value;
typedef struct snode
{
Typenode type;
Value value;
struct snode *p1, *p2, *p3;
} Node;
typedef Node *Pnode;
char *newstring(char*);
int yylex();
Pnode nontermnode(Nonterminal, int),
ntn(Nonterminal),
idnode(),
keynode(Typenode, int),
intconstnode(),
realconstnode(),
strconstnode(),
boolconstnode(),
newnode(Typenode);
void yyerror(),
treeprint(Pnode, int);
lexer.lex
%{
#include "parser.h"
#include "def.h"
int line = 1;
Value lexval;
%}
%option noyywrap
spacing ([ \t])+
commento "#"(.)*\n
letter [A-Za-z]
digit [0­9]
intconst {digit}+
strconst \"([^\"])*\"
boolconst false|true
realconst {intconst}\.{digit}+
id {letter}({letter}|{digit})*
sugar [ \( \) : , ; \. \+ \- \* / ]
%%
{spacing} ;
\n {line++;}
integer {return(INTEGER);}
string {return(STRING);}
boolean {return(BOOLEAN);}
real {return(REAL);}
void {return(VOID);}
func {return(FUNC);}
body {return(BODY);}
end {return(END);}
else {return(ELSE);}
while {return(WHILE);}
do {return(DO);}
for {return(FOR);}
to {return(TO);}
return {return(RETURN);}
read {return(READ);}
write {return(WRITE);}
writeln {return(WRITELN);}
and {return(AND);}
or {return(OR);}
not {return(NOT);}
if {return(IF);}
then {return(THEN);}
break {return(BREAK);}
"<=" {return(LEQ);}
">=" {return(GEQ);}
"!=" {return(NEQ);}
"==" {return(EQU);}
"<" {return(LT);}
">" {return(GT);}
{intconst} {lexval.ival = atoi(yytext); return(INTCONST);}
{strconst} {lexval.sval = newstring(yytext); return(STRCONST);}
{boolconst} {lexval.bval = (yytext[0] == 'f' ? FALSE : TRUE); return(BOOLCONST);}
{realconst} {lexval.rval = atof(yytext); return(REALCONST);}
{id} {lexval.sval = newstring(yytext); return(ID);}
{sugar} {return(yytext[0]);}
. {return(ERROR);}
%%
char *newstring(char *s)
{
char *p;
p = malloc(strlen(s)+1);
strcpy(p, s);
return(p);
}
makefile
bup: lexer.o parser.o tree.o
cc -g -o bup lexer.o parser.o tree.o
lexer.o: lexer.c parser.h def.h
cc -g -c lexer.c
parser.o: parser.c def.h
cc -g -c parser.c
tree.o: tree.c def.h
cc -g -c tree.c
lexer.c: lexer.lex parser.y parser.h parser.c def.h
flex -o lexer.c lexer.lex
parser.h: parser.y def.h
bison -vd -o parser.c parser.y
parser.y
%{
#include "def.h"
#define YYSTYPE Pnode
extern char *yytext;
extern Value lexval;
extern int line;
extern FILE *yyin;
Pnode root = NULL;
%}
%token ID FUNC BODY END BREAK IF THEN ELSE TYPE WHILE DO FOR RETURN READ WRITE WRITELN
%token AND OR INTCONST REALCONST BOOLCONST STRCONST INTEGER REAL NOT STRING BOOLEAN VOID PLUS MINUS TIMES SLASH
%token LEQ GEQ NEQ EQU GT LT TO ERROR
%%
program : var-decl-list func-decl-list body '.' {root = $$ = ntn(NPROGRAM);
root->p1 = ntn(NVARDECLLIST);
root->p2 = ntn(NFUNCDECLLIST);
root->p1->p1 = $1;
root->p2->p1 = $2;
root->p3 = $3;}
;
var-decl-list : var-decl var-decl-list {$$ -> p1=$1;
$1->p3=$2;}
| {$$ = NULL;}
;
var-decl : id-list ':' type ';' {$$ = ntn(NVARDECL);
$$ -> p1 = ntn(NIDLIST);
$$->p1->p1=$1; $$ -> p1 -> p3 = $3;}
;
id-list : ID {$$ = idnode();} ',' id-list {$$ = $2;
$2 -> p3 = $4;}
| ID {$$ = idnode();}
;
type : INTEGER {$$ = keynode(T_TYPE, INTEGER);}
| REAL {$$ = keynode(T_TYPE, REAL);}
| STRING {$$ = keynode(T_TYPE, STRING);}
| BOOLEAN {$$ = keynode(T_TYPE, BOOLEAN);}
| VOID {$$ = keynode(T_TYPE, VOID); }
;
func-decl-list : func-decl func-decl-list {$$ -> p1 = $1;
$1 -> p3 = $2;}
| {$$ = NULL;}
;
func-decl : FUNC ID {$$ = idnode();} '(' opt-param-list ')' ':' type var-decl-list body ';' {$$ -> p1 = $3;
$$ -> p2 = ntn(NOPTPARAMLIST);
$$ -> p2 ->p1=$5;
$$ -> p2 -> p3 = $8;
$$ -> p2 -> p3->p3 = ntn(NVARDECLLIST);
$$ -> p2 -> p3->p3->p1 = $9;
$$ -> p2 -> p3->p3->p3 = $10;}
;
opt-param-list : param-list {$$ = $1;}
| {$$ = NULL;}
;
param-list : param-decl ',' param-list {$$ = $1;
$1 -> p3 = $3;}
| param-decl
;
param-decl : ID {$$ = idnode();} ':' type {$$=ntn(NPARAMDECL);
$$ -> p1 = $2;
$$ -> p2 = $4;}
;
body : BODY stat-list END {$$ = ntn(NSTATLIST);
$$->p1=$2;}
;
stat-list : stat ';' stat-list {$$ = $1;
$1 -> p3 = $3;}
| stat ';' {$$=$1;}
;
stat : assign-stat
| if-stat
| while-stat
| for-stat
| return-stat
| read-stat
| write-stat
| func-call
| BREAK {$$ = newnode(T_BREAK);}
;
assign-stat : ID {$$ = idnode();} '=' expr {$$ = ntn(NASSIGNSTAT);
$$ -> p1 = $2;
$$ -> p2 = $4;}
;
if-stat : IF expr THEN stat-list opt-else-stat END {$$ = ntn(NIFSTAT);
$$ -> p1 = $2;
$$ -> p2 = ntn(NSTATLIST);
$$ ->p2 -> p3 = $5;}
;
opt-else-stat : ELSE stat-list {$$ = ntn(NSTATLIST);
$$->p1=$2;}
| {$$ = NULL;}
;
while-stat : WHILE expr DO stat-list END {$$ = ntn(NWHILESTAT);
$$->p1=$2;
$$->p2=ntn(NSTATLIST);
$$->p2->p1=$4;}
;
for-stat : FOR ID {$$=idnode();} '=' expr TO expr DO stat-list END {$$ = ntn(NFORSTAT);
$$->p1=$3;
$$->p2=$5;
$$->p2->p3=$7;
$$->p2->p3->p3=ntn(NSTATLIST);
$$->p2->p3->p3->p1=$9;}
;
return-stat : RETURN opt-expr {$$ = ntn(NRETURNSTAT);
$$->p1=$2;}
;
opt-expr : expr {$$=$1;}
| {$$=NULL;}
;
read-stat : READ '(' id-list ')' {$$ = ntn(NREADSTAT);
$$->p1=ntn(NIDLIST);
$$->p1->p1=$3;}
;
write-stat : write-op '(' expr-list ')' {$$ = ntn(NWRITESTAT);
$$->p1=$1;
$$->p2=ntn(NEXPRLIST);
$$->p2->p1=$3;}
;
write-op : WRITE {$$ = keynode(T_WRITEOP, WRITE);}
| WRITELN {$$ = keynode(T_WRITEOP, WRITELN);}
;
expr-list : expr ',' expr-list {$$=$1;
$1->p3=$3;}
| expr
;
expr : expr logic-op bool-term { $$=$2;
$2->p1=$1;
$2->p2=$3;}
| bool-term
;
logic-op : AND {$$=nontermnode(NLOGICEXPR, AND);}
| OR {$$=nontermnode(NLOGICEXPR, OR);}
;
bool-term : rel-term rel-op rel-term {$$=$2;
$2->p1=$1;
$2->p2=$3;}
| rel-term
;
rel-op : EQU {$$=nontermnode(NRELEXPR, EQU);}
| NEQ {$$=nontermnode(NRELEXPR, NEQ);}
| GT {$$=nontermnode(NRELEXPR, GT);}
| GEQ {$$=nontermnode(NRELEXPR, GEQ);}
| LT {$$=nontermnode(NRELEXPR, LT);}
| LEQ {$$=nontermnode(NRELEXPR, LEQ);}
;
rel-term : rel-term low-prec-op low-term {$$=$2;
$2->p1=$1;
$2->p2=$3;}
| low-term
;
low-prec-op : PLUS {$$=nontermnode(NMATHEXPR, PLUS);}
| MINUS {$$=nontermnode(NMATHEXPR, MINUS);}
;
low-term : low-term high-prec-op factor {$$=$2;
$2->p1=$1;
$2->p2=$3;}
| factor
;
high-prec-op : TIMES {$$=nontermnode(NMATHEXPR, TIMES);}
| SLASH {$$=nontermnode(NMATHEXPR, SLASH);}
;
factor : unary-op factor {$$=$1;
$1->p3=$2;}
| '(' expr ')' {$$=$2;}
| ID {$$=idnode();}
| const {$$=$1;}
| func-call {$$=$1;}
| cond-expr {$$=$1;}
| cast '(' expr ')' {$$=$1;
$1->p3=$3;}
;
unary-op : MINUS {$$=nontermnode(NNEGEXPR, MINUS);}
| NOT {$$=nontermnode(NNEGEXPR, NOT);}
;
const : INTCONST {$$=intconstnode();}
| REALCONST {$$=realconstnode();}
| STRCONST {$$=strconstnode();}
| BOOLCONST {$$=boolconstnode();}
;
func-call : ID {$$=idnode();} '(' opt-expr-list ')' {$$ = ntn(NFUNCCALL);
$$->p1=$2; $$->p2=$4;}
;
opt-expr-list : expr-list {$$=ntn(NEXPRLIST); $$->p1=$1;}
| {$$=NULL;}
;
cond-expr : IF expr THEN expr ELSE expr END {$$=ntn(NCONDEXPR);
$$->p1=$2;
$$->p2=$4;
$$->p3=$6;}
;
cast : INTEGER {$$=nontermnode(NCASTING,INTEGER);}
| REAL {$$=nontermnode(NCASTING, REAL);}
;
%%
Pnode ntn(Nonterminal nonterm)
{
Pnode p = newnode(T_NONTERMINAL);
p->value.rval = nonterm;
return(p);
}
Pnode nontermnode(Nonterminal nonterm, int valore)
{
Pnode p = newnode(T_NONTERMINAL);
p->value.rval = nonterm;
p->value.ival = valore;
return(p);
}
Pnode idnode()
{
Pnode p = newnode(T_ID);
p->value.sval = lexval.sval;
return(p);
}
Pnode keynode(Typenode keyword, int valore)
{
Pnode p = newnode(keyword);
p->value.ival = valore;
return p;
}
Pnode intconstnode()
{
Pnode p = newnode(T_INTCONST);
p->value.ival = lexval.ival;
return(p);
}
Pnode realconstnode()
{
Pnode p = newnode(T_REALCONST);
p->value.rval = lexval.rval;
return(p);
}
Pnode strconstnode()
{
Pnode p = newnode(T_STRCONST);
p->value.sval = lexval.sval;
return(p);
}
Pnode boolconstnode()
{
Pnode p = newnode(T_BOOLCONST);
p->value.bval = lexval.bval;
return(p);
}
Pnode newnode(Typenode tnode)
{
Pnode p = malloc(sizeof(Node));
p->type = tnode;
p->p1 = p->p2 = p->p3 = NULL;
return(p);
}
int main()
{
int result;
printf("----------------------------------------------");
yyin = stdin;
if((result = yyparse()) == 0)
treeprint(root, 0);
return(result);
}
void yyerror()
{
fprintf(stderr, "Line %d: syntax error on symbol \"%s\"\n",
line, yytext);
exit(-1);
}
tree.c
#include "def.h"
char* tabtypes[] =
{
"T_BREAK",
"T_TYPE",
"T_BOOLEAN",
"T_INTCONST",
"T_REALCONST",
"T_BOOLCONST",
"T_WRITEOP",
"T_STRCONST",
"T_ID",
"T_NONTERMINAL"
};
char* tabnonterm[] =
{
"PROGRAM",
"NVARDECLLIST",
"NFUNCDECLLIST",
"NVARDECL",
"NIDLIST",
"NOPTPARAMLIST",
"NSTATLIST",
"NASSIGNSTAT",
"NWHILESTAT",
"NIFSTAT",
"NFORSTAT",
"NRELEXPR",
"NRETURNSTAT",
"NREADSTAT",
"NLOGICEXPR",
"NWRITESTAT",
"NNEGEXPR",
"NFUNCCALL",
"NEXPRLIST",
"NCONDEXPR",
"NPARAMDECL",
"NMATHEXPR",
"NCASTING"
};
void treeprint(Pnode root, int indent)
{
int i;
Pnode p;
for(i=0; i<indent; i++)
printf(" ");
printf("%s", (root->type == T_NONTERMINAL ? tabnonterm[root->value.ival] : tabtypes[root->type]));
if(root->type == T_ID || root->type == T_STRCONST)
printf(" (%s)", root->value.sval);
else if(root->type == T_INTCONST)
printf(" (%d)", root->value.ival);
else if(root->type == T_BOOLCONST)
printf(" (%s)", (root->value.ival == TRUE ? "true" : "false"));
printf("\n");
for(p=root->p1; p != NULL; p = p->p3)
treeprint(p, indent+1);
}
prog ( File with example of grammar)
numero: integer;
func fattoriale(n: integer): integer
fact: integer;
body
if n == 0 then
fact = 1;
else
fact = n * fattoriale(n­1);
end;
return fact;
end;
func stampaFattoriali(tot: integer): void
i, f: integer;
body
for i=0 to tot do
f = fattoriale(i);
writeln("Il fattoriale di ", i, "è ", f);
end;
end;
body
read(numero);
if numero < 0 then
writeln("Il numero ", numero, "non è valido");
else
stampaFattoriali(numero);
end.
When i type make on terminal , it create the files : tree.o parser.o parser.h parser.c lexer.c lexer.o bup.
When i execute the bup file , the terminal show me this error message :
"ine 1: syntax error on symbol "
So it don't generate the abstract tree.
I don't know if this error refers to the prog or lexer.lex or parse.y file.
Yacc/bison assign their own numbers to terminal tokens, and assume that the lexer will use those numbers. But you provide your own numbers in the def.h header, which yacc/bison knows absolutely nothing about. It will not correctly interpret the codes returned by yylex which will make it impossible to parse correctly.
So don't do that.
Let bison generate the token codes, use the header file it generates (parser.h with your settings), and don't step on its feet by trying to define the enum values yourself.
As a hint about debugging, that is really way too much code to have written before you start debugging, and that fact is exactly illustrated by your complaint at the end of your question that you don't know where to look for the error. Instead of writing the whole project and then hoping it works as a whole, write little pieces and debug them as you go. Although you need to parser to generate the token type values, you don't need to run the parser to test your scanner. You can write a simple program which repeatedly calls yylex and prints the returned types and values. (Or you can just enable flex debugging with the -d command line option, which is even simpler.)
Similarly, you should be able to test your AST methods by writing some test functions which use these methods to build, walk and print out an AST. Make sure that they produce the expected results.
Only once you have evidence that the lexer is producing the correct tokens and that your AST construction functions work should you start to debug your parser. Again, you will find it much easier if you use the built-in debugging facilities; see the Debugging your parser section of the Bison manual for instructions.
Good luck.

How to construct an array in ATS?

For instance, how can I construct an array in ATS containing all of the letters in the upper case from A to Z? In C, this can be done as follows:
char *Letters()
{
int i;
char *cs = (char *)malloc(26);
assert(cs != 0);
for (i = 0; i < 26; i += 1) cs[i] = 'A' + i;
return cs;
}
You could use the tabulate function for creating linear arrays. For instance,
extern
fun
Letters(): arrayptr(char, 26)
implement
Letters() =
arrayptr_tabulate_cloref<char>
(i2sz(26), lam(i) => 'A' + sz2i(i))
If you don't want to use a higher-order function, you can try the following template-based solutioin:
implement
Letters() =
arrayptr_tabulate<char>(i2sz(26)) where
{
implement array_tabulate$fopr<char> (i) = 'A' + sz2i(i)
}
Well, here's one way, although it's extremely complicated, because it follows your outlined approach to the letter: it involves linear proofs for arrays (aka dataviews), memory allocation, and array initialization via a while loop.
extern
fun
Letters (): arrayptr (char, 26)
implement
Letters () = let
val (pf_arr, pf_gc | p_arr) = array_ptr_alloc<char> ((i2sz)26)
var i: int = 0
prval [larr:addr] EQADDR () = eqaddr_make_ptr (p_arr)
var p = p_arr
prvar pf0 = array_v_nil {char} ()
prvar pf1 = pf_arr
//
val () =
while* {i:nat | i <= 26} .<26-i>. (
i: int (i)
, p: ptr (larr + i*sizeof(char))
, pf0: array_v (char, larr, i)
, pf1: array_v (char?, larr+i*sizeof(char), 26-i)
) : (
pf0: array_v (char, larr, 26)
, pf1: array_v (char?, larr+i*sizeof(char), 0)
) => (
i < 26
) {
//
prval (pf_at, pf1_res) = array_v_uncons {char?} (pf1)
prval () = pf1 := pf1_res
//
val c = 'A' + (g0ofg1)i
val () = ptr_set<char> (pf_at | p, c)
val () = p := ptr1_succ<char> (p)
//
prval () = pf0 := array_v_extend {char} (pf0, pf_at)
val () = i := i + 1
//
} // end of [val]
//
prval () = pf_arr := pf0
prval () = array_v_unnil {char?} (pf1)
//
val res = arrayptr_encode (pf_arr, pf_gc | p_arr)
in
res
end // end of [Letters]
You can run the code at Glot.io

Project Euler 2

I am working on problem two of Euler.
I wanted to solve it this way, to compare the time after .
//Find the sum of all the even-valued terms in the Fibonacci sequence which do not exceed four million
I should get
//A: 4613732
but I am getting a huge number :
177112424089630957537
Can someone explain why ?
def Fibonaccu(max: Int) : BigInt = {
var a:BigInt = 0
var b:BigInt = 1
var sum:BigInt= 0
var i:BigInt = 0;
while(i < max){
i+=1
b = a + b
a = b - a
if (b % 2 == 0) sum += b
}
//Return
println(sum)
sum
}
}
Here it is:
scala> val fib: Stream[Int] = 0 #:: fib.scanLeft(1)(_+_)
fib: Stream[Int] = Stream(0, ?)
scala> fib.takeWhile(4000000>).filter(_%2 == 0).sum
res0: Int = 4613732
And here is based on your code:
scala> def Fibonaccu(max: Int) : BigInt = {
| var a:BigInt = 0
| var b:BigInt = 1
| var sum:BigInt= 0
| while(b < max) {
| if(b % 2 == 0) sum += b
| b = a + b
| a = b - a
| }
| sum
| }
Fibonaccu: (max: Int)BigInt
scala> Fibonaccu(4000000)
res1: BigInt = 4613732

Turn this if-then logic into a boolean expression?

I'm having a bit of a brain fart on making this code more concise(preferably a single boolean expression)
This is my code:
if (d.Unemployed)
{
if (type.Unemployed)
{
tmp.Unemployed = true;
}
else
{
tmp.Unemployed = false;
}
}
else
{
if (type.Unemployed)
{
tmp.Unemployed = false;
}
else
{
tmp.Unemployed = true;
}
}
Basically the point is that if either type or d is not unemployed, then tmp should be set to not unemployed.
How about:
tmp.Unemployed = type.Unemployed == d.Unemployed;
If we construct a truth table by following the code, we get
d | type | tmp
---+------+----
1 | 1 | 1
---+------+----
1 | 0 | 0
----+-----+----
0 | 1 | 0
----+-----+----
0 | 0 | 1
The above is equivalent with the negation of the xor operation.
tmp = not (d xor type)
If the language doesn't have the xor operator we can use the != on boolean values.
tmp = ! (d != type);
// or
tmp = d == type;
Thinking about how much "brain fart" this caused you I would consider using a well named variable to avoid having to go through this mental process again in future. Something like this:
isTmpUnemployed = (type.Unemployed == d.Unemployed);
tmp.Unemployed = isTmpUnemployed;
The above code means "both unemployed or both not unemployed". Thus, not (A xor B):
tmp.Unemployed = ! ( D.Unemployed ^ type.Unemployed)
tmp.Unemployed = d.Unemployed || type.Unemployed ? !tmp.Unemployed : null;

How does the TED Talk home page organise the grid of videos?

I've been trying to work out exactly how the TED Talk homepage works. Leaving aside all the animation rubbish, I find the way that the boxes are organised is really fascinating.
At first glance it looks like the jQuery masonry plugin, bu it quickly becomes clear that it tends to create several right angle triangle shapes, but has no fixed number of columns or rows, and the final shape produced is always completely solid (no hollow parts).
My initial assumption was that the boxes (their size is predetermined by some factor on the site) were sorted randomly and then sequentially added to the grid using a few simple rules, however I can't identify what those rules might be, or how they could prevent any hollows in the final shape.
Does anyone have any idea how this works?
Could be wrong but a few observations:
Each section has 19 videos
There are 4 sizes 1 (#1), 1/4 (#2), 1/16 (#3) and 1/32 (#4)
For a given section, there are always 4(#1). The number of (#2), (#3) and (#4) can be either:
4(#1), 10(#2), 4(#3), 1(#1) = 19
4(#1), 11(#2), 4(#3), 0(#1) = 19
4(#1), 11(#2), 3(#3), 1(#1) = 19
4(#1), 12(#2), 2(#3), 1(#1) = 19
4(#1), 13(#2), 1(#3), 1(#1) = 19
As for the order:
The first row always contains 2(#1) and 4(#2)
(#4) are always at the bottom of a column
Here is the javascript code which does it (you need a html page with a div#container):
function ted_layout(settings, coordinates_array, num_elements, start_x, start_y, arrangement, remaining_elements, is_child){
var num_columns = arrangement.length;
var col = 0;
var current_x = start_x;
while( col < num_columns){
var column_x_scale = 100 / arrangement[col];
var current_column_arrangement;
if(is_child){
if(num_elements > 14){
if(column_x_scale == 50){
current_column_arrangement = random_shuffle([1, 2, 2]);
} else {
current_column_arrangement = random_shuffle([1, 2]);
}
} else if(num_elements > 10){
if(column_x_scale == 50){
current_column_arrangement = [1];
} else {
current_column_arrangement = random_shuffle([1, 2]);
}
} else{
current_column_arrangement = random_shuffle([1, 2]);
}
} else {
if(num_elements > 14){
if(column_x_scale == 25){
current_column_arrangement = [1, 1];
} else {
current_column_arrangement = [1];
}
} else if(column_x_scale == 25){
current_column_arrangement = [1, 1];
} else {
current_column_arrangement = [1];
}
}
var num_rows = current_column_arrangement.length;
var current_y = start_y;
var row = 0;
while(row < num_rows){
var numRects = current_column_arrangement[row];
var current_rectangle = 0;
var current_rectangle_x = current_x;
while( current_rectangle < numRects){
if(remaining_elements == 0){
return coordinates_array;
}
var currScale = column_x_scale/numRects;
var height = settings.height * currScale*0.01;
var width = settings.width * currScale*0.01;
if(current_rectangle == numRects-1 && row == num_rows-1 && is_child && Math.random() > 0.5){
coordinates_array.push({x: current_rectangle_x, y:current_y, w:width/2, h:height/2, scale:currScale/2*0.01*2})
}
else{
coordinates_array.push({x: current_rectangle_x, y:current_y, w:width, h:height, scale:currScale*0.01*2})
}
current_rectangle_x += width;
remaining_elements--;
current_rectangle++;
}
row++;
current_y += height;
}
current_x = current_rectangle_x;
col++;
}
if( remaining_elements > 0){
coordinates_array = ted_layout(settings, coordinates_array, num_elements, start_x, current_y, random_shuffle([2, 4, 4, 2]), remaining_elements, true);
}
return coordinates_array;
}
function generate_ted_layout(num_elements){
var settings = {
width: 640,
height: 480,
};
var coordinates_array=[];
returned = ted_layout(settings, coordinates_array, num_elements, 0, 0, random_shuffle([2, 4, 4, 2]), num_elements, false);
console.log("Returned", returned)
return returned;
}
function random_shuffle(array){
var temp;
for(var i = array.length - 1; i >= 1; i--){
var elem = Math.floor(Math.random() * (i + 1));
temp = array[elem];
array[elem] = array[i];
array[i] = temp;
}
return array;
}
function initAndLayout() {
var items = generate_ted_layout(20);
var container = $('#container'); // cache jquery object
console.log(items);
for (var i = 0; i < items.length; i++)
{
var item = items[i];
console.log(item);
$('#container').append($('<div class="item"></div>').css({'left': item.x, 'top': item.y, 'width': item.w, 'height': item.h}));
}
}
I think I've worked it out.
First of all the number of items varies substantially, I'm currently viewing a page with only 13 boxes.
To start I'll name each of the 4 sizes of blocks from largest to smallest as:
A,B,C,D
As we know the first 'row' contains two As and two vertical stacks of Bs, for example:
_______________________
| A | B | A | B |
| |___| |___|
| | B | | B |
|_______|___|_______|___|
The arrangement of these appears to be random, but the Bs are always in the same vertical pattern. Looking at this just now I realised that there are only two rows, and the second row works in the same way.
The second row is twice the height of the first, taking up the rest of the page. It is built of horizontally stacked patterns of shapes, which are (at least in part) selected randomly.
I've found 9 of these patterns of shapes, two of which are a single A or B and the rest are:
_______ _______ _______ ___ ___ _______ ___
| B | B | | A | | B | B | |C|C| | B | | A | |C|C|
|___|___| | | |___|___| | B | |___| | |
| A | | | | B | B | |___| |C|D | |
| | |_______| |___|___| |_______|
| | | B | B | | A | | B |
|_______| |___|___| | | |___|
|B |C| |B |C| | |
|___| |___| |_______|
The next question is how are these selected? There may be some clever searching to find the best configuration: for example if there are X items to be displayed we need to find a configuration with a total of X which does not exceed the width of the row.
This could be done with a metric of pattern density, which would be number of blocks divided by the width of the pattern.

Resources