binding compiler

This commit is contained in:
Asaki Yuki 2026-01-07 10:46:18 +07:00
parent bb9b300d6f
commit 4d5f81f7e5
8 changed files with 188 additions and 15 deletions

View file

@ -17,7 +17,7 @@ export const Memory = {
return namespace return namespace
}, },
gen_ui_file_content(namespace: string, elements: Map<string, UI<Type, Renderer | null>>) { gen_ui_file_contents(namespace: string, elements: Map<string, UI<Type, Renderer | null>>) {
return JSON.stringify( return JSON.stringify(
{ {
namespace, namespace,

View file

@ -2,6 +2,10 @@ declare global {
interface Map<K, V> { interface Map<K, V> {
toJSON(): Record<string, V> toJSON(): Record<string, V>
} }
interface Array<T> {
lastItem(): T
}
} }
Map.prototype.toJSON = function () { Map.prototype.toJSON = function () {
@ -9,3 +13,7 @@ Map.prototype.toJSON = function () {
this.forEach((value, key) => (obj[key] = value)) this.forEach((value, key) => (obj[key] = value))
return obj return obj
} }
Array.prototype.lastItem = function () {
return this[this.length - 1]
}

View file

@ -2,6 +2,6 @@ import { Memory } from "./Memory.js"
process.on("beforeExit", () => { process.on("beforeExit", () => {
Memory.cache.forEach(({ elements, namespace }) => { Memory.cache.forEach(({ elements, namespace }) => {
console.log(Memory.gen_ui_file_content(namespace, elements)) const contents = Memory.gen_ui_file_contents(namespace, elements)
}) })
}) })

View file

@ -0,0 +1,149 @@
import { Token, TokenKind } from "./types.js"
export const BindingTranspiler = {
isBlankChar(char: string) {
return /\s/.test(char)
},
isWordChar(char: string) {
return char && /\w/.test(char)
},
isNumberChar(char: string) {
return /\d/.test(char)
},
token(input: string, kind: TokenKind, start: number, length: number = 1): Token {
return {
value: input.slice(start, start + length),
kind,
start,
length,
}
},
lexer(input: string) {
const tokens: Token[] = []
let index = 0
do {
const token = input[index]
if (BindingTranspiler.isBlankChar(token)) continue
switch (token) {
// Literals
case "#":
case "$": {
const start = index++
do {
const token = input[index]
if (BindingTranspiler.isWordChar(token)) continue
else break
} while (++index < input.length)
tokens.push(BindingTranspiler.token(input, TokenKind.VARIABLE, start, index - start))
break
}
case "'": {
const start = index++
do {
const token = input[index]
if (token === "'") break
} while (++index < input.length)
tokens.push(BindingTranspiler.token(input, TokenKind.STRING, start, index - start + 1))
break
}
case "`": {
const start = index++,
struct: boolean[] = []
do {
const token = input[index]
let lastStruct = struct.lastItem()
if (token === "`") {
if (struct.length) {
if (lastStruct === false) struct.pop()
else struct.push(false)
} else break
}
if (token === "$") {
if (input[index + 1] === "{" && !lastStruct) {
struct.push(true)
index++
}
}
if (token === "}" && lastStruct === true) struct.pop()
} while (++index < input.length)
tokens.push(BindingTranspiler.token(input, TokenKind.TEMPLATE_STRING, start, index - start + 1))
break
}
case ",":
tokens.push(BindingTranspiler.token(input, TokenKind.COMMA, index))
break
// Single operators
case "+":
case "-":
case "*":
case "/":
tokens.push(BindingTranspiler.token(input, TokenKind.OPERATOR, index))
break
case "(":
tokens.push(BindingTranspiler.token(input, TokenKind.OPEN_PARENTHESIS, index))
break
case ")":
tokens.push(BindingTranspiler.token(input, TokenKind.CLOSE_PARENTHESIS, index))
break
// Double operators
case "&":
case "|":
case "=":
if (input[index + 1] === input[index])
tokens.push(BindingTranspiler.token(input, TokenKind.OPERATOR, ++index, 2))
else tokens.push(BindingTranspiler.token(input, TokenKind.OPERATOR, index))
break
case "!":
case ">":
case "<":
if (input[index + 1] === "=")
tokens.push(BindingTranspiler.token(input, TokenKind.OPERATOR, ++index, 2))
else tokens.push(BindingTranspiler.token(input, TokenKind.OPERATOR, index))
break
default: {
let start = index
if (BindingTranspiler.isNumberChar(token)) {
while (BindingTranspiler.isNumberChar(input[index + 1])) index++
tokens.push(BindingTranspiler.token(input, TokenKind.NUMBER, start, index - start + 1))
} else if (BindingTranspiler.isWordChar(token)) {
while (BindingTranspiler.isWordChar(input[index + 1])) index++
tokens.push(BindingTranspiler.token(input, TokenKind.WORD, start, index - start + 1))
}
}
}
} while (++index < input.length)
return tokens
},
parser(input: string, tokens: Token[]) {},
}

View file

@ -0,0 +1 @@
export * from "./Bindings.js"

View file

@ -0,0 +1,20 @@
export enum TokenKind {
VARIABLE,
NUMBER,
STRING,
TEMPLATE_STRING,
WORD,
OPEN_PARENTHESIS,
CLOSE_PARENTHESIS,
OPERATOR,
COMMA,
}
export interface Token {
kind: TokenKind
value: string
start: number
length: number
}

View file

@ -1,9 +1,10 @@
import "./compilers/PreCompile.js" import "./compilers/PreCompile.js"
import "./compilers/RunEnd.js" import "./compilers/RunEnd.js"
export * from "./components/Animation.js"
export * from "./components/UI.js" export * from "./components/UI.js"
export { Animation } from "./components/Animation.js"
export * from "./components/Utils.js" export * from "./components/Utils.js"
export * from "./types/enums/index.js" export * from "./types/enums/index.js"
export * from "./compilers/bindings/index.js"
export * as Properties from "./types/properties/index.js" export * as Properties from "./types/properties/index.js"

View file

@ -1,13 +1,7 @@
import { Binding, Color, Label, Panel } from ".." import { BindingTranspiler } from ".."
Panel({ const input = "abcdef + 123456"
"#test": 123,
[Binding.IS_CREATIVE_LAYOUT]: true, const lexer = BindingTranspiler.lexer(input)
[Binding.INVENTORY_SELECTED_ITEM_COLOR]: Color(0x00ff00),
}).addChild( console.log(lexer)
Label({
text: "Hello, World!",
shadow: true,
color: Color("#3b0202"),
})
)