port lexer to cpp
This commit is contained in:
parent
cacc641378
commit
b3b21f3101
13 changed files with 276 additions and 32 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,3 +1,4 @@
|
||||||
|
build
|
||||||
dist
|
dist
|
||||||
cache
|
cache
|
||||||
node_modules
|
node_modules
|
||||||
|
|
|
||||||
16
binding.gyp
Normal file
16
binding.gyp
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"target_name": "asajs-compiler",
|
||||||
|
"sources": [
|
||||||
|
"src/native/main.cc",
|
||||||
|
],
|
||||||
|
|
||||||
|
"dependencies": [
|
||||||
|
"<!(node -p \"require('node-addon-api').targets\"):node_addon_api",
|
||||||
|
],
|
||||||
|
|
||||||
|
"cflags_cc": [ "-std=c++17" ],
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
54
package-lock.json
generated
54
package-lock.json
generated
|
|
@ -9,29 +9,72 @@
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"jsonc-parser": "^3.3.1"
|
"@types/bindings": "^1.5.5",
|
||||||
|
"bindings": "^1.5.0",
|
||||||
|
"jsonc-parser": "^3.3.1",
|
||||||
|
"node-addon-api": "^8.5.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^25.0.3",
|
"@types/node": "^25.0.3",
|
||||||
|
"node-api-headers": "^1.7.0",
|
||||||
"typescript": "^5.9.3"
|
"typescript": "^5.9.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/bindings": {
|
||||||
|
"version": "1.5.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/bindings/-/bindings-1.5.5.tgz",
|
||||||
|
"integrity": "sha512-y59PRZBTo2/HuN94qRjyJD+465vGoXMsqz9MMJDbtJL9oT5/B+tAL6c3k10epIinC2/BBkLqKzKC6keukl8wdQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "25.0.3",
|
"version": "25.0.9",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.9.tgz",
|
||||||
"integrity": "sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA==",
|
"integrity": "sha512-/rpCXHlCWeqClNBwUhDcusJxXYDjZTyE8v5oTO7WbL8eij2nKhUeU89/6xgjU7N4/Vh3He0BtyhJdQbDyhiXAw==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"undici-types": "~7.16.0"
|
"undici-types": "~7.16.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/bindings": {
|
||||||
|
"version": "1.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
|
||||||
|
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"file-uri-to-path": "1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/file-uri-to-path": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/jsonc-parser": {
|
"node_modules/jsonc-parser": {
|
||||||
"version": "3.3.1",
|
"version": "3.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz",
|
||||||
"integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==",
|
"integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/node-addon-api": {
|
||||||
|
"version": "8.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.5.0.tgz",
|
||||||
|
"integrity": "sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": "^18 || ^20 || >= 21"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/node-api-headers": {
|
||||||
|
"version": "1.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-api-headers/-/node-api-headers-1.7.0.tgz",
|
||||||
|
"integrity": "sha512-uJMGdkhVwu9+I3UsVvI3KW6ICAy/yDfsu5Br9rSnTtY3WpoaComXvKloiV5wtx0Md2rn0B9n29Ys2WMNwWxj9A==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/typescript": {
|
"node_modules/typescript": {
|
||||||
"version": "5.9.3",
|
"version": "5.9.3",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
|
||||||
|
|
@ -50,7 +93,6 @@
|
||||||
"version": "7.16.0",
|
"version": "7.16.0",
|
||||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
|
||||||
"integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
|
"integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
10
package.json
10
package.json
|
|
@ -22,9 +22,9 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
"dev": "tsc --watch",
|
"dev": "tsc --watch",
|
||||||
"test": "bun test/app.ts",
|
|
||||||
"test:watch": "bun --watch test/app.ts",
|
|
||||||
"prefetch": "bun scripts/prefetch",
|
"prefetch": "bun scripts/prefetch",
|
||||||
|
"native:build": "node-gyp build",
|
||||||
|
"native:rebuild": "node-gyp rebuild",
|
||||||
"vanilla:defs": "bun scripts/vanilladefs",
|
"vanilla:defs": "bun scripts/vanilladefs",
|
||||||
"gen:enums": "bun scripts/enum",
|
"gen:enums": "bun scripts/enum",
|
||||||
"gen:items": "bun scripts/items",
|
"gen:items": "bun scripts/items",
|
||||||
|
|
@ -32,9 +32,13 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^25.0.3",
|
"@types/node": "^25.0.3",
|
||||||
|
"node-api-headers": "^1.7.0",
|
||||||
"typescript": "^5.9.3"
|
"typescript": "^5.9.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"jsonc-parser": "^3.3.1"
|
"@types/bindings": "^1.5.5",
|
||||||
|
"bindings": "^1.5.0",
|
||||||
|
"jsonc-parser": "^3.3.1",
|
||||||
|
"node-addon-api": "^8.5.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
14
src/compilers/Bindings.ts
Normal file
14
src/compilers/Bindings.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
import bindings from "bindings"
|
||||||
|
import { Token } from "./bindings/types.js"
|
||||||
|
|
||||||
|
export const {
|
||||||
|
Lexer,
|
||||||
|
isBlankChar,
|
||||||
|
isWordChar,
|
||||||
|
isNumberChar,
|
||||||
|
}: {
|
||||||
|
Lexer: (input: string) => Token[]
|
||||||
|
isBlankChar: (char: string) => boolean
|
||||||
|
isWordChar: (char: string) => boolean
|
||||||
|
isNumberChar: (char: string) => boolean
|
||||||
|
} = bindings("asajs-compiler")
|
||||||
|
|
@ -9,3 +9,7 @@ export function isWordChar(char: string) {
|
||||||
export function isNumberChar(char: string) {
|
export function isNumberChar(char: string) {
|
||||||
return /\d/.test(char)
|
return /\d/.test(char)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isCompileBinding(input: string) {
|
||||||
|
return input.startsWith("[") && input.endsWith("]")
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
|
import { Expression, GenBinding, Token, TokenKind, TSToken, TSTokenKind } from "./types.js"
|
||||||
import { BindingType } from "../../types/enums/BindingType.js"
|
import { BindingType } from "../../types/enums/BindingType.js"
|
||||||
import { BindingItem } from "../../types/properties/value.js"
|
import { BindingItem } from "../../types/properties/value.js"
|
||||||
import { FuntionMap } from "./Funtion.js"
|
import { FuntionMap } from "./Funtion.js"
|
||||||
import { Lexer } from "./Lexer.js"
|
import { Lexer } from "./Lexer.js"
|
||||||
import { Expression, GenBinding, Token, TokenKind, TSToken, TSTokenKind } from "./types.js"
|
|
||||||
|
|
||||||
export class Parser {
|
export class Parser {
|
||||||
position: number = 0
|
position: number = 0
|
||||||
|
|
@ -240,14 +240,14 @@ export class Parser {
|
||||||
this.eat()
|
this.eat()
|
||||||
|
|
||||||
return this.funtionCall(<string>callerToken.value, ...args)
|
return this.funtionCall(<string>callerToken.value, ...args)
|
||||||
} else if (left.kind === TokenKind.OPERATOR) {
|
} else if (left?.kind === TokenKind.OPERATOR) {
|
||||||
this.warn(
|
this.warn(
|
||||||
`Implicit string literal '${callerToken.value}'. Use quoted string ('${callerToken.value}') for clarity!`,
|
`Implicit string literal '${callerToken.value}'. Use quoted string ('${callerToken.value}') for clarity!`,
|
||||||
callerToken,
|
callerToken,
|
||||||
)
|
)
|
||||||
return <string>callerToken.value
|
return <string>callerToken.value
|
||||||
} else {
|
} else {
|
||||||
this.expect(TokenKind.OPERATOR, "Unexpected token!")
|
this.expect(TokenKind.WORD, "Unexpected token!")
|
||||||
return <string>callerToken.value
|
return <string>callerToken.value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
import { IntelliSense, Namespace, Element, VanillaType } from "../types/vanilla/intellisense.js"
|
|
||||||
import { paths } from "../types/vanilla/paths.js"
|
|
||||||
import { UI } from "./UI.js"
|
|
||||||
|
|
||||||
export function Modify<T extends Namespace, K extends Element<T>>(namespace: T, name: K) {
|
|
||||||
// @ts-ignore -- TS cannot prove this, but runtime guarantees it
|
|
||||||
return new UI<VanillaType<T, K>>(undefined, name, namespace, paths[namespace][name])
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +1,11 @@
|
||||||
|
import { isCompileBinding } from "../compilers/bindings/Checker.js"
|
||||||
|
import { Parser } from "../compilers/bindings/Parser.js"
|
||||||
import { FormatProperties } from "../compilers/FormatProperties.js"
|
import { FormatProperties } from "../compilers/FormatProperties.js"
|
||||||
import { Memory } from "../compilers/Memory.js"
|
import { BindingType } from "../types/enums/BindingType.js"
|
||||||
import { Renderer } from "../types/enums/Renderer.js"
|
import { Renderer } from "../types/enums/Renderer.js"
|
||||||
import { Type } from "../types/enums/Type.js"
|
import { Type } from "../types/enums/Type.js"
|
||||||
import { Properties } from "../types/properties/components.js"
|
import { Properties } from "../types/properties/components.js"
|
||||||
|
import { BindingItem } from "../types/properties/value.js"
|
||||||
import { Class } from "./Class.js"
|
import { Class } from "./Class.js"
|
||||||
import { RandomString } from "./Utils.js"
|
import { RandomString } from "./Utils.js"
|
||||||
|
|
||||||
|
|
@ -18,6 +21,7 @@ export class UI<T extends Type, K extends Renderer | null = null> extends Class
|
||||||
extendable: boolean
|
extendable: boolean
|
||||||
|
|
||||||
controls = new Map<string, [UI<Type, Renderer | null>, Properties<Type, Renderer | null>]>()
|
controls = new Map<string, [UI<Type, Renderer | null>, Properties<Type, Renderer | null>]>()
|
||||||
|
bindings: BindingItem[] = []
|
||||||
properties: Properties<T, K> = <any>{}
|
properties: Properties<T, K> = <any>{}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
|
@ -47,6 +51,23 @@ export class UI<T extends Type, K extends Renderer | null = null> extends Class
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addBindings(...bindings: BindingItem[]) {
|
||||||
|
for (const binding of bindings) {
|
||||||
|
if (binding.source_property_name) {
|
||||||
|
if (isCompileBinding(binding.source_property_name)) {
|
||||||
|
const { gen, out } = new Parser(binding.source_property_name.slice(1, -1)).out()
|
||||||
|
if (gen) this.bindings.push(...gen)
|
||||||
|
binding.source_property_name = out
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.binding_type = BindingType.VIEW
|
||||||
|
|
||||||
|
if (!binding.target_property_name) throw new Error("Binding must have a target property name")
|
||||||
|
}
|
||||||
|
this.bindings.push(binding)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
addChild<T extends Type, K extends Renderer | null>(child: UI<T, K>, properties?: Properties<T, K>, name?: string) {
|
addChild<T extends Type, K extends Renderer | null>(child: UI<T, K>, properties?: Properties<T, K>, name?: string) {
|
||||||
if (this === <any>child) {
|
if (this === <any>child) {
|
||||||
throw new Error("Cannot add a child to itself")
|
throw new Error("Cannot add a child to itself")
|
||||||
|
|
@ -69,6 +90,10 @@ export class UI<T extends Type, K extends Renderer | null = null> extends Class
|
||||||
obj.type = this.type
|
obj.type = this.type
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.bindings.length) {
|
||||||
|
obj.bindings = this.bindings
|
||||||
|
}
|
||||||
|
|
||||||
if (this.controls.size) {
|
if (this.controls.size) {
|
||||||
obj.controls = []
|
obj.controls = []
|
||||||
this.controls.forEach((e, key) => obj.controls.push({ [key + e[0]]: e[1] }))
|
this.controls.forEach((e, key) => obj.controls.push({ [key + e[0]]: e[1] }))
|
||||||
|
|
@ -78,7 +103,13 @@ export class UI<T extends Type, K extends Renderer | null = null> extends Class
|
||||||
}
|
}
|
||||||
|
|
||||||
[util.inspect.custom]($: any, opts: any) {
|
[util.inspect.custom]($: any, opts: any) {
|
||||||
const obj: any = FormatProperties(this.properties)
|
const obj: any = {
|
||||||
|
...FormatProperties(this.properties),
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.bindings.length) {
|
||||||
|
obj.bindings = this.bindings
|
||||||
|
}
|
||||||
|
|
||||||
if (this.controls.size) {
|
if (this.controls.size) {
|
||||||
obj.controls = []
|
obj.controls = []
|
||||||
|
|
@ -90,3 +121,10 @@ export class UI<T extends Type, K extends Renderer | null = null> extends Class
|
||||||
}\x1b[0m> \x1b[92m"${this}\x1b[92m"\x1b[0m ${util.inspect(obj, opts)}\n`
|
}\x1b[0m> \x1b[92m"${this}\x1b[92m"\x1b[0m ${util.inspect(obj, opts)}\n`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class ModifyUI<T extends Type> extends UI<T, null> {
|
||||||
|
constructor(namespace: string, name: string, path: string) {
|
||||||
|
if (!path) throw new Error("ModifyUI cannot have a path")
|
||||||
|
super(undefined, name, namespace, path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { Type } from "../types/enums/Type.js"
|
import { Type } from "../types/enums/Type.js"
|
||||||
import { Array3, Binding } from "../types/properties/value.js"
|
import { Array3, Binding } from "../types/properties/value.js"
|
||||||
import { UI } from "./UI.js"
|
import { ModifyUI, UI } from "./UI.js"
|
||||||
|
|
||||||
import { Renderer } from "../types/enums/Renderer.js"
|
import { Renderer } from "../types/enums/Renderer.js"
|
||||||
import {
|
import {
|
||||||
|
|
@ -27,6 +27,8 @@ import {
|
||||||
SliderBox,
|
SliderBox,
|
||||||
} from "../types/properties/components.js"
|
} from "../types/properties/components.js"
|
||||||
import { ItemAuxID } from "../types/enums/Items.js"
|
import { ItemAuxID } from "../types/enums/Items.js"
|
||||||
|
import { Element, Namespace, VanillaType } from "../types/vanilla/intellisense.js"
|
||||||
|
import { paths } from "../types/vanilla/paths.js"
|
||||||
|
|
||||||
const CHARS = "0123456789abcdefghijklmnopqrstuvwxyz"
|
const CHARS = "0123456789abcdefghijklmnopqrstuvwxyz"
|
||||||
|
|
||||||
|
|
@ -86,6 +88,11 @@ export function GetItemByAuxID(auxID: number) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Quick Elements
|
// Quick Elements
|
||||||
|
export function Modify<T extends Namespace, K extends Element<T>>(namespace: T, name: K) {
|
||||||
|
// @ts-ignore -- TS cannot prove this, but runtime guarantees it
|
||||||
|
return new ModifyUI<VanillaType<T, K>>(name, namespace, paths[namespace][name])
|
||||||
|
}
|
||||||
|
|
||||||
export function Panel(properties?: Panel, name?: string, namespace?: string) {
|
export function Panel(properties?: Panel, name?: string, namespace?: string) {
|
||||||
return new UI(Type.PANEL, name, namespace).setProperties(properties || {})
|
return new UI(Type.PANEL, name, namespace).setProperties(properties || {})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,11 @@ import "./compilers/RunEnd.js"
|
||||||
|
|
||||||
export * from "./components/Animation.js"
|
export * from "./components/Animation.js"
|
||||||
export * from "./components/UI.js"
|
export * from "./components/UI.js"
|
||||||
export * from "./components/Modify.js"
|
|
||||||
export * from "./components/Utils.js"
|
export * from "./components/Utils.js"
|
||||||
|
|
||||||
export * from "./types/enums/index.js"
|
export * from "./types/enums/index.js"
|
||||||
export * as Properties from "./types/properties/index.js"
|
export * as Properties from "./types/properties/index.js"
|
||||||
|
|
||||||
|
export * from "./compilers/Bindings.js"
|
||||||
|
|
||||||
export { ItemAuxID } from "./types/enums/Items.js"
|
export { ItemAuxID } from "./types/enums/Items.js"
|
||||||
|
|
|
||||||
131
src/native/main.cc
Normal file
131
src/native/main.cc
Normal file
|
|
@ -0,0 +1,131 @@
|
||||||
|
#include <napi.h>
|
||||||
|
#include <regex>
|
||||||
|
|
||||||
|
enum TokenKind {
|
||||||
|
VARIABLE,
|
||||||
|
NUMBER,
|
||||||
|
STRING,
|
||||||
|
TEMPLATE_STRING,
|
||||||
|
WORD,
|
||||||
|
|
||||||
|
OPEN_PARENTHESIS,
|
||||||
|
CLOSE_PARENTHESIS,
|
||||||
|
|
||||||
|
OPERATOR,
|
||||||
|
COMMA,
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace Lexer {
|
||||||
|
bool isBlankChar(char c) {
|
||||||
|
std::regex pattern(R"(\s)");
|
||||||
|
return std::regex_match(std::string(1, c), pattern);
|
||||||
|
};
|
||||||
|
|
||||||
|
bool isWordChar(char c) {
|
||||||
|
std::regex pattern(R"(\w)");
|
||||||
|
return std::regex_match(std::string(1, c), pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isNumberChar(char c) {
|
||||||
|
std::regex pattern(R"(\d)");
|
||||||
|
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 token = Napi::Object::New(env);
|
||||||
|
|
||||||
|
token.Set(Napi::String::New(env, "start"), Napi::Number::New(env, start));
|
||||||
|
token.Set(Napi::String::New(env, "length"), Napi::Number::New(env, length));
|
||||||
|
token.Set(Napi::String::New(env, "kind"), Napi::Number::New(env, kind));
|
||||||
|
token.Set(Napi::String::New(env, "value"), Napi::String::New(env, input.substr(start, length)));
|
||||||
|
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
Napi::Array Lexer(const Napi::CallbackInfo &info) {
|
||||||
|
Napi::Env env = info.Env();
|
||||||
|
|
||||||
|
Napi::Function consoleLog = env.Global().Get("console").As<Napi::Object>().Get("log").As<Napi::Function>();
|
||||||
|
|
||||||
|
if (info.Length() != 1) {
|
||||||
|
Napi::TypeError::New(env, "One string argument required").ThrowAsJavaScriptException();
|
||||||
|
return Napi::Array::New(env, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!info[0].IsString()) {
|
||||||
|
Napi::TypeError::New(env, "Input must be a string").ThrowAsJavaScriptException();
|
||||||
|
return Napi::Array::New(env, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string input = info[0].As<Napi::String>().Utf8Value();
|
||||||
|
const size_t length = input.size();
|
||||||
|
|
||||||
|
if (length == 0) {
|
||||||
|
return Napi::Array::New(env, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Napi::Object> tokens;
|
||||||
|
|
||||||
|
size_t index = 0;
|
||||||
|
while (index < length) {
|
||||||
|
char c = input[index];
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
default: {
|
||||||
|
size_t start = index;
|
||||||
|
|
||||||
|
if (Lexer::isNumberChar(c)) {
|
||||||
|
while (Lexer::isNumberChar(input[index + 1])) index++;
|
||||||
|
tokens.push_back(
|
||||||
|
Lexer::makeToken(env, input, TokenKind::NUMBER, start, index - start + 1)
|
||||||
|
);
|
||||||
|
} else if (Lexer::isWordChar(c)) {
|
||||||
|
while (Lexer::isWordChar(input[index + 1])) index++;
|
||||||
|
tokens.push_back(
|
||||||
|
Lexer::makeToken(env, input, TokenKind::WORD, start, index - start + 1)
|
||||||
|
);
|
||||||
|
} else if (!Lexer::isBlankChar(c)) {
|
||||||
|
return Napi::Array::New(env, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t tokenLength = tokens.size();
|
||||||
|
Napi::Array result = Napi::Array::New(env, tokenLength);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < tokenLength; i++) {
|
||||||
|
result.Set(i, tokens[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Napi::Object Init(Napi::Env env, Napi::Object exports) {
|
||||||
|
exports.Set(
|
||||||
|
Napi::String::New(env, "Lexer"),
|
||||||
|
Napi::Function::New(env, Lexer::Lexer)
|
||||||
|
);
|
||||||
|
|
||||||
|
exports.Set(
|
||||||
|
Napi::String::New(env, "isBlankChar"),
|
||||||
|
Napi::Function::New(env, Lexer::isBlankChar)
|
||||||
|
);
|
||||||
|
|
||||||
|
exports.Set(
|
||||||
|
Napi::String::New(env, "isWordChar"),
|
||||||
|
Napi::Function::New(env, Lexer::isWordChar)
|
||||||
|
);
|
||||||
|
|
||||||
|
exports.Set(
|
||||||
|
Napi::String::New(env, "isNumberChar"),
|
||||||
|
Napi::Function::New(env, Lexer::isNumberChar)
|
||||||
|
);
|
||||||
|
|
||||||
|
return exports;
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_API_MODULE(NODE_GYP_MODULE_NAME, Init)
|
||||||
10
test/app.ts
10
test/app.ts
|
|
@ -1,9 +1,3 @@
|
||||||
import { Anchor, Modify, Properties } from ".."
|
import { AsaJSCompiler } from ".."
|
||||||
|
|
||||||
const vanilla = Modify("authentication_modals", "ad_modal_dialog").setProperties({
|
console.log(AsaJSCompiler.Lexer("SAYGEX69"))
|
||||||
ignored: true,
|
|
||||||
anchor: Anchor.CENTER,
|
|
||||||
offset: [10, 10],
|
|
||||||
})
|
|
||||||
|
|
||||||
console.log(vanilla)
|
|
||||||
|
|
|
||||||
Reference in a new issue