diff options
Diffstat (limited to 'tree-sitter/dsk/dsk-cli/src/utils')
-rw-r--r-- | tree-sitter/dsk/dsk-cli/src/utils/grammar-generator.ts | 466 | ||||
-rw-r--r-- | tree-sitter/dsk/dsk-cli/src/utils/inference.ts | 286 | ||||
-rw-r--r-- | tree-sitter/dsk/dsk-cli/src/utils/template-processor.ts | 192 |
3 files changed, 944 insertions, 0 deletions
diff --git a/tree-sitter/dsk/dsk-cli/src/utils/grammar-generator.ts b/tree-sitter/dsk/dsk-cli/src/utils/grammar-generator.ts new file mode 100644 index 0000000..1b40eff --- /dev/null +++ b/tree-sitter/dsk/dsk-cli/src/utils/grammar-generator.ts @@ -0,0 +1,466 @@ +/** + * Grammar Generator + * + * Converts collected user information into Tree-sitter grammar.js files + * with paradigm-aware rule generation + */ + +import { LanguageArchitecture, LanguageFeatures, LanguageSyntax } from '../commands/new.js'; + +export interface GrammarRule { + name: string; + definition: string; + comment?: string; +} + +export interface GeneratedGrammar { + name: string; + rules: GrammarRule[]; + extras: string[]; + conflicts: string[][]; + precedences: string[][]; + word?: string; +} + +/** + * Generate a complete Tree-sitter grammar from user specifications + */ +export function generateGrammar( + architecture: LanguageArchitecture, + features: LanguageFeatures, + syntax: LanguageSyntax +): GeneratedGrammar { + const rules: GrammarRule[] = []; + const extras: string[] = []; + + // Start with the root rule - this varies by paradigm + rules.push(generateRootRule(architecture, features)); + + // Add basic token rules + rules.push(...generateTokenRules(syntax)); + + // Add paradigm-specific rules + rules.push(...generateParadigmRules(architecture, features, syntax)); + + // Add data structure rules if specified + if (features.dataStructures.length > 0) { + rules.push(...generateDataStructureRules(features.dataStructures)); + } + + // Add control flow rules if specified + if (features.controlFlow.length > 0) { + rules.push(...generateControlFlowRules(features.controlFlow, syntax)); + } + + // Set up extras (whitespace and comments) + extras.push('/\\s/', `$.${getCommentRuleName(syntax.comments.pattern)}`); + + return { + name: architecture.name, + rules, + extras, + conflicts: [], // TODO: Add conflicts if needed + precedences: generatePrecedences(architecture, features), + word: 'identifier' // Most languages use identifier as word token + }; +} + +/** + * Generate the root rule based on language paradigm + */ +function generateRootRule(architecture: LanguageArchitecture, features: LanguageFeatures): GrammarRule { + let definition: string; + + switch (architecture.paradigm) { + case 'declarative': + definition = 'repeat(choice($.rule_declaration, $.constraint, $.fact))'; + break; + case 'functional': + definition = 'repeat(choice($.function_definition, $.expression, $.binding))'; + break; + case 'object-oriented': + definition = 'repeat(choice($.class_definition, $.statement, $.expression))'; + break; + case 'procedural': + case 'mixed': + default: + definition = 'repeat(choice($.statement, $.expression, $.declaration))'; + break; + } + + return { + name: 'source_file', + definition, + comment: `Root rule for ${architecture.paradigm} language` + }; +} + +/** + * Generate basic token rules (identifiers, numbers, strings, comments) + */ +function generateTokenRules(syntax: LanguageSyntax): GrammarRule[] { + const rules: GrammarRule[] = []; + + // Identifier + rules.push({ + name: 'identifier', + definition: `/${syntax.identifiers.pattern}/`, + comment: `Identifiers: ${syntax.identifiers.examples.join(', ')}` + }); + + // Numbers + rules.push({ + name: 'number', + definition: `/${syntax.numbers.pattern}/`, + comment: `Numbers: ${syntax.numbers.examples.join(', ')}` + }); + + // Strings + rules.push({ + name: 'string', + definition: `/${syntax.strings.pattern}/`, + comment: `Strings: ${syntax.strings.examples.join(', ')}` + }); + + // Comments + const commentRuleName = getCommentRuleName(syntax.comments.pattern); + rules.push({ + name: commentRuleName, + definition: `/${escapeRegex(syntax.comments.pattern)}.*$/`, + comment: `Line comments starting with ${syntax.comments.pattern}` + }); + + return rules; +} + +/** + * Generate paradigm-specific rules + */ +function generateParadigmRules( + architecture: LanguageArchitecture, + features: LanguageFeatures, + syntax: LanguageSyntax +): GrammarRule[] { + const rules: GrammarRule[] = []; + + // Variable declarations (common to most paradigms) + rules.push({ + name: 'variable_declaration', + definition: `seq("${syntax.variables.keyword}", $.identifier, "${syntax.variables.operator}", $.expression, "${syntax.variables.terminator}")`, + comment: `Variable declarations: ${syntax.variables.example}` + }); + + // Expression rule (fundamental to all paradigms) + rules.push(generateExpressionRule(architecture, features)); + + // Statement rule (for imperative paradigms) + if (['procedural', 'object-oriented', 'mixed'].includes(architecture.paradigm)) { + rules.push(generateStatementRule(architecture, features)); + } + + // Add paradigm-specific constructs + switch (architecture.paradigm) { + case 'object-oriented': + if (syntax.paradigmExamples.class) { + rules.push(generateClassRule(syntax.paradigmExamples.class)); + } + break; + case 'functional': + if (syntax.paradigmExamples.function) { + rules.push(generateFunctionRule(syntax.paradigmExamples.function, features.functionTypes)); + } + break; + case 'declarative': + if (syntax.paradigmExamples.rule) { + rules.push(generateDeclarativeRule(syntax.paradigmExamples.rule)); + } + break; + } + + return rules; +} + +/** + * Generate expression rule based on paradigm + */ +function generateExpressionRule(architecture: LanguageArchitecture, features: LanguageFeatures): GrammarRule { + const choices = [ + '$.identifier', + '$.number', + '$.string', + '$.parenthesized_expression' + ]; + + // Add function calls if functions are supported + if (features.functionTypes.length > 0) { + choices.push('$.function_call'); + } + + // Add data structure literals + if (features.dataStructures.includes('arrays')) { + choices.push('$.array_literal'); + } + if (features.dataStructures.includes('objects')) { + choices.push('$.object_literal'); + } + + // Add binary operations for most paradigms + if (architecture.paradigm !== 'declarative') { + choices.push('$.binary_expression'); + } + + return { + name: 'expression', + definition: `choice(${choices.join(', ')})`, + comment: 'Expression rule covering all expression types' + }; +} + +/** + * Generate statement rule for imperative paradigms + */ +function generateStatementRule(architecture: LanguageArchitecture, features: LanguageFeatures): GrammarRule { + const choices = [ + '$.variable_declaration', + '$.expression_statement' + ]; + + // Add control flow statements + if (features.controlFlow.includes('conditionals')) { + choices.push('$.if_statement'); + } + if (features.controlFlow.includes('loops')) { + choices.push('$.for_statement', '$.while_statement'); + } + + return { + name: 'statement', + definition: `choice(${choices.join(', ')})`, + comment: 'Statement rule for imperative constructs' + }; +} + +/** + * Generate data structure rules + */ +function generateDataStructureRules(dataStructures: string[]): GrammarRule[] { + const rules: GrammarRule[] = []; + + if (dataStructures.includes('arrays')) { + rules.push({ + name: 'array_literal', + definition: 'seq("[", optional(seq($.expression, repeat(seq(",", $.expression)))), "]")', + comment: 'Array literals: [1, 2, 3]' + }); + } + + if (dataStructures.includes('objects')) { + rules.push({ + name: 'object_literal', + definition: 'seq("{", optional(seq($.property, repeat(seq(",", $.property)))), "}")', + comment: 'Object literals: {key: value}' + }); + + rules.push({ + name: 'property', + definition: 'seq(choice($.identifier, $.string), ":", $.expression)', + comment: 'Object property: key: value' + }); + } + + if (dataStructures.includes('tuples')) { + rules.push({ + name: 'tuple_literal', + definition: 'seq("(", $.expression, repeat1(seq(",", $.expression)), ")")', + comment: 'Tuple literals: (a, b, c)' + }); + } + + return rules; +} + +/** + * Generate control flow rules + */ +function generateControlFlowRules(controlFlow: string[], syntax: LanguageSyntax): GrammarRule[] { + const rules: GrammarRule[] = []; + + if (controlFlow.includes('conditionals')) { + rules.push({ + name: 'if_statement', + definition: 'seq("if", "(", $.expression, ")", $.block, optional(seq("else", choice($.if_statement, $.block))))', + comment: 'If-else statements' + }); + + rules.push({ + name: 'block', + definition: 'seq("{", repeat($.statement), "}")', + comment: 'Code blocks' + }); + } + + if (controlFlow.includes('loops')) { + rules.push({ + name: 'while_statement', + definition: 'seq("while", "(", $.expression, ")", $.block)', + comment: 'While loops' + }); + + rules.push({ + name: 'for_statement', + definition: 'seq("for", "(", optional($.statement), ";", optional($.expression), ";", optional($.expression), ")", $.block)', + comment: 'For loops' + }); + } + + return rules; +} + +/** + * Generate class rule from user example + */ +function generateClassRule(classExample: string): GrammarRule { + // Simple class rule - could be enhanced with more parsing + return { + name: 'class_definition', + definition: 'seq("class", $.identifier, "{", repeat($.method_definition), "}")', + comment: `Class definition based on: ${classExample}` + }; +} + +/** + * Generate function rule from user example + */ +function generateFunctionRule(functionExample: string, functionTypes: string[]): GrammarRule { + let definition = 'seq("function", $.identifier, "(", optional($.parameter_list), ")", $.block)'; + + // Add arrow functions if supported + if (functionTypes.includes('anonymous')) { + definition = `choice(${definition}, $.arrow_function)`; + } + + return { + name: 'function_definition', + definition, + comment: `Function definition based on: ${functionExample}` + }; +} + +/** + * Generate declarative rule from user example + */ +function generateDeclarativeRule(ruleExample: string): GrammarRule { + return { + name: 'rule_declaration', + definition: 'seq("rule", $.identifier, optional(seq("when", $.expression)))', + comment: `Rule declaration based on: ${ruleExample}` + }; +} + +/** + * Generate precedences based on paradigm + */ +function generatePrecedences(architecture: LanguageArchitecture, features: LanguageFeatures): string[][] { + // Basic precedence for binary operations + const precedences = [ + ['$.binary_expression'] + ]; + + // Add function call precedence if functions are supported + if (features.functionTypes.length > 0) { + precedences.push(['$.function_call']); + } + + return precedences; +} + +/** + * Generate the complete grammar.js file content + */ +export function generateGrammarFile(grammar: GeneratedGrammar): string { + const lines: string[] = []; + + lines.push('/**'); + lines.push(` * Grammar for ${grammar.name}`); + lines.push(' * Generated by DSK (DSL Development Kit)'); + lines.push(' */'); + lines.push(''); + lines.push('module.exports = grammar({'); + lines.push(` name: '${grammar.name}',`); + lines.push(''); + + // Add word token if specified + if (grammar.word) { + lines.push(` word: $ => $.${grammar.word},`); + lines.push(''); + } + + // Add rules + lines.push(' rules: {'); + + grammar.rules.forEach((rule, index) => { + if (rule.comment) { + lines.push(` // ${rule.comment}`); + } + lines.push(` ${rule.name}: $ => ${rule.definition}${index < grammar.rules.length - 1 ? ',' : ''}`); + if (index < grammar.rules.length - 1) { + lines.push(''); + } + }); + + lines.push(' }'); + + // Add extras + if (grammar.extras.length > 0) { + lines.push(','); + lines.push(''); + lines.push(' extras: $ => ['); + grammar.extras.forEach((extra, index) => { + lines.push(` ${extra}${index < grammar.extras.length - 1 ? ',' : ''}`); + }); + lines.push(' ]'); + } + + // Add conflicts if any + if (grammar.conflicts.length > 0) { + lines.push(','); + lines.push(''); + lines.push(' conflicts: $ => ['); + grammar.conflicts.forEach((conflict, index) => { + lines.push(` [${conflict.join(', ')}]${index < grammar.conflicts.length - 1 ? ',' : ''}`); + }); + lines.push(' ]'); + } + + // Add precedences if any + if (grammar.precedences.length > 0) { + lines.push(','); + lines.push(''); + lines.push(' precedences: $ => ['); + grammar.precedences.forEach((prec, index) => { + lines.push(` [${prec.join(', ')}]${index < grammar.precedences.length - 1 ? ',' : ''}`); + }); + lines.push(' ]'); + } + + lines.push('});'); + lines.push(''); + + return lines.join('\n'); +} + +/** + * Helper functions + */ +function getCommentRuleName(commentPattern: string): string { + switch (commentPattern) { + case '//': return 'line_comment_slash'; + case '#': return 'line_comment_hash'; + case ';': return 'line_comment_semicolon'; + default: return 'line_comment'; + } +} + +function escapeRegex(pattern: string): string { + return pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); +} diff --git a/tree-sitter/dsk/dsk-cli/src/utils/inference.ts b/tree-sitter/dsk/dsk-cli/src/utils/inference.ts new file mode 100644 index 0000000..f49e176 --- /dev/null +++ b/tree-sitter/dsk/dsk-cli/src/utils/inference.ts @@ -0,0 +1,286 @@ +/** + * Pattern Inference Engine + * + * Infers regular expression patterns from user examples. + * Uses an extensible library of common token patterns with solid defaults. + */ + +export interface TokenPattern { + name: string; + description: string; + regex: RegExp; + examples: string[]; + priority: number; // Higher priority patterns are tried first +} + +export interface InferenceResult { + pattern: TokenPattern | null; + confidence: number; // 0-1 score indicating match quality + matchedExamples: string[]; + rejectedExamples: string[]; +} + +/** + * Default token pattern library with common programming language constructs + */ +export const DEFAULT_PATTERNS: TokenPattern[] = [ + // Identifiers + { + name: 'c_identifier', + description: 'C-style identifier (letters, digits, underscore, must start with letter/underscore)', + regex: /^[a-zA-Z_][a-zA-Z0-9_]*$/, + examples: ['myVar', 'userName', '_private', 'MAX_SIZE'], + priority: 10 + }, + { + name: 'js_identifier', + description: 'JavaScript-style identifier (letters, digits, $, _, must start with letter/$/_)', + regex: /^[A-Za-z_$][A-Za-z0-9_$]*$/, + examples: ['x', 'var1', '$var', '_var', 'Var3', 'BananaFruitStand'], + priority: 11 + }, + { + name: 'kebab_identifier', + description: 'Kebab-case identifier (letters, digits, hyphens)', + regex: /^[a-zA-Z][a-zA-Z0-9-]*[a-zA-Z0-9]$/, + examples: ['my-var', 'user-name', 'max-size'], + priority: 8 + }, + { + name: 'camel_identifier', + description: 'CamelCase identifier (letters and digits, no separators)', + regex: /^[a-zA-Z][a-zA-Z0-9]*$/, + examples: ['myVar', 'userName', 'maxSize'], + priority: 9 + }, + + // Numbers + { + name: 'number_general', + description: 'Integer or floating point number (optional sign)', + regex: /^[+-]?(?:\d*\.\d+|\d+\.\d*|\d+)$/, + examples: ['1', '-7', '1.24', '10000', '+0.5', '2.'], + priority: 16 + }, + { + name: 'integer', + description: 'Integer number (optional sign, digits)', + regex: /^[+-]?\d+$/, + examples: ['42', '-17', '+123', '0'], + priority: 15 + }, + { + name: 'float', + description: 'Floating point number (optional sign, decimal point)', + regex: /^[+-]?\d*\.\d+$/, + examples: ['3.14', '-2.5', '+0.123', '.5'], + priority: 14 + }, + { + name: 'scientific', + description: 'Scientific notation number', + regex: /^[+-]?\d*\.?\d+[eE][+-]?\d+$/, + examples: ['1e10', '3.14e-2', '-2.5E+3'], + priority: 12 + }, + { + name: 'hex_number', + description: 'Hexadecimal number (0x prefix)', + regex: /^0[xX][0-9a-fA-F]+$/, + examples: ['0xFF', '0x123ABC', '0X00'], + priority: 13 + }, + + // Strings + { + name: 'double_quoted_string', + description: 'Double-quoted string literal', + regex: /^".*"$/, + examples: ['"hello"', '"world"', '""'], + priority: 11 + }, + { + name: 'single_quoted_string', + description: 'Single-quoted string literal', + regex: /^'.*'$/, + examples: ["'hello'", "'world'", "''"], + priority: 11 + }, + { + name: 'backtick_string', + description: 'Backtick-quoted string literal (template strings)', + regex: /^`.*`$/, + examples: ['`hello`', '`world ${var}`', '``'], + priority: 7 + }, + + // Comments + { + name: 'c_line_comment', + description: 'C-style line comment (// prefix)', + regex: /^\/\/.*$/, + examples: ['// comment', '// TODO: fix this'], + priority: 16 + }, + { + name: 'hash_line_comment', + description: 'Hash line comment (# prefix)', + regex: /^#.*$/, + examples: ['# comment', '# TODO: fix this'], + priority: 16 + }, + { + name: 'semicolon_line_comment', + description: 'Semicolon line comment (; prefix)', + regex: /^;.*$/, + examples: ['; comment', '; TODO: fix this'], + priority: 16 + }, + + // Special patterns + { + name: 'boolean', + description: 'Boolean literal', + regex: /^(true|false)$/, + examples: ['true', 'false'], + priority: 17 + }, + { + name: 'null_literal', + description: 'Null/nil literal', + regex: /^(null|nil|None|undefined)$/, + examples: ['null', 'nil', 'None', 'undefined'], + priority: 17 + } +]; + +/** + * Infer a pattern from valid and invalid examples + */ +export function inferPattern( + validExamples: string[], + invalidExamples: string[] = [], + customPatterns: TokenPattern[] = [] +): InferenceResult { + if (validExamples.length === 0) { + return { + pattern: null, + confidence: 0, + matchedExamples: [], + rejectedExamples: invalidExamples + }; + } + + // Combine default patterns with custom patterns + const allPatterns = [...customPatterns, ...DEFAULT_PATTERNS] + .sort((a, b) => b.priority - a.priority); + + // Try each pattern + for (const pattern of allPatterns) { + const validMatches = validExamples.filter(example => pattern.regex.test(example)); + const invalidMatches = invalidExamples.filter(example => pattern.regex.test(example)); + + // Pattern must match ALL valid examples and NO invalid examples + if (validMatches.length === validExamples.length && invalidMatches.length === 0) { + const confidence = calculateConfidence(validExamples, invalidExamples, pattern); + + return { + pattern, + confidence, + matchedExamples: validMatches, + rejectedExamples: invalidExamples + }; + } + } + + // No pattern found + return { + pattern: null, + confidence: 0, + matchedExamples: [], + rejectedExamples: invalidExamples + }; +} + +/** + * Calculate confidence score for a pattern match + */ +function calculateConfidence( + validExamples: string[], + invalidExamples: string[], + pattern: TokenPattern +): number { + let confidence = 0.8; // Base confidence + + // Boost confidence for more valid examples + if (validExamples.length >= 3) confidence += 0.1; + if (validExamples.length >= 5) confidence += 0.05; + + // Boost confidence for having invalid examples that were correctly rejected + if (invalidExamples.length > 0) confidence += 0.05; + + // Boost confidence if examples match the pattern's own examples + const patternExampleMatches = validExamples.filter(ex => + pattern.examples.some(pex => ex === pex) + ); + if (patternExampleMatches.length > 0) { + confidence += 0.05 * patternExampleMatches.length; + } + + return Math.min(confidence, 1.0); +} + +/** + * Generate a custom regex pattern from examples (fallback when inference fails) + */ +export function generateCustomPattern( + validExamples: string[], + invalidExamples: string[] = [] +): string { + if (validExamples.length === 0) return ''; + + // Simple approach: create alternation of literal examples + // This is a fallback - not as robust as proper pattern matching + const escapedExamples = validExamples.map(ex => + ex.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + ); + + return `^(${escapedExamples.join('|')})$`; +} + +/** + * Validate that a pattern works correctly with given examples + */ +export function validatePattern( + pattern: string, + validExamples: string[], + invalidExamples: string[] = [] +): { isValid: boolean; errors: string[] } { + const errors: string[] = []; + + try { + const regex = new RegExp(pattern); + + // Check valid examples + for (const example of validExamples) { + if (!regex.test(example)) { + errors.push(`Pattern does not match valid example: "${example}"`); + } + } + + // Check invalid examples + for (const example of invalidExamples) { + if (regex.test(example)) { + errors.push(`Pattern incorrectly matches invalid example: "${example}"`); + } + } + + } catch (e) { + errors.push(`Invalid regular expression: ${e instanceof Error ? e.message : 'Unknown error'}`); + } + + return { + isValid: errors.length === 0, + errors + }; +} diff --git a/tree-sitter/dsk/dsk-cli/src/utils/template-processor.ts b/tree-sitter/dsk/dsk-cli/src/utils/template-processor.ts new file mode 100644 index 0000000..e237048 --- /dev/null +++ b/tree-sitter/dsk/dsk-cli/src/utils/template-processor.ts @@ -0,0 +1,192 @@ +/** + * Template Processor + * + * Processes template files by replacing placeholders with actual values + */ + +import { readFileSync, writeFileSync, readdirSync, statSync, mkdirSync, copyFileSync } from 'fs'; +import { join, dirname, basename, extname } from 'path'; +import { LanguageArchitecture, LanguageFeatures, LanguageSyntax } from '../commands/new.js'; + +export interface TemplateContext { + architecture: LanguageArchitecture; + features: LanguageFeatures; + syntax: LanguageSyntax; +} + +/** + * Process a template directory and create a project + */ +export function processTemplate( + templateDir: string, + outputDir: string, + context: TemplateContext +): void { + // Create output directory + mkdirSync(outputDir, { recursive: true }); + + // Process all files in template directory + processDirectory(templateDir, outputDir, context); +} + +/** + * Process a directory recursively + */ +function processDirectory( + sourceDir: string, + targetDir: string, + context: TemplateContext +): void { + const items = readdirSync(sourceDir); + + for (const item of items) { + const sourcePath = join(sourceDir, item); + const targetPath = join(targetDir, processFileName(item, context)); + + const stat = statSync(sourcePath); + + if (stat.isDirectory()) { + mkdirSync(targetPath, { recursive: true }); + processDirectory(sourcePath, targetPath, context); + } else { + processFile(sourcePath, targetPath, context); + } + } +} + +/** + * Process a single file + */ +function processFile( + sourcePath: string, + targetPath: string, + context: TemplateContext +): void { + const content = readFileSync(sourcePath, 'utf-8'); + const processedContent = processContent(content, context); + + // Ensure target directory exists + mkdirSync(dirname(targetPath), { recursive: true }); + + writeFileSync(targetPath, processedContent, 'utf-8'); +} + +/** + * Process file name placeholders + */ +function processFileName(fileName: string, context: TemplateContext): string { + const replacements = getReplacements(context); + + let processed = fileName; + for (const [placeholder, value] of Object.entries(replacements)) { + processed = processed.replace(new RegExp(placeholder, 'g'), value); + } + + return processed; +} + +/** + * Process file content placeholders + */ +function processContent(content: string, context: TemplateContext): string { + const replacements = getReplacements(context); + + let processed = content; + for (const [placeholder, value] of Object.entries(replacements)) { + processed = processed.replace(new RegExp(placeholder, 'g'), value); + } + + return processed; +} + +/** + * Get all placeholder replacements + */ +function getReplacements(context: TemplateContext): Record<string, string> { + const { architecture, features, syntax } = context; + + return { + '__DSL_NAME__': architecture.name, + '__PARADIGM__': architecture.paradigm, + '__PURPOSE__': architecture.purpose, + '__DATA_PHILOSOPHY__': architecture.dataPhilosophy, + + // Syntax elements + '__VARIABLE_KEYWORD__': syntax.variables.keyword, + '__ASSIGNMENT_OPERATOR__': syntax.variables.operator, + '__TERMINATOR__': syntax.variables.terminator, + '__VARIABLE_EXAMPLE__': syntax.variables.example, + + '__COMMENT_EXAMPLE__': syntax.comments.pattern, + '__STRING_EXAMPLE__': syntax.strings.examples[0] || '"hello"', + '__NUMBER_EXAMPLE__': syntax.numbers.examples[0] || '42', + '__IDENTIFIER_EXAMPLE__': syntax.identifiers.examples[0] || 'myVar', + + // Paradigm-specific examples + '__PARADIGM_EXAMPLE__': getParadigmExample(architecture, syntax), + + // File extension + '__EXT__': getFileExtension(architecture.name), + + // Feature lists + '__FEATURES_LIST__': generateFeaturesList(features), + '__DATA_STRUCTURES__': features.dataStructures.join(', ') || 'Basic types', + + // Control flow + '__CONTROL_FLOW__': features.controlFlow.join(', ') || 'Sequential execution' + }; +} + +/** + * Get paradigm-specific example code + */ +function getParadigmExample(architecture: LanguageArchitecture, syntax: LanguageSyntax): string { + if (syntax.paradigmExamples.class) { + return syntax.paradigmExamples.class; + } + if (syntax.paradigmExamples.function) { + return syntax.paradigmExamples.function; + } + if (syntax.paradigmExamples.rule) { + return syntax.paradigmExamples.rule; + } + + // Fallback to variable example + return syntax.variables.example; +} + +/** + * Get appropriate file extension for the language + */ +function getFileExtension(languageName: string): string { + // Simple heuristic - could be made configurable + const name = languageName.toLowerCase(); + + if (name.includes('script')) return 'script'; + if (name.includes('lang')) return 'lang'; + if (name.includes('dsl')) return 'dsl'; + + // Default: use first 3 characters of name + return name.substring(0, 3); +} + +/** + * Generate features list for README + */ +function generateFeaturesList(features: LanguageFeatures): string { + const items: string[] = []; + + if (features.controlFlow.length > 0) { + items.push(`- **Control Flow**: ${features.controlFlow.join(', ')}`); + } + + if (features.dataStructures.length > 0) { + items.push(`- **Data Structures**: ${features.dataStructures.join(', ')}`); + } + + if (features.functionTypes.length > 0) { + items.push(`- **Functions**: ${features.functionTypes.join(', ')}`); + } + + return items.length > 0 ? items.join('\n') : '- Basic language constructs'; +} |