#include "./keyword_manager.hpp" namespace tsl { KeywordManager& KeywordManager::GetInstance() { static KeywordManager instance; return instance; } KeywordManager::KeywordManager() { InitKeywords(); } std::vector KeywordManager::GetAllKeywords() { std::vector keyword; keyword.reserve(keywords_.size()); for (const auto& [key, value] : keywords_) keyword.push_back(value); return keyword; } std::vector KeywordManager::GetKeyWordByPrefix(std::string prefix) { std::vector keyword; for (const auto& [key, value] : keywords_) { if (key.starts_with(prefix)) keyword.push_back(value); } return keyword; } std::optional KeywordManager::GetKeywordInfo(std::string key) { auto target = keywords_.find(key); if (target == keywords_.end()) return std::nullopt; return target->second; } void KeywordManager::InitKeywords() { keywords_.reserve(200); InitProgramStructureKeywords(); InitDataTypeKeywords(); InitClassKeywords(); InitControlFlowKeywords(); InitOperatorKeywords(); InitSqlKeywords(); InitBuiltinKeywords(); InitConstantKeywords(); } void KeywordManager::InitProgramStructureKeywords() { keywords_["program"] = { "program", KeywordCategory::kProgramStructure, "## Program\n\n程序开始的入口,一般用户不需要使用,在作为独立的TSL脚本时可以使用。 \n通常来说,倘若编写TSL代码作为CGI执行运行,系统默认以PROGRAM模式运行。虽然TSL可以省略PROGRAM关键字,但是使用PROGRAM关键字可以使得TSL代码里包含子函数.\n\n**例如:**\n```pascal\nprogram Test;\n\tfunction sub1();\n\tbegin\n\t\twriteln('Execute sub1');\n\tend;\nbegin\n\tsub1();\nend.\n```" }; keywords_["function"] = { "function", KeywordCategory::kProgramStructure, "## Function\n\n函数声明开始,组成类似于FUNCTION XXXX(); BEGIN END;的函数块" }; keywords_["procedure"] = { "procedure", KeywordCategory::kProgramStructure, "## Procedure\n\n与FUNCTION类似,但是在函数头后不允许加返回类型值" }; keywords_["unit"] = { "unit", KeywordCategory::kProgramStructure, "## Unit Declaration\n\nDeclares a code unit/module.\n\n**Syntax:**\n```pascal\nunit UnitName;\ninterface\n // public declarations\nimplementation\n // private implementation\nend.\n```" }; keywords_["uses"] = { "uses", KeywordCategory::kProgramStructure, "## Uses Clause\n\nImports external units/modules.\n\n**Syntax:**\n```pascal\nuses Unit1, Unit2, Unit3;\n```\n\n**Example:**\n```pascal\nuses System, SysUtils, Classes;\n```" }; keywords_["implementation"] = { "implementation", KeywordCategory::kProgramStructure, "## Implementation Section\n\nMarks the beginning of the private implementation section in a unit.\n\n**Usage:**\n```pascal\nunit MyUnit;\ninterface\n // public interface\nimplementation\n // private implementation\nend.\n```" }; keywords_["interface"] = { "interface", KeywordCategory::kProgramStructure, "## Interface Section\n\nMarks the public interface section in a unit.\n\n**Usage:**\n```pascal\nunit MyUnit;\ninterface\n // public declarations\n function PublicFunction: integer;\nimplementation\nend.\n```" }; keywords_["initialization"] = { "initialization", KeywordCategory::kProgramStructure, "## Initialization Section\n\nCode executed when the unit is first loaded.\n\n**Usage:**\n```pascal\nunit MyUnit;\ninterface\nimplementation\ninitialization\n // initialization code\nend.\n```" }; keywords_["finalization"] = { "finalization", KeywordCategory::kProgramStructure, "## Finalization Section\n\nCode executed when the program terminates.\n\n**Usage:**\n```pascal\nunit MyUnit;\ninterface\nimplementation\ninitialization\n // setup code\nfinalization\n // cleanup code\nend.\n```" }; } void KeywordManager::InitDataTypeKeywords() { keywords_["string"] = { "string", KeywordCategory::kDataTypes, "## String Type\n\nVariable-length string data type.\n\n**Example:**\n```pascal\nvar\n myString: string;\nbegin\n myString := 'Hello World';\nend;\n```\n\n**Note:** Supports Unicode and automatic memory management." }; keywords_["integer"] = { "integer", KeywordCategory::kDataTypes, "## Integer Type\n\n32-bit signed integer data type.\n\n**Range:** -2,147,483,648 to 2,147,483,647\n\n**Example:**\n```pascal\nvar\n count: integer;\nbegin\n count := 42;\nend;\n```" }; keywords_["boolean"] = { "boolean", KeywordCategory::kDataTypes, "## Boolean Type\n\nLogical data type with values `true` or `false`.\n\n**Example:**\n```pascal\nvar\n isValid: boolean;\nbegin\n isValid := true;\n if isValid then\n echo('Valid!');\nend;\n```" }; keywords_["int64"] = { "int64", KeywordCategory::kDataTypes, "## Int64 Type\n\n64-bit signed integer data type.\n\n**Range:** -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807\n\n**Example:**\n```pascal\nvar\n bigNumber: int64;\nbegin\n bigNumber := 1234567890123456789;\nend;\n```" }; keywords_["real"] = { "real", KeywordCategory::kDataTypes, "## Real Type\n\nFloating-point number data type.\n\n**Example:**\n```pascal\nvar\n price: real;\nbegin\n price := 19.99;\nend;\n```" }; keywords_["array"] = { "array", KeywordCategory::kDataTypes, "## Array Type\n\nCollection of elements of the same type.\n\n**Syntax:**\n```pascal\narray[IndexType] of ElementType\n```\n\n**Examples:**\n```pascal\nvar\n numbers: array[1..10] of integer;\n names: array of string; // dynamic array\nbegin\n numbers[1] := 42;\nend;\n```" }; } void KeywordManager::InitClassKeywords() { keywords_["type"] = { "type", KeywordCategory::kClassTypes, "## Type Declaration\n\nDeclares custom data types.\n\n**Syntax:**\n```pascal\ntype\n TypeName = TypeDefinition;\n```\n\n**Example:**\n```pascal\ntype\n TPoint = record\n X, Y: integer;\n end;\n \n TMyClass = class\n // class members\n end;\n```" }; keywords_["class"] = { "class", KeywordCategory::kClassTypes, "## Class Declaration\n\nDeclares an object-oriented class.\n\n**Syntax:**\n```pascal\ntype\n TClassName = class(TBaseClass)\n private\n // private members\n public\n // public members\n end;\n```\n\n**Example:**\n```pascal\ntype\n TPerson = class\n private\n FName: string;\n public\n constructor Create(AName: string);\n property Name: string read FName write FName;\n end;\n```" }; keywords_["new"] = { "new", KeywordCategory::kClassTypes, "## New Instance\n\nCreates a new instance of a class.\n\n**Syntax:**\n```pascal\nInstanceVar := ClassName.Create();\n```\n\n**Example:**\n```pascal\nvar\n person: TPerson;\nbegin\n person := TPerson.Create('John');\n try\n // use person\n finally\n person.Free;\n end;\nend;\n```" }; } void KeywordManager::InitControlFlowKeywords() { keywords_["if"] = { "if", KeywordCategory::kConditionals, "## If Statement\n\nConditional execution based on a boolean expression.\n\n**Syntax:**\n```pascal\nif condition then\n statement\nelse\n statement;\n```\n\n**Example:**\n```pascal\nif age >= 18 then\n echo('Adult')\nelse\n echo('Minor');\n```\n\n**Multi-line:**\n```pascal\nif score >= 90 then\nbegin\n grade := 'A';\n echo('Excellent!');\nend;\n```" }; keywords_["for"] = { "for", KeywordCategory::kLoops, "## For Loop\n\nIterates over a range of values.\n\n**Syntax:**\n```pascal\nfor variable := startValue to endValue do\n statement;\n \nfor variable := startValue downto endValue do\n statement;\n```\n\n**Examples:**\n```pascal\n// Forward loop\nfor i := 1 to 10 do\n echo(i);\n \n// Reverse loop\nfor i := 10 downto 1 do\n echo(i);\n \n// Array iteration\nfor i := Low(myArray) to High(myArray) do\n echo(myArray[i]);\n```" }; keywords_["while"] = { "while", KeywordCategory::kLoops, "## While Loop\n\nRepeats while a condition is true.\n\n**Syntax:**\n```pascal\nwhile condition do\n statement;\n```\n\n**Example:**\n```pascal\ni := 0;\nwhile i < 10 do\nbegin\n echo(i);\n i := i + 1;\nend;\n```\n\n**Note:** The condition is checked before each iteration." }; keywords_["case"] = { "case", KeywordCategory::kConditionals, "## Case Statement\n\nMulti-way conditional based on value matching.\n\n**Syntax:**\n```pascal\ncase expression of\n value1: statement1;\n value2: statement2;\n else\n defaultStatement;\nend;\n```\n\n**Example:**\n```pascal\ncase dayOfWeek of\n 1: echo('Monday');\n 2: echo('Tuesday');\n 3: echo('Wednesday');\n 4: echo('Thursday');\n 5: echo('Friday');\n 6, 7: echo('Weekend');\n else\n echo('Invalid day');\nend;\n```" }; } void KeywordManager::InitOperatorKeywords() { keywords_["and"] = { "and", KeywordCategory::kLogicalOperators, "## Logical AND\n\nLogical conjunction operator.\n\n**Truth Table:**\n| A | B | A and B |\n|---|---|--------|\n| T | T | T |\n| T | F | F |\n| F | T | F |\n| F | F | F |\n\n**Example:**\n```pascal\nif (age >= 18) and (hasLicense) then\n echo('Can drive');\n```" }; keywords_["or"] = { "or", KeywordCategory::kLogicalOperators, "## Logical OR\n\nLogical disjunction operator.\n\n**Truth Table:**\n| A | B | A or B |\n|---|---|-------|\n| T | T | T |\n| T | F | T |\n| F | T | T |\n| F | F | F |\n\n**Example:**\n```pascal\nif (isAdmin) or (isOwner) then\n echo('Has permission');\n```" }; keywords_["div"] = { "div", KeywordCategory::kArithmeticOperators, "## Integer Division\n\nPerforms integer division (truncates decimal part).\n\n**Example:**\n```pascal\nvar result: integer;\nbegin\n result := 17 div 5; // result = 3\n result := 20 div 4; // result = 5\nend;\n```\n\n**Note:** Use `/` for real division, `div` for integer division." }; keywords_["mod"] = { "mod", KeywordCategory::kArithmeticOperators, "## Modulo Operator\n\nReturns the remainder of integer division.\n\n**Example:**\n```pascal\nvar remainder: integer;\nbegin\n remainder := 17 mod 5; // remainder = 2\n remainder := 20 mod 4; // remainder = 0\n \n // Check if number is even\n if (number mod 2) = 0 then\n echo('Even number');\nend;\n```" }; } void KeywordManager::InitSqlKeywords() { keywords_["select"] = { "select", KeywordCategory::kSqlControl, "## SQL SELECT Statement\n\nRetrieves data from database tables.\n\n**Syntax:**\n```sql\nSELECT column1, column2, ...\nFROM table_name\nWHERE condition\nORDER BY column;\n```\n\n**Examples:**\n```sql\n-- Basic select\nSELECT name, age FROM users;\n\n-- With condition\nSELECT * FROM products WHERE price > 100;\n\n-- With ordering\nSELECT name, salary FROM employees ORDER BY salary DESC;\n```" }; keywords_["update"] = { "update", KeywordCategory::kSqlControl, "## SQL UPDATE Statement\n\nModifies existing records in a table.\n\n**Syntax:**\n```sql\nUPDATE table_name\nSET column1 = value1, column2 = value2, ...\nWHERE condition;\n```\n\n**Examples:**\n```sql\n-- Update single record\nUPDATE users SET age = 30 WHERE id = 1;\n\n-- Update multiple columns\nUPDATE products \nSET price = 99.99, category = 'Electronics'\nWHERE id = 100;\n```\n\n**⚠️ Warning:** Always use WHERE clause to avoid updating all records!" }; } void KeywordManager::InitBuiltinKeywords() { keywords_["echo"] = { "echo", KeywordCategory::kBuiltinFunctions, "## Echo Function\n\nOutputs text to the console or output stream.\n\n**Syntax:**\n```pascal\necho(expression);\necho(format, args...);\n```\n\n**Examples:**\n```pascal\necho('Hello World!');\necho('Number: ', 42);\necho('Name: %s, Age: %d', name, age);\n```\n\n**Features:**\n- Supports multiple arguments\n- Automatic type conversion\n- Format string support" }; keywords_["mtic"] = { "mtic", KeywordCategory::kBuiltinFunctions, "## Timer Start (mtic)\n\nStarts a high-precision timer for performance measurement.\n\n**Usage:**\n```pascal\nmtic(); // Start timer\n// ... code to measure ...\nvar elapsed := mtoc(); // Get elapsed time\necho('Elapsed: ', elapsed, ' seconds');\n```\n\n**Note:** Use with `mtoc()` to measure execution time." }; keywords_["mtoc"] = { "mtoc", KeywordCategory::kBuiltinFunctions, "## Timer End (mtoc)\n\nReturns elapsed time since last `mtic()` call.\n\n**Returns:** Time in seconds (real number)\n\n**Example:**\n```pascal\nmtic();\nfor i := 1 to 1000000 do\n // some computation\nvar timeElapsed := mtoc();\necho('Loop took: ', timeElapsed, ' seconds');\n```" }; } void KeywordManager::InitConstantKeywords() { keywords_["true"] = { "true", KeywordCategory::kBooleanConstants, "## Boolean True\n\nRepresents the boolean value **true**.\n\n**Usage:**\n```pascal\nvar\n flag: boolean;\nbegin\n flag := true;\n \n if flag then\n echo('Flag is set!');\nend;\n```\n\n**Note:** Case-insensitive in most Pascal dialects." }; keywords_["false"] = { "false", KeywordCategory::kBooleanConstants, "## Boolean False\n\nRepresents the boolean value **false**.\n\n**Usage:**\n```pascal\nvar\n isComplete: boolean;\nbegin\n isComplete := false;\n \n while not isComplete do\n begin\n // do work\n isComplete := checkCompletion();\n end;\nend;\n```" }; keywords_["nil"] = { "nil", KeywordCategory::kNullConstants, "## Nil Constant\n\nRepresents a null/empty pointer or object reference.\n\n**Usage:**\n```pascal\nvar\n obj: TMyClass;\nbegin\n obj := nil; // Initialize to null\n \n if obj <> nil then\n obj.DoSomething();\n \n obj := TMyClass.Create();\n try\n // use obj\n finally\n obj.Free;\n obj := nil; // Clear reference\n end;\nend;\n```\n\n**Best Practice:** Always check for nil before using object references." }; keywords_["inf"] = { "inf", KeywordCategory::kMathConstants, "## Infinity Constant\n\nRepresents positive mathematical infinity.\n\n**Usage:**\n```pascal\nvar\n result: real;\nbegin\n result := 1.0 / 0.0; // Results in inf\n \n if result = inf then\n echo('Result is infinite');\nend;\n```\n\n**Note:** Use for floating-point calculations and comparisons." }; keywords_["nan"] = { "nan", KeywordCategory::kMathConstants, "## Not a Number (NaN)\n\nRepresents an undefined or invalid floating-point result.\n\n**Common Causes:**\n- `0.0 / 0.0`\n- `sqrt(-1.0)`\n- `inf - inf`\n\n**Usage:**\n```pascal\nvar\n result: real;\nbegin\n result := sqrt(-1.0); // Results in NaN\n \n if IsNaN(result) then\n echo('Invalid calculation');\nend;\n```\n\n**Note:** NaN ≠ NaN, use `IsNaN()` function for checking." }; } }