example extension and extension creation support

This commit is contained in:
tcsenpai 2025-03-02 22:26:57 +01:00
parent 503c1236cd
commit c9bf5d51aa
8 changed files with 551 additions and 4 deletions

7
.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
__pycache__/
*.pyc
*.pyo
*.pyd
*.pyw
*.pyz
*.pywz

View File

@ -1,5 +1,3 @@
# Scripting Language Factory
A powerful tool for creating, running, and managing custom programming languages based on any slang, meme terminology, or domain-specific vocabulary you prefer.
@ -90,6 +88,27 @@ python transpiler.py compile script.ski -o output_dir -k -c my_mapping.json
Compile your custom language to Python bytecode (.pyc files). The `-k` flag keeps the intermediate Python file.
### Generate VS Code Extension
```
python transpiler.py -c my_mapping.json vscode -o my-language-extension
```
Generate a VS Code extension for syntax highlighting based on your custom language mapping. This creates all the necessary files for a complete VS Code extension, including:
- Syntax highlighting based on your language keywords
- Language configuration for comments, brackets, and indentation
- Package manifest with language metadata
To install the extension:
1. Copy the generated folder to your VS Code extensions directory:
- Windows: `%USERPROFILE%\.vscode\extensions`
- macOS/Linux: `~/.vscode/extensions`
2. Restart VS Code
3. Open a file with your language's extension to see the highlighting in action
NOTE: Advanced auto-completion is not yet supported, but basic auto-completion is available.
## Customizing Your Language
Edit the mapping file to define your own language syntax. The file has a structured format:

3
rizzlang_ext/README.md Normal file
View File

@ -0,0 +1,3 @@
# RizzLang VS Code Extension
This extension provides syntax highlighting for RizzLang files.

View File

@ -0,0 +1,74 @@
{
"comments": {
"lineComment": "#"
},
"brackets": [
[
"{",
"}"
],
[
"[",
"]"
],
[
"(",
")"
]
],
"autoClosingPairs": [
{
"open": "{",
"close": "}"
},
{
"open": "[",
"close": "]"
},
{
"open": "(",
"close": ")"
},
{
"open": "\"",
"close": "\"",
"notIn": [
"string"
]
},
{
"open": "'",
"close": "'",
"notIn": [
"string",
"comment"
]
}
],
"surroundingPairs": [
[
"{",
"}"
],
[
"[",
"]"
],
[
"(",
")"
],
[
"\"",
"\""
],
[
"'",
"'"
]
],
"indentationRules": {
"increaseIndentPattern": "^.*:\\s*$",
"decreaseIndentPattern": "^\\s*$"
}
}

33
rizzlang_ext/package.json Normal file
View File

@ -0,0 +1,33 @@
{
"name": "rizzlang",
"displayName": "RizzLang",
"description": "A meme-based programming language",
"version": "0.1.0",
"engines": {
"vscode": "^1.60.0"
},
"categories": [
"Programming Languages"
],
"contributes": {
"languages": [
{
"id": "rizzlang",
"aliases": [
"RizzLang"
],
"extensions": [
"ski"
],
"configuration": "./language-configuration.json"
}
],
"grammars": [
{
"language": "rizzlang",
"scopeName": "source.rizzlang",
"path": "./syntaxes/rizzlang.tmLanguage.json"
}
]
}
}

View File

@ -0,0 +1,128 @@
{
"$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
"name": "RizzLang",
"patterns": [
{
"include": "#keywords"
},
{
"include": "#strings"
},
{
"include": "#comments"
},
{
"include": "#numbers"
},
{
"include": "#function-call"
},
{
"include": "#decorator"
}
],
"repository": {
"keywords": {
"patterns": [
{
"name": "keyword.control.rizzlang",
"match": "\\b(rizz|fr|yeet|sus|vibe_check|boomer|zoomer)\\b"
},
{
"name": "keyword.declaration.rizzlang",
"match": "\\b(skibidi|toilet|ohio|based|stan|simp|slide into (\\w+))\\b"
},
{
"name": "keyword.operator.rizzlang",
"match": "\\b(bet)\\b"
},
{
"name": "constant.language.rizzlang",
"match": "\\b(no_cap|cap|mid|down_bad|up_good)\\b"
},
{
"name": "support.function.rizzlang",
"match": "\\b(bussin|slay|sheesh|goated|npc|glizzy|drip|rent_free|chad|touch_grass|ong|main_character|villain_arc|gaslighting|gatekeeping|girlboss|sigma|alpha|beta|skill_issue|cope|seethe|mald|ratio (\\w+))\\b"
},
{
"name": "storage.modifier.rizzlang",
"match": "\\b(lowkey|highkey|on god)\\b"
},
{
"name": "keyword.control.exception.rizzlang",
"match": "\\b(finna|bruh|karen|cringe|plot_twist|L_plus_ratio|no shot|spill the tea)\\b"
}
]
},
"strings": {
"patterns": [
{
"name": "string.quoted.double.rizzlang",
"begin": "\"",
"end": "\"",
"patterns": [
{
"name": "constant.character.escape.rizzlang",
"match": "\\\\."
}
]
},
{
"name": "string.quoted.single.rizzlang",
"begin": "'",
"end": "'",
"patterns": [
{
"name": "constant.character.escape.rizzlang",
"match": "\\\\."
}
]
},
{
"name": "string.quoted.triple.rizzlang",
"begin": "\"\"\"",
"end": "\"\"\"",
"patterns": [
{
"name": "constant.character.escape.rizzlang",
"match": "\\\\."
}
]
}
]
},
"comments": {
"patterns": [
{
"name": "comment.line.number-sign.rizzlang",
"match": "#.*$"
}
]
},
"numbers": {
"patterns": [
{
"name": "constant.numeric.rizzlang",
"match": "\\b[0-9]+(\\.[0-9]+)?\\b"
}
]
},
"function-call": {
"patterns": [
{
"name": "entity.name.function.rizzlang",
"match": "\\b([a-zA-Z_][a-zA-Z0-9_]*)\\s*\\("
}
]
},
"decorator": {
"patterns": [
{
"name": "entity.name.function.decorator.rizzlang",
"match": "^\\s*(lowkey|highkey|on god)\\s*$"
}
]
}
},
"scopeName": "source.rizzlang"
}

View File

@ -9,6 +9,7 @@ import readline # For better REPL experience
import py_compile
import shutil
from pathlib import Path
from vscode_extension_generator import generate_vscode_extension
class Transpiler:
def __init__(self, mapping_file):
@ -303,6 +304,9 @@ class Transpiler:
def main():
parser = argparse.ArgumentParser(description='Transpile, execute, or compile custom language files')
# Common arguments that apply to all commands
parser.add_argument('-c', '--config', help='JSON mapping file (defaults to mapping.json in current directory)')
# Create subparsers for different commands
subparsers = parser.add_subparsers(dest='command', help='Command to run')
@ -331,8 +335,9 @@ def main():
create_parser = subparsers.add_parser('create-mapping', help='Create a new mapping file with default values')
create_parser.add_argument('output_file', help='Output file for the mapping')
# Common arguments
parser.add_argument('-c', '--config', help='JSON mapping file (defaults to mapping.json in current directory)')
# VS Code extension command
vscode_parser = subparsers.add_parser('vscode', help='Generate VS Code extension for syntax highlighting')
vscode_parser.add_argument('-o', '--output-dir', help='Output directory for the extension')
args = parser.parse_args()
@ -376,6 +381,9 @@ def main():
elif args.command == 'repl':
transpiler.start_repl()
elif args.command == 'vscode':
generate_vscode_extension(args.config, args.output_dir)
def create_default_mapping(filename):
"""Create a default mapping file with meme/slang terms."""

View File

@ -0,0 +1,275 @@
import json
import os
import shutil
import argparse
import sys
from pathlib import Path
def generate_vscode_extension(mapping_file, output_dir=None):
"""Generate a VS Code extension for syntax highlighting based on a mapping file."""
# Load the mapping file
with open(mapping_file, 'r') as f:
mapping_data = json.load(f)
# Extract language info
if "language_info" in mapping_data:
language_info = mapping_data["language_info"]
language_name = language_info.get("name", "CustomLanguage")
language_extension = language_info.get("file_extension", ".custom")
language_description = language_info.get("description", "A custom programming language")
else:
language_name = "CustomLanguage"
language_extension = ".custom"
language_description = "A custom programming language"
# Remove leading dot from extension if present
if language_extension.startswith('.'):
language_extension = language_extension[1:]
# Create language ID (lowercase, no spaces)
language_id = language_name.lower().replace(' ', '-')
# Determine output directory
if output_dir is None:
output_dir = f"vscode-{language_id}"
# Create extension directory structure
os.makedirs(output_dir, exist_ok=True)
os.makedirs(os.path.join(output_dir, "syntaxes"), exist_ok=True)
# Generate package.json
package_json = {
"name": f"{language_id}",
"displayName": language_name,
"description": language_description,
"version": "0.1.0",
"engines": {
"vscode": "^1.60.0"
},
"categories": [
"Programming Languages"
],
"contributes": {
"languages": [
{
"id": language_id,
"aliases": [language_name],
"extensions": [language_extension],
"configuration": f"./language-configuration.json"
}
],
"grammars": [
{
"language": language_id,
"scopeName": f"source.{language_id}",
"path": f"./syntaxes/{language_id}.tmLanguage.json"
}
]
}
}
# Generate language-configuration.json
language_config = {
"comments": {
"lineComment": "#",
},
"brackets": [
["{", "}"],
["[", "]"],
["(", ")"]
],
"autoClosingPairs": [
{ "open": "{", "close": "}" },
{ "open": "[", "close": "]" },
{ "open": "(", "close": ")" },
{ "open": "\"", "close": "\"", "notIn": ["string"] },
{ "open": "'", "close": "'", "notIn": ["string", "comment"] }
],
"surroundingPairs": [
["{", "}"],
["[", "]"],
["(", ")"],
["\"", "\""],
["'", "'"]
],
"indentationRules": {
"increaseIndentPattern": "^.*:\\s*$",
"decreaseIndentPattern": "^\\s*$"
}
}
# Extract keywords for syntax highlighting
keywords = mapping_data.get("keywords", {})
special_patterns = mapping_data.get("special_patterns", {})
# Group keywords by their Python equivalents
keyword_groups = {
"control": [], # if, else, for, while, etc.
"declaration": [], # def, class, import, etc.
"operator": [], # and, or, not, in, etc.
"constant": [], # True, False, None
"builtin": [], # print, len, etc.
"storage": [], # global, nonlocal
"exception": [] # try, except, finally, raise
}
# Map Python keywords to their groups
python_keyword_groups = {
"if": "control", "else": "control", "elif": "control",
"for": "control", "while": "control", "break": "control",
"continue": "control", "return": "control", "in": "operator",
"def": "declaration", "class": "declaration", "import": "declaration",
"from": "declaration", "as": "declaration", "with": "declaration",
"True": "constant", "False": "constant", "None": "constant",
"print": "builtin", "len": "builtin", "range": "builtin",
"global": "storage", "nonlocal": "storage",
"try": "exception", "except": "exception", "finally": "exception",
"raise": "exception", "assert": "exception", "Exception": "exception"
}
# Categorize custom keywords
for custom_keyword, python_equiv in keywords.items():
group = python_keyword_groups.get(python_equiv, "builtin")
keyword_groups[group].append(custom_keyword)
# Add special pattern keywords
for pattern, python_equiv in special_patterns.items():
# Extract the base keyword from the pattern (e.g., "no\\s+shot" -> "no shot")
base_keyword = pattern.replace("\\s+", " ").replace("\\(\\w+\\)", "").strip()
python_base = python_equiv.split()[0] if " " in python_equiv else python_equiv
group = python_keyword_groups.get(python_base, "builtin")
if base_keyword not in keyword_groups[group]:
keyword_groups[group].append(base_keyword)
# Generate TextMate grammar
grammar = {
"$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
"name": language_name,
"patterns": [
{ "include": "#keywords" },
{ "include": "#strings" },
{ "include": "#comments" },
{ "include": "#numbers" },
{ "include": "#function-call" },
{ "include": "#decorator" }
],
"repository": {
"keywords": {
"patterns": [
{
"name": "keyword.control." + language_id,
"match": "\\b(" + "|".join(keyword_groups["control"]) + ")\\b"
},
{
"name": "keyword.declaration." + language_id,
"match": "\\b(" + "|".join(keyword_groups["declaration"]) + ")\\b"
},
{
"name": "keyword.operator." + language_id,
"match": "\\b(" + "|".join(keyword_groups["operator"]) + ")\\b"
},
{
"name": "constant.language." + language_id,
"match": "\\b(" + "|".join(keyword_groups["constant"]) + ")\\b"
},
{
"name": "support.function." + language_id,
"match": "\\b(" + "|".join(keyword_groups["builtin"]) + ")\\b"
},
{
"name": "storage.modifier." + language_id,
"match": "\\b(" + "|".join(keyword_groups["storage"]) + ")\\b"
},
{
"name": "keyword.control.exception." + language_id,
"match": "\\b(" + "|".join(keyword_groups["exception"]) + ")\\b"
}
]
},
"strings": {
"patterns": [
{
"name": "string.quoted.double." + language_id,
"begin": "\"",
"end": "\"",
"patterns": [
{
"name": "constant.character.escape." + language_id,
"match": "\\\\."
}
]
},
{
"name": "string.quoted.single." + language_id,
"begin": "'",
"end": "'",
"patterns": [
{
"name": "constant.character.escape." + language_id,
"match": "\\\\."
}
]
},
{
"name": "string.quoted.triple." + language_id,
"begin": "\"\"\"",
"end": "\"\"\"",
"patterns": [
{
"name": "constant.character.escape." + language_id,
"match": "\\\\."
}
]
}
]
},
"comments": {
"patterns": [
{
"name": "comment.line.number-sign." + language_id,
"match": "#.*$"
}
]
},
"numbers": {
"patterns": [
{
"name": "constant.numeric." + language_id,
"match": "\\b[0-9]+(\\.[0-9]+)?\\b"
}
]
},
"function-call": {
"patterns": [
{
"name": "entity.name.function." + language_id,
"match": "\\b([a-zA-Z_][a-zA-Z0-9_]*)\\s*\\("
}
]
},
"decorator": {
"patterns": [
{
"name": "entity.name.function.decorator." + language_id,
"match": "^\\s*(" + "|".join(keyword_groups["storage"]) + ")\\s*$"
}
]
}
},
"scopeName": "source." + language_id
}
# Write files
with open(os.path.join(output_dir, "package.json"), 'w') as f:
json.dump(package_json, f, indent=4)
with open(os.path.join(output_dir, "language-configuration.json"), 'w') as f:
json.dump(language_config, f, indent=4)
with open(os.path.join(output_dir, "syntaxes", f"{language_id}.tmLanguage.json"), 'w') as f:
json.dump(grammar, f, indent=4)
# Create README.md
with open(os.path.join(output_dir, "README.md"), 'w') as f:
f.write(f"# {language_name} VS Code Extension\n\n")
f.write(f"This extension provides syntax highlighting for {language_name} files.\n")