tsl-devkit/lsp-server/src/language/keyword_manager.cpp

298 lines
16 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "./keyword_manager.hpp"
namespace tsl
{
KeywordManager& KeywordManager::GetInstance()
{
static KeywordManager instance;
return instance;
}
KeywordManager::KeywordManager()
{
InitKeywords();
}
std::vector<KeywordInfo> KeywordManager::GetAllKeywords()
{
std::vector<KeywordInfo> keyword;
keyword.reserve(keywords_.size());
for (const auto& [key, value] : keywords_)
keyword.push_back(value);
return keyword;
}
std::vector<KeywordInfo> KeywordManager::GetKeyWordByPrefix(std::string prefix)
{
std::vector<KeywordInfo> keyword;
for (const auto& [key, value] : keywords_)
{
if (key.starts_with(prefix))
keyword.push_back(value);
}
return keyword;
}
std::optional<KeywordInfo> 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."
};
}
}