Switch from first/rest to head/tail in example grammars

In the past year I worked on various grammars where first/rest or
head/tail were used as labels for parts of lists. I found I associate
head/tail with a list immediately, while in case of first/rest I have to
"parse" grammar rules for a while before understanding their structure.

Moreover, I tend to assume that rest is a list of the same thigs as
first, but I don't have such assumption in case of head/tail. This
assumption was in conflict with the grammar structure.

I'm not sure how much these observations are applicable to others, but I
decided to act on them and switch from first/rest to head/tail.
redux
David Majda 9 years ago
parent 10d7a6aded
commit e510ecc3d0

@ -6,24 +6,24 @@
*/ */
Expression Expression
= first:Term rest:(_ ("+" / "-") _ Term)* { = head:Term tail:(_ ("+" / "-") _ Term)* {
var result = first, i; var result = head, i;
for (i = 0; i < rest.length; i++) { for (i = 0; i < tail.length; i++) {
if (rest[i][1] === "+") { result += rest[i][3]; } if (tail[i][1] === "+") { result += tail[i][3]; }
if (rest[i][1] === "-") { result -= rest[i][3]; } if (tail[i][1] === "-") { result -= tail[i][3]; }
} }
return result; return result;
} }
Term Term
= first:Factor rest:(_ ("*" / "/") _ Factor)* { = head:Factor tail:(_ ("*" / "/") _ Factor)* {
var result = first, i; var result = head, i;
for (i = 0; i < rest.length; i++) { for (i = 0; i < tail.length; i++) {
if (rest[i][1] === "*") { result *= rest[i][3]; } if (tail[i][1] === "*") { result *= tail[i][3]; }
if (rest[i][1] === "/") { result /= rest[i][3]; } if (tail[i][1] === "/") { result /= tail[i][3]; }
} }
return result; return result;

@ -36,19 +36,19 @@
return result; return result;
} }
function buildList(first, rest, index) { function buildList(head, tail, index) {
return (first !== null ? [first] : []).concat(extractList(rest, index)); return (head !== null ? [head] : []).concat(extractList(tail, index));
} }
function buildExpression(first, rest) { function buildExpression(head, tail) {
var result = first, i; var result = head, i;
for (i = 0; i < rest.length; i++) { for (i = 0; i < tail.length; i++) {
result = { result = {
type: "Expression", type: "Expression",
operator: rest[i][0], operator: tail[i][0],
left: result, left: result,
right: rest[i][1] right: tail[i][1]
}; };
} }
@ -93,7 +93,7 @@ media
} }
media_list media_list
= first:medium rest:("," S* medium)* { return buildList(first, rest, 2); } = head:medium tail:("," S* medium)* { return buildList(head, tail, 2); }
medium medium
= name:IDENT S* { return name; } = name:IDENT S* { return name; }
@ -228,7 +228,7 @@ prio
= IMPORTANT_SYM S* = IMPORTANT_SYM S*
expr expr
= first:term rest:(operator? term)* { return buildExpression(first, rest); } = head:term tail:(operator? term)* { return buildExpression(head, tail); }
term term
= quantity:(PERCENTAGE / LENGTH / EMS / EXS / ANGLE / TIME / FREQ / NUMBER) = quantity:(PERCENTAGE / LENGTH / EMS / EXS / ANGLE / TIME / FREQ / NUMBER)

@ -63,22 +63,22 @@
return result; return result;
} }
function buildList(first, rest, index) { function buildList(head, tail, index) {
return [first].concat(extractList(rest, index)); return [head].concat(extractList(tail, index));
} }
function buildTree(first, rest, builder) { function buildTree(head, tail, builder) {
var result = first, i; var result = head, i;
for (i = 0; i < rest.length; i++) { for (i = 0; i < tail.length; i++) {
result = builder(result, rest[i]); result = builder(result, tail[i]);
} }
return result; return result;
} }
function buildBinaryExpression(first, rest) { function buildBinaryExpression(head, tail) {
return buildTree(first, rest, function(result, element) { return buildTree(head, tail, function(result, element) {
return { return {
type: "BinaryExpression", type: "BinaryExpression",
operator: element[1], operator: element[1],
@ -88,8 +88,8 @@
}); });
} }
function buildLogicalExpression(first, rest) { function buildLogicalExpression(head, tail) {
return buildTree(first, rest, function(result, element) { return buildTree(head, tail, function(result, element) {
return { return {
type: "LogicalExpression", type: "LogicalExpression",
operator: element[1], operator: element[1],
@ -148,10 +148,10 @@ Identifier
= !ReservedWord name:IdentifierName { return name; } = !ReservedWord name:IdentifierName { return name; }
IdentifierName "identifier" IdentifierName "identifier"
= first:IdentifierStart rest:IdentifierPart* { = head:IdentifierStart tail:IdentifierPart* {
return { return {
type: "Identifier", type: "Identifier",
name: first + rest.join("") name: head + tail.join("")
}; };
} }
@ -550,17 +550,17 @@ ArrayLiteral
} }
ElementList ElementList
= first:( = head:(
elision:(Elision __)? element:AssignmentExpression { elision:(Elision __)? element:AssignmentExpression {
return optionalList(extractOptional(elision, 0)).concat(element); return optionalList(extractOptional(elision, 0)).concat(element);
} }
) )
rest:( tail:(
__ "," __ elision:(Elision __)? element:AssignmentExpression { __ "," __ elision:(Elision __)? element:AssignmentExpression {
return optionalList(extractOptional(elision, 0)).concat(element); return optionalList(extractOptional(elision, 0)).concat(element);
} }
)* )*
{ return Array.prototype.concat.apply(first, rest); } { return Array.prototype.concat.apply(head, tail); }
Elision Elision
= "," commas:(__ ",")* { return filledArray(commas.length + 1, null); } = "," commas:(__ ",")* { return filledArray(commas.length + 1, null); }
@ -574,8 +574,8 @@ ObjectLiteral
return { type: "ObjectExpression", properties: properties }; return { type: "ObjectExpression", properties: properties };
} }
PropertyNameAndValueList PropertyNameAndValueList
= first:PropertyAssignment rest:(__ "," __ PropertyAssignment)* { = head:PropertyAssignment tail:(__ "," __ PropertyAssignment)* {
return buildList(first, rest, 3); return buildList(head, tail, 3);
} }
PropertyAssignment PropertyAssignment
@ -622,14 +622,14 @@ PropertySetParameterList
= id:Identifier { return [id]; } = id:Identifier { return [id]; }
MemberExpression MemberExpression
= first:( = head:(
PrimaryExpression PrimaryExpression
/ FunctionExpression / FunctionExpression
/ NewToken __ callee:MemberExpression __ args:Arguments { / NewToken __ callee:MemberExpression __ args:Arguments {
return { type: "NewExpression", callee: callee, arguments: args }; return { type: "NewExpression", callee: callee, arguments: args };
} }
) )
rest:( tail:(
__ "[" __ property:Expression __ "]" { __ "[" __ property:Expression __ "]" {
return { property: property, computed: true }; return { property: property, computed: true };
} }
@ -638,7 +638,7 @@ MemberExpression
} }
)* )*
{ {
return buildTree(first, rest, function(result, element) { return buildTree(head, tail, function(result, element) {
return { return {
type: "MemberExpression", type: "MemberExpression",
object: result, object: result,
@ -655,12 +655,12 @@ NewExpression
} }
CallExpression CallExpression
= first:( = head:(
callee:MemberExpression __ args:Arguments { callee:MemberExpression __ args:Arguments {
return { type: "CallExpression", callee: callee, arguments: args }; return { type: "CallExpression", callee: callee, arguments: args };
} }
) )
rest:( tail:(
__ args:Arguments { __ args:Arguments {
return { type: "CallExpression", arguments: args }; return { type: "CallExpression", arguments: args };
} }
@ -680,7 +680,7 @@ CallExpression
} }
)* )*
{ {
return buildTree(first, rest, function(result, element) { return buildTree(head, tail, function(result, element) {
element[TYPES_TO_PROPERTY_NAMES[element.type]] = result; element[TYPES_TO_PROPERTY_NAMES[element.type]] = result;
return element; return element;
@ -693,8 +693,8 @@ Arguments
} }
ArgumentList ArgumentList
= first:AssignmentExpression rest:(__ "," __ AssignmentExpression)* { = head:AssignmentExpression tail:(__ "," __ AssignmentExpression)* {
return buildList(first, rest, 3); return buildList(head, tail, 3);
} }
LeftHandSideExpression LeftHandSideExpression
@ -743,9 +743,9 @@ UnaryOperator
/ "!" / "!"
MultiplicativeExpression MultiplicativeExpression
= first:UnaryExpression = head:UnaryExpression
rest:(__ MultiplicativeOperator __ UnaryExpression)* tail:(__ MultiplicativeOperator __ UnaryExpression)*
{ return buildBinaryExpression(first, rest); } { return buildBinaryExpression(head, tail); }
MultiplicativeOperator MultiplicativeOperator
= $("*" !"=") = $("*" !"=")
@ -753,18 +753,18 @@ MultiplicativeOperator
/ $("%" !"=") / $("%" !"=")
AdditiveExpression AdditiveExpression
= first:MultiplicativeExpression = head:MultiplicativeExpression
rest:(__ AdditiveOperator __ MultiplicativeExpression)* tail:(__ AdditiveOperator __ MultiplicativeExpression)*
{ return buildBinaryExpression(first, rest); } { return buildBinaryExpression(head, tail); }
AdditiveOperator AdditiveOperator
= $("+" ![+=]) = $("+" ![+=])
/ $("-" ![-=]) / $("-" ![-=])
ShiftExpression ShiftExpression
= first:AdditiveExpression = head:AdditiveExpression
rest:(__ ShiftOperator __ AdditiveExpression)* tail:(__ ShiftOperator __ AdditiveExpression)*
{ return buildBinaryExpression(first, rest); } { return buildBinaryExpression(head, tail); }
ShiftOperator ShiftOperator
= $("<<" !"=") = $("<<" !"=")
@ -772,9 +772,9 @@ ShiftOperator
/ $(">>" !"=") / $(">>" !"=")
RelationalExpression RelationalExpression
= first:ShiftExpression = head:ShiftExpression
rest:(__ RelationalOperator __ ShiftExpression)* tail:(__ RelationalOperator __ ShiftExpression)*
{ return buildBinaryExpression(first, rest); } { return buildBinaryExpression(head, tail); }
RelationalOperator RelationalOperator
= "<=" = "<="
@ -785,9 +785,9 @@ RelationalOperator
/ $InToken / $InToken
RelationalExpressionNoIn RelationalExpressionNoIn
= first:ShiftExpression = head:ShiftExpression
rest:(__ RelationalOperatorNoIn __ ShiftExpression)* tail:(__ RelationalOperatorNoIn __ ShiftExpression)*
{ return buildBinaryExpression(first, rest); } { return buildBinaryExpression(head, tail); }
RelationalOperatorNoIn RelationalOperatorNoIn
= "<=" = "<="
@ -797,14 +797,14 @@ RelationalOperatorNoIn
/ $InstanceofToken / $InstanceofToken
EqualityExpression EqualityExpression
= first:RelationalExpression = head:RelationalExpression
rest:(__ EqualityOperator __ RelationalExpression)* tail:(__ EqualityOperator __ RelationalExpression)*
{ return buildBinaryExpression(first, rest); } { return buildBinaryExpression(head, tail); }
EqualityExpressionNoIn EqualityExpressionNoIn
= first:RelationalExpressionNoIn = head:RelationalExpressionNoIn
rest:(__ EqualityOperator __ RelationalExpressionNoIn)* tail:(__ EqualityOperator __ RelationalExpressionNoIn)*
{ return buildBinaryExpression(first, rest); } { return buildBinaryExpression(head, tail); }
EqualityOperator EqualityOperator
= "===" = "==="
@ -813,66 +813,66 @@ EqualityOperator
/ "!=" / "!="
BitwiseANDExpression BitwiseANDExpression
= first:EqualityExpression = head:EqualityExpression
rest:(__ BitwiseANDOperator __ EqualityExpression)* tail:(__ BitwiseANDOperator __ EqualityExpression)*
{ return buildBinaryExpression(first, rest); } { return buildBinaryExpression(head, tail); }
BitwiseANDExpressionNoIn BitwiseANDExpressionNoIn
= first:EqualityExpressionNoIn = head:EqualityExpressionNoIn
rest:(__ BitwiseANDOperator __ EqualityExpressionNoIn)* tail:(__ BitwiseANDOperator __ EqualityExpressionNoIn)*
{ return buildBinaryExpression(first, rest); } { return buildBinaryExpression(head, tail); }
BitwiseANDOperator BitwiseANDOperator
= $("&" ![&=]) = $("&" ![&=])
BitwiseXORExpression BitwiseXORExpression
= first:BitwiseANDExpression = head:BitwiseANDExpression
rest:(__ BitwiseXOROperator __ BitwiseANDExpression)* tail:(__ BitwiseXOROperator __ BitwiseANDExpression)*
{ return buildBinaryExpression(first, rest); } { return buildBinaryExpression(head, tail); }
BitwiseXORExpressionNoIn BitwiseXORExpressionNoIn
= first:BitwiseANDExpressionNoIn = head:BitwiseANDExpressionNoIn
rest:(__ BitwiseXOROperator __ BitwiseANDExpressionNoIn)* tail:(__ BitwiseXOROperator __ BitwiseANDExpressionNoIn)*
{ return buildBinaryExpression(first, rest); } { return buildBinaryExpression(head, tail); }
BitwiseXOROperator BitwiseXOROperator
= $("^" !"=") = $("^" !"=")
BitwiseORExpression BitwiseORExpression
= first:BitwiseXORExpression = head:BitwiseXORExpression
rest:(__ BitwiseOROperator __ BitwiseXORExpression)* tail:(__ BitwiseOROperator __ BitwiseXORExpression)*
{ return buildBinaryExpression(first, rest); } { return buildBinaryExpression(head, tail); }
BitwiseORExpressionNoIn BitwiseORExpressionNoIn
= first:BitwiseXORExpressionNoIn = head:BitwiseXORExpressionNoIn
rest:(__ BitwiseOROperator __ BitwiseXORExpressionNoIn)* tail:(__ BitwiseOROperator __ BitwiseXORExpressionNoIn)*
{ return buildBinaryExpression(first, rest); } { return buildBinaryExpression(head, tail); }
BitwiseOROperator BitwiseOROperator
= $("|" ![|=]) = $("|" ![|=])
LogicalANDExpression LogicalANDExpression
= first:BitwiseORExpression = head:BitwiseORExpression
rest:(__ LogicalANDOperator __ BitwiseORExpression)* tail:(__ LogicalANDOperator __ BitwiseORExpression)*
{ return buildBinaryExpression(first, rest); } { return buildBinaryExpression(head, tail); }
LogicalANDExpressionNoIn LogicalANDExpressionNoIn
= first:BitwiseORExpressionNoIn = head:BitwiseORExpressionNoIn
rest:(__ LogicalANDOperator __ BitwiseORExpressionNoIn)* tail:(__ LogicalANDOperator __ BitwiseORExpressionNoIn)*
{ return buildBinaryExpression(first, rest); } { return buildBinaryExpression(head, tail); }
LogicalANDOperator LogicalANDOperator
= "&&" = "&&"
LogicalORExpression LogicalORExpression
= first:LogicalANDExpression = head:LogicalANDExpression
rest:(__ LogicalOROperator __ LogicalANDExpression)* tail:(__ LogicalOROperator __ LogicalANDExpression)*
{ return buildBinaryExpression(first, rest); } { return buildBinaryExpression(head, tail); }
LogicalORExpressionNoIn LogicalORExpressionNoIn
= first:LogicalANDExpressionNoIn = head:LogicalANDExpressionNoIn
rest:(__ LogicalOROperator __ LogicalANDExpressionNoIn)* tail:(__ LogicalOROperator __ LogicalANDExpressionNoIn)*
{ return buildBinaryExpression(first, rest); } { return buildBinaryExpression(head, tail); }
LogicalOROperator LogicalOROperator
= "||" = "||"
@ -969,17 +969,17 @@ AssignmentOperator
/ "|=" / "|="
Expression Expression
= first:AssignmentExpression rest:(__ "," __ AssignmentExpression)* { = head:AssignmentExpression tail:(__ "," __ AssignmentExpression)* {
return rest.length > 0 return tail.length > 0
? { type: "SequenceExpression", expressions: buildList(first, rest, 3) } ? { type: "SequenceExpression", expressions: buildList(head, tail, 3) }
: first; : head;
} }
ExpressionNoIn ExpressionNoIn
= first:AssignmentExpressionNoIn rest:(__ "," __ AssignmentExpressionNoIn)* { = head:AssignmentExpressionNoIn tail:(__ "," __ AssignmentExpressionNoIn)* {
return rest.length > 0 return tail.length > 0
? { type: "SequenceExpression", expressions: buildList(first, rest, 3) } ? { type: "SequenceExpression", expressions: buildList(head, tail, 3) }
: first; : head;
} }
/* ----- A.4 Statements ----- */ /* ----- A.4 Statements ----- */
@ -1010,7 +1010,7 @@ Block
} }
StatementList StatementList
= first:Statement rest:(__ Statement)* { return buildList(first, rest, 1); } = head:Statement tail:(__ Statement)* { return buildList(head, tail, 1); }
VariableStatement VariableStatement
= VarToken __ declarations:VariableDeclarationList EOS { = VarToken __ declarations:VariableDeclarationList EOS {
@ -1021,13 +1021,13 @@ VariableStatement
} }
VariableDeclarationList VariableDeclarationList
= first:VariableDeclaration rest:(__ "," __ VariableDeclaration)* { = head:VariableDeclaration tail:(__ "," __ VariableDeclaration)* {
return buildList(first, rest, 3); return buildList(head, tail, 3);
} }
VariableDeclarationListNoIn VariableDeclarationListNoIn
= first:VariableDeclarationNoIn rest:(__ "," __ VariableDeclarationNoIn)* { = head:VariableDeclarationNoIn tail:(__ "," __ VariableDeclarationNoIn)* {
return buildList(first, rest, 3); return buildList(head, tail, 3);
} }
VariableDeclaration VariableDeclaration
@ -1220,7 +1220,7 @@ CaseBlock
} }
CaseClauses CaseClauses
= first:CaseClause rest:(__ CaseClause)* { return buildList(first, rest, 1); } = head:CaseClause tail:(__ CaseClause)* { return buildList(head, tail, 1); }
CaseClause CaseClause
= CaseToken __ test:Expression __ ":" consequent:(__ StatementList)? { = CaseToken __ test:Expression __ ":" consequent:(__ StatementList)? {
@ -1320,8 +1320,8 @@ FunctionExpression
} }
FormalParameterList FormalParameterList
= first:Identifier rest:(__ "," __ Identifier)* { = head:Identifier tail:(__ "," __ Identifier)* {
return buildList(first, rest, 3); return buildList(head, tail, 3);
} }
FunctionBody FunctionBody
@ -1341,8 +1341,8 @@ Program
} }
SourceElements SourceElements
= first:SourceElement rest:(__ SourceElement)* { = head:SourceElement tail:(__ SourceElement)* {
return buildList(first, rest, 1); return buildList(head, tail, 1);
} }
SourceElement SourceElement

@ -49,15 +49,15 @@ true = "true" { return true; }
object object
= begin_object = begin_object
members:( members:(
first:member head:member
rest:(value_separator m:member { return m; })* tail:(value_separator m:member { return m; })*
{ {
var result = {}, i; var result = {}, i;
result[first.name] = first.value; result[head.name] = head.value;
for (i = 0; i < rest.length; i++) { for (i = 0; i < tail.length; i++) {
result[rest[i].name] = rest[i].value; result[tail[i].name] = tail[i].value;
} }
return result; return result;
@ -76,9 +76,9 @@ member
array array
= begin_array = begin_array
values:( values:(
first:value head:value
rest:(value_separator v:value { return v; })* tail:(value_separator v:value { return v; })*
{ return [first].concat(rest); } { return [head].concat(tail); }
)? )?
end_array end_array
{ return values !== null ? values : []; } { return values !== null ? values : []; }

Loading…
Cancel
Save