petcarescript
Version:
PetCareScript - A modern, expressive programming language designed for humans with async, HTTP, database, and testing support
479 lines (414 loc) • 15.9 kB
JavaScript
/**
* PetCareScript Main Entry Point
* Main entry point for the language - VERSÃO MELHORADA 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 = require('../package.json').version;
this.setupStandardLibrary();
}
setupStandardLibrary() {
// A nova abordagem: o interpreter já define todas as funções nativas
// Agora vamos apenas adicionar algumas funções específicas que não estão no interpreter
this.defineAdditionalFunctions();
}
defineAdditionalFunctions() {
// Funções específicas que não estão no interpreter
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;
}
});
// Adicionar algumas funções do CoreLib que podem ter implementações específicas
this.registerSelectiveLibrary(CoreLib, 'Core');
this.registerSelectiveLibrary(MathLib, 'Math');
this.registerSelectiveLibrary(StringLib, 'String');
this.registerSelectiveLibrary(HTTPLib, 'HTTP');
this.registerSelectiveLibrary(TestingLib, 'Testing');
this.registerSelectiveLibrary(AsyncLib, 'Async');
}
registerSelectiveLibrary(lib, name) {
try {
Object.entries(lib).forEach(([key, value]) => {
// Só registra se a função não existe ainda no 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 selective ${name} library: ${error.message}`);
}
}
getHelpText() {
return `
PetCareScript v${this.version} - Built-in Functions:
TYPE CHECKING:
typeOf(value) - Get type of value
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
isFunction(value) - Check if function
isEmpty(value) - Check if empty
TYPE CONVERSION:
toString(value) - Convert to string
toNumber(value) - Convert to number
toBoolean(value) - Convert to boolean
toArray(value) - Convert to array
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
reverse(array) - Reverse array
concat(array, ...others) - Concatenate arrays
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
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
Object.seal(obj) - Seal object
Object.preventExtensions(obj) - Prevent extensions
Object.isFrozen(obj) - Check if frozen
Object.isSealed(obj) - Check if sealed
Object.isExtensible(obj) - Check if extensible
hasProperty(obj, prop) - Check if has property
keys(obj) - Get keys (alias)
values(obj) - Get values (alias)
entries(obj) - Get entries (alias)
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
JSON FUNCTIONS:
JSON.parse(string) - Parse JSON string
JSON.stringify(obj) - Convert to JSON string
parseJSON(string) - Parse JSON (alias)
stringifyJSON(obj) - Stringify JSON (alias)
For more help, 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
};
if (variableArityFunctions[name] !== undefined) {
return variableArityFunctions[name];
}
// Default to function.length
return func.length || 0;
}
run(source) {
try {
// Add debug logging if environment variable is set
const debug = process.env.PCS_DEBUG === 'true';
if (debug) {
console.log('🔍 Debug: Starting tokenization...');
}
// Tokenization
const tokenizer = new Tokenizer(source);
const tokens = tokenizer.tokenize();
if (debug) {
console.log('🔍 Debug: Tokens generated:', tokens.length);
console.log('🔍 Debug: Starting parsing...');
}
// Parsing
const parser = new Parser(tokens);
const ast = parser.parse();
if (debug) {
console.log('🔍 Debug: AST generated, statements:', ast.statements.length);
console.log('🔍 Debug: Starting interpretation...');
}
// Interpretation
this.interpreter.interpret(ast.statements);
if (debug) {
console.log('🔍 Debug: Interpretation completed successfully');
}
return { success: true };
} catch (error) {
const errorMessage = `${error.message}`;
// Don't show full stack trace unless in debug mode
if (process.env.PCS_DEBUG === 'true') {
console.error(`❌ Runtime Error: ${errorMessage}`);
console.error('Stack trace:', error.stack);
} else {
console.error(`❌ Runtime Error: ${errorMessage}`);
}
return {
success: false,
error: errorMessage,
stack: error.stack
};
}
}
runFile(filename) {
const fs = require('fs');
try {
if (!fs.existsSync(filename)) {
throw new Error(`File not found: ${filename}`);
}
const source = fs.readFileSync(filename, 'utf8');
return this.run(source);
} catch (error) {
const errorMessage = `Error reading file: ${error.message}`;
console.error(`❌ File Error: ${errorMessage}`);
return {
success: false,
error: errorMessage
};
}
}
repl() {
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
prompt: 'pcs> '
});
console.log(`🐾 PetCareScript v${this.version} REPL`);
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.showReplHelp();
rl.prompt();
return;
}
if (input === 'clear' || input === 'cls') {
console.clear();
console.log(`🐾 PetCareScript v${this.version} 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 === '') {
rl.prompt();
return;
}
try {
const result = this.run(input);
if (!result.success) {
console.error(`❌ ${result.error}`);
}
} catch (error) {
console.error(`❌ ${error.message}`);
}
rl.prompt();
});
rl.on('close', () => {
console.log('\n👋 Goodbye!');
process.exit(0);
});
rl.on('SIGINT', () => {
console.log('\n👋 Goodbye!');
process.exit(0);
});
}
showReplHelp() {
console.log(`
REPL COMMANDS:
help Show this help
clear, cls Clear screen
version Show version
debug Toggle debug mode
exit, quit Exit REPL
PETCARESCRIPT SYNTAX:
store x = 42; # Define a variable
show x; # Print the value
build hello() { show "Hello!"; } # Define function
hello(); # Call function
# Object manipulation
store obj = { name: "Test", age: 25 };
store keys = Object.keys(obj);
store copy = Object.assign({}, obj);
# Blueprints (OOP)
blueprint Dog {
build init(name) { self.name = name; }
build bark() { show self.name + " barks!"; }
}
store dog = Dog("Rex");
dog.bark();
# HTTP Server
store server = createServer(3000);
server.get("/", build(req, res) { res.json({message: "Hello!"}); });
server.listen(build() { show "Server started!"; });
# Async/Promises
async build fetchData() {
store result = await get("https://api.example.com");
give result;
}
More examples: 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 async, HTTP, database, and testing support',
features: [
'Human-readable syntax',
'Object-oriented programming (blueprints)',
'Async/await support',
'Built-in HTTP server',
'Database integration',
'Testing framework',
'Promise support',
'Template strings',
'Array and string utilities',
'Complete Object manipulation support',
'Advanced Math functions',
'String manipulation and validation',
'Type checking and conversion'
]
};
}
// Method to validate syntax without executing
validateSyntax(source) {
try {
const tokenizer = new Tokenizer(source);
const tokens = tokenizer.tokenize();
const parser = new Parser(tokens);
parser.parse();
return { valid: true };
} catch (error) {
return {
valid: false,
error: error.message
};
}
}
// Method to get available built-in functions
getBuiltinFunctions() {
const functions = [];
this.interpreter.globals.values.forEach((value, key) => {
if (value && typeof value.arity === 'function') {
functions.push({
name: key,
arity: value.arity()
});
}
});
return functions.sort((a, b) => a.name.localeCompare(b.name));
}
}
module.exports = PetCareScript;