Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closes #57: Adding support for AnB Microsyntax #131

Merged
merged 28 commits into from
Aug 7, 2019
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
9700fdd
First stab at anbmicrosyntax (WIP)
2biazdk Oct 3, 2018
be282b0
Merge branch 'master' into anbmicrosyntax
2biazdk Oct 9, 2018
3ee24a4
Merge branch 'master' into anbmicrosyntax
2biazdk Nov 27, 2018
06cd959
Add AnBMicrosyntax as a pseudoclass value
2biazdk Nov 28, 2018
6de1fc1
Support more test cases
2biazdk Nov 30, 2018
6570dc0
Forgot to commit latest work
2biazdk Feb 11, 2019
29c2b99
Merge branch 'master' into anbmicrosyntax
niclashedam Jun 25, 2019
0fdc607
WIP on AnB Microsyntax
niclashedam Jun 26, 2019
9cdd404
Removing uneeded comment
niclashedam Jun 26, 2019
b7a501b
Scaffold the things!
kasperisager Jun 26, 2019
0bec408
WIP on child index grammar
niclashedam Jun 26, 2019
643841c
Refactorz
kasperisager Jun 26, 2019
4289444
WIP on AnB
niclashedam Jun 27, 2019
ee1c3bd
AnB almost done
niclashedam Jun 27, 2019
997144b
refactor selector
niclashedam Jun 27, 2019
fcbf621
Fixing failing selector test and getting selector up to speed
niclashedam Jun 27, 2019
abbab40
Alfa-dom up to speed
niclashedam Jun 27, 2019
8fa3088
Fixing parse
niclashedam Jun 27, 2019
15836c6
AnB fixes
niclashedam Jun 27, 2019
7bd774f
Asserting on floats in number
niclashedam Jun 27, 2019
e32a298
Adding some more tests
niclashedam Jun 27, 2019
2173210
Formatting
niclashedam Jun 27, 2019
7dc4243
Merge branch 'master' into anbmicrosyntax
niclashedam Jul 2, 2019
989a6db
Rework child index implementation
kasperisager Aug 7, 2019
e436da0
Merge branch 'master' into anbmicrosyntax
kasperisager Aug 7, 2019
cbaaee2
Fix undefined reference
kasperisager Aug 7, 2019
b0a08c4
Merge branch 'anbmicrosyntax' of github.com:Siteimprove/alfa into anb…
kasperisager Aug 7, 2019
42c86cc
Fix some test cases
kasperisager Aug 7, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
242 changes: 242 additions & 0 deletions packages/alfa-css/src/grammars/child-index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
import * as Lang from "@siteimprove/alfa-lang";
import { Grammar, skip } from "@siteimprove/alfa-lang";
import * as alphabet from "../alphabet";
import { Token, Tokens, TokenType } from "../alphabet";
import { ChildIndex } from "../types";

namespace ChildIndex {
export const enum TokenType {
Ident,
Number,
DashNDashDigitIdent,
Integer,
NDashDigitDimension,
NDashDigitIdent,
NDashDimension,
NDimension,
SignedInteger,
SignlessInteger
}

export namespace Tokens {
interface Token<T extends TokenType> extends Lang.Token<T> {}

export interface DashNDashDigitIdent
extends Token<TokenType.DashNDashDigitIdent> {
readonly value: string;
}

export interface Integer extends Token<TokenType.Integer> {
readonly value: number;
}

export interface NDashDigitDimension
extends Token<TokenType.NDashDigitDimension> {
readonly unit: string;
readonly value: number;
}

export interface NDashDigitIdent extends Token<TokenType.NDashDigitIdent> {
readonly value: string;
}

export interface NDashDimension extends Token<TokenType.NDashDimension> {
readonly unit: string;
readonly value: number;
}

export interface NDimension extends Token<TokenType.NDimension> {
readonly value: number;
}

export interface SignedInteger extends Token<TokenType.SignedInteger> {
readonly value: number;
}

export interface SignlessInteger extends Token<TokenType.SignlessInteger> {
readonly value: number;
}
}

export type Token =
| alphabet.Tokens.Ident
| alphabet.Tokens.Number
| Tokens.DashNDashDigitIdent
| Tokens.NDashDigitDimension
| Tokens.NDashDigitIdent
| Tokens.NDashDimension
| Tokens.NDimension;
}

function fromToken(token: Token): ChildIndex.Token | null {
switch (token.type) {
case TokenType.Dimension:
if (token.integer === true && token.unit.toLowerCase() === "n") {
return {
type: ChildIndex.TokenType.NDimension,
value: token.value
};
}

if (
token.integer === true &&
token.unit.toLowerCase().match("n-[0-9]+") !== null
) {
return {
unit: token.unit,
type: ChildIndex.TokenType.NDashDigitDimension,
value: token.value
};
}

if (token.integer === true && token.unit.toLowerCase().startsWith("n")) {
return {
unit: token.unit,
type: ChildIndex.TokenType.NDashDimension,
value: token.value
};
}
break;

case TokenType.Ident:
if (token.value.toLowerCase().match("-n-[0-9]+") !== null) {
return {
type: ChildIndex.TokenType.DashNDashDigitIdent,
value: token.value
};
}

if (token.value.toLowerCase().match("n-[0-9]+") !== null) {
return {
type: ChildIndex.TokenType.NDashDigitIdent,
value: token.value
};
}

return token;

case TokenType.Number:
return token;
}

return null;
}

type Production<T extends Token> = Lang.Production<Token, ChildIndex, T>;

const dimension: Production<Tokens.Dimension> = {
token: TokenType.Dimension,
prefix(token, stream) {
let a = 0;
let b = 0;

const childToken = fromToken(token);

if (childToken === null) {
return null;
}

switch (childToken.type) {
case ChildIndex.TokenType.NDimension:
a = childToken.value;
break;

case ChildIndex.TokenType.NDashDimension:
a = childToken.value;
b = Number.parseInt(childToken.unit.substring(1));
break;

case ChildIndex.TokenType.NDashDigitDimension:
a = childToken.value !== null ? childToken.value : 1;
if (childToken.unit.length > 1) {
b = Number.parseInt(childToken.unit.substring(1));
}
}

return { a, b };
}
};

const ident: Production<Tokens.Ident> = {
token: TokenType.Ident,
prefix(token, stream) {
let a = 0;
let b = 0;

const childToken = fromToken(token);

if (childToken === null) {
return null;
}

switch (childToken.type) {
case ChildIndex.TokenType.NDashDigitIdent:
a = 1;
b = Number.parseInt(childToken.value.substring(1));
break;
case ChildIndex.TokenType.DashNDashDigitIdent:
a = -1;
b = Number.parseInt(childToken.value.substring(2));
break;
case TokenType.Ident:
switch (token.value.toLowerCase()) {
case "n":
a = 1;
b = 0;
break;
case "-n":
a = -1;
b = 0;
break;
case "even":
a = 2;
b = 0;
break;
case "odd":
a = 2;
b = 1;
break;
default:
return null;
}
break;
default:
return null;
}

return { a, b };
}
};

const number: Production<Tokens.Number> = {
token: TokenType.Number,
prefix(token, stream) {
const childToken = fromToken(token);

if (childToken === null || childToken.type !== TokenType.Number) {
return null;
}

return {
a: 0,
b: childToken.value
};
},
infix(token, stream, expression, left) {
const childToken = fromToken(token);

if (childToken === null || childToken.type !== TokenType.Number) {
return null;
}

return {
a: left.a,
b: childToken.value
};
}
};

export const ChildIndexGrammar: Grammar<Token, ChildIndex> = new Lang.Grammar(
[[skip(TokenType.Whitespace), dimension, ident, number]],
() => null
);
37 changes: 31 additions & 6 deletions packages/alfa-css/src/grammars/selector.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import * as Lang from "@siteimprove/alfa-lang";
import { Char, Expression, Grammar, Stream } from "@siteimprove/alfa-lang";
import {
Char,
Expression,
Grammar,
Stream,
parse
} from "@siteimprove/alfa-lang";
import { Token, Tokens, TokenType } from "../alphabet";
import {
AttributeMatcher,
Expand All @@ -20,6 +26,7 @@ import {
SimpleSelector,
TypeSelector
} from "../types";
import { ChildIndexGrammar } from "./child-index";

const { isArray } = Array;

Expand Down Expand Up @@ -320,16 +327,16 @@ function pseudoSelector(
case "root":
case "empty":
case "blank":
case "nth-child":
case "nth-last-child":
case "first-child":
case "last-child":
case "only-child":
case "nth-of-type":
case "nth-last-of-type":
case "first-of-type":
case "last-of-type":
case "only-of-type":
case "nth-child":
case "nth-last-child":
case "nth-of-type":
case "nth-last-of-type":
case "nth-col":
case "nth-last-col":
name = next.value;
Expand All @@ -341,7 +348,25 @@ function pseudoSelector(
if (next.type === TokenType.Ident) {
selector = { type: SelectorType.PseudoClassSelector, name, value: null };
} else {
const value = expression();
let value = null;

switch (name) {
case "nth-child":
case "nth-last-child":
case "nth-of-type":
case "nth-last-of-type":
case "nth-col":
case "nth-last-col":
value = parse(stream, ChildIndexGrammar).result;
if (value === null) {
return null;
}
stream.next();
stream.accept(token => token.type === TokenType.Whitespace);
break;
default:
value = expression();
}

next = stream.next();

Expand Down
27 changes: 18 additions & 9 deletions packages/alfa-css/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ export interface TypeSelector {
export interface PseudoClassSelector {
readonly type: SelectorType.PseudoClassSelector;
readonly name: PseudoClass;
readonly value: Selector | Array<Selector> | null;
readonly value: Selector | Array<Selector> | ChildIndex | null;
}

export interface PseudoElementSelector {
Expand Down Expand Up @@ -251,26 +251,30 @@ export type PseudoClass =
| "empty"
// https://www.w3.org/TR/selectors/#blank-pseudo
| "blank"
// https://www.w3.org/TR/selectors/#nth-child-pseudo
| "nth-child"
// https://www.w3.org/TR/selectors/#nth-last-child-pseudo
| "nth-last-child"
// https://www.w3.org/TR/selectors/#first-child-pseudo
| "first-child"
// https://www.w3.org/TR/selectors/#last-child-pseudo
| "last-child"
// https://www.w3.org/TR/selectors/#only-child-pseudo
| "only-child"
// https://www.w3.org/TR/selectors/#nth-of-type-pseudo
| "nth-of-type"
// https://www.w3.org/TR/selectors/#nth-last-of-type-pseudo
| "nth-last-of-type"
// https://www.w3.org/TR/selectors/#first-of-type-pseudo
| "first-of-type"
// https://www.w3.org/TR/selectors/#last-of-type-pseudo
| "last-of-type"
// https://www.w3.org/TR/selectors/#only-of-type-pseudo
| "only-of-type"
// https://www.w3.org/TR/selectors/#child-index
| ChildIndexedPseudoClass;

type ChildIndexedPseudoClass =
// https://www.w3.org/TR/selectors/#nth-child-pseudo
| "nth-child"
// https://www.w3.org/TR/selectors/#nth-last-child-pseudo
| "nth-last-child"
// https://www.w3.org/TR/selectors/#nth-of-type-pseudo
| "nth-of-type"
// https://www.w3.org/TR/selectors/#nth-last-of-type-pseudo
| "nth-last-of-type"
// https://www.w3.org/TR/selectors/#nth-col-pseudo
| "nth-col"
// https://www.w3.org/TR/selectors/#nth-last-col-pseudo
Expand All @@ -297,6 +301,11 @@ export type PseudoElement =
// https://www.w3.org/TR/css-pseudo/#placeholder-pseudo
| "placeholder";

export interface ChildIndex {
readonly a: number;
readonly b: number;
}

export const enum MediaQualifier {
Only,
Not
Expand Down