petcarescript
Version:
PetCareScript - A modern, expressive programming language designed for humans
763 lines (680 loc) β’ 26.7 kB
JavaScript
/**
* PetCareScript Main Entry Point
* Main entry point for the language - VERSΓO OTIMIZADA E CORRIGIDA
*/
const Tokenizer = require('./lexer/tokenizer');
const Parser = require('./parser/parser');
const Interpreter = require('./interpreter/interpreter');
const CoreLib = require('./stdlib/core');
const MathLib = require('./stdlib/math');
const StringLib = require('./stdlib/string');
const HTTPLib = require('./stdlib/http');
const DatabaseLib = require('./stdlib/database');
const TestingLib = require('./stdlib/testing');
const AsyncLib = require('./stdlib/async');
class PetCareScript {
constructor() {
this.interpreter = new Interpreter();
this.version = '1.3.0'; // Updated version
this.setupStandardLibrary();
}
setupStandardLibrary() {
// Enhanced approach: interpreter already defines all native functions
// Now we add only specific functions that are not in the interpreter
this.defineAdditionalFunctions();
}
defineAdditionalFunctions() {
// Core system functions
this.interpreter.globals.define('version', {
arity: () => 0,
call: () => this.version
});
this.interpreter.globals.define('exit', {
arity: () => -1,
call: (interpreter, args) => {
const code = args[0] || 0;
process.exit(code);
}
});
this.interpreter.globals.define('help', {
arity: () => 0,
call: () => {
console.log(this.getHelpText());
return null;
}
});
// Enhanced library registration with better error handling
this.registerEnhancedLibrary(CoreLib, 'Core');
this.registerEnhancedLibrary(MathLib, 'Math');
this.registerEnhancedLibrary(StringLib, 'String');
this.registerEnhancedLibrary(HTTPLib, 'HTTP');
this.registerEnhancedLibrary(TestingLib, 'Testing');
this.registerEnhancedLibrary(AsyncLib, 'Async');
// Enhanced global console object
this.interpreter.globals.define('console', {
log: {
arity: () => -1,
call: (interpreter, args) => {
console.log(...args.map(arg => this.interpreter.stringify(arg)));
return null;
}
},
error: {
arity: () => -1,
call: (interpreter, args) => {
console.error(...args.map(arg => this.interpreter.stringify(arg)));
return null;
}
},
warn: {
arity: () => -1,
call: (interpreter, args) => {
console.warn(...args.map(arg => this.interpreter.stringify(arg)));
return null;
}
},
info: {
arity: () => -1,
call: (interpreter, args) => {
console.info(...args.map(arg => this.interpreter.stringify(arg)));
return null;
}
},
clear: {
arity: () => 0,
call: (interpreter, args) => {
console.clear();
return null;
}
},
time: {
arity: () => 1,
call: (interpreter, args) => {
const label = args[0] || 'default';
console.time(label);
return null;
}
},
timeEnd: {
arity: () => 1,
call: (interpreter, args) => {
const label = args[0] || 'default';
console.timeEnd(label);
return null;
}
}
});
// Enhanced global Math object
this.interpreter.globals.define('Math', {
PI: Math.PI,
E: Math.E,
LN2: Math.LN2,
LN10: Math.LN10,
LOG2E: Math.LOG2E,
LOG10E: Math.LOG10E,
SQRT1_2: Math.SQRT1_2,
SQRT2: Math.SQRT2,
abs: {
arity: () => 1,
call: (interpreter, args) => Math.abs(args[0])
},
max: {
arity: () => -1,
call: (interpreter, args) => Math.max(...args)
},
min: {
arity: () => -1,
call: (interpreter, args) => Math.min(...args)
},
pow: {
arity: () => 2,
call: (interpreter, args) => Math.pow(args[0], args[1])
},
sqrt: {
arity: () => 1,
call: (interpreter, args) => Math.sqrt(args[0])
},
floor: {
arity: () => 1,
call: (interpreter, args) => Math.floor(args[0])
},
ceil: {
arity: () => 1,
call: (interpreter, args) => Math.ceil(args[0])
},
round: {
arity: () => 1,
call: (interpreter, args) => Math.round(args[0])
},
random: {
arity: () => 0,
call: (interpreter, args) => Math.random()
},
sin: {
arity: () => 1,
call: (interpreter, args) => Math.sin(args[0])
},
cos: {
arity: () => 1,
call: (interpreter, args) => Math.cos(args[0])
},
tan: {
arity: () => 1,
call: (interpreter, args) => Math.tan(args[0])
},
asin: {
arity: () => 1,
call: (interpreter, args) => Math.asin(args[0])
},
acos: {
arity: () => 1,
call: (interpreter, args) => Math.acos(args[0])
},
atan: {
arity: () => 1,
call: (interpreter, args) => Math.atan(args[0])
},
atan2: {
arity: () => 2,
call: (interpreter, args) => Math.atan2(args[0], args[1])
},
log: {
arity: () => 1,
call: (interpreter, args) => Math.log(args[0])
},
log10: {
arity: () => 1,
call: (interpreter, args) => Math.log10(args[0])
},
exp: {
arity: () => 1,
call: (interpreter, args) => Math.exp(args[0])
}
});
}
registerEnhancedLibrary(lib, name) {
try {
Object.entries(lib).forEach(([key, value]) => {
// Only register if the function doesn't exist yet in the interpreter
if (!this.interpreter.globals.has(key)) {
if (typeof value === 'function') {
// Check if it's a class constructor
const isClass = value.prototype && value.prototype.constructor === value;
if (isClass) {
// For classes, create a wrapper function that uses 'new'
const arity = this.getFunctionArity(key, value);
this.interpreter.globals.define(key, {
arity: () => arity,
call: (interpreter, args) => {
try {
return new value(...args);
} catch (error) {
throw new Error(`Error in ${name}.${key}: ${error.message}`);
}
}
});
} else {
// For regular functions
const arity = this.getFunctionArity(key, value);
this.interpreter.globals.define(key, {
arity: () => arity,
call: (interpreter, args) => {
try {
return value(...args);
} catch (error) {
throw new Error(`Error in ${name}.${key}: ${error.message}`);
}
}
});
}
} else {
// For non-function values
this.interpreter.globals.define(key, value);
}
}
});
} catch (error) {
console.warn(`Warning: Failed to register enhanced ${name} library: ${error.message}`);
}
}
getHelpText() {
return `
PetCareScript v${this.version} - Enhanced Built-in Functions:
TYPE CHECKING & CONVERSION:
typeOf(value) - Get type of value ('array', 'object', 'string', etc.)
isNumber(value) - Check if number
isString(value) - Check if string
isBoolean(value) - Check if boolean
isArray(value) - Check if array
isObject(value) - Check if object (not array/date)
isFunction(value) - Check if function
isEmpty(value) - Check if empty/null/undefined
toString(value) - Convert to string
toNumber(value) - Convert to number
toBoolean(value) - Convert to boolean
toArray(value) - Convert to array
ENHANCED ARRAY FUNCTIONS:
length(array) - Get length
push(array, item) - Add to end
pop(array) - Remove from end
slice(array, start, end) - Get slice
indexOf(array, item) - Find index
includes(array, item) - Check if contains
join(array, separator) - Join to string
map(array, fn) - Transform elements
filter(array, fn) - Filter elements
reduce(array, fn, init) - Reduce to value
sort(array, fn) - Sort array
sortBy(array, keyFn) - Sort by key/function (NEW!)
reverse(array) - Reverse array
concat(array, ...others) - Concatenate arrays
every(array, fn) - Test if all elements pass (NEW!)
some(array, fn) - Test if any element passes (NEW!)
find(array, fn) - Find first matching element
findIndex(array, fn) - Find index of first match
ENHANCED OBJECT FUNCTIONS:
Object.keys(obj) - Get object keys
Object.values(obj) - Get object values
Object.entries(obj) - Get key-value pairs
Object.assign(target, ...sources) - Merge objects
Object.create(proto) - Create object with prototype
Object.freeze(obj) - Freeze object (immutable)
Object.seal(obj) - Seal object (no new props)
Object.preventExtensions(obj) - Prevent adding properties
Object.isFrozen(obj) - Check if frozen
Object.isSealed(obj) - Check if sealed
Object.isExtensible(obj) - Check if extensible
Object.hasOwnProperty(obj, prop) - Check property ownership
Object.getOwnPropertyNames(obj) - Get all property names
Object.getOwnPropertyDescriptor(obj, prop) - Get property descriptor
Object.defineProperty(obj, prop, desc) - Define property with descriptor
hasProperty(obj, prop) - Check if has property (alias)
keys(obj) - Get keys (global alias)
values(obj) - Get values (global alias)
entries(obj) - Get entries (global alias)
ENHANCED STRING FUNCTIONS:
upper(string) - To uppercase
lower(string) - To lowercase
trim(string) - Remove whitespace
split(string, sep) - Split to array
replace(string, old, new) - Replace text
startsWith(string, prefix) - Check prefix
endsWith(string, suffix) - Check suffix
charAt(string, index) - Get character at index
substring(string, start, end) - Get substring
ENHANCED MATH FUNCTIONS:
abs(number) - Absolute value
max(...numbers) - Maximum value
min(...numbers) - Minimum value
sqrt(number) - Square root
pow(base, exp) - Power
floor(number) - Round down
ceil(number) - Round up
round(number) - Round nearest
random() - Random 0-1
randomInt(min, max) - Random integer
Math.PI, Math.E - Mathematical constants
Math.sin, Math.cos, Math.tan - Trigonometric functions
ENHANCED JSON FUNCTIONS:
JSON.parse(string) - Parse JSON string
JSON.stringify(obj, replacer, space) - Convert to JSON string
parseJSON(string) - Parse JSON (alias)
stringifyJSON(obj) - Stringify JSON (alias)
ENHANCED ASYNC/PROMISE FUNCTIONS:
Promise(executor) - Create new promise
timeout(fn, delay) - Execute function after delay
retry(fn, maxRetries, delay) - Retry function on failure (NEW!)
parallel(tasks) - Execute tasks in parallel (NEW!)
all(promises) - Wait for all promises
sleep(ms) - Sleep for milliseconds
CONSOLE FUNCTIONS:
console.log(...args) - Log to console
console.error(...args) - Log error
console.warn(...args) - Log warning
console.info(...args) - Log info
console.clear() - Clear console
console.time(label) - Start timer
console.timeEnd(label) - End timer
For complete documentation, visit: https://github.com/estevamsl/petcarescript
`;
}
getFunctionArity(name, func) {
// Special cases for functions with variable arguments
const variableArityFunctions = {
'format': -1,
'get': -1,
'post': -1,
'put': -1,
'patch': -1,
'delete': -1,
'assign': -1,
'stringifyJSON': -1,
'log': -1,
'error': -1,
'warn': -1,
'info': -1,
'max': -1,
'min': -1,
'sum': -1,
'concat': -1,
'retry': -1,
'timeout': -1,
'parallel': -1
};
if (variableArityFunctions[name] !== undefined) {
return variableArityFunctions[name];
}
// Default to function.length
return func.length || 0;
}
run(source) {
try {
// Enhanced debug logging
const debug = process.env.PCS_DEBUG === 'true';
if (debug) {
console.log('π Debug: Starting enhanced tokenization...');
}
// Enhanced Tokenization with error handling
const tokenizer = new Tokenizer(source);
const tokens = tokenizer.tokenize();
if (debug) {
console.log(`π Debug: ${tokens.length} tokens generated successfully`);
console.log('π Debug: Starting enhanced parsing...');
}
// Enhanced Parsing with better error messages
const parser = new Parser(tokens);
const ast = parser.parse();
if (debug) {
console.log(`π Debug: AST generated with ${ast.statements.length} statements`);
console.log('π Debug: Starting enhanced interpretation...');
}
// Enhanced Interpretation with performance monitoring
const startTime = Date.now();
this.interpreter.interpret(ast.statements);
const endTime = Date.now();
if (debug) {
console.log(`π Debug: Interpretation completed in ${endTime - startTime}ms`);
}
return { success: true, executionTime: endTime - startTime };
} catch (error) {
const errorMessage = `${error.message}`;
// Enhanced error reporting
if (process.env.PCS_DEBUG === 'true') {
console.error(`β Enhanced Runtime Error: ${errorMessage}`);
console.error('π Error location:', error.stack);
console.error('π Error type:', error.constructor.name);
} else {
console.error(`β Runtime Error: ${errorMessage}`);
}
return {
success: false,
error: errorMessage,
stack: error.stack,
type: error.constructor.name
};
}
}
runFile(filename) {
const fs = require('fs');
try {
if (!fs.existsSync(filename)) {
throw new Error(`File not found: ${filename}`);
}
const source = fs.readFileSync(filename, 'utf8');
// Enhanced file execution with metadata
const result = this.run(source);
result.filename = filename;
result.fileSize = source.length;
return result;
} catch (error) {
const errorMessage = `Error reading file: ${error.message}`;
console.error(`β File Error: ${errorMessage}`);
return {
success: false,
error: errorMessage,
filename: filename
};
}
}
repl() {
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
prompt: 'pcs> '
});
console.log(`πΎ PetCareScript v${this.version} Enhanced REPL`);
console.log('Enhanced features: Object manipulation, async/await, enhanced arrays');
console.log('Type "exit", "quit", or Ctrl+C to quit.');
console.log('Type "help" for available commands.\n');
rl.prompt();
rl.on('line', (line) => {
const input = line.trim();
if (input === 'exit' || input === 'quit') {
rl.close();
return;
}
if (input === 'help') {
this.showEnhancedReplHelp();
rl.prompt();
return;
}
if (input === 'clear' || input === 'cls') {
console.clear();
console.log(`πΎ PetCareScript v${this.version} Enhanced REPL`);
rl.prompt();
return;
}
if (input === 'version') {
console.log(`PetCareScript v${this.version}`);
rl.prompt();
return;
}
if (input === 'debug') {
process.env.PCS_DEBUG = process.env.PCS_DEBUG === 'true' ? 'false' : 'true';
console.log(`Debug mode: ${process.env.PCS_DEBUG === 'true' ? 'ON' : 'OFF'}`);
rl.prompt();
return;
}
if (input === 'features') {
console.log('π Enhanced Features:');
console.log('β’ Complete Object manipulation (keys, values, entries, assign, etc.)');
console.log('β’ Enhanced Arrays (sortBy, every, some, etc.)');
console.log('β’ Async/Promise support (retry, parallel, timeout)');
console.log('β’ Enhanced error handling and debugging');
console.log('β’ Improved performance monitoring');
rl.prompt();
return;
}
if (input === '') {
rl.prompt();
return;
}
try {
const startTime = Date.now();
const result = this.run(input);
const endTime = Date.now();
if (!result.success) {
console.error(`β ${result.error}`);
} else if (process.env.PCS_DEBUG === 'true') {
console.log(`β
Executed in ${endTime - startTime}ms`);
}
} catch (error) {
console.error(`β ${error.message}`);
}
rl.prompt();
});
rl.on('close', () => {
console.log('\nπ Goodbye from PetCareScript Enhanced!');
process.exit(0);
});
rl.on('SIGINT', () => {
console.log('\nπ Goodbye from PetCareScript Enhanced!');
process.exit(0);
});
}
showEnhancedReplHelp() {
console.log(`
ENHANCED REPL COMMANDS:
help Show this help
clear, cls Clear screen
version Show version
debug Toggle debug mode
features Show enhanced features
exit, quit Exit REPL
ENHANCED PETCARESCRIPT SYNTAX:
# Variables and basic operations
store x = 42;
show x;
# Enhanced Object manipulation
store obj = { name: "Test", age: 25, skills: ["JS", "PCS"] };
store keys = Object.keys(obj);
store copy = Object.assign({}, obj);
store frozen = Object.freeze(obj);
show "Frozen: " + (Object.isFrozen(frozen) ? "yes" : "no");
# Enhanced Array operations
store numbers = [3, 1, 4, 1, 5, 9];
store sorted = sortBy(numbers, build(x) { give x; });
store allPositive = every(numbers, build(x) { give x > 0; });
store hasEven = some(numbers, build(x) { give x % 2 == 0; });
# Functions and Blueprints
build hello() { show "Hello Enhanced World!"; }
hello();
blueprint Dog {
init(name) { self.name = name; }
bark() { show self.name + " barks loudly!"; }
}
store dog = Dog("Rex");
dog.bark();
# Enhanced Async/Promise operations
store promise = Promise(build(resolve, reject) {
timeout(build() { resolve("Success!"); }, 1000);
});
# HTTP Server with enhanced middleware
store server = createServer(3000);
server.use(cors(), json(), logger());
server.get("/api/users", build(req, res) {
res.json({users: ["Alice", "Bob"]});
});
server.listen(build() { show "Enhanced server started!"; });
Enhanced Documentation: https://github.com/estevamsl/petcarescript
`);
}
getVersion() {
return this.version;
}
getLanguageInfo() {
return {
name: 'PetCareScript',
version: this.getVersion(),
extension: '.pcs',
description: 'A modern and expressive programming language with enhanced features',
features: [
'Human-readable syntax',
'Enhanced Object manipulation (complete Object API)',
'Enhanced Array operations (sortBy, every, some)',
'Object-oriented programming (blueprints)',
'Enhanced Async/await support (retry, parallel, timeout)',
'Built-in HTTP server with middleware',
'Database integration',
'Testing framework',
'Enhanced Promise support',
'Template strings',
'Complete Object property management',
'Advanced Math functions',
'Enhanced String manipulation and validation',
'Enhanced Type checking and conversion',
'Performance monitoring',
'Enhanced error handling and debugging'
]
};
}
// Enhanced syntax validation
validateSyntax(source) {
try {
const tokenizer = new Tokenizer(source);
const tokens = tokenizer.tokenize();
const parser = new Parser(tokens);
parser.parse();
return {
valid: true,
tokens: tokens.length,
complexity: this.calculateComplexity(source)
};
} catch (error) {
return {
valid: false,
error: error.message,
line: error.token?.line || 'unknown',
column: error.token?.column || 'unknown'
};
}
}
// Enhanced complexity calculation
calculateComplexity(source) {
const lines = source.split('\n').length;
const functions = (source.match(/build\s+\w+/g) || []).length;
const blueprints = (source.match(/blueprint\s+\w+/g) || []).length;
const conditionals = (source.match(/when\s*\(|if\s*\(/g) || []).length;
const loops = (source.match(/repeat\s*\(|loop\s*\(|foreach\s*\(/g) || []).length;
return {
lines,
functions,
blueprints,
conditionals,
loops,
score: lines + (functions * 2) + (blueprints * 3) + conditionals + loops
};
}
// Enhanced built-in functions listing
getBuiltinFunctions() {
const functions = [];
this.interpreter.globals.values.forEach((value, key) => {
if (value && typeof value.arity === 'function') {
functions.push({
name: key,
arity: value.arity(),
type: 'function'
});
} else if (value && typeof value === 'object' && value !== null) {
// Check for nested functions (like Object.keys, Math.abs, etc.)
Object.entries(value).forEach(([subKey, subValue]) => {
if (subValue && typeof subValue.arity === 'function') {
functions.push({
name: `${key}.${subKey}`,
arity: subValue.arity(),
type: 'method'
});
}
});
}
});
return functions.sort((a, b) => a.name.localeCompare(b.name));
}
// Enhanced performance benchmarking
benchmark(source, iterations = 1000) {
const results = [];
for (let i = 0; i < iterations; i++) {
const startTime = Date.now();
const result = this.run(source);
const endTime = Date.now();
if (result.success) {
results.push(endTime - startTime);
}
}
if (results.length === 0) {
return { error: 'No successful executions' };
}
const avg = results.reduce((a, b) => a + b, 0) / results.length;
const min = Math.min(...results);
const max = Math.max(...results);
return {
iterations: results.length,
average: avg,
min: min,
max: max,
total: results.reduce((a, b) => a + b, 0)
};
}
}
module.exports = PetCareScript;