123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188 |
- import * as test from 'tape';
-
- import Lexer, { LexerError, LexerResult } from '../lexer';
- import Token, { TokenTypes as TT } from '../token';
-
- const scan = (source: string): LexerResult => {
- return new Lexer(source).scan();
- };
-
- const EOF = (line: number = 1) => new Token(TT.EOF, 'eof', line);
-
- test('scans punctuation', (t) => {
- t.plan(2);
- const result: LexerResult = scan('(),');
- t.false(result instanceof LexerError);
- if (!(result instanceof LexerError)) {
- t.deepEqual(result.tokens.map((t) => t.type), [
- TT.LPAREN,
- TT.RPAREN,
- TT.COMMA,
- TT.EOF,
- ]);
- }
- });
-
- test('scans property', (t) => {
- t.plan(2);
- const result: LexerResult = scan(':property');
- t.false(result instanceof LexerError);
- if (!(result instanceof LexerError)) {
- t.deepEqual(result.tokens, [new Token(TT.PROPERTY, 'property', 1), EOF()]);
- }
- });
-
- test('scans identifier', (t) => {
- t.plan(2);
- const result: LexerResult = scan('$identifier');
- t.false(result instanceof LexerError);
- if (!(result instanceof LexerError)) {
- t.deepEqual(result.tokens, [
- new Token(TT.IDENTIFIER, 'identifier', 1),
- EOF(),
- ]);
- }
- });
-
- test('scans function name', (t) => {
- t.plan(2);
- const result: LexerResult = scan('@function_name');
- t.false(result instanceof LexerError);
- if (!(result instanceof LexerError)) {
- t.deepEqual(result.tokens, [
- new Token(TT.FUNCTION_NAME, 'function_name', 1),
- EOF(),
- ]);
- }
- });
-
- test('scans literal', (t) => {
- t.plan(2);
- const result: LexerResult = scan('literal');
- t.false(result instanceof LexerError);
- if (!(result instanceof LexerError)) {
- t.deepEqual(result.tokens, [new Token(TT.LITERAL, 'literal', 1), EOF()]);
- }
- });
-
- test('scans literal followed by parens', (t) => {
- t.plan(2);
- const result: LexerResult = scan('literal(literal)literal (');
- t.false(result instanceof LexerError);
- if (!(result instanceof LexerError)) {
- t.deepEqual(result.tokens, [
- new Token(TT.LITERAL, 'literal', 1),
- new Token(TT.LPAREN, '(', 1),
- new Token(TT.LITERAL, 'literal', 1),
- new Token(TT.RPAREN, ')', 1),
- new Token(TT.LITERAL, 'literal', 1),
- new Token(TT.LPAREN, '(', 1),
- EOF(),
- ]);
- }
- });
-
- test('scans literal followed by property', (t) => {
- t.plan(2);
- const result: LexerResult = scan('literal :property');
- t.false(result instanceof LexerError);
- if (!(result instanceof LexerError)) {
- t.deepEqual(result.tokens, [
- new Token(TT.LITERAL, 'literal', 1),
- new Token(TT.PROPERTY, 'property', 1),
- EOF(),
- ]);
- }
- });
-
- test('scans simple expression', (t) => {
- t.plan(2);
- const result: LexerResult = scan('(div :color blue)');
- t.false(result instanceof LexerError);
- if (!(result instanceof LexerError)) {
- t.deepEqual(result.tokens, [
- new Token(TT.LPAREN, '(', 1),
- new Token(TT.LITERAL, 'div', 1),
- new Token(TT.PROPERTY, 'color', 1),
- new Token(TT.LITERAL, 'blue', 1),
- new Token(TT.RPAREN, ')', 1),
- EOF(),
- ]);
- }
- });
-
- test('keeps track of line numbers', (t) => {
- t.plan(2);
- const result: LexerResult = scan('line1\nline2');
- t.false(result instanceof LexerError);
- if (!(result instanceof LexerError)) {
- t.deepEqual(result.tokens, [
- new Token(TT.LITERAL, 'line1', 1),
- new Token(TT.LITERAL, 'line2', 2),
- EOF(2),
- ]);
- }
- });
-
- test('scans literal followed by identifier', (t) => {
- t.plan(2);
- const result: LexerResult = scan('literal $identifier');
- t.false(result instanceof LexerError);
- if (!(result instanceof LexerError)) {
- t.deepEqual(result.tokens, [
- new Token(TT.LITERAL, 'literal', 1),
- new Token(TT.IDENTIFIER, 'identifier', 1),
- EOF(),
- ]);
- }
- });
-
- test('allow dashes', (t) => {
- t.plan(2);
- const result: LexerResult = scan(
- 'literal-dash $identifier-dash @function-dash'
- );
- t.false(result instanceof LexerError);
- if (!(result instanceof LexerError)) {
- t.deepEqual(result.tokens, [
- new Token(TT.LITERAL, 'literal-dash', 1),
- new Token(TT.IDENTIFIER, 'identifier-dash', 1),
- new Token(TT.FUNCTION_NAME, 'function-dash', 1),
- EOF(),
- ]);
- }
- });
-
- test('disallow whitespace in function arguments', (t) => {
- t.plan(2);
- const result: LexerResult = scan('(@rgba 0 0 0 0)');
- t.false(result instanceof LexerError);
- if (!(result instanceof LexerError)) {
- t.deepEqual(result.tokens, [
- new Token(TT.LPAREN, '(', 1),
- new Token(TT.FUNCTION_NAME, 'rgba', 1),
- new Token(TT.LITERAL, '0', 1),
- new Token(TT.LITERAL, '0', 1),
- new Token(TT.LITERAL, '0', 1),
- new Token(TT.LITERAL, '0', 1),
- new Token(TT.RPAREN, ')', 1),
- EOF(),
- ]);
- }
- });
-
- test('ignores comments', (t) => {
- t.plan(2);
- const result: LexerResult = scan('; div with blue text\n(div :color blue)');
- t.false(result instanceof LexerError);
- if (!(result instanceof LexerError)) {
- t.deepEqual(result.tokens, [
- new Token(TT.LPAREN, '(', 2),
- new Token(TT.LITERAL, 'div', 2),
- new Token(TT.PROPERTY, 'color', 2),
- new Token(TT.LITERAL, 'blue', 2),
- new Token(TT.RPAREN, ')', 2),
- EOF(2),
- ]);
- }
- });
|