From 0a4f65b1a81998de23f8af2aa3b8cdce00a7e999 Mon Sep 17 00:00:00 2001 From: Patrick Demian Date: Tue, 6 Oct 2020 06:16:14 -0400 Subject: [PATCH] Big update --- Readme.md | 76 ++++++++++++++++++++++++ build.ts | 4 +- docs/400.html | 2 +- docs/401.html | 2 +- docs/404.html | 2 +- docs/501.html | 2 +- docs/index.html | 2 +- docs/script.min.js | 2 +- docs/style.min.css | 2 +- package-lock.json | 37 ++++++++++-- package.json | 10 ++-- src/script.js | 129 +++++++++++++++++++++++++++++++++++++++++ src/script.ts | 140 +++++++++++++++++++++++++++++++++++++++++++++ src/style.css | 4 +- 14 files changed, 394 insertions(+), 20 deletions(-) create mode 100644 Readme.md diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..d2c6796 --- /dev/null +++ b/Readme.md @@ -0,0 +1,76 @@ +# Human2Regex + +## Purpose + +Generate regular expressions from natural language. Currently WIP, but should look something like this: + +Instead of a convoluted mess of symbols why not + + using global matching + create a group called "capture_me" + match 0+ words or "." or "=" or "-" + match 1+ words + +Running the program should result in the following output: + + Your regex = /\$([\w\.=\-]*[\w]+)/g + "capture_me" is group id 1 + +Is the former not much easier to read and bug fix than the latter? + +Another example + + // H2R supports // # and /**/ as comments + // A group is only captured if given a name. + // You can use "and", "or", "not" to specify `[]` regex + // You can use "then" to combine match statements, however I find using multiple "match" statements easier to read + + // exact matching means use a ^ and $ to signify the start and end of the string + + using global and exact matching + create an optional group called "protocol" + match "http" + optionally match "s" + match "://" + create a group called "subdomain" + repeat + match 1+ words + match "." + create a group called "domain" + match 1+ words or "_" or "-" + match "." + match a word + # port, but we don't care about it, so ignore it + optionally match ":" then 0+ digits + create an optional group called "path" + repeat + match "/" + match 0+ words or "_" or "-" + create an optional group + # we don't want to capture the '?', so don't name the group until afterwards + match "?" + create a group called "query" + repeat + match 1+ words or "_" or "-" + match "=" + match 1+ words or "_" or "-" + create an optional group + # fragment, again, we don't care, so ignore everything afterwards + match "#" + match 0+ anything + +Running the program should result in the following output: + + Your regex = /^(https?:\/\/)?((\w\.)*)(:\d+)?([\w_\-]\.\w)((/[\w_\-]))?(\?([\w_\-]=[\w_\-]))?(#.*)$/g + "protocol" is group id 1 + "subdomain" is group id 2 + "domain" is group id 4 + "path" is group id 5 + "query" is group id 5 or 6 if "path" exists + +## Usage +Configure config.ts +Run + + npm run build + diff --git a/build.ts b/build.ts index 726d594..8ff19ff 100644 --- a/build.ts +++ b/build.ts @@ -5,7 +5,7 @@ import { readFileSync, copyFileSync, writeFileSync, existsSync, mkdirSync } from import { emptyDirSync } from 'fs-extra'; import { minify } from 'html-minifier'; import { basename } from 'path'; -import { minify as uglify } from 'uglify-js'; +import { minify as uglify } from 'uglify-es'; import clean_css from 'clean-css'; import { glob } from 'glob'; import { config } from './config'; @@ -73,7 +73,7 @@ function build() { const error_files = glob.sync(join(config.src, 'error', '*.json')); // get partials - let partials = { + const partials = { header: read_file(join(config.src, '/header.mustache')), footer: read_file(join(config.src, '/footer.mustache')) }; diff --git a/docs/400.html b/docs/400.html index 9816360..db1e89f 100644 --- a/docs/400.html +++ b/docs/400.html @@ -1 +1 @@ -Error 400 - Bad Request

400

Bad Request



The server cannot process the request.

\ No newline at end of file +Error 400 - Bad Request

400

Bad Request



The server cannot process the request.

\ No newline at end of file diff --git a/docs/401.html b/docs/401.html index de1b1c1..98b4129 100644 --- a/docs/401.html +++ b/docs/401.html @@ -1 +1 @@ -Error 401 - Unauthorized

401

Unauthorized



Authentication required.

\ No newline at end of file +Error 401 - Unauthorized

401

Unauthorized



Authentication required.

\ No newline at end of file diff --git a/docs/404.html b/docs/404.html index a433ca9..de773ba 100644 --- a/docs/404.html +++ b/docs/404.html @@ -1 +1 @@ -Error 404 - Not Found

404

Not Found



The resource could not be found.

\ No newline at end of file +Error 404 - Not Found

404

Not Found



The resource could not be found.

\ No newline at end of file diff --git a/docs/501.html b/docs/501.html index 0f69fd9..de46433 100644 --- a/docs/501.html +++ b/docs/501.html @@ -1 +1 @@ -Error 501 - Not Implemented

501

Not Implemented



Unrecognized request method.

\ No newline at end of file +Error 501 - Not Implemented

501

Not Implemented



Unrecognized request method.

\ No newline at end of file diff --git a/docs/index.html b/docs/index.html index 11b83be..a6d9659 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1 +1 @@ -Human2Regex



Stuff here

\ No newline at end of file +Human2Regex



Stuff here

\ No newline at end of file diff --git a/docs/script.min.js b/docs/script.min.js index efb3da0..59fdb0d 100644 --- a/docs/script.min.js +++ b/docs/script.min.js @@ -1,2 +1,2 @@ /*! Copyright (c) 2020 Patrick Demian; Licensed under MIT */ -"use strict";$(function(){}); \ No newline at end of file +"use strict";const keywords=["optional","optionally","match","then","any","of","or","word","digit","unicode","character","multiple","one","two","three","four","five","six","seven","eight","nine","ten","anything","whitespace","as","number","if","starts","with","ends","otherwise","else","unless","while","more","using","global","and","multiline","exact","matching","not","between","tab","linefeed","carriage","return","group","by","exactly","inclusive","inclusively","exclusive","exclusively","including","from","to"];var TokenType;!function(e){e[e.END_OF_STATEMENT=0]="END_OF_STATEMENT",e[e.INDENT=1]="INDENT",e[e.BETWEEN=2]="BETWEEN",e[e.QUOTE=3]="QUOTE",e[e.KEYWORD_BETWEEN=4]="KEYWORD_BETWEEN",e[e.KEYWORD_OPTIONAL=5]="KEYWORD_OPTIONAL",e[e.KEYWORD_MATCH=6]="KEYWORD_MATCH",e[e.KEYWORD_THEN=7]="KEYWORD_THEN",e[e.KEYWORD_AND=8]="KEYWORD_AND",e[e.KEYWORD_OR=9]="KEYWORD_OR",e[e.KEYWORD_ANY=10]="KEYWORD_ANY",e[e.KEYWORD_OF=11]="KEYWORD_OF"}(TokenType||(TokenType={}));class Token{constructor(e,n){this.type=e,this.token_string=n}}class TokenizerOptions{constructor(){this.convert_spaces_to_tabs=!1}}function tokenize(e,n){let t=[];for(let s=0;sli.nav-item>a{font-size:12px;font-weight:800;letter-spacing:1px;text-transform:uppercase}@media only screen and (max-width:991px){#mainNav{position:fixed}}@media only screen and (min-width:992px){#mainNav .navbar-brand{padding:10px 20px;color:#fff}#mainNav .navbar-brand:focus,#mainNav .navbar-brand:hover{color:rgba(255,255,255,.8)}#mainNav .navbar-nav>li.nav-item>a{padding:10px 20px;color:#fff}#mainNav .navbar-nav>li.nav-item>a:focus,#mainNav .navbar-nav>li.nav-item>a:hover{color:rgba(255,255,255,.8)}}header.masthead{background:no-repeat center center;background-color:#868e96;background-attachment:scroll;position:relative;background-size:cover}header.masthead .overlay{position:absolute;top:0;left:0;height:100%;width:100%;background-color:#212529;opacity:.5}header.masthead .site-heading{padding:60px 0 20px;color:#fff}@media only screen and (min-width:768px){header.masthead .site-heading{padding:60px 0 20px}}header.masthead .site-heading{text-align:center}header.masthead .site-heading h1{font-size:50px;margin-top:0}header.masthead .site-heading .subheading{font-size:24px;font-weight:300;line-height:1.1;display:block;margin:10px 0 0;font-family:'Open Sans','Helvetica Neue',Helvetica,Arial,sans-serif}@media only screen and (min-width:768px){header.masthead .site-heading h1{font-size:60px}}.wrapper{display:flex;flex-direction:column;height:100vh}#maincontent{flex:1 0 auto}header{flex-shrink:0}footer{flex-shrink:0;width:100%;right:0;left:0;padding:20px 0 20px;background-color:#54595e;color:#fff}.copyright{font-size:14px;margin-bottom:0;text-align:center}.btn{font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif}.btn-primary{background-color:#00748c;border-color:#00748c}.btn-primary:active,.btn-primary:focus,.btn-primary:hover{color:#fff;background-color:#004b5c!important;border-color:#004b5c!important}.btn-lg{font-size:16px;padding:25px 35px}/*! Copyright (c) 2020 Patrick Demian; Licensed under MIT */.align_header{text-align:center;margin-bottom:20px}.skip-top{top:10px;margin:10px 40%!important}.skip{background:#335075!important;color:#fff!important;position:absolute!important;clip:rect(1px,1px,1px,1px);float:left;margin-left:20%}.skip:active,.skip:focus{font-weight:700;box-shadow:0 0 2px 2px rgba(0,0,0,.6);clip:auto!important;display:block;text-decoration:underline;padding:5px;text-align:center;top:auto;min-width:20%;text-align:center;z-index:10000}.mid-margin{margin-left:20px;margin-right:20px}a{color:#00497a}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,.54)} \ No newline at end of file + */body{font-size:20px;color:#212529}p{line-height:1.5}p a{text-decoration:underline}@media (max-width:575px){.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline label{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;margin-bottom:0}.form-inline .form-group{display:-ms-flexbox;display:flex;-ms-flex:0 0 auto;flex:0 0 auto;-ms-flex-flow:row wrap;flex-flow:row wrap;-ms-flex-align:center;align-items:center;margin-bottom:0}}h1,h2,h3,h4,h5,h6{font-weight:800;font-family:'Open Sans','Helvetica Neue',Helvetica,Arial,sans-serif}::-moz-selection{color:#fff;background:#0085a1;text-shadow:none}::selection{color:#fff;background:#0085a1;text-shadow:none}#mainNav{position:absolute;border-bottom:1px solid transparent;background-color:#232323;font-family:'Open Sans','Helvetica Neue',Helvetica,Arial,sans-serif}#mainNav .navbar-brand{font-weight:800;color:#fff}#mainNav .navbar-toggler{font-size:16px;font-weight:800;padding:13px;text-transform:uppercase;color:#343a40}#mainNav .navbar-nav>li.nav-item>a{font-size:12px;font-weight:800;letter-spacing:1px;text-transform:uppercase}@media only screen and (max-width:991px){#mainNav{position:fixed}}@media only screen and (min-width:992px){#mainNav .navbar-brand{padding:10px 20px;color:#fff}#mainNav .navbar-brand:focus,#mainNav .navbar-brand:hover{color:rgba(255,255,255,.8)}#mainNav .navbar-nav>li.nav-item>a{padding:10px 20px;color:#fff}#mainNav .navbar-nav>li.nav-item>a:focus,#mainNav .navbar-nav>li.nav-item>a:hover{color:rgba(255,255,255,.8)}}header.masthead{background:no-repeat center center;background-color:#868e96;background-attachment:scroll;position:relative;background-size:cover}header.masthead .overlay{position:absolute;top:0;left:0;height:100%;width:100%;background-color:#212529;opacity:.5}header.masthead .site-heading{padding:60px 0 20px;color:#fff}@media only screen and (min-width:768px){header.masthead .site-heading{padding:60px 0 20px}}header.masthead .site-heading{text-align:center}header.masthead .site-heading h1{font-size:50px;margin-top:0}header.masthead .site-heading .subheading{font-size:24px;font-weight:300;line-height:1.1;display:block;margin:10px 0 0;font-family:'Open Sans','Helvetica Neue',Helvetica,Arial,sans-serif}@media only screen and (min-width:768px){header.masthead .site-heading h1{font-size:60px}}.wrapper{display:flex;flex-direction:column;height:100vh}#maincontent{flex:1 0 auto}header{flex-shrink:0}footer{flex-shrink:0;width:100%;right:0;left:0;padding:20px 0 20px;background-color:#232323;color:#fff}.copyright{font-size:14px;margin-bottom:0;text-align:center}.btn{font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif}.btn-primary{background-color:#00748c;border-color:#00748c}.btn-primary:active,.btn-primary:focus,.btn-primary:hover{color:#fff;background-color:#004b5c!important;border-color:#004b5c!important}.btn-lg{font-size:16px;padding:25px 35px}/*! Copyright (c) 2020 Patrick Demian; Licensed under MIT */.align_header{text-align:center;margin-bottom:20px}.skip-top{top:10px;margin:10px 40%!important}.skip{background:#335075!important;color:#fff!important;position:absolute!important;clip:rect(1px,1px,1px,1px);float:left;margin-left:20%}.skip:active,.skip:focus{font-weight:700;box-shadow:0 0 2px 2px rgba(0,0,0,.6);clip:auto!important;display:block;text-decoration:underline;padding:5px;text-align:center;top:auto;min-width:20%;text-align:center;z-index:10000}.mid-margin{margin-left:20px;margin-right:20px}a{color:#00497a}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,.54)} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index e7d85e7..92b4c79 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,9 +44,10 @@ } }, "@types/jquery": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.1.tgz", - "integrity": "sha512-Tyctjh56U7eX2b9udu3wG853ASYP0uagChJcQJXLUXEU6C/JiW5qt5dl8ao01VRj1i5pgXPAf8f1mq4+FDLRQg==", + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.2.tgz", + "integrity": "sha512-+MFOdKF5Zr41t3y2wfzJvK1PrUK0KtPLAFwYownp/0nCoMIANDDu5aFSpWfb8S0ZajCSNeaBnMrBGxksXK5yeg==", + "dev": true, "requires": { "@types/sizzle": "*" } @@ -78,7 +79,17 @@ "@types/sizzle": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.2.tgz", - "integrity": "sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg==" + "integrity": "sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg==", + "dev": true + }, + "@types/uglify-es": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/uglify-es/-/uglify-es-3.0.0.tgz", + "integrity": "sha512-Oc/c7pGIQL0MVhC6g+VftWiDQethKsT4c3fQKYm6nOprkvkx9s1MLrnJprDTKlZL3ZJulMpCF9Qn7s6u3uCNxQ==", + "dev": true, + "requires": { + "@types/uglify-js": "*" + } }, "@types/uglify-js": { "version": "3.11.0", @@ -293,6 +304,24 @@ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true }, + "uglify-es": { + "version": "3.3.9", + "resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz", + "integrity": "sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ==", + "dev": true, + "requires": { + "commander": "~2.13.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "commander": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz", + "integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==", + "dev": true + } + } + }, "uglify-js": { "version": "3.11.0", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.11.0.tgz", diff --git a/package.json b/package.json index d417df5..5bd9222 100644 --- a/package.json +++ b/package.json @@ -8,12 +8,14 @@ "@types/fs-extra": "^9.0.1", "@types/glob": "^7.1.3", "@types/html-minifier": "^3.5.3", + "@types/jquery": "^3.5.2", "@types/mustache": "^4.0.1", - "@types/uglify-js": "^3.9.2", + "@types/uglify-es": "^3.0.0", "fs-extra": "^9.0.0", "glob": "^7.1.6", "html-minifier": "^4.0.0", - "mustache": "^4.0.1" + "mustache": "^4.0.1", + "uglify-es": "^3.3.9" }, "scripts": { "build": "tsc && node build.js && rm build.js && rm config.js", @@ -24,9 +26,7 @@ ], "author": "Patrick Demian", "license": "MIT", - "dependencies": { - "@types/jquery": "^3.5.1" - }, + "dependencies": {}, "repository": { "type": "git", "url": "git+https://github.com/pdemian/human2regex.git" diff --git a/src/script.js b/src/script.js index a5899b5..5e027ff 100644 --- a/src/script.js +++ b/src/script.js @@ -1,5 +1,134 @@ /*! Copyright (c) 2020 Patrick Demian; Licensed under MIT */ "use strict"; +const keywords = [ + "optional", "optionally", "match", "then", "any", "of", "or", "word", "digit", "unicode", "character", + "multiple", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "anything", + "whitespace", "as", "number", "if", "starts", "with", "ends", "otherwise", "else", "unless", "while", "more", + "using", "global", "and", "multiline", "exact", "matching", "not", "between", "tab", "linefeed", "carriage", "return", + "group", "by", "exactly", "inclusive", "inclusively", "exclusive", "exclusively", "including", "from", "to" +]; +var TokenType; +(function (TokenType) { + TokenType[TokenType["END_OF_STATEMENT"] = 0] = "END_OF_STATEMENT"; + TokenType[TokenType["INDENT"] = 1] = "INDENT"; + TokenType[TokenType["BETWEEN"] = 2] = "BETWEEN"; + TokenType[TokenType["QUOTE"] = 3] = "QUOTE"; + TokenType[TokenType["KEYWORD_BETWEEN"] = 4] = "KEYWORD_BETWEEN"; + TokenType[TokenType["KEYWORD_OPTIONAL"] = 5] = "KEYWORD_OPTIONAL"; + TokenType[TokenType["KEYWORD_MATCH"] = 6] = "KEYWORD_MATCH"; + TokenType[TokenType["KEYWORD_THEN"] = 7] = "KEYWORD_THEN"; + TokenType[TokenType["KEYWORD_AND"] = 8] = "KEYWORD_AND"; + TokenType[TokenType["KEYWORD_OR"] = 9] = "KEYWORD_OR"; + TokenType[TokenType["KEYWORD_ANY"] = 10] = "KEYWORD_ANY"; + TokenType[TokenType["KEYWORD_OF"] = 11] = "KEYWORD_OF"; +})(TokenType || (TokenType = {})); +class Token { + constructor(type, token_string) { + this.type = type; + this.token_string = token_string; + } +} +class TokenizerOptions { + constructor() { + this.convert_spaces_to_tabs = false; + } +} +/* Basic Tokenizer: To be replaced with a unicode variant later */ +function tokenize(input, options) { + let tokens = []; + let errors = []; + for (let i = 0; i < input.length; i++) { + // 4 spaces = 1 tab. That is final. Debate over + if (options.convert_spaces_to_tabs && input.startsWith(" ", i)) { + tokens.push(new Token(TokenType.INDENT)); + i += 3; + } + // between (ex: 0...3 or 0-3) + else if (input.startsWith("...", i)) { + tokens.push(new Token(TokenType.BETWEEN)); + i += 2; + } + else if (input.startsWith("..", i)) { + tokens.push(new Token(TokenType.BETWEEN)); + i += 1; + } + // comments + else if (input.startsWith("//", i)) { + i += 1; + while (i < input.length) { + if (input[i] == '\n') { + tokens.push(new Token(TokenType.END_OF_STATEMENT)); + break; + } + i++; + } + } + else if (input.startsWith("\r\n", i)) { + tokens.push(new Token(TokenType.END_OF_STATEMENT)); + i += 1; + } + else { + switch (input[i]) { + // comment + case '#': + i++; + while (i < input.length) { + if (input[i] == '\n') { + tokens.push(new Token(TokenType.END_OF_STATEMENT)); + break; + } + i++; + } + break; + // quote + case '"': + case '\"': + // build up a word between quotes + const quote_char = input[i]; + let found_ending = false; + let quote = ""; + do { + i++; + if (input[i] == quote_char) { + found_ending = true; + break; + } + else if (input[i] == '\n') { + } + } while (i < input.length); + if (found_ending) { + tokens.push(new Token(TokenType.QUOTE, quote)); + } + else { + // Skip until newline and throw an error + } + break; + // between (ex: 0...3 or 0-3) + case '-': + tokens.push(new Token(TokenType.BETWEEN)); + break; + case '\n': + tokens.push(new Token(TokenType.END_OF_STATEMENT)); + break; + case '\r': + // ignore + break; + case '\t': + tokens.push(new Token(TokenType.INDENT)); + break; + case ' ': + break; + default: + // is digit? build up a number + // is char? build up a word + keywords.includes("word"); + // build up a word + break; + } + } + } + return { tokens: tokens, errors: errors }; +} /* String.prototype.escape = function() { var tagsToReplace = { diff --git a/src/script.ts b/src/script.ts index 5a02b5d..831c670 100644 --- a/src/script.ts +++ b/src/script.ts @@ -2,6 +2,146 @@ "use strict"; +const keywords = [ + "optional", "optionally", "match", "then", "any", "of", "or", "word", "digit", "unicode", "character", + "multiple", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "anything", + "whitespace", "as", "number", "if", "starts", "with", "ends", "otherwise", "else", "unless", "while", "more", + "using", "global", "and", "multiline", "exact", "matching", "not", "between", "tab", "linefeed", "carriage", "return", + "group", "by", "exactly", "inclusive", "inclusively", "exclusive", "exclusively", "including", "from", "to" +]; + +enum TokenType { + END_OF_STATEMENT, + INDENT, + BETWEEN, + QUOTE, + KEYWORD_BETWEEN, + KEYWORD_OPTIONAL, + KEYWORD_MATCH, + KEYWORD_THEN, + KEYWORD_AND, + KEYWORD_OR, + KEYWORD_ANY, + KEYWORD_OF, +} + +class Token { + constructor(public type: TokenType, public token_string?: string) { + + } +} + +class TokenizerOptions { + public convert_spaces_to_tabs: boolean = false; + +} + +/* Basic Tokenizer: To be replaced with a unicode variant later */ + +function tokenize(input: string, options: TokenizerOptions) : { tokens: Token[], errors: Error[] } { + let tokens : Token[] = []; + let errors : Error[] = []; + + for(let i = 0; i < input.length; i++) { + + // 4 spaces = 1 tab. That is final. Debate over + if(options.convert_spaces_to_tabs && input.startsWith(" ", i)) { + tokens.push(new Token(TokenType.INDENT)); + i += 3; + } + // between (ex: 0...3 or 0-3) + else if(input.startsWith("...", i)) { + tokens.push(new Token(TokenType.BETWEEN)); + i += 2; + } else if(input.startsWith("..", i)) { + tokens.push(new Token(TokenType.BETWEEN)); + i += 1; + } + // comments + else if(input.startsWith("//", i)) { + i += 1; + while(i < input.length) { + if(input[i] == '\n') { + tokens.push(new Token(TokenType.END_OF_STATEMENT)); + break; + } + i++; + } + } else if (input.startsWith("\r\n", i)) { + tokens.push(new Token(TokenType.END_OF_STATEMENT)); + i += 1; + } else { + switch(input[i]) { + // comment + case '#': + i++; + while(i < input.length) { + if(input[i] == '\n') { + tokens.push(new Token(TokenType.END_OF_STATEMENT)); + break; + } + i++; + } + break; + // quote + case '"': + case '\"': + // build up a word between quotes + const quote_char = input[i]; + let found_ending = false; + + let quote = ""; + + do { + i++; + if(input[i] == quote_char) { + found_ending = true; + break; + } + else if(input[i] == '\n') { + + } + } while(i < input.length); + + if(found_ending) { + tokens.push(new Token(TokenType.QUOTE, quote)); + } + else { + // Skip until newline and throw an error + } + + break; + + // between (ex: 0...3 or 0-3) + case '-': + tokens.push(new Token(TokenType.BETWEEN)); + break; + case '\n': + tokens.push(new Token(TokenType.END_OF_STATEMENT)); + break; + case '\r': + // ignore + break; + case '\t': + tokens.push(new Token(TokenType.INDENT)); + break; + case ' ': + break; + default: + // is digit? build up a number + + // is char? build up a word + + keywords.includes("word"); + // build up a word + break; + } + } + } + + return { tokens: tokens, errors: errors }; +} + /* String.prototype.escape = function() { var tagsToReplace = { diff --git a/src/style.css b/src/style.css index 3f790fb..577c6b4 100644 --- a/src/style.css +++ b/src/style.css @@ -77,7 +77,7 @@ h6 { #mainNav .navbar-brand { font-weight: 800; - color: #343a40; + color: #fff; } #mainNav .navbar-toggler { @@ -191,7 +191,7 @@ footer { right: 0; left: 0; padding: 20px 0 20px; - background-color: #54595e; + background-color: #232323; color: #fff; }