mirror of
https://github.com/tcsenpai/scripting-language-factory.git
synced 2025-06-03 18:00:15 +00:00
example extension and extension creation support
This commit is contained in:
parent
503c1236cd
commit
c9bf5d51aa
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
__pycache__/
|
||||
*.pyc
|
||||
*.pyo
|
||||
*.pyd
|
||||
*.pyw
|
||||
*.pyz
|
||||
*.pywz
|
23
README.md
23
README.md
@ -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
3
rizzlang_ext/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# RizzLang VS Code Extension
|
||||
|
||||
This extension provides syntax highlighting for RizzLang files.
|
74
rizzlang_ext/language-configuration.json
Normal file
74
rizzlang_ext/language-configuration.json
Normal 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
33
rizzlang_ext/package.json
Normal 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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
128
rizzlang_ext/syntaxes/rizzlang.tmLanguage.json
Normal file
128
rizzlang_ext/syntaxes/rizzlang.tmLanguage.json
Normal 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"
|
||||
}
|
@ -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."""
|
||||
|
275
vscode_extension_generator.py
Normal file
275
vscode_extension_generator.py
Normal 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")
|
Loading…
x
Reference in New Issue
Block a user