1// Copyright 2019 Google LLC 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15import { assert } from "chai"; 16import Lexer from "./lexer"; 17import { TokenType } from "./token"; 18 19describe("lexer", () => { 20 describe("skipped content", () => { 21 it("skips whitespace", () => { 22 let input = " \t\r\n\t \tOpKill\t\n\t \r "; 23 let l = new Lexer(input); 24 25 let t = l.next(); 26 assert.equal(t.type, TokenType.kOp); 27 assert.equal(t.line, 2); 28 assert.equal(t.data.name, "OpKill"); 29 30 t = l.next(); 31 assert.equal(t.type, TokenType.kEOF); 32 assert.equal(t.line, 3); 33 }); 34 35 it("skips ; comments", () => { 36 let input = `; start with comment 37OpKill ; end of line comment 38; another comment 39%1`; 40 41 let l = new Lexer(input); 42 let t = l.next(); 43 assert.equal(t.type, TokenType.kOp); 44 assert.equal(t.data.name, "OpKill"); 45 assert.equal(t.line, 2); 46 47 t = l.next(); 48 assert.equal(t.type, TokenType.kResultId); 49 assert.equal(t.data.name, "1"); 50 assert.equal(t.data.val, 1); 51 assert.equal(t.line, 4); 52 }); 53 }); 54 55 describe("numerics", () => { 56 it("parses floats", () => { 57 let input = ["0.0", "0.", ".0", "5.7", "5.", ".7", "-0.0", "-.0", 58 "-0.", "-5.7", "-5.", "-.7"]; 59 60 let results = [0.0, 0.0, 0.0, 5.7, 5.0, 0.7, 0.0, 0.0, 0.0, -5.7, -5.0, 61 -0.7]; 62 input.forEach((val, idx) => { 63 let l = new Lexer(val); 64 let t = l.next(); 65 66 assert.equal(t.type, TokenType.kFloatLiteral, 67 `expected ${val} to be a float got ${t.type}`); 68 assert.equal(t.data, results[idx], 69 `expected ${results[idx]} === ${t.data}`); 70 71 t = l.next(); 72 assert.equal(t.type, TokenType.kEOF); 73 assert.equal(t.data, undefined); 74 }); 75 }); 76 77 it("handles invalid floats", () => { 78 let input = [".", "-."]; 79 input.forEach((val) => { 80 let l = new Lexer(val); 81 let t = l.next(); 82 83 assert.notEqual(t.type, TokenType.kFloatLiteral, 84 `expect ${val} to not match type float`); 85 }); 86 }); 87 88 it("parses integers", () => { 89 let input = ["0", "-0", "123", "-123", "2147483647", "-2147483648", 90 "4294967295", "0x00", "0x24"]; 91 let results = [0, 0, 123, -123,2147483647, -2147483648, 4294967295, 92 0x0, 0x24]; 93 94 input.forEach((val, idx) => { 95 let l = new Lexer(val); 96 let t = l.next(); 97 98 assert.equal(t.type, TokenType.kIntegerLiteral, 99 `expected ${val} to be an integer got ${t.type}`); 100 assert.equal(t.data, results[idx], 101 `expected ${results[idx]} === ${t.data}`); 102 103 t = l.next(); 104 assert.equal(t.type, TokenType.kEOF); 105 assert.equal(t.data, undefined); 106 }); 107 }); 108 }); 109 110 it("matches result_ids", () => { 111 let input = `%123 112%001 113%main 114%_a_b_c`; 115 116 let result = [ 117 {name: "123", val: 123}, 118 {name: "001", val: 1}, 119 {name: "main", val: undefined}, 120 {name: "_a_b_c", val: undefined} 121 ]; 122 123 let l = new Lexer(input); 124 for (let i = 0; i < result.length; ++i) { 125 let t = l.next(); 126 assert.equal(t.type, TokenType.kResultId); 127 assert.equal(t.data.name, result[i].name); 128 assert.equal(t.data.val, result[i].val); 129 } 130 }); 131 132 it("matches punctuation", () => { 133 let input = "="; 134 let results = [TokenType.kEqual]; 135 136 let l = new Lexer(input); 137 for (let i = 0; i < results.length; ++i) { 138 let t = l.next(); 139 assert.equal(t.type, results[i]); 140 assert.equal(t.line, i + 1); 141 } 142 143 let t = l.next(); 144 assert.equal(t.type, TokenType.kEOF); 145 }); 146 147 describe("strings", () => { 148 it("matches strings", () => { 149 let input = "\"GLSL.std.450\""; 150 151 let l = new Lexer(input); 152 let t = l.next(); 153 assert.equal(t.type, TokenType.kStringLiteral); 154 assert.equal(t.data, "GLSL.std.450"); 155 }); 156 157 it("handles unfinished strings", () => { 158 let input = "\"GLSL.std.450"; 159 160 let l = new Lexer(input); 161 let t = l.next(); 162 assert.equal(t.type, TokenType.kError); 163 }); 164 165 it("handles escapes", () => { 166 let input = `"embedded\\"quote" 167"embedded\\\\slash" 168"embedded\\nchar"`; 169 let results = [`embedded\"quote`, `embedded\\slash`, `embeddednchar`]; 170 171 let l = new Lexer(input); 172 for (let i = 0; i < results.length; ++i) { 173 let t = l.next(); 174 assert.equal(t.type, TokenType.kStringLiteral, results[i]); 175 assert.equal(t.data, results[i]); 176 } 177 }); 178 }); 179 180 it("matches keywords", () => { 181 let input = "GLSL Function"; 182 let results = ["GLSL", "Function"]; 183 184 let l = new Lexer(input); 185 for (let i = 0; i < results.length; ++i) { 186 let t = l.next(); 187 assert.equal(t.type, TokenType.kIdentifier, results[i]); 188 assert.equal(t.data, results[i]); 189 } 190 }); 191}); 192