|
|
@ -4,28 +4,33 @@ namespace parkdown; |
|
|
|
|
|
|
|
|
|
|
|
class Lexer { |
|
|
|
class Lexer { |
|
|
|
private array $source; |
|
|
|
private array $source; |
|
|
|
|
|
|
|
private ?string $fileName; |
|
|
|
|
|
|
|
|
|
|
|
public function __construct(string $sourceCode) { |
|
|
|
public function __construct(string $sourceCode, ?string $fileName = null) { |
|
|
|
|
|
|
|
$this->fileName = $fileName; |
|
|
|
$unifiedSource = str_replace(["\r\n", "\r"], "\n", $sourceCode); |
|
|
|
$unifiedSource = str_replace(["\r\n", "\r"], "\n", $sourceCode); |
|
|
|
$this->source = explode("\n", trim($unifiedSource, "\n")); |
|
|
|
$this->source = explode("\n", trim($unifiedSource, "\n")); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public function tokenize() : array { |
|
|
|
public function tokenize() : array { |
|
|
|
$tokens = []; |
|
|
|
$tokens = []; |
|
|
|
|
|
|
|
$row = 1; |
|
|
|
|
|
|
|
|
|
|
|
foreach ($this->source as $line) { |
|
|
|
foreach ($this->source as $line) { |
|
|
|
if (strlen($line) < 1) { |
|
|
|
if (strlen($line) < 1) { |
|
|
|
array_push($tokens, new Token(TokenType::EOL, "\n")); |
|
|
|
array_push($tokens, new Token(TokenType::EOL, "\n", [$row, 0, $this->fileName])); |
|
|
|
|
|
|
|
$row++; |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
$buffer = ""; |
|
|
|
$buffer = ""; |
|
|
|
$number = false; |
|
|
|
$number = false; |
|
|
|
|
|
|
|
$col = 1; |
|
|
|
|
|
|
|
|
|
|
|
$clearBuffer = function() use (&$buffer, &$tokens) { |
|
|
|
$clearBuffer = function() use (&$buffer, &$tokens, $col, $row) { |
|
|
|
if (strlen($buffer) < 1) |
|
|
|
if (strlen($buffer) < 1) |
|
|
|
return; |
|
|
|
return; |
|
|
|
array_push($tokens, new Token(TokenType::TEXT, $buffer)); |
|
|
|
array_push($tokens, new Token(TokenType::TEXT, $buffer, [$col, $row, $this->fileName])); |
|
|
|
$buffer = ""; |
|
|
|
$buffer = ""; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
@ -34,66 +39,66 @@ class Lexer { |
|
|
|
$clearBuffer(); |
|
|
|
$clearBuffer(); |
|
|
|
$number = true; |
|
|
|
$number = true; |
|
|
|
} else if (!is_numeric($char) && $number) { |
|
|
|
} else if (!is_numeric($char) && $number) { |
|
|
|
array_push($tokens, new Token(TokenType::NUMBER, $buffer)); |
|
|
|
array_push($tokens, new Token(TokenType::NUMBER, $buffer, [$col, $row, $this->fileName])); |
|
|
|
$buffer = ""; |
|
|
|
$buffer = ""; |
|
|
|
$number = false; |
|
|
|
$number = false; |
|
|
|
} |
|
|
|
} |
|
|
|
switch($char) { |
|
|
|
switch($char) { |
|
|
|
case '#': |
|
|
|
case '#': |
|
|
|
$clearBuffer(); |
|
|
|
$clearBuffer(); |
|
|
|
array_push($tokens, new Token(TokenType::HASH, $char)); |
|
|
|
array_push($tokens, new Token(TokenType::HASH, $char, [$col, $row, $this->fileName])); |
|
|
|
break; |
|
|
|
break; |
|
|
|
case '*': |
|
|
|
case '*': |
|
|
|
$clearBuffer(); |
|
|
|
$clearBuffer(); |
|
|
|
array_push($tokens, new Token(TokenType::ASTERISK, $char)); |
|
|
|
array_push($tokens, new Token(TokenType::ASTERISK, $char, [$col, $row, $this->fileName])); |
|
|
|
break; |
|
|
|
break; |
|
|
|
case '.': |
|
|
|
case '.': |
|
|
|
$clearBuffer(); |
|
|
|
$clearBuffer(); |
|
|
|
array_push($tokens, new Token(TokenType::DOT, $char)); |
|
|
|
array_push($tokens, new Token(TokenType::DOT, $char, [$col, $row, $this->fileName])); |
|
|
|
break; |
|
|
|
break; |
|
|
|
case '-': |
|
|
|
case '-': |
|
|
|
$clearBuffer(); |
|
|
|
$clearBuffer(); |
|
|
|
array_push($tokens, new Token(TokenType::MINUS, $char)); |
|
|
|
array_push($tokens, new Token(TokenType::MINUS, $char, [$col, $row, $this->fileName])); |
|
|
|
break; |
|
|
|
break; |
|
|
|
case '`': |
|
|
|
case '`': |
|
|
|
$clearBuffer(); |
|
|
|
$clearBuffer(); |
|
|
|
array_push($tokens, new Token(TokenType::BACKTICK, $char)); |
|
|
|
array_push($tokens, new Token(TokenType::BACKTICK, $char, [$col, $row, $this->fileName])); |
|
|
|
break; |
|
|
|
break; |
|
|
|
case '[': |
|
|
|
case '[': |
|
|
|
$clearBuffer(); |
|
|
|
$clearBuffer(); |
|
|
|
array_push($tokens, new Token(TokenType::LBRACKET, $char)); |
|
|
|
array_push($tokens, new Token(TokenType::LBRACKET, $char, [$col, $row, $this->fileName])); |
|
|
|
break; |
|
|
|
break; |
|
|
|
case ']': |
|
|
|
case ']': |
|
|
|
$clearBuffer(); |
|
|
|
$clearBuffer(); |
|
|
|
array_push($tokens, new Token(TokenType::RBRACKET, $char)); |
|
|
|
array_push($tokens, new Token(TokenType::RBRACKET, $char, [$col, $row, $this->fileName])); |
|
|
|
break; |
|
|
|
break; |
|
|
|
case '(': |
|
|
|
case '(': |
|
|
|
$clearBuffer(); |
|
|
|
$clearBuffer(); |
|
|
|
array_push($tokens, new Token(TokenType::LPAREN, $char)); |
|
|
|
array_push($tokens, new Token(TokenType::LPAREN, $char, [$col, $row, $this->fileName])); |
|
|
|
break; |
|
|
|
break; |
|
|
|
case ')': |
|
|
|
case ')': |
|
|
|
$clearBuffer(); |
|
|
|
$clearBuffer(); |
|
|
|
array_push($tokens, new Token(TokenType::RPAREN, $char)); |
|
|
|
array_push($tokens, new Token(TokenType::RPAREN, $char, [$col, $row, $this->fileName])); |
|
|
|
break; |
|
|
|
break; |
|
|
|
case '!': |
|
|
|
case '!': |
|
|
|
$clearBuffer(); |
|
|
|
$clearBuffer(); |
|
|
|
array_push($tokens, new Token(TokenType::BANG, $char)); |
|
|
|
array_push($tokens, new Token(TokenType::BANG, $char, [$col, $row, $this->fileName])); |
|
|
|
break; |
|
|
|
break; |
|
|
|
case '|': |
|
|
|
case '|': |
|
|
|
$clearBuffer(); |
|
|
|
$clearBuffer(); |
|
|
|
array_push($tokens, new Token(TokenType::PIPE, $char)); |
|
|
|
array_push($tokens, new Token(TokenType::PIPE, $char, [$col, $row, $this->fileName])); |
|
|
|
break; |
|
|
|
break; |
|
|
|
case '\\': |
|
|
|
case '\\': |
|
|
|
$clearBuffer(); |
|
|
|
$clearBuffer(); |
|
|
|
array_push($tokens, new Token(TokenType::BACKSLASH, $char)); |
|
|
|
array_push($tokens, new Token(TokenType::BACKSLASH, $char, [$col, $row, $this->fileName])); |
|
|
|
break; |
|
|
|
break; |
|
|
|
case '>': |
|
|
|
case '>': |
|
|
|
$clearBuffer(); |
|
|
|
$clearBuffer(); |
|
|
|
array_push($tokens, new Token(TokenType::GT, $char)); |
|
|
|
array_push($tokens, new Token(TokenType::GT, $char, [$col, $row, $this->fileName])); |
|
|
|
break; |
|
|
|
break; |
|
|
|
case ' ': |
|
|
|
case ' ': |
|
|
|
$clearBuffer(); |
|
|
|
$clearBuffer(); |
|
|
|
array_push($tokens, new Token(TokenType::TAB, $char)); |
|
|
|
array_push($tokens, new Token(TokenType::TAB, $char, [$col, $row, $this->fileName])); |
|
|
|
break; |
|
|
|
break; |
|
|
|
case ':': |
|
|
|
case ':': |
|
|
|
if (str_ends_with($buffer, "http") || str_ends_with($buffer, "https")) { |
|
|
|
if (str_ends_with($buffer, "http") || str_ends_with($buffer, "https")) { |
|
|
@ -102,26 +107,30 @@ class Lexer { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
$clearBuffer(); |
|
|
|
$clearBuffer(); |
|
|
|
array_push($tokens, new Token(TokenType::COLON, $char)); |
|
|
|
array_push($tokens, new Token(TokenType::COLON, $char, [$col, $row, $this->fileName])); |
|
|
|
break; |
|
|
|
break; |
|
|
|
case '{': |
|
|
|
case '{': |
|
|
|
$clearBuffer(); |
|
|
|
$clearBuffer(); |
|
|
|
array_push($tokens, new Token(TokenType::LBRACE, $char)); |
|
|
|
array_push($tokens, new Token(TokenType::LBRACE, $char, [$col, $row, $this->fileName])); |
|
|
|
break; |
|
|
|
break; |
|
|
|
case '}': |
|
|
|
case '}': |
|
|
|
$clearBuffer(); |
|
|
|
$clearBuffer(); |
|
|
|
array_push($tokens, new Token(TokenType::RBRACE, $char)); |
|
|
|
array_push($tokens, new Token(TokenType::RBRACE, $char, [$col, $row, $this->fileName])); |
|
|
|
break; |
|
|
|
break; |
|
|
|
default: |
|
|
|
default: |
|
|
|
$buffer .= $char; |
|
|
|
$buffer .= $char; |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$col++; |
|
|
|
} |
|
|
|
} |
|
|
|
$clearBuffer(); |
|
|
|
$clearBuffer(); |
|
|
|
array_push($tokens, new Token(TokenType::EOL, "\n")); |
|
|
|
array_push($tokens, new Token(TokenType::EOL, "\n", [$col, $row, $this->fileName])); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$row++; |
|
|
|
} |
|
|
|
} |
|
|
|
$clearBuffer(); |
|
|
|
$clearBuffer(); |
|
|
|
array_push($tokens, new Token(TokenType::EOF, "\0")); |
|
|
|
array_push($tokens, new Token(TokenType::EOF, "\0", [$col, $row, $this->fileName])); |
|
|
|
|
|
|
|
|
|
|
|
return $tokens; |
|
|
|
return $tokens; |
|
|
|
} |
|
|
|
} |
|
|
|