Refactor TokenStream (and some minor changes to Token) (#4695)
* Refactor TokenStream (and some minor changes to Token) Signed-off-by: Nick Cameron <nrc@ncameron.org> * Tidy up lexer tests Signed-off-by: Nick Cameron <nrc@ncameron.org> --------- Signed-off-by: Nick Cameron <nrc@ncameron.org>
This commit is contained in:
@ -137,7 +137,7 @@ pub use lsp::test_util::kcl_lsp_server;
|
||||
impl Program {
|
||||
pub fn parse(input: &str) -> Result<(Option<Program>, Vec<CompilationError>), KclError> {
|
||||
let module_id = ModuleId::default();
|
||||
let tokens = parsing::token::lexer(input, module_id)?;
|
||||
let tokens = parsing::token::lex(input, module_id)?;
|
||||
let (ast, errs) = parsing::parse_tokens(tokens).0?;
|
||||
|
||||
Ok((ast.map(|ast| Program { ast }), errs))
|
||||
@ -145,7 +145,7 @@ impl Program {
|
||||
|
||||
pub fn parse_no_errs(input: &str) -> Result<Program, KclError> {
|
||||
let module_id = ModuleId::default();
|
||||
let tokens = parsing::token::lexer(input, module_id)?;
|
||||
let tokens = parsing::token::lex(input, module_id)?;
|
||||
let ast = parsing::parse_tokens(tokens).parse_errs_as_err()?;
|
||||
|
||||
Ok(Program { ast })
|
||||
|
||||
@ -46,34 +46,31 @@ use crate::{
|
||||
lsp::{backend::Backend as _, util::IntoDiagnostic},
|
||||
parsing::{
|
||||
ast::types::{Expr, Node, VariableKind},
|
||||
token::TokenType,
|
||||
token::TokenStream,
|
||||
PIPE_OPERATOR,
|
||||
},
|
||||
CacheInformation, ModuleId, OldAstState, Program, SourceRange,
|
||||
};
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
pub static ref SEMANTIC_TOKEN_TYPES: Vec<SemanticTokenType> = {
|
||||
// This is safe to unwrap because we know all the token types are valid.
|
||||
// And the test would fail if they were not.
|
||||
let mut gen = TokenType::all_semantic_token_types().unwrap();
|
||||
gen.extend(vec![
|
||||
const SEMANTIC_TOKEN_TYPES: [SemanticTokenType; 10] = [
|
||||
SemanticTokenType::NUMBER,
|
||||
SemanticTokenType::VARIABLE,
|
||||
SemanticTokenType::KEYWORD,
|
||||
SemanticTokenType::TYPE,
|
||||
SemanticTokenType::STRING,
|
||||
SemanticTokenType::OPERATOR,
|
||||
SemanticTokenType::COMMENT,
|
||||
SemanticTokenType::FUNCTION,
|
||||
SemanticTokenType::PARAMETER,
|
||||
SemanticTokenType::PROPERTY,
|
||||
]);
|
||||
gen
|
||||
};
|
||||
];
|
||||
|
||||
pub static ref SEMANTIC_TOKEN_MODIFIERS: Vec<SemanticTokenModifier> = {
|
||||
vec![
|
||||
const SEMANTIC_TOKEN_MODIFIERS: [SemanticTokenModifier; 5] = [
|
||||
SemanticTokenModifier::DECLARATION,
|
||||
SemanticTokenModifier::DEFINITION,
|
||||
SemanticTokenModifier::DEFAULT_LIBRARY,
|
||||
SemanticTokenModifier::READONLY,
|
||||
SemanticTokenModifier::STATIC,
|
||||
]
|
||||
};
|
||||
}
|
||||
];
|
||||
|
||||
/// A subcommand for running the server.
|
||||
#[derive(Clone, Debug)]
|
||||
@ -102,7 +99,7 @@ pub struct Backend {
|
||||
/// The stdlib signatures for the language.
|
||||
pub stdlib_signatures: HashMap<String, SignatureHelp>,
|
||||
/// Token maps.
|
||||
pub token_map: DashMap<String, Vec<crate::parsing::token::Token>>,
|
||||
pub(super) token_map: DashMap<String, TokenStream>,
|
||||
/// AST maps.
|
||||
pub ast_map: DashMap<String, Node<crate::parsing::ast::types::Program>>,
|
||||
/// Last successful execution.
|
||||
@ -281,7 +278,7 @@ impl crate::lsp::backend::Backend for Backend {
|
||||
|
||||
// Lets update the tokens.
|
||||
let module_id = ModuleId::default();
|
||||
let tokens = match crate::parsing::token::lexer(¶ms.text, module_id) {
|
||||
let tokens = match crate::parsing::token::lex(¶ms.text, module_id) {
|
||||
Ok(tokens) => tokens,
|
||||
Err(err) => {
|
||||
self.add_to_diagnostics(¶ms, &[err], true).await;
|
||||
@ -407,11 +404,11 @@ impl Backend {
|
||||
self.executor_ctx.read().await
|
||||
}
|
||||
|
||||
async fn update_semantic_tokens(&self, tokens: &[crate::parsing::token::Token], params: &TextDocumentItem) {
|
||||
async fn update_semantic_tokens(&self, tokens: &TokenStream, params: &TextDocumentItem) {
|
||||
// Update the semantic tokens map.
|
||||
let mut semantic_tokens = vec![];
|
||||
let mut last_position = Position::new(0, 0);
|
||||
for token in tokens {
|
||||
for token in tokens.as_slice() {
|
||||
let Ok(token_type) = SemanticTokenType::try_from(token.token_type) else {
|
||||
// We continue here because not all tokens can be converted this way, we will get
|
||||
// the rest from the ast.
|
||||
@ -563,7 +560,7 @@ impl Backend {
|
||||
let semantic_token = SemanticToken {
|
||||
delta_line: position.line - last_position.line + 1,
|
||||
delta_start: 0,
|
||||
length: token.value.len() as u32,
|
||||
length: (token.end - token.start) as u32,
|
||||
token_type: token_type_index,
|
||||
token_modifiers_bitset,
|
||||
};
|
||||
@ -582,7 +579,7 @@ impl Backend {
|
||||
} else {
|
||||
position.character - last_position.character
|
||||
},
|
||||
length: token.value.len() as u32,
|
||||
length: (token.end - token.start) as u32,
|
||||
token_type: token_type_index,
|
||||
token_modifiers_bitset,
|
||||
};
|
||||
@ -963,8 +960,8 @@ impl LanguageServer for Backend {
|
||||
semantic_tokens_options: SemanticTokensOptions {
|
||||
work_done_progress_options: WorkDoneProgressOptions::default(),
|
||||
legend: SemanticTokensLegend {
|
||||
token_types: SEMANTIC_TOKEN_TYPES.clone(),
|
||||
token_modifiers: SEMANTIC_TOKEN_MODIFIERS.clone(),
|
||||
token_types: SEMANTIC_TOKEN_TYPES.to_vec(),
|
||||
token_modifiers: SEMANTIC_TOKEN_MODIFIERS.to_vec(),
|
||||
},
|
||||
range: Some(false),
|
||||
full: Some(SemanticTokensFullOptions::Bool(true)),
|
||||
|
||||
@ -1082,7 +1082,7 @@ fn myFn = (param1) => {
|
||||
|
||||
// Get the token map.
|
||||
let token_map = server.token_map.get("file:///test.kcl").unwrap().clone();
|
||||
assert!(token_map != vec![]);
|
||||
assert!(!token_map.is_empty());
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
||||
@ -2206,7 +2206,7 @@ part001 = cube([0,0], 20)
|
||||
|
||||
// Get the tokens.
|
||||
let tokens = server.token_map.get("file:///test.kcl").unwrap().clone();
|
||||
assert_eq!(tokens.len(), 120);
|
||||
assert_eq!(tokens.as_slice().len(), 120);
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
||||
@ -3379,11 +3379,11 @@ part001 = startSketchOn('XY')
|
||||
|
||||
// Get the symbols map.
|
||||
let symbols_map = server.symbols_map.get("file:///test.kcl").unwrap().clone();
|
||||
assert!(symbols_map != vec![]);
|
||||
assert!(!symbols_map.is_empty());
|
||||
|
||||
// Get the semantic tokens map.
|
||||
let semantic_tokens_map = server.semantic_tokens_map.get("file:///test.kcl").unwrap().clone();
|
||||
assert!(semantic_tokens_map != vec![]);
|
||||
assert!(!semantic_tokens_map.is_empty());
|
||||
|
||||
// Get the memory.
|
||||
let memory = server.memory_map.get("file:///test.kcl").unwrap().clone();
|
||||
@ -3422,7 +3422,7 @@ NEW_LINT = 1"#
|
||||
|
||||
// Get the semantic tokens map.
|
||||
let semantic_tokens_map = server.semantic_tokens_map.get("file:///test.kcl").unwrap().clone();
|
||||
assert!(semantic_tokens_map != vec![]);
|
||||
assert!(!semantic_tokens_map.is_empty());
|
||||
|
||||
// Get the memory.
|
||||
let memory = server.memory_map.get("file:///test.kcl");
|
||||
@ -3466,7 +3466,7 @@ part001 = startSketchOn('XY')
|
||||
|
||||
// Get the token map.
|
||||
let token_map = server.token_map.get("file:///test.kcl").unwrap().clone();
|
||||
assert!(token_map != vec![]);
|
||||
assert!(!token_map.is_empty());
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
||||
@ -3474,11 +3474,11 @@ part001 = startSketchOn('XY')
|
||||
|
||||
// Get the symbols map.
|
||||
let symbols_map = server.symbols_map.get("file:///test.kcl").unwrap().clone();
|
||||
assert!(symbols_map != vec![]);
|
||||
assert!(!symbols_map.is_empty());
|
||||
|
||||
// Get the semantic tokens map.
|
||||
let semantic_tokens_map = server.semantic_tokens_map.get("file:///test.kcl").unwrap().clone();
|
||||
assert!(semantic_tokens_map != vec![]);
|
||||
assert!(!semantic_tokens_map.is_empty());
|
||||
|
||||
// Get the memory.
|
||||
let memory = server.memory_map.get("file:///test.kcl").unwrap().clone();
|
||||
@ -3509,7 +3509,7 @@ part001 = startSketchOn('XY')
|
||||
|
||||
// Get the token map.
|
||||
let token_map = server.token_map.get("file:///test.kcl").unwrap().clone();
|
||||
assert!(token_map != vec![]);
|
||||
assert!(!token_map.is_empty());
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
||||
@ -3517,11 +3517,11 @@ part001 = startSketchOn('XY')
|
||||
|
||||
// Get the symbols map.
|
||||
let symbols_map = server.symbols_map.get("file:///test.kcl").unwrap().clone();
|
||||
assert!(symbols_map != vec![]);
|
||||
assert!(!symbols_map.is_empty());
|
||||
|
||||
// Get the semantic tokens map.
|
||||
let semantic_tokens_map = server.semantic_tokens_map.get("file:///test.kcl").unwrap().clone();
|
||||
assert!(semantic_tokens_map != vec![]);
|
||||
assert!(!semantic_tokens_map.is_empty());
|
||||
|
||||
// Get the memory.
|
||||
let memory = server.memory_map.get("file:///test.kcl");
|
||||
|
||||
@ -2,7 +2,7 @@ use crate::{
|
||||
errors::{CompilationError, KclError, KclErrorDetails},
|
||||
parsing::{
|
||||
ast::types::{Node, Program},
|
||||
token::{Token, TokenType},
|
||||
token::TokenStream,
|
||||
},
|
||||
source_range::{ModuleId, SourceRange},
|
||||
};
|
||||
@ -34,15 +34,13 @@ pub fn top_level_parse(code: &str) -> ParseResult {
|
||||
|
||||
/// Parse the given KCL code into an AST.
|
||||
pub fn parse_str(code: &str, module_id: ModuleId) -> ParseResult {
|
||||
let tokens = pr_try!(crate::parsing::token::lexer(code, module_id));
|
||||
let tokens = pr_try!(crate::parsing::token::lex(code, module_id));
|
||||
parse_tokens(tokens)
|
||||
}
|
||||
|
||||
/// Parse the supplied tokens into an AST.
|
||||
pub fn parse_tokens(tokens: Vec<Token>) -> ParseResult {
|
||||
let (tokens, unknown_tokens): (Vec<Token>, Vec<Token>) = tokens
|
||||
.into_iter()
|
||||
.partition(|token| token.token_type != TokenType::Unknown);
|
||||
pub fn parse_tokens(mut tokens: TokenStream) -> ParseResult {
|
||||
let unknown_tokens = tokens.remove_unknown();
|
||||
|
||||
if !unknown_tokens.is_empty() {
|
||||
let source_ranges = unknown_tokens.iter().map(SourceRange::from).collect();
|
||||
@ -69,7 +67,7 @@ pub fn parse_tokens(tokens: Vec<Token>) -> ParseResult {
|
||||
return Node::<Program>::default().into();
|
||||
}
|
||||
|
||||
parser::run_parser(&mut tokens.as_slice())
|
||||
parser::run_parser(tokens.as_slice())
|
||||
}
|
||||
|
||||
/// Result of parsing.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,28 +1,221 @@
|
||||
use std::str::FromStr;
|
||||
// Clippy does not agree with rustc here for some reason.
|
||||
#![allow(clippy::needless_lifetimes)]
|
||||
|
||||
use std::{fmt, iter::Enumerate, num::NonZeroUsize};
|
||||
|
||||
use anyhow::Result;
|
||||
use parse_display::{Display, FromStr};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use parse_display::Display;
|
||||
use tower_lsp::lsp_types::SemanticTokenType;
|
||||
use winnow::{error::ParseError, stream::ContainsToken};
|
||||
use winnow::{
|
||||
self,
|
||||
error::ParseError,
|
||||
stream::{ContainsToken, Stream},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
errors::KclError,
|
||||
parsing::ast::types::{ItemVisibility, VariableKind},
|
||||
source_range::{ModuleId, SourceRange},
|
||||
};
|
||||
use tokeniser::Input;
|
||||
|
||||
mod tokeniser;
|
||||
|
||||
// Re-export
|
||||
pub use tokeniser::Input;
|
||||
#[cfg(test)]
|
||||
pub(crate) use tokeniser::RESERVED_WORDS;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub(crate) struct TokenStream {
|
||||
tokens: Vec<Token>,
|
||||
}
|
||||
|
||||
impl TokenStream {
|
||||
fn new(tokens: Vec<Token>) -> Self {
|
||||
Self { tokens }
|
||||
}
|
||||
|
||||
pub(super) fn remove_unknown(&mut self) -> Vec<Token> {
|
||||
let tokens = std::mem::take(&mut self.tokens);
|
||||
let (tokens, unknown_tokens): (Vec<Token>, Vec<Token>) = tokens
|
||||
.into_iter()
|
||||
.partition(|token| token.token_type != TokenType::Unknown);
|
||||
self.tokens = tokens;
|
||||
unknown_tokens
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> impl Iterator<Item = &Token> {
|
||||
self.tokens.iter()
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.tokens.is_empty()
|
||||
}
|
||||
|
||||
pub fn as_slice(&self) -> TokenSlice {
|
||||
TokenSlice::from(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a TokenStream> for TokenSlice<'a> {
|
||||
fn from(stream: &'a TokenStream) -> Self {
|
||||
TokenSlice {
|
||||
start: 0,
|
||||
end: stream.tokens.len(),
|
||||
stream,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for TokenStream {
|
||||
type Item = Token;
|
||||
|
||||
type IntoIter = std::vec::IntoIter<Token>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.tokens.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct TokenSlice<'a> {
|
||||
stream: &'a TokenStream,
|
||||
start: usize,
|
||||
end: usize,
|
||||
}
|
||||
|
||||
impl<'a> std::ops::Deref for TokenSlice<'a> {
|
||||
type Target = [Token];
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.stream.tokens[self.start..self.end]
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TokenSlice<'a> {
|
||||
pub fn token(&self, i: usize) -> &Token {
|
||||
&self.stream.tokens[i + self.start]
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> impl Iterator<Item = &Token> {
|
||||
(**self).iter()
|
||||
}
|
||||
|
||||
pub fn without_ends(&self) -> Self {
|
||||
Self {
|
||||
start: self.start + 1,
|
||||
end: self.end - 1,
|
||||
stream: self.stream,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoIterator for TokenSlice<'a> {
|
||||
type Item = &'a Token;
|
||||
|
||||
type IntoIter = std::slice::Iter<'a, Token>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.stream.tokens[self.start..self.end].iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Stream for TokenSlice<'a> {
|
||||
type Token = Token;
|
||||
type Slice = Self;
|
||||
type IterOffsets = Enumerate<std::vec::IntoIter<Token>>;
|
||||
type Checkpoint = Checkpoint;
|
||||
|
||||
fn iter_offsets(&self) -> Self::IterOffsets {
|
||||
#[allow(clippy::unnecessary_to_owned)]
|
||||
self.to_vec().into_iter().enumerate()
|
||||
}
|
||||
|
||||
fn eof_offset(&self) -> usize {
|
||||
self.len()
|
||||
}
|
||||
|
||||
fn next_token(&mut self) -> Option<Self::Token> {
|
||||
let token = self.first()?.clone();
|
||||
self.start += 1;
|
||||
Some(token)
|
||||
}
|
||||
|
||||
fn offset_for<P>(&self, predicate: P) -> Option<usize>
|
||||
where
|
||||
P: Fn(Self::Token) -> bool,
|
||||
{
|
||||
self.iter().position(|b| predicate(b.clone()))
|
||||
}
|
||||
|
||||
fn offset_at(&self, tokens: usize) -> Result<usize, winnow::error::Needed> {
|
||||
if let Some(needed) = tokens.checked_sub(self.len()).and_then(NonZeroUsize::new) {
|
||||
Err(winnow::error::Needed::Size(needed))
|
||||
} else {
|
||||
Ok(tokens)
|
||||
}
|
||||
}
|
||||
|
||||
fn next_slice(&mut self, offset: usize) -> Self::Slice {
|
||||
assert!(self.start + offset <= self.end);
|
||||
|
||||
let next = TokenSlice {
|
||||
stream: self.stream,
|
||||
start: self.start,
|
||||
end: self.start + offset,
|
||||
};
|
||||
self.start += offset;
|
||||
next
|
||||
}
|
||||
|
||||
fn checkpoint(&self) -> Self::Checkpoint {
|
||||
Checkpoint(self.start, self.end)
|
||||
}
|
||||
|
||||
fn reset(&mut self, checkpoint: &Self::Checkpoint) {
|
||||
self.start = checkpoint.0;
|
||||
self.end = checkpoint.1;
|
||||
}
|
||||
|
||||
fn raw(&self) -> &dyn fmt::Debug {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> winnow::stream::Offset for TokenSlice<'a> {
|
||||
fn offset_from(&self, start: &Self) -> usize {
|
||||
self.start - start.start
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> winnow::stream::Offset<Checkpoint> for TokenSlice<'a> {
|
||||
fn offset_from(&self, start: &Checkpoint) -> usize {
|
||||
self.start - start.0
|
||||
}
|
||||
}
|
||||
|
||||
impl winnow::stream::Offset for Checkpoint {
|
||||
fn offset_from(&self, start: &Self) -> usize {
|
||||
self.0 - start.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> winnow::stream::StreamIsPartial for TokenSlice<'a> {
|
||||
type PartialState = ();
|
||||
|
||||
fn complete(&mut self) -> Self::PartialState {}
|
||||
|
||||
fn restore_partial(&mut self, _: Self::PartialState) {}
|
||||
|
||||
fn is_partial_supported() -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Checkpoint(usize, usize);
|
||||
|
||||
/// The types of tokens.
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone, Deserialize, Serialize, JsonSchema, FromStr, Display)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone, Display)]
|
||||
#[display(style = "camelCase")]
|
||||
pub enum TokenType {
|
||||
/// A number.
|
||||
@ -73,6 +266,8 @@ pub enum TokenType {
|
||||
impl TryFrom<TokenType> for SemanticTokenType {
|
||||
type Error = anyhow::Error;
|
||||
fn try_from(token_type: TokenType) -> Result<Self> {
|
||||
// If you return a new kind of `SemanticTokenType`, make sure to update `SEMANTIC_TOKEN_TYPES`
|
||||
// in the LSP implementation.
|
||||
Ok(match token_type {
|
||||
TokenType::Number => Self::NUMBER,
|
||||
TokenType::Word => Self::VARIABLE,
|
||||
@ -102,52 +297,6 @@ impl TryFrom<TokenType> for SemanticTokenType {
|
||||
}
|
||||
|
||||
impl TokenType {
|
||||
// This is for the lsp server.
|
||||
// Don't call this function directly in the code use a lazy_static instead
|
||||
// like we do in the lsp server.
|
||||
pub fn all_semantic_token_types() -> Result<Vec<SemanticTokenType>> {
|
||||
let mut settings = schemars::gen::SchemaSettings::openapi3();
|
||||
settings.inline_subschemas = true;
|
||||
let mut generator = schemars::gen::SchemaGenerator::new(settings);
|
||||
|
||||
let schema = TokenType::json_schema(&mut generator);
|
||||
let schemars::schema::Schema::Object(o) = &schema else {
|
||||
anyhow::bail!("expected object schema: {:#?}", schema);
|
||||
};
|
||||
let Some(subschemas) = &o.subschemas else {
|
||||
anyhow::bail!("expected subschemas: {:#?}", schema);
|
||||
};
|
||||
let Some(one_ofs) = &subschemas.one_of else {
|
||||
anyhow::bail!("expected one_of: {:#?}", schema);
|
||||
};
|
||||
|
||||
let mut semantic_tokens = vec![];
|
||||
for one_of in one_ofs {
|
||||
let schemars::schema::Schema::Object(o) = one_of else {
|
||||
anyhow::bail!("expected object one_of: {:#?}", one_of);
|
||||
};
|
||||
|
||||
let Some(enum_values) = o.enum_values.as_ref() else {
|
||||
anyhow::bail!("expected enum values: {:#?}", o);
|
||||
};
|
||||
|
||||
if enum_values.len() > 1 {
|
||||
anyhow::bail!("expected only one enum value: {:#?}", o);
|
||||
}
|
||||
|
||||
if enum_values.is_empty() {
|
||||
anyhow::bail!("expected at least one enum value: {:#?}", o);
|
||||
}
|
||||
|
||||
let label = TokenType::from_str(&enum_values[0].to_string().replace('"', ""))?;
|
||||
if let Ok(semantic_token_type) = SemanticTokenType::try_from(label) {
|
||||
semantic_tokens.push(semantic_token_type);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(semantic_tokens)
|
||||
}
|
||||
|
||||
pub fn is_whitespace(&self) -> bool {
|
||||
matches!(self, Self::Whitespace)
|
||||
}
|
||||
@ -157,17 +306,15 @@ impl TokenType {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Deserialize, Serialize, Clone)]
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub struct Token {
|
||||
#[serde(rename = "type")]
|
||||
pub token_type: TokenType,
|
||||
/// Offset in the source code where this token begins.
|
||||
pub start: usize,
|
||||
/// Offset in the source code where this token ends.
|
||||
pub end: usize,
|
||||
#[serde(default, skip_serializing_if = "ModuleId::is_top_level")]
|
||||
pub module_id: ModuleId,
|
||||
pub value: String,
|
||||
pub(super) module_id: ModuleId,
|
||||
pub(super) value: String,
|
||||
}
|
||||
|
||||
impl ContainsToken<Token> for (TokenType, &str) {
|
||||
@ -249,7 +396,7 @@ impl From<&Token> for SourceRange {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lexer(s: &str, module_id: ModuleId) -> Result<Vec<Token>, KclError> {
|
||||
pub fn lex(s: &str, module_id: ModuleId) -> Result<TokenStream, KclError> {
|
||||
tokeniser::lex(s, module_id).map_err(From::from)
|
||||
}
|
||||
|
||||
@ -281,15 +428,3 @@ impl From<ParseError<Input<'_>, winnow::error::ContextError>> for KclError {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
// We have this as a test so we can ensure it never panics with an unwrap in the server.
|
||||
#[test]
|
||||
fn test_token_type_to_semantic_token_type() {
|
||||
let semantic_types = TokenType::all_semantic_token_types().unwrap();
|
||||
assert!(!semantic_types.is_empty());
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -47,7 +47,7 @@ fn read(filename: &'static str, test_name: &str) -> String {
|
||||
|
||||
fn parse(test_name: &str) {
|
||||
let input = read("input.kcl", test_name);
|
||||
let tokens = crate::parsing::token::lexer(&input, ModuleId::default()).unwrap();
|
||||
let tokens = crate::parsing::token::lex(&input, ModuleId::default()).unwrap();
|
||||
|
||||
// Parse the tokens into an AST.
|
||||
let parse_res = Result::<_, KclError>::Ok(crate::parsing::parse_tokens(tokens).unwrap());
|
||||
|
||||
@ -2137,8 +2137,10 @@ fn f() {
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
{
|
||||
let tokens = crate::parsing::token::lexer(raw, ModuleId::default()).unwrap();
|
||||
let literal = crate::parsing::parser::unsigned_number_literal.parse(&tokens).unwrap();
|
||||
let tokens = crate::parsing::token::lex(raw, ModuleId::default()).unwrap();
|
||||
let literal = crate::parsing::parser::unsigned_number_literal
|
||||
.parse(tokens.as_slice())
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
literal.recast(),
|
||||
expected,
|
||||
@ -2216,9 +2218,9 @@ sketch002 = startSketchOn({
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
{
|
||||
let tokens = crate::parsing::token::lexer(input, ModuleId::default()).unwrap();
|
||||
crate::parsing::parser::print_tokens(&tokens);
|
||||
let expr = crate::parsing::parser::object.parse(&tokens).unwrap();
|
||||
let tokens = crate::parsing::token::lex(input, ModuleId::default()).unwrap();
|
||||
crate::parsing::parser::print_tokens(tokens.as_slice());
|
||||
let expr = crate::parsing::parser::object.parse(tokens.as_slice()).unwrap();
|
||||
assert_eq!(
|
||||
expr.recast(&FormatOptions::new(), 0, ExprContext::Other),
|
||||
expected,
|
||||
@ -2314,8 +2316,10 @@ sketch002 = startSketchOn({
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
{
|
||||
let tokens = crate::parsing::token::lexer(input, ModuleId::default()).unwrap();
|
||||
let expr = crate::parsing::parser::array_elem_by_elem.parse(&tokens).unwrap();
|
||||
let tokens = crate::parsing::token::lex(input, ModuleId::default()).unwrap();
|
||||
let expr = crate::parsing::parser::array_elem_by_elem
|
||||
.parse(tokens.as_slice())
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
expr.recast(&FormatOptions::new(), 0, ExprContext::Other),
|
||||
expected,
|
||||
|
||||
Reference in New Issue
Block a user