298 lines
16 KiB
C++
298 lines
16 KiB
C++
#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."
|
||
};
|
||
}
|
||
}
|