Building the SWX Scripting Language on Node.js: Architecture and Implementation
SWX is a scripting language built on Node.js that handles the full code processing pipeline: from lexical analysis to execution. The process involves a lexer, parser, and interpreter.
Source code → [Lexer] → Tokens → [Parser] → AST → [Interpreter] → Result
The lexer breaks code into tokens, supporting custom operators like >~ for comparison and =? for equality. The parser builds the AST, and the interpreter traverses the tree to execute nodes.
Lexer: Tokenizing the Code
The lexer (lexer.js) converts strings into a sequence of tokens. Example:
swx x = 42
Becomes: KEYWORD(swx) IDENT(x) ASSIGN(=) NUMBER(42).
Handling multi-character operators requires precedence: >= is recognized as a whole. Contextual modes resolve conflicts with identifiers in the HTML generator.
Parser and AST
The parser (parser.js) uses recursive descent to build the AST, respecting operator precedence. Example condition:
swx x = 10
sw x >~ 5 {
wx "greater than five"
}
AST:
{
"type": "IfStatement",
"condition": {
"type": "BinaryExpression",
"operator": ">=",
"left": { "type": "Identifier", "name": "x" },
"right": { "type": "NumberLiteral", "value": 5 }
},
"body": [
{
"type": "PrintStatement",
"value": { "type": "StringLiteral", "value": "greater than five" }
}
]
}
Precedence ensures correctness: 2 + 3 4 evaluates as 2 + (3 4).
Interpreter: Executing the AST
The tree-walking interpreter (interpreter.js) implements handlers for nodes:
IfStatement: Evaluate condition and select branch.ForLoop: Iterate by counter.FunctionDeclaration: Store in symbol table.BinaryExpression: Handle arithmetic and logic.
Syntax and Constructs
SWX features a unique syntax:
Variables and Output
swx name = "SlywerX"
swx age = 20
wx "Hi, {name}! You're {age} years old."
Conditions and Loops
swfor if, withdras else-if/else.xs 5 { ... }— loop N times.xw item in arr { ... }— foreach.xl condition { ... }— while with 1 million iteration limit.
Functions and Pattern Matching
sx add(a, b = 0) => {
ws a + b
}
match status {
case 200 => { wx "OK" }
case 404 => { wx "Not Found" }
default => { wx "Unknown" }
}
Pipe operator |> chains functions: "hello" |> upper.
Cryptography
The #x module integrates Node.js crypto:
swx hash = #x.sha256("hello")
wx hash // 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
swx encrypted = #x.aes_enc("secret data", "mykey")
swx decrypted = #x.aes_dec(encrypted, "mykey")
swx keys = #x.rsa_keys(2048)
swx signature = #x.rsa_sign("data", keys.private)
wx #x.rsa_verify("data", signature, keys.public) // true
HTML Rendering
The sx> DSL generates HTML with CSS:
sx> "output/index.html" {
@style {
body >> bg(#030810) color(#fff) font(Courier New, monospace)
h1 >> color(#00e5ff) size(24px) bold uppercase
.btn >> bg(#00e5ff) color(#000) pad(10px 20px) pointer
}
@body {
div.card >> {
h1 >> "Hello from SWX"
button.btn >> (onclick: "alert('works!')") { "Click Me" }
}
}
}
Supports nesting and attributes.
Implementation Challenges
- Parser Precedence: Recursive descent with Pratt parsing.
- Lexer Conflicts: Context for
*~and CSS. - While Loops: Iteration limit to prevent hangs.
- Standard Library: Testing on unstable interpreter.
Key Takeaways
- Full stack: lexer, parser, interpreter on Node.js.
- Custom syntax with pipes, pattern matching, and crypto module.
- HTML DSL for markup generation.
- Safeguards against infinite loops and lexer conflicts.
- Version 7.0.0 with RSA and AES.
— Editorial Team
No comments yet.