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 24 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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion packages/alfa-css/src/alphabet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ export namespace Tokens {
export interface Number extends Token<TokenType.Number> {
readonly value: number;
readonly integer: boolean;
readonly signed: boolean;
}

export interface Percentage extends Token<TokenType.Percentage> {
Expand All @@ -89,6 +90,7 @@ export namespace Tokens {
export interface Dimension extends Token<TokenType.Dimension> {
readonly value: number;
readonly integer: boolean;
readonly signed: boolean;
readonly unit: string;
}

Expand Down Expand Up @@ -461,10 +463,13 @@ function consumeNumber(char: number, stream: Stream<number>): Tokens.Number {

let next: number | null = char;

let isSigned = false;

if (next === Char.PlusSign || next === Char.HyphenMinus) {
result.push(next);
stream.advance(1);
next = stream.peek(0);
isSigned = true;
}

while (next !== null && isNumeric(next)) {
Expand Down Expand Up @@ -521,7 +526,8 @@ function consumeNumber(char: number, stream: Stream<number>): Tokens.Number {
return {
type: TokenType.Number,
value: consumeInteger(result),
integer: isInteger
integer: isInteger,
signed: isSigned
};
}

Expand All @@ -541,6 +547,7 @@ function consumeNumeric(
type: TokenType.Dimension,
value: number.value,
integer: number.integer,
signed: number.signed,
unit: consumeName(next, stream)
};
}
Expand Down
229 changes: 229 additions & 0 deletions packages/alfa-css/src/grammars/child-index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
import * as Lang from "@siteimprove/alfa-lang";
import { Char, Grammar, isNumeric, skip, Stream } from "@siteimprove/alfa-lang";
import { Token, Tokens, TokenType } from "../alphabet";
import { ChildIndex } from "../types";

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

const number: Production<Tokens.Number> = {
token: TokenType.Number,
prefix(token, stream) {
if (!token.integer) {
return null;
}

return {
step: 0,
offset: token.value
};
}
};

const dimension: Production<Tokens.Dimension> = {
token: TokenType.Dimension,
prefix(token, stream) {
if (!token.integer) {
return null;
}

const unit = token.unit.toLowerCase();

switch (unit) {
case "n":
return { step: token.value, offset: parseOffset(stream) };

case "n-":
return { step: token.value, offset: -1 * parseOffset(stream, true) };
}

{
const stream = new Stream(unit.length, i => unit.charCodeAt(i));

let next = stream.peek(0);

if (next === null || next !== Char.SmallLetterN) {
return null;
}

stream.advance(1);
next = stream.peek(0);

if (next === null || next !== Char.HyphenMinus) {
return null;
}

stream.advance(1);
next = stream.peek(0);

if (next === null || !isNumeric(next)) {
return null;
}

let offset = 0;

while (next !== null && isNumeric(next)) {
offset = offset * 10 + next - Char.DigitZero;

stream.advance(1);
next = stream.peek(0);
}

if (!stream.done()) {
return null;
}

return { step: token.value, offset: -1 * offset };
}

return null;
}
};

const ident: Production<Tokens.Ident> = {
token: TokenType.Ident,
prefix(token, stream) {
const value = token.value.toLowerCase();

switch (value) {
case "n":
return { step: 1, offset: parseOffset(stream) };

case "-n":
return { step: -1, offset: parseOffset(stream) };

case "n-":
return { step: 1, offset: -1 * parseOffset(stream, true) };

case "-n-":
return { step: -1, offset: -1 * parseOffset(stream, true) };

case "even":
return { step: 2, offset: 0 };

case "odd":
return { step: 2, offset: 1 };
}

{
const stream = new Stream(value.length, i => value.charCodeAt(i));

let step = 1;
let next = stream.peek(0);

if (next !== null && next === Char.HyphenMinus) {
step = -1;

stream.advance(1);
next = stream.peek(0);
}

if (next === null || next !== Char.SmallLetterN) {
return null;
}

stream.advance(1);
next = stream.peek(0);

if (next === null || next !== Char.HyphenMinus) {
return null;
}

stream.advance(1);
next = stream.peek(0);

if (next === null || !isNumeric(next)) {
return null;
}

let offset = 0;

while (next !== null && isNumeric(next)) {
offset = offset * 10 + next - Char.DigitZero;

stream.advance(1);
next = stream.peek(0);
}

if (!stream.done()) {
return null;
}

return { step, offset: -1 * offset };
}
}
};

const delim: Production<Tokens.Delim> = {
token: TokenType.Delim,
prefix(token, stream, expression) {
switch (token.value) {
case Char.PlusSign: {
const next = stream.peek(0);

if (next === null || next.type !== TokenType.Ident) {
break;
}

return expression();
}
}

return null;
}
};

export const ChildIndexGrammar: Grammar<Token, ChildIndex> = new Lang.Grammar(
[[skip(TokenType.Whitespace), dimension, ident, number, delim]],
() => null
);

function parseOffset(stream: Stream<Token>, signless = false): number {
stream.accept(token => token.type === TokenType.Whitespace);

let next = stream.peek(0);

if (next === null) {
return 0;
}

let sign: number | null = null;

if (next.type === TokenType.Delim) {
if (signless) {
return 0;
}

switch (next.value) {
case Char.PlusSign:
sign = 1;
break;
case Char.HyphenMinus:
sign = -1;
break;
default:
return 0;
}

stream.advance(1);
stream.accept(token => token.type === TokenType.Whitespace);

signless = true;
next = stream.peek(0);

if (next === null) {
return 0;
}
}

if (
next.type !== TokenType.Number ||
!next.integer ||
signless === next.signed
) {
return 0;
}

stream.advance(1);

return sign === null ? next.value : sign * next.value;
}
Loading