EasyScript
A simple scripting language interpreter that blends Python and JavaScript syntax, designed for easy expression evaluation, business rule processing, and LDAP/user object manipulation.
Features
- Hybrid Syntax: Combines the best of Python and JavaScript syntax
- JavaScript-style String Concatenation: Automatic string conversion (e.g.,
"hello" + 5→"hello5") - Python-style Boolean Operators: Supports
and,or, andnotoperators - Object Property Access: Dot notation for accessing object properties (
user.cn,user.mail) - Built-in Variables: Pre-defined variables (
day,month,year) with support for object injection - Built-in Functions: Essential functions like
len(),log(),abs(),min(),max(),round() - Regex Matching: Pattern matching with
~operator (string ~ pattern) - Conditional Logic: Support for
if-then-elsestatements (thethenkeyword is required) - Mixed Boolean Values: Supports both
True/Falseandtrue/false - Comments: Both Python-style (
#) and JavaScript-style (//) comments supported - REPL Mode: Interactive command-line interface for testing expressions
- Null Support: Built-in
nullkeyword for null values
Quick Start
Command Line / REPL Usage
# Run EasyScript directly
python -m easyscript
# Or use the REPL interactively
python -m easyscript --repl
In REPL mode, you can interactively test expressions:
EasyScript REPL (type 'exit' to quit, 'help' for commands)
> 5 + 3 * 2
13
> "Hello " + "World"
Hello World
> abs(-15)
15
> min(10, 5, 20)
5
Python Integration
from easyscript import EasyScriptEvaluator
# Create an evaluator instance
evaluator = EasyScriptEvaluator()
# Basic arithmetic
result = evaluator.evaluate("3 + 5") # Returns: 8
# New built-in functions
result = evaluator.evaluate("abs(-10)") # Returns: 10
result = evaluator.evaluate("min(5, 3, 8)") # Returns: 3
result = evaluator.evaluate("max(5, 3, 8)") # Returns: 8
result = evaluator.evaluate("round(3.7)") # Returns: 4
# String concatenation
result = evaluator.evaluate('"Hello " + "World"') # Returns: "Hello World"
# JavaScript-style string + number
result = evaluator.evaluate('"Count: " + 42') # Returns: "Count: 42"
# Null values
result = evaluator.evaluate("null") # Returns: None
# Built-in variables
result = evaluator.evaluate("year") # Returns: current year
# Object injection
class User:
def __init__(self):
self.cn = "John Doe"
self.mail = "john@example.com"
user = User()
result = evaluator.evaluate("user.cn", {"user": user}) # Returns: "John Doe"
# Log function (prints and returns value)
result = evaluator.evaluate('log("Debug info")') # Prints: Debug info, Returns: "Debug info"
# Regex matching
result = evaluator.evaluate('user.mail ~ ".*@.*"', {"user": user}) # Returns: True
# Conditional logic
result = evaluator.evaluate('if len(user.cn) > 3 then true else false', {"user": user}) # Returns: True
# Comments in expressions (both styles supported)
result = evaluator.evaluate('5 + 3 # Python-style comment') # Returns: 8
result = evaluator.evaluate('5 + 3 // JavaScript-style comment') # Returns: 8
Syntax Examples
Basic Operations
// Arithmetic
3 + 5 * 2 // 13
10 / 2 - 1 // 4.0
// Built-in functions
abs(-15) // 15
min(10, 5, 20) // 5
max(10, 5, 20) // 20
round(3.7) // 4
round(3.14159, 2) // 3.14
// String operations
"Hello " + "World" // "Hello World"
"Value: " + 42 // "Value: 42"
len("Hello") // 5
log("Debug: " + 42) // Prints: Debug: 42, Returns: "Debug: 42"
// Null values
null // null
null == null // True
// Comparisons
5 > 3 // True
"abc" == "abc" // True
len("test") >= 4 // True
// Regex matching
"hello" ~ "h.*o" // True
"test123" ~ "[0-9]+" // True
"email@domain.com" ~ ".*@.*" // True
Boolean Logic
// Python-style boolean operators
true and false // False
true or false // True
not true // False
not false // True
// Operator precedence (not has higher precedence)
not true and false // False (equivalent to: (not true) and false)
not (true and false) // True
// Mixed case support
True and False // False
true and False // False
not True // False
Conditional Expressions
// if-then-else syntax (then keyword is mandatory)
if 5 > 3 then "greater" else "not greater" // "greater"
if false then "yes" else "no" // "no"
// Conditions can be complex expressions
if len("hello") >= 5 then "long" else "short" // "long"
if year > 2020 and month == 12 then "recent december" else "other time"
// Nested conditionals
if user.active then (if user.role == "admin" then "admin user" else "regular user") else "inactive"
// Numeric results
if user.age >= 18 then user.age else 0
// Using with object properties
if user.department == "IT" then user.salary * 1.1 else user.salary
Comments
// Python-style comments using #
5 + 3 # This is a comment
"hello" + "world" # Comments can appear at end of line
# Full line comments are supported
5 + 3 # Result: 8
// JavaScript-style comments using //
5 + 3 // This is also a comment
"hello" + "world" // JavaScript-style comment
// Both comment styles can be mixed
5 # Python comment
+ 3 // JavaScript comment
* 2 # Result: 16
// Comments in multi-line expressions
5 # first number
+ 3 // second number
* 2 # multiply result
Object Injection and Access
// Create and inject custom objects
from easyscript import EasyScriptEvaluator
class User:
def __init__(self):
self.cn = "John Doe"
self.mail = "john.doe@company.com"
self.department = "Engineering"
user = User()
evaluator = EasyScriptEvaluator()
// Access injected object properties
evaluator.evaluate("user.cn", {"user": user}) // "John Doe"
evaluator.evaluate("user.mail", {"user": user}) // "john.doe@company.com"
// Use in expressions
evaluator.evaluate('"Hello " + user.cn', {"user": user}) // "Hello John Doe"
evaluator.evaluate('len(user.mail) > 10', {"user": user}) // True
evaluator.evaluate('user.mail ~ ".*@.*"', {"user": user}) // True (email validation)
Conditional Statements
// Basic conditional - 'then' keyword is required
if 5 > 3 then true else false // True
// String results
if len(user.cn) > 3 then "Long name" else "Short name" // "Long name"
// Complex conditions
if user.department == "Engineering" and len(user.cn) > 3 then "Valid engineer" else "Invalid"
// Nested expressions
if year > 2020 then year - 2020 else 0 // Returns difference from 2020
// Boolean expressions
if user.active then "Active user" else "Inactive user"
Built-in Variables
EasyScript provides several built-in variables:
day: Current day of the monthmonth: Current month (1-12)year: Current year
Additional objects can be injected using the variables parameter.
Use Cases
EasyScript is particularly useful for:
- Business Rule Processing: Evaluate complex business logic with simple syntax
- LDAP/Directory Services: Process user attributes and directory data
- Configuration Management: Dynamic configuration based on conditions
- Data Validation: Validate data with readable expressions
- Template Processing: Generate dynamic content based on user data
Installation
Simply install the package or download the easyscript.py file:
pip install easyscript
from easyscript import EasyScriptEvaluator
Requirements
- Python 3.6+
- No external dependencies
Running Tests
Run the included test suite to verify functionality:
# Basic functionality tests
python tests/test_easyscript.py
# Object injection examples (includes LDAPUser example class)
python tests/test_easyscript_user.py
# Or run all tests
python -m pytest tests/
Note: The LDAPUser class used in tests is just an example of object injection and is located in tests/test_helpers.py. It's not part of the main library.
Object Injection
EasyScript's power comes from injecting your own objects and data:
from easyscript import EasyScriptEvaluator
evaluator = EasyScriptEvaluator()
# Inject any Python object
class Config:
def __init__(self):
self.debug = True
self.api_url = "https://api.example.com"
class User:
def __init__(self, name, email):
self.name = name
self.email = email
self.active = True
# Create instances
config = Config()
user = User("Alice", "alice@company.com")
# Inject multiple objects
variables = {
'config': config,
'user': user,
'version': '1.0'
}
# Use in expressions
result = evaluator.evaluate('user.name + " - " + config.api_url', variables)
# Returns: "Alice - https://api.example.com"
result = evaluator.evaluate('if user.active and config.debug then "Debug mode" else "Production mode"', variables)
# Returns: "Debug mode"
result = evaluator.evaluate('user.email ~ ".*@company\.com"', variables)
# Returns: True
Contributing
Contributions are welcome! Feel free to:
- Report bugs
- Suggest new features
- Submit pull requests
- Improve documentation
License
This project is released under the MIT License. See the LICENSE file for details.
Examples
Real-world Usage Scenarios
User Access Control:
if user.department == "IT" and len(user.cn) > 0 then true else false
Dynamic Greetings:
if month >= 6 and month <= 8 then "Summer greetings, " + user.givenName else "Hello, " + user.givenName
Data Validation:
# Inject user object
user = User("john", "john@company.com")
variables = {"user": user}
result = evaluator.evaluate('if len(user.mail) > 5 and user.mail ~ ".*@.*" then true else false', variables)
Pattern Matching:
result = evaluator.evaluate('if user.username ~ "^[a-z]+$" then "Valid username" else "Invalid username"', variables)
result = evaluator.evaluate('if user.mail ~ ".*@company\.com$" then "Company email" else "External email"', variables)
Configuration Logic:
if user.title == "Manager" or user.department == "Executive" then "admin" else "user"
Metadata
Release files for easyscript 0.6.6
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| easyscript-0.6.6.tar.gz | 40.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| easyscript-0.6.6-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 58.8 kB
Release files / easyscript-0.6.6.tar.gz
| Download URL | easyscript-0.6.6.tar.gz |
|---|---|
| Size | 40.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a603eb0c2339388c66a21d6ac21094a8407714a7ee0a49f799652dd6e71bcbce
|
|
BLAKE2b-256 checksum How to use checksums |
eef86119227d6b3e295b8ef5d3fb3a53e29d2674f97ae0193b6da436ccb2a890
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.10
|
Release files / easyscript-0.6.6-py3-none-any.whl
| Download URL | easyscript-0.6.6-py3-none-any.whl |
|---|---|
| Size | 18.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
99fc6ac2c207fd356697909d6babcf678479467cb7d27e33cbaf0e0dc372dc9f
|
|
BLAKE2b-256 checksum How to use checksums |
09c74d0e093e886638b6489a55aa6f7e0993f209899455840b92885d8445b8f5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.10
|