diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..7e2c842 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,15 @@ +{ + "configurations": [ + { + "name": "Win32", + "includePath": ["${workspaceFolder}/**"], + "defines": ["_DEBUG", "UNICODE", "_UNICODE"], + "windowsSdkVersion": "10.0.26100.0", + "compilerPath": "cl.exe", + "cStandard": "c17", + "cppStandard": "c++20", + "intelliSenseMode": "windows-msvc-x64" + } + ], + "version": 4 +} diff --git a/binding.gyp b/binding.gyp index 785d79a..3e05f8b 100644 --- a/binding.gyp +++ b/binding.gyp @@ -10,7 +10,11 @@ " +#include #include enum TokenKind { @@ -31,7 +32,7 @@ namespace Lexer { return std::regex_match(std::string(1, c), pattern); } - Napi::Object makeToken(Napi::Env &env, const std::string &input, TokenKind kind, size_t start, size_t length) { + Napi::Object makeToken(Napi::Env &env, const std::string &input, TokenKind kind, size_t start, size_t length = 1) { Napi::Object token = Napi::Object::New(env); token.Set(Napi::String::New(env, "start"), Napi::Number::New(env, start)); @@ -71,8 +72,71 @@ namespace Lexer { char c = input[index]; switch (c) { + // Literals + case '#': + case '$': { + const size_t start = index++; + + while (index < length) { + const char c = input[index]; + if (Lexer::isWordChar(c)) index++; + else break; + } + + tokens.push_back(makeToken(env, input, TokenKind::VARIABLE, start, index-- - start)); + break; + } break; + + case '\'': { + const size_t start = index++; + + while (index < length) { + const char c = input[index]; + if (c == '\'') break; + index++; + } + + tokens.push_back(makeToken(env, input, TokenKind::STRING, start, index - start + 1)); + } break; + + case ',': + tokens.push_back(makeToken(env, input, TokenKind::COMMA, index)); + break; + + // Single operators + case '+': + case '-': + case '*': + case '/': + case '%': + tokens.push_back(makeToken(env, input, TokenKind::OPERATOR, index)); + break; + + case '(': + tokens.push_back(makeToken(env, input, TokenKind::OPEN_PARENTHESIS, index)); + break; + + case ')': + tokens.push_back(makeToken(env, input, TokenKind::CLOSE_PARENTHESIS, index)); + break; + + // Double operators + case '&': + case '|': + case '=': + if (input[index + 1] == input[index]) tokens.push_back(makeToken(env, input, TokenKind::OPERATOR, index++, 2)); + else tokens.push_back(makeToken(env, input, TokenKind::OPERATOR, index)); + break; + + case '!': + case '>': + case '<': + if (input[index + 1] == '=') tokens.push_back(makeToken(env, input, TokenKind::OPERATOR, index++, 2)); + else tokens.push_back(makeToken(env, input, TokenKind::OPERATOR, index)); + break; + default: { - size_t start = index; + const size_t start = index; if (Lexer::isNumberChar(c)) { while (Lexer::isNumberChar(input[index + 1])) index++; @@ -85,9 +149,17 @@ namespace Lexer { Lexer::makeToken(env, input, TokenKind::WORD, start, index - start + 1) ); } else if (!Lexer::isBlankChar(c)) { + std::string message = std::format( + "\x1b[31m{}>>>{}<<<{}\nInvalid character\x1b[0m", + input.substr(0, start), + input.substr(start, index - start + 1), + input.substr(index + 1) + ); + + Napi::TypeError::New(env, Napi::String::New(env, message)).ThrowAsJavaScriptException(); return Napi::Array::New(env, 0); } - } + } break; }; index++; @@ -96,9 +168,8 @@ namespace Lexer { size_t tokenLength = tokens.size(); Napi::Array result = Napi::Array::New(env, tokenLength); - for (size_t i = 0; i < tokenLength; i++) { + for (size_t i = 0; i < tokenLength; i++) result.Set(i, tokens[i]); - } return result; } diff --git a/test/app.ts b/test/app.ts index 6356e7c..39d8a4b 100644 --- a/test/app.ts +++ b/test/app.ts @@ -1,3 +1,17 @@ -import { AsaJSCompiler } from ".." +import { Lexer, NativeLexer } from ".." -console.log(AsaJSCompiler.Lexer("SAYGEX69")) +const input = Array.from( + { length: 50 }, + () => + "#test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <= #test $test 'abcde' test 123 + - * / % , ( ) & && | || = == ! != > >= < <=", +).join(" ") + +const nn = performance.now() +NativeLexer(input) +const nt = performance.now() + +const n = performance.now() +Lexer(input) +const t = performance.now() + +console.log(`Native: ${nt - nn}ms, JS: ${t - n}ms`)