mirror of
https://github.com/tcsenpai/scripting-language-factory.git
synced 2025-06-03 18:00:15 +00:00
advanced features
This commit is contained in:
parent
849698bcee
commit
503c1236cd
13
LICENSE.md
Normal file
13
LICENSE.md
Normal file
@ -0,0 +1,13 @@
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
Version 2, December 2004
|
||||
|
||||
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified
|
||||
copies of this license document, and changing it is allowed as long
|
||||
as the name is changed.
|
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. You just DO WHAT THE FUCK YOU WANT TO.
|
225
README.md
Normal file
225
README.md
Normal file
@ -0,0 +1,225 @@
|
||||
|
||||
|
||||
# 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.
|
||||
|
||||
## Overview
|
||||
|
||||
This project allows you to define your own programming language syntax by mapping custom keywords to Python equivalents. It provides a complete environment for working with your custom language, including:
|
||||
|
||||
- Transpilation between your language and Python
|
||||
- Direct execution of your language scripts
|
||||
- Interactive REPL for development
|
||||
- Compilation to Python bytecode
|
||||
- Extensive customization options
|
||||
|
||||
## Installation
|
||||
|
||||
1. Clone this repository:
|
||||
```
|
||||
git clone https://github.com/yourusername/scripting-language-factory.git
|
||||
cd scripting-language-factory
|
||||
```
|
||||
|
||||
2. No additional dependencies required beyond Python 3.6+
|
||||
|
||||
## Quick Start
|
||||
|
||||
1. Create a default mapping file:
|
||||
```
|
||||
python transpiler.py create-mapping my_mapping.json
|
||||
```
|
||||
|
||||
2. Write a script in your custom language (e.g., `hello.ski`):
|
||||
```
|
||||
ohio math
|
||||
|
||||
skibidi say_hello(name):
|
||||
bussin(f"What's good, {name}!")
|
||||
rizz f"Hello function executed for {name}"
|
||||
|
||||
yeet main_character == "__main__":
|
||||
say_hello("fam")
|
||||
```
|
||||
|
||||
3. Run your script:
|
||||
```
|
||||
python transpiler.py run hello.ski -c my_mapping.json
|
||||
```
|
||||
|
||||
## Command Reference
|
||||
|
||||
### Create a Mapping File
|
||||
|
||||
```
|
||||
python transpiler.py create-mapping filename.json
|
||||
```
|
||||
|
||||
This creates a JSON file with default keyword mappings that you can customize.
|
||||
|
||||
### Transpile a File
|
||||
|
||||
```
|
||||
python transpiler.py transpile input.ski -o output.py -c my_mapping.json
|
||||
```
|
||||
|
||||
Convert your custom language to Python. Use the `-r` flag to convert from Python back to your custom language.
|
||||
|
||||
### Run a Script
|
||||
|
||||
```
|
||||
python transpiler.py run script.ski -c my_mapping.json [args...]
|
||||
```
|
||||
|
||||
Execute a script written in your custom language. Add `--debug` to see the transpiled Python code.
|
||||
|
||||
### Start the REPL
|
||||
|
||||
```
|
||||
python transpiler.py repl -c my_mapping.json
|
||||
```
|
||||
|
||||
Launch an interactive Read-Eval-Print Loop for your custom language.
|
||||
|
||||
### Compile to Bytecode
|
||||
|
||||
```
|
||||
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.
|
||||
|
||||
## Customizing Your Language
|
||||
|
||||
Edit the mapping file to define your own language syntax. The file has a structured format:
|
||||
|
||||
```json
|
||||
{
|
||||
"keywords": {
|
||||
"skibidi": "def",
|
||||
"toilet": "class",
|
||||
"bussin": "print",
|
||||
"rizz": "return",
|
||||
...
|
||||
},
|
||||
"special_patterns": {
|
||||
"no\\s+shot": "assert",
|
||||
"on\\s+god": "global",
|
||||
"spill\\s+the\\s+tea": "raise Exception",
|
||||
"ratio\\s+(\\w+)": "del \\1"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "YourLanguage",
|
||||
"version": "1.0.0",
|
||||
"description": "Your custom language description",
|
||||
"file_extension": ".yourlang"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- **keywords**: Simple word-to-word mappings
|
||||
- **special_patterns**: Regular expressions for more complex syntax patterns
|
||||
- **language_info**: Metadata about your language
|
||||
|
||||
You can add as many mappings as you want, including slang, meme terms, or domain-specific vocabulary.
|
||||
|
||||
## Special Syntax Features
|
||||
|
||||
The transpiler supports special multi-word phrases and patterns:
|
||||
|
||||
- `no shot <condition>` → `assert <condition>`
|
||||
- `on god <variable>` → `global <variable>`
|
||||
- `spill the tea` → `raise Exception`
|
||||
- `ratio <variable>` → `del <variable>`
|
||||
|
||||
## Example
|
||||
|
||||
Here's a sample program in our default "meme language":
|
||||
|
||||
```
|
||||
ohio math
|
||||
ohio random simp rng
|
||||
|
||||
on god counter
|
||||
counter = 0
|
||||
|
||||
toilet RizzCalculator(npc):
|
||||
skibidi villain_arc(goated, name="Rizz Master"):
|
||||
goated.name = name
|
||||
goated.rizz_level = 0
|
||||
|
||||
girlboss
|
||||
skibidi rizz_level(goated):
|
||||
rizz goated.rizz_level
|
||||
|
||||
sigma
|
||||
skibidi get_random_rizz():
|
||||
rizz rng.randint(1, 100)
|
||||
|
||||
skibidi add_rizz(goated, amount):
|
||||
finna:
|
||||
goated.rizz_level += amount
|
||||
rizz goated.rizz_level
|
||||
bruh L_plus_ratio simp e:
|
||||
bussin(f"L + ratio: {e}")
|
||||
rizz mid
|
||||
|
||||
yeet main_character == "__main__":
|
||||
calculator = RizzCalculator("Rizzy McRizzface")
|
||||
|
||||
fr i bet range(5):
|
||||
random_rizz = RizzCalculator.get_random_rizz()
|
||||
calculator.add_rizz(random_rizz)
|
||||
counter += 1
|
||||
|
||||
bussin(f"Final rizz level: {calculator.rizz_level}")
|
||||
```
|
||||
|
||||
## Advanced Features
|
||||
|
||||
- **Indentation Handling**: The transpiler automatically fixes indentation in the generated Python code.
|
||||
- **Decorator Support**: Properly handles Python decorators like `@property` and `@staticmethod`.
|
||||
- **Error Reporting**: Provides helpful debugging information when errors occur.
|
||||
- **Command History**: The REPL maintains command history between sessions.
|
||||
|
||||
## Creating Your Own Language
|
||||
|
||||
1. Start with the default mapping file
|
||||
2. Replace keywords with your preferred terms
|
||||
3. Add new mappings for additional Python features
|
||||
4. Create special syntax patterns for complex transformations
|
||||
5. Write scripts in your new language
|
||||
6. Share your language with others by distributing your mapping file
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If you encounter errors:
|
||||
|
||||
1. Use the `--debug` flag to see the transpiled Python code:
|
||||
```
|
||||
python transpiler.py run script.ski --debug -c my_mapping.json
|
||||
```
|
||||
|
||||
2. Transpile to Python and inspect the code:
|
||||
```
|
||||
python transpiler.py transpile script.ski -o debug.py -c my_mapping.json
|
||||
```
|
||||
|
||||
3. Check for syntax errors in your custom language script
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome! Feel free to:
|
||||
- Add support for more Python features
|
||||
- Improve error handling and debugging
|
||||
- Create pre-defined language mappings
|
||||
- Enhance the REPL experience
|
||||
|
||||
## License
|
||||
|
||||
[LICENSE.md](LICENSE.md)
|
||||
|
||||
## Acknowledgments
|
||||
|
||||
This project was inspired by the creativity of internet slang and meme culture, and the flexibility of the Python programming language.
|
26
example.ski
26
example.ski
@ -1,26 +0,0 @@
|
||||
ohio math
|
||||
|
||||
skibidi add_numbers(a, b):
|
||||
rizz a + b
|
||||
|
||||
toilet Calculator:
|
||||
skibidi __init__(self):
|
||||
self.result = 0
|
||||
|
||||
skibidi calculate(self, x, y):
|
||||
finna:
|
||||
self.result = add_numbers(x, y)
|
||||
bussin(f"Result: {self.result}")
|
||||
rizz self.result
|
||||
bruh Exception as e:
|
||||
bussin(f"Error: {e}")
|
||||
rizz cap
|
||||
|
||||
yeet __name__ == "__main__":
|
||||
calc = Calculator()
|
||||
fr i in range(1, 5):
|
||||
bussin(f"Adding {i} and {i*2}")
|
||||
calc.calculate(i, i*2)
|
||||
|
||||
based open("output.txt", "w") as f:
|
||||
f.write("Calculations complete!")
|
17
mapping.json
17
mapping.json
@ -1,17 +0,0 @@
|
||||
{
|
||||
"skibidi": "def",
|
||||
"toilet": "class",
|
||||
"ohio": "import",
|
||||
"rizz": "return",
|
||||
"bussin": "print",
|
||||
"fr": "for",
|
||||
"no_cap": "True",
|
||||
"cap": "False",
|
||||
"yeet": "if",
|
||||
"sus": "else",
|
||||
"vibe_check": "while",
|
||||
"finna": "try",
|
||||
"bruh": "except",
|
||||
"slay": "lambda",
|
||||
"based": "with"
|
||||
}
|
78
rizzlang/example.ski
Normal file
78
rizzlang/example.ski
Normal file
@ -0,0 +1,78 @@
|
||||
ohio math
|
||||
ohio random simp rng
|
||||
|
||||
on god counter
|
||||
counter = 0 # Initialize the counter
|
||||
|
||||
skibidi calculate_rizz(x, y):
|
||||
vibe_check x < 10:
|
||||
x += 1
|
||||
bussin(f"Increasing rizz to {x}")
|
||||
|
||||
yeet y > 20:
|
||||
karen ValueError("Too much rizz")
|
||||
sus:
|
||||
rizz x * y
|
||||
|
||||
toilet RizzCalculator(npc):
|
||||
skibidi villain_arc(goated, name="Rizz Master"):
|
||||
goated.name = name
|
||||
goated.rizz_level = 0
|
||||
|
||||
girlboss
|
||||
skibidi rizz_level(goated):
|
||||
rizz goated.rizz_level
|
||||
|
||||
sigma
|
||||
skibidi get_random_rizz():
|
||||
rizz rng.randint(1, 100)
|
||||
|
||||
skibidi add_rizz(goated, amount):
|
||||
finna:
|
||||
goated.rizz_level += amount
|
||||
yeet goated.rizz_level > 100:
|
||||
bussin("MAXIMUM RIZZ ACHIEVED!")
|
||||
goated.rizz_level = 100
|
||||
rizz goated.rizz_level
|
||||
bruh L_plus_ratio simp e:
|
||||
bussin(f"L + ratio: {e}")
|
||||
rizz mid
|
||||
plot_twist:
|
||||
bussin("Rizz calculation complete")
|
||||
|
||||
yeet main_character == "__main__":
|
||||
no shot 2 + 2 == 4, "Math is working"
|
||||
|
||||
calculator = RizzCalculator("Rizzy McRizzface")
|
||||
|
||||
drip stats = {
|
||||
"name": calculator.name,
|
||||
"initial_rizz": calculator.rizz_level
|
||||
}
|
||||
|
||||
glizzy rizz_levels = []
|
||||
|
||||
fr i bet range(5):
|
||||
random_rizz = RizzCalculator.get_random_rizz()
|
||||
bussin(f"Got random rizz: {random_rizz}")
|
||||
calculator.add_rizz(random_rizz)
|
||||
rizz_levels.append(calculator.rizz_level)
|
||||
counter += 1 # Increment counter
|
||||
|
||||
bussin(f"Final rizz levels: {rizz_levels}")
|
||||
bussin(f"Counter value: {counter}")
|
||||
|
||||
yeet calculator.rizz_level > 50:
|
||||
bussin("High rizz achieved!")
|
||||
sus:
|
||||
bussin("Need more rizz...")
|
||||
|
||||
# Demonstrate special syntax
|
||||
yeet counter > 3: # Changed from 10 to 3 so it will be true
|
||||
bussin("Deleting counter...")
|
||||
ratio counter # Delete counter
|
||||
finna:
|
||||
bussin(counter) # This will fail since counter is deleted
|
||||
bruh NameError:
|
||||
bussin("Counter successfully deleted!")
|
||||
spill the tea # Raise exception
|
68
rizzlang/mapping.json
Normal file
68
rizzlang/mapping.json
Normal file
@ -0,0 +1,68 @@
|
||||
{
|
||||
"keywords": {
|
||||
"skibidi": "def",
|
||||
"toilet": "class",
|
||||
"ohio": "import",
|
||||
"rizz": "return",
|
||||
"bussin": "print",
|
||||
"fr": "for",
|
||||
"no_cap": "True",
|
||||
"cap": "False",
|
||||
"yeet": "if",
|
||||
"sus": "else",
|
||||
"vibe_check": "while",
|
||||
"finna": "try",
|
||||
"bruh": "except",
|
||||
"slay": "lambda",
|
||||
"based": "with",
|
||||
"sheesh": "pass",
|
||||
"mid": "None",
|
||||
"goated": "self",
|
||||
"npc": "object",
|
||||
"glizzy": "list",
|
||||
"drip": "dict",
|
||||
"bet": "in",
|
||||
"rent_free": "yield",
|
||||
"chad": "super",
|
||||
"karen": "raise",
|
||||
"boomer": "break",
|
||||
"zoomer": "continue",
|
||||
"stan": "from",
|
||||
"simp": "as",
|
||||
"cringe": "assert",
|
||||
"touch_grass": "exit",
|
||||
"down_bad": "False",
|
||||
"up_good": "True",
|
||||
"ong": "not",
|
||||
"lowkey": "nonlocal",
|
||||
"highkey": "global",
|
||||
"main_character": "__main__",
|
||||
"villain_arc": "__init__",
|
||||
"plot_twist": "finally",
|
||||
"gaslighting": "isinstance",
|
||||
"gatekeeping": "issubclass",
|
||||
"girlboss": "property",
|
||||
"sigma": "staticmethod",
|
||||
"alpha": "classmethod",
|
||||
"beta": "abstractmethod",
|
||||
"L_plus_ratio": "Exception",
|
||||
"skill_issue": "ValueError",
|
||||
"cope": "TypeError",
|
||||
"seethe": "KeyError",
|
||||
"mald": "IndexError"
|
||||
},
|
||||
"special_patterns": {
|
||||
"no\\s+shot": "assert",
|
||||
"on\\s+god": "global",
|
||||
"slide\\s+into\\s+(\\w+)": "import \\1",
|
||||
"spill\\s+the\\s+tea": "raise Exception",
|
||||
"ratio\\s+(\\w+)": "del \\1"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "RizzLang",
|
||||
"version": "1.0.0",
|
||||
"description": "A meme-based programming language",
|
||||
"file_extension": ".ski",
|
||||
"author": "Scripting Language Factory"
|
||||
}
|
||||
}
|
410
transpiler.py
410
transpiler.py
@ -2,12 +2,34 @@ import json
|
||||
import re
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
import subprocess
|
||||
import readline # For better REPL experience
|
||||
import py_compile
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
|
||||
class Transpiler:
|
||||
def __init__(self, mapping_file):
|
||||
"""Initialize the transpiler with a JSON mapping file."""
|
||||
with open(mapping_file, 'r') as f:
|
||||
self.mapping = json.load(f)
|
||||
mapping_data = json.load(f)
|
||||
|
||||
# Handle structured mapping format
|
||||
if isinstance(mapping_data, dict) and "keywords" in mapping_data:
|
||||
self.mapping = mapping_data.get("keywords", {})
|
||||
else:
|
||||
# Convert legacy format to structured format
|
||||
self.mapping = mapping_data
|
||||
print("Warning: Using legacy mapping format. Consider updating to structured format.", file=sys.stderr)
|
||||
|
||||
special_patterns_raw = mapping_data.get("special_patterns", {})
|
||||
|
||||
# Convert string patterns to actual regex patterns
|
||||
self.special_patterns = {}
|
||||
for pattern_str, replacement in special_patterns_raw.items():
|
||||
self.special_patterns[pattern_str] = replacement
|
||||
|
||||
# Create reverse mapping for Python to custom language
|
||||
self.reverse_mapping = {v: k for k, v in self.mapping.items()}
|
||||
@ -19,19 +41,83 @@ class Transpiler:
|
||||
# Create regex patterns for word boundaries
|
||||
self.patterns = {k: re.compile(r'\b' + re.escape(k) + r'\b') for k in self.sorted_keywords}
|
||||
self.reverse_patterns = {k: re.compile(r'\b' + re.escape(k) + r'\b') for k in self.sorted_reverse_keywords}
|
||||
|
||||
# Compile special patterns
|
||||
self.compiled_special_patterns = {re.compile(k): v for k, v in self.special_patterns.items()}
|
||||
|
||||
def to_python(self, source_code):
|
||||
"""Convert custom language to Python."""
|
||||
result = source_code
|
||||
|
||||
# Apply special patterns first
|
||||
for pattern, replacement in self.compiled_special_patterns.items():
|
||||
result = pattern.sub(replacement, result)
|
||||
|
||||
# Then apply regular word replacements
|
||||
for keyword in self.sorted_keywords:
|
||||
result = self.patterns[keyword].sub(self.mapping[keyword], result)
|
||||
|
||||
# Fix common syntax issues
|
||||
|
||||
# Fix decorators - first convert standalone decorators to proper Python syntax
|
||||
result = re.sub(r'@property\s*$', r'@property', result)
|
||||
result = re.sub(r'@staticmethod\s*$', r'@staticmethod', result)
|
||||
result = re.sub(r'@classmethod\s*$', r'@classmethod', result)
|
||||
|
||||
# Fix main_character check
|
||||
result = result.replace('if __main__ ==', 'if __name__ ==')
|
||||
|
||||
# Fix list and dict literals
|
||||
result = result.replace('list ', '')
|
||||
result = result.replace('dict ', '')
|
||||
|
||||
# Fix L_plus_ratio exception
|
||||
result = result.replace('L_plus_del', 'Exception')
|
||||
|
||||
# Fix indentation
|
||||
lines = result.split('\n')
|
||||
properly_indented_lines = []
|
||||
for line in lines:
|
||||
# Count leading spaces
|
||||
leading_spaces = len(line) - len(line.lstrip())
|
||||
# Calculate proper indentation level (4 spaces per level)
|
||||
indent_level = leading_spaces // 4
|
||||
# Create properly indented line
|
||||
properly_indented_lines.append(' ' * indent_level + line.lstrip())
|
||||
|
||||
result = '\n'.join(properly_indented_lines)
|
||||
|
||||
return result
|
||||
|
||||
def from_python(self, python_code):
|
||||
"""Convert Python to custom language."""
|
||||
result = python_code
|
||||
|
||||
# Apply regular word replacements first
|
||||
for keyword in self.sorted_reverse_keywords:
|
||||
result = self.reverse_patterns[keyword].sub(self.reverse_mapping[keyword], result)
|
||||
|
||||
# Then apply special patterns in reverse
|
||||
for pattern, replacement in self.compiled_special_patterns.items():
|
||||
# Create reverse pattern
|
||||
reverse_pattern = re.compile(r'\b' + re.escape(replacement) + r'\b')
|
||||
# Extract capture groups if any
|
||||
match = re.search(r'\\(\d+)', pattern.pattern)
|
||||
if match:
|
||||
# If there are capture groups, we need to handle them specially
|
||||
capture_group = int(match.group(1))
|
||||
# Find all matches of the reverse pattern
|
||||
matches = reverse_pattern.finditer(result)
|
||||
for m in matches:
|
||||
# Extract the captured value
|
||||
captured = m.group(capture_group) if capture_group <= len(m.groups()) else ""
|
||||
# Replace with the original pattern format
|
||||
original_format = pattern.pattern.replace(f'\\{capture_group}', captured)
|
||||
result = result.replace(m.group(0), original_format)
|
||||
else:
|
||||
# Simple replacement
|
||||
result = reverse_pattern.sub(pattern.pattern, result)
|
||||
|
||||
return result
|
||||
|
||||
def transpile_file(self, input_file, output_file=None, reverse=False):
|
||||
@ -50,24 +136,320 @@ class Transpiler:
|
||||
return f"Transpiled to {output_file}"
|
||||
else:
|
||||
return result
|
||||
|
||||
def execute_code(self, input_file, args=None, debug=False):
|
||||
"""Execute a custom language file by transpiling to Python and running it."""
|
||||
# Create a temporary file for the transpiled Python code
|
||||
with tempfile.NamedTemporaryFile(suffix='.py', delete=False) as temp_file:
|
||||
temp_filename = temp_file.name
|
||||
|
||||
try:
|
||||
# Transpile the input file to the temporary Python file
|
||||
self.transpile_file(input_file, temp_filename)
|
||||
|
||||
# If debug mode is enabled, print the transpiled Python code
|
||||
if debug:
|
||||
with open(temp_filename, 'r') as f:
|
||||
print("=== Transpiled Python Code ===")
|
||||
print(f.read())
|
||||
print("=============================")
|
||||
|
||||
# Prepare command to run the Python file
|
||||
cmd = [sys.executable, temp_filename]
|
||||
if args:
|
||||
cmd.extend(args)
|
||||
|
||||
# Execute the Python file
|
||||
result = subprocess.run(cmd, capture_output=True, text=True)
|
||||
|
||||
# Print output and errors
|
||||
if result.stdout:
|
||||
print(result.stdout, end='')
|
||||
if result.stderr:
|
||||
print(result.stderr, end='', file=sys.stderr)
|
||||
|
||||
# If there's a syntax error, try to map it back to the original file
|
||||
if "SyntaxError" in result.stderr:
|
||||
print("\n=== Debugging Information ===")
|
||||
print(f"The error occurred in the transpiled Python code. To debug:")
|
||||
print(f"1. Run with debug flag: python transpiler.py run {input_file} --debug")
|
||||
print(f"2. Or transpile to inspect: python transpiler.py transpile {input_file} -o debug.py")
|
||||
print("==============================")
|
||||
|
||||
return result.returncode
|
||||
finally:
|
||||
# Clean up the temporary file unless in debug mode
|
||||
if os.path.exists(temp_filename) and not debug:
|
||||
os.remove(temp_filename)
|
||||
|
||||
def compile_code(self, input_file, output_dir=None, keep_py=False):
|
||||
"""Compile a custom language file to Python bytecode."""
|
||||
# Get the base name of the input file
|
||||
base_name = os.path.basename(input_file)
|
||||
name_without_ext = os.path.splitext(base_name)[0]
|
||||
|
||||
# Determine output directory
|
||||
if output_dir is None:
|
||||
output_dir = os.path.dirname(input_file) or '.'
|
||||
|
||||
# Create output directory if it doesn't exist
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
|
||||
# Create a temporary Python file
|
||||
py_file = os.path.join(output_dir, f"{name_without_ext}.py")
|
||||
|
||||
try:
|
||||
# Transpile the input file to Python
|
||||
self.transpile_file(input_file, py_file)
|
||||
|
||||
# Compile the Python file to bytecode
|
||||
py_compile.compile(py_file, cfile=os.path.join(output_dir, f"{name_without_ext}.pyc"))
|
||||
|
||||
print(f"Compiled to {os.path.join(output_dir, name_without_ext + '.pyc')}")
|
||||
|
||||
# Optionally remove the intermediate Python file
|
||||
if not keep_py and os.path.exists(py_file):
|
||||
os.remove(py_file)
|
||||
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"Compilation error: {e}", file=sys.stderr)
|
||||
# Clean up in case of error
|
||||
if os.path.exists(py_file) and not keep_py:
|
||||
os.remove(py_file)
|
||||
return False
|
||||
|
||||
def start_repl(self):
|
||||
"""Start a REPL (Read-Eval-Print Loop) for the custom language."""
|
||||
print(f"Custom Language REPL (Python {sys.version.split()[0]})")
|
||||
print("Type 'exit()' or 'quit()' to exit")
|
||||
|
||||
# Set up readline history
|
||||
histfile = os.path.join(os.path.expanduser("~"), ".custom_lang_history")
|
||||
try:
|
||||
readline.read_history_file(histfile)
|
||||
readline.set_history_length(1000)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
# Create a temporary module for the REPL
|
||||
temp_module = {}
|
||||
|
||||
# Keep track of indentation level
|
||||
indent_level = 0
|
||||
buffer = []
|
||||
|
||||
while True:
|
||||
try:
|
||||
# Determine prompt based on indentation
|
||||
if indent_level > 0:
|
||||
prompt = "... " + " " * indent_level
|
||||
else:
|
||||
prompt = ">>> "
|
||||
|
||||
# Get input from user
|
||||
line = input(prompt)
|
||||
|
||||
# Check for exit commands
|
||||
if line.strip() in ('exit()', 'quit()') and indent_level == 0:
|
||||
break
|
||||
|
||||
# Add line to buffer
|
||||
buffer.append(line)
|
||||
|
||||
# Update indentation level
|
||||
if line.endswith(':'):
|
||||
indent_level += 1
|
||||
elif line.strip() == '' and indent_level > 0:
|
||||
indent_level -= 1
|
||||
|
||||
# If we're back to zero indentation, execute the buffer
|
||||
if indent_level == 0 and buffer:
|
||||
# Join the buffer into a single string
|
||||
code_to_execute = '\n'.join(buffer)
|
||||
buffer = []
|
||||
|
||||
# Transpile the custom code to Python
|
||||
python_code = self.to_python(code_to_execute)
|
||||
|
||||
try:
|
||||
# Execute the Python code
|
||||
result = eval(python_code, temp_module)
|
||||
if result is not None:
|
||||
print(repr(result))
|
||||
except SyntaxError:
|
||||
try:
|
||||
# If it's not an expression, execute it as a statement
|
||||
exec(python_code, temp_module)
|
||||
except Exception as e:
|
||||
print(f"Error: {e}", file=sys.stderr)
|
||||
except Exception as e:
|
||||
print(f"Error: {e}", file=sys.stderr)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("\nKeyboardInterrupt")
|
||||
buffer = []
|
||||
indent_level = 0
|
||||
except EOFError:
|
||||
print("\nExiting...")
|
||||
break
|
||||
|
||||
# Save readline history
|
||||
try:
|
||||
readline.write_history_file(histfile)
|
||||
except:
|
||||
pass
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Transpile between custom language and Python')
|
||||
parser.add_argument('input_file', help='Input file to transpile')
|
||||
parser.add_argument('-o', '--output', help='Output file (if not specified, prints to stdout)')
|
||||
parser.add_argument('-m', '--mapping', required=True, help='JSON mapping file')
|
||||
parser.add_argument('-r', '--reverse', action='store_true', help='Transpile from Python to custom language')
|
||||
parser = argparse.ArgumentParser(description='Transpile, execute, or compile custom language files')
|
||||
|
||||
# Create subparsers for different commands
|
||||
subparsers = parser.add_subparsers(dest='command', help='Command to run')
|
||||
|
||||
# Transpile command
|
||||
transpile_parser = subparsers.add_parser('transpile', help='Transpile between custom language and Python')
|
||||
transpile_parser.add_argument('input_file', help='Input file to transpile')
|
||||
transpile_parser.add_argument('-o', '--output', help='Output file (if not specified, prints to stdout)')
|
||||
transpile_parser.add_argument('-r', '--reverse', action='store_true', help='Transpile from Python to custom language')
|
||||
|
||||
# Execute command
|
||||
execute_parser = subparsers.add_parser('run', help='Execute a custom language file')
|
||||
execute_parser.add_argument('input_file', help='Input file to execute')
|
||||
execute_parser.add_argument('args', nargs='*', help='Arguments to pass to the program')
|
||||
execute_parser.add_argument('--debug', action='store_true', help='Show transpiled Python code for debugging')
|
||||
|
||||
# Compile command
|
||||
compile_parser = subparsers.add_parser('compile', help='Compile a custom language file to Python bytecode')
|
||||
compile_parser.add_argument('input_file', help='Input file to compile')
|
||||
compile_parser.add_argument('-o', '--output-dir', help='Output directory for compiled files')
|
||||
compile_parser.add_argument('-k', '--keep-py', action='store_true', help='Keep intermediate Python file')
|
||||
|
||||
# REPL command
|
||||
repl_parser = subparsers.add_parser('repl', help='Start a REPL for the custom language')
|
||||
|
||||
# Create mapping command
|
||||
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)')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
transpiler = Transpiler(args.mapping)
|
||||
# If no command is specified, show help
|
||||
if not args.command:
|
||||
parser.print_help()
|
||||
return
|
||||
|
||||
if args.output:
|
||||
result = transpiler.transpile_file(args.input_file, args.output, args.reverse)
|
||||
print(result)
|
||||
else:
|
||||
result = transpiler.transpile_file(args.input_file, reverse=args.reverse)
|
||||
print(result)
|
||||
# Handle create-mapping command
|
||||
if args.command == 'create-mapping':
|
||||
create_default_mapping(args.output_file)
|
||||
print(f"Created default mapping file at {args.output_file}")
|
||||
return
|
||||
|
||||
# Ensure mapping file is provided for other commands
|
||||
if not args.config:
|
||||
# Try to find a mapping.json file in the current directory
|
||||
if os.path.exists('mapping.json'):
|
||||
args.config = 'mapping.json'
|
||||
else:
|
||||
print("Error: Mapping file is required. Use -c/--config option or create a mapping.json file in the current directory.", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
# Create transpiler
|
||||
transpiler = Transpiler(args.config)
|
||||
|
||||
# Handle commands
|
||||
if args.command == 'transpile':
|
||||
if args.output:
|
||||
result = transpiler.transpile_file(args.input_file, args.output, args.reverse)
|
||||
print(result)
|
||||
else:
|
||||
result = transpiler.transpile_file(args.input_file, reverse=args.reverse)
|
||||
print(result)
|
||||
|
||||
elif args.command == 'run':
|
||||
return transpiler.execute_code(args.input_file, args.args, args.debug)
|
||||
|
||||
elif args.command == 'compile':
|
||||
transpiler.compile_code(args.input_file, args.output_dir, args.keep_py)
|
||||
|
||||
elif args.command == 'repl':
|
||||
transpiler.start_repl()
|
||||
|
||||
def create_default_mapping(filename):
|
||||
"""Create a default mapping file with meme/slang terms."""
|
||||
default_mapping = {
|
||||
"keywords": {
|
||||
"skibidi": "def",
|
||||
"toilet": "class",
|
||||
"ohio": "import",
|
||||
"rizz": "return",
|
||||
"bussin": "print",
|
||||
"fr": "for",
|
||||
"no_cap": "True",
|
||||
"cap": "False",
|
||||
"yeet": "if",
|
||||
"sus": "else",
|
||||
"vibe_check": "while",
|
||||
"finna": "try",
|
||||
"bruh": "except",
|
||||
"slay": "lambda",
|
||||
"based": "with",
|
||||
"sheesh": "pass",
|
||||
"mid": "None",
|
||||
"goated": "self",
|
||||
"npc": "object",
|
||||
"glizzy": "list",
|
||||
"drip": "dict",
|
||||
"bet": "in",
|
||||
"rent_free": "yield",
|
||||
"chad": "super",
|
||||
"karen": "raise",
|
||||
"boomer": "break",
|
||||
"zoomer": "continue",
|
||||
"stan": "from",
|
||||
"simp": "as",
|
||||
"cringe": "assert",
|
||||
"touch_grass": "exit",
|
||||
"down_bad": "False",
|
||||
"up_good": "True",
|
||||
"ong": "not",
|
||||
"lowkey": "nonlocal",
|
||||
"highkey": "global",
|
||||
"main_character": "__main__",
|
||||
"villain_arc": "__init__",
|
||||
"plot_twist": "finally",
|
||||
"gaslighting": "isinstance",
|
||||
"gatekeeping": "issubclass",
|
||||
"girlboss": "property",
|
||||
"sigma": "staticmethod",
|
||||
"alpha": "classmethod",
|
||||
"beta": "abstractmethod",
|
||||
"L_plus_ratio": "Exception",
|
||||
"skill_issue": "ValueError",
|
||||
"cope": "TypeError",
|
||||
"seethe": "KeyError",
|
||||
"mald": "IndexError"
|
||||
},
|
||||
"special_patterns": {
|
||||
"no\\s+shot": "assert",
|
||||
"on\\s+god": "global",
|
||||
"slide\\s+into\\s+(\\w+)": "import \\1",
|
||||
"spill\\s+the\\s+tea": "raise Exception",
|
||||
"ratio\\s+(\\w+)": "del \\1"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "RizzLang",
|
||||
"version": "1.0.0",
|
||||
"description": "A meme-based programming language",
|
||||
"file_extension": ".ski",
|
||||
"author": "Scripting Language Factory"
|
||||
}
|
||||
}
|
||||
|
||||
with open(filename, 'w') as f:
|
||||
json.dump(default_mapping, f, indent=4)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
sys.exit(main() or 0)
|
Loading…
x
Reference in New Issue
Block a user