UNPKG

petcarescript

Version:

PetCareScript - A modern, expressive programming language designed for humans

763 lines (680 loc) β€’ 26.7 kB
/** * 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;